Esempio n. 1
0
char * __attribute_warn_unused_result__
anytostr (inttype i, char *buf)
{
  verify (TYPE_SIGNED (inttype) == inttype_is_signed);
  char *p = buf + INT_STRLEN_BOUND (inttype);
  *p = 0;

#if inttype_is_signed
  if (i < 0)
    {
      do
        *--p = '0' - i % 10;
      while ((i /= 10) != 0);

      *--p = '-';
    }
  else
#endif
    {
      do
        *--p = '0' + i % 10;
      while ((i /= 10) != 0);
    }

  return p;
}
Esempio n. 2
0
void
write_directory_file (void)
{
  FILE *fp = listed_incremental_stream;
  char buf[UINTMAX_STRSIZE_BOUND];
  char *s;

  if (! fp)
    return;

  if (fseeko (fp, 0L, SEEK_SET) != 0)
    seek_error (listed_incremental_option);
  if (sys_truncate (fileno (fp)) != 0)
    truncate_error (listed_incremental_option);

  fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
	   TAR_INCREMENTAL_VERSION);

  s = (TYPE_SIGNED (time_t)
       ? imaxtostr (start_time.tv_sec, buf)
       : umaxtostr (start_time.tv_sec, buf));
  fwrite (s, strlen (s) + 1, 1, fp);
  s = umaxtostr (start_time.tv_nsec, buf);
  fwrite (s, strlen (s) + 1, 1, fp);

  if (! ferror (fp) && directory_table)
    hash_do_for_each (directory_table, write_directory_file_entry, fp);

  if (ferror (fp))
    write_error (listed_incremental_option);
  if (fclose (fp) != 0)
    close_error (listed_incremental_option);
}
Esempio n. 3
0
static int
differ_by_repeat(pg_time_t t1, pg_time_t t0)
{
	if (TYPE_INTEGRAL(pg_time_t) &&
		TYPE_BIT(pg_time_t) -TYPE_SIGNED(pg_time_t) <SECSPERREPEAT_BITS)
		return 0;
	return t1 - t0 == SECSPERREPEAT;
}
Esempio n. 4
0
extern char *
gid_to_name (gid_t gid)
{
    char buf[INT_BUFSIZE_BOUND (intmax_t)];
    struct group *grp = getgrgid (gid);
    return xstrdup (grp ? grp->gr_name
                    : TYPE_SIGNED (gid_t) ? imaxtostr (gid, buf)
                    : umaxtostr (gid, buf));
}
Esempio n. 5
0
extern char *
uid_to_name (uid_t uid)
{
    char buf[INT_BUFSIZE_BOUND (intmax_t)];
    struct passwd *pwd = getpwuid (uid);
    return xstrdup (pwd ? pwd->pw_name
                    : TYPE_SIGNED (uid_t) ? imaxtostr (uid, buf)
                    : umaxtostr (uid, buf));
}
Esempio n. 6
0
static int
differ_by_repeat(const time_t t1, const time_t t0)
{
	int_fast64_t _t0 = t0;
	int_fast64_t _t1 = t1;

	if (TYPE_INTEGRAL(time_t) &&
		TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
			return 0;
	return _t1 - _t0 == SECSPERREPEAT;
}
double ATTRIBUTE_CONST
difftime(const time_t time1, const time_t time0)
{
	/*
	** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
	** (assuming that the larger type has more precision).
	*/
	/*CONSTCOND*/
	if (sizeof (double) > sizeof (time_t))
		return (double) time1 - (double) time0;
	/*LINTED const not */
	if (!TYPE_INTEGRAL(time_t)) {
		/*
		** time_t is floating.
		*/
		return time1 - time0;
	}
	/*LINTED const not */
	if (!TYPE_SIGNED(time_t)) {
		/*
		** time_t is integral and unsigned.
		** The difference of two unsigned values can't overflow
		** if the minuend is greater than or equal to the subtrahend.
		*/
		if (time1 >= time0)
			return            time1 - time0;
		else	return -(double) (time0 - time1);
	}
	/*
	** time_t is integral and signed.
	** Handle cases where both time1 and time0 have the same sign
	** (meaning that their difference cannot overflow).
	*/
	if ((time1 < 0) == (time0 < 0))
		return time1 - time0;
	/*
	** time1 and time0 have opposite signs.
	** Punt if uintmax_t is too narrow.
	** This suffers from double rounding; attempt to lessen that
	** by using long double temporaries.
	*/
	/* CONSTCOND */
	if (sizeof (uintmax_t) < sizeof (time_t))
		return (double) time1 - (double) time0;
	/*
	** Stay calm...decent optimizers will eliminate the complexity below.
	*/
	if (time1 >= 0 /* && time0 < 0 */)
		return    (uintmax_t) time1 + (uintmax_t) (-(time0 + 1)) + 1;
	return -(double) ((uintmax_t) time0 + (uintmax_t) (-(time1 + 1)) + 1);
}
/* Hash some device info.  */
static size_t
dev_info_hash (void const *x, size_t table_size)
{
  struct fs_res const *p = x;

  /* Beware signed arithmetic gotchas.  */
  if (TYPE_SIGNED (dev_t) && SIZE_MAX < MAX (INT_MAX, TYPE_MAXIMUM (dev_t)))
    {
      uintmax_t dev = p->dev;
      return dev % table_size;
    }

  return p->dev % table_size;
}
Esempio n. 9
0
double
difftime(const time_t time1, const time_t time0)
{
	/*
	** If (sizeof (double) > sizeof (time_t)) simply convert and subtract
	** (assuming that the larger type has more precision).
	** This is the common real-world case circa 2004.
	*/
	if (sizeof (double) > sizeof (time_t))
		return (double) time1 - (double) time0;
	if (!TYPE_INTEGRAL(time_t)) {
		/*
		** time_t is floating.
		*/
		return time1 - time0;
	}
	if (!TYPE_SIGNED(time_t)) {
		/*
		** time_t is integral and unsigned.
		** The difference of two unsigned values can't overflow
		** if the minuend is greater than or equal to the subtrahend.
		*/
		if (time1 >= time0)
			return time1 - time0;
		else	return -((double) (time0 - time1));
	}
	/*
	** time_t is integral and signed.
	** Handle cases where both time1 and time0 have the same sign
	** (meaning that their difference cannot overflow).
	*/
	if ((time1 < 0) == (time0 < 0))
		return time1 - time0;
	/*
	** time1 and time0 have opposite signs.
	** Punt if unsigned long is too narrow.
	*/
	if (sizeof (unsigned long) < sizeof (time_t))
		return (double) time1 - (double) time0;
	/*
	** Stay calm...decent optimizers will eliminate the complexity below.
	*/
	if (time1 >= 0 /* && time0 < 0 */)
		return (unsigned long) time1 +
			(unsigned long) (-(time0 + 1)) + 1;
	return -(double) ((unsigned long) time0 +
		(unsigned long) (-(time1 + 1)) + 1);
}
Esempio n. 10
0
static strtol_error
bkm_scale (__strtol_t *x, int scale_factor)
{
  if (TYPE_SIGNED (__strtol_t) && *x < STRTOL_T_MINIMUM / scale_factor)
    {
      *x = STRTOL_T_MINIMUM;
      return LONGINT_OVERFLOW;
    }
  if (STRTOL_T_MAXIMUM / scale_factor < *x)
    {
      *x = STRTOL_T_MAXIMUM;
      return LONGINT_OVERFLOW;
    }
  *x *= scale_factor;
  return LONGINT_OK;
}
Esempio n. 11
0
/* Return 1 if A + B does not overflow.  If time_t is unsigned and if
   B's top bit is set, assume that the sum represents A - -B, and
   return 1 if the subtraction does not wrap around.  */
static int
time_t_add_ok (time_t a, time_t b)
{
  if (! TYPE_SIGNED (time_t))
    {
      time_t sum = a + b;
      return (sum < a) == (TIME_T_MIDPOINT <= b);
    }
  else if (WRAPV)
    {
      time_t sum = a + b;
      return (sum < a) == (b < 0);
    }
  else
    {
      time_t avg = time_t_avg (a, b);
      return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2;
    }
}
Esempio n. 12
0
/* Return 1 if A + B does not overflow.  If time_t is unsigned and if
   B's top bit is set, assume that the sum represents A - -B, and
   return 1 if the subtraction does not wrap around.  */
static int
time_t_add_ok(time_t a, time_t b)
{
  if (! TYPE_SIGNED(time_t))
    {
      time_t sum = (a + b);
      return ((sum < a) == (TIME_T_MIDPOINT <= b));
    }
  else if (WRAPV)
    {
      time_t sum = (a + b);
      return ((sum < a) == (b < 0));
    }
  else
    {
      time_t avg = time_t_avg(a, b);
      return (((TIME_T_MIN / 2) <= avg) && (avg <= (TIME_T_MAX / 2)));
    }
}
Esempio n. 13
0
/* Output incremental data for the directory ENTRY to the file DATA.
   Return nonzero if successful, preserving errno on write failure.  */
static bool
write_directory_file_entry (void *entry, void *data)
{
  struct directory const *directory = entry;
  FILE *fp = data;

  if (DIR_IS_FOUND (directory))
    {
      char buf[UINTMAX_STRSIZE_BOUND];
      char *s;

      s = DIR_IS_NFS (directory) ? "1" : "0";
      fwrite (s, 2, 1, fp);
      s = (TYPE_SIGNED (time_t)
	   ? imaxtostr (directory->mtime.tv_sec, buf)
	   : umaxtostr (directory->mtime.tv_sec, buf));
      fwrite (s, strlen (s) + 1, 1, fp);
      s = umaxtostr (directory->mtime.tv_nsec, buf);
      fwrite (s, strlen (s) + 1, 1, fp);
      s = umaxtostr (directory->device_number, buf);
      fwrite (s, strlen (s) + 1, 1, fp);
      s = umaxtostr (directory->inode_number, buf);
      fwrite (s, strlen (s) + 1, 1, fp);

      fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
      if (directory->dump)
	{
	  const char *p;
	  dumpdir_iter_t itr;

	  for (p = dumpdir_first (directory->dump, 0, &itr);
	       p;
	       p = dumpdir_next (itr))
	    fwrite (p, strlen (p) + 1, 1, fp);
	  free (itr);
	}
      fwrite ("\0\0", 2, 1, fp);
    }

  return ! ferror (fp);
}
Esempio n. 14
0
struct timespec
decode_timespec (char const *arg, char **arg_lim, bool parse_fraction)
{
  time_t s = TYPE_MINIMUM (time_t);
  int ns = -1;
  char const *p = arg;
  bool negative = *arg == '-';
  struct timespec r;

  if (! ISDIGIT (arg[negative]))
    errno = EINVAL;
  else
    {
      errno = 0;

      if (negative)
	{
	  intmax_t i = strtoimax (arg, arg_lim, 10);
	  if (TYPE_SIGNED (time_t) ? TYPE_MINIMUM (time_t) <= i : 0 <= i)
	    s = i;
	  else
	    errno = ERANGE;
	}
      else
	{
	  uintmax_t i = strtoumax (arg, arg_lim, 10);
	  if (i <= TYPE_MAXIMUM (time_t))
	    s = i;
	  else
	    errno = ERANGE;
	}

      p = *arg_lim;
      ns = 0;

      if (parse_fraction && *p == '.')
	{
	  int digits = 0;
	  bool trailing_nonzero = false;

	  while (ISDIGIT (*++p))
	    if (digits < LOG10_BILLION)
	      digits++, ns = 10 * ns + (*p - '0');
	    else
	      trailing_nonzero |= *p != '0';

	  while (digits < LOG10_BILLION)
	    digits++, ns *= 10;

	  if (negative)
	    {
	      /* Convert "-1.10000000000001" to s == -2, ns == 89999999.
		 I.e., truncate time stamps towards minus infinity while
		 converting them to internal form.  */
	      ns += trailing_nonzero;
	      if (ns != 0)
		{
		  if (s == TYPE_MINIMUM (time_t))
		    ns = -1;
		  else
		    {
		      s--;
		      ns = BILLION - ns;
		    }
		}
	    }
	}

      if (errno == ERANGE)
	ns = -1;
    }

  *arg_lim = (char *) p;
  r.tv_sec = s;
  r.tv_nsec = ns;
  return r;
}
Esempio n. 15
0
static int
tzload(const char *name, struct state * const sp, const int doextend)
{
	const char *		p;
	int			i;
	int			fid;
	int			stored;
	int			nread;
	typedef union {
		struct tzhead	tzhead;
		char		buf[2 * sizeof(struct tzhead) +
					2 * sizeof *sp +
					4 * TZ_MAX_TIMES];
	} u_t;
	u_t				u;
	u_t * const			up = &u;

	sp->goback = sp->goahead = FALSE;

	/* XXX The following is from OpenBSD, and I'm not sure it is correct */
	if (name != NULL && issetugid() != 0)
		if ((name[0] == ':' && name[1] == '/') || 
		    name[0] == '/' || strchr(name, '.'))
			name = NULL;
	if (name == NULL && (name = TZDEFAULT) == NULL)
		goto oops;
	{
		int	doaccess;
		struct stat	stab;
		/*
		** Section 4.9.1 of the C standard says that
		** "FILENAME_MAX expands to an integral constant expression
		** that is the size needed for an array of char large enough
		** to hold the longest file name string that the implementation
		** guarantees can be opened."
		*/
		char		fullname[FILENAME_MAX + 1];

		if (name[0] == ':')
			++name;
		doaccess = name[0] == '/';
		if (!doaccess) {
			if ((p = TZDIR) == NULL)
				goto oops;
			if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
				goto oops;
			strcpy(fullname, p);
			strcat(fullname, "/");
			strcat(fullname, name);
			/*
			** Set doaccess if '.' (as in "../") shows up in name.
			*/
			if (strchr(name, '.') != NULL)
				doaccess = TRUE;
			name = fullname;
		}
		if (doaccess && access(name, R_OK) != 0)
			goto oops;
		if ((fid = _open(name, O_RDONLY)) == -1)
			goto oops;
		if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
			_close(fid);
			return -1;
		}
	}
	nread = _read(fid, up->buf, sizeof up->buf);
	if (_close(fid) < 0 || nread <= 0)
		goto oops;
	for (stored = 4; stored <= 8; stored *= 2) {
		int		ttisstdcnt;
		int		ttisgmtcnt;

		ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
		ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
		sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
		sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
		sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
		sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
		p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
				goto oops;
		if (nread - (p - up->buf) <
			sp->timecnt * stored +		/* ats */
			sp->timecnt +			/* types */
			sp->typecnt * 6 +		/* ttinfos */
			sp->charcnt +			/* chars */
			sp->leapcnt * (stored + 4) +	/* lsinfos */
			ttisstdcnt +			/* ttisstds */
			ttisgmtcnt)			/* ttisgmts */
				goto oops;
		for (i = 0; i < sp->timecnt; ++i) {
			sp->ats[i] = (stored == 4) ?
				detzcode(p) : detzcode64(p);
			p += stored;
		}
		for (i = 0; i < sp->timecnt; ++i) {
			sp->types[i] = (unsigned char) *p++;
			if (sp->types[i] >= sp->typecnt)
				goto oops;
		}
		for (i = 0; i < sp->typecnt; ++i) {
			struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			ttisp->tt_gmtoff = detzcode(p);
			p += 4;
			ttisp->tt_isdst = (unsigned char) *p++;
			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
				goto oops;
			ttisp->tt_abbrind = (unsigned char) *p++;
			if (ttisp->tt_abbrind < 0 ||
				ttisp->tt_abbrind > sp->charcnt)
					goto oops;
		}
		for (i = 0; i < sp->charcnt; ++i)
			sp->chars[i] = *p++;
		sp->chars[i] = '\0';	/* ensure '\0' at end */
		for (i = 0; i < sp->leapcnt; ++i) {
			struct lsinfo *	lsisp;

			lsisp = &sp->lsis[i];
			lsisp->ls_trans = (stored == 4) ?
				detzcode(p) : detzcode64(p);
			p += stored;
			lsisp->ls_corr = detzcode(p);
			p += 4;
		}
		for (i = 0; i < sp->typecnt; ++i) {
			struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			if (ttisstdcnt == 0)
				ttisp->tt_ttisstd = FALSE;
			else {
				ttisp->tt_ttisstd = *p++;
				if (ttisp->tt_ttisstd != TRUE &&
					ttisp->tt_ttisstd != FALSE)
						goto oops;
			}
		}
		for (i = 0; i < sp->typecnt; ++i) {
			struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			if (ttisgmtcnt == 0)
				ttisp->tt_ttisgmt = FALSE;
			else {
				ttisp->tt_ttisgmt = *p++;
				if (ttisp->tt_ttisgmt != TRUE &&
					ttisp->tt_ttisgmt != FALSE)
						goto oops;
			}
		}
		/*
		** Out-of-sort ats should mean we're running on a
		** signed time_t system but using a data file with
		** unsigned values (or vice versa).
		*/
		for (i = 0; i < sp->timecnt - 2; ++i)
			if (sp->ats[i] > sp->ats[i + 1]) {
				++i;
				if (TYPE_SIGNED(time_t)) {
					/*
					** Ignore the end (easy).
					*/
					sp->timecnt = i;
				} else {
					/*
					** Ignore the beginning (harder).
					*/
					int	j;

					for (j = 0; j + i < sp->timecnt; ++j) {
						sp->ats[j] = sp->ats[j + i];
						sp->types[j] = sp->types[j + i];
					}
					sp->timecnt = j;
				}
				break;
			}
		/*
		** If this is an old file, we're done.
		*/
		if (up->tzhead.tzh_version[0] == '\0')
			break;
		nread -= p - up->buf;
		for (i = 0; i < nread; ++i)
			up->buf[i] = p[i];
		/*
		** If this is a narrow integer time_t system, we're done.
		*/
		if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
			break;
	}
	if (doextend && nread > 2 &&
		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
		sp->typecnt + 2 <= TZ_MAX_TYPES) {
			struct state	ts;
			int		result;

			up->buf[nread - 1] = '\0';
			result = tzparse(&up->buf[1], &ts, FALSE);
			if (result == 0 && ts.typecnt == 2 &&
				sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
					for (i = 0; i < 2; ++i)
						ts.ttis[i].tt_abbrind +=
							sp->charcnt;
					for (i = 0; i < ts.charcnt; ++i)
						sp->chars[sp->charcnt++] =
							ts.chars[i];
					i = 0;
					while (i < ts.timecnt &&
						ts.ats[i] <=
						sp->ats[sp->timecnt - 1])
							++i;
					while (i < ts.timecnt &&
					    sp->timecnt < TZ_MAX_TIMES) {
						sp->ats[sp->timecnt] =
							ts.ats[i];
						sp->types[sp->timecnt] =
							sp->typecnt +
							ts.types[i];
						++sp->timecnt;
						++i;
					}
					sp->ttis[sp->typecnt++] = ts.ttis[0];
					sp->ttis[sp->typecnt++] = ts.ttis[1];
			}
	}
	if (sp->timecnt > 1) {
		for (i = 1; i < sp->timecnt; ++i)
			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
				differ_by_repeat(sp->ats[i], sp->ats[0])) {
					sp->goback = TRUE;
					break;
				}
		for (i = sp->timecnt - 2; i >= 0; --i)
			if (typesequiv(sp, sp->types[sp->timecnt - 1],
				sp->types[i]) &&
				differ_by_repeat(sp->ats[sp->timecnt - 1],
				sp->ats[i])) {
					sp->goahead = TRUE;
					break;
		}
	}
	return 0;
