/** * MIT/X Consortium License * * Copyright © 2015 Mattias Andrée * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #define t(...) do { if (__VA_ARGS__) goto fail; } while (0) /** * 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) { 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; }