freebsd-dev/gnu/usr.bin/rcs/lib/rcsrev.c

912 lines
22 KiB
C
Raw Normal View History

/* Handle RCS revision numbers. */
1993-06-18 04:22:21 +00:00
/* Copyright 1982, 1988, 1989 Walter Tichy
Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
1993-06-18 04:22:21 +00:00
Distributed under license by the Free Software Foundation, Inc.
This file is part of RCS.
RCS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
RCS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RCS; see the file COPYING.
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1993-06-18 04:22:21 +00:00
Report problems and direct all questions to:
rcs-bugs@cs.purdue.edu
*/
/*
* Revision 5.10 1995/06/16 06:19:24 eggert
* Update FSF address.
*
* Revision 5.9 1995/06/01 16:23:43 eggert
* (cmpdate, normalizeyear): New functions work around MKS RCS incompatibility.
* (cmpnum, compartial): s[d] -> *(s+d) to work around Cray compiler bug.
* (genrevs, genbranch): cmpnum -> cmpdate
*
* Revision 5.8 1994/03/17 14:05:48 eggert
* Remove lint.
*
* Revision 5.7 1993/11/09 17:40:15 eggert
* Fix format string typos.
*
* Revision 5.6 1993/11/03 17:42:27 eggert
* Revision number `.N' now stands for `D.N', where D is the default branch.
* Add -z. Improve quality of diagnostics. Add `namedrev' for Name support.
*
* Revision 5.5 1992/07/28 16:12:44 eggert
* Identifiers may now start with a digit. Avoid `unsigned'.
*
* Revision 5.4 1992/01/06 02:42:34 eggert
* while (E) ; -> while (E) continue;
1995-05-30 05:05:38 +00:00
*
1993-06-18 04:22:21 +00:00
* Revision 5.3 1991/08/19 03:13:55 eggert
* Add `-r$', `-rB.'. Remove botches like `<now>' from messages. Tune.
*
* Revision 5.2 1991/04/21 11:58:28 eggert
* Add tiprev().
*
* Revision 5.1 1991/02/25 07:12:43 eggert
* Avoid overflow when comparing revision numbers.
*
* Revision 5.0 1990/08/22 08:13:43 eggert
* Remove compile-time limits; use malloc instead.
* Ansify and Posixate. Tune.
* Remove possibility of an internal error. Remove lint.
*
* Revision 4.5 89/05/01 15:13:22 narten
* changed copyright header to reflect current distribution rules
1995-05-30 05:05:38 +00:00
*
1993-06-18 04:22:21 +00:00
* Revision 4.4 87/12/18 11:45:22 narten
1995-05-30 05:05:38 +00:00
* more lint cleanups. Also, the NOTREACHED comment is no longer necessary,
1993-06-18 04:22:21 +00:00
* since there's now a return value there with a value. (Guy Harris)
1995-05-30 05:05:38 +00:00
*
1993-06-18 04:22:21 +00:00
* Revision 4.3 87/10/18 10:38:42 narten
1995-05-30 05:05:38 +00:00
* Updating version numbers. Changes relative to version 1.1 actually
1993-06-18 04:22:21 +00:00
* relative to 4.1
1995-05-30 05:05:38 +00:00
*
1993-06-18 04:22:21 +00:00
* Revision 1.3 87/09/24 14:00:37 narten
1995-05-30 05:05:38 +00:00
* Sources now pass through lint (if you ignore printf/sprintf/fprintf
1993-06-18 04:22:21 +00:00
* warnings)
1995-05-30 05:05:38 +00:00
*
1993-06-18 04:22:21 +00:00
* Revision 1.2 87/03/27 14:22:37 jenkins
* Port to suns
1995-05-30 05:05:38 +00:00
*
1993-06-18 04:22:21 +00:00
* Revision 4.1 83/03/25 21:10:45 wft
* Only changed $Header to $Id.
1995-05-30 05:05:38 +00:00
*
1993-06-18 04:22:21 +00:00
* Revision 3.4 82/12/04 13:24:08 wft
* Replaced getdelta() with gettree().
*
* Revision 3.3 82/11/28 21:33:15 wft
* fixed compartial() and compnum() for nil-parameters; fixed nils
* in error messages. Testprogram output shortenend.
*
* Revision 3.2 82/10/18 21:19:47 wft
* renamed compnum->cmpnum, compnumfld->cmpnumfld,
* numericrevno->numricrevno.
*
* Revision 3.1 82/10/11 19:46:09 wft
* changed expandsym() to check for source==nil; returns zero length string
* in that case.
*/
#include "rcsbase.h"
1999-08-27 23:37:10 +00:00
libId(revId, "$FreeBSD$")
1993-06-18 04:22:21 +00:00
static char const *branchtip P((char const*));
static char const *lookupsym P((char const*));
static char const *normalizeyear P((char const*,char[5]));
static struct hshentry *genbranch P((struct hshentry const*,char const*,int,char const*,char const*,char const*,struct hshentries**));
static void absent P((char const*,int));
static void cantfindbranch P((char const*,char const[datesize],char const*,char const*));
static void store1 P((struct hshentries***,struct hshentry*));
1993-06-18 04:22:21 +00:00
int
1993-06-18 04:22:21 +00:00
countnumflds(s)
char const *s;
/* Given a pointer s to a dotted number (date or revision number),
* countnumflds returns the number of digitfields in s.
*/
{
register char const *sp;
register int count;
if (!(sp=s) || !*sp)
return 0;
1993-06-18 04:22:21 +00:00
count = 1;
do {
if (*sp++ == '.') count++;
} while (*sp);
return(count);
}
void
getbranchno(revno,branchno)
char const *revno;
struct buf *branchno;
/* Given a revision number revno, getbranchno copies the number of the branch
1993-06-18 04:22:21 +00:00
* on which revno is into branchno. If revno itself is a branch number,
* it is copied unchanged.
*/
{
register int numflds;
1993-06-18 04:22:21 +00:00
register char *tp;
bufscpy(branchno, revno);
numflds=countnumflds(revno);
if (!(numflds & 1)) {
tp = branchno->string;
while (--numflds)
while (*tp++ != '.')
continue;
1993-06-18 04:22:21 +00:00
*(tp-1)='\0';
}
}
int cmpnum(num1, num2)
char const *num1, *num2;
/* compares the two dotted numbers num1 and num2 lexicographically
* by field. Individual fields are compared numerically.
* returns <0, 0, >0 if num1<num2, num1==num2, and num1>num2, resp.
* omitted fields are assumed to be higher than the existing ones.
*/
{
register char const *s1, *s2;
register size_t d1, d2;
register int r;
s1 = num1 ? num1 : "";
s2 = num2 ? num2 : "";
1993-06-18 04:22:21 +00:00
for (;;) {
/* Give precedence to shorter one. */
if (!*s1)
return (unsigned char)*s2;
if (!*s2)
return -1;
/* Strip leading zeros, then find number of digits. */
while (*s1=='0') ++s1;
while (*s2=='0') ++s2;
for (d1=0; isdigit(*(s1+d1)); d1++) continue;
for (d2=0; isdigit(*(s2+d2)); d2++) continue;
1993-06-18 04:22:21 +00:00
/* Do not convert to integer; it might overflow! */
if (d1 != d2)
return d1<d2 ? -1 : 1;
if ((r = memcmp(s1, s2, d1)))
return r;
s1 += d1;
s2 += d1;
/* skip '.' */
if (*s1) s1++;
if (*s2) s2++;
}
}
int cmpnumfld(num1, num2, fld)
char const *num1, *num2;
int fld;
1993-06-18 04:22:21 +00:00
/* Compare the two dotted numbers at field fld.
* num1 and num2 must have at least fld fields.
* fld must be positive.
*/
{
register char const *s1, *s2;
register size_t d1, d2;
s1 = num1;
s2 = num2;
/* skip fld-1 fields */
while (--fld) {
while (*s1++ != '.')
continue;
1993-06-18 04:22:21 +00:00
while (*s2++ != '.')
continue;
1993-06-18 04:22:21 +00:00
}
/* Now s1 and s2 point to the beginning of the respective fields */
while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
1993-06-18 04:22:21 +00:00
return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;
}
int
cmpdate(d1, d2)
char const *d1, *d2;
/*
* Compare the two dates. This is just like cmpnum,
* except that for compatibility with old versions of RCS,
* 1900 is added to dates with two-digit years.
*/
{
char year1[5], year2[5];
int r = cmpnumfld(normalizeyear(d1,year1), normalizeyear(d2,year2), 1);
if (r)
return r;
else {
while (isdigit(*d1)) d1++; d1 += *d1=='.';
while (isdigit(*d2)) d2++; d2 += *d2=='.';
return cmpnum(d1, d2);
}
}
static char const *
normalizeyear(date, year)
char const *date;
char year[5];
{
if (isdigit(date[0]) && isdigit(date[1]) && !isdigit(date[2])) {
year[0] = '1';
year[1] = '9';
year[2] = date[0];
year[3] = date[1];
year[4] = 0;
return year;
} else
return date;
}
1993-06-18 04:22:21 +00:00
static void
cantfindbranch(revno, date, author, state)
char const *revno, date[datesize], *author, *state;
{
char datebuf[datesize + zonelenmax];
1993-06-18 04:22:21 +00:00
rcserror("No revision on branch %s has%s%s%s%s%s%s.",
1993-06-18 04:22:21 +00:00
revno,
date ? " a date before " : "",
date ? date2str(date,datebuf) : "",
author ? " and author "+(date?0:4) : "",
author ? author : "",
state ? " and state "+(date||author?0:4) : "",
state ? state : ""
);
}
static void
absent(revno, field)
char const *revno;
int field;
1993-06-18 04:22:21 +00:00
{
struct buf t;
bufautobegin(&t);
rcserror("%s %s absent", field&1?"revision":"branch",
1993-06-18 04:22:21 +00:00
partialno(&t,revno,field)
);
bufautoend(&t);
}
int
compartial(num1, num2, length)
char const *num1, *num2;
int length;
1993-06-18 04:22:21 +00:00
/* compare the first "length" fields of two dot numbers;
the omitted field is considered to be larger than any number */
/* restriction: at least one number has length or more fields */
{
register char const *s1, *s2;
register size_t d1, d2;
register int r;
s1 = num1; s2 = num2;
if (!s1) return 1;
if (!s2) return -1;
for (;;) {
if (!*s1) return 1;
if (!*s2) return -1;
while (*s1=='0') ++s1; for (d1=0; isdigit(*(s1+d1)); d1++) continue;
while (*s2=='0') ++s2; for (d2=0; isdigit(*(s2+d2)); d2++) continue;
1993-06-18 04:22:21 +00:00
if (d1 != d2)
return d1<d2 ? -1 : 1;
if ((r = memcmp(s1, s2, d1)))
return r;
if (!--length)
return 0;
1993-06-18 04:22:21 +00:00
s1 += d1;
s2 += d1;
if (*s1 == '.') s1++;
if (*s2 == '.') s2++;
}
}
char * partialno(rev1,rev2,length)
struct buf *rev1;
char const *rev2;
register int length;
1993-06-18 04:22:21 +00:00
/* Function: Copies length fields of revision number rev2 into rev1.
* Return rev1's string.
*/
{
register char *r1;
bufscpy(rev1, rev2);
r1 = rev1->string;
while (length) {
while (*r1!='.' && *r1)
++r1;
++r1;
length--;
}
/* eliminate last '.'*/
*(r1-1)='\0';
return rev1->string;
}
static void
store1(store, next)
struct hshentries ***store;
struct hshentry *next;
/*
* Allocate a new list node that addresses NEXT.
* Append it to the list that **STORE is the end pointer of.
*/
{
register struct hshentries *p;
p = ftalloc(struct hshentries);
p->first = next;
**store = p;
*store = &p->rest;
}
struct hshentry * genrevs(revno,date,author,state,store)
char const *revno, *date, *author, *state;
struct hshentries **store;
/* Function: finds the deltas needed for reconstructing the
* revision given by revno, date, author, and state, and stores pointers
* to these deltas into a list whose starting address is given by store.
* The last delta (target delta) is returned.
* If the proper delta could not be found, 0 is returned.
1993-06-18 04:22:21 +00:00
*/
{
int length;
1993-06-18 04:22:21 +00:00
register struct hshentry * next;
int result;
char const *branchnum;
struct buf t;
char datebuf[datesize + zonelenmax];
1993-06-18 04:22:21 +00:00
bufautobegin(&t);
if (!(next = Head)) {
rcserror("RCS file empty");
1993-06-18 04:22:21 +00:00
goto norev;
}
length = countnumflds(revno);
if (length >= 1) {
/* at least one field; find branch exactly */
while ((result=cmpnumfld(revno,next->num,1)) < 0) {
store1(&store, next);
next = next->next;
if (!next) {
rcserror("branch number %s too low", partialno(&t,revno,1));
1993-06-18 04:22:21 +00:00
goto norev;
}
}
if (result>0) {
absent(revno, 1);
goto norev;
}
}
if (length<=1){
/* pick latest one on given branch */
branchnum = next->num; /* works even for empty revno*/
while (next &&
cmpnumfld(branchnum,next->num,1) == 0 &&
(
(date && cmpdate(date,next->date) < 0) ||
(author && strcmp(author,next->author) != 0) ||
(state && strcmp(state,next->state) != 0)
)
)
1993-06-18 04:22:21 +00:00
{
store1(&store, next);
next=next->next;
}
if (!next ||
1993-06-18 04:22:21 +00:00
(cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
cantfindbranch(
length ? revno : partialno(&t,branchnum,1),
date, author, state
);
goto norev;
} else {
store1(&store, next);
}
*store = 0;
1993-06-18 04:22:21 +00:00
return next;
}
/* length >=2 */
/* find revision; may go low if length==2*/
while ((result=cmpnumfld(revno,next->num,2)) < 0 &&
(cmpnumfld(revno,next->num,1)==0) ) {
store1(&store, next);
next = next->next;
if (!next)
break;
}
if (!next || cmpnumfld(revno,next->num,1) != 0) {
rcserror("revision number %s too low", partialno(&t,revno,2));
1993-06-18 04:22:21 +00:00
goto norev;
}
if ((length>2) && (result!=0)) {
absent(revno, 2);
goto norev;
}
/* print last one */
store1(&store, next);
if (length>2)
return genbranch(next,revno,length,date,author,state,store);
else { /* length == 2*/
if (date && cmpdate(date,next->date)<0) {
rcserror("Revision %s has date %s.",
1993-06-18 04:22:21 +00:00
next->num,
date2str(next->date, datebuf)
);
return 0;
}
if (author && strcmp(author,next->author)!=0) {
rcserror("Revision %s has author %s.",
next->num, next->author
);
return 0;
1993-06-18 04:22:21 +00:00
}
if (state && strcmp(state,next->state)!=0) {
rcserror("Revision %s has state %s.",
next->num,
next->state ? next->state : "<empty>"
);
return 0;
1993-06-18 04:22:21 +00:00
}
*store = 0;
1993-06-18 04:22:21 +00:00
return next;
}
norev:
bufautoend(&t);
return 0;
1993-06-18 04:22:21 +00:00
}
static struct hshentry *
genbranch(bpoint, revno, length, date, author, state, store)
struct hshentry const *bpoint;
char const *revno;
int length;
1993-06-18 04:22:21 +00:00
char const *date, *author, *state;
struct hshentries **store;
/* Function: given a branchpoint, a revision number, date, author, and state,
* genbranch finds the deltas necessary to reconstruct the given revision
* from the branch point on.
* Pointers to the found deltas are stored in a list beginning with store.
* revno must be on a side branch.
* Return 0 on error.
1993-06-18 04:22:21 +00:00
*/
{
int field;
1993-06-18 04:22:21 +00:00
register struct hshentry * next, * trail;
register struct branchhead const *bhead;
int result;
struct buf t;
char datebuf[datesize + zonelenmax];
1993-06-18 04:22:21 +00:00
field = 3;
bhead = bpoint->branches;
do {
if (!bhead) {
bufautobegin(&t);
rcserror("no side branches present for %s",
partialno(&t,revno,field-1)
);
1993-06-18 04:22:21 +00:00
bufautoend(&t);
return 0;
1993-06-18 04:22:21 +00:00
}
/*find branch head*/
/*branches are arranged in increasing order*/
while (0 < (result=cmpnumfld(revno,bhead->hsh->num,field))) {
bhead = bhead->nextbranch;
if (!bhead) {
bufautobegin(&t);
rcserror("branch number %s too high",
partialno(&t,revno,field)
);
1993-06-18 04:22:21 +00:00
bufautoend(&t);
return 0;
1993-06-18 04:22:21 +00:00
}
}
if (result<0) {
absent(revno, field);
return 0;
1993-06-18 04:22:21 +00:00
}
next = bhead->hsh;
if (length==field) {
/* pick latest one on that branch */
trail = 0;
do { if ((!date || cmpdate(date,next->date)>=0) &&
(!author || strcmp(author,next->author)==0) &&
(!state || strcmp(state,next->state)==0)
1993-06-18 04:22:21 +00:00
) trail = next;
next=next->next;
} while (next);
1993-06-18 04:22:21 +00:00
if (!trail) {
1993-06-18 04:22:21 +00:00
cantfindbranch(revno, date, author, state);
return 0;
1993-06-18 04:22:21 +00:00
} else { /* print up to last one suitable */
next = bhead->hsh;
while (next!=trail) {
store1(&store, next);
next=next->next;
}
store1(&store, next);
}
*store = 0;
1993-06-18 04:22:21 +00:00
return next;
}
/* length > field */
/* find revision */
/* check low */
if (cmpnumfld(revno,next->num,field+1)<0) {
bufautobegin(&t);
rcserror("revision number %s too low",
partialno(&t,revno,field+1)
);
1993-06-18 04:22:21 +00:00
bufautoend(&t);
return 0;
1993-06-18 04:22:21 +00:00
}
do {
store1(&store, next);
trail = next;
next = next->next;
} while (next && cmpnumfld(revno,next->num,field+1)>=0);
1993-06-18 04:22:21 +00:00
if ((length>field+1) && /*need exact hit */
(cmpnumfld(revno,trail->num,field+1) !=0)){
absent(revno, field+1);
return 0;
1993-06-18 04:22:21 +00:00
}
if (length == field+1) {
if (date && cmpdate(date,trail->date)<0) {
rcserror("Revision %s has date %s.",
1993-06-18 04:22:21 +00:00
trail->num,
date2str(trail->date, datebuf)
);
return 0;
1993-06-18 04:22:21 +00:00
}
if (author && strcmp(author,trail->author)!=0) {
rcserror("Revision %s has author %s.",
trail->num, trail->author
);
return 0;
1993-06-18 04:22:21 +00:00
}
if (state && strcmp(state,trail->state)!=0) {
rcserror("Revision %s has state %s.",
trail->num,
trail->state ? trail->state : "<empty>"
);
return 0;
1993-06-18 04:22:21 +00:00
}
}
bhead = trail->branches;
} while ((field+=2) <= length);
*store = 0;
1993-06-18 04:22:21 +00:00
return trail;
}
static char const *
lookupsym(id)
char const *id;
/* Function: looks up id in the list of symbolic names starting
* with pointer SYMBOLS, and returns a pointer to the corresponding
* revision number. Return 0 if not present.
1993-06-18 04:22:21 +00:00
*/
{
register struct assoc const *next;
for (next = Symbols; next; next = next->nextassoc)
1993-06-18 04:22:21 +00:00
if (strcmp(id, next->symbol)==0)
return next->num;
return 0;
1993-06-18 04:22:21 +00:00
}
int expandsym(source, target)
char const *source;
struct buf *target;
/* Function: Source points to a revision number. Expandsym copies
* the number to target, but replaces all symbolic fields in the
* source number with their numeric values.
* Expand a branch followed by `.' to the latest revision on that branch.
* Ignore `.' after a revision. Remove leading zeros.
* returns false on error;
*/
{
return fexpandsym(source, target, (RILE*)0);
}
int
fexpandsym(source, target, fp)
char const *source;
struct buf *target;
RILE *fp;
/* Same as expandsym, except if FP is nonzero, it is used to expand KDELIM. */
{
register char const *sp, *bp;
register char *tp;
char const *tlim;
int dots;
1993-06-18 04:22:21 +00:00
sp = source;
bufalloc(target, 1);
tp = target->string;
if (!sp || !*sp) { /* Accept 0 pointer as a legal value. */
1993-06-18 04:22:21 +00:00
*tp='\0';
return true;
}
if (sp[0] == KDELIM && !sp[1]) {
if (!getoldkeys(fp))
return false;
if (!*prevrev.string) {
workerror("working file lacks revision number");
1993-06-18 04:22:21 +00:00
return false;
}
bufscpy(target, prevrev.string);
return true;
}
tlim = tp + target->size;
dots = 0;
for (;;) {
register char *p = tp;
size_t s = tp - target->string;
int id = false;
for (;;) {
switch (ctab[(unsigned char)*sp]) {
case IDCHAR:
case LETTER:
case Letter:
id = true;
/* fall into */
case DIGIT:
if (tlim <= p)
p = bufenlarge(target, &tlim);
*p++ = *sp++;
continue;
default:
break;
}
break;
}
if (tlim <= p)
p = bufenlarge(target, &tlim);
*p = 0;
tp = target->string + s;
1993-06-18 04:22:21 +00:00
if (id) {
1993-06-18 04:22:21 +00:00
bp = lookupsym(tp);
if (!bp) {
rcserror("Symbolic name `%s' is undefined.",tp);
1993-06-18 04:22:21 +00:00
return false;
}
} else {
/* skip leading zeros */
for (bp = tp; *bp=='0' && isdigit(bp[1]); bp++)
continue;
if (!*bp)
if (s || *sp!='.')
break;
else {
/* Insert default branch before initial `.'. */
char const *b;
if (Dbranch)
b = Dbranch;
else if (Head)
b = Head->num;
else
break;
getbranchno(b, target);
bp = tp = target->string;
tlim = tp + target->size;
}
}
while ((*tp++ = *bp++))
if (tlim <= tp)
tp = bufenlarge(target, &tlim);
1993-06-18 04:22:21 +00:00
switch (*sp++) {
case '\0':
1993-06-18 04:22:21 +00:00
return true;
case '.':
if (!*sp) {
if (dots & 1)
break;
if (!(bp = branchtip(target->string)))
return false;
bufscpy(target, bp);
return true;
}
++dots;
tp[-1] = '.';
continue;
1993-06-18 04:22:21 +00:00
}
break;
1993-06-18 04:22:21 +00:00
}
rcserror("improper revision number: %s", source);
1993-06-18 04:22:21 +00:00
return false;
}
char const *
namedrev(name, delta)
char const *name;
struct hshentry *delta;
/* Yield NAME if it names DELTA, 0 otherwise. */
{
if (name) {
char const *id = 0, *p, *val;
for (p = name; ; p++)
switch (ctab[(unsigned char)*p]) {
case IDCHAR:
case LETTER:
case Letter:
id = name;
break;
case DIGIT:
break;
case UNKN:
if (!*p && id &&
(val = lookupsym(id)) &&
strcmp(val, delta->num) == 0
)
return id;
/* fall into */
default:
return 0;
}
}
return 0;
}
1993-06-18 04:22:21 +00:00
static char const *
branchtip(branch)
char const *branch;
{
struct hshentry *h;
struct hshentries *hs;
h = genrevs(branch, (char*)0, (char*)0, (char*)0, &hs);
return h ? h->num : (char const*)0;
}
char const *
tiprev()
{
return Dbranch ? branchtip(Dbranch) : Head ? Head->num : (char const*)0;
}
#ifdef REVTEST
/*
* Test the routines that generate a sequence of delta numbers
* needed to regenerate a given delta.
*/
1993-06-18 04:22:21 +00:00
char const cmdid[] = "revtest";
int
main(argc,argv)
int argc; char * argv[];
{
static struct buf numricrevno;
char symrevno[100]; /* used for input of revision numbers */
char author[20];
char state[20];
char date[20];
struct hshentries *gendeltas;
struct hshentry * target;
int i;
if (argc<2) {
aputs("No input file\n",stderr);
exitmain(EXIT_FAILURE);
}
if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) {
faterror("can't open input file %s", argv[1]);
}
Lexinit();
getadmin();
gettree();
getdesc(false);
do {
/* all output goes to stderr, to have diagnostics and */
/* errors in sequence. */
aputs("\nEnter revision number or <return> or '.': ",stderr);
1995-12-01 08:26:36 +00:00
if (!fgets(symrevno, 100, stdin)) break;
1993-06-18 04:22:21 +00:00
if (*symrevno == '.') break;
aprintf(stderr,"%s;\n",symrevno);
expandsym(symrevno,&numricrevno);
aprintf(stderr,"expanded number: %s; ",numricrevno.string);
aprintf(stderr,"Date: ");
1995-12-01 08:26:36 +00:00
fgets(date, 20, stdin); aprintf(stderr,"%s; ",date);
1993-06-18 04:22:21 +00:00
aprintf(stderr,"Author: ");
1995-12-01 08:26:36 +00:00
fgets(author, 20, stdin); aprintf(stderr,"%s; ",author);
1993-06-18 04:22:21 +00:00
aprintf(stderr,"State: ");
1995-12-01 08:26:36 +00:00
fgets(state, 20, stdin); aprintf(stderr, "%s;\n", state);
target = genrevs(numricrevno.string, *date?date:(char *)0, *author?author:(char *)0,
*state?state:(char*)0, &gendeltas);
if (target) {
1993-06-18 04:22:21 +00:00
while (gendeltas) {
aprintf(stderr,"%s\n",gendeltas->first->num);
gendeltas = gendeltas->next;
}
}
} while (true);
aprintf(stderr,"done\n");
exitmain(EXIT_SUCCESS);
}
void exiterr() { _exit(EXIT_FAILURE); }
1993-06-18 04:22:21 +00:00
#endif