oops:
	return -1;
}
Esempio n. 16
0
#endif /* !defined TYPE_BIT */

#ifndef TYPE_SIGNED
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshift-negative-value"
#endif

/* The minimum and maximum finite time values.  */
static time_t const time_t_min =
   (TYPE_SIGNED (time_t) ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1) : 0);
static time_t const time_t_max =
   (TYPE_SIGNED (time_t)
       ? -(~0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
       : -1);

#ifdef __clang__
#pragma clang diagnostic pop
#pragma clang diagnostic pop
#endif

#ifndef TZ_MAX_TIMES
#define TZ_MAX_TIMES 2000
#endif /* !defined TZ_MAX_TIMES */

#ifndef TZ_MAX_TYPES
Esempio n. 17
0
#include "diff.h"
#include <cmpbuf.h>
#include <file-type.h>
#include <setmode.h>
#include <xalloc.h>

/* Rotate an unsigned value to the left.  */
#define ROL(v, n) ((v) << (n) | (v) >> (sizeof (v) * CHAR_BIT - (n)))

/* Given a hash value and a new character, return a new hash value.  */
#define HASH(h, c) ((c) + ROL (h, 7))

/* The type of a hash value.  */
typedef size_t hash_value;
verify (hash_value_is_unsigned, ! TYPE_SIGNED (hash_value));

/* Lines are put into equivalence classes of lines that match in lines_differ.
   Each equivalence class is represented by one of these structures,
   but only while the classes are being computed.
   Afterward, each class is represented by a number.  */
struct equivclass
{
  lin next;		/* Next item in this bucket.  */
  hash_value hash;	/* Hash of lines in this class.  */
  char const *line;	/* A line that fits this class.  */
  size_t length;	/* That line's length, not counting its newline.  */
};

/* Hash-table: array of buckets, each being a chain of equivalence classes.
   buckets[-1] is reserved for incomplete lines.  */
Esempio n. 18
0
static enum decode_time_status
_decode_time (struct timespec *ts, char const *arg, char const *keyword)
{
  time_t s;
  unsigned long int ns = 0;
  char *p;
  char *arg_lim;
  bool negative = *arg == '-';

  errno = 0;

  if (ISDIGIT (arg[negative]))
    {
      if (negative)
	{
	  intmax_t i = strtoimax (arg, &arg_lim, 10);
	  if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0)
	    return decode_time_range;
	  s = i;
	}
      else
	{
	  uintmax_t i = strtoumax (arg, &arg_lim, 10);
	  if (TYPE_MAXIMUM (time_t) < i)
	    return decode_time_range;
	  s = i;
	}

      p = arg_lim;

      if (errno == ERANGE)
	return decode_time_range;

      if (*p == '.')
	{
	  int digits = 0;
	  bool trailing_nonzero = false;

	  while (ISDIGIT (*++p))
	    if (digits < LOG10_BILLION)
	      {
		ns = 10 * ns + (*p - '0');
		digits++;
	      }
	    else
	      trailing_nonzero |= *p != '0';

	  while (digits++ < LOG10_BILLION)
	    ns *= 10;

	  if (negative)
	    {
	      /* Convert "-1.10000000000001" to s == -2, ns == 89999999.
		 I.e., truncate time stamps towards minus infinity while
		 converting them to internal form.  */
	      ns += trailing_nonzero;
	      if (ns != 0)
		{
		  if (s == TYPE_MINIMUM (time_t))
		    return decode_time_range;
		  s--;
		  ns = BILLION - ns;
		}
	    }
	}

      if (! *p)
	{
	  ts->tv_sec = s;
	  ts->tv_nsec = ns;
	  return decode_time_success;
	}
    }

  return decode_time_bad_header;
}
Esempio n. 19
0
File: io.c Progetto: Lonis/diffutils
#include "diff.h"
#include <binary-io.h>
#include <cmpbuf.h>
#include <file-type.h>
#include <xalloc.h>

