From 3618811496a6d131fd4bffa19e262c521d39e819 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Tue, 1 Oct 2019 18:41:17 +0100 Subject: [PATCH] utils/macros.h: Add and `foocmp' helper macros. Both of these have been a nuisance for years. Do something about it. The command git grep -En '\<(is|to)[a-z]+\(|\<(str|mem)[a-z]*cmp\(' -- '*.[ch]' finds code which it might be good to change. The hairy Emacs command (query-replace-regexp "\\<\\(\\(str\\|mem\\)\\sw*cmp\\)(\\([^,]*\\), \\([^)]*\\)) \\(==\\|!=\\|<\\|<=\\|>\\|>=\\) 0" '(replace-eval-replacement . (concat (replace-quote (upcase (match-string 1))) "(\\3, \\5, \\4)")) nil (if (and transient-mark-mode mark-active) (region-beginning)) (if (and transient-mark-mode mark-active) (region-end)) nil) will convert easy cases of `foocmp' calls, but hard ones have to be done by hand. --- codec/baseconv.c | 7 +++-- codec/bincode.c | 7 +++-- codec/url.c | 5 ++-- hash/crc-mktab.c | 5 ++-- hash/unihash-mkstatic.c | 4 +-- sel/bres-adns.c | 2 +- sel/ident.c | 11 +++---- struct/dstr-putf.c | 15 +++++----- struct/sym.c | 4 ++- struct/t/assoc-test.c | 11 +++---- struct/t/da-test.c | 29 ++++++++++--------- struct/t/dstr-putf-test.c | 3 +- struct/t/sym-test.c | 11 +++---- sys/t/fdpass-test.c | 8 ++--- sys/t/mdup-test.c | 3 +- test/testrig.c | 13 +++++---- trace/trace.c | 3 +- trace/traceopt.c | 3 +- utils/macros.3 | 74 +++++++++++++++++++++++++++++++++++++++++++++++ utils/macros.h | 26 +++++++++++++++++ utils/str.c | 9 +++--- utils/versioncmp.c | 9 +++--- 22 files changed, 190 insertions(+), 72 deletions(-) diff --git a/codec/baseconv.c b/codec/baseconv.c index bdb850f..b7cb0a0 100644 --- a/codec/baseconv.c +++ b/codec/baseconv.c @@ -35,6 +35,7 @@ #include "alloc.h" #include "codec.h" #include "dstr.h" +#include "macros.h" #include "sub.h" #include "base64.h" @@ -279,7 +280,7 @@ enum { #define PUTWRAP(x) WRAP({ \ char ch = encodemap[x]; \ - if (f & CDCF_LOWERC) ch = tolower((unsigned char)ch); \ + if (f & CDCF_LOWERC) ch = TOLOWER(ch); \ DPUTC(d, ch); \ }) @@ -350,9 +351,9 @@ static int ctxn##_dodecode(ctxn##_ctx *ctx, \ case 0: \ break; \ case CDCF_LOWERC: \ - if (isupper(ch)) goto badch; \ + if (ISUPPER(ch)) goto badch; \ default: \ - ch = toupper(ch); \ + ch = TOUPPER(ch); \ } \ x = decodemap[ch]; \ switch (x) { \ diff --git a/codec/bincode.c b/codec/bincode.c index af1e677..77d2457 100644 --- a/codec/bincode.c +++ b/codec/bincode.c @@ -36,6 +36,7 @@ #include "codec.h" #include "dstr.h" +#include "macros.h" #include "mdwopt.h" #include "quis.h" #include "report.h" @@ -195,7 +196,7 @@ int main(int argc, char *argv[]) n = strcspn(p, ","); for (i = 0; flagtab[i].name; i++) { if (strlen(flagtab[i].name) == n && - strncmp(flagtab[i].name, p, n) == 0) + STRNCMP(flagtab[i].name, ==, p, n)) goto found; } die(EXIT_FAILURE, "unknown flag `%.*s'", (int)n, p); @@ -215,7 +216,7 @@ int main(int argc, char *argv[]) for (cc = cctab;; cc++) { if (!*cc) die(EXIT_FAILURE, "unknown codec `%s'", *argv); - else if (strcmp(*argv, (*cc)->name) == 0) break; + else if (STRCMP(*argv, ==, (*cc)->name)) break; } argv++; argc--; @@ -267,7 +268,7 @@ int main(int argc, char *argv[]) if (!argc) code(c, "", stdin, ofp); else for (i = 0; i < argc; i++) { - if (strcmp(argv[i], "-") == 0) + if (STRCMP(argv[i], ==, "-")) code(c, "", stdin, ofp); else if ((ifp = fopen(argv[i], imode)) == 0) { die(EXIT_FAILURE, "couldn't open `%s' for reading: %s", diff --git a/codec/url.c b/codec/url.c index 0de87ae..eecfe82 100644 --- a/codec/url.c +++ b/codec/url.c @@ -33,6 +33,7 @@ #include #include "dstr.h" +#include "macros.h" #include "url.h" /*----- Main code ---------------------------------------------------------*/ @@ -66,8 +67,8 @@ static void encode(url_ectx *ctx, dstr *d, const char *p) case ' ': DPUTC(d, '+'); break; default: - if (isspace((unsigned char)*p)) goto unsafe; - else if (isalnum((unsigned char)*p)) goto safe; + if (ISSPACE(*p)) goto unsafe; + else if (ISALNUM(*p)) goto safe; else if (ctx->f&URLF_LAX) goto safe; else goto unsafe; case '/': case '~': diff --git a/hash/crc-mktab.c b/hash/crc-mktab.c index 4453cf3..a176d16 100644 --- a/hash/crc-mktab.c +++ b/hash/crc-mktab.c @@ -37,6 +37,7 @@ #include #include +#include "macros.h" #include "mdwopt.h" #include "quis.h" #include "report.h" @@ -266,8 +267,8 @@ int main(int argc, char *argv[]) die(EXIT_FAILURE, "not enough memory"); guard = p; for (q = file; *q; p++, q++) { - if (isalnum((unsigned char)*q)) - *p = toupper((unsigned char)*q); + if (ISALNUM(*q)) + *p = TOUPPER(*q); else *p = '_'; } diff --git a/hash/unihash-mkstatic.c b/hash/unihash-mkstatic.c index 0505fcf..958b3d7 100644 --- a/hash/unihash-mkstatic.c +++ b/hash/unihash-mkstatic.c @@ -187,8 +187,8 @@ int main(int argc, char *argv[]) die(EXIT_FAILURE, "not enough memory"); guard = p; for (q = file; *q; p++, q++) { - if (isalnum((unsigned char)*q)) - *p = toupper((unsigned char)*q); + if (ISALNUM(*q)) + *p = TOUPPER(*q); else *p = '_'; } diff --git a/sel/bres-adns.c b/sel/bres-adns.c index 03fafa4..491a9a8 100644 --- a/sel/bres-adns.c +++ b/sel/bres-adns.c @@ -215,7 +215,7 @@ static void report(bres_client *rc, adns_answer *a, if (a->cname) n[j++] = a->cname; else { n[j++] = *nv; nv++; nn--; } for (i = 0; i < nn && j < N(n) - 1; i++) - if (strcmp(n[0], nv[i]) != 0) n[j++] = nv[i]; + if (STRCMP(n[0], !=, nv[i])) n[j++] = nv[i]; n[j++] = 0; for (i = j = 0; i < an && j < N(aa) - 1; i++) { if (av[i].addr.sa.sa_family == AF_INET) diff --git a/sel/ident.c b/sel/ident.c index 0017f0a..a59cd22 100644 --- a/sel/ident.c +++ b/sel/ident.c @@ -44,6 +44,7 @@ #include "dstr.h" #include "exc.h" #include "ident.h" +#include "macros.h" #include "selbuf.h" /*----- Main code ---------------------------------------------------------*/ @@ -77,13 +78,13 @@ static char *next(char **pp) /* --- Skip past any leading whitespace --- */ - while (isspace((unsigned char)*p)) + while (ISSPACE(*p)) p++; /* --- Now start work on the string itself --- */ for (;;) { - if (*p == 0 || *p == ':' || *p == ',' || isspace((unsigned char)*p)) + if (*p == 0 || *p == ':' || *p == ',' || ISSPACE(*p)) break; else if (*p == '\\') { p++; @@ -97,7 +98,7 @@ static char *next(char **pp) /* --- Tidy up afterwards --- */ - while (isspace((unsigned char)*p)) + while (ISSPACE(*p)) p++; if (*p == 0) *pp = 0; @@ -132,11 +133,11 @@ static void parse(char *p, ident_reply *i) /* --- Find out what sort of a reply this is --- */ q = next(&p); - if (strcmp(q, "USERID") == 0) { + if (STRCMP(q, ==, "USERID")) { i->type = IDENT_USERID; i->u.userid.os = next(&p); i->u.userid.user = next(&p); - } else if (strcmp(q, "ERROR") == 0) { + } else if (STRCMP(q, ==, "ERROR")) { i->type = IDENT_ERROR; i->u.error = next(&p); } else diff --git a/struct/dstr-putf.c b/struct/dstr-putf.c index e097968..270f9a3 100644 --- a/struct/dstr-putf.c +++ b/struct/dstr-putf.c @@ -47,6 +47,7 @@ #include "darray.h" #include "dstr.h" +#include "macros.h" /*----- Tunable constants -------------------------------------------------*/ @@ -247,7 +248,7 @@ int dstr_vputf(dstr *d, const char *p, va_list *ap) done_flags: i = 0; - while (isdigit((unsigned char)*p)) i = 10*i + *p++ - '0'; + while (ISDIGIT(*p)) i = 10*i + *p++ - '0'; /* --- Snag: this might have been an argument position indicator --- */ @@ -269,11 +270,11 @@ int dstr_vputf(dstr *d, const char *p, va_list *ap) fs->wd = i; } else if (*p == '*') { p++; - if (!isdigit((unsigned char)*p)) + if (!ISDIGIT(*p)) i = anext++; else { i = *p++ - '0'; - while (isdigit((unsigned char)*p)) i = 10*i + *p++ - '0'; + while (ISDIGIT(*p)) i = 10*i + *p++ - '0'; assert(*p == '$'); p++; assert(i > 0); i--; } @@ -286,19 +287,19 @@ int dstr_vputf(dstr *d, const char *p, va_list *ap) if (*p == '.') { p++; f |= f_prec; - if (isdigit((unsigned char)*p)) { + if (ISDIGIT(*p)) { i = *p++ - '0'; - while (isdigit((unsigned char)*p)) i = 10*i + *p++ - '0'; + while (ISDIGIT(*p)) i = 10*i + *p++ - '0'; fs->prec = i; } else if (*p != '*') fs->prec = 0; else { p++; - if (!isdigit((unsigned char)*p)) + if (!ISDIGIT(*p)) i = anext++; else { i = *p++ - '0'; - while (isdigit((unsigned char)*p)) i = 10*i + *p++ - '0'; + while (ISDIGIT(*p)) i = 10*i + *p++ - '0'; assert(*p == '$'); p++; assert(i > 0); i--; } diff --git a/struct/sym.c b/struct/sym.c index 4543811..2eb309c 100644 --- a/struct/sym.c +++ b/struct/sym.c @@ -40,6 +40,7 @@ #include "bits.h" #include "exc.h" #include "hash.h" +#include "macros.h" #include "sub.h" #include "sym.h" #include "unihash.h" @@ -136,7 +137,8 @@ void *sym_find(sym_table *t, const char *n, long l, size_t sz, unsigned *f) for (p = bin; *p; p = &(*p)->next) { q = (sym_base *)*p; - if (hash == q->b.hash && len == q->len && !memcmp(n, SYM_NAME(q), len)) { + if (hash == q->b.hash && len == q->len && + MEMCMP(n, ==, SYM_NAME(q), len)) { /* --- Found a match --- * * diff --git a/struct/t/assoc-test.c b/struct/t/assoc-test.c index bd1bab4..a727bbf 100644 --- a/struct/t/assoc-test.c +++ b/struct/t/assoc-test.c @@ -5,6 +5,7 @@ #include "assoc.h" #include "atom.h" +#include "macros.h" typedef struct word { assoc_base _b; @@ -34,7 +35,7 @@ int main(void) buf[strlen(buf) - 1] = 0; p = strtok(buf, " "); - if (strcmp(p, "set") == 0) { + if (STRCMP(p, ==, "set")) { char *k = strtok(0, " "); int i = atoi(strtok(0, " ")); unsigned f; @@ -42,14 +43,14 @@ int main(void) w->i = i; if (!f) n++; - } else if (strcmp(p, "get") == 0) { + } else if (STRCMP(p, ==, "get")) { char *k = strtok(0, " "); word *w = assoc_find(&t, atom_intern(&at, k), 0, 0); if (w) printf("%i\n", w->i); else puts("*MISSING*"); - } else if (strcmp(p, "del") == 0) { + } else if (STRCMP(p, ==, "del")) { char *k = strtok(0, " "); word *w = assoc_find(&t, atom_intern(&at, k), 0, 0); if (w) { @@ -57,9 +58,9 @@ int main(void) n--; } else puts("*MISSING*"); - } else if (strcmp(p, "count") == 0) { + } else if (STRCMP(p, ==, "count")) { printf("%lu\n", (unsigned long)n); - } else if (strcmp(p, "show") == 0) { + } else if (STRCMP(p, ==, "show")) { assoc_iter i; word *w; word **v, **vv; diff --git a/struct/t/da-test.c b/struct/t/da-test.c index 0f3e625..ba86a8d 100644 --- a/struct/t/da-test.c +++ b/struct/t/da-test.c @@ -10,6 +10,7 @@ #include "darray.h" #include "exc.h" +#include "macros.h" DA_DECL(vec, int); @@ -49,18 +50,18 @@ int main(void) p = strtok(buf, " "); TRY { - if (strcmp(p, "push") == 0) { + if (STRCMP(p, ==, "push")) { int n = atoi(strtok(0, " ")); DA_PUSH(&v, n); - } else if (strcmp(p, "unshift") == 0) { + } else if (STRCMP(p, ==, "unshift")) { int n = atoi(strtok(0, " ")); DA_UNSHIFT(&v, n); - } else if (strcmp(p, "pop") == 0) { + } else if (STRCMP(p, ==, "pop")) { printf("%i\n", DA_POP(&v)); - } else if (strcmp(p, "shift") == 0) { + } else if (STRCMP(p, ==, "shift")) { printf("%i\n", DA_SHIFT(&v)); - } else if (strcmp(p, "insert") == 0 || - strcmp(p, "append") == 0) { + } else if (STRCMP(p, ==, "insert") || + STRCMP(p, ==, "append")) { vec vv; char *q = p; DA_CREATE(&vv); @@ -69,7 +70,7 @@ int main(void) int n = atoi(p); DA_PUSH(&vv, n); } - if (strcmp(q, "insert") == 0) { + if (STRCMP(q, ==, "insert")) { DA_SHUNT(&v, DA_LEN(&vv)); DA_SLIDE(&v, DA_LEN(&vv)); memcpy(DA(&v), DA(&vv), DA_LEN(&vv) * sizeof(int)); @@ -80,13 +81,13 @@ int main(void) memcpy(DA(&v) + l, DA(&vv), DA_LEN(&vv) * sizeof(int)); } DA_DESTROY(&vv); - } else if (strcmp(p, "delete") == 0) { + } else if (STRCMP(p, ==, "delete")) { int n = atoi(strtok(0, " ")); DA_UNSLIDE(&v, n); - } else if (strcmp(p, "reduce") == 0) { + } else if (STRCMP(p, ==, "reduce")) { int n = atoi(strtok(0, " ")); DA_SHRINK(&v, n); - } else if (strcmp(p, "set") == 0) { + } else if (STRCMP(p, ==, "set")) { size_t i = atoi(strtok(0, " ")); int n = atoi(strtok(0, " ")); size_t l = DA_LEN(&v); @@ -97,23 +98,23 @@ int main(void) DA(&v)[j] = -1; } DA(&v)[i] = n; - } else if (strcmp(p, "get") == 0) { + } else if (STRCMP(p, ==, "get")) { size_t i = atoi(strtok(0, " ")); if (i >= DA_LEN(&v)) puts("*RANGE*"); else printf("%i\n", DA(&v)[i]); - } else if (strcmp(p, "first") == 0) { + } else if (STRCMP(p, ==, "first")) { if (DA_LEN(&v)) printf("%i\n", DA_FIRST(&v)); else puts("*RANGE*"); - } else if (strcmp(p, "last") == 0) { + } else if (STRCMP(p, ==, "last")) { if (DA_LEN(&v)) printf("%i\n", DA_LAST(&v)); else puts("*RANGE*"); - } else if (strcmp(p, "show") == 0) { + } else if (STRCMP(p, ==, "show")) { if (DA_LEN(&v) == 0) puts("*EMPTY*"); else { diff --git a/struct/t/dstr-putf-test.c b/struct/t/dstr-putf-test.c index 5de7870..462371d 100644 --- a/struct/t/dstr-putf-test.c +++ b/struct/t/dstr-putf-test.c @@ -8,6 +8,7 @@ #include #include "dstr.h" +#include "macros.h" static int win = 0, lose = 0; static dstr d = DSTR_INIT; @@ -15,7 +16,7 @@ static char buf[1024]; static void check(const char *what, const char *want) { - if (strcmp(want, d.buf) == 0) + if (STRCMP(want, ==, d.buf)) win++; else { lose++; diff --git a/struct/t/sym-test.c b/struct/t/sym-test.c index 8a9435f..dfc2391 100644 --- a/struct/t/sym-test.c +++ b/struct/t/sym-test.c @@ -3,6 +3,7 @@ #include #include +#include "macros.h" #include "sym.h" typedef struct word { @@ -31,7 +32,7 @@ int main(void) buf[strlen(buf) - 1] = 0; p = strtok(buf, " "); - if (strcmp(p, "set") == 0) { + if (STRCMP(p, ==, "set")) { char *k = strtok(0, " "); int i = atoi(strtok(0, " ")); unsigned f; @@ -39,14 +40,14 @@ int main(void) w->i = i; if (!f) n++; - } else if (strcmp(p, "get") == 0) { + } else if (STRCMP(p, ==, "get")) { char *k = strtok(0, " "); word *w = sym_find(&t, k, -1, 0, 0); if (w) printf("%i\n", w->i); else puts("*MISSING*"); - } else if (strcmp(p, "del") == 0) { + } else if (STRCMP(p, ==, "del")) { char *k = strtok(0, " "); word *w = sym_find(&t, k, -1, 0, 0); if (w) { @@ -54,9 +55,9 @@ int main(void) n--; } else puts("*MISSING*"); - } else if (strcmp(p, "count") == 0) { + } else if (STRCMP(p, ==, "count")) { printf("%lu\n", (unsigned long)n); - } else if (strcmp(p, "show") == 0) { + } else if (STRCMP(p, ==, "show")) { sym_iter i; word *w; word **v, **vv; diff --git a/sys/t/fdpass-test.c b/sys/t/fdpass-test.c index 0196638..54fc8dc 100644 --- a/sys/t/fdpass-test.c +++ b/sys/t/fdpass-test.c @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) ego(argv[0]); - if (argc == 3 && strcmp(argv[1], "server") == 0) { + if (argc == 3 && STRCMP(argv[1], ==, "server")) { set_unix_addr(&sun, argv[2]); lsk = socket(PF_UNIX, SOCK_STREAM, 0); if (lsk < 0) die(2, "socket: %s", strerror(errno)); @@ -77,14 +77,14 @@ int main(int argc, char *argv[]) if (n < 0) die(2, "fdrecv: %s", strerror(errno)); close(sk); if (fd == -1) die(2, "no fd found"); - if (n != sizeof(sockmsg) || strcmp(buf, sockmsg) != 0) + if (n != sizeof(sockmsg) || STRCMP(buf, !=, sockmsg)) die(2, "socket message mismatch (found `%.*s')", (int)n, buf); n = read(fd, buf, sizeof(buf)); if (n < 0) die(2, "read: %s", strerror(errno)); - if (n != sizeof(pipemsg) || strcmp(buf, pipemsg) != 0) + if (n != sizeof(pipemsg) || STRCMP(buf, !=, pipemsg)) die(2, "pipe message mismatch (found `%.*s')", (int)n, buf); close(fd); - } else if (argc == 3 && strcmp(argv[1], "client") == 0) { + } else if (argc == 3 && STRCMP(argv[1], ==, "client")) { set_unix_addr(&sun, argv[2]); if (pipe(pfd)) die(2, "pipe: %s", strerror(errno)); sk = socket(PF_UNIX, SOCK_STREAM, 0); diff --git a/sys/t/mdup-test.c b/sys/t/mdup-test.c index 43aa45d..6597b33 100644 --- a/sys/t/mdup-test.c +++ b/sys/t/mdup-test.c @@ -6,6 +6,7 @@ #include #include #include +#include "macros.h" #include "mdup.h" #define MAXFD 256 @@ -33,7 +34,7 @@ int main(int argc, char *argv[]) int verbose = 0; for (i = 1, j = 0; i < argc; i++) { - if (strcmp(argv[i], "-v") == 0) { verbose++; continue; } + if (STRCMP(argv[i], ==, "-v")) { verbose++; continue; } if (j >= MAXFD) { fprintf(stderr, "too many\n"); exit(1); } if (sscanf(argv[i], "%d:%d", &fds[j].cur, &fds[j].want) < 2 || fds[j].cur >= MAXFD) diff --git a/test/testrig.c b/test/testrig.c index c85276f..c7dea67 100644 --- a/test/testrig.c +++ b/test/testrig.c @@ -34,6 +34,7 @@ #include #include "dstr.h" +#include "macros.h" #include "report.h" #include "quis.h" #include "testrig.h" @@ -99,7 +100,7 @@ again: /* --- Skip leading whitespace --- */ - while (isspace((unsigned char)ch)) + while (ISSPACE(ch)) ch = getc(fp); /* --- Trap some special characters --- */ @@ -163,7 +164,7 @@ again: case '`': goto done; default: - if (isspace((unsigned char)ch)) + if (ISSPACE(ch)) goto done; } if (ch == '\\') { @@ -328,7 +329,7 @@ int test_do(const test_suite suites[], FILE *fp, test_results *results) goto done; } - if (strcmp(tok.buf, "SUITE") == 0) { + if (STRCMP(tok.buf, ==, "SUITE")) { t = gettok(fp); if (t != TOK_WORD) { moan("expected ; found `%s'", decode(t)); @@ -339,7 +340,7 @@ int test_do(const test_suite suites[], FILE *fp, test_results *results) chunks = 0; break; } - if (strcmp(tok.buf, ss->name) == 0) { + if (STRCMP(tok.buf, ==, ss->name)) { chunks = ss->chunks; break; } @@ -354,7 +355,7 @@ int test_do(const test_suite suites[], FILE *fp, test_results *results) for (cch = chunks; ; cch++) { if (!cch->name) goto skip_chunk; - if (strcmp(tok.buf, cch->name) == 0) + if (STRCMP(tok.buf, ==, cch->name)) break; } @@ -479,7 +480,7 @@ void test_run(int argc, char *argv[], if (i >= argc - 1) break; p = argv[++i]; - if (strcmp(p, "--") == 0) { + if (STRCMP(p, ==, "--")) { i++; break; } diff --git a/trace/trace.c b/trace/trace.c index 2681cd3..e06bf7b 100644 --- a/trace/trace.c +++ b/trace/trace.c @@ -38,6 +38,7 @@ /* --- Local headers --- */ #include "dstr.h" +#include "macros.h" #include "quis.h" #include "trace.h" @@ -132,7 +133,7 @@ void trace_block(unsigned l, const char *s, const void *b, size_t sz) dstr_puts(&d, ": "); for (i = 0; i < 8; i++) { if (i < sz) - dstr_putc(&d, isprint(p[i]) ? p[i] : '.'); + dstr_putc(&d, ISPRINT(p[i]) ? p[i] : '.'); else dstr_putc(&d, '*'); } diff --git a/trace/traceopt.c b/trace/traceopt.c index 78d82bd..bbb8b02 100644 --- a/trace/traceopt.c +++ b/trace/traceopt.c @@ -31,6 +31,7 @@ #include #include +#include "macros.h" #include "report.h" #include "trace.h" @@ -57,7 +58,7 @@ unsigned traceopt(const trace_opt *t, const char *p, /* --- Dump out help text --- */ - if (!p || !strcmp(p, "?")) { + if (!p || STRCMP(p, ==, "?")) { const trace_opt *tt; puts("Trace options:"); for (tt = t; tt->ch; tt++) { diff --git a/utils/macros.3 b/utils/macros.3 index 98ab238..2d17fa6 100644 --- a/utils/macros.3 +++ b/utils/macros.3 @@ -6,6 +6,25 @@ macros \- useful macros .\" @STR .\" @GLUE .\" @STATIC_ASSERT +.\" @ISALNUM +.\" @ISALPHA +.\" @ISASCII +.\" @ISBLANK +.\" @ISCNTRL +.\" @ISDIGIT +.\" @ISGRAPH +.\" @ISLOWER +.\" @ISPRINT +.\" @ISPUNCT +.\" @ISSPACE +.\" @ISUPPER +.\" @ISXDIGIT +.\" @TOASCII +.\" @TOLOWER +.\" @TOUPPER +.\" @MEMCMP +.\" @STRCMP +.\" @STRNCMP .\" @DISCARD .\" @IGNORE .\" @DEPRECATED @@ -27,6 +46,27 @@ macros \- useful macros .BI "GLUE(" tokens\fR... ", " tokens\fR... ")" .BI "STATIC_ASSERT(" cond ", " msg ");" +.BI "ISALNUM(int " ch ");" +.BI "ISALPHA(int " ch ");" +.BI "ISASCII(int " ch ");" +.BI "ISBLANK(int " ch ");" +.BI "ISCNTRL(int " ch ");" +.BI "ISDIGIT(int " ch ");" +.BI "ISGRAPH(int " ch ");" +.BI "ISLOWER(int " ch ");" +.BI "ISPRINT(int " ch ");" +.BI "ISPUNCT(int " ch ");" +.BI "ISSPACE(int " ch ");" +.BI "ISUPPER(int " ch ");" +.BI "ISXDIGIT(int " ch ");" +.BI "TOASCII(int " ch ");" +.BI "TOLOWER(int " ch ");" +.BI "TOUPPER(int " ch ");" + +.BI "MEMCMP(const void *" x ", " op ", const void *" y ", size_t " n ");" +.BI "STRCMP(const char *" x ", " op ", const char *" y ");" +.BI "STRNCMP(const char *" x ", " op ", const char *" y ", size_t " n ");" + .BI "void DISCARD(" scalar ");" .BI "void IGNORE(" variable ");" @@ -78,6 +118,40 @@ falls back to a somewhat ugly hack which currently ignores the .IR msg . .PP The +.BR IS ...\& +and +.BR TO ...\& +macros are wrappers around the corresponding standard +.B +macros with the corresponding lowercase names. They take care of +forcing the character argument +.I ch +to +.BR "unsigned char" : +this conversion is necessary on platforms with signed +.B char +to avoid passing negative values into the standard macros. +.PP +The +.BR MEMCMP , +.BR STRCMP , +and +.B STRNCMP +macros are wrappers around the standard +.B +functions with the corresponding lowercase names. They take an +additional argument +.I op +which is a equality or ordering operator (e.g., +.B == +or +.BR > ) +inserted between the two operands. The standard functions return a +false value if and only if the operands are equal, which is +counterintuitive and leads to mistakes; requiring an explicit relational +operator should reduce the number of such mistakes. +.PP +The .B DISCARD macro discards its argument, which must be of some scalar type. This can be useful in muffling warnings about ignoring return codes in cases diff --git a/utils/macros.h b/utils/macros.h index 9e27a48..a5263e1 100644 --- a/utils/macros.h +++ b/utils/macros.h @@ -57,6 +57,32 @@ IGNORABLE extern char static_assert_failed[2*!!(cond) - 1] #endif +/*----- String and character hacks ----------------------------------------*/ + +#define CTYPE_HACK(func, ch) (func((unsigned char)(ch))) + +#define ISALNUM(ch) CTYPE_HACK(isalnum, ch) +#define ISALPHA(ch) CTYPE_HACK(isalpha, ch) +#define ISASCII(ch) CTYPE_HACK(isascii, ch) +#define ISBLANK(ch) CTYPE_HACK(isblank, ch) +#define ISCNTRL(ch) CTYPE_HACK(iscntrl, ch) +#define ISDIGIT(ch) CTYPE_HACK(isdigit, ch) +#define ISGRAPH(ch) CTYPE_HACK(isgraph, ch) +#define ISLOWER(ch) CTYPE_HACK(islower, ch) +#define ISPRINT(ch) CTYPE_HACK(isprint, ch) +#define ISPUNCT(ch) CTYPE_HACK(ispunct, ch) +#define ISSPACE(ch) CTYPE_HACK(isspace, ch) +#define ISUPPER(ch) CTYPE_HACK(isupper, ch) +#define ISXDIGIT(ch) CTYPE_HACK(isxdigit, ch) + +#define TOASCII(ch) CTYPE_HACK(toascii, ch) +#define TOLOWER(ch) CTYPE_HACK(tolower, ch) +#define TOUPPER(ch) CTYPE_HACK(toupper, ch) + +#define MEMCMP(x, op, y, n) (memcmp((x), (y), (n)) op 0) +#define STRCMP(x, op, y) (strcmp((x), (y)) op 0) +#define STRNCMP(x, op, y, n) (strncmp((x), (y), (n)) op 0) + /*----- Compiler diagnostics ----------------------------------------------*/ /* --- Compiler-specific definitions --- */ diff --git a/utils/str.c b/utils/str.c index 51ca323..e759828 100644 --- a/utils/str.c +++ b/utils/str.c @@ -32,6 +32,7 @@ #include #include +#include "macros.h" #include "str.h" /*----- Main code ---------------------------------------------------------*/ @@ -58,7 +59,7 @@ char *str_qword(char **pp, unsigned f) if (!p) return (0); - while (isspace((unsigned char)*p)) + while (ISSPACE(*p)) p++; if (!*p) { *pp = 0; @@ -83,8 +84,8 @@ char *str_qword(char **pp, unsigned f) *qq++ = *q; break; default: - if (isspace((unsigned char)*q)) { - do q++; while (*q && isspace((unsigned char)*q)); + if (ISSPACE(*q)) { + do q++; while (*q && ISSPACE(*q)); goto done; } else if (!(f & STRF_QUOTE)) goto stdchar; @@ -312,7 +313,7 @@ void str_sanitize(char *d, const char *p, size_t sz) sz--; while (*p && sz) { int ch = *p++; - if (!isgraph((unsigned char)ch)) + if (!ISGRAPH(ch)) ch = '_'; *d++ = ch; sz--; diff --git a/utils/versioncmp.c b/utils/versioncmp.c index 3556916..e8bf9ae 100644 --- a/utils/versioncmp.c +++ b/utils/versioncmp.c @@ -30,6 +30,7 @@ #include #include +#include "macros.h" #include "versioncmp.h" /*----- Main code ---------------------------------------------------------*/ @@ -79,7 +80,7 @@ static int vint(const char **vv, const char *vl) while (v < vl) { ch = *v; - if (!isdigit((unsigned char)ch)) + if (!ISDIGIT(ch)) break; v++; n = n * 10 + (ch - '0'); @@ -96,7 +97,7 @@ static const char *vchr(const char **vv, const char *vl) while (v < vl) { ch = *v; - if (isdigit((unsigned char)ch)) + if (ISDIGIT(ch)) break; v++; } @@ -124,12 +125,12 @@ static int vcmp(const char *va, const char *val, pa = vchr(&va, val); pb = vchr(&vb, vbl); for (;;) { if (pa == va) ia = 1; - else if (isalpha((unsigned char)*pa)) ia = 2; + else if (ISALPHA(*pa)) ia = 2; else if (*pa == '~') ia = 0; else ia = 3; if (pb == vb) ib = 1; - else if (isalpha((unsigned char)*pb)) ib = 2; + else if (ISALPHA(*pb)) ib = 2; else if (*pb == '~') ib = 0; else ib = 3; -- 2.11.0