BrmBuro ======= Brmlab Bureacratic system. License ------- ISC License Copyright 2023 Brmlab, z.s. Dominik Pantůček Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Features -------- * members base management * member files parsing and validation * member ids validation * generating new member id * information about active, suspended, destroyed and student members * current status * historical data * detailed member information * querying members by id or nick Requirements ------------ There are no runtime requirements, it is possible to build binary that requires only libc. Build requirements: * Chicken Scheme 5 * make (tested with GNU make) Building -------- Building a shared binary with .so modules: make shared Building static binary: make static It is possible to run the main tool as script with Chicken Scheme interpreter and POSIX-compatible shell for the purpose of development. Development requirements: * POSIX shell Preparing module import files for running as script: make Cleaning the built files from the build directory: make clean Building the import module files, shared and static binaries together: make all Functional Modules ------------------ ### Configuration ### Member File ### Member Record ### Member Base Specific Support Modules ------------------------ ### Month ### Period ### Primes Generic Support Modules ----------------------- These modules are not specific to this project but had to be implemented anyway to not require any external dependencies. ### ANSI A simple module for creating ANSI (ECMA-48) sequence strings. (ansi . args) * ```args``` - a list of color/style keywords Produces an ANSI CSI (Control Sequence Introducer) SGR (Select Graphic Rendition) strings with given attributes (re)set. It understands the following keywords: * ```#:black``` - black text foreground color * ```#:red``` - red text foreground color * ```#:green``` - green text foreground color * ```#:yellow``` - yellow text foreground color * ```#:blue``` - blue text foreground color * ```#:magenta``` - magenta text foreground color * ```#:cyan``` - cyan text foreground color * ```#:white``` - white (grey) text foreground color * ```#:default``` - reset all attributes to terminal defaults * ```#:bold``` - bold font (and/or bright foreground color on some terminals) The order is important as the ```#:default``` resets all attributes given even in the same attribute list. a:error Used to signal errors. Defaults to red bold text. a:warning Used to signal non-fatal warnings. Defaults to regular yellow text. a:success Signals success of an operation. Defaults to bold green text. a:neutral Used for generic text. Defaults to regular white (grey) text. a:default Special style which just resets the terminal output attributes to terminal defaults. a:muted Used for displaying the text "muted" (dimmed). Defaults to bold/bright black text. a:highlight Generic highlight of given text. Defaults to bold blue text. ### Command Line parsing Generic syntax-based implementation of command-line options parsing with focus on generated help and ergonomic binding of option arguments. (command-line print-help (opt (args ...) help body ...) ...) * ```print-help``` - identifier binding for the help printing procedure * ```opt``` - command-line option name as identifier (unquoted symbol) * ```args ...``` - optional arguments of given option * ```help``` - help string for this option * ```body ...``` - expressions to be evaluated upon option match Parses command-line arguments based on the specification given. If evaluated inside ```csi``` script, only options and arguments after the ```--``` meta-option are parsed. If evaluated inside compiled binary, all arguments are parsed as usual. Each option is represented by the ```opt``` option identifier (unquoted symbol), optional arguments ```args``` which become bound in the option specification ```body ...``` expressions, help string and the actual expressions to be evaluated when the option (and possibly its arguments) match. If an option is encountered on the command-line and not enough arguments (according to the option specification) are provided for it, an exception is raised. Within any of the ```body ...``` expressions the ```print-help``` procedure can be used to print the options, their argument names and help strings in a nice, human-readable format. ### Dictionary Simple key/value dictionary with most operations implemented in linear time. The dictionary is internally represented as ```assq``` list and is best suitable for symbols and numbers as keys. (make-dict) Creates an empty dictionary. (dict-has-key? d k) * ```d``` - the dictionary * ```k``` - key to check Returns ```#t``` (true) if the dictionary ```d``` contains the key ```k```. (dict-ref d k [v]) * ```d``` - the dictionary * ```k``` - the key to retrieve * ```v``` - optional default value Retrieves given key ```k``` from the dictionary ```d```. If the key is not stored in the dictionary an error is raised unless an optional value ```v``` is provided which is then returned in that case. (dict-remove d k) * ```d``` - the dictionary * ```k``` - the key to remove Removes the key ```k``` from the given dictionary ```d``` raising an exception if the key is not stored in the dictionary. (dict-set d k v) * ```d``` - the dictionary * ```k``` - key to (re)set * ```v``` - the value to set If the dictionary ```d``` does not contain the key ```k```, adds the value ```v``` into it under the given key. If the key is present, its value is then replaced. (dict-keys d) * ```d``` - the dictionary Returns the list of keys contained in the dictionary ```d```. (dict-map proc d) * ```proc``` - procedure for processing * ```d``` - the dictionary Returns a dictionary created by processing all elements of the dictionary ```d``` using the procedure ```proc```. If the procedure accepts just one argument, only values are passed to it. If the procedure accepts two arguments, both the key and value are passed to it. In both cases, the procedure must produce only the value. (dict-filter pred? d) * ```pred?``` - predicate procedure * ```d``` - the dictionary Returns a new dictionary created by keeping only the key/value pairs from the dictionary ```d``` matching the predicate ```pred?```. If the procedure accepts just one argument, only values are passed to it. If the procedure accepts two arguments, both the key and value are passed to it. (dict-reduce init proc d) * ```init``` - arbitrary initial value * ```proc``` - procedure for performing the reducing step * ```d``` - the dictionary to reduce Iterates over the key/value pairs of given dictionary ```d``` initializing the algorithm with the ```init``` value given. In each step the procedure ```proc``` is called with three arguments: the value accumulated so far, key and value. ### Listing This module implements listing a text file with line numbers and optional highlights of given source lines, optionally with comments for those lines. (print-source-listing lines highlights context hl-pre hl-post ctx-pre ctx-post ellipsis) * ```lines``` - list of string representing lines of the text file * ```highlights``` - list of highlights (see below) * ```context``` - number of context lines to be shown around highlighted lies * ```hl-pre``` - string introducing highlighted lines * ```hl-post``` - string terminating highlighted lines * ```ctx-pre``` - string introducing context lines * ```ctx-post``` - string terminating context lines * ```ellipsis``` - string representing lines omitted from the output Prints given text file represented by the ```lines``` list of strings. Lines to be highlighted can be specified in the ```highlights``` list. The highlight specification is either a number or a list containing the line number and string comment. The lines are actually highlighted by prepending them with ```hl-pre``` string and the highlight is finished by appending ```hl-post``` to them. Usually some constants from the ```ansi``` module are used. If some lines are highlighted a number of ```context``` lines surrounding them may be printed as well. If this argument is negative, all non-highlighted lines are printed as context lines. Context lines are prepended with ```ctx-pre``` string and terminated by ```ctx-post``` string. If some lines between highlight and/or context lines are omitted, ```ellipsis``` string is printed on single line as a substitute. ### Progress Provides syntax forms and procedures for showing progress of a process. (with-progress echo? pre post body ...) * ```echo?``` - flag enabling progress output * ```pre``` - string to be printed at start * ```post``` - string to be printed after finish * ```body ...``` - expressions of the process tracked Displays process progress starting with the ```pre``` string, adding arbitrary string to the output using the ```progress-advance``` during each and every step. If the process reaches its finish, the output line is finished with the ```post``` string and cursor is moved to new line. During the steps, the whole line is always refreshed when the progress gets updated. If ```echo?``` is ```#f``` (false), nothing is output. (progress-advance [str]) * ```str``` - string to add to progress, defaults to "." Adds given string to current progress and refreshes the progress line. Must be evaluated within ```with-progress``` expression. (progress-break body ...) * ```body ...``` - arbitrary expressions to be evaluated Evaluates the ```body ...``` expressions. Hides current progress line before the evaluation and redisplays it when finished. ### Testing This module provides simple syntax forms for (unit) testing of other modules. (run-tests name body ...) * ```name``` - identifier describing the module being tested * ```body ...``` - test expressions Runs all tests specified on the ```body ...```. Firstly it prints "[test] name " at the beginning of the line. Secondly it runs all tests, printing "." for each test successfully passed. If all tests pass, prints " ok." and moves the cursor to the next line. In case any of the tests fails, exception is raised and program terminates. (test-eq? name expression expected-result) * ```name``` - identifier representing the name of the test * ```expression``` - expression to be evaluated * ```expected-result``` - expected result of the test expression Evaluates the test ```expression``` and compares the result with ```expected-result``` using ```eq?```. If the comparison fails, an exception is raised with the ```name``` of the test added to the exception. If the test passes, prints "." like all tests from this module do. (test-equal? name expression expected-result) * ```name``` - identifier representing the name of the test * ```expression``` - expression to be evaluated * ```expected-result``` - expected result of the test expression Evaluates the test ```expression``` and compares the result with ```expected-result``` using ```equal?```. If the comparison fails, an exception is raised with the ```name``` of the test added to the exception. If the test passes, prints "." like all tests from this module do. (test-true name expression) * ```name``` - identifier representing the name of the test * ```expression``` - expression to be evaluated Evaluates the test ```expression``` and checks whether the result is ```#t``` (true). An exception is raised if it is not with the ```name``` of the test added to the exception. If the test passes, prints "." like all tests from this module do. (test-false name expression) * ```name``` - identifier representing the name of the test * ```expression``` - expression to be evaluated Evaluates the test ```expression``` and checks whether the result is ```#f``` (false). An exception is raised if it is not with the ```name``` of the test added to the exception. If the test passes, prints "." like all tests from this module do. (test-exn name expression) * ```name``` - identifier representing the name of the test * ```expression``` - expression to be evaluated Evaluates the test ```expression``` and checks whether it raised an exception. An exception is raised if no exception was raised during the evaluation. If the test passes, prints "." like all tests from this module do. ### Utils To ensure there are no external dependencies (including chicken eggs), this module re-implements any basic procedures which are required for any algorithms used. (filter pred? lst) * ```pred?``` - procedure accepting any value and returning #t or #f * ```lst``` - list to be filtered Returns a list containing only elements matching given ```pred?``` predicate.