/* Rotate an unsigned value to the left.  */
#define ROL(v, n) ((v) << (n) | (v) >> (sizeof (v) * CHAR_BIT - (n)))

/* Given a hash value and a new character, return a new hash value.  */
#define HASH(h, c) ((c) + ROL (h, 7))

/* The type of a hash value.  */
typedef size_t hash_value;
verify (! TYPE_SIGNED (hash_value));

/* Lines are put into equivalence classes of lines that match in lines_differ.
   Each equivalence class is represented by one of these structures,
   but only while the classes are being computed.
   Afterward, each class is represented by a number.  */
struct equivclass
{
  lin next;		/* Next item in this bucket.  */
  hash_value hash;	/* Hash of lines in this class.  */
  char const *line;	/* A line that fits this class.  */
  size_t length;	/* That line's length, not counting its newline.  */
};

/* Hash-table: array of buckets, each being a chain of equivalence classes.
   buckets[-1] is reserved for incomplete lines.  */
Esempio n. 20
0
strtol_error
__xstrtol (const char *s, char **ptr, int strtol_base,
           __strtol_t *val, const char *valid_suffixes)
{
  char *t_ptr;
  char **p;
  __strtol_t tmp;
  strtol_error err = LONGINT_OK;

  assert (0 <= strtol_base && strtol_base <= 36);

  p = (ptr ? ptr : &t_ptr);

  if (! TYPE_SIGNED (__strtol_t))
    {
      const char *q = s;
      unsigned char ch = *q;
      while (isspace (ch))
        ch = *++q;
      if (ch == '-')
        return LONGINT_INVALID;
    }

  errno = 0;
  tmp = __strtol (s, p, strtol_base);

  if (*p == s)
    {
      /* If there is no number but there is a valid suffix, assume the
         number is 1.  The string is invalid otherwise.  */
      if (valid_suffixes && **p && strchr (valid_suffixes, **p))
        tmp = 1;
      else
        return LONGINT_INVALID;
    }
  else if (errno != 0)
    {
      if (errno != ERANGE)
        return LONGINT_INVALID;
      err = LONGINT_OVERFLOW;
    }

  /* Let valid_suffixes == NULL mean `allow any suffix'.  */
  /* FIXME: update all callers except the ones that allow suffixes
     after the number, changing last parameter NULL to `""'.  */
  if (!valid_suffixes)
    {
      *val = tmp;
      return err;
    }

  if (**p != '\0')
    {
      int base = 1024;
      int suffixes = 1;
      strtol_error overflow;

      if (!strchr (valid_suffixes, **p))
        {
          *val = tmp;
          return err | LONGINT_INVALID_SUFFIX_CHAR;
        }

      if (strchr (valid_suffixes, '0'))
        {
          /* The ``valid suffix'' '0' is a special flag meaning that
             an optional second suffix is allowed, which can change
             the base.  A suffix "B" (e.g. "100MB") stands for a power
             of 1000, whereas a suffix "iB" (e.g. "100MiB") stands for
             a power of 1024.  If no suffix (e.g. "100M"), assume
             power-of-1024.  */

          switch (p[0][1])
            {
            case 'i':
              if (p[0][2] == 'B')
                suffixes += 2;
              break;

            case 'B':
            case 'D': /* 'D' is obsolescent */
              base = 1000;
              suffixes++;
              break;
            }
        }

      switch (**p)
        {
        case 'b':
          overflow = bkm_scale (&tmp, 512);
          break;

        case 'B':
          overflow = bkm_scale (&tmp, 1024);
          break;

        case 'c':
          overflow = 0;
          break;

        case 'E': /* exa or exbi */
          overflow = bkm_scale_by_power (&tmp, base, 6);
          break;

        case 'G': /* giga or gibi */
        case 'g': /* 'g' is undocumented; for compatibility only */
          overflow = bkm_scale_by_power (&tmp, base, 3);
          break;

        case 'k': /* kilo */
        case 'K': /* kibi */
          overflow = bkm_scale_by_power (&tmp, base, 1);
          break;

        case 'M': /* mega or mebi */
        case 'm': /* 'm' is undocumented; for compatibility only */
          overflow = bkm_scale_by_power (&tmp, base, 2);
          break;

        case 'P': /* peta or pebi */
          overflow = bkm_scale_by_power (&tmp, base, 5);
          break;

        case 'T': /* tera or tebi */
        case 't': /* 't' is undocumented; for compatibility only */
          overflow = bkm_scale_by_power (&tmp, base, 4);
          break;

        case 'w':
          overflow = bkm_scale (&tmp, 2);
          break;

        case 'Y': /* yotta or 2**80 */
          overflow = bkm_scale_by_power (&tmp, base, 8);
          break;

        case 'Z': /* zetta or 2**70 */
          overflow = bkm_scale_by_power (&tmp, base, 7);
          break;

        default:
          *val = tmp;
          return err | LONGINT_INVALID_SUFFIX_CHAR;
        }

      err |= overflow;
      *p += suffixes;
      if (**p)
        err |= LONGINT_INVALID_SUFFIX_CHAR;
    }

  *val = tmp;
  return err;
}
Esempio n. 21
0
strtol_error
__xstrtol (const char *s, char **ptr, int strtol_base,
	   __strtol_t *val, const char *valid_suffixes)
{
  char *t_ptr;
  char **p;
  __strtol_t tmp;

  assert (0 <= strtol_base && strtol_base <= 36);

  p = (ptr ? ptr : &t_ptr);

  if (! TYPE_SIGNED (__strtol_t))
    {
      const char *q = s;
      while (ISSPACE ((unsigned char) *q))
	++q;
      if (*q == '-')
	return LONGINT_INVALID;
    }

  errno = 0;
  tmp = __strtol (s, p, strtol_base);
  if (errno != 0)
    return LONGINT_OVERFLOW;
  if (*p == s)
    return LONGINT_INVALID;

  /* Let valid_suffixes == NULL mean `allow any suffix'.  */
  /* FIXME: update all callers except the ones that allow suffixes
     after the number, changing last parameter NULL to `""'.  */
  if (!valid_suffixes)
    {
      *val = tmp;
      return LONGINT_OK;
    }

  if (**p != '\0')
    {
      int base = 1024;
      int suffixes = 1;
      int overflow;

      if (!strchr (valid_suffixes, **p))
	{
	  *val = tmp;
	  return LONGINT_INVALID_SUFFIX_CHAR;
	}

      if (strchr (valid_suffixes, '0'))
	{
	  /* The ``valid suffix'' '0' is a special flag meaning that
	     an optional second suffix is allowed, which can change
	     the base, e.g. "100MD" for 100 megabytes decimal.  */

	  switch (p[0][1])
	    {
	    case 'B':
	      suffixes++;
	      break;

	    case 'D':
	      base = 1000;
	      suffixes++;
	      break;
	    }
	}

      switch (**p)
	{
	case 'b':
	  overflow = bkm_scale (&tmp, 512);
	  break;

	case 'B':
	  overflow = bkm_scale (&tmp, 1024);
	  break;

	case 'c':
	  overflow = 0;
	  break;

	case 'E': /* Exa */
	  overflow = bkm_scale_by_power (&tmp, base, 6);
	  break;

	case 'G': /* Giga */
	  overflow = bkm_scale_by_power (&tmp, base, 3);
	  break;

	case 'k': /* kilo */
	  overflow = bkm_scale_by_power (&tmp, base, 1);
	  break;

	case 'M': /* Mega */
	case 'm': /* 'm' is undocumented; for backward compatibility only */
	  overflow = bkm_scale_by_power (&tmp, base, 2);
	  break;

	case 'P': /* Peta */
	  overflow = bkm_scale_by_power (&tmp, base, 5);
	  break;

	case 'T': /* Tera */
	  overflow = bkm_scale_by_power (&tmp, base, 4);
	  break;

	case 'w':
	  overflow = bkm_scale (&tmp, 2);
	  break;

	case 'Y': /* Yotta */
	  overflow = bkm_scale_by_power (&tmp, base, 8);
	  break;

	case 'Z': /* Zetta */
	  overflow = bkm_scale_by_power (&tmp, base, 7);
	  break;

	default:
	  *val = tmp;
	  return LONGINT_INVALID_SUFFIX_CHAR;
	  break;
	}

      if (overflow)
	return LONGINT_OVERFLOW;

      (*p) += suffixes;
    }

  *val = tmp;
  return LONGINT_OK;
}
Esempio n. 22
0
#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901) && !defined restrict
# define restrict /* empty */
#endif

