tz 8-bit-clean proposed patch

Paul Eggert eggert at twinsun.com
Mon Oct 30 01:29:39 UTC 1995


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



More information about the tz mailing list