Initial revision
authorJim Meyering <jim@meyering.net>
Sun, 1 Nov 1992 05:44:30 +0000 (05:44 +0000)
committerJim Meyering <jim@meyering.net>
Sun, 1 Nov 1992 05:44:30 +0000 (05:44 +0000)
18 files changed:
lib/alloca.c [new file with mode: 0644]
lib/basename.c [new file with mode: 0644]
lib/error.c [new file with mode: 0644]
lib/getdate.y [new file with mode: 0644]
lib/gethostname.c [new file with mode: 0644]
lib/getopt.c [new file with mode: 0644]
lib/getopt.h [new file with mode: 0644]
lib/getopt1.c [new file with mode: 0644]
lib/getugroups.c [new file with mode: 0644]
lib/getusershell.c [new file with mode: 0644]
lib/mktime.c [new file with mode: 0644]
lib/posixtm.y [new file with mode: 0644]
lib/putenv.c [new file with mode: 0644]
lib/stime.c [new file with mode: 0644]
lib/strcspn.c [new file with mode: 0644]
lib/strftime.c [new file with mode: 0644]
lib/strtod.c [new file with mode: 0644]
lib/xmalloc.c [new file with mode: 0644]

diff --git a/lib/alloca.c b/lib/alloca.c
new file mode 100644 (file)
index 0000000..c1ff222
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+       alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+
+       last edit:      86/05/30        rms
+          include config.h, since on VMS it renames some symbols.
+          Use xmalloc instead of malloc.
+
+       This implementation of the PWB library alloca() function,
+       which is used to allocate space off the run-time stack so
+       that it is automatically reclaimed upon procedure exit, 
+       was inspired by discussions with J. Q. Johnson of Cornell.
+
+       It should work under any C implementation that uses an
+       actual procedure stack (as opposed to a linked list of
+       frames).  There are some preprocessor constants that can
+       be defined when compiling for your specific system, for
+       improved efficiency; however, the defaults should be okay.
+
+       The general concept of this implementation is to keep
+       track of all alloca()-allocated blocks, and reclaim any
+       that are found to be deeper in the stack than the current
+       invocation.  This heuristic does not reclaim storage as
+       soon as it becomes invalid, but it will do so eventually.
+
+       As a special case, alloca(0) reclaims storage without
+       allocating any.  It is a good idea to use alloca(0) in
+       your main control loop, etc. to force garbage collection.
+*/
+#ifndef lint
+static char    SCCSid[] = "@(#)alloca.c        1.1";   /* for the "what" utility */
+#endif
+
+#ifdef emacs
+#include "config.h"
+#ifdef static
+/* actually, only want this if static is defined as ""
+   -- this is for usg, in which emacs must undefine static
+   in order to make unexec workable
+   */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+#ifndef alloca  /* If compiling with GCC, this file's not needed.  */
+
+#ifdef __STDC__
+typedef void   *pointer;               /* generic pointer type */
+#else
+typedef char   *pointer;               /* generic pointer type */
+#endif
+
+#define        NULL    0                       /* null pointer constant */
+
+extern void    free();
+extern pointer xmalloc();
+
+/*
+       Define STACK_DIRECTION if you know the direction of stack
+       growth for your system; otherwise it will be automatically
+       deduced at run-time.
+
+       STACK_DIRECTION > 0 => grows toward higher addresses
+       STACK_DIRECTION < 0 => grows toward lower addresses
+       STACK_DIRECTION = 0 => direction of growth unknown
+*/
+
+#ifndef STACK_DIRECTION
+#define        STACK_DIRECTION 0               /* direction unknown */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define        STACK_DIR       STACK_DIRECTION /* known at compile-time */
+
+#else  /* STACK_DIRECTION == 0; need run-time code */
+
+static int     stack_dir;              /* 1 or -1 once known */
+#define        STACK_DIR       stack_dir
+
+static void
+find_stack_direction (/* void */)
+{
+  static char  *addr = NULL;   /* address of first
+                                  `dummy', once known */
+  auto char    dummy;          /* to get stack address */
+
+  if (addr == NULL)
+    {                          /* initial entry */
+      addr = &dummy;
+
+      find_stack_direction (); /* recurse once */
+    }
+  else                         /* second entry */
+    if (&dummy > addr)
+      stack_dir = 1;           /* stack grew upward */
+    else
+      stack_dir = -1;          /* stack grew downward */
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/*
+       An "alloca header" is used to:
+       (a) chain together all alloca()ed blocks;
+       (b) keep track of stack depth.
+
+       It is very important that sizeof(header) agree with malloc()
+       alignment chunk size.  The following default should work okay.
+*/
+
+#ifndef        ALIGN_SIZE
+#define        ALIGN_SIZE      sizeof(double)
+#endif
+
+typedef union hdr
+{
+  char align[ALIGN_SIZE];      /* to force sizeof(header) */
+  struct
+    {
+      union hdr *next;         /* for chaining headers */
+      char *deep;              /* for stack depth measure */
+    } h;
+} header;
+
+/*
+       alloca( size ) returns a pointer to at least `size' bytes of
+       storage which will be automatically reclaimed upon exit from
+       the procedure that called alloca().  Originally, this space
+       was supposed to be taken from the current stack frame of the
+       caller, but that method cannot be made to work for some
+       implementations of C, for example under Gould's UTX/32.
+*/
+
+static header *last_alloca_header = NULL; /* -> last alloca header */
+
+pointer
+alloca (size)                  /* returns pointer to storage */
+     unsigned  size;           /* # bytes to allocate */
+{
+  auto char    probe;          /* probes stack depth: */
+  register char        *depth = &probe;
+
+#if STACK_DIRECTION == 0
+  if (STACK_DIR == 0)          /* unknown growth direction */
+    find_stack_direction ();
+#endif
+
+                               /* Reclaim garbage, defined as all alloca()ed storage that
+                                  was allocated from deeper in the stack than currently. */
+
+  {
+    register header    *hp;    /* traverses linked list */
+
+    for (hp = last_alloca_header; hp != NULL;)
+      if ((STACK_DIR > 0 && hp->h.deep > depth)
+         || (STACK_DIR < 0 && hp->h.deep < depth))
+       {
+         register header       *np = hp->h.next;
+
+         free ((pointer) hp);  /* collect garbage */
+
+         hp = np;              /* -> next header */
+       }
+      else
+       break;                  /* rest are not deeper */
+
+    last_alloca_header = hp;   /* -> last valid storage */
+  }
+
+  if (size == 0)
+    return NULL;               /* no allocation required */
+
+  /* Allocate combined header + user data storage. */
+
+  {
+    register pointer   new = xmalloc (sizeof (header) + size);
+    /* address of header */
+
+    ((header *)new)->h.next = last_alloca_header;
+    ((header *)new)->h.deep = depth;
+
+    last_alloca_header = (header *)new;
+
+    /* User storage begins just after header. */
+
+    return (pointer)((char *)new + sizeof(header));
+  }
+}
+
+#endif /* no alloca */
diff --git a/lib/basename.c b/lib/basename.c
new file mode 100644 (file)
index 0000000..b8e7e1f
--- /dev/null
@@ -0,0 +1,35 @@
+/* basename.c -- return the last element in a path
+   Copyright (C) 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#define rindex strrchr
+#else
+#include <strings.h>
+#endif
+
+/* Return NAME with any leading path stripped off.  */
+
+char *
+basename (name)
+     char *name;
+{
+  char *base;
+
+  base = rindex (name, '/');
+  return base ? base + 1 : name;
+}
diff --git a/lib/error.c b/lib/error.c
new file mode 100644 (file)
index 0000000..7e61f15
--- /dev/null
@@ -0,0 +1,105 @@
+/* error.c -- error handler for noninteractive utilities
+   Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie.  */
+
+#include <stdio.h>
+
+#ifdef HAVE_VPRINTF
+
+#if __STDC__
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else /* !__STDC__ */
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif /* !__STDC__ */
+
+#else /* !HAVE_VPRINTF */
+
+#ifdef HAVE_DOPRNT
+#define va_alist args
+#define va_dcl int args;
+#else /* !HAVE_DOPRNT */
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif /* !HAVE_DOPRNT */
+
+#endif /* !HAVE_VPRINTF */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* !STDC_HEADERS */
+void exit ();
+#endif /* !STDC_HEADERS */
+
+#ifndef HAVE_STRERROR
+static char *
+private_strerror (errnum)
+     int errnum;
+{
+  extern char *sys_errlist[];
+  extern int sys_nerr;
+
+  if (errnum > 0 && errnum <= sys_nerr)
+    return sys_errlist[errnum];
+  return "Unknown system error";
+}
+#define strerror private_strerror
+#endif /* !HAVE_STRERROR */
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+   format string with optional args.
+   If ERRNUM is nonzero, print its corresponding system error message.
+   Exit with status STATUS if it is nonzero.  */
+/* VARARGS */
+void
+#if defined (HAVE_VPRINTF) && __STDC__
+error (int status, int errnum, char *message, ...)
+#else /* !HAVE_VPRINTF or !__STDC__ */
+error (status, errnum, message, va_alist)
+     int status;
+     int errnum;
+     char *message;
+     va_dcl
+#endif /* !HAVE_VPRINTF or !__STDC__ */
+{
+  extern char *program_name;
+#ifdef HAVE_VPRINTF
+  va_list args;
+#endif /* HAVE_VPRINTF */
+
+  fprintf (stderr, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
+  VA_START (args, message);
+  vfprintf (stderr, message, args);
+  va_end (args);
+#else /* !HAVE_VPRINTF */
+#ifdef HAVE_DOPRNT
+  _doprnt (message, &args, stderr);
+#else /* !HAVE_DOPRNT */
+  fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif /* !HAVE_DOPRNT */
+#endif /* !HAVE_VPRINTF */
+  if (errnum)
+    fprintf (stderr, ": %s", strerror (errnum));
+  putc ('\n', stderr);
+  fflush (stderr);
+  if (status)
+    exit (status);
+}
diff --git a/lib/getdate.y b/lib/getdate.y
new file mode 100644 (file)
index 0000000..bff1a9b
--- /dev/null
@@ -0,0 +1,965 @@
+%{
+/* $Revision: 2.1 $
+**
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**  send any email to Rich.
+**
+**  This grammar has eight shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef sparc
+#include <alloca.h>
+#else
+#ifdef _AIX /* for Bison */
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+   current time zone checks various CPP symbols to see if special
+   tricks are need, but defaults to using the gettimeofday system call.
+   Include <sys/time.h> if that will be used.  */
+
+#if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
+#include <sys/time.h>
+#endif
+
+#if    defined(vms)
+
+#include <types.h>
+#include <time.h>
+
+#else
+
+#include <sys/types.h>
+
+#if    defined(USG) || !defined(HAVE_FTIME)
+/*
+**  If you need to do a tzset() call to set the
+**  timezone, and don't have ftime().
+*/
+struct timeb {
+    time_t             time;           /* Seconds since the epoch      */
+    unsigned short     millitm;        /* Field not used               */
+    short              timezone;
+    short              dstflag;        /* Field not used               */
+};
+
+#else
+
+#include <sys/timeb.h>
+
+#endif /* defined(USG) && !defined(HAVE_FTIME) */
+
+#if    defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
+#include <sys/time.h>
+#else
+#if defined(_AIX)
+#include <sys/time.h>
+#endif
+#include <time.h>
+#endif /* defined(BSD4_2) */
+
+#endif /* defined(vms) */
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+#if sgi
+#undef timezone
+#endif
+
+extern struct tm       *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+#if    !defined(lint) && !defined(SABER)
+static char RCS[] =
+       "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
+#endif /* !defined(lint) && !defined(SABER) */
+
+
+#define EPOCH          1970
+#define HOUR(x)                ((time_t)(x) * 60)
+#define SECSPERDAY     (24L * 60L * 60L)
+
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    char       *name;
+    int                type;
+    time_t     value;
+} TABLE;
+
+
+/*
+**  Daylight-savings mode:  on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+    DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static char    *yyInput;
+static DSTMODE yyDSTmode;
+static time_t  yyDayOrdinal;
+static time_t  yyDayNumber;
+static int     yyHaveDate;
+static int     yyHaveDay;
+static int     yyHaveRel;
+static int     yyHaveTime;
+static int     yyHaveZone;
+static time_t  yyTimezone;
+static time_t  yyDay;
+static time_t  yyHour;
+static time_t  yyMinutes;
+static time_t  yyMonth;
+static time_t  yySeconds;
+static time_t  yyYear;
+static MERIDIAN        yyMeridian;
+static time_t  yyRelMonth;
+static time_t  yyRelSeconds;
+
+%}
+
+%union {
+    time_t             Number;
+    enum _MERIDIAN     Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type  <Number>        tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type  <Number>        tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type  <Meridian>      tMERIDIAN o_merid
+
+%%
+
+spec   : /* NULL */
+       | spec item
+       ;
+
+item   : time {
+           yyHaveTime++;
+       }
+       | zone {
+           yyHaveZone++;
+       }
+       | date {
+           yyHaveDate++;
+       }
+       | day {
+           yyHaveDay++;
+       }
+       | rel {
+           yyHaveRel++;
+       }
+       | number
+       ;
+
+time   : tUNUMBER tMERIDIAN {
+           yyHour = $1;
+           yyMinutes = 0;
+           yySeconds = 0;
+           yyMeridian = $2;
+       }
+       | tUNUMBER ':' tUNUMBER o_merid {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = 0;
+           yyMeridian = $4;
+       }
+       | tUNUMBER ':' tUNUMBER tSNUMBER {
+           yyHour = $1;
+           yyMinutes = $3;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+       }
+       | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = $5;
+           yyMeridian = $6;
+       }
+       | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = $5;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+       }
+       ;
+
+zone   : tZONE {
+           yyTimezone = $1;
+           yyDSTmode = DSToff;
+       }
+       | tDAYZONE {
+           yyTimezone = $1;
+           yyDSTmode = DSTon;
+       }
+       |
+         tZONE tDST {
+           yyTimezone = $1;
+           yyDSTmode = DSTon;
+       }
+       ;
+
+day    : tDAY {
+           yyDayOrdinal = 1;
+           yyDayNumber = $1;
+       }
+       | tDAY ',' {
+           yyDayOrdinal = 1;
+           yyDayNumber = $1;
+       }
+       | tUNUMBER tDAY {
+           yyDayOrdinal = $1;
+           yyDayNumber = $2;
+       }
+       ;
+
+date   : tUNUMBER '/' tUNUMBER {
+           yyMonth = $1;
+           yyDay = $3;
+       }
+       | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+           yyMonth = $1;
+           yyDay = $3;
+           yyYear = $5;
+       }
+       | tUNUMBER tSNUMBER tSNUMBER {
+           /* ISO 8601 format.  yyyy-mm-dd.  */
+           yyYear = $1;
+           yyMonth = -$2;
+           yyDay = -$3;
+       }
+       | tMONTH tUNUMBER {
+           yyMonth = $1;
+           yyDay = $2;
+       }
+       | tMONTH tUNUMBER ',' tUNUMBER {
+           yyMonth = $1;
+           yyDay = $2;
+           yyYear = $4;
+       }
+       | tUNUMBER tMONTH {
+           yyMonth = $2;
+           yyDay = $1;
+       }
+       | tUNUMBER tMONTH tUNUMBER {
+           yyMonth = $2;
+           yyDay = $1;
+           yyYear = $3;
+       }
+       ;
+
+rel    : relunit tAGO {
+           yyRelSeconds = -yyRelSeconds;
+           yyRelMonth = -yyRelMonth;
+       }
+       | relunit
+       ;
+
+relunit        : tUNUMBER tMINUTE_UNIT {
+           yyRelSeconds += $1 * $2 * 60L;
+       }
+       | tSNUMBER tMINUTE_UNIT {
+           yyRelSeconds += $1 * $2 * 60L;
+       }
+       | tMINUTE_UNIT {
+           yyRelSeconds += $1 * 60L;
+       }
+       | tSNUMBER tSEC_UNIT {
+           yyRelSeconds += $1;
+       }
+       | tUNUMBER tSEC_UNIT {
+           yyRelSeconds += $1;
+       }
+       | tSEC_UNIT {
+           yyRelSeconds++;
+       }
+       | tSNUMBER tMONTH_UNIT {
+           yyRelMonth += $1 * $2;
+       }
+       | tUNUMBER tMONTH_UNIT {
+           yyRelMonth += $1 * $2;
+       }
+       | tMONTH_UNIT {
+           yyRelMonth += $1;
+       }
+       ;
+
+number : tUNUMBER {
+           if (yyHaveTime && yyHaveDate && !yyHaveRel)
+               yyYear = $1;
+           else {
+               if($1>10000) {
+                   time_t date_part;
+
+                   date_part= $1/10000;
+                   yyHaveDate++;
+                   yyDay= (date_part)%100;
+                   yyMonth= (date_part/100)%100;
+                   yyYear = date_part/10000;
+               } 
+               yyHaveTime++;
+               if ($1 < 100) {
+                   yyHour = $1;
+                   yyMinutes = 0;
+               }
+               else {
+                   yyHour = $1 / 100;
+                   yyMinutes = $1 % 100;
+               }
+               yySeconds = 0;
+               yyMeridian = MER24;
+           }
+       }
+       ;
+
+o_merid        : /* NULL */ {
+           $$ = MER24;
+       }
+       | tMERIDIAN {
+           $$ = $1;
+       }
+       ;
+
+%%
+
+/* Month and day table. */
+static TABLE   MonthDayTable[] = {
+    { "january",       tMONTH,  1 },
+    { "february",      tMONTH,  2 },
+    { "march",         tMONTH,  3 },
+    { "april",         tMONTH,  4 },
+    { "may",           tMONTH,  5 },
+    { "june",          tMONTH,  6 },
+    { "july",          tMONTH,  7 },
+    { "august",                tMONTH,  8 },
+    { "september",     tMONTH,  9 },
+    { "sept",          tMONTH,  9 },
+    { "october",       tMONTH, 10 },
+    { "november",      tMONTH, 11 },
+    { "december",      tMONTH, 12 },
+    { "sunday",                tDAY, 0 },
+    { "monday",                tDAY, 1 },
+    { "tuesday",       tDAY, 2 },
+    { "tues",          tDAY, 2 },
+    { "wednesday",     tDAY, 3 },
+    { "wednes",                tDAY, 3 },
+    { "thursday",      tDAY, 4 },
+    { "thur",          tDAY, 4 },
+    { "thurs",         tDAY, 4 },
+    { "friday",                tDAY, 5 },
+    { "saturday",      tDAY, 6 },
+    { NULL }
+};
+
+/* Time units table. */
+static TABLE   UnitsTable[] = {
+    { "year",          tMONTH_UNIT,    12 },
+    { "month",         tMONTH_UNIT,    1 },
+    { "fortnight",     tMINUTE_UNIT,   14 * 24 * 60 },
+    { "week",          tMINUTE_UNIT,   7 * 24 * 60 },
+    { "day",           tMINUTE_UNIT,   1 * 24 * 60 },
+    { "hour",          tMINUTE_UNIT,   60 },
+    { "minute",                tMINUTE_UNIT,   1 },
+    { "min",           tMINUTE_UNIT,   1 },
+    { "second",                tSEC_UNIT,      1 },
+    { "sec",           tSEC_UNIT,      1 },
+    { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE   OtherTable[] = {
+    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
+    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
+    { "today",         tMINUTE_UNIT,   0 },
+    { "now",           tMINUTE_UNIT,   0 },
+    { "last",          tUNUMBER,       -1 },
+    { "this",          tMINUTE_UNIT,   0 },
+    { "next",          tUNUMBER,       2 },
+    { "first",         tUNUMBER,       1 },
+/*  { "second",                tUNUMBER,       2 }, */
+    { "third",         tUNUMBER,       3 },
+    { "fourth",                tUNUMBER,       4 },
+    { "fifth",         tUNUMBER,       5 },
+    { "sixth",         tUNUMBER,       6 },
+    { "seventh",       tUNUMBER,       7 },
+    { "eighth",                tUNUMBER,       8 },
+    { "ninth",         tUNUMBER,       9 },
+    { "tenth",         tUNUMBER,       10 },
+    { "eleventh",      tUNUMBER,       11 },
+    { "twelfth",       tUNUMBER,       12 },
+    { "ago",           tAGO,   1 },
+    { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE   TimezoneTable[] = {
+    { "gmt",   tZONE,     HOUR( 0) },  /* Greenwich Mean */
+    { "ut",    tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
+    { "utc",   tZONE,     HOUR( 0) },
+    { "wet",   tZONE,     HOUR( 0) },  /* Western European */
+    { "bst",   tDAYZONE,  HOUR( 0) },  /* British Summer */
+    { "wat",   tZONE,     HOUR( 1) },  /* West Africa */
+    { "at",    tZONE,     HOUR( 2) },  /* Azores */
+#if    0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",   tZONE,     HOUR( 3) },  /* Brazil Standard */
+    { "gst",   tZONE,     HOUR( 3) },  /* Greenland Standard */
+#endif
+#if 0
+    { "nft",   tZONE,     HOUR(3.5) }, /* Newfoundland */
+    { "nst",   tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
+    { "ndt",   tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+    { "ast",   tZONE,     HOUR( 4) },  /* Atlantic Standard */
+    { "adt",   tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
+    { "est",   tZONE,     HOUR( 5) },  /* Eastern Standard */
+    { "edt",   tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
+    { "cst",   tZONE,     HOUR( 6) },  /* Central Standard */
+    { "cdt",   tDAYZONE,  HOUR( 6) },  /* Central Daylight */
+    { "mst",   tZONE,     HOUR( 7) },  /* Mountain Standard */
+    { "mdt",   tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
+    { "pst",   tZONE,     HOUR( 8) },  /* Pacific Standard */
+    { "pdt",   tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
+    { "yst",   tZONE,     HOUR( 9) },  /* Yukon Standard */
+    { "ydt",   tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
+    { "hst",   tZONE,     HOUR(10) },  /* Hawaii Standard */
+    { "hdt",   tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
+    { "cat",   tZONE,     HOUR(10) },  /* Central Alaska */
+    { "ahst",  tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
+    { "nt",    tZONE,     HOUR(11) },  /* Nome */
+    { "idlw",  tZONE,     HOUR(12) },  /* International Date Line West */
+    { "cet",   tZONE,     -HOUR(1) },  /* Central European */
+    { "met",   tZONE,     -HOUR(1) },  /* Middle European */
+    { "mewt",  tZONE,     -HOUR(1) },  /* Middle European Winter */
+    { "mest",  tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
+    { "swt",   tZONE,     -HOUR(1) },  /* Swedish Winter */
+    { "sst",   tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
+    { "fwt",   tZONE,     -HOUR(1) },  /* French Winter */
+    { "fst",   tDAYZONE,  -HOUR(1) },  /* French Summer */
+    { "eet",   tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
+    { "bt",    tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
+#endif
+    { "zp4",   tZONE,     -HOUR(4) },  /* USSR Zone 3 */
+    { "zp5",   tZONE,     -HOUR(5) },  /* USSR Zone 4 */
+#if 0
+    { "ist",   tZONE,     -HOUR(5.5) },/* Indian Standard */
+#endif
+    { "zp6",   tZONE,     -HOUR(6) },  /* USSR Zone 5 */
+#if    0
+    /* For completeness.  NST is also Newfoundland Stanard, and SST is
+     * also Swedish Summer. */
+    { "nst",   tZONE,     -HOUR(6.5) },/* North Sumatra */
+    { "sst",   tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+    { "wast",  tZONE,     -HOUR(7) },  /* West Australian Standard */
+    { "wadt",  tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
+#if 0
+    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",   tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
+    { "jst",   tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",  tZONE,     -HOUR(9.5) },/* Central Australian Standard */
+    { "cadt",  tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+    { "east",  tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
+    { "eadt",  tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
+    { "gst",   tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+    { "nzt",   tZONE,     -HOUR(12) }, /* New Zealand */
+    { "nzst",  tZONE,     -HOUR(12) }, /* New Zealand Standard */
+    { "nzdt",  tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
+    { "idle",  tZONE,     -HOUR(12) }, /* International Date Line East */
+    {  NULL  }
+};
+
+/* Military timezone table. */
+static TABLE   MilitaryTable[] = {
+    { "a",     tZONE,  HOUR(  1) },
+    { "b",     tZONE,  HOUR(  2) },
+    { "c",     tZONE,  HOUR(  3) },
+    { "d",     tZONE,  HOUR(  4) },
+    { "e",     tZONE,  HOUR(  5) },
+    { "f",     tZONE,  HOUR(  6) },
+    { "g",     tZONE,  HOUR(  7) },
+    { "h",     tZONE,  HOUR(  8) },
+    { "i",     tZONE,  HOUR(  9) },
+    { "k",     tZONE,  HOUR( 10) },
+    { "l",     tZONE,  HOUR( 11) },
+    { "m",     tZONE,  HOUR( 12) },
+    { "n",     tZONE,  HOUR(- 1) },
+    { "o",     tZONE,  HOUR(- 2) },
+    { "p",     tZONE,  HOUR(- 3) },
+    { "q",     tZONE,  HOUR(- 4) },
+    { "r",     tZONE,  HOUR(- 5) },
+    { "s",     tZONE,  HOUR(- 6) },
+    { "t",     tZONE,  HOUR(- 7) },
+    { "u",     tZONE,  HOUR(- 8) },
+    { "v",     tZONE,  HOUR(- 9) },
+    { "w",     tZONE,  HOUR(-10) },
+    { "x",     tZONE,  HOUR(-11) },
+    { "y",     tZONE,  HOUR(-12) },
+    { "z",     tZONE,  HOUR(  0) },
+    { NULL }
+};
+
+\f
+
+
+/* ARGSUSED */
+int
+yyerror(s)
+    char       *s;
+{
+  return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+{
+    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+       return -1;
+    switch (Meridian) {
+    case MER24:
+       if (Hours < 0 || Hours > 23)
+           return -1;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERam:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERpm:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+    }
+    /* NOTREACHED */
+}
+
+
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+    time_t     Month;
+    time_t     Day;
+    time_t     Year;
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+    DSTMODE    DSTmode;
+{
+    static int DaysInMonth[12] = {
+       31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    time_t     tod;
+    time_t     Julian;
+    int                i;
+
+    if (Year < 0)
+       Year = -Year;
+    if (Year < 100)
+       Year += 1900;
+    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+                   ? 29 : 28;
+    if (Year < EPOCH || Year > 1999
+     || Month < 1 || Month > 12
+     /* Lint fluff:  "conversion from long may lose accuracy" */
+     || Day < 1 || Day > DaysInMonth[(int)--Month])
+       return -1;
+
+    for (Julian = Day - 1, i = 0; i < Month; i++)
+       Julian += DaysInMonth[i];
+    for (i = EPOCH; i < Year; i++)
+       Julian += 365 + (i % 4 == 0);
+    Julian *= SECSPERDAY;
+    Julian += yyTimezone * 60L;
+    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+       return -1;
+    Julian += tod;
+    if (DSTmode == DSTon
+     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+       Julian -= 60 * 60;
+    return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+    time_t     Start;
+    time_t     Future;
+{
+    time_t     StartDay;
+    time_t     FutureDay;
+
+    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+    time_t     Start;
+    time_t     DayOrdinal;
+    time_t     DayNumber;
+{
+    struct tm  *tm;
+    time_t     now;
+
+    now = Start;
+    tm = localtime(&now);
+    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+    return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+    time_t     Start;
+    time_t     RelMonth;
+{
+    struct tm  *tm;
+    time_t     Month;
+    time_t     Year;
+
+    if (RelMonth == 0)
+       return 0;
+    tm = localtime(&Start);
+    Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+    Year = Month / 12;
+    Month = Month % 12 + 1;
+    return DSTcorrect(Start,
+           Convert(Month, (time_t)tm->tm_mday, Year,
+               (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+               MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+    char               *buff;
+{
+    register char      *p;
+    register char      *q;
+    register TABLE     *tp;
+    int                        i;
+    int                        abbrev;
+
+    /* Make it lowercase. */
+    for (p = buff; *p; p++)
+       if (isupper(*p))
+           *p = tolower(*p);
+
+    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+       yylval.Meridian = MERam;
+       return tMERIDIAN;
+    }
+    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+       yylval.Meridian = MERpm;
+       return tMERIDIAN;
+    }
+
+    /* See if we have an abbreviation for a month. */
+    if (strlen(buff) == 3)
+       abbrev = 1;
+    else if (strlen(buff) == 4 && buff[3] == '.') {
+       abbrev = 1;
+       buff[3] = '\0';
+    }
+    else
+       abbrev = 0;
+
+    for (tp = MonthDayTable; tp->name; tp++) {
+       if (abbrev) {
+           if (strncmp(buff, tp->name, 3) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       }
+       else if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+    }
+
+    for (tp = TimezoneTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    if (strcmp(buff, "dst") == 0) 
+       return tDST;
+
+    for (tp = UnitsTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Strip off any plural and try the units table again. */
+    i = strlen(buff) - 1;
+    if (buff[i] == 's') {
+       buff[i] = '\0';
+       for (tp = UnitsTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       buff[i] = 's';          /* Put back for "this" in OtherTable. */
+    }
+
+    for (tp = OtherTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Military timezones. */
+    if (buff[1] == '\0' && isalpha(*buff)) {
+       for (tp = MilitaryTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+    }
+
+    /* Drop out any periods and try the timezone table again. */
+    for (i = 0, p = q = buff; *q; q++)
+       if (*q != '.')
+           *p++ = *q;
+       else
+           i++;
+    *p = '\0';
+    if (i)
+       for (tp = TimezoneTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+
+    return tID;
+}
+
+
+int
+yylex()
+{
+    register char      c;
+    register char      *p;
+    char               buff[20];
+    int                        Count;
+    int                        sign;
+
+    for ( ; ; ) {
+       while (isspace(*yyInput))
+           yyInput++;
+
+       if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+           if (c == '-' || c == '+') {
+               sign = c == '-' ? -1 : 1;
+               if (!isdigit(*++yyInput))
+                   /* skip the '-' sign */
+                   continue;
+           }
+           else
+               sign = 0;
+           for (yylval.Number = 0; isdigit(c = *yyInput++); )
+               yylval.Number = 10 * yylval.Number + c - '0';
+           yyInput--;
+           if (sign < 0)
+               yylval.Number = -yylval.Number;
+           return sign ? tSNUMBER : tUNUMBER;
+       }
+       if (isalpha(c)) {
+           for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+               if (p < &buff[sizeof buff - 1])
+                   *p++ = c;
+           *p = '\0';
+           yyInput--;
+           return LookupWord(buff);
+       }
+       if (c != '(')
+           return *yyInput++;
+       Count = 0;
+       do {
+           c = *yyInput++;
+           if (c == '\0')
+               return c;
+           if (c == '(')
+               Count++;
+           else if (c == ')')
+               Count--;
+       } while (Count > 0);
+    }
+}
+
+
+time_t
+get_date(p, now)
+    char               *p;
+    struct timeb       *now;
+{
+    struct tm          *tm;
+    struct timeb       ftz;
+    time_t             Start;
+    time_t             tod;
+
+    yyInput = p;
+    if (now == NULL) {
+        now = &ftz;
+#if    !defined(HAVE_FTIME)
+       (void)time(&ftz.time);
+       /* Set the timezone global. */
+       tzset();
+       {
+#if sgi
+           ftz.timezone = (int) _timezone / 60;
+#else /* not sgi */
+#ifdef __386BSD__
+           ftz.timezone = 0;
+#else /* neither sgi nor 386BSD */
+#if defined (USG)
+           extern time_t timezone;
+
+           ftz.timezone = (int) timezone / 60;
+#else /* neither sgi nor 386BSD nor USG */
+           struct timeval tv;
+           struct timezone tz;
+
+           gettimeofday (&tv, &tz);
+           ftz.timezone = (int) tz.tz_minuteswest;
+#endif /* neither sgi nor 386BSD nor USG */
+#endif /* neither sgi nor 386BSD */
+#endif /* not sgi */
+       }
+#else /* HAVE_FTIME */
+       (void)ftime(&ftz);
+#endif /* HAVE_FTIME */
+    }
+
+    tm = localtime(&now->time);
+    yyYear = tm->tm_year;
+    yyMonth = tm->tm_mon + 1;
+    yyDay = tm->tm_mday;
+    yyTimezone = now->timezone;
+    yyDSTmode = DSTmaybe;
+    yyHour = 0;
+    yyMinutes = 0;
+    yySeconds = 0;
+    yyMeridian = MER24;
+    yyRelSeconds = 0;
+    yyRelMonth = 0;
+    yyHaveDate = 0;
+    yyHaveDay = 0;
+    yyHaveRel = 0;
+    yyHaveTime = 0;
+    yyHaveZone = 0;
+
+    if (yyparse()
+     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+       return -1;
+
+    if (yyHaveDate || yyHaveTime || yyHaveDay) {
+       Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+                   yyMeridian, yyDSTmode);
+       if (Start < 0)
+           return -1;
+    }
+    else {
+       Start = now->time;
+       if (!yyHaveRel)
+           Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+    }
+
+    Start += yyRelSeconds;
+    Start += RelativeMonth(Start, yyRelMonth);
+
+    if (yyHaveDay && !yyHaveDate) {
+       tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+       Start += tod;
+    }
+
+    /* Have to do *something* with a legitimate -1 so it's distinguishable
+     * from the error return value.  (Alternately could set errno on error.) */
+    return Start == -1 ? 0 : Start;
+}
+
+
+#if    defined(TEST)
+
+/* ARGSUSED */
+main(ac, av)
+    int                ac;
+    char       *av[];
+{
+    char       buff[128];
+    time_t     d;
+
+    (void)printf("Enter date, or blank line to exit.\n\t> ");
+    (void)fflush(stdout);
+    while (gets(buff) && buff[0]) {
+       d = get_date(buff, (struct timeb *)NULL);
+       if (d == -1)
+           (void)printf("Bad format - couldn't convert.\n");
+       else
+           (void)printf("%s", ctime(&d));
+       (void)printf("\t> ");
+       (void)fflush(stdout);
+    }
+    exit(0);
+    /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/lib/gethostname.c b/lib/gethostname.c
new file mode 100644 (file)
index 0000000..fe78dbb
--- /dev/null
@@ -0,0 +1,49 @@
+/* gethostname emulation for SysV and POSIX.1.
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#ifdef HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+
+/* Put up to LEN chars of the host name into NAME.
+   Null terminate it if the name is shorter than LEN.
+   Return 0 if ok, -1 if error.  */
+
+int
+gethostname (name, len)
+     char *name;
+     int len;
+{
+#ifdef HAVE_UNAME
+  struct utsname uts;
+
+  if (uname (&uts) == -1)
+    return -1;
+  if (len > sizeof (uts.nodename))
+    {
+      /* More space than we need is available.  */
+      name[sizeof (uts.nodename)] = '\0';
+      len = sizeof (uts.nodename);
+    }
+  strncpy (name, uts.nodename, len);
+#else
+  strcpy (name, "");           /* Hardcode your system name if you want.  */
+#endif
+  return 0;
+}
diff --git a/lib/getopt.c b/lib/getopt.c
new file mode 100644 (file)
index 0000000..771b511
--- /dev/null
@@ -0,0 +1,679 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+/* AIX requires this to be the first thing in the file.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#include <stdio.h>
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#else  /* Not GNU C library.  */
+#define        __alloca        alloca
+#endif /* GNU C library.  */
+
+#if !__STDC__
+#define const
+#endif
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+#define GETOPT_COMPAT
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define        my_index        strchr
+#define        my_bcopy(src, dst, n)   memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (string, chr)
+     char *string;
+     int chr;
+{
+  while (*string)
+    {
+      if (*string == chr)
+       return string;
+      string++;
+    }
+  return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+     char *from, *to;
+     int size;
+{
+  int i;
+  for (i = 0; i < size; i++)
+    to[i] = from[i];
+}
+#endif                         /* GNU C library.  */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+  char **temp = (char **) __alloca (nonopts_size);
+
+  /* Interchange the two blocks of data in ARGV.  */
+
+  my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+  my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+           (optind - last_nonopt) * sizeof (char *));
+  my_bcopy ((char *) temp,
+           (char *) &argv[first_nonopt + optind - last_nonopt],
+           nonopts_size);
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+       {
+         ordering = RETURN_IN_ORDER;
+         ++optstring;
+       }
+      else if (optstring[0] == '+')
+       {
+         ordering = REQUIRE_ORDER;
+         ++optstring;
+       }
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+       ordering = REQUIRE_ORDER;
+      else
+       ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Now skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc
+                && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+                && (longopts == NULL
+                    || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+                )
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* Special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return EOF;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+         && (longopts == NULL
+             || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+         )
+       {
+         if (ordering == REQUIRE_ORDER)
+           return EOF;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+          && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+       s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+          p++, option_index++)
+       if (!strncmp (p->name, nextchar, s - nextchar))
+         {
+           if (s - nextchar == strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, "%s: option `%s' is ambiguous\n",
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*s)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = s + 1;
+             else
+               {
+                 if (opterr)
+                   {
+                     if (argv[optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                                "%s: option `--%s' doesn't allow an argument\n",
+                                argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                            "%s: option `%c%s' doesn't allow an argument\n",
+                            argv[0], argv[optind - 1][0], pfound->name);
+                   }
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr, "%s: option `%s' requires an argument\n",
+                            argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, "%s: unrecognized option `--%s'\n",
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+           if (c < 040 || c >= 0177)
+             fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+                      argv[0], c);
+           else
+             fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+         }
+       return '?';
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = 0;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 fprintf (stderr, "%s: option `-%c' requires an argument\n",
+                          argv[0], c);
+               c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/getopt.h b/lib/getopt.h
new file mode 100644 (file)
index 0000000..93a5cf7
--- /dev/null
@@ -0,0 +1,125 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if    __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define        no_argument             0
+#define required_argument      1
+#define optional_argument      2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind,
+                            int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/lib/getopt1.c b/lib/getopt1.c
new file mode 100644 (file)
index 0000000..36eb7cd
--- /dev/null
@@ -0,0 +1,153 @@
+/* Getopt for GNU.
+   Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+#include "getopt.h"
+
+#ifndef __STDC__
+#define const
+#endif
+
+#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC)
+#include <stdlib.h>
+#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+char *getenv ();
+#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int 
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (optarg)
+           printf (" with arg %s", optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/getugroups.c b/lib/getugroups.c
new file mode 100644 (file)
index 0000000..4ac6dfc
--- /dev/null
@@ -0,0 +1,86 @@
+/* getugroups.c -- return a list of the groups a user is in
+   Copyright (C) 1990, 1991 Free Software Foundation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie. */
+
+#include <sys/types.h>
+#include <grp.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Even though SunOS 4, Ultrix 4, and 386BSD are mostly POSIX.1 compliant,
+   their getgroups system call (except in the `System V' environment, which
+   is troublesome in other ways) fills in an array of int, not gid_t
+   (which is `short' on those systems).  We do the same, for consistency.
+   Kludge, kludge.  */
+
+#ifdef _POSIX_VERSION
+#if !defined(sun) && !defined(ultrix) && !defined(__386BSD__)
+#define GETGROUPS_T gid_t
+#else /* sun or ultrix or 386BSD */
+#define GETGROUPS_T int
+#endif /* sun or ultrix or 386BSD */
+#else /* not _POSIX_VERSION */
+#define GETGROUPS_T int
+#endif /* not _POSIX_VERSION */
+
+/* setgrent, getgrent, and endgrent are not specified by POSIX.1,
+   so header files might not declare them.
+   If you don't have them at all, we can't implement this function.
+   You lose!  */
+struct group *getgrent ();
+
+#if defined(USG) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* Like `getgroups', but for user USERNAME instead of for
+   the current process. */
+
+int
+getugroups (maxcount, grouplist, username)
+     int maxcount;
+     GETGROUPS_T *grouplist;
+     char *username;
+{
+  struct group *grp;
+  register char **cp;
+  register int count = 0;
+
+  setgrent ();
+  while ((grp = getgrent ()) != 0)
+    for (cp = grp->gr_mem; *cp; ++cp)
+      if (!strcmp (username, *cp))
+       {
+         if (maxcount != 0)
+           {
+             if (count >= maxcount)
+               {
+                 endgrent ();
+                 return count;
+               }
+             grouplist[count] = grp->gr_gid;
+           }
+         count++;
+       }
+  endgrent ();
+  return count;
+}
diff --git a/lib/getusershell.c b/lib/getusershell.c
new file mode 100644 (file)
index 0000000..6e2e0c1
--- /dev/null
@@ -0,0 +1,196 @@
+/* getusershell.c -- Return names of valid user shells.
+   Copyright (C) 1991 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#ifndef SHELLS_FILE
+/* File containing a list of nonrestricted shells, one per line. */
+#define SHELLS_FILE "/etc/shells"
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+static int readname ();
+
+/* List of shells to use if the shells file is missing. */
+static char *default_shells[] =
+{
+  "/bin/sh", "/bin/csh", "/usr/bin/sh", "/usr/bin/csh", NULL
+};
+
+/* Index of the next shell in `default_shells' to return.
+   0 means we are not using `default_shells'. */
+static int default_index = 0;
+
+/* Input stream from the shells file. */
+static FILE *shellstream = NULL;
+
+/* Line of input from the shells file. */
+static char *line = NULL;
+
+/* Number of bytes allocated for `line'. */
+static int line_size = 0;
+\f
+/* Return an entry from the shells file, ignoring comment lines.
+   Return NULL if there are no more entries.  */
+
+char *
+getusershell ()
+{
+  if (default_index > 0)
+    {
+      if (default_shells[default_index])
+       /* Not at the end of the list yet.  */
+       return default_shells[default_index++];
+      return NULL;
+    }
+
+  if (shellstream == NULL)
+    {
+      shellstream = fopen (SHELLS_FILE, "r");
+      if (shellstream == NULL)
+       {
+         /* No shells file.  Use the default list.  */
+         default_index = 1;
+         return default_shells[0];
+       }
+    }
+
+  while (readname (&line, &line_size, shellstream))
+    {
+      if (*line != '#')
+       return line;
+    }
+  return NULL;                 /* End of file. */
+}
+
+/* Rewind the shells file. */
+
+void
+setusershell ()
+{
+  default_index = 0;
+  if (shellstream == NULL)
+    shellstream = fopen (SHELLS_FILE, "r");
+  else
+    fseek (shellstream, 0L, 0);
+}
+
+/* Close the shells file. */
+
+void
+endusershell ()
+{
+  if (shellstream)
+    {
+      fclose (shellstream);
+      shellstream = NULL;
+    }
+}
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+static char *
+xmalloc (n)
+     unsigned n;
+{
+  char *p;
+
+  p = malloc (n);
+  if (p == 0)
+    {
+      fprintf (stderr, "virtual memory exhausted\n");
+      exit (1);
+    }
+  return p;
+}
+
+/* Reallocate space P to size N, with error checking.  */
+
+static char *
+xrealloc (p, n)
+     char *p;
+     unsigned n;
+{
+  p = realloc (p, n);
+  if (p == 0)
+    {
+      fprintf (stderr, "virtual memory exhausted\n");
+      exit (1);
+    }
+  return p;
+}
+
+/* Read a line from STREAM, removing any newline at the end.
+   Place the result in *NAME, which is malloc'd
+   and/or realloc'd as necessary and can start out NULL,
+   and whose size is passed and returned in *SIZE.
+
+   Return the number of characters placed in *NAME
+   if some nonempty sequence was found, otherwise 0.  */
+
+static int
+readname (name, size, stream)
+     char **name;
+     int *size;
+     FILE *stream;
+{
+  int c;
+  int name_index = 0;
+
+  if (*name == NULL)
+    {
+      *size = 10;
+      *name = (char *) xmalloc (*size);
+    }
+
+  /* Skip blank space.  */
+  while ((c = getc (stream)) != EOF && isspace (c))
+    /* Do nothing. */ ;
+  
+  while (c != EOF && !isspace (c))
+    {
+      (*name)[name_index++] = c;
+      while (name_index >= *size)
+       {
+         *size *= 2;
+         *name = (char *) xrealloc (*name, *size);
+       }
+      c = getc (stream);
+    }
+  (*name)[name_index] = '\0';
+  return name_index;
+}
+
+#ifdef TEST
+main ()
+{
+  char *s;
+
+  while (s = getusershell ())
+    puts (s);
+  exit (0);
+}
+#endif
diff --git a/lib/mktime.c b/lib/mktime.c
new file mode 100644 (file)
index 0000000..1c5bf64
--- /dev/null
@@ -0,0 +1,224 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+#ifdef TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#else
+#define        LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
+#define LONG_MIN (-LONG_MAX - 1)
+#define        INT_MAX (~(1 << (sizeof (int) * 8 - 1)))
+#define INT_MIN (-INT_MAX - 1)
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+   except every 100th isn't, and every 1000th is).  */
+#define        __isleap(year)  \
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 1000 == 0))
+#endif
+
+/* How many days are in each month.  */
+static unsigned short int __mon_lengths[2][12] =
+{
+  /* Normal years.  */
+  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+  /* Leap years.  */
+  { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+#define        invalid()       return (time_t) -1
+
+/* Return the `time_t' representation of TP and normalizes TP.
+   Return (time_t) -1 if TP is not representable as a `time_t'.
+   Note that 31 Dec 1969 23:59:59 is not representable
+   because it is represented as (time_t) -1.  */
+time_t
+mktime(tp)
+register struct tm *tp;
+{
+  static struct tm min, max;
+  static char init = 0;
+
+  register time_t result;
+  register time_t t;
+  register int i;
+  register unsigned short *l;
+  register struct tm *new;
+  time_t end;
+
+  if (tp == NULL)
+    {
+      errno = EINVAL;
+      invalid();
+    }
+
+  if (!init)
+    {
+      init = 1;
+      end = (time_t) LONG_MIN;
+      new = gmtime(&end);
+      if (new != NULL)
+       min = *new;
+      else
+       min.tm_sec = min.tm_min = min.tm_hour =
+         min.tm_mday = min.tm_mon = min.tm_year = INT_MIN;
+
+      end = (time_t) LONG_MAX;
+      new = gmtime(&end);
+      if (new != NULL)
+       max = *new;
+      else
+       max.tm_sec = max.tm_min = max.tm_hour =
+         max.tm_mday = max.tm_mon = max.tm_year = INT_MAX;
+    }
+
+  /* Make all the elements of TP that we pay attention to
+     be within the ranges of reasonable values for those things.  */
+#define        normalize(elt, min, max, nextelt) \
+  while (tp->elt < min)                                                              \
+    {                                                                        \
+      --tp->nextelt;                                                         \
+      tp->elt += max + 1;                                                    \
+    }                                                                        \
+  while (tp->elt > max)                                                              \
+    {                                                                        \
+      ++tp->nextelt;                                                         \
+      tp->elt -= max + 1;                                                    \
+    }
+
+  normalize (tm_sec, 0, 59, tm_min);
+  normalize (tm_min, 0, 59, tm_hour);
+  normalize (tm_hour, 0, 24, tm_mday);
+
+  /* Normalize the month first so we can use
+     it to figure the range for the day.  */
+  normalize (tm_mon, 0, 11, tm_year);
+  normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
+            tm_mon);
+
+  /* Normalize the month again, since normalizing
+     the day may have pushed it out of range.  */
+  normalize (tm_mon, 0, 11, tm_year);
+
+  /* Normalize the day again, because normalizing
+     the month may have changed the range.  */
+  normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
+            tm_mon);
+
+  /* Check for out-of-range values.  */
+#define        lowhigh(field, minmax, cmp)     (tp->field cmp minmax.field)
+#define        low(field)                      lowhigh(field, min, <)
+#define        high(field)                     lowhigh(field, max, >)
+#define        oor(field)                      (low(field) || high(field))
+#define        lowbound(field)                 (tp->field == min.field)
+#define        highbound(field)                (tp->field == max.field)
+  if (oor(tm_year))
+    invalid();
+  else if (lowbound(tm_year))
+    {
+      if (low(tm_mon))
+       invalid();
+      else if (lowbound(tm_mon))
+       {
+         if (low(tm_mday))
+           invalid();
+         else if (lowbound(tm_mday))
+           {
+             if (low(tm_hour))
+               invalid();
+             else if (lowbound(tm_hour))
+               {
+                 if (low(tm_min))
+                   invalid();
+                 else if (lowbound(tm_min))
+                   {
+                     if (low(tm_sec))
+                       invalid();
+                   }
+               }
+           }
+       }
+    }
+  else if (highbound(tm_year))
+    {
+      if (high(tm_mon))
+       invalid();
+      else if (highbound(tm_mon))
+       {
+         if (high(tm_mday))
+           invalid();
+         else if (highbound(tm_mday))
+           {
+             if (high(tm_hour))
+               invalid();
+             else if (highbound(tm_hour))
+               {
+                 if (high(tm_min))
+                   invalid();
+                 else if (highbound(tm_min))
+                   {
+                     if (high(tm_sec))
+                       invalid();
+                   }
+               }
+           }
+       }
+    }
+
+  t = 0;
+  for (i = 1970; i > 1900 + tp->tm_year; --i)
+    t -= __isleap(i) ? 366 : 365;
+  for (i = 1970; i < 1900 + tp->tm_year; ++i)
+    t += __isleap(i) ? 366 : 365;
+  l = __mon_lengths[__isleap(1900 + tp->tm_year)];
+  for (i = 0; i < tp->tm_mon; ++i)
+    t += l[i];
+  t += tp->tm_mday - 1;
+  result = ((t * 60 * 60 * 24) +
+           (tp->tm_hour * 60 * 60) +
+           (tp->tm_min * 60) +
+           tp->tm_sec);
+
+  end = result;
+#if 0                          /* This code breaks it, on SunOS anyway. */
+  if (tp->tm_isdst < 0)
+    new = localtime(&end);
+  else
+#endif
+    new = gmtime(&end);
+  if (new == NULL)
+    invalid();
+  new->tm_isdst = tp->tm_isdst;
+  *tp = *new;
+
+  return result;
+}
diff --git a/lib/posixtm.y b/lib/posixtm.y
new file mode 100644 (file)
index 0000000..bb5b40e
--- /dev/null
@@ -0,0 +1,173 @@
+/* Parse dates for touch.
+   Copyright (C) 1989, 1990, 1991 Free Software Foundation Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by Jim Kingdon and David MacKenzie. */
+%{
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef sparc
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+
+#define YYDEBUG 1
+
+/* Lexical analyzer's current scan position in the input string. */
+static char *curpos;
+
+/* The return value. */
+static struct tm t;
+
+time_t mktime ();
+
+#define yyparse posixtime_yyparse
+static int yylex ();
+static int yyerror ();
+%}
+
+%token DIGIT
+
+%%
+date :
+       digitpair /* month */
+       digitpair /* day */
+       digitpair /* hours */
+       digitpair /* minutes */
+       year
+       seconds {
+                if ($1 >= 1 && $1 <= 12)
+                  t.tm_mon = $1 - 1;
+                else {
+                  YYABORT;
+                }
+                if ($2 >= 1 && $2 <= 31)
+                  t.tm_mday = $2;
+                else {
+                  YYABORT;
+                }
+                if ($3 >= 0 && $3 <= 23)
+                  t.tm_hour = $3;
+                else {
+                  YYABORT;
+                }
+                if ($4 >= 0 && $4 <= 59)
+                  t.tm_min = $4;
+                else {
+                  YYABORT;
+                }
+              }
+
+year : digitpair {
+                   t.tm_year = $1;
+                  /* Deduce the century based on the year.
+                     See POSIX.2 section 4.63.3.  */
+                  if ($1 <= 68)
+                    t.tm_year += 100;
+                }
+    | digitpair digitpair {
+                            t.tm_year = $1 * 100 + $2;
+                           if (t.tm_year < 1900) {
+                             YYABORT;
+                           } else
+                             t.tm_year -= 1900;
+                         }
+    | /* empty */ {
+                    time_t now;
+                   struct tm *tmp;
+
+                    /* Use current year.  */
+                    time (&now);
+                   tmp = localtime (&now);
+                   t.tm_year = tmp->tm_year;
+                 }
+    ;
+
+seconds : /* empty */ {
+                        t.tm_sec = 0;
+                     }
+        | '.' digitpair {
+                         if ($2 >= 0 && $2 <= 61)
+                           t.tm_sec = $2;
+                         else {
+                           YYABORT;
+                         }
+                       }
+        ;
+
+digitpair : DIGIT DIGIT {
+                          $$ = $1 * 10 + $2;
+                       }
+          ;
+%%
+static int
+yylex ()
+{
+  char ch = *curpos++;
+
+  if (ch >= '0' && ch <= '9')
+    {
+      yylval = ch - '0';
+      return DIGIT;
+    }
+  else if (ch == '.' || ch == 0)
+    return ch;
+  else
+    return '?';                        /* Cause an error.  */
+}
+
+static int
+yyerror ()
+{
+  return 0;
+}
+
+/* Parse a POSIX-style date and return it, or (time_t)-1 for an error.  */
+
+time_t
+posixtime (s)
+     char *s;
+{
+  curpos = s;
+  /* Let mktime decide whether it is daylight savings time.  */
+  t.tm_isdst = -1;
+  if (yyparse ())
+    return (time_t)-1;
+  else
+    return mktime (&t);
+}
+
+/* Parse a POSIX-style date and return it, or NULL for an error.  */
+
+struct tm *
+posixtm (s)
+     char *s;
+{
+  if (posixtime (s) == -1)
+    return NULL;
+  return &t;
+}
diff --git a/lib/putenv.c b/lib/putenv.c
new file mode 100644 (file)
index 0000000..512878c
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <sys/types.h>
+#include <errno.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern int errno;
+#endif
+
+#if defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#define index strchr
+#define bcopy(s, d, n) memcpy((d), (s), (n))
+#else /* not (STDC_HEADERS or USG) */
+#include <strings.h>
+#endif /* STDC_HEADERS or USG */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#if !__STDC__
+#define const
+#endif
+
+extern char **environ;
+
+/* Put STRING, which is of the form "NAME=VALUE", in the environment.  */
+int
+putenv (string)
+     const char *string;
+{
+  char *name_end = index (string, '=');
+  register size_t size;
+  register char **ep;
+
+  if (name_end == NULL)
+    {
+      /* Remove the variable from the environment.  */
+      size = strlen (string);
+      for (ep = environ; *ep != NULL; ++ep)
+       if (!strncmp (*ep, string, size) && (*ep)[size] == '=')
+         {
+           while (ep[1] != NULL)
+             {
+               ep[0] = ep[1];
+               ++ep;
+             }
+           *ep = NULL;
+           return 0;
+         }
+    }
+
+  size = 0;
+  for (ep = environ; *ep != NULL; ++ep)
+    if (!strncmp (*ep, string, name_end - string) &&
+       (*ep)[name_end - string] == '=')
+      break;
+    else
+      ++size;
+
+  if (*ep == NULL)
+    {
+      static char **last_environ = NULL;
+      char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
+      if (new_environ == NULL)
+       return -1;
+      (void) bcopy ((char *) environ, (char *) new_environ, size * sizeof (char *));
+      new_environ[size] = (char *) string;
+      new_environ[size + 1] = NULL;
+      if (last_environ != NULL)
+       free ((char *) last_environ);
+      last_environ = new_environ;
+      environ = new_environ;
+    }
+  else
+    *ep = (char *) string;
+
+  return 0;
+}
diff --git a/lib/stime.c b/lib/stime.c
new file mode 100644 (file)
index 0000000..e647953
--- /dev/null
@@ -0,0 +1,34 @@
+/* stime -- set the system clock
+   Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* David MacKenzie <djm@ai.mit.edu> */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+/* Set the system time to *WHEN seconds past the start of 1970 GMT. */
+
+int
+stime (when)
+     time_t *when;
+{
+  struct timeval tv;
+
+  tv.tv_sec = *when;
+  tv.tv_usec = 0;
+  return settimeofday (&tv, (struct timezone *) 0);
+}
diff --git a/lib/strcspn.c b/lib/strcspn.c
new file mode 100644 (file)
index 0000000..ea61aa1
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+char *index ();
+
+/* Return the length of the maximum inital segment of S
+   which contains no characters from REJECT.  */
+int
+strcspn (s, reject)
+     register char *s;
+     register char *reject;
+{
+  register int count = 0;
+
+  while (*s != '\0')
+    if (index (reject, *s++) == 0)
+      ++count;
+    else
+      return count;
+
+  return count;
+}
diff --git a/lib/strftime.c b/lib/strftime.c
new file mode 100644 (file)
index 0000000..cc4953e
--- /dev/null
@@ -0,0 +1,428 @@
+/* strftime - custom formatting of date and/or time
+   Copyright (C) 1989, 1991, 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Note: this version of strftime lacks locale support,
+   but it is standalone.
+
+   Performs `%' substitutions similar to those in printf.  Except
+   where noted, substituted fields have a fixed size; numeric fields are
+   padded if necessary.  Padding is with zeros by default; for fields
+   that display a single number, padding can be changed or inhibited by
+   following the `%' with one of the modifiers described below.  Unknown
+   field specifiers are copied as normal characters.  All other
+   characters are copied to the output without change.
+
+   Supports a superset of the ANSI C field specifiers.
+
+   Literal character fields:
+   %   %
+   n   newline
+   t   tab
+
+   Numeric modifiers (a nonstandard extension):
+   -   do not pad the field
+   _   pad the field with spaces
+
+   Time fields:
+   %H  hour (00..23)
+   %I  hour (01..12)
+   %k  hour ( 0..23)
+   %l  hour ( 1..12)
+   %M  minute (00..59)
+   %p  locale's AM or PM
+   %r  time, 12-hour (hh:mm:ss [AP]M)
+   %R  time, 24-hour (hh:mm)
+   %S  second (00..61)
+   %T  time, 24-hour (hh:mm:ss)
+   %X  locale's time representation (%H:%M:%S)
+   %Z  time zone (EDT), or nothing if no time zone is determinable
+
+   Date fields:
+   %a  locale's abbreviated weekday name (Sun..Sat)
+   %A  locale's full weekday name, variable length (Sunday..Saturday)
+   %b  locale's abbreviated month name (Jan..Dec)
+   %B  locale's full month name, variable length (January..December)
+   %c  locale's date and time (Sat Nov 04 12:02:33 EST 1989)
+   %C  century (00..99)
+   %d  day of month (01..31)
+   %e  day of month ( 1..31)
+   %D  date (mm/dd/yy)
+   %h  same as %b
+   %j  day of year (001..366)
+   %m  month (01..12)
+   %U  week number of year with Sunday as first day of week (00..53)
+   %w  day of week (0..6)
+   %W  week number of year with Monday as first day of week (00..53)
+   %x  locale's date representation (mm/dd/yy)
+   %y  last two digits of year (00..99)
+   %Y  year (1970...)
+
+   David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#include <sys/types.h>
+#if defined(TM_IN_SYS_TIME) || (!defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME))
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#if defined(HAVE_TZNAME)
+extern char *tzname[2];
+#endif
+
+#if !__STDC__
+#define const
+#endif
+
+/* Types of padding for numbers in date and time. */
+enum padding
+{
+  none, blank, zero
+};
+
+static char *days[] =
+{
+  "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+};
+
+static char *months[] =
+{
+  "January", "February", "March", "April", "May", "June",
+  "July", "August", "September", "October", "November", "December"
+};
+
+/* Add character C to STRING and increment LENGTH,
+   unless LENGTH would exceed MAX. */
+
+#define add_char(c) (length + 1 <= max) && (string[length++] = (c))
+
+/* Add a 2 digit number to STRING, padding if specified.
+   Return the number of characters added, up to MAX. */
+
+static int
+add_num2 (string, num, max, pad)
+     char *string;
+     int num;
+     int max;
+     enum padding pad;
+{
+  int top = num / 10;
+  int length = 0;
+
+  if (top == 0 && pad == blank)
+    add_char (' ');
+  else if (top != 0 || pad == zero)
+    add_char (top + '0');
+  add_char (num % 10 + '0');
+  return length;
+}
+
+/* Add a 3 digit number to STRING, padding if specified.
+   Return the number of characters added, up to MAX. */
+
+static int
+add_num3 (string, num, max, pad)
+     char *string;
+     int num;
+     int max;
+     enum padding pad;
+{
+  int top = num / 100;
+  int mid = (num - top * 100) / 10;
+  int length = 0;
+
+  if (top == 0 && pad == blank)
+    add_char (' ');
+  else if (top != 0 || pad == zero)
+    add_char (top + '0');
+  if (mid == 0 && top == 0 && pad == blank)
+    add_char (' ');
+  else if (mid != 0 || top != 0 || pad == zero)
+    add_char (mid + '0');
+  add_char (num % 10 + '0');
+  return length;
+}
+
+/* Like strncpy except return the number of characters copied. */
+
+static int
+add_str (to, from, max)
+     char *to;
+     char *from;
+     int max;
+{
+  int i;
+
+  for (i = 0; from[i] && i <= max; ++i)
+    to[i] = from[i];
+  return i;
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+   starting on Sundays. */
+
+static int
+sun_week (tm)
+     struct tm *tm;
+{
+  int dl;
+
+  /* Set `dl' to the day in the year of the last day of the week previous
+     to the one containing the day specified in TM.  If the day specified
+     in TM is in the first week of the year, `dl' will be negative or 0.
+     Otherwise, calculate the number of complete weeks before our week
+     (dl / 7) and add any partial week at the start of the year (dl % 7). */
+  dl = tm->tm_yday - tm->tm_wday;
+  return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+   starting on Mondays. */
+
+static int
+mon_week (tm)
+     struct tm *tm;
+{
+  int dl, wday;
+
+  if (tm->tm_wday == 0)
+    wday = 6;
+  else
+    wday = tm->tm_wday - 1;
+  dl = tm->tm_yday - wday;
+  return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+#if !defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME)
+char *
+zone_name (tp)
+     struct tm *tp;
+{
+  char *timezone ();
+  struct timeval tv;
+  struct timezone tz;
+
+  gettimeofday (&tv, &tz);
+  return timezone (tz.tz_minuteswest, tp->tm_isdst);
+}
+#endif
+
+/* Format the time given in TM according to FORMAT, and put the
+   results in STRING.
+   Return the number of characters (not including terminating null)
+   that were put into STRING, or 0 if the length would have
+   exceeded MAX. */
+
+size_t
+strftime (string, max, format, tm)
+     char *string;
+     size_t max;
+     const char *format;
+     const struct tm *tm;
+{
+  enum padding pad;            /* Type of padding to apply. */
+  size_t length = 0;           /* Characters put in STRING so far. */
+
+  for (; *format && length < max; ++format)
+    {
+      if (*format != '%')
+       add_char (*format);
+      else
+       {
+         ++format;
+         /* Modifiers: */
+         if (*format == '-')
+           {
+             pad = none;
+             ++format;
+           }
+         else if (*format == '_')
+           {
+             pad = blank;
+             ++format;
+           }
+         else
+           pad = zero;
+
+         switch (*format)
+           {
+             /* Literal character fields: */
+           case 0:
+           case '%':
+             add_char ('%');
+             break;
+           case 'n':
+             add_char ('\n');
+             break;
+           case 't':
+             add_char ('\t');
+             break;
+           default:
+             add_char (*format);
+             break;
+
+             /* Time fields: */
+           case 'H':
+           case 'k':
+             length +=
+               add_num2 (&string[length], tm->tm_hour, max - length,
+                         *format == 'H' ? pad : blank);
+             break;
+           case 'I':
+           case 'l':
+             {
+               int hour12;
+
+               if (tm->tm_hour == 0)
+                 hour12 = 12;
+               else if (tm->tm_hour > 12)
+                 hour12 = tm->tm_hour - 12;
+               else
+                 hour12 = tm->tm_hour;
+               length +=
+                 add_num2 (&string[length], hour12, max - length,
+                           *format == 'I' ? pad : blank);
+             }
+             break;
+           case 'M':
+             length +=
+               add_num2 (&string[length], tm->tm_min, max - length, pad);
+             break;
+           case 'p':
+             if (tm->tm_hour < 12)
+               add_char ('A');
+             else
+               add_char ('P');
+             add_char ('M');
+             break;
+           case 'r':
+             length +=
+               strftime (&string[length], max - length, "%I:%M:%S %p", tm);
+             break;
+           case 'R':
+             length +=
+               strftime (&string[length], max - length, "%H:%M", tm);
+             break;
+           case 'S':
+             length +=
+               add_num2 (&string[length], tm->tm_sec, max - length, pad);
+             break;
+           case 'T':
+             length +=
+               strftime (&string[length], max - length, "%H:%M:%S", tm);
+             break;
+           case 'X':
+             length +=
+               strftime (&string[length], max - length, "%H:%M:%S", tm);
+             break;
+           case 'Z':
+#ifdef HAVE_TM_ZONE
+             length += add_str (&string[length], tm->tm_zone, max - length);
+#else
+#ifdef HAVE_TZNAME
+             if (tm->tm_isdst && tzname[1] && *tzname[1])
+               length += add_str (&string[length], tzname[1], max - length);
+             else
+               length += add_str (&string[length], tzname[0], max - length);
+#else
+             length += add_str (&string[length], zone_name (tm), max - length);
+#endif
+#endif
+             break;
+
+             /* Date fields: */
+           case 'a':
+             add_char (days[tm->tm_wday][0]);
+             add_char (days[tm->tm_wday][1]);
+             add_char (days[tm->tm_wday][2]);
+             break;
+           case 'A':
+             length +=
+               add_str (&string[length], days[tm->tm_wday], max - length);
+             break;
+           case 'b':
+           case 'h':
+             add_char (months[tm->tm_mon][0]);
+             add_char (months[tm->tm_mon][1]);
+             add_char (months[tm->tm_mon][2]);
+             break;
+           case 'B':
+             length +=
+               add_str (&string[length], months[tm->tm_mon], max - length);
+             break;
+           case 'c':
+             length +=
+               strftime (&string[length], max - length,
+                         "%a %b %d %H:%M:%S %Z %Y", tm);
+             break;
+           case 'C':
+             length +=
+               add_num2 (&string[length], (tm->tm_year + 1900) / 100,
+                         max - length, pad);
+             break;
+           case 'd':
+             length +=
+               add_num2 (&string[length], tm->tm_mday, max - length, pad);
+             break;
+           case 'e':
+             length +=
+               add_num2 (&string[length], tm->tm_mday, max - length, blank);
+             break;
+           case 'D':
+             length +=
+               strftime (&string[length], max - length, "%m/%d/%y", tm);
+             break;
+           case 'j':
+             length +=
+               add_num3 (&string[length], tm->tm_yday + 1, max - length, pad);
+             break;
+           case 'm':
+             length +=
+               add_num2 (&string[length], tm->tm_mon + 1, max - length, pad);
+             break;
+           case 'U':
+             length +=
+               add_num2 (&string[length], sun_week (tm), max - length, pad);
+             break;
+           case 'w':
+             add_char (tm->tm_wday + '0');
+             break;
+           case 'W':
+             length +=
+               add_num2 (&string[length], mon_week (tm), max - length, pad);
+             break;
+           case 'x':
+             length +=
+               strftime (&string[length], max - length, "%m/%d/%y", tm);
+             break;
+           case 'y':
+             length +=
+               add_num2 (&string[length], tm->tm_year % 100,
+                         max - length, pad);
+             break;
+           case 'Y':
+             add_char ((tm->tm_year + 1900) / 1000 + '0');
+             length +=
+               add_num3 (&string[length],
+                         (1900 + tm->tm_year) % 1000, max - length, zero);
+             break;
+           }
+       }
+    }
+  add_char (0);
+  return length - 1;
+}
diff --git a/lib/strtod.c b/lib/strtod.c
new file mode 100644 (file)
index 0000000..4441102
--- /dev/null
@@ -0,0 +1,188 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <errno.h>
+#include <ctype.h>
+#include <math.h>
+
+#if STDC_HEADERS
+#include <float.h>
+#include <stdlib.h>
+#include <string.h>
+#else
+#define NULL 0
+#define DBL_MAX 1.7976931348623159e+308
+#define DBL_MIN 2.2250738585072010e-308
+extern int errno;
+#endif
+#ifndef HUGE_VAL
+#define HUGE_VAL HUGE
+#endif
+
+#if !__STDC__
+#define const
+#endif
+
+/* Convert NPTR to a double.  If ENDPTR is not NULL, a pointer to the
+   character after the last one used in the number is put in *ENDPTR.  */
+double
+strtod (nptr, endptr)
+     const char *nptr;
+     char **endptr;
+{
+  register const char *s;
+  short int sign;
+
+  /* The number so far.  */
+  double num;
+
+  int got_dot;                 /* Found a decimal point.  */
+  int got_digit;               /* Seen any digits.  */
+
+  /* The exponent of the number.  */
+  long int exponent;
+
+  if (nptr == NULL)
+    {
+      errno = EINVAL;
+      goto noconv;
+    }
+
+  s = nptr;
+
+  /* Eat whitespace.  */
+  while (isspace (*s))
+    ++s;
+
+  /* Get the sign.  */
+  sign = *s == '-' ? -1 : 1;
+  if (*s == '-' || *s == '+')
+    ++s;
+
+  num = 0.0;
+  got_dot = 0;
+  got_digit = 0;
+  exponent = 0;
+  for (;; ++s)
+    {
+      if (isdigit (*s))
+       {
+         got_digit = 1;
+
+         /* Make sure that multiplication by 10 will not overflow.  */
+         if (num > DBL_MAX * 0.1)
+           /* The value of the digit doesn't matter, since we have already
+              gotten as many digits as can be represented in a `double'.
+              This doesn't necessarily mean the result will overflow.
+              The exponent may reduce it to within range.
+
+              We just need to record that there was another
+              digit so that we can multiply by 10 later.  */
+           ++exponent;
+         else
+           num = (num * 10.0) + (*s - '0');
+
+         /* Keep track of the number of digits after the decimal point.
+            If we just divided by 10 here, we would lose precision.  */
+         if (got_dot)
+           --exponent;
+       }
+      else if (!got_dot && *s == '.')
+       /* Record that we have found the decimal point.  */
+       got_dot = 1;
+      else
+       /* Any other character terminates the number.  */
+       break;
+    }
+
+  if (!got_digit)
+    goto noconv;
+
+  if (tolower (*s) == 'e')
+    {
+      /* Get the exponent specified after the `e' or `E'.  */
+      int save = errno;
+      char *end;
+      long int exp;
+
+      errno = 0;
+      ++s;
+      exp = strtol (s, &end, 10);
+      if (errno == ERANGE)
+       {
+         /* The exponent overflowed a `long int'.  It is probably a safe
+            assumption that an exponent that cannot be represented by
+            a `long int' exceeds the limits of a `double'.  */
+         if (endptr != NULL)
+           *endptr = end;
+         if (exp < 0)
+           goto underflow;
+         else
+           goto overflow;
+       }
+      else if (end == s)
+       /* There was no exponent.  Reset END to point to
+          the 'e' or 'E', so *ENDPTR will be set there.  */
+       end = (char *) s - 1;
+      errno = save;
+      s = end;
+      exponent += exp;
+    }
+
+  if (endptr != NULL)
+    *endptr = (char *) s;
+
+  if (num == 0.0)
+    return 0.0;
+
+  /* Multiply NUM by 10 to the EXPONENT power,
+     checking for overflow and underflow.  */
+
+  if (exponent < 0)
+    {
+      if (num < DBL_MIN * pow (10.0, (double) -exponent))
+       goto underflow;
+    }
+  else if (exponent > 0)
+    {
+      if (num > DBL_MAX * pow (10.0, (double) -exponent))
+       goto overflow;
+    }
+
+  num *= pow (10.0, (double) exponent);
+
+  return num * sign;
+
+overflow:
+  /* Return an overflow error.  */
+  errno = ERANGE;
+  return HUGE_VAL * sign;
+
+underflow:
+  /* Return an underflow error.  */
+  if (endptr != NULL)
+    *endptr = (char *) nptr;
+  errno = ERANGE;
+  return 0.0;
+
+noconv:
+  /* There was no number.  */
+  if (endptr != NULL)
+    *endptr = (char *) nptr;
+  return 0.0;
+}
diff --git a/lib/xmalloc.c b/lib/xmalloc.c
new file mode 100644 (file)
index 0000000..f989004
--- /dev/null
@@ -0,0 +1,65 @@
+/* xmalloc.c -- malloc with out of memory checking
+   Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+void free ();
+#endif
+
+void error ();
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+char *
+xmalloc (n)
+     unsigned n;
+{
+  char *p;
+
+  p = malloc (n);
+  if (p == 0)
+    /* Must exit with 2 for `cmp'.  */
+    error (2, 0, "virtual memory exhausted");
+  return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.
+   If P is NULL, run xmalloc.
+   If N is 0, run free and return NULL.  */
+
+char *
+xrealloc (p, n)
+     char *p;
+     unsigned n;
+{
+  if (p == 0)
+    return xmalloc (n);
+  if (n == 0)
+    {
+      free (p);
+      return 0;
+    }
+  p = realloc (p, n);
+  if (p == 0)
+    /* Must exit with 2 for `cmp'.  */
+    error (2, 0, "virtual memory exhausted");
+  return p;
+}