#ifndef TYPE_BIT
#define TYPE_BIT(type)	(sizeof (type) * CHAR_BIT)
#endif /* !defined TYPE_BIT */

#ifndef TYPE_SIGNED
#define TYPE_SIGNED(type) (((type) -1) < 0)
#endif /* !defined TYPE_SIGNED */

/* The minimum and maximum finite time values.  */
static time_t const time_t_min =
    (TYPE_SIGNED(time_t)
        ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
        : 0);
static time_t const time_t_max =
    (TYPE_SIGNED(time_t)
        ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
        : -1);


#ifndef TZ_MAX_TIMES
#define TZ_MAX_TIMES	2000
#endif /* !defined TZ_MAX_TIMES */

#ifndef TZ_MAX_TYPES
/* This must be at least 17 for Europe/Samara and Europe/Vilnius.  */
#define TZ_MAX_TYPES	256 /* Limited by what (unsigned char)'s can hold */
Esempio n. 23
0
static char *
_fmt(const char *format, const struct tm *const t, char * pt,
     const char *const ptlim, int *warnp)
{
	for ( ; *format; ++format) {
		if (*format == '%') {
label:
			switch (*++format) {
			case '\0':
				--format;
				break;
			case 'A':
				pt = _add((t->tm_wday < 0 ||
					t->tm_wday >= DAYSPERWEEK) ?
					"?" : Locale->weekday[t->tm_wday],
					pt, ptlim);
				continue;
			case 'a':
				pt = _add((t->tm_wday < 0 ||
					t->tm_wday >= DAYSPERWEEK) ?
					"?" : Locale->wday[t->tm_wday],
					pt, ptlim);
				continue;
			case 'B':
				pt = _add((t->tm_mon < 0 ||
					t->tm_mon >= MONSPERYEAR) ?
					"?" : Locale->month[t->tm_mon],
					pt, ptlim);
				continue;
			case 'b':
			case 'h':
				pt = _add((t->tm_mon < 0 ||
					t->tm_mon >= MONSPERYEAR) ?
					"?" : Locale->mon[t->tm_mon],
					pt, ptlim);
				continue;
			case 'C':
				/*
				** %C used to do a...
				**	_fmt("%a %b %e %X %Y", t);
				** ...whereas now POSIX 1003.2 calls for
				** something completely different.
				** (ado, 1993-05-24)
				*/
				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
					pt, ptlim);
				continue;
			case 'c':
				{
				int warn2 = IN_SOME;

				pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2);
				if (warn2 == IN_ALL)
					warn2 = IN_THIS;
				if (warn2 > *warnp)
					*warnp = warn2;
				}
				continue;
			case 'D':
				pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
				continue;
			case 'd':
				pt = _conv(t->tm_mday, "%02d", pt, ptlim);
				continue;
			case 'E':
			case 'O':
				/*
				** C99 locale modifiers.
				** The sequences
				**	%Ec %EC %Ex %EX %Ey %EY
				**	%Od %oe %OH %OI %Om %OM
				**	%OS %Ou %OU %OV %Ow %OW %Oy
				** are supposed to provide alternate
				** representations.
				*/
				goto label;
			case 'e':
				pt = _conv(t->tm_mday, "%2d", pt, ptlim);
				continue;
			case 'F':
				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
				continue;
			case 'H':
				pt = _conv(t->tm_hour, "%02d", pt, ptlim);
				continue;
			case 'I':
				pt = _conv((t->tm_hour % 12) ?
					(t->tm_hour % 12) : 12,
					"%02d", pt, ptlim);
				continue;
			case 'j':
				pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
				continue;
			case 'k':
				/*
				** This used to be...
				**	_conv(t->tm_hour % 12 ?
				**		t->tm_hour % 12 : 12, 2, ' ');
				** ...and has been changed to the below to
				** match SunOS 4.1.1 and Arnold Robbins'
				** strftime version 3.0. That is, "%k" and
				** "%l" have been swapped.
				** (ado, 1993-05-24)
				*/
				pt = _conv(t->tm_hour, "%2d", pt, ptlim);
				continue;
#ifdef KITCHEN_SINK
			case 'K':
				/*
				** After all this time, still unclaimed!
				*/
				pt = _add("kitchen sink", pt, ptlim);
				continue;
#endif /* defined KITCHEN_SINK */
			case 'l':
				/*
				** This used to be...
				**	_conv(t->tm_hour, 2, ' ');
				** ...and has been changed to the below to
				** match SunOS 4.1.1 and Arnold Robbin's
				** strftime version 3.0. That is, "%k" and
				** "%l" have been swapped.
				** (ado, 1993-05-24)
				*/
				pt = _conv((t->tm_hour % 12) ?
					(t->tm_hour % 12) : 12,
					"%2d", pt, ptlim);
				continue;
			case 'M':
				pt = _conv(t->tm_min, "%02d", pt, ptlim);
				continue;
			case 'm':
				pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
				continue;
			case 'n':
				pt = _add("\n", pt, ptlim);
				continue;
			case 'p':
				pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
					Locale->pm :
					Locale->am,
					pt, ptlim);
				continue;
			case 'R':
				pt = _fmt("%H:%M", t, pt, ptlim, warnp);
				continue;
			case 'r':
				pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
				continue;
			case 'S':
				pt = _conv(t->tm_sec, "%02d", pt, ptlim);
				continue;
			case 's':
				{
					struct tm	tm;
					char		buf[INT_STRLEN_MAXIMUM(
								time_t) + 1];
					time_t		mkt;

					tm = *t;
					mkt = mktime(&tm);
					if (TYPE_SIGNED(time_t))
						(void) sprintf(buf, "%"PRIdMAX,
							(intmax_t) mkt);
					else	(void) sprintf(buf, "%"PRIuMAX,
							(uintmax_t) mkt);
					pt = _add(buf, pt, ptlim);
				}
				continue;
			case 'T':
				pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
				continue;
			case 't':
				pt = _add("\t", pt, ptlim);
				continue;
			case 'U':
				pt = _conv((t->tm_yday + DAYSPERWEEK -
					t->tm_wday) / DAYSPERWEEK,
					"%02d", pt, ptlim);
				continue;
			case 'u':
				/*
				** From Arnold Robbins' strftime version 3.0:
				** "ISO 8601: Weekday as a decimal number
				** [1 (Monday) - 7]"
				** (ado, 1993-05-24)
				*/
				pt = _conv((t->tm_wday == 0) ?
					DAYSPERWEEK : t->tm_wday,
					"%d", pt, ptlim);
				continue;
			case 'V':	/* ISO 8601 week number */
			case 'G':	/* ISO 8601 year (four digits) */
			case 'g':	/* ISO 8601 year (two digits) */
/*
** From Arnold Robbins' strftime version 3.0: "the week number of the
** year (the first Monday as the first day of week 1) as a decimal number
** (01-53)."
** (ado, 1993-05-24)
**
** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
** "Week 01 of a year is per definition the first week which has the
** Thursday in this year, which is equivalent to the week which contains
** the fourth day of January. In other words, the first week of a new year
** is the week which has the majority of its days in the new year. Week 01
** might also contain days from the previous year and the week before week
** 01 of a year is the last week (52 or 53) of the previous year even if
** it contains days from the new year. A week starts with Monday (day 1)
** and ends with Sunday (day 7). For example, the first week of the year
** 1997 lasts from 1996-12-30 to 1997-01-05..."
** (ado, 1996-01-02)
*/
				{
					int	year;
					int	base;
					int	yday;
					int	wday;
					int	w;

					year = t->tm_year;
					base = TM_YEAR_BASE;
					yday = t->tm_yday;
					wday = t->tm_wday;
					for ( ; ; ) {
						int	len;
						int	bot;
						int	top;

						len = isleap_sum(year, base) ?
							DAYSPERLYEAR :
							DAYSPERNYEAR;
						/*
						** What yday (-3 ... 3) does
						** the ISO year begin on?
						*/
						bot = ((yday + 11 - wday) %
							DAYSPERWEEK) - 3;
						/*
						** What yday does the NEXT
						** ISO year begin on?
						*/
						top = bot -
							(len % DAYSPERWEEK);
						if (top < -3)
							top += DAYSPERWEEK;
						top += len;
						if (yday >= top) {
							++base;
							w = 1;
							break;
						}
						if (yday >= bot) {
							w = 1 + ((yday - bot) /
								DAYSPERWEEK);
							break;
						}
						--base;
						yday += isleap_sum(year, base) ?
							DAYSPERLYEAR :
							DAYSPERNYEAR;
					}
#ifdef XPG4_1994_04_09
					if ((w == 52 &&
						t->tm_mon == TM_JANUARY) ||
						(w == 1 &&
						t->tm_mon == TM_DECEMBER))
							w = 53;
#endif /* defined XPG4_1994_04_09 */
					if (*format == 'V')
						pt = _conv(w, "%02d",
							pt, ptlim);
					else if (*format == 'g') {
						*warnp = IN_ALL;
						pt = _yconv(year, base, 0, 1,
							pt, ptlim);
					} else	pt = _yconv(year, base, 1, 1,
							pt, ptlim);
				}
				continue;
			case 'v':
				/*
				** From Arnold Robbins' strftime version 3.0:
				** "date as dd-bbb-YYYY"
				** (ado, 1993-05-24)
				*/
				pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
				continue;
			case 'W':
				pt = _conv((t->tm_yday + DAYSPERWEEK -
					(t->tm_wday ?
					(t->tm_wday - 1) :
					(DAYSPERWEEK - 1))) / DAYSPERWEEK,
					"%02d", pt, ptlim);
				continue;
			case 'w':
				pt = _conv(t->tm_wday, "%d", pt, ptlim);
				continue;
			case 'X':
				pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
				continue;
			case 'x':
				{
				int	warn2 = IN_SOME;

				pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
				if (warn2 == IN_ALL)
					warn2 = IN_THIS;
				if (warn2 > *warnp)
					*warnp = warn2;
				}
				continue;
			case 'y':
				*warnp = IN_ALL;
				pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
					pt, ptlim);
				continue;
			case 'Y':
				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
					pt, ptlim);
				continue;
			case 'Z':
