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;
}