* kdb5_edit.c: add modent
authorTom Yu <tlyu@mit.edu>
Tue, 14 Feb 1995 22:57:45 +0000 (22:57 +0000)
committerTom Yu <tlyu@mit.edu>
Tue, 14 Feb 1995 22:57:45 +0000 (22:57 +0000)
* getdate.y: import get_date
* kdbt_ed_ct.ct: add modent
* configure.in:
* Makefile.in: support for getdate.y

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@4945 dc483132-0cff-0310-8789-dd5450dbe970

src/admin/edit/ChangeLog
src/admin/edit/Makefile.in
src/admin/edit/configure.in
src/admin/edit/getdate.y [new file with mode: 0644]
src/admin/edit/kdb5_ed_ct.ct
src/admin/edit/kdb5_edit.c

index c275e11318d8390454f38e57e9659f6eec271292..e6142bfb818df33d6f6677b9662fc91478f1904c 100644 (file)
@@ -1,3 +1,11 @@
+Tue Feb 14 17:55:47 1995  Tom Yu  (tlyu@dragons-lair)
+
+       * kdb5_edit.c: add modent
+       * getdate.y: import get_date
+       * kdbt_ed_ct.ct: add modent
+       * configure.in:
+       * Makefile.in: support for getdate.y
+
 Wed Feb  8 20:08:36 1995  Tom Yu  (tlyu@dragons-lair)
 
        * kdb5_edit.c (show_principal): make sane and print all useful
index 335092337ae0e1269b1669c0199d3762afa727c6..d89095cf04ab00ea4120dfc8418f4deb48322f00 100644 (file)
@@ -21,14 +21,33 @@ DEPLIBS = $(DEPKDBLIB) $(DEPKLIB)
 LOCAL_LIBRARIES = $(KDBLIB) $(KLIB) $(K4LIB)
 LOCALINCLUDE=-I$(SRCTOP)/include/kerberosIV -I$(BUILDTOP)/include/kerberosIV
 
-OBJS= kdb5_edit.o kdb5_ed_ct.o util.o dump.o dumpv4.o ss_wrapper.o
-SRCS= $(srcdir)/kdb5_edit.c $(srcdir)/kdb5_ed_ct.c $(srcdir)/util.c $(srcdir)/dump.c $(srcdir)/ss_wrapper.c $(srcdir)/dumpv4.c
+OBJS= kdb5_edit.o \
+       kdb5_ed_ct.o \
+       util.o \
+       dump.o \
+       dumpv4.o \
+       ss_wrapper.o \
+       getdate.o \
+       $(LIBOBJS)
+SRCS= $(srcdir)/kdb5_edit.c \
+       $(srcdir)/kdb5_ed_ct.c \
+       $(srcdir)/util.c \
+       $(srcdir)/dump.c \
+       $(srcdir)/ss_wrapper.c \
+       $(srcdir)/dumpv4.c \
+       $(srcdir)/getdate.o
 
 all:: kdb5_edit
 
 kdb5_edit: kdb5_edit.o $(DEPLIBS) $(OBJS)
        $(CC) $(CFLAGS) -o kdb5_edit $(OBJS) $(LOCAL_LIBRARIES) $(LIBS)
 
+getdate.c getdate.h: getdate.y
+       $(RM) getdate.c getdate.h y.tab.*
+       $(YACC) -d $(srcdir)/getdate.y
+       $(MV) y.tab.c getdate.c
+       $(MV) y.tab.h getdate.h
+
 install::
        $(INSTALL_PROGRAM) kdb5_edit ${DESTDIR}$(ADMIN_BINDIR)/kdb5_edit
        $(INSTALL_DATA) $(srcdir)/kdb5_edit.M ${DESTDIR}$(ADMIN_MANDIR)/kdb5_edit.8
@@ -44,6 +63,8 @@ clean::
 depend:: kdb5_ed_ct.c
 
 clean::
