diff options
-rw-r--r-- | doc/info/librarian.texinfo | 4 | ||||
-rw-r--r-- | src/librarian.c | 196 |
2 files changed, 197 insertions, 3 deletions
diff --git a/doc/info/librarian.texinfo b/doc/info/librarian.texinfo index 7d3b416..cc26211 100644 --- a/doc/info/librarian.texinfo +++ b/doc/info/librarian.texinfo @@ -148,7 +148,9 @@ Upper cased arguments are interpreted as @code{VARIABLE} options, other arguments are interpreted as @code{LIBRARY} options, and should be, but are not required to be, lower -cased. +cased. Additionally, @code{VARIABLE} may only +consist of letters, digits, @code{_} (underscore), +@code{-} (hyphen). If @code{VARIABLE} is omitted, the process will exit with the value @code{0} if all listed libraries, diff --git a/src/librarian.c b/src/librarian.c index 7d3b4d4..8179f76 100644 --- a/src/librarian.c +++ b/src/librarian.c @@ -21,10 +21,202 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#define t(...) do { if (__VA_ARGS__) goto fail; } while (0) -int main(void) + +/** + * The name of the process. + */ +static const char *argv0; + + +/** + * A library and version range. + */ +struct library { + /** + * The name of the library. + */ + const char *name; + + /** + * The lowest acceptable version. + * `NULL` if unbounded. + */ + const char *lower; + + /** + * The highest acceptable version. + * `NULL` if unbounded. + */ + const char *upper; + + /** + * Is the version stored in + * `lower` acceptable. + */ + int lower_closed; + + /** + * Is the version stored in + * `ypper` acceptable. + */ + int upper_closed; +}; + + + +/** + * Determine whether a string is the + * name of a non-reserved variable. + * + * @param s The string. + * @return 1: The string is a varible name. + * 0: The string is a library. + */ +static int is_variable(const char *s) { - return 0; + for (; *s; s++) { + if (isupper(*s)) ; + else if (isdigit(*s)) ; + else if (strchr("_-", *s)) ; + else + return 0; + } + return 1; +} + + +/** + * Parse a library–library-version range + * argument. + * + * @param s The string. + * @param lib Output parameter for the library spec:s. + * @return 0: Successful. + * 1: Syntax error. + */ +static int parse_library(char *s, struct library *lib) +{ +#define CLEANUP \ + free(libraries) + + char *p; + char c; + + memset(lib, 0, sizeof(*lib)); + + if (strchr(s, '/') || strchr("<>=", *s)) + return 1; + + lib->name = s; + p = strpbrk(s, "<>="); + if (p == NULL) + return 0; + c = *p, *p++ = '\0'; + + switch (c) { + case '=': + lib->lower_closed = lib->upper_closed = 1; + lib->lower = lib->upper = p; + break; + case '>': + p += lib->lower_closed = (*p == '='); + lib->lower = p; + s = strchr(p, '<'); + if (s == NULL) + break; + *s++ = '\0'; + if (!*(p = s)) + return 0; + /* fall through */ + case '<': + p += lib->upper_closed = (*p == '='); + lib->upper = p; + break; + default: + assert(0); + abort(); + break; + } + + return (strpbrk(p, "<>=") || !*p); +} + + +/** + * @return 0: Program was successful. + * 1: An error occurred. + * 2: A library was not found. + * 3: Usage error. + */ +int main(int argc, char *argv[]) +{ + int dashed = 0, f_deps = 0, f_locate = 0, f_oldest = 0; + char *arg; + char **args = argv; + char **args_last = argv; + char **variables = argv; + char **variables_last = argv; + struct library *libraries = NULL; + struct library *libraries_last; + + /* Parse arguments. */ + argv0 = argv ? (argc--, *argv++) : "pp"; + while (argc) { + if (!dashed && !strcmp(*argv, "--")) { + dashed = 1; + argv++; + argc--; + } else if (!dashed && (**argv == '-')) { + arg = *argv++; + argc--; + if (!*arg) + goto usage; + for (arg++; *arg; arg++) { + if (*arg == 'd') + f_deps = 1; + else if (*arg == 'l') + f_locate = 1; + else if (*arg == 'o') + f_oldest = 1; + else + goto usage; + } + } else { + *args_last++ = *argv++; + argc--; + } + } + + /* Parse VARIABLE and LIBRARY arguments. */ + libraries = malloc((size_t)(args_last - args) * sizeof(*libraries)); + libraries_last = libraries; + t (libraries == NULL); + for (; args != args_last; args++) { + if (is_variable(*args)) + *variables_last = *args; + else if (parse_library(*args, libraries_last++)) + goto usage; + } + + CLEANUP; + return 0; + +fail: + perror(argv0); + CLEANUP; + return 1; + +usage: + fprintf(stderr, "%s: Invalid arguments, see `man 1 librarian'.\n", argv0); + CLEANUP; + return 3; } |