changeset 9:f8dce34b5ab0

Initial revision
author Jim Meyering <jim@meyering.net>
date Sun, 01 Nov 1992 05:44:30 +0000
parents f3ddcf3cf2fa
children b897a21e7492 64f55f73d1ab
files lib/alloca.c lib/basename.c lib/error.c lib/getdate.y lib/gethostname.c lib/getopt.c lib/getopt.h lib/getopt1.c lib/getugroups.c lib/getusershell.c lib/mktime.c lib/posixtm.y lib/putenv.c lib/stime.c lib/strcspn.c lib/strftime.c lib/strtod.c lib/xmalloc.c
diffstat 18 files changed, 3837 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/lib/alloca.c
@@ -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 */
new file mode 100644
--- /dev/null
+++ b/lib/basename.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/error.c
@@ -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);
+}
new file mode 100644
--- /dev/null
+++ b/lib/getdate.y
@@ -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 }
+};
+
+
+
+
+/* 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) */
new file mode 100644
--- /dev/null
+++ b/lib/gethostname.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/getopt.c
@@ -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.  */
+
+/* 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;
+
+#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.  */
+
+/* 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;
+}
+
+/* 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);
+}
+
+#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 */
new file mode 100644
--- /dev/null
+++ b/lib/getopt.h
@@ -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 */
new file mode 100644
--- /dev/null
+++ b/lib/getopt1.c
@@ -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.  */
+
+#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);
+}
+
+#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 */
new file mode 100644
--- /dev/null
+++ b/lib/getugroups.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/getusershell.c
@@ -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;
+
+/* 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
new file mode 100644
--- /dev/null
+++ b/lib/mktime.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/posixtm.y
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/putenv.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/stime.c
@@ -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);
+}
new file mode 100644
--- /dev/null
+++ b/lib/strcspn.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/strftime.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/strtod.c
@@ -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;
+}
new file mode 100644
--- /dev/null
+++ b/lib/xmalloc.c
@@ -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;
+}