tz 8-bit-clean proposed patch

In a few places the tz code assumes that characters are nonnegative. The tz code uses `isascii' to avoid this problem sometimes, but not always, and anyway `isascii' isn't portable to some hosts that have strict ANSI or Posix checking turned on, since isascii is not required by either the C Standard or Posix. Here is a proposed patch that handles top-bit-on characters correctly in all the places where I found this problem. The patch is portable to hosts that don't define isascii. The proposed patch also removes a few unnecessary tests, and changes one call to ciequal to invoke strcmp, since the argument string has no alphabetic characters in it. =================================================================== RCS file: RCS/private.h,v retrieving revision 1995.3 retrieving revision 1995.3.1.1 diff -c -r1995.3 -r1995.3.1.1 *** private.h 1995/03/11 17:55:53 1995.3 --- private.h 1995/10/30 00:43:48 1995.3.1.1 *************** *** 47,53 **** #include "sys/types.h" /* for time_t */ #include "stdio.h" - #include "ctype.h" #include "errno.h" #include "string.h" #include "limits.h" /* for CHAR_BIT */ --- 47,52 ---- *************** *** 66,71 **** --- 65,73 ---- #define R_OK 4 #endif /* !defined R_OK */ #endif /* !(HAVE_UNISTD_H - 0) */ + + /* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */ + #define is_digit(c) ((unsigned)(c) - '0' <= 9) /* ** Workarounds for compilers/systems. =================================================================== RCS file: RCS/date.c,v retrieving revision 1995.3 retrieving revision 1995.3.1.1 diff -c -r1995.3 -r1995.3.1.1 *** date.c 1995/03/11 17:55:47 1995.3 --- date.c 1995/10/30 00:43:48 1995.3.1.1 *************** *** 459,465 **** nondigit(cp) register const char * cp; { ! while (isdigit(*cp)) ++cp; return cp; } --- 459,465 ---- nondigit(cp) register const char * cp; { ! while (is_digit(*cp)) ++cp; return cp; } *************** *** 592,598 **** dotp = strchr(value, '.'); for (cp = value; *cp != '\0'; ++cp) ! if (!isdigit(*cp) && cp != dotp) wildinput("time", value, "contains a nondigit"); if (dotp == NULL) --- 592,598 ---- dotp = strchr(value, '.'); for (cp = value; *cp != '\0'; ++cp) ! if (!is_digit(*cp) && cp != dotp) wildinput("time", value, "contains a nondigit"); if (dotp == NULL) =================================================================== RCS file: RCS/localtime.c,v retrieving revision 1995.6 retrieving revision 1995.6.1.1 diff -c -r1995.6 -r1995.6.1.1 *** localtime.c 1995/10/28 16:09:02 1995.6 --- localtime.c 1995/10/30 00:43:48 1995.6.1.1 *************** *** 415,421 **** { register char c; ! while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && c != '+') ++strp; return strp; --- 415,421 ---- { register char c; ! while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+') ++strp; return strp; *************** *** 438,452 **** register char c; register int num; ! if (strp == NULL || !isdigit(*strp)) return NULL; num = 0; ! while ((c = *strp) != '\0' && isdigit(c)) { num = num * 10 + (c - '0'); if (num > max) return NULL; /* illegal value */ ! ++strp; ! } if (num < min) return NULL; /* illegal value */ *nump = num; --- 438,452 ---- register char c; register int num; ! if (strp == NULL || !is_digit(c = *strp)) return NULL; num = 0; ! do { num = num * 10 + (c - '0'); if (num > max) return NULL; /* illegal value */ ! c = *++strp; ! } while (is_digit(c)); if (num < min) return NULL; /* illegal value */ *nump = num; *************** *** 508,521 **** register const char * strp; long * const offsetp; { ! register int neg; if (*strp == '-') { neg = 1; ++strp; ! } else if (isdigit(*strp) || *strp++ == '+') ! neg = 0; ! else return NULL; /* illegal offset */ strp = getsecs(strp, offsetp); if (strp == NULL) return NULL; /* illegal time */ --- 508,520 ---- register const char * strp; long * const offsetp; { ! register int neg = 0; if (*strp == '-') { neg = 1; ++strp; ! } else if (*strp == '+') ! ++strp; strp = getsecs(strp, offsetp); if (strp == NULL) return NULL; /* illegal time */ *************** *** 560,566 **** if (*strp++ != '.') return NULL; strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); ! } else if (isdigit(*strp)) { /* ** Day of year. */ --- 559,565 ---- if (*strp++ != '.') return NULL; strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); ! } else if (is_digit(*strp)) { /* ** Day of year. */ =================================================================== RCS file: RCS/scheck.c,v retrieving revision 1994.8 retrieving revision 1994.8.1.1 diff -c -r1994.8 -r1994.8.1.1 *** scheck.c 1994/12/09 04:33:18 1994.8 --- scheck.c 1995/10/30 00:43:48 1994.8.1.1 *************** *** 42,48 **** *tp++ = '*'; if (*fp == '*') ++fp; ! while (isascii(*fp) && isdigit(*fp)) *tp++ = *fp++; if (*fp == 'l' || *fp == 'h') *tp++ = *fp++; --- 42,48 ---- *tp++ = '*'; if (*fp == '*') ++fp; ! while (is_digit(*fp)) *tp++ = *fp++; if (*fp == 'l' || *fp == 'h') *tp++ = *fp++; =================================================================== RCS file: RCS/zic.c,v retrieving revision 1995.6 retrieving revision 1995.6.1.1 diff -c -r1995.6 -r1995.6.1.1 *** zic.c 1995/10/28 20:51:12 1995.6 --- zic.c 1995/10/30 00:43:48 1995.6.1.1 *************** *** 10,15 **** --- 10,28 ---- #include "sys/stat.h" /* for umask manifest constants */ #endif /* defined unix */ + /* + ** On some ancient hosts, predicates like `isspace(C)' are defined + ** only if isascii(C) || C == EOF. Modern hosts obey the C Standard, + ** which says they are defined only if C == (unsigned char)C || C == EOF. + ** Neither the C Standard nor Posix require that `isascii' exist. + ** For portability, we check both ancient and modern requirements. + ** If isascii is not defined, the isascii check succeeds trivially. + */ + #include "ctype.h" + #ifndef isascii + #define isascii(x) 1 + #endif + struct rule { const char * r_filename; int r_linenum; *************** *** 721,727 **** while (fields[nfields] != NULL) { static char nada; ! if (ciequal(fields[nfields], "-")) fields[nfields] = &nada; ++nfields; } --- 734,740 ---- while (fields[nfields] != NULL) { static char nada; ! if (strcmp(fields[nfields], "-") == 0) fields[nfields] = &nada; ++nfields; } *************** *** 1702,1709 **** static int lowerit(a) ! const int a; { return (isascii(a) && isupper(a)) ? tolower(a) : a; } --- 1715,1723 ---- static int lowerit(a) ! int a; { + a = (unsigned char)a; return (isascii(a) && isupper(a)) ? tolower(a) : a; } *************** *** 1775,1781 **** emalloc((int) ((strlen(cp) + 1) * sizeof *array)); nsubs = 0; for ( ; ; ) { ! while (isascii(*cp) && isspace(*cp)) ++cp; if (*cp == '\0' || *cp == '#') break; --- 1789,1795 ---- emalloc((int) ((strlen(cp) + 1) * sizeof *array)); nsubs = 0; for ( ; ; ) { ! while (isascii(*cp) && isspace((unsigned char)*cp)) ++cp; if (*cp == '\0' || *cp == '#') break; *************** *** 1788,1795 **** ++dp; else error("Odd number of quotation marks"); } while (*cp != '\0' && *cp != '#' && ! (!isascii(*cp) || !isspace(*cp))); ! if (isascii(*cp) && isspace(*cp)) ++cp; *dp = '\0'; } --- 1802,1809 ---- ++dp; else error("Odd number of quotation marks"); } while (*cp != '\0' && *cp != '#' && ! (!isascii(*cp) || !isspace((unsigned char)*cp))); ! if (isascii(*cp) && isspace((unsigned char)*cp)) ++cp; *dp = '\0'; } *************** *** 1952,1959 **** /* ** DOS drive specifier? */ ! if (strlen(name) == 2 && isascii(name[0]) && ! isalpha(name[0]) && name[1] == ':') { *cp = '/'; continue; } --- 1966,1973 ---- /* ** DOS drive specifier? */ ! if (isalpha((unsigned char)name[0]) ! && name[1] == ':' && !name[2]) { *cp = '/'; continue; }
participants (1)
-
Paul Eggert