delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2001/08/12/18:30:56

From: "Tim Van Holder" <tim DOT van DOT holder AT pandora DOT be>
To: <djgpp-workers AT delorie DOT com>
Subject: getdate prototype
Date: Mon, 13 Aug 2001 00:31:15 +0200
Message-ID: <CAEGKOHJKAAFPKOCLHDIKEIDCGAA.tim.van.holder@pandora.be>
MIME-Version: 1.0
X-Priority: 3 (Normal)
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0)
Importance: Normal
X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400
Reply-To: djgpp-workers AT delorie DOT com

This is a multi-part message in MIME format.

------=_NextPart_000_0007_01C1238F.42ECDF80
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

(Finally got around to testing & tweaking the draft I
created a while back - these are the results)

Attached are a diff (for include/ and the makefile) and
a source file for the first draft of an implementation
of the POSIX getdate() function, which takes a string
and tries to parse it into a struct tm based on a set
of masks.

This is

 a) far from optimal code; the current state is basically
    based literally on the standard.  So there is probably
    a lot of room for optimization.
 b) not tested heavily
 c) incomplete, in that it does not support timezones (it
    always uses the current one).  It probably also has
    issues with DST.

It seems to work reasonably well, but is definitely not
ready for production use.
Any and all input is appreciated.

------=_NextPart_000_0007_01C1238F.42ECDF80
Content-Type: application/octet-stream;
	name="getdate.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="getdate.diff"

Index: include/dos.h=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: /cvs/djgpp/djgpp/include/dos.h,v=0A=
retrieving revision 1.9=0A=
diff -u -r1.9 dos.h=0A=
--- include/dos.h	2001/07/27 10:42:44	1.9=0A=
+++ include/dos.h	2001/08/12 22:08:42=0A=
@@ -164,10 +164,21 @@=0A=
 int getcbrk(void);=0A=
 int setcbrk(int _new_value);=0A=
 =0A=
-void getdate(struct date *);=0A=
+void _dos_getdate(struct date *);=0A=
 void gettime(struct time *);=0A=
 void setdate(struct date *);=0A=
 void settime(struct time *);=0A=
+=0A=
+/* This is to resolve the name clash between our getdate and the one=0A=
+   from the POSIX spec (in time.h).=0A=
+   IMPORTANT:=0A=
+   If both dos.h and time.h are included, the getdate function used=0A=
+   will always be the POSIX one, and never this DOS-oriented one (which=0A=
+   will then only be available as _dos_getdate). */=0A=
+#ifndef __POSIX_GETDATE=0A=
+# undef  getdate=0A=
+# define getdate _dos_getdate=0A=
+#endif=0A=
 =0A=
 void getdfree(unsigned char _drive, struct dfree *_ptr);=0A=
 =0A=
Index: include/time.h=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: /cvs/djgpp/djgpp/include/time.h,v=0A=
retrieving revision 1.5=0A=
diff -u -r1.5 time.h=0A=
--- include/time.h	2000/12/05 14:05:53	1.5=0A=
+++ include/time.h	2001/08/12 22:08:42=0A=
@@ -48,10 +48,15 @@=0A=
   int __tm_gmtoff;=0A=
 };=0A=
 =0A=
+/* This helps with the nameclash for getdate (see dos.h for details) */=0A=
+#undef getdate=0A=
+#define __POSIX_GETDATE=0A=
+=0A=
 char *		asctime(const struct tm *_tptr);=0A=
 clock_t		clock(void);=0A=
 char *		ctime(const time_t *_cal);=0A=
 double		difftime(time_t _t1, time_t _t0);=0A=
+struct tm *	getdate(const char * _spec);=0A=
 struct tm *	gmtime(const time_t *_tod);=0A=
 struct tm *	localtime(const time_t *_tod);=0A=
 time_t		mktime(struct tm *_tptr);=0A=
Index: src/libc/posix/time/makefile=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
--- /dev/null	Mon Aug 13 00:11:42 2001=0A=
+++ src/libc/posix/time/makefile	Mon Jun 18 23:22:40 2001=0A=
@@ -0,0 +1,7 @@=0A=
+# Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details=0A=
+=0A=
+TOP=3D../..=0A=
+=0A=
+SRC +=3D getdate.c=0A=
+=0A=
+include $(TOP)/../makefile.inc=0A=

------=_NextPart_000_0007_01C1238F.42ECDF80
Content-Type: application/octet-stream;
	name="getdate.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="getdate.c"

