[comp.sources.amiga] v89i226: rcs - revision control system, Part11/14

page%swap@Sun.COM (Bob Page) (11/19/89)

Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
Posting-number: Volume 89, Issue 226
Archive-name: unix/rcs.11

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	rcs/rcs.rcsfiles/rcssyn.c,v
#	rcs/rcs.rcsfiles/rcsutil.c,v
#	rcs/rcs.rcsfiles/rlog.c,v
# This is archive 11 of a 14-part kit.
# This archive created: Sun Nov 19 01:12:11 1989
if `test ! -d rcs`
then
  mkdir rcs
  echo "mkdir rcs"
fi
if `test ! -d rcs/rcs.rcsfiles`
then
  mkdir rcs/rcs.rcsfiles
  echo "mkdir rcs/rcs.rcsfiles"
fi
echo "extracting rcs/rcs.rcsfiles/rcssyn.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcssyn.c,v
Xhead     4.6;
Xbranch   4.6.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.6.2 cbmvax_source:4.6.1 uunet_june89_dist:4.6;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.6
Xdate     89.05.01.15.13.32;  author narten;  state Exp;
Xbranches 4.6.1.1 4.6.2.1;
Xnext     ;
X
X4.6.1.1
Xdate     89.08.11.01.43.06;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.6.2.1
Xdate     89.10.13.19.19.15;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.2;
X
X4.6.2.2
Xdate     89.10.15.15.45.04;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RCS file input.
X@
X
X
X
X4.6
Xlog
X@checked in with -k by rsbx at 89.08.10.16.23.06.
X@
Xtext
X@/*
X *                     RCS file input
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: rcssyn.c,v 4.6 89/05/01 15:13:32 narten Exp $ Purdue CS";
X#endif
X/*********************************************************************************
X *                       Syntax Analysis.
X *                       Keyword table
X *                       Testprogram: define SYNDB
X *                       Compatibility with Release 2: define COMPAT2
X *********************************************************************************
X */
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X/* $Log:	rcssyn.c,v $
X * Revision 4.6  89/05/01  15:13:32  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.5  88/11/08  12:00:37  narten
X * changes from  eggert@@sm.unisys.com (Paul Eggert)
X * 
X * Revision 4.5  88/08/09  19:13:21  eggert
X * Allow cc -R; remove lint.
X * 
X * Revision 4.4  87/12/18  11:46:16  narten
X * more lint cleanups (Guy Harris)
X * 
X * Revision 4.3  87/10/18  10:39:36  narten
X * Updating version numbers. Changes relative to 1.1 actually relative to
X * 4.1
X * 
X * Revision 1.3  87/09/24  14:00:49  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:40  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:40  kcs
X * Initial revision
X * 
X * Revision 4.1  83/03/28  11:38:49  wft
X * Added parsing and printing of default branch.
X * 
X * Revision 3.6  83/01/15  17:46:50  wft
X * Changed readdelta() to initialize selector and log-pointer.
X * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM.
X *
X * Revision 3.5  82/12/08  21:58:58  wft
X * renamed Commentleader to Commleader.
X *
X * Revision 3.4  82/12/04  13:24:40  wft
X * Added routine gettree(), which updates keeplock after reading the
X * delta tree.
X *
X * Revision 3.3  82/11/28  21:30:11  wft
X * Reading and printing of Suffix removed; version COMPAT2 skips the
X * Suffix for files of release 2 format. Fixed problems with printing nil.
X *
X * Revision 3.2  82/10/18  21:18:25  wft
X * renamed putdeltatext to putdtext.
X *
X * Revision 3.1  82/10/11  19:45:11  wft
X * made sure getc() returns into an integer.
X */
X
X
X
X/*
X#define COMPAT2
X/* version COMPAT2 reads files of the format of release 2 and 3, but
X * generates files of release 3 format. Need not be defined if no
X * old RCS files generated with release 2 exist.
X */
X/*
X#define SYNDB
X/* version SYNDB is for debugging the syntax analysis for RCS files.
X * SYNDB performs additional error checks.
X */
X/*
X#define SYNTEST
X/* version SYNTEST inputs a RCS file and then prints out its internal
X * data structures.
X*/
X
X#include "rcsbase.h"
Xextern FILE * finptr;        /*RCS input file*/
Xextern char * getid();
Xextern struct hshentry * getnum();
Xextern int    getkey();
Xextern int    getlex();
Xextern        readstring();
Xextern        savestring();
X
X/* forward */
Xchar * getkeyval();
X
X/* keyword table */
X
Xchar Kaccess[]   = "access";
Xchar Kauthor[]   = "author";
Xchar Kbranch[]   = "branch";
Xchar Kbranches[] = "branches";
Xchar Kcomment[]  = "comment";
Xchar Kdate[]     = "date";
Xchar Kdesc[]     = "desc";
Xchar Khead[]     = "head";
Xchar Klocks[]    = "locks";
Xchar Klog[]      = "log";
Xchar Knext[]     = "next";
Xchar Kstate[]    = "state";
Xchar Kstrict[]   = "strict";
X#ifdef COMPAT2
Xchar Ksuffix[]   = "suffix";
X#endif
Xchar Ksymbols[]  = "symbols";
Xchar Ktext[]     = "text";
X
X#define COMMLENGTH 20
Xchar              Commleader[COMMLENGTH];
Xchar            * Comment;
Xstruct access   * AccessList;
Xstruct access   * LastAccess;
Xstruct assoc    * Symbols;
Xstruct assoc    * LastSymbol;
Xstruct lock     * Locks;
Xstruct lock     * LastLock;
Xint               StrictLocks;
Xstruct hshentry * Head;
Xstruct hshentry * Dbranch;
Xint               TotalDeltas;
X
X
X
Xgetadmin()
X/* Function: Reads an <admin> and initializes the globals
X * AccessList, LastAccess, Symbols, LastSymbol,
X * Locks, LastLock, StrictLocks, Head, Comment, TotalDeltas;
X */
X{
X        register char   * id;
X        struct access   * newaccess;
X        struct assoc    * newassoc;
X        struct lock     * newlock;
X        struct hshentry * delta;
X
X        Comment="";
X        AccessList=LastAccess=nil;
X        Symbols=LastSymbol=nil;
X        Locks=LastLock=nil;
X        Dbranch = Head = nil;
X        TotalDeltas=0;
X
X        if (!getkey(Khead)) fatserror("Missing head");
X        Head=getnum();
X#       ifdef SYNDB
X        if (Head&&((countnumflds(Head->num)%2)!=0))
X                serror("Delta number required for head");
X#       endif
X        if (!getlex(SEMI)) serror("Missing ';' after head");
X
X        if (getkey(Kbranch)) { /* optional */
X                Dbranch=getnum();
X                if (!getlex(SEMI)) serror("Missing ';' after branch list");
X        }
X
X
X#ifdef COMPAT2
X        /* read suffix. Only in release 2 format */
X        if (getkey(Ksuffix)) {
X                if (nexttok==STRING) {
X                        readstring(); nextlex(); /*through away the suffix*/
X                } elsif(nexttok==ID) {
X                        nextlex();
X                }
X                if (!getlex(SEMI)) serror("Missing ';' after %s",Ksuffix);
X        }
X#endif
X
X        if (!getkey(Kaccess)) fatserror("Missing access list");
X        while (id=getid()) {
X                newaccess = (struct access *)talloc(sizeof(struct access));
X                newaccess->login = id;
X                newaccess->nextaccess = nil;
X                if (AccessList == nil) {
X                        AccessList=LastAccess=newaccess;
X                } else {
X                        LastAccess=LastAccess->nextaccess=newaccess;
X                }
X        }
X        if (!getlex(SEMI)) serror("Missing ';' after access list");
X
X        if (!getkey(Ksymbols)) fatserror("Missing symbols");
X        while (id = getid()) {
X                if (!getlex(COLON))
X                        serror("Missing ':' in symbolic name definition");
X                if (!(delta=getnum())) {
X                        serror("Missing number in symbolic name definition");
X                } else { /*add new pair to association list*/
X                        newassoc=(struct assoc *)talloc(sizeof(struct assoc));
X                        newassoc->symbol=id;
X                        newassoc->delta=delta;
X                        newassoc->nextassoc=nil;
X                        if (Symbols == nil) {
X                                Symbols=LastSymbol=newassoc;
X                        } else {
X                                LastSymbol=LastSymbol->nextassoc=newassoc;
X                        }
X                }
X        }
X        if (!getlex(SEMI)) serror("Missing ';' after symbolic names");
X
X        if (!getkey(Klocks)) serror("Missing locks");
X        while (id = getid()) {
X                if (!getlex(COLON))
X                        serror("Missing ':' in lock");
X                if (!(delta=getnum())) {
X                        serror("Missing number in lock");
X                } else { /*add new pair to lock list*/
X#                       ifdef SYNDB
X                        if ((countnumflds(delta->num)%2)!=0)
X                                serror("Delta number required for lock");
X#                       endif
X                        newlock=(struct lock *)talloc(sizeof(struct lock));
X                        newlock->login=id;
X                        newlock->delta=delta;
X                        newlock->nextlock=nil;
X                        if (Locks == nil) {
X                                Locks=LastLock=newlock;
X                        } else {
X                                LastLock=LastLock->nextlock=newlock;
X                        }
X                }
X        }
X        if (!getlex(SEMI)) serror("Missing ';' after locks");
X        if (!getkey(Kstrict)) {
X                StrictLocks = false;
X        } else {
X                StrictLocks = true;
X                if (!getlex(SEMI)) serror("Missing ';' after keyword %s",Kstrict);
X        }
X        if (getkey(Kcomment) && (nexttok==STRING)) {
X                VOID savestring(Commleader,COMMLENGTH);nextlex();
X                Comment=Commleader;
X                if (!getlex(SEMI)) serror("Missing ';' after %s",Kcomment);
X        }
X}
X
X
X
Xgetdelta()
X/* Function: reads a delta block.
X * returns false if the current block does not start with a number.
X */
X{
X        register struct hshentry * Delta, * num;
X        struct branchhead * LastBranch, * NewBranch;
X
X        if (!(Delta=getnum())) return false;
X#       ifdef SYNDB
X        if ((countnumflds(Delta->num)%2)!=0)
X                serror("Delta number required");
X#       endif
X
X        hshenter = false; /*Don't enter dates into hashtable*/
X        Delta->date = getkeyval(Kdate, NUM, false);
X        hshenter=true;    /*reset hshenter for revision numbers.*/
X
X        Delta->author = getkeyval(Kauthor, ID, false);
X
X        Delta->state = getkeyval(Kstate, ID, true);
X
X        if (!getkey(Kbranches)) fatserror("Missing branches");
X        Delta->branches = LastBranch=nil;
X        while (num=getnum()) {
X#               ifdef SYNDB
X                if ((countnumflds(num->num)%2)!=0)
X                        serror("Delta number required");
X#               endif
X                NewBranch = (struct branchhead *)talloc(sizeof(struct branchhead));
X                NewBranch->hsh = num;
X                NewBranch->nextbranch = nil;
X                if (LastBranch == nil) {
X                        Delta->branches=LastBranch=NewBranch;
X                } else {
X                        LastBranch=LastBranch->nextbranch=NewBranch;
X                }
X        }
X        if (!getlex(SEMI)) serror("Missing ';' after branches");
X
X        if (!getkey(Knext)) fatserror("Missing next");
X        Delta->next=num=getnum();
X#       ifdef SYNDB
X        if (num&&((countnumflds(num->num)%2)!=0))
X                serror("Delta number required");
X#       endif
X        if (!getlex(SEMI)) serror("Missing ';' after next");
X        Delta->log=Delta->lockedby = nil;
X        Delta->selector = '\0';
X        TotalDeltas++;
X        return (true);
X}
X
X
Xgettree()
X/* Function: Reads in the delta tree with getdelta(), then
X * updates the lockedby fields.
X */
X{       struct lock * currlock;
X        while (getdelta());
X        currlock=Locks;
X        while (currlock) {
X                currlock->delta->lockedby = currlock->login;
X                currlock = currlock->nextlock;
X        }
X}
X
X
Xgetdesc(prdesc)
Xint  prdesc;
X/* Function: read in descriptive text
X * nexttok is not advanced afterwards.
X * if prdesc==true, the text is printed to stdout.
X */
X{
X
X        if (!getkey(Kdesc) || (nexttok!=STRING)) fatserror("Missing descriptive text");
X        if (prdesc)
X                printstring();  /*echo string*/
X        else    readstring();   /*skip string*/
X}
X
X
X
X
X
X
Xchar * getkeyval(keyword, token, optional)
Xenum tokens token; char * keyword; int optional;
X/* reads a pair of the form
X * <keyword> <token> ;
X * where token is one of <id> or <num>. optional indicates whether
X * <token> is optional. A pointer to
X * the acutal character string of <id> or <num) is returned.
X * Getkeyval terminates the program on missing keyword or token, continues
X * on missing ;.
X */
X{
X        register char * val;
X
X        if (!getkey(keyword)) {
X                fatserror("Missing %s", keyword);
X        }
X        if (nexttok==token) {
X                val = NextString;
X                nextlex();
X        } else {
X                if (!optional) {fatserror("Missing %s", keyword); }
X                else val = nil;
X        }
X        if (!getlex(SEMI)) serror("Missing ';' after %s",keyword);
X        return(val);
X}
X
X
X
X
Xputadmin(fout)
Xregister FILE * fout;
X/* Function: Print the <admin> node read with getadmin() to file fout.
X * Assumption: Variables AccessList, Symbols, Locks, StrictLocks,
X * and Head have been set.
X */
X{       struct assoc  * curassoc;
X        struct lock   * curlock;
X        struct access * curaccess;
X        register char * sp;
X
X        VOID fputs(Khead,fout); VOID fputs("     ",fout);
X        if (Head) VOID fputs(Head->num,fout);
X
X        VOID fprintf(fout,";\n%s   ",Kbranch);
X        if (Dbranch) VOID fputs(Dbranch->num,fout);
X
X        VOID fprintf(fout,";\n%s  ",Kaccess);
X        curaccess = AccessList;
X        if (curaccess==nil) VOID putc(' ',fout);
X        while (curaccess) {
X               VOID putc(' ',fout);
X               VOID fputs(curaccess->login,fout);
X               curaccess = curaccess->nextaccess;
X        }
X        VOID fprintf(fout,";\n%s ",Ksymbols);
X        curassoc = Symbols;
X        if (curassoc==nil) VOID putc(' ',fout);
X        while (curassoc) {
X               VOID fprintf(fout," %s:%s",curassoc->symbol, curassoc->delta->num);
X               curassoc = curassoc->nextassoc;
X        }
X        VOID fprintf(fout,";\n%s   ",Klocks);
X        curlock = Locks;
X        if (curlock==nil) VOID putc(' ',fout);
X        while (curlock) {
X               VOID fprintf(fout," %s:%s",curlock->login, curlock->delta->num);
X               curlock = curlock->nextlock;
X        }
X        if (StrictLocks) VOID fprintf(fout,"; %s",Kstrict);
X        VOID fprintf(fout,";\n%s  %c",Kcomment,SDELIM);
X        if((sp=Comment)!=nil) {
X               while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout);
X        }
X        VOID fprintf(fout,"%c;\n\n",SDELIM);
X}
X
X
X
X
Xputdelta(node,fout)
Xregister struct hshentry * node;
Xregister FILE * fout;
X/* Function: prints a <delta> node to fout;
X */
X{      struct branchhead * nextbranch;
X
X        if (node == nil) return;
X
X        VOID fprintf(fout,"\n%s\n",node->num);
X        VOID fprintf(fout,"%s     %s;  %s %s;  %s ",
X                Kdate,node->date,Kauthor,node->author,Kstate);
X        if (node->state!=nil) VOID fputs(node->state,fout);
X        VOID fputs(";\nbranches",fout);
X        nextbranch = node->branches;
X        if (nextbranch==nil) VOID putc(' ',fout);
X        while (nextbranch) {
X               VOID putc(' ',fout);
X               VOID fputs(nextbranch->hsh->num,fout);
X               nextbranch = nextbranch->nextbranch;
X        }
X
X        VOID fprintf(fout,";\n%s     ",Knext);
X        if (node->next!=nil) VOID fputs(node->next->num,fout);
X        VOID fputs(";\n",fout);
X
X}
X
X
X
X
Xputtree(root,fout)
Xstruct hshentry * root;
Xregister FILE * fout;
X/* Function: prints the delta tree in preorder to fout, starting with root.
X */
X{       struct branchhead * nextbranch;
X
X        if (root==nil) return;
X
X        if (root->selector !=DELETE)putdelta(root,fout);
X        /* selector DELETE means deleted; set by rcs -o */
X
X        puttree(root->next,fout);
X
X        nextbranch = root->branches;
X        while (nextbranch) {
X             puttree(nextbranch->hsh,fout);
X             nextbranch = nextbranch->nextbranch;
X        }
X}
X
X
X
Xint putdtext(num,log,srcfilename,fout)
Xchar * num, * log, * srcfilename; FILE * fout;
X/* Function: write a deltatext-node to fout.
X * num points to the deltanumber, log to the logmessage, and
X * sourcefile contains the text. Doubles up all SDELIMs in both the
X * log and the text; Makes sure the log message ends in \n.
X * returns false on error.
X */
X{
X        register char * sp;
X	register int c;
X        register FILE * fin;
X
X        VOID fprintf(fout,DELNUMFORM,num,Klog);
X        /* put log */
X        VOID putc(SDELIM,fout);
X        sp=log;
X        while (*sp) if (putc(*sp++,fout)==SDELIM) VOID putc(SDELIM,fout);
X        if (*(sp-1)!='\n') VOID putc('\n', fout); /*append \n if necessary*/
X        /* put text */
X        VOID fprintf(fout, "%c\n%s\n%c",SDELIM,Ktext,SDELIM);
X        if ((fin=fopen(srcfilename,"r"))==NULL) {
X                error("Can't open source file %s",srcfilename);
X                return false;
X        }
X        while ((c=fgetc(fin))!=EOF) {
X                if (c==SDELIM) VOID putc(SDELIM,fout);   /*double up SDELIM*/
X                VOID putc(c,fout);
X        }
X        VOID putc(SDELIM,fout); VOID putc('\n',fout);
X        VOID fclose(fin);
X        return true;
X}
X
X
X
X#ifdef SYNTEST
X
Xmain(argc,argv)
Xint argc; char * argv[];
X{
X
X        cmdid = "syntest";
X        if (argc<2) {
X                VOID fputs("No input file\n",stderr);
X                exit(-1);
X        }
X        if ((finptr=fopen(argv[1], "r")) == NULL) {
X                faterror("Can't open input file %s\n",argv[1]);
X        }
X        Lexinit();
X        getadmin();
X        putadmin(stdout);
X
X        gettree();
X        puttree(Head,stdout);
X
X        getdesc(true);
X
X        if (nextlex(),nexttok!=EOFILE) {
X                fatserror("Syntax error");
X        }
X        exit(0);
X}
X
X
Xcleanup(){}
X/*dummy*/
X
X
X#endif
X
X@
X
X
X4.6.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d5 1
Xa5 5
X<<<<<<< rcssyn.c
Xstatic char rcsid[]= "$Id: rcssyn.c,v 4.6.1.1 89/08/11 01:43:06 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
Xstatic char rcsid[]= "$Id: rcssyn.c,v 1.2 89/09/17 13:36:37 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa41 16
X<<<<<<< rcssyn.c
X * Revision 4.6.1.1  89/08/11  01:43:06  rsbx
X * Start of cbmvax RCS source branch.
X * 
X * Revision 4.6  89/05/01  15:13:32  narten
X * checked in with -k by rsbx at 89.08.10.16.23.06.
X=======
X * Revision 1.2  89/09/17  13:36:37  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X * 
X * Revision 1.2  88/09/03  15:12:39  rick
X * Port to AmigaDos.  All done with conditional compiles
X>>>>>>> 1.2
X * 
X@
X
X
X4.6.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d5 5
Xa9 1
Xstatic char rcsid[]= "$Id: rcssyn.c,v 4.6.2.1 89/10/13 19:19:15 rsbx Exp Locker: rsbx $ Purdue CS";
Xd46 1
Xa46 3
X * Revision 4.6.2.1  89/10/13  19:19:15  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd52 9
X@
X
X
X4.6.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a42 3
X * checked in with -k by rsbx at 89.08.10.16.23.06.
X * 
X * Revision 4.6  89/05/01  15:13:32  narten
X@
SHAR_EOF
echo "extracting rcs/rcs.rcsfiles/rcsutil.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcsutil.c,v
Xhead     4.6;
Xbranch   4.6.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.6.2 cbmvax_source:4.6.1 uunet_june89_dist:4.6;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.6
Xdate     89.05.01.15.13.40;  author narten;  state Exp;
Xbranches 4.6.1.1 4.6.2.1;
Xnext     ;
X
X4.6.1.1
Xdate     89.08.11.01.43.12;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.1.2;
X
X4.6.1.2
Xdate     89.08.11.02.17.29;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.1.3;
X
X4.6.1.3
Xdate     89.10.16.15.08.36;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.6.2.1
Xdate     89.10.13.19.19.20;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.2;
X
X4.6.2.2
Xdate     89.10.15.15.45.09;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.3;
X
X4.6.2.3
Xdate     89.10.15.18.27.58;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.4;
X
X4.6.2.4
Xdate     89.10.16.19.01.15;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.5;
X
X4.6.2.5
Xdate     89.10.16.19.07.28;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.6;
X
X4.6.2.6
Xdate     89.10.16.23.54.57;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.7;
X
X4.6.2.7
Xdate     89.10.17.15.04.39;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.6.2.8;
X
X4.6.2.8
Xdate     89.10.18.10.54.09;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RCS utilities.
X@
X
X
X4.6
Xlog
X@checked in with -k by rsbx at 89.08.10.16.23.16.
X@
Xtext
X@/*
X *                     RCS utilities
X */
X#ifndef lint
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6 89/05/01 15:13:40 narten Exp $ Purdue CS";
X#endif
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X
X
X/* $Log:	rcsutil.c,v $
X * Revision 4.6  89/05/01  15:13:40  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.5  88/11/08  16:01:02  narten
X * corrected use of varargs routines
X * 
X * Revision 4.4  88/11/08  12:00:28  narten
X * changes from  eggert@@sm.unisys.com (Paul Eggert)
X * 
X * Revision 4.4  88/08/09  19:13:24  eggert
X * Check for memory exhaustion.
X * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
X * Use execv(), not system(); yield exit status like diff(1)'s.
X * 
X * Revision 4.3  87/10/18  10:40:22  narten
X * Updating version numbers. Changes relative to 1.1 actually
X * relative to 4.1
X * 
X * Revision 1.3  87/09/24  14:01:01  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:43  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:43  kcs
X * Initial revision
X * 
X * Revision 4.1  83/05/10  15:53:13  wft
X * Added getcaller() and findlock().
X * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
X * (needed for background jobs in older shells). Added restoreints().
X * Removed printing of full RCS path from logcommand().
X * 
X * Revision 3.8  83/02/15  15:41:49  wft
X * Added routine fastcopy() to copy remainder of a file in blocks.
X *
X * Revision 3.7  82/12/24  15:25:19  wft
X * added catchints(), ignoreints() for catching and ingnoring interrupts;
X * fixed catchsig().
X *
X * Revision 3.6  82/12/08  21:52:05  wft
X * Using DATEFORM to format dates.
X *
X * Revision 3.5  82/12/04  18:20:49  wft
X * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
X * lockedby-field.
X *
X * Revision 3.4  82/12/03  17:17:43  wft
X * Added check to addlock() ensuring only one lock per person.
X * Addlock also returns a pointer to the lock created. Deleted fancydate().
X *
X * Revision 3.3  82/11/27  12:24:37  wft
X * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
X * Introduced macro SNOOP so that snoop can be placed in directory other than
X * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
X *
X * Revision 3.2  82/10/18  21:15:11  wft
X * added function getfullRCSname().
X *
X * Revision 3.1  82/10/13  16:17:37  wft
X * Cleanup message is now suppressed in quiet mode.
X */
X
X
X
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X#include "rcsbase.h"
X#include <pwd.h>
X#include <varargs.h>
X
X#if defined(USG) || defined(V4_2BSD)
X#include <fcntl.h>
X#endif
X
X#ifndef V4_2BSD
X#define vfork fork
X#endif
X
Xextern char * bindex();
Xextern FILE * finptr;
Xextern char * RCSfilename;
Xextern char * getlogin();
Xextern struct passwd *getpwuid();
Xextern char * malloc();
X
X
Xchar * talloc(size)
Xunsigned size;
X{
X	char * p;
X	if (!(p = malloc(size))) {
X		faterror("out of memory");
X	}
X	return p;
X}
X
X
X
Xchar * getcaller()
X/* Function: gets the callers login from his uid.
X * If the uid is root, tries to get the true login with getlogin().
X */
X{       char * name;
X	int uid;
X	uid=getuid();
X	if (uid==0) {
X		/* super user; try getlogin() to distinguish */
X		name = getlogin();
X		if (name!=nil && *name!='\0')
X			return name;
X	}
X	return(getpwuid(uid)->pw_name);
X}
X
X
X
Xstruct hshentry * findlock(who,delete)
Xchar * who; int delete;
X/* Finds the first lock held by who and returns a pointer
X * to the locked delta; also removes the lock if delete==true.
X * Returns nil if there is no lock held by who.
X */
X{
X        register struct lock * next, * trail;
X        struct lock dummy;
X
X        dummy.nextlock=next=Locks;
X        trail = &dummy;
X        while (next!=nil) {
X                if(strcmp(who,next->login)==0) break; /*found a lock*/
X                trail=next;
X                next=next->nextlock;
X        }
X        if (next!=nil) {
X		/* found one */
X		if (delete) {
X		    /* delete it */
X		    trail->nextlock=next->nextlock;
X		    Locks=dummy.nextlock;
X		    next->delta->lockedby=nil; /* reset locked-by */
X		}
X                return next->delta;
X        } else  return nil;
X}
X
X
X
X
X
X
X
Xstruct lock * addlock(delta,who)
Xstruct hshentry * delta; char * who;
X/* Given a delta, addlock checks whether
X * the delta is locked by somebody other than who.
X * If so, an error message is printed, and false returned.
X * If the delta is not reserved at all, a lock for it is added,
X * and a pointer for the lock returned.
X */
X{
X        struct lock * next;
X
X        next=Locks;
X        while (next!=nil) {
X                if (cmpnum(delta->num,next->delta->num)==0) {
X                        if (strcmp(who,next->login)==0)
X                                return next;
X                                /* lock exists already */
X                        else {
X                                error("revision %s already locked by %s",
X                                      delta->num, next->login);
X                                return false;
X                        }
X                } else {
X                        if (strcmp(who,next->login)==0) {
X                                error("you already locked %s; only one lock allowed per person.",
X                                       next->delta->num);
X                                return false;
X                        } else {
X                                next=next->nextlock;
X                        }
X                }
X        }
X        /* not found; set up new lockblock */
X        next= (struct lock *) talloc(sizeof (struct lock));
X        delta->lockedby=next->login=who;
X        next->delta= delta;
X        next->nextlock=Locks;
X        Locks=next;
X        return next;
X}
X
X
X
Xint addsymbol(delta,name,rebind)
Xstruct hshentry * delta; char * name; int rebind;
X/* Function: adds a new symbolic name and associates it with node delta.
X * If name already exists and rebind is true, the name is associated
X * with the new delta; otherwise, an error message is printed and
X * false returned. Returns true it successful.
X */
X{       register struct assoc * next;
X        next=Symbols;
X        while (next!=nil) {
X                if (strcmp(name,next->symbol)==0) {
X                        if (rebind) {
X                                next->delta=delta;
X                                return true;
X                        } else {
X                                error("symbolic name %s already bound to %s",
X                                        name,next->delta->num);
X                                return false;
X                        }
X                } else  next = next->nextassoc;
X        }
X        /* not found; insert new pair. */
X        next = (struct assoc *) talloc(sizeof(struct assoc));
X        next->symbol=name;
X        next->delta=delta;
X        next->nextassoc=Symbols;
X        Symbols = next;
X        return true;
X}
X
X
X
X
Xint checkaccesslist(who)
Xchar * who;
X/* function: Returns true if who is the superuser, the owner of the
X * file, the access list is empty, or who is on the access list.
X * Prints an error message and returns false otherwise.
X */
X{
X        register struct access * next;
X        struct stat statbuf;
X
X        if ((AccessList==nil) || (strcmp(who,"root")==0))
X                return true;
X
X        next=AccessList;
X        do {
X                if (strcmp(who,next->login)==0)
X                        return true;
X                next=next->nextaccess;
X        } while (next!=nil);
X
X        VOID fstat(fileno(finptr),&statbuf);  /* get owner of file */
X        if (getuid() == statbuf.st_uid) return true;
X
X        error("User %s not on the access list",who);
X        return false;
X}
X
X
Xstatic SIGNAL_TYPE catchsig(s)
X{
X	ignoreints();
X        diagnose("\nRCS: cleaning up\n");
X        VOID cleanup();
X	exit(2);
X#ifdef lint
X	catchsig(s);
X#endif
X}
X
Xstatic sig[] = {SIGINT,SIGHUP,SIGQUIT,SIGPIPE,SIGTERM};
X#define SIGS (sizeof(sig)/sizeof(*sig))
Xstatic SIGNAL_TYPE (*catcher[SIGS])();
X  
X  void catchints()
X  {
X	register i;
X	for (i=SIGS; 0<=--i; )
X	    catcher[i]  =
X		signal(sig[i],SIG_IGN) == SIG_IGN  ?  SIG_IGN  :  catchsig;
X	restoreints();
X  }
X
X  void ignoreints()
X  {
X	register i;
X	for (i=SIGS; 0<=--i; )
X		VOID signal(sig[i], SIG_IGN);
X  }
X
Xvoid restoreints()
X{
X	register i;
X	for (i=SIGS; 0<=--i; )
X		if (catcher[i] != SIG_IGN)
X			VOID signal(sig[i], catcher[i]);
X}
X
Xfastcopy(inf,outf)
XFILE * inf, * outf;
X/* Function: copies the remainder of file inf to outf. First copies the
X * rest that is in the IO-buffer of inf character by character, and then
X * copies the remainder in blocks.
X */
X{       char buf[BUFSIZ];
X        register int rcount, wcount;
X
X        /* write the rest of the buffer to outf */
X        while ((--inf->_cnt)>=0) {
X                VOID putc(*inf->_ptr++&0377,outf);
X        }
X        if (fflush(outf) == EOF) {
X		writeerror();
X	}
X
X        /*now read the rest of the file in blocks*/
X        while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) {
X                wcount=write(fileno(outf),buf,rcount);
X                if (wcount!=rcount) {
X                    writeerror();
X                }
X        }
X}
X
X
X
X
X
X
X#ifdef SNOOPFILE
X
X#include "time.h"
Xextern struct tm* localtime();
Xextern long time();
X
Xlogcommand(commandname,delta, sequence,login)
Xchar* commandname; struct hshentry * delta, * sequence[];char * login;
X/* Function: start a process to write the file that
X * logs the RCS command.
X * Each line in the log file contains the following information:
X * operation, revision(r), backward deltas applied(b), forward deltas applied(f),
X * total deltas present(t), creation date of delta(d), date of operation(o),
X * login of caller, RCS file name.
X */
X{
X        char logline[200];
X        char curdate[datelength];
X	char *inoutargs[5];
X        register int i, backward, forward;
X        long clock;
X        struct tm * tm;
X
X        clock=time((long *)0);
X        tm=localtime(&clock);
X
X        VOID sprintf(curdate,DATEFORM,
X                tm->tm_year, tm->tm_mon+1, tm->tm_mday,
X                tm->tm_hour, tm->tm_min, tm->tm_sec);
X
X        i= backward=forward=0;
X        while(sequence[i]!=nil) {  /* count deltas to be applied*/
X        if (countnumflds(sequence[i]->num) == 2)
X                backward++;  /* reverse delta */
X        else    forward++;   /* branch delta  */
X        i++;
X        }
X	VOID sprintf(logline,"%s %10sr %3db %3df %3dt %sc %so %s %s",
X		commandname,delta->num,backward,forward,TotalDeltas,delta->date,
X		curdate,login,bindex(getfullRCSname(),'/'));
X	inoutargs[0] = nil;
X	inoutargs[1] = nil;
X	inoutargs[2] = SNOOP;
X	inoutargs[3] = logline;
X	inoutargs[4] = nil;
X	VOID run_back(inoutargs);
X}
X#endif
X
X
Xstatic int fdreopen(fd, file, flags, mode)
X	char *file;
X{
X	int newfd;
X	VOID close(fd);
X	newfd = flags==-1 ? creat(file,mode) : open(file,flags,mode);
X	if (newfd < 0  ||  newfd == fd)
X		return newfd;
X#ifdef F_DUPFD
X	fd = fcntl(newfd, F_DUPFD, fd);
X#else
X	fd = dup2(newfd, fd);
X#endif
X	VOID close(newfd);
X	return fd;
X}
X
Xstatic void tryopen(fd,file,flags)
X	char *file;
X{
X	if (file  &&  fdreopen(fd,file,flags,0600) != fd) {
X		VOID write(fileno(stderr), file, strlen(file));
X		VOID write(fileno(stderr), ": cannot open\n", 14);
X		_exit(2);
X	}
X}
X
X/*
X/* Run in the background a command specified by the strings in 'inoutargs'.
X/* inoutargs[0], if nonnil, is the name of the input file.
X/* inoutargs[1], if nonnil, is the name of the output file.
X/* inoutargs[2..] form the command to be run in the background.
X/*/
Xstatic int run_back(inoutargs)
X	register char **inoutargs;
X{
X	int pid;
X	if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
X		return -1;
X	if (!(pid = vfork())) {
X		tryopen(fileno(stdin), inoutargs[0], 0);
X		tryopen(fileno(stdout), inoutargs[1], -1);
X		VOID execv(inoutargs[2], &inoutargs[2]);
X		inoutargs[1] = "/bin/sh";
X		VOID execv(inoutargs[1], &inoutargs[1]);
X		VOID write(fileno(stderr), "/bin/sh: not found\n", 19);
X		_exit(2);
X	}
X	return pid;
X}
X
X#define CARGSMAX 20
X/*
X/* Run a command.
X/* The first two arguments are the input and output files (if nonnil);
X/* the rest specify the command and its arguments.
X/*/
Xint run(va_alist)
X	va_dcl
X{
X	va_list ap;
X	int pid, wstatus, w;
X	char *rgargs[CARGSMAX];
X	register i = 0;
X	va_start(ap);
X	rgargs[0] = va_arg(ap, char *);
X	rgargs[1] = va_arg(ap, char *);
X	for (i =2; i< CARGSMAX; i++) {
X	    rgargs[i] = va_arg(ap, char *);
X	    if (rgargs[i] == NULL)
X		break;
X	}
X	va_end(ap);
X	pid = run_back(rgargs);
X	if (pid < 0)
X		return pid;
X	for (;;)
X		if ((w = wait(&wstatus)) < 0)
X			return w;
X		else if (w == pid)
X			return wstatus;
X}
X@
X
X
X4.6.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d5 1
Xa5 5
X<<<<<<< rcsutil.c
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.1.2 89/08/11 02:17:29 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
Xstatic char rcsid[]= "$Id: rcsutil.c,v 1.2 89/09/17 13:36:49 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa36 14
X<<<<<<< rcsutil.c
X * Revision 4.6.1.2  89/08/11  02:17:29  rsbx
X * Changed catchints() to compile on cbmvax.
X=======
X * Revision 1.2  89/09/17  13:36:49  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X>>>>>>> 1.2
X * 
X<<<<<<< rcsutil.c
X * Revision 4.6.1.1  89/08/11  01:43:12  rsbx
X * Start of cbmvax RCS source branch.
X * 
Xa37 3
X * checked in with -k by rsbx at 89.08.10.16.23.16.
X * 
X * Revision 4.6  89/05/01  15:13:40  narten
Xa50 11
X=======
X * Revision 1.4  89/09/16  09:43:48  rick
X * Modified AMIGA changes to work with Lattice C
X * 
X * Revision 1.3  88/09/03  17:16:22  rick
X * Make fastcopy really fast for AmigaDos
X * 
X * Revision 1.2  88/09/03  15:12:57  rick
X * Port to AmigaDos.  All done with conditional compiles
X * 
X>>>>>>> 1.2
Xd103 1
Xa103 1
X#ifndef AMIGA
Xd107 1
Xa108 1
X<<<<<<< rcsutil.c
Xa113 7
X=======
X#else
X#include "stat.h"
X#include <signal.h>
X#endif
X#include "rcsbase.h"
X>>>>>>> 1.2
Xa125 8
X<<<<<<< rcsutil.c
X=======
X#ifdef AMIGA
Xshort	oldSIGINT;
X#else
Xint    (*oldSIGINT)();         /* saves the original value for SIGINT */
X#endif
X>>>>>>> 1.2
Xa126 1
X<<<<<<< rcsutil.c
Xa135 6
X=======
X#ifdef AMIGA
Xchar *getcaller()
X{
X	char *getenv();
X>>>>>>> 1.2
Xa136 1
X<<<<<<< rcsutil.c
Xa138 5
X=======
X	return(getenv("LOGNAME"));
X}
X#else
X>>>>>>> 1.2
Xa153 1
X#endif
Xd156 1
Xa287 3
X#ifdef AMIGA
X        return true;
X#else
Xa292 1
X#endif
Xa294 1
X<<<<<<< rcsutil.c
Xa298 31
X=======
X#ifdef AMIGA
X
Xcatchsig()
X{
X	diagnose("\nRCS: cleaning up\n");
X	VOID cleanup();
X	exit(1);
X}
X
Xvoid catchints()
X{
X	signal(SIGINT,catchsig);
X}
X
Xvoid ignoreints()
X{
X	signal(SIGINT,SIG_IGN);
X}
X
Xvoid restoreints()
X{
X	signal(SIGINT,catchsig);
X}
X
X#else
X
Xcatchsig(sig)
X{
X	VOID signal(sig, SIG_IGN);
X>>>>>>> 1.2
Xd315 2
Xa316 4
X	    if (signal(sig[i],SIG_IGN) == SIG_IGN)
X		catcher[i] = SIG_IGN;
X	    else
X		catcher[i] = catchsig;
Xa333 1
X#endif
Xa334 1
X<<<<<<< rcsutil.c
Xa335 27
X=======
X#ifdef AMIGA
X#define AMIGABUF (4 *1024)
Xfastcopy(inf,outf)
XFILE *inf,*outf;
X{
X	static char buf[AMIGABUF];
X	register int rcount, wcount;
X	int infd,outfd;
X
X	while (inf->_rcnt--)
X		putc(*inf->_ptr++,outf);
X	fflush(outf);
X	infd = fileno(inf);
X	outfd = fileno(outf);
X
X	while ((rcount = read(infd,buf,AMIGABUF)) > 0) {
X		if (rcount) {
X			wcount = write(outfd,buf,rcount);
X            if (wcount!=rcount)
X                faterror("write error");
X        }
X	}
X}
X#else
Xfastcopy(inf,outf)
X>>>>>>> 1.2
Xa359 4
X<<<<<<< rcsutil.c
X=======
X#endif
X>>>>>>> 1.2
X@
X
X
X4.6.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d5 5
Xa9 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.1 89/10/13 19:19:20 rsbx Exp Locker: rsbx $ Purdue CS";
Xd41 1
Xa41 3
X * Revision 4.6.2.1  89/10/13  19:19:20  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd44 6
Xd51 1
Xd72 11
Xd140 2
Xd146 1
Xa146 1
X
Xa150 1
X
Xd152 1
Xa153 6
X#ifdef STDARGS
X#include <stdarg.h>
X#else
X#include <varargs.h>
X#endif
X
Xd165 2
Xd168 1
Xa168 2
Xextern int run_back(char **inoutargs);
X/* short	oldSIGINT; */
Xd172 1
Xd174 1
Xd184 1
Xa184 2
X
X
Xd189 6
Xd198 1
Xa335 1
X#ifndef AMIGA
Xd337 1
Xa337 1
X#endif
Xd359 6
Xd367 1
Xa367 1
Xstatic SIGNAL_TYPE catchsig()
Xd391 1
Xa391 1
Xstatic SIGNAL_TYPE catchsig(s)
Xd393 2
Xa394 1
X	ignoreints();
Xd407 1
Xa407 1
Xvoid catchints()
Xd418 1
Xa418 1
Xvoid ignoreints()
Xd434 3
Xd462 1
Xd487 2
Xd490 1
Xd546 1
Xa546 1
X#ifndef AMIGA
Xa596 1
X#endif
Xa598 1
X#ifdef STDARGS
Xd600 4
Xa603 34
X * Run a command.
X * The first two arguments are the input and output files (if nonnil);
X * the rest specify the command and its arguments.
X */
Xint run(char *arg0, char *arg1, ...)
X{
X	va_list ap;
X	int pid, wstatus, w;
X	char *rgargs[CARGSMAX];
X	register i;
X	va_start(ap, arg1);
X	rgargs[0] = arg0;
X	rgargs[1] = arg1;
X	for (i =2; i< CARGSMAX; i++) {
X	    rgargs[i] = va_arg(ap, char *);
X	    if (rgargs[i] == NULL)
X		break;
X	}
X	va_end(ap);
X	pid = run_back(rgargs);
X	if (pid < 0)
X		return pid;
X	for (;;)
X		if ((w = wait(&wstatus)) < 0)
X			return w;
X		else if (w == pid)
X			return wstatus;
X}
X#else
X/*
X * Run a command.
X * The first two arguments are the input and output files (if nonnil);
X * the rest specify the command and its arguments.
X */
Xa628 1
X#endif
X@
X
X
X4.6.2.3
Xlog
X@More changes to make Amiga port work.
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.2 89/10/15 15:45:09 rsbx Exp $ Purdue CS";
Xa36 4
X * Revision 4.6.2.2  89/10/15  15:45:09  rsbx
X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
X * sources I have here (and are later than the ones Rick used).
X * 
Xa167 2
Xchar *getenv();
Xstatic char *unknownname = "Unknown";
Xd170 2
Xa171 8
X	char *name;
X	name = getenv("LOGNAME");
X
X	if ((name == NULL) || (*name == '\0'))
X		{
X		return unknownname;
X		}
X	return name;
X@
X
X
X4.6.2.4
Xlog
X@run() moved from rcsutil.c to amiga.c and made to work.
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.1.3 89/10/16 15:08:36 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.6.2.3  89/10/15  18:27:58  rsbx
X * More changes to make Amiga port work.
X * 
Xd153 6
Xd571 1
Xa634 1
X#endif
X@
X
X
X4.6.2.5
Xlog
X@Changed file path handling to deal with Amiga file path sematics.
X@
Xtext
X@a36 3
X * Revision 4.6.1.3  89/10/16  15:08:36  rsbx
X * run() move from rcsutil.c to amiga.c and made to work.
X * 
Xd122 1
Xa122 4
X#ifdef AMIGA
X#include "stat.h"
X#include <signal.h>
X#else
Xd132 3
Xd149 1
Xd430 3
Xa432 3
X		if (wcount!=rcount)
X                	faterror("write error");
X	        }
Xd507 1
Xa507 1
X		curdate,login,fnamepart(getfullRCSname()));
X@
X
X
X4.6.2.6
Xlog
X@Changes to getcaller().
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.5 89/10/16 19:07:28 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.6.2.5  89/10/16  19:07:28  rsbx
X * Changed file path handling to deal with Amiga file path sematics.
X * 
Xa140 1
X#include <ctype.h>
Xd176 1
Xa176 2
X	char *sp;
X	char c;
Xd178 3
Xa180 18
X	sp = name = getenv("LOGNAME");
X
X#ifdef TODO
X/* check for ethernet user/hostname */
X#endif
X	
X	if (sp) {
X		while ((c = *sp) && (isascii(c))) {
X			switch (ctab[c]) {
X				case IDCHAR:
X				case LETTER:
X				case DIGIT:
X					sp++;
X					continue;
X				default:
X					*sp = '\0';
X					break;
X			}
Xa181 5
X	}
X
X	if ((name == NULL) || (*name == '\0')) {
X		return unknownname;
X	}
X@
X
X
X4.6.2.7
Xlog
X@Yet more changes to getcaller().
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.6 89/10/16 23:54:57 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.6.2.6  89/10/16  23:54:57  rsbx
X * Changes to getcaller().
X * 
Xd183 1
Xa183 3
X	if (!(name = getenv("LOGNAME"))) {
X		return unknownname;
X	}
Xd188 13
Xa200 11
X	sp =name;
X	while ((c = *sp) && (isascii(c))) {
X		switch (ctab[c]) {
X			case IDCHAR:
X			case LETTER:
X			case DIGIT:
X				sp++;
X				continue;
X			default:
X				*sp = '\0';
X				break;
Xd204 1
Xa204 3
X
X	if (*name == '\0') {
X		free(name);
Xd207 1
Xa207 5
X
X	sp = talloc(sp-name+1);
X	strcpy(sp, name);
X	free(name);
X	return sp;
X@
X
X
X4.6.2.8
Xlog
X@LOGNAME changed to USERNAME. Still need to check the Ameristar software
Xfor username.
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.7 89/10/17 15:04:39 rsbx Exp $ Purdue CS";
Xa36 3
X * Revision 4.6.2.7  89/10/17  15:04:39  rsbx
X * Yet more changes to getcaller().
X * 
Xd186 1
Xa186 1
X	if (!(name = getenv("USERNAME"))) {
X@
X
X
X4.6.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@a37 3
X * checked in with -k by rsbx at 89.08.10.16.23.16.
X * 
X * Revision 4.6  89/05/01  15:13:40  narten
X@
X
X
X4.6.1.2
Xlog
X@Changed catchints() to compile on cbmvax.
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.1.1 89/08/11 01:43:12 rsbx Exp Locker: rsbx $ Purdue CS";
Xa36 3
X * Revision 4.6.1.1  89/08/11  01:43:12  rsbx
X * Start of cbmvax RCS source branch.
X * 
Xd318 2
Xa319 4
X	    if (signal(sig[i],SIG_IGN) == SIG_IGN)
X		catcher[i] = SIG_IGN;
X	    else
X		catcher[i] = catchsig;
X@
X
X
X4.6.1.3
Xlog
X@run() move from rcsutil.c to amiga.c and made to work.
X@
Xtext
X@d5 1
Xa5 1
Xstatic char rcsid[]= "$Id: rcsutil.c,v 4.6.2.3 89/10/15 18:27:58 rsbx Exp $ Purdue CS";
Xa36 13
X * Revision 4.6.2.3  89/10/15  18:27:58  rsbx
X * More changes to make Amiga port work.
X * 
X * Revision 4.6.2.2  89/10/15  15:45:09  rsbx
X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
X * sources I have here (and are later than the ones Rick used).
X * 
X * Revision 4.6.2.1  89/10/13  19:19:20  rsbx
X * Start of Amiga RCS port branch.
X * 
X * Revision 4.6.1.2  89/08/11  02:17:29  rsbx
X * Changed catchints() to compile on cbmvax.
X * 
Xd109 1
Xa109 1
X#ifndef AMIGA
Xd113 1
Xd115 1
Xa120 13
X#else
X#include "stat.h"
X#include <signal.h>
X#endif
X
X#include "rcsbase.h"
X
X#ifdef STDARGS
X#include <stdarg.h>
X#else
X#include <varargs.h>
X#endif
X
Xa143 7
X#ifdef AMIGA
Xchar *getenv();
Xstatic char *unknownname = "Unknown";
Xchar *getcaller()
X{
X	char *name;
X	name = getenv("LOGNAME");
Xa144 7
X	if ((name == NULL) || (*name == '\0'))
X		{
X		return unknownname;
X		}
X	return name;
X}
X#else
Xa159 1
X#endif
Xd162 1
Xa281 1
X#ifndef AMIGA
Xd283 1
Xa283 1
X#endif
Xa293 3
X#ifdef AMIGA
X        return true;
X#else
Xa298 1
X#endif
Xa300 1
X#ifdef AMIGA
Xa301 24
Xstatic SIGNAL_TYPE catchsig()
X{
X	diagnose("\nRCS: cleaning up\n");
X	VOID cleanup();
X	exit(1);
X}
X
Xvoid catchints()
X{
X	signal(SIGINT,catchsig);
X}
X
Xvoid ignoreints()
X{
X	signal(SIGINT,SIG_IGN);
X}
X
Xvoid restoreints()
X{
X	signal(SIGINT,catchsig);
X}
X
X#else
X
Xd317 1
Xa317 1
Xvoid catchints()
Xd328 1
Xa328 1
Xvoid ignoreints()
Xa341 1
X#endif
Xa342 2
X#ifdef AMIGA
X#define AMIGABUF (4 *1024)
Xa343 22
XFILE *inf,*outf;
X{
X	static char buf[AMIGABUF];
X	register int rcount, wcount;
X	int infd,outfd;
X
X	while (inf->_rcnt--)
X		putc(*inf->_ptr++,outf);
X	fflush(outf);
X	infd = fileno(inf);
X	outfd = fileno(outf);
X
X	while ((rcount = read(infd,buf,AMIGABUF)) > 0) {
X		if (rcount) {
X			wcount = write(outfd,buf,rcount);
X            if (wcount!=rcount)
X                faterror("write error");
X        }
X	}
X}
X#else
Xfastcopy(inf,outf)
Xa367 1
X#endif
Xd423 1
Xa423 1
X#ifndef AMIGA
Xa475 1
X#ifdef STDARGS
Xd477 4
Xa480 34
X * Run a command.
X * The first two arguments are the input and output files (if nonnil);
X * the rest specify the command and its arguments.
X */
Xint run(char *arg0, char *arg1, ...)
X{
X	va_list ap;
X	int pid, wstatus, w;
X	char *rgargs[CARGSMAX];
X	register i;
X	va_start(ap, arg1);
X	rgargs[0] = arg0;
X	rgargs[1] = arg1;
X	for (i =2; i< CARGSMAX; i++) {
X	    rgargs[i] = va_arg(ap, char *);
X	    if (rgargs[i] == NULL)
X		break;
X	}
X	va_end(ap);
X	pid = run_back(rgargs);
X	if (pid < 0)
X		return pid;
X	for (;;)
X		if ((w = wait(&wstatus)) < 0)
X			return w;
X		else if (w == pid)
X			return wstatus;
X}
X#else
X/*
X * Run a command.
X * The first two arguments are the input and output files (if nonnil);
X * the rest specify the command and its arguments.
X */
Xa505 2
X#endif
X#endif
X@
SHAR_EOF
echo "extracting rcs/rcs.rcsfiles/rlog.c,v"
sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rlog.c,v
Xhead     4.7;
Xbranch   4.7.2;
Xaccess   ;
Xsymbols  amiga_rcs:4.7.2 cbmvax_source:4.7.1 uunet_june89_dist:4.7;
Xlocks    ; strict;
Xcomment  @ * @;
X
X
X4.7
Xdate     89.05.01.15.13.48;  author narten;  state Exp;
Xbranches 4.7.1.1 4.7.2.1;
Xnext     ;
X
X4.7.1.1
Xdate     89.08.11.01.43.14;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X4.7.2.1
Xdate     89.10.13.19.19.26;  author rsbx;  state Exp;
Xbranches ;
Xnext     4.7.2.2;
X
X4.7.2.2
Xdate     89.10.15.15.45.14;  author rsbx;  state Exp;
Xbranches ;
Xnext     ;
X
X
Xdesc
X@RLOG operation.
X@
X
X
X
X4.7
Xlog
X@checked in with -k by rsbx at 89.08.10.16.23.28.
X@
Xtext
X@/*
X *                       RLOG    operation
X */
X#ifndef lint
Xstatic char rcsid[]=
X"$Header: /usr/src/local/bin/rcs/src/RCS/rlog.c,v 4.7 89/05/01 15:13:48 narten Exp $ Purdue CS";
X#endif
X/*****************************************************************************
X *                       print contents of RCS files
X *****************************************************************************
X */
X
X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Walter Tichy.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * Report all problems and direct all questions to:
X *   rcs-bugs@@cs.purdue.edu
X * 
X
X
X
X
X
X
X
X*/
X
X
X
X
X/* $Log:	rlog.c,v $
X * Revision 4.7  89/05/01  15:13:48  narten
X * changed copyright header to reflect current distribution rules
X * 
X * Revision 4.6  88/11/08  11:59:40  narten
X * changes from  eggert@@sm.unisys.com (Paul Eggert)
X * 
X * Revision 4.6  88/08/09  19:13:28  eggert
X * Check for memory exhaustion; don't access freed storage.
X * Shrink stdio code size; remove lint.
X * 
X * Revision 4.5  87/12/18  11:46:38  narten
X * more lint cleanups (Guy Harris)
X * 
X * Revision 4.4  87/10/18  10:41:12  narten
X * Updating version numbers
X * Changes relative to 1.1 actually relative to 4.2
X * 
X * Revision 1.3  87/09/24  14:01:10  narten
X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
X * warnings)
X * 
X * Revision 1.2  87/03/27  14:22:45  jenkins
X * Port to suns
X * 
X * Revision 1.1  84/01/23  14:50:45  kcs
X * Initial revision
X * 
X * Revision 4.2  83/12/05  09:18:09  wft
X * changed rewriteflag to external.
X * 
X * Revision 4.1  83/05/11  16:16:55  wft
X * Added -b, updated getnumericrev() accordingly.
X * Replaced getpwuid() with getcaller().
X * 
X * Revision 3.7  83/05/11  14:24:13  wft
X * Added options -L and -R;
X * Fixed selection bug with -l on multiple files.
X * Fixed error on dates of the form -d'>date' (rewrote getdatepair()).
X * 
X * Revision 3.6  82/12/24  15:57:53  wft
X * shortened output format.
X *
X * Revision 3.5  82/12/08  21:45:26  wft
X * removed call to checkaccesslist(); used DATEFORM to format all dates;
X * removed unused variables.
X *
X * Revision 3.4  82/12/04  13:26:25  wft
X * Replaced getdelta() with gettree(); removed updating of field lockedby.
X *
X * Revision 3.3  82/12/03  14:08:20  wft
X * Replaced getlogin with getpwuid(), %02d with %.2d, fancydate with PRINTDATE.
X * Fixed printing of nil, removed printing of Suffix,
X * added shortcut if no revisions are printed, disambiguated struct members.
X *
X * Revision 3.2  82/10/18  21:09:06  wft
X * call to curdir replaced with getfullRCSname(),
X * fixed call to getlogin(), cosmetic changes on output,
X * changed conflicting long identifiers.
X *
X * Revision 3.1  82/10/13  16:07:56  wft
X * fixed type of variables receiving from getc() (char -> int).
X */
X
X
X
X#include "time.h"
X#include "rcsbase.h"
X#ifndef lint
Xstatic char rcsbaseid[] = RCSBASE;
X#endif
X
Xextern char * partialno();
Xextern char * getcaller();          /*get login of caller                   */
Xextern        free();
Xextern int    countnumflds();
Xextern int    compartial();
Xextern int    expandsym();          /*get numeric name of a revision        */
Xextern int nextc;                   /*next input character                  */
Xextern char Klog[];
Xextern char Ktext[];
Xextern int  partime();
Xextern long maketime();             /*convert parsed time to unix time.     */
Xextern struct tm * localtime();     /*convert unixtime into a tm-structure  */
Xextern int  pairfilenames();
Xextern struct hshentry  * getnum();
Xextern FILE * finptr;               /* RCS input file                       */
Xextern FILE * frewrite;             /* new RCS file                         */
Xextern int    rewriteflag;          /* indicates whether input should be    */
X				    /* echoed to frewrite */
Xextern int    nerror;               /* error counter                        */
X
Xchar * RCSfilename, * workfilename;
X
Xchar * caller;                        /* caller's login;                    */
Xint  descflag, selectflag, selectop;  /* option to print access list, symbolic  */
X                                      /* names, descriptive text, locks and */
X                                      /* Head                               */
Xint  onlylockflag;		      /* option to print only files         */
X				      /* with locks			    */
Xint  onlyRCSflag;                     /* option to print only RCS file name */
Xint  lockflag;                        /* whether locker option is set       */
Xint  revno;                           /* number of revision chosen          */
X
Xstruct  lockers {                     /* lockers in locker option; stored   */
X     char               * login;      /* lockerlist                         */
X     struct     lockers * lockerlink;
X     }  ;
X
Xstruct  stateattri {                  /* states in state option; stored in  */
X     char               * status;     /* statelist                          */
X     struct  stateattri * nextstate;
X     }  ;
X
Xstruct  authors {                     /* login names in author option;      */
X     char               * login;      /* stored in authorlist               */
X     struct     authors * nextauthor;
X     }  ;
X
Xstruct Revpairs{                      /* revision or branch range in -r     */
X     int                  numfld;     /* option; stored in revlist          */
X     char               * strtrev;
X     char               * endrev;
X     struct  Revpairs   * rnext;
X     } ;
X
Xstruct Datepairs{                     /* date range in -d option; stored in */
X     char               strtdate[datelength];   /* duelst and datelist      */
X     char               enddate[datelength];
X     struct  Datepairs  * dnext;
X     };
X
Xchar   Dotstring[200];                /* string of numeric revision name    */
Xchar   * Nextdotstring;               /* next available place of Dotstring  */
Xstruct  Datepairs       * datelist,  * duelst;
Xstruct  Revpairs        * revlist, * Revlst;
Xint                     branchflag; /* set on -b */
Xstruct  lockers         * lockerlist;
Xstruct  stateattri      * statelist;
Xstruct  authors         * authorlist;
X
X
X
Xmain (argc, argv)
Xint argc;
Xchar * argv[];
X{
X        struct  Datepairs       * currdate;
X        struct  assoc         * curassoc;
X        struct  access        * curaccess;
X        struct  lock          * currlock;
X        char * cmdusage;
X
X	cmdusage = "command format:\nrlog -L -R -h -t -b -ddates -l[lockers] -rrevisions -sstates -w[logins] file ...";
X        cmdid = "rlog";
X        descflag = selectflag = true;
X        lockflag = onlylockflag = selectop = false;
X	onlyRCSflag = false;
X        lockerlist = nil;
X        authorlist = nil;
X        statelist = nil;
X        Revlst = revlist = nil;
X        branchflag= false;
X        duelst = datelist = nil;
X	caller=getcaller();
X
X        while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
X                switch ((*argv)[1]) {
X
X		case 'L':
X			onlylockflag = true;
X			break;
X
X		case 'R':
X			onlyRCSflag =true;
X			break;
X
X                case 'l':
X                        selectop = true;
X                        lockflag = true;
X                        getlocker( (*argv)+2 );
X                        break;
X
X                case 'b':
X                        selectop = true;
X                        branchflag = true;
X                        break;
X
X                case 'r':
X                        selectop = true;
X                        getrevpairs( (*argv)+2 );
X                        break;
X
X                case 'd':
X                        selectop = true;
X                        getdatepair( (*argv)+2 );
X                        break;
X
X                case 's':
X                        selectop = true;
X                        getstate( (*argv)+2);
X                        break;
X
X                case 'w':
X                        selectop = true;
X                        getauthor( (*argv)+2);
X                        break;
X
X                case 'h':
X                        if ( ! selectflag ) warn("option -t overrides -h");
X                        else    descflag = false;
X                        break;
X
X                case 't':
X                        selectflag = false;
X                        if ( ! descflag ) warn("option -t overrides -h");
X                        descflag = true;
X                        break;
X
X                default:
X                        faterror("unknown option: %s\n%s", *argv,cmdusage);
X
X                };
X        } /* end of option processing */
X
X        if (argc<1) faterror("No input file\n%s",cmdusage);
X
X
X        /* now handle all filenames */
X        do {
X            rewriteflag=false;
X            finptr=frewrite=nil;
X
X
X            if (!pairfilenames(argc, argv, true,false)) continue;
X
X            /* now RCSfilename contains the name of the RCS file, and finptr
X             * the file descriptor. Workfilename contains the name of the
X             * working file.
X             */
X
X            if ( !trysema(RCSfilename, false)) goto loopend; /*  give up */
X
X            /* do nothing if -L is given and there are no locks*/
X	    if ( onlylockflag && Locks == nil ) goto loopend;
X
X	    if ( onlyRCSflag ) {
X		VOID fprintf(stdout, "%s\n", RCSfilename);
X		goto loopend;
X	    }
X            /*   print RCS filename , working filename and optional
X                 administrative information                         */
X            VOID fprintf(stdout, "\nRCS file:        %s;   ",RCSfilename);
X            /* could use getfullRCSname() here, but that is very slow */
X            VOID fprintf(stdout, "Working file:    %s\n", workfilename);
X            VOID fprintf(stdout, "head:            %s\n", Head==nil?"":Head->num);
X            VOID fprintf(stdout, "branch:          %s\n", Dbranch==nil?"":Dbranch->num);
X
X            VOID fputs("locks:         ", stdout);  /*  print locker list   */
X            currlock = Locks;
X            while( currlock ) {
X                VOID fprintf(stdout,"  %s: %s;", currlock->login,
X                                currlock->delta->num);
X                currlock = currlock->nextlock;
X            }
X            if ( StrictLocks )
X                VOID fputs(Locks==nil?"  ;  strict":"  strict",stdout);
X
X            VOID fputs("\naccess list:   ", stdout);      /*  print access list  */
X            curaccess = AccessList;
X            while(curaccess) {
X                VOID fputs("  ",stdout);
X                VOID fputs(curaccess->login, stdout);
X                curaccess = curaccess->nextaccess;
X            }
X
X            VOID fputs("\nsymbolic names:", stdout);   /*  print symbolic names   */
X            curassoc = Symbols;
X            while( curassoc ) {
X                VOID fprintf(stdout, "  %s: %s;",curassoc->symbol,
X                           curassoc->delta->num);
X                curassoc = curassoc->nextassoc;
X            }
X
X            VOID fprintf(stdout,"\ncomment leader:  \"%s\"\n",Comment);
X
X            gettree();
X            VOID fprintf(stdout, "total revisions: %d;    ", TotalDeltas);
X            if ( Head == nil || !selectflag || !descflag) {
X                VOID putc('\n',stdout);
X                if (descflag) VOID fputs("description:\n", stdout);
X                getdesc(descflag);
X                VOID fputs("=============================================================================\n",stdout);
X                goto loopend;
X            }
X
X
X            /*  keep only those locks given by -l */
X            if (lockflag)
X                trunclocks();
X            getnumericrev();    /* get numeric revision or branch names */
X            revno = 0;
X
X            exttree(Head);
X
X            /*  get most recently date of the dates pointed by duelst  */
X            currdate = duelst;
X            while( currdate) {
X                recentdate(Head, currdate);
X                currdate = currdate->dnext;
X	    }
X
X            extdate(Head);
X
X            /*  reinitialize the date specification list   */
X            currdate = duelst;
X            while(currdate) {
X                VOID sprintf(currdate->strtdate,DATEFORM,0,0,0,0,0,0);
X                currdate = currdate->dnext;
X            }
X
X            if ( selectop || ( selectflag && descflag) )
X                VOID fprintf(stdout, "selected revisions: %d", revno);
X            VOID putc('\n', stdout);
X            if (descflag) VOID fputs("description:\n", stdout);
X            getdesc(descflag);
X            while( (nexttok != EOFILE) && readdeltalog());
X            if (selectflag && descflag && revno) {
X                putrunk();
X                putree(Head);
X                if (nextlex(), nexttok != EOFILE)
X                    fatserror("syntax error; expecting EOF");
X            }
X            VOID fputs("=============================================================================\n",stdout);
X        loopend:
X            VOID fclose(finptr);
X        } while( ++argv, --argc >= 1);
X        exit(nerror!=0);
X}
X
X
X
Xputrunk()
X/*  function:  print revisions chosen, which are in trunk      */
X
X{
X        struct  hshentry        * ptr, * pre;
X
X        if (Head == nil) return;   /*  empty tree  */
X
X        pre = Head;
X        ptr = Head->next;
X        while( ptr ) {
X            putadelta(pre,ptr,true);
X            pre = ptr;
X            ptr = ptr->next;
X        }
X        putadelta(pre,ptr,true);
X}
X
X
X
Xputree(root)
Xstruct  hshentry  *root;
X/*   function: print delta tree( not include trunck) in reversed calender
X               order on each branch                                        */
X
X{
X        if ( root == nil ) return;
X
X        putree(root->next);
X
X        putforest(root->branches);
X}
X
X
X
X
Xputforest(branchroot)
Xstruct   branchhead     * branchroot;
X/*   function:  print branches that has the same direct ancestor    */
X{
X
X        if ( branchroot == nil ) return;
X
X        putforest(branchroot->nextbranch);
X
X        putabranch(branchroot->hsh);
X        putree(branchroot->hsh);
X}
X
X
X
X
Xputabranch(root)
Xstruct      hshentry   *root;
X/*   function  :  print one branch     */
X
X{
X
X        if ( root == nil) return;
X
X        putabranch(root->next);
X
X        putadelta(root, root, false);
X}
X
X
X
X
X
Xputadelta(node,editscript,trunk)
Xregister  struct   hshentry    * node;
Xregister  struct   hshentry    * editscript;
Xint                              trunk;
X/*  function: print delta node if node->selector is 's'.        */
X/*      editscript indicates where the editscript is stored     */
X/*      trunk indicated whether this node is in trunk           */
X{
X        struct  branchhead      * newbranch;
X        char                    * branchnum,  branch[40];
X
X        if ( ( node == nil) || ( node->selector == 'u'))
X            return;
X
X        VOID fprintf(stdout,"----------------------------\n");
X        VOID fprintf(stdout, "revision %s        ",node->num);
X        if ( node->lockedby )
X           VOID fprintf(stdout, "locked by: %s;       ", node->lockedby);
X        VOID putc('\n', stdout);
X
X        VOID fputs("date: ",stdout);
X        VOID PRINTDATE(stdout,node->date); VOID putc(' ',stdout);
X        VOID PRINTTIME(stdout,node->date);
X        VOID fprintf(stdout, ";  author: %s;  ", node->author);
X        VOID fprintf(stdout, "state: %s;  ", node->state);
X
X        if ( editscript )
X           if(trunk)
X              VOID fprintf(stdout,"lines added/del: %d/%d",
X                             editscript->deletelns, editscript->insertlns);
X           else
X              VOID fprintf(stdout,"lines added/del: %d/%d",
X                             editscript->insertlns, editscript->deletelns);
X
X        VOID putc('\n', stdout);
X
X        branchnum = & (branch[0]);
X        newbranch = node->branches;
X        if ( newbranch ) {
X           VOID fputs("branches:  ", stdout);
X           while( newbranch ) {
X                getbranchno(newbranch->hsh->num, branchnum);
X                VOID fprintf(stdout, "%s;  ", branchnum);
X                newbranch = newbranch->nextbranch;
X           }
X           VOID putc('\n', stdout);
X        }
X
X        VOID fputs(node->log,stdout);
X}
X
X
X
X
X
Xreaddeltalog()
X/*  Function : get the log message and skip the text of a deltatext node.
X *             Return false if current block does not start with a number.
X *             Assumes the current lexeme is not yet in nexttok; does not
X *             advance nexttok.
X */
X{
X        register struct  hshentry  * Delta;
X
X        nextlex();
X        if ( !(Delta = getnum() )) return(false);
X        if ( ! getkey(Klog) || ( nexttok != STRING ) )
X                fatserror("Missing log entry");
X        Delta->log = talloc(logsize);
X        VOID savestring(Delta->log, logsize);
X        nextlex();
X        if ( ! getkey(Ktext) || (nexttok != STRING) )
X                fatserror("Missing delta text");
X        Delta->insertlns = Delta->deletelns = 0;
X        if ( Delta != Head)
X                getscript(Delta);
X        else
X                readstring();
X        return true;
X}
X
X
X
Xgetscript(Delta)
Xstruct    hshentry   * Delta;
X/*   function:  read edit script of Delta and count how many lines added  */
X/*              and deleted in the script                                 */
X
X{
X        int ed;   /*  editor command  */
X	register FILE * fin;
X        register  int   c;
X        register  int   i;
X        int             length;
X
X	fin = finptr;
X	while( (ed = getc(fin)) != EOF) {
X           /*  assume first none white character is command name  */
X            while( ed == '\n' || ed == ' ' || ed == '\t')
X		ed = getc(fin);
X            if (ed == SDELIM) break;  /*  script text is ended   */
X	    while( ( c = getc(fin)) == ' ' );  /*  skip blank  */
X            if ( ! ('0' <= c && c <= '9')) {
X                faterror("Missing line number in edit script");
X                break;
X            }
X	    while( '0' <= (c = getc(fin)) && c <= '9' ) ;
X
X	    while( c == ' ')c = getc(fin);  /*  skip blanks  */
X            if ( !('0' <= c && c <= '9' ) ) {
X                faterror("Incorrect range in edit script");
X                break;
X            }
X            length = c - '0';
X	    while( '0' <= (c = getc(fin)) && c <= '9' )
X                length = length * 10 + c - '0';
X	    while( c != '\n' && c != EOF) c = getc(fin);
X            switch (ed) {
X            case 'd' :
X                 Delta->deletelns += length;
X                 break;
X
X            case 'a' :
X                 /*  skip scripted lines  */
X                 for ( i=length; i > 0 && c != EOF; i--){
X		     while( (c=getc(fin)) != '\n' && c != EOF);
X                     Delta->insertlns++;
X                 }
X                 break;
X
X            default:
X                 faterror("Unknown command in edit script: %c", ed);
X                 break;
X            }
X        }
X	nextc = getc(fin);
X}
X
X
X
X
X
X
X
Xexttree(root)
Xstruct hshentry  *root;
X/*  function: select revisions , starting with root             */
X
X{
X        struct branchhead       * newbranch;
X
X        if (root == nil) return;
X
X        extractdelta(root);
X        exttree(root->next);
X
X        newbranch = root->branches;
X        while( newbranch ) {
X            exttree(newbranch->hsh);
X            newbranch = newbranch->nextbranch;
X        }
X}
X
X
X
X
Xgetlocker(argv)
Xchar    * argv;
X/*   function : get the login names of lockers from command line   */
X/*              and store in lockerlist.                           */
X
X{
X        register char c;
X        struct   lockers   * newlocker;
X        argv--;
X        while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                 c == '\n' || c == ';')  ;
X        if (  c == '\0') {
X            lockerlist=nil;
X            return;
X        }
X
X        while( c != '\0' ) {
X            newlocker = ( struct lockers *)talloc( sizeof(struct lockers) );
X            newlocker->lockerlink = lockerlist;
X            newlocker->login = argv;
X            lockerlist = newlocker;
X            while ( ( c = (*++argv)) != ',' && c != '\0' && c != ' '
X                       && c != '\t' && c != '\n' && c != ';') ;
X            *argv = '\0';
X            if ( c == '\0' ) return;
X            while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                     c == '\n' || c == ';')  ;
X        }
X}
X
X
X
Xgetauthor(argv)
Xchar   *argv;
X/*   function:  get the author's name form command line   */
X/*              and store in aauthorlist                  */
X
X{
X        register    c;
X        struct     authors  * newauthor;
X
X        argv--;
X        while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                 c == '\n' || c == ';')  ;
X        if ( c == '\0' ) {
X            authorlist = (struct authors *)talloc(sizeof(struct authors));
X            authorlist->login = caller;
X            authorlist->nextauthor  = nil;
X            return;
X        }
X
X        while( c != '\0' ) {
X            newauthor = (struct authors *)talloc(sizeof(struct authors));
X            newauthor->nextauthor = authorlist;
X            newauthor->login = argv;
X            authorlist = newauthor;
X            while( ( c = *++argv) != ',' && c != '\0' && c != ' '
X                     && c != '\t' && c != '\n' && c != ';') ;
X            * argv = '\0';
X            if ( c == '\0') return;
X            while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                     c == '\n' || c == ';')  ;
X        }
X}
X
X
X
X
Xgetstate(argv)
Xchar   * argv;
X/*   function :  get the states of revisions from command line  */
X/*               and store in statelist                         */
X
X{
X        register  char  c;
X        struct    stateattri    *newstate;
X
X        argv--;
X        while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                 c == '\n' || c == ';')  ;
X        if ( c == '\0'){
X            warn(" Missing state attributes after -s options");
X            return;
X        }
X
X        while( c != '\0' ) {
X            newstate = (struct stateattri *)talloc(sizeof(struct stateattri));
X            newstate->nextstate = statelist;
X            newstate->status = argv;
X            statelist = newstate;
X            while( (c = (*++argv)) != ',' && c != '\0' && c != ' '
X                    && c != '\t' && c != '\n' && c != ';')  ;
X            *argv = '\0';
X            if ( c == '\0' ) return;
X            while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                     c == '\n' || c == ';')  ;
X        }
X}
X
X
X
Xtrunclocks()
X/*  Function:  Truncate the list of locks to those that are held by the  */
X/*             id's on lockerlist. Do not truncate if lockerlist empty.  */
X
X{
X        struct lockers  * plocker;
X        struct lock     * plocked,  * nextlocked;
X
X        if ( (lockerlist == nil) || (Locks == nil)) return;
X
X        /* shorten Locks to those contained in lockerlist */
X        plocked = Locks;
X        Locks = nil;
X        while( plocked != nil) {
X            plocker = lockerlist;
X            while((plocker != nil) && ( strcmp(plocker->login, plocked->login)!=0))
X                plocker = plocker->lockerlink;
X            nextlocked = plocked->nextlock;
X            if ( plocker != nil) {
X                plocked->nextlock = Locks;
X                Locks = plocked;
X            }
X            plocked = nextlocked;
X        }
X}
X
X
X
Xrecentdate(root, pd)
Xstruct 	hshentry	* root;
Xstruct	Datepairs	* pd;
X/*  function:  Finds the delta that is closest to the cutoff date given by   */
X/*             pd among the revisions selected by exttree.                   */
X/*             Successively narrows down the interfal given by pd,           */
X/*             and sets the strtdate of pd to the date of the selected delta */
X{
X        struct  branchhead      * newbranch;
X
X	if ( root == nil) return;
X        if ( root->selector == 's') {
X             if ( cmpnum(root->date, pd->strtdate) >= 0 &&
X                  cmpnum(root->date, pd->enddate) <= 0)
X		VOID strcpy(pd->strtdate, root->date);
X        }
X
X        recentdate(root->next, pd);
X        newbranch = root->branches;
X        while( newbranch) {
X           recentdate(newbranch->hsh, pd);
X           newbranch = newbranch->nextbranch;
X	}
X}
X
X
X
X
X
X
Xextdate(root)
Xstruct  hshentry        * root;
X/*  function:  select revisions which are in the date range specified     */
X/*             in duelst  and datelist, start at root                     */
X
X{
X        struct  branchhead      * newbranch;
X        struct  Datepairs       * pdate;
X
X        if ( root == nil) return;
X
X        if ( datelist || duelst) {
X            pdate = datelist;
X            while( pdate ) {
X                if ( (pdate->strtdate)[0] == '\0' || cmpnum(root->date,pdate->strtdate) >= 0){
X                   if ((pdate->enddate)[0] == '\0' || cmpnum(pdate->enddate,root->date) >= 0)
X                        break;
X                }
X                pdate = pdate->dnext;
X            }
X            if ( pdate == nil) {
X                pdate = duelst;
X                while(pdate) {
X                   if ( cmpnum(root->date, pdate->strtdate) == 0)
X                      break;
X                   pdate = pdate->dnext;
X                }
X            }
X            if ( pdate == nil)
X                root->selector = 'u';
X        }
X        if (root->selector == 's') revno++;
X
X        extdate(root->next);
X
X        newbranch = root->branches;
X        while( newbranch ) {
X           extdate(newbranch->hsh);
X           newbranch = newbranch->nextbranch;
X        }
X}
X
X
X
Xextractdelta(pdelta)
Xstruct  hshentry        * pdelta;
X/*  function:  compare information of pdelta to the authorlst, lockerlist, */
X/*             statelist, revlist and mark 's' on selector if pdelta is    */
X/*             selected; otherwise, mark 'u'                               */
X
X{
X        struct  lock            * plock;
X        struct  stateattri      * pstate;
X        struct  authors         * pauthor;
X        struct  Revpairs        * prevision;
X        int                       length;
X
X        pdelta->selector = 's';
X        if ( authorlist ) {  /*  certain author's revisions wanted only  */
X            pauthor = authorlist;
X            while((pauthor != nil) && ( strcmp(pauthor->login, pdelta->author)!=0))
X                pauthor = pauthor->nextauthor;
X            if ( pauthor == nil ) {
X                pdelta->selector = 'u';
X                return;
X            }
X        }
X        if ( statelist ) {   /* revisions with certain state wanted  */
X            pstate = statelist;
X            while((pstate != nil) && (strcmp(pstate->status, pdelta->state)!=0))
X                pstate = pstate->nextstate;
X            if ( pstate == nil ) {
X                pdelta->selector = 'u';
X                return;
X            }
X        }
X        if ( lockflag ) {    /*  locked revisions   */
X            plock = Locks;
X            while( plock && (plock->delta != pdelta))
X                plock = plock->nextlock;
X            if (plock == nil ) {
X                pdelta->selector = 'u';
X                return;
X            }
X        }
X        if ( Revlst ) {   /*  revisions or branches selected  */
X
X            prevision = Revlst;
X            while( prevision != nil ) {
X                length = prevision->numfld;
X                if ( length % 2 == 1) { /*  a branch number  */
X                     if ( countnumflds(pdelta->num) ==(length+1))
X                        if ( (compartial(pdelta->num, prevision->strtrev,length) >= 0)&&
X                             (compartial(prevision->endrev, pdelta->num, length) >= 0) )
X                             break;
X                }
X                else if ( countnumflds(pdelta->num ) == length)  /*  a revision */
X                    if ( (compartial(pdelta->num, prevision->strtrev, length) >= 0) &&
X                         (compartial(prevision->endrev, pdelta->num, length) >= 0) )
X                        break;
X                prevision = prevision->rnext;
X            }
X            if (prevision == nil)  {
X                pdelta->selector = 'u';
X                return;
X            }
X        }
X}
X
X
X
Xchar * procdate(target, source)
Xchar * target, * source;
X/* Function: Parses a free-format date in target, converts it
X * into RCS internal format, and stores the result into source.
X * Returns target on success, nil otherwise.
X */
X{
X	long            unixtime;
X	struct     tm   parseddate,  *ftm;
X
X	if ( partime(source, &parseddate) == 0) {
X	    error("Can't parse date/time: %s", source);
X	    *target= '\0';
X	    return nil;
X	}
X	if ( (unixtime = maketime(&parseddate)) == 0L) {
X	    error("Inconsistent date/time: %s", source);
X	    *target='\0';
X	    return nil;
X	}
X	ftm = localtime(&unixtime);
X	VOID sprintf(target,DATEFORM,
X	ftm->tm_year,ftm->tm_mon+1,ftm->tm_mday,ftm->tm_hour,ftm->tm_min,ftm->tm_sec);
X	return target;
X}
X
X
X
Xgetdatepair(argv)
X   char   * argv;
X/*  function:  get time range from command line and store in datelist if    */
X/*             a time range specified or in duelst if a time spot specified */
X
X{
X        register   char         c;
X        struct     Datepairs    * nextdate;
X        char                    * rawdate;
X	int                     switchflag;
X
X        argv--;
X        while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                 c == '\n' || c == ';')  ;
X        if ( c == '\0' ) {
X            warn("Missing date/time after -d");
X            return;
X        }
X
X        while( c != '\0' )  {
X	    switchflag = false;
X	    nextdate = (struct Datepairs *) talloc(sizeof(struct Datepairs));
X            if ( c == '<' ) {   /*   case: -d <date   */
X                c = *++argv;
X                (nextdate->strtdate)[0] = '\0';
X	    } elsif (c == '>') {        /*  case:  -d >date     */
X		c = *++argv;
X		(nextdate->enddate)[0] = '\0';
X		switchflag = true;
X	    } else {
X                rawdate = argv;
X		while( c != '<' && c != '>' && c != ';' && c != '\0')
X		     c = *++argv;
X                *argv = '\0';
X		if ( c == '>' ) switchflag=true;
X		if (procdate(switchflag?nextdate->enddate:nextdate->strtdate,
X			     rawdate)==nil) continue;
X		if ( c == ';' || c == '\0') {  /*  case: -d date  */
X		    VOID strcpy(nextdate->enddate,nextdate->strtdate);
X		    VOID sprintf(nextdate->strtdate,DATEFORM,0,0,0,0,0,0);
X                    nextdate->dnext = duelst;
X                    duelst = nextdate;
X		    goto end;
X		} else {
X		    /*   case:   -d date<  or -d  date>; see switchflag */
X		    while ( (c= *++argv) == ' ' || c=='\t' || c=='\n');
X		    if ( c == ';' || c == '\0') {
X			/* second date missing */
X			if (switchflag)
X			    *nextdate->strtdate= '\0';
X			else
X			    *nextdate->enddate= '\0';
X			nextdate->dnext = datelist;
X			datelist = nextdate;
X			goto end;
X		    }
X                }
X            }
X            rawdate = argv;
X	    while( c != '>' && c != '<' && c != ';' && c != '\0')
X 		c = *++argv;
X            *argv = '\0';
X	    if (procdate(switchflag?nextdate->strtdate:nextdate->enddate,
X			 rawdate)==nil) continue;
X            nextdate->dnext = datelist;
X	    datelist = nextdate;
X     end:
X/*
X	    VOID printf("startdate: %s; enddate: %s;\n", nextdate->strtdate,nextdate->enddate);
X*/
X	    if ( c == '\0')  return;
X            while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n');
X        }
X}
X
X
X
X
X
Xgetnumericrev()
X/*  function:  get the numeric name of revisions which stored in revlist  */
X/*             and then stored the numeric names in Revlst                */
X/*             if branchflag, also add default branch                     */
X
X{
X        struct  Revpairs        * ptr, *pt;
X        int     flag;
X        char    *temprev;
X
X        /*  free the previous numeric revision list  */
X        pt = Revlst;
X        while( pt) {
X	   ptr = pt->rnext;
X           free((char *)pt);
X           pt = ptr;
X        }
X        Nextdotstring = &Dotstring[0]; /* reset buffer */
X
X
X        Revlst = nil;
X        ptr = revlist;
X        while( ptr ) {
X            pt = (struct Revpairs *) talloc(sizeof(struct Revpairs));
X            if ( ptr->numfld == 1 ){ /*  case:  -r rev   */
X                if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
X                    pt->numfld = countnumflds(Nextdotstring);
X                    pt->strtrev = pt->endrev = Nextdotstring;
X                    while( *Nextdotstring++ != '\0' )  ;
X                }
X            }
X            else if( ptr->numfld == 2){ /*  case: -r rev-   */
X                if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true) {
X                    pt->numfld = countnumflds(Nextdotstring);
X                    pt->strtrev = Nextdotstring;
X                    while( *Nextdotstring++ != '\0' ) ;
X                    pt->endrev = Nextdotstring;
X                    if ( pt->numfld > 2) choptail(pt->strtrev);
X                    * Nextdotstring++ = '\0';
X                }
X             }
X             else if(ptr->numfld == 3)  { /*  case: -r -rev   */
X                if ( (flag = expandsym(ptr->endrev, Nextdotstring)) == true) {
X                    pt->endrev = Nextdotstring;
X                    while( *Nextdotstring++ != '\0' )  ;
X                    pt->numfld = countnumflds(pt->endrev);
X                    pt->strtrev = Nextdotstring;
X                    if ( pt->numfld == 2)
X                        *Nextdotstring++ = '1';
X                    else
X                        choptail(pt->endrev);
X                    *Nextdotstring++ = '.';
X                    *Nextdotstring++ = '1';
X                    *Nextdotstring++ = '\0';
X                }
X             }
X             else  {     /*   case:  -r rev1-rev2   */
X                if ( (flag = expandsym(ptr->strtrev, Nextdotstring)) == true ) {
X                    pt->strtrev = Nextdotstring;
X                    while( *Nextdotstring++ != '\0' )  ;
X                    if ( ( flag = expandsym(ptr->endrev, Nextdotstring)) == true)  {
X                        pt->numfld = countnumflds(pt->strtrev);
X                        pt->endrev = Nextdotstring;
X                        while( *Nextdotstring++ != '\0' ) ;
X                        if((flag = checkrevpair(pt->strtrev, pt->endrev)) == true)
X                           /*  switch pt->strtrev with pt->endrev, if pt->strtrev > pt->endre  */
X                            if (compartial(pt->strtrev, pt->endrev, pt->numfld) > 0 ) {
X                                temprev = pt->strtrev;
X                                pt->strtrev = pt->endrev;
X                                pt->endrev = temprev;
X                            }
X                     }
X                }
X             }
X
X             if ( flag ){
X                pt->rnext = Revlst;
X                Revlst = pt;
X             }
X             else
X                free((char *)pt);
X             ptr = ptr->rnext;
X        }
X        /* Now take care of branchflag */
X        if (branchflag) {
X            flag =true;
X            pt = (struct Revpairs *) talloc(sizeof(struct Revpairs));
X            if (Dbranch) {
X                pt->strtrev = pt->endrev = Dbranch->num;
X            } elsif (Head!=nil) {
X                pt->strtrev = pt->endrev = /* branch number of head */
X                    partialno(Nextdotstring,Head->num,1);
X                while( *Nextdotstring++ != '\0' ) ;
X            } else flag = false;
X            if (flag) { /* prepend new node */
X                pt->rnext=Revlst; Revlst=pt;
X                pt->numfld = countnumflds(pt->strtrev);
X            }
X        }
X
X}
X
X
X
Xcheckrevpair(num1,num2)
Xchar    *num1,  *num2;
X/*  function:  check whether num1, num2 are legal pair,i.e.
X    only the last field are different and have same number of
X    feilds( if length <= 2, may be different if first field)   */
X
X{
X        int    length;
X
X        if ( (length = countnumflds(num1)) != countnumflds(num2) ) {
X            error(" Invalid branch or revision pair %s : %s", num1, num2);
X            return false;
X        }
X        if ( length > 2 )
X            if (compartial(num1, num2, length-1) != 0) {
X                error("Invalid branch or revision pair %s : %s", num1, num2);
X                return false;
X            }
X
X        return true;
X}
X
X
X
Xgetrevpairs(argv)
Xregister     char    * argv;
X/*  function:  get revision or branch range from command line, and   */
X/*             store in revlist                                      */
X
X{
X        register    char    c;
X        struct      Revpairs  * nextrevpair;
X        int         flag;
X
X        argv--;
X        while( ( c = (*++argv)) == ',' || c == ' ' || c == '\t' ||
X                 c == '\n' || c == ';')  ;
X        if ( c == '\0' ) {
X            warn(" Missing revision or branch number after -r");
X            return;
X        }
X
X        while( c != '\0') {
X            while(  c  == ',' || c == ' ' || c == '\t' ||
X                     c == '\n' || c == ';') c = *++argv;
X            if (c == '\0')  return;
X            nextrevpair = (struct Revpairs *) talloc(sizeof(struct Revpairs));
X            nextrevpair->rnext = revlist;
X            revlist = nextrevpair;
X            nextrevpair->numfld  = nil;
X            nextrevpair->strtrev = nil;
X            nextrevpair->endrev  = nil;
X            flag = false;
X            if (  c == '<' || c == '-' ) {  /*  case: -r -rev  or -r <rev  */
X                flag = true;
X                while( (c =(*++argv)) == ' ' || c == '\t' || c =='\n') ;
X            }
X            else {
X                nextrevpair->strtrev = argv;
X                /*   get a revision or branch name  */
X                while( c != ',' && c != ';' && c != ' ' && c != '\0' && c != '-'
X                        && c != '\t' && c != '\n' && c != '<') c = *++argv;
X
X                *argv = '\0';
X
X                if ( c != '<' && c != '-') {    /*  case: rev  */
X                    nextrevpair->numfld = 1;
X                    continue;
X                }
X
X                if ( (c =(*++argv)) == ',' || c == '\0' || c == ' '
X                      || c == '\t' || c == '\n' || c == ';') {/*  case: rev_  */
X                    nextrevpair->numfld = 2;
X                    continue;
X                }
X            }
X            nextrevpair->endrev = argv;
X            while( c != ',' && c != ' ' && c != '\0' && c != '\t' && c != '<'
X                   && c != '\n' && c != '-' && c != ';')  c = *++argv;
X
X            * argv = '\0';
X            if ( c == '<'){
X                error("separator expected near %s", nextrevpair->endrev);
X                while( (c = *++argv) != ',' && c != ' ' && c != '\0' &&
X                        c != '\t' && c != '\n' && c != ';' ) ;
X                revlist = nextrevpair->rnext;
X                continue;
X            }
X            else  {
X                if (flag)   /*  case:  -rev   */
X                    nextrevpair->numfld  = 3;
X
X                else     /*   rev1-rev2  appears  */
X                    nextrevpair->numfld = 4;
X            }
X        }
X}
X
X
X
Xchoptail(strhead)
Xchar     * strhead;
X/*   function : chop off the last field of a branch or a revision number  */
X
X{
X        char    *pt, *sp;
X
X        for(pt = Nextdotstring-1; pt != strhead && *pt != '.'; pt--) ;
X        for(sp = strhead; sp < pt; sp++) *Nextdotstring++ = *sp;
X}
X
X@
X
X
X4.7.2.1
Xlog
X@Start of Amiga RCS port branch.
X@
Xtext
X@d6 1
Xa6 5
X<<<<<<< rlog.c
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/rlog.c,v 4.7.1.1 89/08/11 01:43:14 rsbx Exp Locker: rsbx $ Purdue CS";
X=======
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rlog.c,v 1.2 89/09/17 13:36:54 rick Exp $ Purdue CS";
X>>>>>>> 1.2
Xa41 16
X<<<<<<< rlog.c
X * Revision 4.7.1.1  89/08/11  01:43:14  rsbx
X * Start of cbmvax RCS source branch.
X * 
X * Revision 4.7  89/05/01  15:13:48  narten
X * checked in with -k by rsbx at 89.08.10.16.23.28.
X=======
X * Revision 1.2  89/09/17  13:36:54  rick
X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
X * All changes done with conditional compile (#ifdef AMIGA).  This version
X * compiles correctly with Lattice C version 5.02 or later.
X * 
X * Revision 1.2  88/09/03  15:13:12  rick
X * Port to AmigaDos.  All done with conditional compiles
X>>>>>>> 1.2
X * 
X@
X
X
X4.7.2.2
Xlog
X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
Xsources I have here (and are later than the ones Rick used).
X@
Xtext
X@d6 5
Xa10 1
X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rlog.c,v 4.7.2.1 89/10/13 19:19:26 rsbx Exp Locker: rsbx $ Purdue CS";
Xd46 1
Xa46 3
X * Revision 4.7.2.1  89/10/13  19:19:26  rsbx
X * Start of Amiga RCS port branch.
X * 
Xd52 9
X@
X
X
X4.7.1.1
Xlog
X@Start of cbmvax RCS source branch.
X@
Xtext
X@d6 1
Xa6 1
X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/rlog.c,v 4.7 89/05/01 15:13:48 narten Exp $ Purdue CS";
Xa41 3
X * Revision 4.7  89/05/01  15:13:48  narten
X * checked in with -k by rsbx at 89.08.10.16.23.28.
X * 
X@
SHAR_EOF
echo "End of archive 11 (of 14)"
# if you want to concatenate archives, remove anything after this line
exit