home *** CD-ROM | disk | FTP | other *** search
- Subject: v24i004: RCS source control system, Part04/12
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 2397c1e8 b47b14fe de8867e1 de8b4ea9
-
- Submitted-by: Adam Hammer <hammer@cs.purdue.edu>
- Posting-number: Volume 24, Issue 4
- Archive-name: rcs/part04
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: src/rcsutil.c src/rlog.c
- # Wrapped by rsalz@litchi.bbn.com on Thu Feb 21 14:36:57 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 4 (of 12)."'
- if test -f 'src/rcsutil.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/rcsutil.c'\"
- else
- echo shar: Extracting \"'src/rcsutil.c'\" \(17610 characters\)
- sed "s/^X//" >'src/rcsutil.c' <<'END_OF_FILE'
- X/*
- X * RCS utilities
- X */
- X
- X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- X Copyright 1990 by Paul Eggert
- X Distributed under license by the Free Software Foundation, Inc.
- X
- XThis file is part of RCS.
- X
- XRCS is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XRCS is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with RCS; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- XReport problems and direct all questions to:
- X
- X rcs-bugs@cs.purdue.edu
- X
- X*/
- X
- X
- X
- X
- X/* $Log: rcsutil.c,v $
- X * Revision 5.5 1990/12/04 05:18:49 eggert
- X * Don't output a blank line after a signal diagnostic.
- X * Use -I for prompts and -q for diagnostics.
- X *
- X * Revision 5.4 1990/11/01 05:03:53 eggert
- X * Remove unneeded setid check. Add awrite(), fremember().
- X *
- X * Revision 5.3 1990/10/06 00:16:45 eggert
- X * Don't fread F if feof(F).
- X *
- X * Revision 5.2 1990/09/04 08:02:31 eggert
- X * Store fread()'s result in an fread_type object.
- X *
- X * Revision 5.1 1990/08/29 07:14:07 eggert
- X * Declare getpwuid() more carefully.
- X *
- X * Revision 5.0 1990/08/22 08:13:46 eggert
- X * Add setuid support. Permit multiple locks per user.
- X * Remove compile-time limits; use malloc instead.
- X * Switch to GMT. Permit dates past 1999/12/31.
- X * Add -V. Remove snooping. Ansify and Posixate.
- X * Tune. Some USG hosts define NSIG but not sys_siglist.
- X * Don't run /bin/sh if it's hopeless.
- X * Don't leave garbage behind if the output is an empty pipe.
- X * Clean up after SIGXCPU or SIGXFSZ. Print name of signal that caused cleanup.
- X *
- 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/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 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 "rcsbase.h"
- X
- X#if !MAKEDEPEND && defined(declare_getpwuid)
- X# include <pwd.h>
- X declare_getpwuid
- X#endif
- X
- XlibId(utilId, "$Id: rcsutil.c,v 5.5 1990/12/04 05:18:49 eggert Exp $")
- X
- X#if lint
- X malloc_type lintalloc;
- X#endif
- X
- X#if has_getuid
- X uid_t ruid;
- X#endif
- X#if SETID
- X static uid_t euid;
- X static gid_t egid, rgid;
- X#endif
- X
- X/*
- X * list of blocks allocated with ftestalloc()
- X * These blocks can be freed by ffree when we're done with the current file.
- X * We could put the free block inside struct alloclist, rather than a pointer
- X * to the free block, but that would be less portable.
- X */
- Xstruct alloclist {
- X malloc_type alloc;
- X struct alloclist *nextalloc;
- X};
- Xstatic struct alloclist *alloced;
- X
- X
- X static malloc_type
- Xokalloc(p)
- X malloc_type p;
- X{
- X if (!p)
- X faterror("out of memory");
- X return p;
- X}
- X
- X malloc_type
- Xtestalloc(size)
- X size_t size;
- X/* Allocate a block, testing that the allocation succeeded. */
- X{
- X return okalloc(malloc(size));
- X}
- X
- X malloc_type
- Xtestrealloc(ptr, size)
- X malloc_type ptr;
- X size_t size;
- X/* Reallocate a block, testing that the allocation succeeded. */
- X{
- X return okalloc(realloc(ptr, size));
- X}
- X
- X malloc_type
- Xfremember(ptr)
- X malloc_type ptr;
- X/* Remember PTR in 'alloced' so that it can be freed later. Yield PTR. */
- X{
- X register struct alloclist *q = talloc(struct alloclist);
- X q->nextalloc = alloced;
- X alloced = q;
- X return q->alloc = ptr;
- X}
- X
- X malloc_type
- Xftestalloc(size)
- X size_t size;
- X/* Allocate a block, putting it in 'alloced' so it can be freed later. */
- X{
- X return fremember(testalloc(size));
- X}
- X
- X void
- Xffree()
- X/* Free all blocks allocated with ftestalloc(). */
- X{
- X register struct alloclist *p, *q;
- X for (p = alloced; p; p = q) {
- X q = p->nextalloc;
- X tfree(p->alloc);
- X tfree(p);
- X }
- X alloced = nil;
- X}
- X
- X void
- Xffree1(f)
- X register const char *f;
- X/* Free the block f, which was allocated by ftestalloc. */
- X{
- X register struct alloclist *p, **a = &alloced;
- X
- X while ((p = *a)->alloc != f)
- X a = &p->nextalloc;
- X *a = p->nextalloc;
- X tfree(p->alloc);
- X tfree(p);
- X}
- X
- X const char *
- Xstrsave(s)
- X const char *s;
- X/* Save s in permanently allocated storage. */
- X{
- X return strcpy(tnalloc(char, strlen(s)+1), s);
- X}
- X
- X const char *
- Xfstrsave(s)
- X const char *s;
- X/* Save s in storage that will be deallocated when we're done with this file. */
- X{
- X return strcpy(ftnalloc(char, strlen(s)+1), s);
- X}
- X
- X char *
- Xcgetenv(name)
- X const char *name;
- X/* Like getenv(), but yield a copy; getenv() can overwrite old results. */
- X{
- X register char *p;
- X
- X return (p=getenv(name)) ? strsave(p) : p;
- X}
- X
- X
- X const char *
- Xgetcaller()
- X/* Function: gets the caller's login.
- X */
- X{
- X static char *name;
- X
- X if (!name) {
- X if (!(
- X /* Use getenv() if we're trustworthy; it's much faster. */
- X#if SETID
- X euid==ruid && egid==rgid &&
- X#endif
- X (
- X (name = cgetenv("LOGNAME"))
- X || (name = cgetenv("USER"))
- X )
- X
- X /* Follow a procedure recommended by Posix 1003.1-1988. */
- X || (name = getlogin())
- X )) {
- X#if has_getuid & defined(declare_getpwuid)
- X const struct passwd *pw = getpwuid(ruid);
- X if (!pw)
- X faterror("no password entry for userid %lu",
- X (unsigned long)ruid
- X );
- X name = pw->pw_name;
- X#else
- X faterror("Who are you? Please set LOGNAME.");
- X#endif
- X }
- X checksid(name);
- X }
- X return name;
- X}
- X
- X
- X
- X int
- Xfindlock(delete, target)
- X int delete;
- X struct hshentry **target;
- X/* Finds the first lock held by caller and returns a pointer
- X * to the locked delta; also removes the lock if delete is set.
- X * Returns 0 for no locks, 1 for one, 2 for two or more.
- X * If one lock, puts it into *target.
- X */
- X{
- X register struct lock *next, **trail, **found = nil;
- X
- X for (trail = &Locks; (next = *trail); trail = &next->nextlock)
- X if (strcmp(getcaller(), next->login) == 0) {
- X if (found) {
- X error("multiple revisions locked by %s; please specify one", getcaller());
- X return 2;
- X }
- X found = trail;
- X }
- X if (!found)
- X return 0;
- X next = *found;
- X *target = next->delta;
- X if (delete) {
- X next->delta->lockedby = nil;
- X *found = next->nextlock;
- X }
- X return 1;
- X}
- X
- X
- X
- X
- X
- X
- X
- X int
- Xaddlock(delta)
- Xstruct hshentry * delta;
- X/* Add a lock held by caller to delta and yield 1 if successful.
- X * Print an error message and yield -1 if no lock is added because
- X * the delta is locked by somebody other than caller.
- X * Yield 0 if the caller already holds the lock. */
- 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(getcaller(),next->login)==0)
- X return 0;
- X else {
- X error("revision %s already locked by %s",
- X delta->num, next->login);
- X return -1;
- X }
- X }
- X next = next->nextlock;
- X }
- X /* set up new lockblock */
- X next = ftalloc(struct lock);
- X delta->lockedby=next->login=getcaller();
- X next->delta= delta;
- X next->nextlock=Locks;
- X Locks=next;
- X return 1;
- X}
- X
- X
- X
- X int
- Xaddsymbol(num, name, rebind)
- X const char *num, *name;
- X int rebind;
- X/* Function: adds a new symbolic name and associates it with revision num.
- X * If name already exists and rebind is true, the name is associated
- X * with the new num; 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->num = num;
- X return true;
- X } else {
- X error("symbolic name %s already bound to %s",
- X name, next->num);
- X return false;
- X }
- X } else next = next->nextassoc;
- X }
- X /* not found; insert new pair. */
- X next = ftalloc(struct assoc);
- X next->symbol=name;
- X next->num = num;
- X next->nextassoc=Symbols;
- X Symbols = next;
- X return true;
- X}
- X
- X
- X
- X
- Xint checkaccesslist()
- X/* function: Returns true if caller is the superuser, the owner of the
- X * file, the access list is empty, or caller is on the access list.
- X * Prints an error message and returns false otherwise.
- X */
- X{
- X register const struct access *next;
- X
- X if (!AccessList || strcmp(getcaller(),"root")==0)
- X return true;
- X
- X next=AccessList;
- X do {
- X if (strcmp(getcaller(),next->login)==0)
- X return true;
- X next=next->nextaccess;
- X } while (next!=nil);
- X
- X#if has_getuid
- X {
- X struct stat statbuf;
- X VOID fstat(fileno(finptr),&statbuf); /* get owner of file */
- X if (myself(statbuf.st_uid)) return true;
- X }
- X#endif
- X
- X error("user %s not on the access list", getcaller());
- X return false;
- X}
- X
- X
- X/*
- X * Signal handling
- X *
- X * ANSI C places too many restrictions on signal handlers.
- X * We obey as many of them as we can.
- X * Posix places fewer restrictions, and we are Posix-compatible here.
- X */
- X
- Xstatic volatile sig_atomic_t heldsignal, holdlevel;
- X
- X static signal_type
- Xcatchsig(s)
- X int s;
- X{
- X const char *sname;
- X char buf[BUFSIZ];
- X
- X#if sig_zaps_handler
- X /* If a signal arrives before we reset the signal handler, we lose. */
- X VOID signal(s, SIG_IGN);
- X#endif
- X if (holdlevel) {
- X heldsignal = s;
- X return;
- X }
- X ignoreints();
- X setrid();
- X if (!quietflag) {
- X sname = nil;
- X#if has_sys_siglist & defined(NSIG)
- X if ((unsigned)s < NSIG) {
- X# ifndef sys_siglist
- X extern const char *sys_siglist[];
- X# endif
- X sname = sys_siglist[s];
- X }
- X#else
- X switch (s) {
- X#ifdef SIGHUP
- X case SIGHUP: sname = "Hangup"; break;
- X#endif
- X#ifdef SIGINT
- X case SIGINT: sname = "Interrupt"; break;
- X#endif
- X#ifdef SIGPIPE
- X case SIGPIPE: sname = "Broken pipe"; break;
- X#endif
- X#ifdef SIGQUIT
- X case SIGQUIT: sname = "Quit"; break;
- X#endif
- X#ifdef SIGTERM
- X case SIGTERM: sname = "Terminated"; break;
- X#endif
- X#ifdef SIGXCPU
- X case SIGXCPU: sname = "Cputime limit exceeded"; break;
- X#endif
- X#ifdef SIGXFSZ
- X case SIGXFSZ: sname = "Filesize limit exceeded"; break;
- X#endif
- X }
- X#endif
- X if (sname)
- X VOID sprintf(buf, "\nRCS: %s. Cleaning up.\n", sname);
- X else
- X VOID sprintf(buf, "\nRCS: Signal %d. Cleaning up.\n", s);
- X VOID write(STDERR_FILENO, buf, strlen(buf));
- X }
- X exiterr();
- X}
- X
- X void
- Xignoreints()
- X{
- X ++holdlevel;
- X}
- X
- X void
- Xrestoreints()
- X{
- X if (!--holdlevel && heldsignal)
- X VOID catchsig(heldsignal);
- X}
- X
- X
- Xstatic const sig[] = {
- X#ifdef SIGHUP
- X SIGHUP,
- X#endif
- X#ifdef SIGINT
- X SIGINT,
- X#endif
- X#ifdef SIGPIPE
- X SIGPIPE,
- X#endif
- X#ifdef SIGQUIT
- X SIGQUIT,
- X#endif
- X#ifdef SIGTERM
- X SIGTERM,
- X#endif
- X#ifdef SIGXCPU
- X SIGXCPU,
- X#endif
- X#ifdef SIGXFSZ
- X SIGXFSZ,
- X#endif
- X};
- X#define SIGS (sizeof(sig)/sizeof(*sig))
- X
- X
- X#if has_sigaction
- X
- X static void
- X checksig(r)
- X int r;
- X {
- X if (r < 0)
- X efaterror("signal");
- X }
- X
- X void
- X catchints()
- X {
- X register int i;
- X sigset_t blocked;
- X struct sigaction act;
- X
- X checksig(sigemptyset(&blocked));
- X for (i=SIGS; 0<=--i; )
- X checksig(sigaddset(&blocked, sig[i]));
- X for (i=SIGS; 0<=--i; ) {
- X checksig(sigaction(sig[i], (struct sigaction*)nil, &act));
- X if (act.sa_handler != SIG_IGN) {
- X act.sa_handler = catchsig;
- X act.sa_mask = blocked;
- X checksig(sigaction(sig[i], &act, (struct sigaction*)nil));
- X }
- X }
- X }
- X
- X#else
- X#if has_sigblock
- X
- X void catchints()
- X {
- X register int i;
- X int mask;
- X
- X mask = 0;
- X for (i=SIGS; 0<=--i; )
- X mask |= sigmask(sig[i]);
- X mask = sigblock(mask);
- X for (i=SIGS; 0<=--i; )
- X if (signal(sig[i], catchsig) == SIG_IGN)
- X VOID signal(sig[i], SIG_IGN);
- X VOID sigsetmask(mask);
- X }
- X
- X#else
- X
- X void catchints()
- X {
- X register i;
- X for (i=SIGS; 0<=--i; )
- X if (signal(sig[i], SIG_IGN) != SIG_IGN)
- X VOID signal(sig[i], catchsig);
- X }
- X
- X#endif
- X#endif
- X
- X
- X void
- Xfastcopy(inf,outf)
- XFILE * inf, * outf;
- X/* Function: copies the remainder of file inf to outf.
- X */
- X{ char buf[BUFSIZ];
- X register fread_type rcount;
- X
- X /*now read the rest of the file in blocks*/
- X while (!feof(inf) && (rcount = fread(buf,sizeof(char),BUFSIZ,inf))) {
- X awrite(buf, rcount, outf);
- X }
- X}
- X
- X void
- Xawrite(buf, chars, f)
- X const char *buf;
- X fread_type chars;
- X FILE *f;
- X{
- X if (fwrite(buf, sizeof(char), chars, f) != chars)
- X IOerror();
- X}
- X
- X
- X
- X
- X
- X/*
- X* Print RCS format date and time in user-readable format.
- X*/
- X void
- Xprintdate(f, date, separator)
- X register FILE *f;
- X const char *date, *separator;
- X{
- X register const char *p = date;
- X
- X while (*p++ != '.')
- X ;
- X aprintf(f, "%s%.*s/%.2s/%.2s%s%.2s:%.2s:%s",
- X date[2]=='.' && VERSION(5)<=RCSversion ? "19" : "",
- X p-date-1, date,
- X p, p+3, separator, p+6, p+9, p+12
- X );
- X}
- X
- X
- X
- X
- Xstatic int fdreopen(fd, file, flags, mode)
- X int fd;
- X const char *file;
- X int flags;
- X mode_t mode;
- X{
- X int newfd;
- X VOID close(fd);
- X newfd =
- X#if !open_can_creat
- X flags&O_CREAT ? creat(file,mode) :
- X#endif
- X open(file,flags,mode);
- X if (newfd < 0 || newfd == fd)
- X return newfd;
- X fd = dup2(newfd, fd);
- X VOID close(newfd);
- X return fd;
- X}
- X
- Xstatic void tryopen(fd,file,flags)
- X int fd, flags;
- X const char *file;
- X{
- X if (file && fdreopen(fd,file,flags,S_IRUSR|S_IWUSR) != fd) {
- X VOID write(STDERR_FILENO, file, strlen(file));
- X VOID write(STDERR_FILENO, ": can't open\n", 13);
- X _exit(EXIT_TROUBLE);
- X }
- X}
- X
- X/*
- X* Run 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.
- X*/
- X int
- Xrunv(inoutargs)
- X const char **inoutargs;
- X{
- X int pid;
- X int wstatus, w;
- X register const char **p;
- X oflush();
- X eflush();
- X if (!(pid = vfork())) {
- X p = inoutargs;
- X tryopen(STDIN_FILENO, *p++, O_RDONLY);
- X tryopen(STDOUT_FILENO, *p++, O_CREAT|O_TRUNC|O_WRONLY);
- X VOID EXECRCS(*p, p);
- X if (errno == ENOEXEC) {
- X *--p = "/bin/sh";
- X VOID execv(*p, p);
- X }
- X VOID write(STDERR_FILENO, *p, strlen(*p));
- X VOID write(STDERR_FILENO, ": not found\n", 12);
- X _exit(EXIT_TROUBLE);
- X }
- X if (pid < 0)
- X return pid;
- X do {
- X if ((w = wait(&wstatus)) < 0)
- X return w;
- X } while (w != pid);
- X return wstatus;
- 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*/
- X int
- X#if has_prototypes
- Xrun(const char *infile, const char *outfile, ...)
- X#else
- X /*VARARGS2*/
- Xrun(infile, outfile, va_alist)
- X const char *infile;
- X const char *outfile;
- X va_dcl
- X#endif
- X{
- X va_list ap;
- X const char *rgargs[CARGSMAX];
- X register i = 0;
- X rgargs[0] = infile;
- X rgargs[1] = outfile;
- X vararg_start(ap, outfile);
- X for (i = 2; (rgargs[i++] = va_arg(ap, const char*)); )
- X if (CARGSMAX <= i)
- X faterror("too many command arguments");
- X va_end(ap);
- X return runv(rgargs);
- X}
- X
- X
- Xint RCSversion;
- X
- X void
- XsetRCSversion(str)
- X const char *str;
- X{
- X static const char *oldversion;
- X
- X register const char *s = str + 2;
- X int v = VERSION_DEFAULT;
- X
- X if (oldversion)
- X redefined('V');
- X oldversion = str;
- X
- X if (*s) {
- X v = 0;
- X while (isdigit(*s))
- X v = 10*v + *s++ - '0';
- X if (*s)
- X faterror("%s isn't a number", str);
- X if (v < VERSION_MIN || VERSION_MAX < v)
- X faterror("%s out of range %d..%d", str, VERSION_MIN, VERSION_MAX);
- X }
- X
- X RCSversion = VERSION(v);
- X}
- X
- X void
- Xinitid()
- X{
- X#if SETID
- X egid = getegid();
- X euid = geteuid();
- X rgid = getgid();
- X#endif
- X#if has_getuid
- X ruid = getuid();
- X#endif
- X setrid();
- X}
- X
- X
- X#if SETID
- X void
- Xseteid()
- X/* Become effective user and group. */
- X{
- X if (euid!=ruid && seteuid(euid)<0 || egid!=rgid && setegid(egid)<0)
- X efaterror("seteid");
- X}
- X
- X void
- Xsetrid()
- X/* Become real user and group. */
- X{
- X if (euid!=ruid && seteuid(ruid)<0 || egid!=rgid && setegid(rgid)<0)
- X efaterror("setrid");
- X}
- X#endif
- END_OF_FILE
- if test 17610 -ne `wc -c <'src/rcsutil.c'`; then
- echo shar: \"'src/rcsutil.c'\" unpacked with wrong size!
- fi
- # end of 'src/rcsutil.c'
- fi
- if test -f 'src/rlog.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/rlog.c'\"
- else
- echo shar: Extracting \"'src/rlog.c'\" \(32911 characters\)
- sed "s/^X//" >'src/rlog.c' <<'END_OF_FILE'
- X/*
- X * RLOG operation
- X */
- X/*****************************************************************************
- X * print contents of RCS files
- X *****************************************************************************
- X */
- X
- X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
- X Copyright 1990 by Paul Eggert
- X Distributed under license by the Free Software Foundation, Inc.
- X
- XThis file is part of RCS.
- X
- XRCS is free software; you can redistribute it and/or modify
- Xit under the terms of the GNU General Public License as published by
- Xthe Free Software Foundation; either version 1, or (at your option)
- Xany later version.
- X
- XRCS is distributed in the hope that it will be useful,
- Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
- XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- XGNU General Public License for more details.
- X
- XYou should have received a copy of the GNU General Public License
- Xalong with RCS; see the file COPYING. If not, write to
- Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- XReport problems and direct all questions to:
- X
- X rcs-bugs@cs.purdue.edu
- X
- X*/
- X
- X
- X
- X
- X/* $Log: rlog.c,v $
- X * Revision 5.5 1990/11/01 05:03:55 eggert
- X * Permit arbitrary data in logs and comment leaders.
- X *
- X * Revision 5.4 1990/10/04 06:30:22 eggert
- X * Accumulate exit status across files.
- X *
- X * Revision 5.3 1990/09/11 02:41:16 eggert
- X * Plug memory leak.
- X *
- X * Revision 5.2 1990/09/04 08:02:33 eggert
- X * Count RCS lines better.
- X *
- X * Revision 5.0 1990/08/22 08:13:48 eggert
- X * Remove compile-time limits; use malloc instead. Add setuid support.
- X * Switch to GMT.
- X * Report dates in long form, to warn about dates past 1999/12/31.
- X * Change "added/del" message to make room for the longer dates.
- X * Don't generate trailing white space. Add -V. Ansify and Posixate.
- X *
- 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/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 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 "rcsbase.h"
- X
- Xstruct lockers { /* lockers in locker option; stored */
- X const char * login; /* lockerlist */
- X struct lockers * lockerlink;
- X } ;
- X
- Xstruct stateattri { /* states in state option; stored in */
- X const char * status; /* statelist */
- X struct stateattri * nextstate;
- X } ;
- X
- Xstruct authors { /* login names in author option; */
- X const char * login; /* stored in authorlist */
- X struct authors * nextauthor;
- X } ;
- X
- Xstruct Revpairs{ /* revision or branch range in -r */
- X unsigned numfld; /* option; stored in revlist */
- X const char * strtrev;
- X const char * endrev;
- X struct Revpairs * rnext;
- X } ;
- X
- Xstruct Datepairs{ /* date range in -d option; stored in */
- X char strtdate[datesize]; /* duelst and datelist */
- X char enddate[datesize];
- X struct Datepairs * dnext;
- X };
- X
- Xstatic char extractdelta P((const struct hshentry*));
- Xstatic int checkrevpair P((const char*,const char*));
- Xstatic int readdeltalog P((void));
- Xstatic void cleanup P((void));
- Xstatic void extdate P((struct hshentry*));
- Xstatic void exttree P((struct hshentry*));
- Xstatic void getauthor P((char*));
- Xstatic void getdatepair P((char*));
- Xstatic void getlocker P((char*));
- Xstatic void getnumericrev P((void));
- Xstatic void getrevpairs P((char*));
- Xstatic void getscript P((struct hshentry*));
- Xstatic void getstate P((char*));
- Xstatic void putabranch P((const struct hshentry*));
- Xstatic void putadelta P((const struct hshentry*,const struct hshentry*,int));
- Xstatic void putforest P((const struct branchhead*));
- Xstatic void putree P((const struct hshentry*));
- Xstatic void putrunk P((void));
- Xstatic void recentdate P((const struct hshentry*,struct Datepairs*));
- Xstatic void trunclocks P((void));
- X
- Xstatic const char *insDelFormat;
- Xstatic int branchflag; /*set on -b */
- Xstatic int exitstatus;
- Xstatic int lockflag;
- Xstatic int revno; /* number of revision chosen */
- Xstatic struct Datepairs *datelist, *duelst;
- Xstatic struct Revpairs *revlist, *Revlst;
- Xstatic struct authors *authorlist;
- Xstatic struct lockers *lockerlist;
- Xstatic struct stateattri *statelist;
- X
- X
- XmainProg(rlogId, "rlog", "$Id: rlog.c,v 5.5 1990/11/01 05:03:55 eggert Exp $")
- X{
- X static const char cmdusage[] =
- X "\nrlog usage: rlog -{bhLRt} -ddates -l[lockers] -rrevs -sstates -w[logins] -Vn file ...";
- X
- X struct Datepairs *currdate;
- X const char *accessListString, *accessFormat, *commentFormat;
- X const char *headFormat, *symbolFormat;
- X const struct access *curaccess;
- X const struct assoc *curassoc;
- X const struct lock *currlock;
- X int descflag, selectflag;
- X int onlylockflag; /* print only files with locks */
- X int selectop; /* print only some revisions */
- X int onlyRCSflag; /* print only RCS file name */
- X
- X initid();
- X
- X descflag = selectflag = true;
- X onlylockflag = selectop = onlyRCSflag = false;
- 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("-t overrides -h.");
- X else descflag = false;
- X break;
- X
- X case 't':
- X selectflag = false;
- X if ( ! descflag ) warn("-t overrides -h.");
- X descflag = true;
- X break;
- X
- X case 'V':
- X setRCSversion(*argv);
- X break;
- X
- X default:
- X faterror("unknown option: %s%s", *argv, cmdusage);
- X
- X };
- X } /* end of option processing */
- X
- X if (argc<1) faterror("no input file%s", cmdusage);
- X
- X if (RCSversion < VERSION(5)) {
- X accessListString = "\naccess list: ";
- X accessFormat = " %s";
- X commentFormat = "\ncomment leader: \"";
- X headFormat = "\nRCS file: %s; Working file: %s\nhead: %s%s\nbranch: %s%s\nlocks: ";
- X insDelFormat = " lines added/del: %lu/%lu";
- X symbolFormat = " %s: %s;";
- X } else {
- X accessListString = "\naccess list:";
- X accessFormat = "\n\t%s";
- X commentFormat = "\ncomment leader: \"";
- X headFormat = "\nRCS file: %s\nWorking file: %s\nhead:%s%s\nbranch:%s%s\nlocks:%s";
- X insDelFormat = " lines: +%lu -%lu";
- X symbolFormat = "\n\t%s: %s";
- X }
- X
- X /* now handle all filenames */
- X do {
- X finptr = NULL;
- X ffree();
- X
- X if (!pairfilenames(argc, argv, rcsreadopen, true, false))
- X 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 /* Keep only those locks given by -l. */
- X if (lockflag)
- X trunclocks();
- X
- X /* do nothing if -L is given and there are no locks*/
- X if (onlylockflag && !Locks)
- X continue;
- X
- X if ( onlyRCSflag ) {
- X aprintf(stdout, "%s\n", RCSfilename);
- X continue;
- X }
- X /* print RCS filename , working filename and optional
- X administrative information */
- X /* could use getfullRCSname() here, but that is very slow */
- X aprintf(stdout, headFormat, RCSfilename, workfilename,
- X Head ? " " : "", Head ? Head->num : "",
- X Dbranch ? " " : "", Dbranch ? Dbranch : "",
- X StrictLocks ? " strict" : ""
- X );
- X currlock = Locks;
- X while( currlock ) {
- X aprintf(stdout, symbolFormat, currlock->login,
- X currlock->delta->num);
- X currlock = currlock->nextlock;
- X }
- X if (StrictLocks && RCSversion<VERSION(5))
- X aputs(" strict", stdout);
- X
- X aputs(accessListString, stdout); /* print access list */
- X curaccess = AccessList;
- X while(curaccess) {
- X aprintf(stdout, accessFormat, curaccess->login);
- X curaccess = curaccess->nextaccess;
- X }
- X
- X aputs("\nsymbolic names:", stdout); /* print symbolic names */
- X for (curassoc=Symbols; curassoc; curassoc=curassoc->nextassoc)
- X aprintf(stdout, symbolFormat, curassoc->symbol, curassoc->num);
- X aputs(commentFormat, stdout);
- X awrite(Comment.string, Comment.size, stdout);
- X aputs("\"\n", stdout);
- X if (VERSION(5)<=RCSversion || Expand != KEYVAL_EXPAND)
- X aprintf(stdout, "keyword substitution: %s\n",
- X expand_names[Expand]
- X );
- X
- X gettree();
- X
- X aprintf(stdout, "total revisions: %d", TotalDeltas);
- X
- X if ( Head == nil || !selectflag || !descflag) {
- X afputc('\n',stdout);
- X if (descflag) aputs("description:\n", stdout);
- X getdesc(descflag);
- X goto rlogend;
- X }
- X
- X
- 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 aprintf(stdout, ";\tselected revisions: %d", revno);
- X afputc('\n', stdout);
- X if (descflag) aputs("description:\n", stdout);
- X getdesc(descflag);
- X if (selectflag && descflag && revno) {
- X while (readdeltalog())
- X ;
- X putrunk();
- X putree(Head);
- X if (nexttok != EOFILE)
- X fatserror("expecting EOF");
- X }
- X rlogend:
- X aputs("=============================================================================\n",stdout);
- X } while (cleanup(),
- X ++argv, --argc >= 1);
- X exitmain(exitstatus);
- X}
- X
- X static void
- Xcleanup()
- X{
- X if (nerror) exitstatus = EXIT_FAILURE;
- X if (finptr) ffclose(finptr);
- X}
- X
- X#if lint
- X# define exiterr rlogExit
- X#endif
- X exiting void
- Xexiterr()
- X{
- X _exit(EXIT_FAILURE);
- X}
- X
- X
- X
- X static void
- Xputrunk()
- X/* function: print revisions chosen, which are in trunk */
- X
- X{
- X register const struct hshentry *ptr;
- X
- X for (ptr = Head; ptr; ptr = ptr->next)
- X putadelta(ptr, ptr->next, true);
- X}
- X
- X
- X
- X static void
- Xputree(root)
- X const struct hshentry *root;
- X/* function: print delta tree (not including trunk) in reverse
- 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
- X static void
- Xputforest(branchroot)
- X const struct 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
- X static void
- Xputabranch(root)
- X const struct 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
- X static void
- Xputadelta(node,editscript,trunk)
- X register const struct hshentry *node, *editscript;
- X int trunk;
- X/* function: Print delta node if node->selector is set. */
- X/* editscript indicates where the editscript is stored */
- X/* trunk indicated whether this node is in trunk */
- X{
- X const struct branchhead *newbranch;
- X struct buf branchnum;
- X
- X if (!node->selector)
- X return;
- X
- X aprintf(stdout,
- X "----------------------------\nrevision %s", node->num
- X );
- X if ( node->lockedby )
- X aprintf(stdout, "\tlocked by: %s;", node->lockedby);
- X
- X aputs("\ndate: ",stdout);
- X printdate(stdout, node->date, " ");
- X aprintf(stdout, "; author: %s; state: %s;",
- X node->author, node->state
- X );
- X
- X if ( editscript )
- X if(trunk)
- X aprintf(stdout, insDelFormat,
- X editscript->deletelns, editscript->insertlns);
- X else
- X aprintf(stdout, insDelFormat,
- X editscript->insertlns, editscript->deletelns);
- X
- X newbranch = node->branches;
- X if ( newbranch ) {
- X bufautobegin(&branchnum);
- X aputs("\nbranches:", stdout);
- X while( newbranch ) {
- X getbranchno(newbranch->hsh->num, &branchnum);
- X aprintf(stdout, " %s;", branchnum.string);
- X newbranch = newbranch->nextbranch;
- X }
- X bufautoend(&branchnum);
- X }
- X
- X afputc('\n', stdout);
- X awrite(node->log.string, node->log.size, stdout);
- X}
- X
- X
- X
- X
- X
- X static int
- 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 struct buf logbuf;
- X
- X nextlex();
- X if ( !(Delta = getnum() )) return(false);
- X getkeystring(Klog);
- X bufautobegin(&logbuf);
- X Delta->log = savestring(&logbuf);
- X /*
- X * Do the following instead of bufautoend(&logbuf),
- X * because the buffer must survive until we are done with the file.
- X */
- X Delta->log.string = (char *)fremember(testrealloc(
- X (malloc_type)logbuf.string,
- X Delta->log.size
- X ));
- X
- X nextlex();
- X while (nexttok==ID && strcmp(NextString,Ktext)!=0)
- X ignorephrase();
- X getkeystring(Ktext);
- X Delta->insertlns = Delta->deletelns = 0;
- X if ( Delta != Head)
- X getscript(Delta);
- X else
- X readstring();
- X return true;
- X}
- X
- X
- X
- X static void
- 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 unsigned long i;
- X struct diffcmd dc;
- X
- X fin = finptr;
- X initdiffcmd(&dc);
- X while (0 <= (ed = getdiffcmd(fin,SDELIM,(FILE *)0,&dc)))
- X if (!ed)
- X Delta->deletelns += dc.nlines;
- X else {
- X /* skip scripted lines */
- X i = dc.nlines;
- X Delta->insertlns += i;
- X do {
- X while ((c=getc(fin)) != '\n')
- X if (c==EOF || c==SDELIM && (c=getc(fin))!=SDELIM) {
- X if (c==EOF || i!=1)
- X fatserror("unexpected end to edit script");
- X nextc = c;
- X return;
- X }
- X ++rcsline;
- X } while (--i);
- X }
- X nextc = getc(fin);
- X}
- X
- X
- X
- X
- X
- X
- X
- X static void
- Xexttree(root)
- Xstruct hshentry *root;
- X/* function: select revisions , starting with root */
- X
- X{
- X const struct branchhead *newbranch;
- X
- X if (root == nil) return;
- X
- X root->selector = 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
- X static void
- 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 = talloc(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
- X static void
- Xgetauthor(argv)
- Xchar *argv;
- X/* function: get the author's name from command line */
- X/* and store in authorlist */
- 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 = talloc(struct authors);
- X authorlist->login = getcaller();
- X authorlist->nextauthor = nil;
- X return;
- X }
- X
- X while( c != '\0' ) {
- X newauthor = talloc(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
- X static void
- 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 = talloc(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
- X static void
- 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 const 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
- X static void
- Xrecentdate(root, pd)
- X const struct hshentry *root;
- X struct 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 interval given by pd, */
- X/* and sets the strtdate of pd to the date of the selected delta */
- X{
- X const struct branchhead *newbranch;
- X
- X if ( root == nil) return;
- X if (root->selector) {
- 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
- X static void
- 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 const struct branchhead *newbranch;
- X const 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 for (;;) {
- X if (!pdate) {
- X root->selector = false;
- X break;
- X }
- X if ( cmpnum(root->date, pdate->strtdate) == 0)
- X break;
- X pdate = pdate->dnext;
- X }
- X }
- X }
- X if (root->selector)
- X ++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
- X static char
- Xextractdelta(pdelta)
- X const struct hshentry *pdelta;
- X/* function: compare information of pdelta to the authorlist, lockerlist,*/
- X/* statelist, revlist and yield true if pdelta is selected. */
- X
- X{
- X const struct lock *plock;
- X const struct stateattri *pstate;
- X const struct authors *pauthor;
- X const struct Revpairs *prevision;
- X unsigned length;
- X
- X if ((pauthor = authorlist)) /* only certain authors wanted */
- X while (strcmp(pauthor->login, pdelta->author) != 0)
- X if (!(pauthor = pauthor->nextauthor))
- X return false;
- X if ((pstate = statelist)) /* only certain states wanted */
- X while (strcmp(pstate->status, pdelta->state) != 0)
- X if (!(pstate = pstate->nextstate))
- X return false;
- X if (lockflag) /* only locked revisions wanted */
- X for (plock = Locks; ; plock = plock->nextlock)
- X if (!plock)
- X return false;
- X else if (plock->delta == pdelta)
- X break;
- X if ((prevision = Revlst)) /* only certain revs or branches wanted */
- X for (;;) {
- X length = prevision->numfld;
- X if (
- X countnumflds(pdelta->num) == length+(length&1) &&
- X 0 <= compartial(pdelta->num, prevision->strtrev, length) &&
- X 0 <= compartial(prevision->endrev, pdelta->num, length)
- X )
- X break;
- X if (!(prevision = prevision->rnext))
- X return false;
- X }
- X return true;
- X}
- X
- X
- X
- X static void
- 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 const 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 = talloc(struct Datepairs);
- X if ( c == '<' ) { /* case: -d <date */
- X c = *++argv;
- X (nextdate->strtdate)[0] = '\0';
- X } else if (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 str2date(rawdate,
- X switchflag ? nextdate->enddate : nextdate->strtdate);
- 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 str2date(rawdate,
- X switchflag ? nextdate->strtdate : nextdate->enddate);
- X nextdate->dnext = datelist;
- X datelist = nextdate;
- X end:
- X if ( c == '\0') return;
- X while( (c = *++argv) == ';' || c == ' ' || c == '\t' || c =='\n');
- X }
- X}
- X
- X
- X
- X static void
- 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 unsigned n;
- X struct buf s, e;
- X const struct buf *rstart, *rend;
- X
- X Revlst = nil;
- X ptr = revlist;
- X bufautobegin(&s);
- X bufautobegin(&e);
- X while( ptr ) {
- X n = 0;
- X rstart = &s;
- X rend = &e;
- X
- X switch (ptr->numfld) {
- X
- X case 1: /* -r rev */
- X if (expandsym(ptr->strtrev, &s)) {
- X rend = &s;
- X n = countnumflds(s.string);
- X }
- X break;
- X
- X case 2: /* -r rev- */
- X if (expandsym(ptr->strtrev, &s)) {
- X bufscpy(&e, s.string);
- X n = countnumflds(s.string);
- X (n<2 ? e.string : strrchr(e.string,'.'))[0] = 0;
- X }
- X break;
- X
- X case 3: /* -r -rev */
- X if (expandsym(ptr->endrev, &e)) {
- X if ((n = countnumflds(e.string)) < 2)
- X bufscpy(&s, ".1");
- X else {
- X bufscpy(&s, e.string);
- X VOID strcpy(strrchr(s.string,'.'), ".1");
- X }
- X }
- X break;
- X
- X default: /* -r rev1-rev2 */
- X if (
- X expandsym(ptr->strtrev, &s)
- X && expandsym(ptr->endrev, &e)
- X && checkrevpair(s.string, e.string)
- X ) {
- X n = countnumflds(s.string);
- X /* Swap if out of order. */
- X if (compartial(s.string,e.string,n) > 0) {
- X rstart = &e;
- X rend = &s;
- X }
- X }
- X break;
- X }
- X
- X if (n) {
- X pt = ftalloc(struct Revpairs);
- X pt->numfld = n;
- X pt->strtrev = fstrsave(rstart->string);
- X pt->endrev = fstrsave(rend->string);
- X pt->rnext = Revlst;
- X Revlst = pt;
- X }
- X ptr = ptr->rnext;
- X }
- X /* Now take care of branchflag */
- X if (branchflag && (Dbranch||Head)) {
- X pt = ftalloc(struct Revpairs);
- X pt->strtrev = pt->endrev =
- X Dbranch ? Dbranch : fstrsave(partialno(&s,Head->num,1));
- X pt->rnext=Revlst; Revlst=pt;
- X pt->numfld = countnumflds(pt->strtrev);
- X }
- X bufautoend(&s);
- X bufautoend(&e);
- X}
- X
- X
- X
- X static int
- Xcheckrevpair(num1,num2)
- X const char *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 fields( if length <= 2, may be different if first field) */
- X
- X{
- X unsigned length = countnumflds(num1);
- X
- X if (
- X countnumflds(num2) != length
- X || 2 < length && compartial(num1, num2, length-1) != 0
- X ) {
- X error("invalid branch or revision pair %s : %s", num1, num2);
- X return false;
- X }
- X
- X return true;
- X}
- X
- X
- X
- X static void
- 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 = talloc(struct Revpairs);
- X nextrevpair->rnext = revlist;
- X revlist = nextrevpair;
- X nextrevpair->numfld = 0;
- 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}
- END_OF_FILE
- if test 32911 -ne `wc -c <'src/rlog.c'`; then
- echo shar: \"'src/rlog.c'\" unpacked with wrong size!
- fi
- # end of 'src/rlog.c'
- fi
- echo shar: End of archive 4 \(of 12\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 12 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-