/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */

#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
#include <tzfile.h>

#include <libc/environ.h>

int getdate_err =3D 0;

static time_t maskfile_modtime =3D 0;

struct mask_entry {
  char* mask;
  struct mask_entry* next;
}* mask_entries =3D NULL;

/* These are "borrowed" from strftime.c - maybe they should be shared
 * data to reduce the library size? */

static const char *afmt[] =3D {
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
};

static const char *Afmt[] =3D {
  "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  "Saturday",
};

static const char *bfmt[] =3D {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
  "Oct", "Nov", "Dec",
};

static const char *Bfmt[] =3D {
  "January", "February", "March", "April", "May", "June", "July",
  "August", "September", "October", "November", "December",
};

static void
cleanup_entries(void)
{
  struct mask_entry* e =3D mask_entries;

  while (e !=3D NULL) {
    mask_entries =3D mask_entries->next;
    if (e->mask !=3D NULL)
      free (e->mask);
    free (e);
    e =3D mask_entries;
  }
}

static const char*
expand_mask(const char* mask)
{
static char expanded[256] =3D { "" };
char* e =3D expanded;
  while (mask && *mask && e < (expanded + sizeof expanded)) {
    if (*mask =3D=3D '%') {
      ++mask;
      switch (*mask) {
        case 'c': /* "normal" date/time -> %a %b %e %H:%M:%S %Y */
	  strcpy (e, "%a %b %e %H:%M:%S %Y");
	  e +=3D strlen ("%a %b %e %H:%M:%S %Y");
	  break;
        case 'D':
        case 'x': /* "normal" date */
	  strcpy (e, "%m/%d/%y");
	  e +=3D strlen ("%m/%d/%y");
	  break;
        case 'r': /* "normal" AM/PM time -> '%I:%M:%S %p' for POSIX */
	  strcpy (e, "%I:%M:%S %p");
	  e +=3D strlen ("%I:%M:%S %p");
	  break;
        case 'R':
	  strcpy (e, "%H:%M");
	  e +=3D strlen ("%H:%M");
	  break;
        case 'T':
        case 'X': /* "normal" time */
	  strcpy (e, "%H:%M:%S");
	  e +=3D strlen ("%H:%M:%S");
	  break;
        default:
	  *e++ =3D '%';
	  *e++ =3D *mask;
	  break;
      }
    }
    else
      *e++ =3D *mask;
    ++mask;
  }
  *e =3D 0;
  return expanded;
}

static int
maybe_read_maskfile(void)
{
  static int cleanup_registered =3D 0;
  struct stat info;
  char* maskfilename =3D getenv ("DATEMSK");

  if (maskfilename =3D=3D NULL)
    return 1; /* $DATEMSK not set */

  if (stat (maskfilename, &info) !=3D 0)
    return 3; /* Could not get file status information */

  if (!S_ISREG (info.st_mode))
    return 4; /* Template file is not a regular file */

  if (!cleanup_registered)
  {
    atexit (cleanup_entries);
    cleanup_registered =3D 1;
  }

  if (info.st_mtime > maskfile_modtime)
  {
    /* FIXME: Should this be fixed-size? If so, is this large enough? */
    char maskline[256] =3D { "" };
    FILE* maskfile =3D fopen (maskfilename, "r");
    struct mask_entry* last_entry =3D NULL;

    cleanup_entries ();

    if (maskfile =3D=3D NULL)
      return 2; /* Template file cannot be opened for reading */

    while (1)
    {
      if (fgets (maskline, 256, maskfile) =3D=3D NULL && !feof =
(maskfile))
      {
	fclose (maskfile);
	return 5; /* I/O error while reading */
      }
      if (feof (maskfile))
	break;

      { /* strip trailing newline */
      char* end =3D maskline + strlen (maskline) - 1;
        while (end >=3D maskline && (*end =3D=3D '\r' || *end =3D=3D =
'\n'))
	  *end =3D '\0';
      }
      expand_mask (maskline);
      if (*maskline =3D=3D '\0')
	continue;
      if (last_entry =3D=3D NULL)
      {
	mask_entries =3D (struct mask_entry*) malloc (sizeof (struct =
mask_entry));
	last_entry =3D mask_entries;
      }
      else
      {
	last_entry->next =3D (struct mask_entry*) malloc (sizeof (struct =
mask_entry));
	last_entry =3D last_entry->next;
      }
      last_entry->mask =3D (char*) malloc (strlen (maskline) + 1);
      strcpy (last_entry->mask, maskline);
      last_entry->next =3D NULL;
    }

    fclose (maskfile);
    maskfile_modtime =3D info.st_mtime;
  }
  return 0;
}