#ifdef TM_ZONE
				if (t->TM_ZONE != NULL)
					pt = _add(t->TM_ZONE, pt, ptlim);
				else
#endif /* defined TM_ZONE */
				if (t->tm_isdst >= 0)
					pt = _add(tzname[t->tm_isdst != 0],
						pt, ptlim);
				/*
				** C99 says that %Z must be replaced by the
				** empty string if the time zone is not
				** determinable.
				*/
				continue;
			case 'z':
				{
				long		diff;
				char const *	sign;

				if (t->tm_isdst < 0)
					continue;
#ifdef TM_GMTOFF
				diff = t->TM_GMTOFF;
#else /* !defined TM_GMTOFF */
				/*
				** C99 says that the UT offset must
				** be computed by looking only at
				** tm_isdst. This requirement is
				** incorrect, since it means the code
				** must rely on magic (in this case
				** altzone and timezone), and the
				** magic might not have the correct
				** offset. Doing things correctly is
				** tricky and requires disobeying C99;
				** see GNU C strftime for details.
				** For now, punt and conform to the
				** standard, even though it's incorrect.
				**
				** C99 says that %z must be replaced by the
				** empty string if the time zone is not
				** determinable, so output nothing if the
				** appropriate variables are not available.
				*/
				if (t->tm_isdst == 0)
#ifdef USG_COMPAT
					diff = -timezone;
#else /* !defined USG_COMPAT */
					continue;
#endif /* !defined USG_COMPAT */
				else
#ifdef ALTZONE
					diff = -altzone;
#else /* !defined ALTZONE */
					continue;
#endif /* !defined ALTZONE */
#endif /* !defined TM_GMTOFF */
				if (diff < 0) {
					sign = "-";
					diff = -diff;
				} else	sign = "+";
				pt = _add(sign, pt, ptlim);
				diff /= SECSPERMIN;
				diff = (diff / MINSPERHOUR) * 100 +
					(diff % MINSPERHOUR);
				pt = _conv(diff, "%04d", pt, ptlim);
				}
				continue;
			case '+':
				pt = _fmt(Locale->date_fmt, t, pt, ptlim,
					warnp);
				continue;
			case '%':
			/*
			** X311J/88-090 (4.12.3.5): if conversion char is
			** undefined, behavior is undefined. Print out the
			** character itself as printf(3) also does.
			*/
			default:
				break;
			}
		}
