BSD 4_3_Net_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 25 Feb 1991 04:12:48 +0000 (20:12 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Mon, 25 Feb 1991 04:12:48 +0000 (20:12 -0800)
Work on file usr/src/contrib/rcs/src/ident.c
Work on file usr/src/contrib/rcs/src/rcsutil.c
Work on file usr/src/contrib/rcs/src/snoop.c
Work on file usr/src/contrib/rcs/src/rcslex.c
Work on file usr/src/contrib/rcs/src/rcsbase.h

Synthesized-from: CSRG/cd2/net.2

usr/src/contrib/rcs/src/ident.c [new file with mode: 0644]
usr/src/contrib/rcs/src/rcsbase.h [new file with mode: 0644]
usr/src/contrib/rcs/src/rcslex.c [new file with mode: 0644]
usr/src/contrib/rcs/src/rcsutil.c [new file with mode: 0644]
usr/src/contrib/rcs/src/snoop.c [new file with mode: 0644]

diff --git a/usr/src/contrib/rcs/src/ident.c b/usr/src/contrib/rcs/src/ident.c
new file mode 100644 (file)
index 0000000..622a899
--- /dev/null
@@ -0,0 +1,170 @@
+/* Copyright (C) 1982, 1988, 1989 Walter Tichy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Walter Tichy.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Report all problems and direct all questions to:
+ *   rcs-bugs@cs.purdue.edu
+ * 
+
+
+
+
+
+
+
+*/
+
+/*
+ *                     RCS identification operation
+ */
+#ifndef lint
+static char rcsid[]=
+"$Header: /usr/src/local/bin/rcs/src/RCS/ident.c,v 4.5 89/05/01 15:11:54 narten Exp $Purdue CS";
+#endif
+
+/* $Log:       ident.c,v $
+ * Revision 4.5  89/05/01  15:11:54  narten
+ * changed copyright header to reflect current distribution rules
+ * 
+ * Revision 4.4  87/10/23  17:09:57  narten
+ * added exit(0) so exit return code would be non random
+ * 
+ * Revision 4.3  87/10/18  10:23:55  narten
+ * Updating version numbers. Changes relative to 1.1 are actually relative
+ * to 4.1
+ * 
+ * Revision 1.3  87/07/09  09:20:52  trinkle
+ * Added check to make sure there is at least one arg before comparing argv[1]
+ * with "-q".  This necessary on machines that don't allow dereferncing null
+ * pointers (i.e. Suns).
+ * 
+ * Revision 1.2  87/03/27  14:21:47  jenkins
+ * Port to suns
+ * 
+ * Revision 1.1  84/01/23  14:50:03  kcs
+ * Initial revision
+ * 
+ * Revision 4.1  83/05/10  16:31:02  wft
+ * Added option -q and input from reading stdin.
+ * Marker matching is now done with trymatch() (independent of keywords).
+ * 
+ * Revision 3.4  83/02/18  17:37:49  wft
+ * removed printing of new line after last file.
+ *
+ * Revision 3.3  82/12/04  12:48:55  wft
+ * Added LOCKER.
+ *
+ * Revision 3.2  82/11/28  18:24:17  wft
+ * removed Suffix; added ungetc to avoid skipping over trailing KDELIM.
+ *
+ * Revision 3.1  82/10/13  15:58:51  wft
+ * fixed type of variables receiving from getc() (char-->int).
+*/
+
+#include  "rcsbase.h"
+#ifdef _FSTDIO
+#undef putc
+#define putc __sputc
+#else
+#define fflsbuf _flsbuf
+#endif
+/* redefinition of putc not needed */
+#ifndef lint
+static char rcsbaseid[] = RCSBASE;
+#endif
+
+extern enum markers trymatch();
+
+int quietflag;
+
+main(argc, argv)
+int  argc; char  *argv[];
+/*  Ident searches the named files for all occurrences
+ *  of the pattern $keyword:...$, where the keywords are
+ *  Author, Date, Header, Id, Log, RCSfile, Revision, Source, and State.
+ */
+
+{
+   FILE *fp, *fopen();
+
+   quietflag = false;
+   if (argc > 1 && strcmp("-q",argv[1])==0) {
+        quietflag = true;
+        argc--; argv++;
+   }
+
+   if (argc<2) {
+        if ((scanfile(stdin) == 0) && !quietflag)
+           VOID fprintf(stderr, "ident warning: no id keywords in input\n");
+       exit(0);
+   }
+
+   while ( --argc > 0 ) {
+      if ( (fp = fopen(*++argv, "r") ) == NULL ) {
+         VOID fprintf(stderr,  "ident error: can't open %s\n", *argv);
+         continue;
+      } else {
+         VOID printf( "%s:\n", *argv);   /*  print file name  */
+        if ((scanfile(fp) == 0) && !quietflag)
+           VOID fprintf(stderr, "ident warning: no id keywords in %s\n", *argv);
+        if (argc>1) putchar('\n');
+        VOID fclose(fp);
+      }
+   }
+   exit(0);
+}
+
+
+int scanfile(file)
+FILE * file;
+/* Function: scan an open file with descriptor file for keywords.
+ * Returns the number of matches.
+ */
+{
+   register int matchcount;
+   register int c;
+
+
+   matchcount = 0;
+   while( (c=getc(file)) != EOF) {
+      if ( (char)c==KDELIM)
+        matchcount += match(file);
+   }
+   return matchcount;
+}
+
+
+
+match(fp)   /* group substring between two KDELIM's; then do pattern match */
+FILE *fp;
+{
+   char line[keyvallength];
+   register int c;
+   register char * tp;
+
+   tp = line;
+   while( (c = getc(fp)) != KDELIM ) {
+      *tp++ = c;
+      if ( c==EOF || c=='\n' || tp>= line+keyvallength-2)
+         return(0);
+   }
+   *tp++ = c;     /*append trailing KDELIM*/
+   *tp   = '\0';
+   if (trymatch(line,true)!=Nomatch) {
+        VOID fprintf(stdout,"     $%s\n",line);
+        return(1);
+   } else {
+      /* no match; put trailing KDELIM back into input */
+      VOID ungetc(c,fp );
+      return(0);
+   }
+}
diff --git a/usr/src/contrib/rcs/src/rcsbase.h b/usr/src/contrib/rcs/src/rcsbase.h
new file mode 100644 (file)
index 0000000..ea1459a
--- /dev/null
@@ -0,0 +1,390 @@
+
+/*
+ *                     RCS common definitions and data structures
+ */
+#define RCSBASE "$Id: rcsbase.h,v 4.9 89/05/01 15:17:14 narten Exp $"
+
+/* Copyright (C) 1982, 1988, 1989 Walter Tichy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Walter Tichy.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Report all problems and direct all questions to:
+ *   rcs-bugs@cs.purdue.edu
+ * 
+
+
+
+
+
+
+
+*/
+
+
+
+/*****************************************************************************
+ * INSTRUCTIONS:
+ * =============
+ * The following should be handled in the Makefile:
+ *     For USG Unix, define USG; for BSD Unix, don't (see ifdef USG).
+ *     For 4.2 bsd, define V4_2BSD; this will replace the routines
+ *     getwd() and rename() with the corresponding ones in the C-library.
+ *     V4_2BSD also selects different definitions for the macros NCPFN and NCPPN
+ *     (max. number of characters per filename, number of characters per path name).
+ *     Define STRICT_LOCKING appropriately (see STRICT_LOCKING).
+ * The following need be changed for porting to a different machine:
+ *     Define SMALLOG for a machine with small memory (like the PDP11).
+ *     SMALLOG conserves space for log messages.
+ *     Change BYTESIZ if necessary.
+ * If you need to change the comment leaders, update the table comtable[]
+ * in rcsfnms.c. (This can wait until you know what a comment leader is.)
+ *****************************************************************************
+ */
+
+
+/* $Log:       rcsbase.h,v $
+ * Revision 4.9  89/05/01  15:17:14  narten
+ * botched previous USG fix 
+ * 
+ * Revision 4.8  89/05/01  14:53:05  narten
+ * changed #include <strings.h> -> string.h for USG systems.
+ * 
+ * Revision 4.7  88/11/08  15:58:45  narten
+ * removed defs for functions loaded from libraries
+ * 
+ * Revision 4.6  88/11/08  12:04:06  narten
+ * changes from eggert@sm.unisys.com (Paul Eggert)
+ * 
+ * Revision 4.6  88/08/09  19:12:36  eggert
+ * Shrink stdio code size; remove lint; permit -Dhshsize=nn.
+ * 
+ * Revision 4.5  87/12/18  17:06:41  narten
+ * made removed BSD ifdef, now uses V4_2BSD
+ * 
+ * Revision 4.4  87/10/18  10:29:49  narten
+ * Updating version numbers
+ * Changes relative to 1.1 are actually relative to 4.2
+ * 
+ * Revision 1.3  87/09/24  14:02:25  narten
+ * changes for lint
+ * 
+ * Revision 1.2  87/03/27  14:22:02  jenkins
+ * Port to suns
+ * 
+ * Revision 1.1  84/01/23  14:50:14  kcs
+ * Initial revision
+ * 
+ * Revision 4.2  83/12/20  16:04:20  wft
+ * merged 3.6.1.1 and 4.1 (SMALLOG, logsize).
+ * moved setting of STRICT_LOCKING to Makefile.
+ * changed DOLLAR to UNKN (conflict with KDELIM).
+ * 
+ * Revision 4.1  83/05/04  09:12:41  wft
+ * Added markers Id and RCSfile.
+ * Added Dbranch for default branches.
+ * 
+ * Revision 3.6.1.1  83/12/02  21:56:22  wft
+ * Increased logsize, added macro SMALLOG.
+ * 
+ * Revision 3.6  83/01/15  16:43:28  wft
+ * 4.2 prerelease
+ * 
+ * Revision 3.6  83/01/15  16:43:28  wft
+ * Replaced dbm.h with BYTESIZ, fixed definition of rindex().
+ * Added variants of NCPFN and NCPPN for bsd 4.2, selected by defining V4_2BSD.
+ * Added macro DELNUMFORM to have uniform format for printing delta text nodes.
+ * Added macro DELETE to mark deleted deltas.
+ *
+ * Revision 3.5  82/12/10  12:16:56  wft
+ * Added two forms of DATEFORM, one using %02d, the other %.2d.
+ *
+ * Revision 3.4  82/12/04  20:01:25  wft
+ * added LOCKER, Locker, and USG (redefinition of rindex).
+ *
+ * Revision 3.3  82/12/03  12:22:04  wft
+ * Added dbm.h, stdio.h, RCSBASE, RCSSEP, RCSSUF, WORKMODE, TMPFILE3,
+ * PRINTDATE, PRINTTIME, map, and ctab; removed Suffix. Redefined keyvallength
+ * using NCPPN. Changed putc() to abort on write error.
+ *
+ * Revision 3.2  82/10/18  15:03:52  wft
+ * added macro STRICT_LOCKING, removed RCSUMASK.
+ * renamed JOINFILE[1,2] to JOINFIL[1,2].
+ *
+ * Revision 3.1  82/10/11  19:41:17  wft
+ * removed NBPW, NBPC, NCPW.
+ * added typdef int void to aid compiling
+ */
+
+
+
+#include <stdio.h>
+#ifdef USG
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#undef putc         /* will be redefined */
+
+
+#ifdef USG
+#       define rindex    strrchr
+#       define DATEFORM  "%.2d.%.2d.%.2d.%.2d.%.2d.%.2d"
+#else
+#       define DATEFORM  "%02d.%02d.%02d.%02d.%02d.%02d"
+#endif
+/* Make sure one of %02d or %.2d prints a number with a field width 2, with
+ * leading zeroes. For example, 0, 1, and 22 must be printed as 00, 01, and
+ * 22. Otherwise, there will be problems with the dates.
+ */
+
+#define PRINTDATE(file,date) fprintf(file,"%.2s/%.2s/%.2s",date,date+3,date+6)
+#define PRINTTIME(file,date) fprintf(file,"%.2s:%.2s:%.2s",date+9,date+12,date+15)
+/* print RCS format date and time in nice format from a string              */
+
+/*
+ * Parameters
+ */
+#define BYTESIZ             8 /* number of bits in a byte                   */
+
+/*#define STRICT_LOCKING    0 /* 0 sets the default locking to non-strict;  */
+                              /* used in experimental environments.         */
+                              /* 1 sets the default locking to strict;      */
+                              /* used in production environments.           */
+                             /* STRICT_LOCKING is set in the Makefile!     */
+#ifndef hshsize
+#define hshsize           239 /* hashtable size; MUST be prime and -1 mod 4 */
+                              /* other choices: 547 or 719                  */
+#endif
+
+#define strtsize (hshsize * 50) /* string table size                        */
+#ifdef SMALLOG
+#  define logsize         1024 /* max. size of log message for pdp11        */
+#else
+#  define logsize         4096 /* max. size of log message for others       */
+#endif
+#define revlength          30 /* max. length of revision numbers            */
+#define datelength         20 /* length of a date in RCS format             */
+#define joinlength         20 /* number of joined revisions permitted       */
+#define RCSDIR         "RCS/" /* subdirectory for RCS files                 */
+#define RCSSUF            'v' /* suffix for RCS files                       */
+#define RCSSEP            ',' /* separator for RCSSUF                       */
+#define KDELIM            '$' /* delimiter for keywords                     */
+#define VDELIM            ':' /* separates keywords from values             */
+#define DEFAULTSTATE    "Exp" /* default state of revisions                 */
+#ifdef V4_2BSD
+#  define NCPFN           256 /* number of characters per filename          */
+#  define NCPPN          1024 /* number of characters per pathname          */
+#else
+#  define NCPFN            14 /* number of characters per filename          */
+#  define NCPPN       6*NCPFN /* number of characters per pathname          */
+#endif
+#define keylength          20 /* buffer length for expansion keywords       */
+#define keyvallength NCPPN+revlength+datelength+60
+                              /* buffer length for keyword expansion        */
+
+
+
+#define true     1
+#define false    0
+#define nil      0
+#define elsif    else if
+#define elif     else if
+
+
+/* temporary file names */
+
+#define NEWRCSFILE  ",RCSnewXXXXXX"
+#define DIFFILE     ",RCSciXXXXXX"
+#define TMPFILE1    ",RCSt1XXXXXX"
+#define TMPFILE2    ",RCSt2XXXXXX"
+#define TMPFILE3    ",RCSt3XXXXXX"
+#define JOINFIL2    ",RCSj2XXXXXX"
+#define JOINFIL3    ",RCSj3XXXXXX"
+
+
+#ifdef _FSTDIO
+#define putc(x,p) (--(p)->_w < 0 ? wbuf((unsigned)(x), p) : \
+                       (*(p)->_p = (x), (int)*(p)->_p++))
+#else
+#define putc(x,p) (--(p)->_cnt>=0? ((int)(*(p)->_ptr++=(unsigned)(x))):fflsbuf((unsigned)(x),p))
+#endif
+/* This version of putc prints a char, but aborts on write error            */
+
+#define GETC(in,out,echo) (c=getc(in), echo?putc(c,out):c)
+/* GETC modifies a local variable c; a kludge, but smaller and faster.      */
+/* GETC writes a del-character (octal 177) on end of file                   */
+
+#define WORKMODE(RCSmode) (RCSmode&~0222)|((lockflag||!StrictLocks)?0600:0000)
+/* computes mode of working file: same as RCSmode, but write permission     */
+/* determined by lockflag and StrictLocks.                                  */
+
+
+/* character classes and token codes */
+enum tokens {
+/* char classes*/  DIGIT, IDCHAR, NEWLN, LETTER, PERIOD, SBEGIN, SPACE, UNKN,
+/* tokens */       COLON, DATE, EOFILE, ID, KEYW, NUM, SEMI, STRING,
+};
+
+#define AT      SBEGIN  /* class SBEGIN (string begin) is returned by lex. anal. */
+#define SDELIM  '@'     /* the actual character is needed for string handling*/
+/* these must be changed consistently, for instance to:
+ * #define DQUOTE       SBEGIN
+ * #define SDELIM       '"'
+ * #define AT           IDCHAR
+ * there should be no overlap among SDELIM, KDELIM, and VDELIM
+ */
+
+/* other characters */
+
+#define ACCENT   IDCHAR
+#define AMPER    IDCHAR
+#define BACKSL   IDCHAR
+#define BAR      IDCHAR
+#define COMMA    UNKN
+#define DIVIDE   IDCHAR
+#define DOLLAR   UNKN                /* overlap with KDELIM */
+#define DQUOTE   IDCHAR
+#define EQUAL    IDCHAR
+#define EXCLA    IDCHAR
+#define GREAT    IDCHAR
+#define HASH     IDCHAR
+#define INSERT   UNKN
+#define LBRACE   IDCHAR
+#define LBRACK   IDCHAR
+#define LESS     IDCHAR
+#define LPARN    IDCHAR
+#define MINUS    IDCHAR
+#define PERCNT   IDCHAR
+#define PLUS     IDCHAR
+#define QUEST    IDCHAR
+#define RBRACE   IDCHAR
+#define RBRACK   IDCHAR
+#define RPARN    IDCHAR
+#define SQUOTE   IDCHAR
+#define TILDE    IDCHAR
+#define TIMES    IDCHAR
+#define UNDER    IDCHAR
+#define UPARR    IDCHAR
+
+
+
+
+/***************************************
+ * Data structures for the symbol table
+ ***************************************/
+
+
+/* Hash table entry */
+struct hshentry {
+        char              * num;      /* pointer to revision number (ASCIZ) */
+        char              * date;     /* pointer to date of checking        */
+        char              * author;   /* login of person checking in        */
+        char              * lockedby; /* who locks the revision             */
+        char              * log;      /* log message requested at checkin   */
+        char              * state;    /* state of revision (Exp by default) */
+        struct branchhead * branches; /* list of first revisions on branches*/
+        struct hshentry   * next;     /* next revision on same branch       */
+        int                 insertlns;/* lines inserted (computed by rlog)  */
+        int                 deletelns;/* lines deleted  (computed by rlog)  */
+        char                selector; /* marks entry for selection/deletion */
+};
+
+/* list element for branch lists */
+struct branchhead {
+        struct hshentry   * hsh;
+        struct branchhead * nextbranch;
+};
+
+/* accesslist element */
+struct access {
+        char              * login;
+        struct access     * nextaccess;
+};
+
+/* list element for locks  */
+struct lock {
+        char              * login;
+        struct hshentry   * delta;
+        struct lock       * nextlock;
+};
+
+/* list element for symbolic names */
+struct assoc {
+        char              * symbol;
+        struct hshentry   * delta;
+        struct assoc      * nextassoc;
+};
+
+
+/* common variables (getadmin and getdelta())*/
+extern char            * Comment;
+extern struct access   * AccessList;
+extern struct assoc    * Symbols;
+extern struct lock     * Locks;
+extern struct hshentry * Head;
+extern struct hshentry * Dbranch;
+extern int               StrictLocks;
+extern int               TotalDeltas;
+#ifndef lint
+static char copyright[]="Copyright (C) 1982 by Walter F. Tichy";
+#endif
+
+/* common variables (lexical analyzer)*/
+extern enum tokens map[];
+#define ctab (&map[1])
+extern enum tokens       nexttok;
+extern int               hshenter;
+extern char            * NextString;
+extern char            * cmdid;
+
+#if defined(USG) || defined(V4_2BSD)
+#define VOID   (void)
+#else
+typedef int void;
+#define VOID
+#endif
+
+/* common routines */
+extern char *talloc();
+extern int serror();
+extern int faterror();
+extern int fatserror();
+extern void ignoreints();
+extern void catchints();
+extern void restoreints();
+
+#ifdef USG
+extern int sprintf();
+#endif
+
+/*
+ * Markers for keyword expansion (used in co and ident)
+ */
+#define AUTHOR          "Author"
+#define DATE            "Date"
+#define HEADER          "Header"
+#define IDH             "Id"
+#define LOCKER          "Locker"
+#define LOG             "Log"
+#define RCSFILE         "RCSfile"
+#define REVISION        "Revision"
+#define SOURCE          "Source"
+#define STATE           "State"
+
+enum markers { Nomatch, Author, Date, Header, Id,
+              Locker, Log, RCSfile, Revision, Source, State };
+
+#define DELNUMFORM      "\n\n%s\n%s\n"
+/* used by putdtext and scanlogtext */
+#define DELETE          'D'
+/* set by rcs -o and used by puttree() in rcssyn */
+
diff --git a/usr/src/contrib/rcs/src/rcslex.c b/usr/src/contrib/rcs/src/rcslex.c
new file mode 100644 (file)
index 0000000..1d0bce2
--- /dev/null
@@ -0,0 +1,807 @@
+/*
+ *                     RCS file input
+ */
+#ifndef lint
+static char rcsid[]= "$Id: rcslex.c,v 4.6 89/05/01 15:13:07 narten Exp $ Purdue CS";
+#endif
+/*********************************************************************************
+ *                     Lexical Analysis.
+ *                     Character mapping table,
+ *                     hashtable, Lexinit, nextlex, getlex, getkey,
+ *                     getid, getnum, readstring, printstring, savestring,
+ *                     checkid, serror, fatserror, error, faterror, warn, diagnose
+ *                     fflsbuf, puts, fprintf
+ *                     Testprogram: define LEXDB
+ *********************************************************************************
+ */
+
+/* Copyright (C) 1982, 1988, 1989 Walter Tichy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Walter Tichy.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Report all problems and direct all questions to:
+ *   rcs-bugs@cs.purdue.edu
+ * 
+
+
+
+
+
+
+
+*/
+
+
+
+/* $Log:       rcslex.c,v $
+ * Revision 4.6  89/05/01  15:13:07  narten
+ * changed copyright header to reflect current distribution rules
+ * 
+ * Revision 4.5  88/11/08  12:00:54  narten
+ * changes from  eggert@sm.unisys.com (Paul Eggert)
+ * 
+ * Revision 4.5  88/08/28  15:01:12  eggert
+ * Don't loop when writing error messages to a full filesystem.
+ * Flush stderr/stdout when mixing output.
+ * Yield exit status compatible with diff(1).
+ * Shrink stdio code size; allow cc -R; remove lint.
+ * 
+ * Revision 4.4  87/12/18  11:44:47  narten
+ * fixed to use "varargs" in "fprintf"; this is required if it is to
+ * work on a SPARC machine such as a Sun-4
+ * 
+ * Revision 4.3  87/10/18  10:37:18  narten
+ * Updating version numbers. Changes relative to 1.1 actually relative
+ * to version 4.1
+ * 
+ * Revision 1.3  87/09/24  14:00:17  narten
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
+ * warnings)
+ * 
+ * Revision 1.2  87/03/27  14:22:33  jenkins
+ * Port to suns
+ * 
+ * Revision 1.1  84/01/23  14:50:33  kcs
+ * Initial revision
+ * 
+ * Revision 4.1  83/03/25  18:12:51  wft
+ * Only changed $Header to $Id.
+ * 
+ * Revision 3.3  82/12/10  16:22:37  wft
+ * Improved error messages, changed exit status on error to 1.
+ *
+ * Revision 3.2  82/11/28  21:27:10  wft
+ * Renamed ctab to map and included EOFILE; ctab is now a macro in rcsbase.h.
+ * Added fflsbuf(), fputs(), and fprintf(), which abort the RCS operations
+ * properly in case there is an IO-error (e.g., file system full).
+ *
+ * Revision 3.1  82/10/11  19:43:56  wft
+ * removed unused label out:;
+ * made sure all calls to getc() return into an integer, not a char.
+ */
+
+
+/*
+#define LEXDB
+/* version LEXDB is for testing the lexical analyzer. The testprogram
+ * reads a stream of lexemes, enters the revision numbers into the
+ * hashtable, and prints the recognized tokens. Keywords are recognized
+ * as identifiers.
+ */
+
+
+
+#include "rcsbase.h"
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+
+
+/* character mapping table */
+enum tokens map[] = {
+        EOFILE,         /* this will end up at ctab[-1] */
+        UNKN,   INSERT, UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
+        UNKN,   SPACE,  NEWLN,  UNKN,   SPACE,  UNKN,   UNKN,   UNKN,
+        UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
+        UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
+        SPACE,  EXCLA,  DQUOTE, HASH,   DOLLAR, PERCNT, AMPER,  SQUOTE,
+        LPARN,  RPARN,  TIMES,  PLUS,   COMMA,  MINUS,  PERIOD, DIVIDE,
+        DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,
+        DIGIT,  DIGIT,  COLON,  SEMI,   LESS,   EQUAL,  GREAT,  QUEST,
+        AT,     LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+        LETTER, LETTER, LETTER, LBRACK, BACKSL, RBRACK, UPARR,  UNDER,
+        ACCENT, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+        LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+        LETTER, LETTER, LETTER, LBRACE, BAR,    RBRACE, TILDE,  UNKN
+};
+
+
+
+
+struct hshentry * nexthsh;  /*pointer to next hashtable-entry, set by lookup*/
+
+enum tokens     nexttok;    /*next token, set by nextlex                    */
+
+int             hshenter;   /*if true, next suitable lexeme will be entered */
+                            /*into the symbol table. Handle with care.      */
+int             nextc;      /*next input character, initialized by Lexinit  */
+
+int             eof;        /*end-of-file indicator, set to >0 on end of file*/
+int             line;       /*current line-number of input                  */
+int             nerror;     /*counter for errors                            */
+int             nwarn;      /*counter for warnings                          */
+char *          cmdid;      /*command identification for error messages     */
+int             quietflag;  /*indicates quiet mode                          */
+FILE *          finptr;     /*input file descriptor                         */
+
+FILE *          frewrite;   /*file descriptor for echoing input             */
+
+int             rewriteflag;/*indicates whether to echo to frewrite         */
+
+char            StringTab[strtsize]; /* string table and heap               */
+
+char *          NextString;         /*pointer to next identifier in StringTab*/
+char *          Topchar;            /*pointer to next free byte in StringTab*/
+                                    /*set by nextlex, lookup                */
+struct hshentry hshtab[hshsize];    /*hashtable                             */
+
+
+
+
+
+lookup() {
+
+/* Function: Looks up the character string pointed to by NextString in the
+ * hashtable. If the string is not present, a new entry for it is created.
+ * If the string is present, TopChar is moved back to save the space for
+ * the string, and NextString is set to point to the original string.
+ * In any case, the address of the corresponding hashtable entry is placed
+ * into nexthsh.
+ * Algorithm: Quadratic hash, covering all entries.
+ * Assumptions: NextString points at the first character of the string.
+ * Topchar points at the first empty byte after the string.
+ */
+
+        register int     ihash;      /* index into hashtable */
+        register char    * sp, * np;
+        int              c, delta, final, FirstScan; /*loop control*/
+
+        /* calculate hash code */
+        sp = NextString;
+        ihash = 0;
+        while (*sp) ihash += *sp++;
+
+        /* set up first search loop (c=0,step=1,until (hshsiz-1)/2 */
+        c=0;delta=1;final=(hshsize-1)/2;
+        FirstScan=true;   /*first loop */
+
+        for (;;) {
+                ihash = (ihash+c)%hshsize;   /*next index*/
+
+                if (hshtab[ihash].num == nil) {
+                        /*empty slot found*/
+                        hshtab[ihash].num = NextString;
+                        nexthsh= &hshtab[ihash];/*save hashtable address*/
+#                       ifdef LEXDB
+                        VOID printf("\nEntered: %s at %d ",nexthsh->num, ihash);
+#                       endif
+                        return;
+                }
+                /* compare strings */
+                sp=NextString;np=hshtab[ihash].num;
+                while (*sp == *np++) {
+                        if (*sp == 0) {
+                                /* match found */
+                                nexthsh= &hshtab[ihash];
+                                Topchar = NextString;
+                                NextString = nexthsh->num;
+                                return;
+                        } else sp++;
+                }
+
+                /* neither empty slot nor string found */
+                /* calculate next index and repeat */
+                if (c != final)
+                        c += delta;
+                else {
+                        if (FirstScan) {
+                                /*set up second sweep*/
+                                delta = -1; final = 1; FirstScan= false;
+                        } else {
+                                fatserror("Hashtable overflow");
+                        }
+                }
+        }
+};
+
+
+
+
+
+
+Lexinit()
+/* Function: Initialization of lexical analyzer:
+ * initializes the hastable,
+ * initializes nextc, nexttok if finptr != NULL
+ */
+{       register int            c;
+
+        for (c=hshsize-1; c>=0; c--) {
+                hshtab[c].num = nil;
+        }
+
+        hshenter=true; eof=0; line=1; nerror=0; nwarn=0;
+        NextString=nil; Topchar = &StringTab[0];
+        if (finptr) {
+                nextc = GETC(finptr,frewrite,rewriteflag); /*initial character*/
+                nextlex();            /*initial token*/
+        } else {
+                nextc = '\0';
+                nexttok=EOFILE;
+        }
+}
+
+
+
+
+
+
+
+nextlex()
+
+/* Function: Reads the next token and sets nexttok to the next token code.
+ * Only if the hshenter==true, a revision number is entered into the
+ * hashtable and a pointer to it is placed into nexthsh.
+ * This is useful for avoiding that dates are placed into the hashtable.
+ * For ID's and NUM's, NextString is set to the character string in the
+ * string table. Assumption: nextc contains the next character.
+ */
+{       register c;
+       register FILE * fin, * frew;
+        register char * sp;
+        register enum tokens d;
+
+        if (eof) {
+                nexttok=EOFILE;
+                return;
+        }
+       fin=finptr; frew=frewrite;
+loop:
+        switch(nexttok=ctab[nextc]) {
+
+        case UNKN:
+        case IDCHAR:
+        case PERIOD:
+                serror("unknown Character: %c",nextc);
+                nextc=GETC(fin,frew,rewriteflag);
+                goto loop;
+
+        case NEWLN:
+                line++;
+#               ifdef LEXDB
+                VOID putchar('\n');
+#               endif
+                /* Note: falls into next case */
+
+        case SPACE:
+                nextc=GETC(fin,frew,rewriteflag);
+                goto loop;
+
+        case EOFILE:
+                eof++;
+                nexttok=EOFILE;
+                return;
+
+        case DIGIT:
+                NextString = sp = Topchar;
+                *sp++ = nextc;
+                while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==DIGIT ||
+                        d==PERIOD) {
+                        *sp++ = c;         /* 1.2. and 1.2 are different */
+                }
+                *sp++ = '\0';
+                if (sp >= StringTab+strtsize) {
+                        /*may have written outside stringtable already*/
+                        fatserror("Stringtable overflow");
+                }
+                Topchar = sp;
+                nextc = c;
+                if (hshenter == true)
+                        lookup();      /* lookup updates NextString, Topchar*/
+                nexttok = NUM;
+                return;
+
+
+        case LETTER:
+                NextString = sp = Topchar;
+                *sp++ = nextc;
+                while ((d=ctab[c=GETC(fin,frew,rewriteflag)])==LETTER ||
+                        d==DIGIT || d==IDCHAR) {
+                        *sp++ = c;
+                }
+                *sp++ = '\0';
+                if (sp >= StringTab+strtsize) {
+                        /*may have written outside stringtable already*/
+                        fatserror("Stringtable overflow");
+                }
+                Topchar = sp;
+                nextc = c;
+                nexttok = ID;  /* may be ID or keyword */
+                return;
+
+        case SBEGIN: /* long string */
+                nexttok = STRING;
+                /* note: only the initial SBEGIN has been read*/
+                /* read the string, and reset nextc afterwards*/
+                return;
+
+        default:
+                nextc=GETC(fin,frew,rewriteflag);
+                return;
+        }
+}
+
+
+int getlex(token)
+enum tokens token;
+/* Function: Checks if nexttok is the same as token. If so,
+ * advances the input by calling nextlex and returns true.
+ * otherwise returns false.
+ * Doesn't work for strings and keywords; loses the character string for ids.
+ */
+{
+        if (nexttok==token) {
+                nextlex();
+                return(true);
+        } else  return(false);
+}
+
+int getkey (key)
+char * key;
+/* Function: If the current token is a keyword identical to key,
+ * getkey advances the input by calling nextlex and returns true;
+ * otherwise returns false.
+ */
+{
+        register char *s1,*s2;
+
+        if (nexttok==ID) {
+                s1=key; s2=NextString;
+                while(*s1 == *s2++)
+                     if (*s1++ == '\0') {
+                         /* match found */
+                         Topchar = NextString; /*reset Topchar */
+                         nextlex();
+                         return(true);
+                     }
+        }
+        return(false);
+}
+
+
+
+char * getid()
+/* Function: Checks if nexttok is an identifier. If so,
+ * advances the input by calling nextlex and returns a pointer
+ * to the identifier; otherwise returns nil.
+ * Treats keywords as identifiers.
+ */
+{
+        register char * name;
+        if (nexttok==ID) {
+                name = NextString;
+                nextlex();
+                return name;
+        } else  return nil;
+}
+
+
+struct hshentry * getnum()
+/* Function: Checks if nexttok is a number. If so,
+ * advances the input by calling nextlex and returns a pointer
+ * to the hashtable entry. Otherwise returns nil.
+ * Doesn't work if hshenter is false.
+ */
+{
+        register struct hshentry * num;
+        if (nexttok==NUM) {
+                num=nexthsh;
+                nextlex();
+                return num;
+        } else  return nil;
+}
+
+
+readstring()
+/* skip over characters until terminating single SDELIM        */
+/* if rewriteflag==true, copy every character read to frewrite.*/
+/* Does not advance nextlex at the end.                        */
+{       register c;
+       register FILE * fin,  * frew;
+       fin=finptr; frew=frewrite;
+        if (rewriteflag) {
+                /* copy string verbatim to frewrite */
+                while ((c=getc(fin)) != EOF) {
+                       VOID putc(c,frew);
+                        if (c==SDELIM) {
+                                if ((c=getc(fin)) == EOF || putc(c,frew) != SDELIM) {
+                                        /* end of string */
+                                        nextc=c;
+                                        return;
+                                }
+                        }
+                }
+        } else {
+                /* skip string */
+                while ((c=getc(fin)) != EOF) {
+                        if (c==SDELIM) {
+                                if ((c=getc(fin)) != SDELIM) {
+                                        /* end of string */
+                                        nextc=c;
+                                        return;
+                                }
+                        }
+                }
+        }
+        nextc = c;
+        error("Unterminated string");
+}
+
+
+printstring()
+/* Function: copy a string to stdout, until terminated with a single SDELIM.
+ * Does not advance nextlex at the end.
+ */
+{
+        register c;
+       register FILE * fin;
+       fin=finptr;
+       while ((c=getc(fin)) != EOF) {
+                if (c==SDELIM) {
+                       if ((c=getc(fin)) != SDELIM) {
+                                /* end of string */
+                                nextc=c;
+                                return;
+                        }
+                }
+                VOID putchar(c);
+        }
+        nextc = c;
+        error("Unterminated string");
+}
+
+
+
+savestring(target,length)
+char * target; int length;
+/* copies a string terminated with SDELIM from file finptr to buffer target,
+ * but not more than length bytes. If the string is longer than length,
+ * the extra characters are skipped. The string may be empty, in which
+ * case a '\0' is placed into target.
+ * Double SDELIM is replaced with SDELIM.
+ * If rewriteflag==true, the string is also copied unchanged to frewrite.
+ * Returns the length of the saved string.
+ * Does not advance nextlex at the end.
+ */
+{
+        register c;
+       register FILE * fin, * frew;
+        register char * tp, * max;
+
+       fin=finptr; frew=frewrite;
+        tp=target; max= target+length; /*max is one too large*/
+        while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
+               *tp++ =c;
+                if (c== SDELIM) {
+                        if ((c=GETC(fin,frew,rewriteflag))!=SDELIM) {
+                                /* end of string */
+                                *(tp-1)='\0';
+                                nextc=c;
+                                return;
+                        }
+                }
+                if (tp >= max) {
+                        /* overflow */
+                        error("string buffer overflow -- truncating string");
+                        target[length-1]='\0';
+                        /* skip rest of string */
+                        while ((c=GETC(fin,frew,rewriteflag))!=EOF) {
+                                if ((c==SDELIM) && ((c=GETC(fin,frew,rewriteflag))!=SDELIM)) {
+                                        /* end of string */
+                                        nextc=c;
+                                        return;
+                                }
+                        }
+                        nextc = c;
+                        error("Can't find %c to terminate string before end of file",SDELIM);
+                        return;
+                }
+        }
+        nextc = c;
+        error("Can't find %c to terminate string before end of file",SDELIM);
+}
+
+
+char  *checkid(id, delim)
+char    *id, delim;
+/*   Function:  check whether the string starting at id is an   */
+/*              identifier and return a pointer to the last char*/
+/*              of the identifer. White space, delim and '\0'   */
+/*              are legal delimeters. Aborts the program if not */
+/*              a legal identifier. Useful for checking commands*/
+{
+        register enum  tokens  d;
+        register char    *temp;
+        register char    c,tc;
+
+        temp = id;
+        if ( ctab[*id] == LETTER ) {
+            while( (d=ctab[c=(*++id)]) == LETTER || d==DIGIT || d==IDCHAR) ;
+            if ( c!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) {
+                /* append \0 to end of id before error message */
+                tc = c;
+                while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
+                *id = '\0';
+                faterror("Invalid character %c in identifier %s",tc,temp);
+                return nil ;
+            } else
+                return id;
+        } else {
+            /* append \0 to end of id before error message */
+            while( (c=(*++id))!=' ' && c!='\t' && c!='\n' && c!='\0' && c!=delim) ;
+            *id = '\0';
+            faterror("Identifier %s does not start with letter",temp);
+            return nil;
+        }
+}
+
+writeerror()
+{
+       static looping;
+       if (looping)
+               exit(2);
+       looping = 1;
+       faterror("write error");
+}
+
+nlflush(iop)
+register FILE * iop;
+{
+       if (putc('\n',iop)==EOF || fflush(iop)==EOF)
+                writeerror();
+}
+
+
+/*VARARGS1*/
+serror(e,e1,e2,e3,e4,e5)
+char * e, * e1, * e2, * e3, * e4, * e5;
+/* non-fatal syntax error */
+{       nerror++;
+        VOID fprintf(stderr,"%s error, line %d: ", cmdid, line);
+        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
+        nlflush(stderr);
+}
+
+/*VARARGS1*/
+error(e,e1,e2,e3,e4,e5)
+char * e, * e1, * e2, * e3, * e4, * e5;
+/* non-fatal error */
+{       nerror++;
+        VOID fprintf(stderr,"%s error: ",cmdid);
+        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
+        nlflush(stderr);
+}
+
+/*VARARGS1*/
+fatserror(e,e1,e2,e3,e4,e5)
+char * e, * e1, * e2, * e3, * e4, * e5;
+/* fatal syntax error */
+{       nerror++;
+        VOID fprintf(stderr,"%s error, line %d: ", cmdid,line);
+        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
+        VOID fprintf(stderr,"\n%s aborted\n",cmdid);
+        VOID cleanup();
+        exit(2);
+}
+
+/*VARARGS1*/
+faterror(e,e1,e2,e3,e4,e5)
+char * e, * e1, * e2, * e3, * e4, * e5;
+/* fatal error, terminates program after cleanup */
+{       nerror++;
+        VOID fprintf(stderr,"%s error: ",cmdid);
+        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
+        VOID fprintf(stderr,"\n%s aborted\n",cmdid);
+        VOID cleanup();
+        exit(2);
+}
+
+/*VARARGS1*/
+warn(e,e1,e2,e3,e4,e5)
+char * e, * e1, * e2, * e3, * e4, * e5;
+/* prints a warning message */
+{       nwarn++;
+        VOID fprintf(stderr,"%s warning: ",cmdid);
+        VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
+        nlflush(stderr);
+}
+
+
+/*VARARGS1*/
+diagnose(e,e1,e2,e3,e4,e5)
+char * e, * e1, * e2, * e3, * e4, * e5;
+/* prints a diagnostic message */
+{
+        if (!quietflag) {
+                VOID fprintf(stderr,e, e1, e2, e3, e4, e5);
+                nlflush(stderr);
+        }
+}
+
+
+
+#ifdef _FSTDIO
+wbuf(c, fp)
+       unsigned c;
+       register FILE *fp;
+{
+       register int result;
+
+       if ((result = __sputc(c, fp)) == EOF)
+               writeerror();
+       return result;
+}
+#else
+fflsbuf(c, iop)
+unsigned c; register FILE * iop;
+/* Function: Flush iop.
+ * Same routine as _flsbuf in stdio, but aborts program on error.
+ */
+{       register result;
+        if ((result=_flsbuf(c,iop))==EOF)
+                writeerror();
+        return result;
+}
+#endif
+
+
+#ifdef _FSTDIO
+fputs(s, iop)
+       const char *s;
+       FILE *iop;
+{
+
+       VOID fprintf(iop, "%s", s);
+       return 0;
+}
+#else
+fputs(s, iop)
+register char *s;
+register FILE *iop;
+/* Function: Put string s on file iop, abort on error.
+ * Same as puts in stdio, but with different putc macro.
+ */
+{
+       register r;
+       register c;
+
+       while (c = *s++)
+               r = putc(c, iop);
+       return(r);
+}
+#endif
+
+
+
+#if __STDC__
+fprintf(FILE *iop, const char *fmt, ...)
+#else
+fprintf(iop, fmt, va_alist)
+FILE *iop;
+const char *fmt;
+va_dcl
+#endif
+/* Function: formatted output. Same as fprintf in stdio,
+ * but aborts program on error
+ */
+{
+       register int value;
+       va_list ap;
+
+#ifdef __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+#ifdef VFPRINTF
+       VOID vfprintf(iop, fmt, ap);
+#else
+       _doprnt(fmt, ap, iop);
+#endif
+        if (ferror(iop)) {
+               writeerror();
+                value = EOF;
+        } else value = 0;
+       va_end(ap);
+       return value;
+}
+
+
+
+#ifdef LEXDB
+/* test program reading a stream of lexems and printing the tokens.
+ */
+
+
+
+main(argc,argv)
+int argc; char * argv[];
+{
+        cmdid="lextest";
+        if (argc<2) {
+                VOID fputs("No input file\n",stderr);
+                exit(1);
+        }
+        if ((finptr=fopen(argv[1], "r")) == NULL) {
+                faterror("Can't open input file %s\n",argv[1]);
+        }
+        Lexinit();
+        rewriteflag=false;
+        while (nexttok != EOFILE) {
+        switch (nexttok) {
+
+        case ID:
+                VOID printf("ID: %s",NextString);
+                break;
+
+        case NUM:
+                if (hshenter==true)
+                   VOID printf("NUM: %s, index: %d",nexthsh->num, nexthsh-hshtab);
+                else
+                   VOID printf("NUM, unentered: %s",NextString);
+                hshenter = !hshenter; /*alternate between dates and numbers*/
+                break;
+
+        case COLON:
+                VOID printf("COLON"); break;
+
+        case SEMI:
+                VOID printf("SEMI"); break;
+
+        case STRING:
+                readstring();
+                VOID printf("STRING"); break;
+
+        case UNKN:
+                VOID printf("UNKN"); break;
+
+        default:
+                VOID printf("DEFAULT"); break;
+        }
+        VOID printf(" | ");
+        nextlex();
+        }
+        VOID printf("\nEnd of lexical analyzer test\n");
+}
+
+cleanup()
+/* dummy */
+{}
+
+
+#endif
diff --git a/usr/src/contrib/rcs/src/rcsutil.c b/usr/src/contrib/rcs/src/rcsutil.c
new file mode 100644 (file)
index 0000000..2fcc98c
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ *                     RCS utilities
+ */
+#ifndef lint
+static char rcsid[]= "$Id: rcsutil.c,v 4.6 89/05/01 15:13:40 narten Exp $ Purdue CS";
+#endif
+
+/* Copyright (C) 1982, 1988, 1989 Walter Tichy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Walter Tichy.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Report all problems and direct all questions to:
+ *   rcs-bugs@cs.purdue.edu
+ * 
+
+
+
+
+
+
+
+*/
+
+
+
+
+/* $Log:       rcsutil.c,v $
+ * Revision 4.6  89/05/01  15:13:40  narten
+ * changed copyright header to reflect current distribution rules
+ * 
+ * Revision 4.5  88/11/08  16:01:02  narten
+ * corrected use of varargs routines
+ * 
+ * Revision 4.4  88/11/08  12:00:28  narten
+ * changes from  eggert@sm.unisys.com (Paul Eggert)
+ * 
+ * Revision 4.4  88/08/09  19:13:24  eggert
+ * Check for memory exhaustion.
+ * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
+ * Use execv(), not system(); yield exit status like diff(1)'s.
+ * 
+ * Revision 4.3  87/10/18  10:40:22  narten
+ * Updating version numbers. Changes relative to 1.1 actually
+ * relative to 4.1
+ * 
+ * Revision 1.3  87/09/24  14:01:01  narten
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
+ * warnings)
+ * 
+ * Revision 1.2  87/03/27  14:22:43  jenkins
+ * Port to suns
+ * 
+ * Revision 1.1  84/01/23  14:50:43  kcs
+ * Initial revision
+ * 
+ * Revision 4.1  83/05/10  15:53:13  wft
+ * Added getcaller() and findlock().
+ * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
+ * (needed for background jobs in older shells). Added restoreints().
+ * Removed printing of full RCS path from logcommand().
+ * 
+ * Revision 3.8  83/02/15  15:41:49  wft
+ * Added routine fastcopy() to copy remainder of a file in blocks.
+ *
+ * Revision 3.7  82/12/24  15:25:19  wft
+ * added catchints(), ignoreints() for catching and ingnoring interrupts;
+ * fixed catchsig().
+ *
+ * Revision 3.6  82/12/08  21:52:05  wft
+ * Using DATEFORM to format dates.
+ *
+ * Revision 3.5  82/12/04  18:20:49  wft
+ * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
+ * lockedby-field.
+ *
+ * Revision 3.4  82/12/03  17:17:43  wft
+ * Added check to addlock() ensuring only one lock per person.
+ * Addlock also returns a pointer to the lock created. Deleted fancydate().
+ *
+ * Revision 3.3  82/11/27  12:24:37  wft
+ * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
+ * Introduced macro SNOOP so that snoop can be placed in directory other than
+ * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
+ *
+ * Revision 3.2  82/10/18  21:15:11  wft
+ * added function getfullRCSname().
+ *
+ * Revision 3.1  82/10/13  16:17:37  wft
+ * Cleanup message is now suppressed in quiet mode.
+ */
+
+
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include "rcsbase.h"
+#include <pwd.h>
+#include <varargs.h>
+
+#if defined(USG) || defined(V4_2BSD)
+#include <fcntl.h>
+#endif
+
+#ifndef V4_2BSD
+#define vfork fork
+#endif
+
+extern char * bindex();
+extern FILE * finptr;
+extern char * RCSfilename;
+extern char * getlogin();
+extern char * malloc();
+
+
+char * talloc(size)
+unsigned size;
+{
+       char * p;
+       if (!(p = malloc(size))) {
+               faterror("out of memory");
+       }
+       return p;
+}
+
+
+
+char * getcaller()
+/* Function: gets the callers login from his uid.
+ * If the uid is root, tries to get the true login with getlogin().
+ */
+{
+       struct passwd *pw;
+       char *name;
+       static int special_user();
+
+       pw = getpwuid(getuid());
+       if (pw == NULL || special_user(name = pw->pw_name))
+               if ((name = getlogin()) == NULL || *name == 0)
+                       name = pw == NULL ? "nobody" : pw->pw_name;
+       return (name);
+}
+
+static
+special_user(s)
+       register char *s;
+{
+       register char **p;
+       static char *u[] = { "root", "daemon", "bin", "news", 0 };
+
+       for (p = u; *p; p++)
+               if (**p == *s && strcmp(*p, s) == 0)
+                       return (1);
+       return (0);
+}
+
+
+struct hshentry * findlock(who,delete)
+char * who; int delete;
+/* Finds the first lock held by who and returns a pointer
+ * to the locked delta; also removes the lock if delete==true.
+ * Returns nil if there is no lock held by who.
+ */
+{
+        register struct lock * next, * trail;
+        struct lock dummy;
+
+        dummy.nextlock=next=Locks;
+        trail = &dummy;
+        while (next!=nil) {
+                if(strcmp(who,next->login)==0) break; /*found a lock*/
+                trail=next;
+                next=next->nextlock;
+        }
+        if (next!=nil) {
+               /* found one */
+               if (delete) {
+                   /* delete it */
+                   trail->nextlock=next->nextlock;
+                   Locks=dummy.nextlock;
+                   next->delta->lockedby=nil; /* reset locked-by */
+               }
+                return next->delta;
+        } else  return nil;
+}
+
+
+
+
+
+
+
+struct lock * addlock(delta,who)
+struct hshentry * delta; char * who;
+/* Given a delta, addlock checks whether
+ * the delta is locked by somebody other than who.
+ * If so, an error message is printed, and false returned.
+ * If the delta is not reserved at all, a lock for it is added,
+ * and a pointer for the lock returned.
+ */
+{
+        struct lock * next;
+
+        next=Locks;
+        while (next!=nil) {
+                if (cmpnum(delta->num,next->delta->num)==0) {
+                        if (strcmp(who,next->login)==0)
+                                return next;
+                                /* lock exists already */
+                        else {
+                                error("revision %s already locked by %s",
+                                      delta->num, next->login);
+                                return false;
+                        }
+                } else {
+                        if (strcmp(who,next->login)==0) {
+                                error("you already locked %s; only one lock allowed per person.",
+                                       next->delta->num);
+                                return false;
+                        } else {
+                                next=next->nextlock;
+                        }
+                }
+        }
+        /* not found; set up new lockblock */
+        next= (struct lock *) talloc(sizeof (struct lock));
+        delta->lockedby=next->login=who;
+        next->delta= delta;
+        next->nextlock=Locks;
+        Locks=next;
+        return next;
+}
+
+
+
+int addsymbol(delta,name,rebind)
+struct hshentry * delta; char * name; int rebind;
+/* Function: adds a new symbolic name and associates it with node delta.
+ * If name already exists and rebind is true, the name is associated
+ * with the new delta; otherwise, an error message is printed and
+ * false returned. Returns true it successful.
+ */
+{       register struct assoc * next;
+        next=Symbols;
+        while (next!=nil) {
+                if (strcmp(name,next->symbol)==0) {
+                        if (rebind) {
+                                next->delta=delta;
+                                return true;
+                        } else {
+                                error("symbolic name %s already bound to %s",
+                                        name,next->delta->num);
+                                return false;
+                        }
+                } else  next = next->nextassoc;
+        }
+        /* not found; insert new pair. */
+        next = (struct assoc *) talloc(sizeof(struct assoc));
+        next->symbol=name;
+        next->delta=delta;
+        next->nextassoc=Symbols;
+        Symbols = next;
+        return true;
+}
+
+
+
+
+int checkaccesslist(who)
+char * who;
+/* function: Returns true if who is the superuser, the owner of the
+ * file, the access list is empty, or who is on the access list.
+ * Prints an error message and returns false otherwise.
+ */
+{
+        register struct access * next;
+        struct stat statbuf;
+
+        if ((AccessList==nil) || (strcmp(who,"root")==0))
+                return true;
+
+        next=AccessList;
+        do {
+                if (strcmp(who,next->login)==0)
+                        return true;
+                next=next->nextaccess;
+        } while (next!=nil);
+
+        VOID fstat(fileno(finptr),&statbuf);  /* get owner of file */
+        if (getuid() == statbuf.st_uid) return true;
+
+        error("User %s not on the access list",who);
+        return false;
+}
+
+
+static SIGNAL_TYPE catchsig(s)
+{
+       ignoreints();
+        diagnose("\nRCS: cleaning up\n");
+        VOID cleanup();
+       exit(2);
+#ifdef lint
+       catchsig(s);
+#endif
+}
+
+static sig[] = {SIGINT,SIGHUP,SIGQUIT,SIGPIPE,SIGTERM};
+#define SIGS (sizeof(sig)/sizeof(*sig))
+static SIGNAL_TYPE (*catcher[SIGS])();
+  
+  void catchints()
+  {
+       register i;
+       for (i=SIGS; 0<=--i; )
+           catcher[i]  =
+               signal(sig[i],SIG_IGN) == SIG_IGN  ?  SIG_IGN  :  catchsig;
+       restoreints();
+  }
+
+  void ignoreints()
+  {
+       register i;
+       for (i=SIGS; 0<=--i; )
+               VOID signal(sig[i], SIG_IGN);
+  }
+
+void restoreints()
+{
+       register i;
+       for (i=SIGS; 0<=--i; )
+               if (catcher[i] != SIG_IGN)
+                       VOID signal(sig[i], catcher[i]);
+}
+
+fastcopy(inf,outf)
+FILE * inf, * outf;
+/* Function: copies the remainder of file inf to outf. First copies the
+ * rest that is in the IO-buffer of inf character by character, and then
+ * copies the remainder in blocks.
+ */
+{       char buf[BUFSIZ];
+        register int rcount, wcount;
+
+        /* write the rest of the buffer to outf */
+#ifdef _FSTDIO
+       while (--inf->_r >= 0)
+               VOID putc(*inf->_p++, outf);
+#else
+        while ((--inf->_cnt)>=0) {
+                VOID putc(*inf->_ptr++&0377,outf);
+        }
+#endif
+        if (fflush(outf) == EOF) {
+               writeerror();
+       }
+
+        /*now read the rest of the file in blocks*/
+        while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) {
+                wcount=write(fileno(outf),buf,rcount);
+                if (wcount!=rcount) {
+                    writeerror();
+                }
+        }
+}
+
+
+
+
+
+
+#ifdef SNOOPFILE
+
+#include "time.h"
+extern struct tm* localtime();
+extern long time();
+
+logcommand(commandname,delta, sequence,login)
+char* commandname; struct hshentry * delta, * sequence[];char * login;
+/* Function: start a process to write the file that
+ * logs the RCS command.
+ * Each line in the log file contains the following information:
+ * operation, revision(r), backward deltas applied(b), forward deltas applied(f),
+ * total deltas present(t), creation date of delta(d), date of operation(o),
+ * login of caller, RCS file name.
+ */
+{
+        char logline[200];
+        char curdate[datelength];
+       char *inoutargs[5];
+        register int i, backward, forward;
+        long clock;
+        struct tm * tm;
+
+        clock=time((long *)0);
+        tm=localtime(&clock);
+
+        VOID sprintf(curdate,DATEFORM,
+                tm->tm_year, tm->tm_mon+1, tm->tm_mday,
+                tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+        i= backward=forward=0;
+        while(sequence[i]!=nil) {  /* count deltas to be applied*/
+        if (countnumflds(sequence[i]->num) == 2)
+                backward++;  /* reverse delta */
+        else    forward++;   /* branch delta  */
+        i++;
+        }
+       VOID sprintf(logline,"%s %10sr %3db %3df %3dt %sc %so %s %s",
+               commandname,delta->num,backward,forward,TotalDeltas,delta->date,
+               curdate,login,bindex(getfullRCSname(),'/'));
+       inoutargs[0] = nil;
+       inoutargs[1] = nil;
+       inoutargs[2] = SNOOP;
+       inoutargs[3] = logline;
+       inoutargs[4] = nil;
+       VOID run_back(inoutargs);
+}
+#endif
+
+
+static int fdreopen(fd, file, flags, mode)
+       char *file;
+{
+       int newfd;
+       VOID close(fd);
+       newfd = flags==-1 ? creat(file,mode) : open(file,flags,mode);
+       if (newfd < 0  ||  newfd == fd)
+               return newfd;
+#ifdef F_DUPFD
+       fd = fcntl(newfd, F_DUPFD, fd);
+#else
+       fd = dup2(newfd, fd);
+#endif
+       VOID close(newfd);
+       return fd;
+}
+
+static void tryopen(fd,file,flags)
+       char *file;
+{
+       if (file  &&  fdreopen(fd,file,flags,0600) != fd) {
+               VOID write(fileno(stderr), file, strlen(file));
+               VOID write(fileno(stderr), ": cannot open\n", 14);
+               _exit(2);
+       }
+}
+
+/*
+/* Run in the background a command specified by the strings in 'inoutargs'.
+/* inoutargs[0], if nonnil, is the name of the input file.
+/* inoutargs[1], if nonnil, is the name of the output file.
+/* inoutargs[2..] form the command to be run in the background.
+/*/
+static int run_back(inoutargs)
+       register char **inoutargs;
+{
+       int pid;
+       if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
+               return -1;
+       if (!(pid = vfork())) {
+               tryopen(fileno(stdin), inoutargs[0], 0);
+               tryopen(fileno(stdout), inoutargs[1], -1);
+               VOID execv(inoutargs[2], &inoutargs[2]);
+               inoutargs[1] = "/bin/sh";
+               VOID execv(inoutargs[1], &inoutargs[1]);
+               VOID write(fileno(stderr), "/bin/sh: not found\n", 19);
+               _exit(2);
+       }
+       return pid;
+}
+
+#define CARGSMAX 20
+/*
+/* Run a command.
+/* The first two arguments are the input and output files (if nonnil);
+/* the rest specify the command and its arguments.
+/*/
+int run(va_alist)
+       va_dcl
+{
+       va_list ap;
+       int pid, wstatus, w;
+       char *rgargs[CARGSMAX];
+       register i = 0;
+       va_start(ap);
+       rgargs[0] = va_arg(ap, char *);
+       rgargs[1] = va_arg(ap, char *);
+       for (i =2; i< CARGSMAX; i++) {
+           rgargs[i] = va_arg(ap, char *);
+           if (rgargs[i] == NULL)
+               break;
+       }
+       va_end(ap);
+       pid = run_back(rgargs);
+       if (pid < 0)
+               return pid;
+       for (;;)
+               if ((w = wait(&wstatus)) < 0)
+                       return w;
+               else if (w == pid)
+                       return wstatus;
+}
diff --git a/usr/src/contrib/rcs/src/snoop.c b/usr/src/contrib/rcs/src/snoop.c
new file mode 100644 (file)
index 0000000..527a892
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *                     Logging of RCS commands co and ci
+ */
+#ifndef lint
+ static char rcsid[]=
+ "$Header: /usr/src/local/bin/rcs/src/RCS/snoop.c,v 4.4 89/05/01 15:14:00 narten Exp $ Purdue CS";
+#endif
+/*******************************************************************
+ * This program appends argv[1] to the file SNOOPFILE.
+ * To avoid overlaps, it creates a lockfile with name lock in the same
+ * directory as SNOOPFILE. SNOOPFILE must be defined in the cc command. 
+ * Prints an error message if lockfile doesn't get deleted after
+ * MAXTRIES tries.
+ *******************************************************************
+ */
+
+/* Copyright (C) 1982, 1988, 1989 Walter Tichy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Walter Tichy.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Report all problems and direct all questions to:
+ *   rcs-bugs@cs.purdue.edu
+ * 
+
+
+
+
+
+
+
+*/
+
+
+/* $Log:       snoop.c,v $
+ * Revision 4.4  89/05/01  15:14:00  narten
+ * changed copyright header to reflect current distribution rules
+ * 
+ * Revision 4.3  87/12/18  11:46:52  narten
+ * more lint cleanups (Guy Harris)
+ * 
+ * Revision 4.2  87/10/18  10:41:47  narten
+ * Changing version numbers. Changes relative to 1.1 actually relative to 
+ * 4.1
+ * 
+ * Revision 1.2  87/09/24  14:01:41  narten
+ * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
+ * warnings)
+ * 
+ * Revision 1.1  84/01/23  14:50:49  kcs
+ * Initial revision
+ * 
+ * Revision 4.1  83/03/28  13:23:42  wft
+ * No change; just new revision number.
+ * 
+ * Revision 3.2  82/12/04  17:14:31  wft
+ * Added rcsbase.h, changed SNOOPDIR to SNOOPFILE, reintroduced
+ * error message in case of permanent locking.
+ * 
+ * Revision 3.1  82/10/18  21:22:03  wft
+ * Number of polls now 20, no error message if critical section can't
+ * be entered.
+ * 
+ * Revision 2.3  82/07/01  23:49:28  wft
+ * changed copyright notice only.
+ * 
+ * Revision 2.2  82/06/03  20:00:10  wft
+ * changed name from rcslog to snoop, replaced LOGDIR with SNOOPDIR.
+ * 
+ * Revision 2.1  82/05/06  17:55:54  wft
+ * Initial revision
+ *
+ */
+
+
+#include "rcsbase.h"
+#ifdef _FSTDIO
+#undef putc
+#define putc __sputc
+#define fflsbuf _flsbuf
+#endif
+/* undo redefinition of putc in rcsbase.h */
+
+char  lockfname[NCPPN];
+FILE * logfile;
+int lockfile;
+
+#define MAXTRIES 20
+
+main(argc,argv)
+int argc; char * argv[];
+/* writes argv[1] to SNOOPFILE and appends a newline. Invoked as follows:
+ * rcslog logmessage
+ */
+{       int tries;
+        register char * lastslash, *sp;
+
+        VOID strcpy(lockfname,(char *) SNOOPFILE);
+        lastslash = sp = lockfname;
+        while (*sp) if (*sp++ =='/') lastslash=sp; /* points beyond / */
+        VOID strcpy(lastslash,",lockfile");
+        tries=0;
+        while (((lockfile=creat(lockfname, 000)) == -1) && (tries<=MAXTRIES)) {
+                tries++;
+                sleep(5);
+        }
+        if (tries<=MAXTRIES) {
+                VOID close(lockfile);
+                if ((logfile=fopen(SNOOPFILE,"a")) ==NULL) {
+                        VOID fprintf(stderr,"Can't open logfile %s\n",SNOOPFILE);
+                } else {
+                        VOID fputs(argv[1],logfile);
+                        VOID putc('\n',logfile);
+                        VOID fclose(logfile);
+                }
+                VOID unlink(lockfname);
+        } else {
+                VOID fprintf(stderr,"RCS logfile %s seems permanently locked.\n",SNOOPFILE);
+                VOID fprintf(stderr,"Please alert system administrator\n");
+        }
+}