utils/macros.h: Add <ctype.h> and `foocmp' helper macros.
authorMark Wooding <mdw@distorted.org.uk>
Tue, 1 Oct 2019 17:41:17 +0000 (18:41 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 8 May 2020 12:44:29 +0000 (13:44 +0100)
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.

22 files changed:
codec/baseconv.c
codec/bincode.c
codec/url.c
hash/crc-mktab.c
hash/unihash-mkstatic.c
sel/bres-adns.c
sel/ident.c
struct/dstr-putf.c
struct/sym.c
struct/t/assoc-test.c
struct/t/da-test.c
struct/t/dstr-putf-test.c
struct/t/sym-test.c
sys/t/fdpass-test.c
sys/t/mdup-test.c
test/testrig.c
trace/trace.c
trace/traceopt.c
utils/macros.3
utils/macros.h
utils/str.c
utils/versioncmp.c

index bdb850f..b7cb0a0 100644 (file)
@@ -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) {                                                     \
index af1e677..77d2457 100644 (file)
@@ -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>", stdin, ofp);
   else for (i = 0; i < argc; i++) {
-    if (strcmp(argv[i], "-") == 0)
+    if (STRCMP(argv[i], ==, "-"))
       code(c, "<stdin>", stdin, ofp);
     else if ((ifp = fopen(argv[i], imode)) == 0) {
       die(EXIT_FAILURE, "couldn't open `%s' for reading: %s",
index 0de87ae..eecfe82 100644 (file)
@@ -33,6 +33,7 @@
 #include <string.h>
 
 #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 '~':
index 4453cf3..a176d16 100644 (file)
@@ -37,6 +37,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#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 = '_';
       }
index 0505fcf..958b3d7 100644 (file)
@@ -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 = '_';
       }
index 03fafa4..491a9a8 100644 (file)
@@ -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)
index 0017f0a..a59cd22 100644 (file)
@@ -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
index e097968..270f9a3 100644 (file)
@@ -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--;
        }
index 4543811..2eb309c 100644 (file)
@@ -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 --- *
        *
index bd1bab4..a727bbf 100644 (file)
@@ -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;
index 0f3e625..ba86a8d 100644 (file)
@@ -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 {
index 5de7870..462371d 100644 (file)
@@ -8,6 +8,7 @@
 #include <string.h>
 
 #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++;
index 8a9435f..dfc2391 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#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;
index 0196638..54fc8dc 100644 (file)
@@ -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);
index 43aa45d..6597b33 100644 (file)
@@ -6,6 +6,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#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)
index c85276f..c7dea67 100644 (file)
@@ -34,6 +34,7 @@
 #include <string.h>
 
 #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 <word>; 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;
        }
index 2681cd3..e06bf7b 100644 (file)
@@ -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, '*');
     }
index 78d82bd..bbb8b02 100644 (file)
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <stdlib.h>
 
+#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++) {
index 98ab238..2d17fa6 100644 (file)
@@ -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 <ctype.h>
+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 <string.h>
+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
index 9e27a48..a5263e1 100644 (file)
        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 --- */
index 51ca323..e759828 100644 (file)
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#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--;
index 3556916..e8bf9ae 100644 (file)
@@ -30,6 +30,7 @@
 #include <ctype.h>
 #include <string.h>
 
+#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;