-       $(RM) kdb5_edit
-
+       $(RM) kdb5_edit getdate getdate.c getdate.h y.tab.c y.tab.h
 
+# testing rule for building getdate
+getdate: getdate.c
+       $(CC) -o getdate $(CFLAGS) -DTEST getdate.c
index 73d33b82834ebaf7a54fa2619eb5b0387b02656a..60f53251b8c81e889e2f4197fb583c4ffb549af0 100644 (file)
@@ -3,6 +3,10 @@ WITH_CCOPTS
 CONFIG_RULES
 AC_SET_BUILDTOP
 AC_PROG_INSTALL
+AC_PROG_YACC
+AC_HAVE_HEADERS(unistd.h sys/timeb.h alloca.h)
+AC_HAVE_FUNCS(ftime timezone)
+AC_CONST
 AC_CHECK_LIB(socket,main)
 AC_CHECK_LIB(nsl,main)
 AC_CHECK_LIB(ndbm,main)
diff --git a/src/admin/edit/getdate.y b/src/admin/edit/getdate.y
new file mode 100644 (file)
index 0000000..6b03e73
--- /dev/null
@@ -0,0 +1,1006 @@
+%{
+/*
+**  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 nine 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 HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+#undef static
+#endif
+
+/* The following block of alloca-related preprocessor directives is here
+   solely to allow compilation by non GNU-C compilers of the C parser
+   produced from this file by old versions of bison.  Newer versions of
+   bison include a block similar to this one in bison.simple.  */
+
+#ifdef __GNUC__
+#undef alloca
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX /* for Bison */
+ #pragma alloca
+#else
+void *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(vms)
+
+#include <types.h>
+#include <time.h>
+
+#else
+
+#include <sys/types.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef timezone
+#undef timezone /* needed for sgi */
+#endif
+
+#if defined(HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#else
+/*
+** We use the obsolete `struct timeb' as part of our interface!
+** Since the system doesn't have it, we define it here;
+** our callers must do likewise.
+*/
+struct timeb {
+    time_t             time;           /* Seconds since the epoch      */
+    unsigned short     millitm;        /* Field not used               */
+    short              timezone;       /* Minutes west of GMT          */
+    short              dstflag;        /* Field not used               */
+};
+#endif /* defined(HAVE_SYS_TIMEB_H) */
+
+#endif /* defined(vms) */
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+extern struct tm       *gmtime();
+extern struct tm       *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int yylex ();
+static int yyerror ();
+
+#if    !defined(lint) && !defined(SABER)
+static char RCS[] =
+       "$Header$";
+#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;
+       }
+       | tUNUMBER tMONTH tSNUMBER {
+           /* e.g. 17-JUN-1992.  */
+           yyDay = $1;
+           yyMonth = $2;
+           yyYear = -$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) {
+                   yyHaveDate++;
+                   yyDay= ($1)%100;
+                   yyMonth= ($1/100)%100;
+                   yyYear = $1/10000;
+               }
+               else {
+                   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 const 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 const 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 const 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 const 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 const MilitaryTable[] = {
+    { "a",     tZONE,  HOUR(  1) },
+    { "b",     tZONE,  HOUR(  2) },
+    { "c",     tZONE,  HOUR(  3) },
+    { "d",     tZONE,  HOUR(  4) },
+    { "e",     tZONE,  HOUR(  5) },
+    { "f",     tZONE,  HOUR(  6) },
+    { "g",     tZONE,  HOUR(  7) },
+    { "h",     tZONE,  HOUR(  8) },
+    { "i",     tZONE,  HOUR(  9) },
+    { "k",     tZONE,  HOUR( 10) },
+    { "l",     tZONE,  HOUR( 11) },
+    { "m",     tZONE,  HOUR( 12) },
+    { "n",     tZONE,  HOUR(- 1) },
+    { "o",     tZONE,  HOUR(- 2) },
+    { "p",     tZONE,  HOUR(- 3) },
+    { "q",     tZONE,  HOUR(- 4) },
+    { "r",     tZONE,  HOUR(- 5) },
+    { "s",     tZONE,  HOUR(- 6) },
+    { "t",     tZONE,  HOUR(- 7) },
+    { "u",     tZONE,  HOUR(- 8) },
+    { "v",     tZONE,  HOUR(- 9) },
+    { "w",     tZONE,  HOUR(-10) },
+    { "x",     tZONE,  HOUR(-11) },
+    { "y",     tZONE,  HOUR(-12) },
+    { "z",     tZONE,  HOUR(  0) },
+    { NULL }
+};
+
+\f
+
+
+/* ARGSUSED */
+static 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;
+    default:
+       abort ();
+    }
+    /* 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 const 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;
+}
+
+
+static 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);
+    }
+}
+
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static time_t
+difftm(a, b)
+     struct tm *a, *b;
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  return
+    (
+     (
+      (
+       /* difference in day of year */
+       a->tm_yday - b->tm_yday
+       /* + intervening leap days */
+       +  ((ay >> 2) - (by >> 2))
+       -  (ay/100 - by/100)
+       +  ((ay/100 >> 2) - (by/100 >> 2))
+       /* + difference in years * 365 */
+       +  (time_t)(ay-by) * 365
+       )*24 + (a->tm_hour - b->tm_hour)
+      )*60 + (a->tm_min - b->tm_min)
+     )*60 + (a->tm_sec - b->tm_sec);
+}
+
+time_t
+get_date(p, now)
+    char               *p;
+    struct timeb       *now;
+{
+    struct tm          *tm, gmt;
+    struct timeb       ftz;
+    time_t             Start;
+    time_t             tod;
+
+    yyInput = p;
+    if (now == NULL) {
+        now = &ftz;
+       (void)time(&ftz.time);
+
+       if (! (tm = gmtime (&ftz.time)))
+           return -1;
+       gmt = *tm;      /* Make a copy, in case localtime modifies *tm.  */
+       ftz.timezone = difftm (&gmt, localtime (&ftz.time)) / 60;
+    }
+
+    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) */
index 23352a471a0c77b5a13c6cfa28e1ae23d2a1d5cf..423962f9db1b13d803fd9ad2449533dc83d9b623 100644 (file)
@@ -57,6 +57,9 @@ request extract_srvtab, "Extract service key table",
 request extract_v4_srvtab, "Extract service key table",
        extract_v4_srvtab, xst4;
 