TzTransitionList parseTimeZone(const char* tzName)
{
	static const char* zoneInfoDir = "/usr/share/zoneinfo/";
	static const char* etcZoneInfoDir = "/usr/share/zoneinfo/Etc/";
	std::string filePath = zoneInfoDir;
	filePath += tzName;
	
	struct stat stBuf;
	FILE* fp = fopen(filePath.c_str(), "r");
	if (!fp && errno == ENOENT)
	{
		// if file not found - try alternative filePath
		printf("Failed to find file: %s\n", filePath.c_str());

		filePath = etcZoneInfoDir;
		filePath += tzName;

		fp = fopen(filePath.c_str(), "r");
		if (!fp && errno == ENOENT)
		{
			printf("Failed to find second try file: %s\n", filePath.c_str());
			return TzTransitionList();
		}
	}
	if (fp)
	{
		if (fstat(fileno(fp), &stBuf) != 0)
		{
			printf("Failed to stat opened file: %s\n", filePath.c_str());
			fclose(fp);
			return TzTransitionList();
		}

		if (stBuf.st_size <= (int) sizeof(tzhead)) {
			printf("file too short to be a tz file: %s\n", filePath.c_str());
			fclose(fp);
			return TzTransitionList();
		}
	}
	else
	{
		printf("Failed to open file: %s\n", filePath.c_str());
		return TzTransitionList();
	}	

	char* buf = (char*) malloc(stBuf.st_size);
	size_t size = fread(buf, 1, stBuf.st_size, fp);
	fclose(fp);

	if (size != (size_t) stBuf.st_size) {
		printf("Short read on file: %s\n", filePath.c_str());
		free(buf);
		return TzTransitionList();
	}

	ttentrylist       ttEntryList;
	ttinfolist        ttInfoList;
	std::vector<char> ttAbbrList;

	/*
	  The  time zone information files used by tzset(3) begin with the
	  magic characters "TZif" to identify then as time zone information
	  files, followed by sixteen bytes reserved for future use,
	  followed by six four-byte values of type long, written in  a  "standard"
	  byte order (the high-order byte of the value is written first).
	  These values are, in order:

       tzh_ttisgmtcnt
              The number of UTC/local indicators stored in the file.

       tzh_ttisstdcnt
              The number of standard/wall indicators stored in the file.

       tzh_leapcnt
              The number of leap seconds for which data is stored in the file.

       tzh_timecnt
              The number of "transition times" for which data is stored in the file.

       tzh_typecnt
              The number of "local time types" for which data is stored in the file (must not be zero).

       tzh_charcnt
              The number of characters of "time zone abbreviation strings" stored in the file.
	*/
	
	long isGmt = 0;
	long isStd = 0;  
	long leapCnt = 0;
	long timeCnt = 0;
	long typeCnt = 0;	
	long charCnt = 0;

	(void) isGmt;
	(void) isStd;
	(void) leapCnt;
	(void) timeCnt;
	(void) typeCnt;
	(void) charCnt;
	
	int index = 0;
	for (int stored = 4; stored <= 8; stored *= 2) {

		DBG("-----------------------------------------------------\n");

		if (memcmp(buf, TZ_MAGIC, 4) != 0) {
			printf("Not a tz file. Header signature mismatch: %s\n", filePath.c_str());
			free(buf);
			return TzTransitionList();
		}
		
		struct tzhead* head = (struct tzhead*) (buf + index);

		isGmt   = detzcode(head->tzh_ttisgmtcnt);
		isStd   = detzcode(head->tzh_ttisstdcnt);
		leapCnt = detzcode(head->tzh_leapcnt);
		timeCnt = detzcode(head->tzh_timecnt);
		typeCnt = detzcode(head->tzh_typecnt);
		charCnt = detzcode(head->tzh_charcnt);

		ttInfoList.clear();
		ttInfoList.reserve(timeCnt);

		ttEntryList.clear();
		ttEntryList.reserve(typeCnt);

		ttAbbrList.clear();
		ttAbbrList.reserve(charCnt + 1);

		index += sizeof(struct tzhead);
	
		DBG("tzh_ttisgmtcnt: %ld\n", isGmt);
		DBG("tzh_ttisstdcnt: %ld\n", isStd);
		DBG("tzh_leapcnt: %ld\n", leapCnt);
		DBG("tzh_timecnt: %ld\n", timeCnt);
		DBG("tzh_typecnt: %ld\n", typeCnt);
		DBG("tzh_charcnt: %ld\n", charCnt);

		/* The  above  header  is followed by tzh_timecnt four-byte values of type
		   long, sorted in ascending order.  These values are  written  in  "standard"
		   byte  order.   Each is used as a transition time (as returned by
		   time(2)) at which the rules for computing local time change. */
		for (long i = 0; i < timeCnt; i++) {
			time_t time;
			time = (stored == 4) ? detzcode(buf + index) : detzcode64(buf + index);
			index += stored;
			
			ttentry e;
			e.time = time;
			ttEntryList.push_back(e);

			DBG("tzh_timecnt: Time: %ld, %s", time, asctime(gmtime(&time)));			
		}

		/* Next come tzh_timecnt one-byte values of type unsigned char;
		   each one tells which of the different types of "local time"
		   types described in the file is associated with the same-indexed
		   transition time. */
		for (long i = 0; i < timeCnt; i++) {
			unsigned char indexToLocalTime = (unsigned char) buf[index];
			index++;

			ttEntryList[i].indexToLocalTime = indexToLocalTime;
			
			DBG("tzh_timecnt: Index: %d\n", indexToLocalTime);			
		}

		/* These values serve as indices into an  array  of
		   ttinfo structures that appears next in the file; these structures are
		   defined as follows:

           struct ttinfo {
		   long         tt_gmtoff;
		   int          tt_isdst;
		   unsigned int tt_abbrind;
           };

		   Each  structure is written as a four-byte value for tt_gmtoff of type
		   long, in a standard byte order, followed by a one-byte value
		   for tt_isdst and a one-byte value for tt_abbrind.  In each structure,
		   tt_gmtoff gives the number of seconds to be  added  to  UTC,
		   tt_isdst  tells  whether  tm_isdst  should  be  set by localtime(3),
		   and tt_abbrind serves as an index into the array of time zone
		   abbreviation characters that follow the ttinfo structure(s) in the file. */
		for (long i = 0; i < typeCnt; i++) {

			ttinfo ttInfo;
			ttInfo.gmtOffset = detzcode(buf + index);
			index += 4;
			ttInfo.isDst = (unsigned char) buf[index];
			index++;
			ttInfo.abbrIndex = (unsigned char) buf[index];
			index++;

			ttInfoList.push_back(ttInfo);

			DBG("gmtOff: %ld, isDst: %d, abbrind: %d\n",
				ttInfo.gmtOffset, ttInfo.isDst, ttInfo.abbrIndex);
		}

		DBG("abbrev: ");
		for (long i = 0; i < charCnt; i++) {
			DBG("%c", buf[index]);
			ttAbbrList.push_back(buf[index]);
			index++;
		}
		ttAbbrList.push_back(0);
		DBG("\n");

		/* Then there are tzh_leapcnt pairs of four-byte values,
		   written in standard byte order; the first value of each
		   pair gives the  time (as  returned by time(2)) at which a leap
		   second occurs; the second gives the total number of leap seconds
		   to be applied after the given time.  The pairs of values are
		   sorted in ascending order by time. */
		for (long i = 0; i < leapCnt; i++) {

			long leapTime = (stored == 4) ? detzcode(buf + index)
							: detzcode64(buf + index);
			index += stored;

			long leapSeconds = detzcode(buf + index);
			index += 4;

			(void) leapTime;
			(void) leapSeconds;

			DBG("leapTime: %ld, leapSeconds: %ld\n",
				leapTime, leapSeconds);
		}

		/*
		  Then there are tzh_ttisstdcnt standard/wall indicators, each
		  stored as a one-byte value; they tell whether the  transition
		  times associated with local time types were specified as standard
		  time or wall clock time, and are used when a time zone file is
		  used in handling POSIX-style time zone environment variables.
		*/
		for (long i = 0; i < typeCnt; i++) {

			int standardOrWallClock = (unsigned char) buf[index];
			index++;

			(void) standardOrWallClock;
			DBG("standardOrWallClock: %d\n", standardOrWallClock);
		}
	

		/*
		  Finally, there are tzh_ttisgmtcnt UTC/local indicators,
		  each stored as a one-byte value; they tell whether  the
		  transition  times associated  with  local  time  types  were
		  specified as UTC or local time, and are used when a time zone
		  file is used in handling POSIX-style time zone environment variables.
		*/
		for (long i = 0; i < typeCnt; i++) {

			int utcOrLocalTime = (unsigned char) buf[index];
			index++;

			(void) utcOrLocalTime;
			DBG("utcOrLocalTime: %d\n", utcOrLocalTime);
		}

		/*
		  Localtime uses the first standard-time ttinfo structure in the file
		  (or simply the first ttinfo structure  in  the  absence  of  a
		  standard-time structure) if either tzh_timecnt is zero or the time
		  argument is less than the first transition time recorded in the
		  file.
		*/

		/*
		 * Out-of-sort ats should mean we're running on a
		 * signed time_t system but using a data file with
		 * unsigned values (or vice versa).
		 */
		for (int i = 0; i < timeCnt - 2; ++i) {
			if (ttEntryList[i].time > ttEntryList[i+1].time) {
				++i;
				if (TYPE_SIGNED(time_t)) {
					// Ignore the end (easy).
					timeCnt = i;
				} else {
					// Ignore the beginning (harder).
					int j;
					for (j = 0; (j + i) < timeCnt; ++j) {
						ttEntryList[j] = ttEntryList[j+i];
					}
					timeCnt = j;
				}
				break;
			}
		}

		/*
		 * If this is an old file, we're done.
		 */
		if (head->tzh_version[0] == '\0') {
			DBG("Version 0 file. breaking\n");
			break;
		}

		/*
		 * If this is a narrow integer time_t system, we're done.
		 */
		if ((stored >= (int) sizeof(time_t)) && (TYPE_INTEGRAL(time_t))) {
			DBG("narrow integer time_t system. breaking\n");
			break;
		}
	}
	
	DBG("Total Buffer size parsed: %d\n", index);
	
	free(buf);

	// Dummy entry for standardized timezones which never had
	// a transition time
	if (ttEntryList.empty() && !ttInfoList.empty()) {
		ttentry e;
		timeCnt = 1;
		e.time = -2147483648UL;
		e.indexToLocalTime = 0;
		ttEntryList.push_back(e);		
	}

	TzTransitionList result;
	for (int i = 0; i < timeCnt; i++) {
		const ttentry& entry = ttEntryList[i];
		const ttinfo& info   = ttInfoList[entry.indexToLocalTime];
		struct tm* gmTime    = gmtime(&entry.time);
		
		TzTransition trans;
		trans.time        = entry.time;
		trans.utcOffset   = info.gmtOffset;
		trans.isDst       = info.isDst;
		trans.year        = gmTime->tm_year + 1900;
		trans.abbrName[0] = 0;

		int j = info.abbrIndex;
		int k = 0;
		for (; (j < (int) ttAbbrList.size()) && (k < TZ_ABBR_MAX_LEN);
			 j++, k++) {
			trans.abbrName[k] = ttAbbrList[j];
			if (ttAbbrList[j] == 0)
				break;
		}
		trans.abbrName[TZ_ABBR_MAX_LEN-1] = 0;

		result.push_back(trans);
	}

	return result;
}
Esempio n. 25
0
int
main (void)
{
  unsigned int i;
  int fail = 0;
  char curr_year_str[30];
  struct tm *tm;
  time_t t_now;
  int err;
  size_t n_bytes;

  /* The above test data requires Universal Time, e.g., TZ="UTC0".  */
  err = setenv ("TZ", "UTC0", 1);
  ASSERT (err == 0);

  t_now = time (NULL);
  ASSERT (t_now != (time_t) -1);
  tm = localtime (&t_now);
  ASSERT (tm);
  n_bytes = strftime (curr_year_str, sizeof curr_year_str, "%Y", tm);
  ASSERT (0 < n_bytes);

  for (i = 0; T[i].in; i++)
    {
      time_t t_out;
      time_t t_exp = T[i].t_expected;
      bool ok;

      /* Some tests assume that time_t is signed.
         If it is unsigned and the result is negative, skip the test. */
      if (T[i].t_expected < 0 && ! TYPE_SIGNED (time_t))
        {
          printf ("skipping %s: result is negative, "
                  "but your time_t is unsigned\n", T[i].in);
          continue;
        }

      if (T[i].valid && t_exp != T[i].t_expected)
        {
          printf ("skipping %s: result is out of range of your time_t\n",
                  T[i].in);
          continue;
        }

      /* If an input string does not specify the year number, determine
         the expected output by calling posixtime with an otherwise
         equivalent string that starts with the current year.  */
      if (8 <= strlen (T[i].in)
          && (T[i].in[8] == '.' || T[i].in[8] == '\0'))
        {
          char tmp_buf[20];
          stpcpy (stpcpy (tmp_buf, curr_year_str), T[i].in);
          ASSERT (posixtime (&t_exp, tmp_buf, T[i].syntax_bits));
        }

      ok = posixtime (&t_out, T[i].in, T[i].syntax_bits);
      if (ok != !!T[i].valid)
        {
          printf ("%s return value mismatch: got %d, expected %d\n",
                  T[i].in, !!ok, T[i].valid);
          fail = 1;
          continue;
        }

      if (!ok)
        continue;

      if (t_out != t_exp)
        {
          printf ("%s mismatch (-: actual; +:expected)\n-%12ld\n+%12ld\n",
                  T[i].in, t_out, t_exp);
          fail = 1;
        }
    }

  return fail;
}
Esempio n. 26
0
static char *
_fmt(const char * format, const struct tm * const t, char * pt, const char * const ptlim, int * warnp)
{
    for ( ; *format; ++format) {
        if (*format == '%') {
label:
            switch (*++format) {
            case '\0':
                --format;
                break;
            case 'A':
                pt = _add((t->tm_wday < 0 ||
                           t->tm_wday >= DAYSPERWEEK) ?
                          "?" : Locale->weekday[t->tm_wday],
                          pt, ptlim);
                continue;
            case 'a':
                pt = _add((t->tm_wday < 0 ||
                           t->tm_wday >= DAYSPERWEEK) ?
                          "?" : Locale->wday[t->tm_wday],
                          pt, ptlim);
                continue;
            case 'B':
                pt = _add((t->tm_mon < 0 ||
                           t->tm_mon >= MONSPERYEAR) ?
                          "?" : Locale->month[t->tm_mon],
                          pt, ptlim);
                continue;
            case 'b':
            case 'h':
                pt = _add((t->tm_mon < 0 ||
                           t->tm_mon >= MONSPERYEAR) ?
                          "?" : Locale->mon[t->tm_mon],
                          pt, ptlim);
                continue;
            case 'C':
                /*
                ** %C used to do a...
                **	_fmt("%a %b %e %X %Y", t);
                ** ...whereas now POSIX 1003.2 calls for
                ** something completely different.
                ** (ado, 1993-05-24)
                */
                pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
                           "%02d", pt, ptlim);
                continue;
            case 'c':
            {
                int warn2 = IN_SOME;

                pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp);
                if (warn2 == IN_ALL)
                    warn2 = IN_THIS;
                if (warn2 > *warnp)
                    *warnp = warn2;
            }
            continue;
            case 'D':
                pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
                continue;
            case 'd':
                pt = _conv(t->tm_mday, "%02d", pt, ptlim);
                continue;
            case 'E':
            case 'O':
                /*
                ** C99 locale modifiers.
                ** The sequences
                **	%Ec %EC %Ex %EX %Ey %EY
                **	%Od %oe %OH %OI %Om %OM
                **	%OS %Ou %OU %OV %Ow %OW %Oy
                ** are supposed to provide alternate
                ** representations.
                */
                goto label;
            case 'e':
                pt = _conv(t->tm_mday, "%2d", pt, ptlim);
                continue;
            case 'F':
                pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
                continue;
            case 'H':
                pt = _conv(t->tm_hour, "%02d", pt, ptlim);
                continue;
            case 'I':
                pt = _conv((t->tm_hour % 12) ?
                           (t->tm_hour % 12) : 12,
                           "%02d", pt, ptlim);
                continue;
            case 'j':
                pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
                continue;
            case 'k':
                /*
                ** This used to be...
                **	_conv(t->tm_hour % 12 ?
                **		t->tm_hour % 12 : 12, 2, ' ');
                ** ...and has been changed to the below to
                ** match SunOS 4.1.1 and Arnold Robbins'
                ** strftime version 3.0.  That is, "%k" and
                ** "%l" have been swapped.
                ** (ado, 1993-05-24)
                */
                pt = _conv(t->tm_hour, "%2d", pt, ptlim);
                continue;
#ifdef KITCHEN_SINK
            case 'K':
                /*
                ** After all this time, still unclaimed!
                */
                pt = _add("kitchen sink", pt, ptlim);
                continue;
#endif /* defined KITCHEN_SINK */
            case 'l':
                /*
                ** This used to be...
                **	_conv(t->tm_hour, 2, ' ');
                ** ...and has been changed to the below to
                ** match SunOS 4.1.1 and Arnold Robbin's
                ** strftime version 3.0.  That is, "%k" and
                ** "%l" have been swapped.
                ** (ado, 1993-05-24)
                */
                pt = _conv((t->tm_hour % 12) ?
                           (t->tm_hour % 12) : 12,
                           "%2d", pt, ptlim);
                continue;
            case 'M':
                pt = _conv(t->tm_min, "%02d", pt, ptlim);
                continue;
            case 'm':
                pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
                continue;
            case 'n':
                pt = _add("\n", pt, ptlim);
                continue;
            case 'p':
                pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
                          Locale->pm :
                          Locale->am,
                          pt, ptlim);
                continue;
            case 'R':
                pt = _fmt("%H:%M", t, pt, ptlim, warnp);
                continue;
            case 'r':
                pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
                continue;
            case 'S':
                pt = _conv(t->tm_sec, "%02d", pt, ptlim);
                continue;
            case 's':
            {
                struct tm	tm;
                char		buf[INT_STRLEN_MAXIMUM(
                                    time_t) + 1];
                time_t		mkt;

                tm = *t;
                mkt = mktime(&tm);
                if (TYPE_SIGNED(time_t))
                    (void) _snprintf(buf, sizeof buf,
                                     "%ld", (long) mkt);
                else	(void) _snprintf(buf, sizeof buf,
                                             "%lu", (unsigned long) mkt);
                pt = _add(buf, pt, ptlim);
            }
            continue;
            case 'T':
                pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
                continue;
            case 't':
                pt = _add("\t", pt, ptlim);
                continue;
            case 'U':
                pt = _conv((t->tm_yday + DAYSPERWEEK -
                            t->tm_wday) / DAYSPERWEEK,
                           "%02d", pt, ptlim);
                continue;
            case 'u':
                /*
                ** From Arnold Robbins' strftime version 3.0:
                ** "ISO 8601: Weekday as a decimal number
                ** [1 (Monday) - 7]"
                ** (ado, 1993-05-24)
                */
                pt = _conv((t->tm_wday == 0) ?
                           DAYSPERWEEK : t->tm_wday,
                           "%d", pt, ptlim);
                continue;
            case 'V':	/* ISO 8601 week number */
            case 'G':	/* ISO 8601 year (four digits) */
            case 'g':	/* ISO 8601 year (two digits) */
            {
                int	year;
                int	yday;
                int	wday;
                int	w;

                year = t->tm_year + TM_YEAR_BASE;
                yday = t->tm_yday;
                wday = t->tm_wday;
                for ( ; ; ) {
                    int	len;
                    int	bot;
                    int	top;

                    len = isleap(year) ?
                          DAYSPERLYEAR :
                          DAYSPERNYEAR;
                    /*
                    ** What yday (-3 ... 3) does
                    ** the ISO year begin on?
                    */
                    bot = ((yday + 11 - wday) %
                           DAYSPERWEEK) - 3;
                    /*
                    ** What yday does the NEXT
                    ** ISO year begin on?
                    */
                    top = bot -
                          (len % DAYSPERWEEK);
                    if (top < -3)
                        top += DAYSPERWEEK;
                    top += len;
                    if (yday >= top) {
                        ++year;
                        w = 1;
                        break;
                    }
                    if (yday >= bot) {
                        w = 1 + ((yday - bot) /
                                 DAYSPERWEEK);
                        break;
                    }
                    --year;
                    yday += isleap(year) ?
                            DAYSPERLYEAR :
                            DAYSPERNYEAR;
                }
                if (*format == 'V')
                    pt = _conv(w, "%02d",
                               pt, ptlim);
                else if (*format == 'g') {
                    *warnp = IN_ALL;
                    pt = _conv(year % 100, "%02d",
                               pt, ptlim);
                } else	pt = _conv(year, "%04d",
                                       pt, ptlim);
            }
            continue;
            case 'v':
                pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
                continue;
            case 'W':
                pt = _conv((t->tm_yday + DAYSPERWEEK -
                            (t->tm_wday ?
                             (t->tm_wday - 1) :
                             (DAYSPERWEEK - 1))) / DAYSPERWEEK,
                           "%02d", pt, ptlim);
                continue;
            case 'w':
                pt = _conv(t->tm_wday, "%d", pt, ptlim);
                continue;
            case 'X':
                pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
                continue;
            case 'x':
            {
                int	warn2 = IN_SOME;

                pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
                if (warn2 == IN_ALL)
                    warn2 = IN_THIS;
                if (warn2 > *warnp)
                    *warnp = warn2;
            }
            continue;
            case 'y':
                *warnp = IN_ALL;
                pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
                           "%02d", pt, ptlim);
                continue;
            case 'Y':
                pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
                           pt, ptlim);
                continue;
            case 'Z':
                if (t->tm_isdst >= 0)
                    pt = _add(tzname[t->tm_isdst != 0],
                              pt, ptlim);
                /*
                ** C99 says that %Z must be replaced by the
                ** empty string if the time zone is not
                ** determinable.
                */
                continue;
            case 'z':
            {
                int		diff;
                char const *	sign;

                if (t->tm_isdst < 0)
                    continue;
                continue;
                if (diff < 0) {
                    sign = "-";
                    diff = -diff;
                } else	sign = "+";
                pt = _add(sign, pt, ptlim);
                diff /= 60;
                pt = _conv((diff/60)*100 + diff%60,
                           "%04d", pt, ptlim);
            }
            continue;
            case '+':
                pt = _fmt(Locale->date_fmt, t, pt, ptlim,
                          warnp);
                continue;
            case '%':
            default:
                break;
            }
        }
        if (pt == ptlim)
            break;
        *pt++ = *format;
    }
    return pt;
}
Esempio n. 27
0
#ifdef O_BINARY
#define OPEN_MODE	(O_RDONLY | O_BINARY)
#endif /* defined O_BINARY */
#ifndef O_BINARY
#define OPEN_MODE	O_RDONLY
#endif /* !defined O_BINARY */

