aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/info/librarian.texinfo4
-rw-r--r--src/librarian.c196
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;
}