diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/librarian.c | 246 | ||||
-rw-r--r-- | src/util.h | 81 |
3 files changed, 165 insertions, 164 deletions
@@ -43,7 +43,7 @@ bin/librarian: obj/librarian.o @mkdir -p bin ${CC} ${FLAGS} -o $@ $^ ${LDFLAGS} -obj/%.o: src/%.c +obj/%.o: src/%.c src/*.h mkdir -p obj ${CC} ${FLAGS} -c -o $@ ${CPPFLAGS} ${CFLAGS} $< diff --git a/src/librarian.c b/src/librarian.c index 48a09b1..755d9f5 100644 --- a/src/librarian.c +++ b/src/librarian.c @@ -22,6 +22,7 @@ * DEALINGS IN THE SOFTWARE. */ #define _POSIX_C_SOURCE 200809L +#include "util.h" #include <stdio.h> #include <ctype.h> #include <string.h> @@ -30,10 +31,6 @@ #include <dirent.h> #include <unistd.h> #include <fcntl.h> -#include <assert.h> - -#define t(...) do { if (__VA_ARGS__) goto fail; } while (0) - /** @@ -163,13 +160,9 @@ static int found_file_name_cmp(const void *a, const void *b) */ static int is_variable(const char *s) { - for (; *s; s++) { - if (isupper(*s)) ; - else if (isdigit(*s)) ; - else if (strchr("_-", *s)) ; - else + for (; *s; s++) + if (!isupper(*s) && !isdigit(*s) && !strchr("_-", *s)) return 0; - } return 1; } @@ -219,8 +212,7 @@ static int parse_library(char *s, struct library *lib) lib->upper = p; break; default: - assert(0); - abort(); + NEVER_REACHED; break; } @@ -243,7 +235,6 @@ static int version_subcmp(char *a, char *b) { char *ap; char *bp; - char ac, bc; int r; while (*a || *b) { @@ -253,12 +244,9 @@ static int version_subcmp(char *a, char *b) bp = b + strspn(b, "0123456789"); while (*a == '0') a++; while (*b == '0') b++; - ac = *ap, bc = *bp; - *ap = '\0', *bp = '\0'; - if (ap - a < bp - b) return *ap = ac, *bp = bc, -1; - if (ap - a > bp - b) return *ap = ac, *bp = bc, +1; - r = strcmp(a, b); - *ap = ac, *bp = bc; + if (ap - a < bp - b) return -1; + if (ap - a > bp - b) return +1; + TEMP_NUL(ap, TEMP_NUL(bp, r = strcmp(a, b))); a = isdigit(*a) ? (ap + 1) : a; b = isdigit(*b) ? (bp + 1) : b; if (r) return r; @@ -266,10 +254,7 @@ static int version_subcmp(char *a, char *b) /* Compare letter (non-digit) part. */ ap = a + strcspn(a, "0123456789"); bp = b + strcspn(b, "0123456789"); - ac = *ap, bc = *bp; - *ap = '\0', *bp = '\0'; - r = strcmp(a, b); - *ap = ac, *bp = bc; + TEMP_NUL(ap, TEMP_NUL(bp, r = strcmp(a, b))); a = *a && !isdigit(*a) ? (ap + 1) : a; b = *b && !isdigit(*b) ? (bp + 1) : b; if (r) return r; @@ -290,49 +275,35 @@ static int version_subcmp(char *a, char *b) */ static int version_cmp(char *a, char *b) { -#define COMPARE \ - if (ap && bp) { \ - ac = *ap, bc = *bp; \ - *ap = *bp = '\0'; \ - r = version_subcmp(a, b); \ - *ap = ac, *bp = bc; \ - a = ap + 1, b = bp + 1; \ - } else if (ap) { \ - ac = *ap, *ap = '\0'; \ - r = version_subcmp(a, nil); \ - *ap = ac, a = ap + 1; \ - } else if (bp) { \ - bc = *bp, *bp = '\0'; \ - r = version_subcmp(nil, b); \ - *bp = bc, b = bp + 1; \ - } \ +#define COMPARE \ + if (ap && bp) { \ + TEMP_NUL(ap, TEMP_NUL(bp, r = version_subcmp(a, b))); \ + } else if (ap) { \ + TEMP_NUL(ap, r = version_subcmp(a, nil)); \ + } else if (bp) { \ + TEMP_NUL(bp, r = version_subcmp(nil, b)); \ + } \ + a = ap ? (ap + 1) : a; \ + b = bp ? (bp + 1) : b; \ if (r) return r +#define END_AT(C) ap = strchr(a, (C)), bp = strchr(b, (C)) char *ap; char *bp; - char ac, bc; int r = 0; static char nil[1] = { '\0' }; /* Compare epoch. */ - ap = strchr(a, ':'); - bp = strchr(b, ':'); + END_AT(':'); COMPARE; /* Compare non-epoch */ - for (;;) { - ap = strchr(a, '.'); - bp = strchr(b, '.'); - if (!ap && !bp) - break; + while (END_AT('.'), (ap || bp)) { COMPARE; } - ap = strchr(a, '\0'); - bp = strchr(b, '\0'); + END_AT('\0'); COMPARE; return 0; - -#undef COMPARE } @@ -371,10 +342,10 @@ static char *locate_in_dir(struct library *lib, char *path, int oldest) DIR *d = NULL; struct dirent *f; char *p; - char *old = NULL; + void *new; char *best = NULL; char *best_ver; - int r, saved_errno; + int r; d = opendir(path); t (d == NULL); @@ -389,20 +360,15 @@ static char *locate_in_dir(struct library *lib, char *path, int oldest) *p++ = '='; if (!test_library_version(p, lib)) continue; - if (best == NULL) { - old = best, best = strdup(f->d_name); - } else { - best_ver = strrchr(best, '='); - assert(best_ver && !strchr(best_ver, '/')); + if (best != NULL) { + GET_VERSION(best_ver, best); r = version_cmp(p, best_ver + 1); - if (oldest ? (r < 0) : (r > 0)) - old = best, best = strdup(f->d_name); - } - if (best == NULL) { - best = old; - goto fail; + if (!(oldest ? (r < 0) : (r > 0))) + continue; } - free(old); + new = strdup(f->d_name); + t (new == NULL); + free(best), best = new; } t (errno); @@ -419,12 +385,11 @@ static char *locate_in_dir(struct library *lib, char *path, int oldest) return p; fail: - saved_errno = errno; + RETURN (NULL) { free(best); if (d != NULL) closedir(d); - errno = saved_errno; - return NULL; + } } @@ -448,7 +413,7 @@ static char *locate(struct library *lib, char *path, int oldest) char *old; char *best_ver; char *found_ver; - int r, saved_errno; + int r; for (p = path; end; *e = (end ? ':' : '\0'), p = end + 1) { end = strchr(p, ':'); @@ -465,10 +430,8 @@ static char *locate(struct library *lib, char *path, int oldest) if (best == NULL) { old = best, best = found; } else { - best_ver = strrchr(best, '='); - found_ver = strrchr(found, '='); - assert(best_ver && !strchr(best_ver, '/')); - assert(found_ver && !strchr(found_ver, '/')); + GET_VERSION(best_ver, best); + GET_VERSION(found_ver, found); r = version_cmp(found_ver + 1, best_ver + 1); if (oldest ? (r < 0) : (r > 0)) old = best, best = found; @@ -479,10 +442,8 @@ static char *locate(struct library *lib, char *path, int oldest) return errno = 0, best; fail: - saved_errno = errno; + RETURN (NULL) free(best); - errno = saved_errno; - return NULL; } @@ -507,7 +468,6 @@ static int find_librarian_files(struct library *libraries, size_t n, char *path, char *best_ver; char *found_ver; const char *last = NULL; - void *new; size_t ffc = found_files_count; int r; struct found_file f; @@ -515,9 +475,7 @@ static int find_librarian_files(struct library *libraries, size_t n, char *path, qsort(libraries, n, sizeof(*libraries), library_name_cmp); qsort(found_files, ffc, sizeof(*found_files), found_file_name_cmp); - new = realloc(found_files, (ffc + n) * sizeof(*found_files)); - t (new == NULL); - found_files = new; + REALLOC(found_files, ffc + n); for (i = 0; i < n; i++) { f.name = libraries[i].name; @@ -532,31 +490,23 @@ static int find_librarian_files(struct library *libraries, size_t n, char *path, if (found == NULL) goto not_this_range; if (last && !strcmp(f.name, last)) { - best_ver = strrchr(best, '='); - found_ver = strrchr(found, '='); - assert(best_ver && !strchr(best_ver, '/')); - assert(found_ver && !strchr(found_ver, '/')); - r = version_cmp(found + 1, best_ver + 1); - r = oldest ? (r < 0) : (r > 0); - if (r) - free(best); + GET_VERSION(best_ver, best); + GET_VERSION(found_ver, found); + r = version_cmp(found + 1, best_ver + 1); + if (!(oldest ? (r < 0) : (r > 0))) + continue; + free(best); } else { - r = 1, found_files_count++; - } - if (r) { - found_ver = strrchr(found, '='); - assert(found_ver && !strchr(found_ver, '/')); - found_files[found_files_count - 1].name = f.name; - found_files[found_files_count - 1].version = found_ver + 1; - found_files[found_files_count - 1].path = best = found; + last = f.name, found_files_count++; } - last = f.name; + GET_VERSION(found_ver, found); + found_files[found_files_count - 1].name = f.name; + found_files[found_files_count - 1].version = found_ver + 1; + found_files[found_files_count - 1].path = best = found; continue; not_this_range: - if (i + 1 == n) - goto not_found; - if (strcmp(f.name, libraries[i + 1].name)) + if ((i + 1 == n) || strcmp(f.name, libraries[i + 1].name)) goto not_found; continue; } @@ -592,10 +542,9 @@ fail: */ static char *find_variable(const char *path, const char *var) { - int fd = -1, saved_errno; + int fd = -1; size_t ptr = 0, size = 0, len; char *buffer = NULL; - void *new; char *p; char *q; char *sought = NULL; @@ -605,12 +554,7 @@ static char *find_variable(const char *path, const char *var) t (fd == -1); for (;;) { - if (ptr == size) { - size = size ? (size << 1) : 512; - new = realloc(buffer, size); - t (new == NULL); - buffer = new; - } + MAYBE_GROW(buffer, ptr, size, 512); n = read(fd, buffer + ptr, size - ptr); t (n < 0); if (n == 0) @@ -619,9 +563,7 @@ static char *find_variable(const char *path, const char *var) } close(fd), fd = -1; - new = realloc(buffer, ptr + 3); - t (new == NULL); - buffer = new; + REALLOC(buffer, ptr + 3); buffer[ptr++] = '\n'; buffer[ptr++] = '\0'; memmove(buffer + 1, buffer, ptr); @@ -656,13 +598,12 @@ static char *find_variable(const char *path, const char *var) return p; fail: - saved_errno = errno; + RETURN (NULL) { if (fd >= 0) close(fd); free(buffer); free(sought); - errno = saved_errno; - return NULL; + } } @@ -684,10 +625,8 @@ static char *get_variables(const char **vars, const char **vars_end, size_t file size_t ptr = 0; size_t size = 0; size_t len = 0; - void *new; char *rc; char *p; - int saved_errno; while (files_start < found_files_count) { path = found_files[files_start++].path; @@ -696,12 +635,7 @@ static char *get_variables(const char **vars, const char **vars_end, size_t file t (!part && errno); if (!part || !*part) continue; - if (ptr == size) { - size = size ? (size << 1) : 8; - new = realloc(parts, size * sizeof(*parts)); - t (new == NULL); - parts = new; - } + MAYBE_GROW(parts, ptr, size, 8); len += strlen(part) + 1; parts[ptr++] = part; } @@ -722,12 +656,11 @@ static char *get_variables(const char **vars, const char **vars_end, size_t file return rc; fail: - saved_errno = errno; + RETURN (NULL) { while (ptr--) free(parts[ptr]); free(parts); - errno = saved_errno; - return NULL; + } } @@ -746,7 +679,8 @@ int main(int argc, char *argv[]) const char **variables = (const char **)argv; const char **variables_last = variables; struct library *libraries = NULL; - struct library *libraries_last; + size_t libraries_ptr = 0; + size_t libraries_size = 0; const char *path_; char *path = NULL; int rc; @@ -759,46 +693,38 @@ int main(int argc, char *argv[]) size_t free_this_ptr = 0; size_t free_this_size = 0; const char *deps_string = "deps"; - void *new; /* Parse arguments. */ argv0 = argv ? (argc--, *argv++) : "pp"; - while (argc) { + 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; + 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--; } } if (f_deps && f_locate) goto usage; /* Parse VARIABLE and LIBRARY arguments. */ - libraries = malloc((size_t)(args_last - args) * sizeof(*libraries)); - libraries_last = libraries; + libraries_size = (size_t)(args_last - args); + libraries = malloc(libraries_size * sizeof(*libraries)); t (libraries == NULL); for (; args != args_last; args++) { if (is_variable(*args)) *variables_last++ = *args; - else if (parse_library(*args, libraries_last++)) + else if (parse_library(*args, libraries + libraries_ptr++)) goto usage; } @@ -812,7 +738,7 @@ int main(int argc, char *argv[]) /* Find librarian files. */ for (start_libs = 0;;) { start_files = found_files_count; - n = (size_t)(libraries_last - libraries) - start_libs; + n = libraries_ptr - start_libs; if (n == 0) break; if (find_librarian_files(libraries + start_libs, n, path, f_oldest)) { @@ -820,28 +746,21 @@ int main(int argc, char *argv[]) goto not_found; } start_libs += n; - if (f_locate) + if (f_locate || !f_deps) break; - if (f_deps) { - data = get_variables(&deps_string, 1 + &deps_string, start_files); - t (data == NULL); - for (end = s = data; end; s = end + 1) { - while (isspace(*s)) - s++; - end = strpbrk(s, " \t\r\n\f\v"); - if (end) - *end = '\0'; - if (*s && parse_library(s, libraries_last++)) - goto not_found; - } - if (free_this_ptr == free_this_size) { - free_this_size = free_this_size ? (free_this_size << 1) : 4; - new = realloc(free_this, free_this_size * sizeof(void*)); - t (new == NULL); - free_this = new; - } - free_this[free_this_ptr++] = data; + data = get_variables(&deps_string, 1 + &deps_string, start_files); + t (data == NULL); + for (end = s = data; end; s = end + 1) { + while (isspace(*s)) + s++; + if ((end = strpbrk(s, " \t\r\n\f\v"))) + *end = '\0'; + MAYBE_GROW(libraries, libraries_ptr, libraries_size, 1); + if (*s && parse_library(s, libraries + libraries_ptr++)) + goto not_found; } + MAYBE_GROW(free_this, free_this_ptr, free_this_size, 4); + free_this[free_this_ptr++] = data, data = NULL; } if (f_locate) { while (found_files_count) @@ -868,6 +787,7 @@ usage: fprintf(stderr, "%s: Invalid arguments, see `man 1 librarian'.\n", argv0); rc = 3; goto cleanup; + cleanup: while (found_files_count--) free(found_files[found_files_count].path); diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..fb78e17 --- /dev/null +++ b/src/util.h @@ -0,0 +1,81 @@ +/** + * MIT/X Consortium License + * + * Copyright © 2015 Mattias Andrée <maandree@member.fsf.org> + * + * 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 <stdlib.h> +#include <string.h> +#include <assert.h> + + +#define t(...) do { if (__VA_ARGS__) goto fail; } while (0) + + +#define REALLOC(PTR, SIZE) \ + do { \ + void *new__; \ + new__ = realloc(PTR, (SIZE) * sizeof(*(PTR))); \ + t (new__ == NULL); \ + (PTR) = new__; \ + } while (0) + + +#define GROW(PTR, SIZE, DEFAULT) \ + do { \ + (SIZE) = (SIZE) ? ((SIZE) << 1) : (DEFAULT); \ + REALLOC(PTR, SIZE); \ + } while (0) + + +#define MAYBE_GROW(PTR, USED, SIZE, DEFAULT) \ + do { \ + if ((USED) == (SIZE)) \ + GROW(PTR, SIZE, DEFAULT); \ + } while (0) + + +#define GET_VERSION(VER, PATH) \ + do { \ + (VER) = strrchr((PATH), '='); \ + assert((VER) && !strchr((VER), '/')); \ + } while (0) + + +#define NEVER_REACHED \ + do { \ + assert(0); \ + abort(); \ + } while (0) + + +#define RETURN(R) \ + for (int errno__ = errno, x__ = 0;; errno = errno__, x__++) \ + if (x__) return (R); else + + +#define TEMP_NUL(P, ACTION) \ + do { \ + char P##__c = *(P); \ + *(P) = '\0'; \ + ACTION; \ + *(P) = P##__c; \ + } while (0) + |