/* Complex computations to determine the min/max of time_t depending
 * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL.
 * These macros cannot be used in pre-processor directives, so we
 * let the C compiler do the work, which makes things a bit funky.
 */
static const time_t TIME_T_MAX =
    TYPE_INTEGRAL(time_t) ?
        ( TYPE_SIGNED(time_t) ?
            ~((time_t)1 << (TYPE_BIT(time_t)-1))
        :
            ~(time_t)0
        )
    : /* if time_t is a floating point number */
        ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX );

static const time_t TIME_T_MIN =
    TYPE_INTEGRAL(time_t) ?
        ( TYPE_SIGNED(time_t) ?
            ((time_t)1 << (TYPE_BIT(time_t)-1))
        :
            0
        )
    :
Esempio n. 28
0
int
tzload(const char *name, char *canonname, struct state * sp, int doextend)
{
	const char *p;
	int			i;
	int			fid;
	int			stored;
	int			nread;
	union
	{
		struct tzhead tzhead;
		char		buf[2 * sizeof(struct tzhead) +
									2 * sizeof *sp +
									4 * TZ_MAX_TIMES];
	}			u;

	sp->goback = sp->goahead = FALSE;
	if (name == NULL && (name = TZDEFAULT) == NULL)
		return -1;
	if (name[0] == ':')
		++name;
	fid = pg_open_tzfile(name, canonname);
	if (fid < 0)
		return -1;
	nread = read(fid, u.buf, sizeof u.buf);
	if (close(fid) != 0 || nread <= 0)
		return -1;
	for (stored = 4; stored <= 8; stored *= 2)
	{
		int			ttisstdcnt;
		int			ttisgmtcnt;

		ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
		ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
		sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
		sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
		sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
		sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
		p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
			return -1;
		if (nread - (p - u.buf) <
			sp->timecnt * stored +		/* ats */
			sp->timecnt +		/* types */
			sp->typecnt * 6 +	/* ttinfos */
			sp->charcnt +		/* chars */
			sp->leapcnt * (stored + 4) +		/* lsinfos */
			ttisstdcnt +		/* ttisstds */
			ttisgmtcnt)			/* ttisgmts */
			return -1;
		for (i = 0; i < sp->timecnt; ++i)
		{
			sp->ats[i] = (stored == 4) ? detzcode(p) : detzcode64(p);
			p += stored;
		}
		for (i = 0; i < sp->timecnt; ++i)
		{
			sp->types[i] = (unsigned char) *p++;
			if (sp->types[i] >= sp->typecnt)
				return -1;
		}
		for (i = 0; i < sp->typecnt; ++i)
		{
			struct ttinfo *ttisp;

			ttisp = &sp->ttis[i];
			ttisp->tt_gmtoff = detzcode(p);
			p += 4;
			ttisp->tt_isdst = (unsigned char) *p++;
			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
				return -1;
			ttisp->tt_abbrind = (unsigned char) *p++;
			if (ttisp->tt_abbrind < 0 ||
				ttisp->tt_abbrind > sp->charcnt)
				return -1;
		}
		for (i = 0; i < sp->charcnt; ++i)
			sp->chars[i] = *p++;
		sp->chars[i] = '\0';	/* ensure '\0' at end */
		for (i = 0; i < sp->leapcnt; ++i)
		{
			struct lsinfo *lsisp;

			lsisp = &sp->lsis[i];
			lsisp->ls_trans = (stored == 4) ? detzcode(p) : detzcode64(p);
			p += stored;
			lsisp->ls_corr = detzcode(p);
			p += 4;
		}
		for (i = 0; i < sp->typecnt; ++i)
		{
			struct ttinfo *ttisp;

			ttisp = &sp->ttis[i];
			if (ttisstdcnt == 0)
				ttisp->tt_ttisstd = FALSE;
			else
			{
				ttisp->tt_ttisstd = *p++;
				if (ttisp->tt_ttisstd != TRUE &&
					ttisp->tt_ttisstd != FALSE)
					return -1;
			}
		}
		for (i = 0; i < sp->typecnt; ++i)
		{
			struct ttinfo *ttisp;

			ttisp = &sp->ttis[i];
			if (ttisgmtcnt == 0)
				ttisp->tt_ttisgmt = FALSE;
			else
			{
				ttisp->tt_ttisgmt = *p++;
				if (ttisp->tt_ttisgmt != TRUE &&
					ttisp->tt_ttisgmt != FALSE)
					return -1;
			}
		}

		/*
		 * Out-of-sort ats should mean we're running on a signed time_t system
		 * but using a data file with unsigned values (or vice versa).
		 */
		for (i = 0; i < sp->timecnt - 2; ++i)
			if (sp->ats[i] > sp->ats[i + 1])
			{
				++i;
				if (TYPE_SIGNED(pg_time_t))
				{
					/*
					 * Ignore the end (easy).
					 */
					sp->timecnt = i;
				}
				else
				{
					/*
					 * Ignore the beginning (harder).
					 */
					int			j;

					for (j = 0; j + i < sp->timecnt; ++j)
					{
						sp->ats[j] = sp->ats[j + i];
						sp->types[j] = sp->types[j + i];
					}
					sp->timecnt = j;
				}
				break;
			}

		/*
		 * If this is an old file, we're done.
		 */
		if (u.tzhead.tzh_version[0] == '\0')
			break;
		nread -= p - u.buf;
		for (i = 0; i < nread; ++i)
			u.buf[i] = p[i];

		/*
		 * If this is a narrow integer time_t system, we're done.
		 */
		if (stored >= (int) sizeof(pg_time_t) && TYPE_INTEGRAL(pg_time_t))
			break;
	}
	if (doextend && nread > 2 &&
		u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
		sp->typecnt + 2 <= TZ_MAX_TYPES)
	{
		struct state ts;
		int			result;

		u.buf[nread - 1] = '\0';
		result = tzparse(&u.buf[1], &ts, FALSE);
		if (result == 0 && ts.typecnt == 2 &&
			sp->charcnt + ts.charcnt <= TZ_MAX_CHARS)
		{
			for (i = 0; i < 2; ++i)
				ts.ttis[i].tt_abbrind +=
					sp->charcnt;
			for (i = 0; i < ts.charcnt; ++i)
				sp->chars[sp->charcnt++] =
					ts.chars[i];
			i = 0;
			while (i < ts.timecnt &&
				   ts.ats[i] <=
				   sp->ats[sp->timecnt - 1])
				++i;
			while (i < ts.timecnt &&
				   sp->timecnt < TZ_MAX_TIMES)
			{
				sp->ats[sp->timecnt] =
					ts.ats[i];
				sp->types[sp->timecnt] =
					sp->typecnt +
					ts.types[i];
				++sp->timecnt;
				++i;
			}
			sp->ttis[sp->typecnt++] = ts.ttis[0];
			sp->ttis[sp->typecnt++] = ts.ttis[1];
		}
	}
	if (sp->timecnt > 1)
	{
		for (i = 1; i < sp->timecnt; ++i)
			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
				differ_by_repeat(sp->ats[i], sp->ats[0]))
			{
				sp->goback = TRUE;
				break;
			}
		for (i = sp->timecnt - 2; i >= 0; --i)
			if (typesequiv(sp, sp->types[sp->timecnt - 1],
						   sp->types[i]) &&
				differ_by_repeat(sp->ats[sp->timecnt - 1],
								 sp->ats[i]))
			{
				sp->goahead = TRUE;
				break;
			}
	}
	return 0;
}
Esempio n. 29
0
static time_t
time2sub(struct tm * const tmp,
      struct tm * (* const funcp)(const time_t *, long, struct tm *),
      const long offset, int * const okayp, const int do_norm_secs)
{
	const struct state *	sp;
	int			dir;
	int			i, j;
	int			saved_seconds;
	long			li;
	time_t			lo;
	time_t			hi;
	long			y;
	time_t			newt;
	time_t			t;
	struct tm		yourtm, mytm;

	*okayp = FALSE;
	yourtm = *tmp;
	if (do_norm_secs) {
		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
			SECSPERMIN))
				return WRONG;
	}
	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
		return WRONG;
	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
		return WRONG;
	y = yourtm.tm_year;
	if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
		return WRONG;
	/*
	** Turn y into an actual year number for now.
	** It is converted back to an offset from TM_YEAR_BASE later.
	*/
	if (long_increment_overflow(&y, TM_YEAR_BASE))
		return WRONG;
	while (yourtm.tm_mday <= 0) {
		if (long_increment_overflow(&y, -1))
			return WRONG;
		li = y + (1 < yourtm.tm_mon);
		yourtm.tm_mday += year_lengths[isleap(li)];
	}
	while (yourtm.tm_mday > DAYSPERLYEAR) {
		li = y + (1 < yourtm.tm_mon);
		yourtm.tm_mday -= year_lengths[isleap(li)];
		if (long_increment_overflow(&y, 1))
			return WRONG;
	}
	for ( ; ; ) {
		i = mon_lengths[isleap(y)][yourtm.tm_mon];
		if (yourtm.tm_mday <= i)
			break;
		yourtm.tm_mday -= i;
		if (++yourtm.tm_mon >= MONSPERYEAR) {
			yourtm.tm_mon = 0;
			if (long_increment_overflow(&y, 1))
				return WRONG;
		}
	}
	if (long_increment_overflow(&y, -TM_YEAR_BASE))
		return WRONG;
	yourtm.tm_year = y;
	if (yourtm.tm_year != y)
		return WRONG;
	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
		saved_seconds = 0;
	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
		/*
		** We can't set tm_sec to 0, because that might push the
		** time below the minimum representable time.
		** Set tm_sec to 59 instead.
		** This assumes that the minimum representable time is
		** not in the same minute that a leap second was deleted from,
		** which is a safer assumption than using 58 would be.
		*/
		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
			return WRONG;
		saved_seconds = yourtm.tm_sec;
		yourtm.tm_sec = SECSPERMIN - 1;
	} else {
		saved_seconds = yourtm.tm_sec;
		yourtm.tm_sec = 0;
	}
	/*
	** Do a binary search (this works whatever time_t's type is).
	*/
	if (!TYPE_SIGNED(time_t)) {
		lo = 0;
		hi = lo - 1;
	} else if (!TYPE_INTEGRAL(time_t)) {
		if (sizeof(time_t) > sizeof(float))
			hi = (time_t) DBL_MAX;
		else	hi = (time_t) FLT_MAX;
		lo = -hi;
	} else {
		lo = 1;
		for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
			lo *= 2;
		hi = -(lo + 1);
	}
	for ( ; ; ) {
		t = lo / 2 + hi / 2;
		if (t < lo)
			t = lo;
		else if (t > hi)
			t = hi;
		if ((*funcp)(&t, offset, &mytm) == NULL) {
			/*
			** Assume that t is too extreme to be represented in
			** a struct tm; arrange things so that it is less
			** extreme on the next pass.
			*/
			dir = (t > 0) ? 1 : -1;
		} else	dir = tmcomp(&mytm, &yourtm);
		if (dir != 0) {
			if (t == lo) {
				++t;
				if (t <= lo)
					return WRONG;
				++lo;
			} else if (t == hi) {
				--t;
				if (t >= hi)
					return WRONG;
				--hi;
			}
			if (lo > hi)
				return WRONG;
			if (dir > 0)
				hi = t;
			else	lo = t;
			continue;
		}
		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
			break;
		/*
		** Right time, wrong type.
		** Hunt for right time, right type.
		** It's okay to guess wrong since the guess
		** gets checked.
		*/
		sp = (const struct state *)
			((funcp == localsub) ? lclptr : gmtptr);

		for (i = sp->typecnt - 1; i >= 0; --i) {
			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
				continue;
			for (j = sp->typecnt - 1; j >= 0; --j) {
				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
					continue;
				newt = t + sp->ttis[j].tt_gmtoff -
					sp->ttis[i].tt_gmtoff;
				if ((*funcp)(&newt, offset, &mytm) == NULL)
					continue;
				if (tmcomp(&mytm, &yourtm) != 0)
					continue;
				if (mytm.tm_isdst != yourtm.tm_isdst)
					continue;
				/*
				** We have a match.
				*/
				t = newt;
				goto label;
			}
		}
		return WRONG;
	}
label:
	newt = t + saved_seconds;
	if ((newt < t) != (saved_seconds < 0))
		return WRONG;
	t = newt;
	if ((*funcp)(&t, offset, tmp))
		*okayp = TRUE;
	return t;
}