static int
decode_mask(const char *datespec, const char *datemask, struct tm *dest)
{
  time_t now_seconds =3D time (NULL);
  struct tm *now =3D localtime (&now_seconds);
  const char *spec =3D datespec;
  const char *mask =3D datemask;
  /* flags (FIXME: better a single bitfield for all format flags?) */
  int century_seen =3D 0;

  /* Paranoia */
  if (datespec =3D=3D NULL || datemask =3D=3D NULL || dest =3D=3D NULL)
    return 0;

  /* start with a clean slate */
  getdate_err =3D 0;
  dest->tm_sec =3D -1;
  dest->tm_min =3D -1;
  dest->tm_hour =3D -1;
  dest->tm_mday =3D -1;
  dest->tm_mon =3D -1;
  dest->tm_year =3D -1;
  dest->tm_wday =3D -1;
  dest->tm_yday =3D -1;
  dest->tm_isdst =3D -1;
  dest->tm_gmtoff =3D 0;
  dest->tm_zone =3D NULL;

  /* Skip whitespace */
  while (isspace (*mask))
    ++mask;
  while (isspace (*spec))
    ++spec;

  while (*mask)
  {
    if (*mask =3D=3D '%')
    {
      char numbuf[5] =3D { "" };
      int i =3D 0;

      ++mask;
      /* Note that the c, D, r, R, T, x, and X formats are already =
expanded */
      switch (*mask)
      {
        case '%':
	  if (*spec !=3D '%')
	    return 0;
	  ++spec;
	  break;
        case 'a': /* abbreviated weekday name */
	  for (i =3D 0; i < 7; ++i)
	  {
	  const size_t len =3D strlen (afmt[i]);
	    if (strncasecmp (spec, afmt[i], len) =3D=3D 0)
	    {
	      spec +=3D len;
	      break;
	    }
	  }
	  if (i =3D=3D 7)
	    return 0;
	  dest->tm_wday =3D i;
	  break;
        case 'A': /* full weekday name */
	  for (i =3D 0; i < 7; ++i)
	  {
	  const size_t len =3D strlen (Afmt[i]);
	    if (strncasecmp (spec, Afmt[i], len) =3D=3D 0)
	    {
	      spec +=3D len;
	      break;
	    }
	  }
	  if (i =3D=3D 7)
	    return 0;
	  dest->tm_wday =3D i;
	  break;
        case 'b': /* abbreviated month name */
        case 'h': /* same */
	  for (i =3D 0; i < 12; ++i)
	  {
	  const size_t len =3D strlen (bfmt[i]);
	    if (strncasecmp (spec, bfmt[i], len) =3D=3D 0)
	    {
	      spec +=3D len;
	      break;
	    }
	  }
	  if (i =3D=3D 12)
	    return 0;
	  dest->tm_mon =3D i;
	  break;
        case 'B': /* full month name */
	  for (i =3D 0; i < 12; ++i)
	  {
	  const size_t len =3D strlen (Bfmt[i]);
	    if (strncasecmp (spec, Bfmt[i], len) =3D=3D 0)
	    {
	      spec +=3D len;
	      break;
	    }
	  }
	  if (i =3D=3D 12)
	    return 0;
	  dest->tm_mon =3D i;
	  break;
        case 'C': /* century number (optional leading 0) */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* lowest possible is 19 */
	  if (i < 19)
	    getdate_err =3D 8; /* Invalid input */
	  else
	  {
	    if (dest->tm_year =3D=3D -1)
	      dest->tm_year =3D 0;
	    dest->tm_year =3D (dest->tm_year % 100) + 100 * (i - 19);
	    century_seen =3D 1;
	  }
	  break;
        case 'd': /* day of month (optional leading 0) */
        case 'e': /* same */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* range is [1,31] */
	  if (i =3D=3D 0 || i > 31)
	    getdate_err =3D 8; /* Invalid input */
	  else
	    dest->tm_mday =3D i;
	  break;
        case 'H': /* hour (24-hour base) */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* range is [0,23] */
	  if (i > 23)
	    getdate_err =3D 8; /* Invalid input */
	  else
	    dest->tm_hour =3D i;
	  break;
        case 'I': /* hour (12-hour base) */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* range is [1,12] */
	  if (i =3D=3D 0 || i > 12)
	    getdate_err =3D 8; /* Invalid input */
	  else /* FIXME: what if %p was already seen? */
	    dest->tm_hour =3D i - 1;
	  break;
        case 'm': /* month number */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* range is [1,12] */
	  if (i =3D=3D 0 || i > 12)
	    getdate_err =3D 8; /* Invalid input */
	  else
	    dest->tm_mon =3D i - 1;
	  break;
        case 'M': /* minute */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* range is [0,59] */
	  if (i > 59)
	    getdate_err =3D 8; /* Invalid input */
	  else
	    dest->tm_min =3D i;
	  break;
        case 'n': /* a newline */
	  if (*spec !=3D '\n')
	    return 0;
	  ++spec;
	  break;
        case 'p': /* AM/PM (or local equivalent) */
	  printf ("am/pm =3D=3D %.2s?\n", spec);
	  if (strncasecmp (spec, "am", 2) =3D=3D 0)
	    spec +=3D 2;
	  else if (strncasecmp (spec, "pm", 2) =3D=3D 0)
	  {
	    spec +=3D 2;
	    dest->tm_hour +=3D 12;
	  }
	  else
	    return 0;
	  break;
        case 'S': /* second */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* range is [0,60] (60 for leap seconds) */
	  if (i > 60)
	    getdate_err =3D 8; /* Invalid input */
	  else
	    dest->tm_sec =3D i;
	  break;
        case 't': /* a tab */
	  if (*spec !=3D '\t')
	    return 0;
	  ++spec;
	  break;
        case 'w': /* weekday number */
	  if (!isdigit (*spec))
	    return 0;
	  dest->tm_wday =3D *spec++ - '0';
	  break;
        case 'y': /* year within century */
	  if (!isdigit (*spec))
	    return 0;
	  numbuf[0] =3D *spec++;
	  if (isdigit (*spec))
	    numbuf[1] =3D *spec++;
	  i =3D atoi (numbuf);
	  /* range is [0,99] */
	  if (i > 99)
	    getdate_err =3D 8; /* Invalid input */
	  else if (century_seen)
	  {
	    dest->tm_year -=3D (dest->tm_year % 100);
	    dest->tm_year +=3D i;
	  }
	  else
	  {
	    dest->tm_year =3D i;
	    if (i < 69)
	      dest->tm_year +=3D 100; /* 2000-2068 */
	  }
	  break;
        case 'Y': /* 4-digit year */
	  for (i =3D 0; i < 4; ++i)
	  {
	    if (!isdigit (*spec))
	      return 0;
	    numbuf[i] =3D *spec++;
	  }
	  i =3D atoi (numbuf);
	  /* range is [1900,...] */
	  if (i < 1900)
	    getdate_err =3D 8; /* Invalid input */
	  else
	  {
	    dest->tm_year =3D i - 1900;
	    century_seen =3D 1;
	  }
	  break;
        case 'Z': /* Timezone name or empty */
	  /* Only support current TZ for now */
	  if (now->tm_zone !=3D NULL)
	  {
	    size_t len =3D strlen (now->tm_zone);

	    if (strncasecmp (spec, now->tm_zone, len) =3D=3D 0)
	      spec +=3D len;
	    /* No need to set it here; it's done unconditionally below */
	  }
	  break;
        default:
	  /* Behaviour for this is undefined; just ignore this mask */
	  return 0;
      }
    }
    else
    {
      if (*spec =3D=3D *mask)
	++spec;
      else
	return 0; /* Match failed */
    }

    /* Advance */
    ++mask;

    /* Skip whitespace */
    while (isspace (*mask))
      ++mask;
    while (isspace (*spec))
      ++spec;
  }
  if (*spec || *mask)
    return 0;

  /* Now the tricky bit: filling out the structure */
  if (getdate_err =3D=3D 0)
  {
    int day_delta =3D 0;

    /* We only allow times in the current TZ, so copy the info */
    if (dest->tm_zone =3D=3D NULL)
      dest->tm_zone =3D now->tm_zone;

    /* if only weekday, first day in the future that matches it */
    if (dest->tm_mday =3D=3D -1 && dest->tm_wday !=3D -1)
      day_delta =3D (dest->tm_wday - now->tm_wday);

    /* if month but no year, first year in the future with that day & =
month,
       assuming day 1 if no day given */
    if (dest->tm_mon !=3D -1)
    {
      if (dest->tm_mday =3D=3D -1)
	dest->tm_mday =3D 1;
      if (dest->tm_year =3D=3D -1)
      {
	dest->tm_year =3D now->tm_year;
	if (dest->tm_mon < now->tm_mon ||
	    (dest->tm_mon =3D=3D now->tm_mon &&
	     (dest->tm_mday < now->tm_mday ||
	      (dest->tm_mday =3D=3D now->tm_mday &&
	       (dest->tm_hour < now->tm_hour ||
		(dest->tm_hour =3D=3D now->tm_hour &&
		 (dest->tm_mon < now->tm_mon ||
		  (dest->tm_mon =3D=3D now->tm_mon &&
		   (dest->tm_sec < now->tm_sec)))))))))
	  ++dest->tm_year;
      }
    }

    /* Missing time components: assume current time */
    if (dest->tm_hour =3D=3D -1)
      dest->tm_hour =3D now->tm_hour;
    if (dest->tm_min =3D=3D -1)
      dest->tm_min =3D now->tm_min;
    if (dest->tm_sec =3D=3D -1)
      dest->tm_sec =3D now->tm_sec;

    /* If no date, first date in the future with correct time */
    if (dest->tm_mday =3D=3D -1 && dest->tm_mon =3D=3D -1 && =
dest->tm_year =3D=3D -1)
    {
      dest->tm_mday =3D now->tm_mday;
      dest->tm_wday =3D now->tm_wday;
      dest->tm_yday =3D now->tm_yday;
      dest->tm_mon =3D now->tm_mon;
      dest->tm_year =3D now->tm_year;
      if (dest->tm_hour < now->tm_hour ||
	  (dest->tm_hour =3D=3D now->tm_hour &&
	   (dest->tm_mon < now->tm_mon ||
	    (dest->tm_mon =3D=3D now->tm_mon &&
	     (dest->tm_sec < now->tm_sec)))))
	++day_delta;
    }

    /* Anything still blank? */
    if (dest->tm_mday =3D=3D -1)
      dest->tm_mday =3D now->tm_mday;
    if (dest->tm_mon =3D=3D -1)
      dest->tm_mon =3D now->tm_mon;
    if (dest->tm_year =3D=3D -1)
      dest->tm_year =3D now->tm_year;

    { /* Now the final validity check */
    time_t numeric_dest =3D mktime (dest);
    struct tm * dest_checked =3D NULL;

      if (numeric_dest < 0)
      {
	getdate_err =3D 8;
	return 1;
      }
      numeric_dest +=3D (day_delta * 24 * 60 * 60);
      dest_checked =3D gmtime (&numeric_dest);
      numeric_dest +=3D now->tm_gmtoff;
      dest_checked =3D gmtime (&numeric_dest);
      if (dest_checked =3D=3D NULL)
      {
	getdate_err =3D 8;
	return 1;
      }
      memcpy (dest, dest_checked, sizeof *dest);
      return 1;
    }
  }

  return 1;
}

static int
match_and_decode_mask(const char *datespec, struct tm *dest)
{
  struct mask_entry* e =3D mask_entries;

  while (e !=3D NULL) {
    if (decode_mask (datespec, e->mask, dest))
      return getdate_err;
    e =3D e->next;
  }

  return 7; /* No matching line */
}

struct tm *
getdate(const char * datespec)
{
static struct tm decoded_time;
  memset (&decoded_time, 0, sizeof decoded_time);
  getdate_err =3D maybe_read_maskfile ();
  if (getdate_err !=3D 0)
    return NULL;
  getdate_err =3D match_and_decode_mask (datespec, &decoded_time);
  return ((getdate_err =3D=3D 0) ? &decoded_time : NULL);
}

#ifdef TEST

int
main(int argc, char** argv)
{
  char strftbuf[256];
  int i =3D 1;
  for (; i < argc; ++i)
  {
    struct tm* t =3D getdate (argv[i]);
    if (t =3D=3D NULL)
      printf ("getdate(%s) failed with code %d\n", argv[i], =
getdate_err);
    else
      printf ("getdate(%s) succeeded and returned %s", argv[i], asctime =
(t));
  }
  return 0;
}

#endif

------=_NextPart_000_0007_01C1238F.42ECDF80--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019