+request modent, "Modify entry",
+       modify_entry, modent;
+
 request list_db, "List database entries",
        list_db, ldb;
 
index 2d80bcb2272442effec84adef15cc1e2d40b9c9e..77d98726568ead0dd7758c1a1939d688fd38362b 100644 (file)
 #include <com_err.h>
 #include <stdio.h>
 #include <time.h>
+#include <sys/timeb.h>
 
 #include "kdb5_edit.h"
 
+/* special struct to convert flag names for principals
+   to actual krb5_flags for a principal */
+struct pflag {
+    char *flagname;            /* name of flag as typed to CLI */
+    int flaglen;               /* length of string (not counting -,+) */
+    krb5_flags theflag;                /* actual principal flag to set/clear */
+    int set;                   /* 0 means clear, 1 means set (on '-') */
+};
+
 struct mblock mblock = {                               /* XXX */
     KRB5_KDB_MAX_LIFE,
     KRB5_KDB_MAX_RLIFE,
@@ -1429,7 +1439,8 @@ void show_principal(argc, argv)
        NULL,                   /* 0x00000400 */
        NULL,                   /* 0x00000800 */
        "DISALLOW_SVR",         /* 0x00001000 */
-       "PWCHANGE_SERVICE"      /* 0x00002000 */
+       "PWCHANGE_SERVICE",     /* 0x00002000 */
+       /* yes abuse detail that rest are initialized to NULL */
        };
 
     if (argc < 2) {
@@ -1521,6 +1532,208 @@ errout:
        krb5_db_free_principal(edit_context, &entry, nprincs);
 }
 
