Initial commit
This commit is contained in:
commit
22c5179503
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# bulb
|
||||
|
||||
A simple bulletin board for your server. Users of the system can post and read
|
||||
messages using the "bulb" command. You can also set up multiple boards.
|
||||
|
||||
## Usage
|
||||
|
||||
To list available boards:
|
||||
|
||||
```
|
||||
bulb
|
||||
```
|
||||
|
||||
To post a message:
|
||||
|
||||
```
|
||||
bulb post Message text
|
||||
bulb post -b <board-name> Message text
|
||||
```
|
||||
|
||||
To read recent messages:
|
||||
|
||||
```
|
||||
bulb read
|
||||
bulb read -b <board-name>
|
||||
bulb read -n <message-count>
|
||||
```
|
109
cmd/bulb/main.ha
Normal file
109
cmd/bulb/main.ha
Normal file
@ -0,0 +1,109 @@
|
||||
use errors;
|
||||
use fmt;
|
||||
use fs;
|
||||
use getopt;
|
||||
use os;
|
||||
use strconv;
|
||||
use strings;
|
||||
use unix;
|
||||
|
||||
const default_board = "general";
|
||||
|
||||
let name = "";
|
||||
@init fn name() void = name = os::args[0];
|
||||
|
||||
let path: []str = [];
|
||||
@init fn path() void = path = strings::split(os::tryenv("BULBPATH", "/var/bulb"), ":");
|
||||
@fini fn path() void = free(path);
|
||||
|
||||
export fn main() void = {
|
||||
// parse args
|
||||
const cmd = getopt::parse(
|
||||
os::args,
|
||||
"bulletin board",
|
||||
("post", [
|
||||
('a', "post anonymously"),
|
||||
('b', "board", "which board to post on"),
|
||||
"message...",
|
||||
]): getopt::subcmd_help,
|
||||
("read", [
|
||||
('b', "board", "which board to read"),
|
||||
('n', "number", "display N most recent messages"),
|
||||
]): getopt::subcmd_help);
|
||||
defer getopt::finish(&cmd);
|
||||
|
||||
match (cmd.subcmd) {
|
||||
case let subcmd: (str, *getopt::command) =>
|
||||
if (subcmd.0 == "post") {
|
||||
subcmd_post(subcmd.1);
|
||||
} else if (subcmd.0 == "read") {
|
||||
match (subcmd_read(subcmd.1)) {
|
||||
case errors::invalid =>
|
||||
getopt::printhelp(cmd);
|
||||
os::exit(os::status::FAILURE);
|
||||
case void => void;
|
||||
};
|
||||
};
|
||||
case void =>
|
||||
subcmd_ls(&cmd);
|
||||
};
|
||||
};
|
||||
|
||||
fn subcmd_post(cmd: *getopt::command) void = {
|
||||
let anonymous = false;
|
||||
let board = default_board;
|
||||
for (let opt .. cmd.opts) {
|
||||
switch (opt.0) {
|
||||
case 'a' => anonymous = true;
|
||||
case 'b' => board = opt.1;
|
||||
case => abort();
|
||||
};
|
||||
};
|
||||
|
||||
// TODO
|
||||
};
|
||||
|
||||
fn subcmd_read(cmd: *getopt::command) (void | errors::invalid) = {
|
||||
let board = default_board;
|
||||
let number = 8;
|
||||
for (let opt .. cmd.opts) {
|
||||
switch (opt.0) {
|
||||
case 'b' =>
|
||||
board = opt.1;
|
||||
case 'n' =>
|
||||
match (strconv::stoi(opt.1)) {
|
||||
case let num: int => number = num;
|
||||
case => return errors::invalid;
|
||||
};
|
||||
case => abort();
|
||||
};
|
||||
};
|
||||
|
||||
// TODO
|
||||
};
|
||||
|
||||
fn subcmd_ls(cmd: *getopt::command) void = {
|
||||
for (let directory .. path) {
|
||||
match (list_boards_in(directory)) {
|
||||
case let err: fs::error =>
|
||||
fmt::errorf (
|
||||
"{}: Can't list boards in {}: {}\n",
|
||||
name,
|
||||
directory,
|
||||
fs::strerror(err))!;
|
||||
case void => void;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fn list_boards_in(directory: str) (void | fs::error) = {
|
||||
let entries = os::readdir(directory)?;
|
||||
defer fs::dirents_free(entries);
|
||||
for (let entry .. entries) {
|
||||
fmt::println(entry.name)!;
|
||||
};
|
||||
};
|
||||
|
||||
//fn look_up_board(board: str, path: []str) (str | void) {
|
||||
// TODO
|
||||
//};
|
Loading…
Reference in New Issue
Block a user