+int parse_princ_args(argc, argv, entry, pass, randkey, caller)
+    int argc;
+    char *argv[];
+    krb5_db_entry *entry;
+    char **pass;
+    int *randkey;
+    char *caller;
+{
+    int i, j, attrib_set;
+    time_t date;
+    struct timeb now;
+    krb5_error_code retval;
+    
+    static struct pflag flags[] = {
+    {"allow_postdated",        15,     KRB5_KDB_DISALLOW_POSTDATED,    1},
+    {"allow_forwardable",17,   KRB5_KDB_DISALLOW_FORWARDABLE,  1},
+    {"allow_tgs_req",  13,     KRB5_KDB_DISALLOW_TGT_BASED,    1},
+    {"allow_renewable",        15,     KRB5_KDB_DISALLOW_RENEWABLE,    1},
+    {"allow_proxiable",        15,     KRB5_KDB_DISALLOW_PROXIABLE,    1},
+    {"allow_dup_skey", 14,     KRB5_KDB_DISALLOW_DUP_SKEY,     1},
+    {"allow_tix",      9,      KRB5_KDB_DISALLOW_ALL_TIX,      1},
+    {"requires_preauth",16,    KRB5_KDB_REQUIRES_PRE_AUTH,     0},
+    {"requires_hwauth",        15,     KRB5_KDB_REQUIRES_HW_AUTH,      0},
+    {"needchange",     10,     KRB5_KDB_REQUIRES_PWCHANGE,     0},
+    {"allow_svr",      9,      KRB5_KDB_DISALLOW_SVR,          1},
+    {"password_changing_service",25,KRB5_KDB_PWCHANGE_SERVICE, 0}
+    };
+    
+    *pass = NULL;
+    ftime(&now);
+    *randkey = 0;
+    for (i = 1; i < argc - 1; i++) {
+       attrib_set = 0;
+       if (strlen(argv[i]) == 5 &&
+           !strcmp("-kvno", argv[i])) {
+           if (++i > argc - 2)
+               return -1;
+           else {
+               entry->kvno = atoi(argv[i]);
+               continue;
+           }
+       }
+       if (strlen(argv[i]) == 8 &&
+           !strcmp("-maxlife", argv[i])) {
+           if (++i > argc - 2)
+               return -1;
+           else {
+               entry->max_life = get_date(argv[i], now) - now.time;
+               continue;
+           }
+       }
+       if (strlen(argv[i]) == 7 &&
+           !strcmp("-expire", argv[i])) {
+           if (++i > argc - 2)
+               return -1;
+           else {
+               date = get_date(argv[i], now);
+               entry->expiration = date == (time_t) -1 ? 0 : date;
+               continue;
+           }
+       }
+       if (strlen(argv[i]) == 9 &&
+           !strcmp("-pwexpire", argv[i])) {
+           if (++i > argc - 2)
+               return -1;
+           else {
+               date = get_date(argv[i], now);
+               entry->pw_expiration = date == (time_t) -1 ? 0 : date;
+               continue;
+           }
+       }
+       if (strlen(argv[i]) == 3 &&
+           !strcmp("-pw", argv[i])) {
+           if (++i > argc - 2)
+               return -1;
+           else {
+               *pass = argv[i];
+               continue;
+           }
+       }
+       if (strlen(argv[i]) == 8 &&
+           !strcmp("-randkey", argv[i])) {
+           ++*randkey;
+           continue;
+       }
+       for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
+           if (strlen(argv[i]) == flags[j].flaglen + 1 &&
+               !strcmp(flags[j].flagname,
+                       &argv[i][1] /* strip off leading + or - */)) {
+               if (flags[j].set && argv[i][0] == '-' ||
+                   !flags[j].set && argv[i][0] == '+') {
+                   entry->attributes |= flags[j].theflag;
+                   attrib_set++;
+                   break;
+               } else if (flags[j].set && argv[i][0] == '+' ||
+                          !flags[j].set && argv[i][0] == '-') {
+                   entry->attributes &= ~flags[j].theflag;
+                   attrib_set++;
+                   break;
+               } else {
+                   return -1;
+               }
+           }
+       }
+       if (!attrib_set)
+           return -1;          /* nothing was parsed */
+    }
+    if (i != argc - 1) {
+       fprintf(stderr, "%s: parser lost count!\n", caller);
+       return -1;
+    }
+    retval = krb5_parse_name(edit_context, argv[i], &entry->principal);
+    if (retval) {
+       com_err(caller, retval, "while parsing principal");
+       return -1;
+    }
+    return 0;
+}
+
+void modent(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_db_entry entry, oldentry;
+    krb5_principal kprinc;
+    krb5_error_code retval;
+    krb5_boolean more;
+    char *pass, *canon;
+    int one = 1, nprincs = 1, randkey = 0;
+    
+    retval = krb5_parse_name(edit_context, argv[argc - 1], &kprinc);
+    if (retval) {
+       com_err("modify_principal", retval, "while parsing principal");
+       return;
+    }
+    retval = krb5_unparse_name(edit_context, kprinc, &canon);
+    if (retval) {
+       com_err("modify_principal", retval,
+               "while canonicalizing principal");
+       krb5_free_principal(edit_context, kprinc);
+       return;
+    }
+    retval = krb5_db_get_principal(edit_context, kprinc, &oldentry,
+                                  &nprincs, &more);
+    krb5_free_principal(edit_context, kprinc);
+    if (retval) {
+       com_err("modify_entry", retval, "while getting \"%s\".",
+               canon);
+       free(canon);
+       return;
+    }
+    if (!nprincs) {
+       com_err(argv[0], 0, "No principal \"%s\" exists", canon);
+       exit_status++;
+       free(canon);
+       return;
+    }
+    memcpy((krb5_pointer) &entry, (krb5_pointer) &oldentry,
+          sizeof (krb5_db_entry));
+    retval = parse_princ_args(argc, argv,
+                             &entry, &pass, &randkey,
+                             "modify_principal");
+    if (retval) {
+       fprintf(stderr, "modify_principal: bad arguments\n");
+       krb5_free_principal(edit_context, entry.principal);
+       free(canon);
+       return;
+    }
+    if (randkey) {
+       fprintf(stderr, "modify_principal: -randkey not allowed\n");
+       krb5_free_principal(edit_context, entry.principal);
+       free(canon);
+       return;
+    }
+    entry.mod_name = master_princ;
+    if (retval = krb5_timeofday(edit_context, &entry.mod_date)) {
+       com_err(argv[0], retval, "while fetching date");
+       krb5_free_principal(edit_context, entry.principal);
+       exit_status++;
+       free(canon);
+       return;
+    }
+    retval = krb5_db_put_principal(edit_context, &entry, &one);
+    krb5_free_principal(edit_context, entry.principal);
+    if (retval) {
+       com_err("modify_principal", retval,
+               "while modifying \"%s\".", canon);
+       free(canon);
+       return;
+    }
+    if (one != 1) {
+       com_err(argv[0], 0, "entry not stored in database (unknown failure)");
+       exit_status++;
+    }
+    printf("Principal \"%s\" modified.\n", canon);
+    free(canon);
+}
+
+#ifdef HAVE_GETCWD
+#define getwd(x) getcwd(x,MAXPATHLEN)
+#endif
+
 void change_working_dir(argc, argv)
        int     argc;
        char    **argv;
@@ -1537,10 +1750,6 @@ void change_working_dir(argc, argv)
        }
 }
 
-#ifdef HAVE_GETCWD
-#define getwd(x) getcwd(x,MAXPATHLEN)
-#endif
-
 void print_working_dir(argc, argv)
        int     argc;
        char    **argv;