rcs: Fix gcc80 warnings (-Wdangling-else and -Wmisleading-indentation).
[dragonfly.git] / gnu / usr.bin / rcs / lib / rcsrev.c
blobe0f0ddc7e092fa4a5df5c2838a26a66be8a1d0d9
1 /* Handle RCS revision numbers. */
3 /* Copyright 1982, 1988, 1989 Walter Tichy
4 Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
5 Distributed under license by the Free Software Foundation, Inc.
7 This file is part of RCS.
9 RCS is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 RCS is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with RCS; see the file COPYING.
21 If not, write to the Free Software Foundation,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 Report problems and direct all questions to:
26 rcs-bugs@cs.purdue.edu
31 * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcsrev.c,v 1.8 1999/08/27 23:36:48 peter Exp $
32 * $DragonFly: src/gnu/usr.bin/rcs/lib/rcsrev.c,v 1.2 2003/06/17 04:25:47 dillon Exp $
34 * Revision 5.10 1995/06/16 06:19:24 eggert
35 * Update FSF address.
37 * Revision 5.9 1995/06/01 16:23:43 eggert
38 * (cmpdate, normalizeyear): New functions work around MKS RCS incompatibility.
39 * (cmpnum, compartial): s[d] -> *(s+d) to work around Cray compiler bug.
40 * (genrevs, genbranch): cmpnum -> cmpdate
42 * Revision 5.8 1994/03/17 14:05:48 eggert
43 * Remove lint.
45 * Revision 5.7 1993/11/09 17:40:15 eggert
46 * Fix format string typos.
48 * Revision 5.6 1993/11/03 17:42:27 eggert
49 * Revision number `.N' now stands for `D.N', where D is the default branch.
50 * Add -z. Improve quality of diagnostics. Add `namedrev' for Name support.
52 * Revision 5.5 1992/07/28 16:12:44 eggert
53 * Identifiers may now start with a digit. Avoid `unsigned'.
55 * Revision 5.4 1992/01/06 02:42:34 eggert
56 * while (E) ; -> while (E) continue;
58 * Revision 5.3 1991/08/19 03:13:55 eggert
59 * Add `-r$', `-rB.'. Remove botches like `<now>' from messages. Tune.
61 * Revision 5.2 1991/04/21 11:58:28 eggert
62 * Add tiprev().
64 * Revision 5.1 1991/02/25 07:12:43 eggert
65 * Avoid overflow when comparing revision numbers.
67 * Revision 5.0 1990/08/22 08:13:43 eggert
68 * Remove compile-time limits; use malloc instead.
69 * Ansify and Posixate. Tune.
70 * Remove possibility of an internal error. Remove lint.
72 * Revision 4.5 89/05/01 15:13:22 narten
73 * changed copyright header to reflect current distribution rules
75 * Revision 4.4 87/12/18 11:45:22 narten
76 * more lint cleanups. Also, the NOTREACHED comment is no longer necessary,
77 * since there's now a return value there with a value. (Guy Harris)
79 * Revision 4.3 87/10/18 10:38:42 narten
80 * Updating version numbers. Changes relative to version 1.1 actually
81 * relative to 4.1
83 * Revision 1.3 87/09/24 14:00:37 narten
84 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
85 * warnings)
87 * Revision 1.2 87/03/27 14:22:37 jenkins
88 * Port to suns
90 * Revision 4.1 83/03/25 21:10:45 wft
91 * Only changed $Header to $Id.
93 * Revision 3.4 82/12/04 13:24:08 wft
94 * Replaced getdelta() with gettree().
96 * Revision 3.3 82/11/28 21:33:15 wft
97 * fixed compartial() and compnum() for nil-parameters; fixed nils
98 * in error messages. Testprogram output shortenend.
100 * Revision 3.2 82/10/18 21:19:47 wft
101 * renamed compnum->cmpnum, compnumfld->cmpnumfld,
102 * numericrevno->numricrevno.
104 * Revision 3.1 82/10/11 19:46:09 wft
105 * changed expandsym() to check for source==nil; returns zero length string
106 * in that case.
109 #include "rcsbase.h"
111 libId(revId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcsrev.c,v 1.2 2003/06/17 04:25:47 dillon Exp $")
113 static char const *branchtip P((char const*));
114 static char const *lookupsym P((char const*));
115 static char const *normalizeyear P((char const*,char[5]));
116 static struct hshentry *genbranch P((struct hshentry const*,char const*,int,char const*,char const*,char const*,struct hshentries**));
117 static void absent P((char const*,int));
118 static void cantfindbranch P((char const*,char const[datesize],char const*,char const*));
119 static void store1 P((struct hshentries***,struct hshentry*));
124 countnumflds(s)
125 char const *s;
126 /* Given a pointer s to a dotted number (date or revision number),
127 * countnumflds returns the number of digitfields in s.
130 register char const *sp;
131 register int count;
132 if (!(sp=s) || !*sp)
133 return 0;
134 count = 1;
135 do {
136 if (*sp++ == '.') count++;
137 } while (*sp);
138 return(count);
141 void
142 getbranchno(revno,branchno)
143 char const *revno;
144 struct buf *branchno;
145 /* Given a revision number revno, getbranchno copies the number of the branch
146 * on which revno is into branchno. If revno itself is a branch number,
147 * it is copied unchanged.
150 register int numflds;
151 register char *tp;
153 bufscpy(branchno, revno);
154 numflds=countnumflds(revno);
155 if (!(numflds & 1)) {
156 tp = branchno->string;
157 while (--numflds)
158 while (*tp++ != '.')
159 continue;
160 *(tp-1)='\0';
166 int cmpnum(num1, num2)
167 char const *num1, *num2;
168 /* compares the two dotted numbers num1 and num2 lexicographically
169 * by field. Individual fields are compared numerically.
170 * returns <0, 0, >0 if num1<num2, num1==num2, and num1>num2, resp.
171 * omitted fields are assumed to be higher than the existing ones.
174 register char const *s1, *s2;
175 register size_t d1, d2;
176 register int r;
178 s1 = num1 ? num1 : "";
179 s2 = num2 ? num2 : "";
181 for (;;) {
182 /* Give precedence to shorter one. */
183 if (!*s1)
184 return (unsigned char)*s2;
185 if (!*s2)
186 return -1;
188 /* Strip leading zeros, then find number of digits. */
189 while (*s1=='0') ++s1;
190 while (*s2=='0') ++s2;
191 for (d1=0; isdigit(*(s1+d1)); d1++) continue;
192 for (d2=0; isdigit(*(s2+d2)); d2++) continue;
194 /* Do not convert to integer; it might overflow! */
195 if (d1 != d2)
196 return d1<d2 ? -1 : 1;
197 if ((r = memcmp(s1, s2, d1)))
198 return r;
199 s1 += d1;
200 s2 += d1;
202 /* skip '.' */
203 if (*s1) s1++;
204 if (*s2) s2++;
210 int cmpnumfld(num1, num2, fld)
211 char const *num1, *num2;
212 int fld;
213 /* Compare the two dotted numbers at field fld.
214 * num1 and num2 must have at least fld fields.
215 * fld must be positive.
218 register char const *s1, *s2;
219 register size_t d1, d2;
221 s1 = num1;
222 s2 = num2;
223 /* skip fld-1 fields */
224 while (--fld) {
225 while (*s1++ != '.')
226 continue;
227 while (*s2++ != '.')
228 continue;
230 /* Now s1 and s2 point to the beginning of the respective fields */
231 while (*s1=='0')
232 ++s1;
233 for (d1=0; isdigit(*(s1+d1)); d1++)
234 continue;
235 while (*s2=='0')
236 ++s2;
237 for (d2=0; isdigit(*(s2+d2)); d2++)
238 continue;
240 return d1<d2 ? -1 : d1==d2 ? memcmp(s1,s2,d1) : 1;
245 cmpdate(d1, d2)
246 char const *d1, *d2;
248 * Compare the two dates. This is just like cmpnum,
249 * except that for compatibility with old versions of RCS,
250 * 1900 is added to dates with two-digit years.
253 char year1[5], year2[5];
254 int r = cmpnumfld(normalizeyear(d1,year1), normalizeyear(d2,year2), 1);
256 if (r)
257 return r;
258 else {
259 while (isdigit(*d1))
260 d1++;
261 d1 += *d1=='.';
262 while (isdigit(*d2))
263 d2++;
264 d2 += *d2=='.';
265 return cmpnum(d1, d2);
269 static char const *
270 normalizeyear(date, year)
271 char const *date;
272 char year[5];
274 if (isdigit(date[0]) && isdigit(date[1]) && !isdigit(date[2])) {
275 year[0] = '1';
276 year[1] = '9';
277 year[2] = date[0];
278 year[3] = date[1];
279 year[4] = 0;
280 return year;
281 } else
282 return date;
286 static void
287 cantfindbranch(revno, date, author, state)
288 char const *revno, date[datesize], *author, *state;
290 char datebuf[datesize + zonelenmax];
292 rcserror("No revision on branch %s has%s%s%s%s%s%s.",
293 revno,
294 date ? " a date before " : "",
295 date ? date2str(date,datebuf) : "",
296 author ? " and author "+(date?0:4) : "",
297 author ? author : "",
298 state ? " and state "+(date||author?0:4) : "",
299 state ? state : ""
303 static void
304 absent(revno, field)
305 char const *revno;
306 int field;
308 struct buf t;
309 bufautobegin(&t);
310 rcserror("%s %s absent", field&1?"revision":"branch",
311 partialno(&t,revno,field)
313 bufautoend(&t);
318 compartial(num1, num2, length)
319 char const *num1, *num2;
320 int length;
322 /* compare the first "length" fields of two dot numbers;
323 the omitted field is considered to be larger than any number */
324 /* restriction: at least one number has length or more fields */
327 register char const *s1, *s2;
328 register size_t d1, d2;
329 register int r;
331 s1 = num1; s2 = num2;
332 if (!s1) return 1;
333 if (!s2) return -1;
335 for (;;) {
336 if (!*s1) return 1;
337 if (!*s2) return -1;
339 while (*s1=='0')
340 ++s1;
341 for (d1=0; isdigit(*(s1+d1)); d1++)
342 continue;
343 while (*s2=='0')
344 ++s2;
345 for (d2=0; isdigit(*(s2+d2)); d2++)
346 continue;
348 if (d1 != d2)
349 return d1<d2 ? -1 : 1;
350 if ((r = memcmp(s1, s2, d1)))
351 return r;
352 if (!--length)
353 return 0;
355 s1 += d1;
356 s2 += d1;
358 if (*s1 == '.') s1++;
359 if (*s2 == '.') s2++;
364 char * partialno(rev1,rev2,length)
365 struct buf *rev1;
366 char const *rev2;
367 register int length;
368 /* Function: Copies length fields of revision number rev2 into rev1.
369 * Return rev1's string.
372 register char *r1;
374 bufscpy(rev1, rev2);
375 r1 = rev1->string;
376 while (length) {
377 while (*r1!='.' && *r1)
378 ++r1;
379 ++r1;
380 length--;
382 /* eliminate last '.'*/
383 *(r1-1)='\0';
384 return rev1->string;
390 static void
391 store1(store, next)
392 struct hshentries ***store;
393 struct hshentry *next;
395 * Allocate a new list node that addresses NEXT.
396 * Append it to the list that **STORE is the end pointer of.
399 register struct hshentries *p;
401 p = ftalloc(struct hshentries);
402 p->first = next;
403 **store = p;
404 *store = &p->rest;
407 struct hshentry * genrevs(revno,date,author,state,store)
408 char const *revno, *date, *author, *state;
409 struct hshentries **store;
410 /* Function: finds the deltas needed for reconstructing the
411 * revision given by revno, date, author, and state, and stores pointers
412 * to these deltas into a list whose starting address is given by store.
413 * The last delta (target delta) is returned.
414 * If the proper delta could not be found, 0 is returned.
417 int length;
418 register struct hshentry * next;
419 int result;
420 char const *branchnum;
421 struct buf t;
422 char datebuf[datesize + zonelenmax];
424 bufautobegin(&t);
426 if (!(next = Head)) {
427 rcserror("RCS file empty");
428 goto norev;
431 length = countnumflds(revno);
433 if (length >= 1) {
434 /* at least one field; find branch exactly */
435 while ((result=cmpnumfld(revno,next->num,1)) < 0) {
436 store1(&store, next);
437 next = next->next;
438 if (!next) {
439 rcserror("branch number %s too low", partialno(&t,revno,1));
440 goto norev;
444 if (result>0) {
445 absent(revno, 1);
446 goto norev;
449 if (length<=1){
450 /* pick latest one on given branch */
451 branchnum = next->num; /* works even for empty revno*/
452 while (next &&
453 cmpnumfld(branchnum,next->num,1) == 0 &&
455 (date && cmpdate(date,next->date) < 0) ||
456 (author && strcmp(author,next->author) != 0) ||
457 (state && strcmp(state,next->state) != 0)
461 store1(&store, next);
462 next=next->next;
464 if (!next ||
465 (cmpnumfld(branchnum,next->num,1)!=0))/*overshot*/ {
466 cantfindbranch(
467 length ? revno : partialno(&t,branchnum,1),
468 date, author, state
470 goto norev;
471 } else {
472 store1(&store, next);
474 *store = 0;
475 return next;
478 /* length >=2 */
479 /* find revision; may go low if length==2*/
480 while ((result=cmpnumfld(revno,next->num,2)) < 0 &&
481 (cmpnumfld(revno,next->num,1)==0) ) {
482 store1(&store, next);
483 next = next->next;
484 if (!next)
485 break;
488 if (!next || cmpnumfld(revno,next->num,1) != 0) {
489 rcserror("revision number %s too low", partialno(&t,revno,2));
490 goto norev;
492 if ((length>2) && (result!=0)) {
493 absent(revno, 2);
494 goto norev;
497 /* print last one */
498 store1(&store, next);
500 if (length>2)
501 return genbranch(next,revno,length,date,author,state,store);
502 else { /* length == 2*/
503 if (date && cmpdate(date,next->date)<0) {
504 rcserror("Revision %s has date %s.",
505 next->num,
506 date2str(next->date, datebuf)
508 return 0;
510 if (author && strcmp(author,next->author)!=0) {
511 rcserror("Revision %s has author %s.",
512 next->num, next->author
514 return 0;
516 if (state && strcmp(state,next->state)!=0) {
517 rcserror("Revision %s has state %s.",
518 next->num,
519 next->state ? next->state : "<empty>"
521 return 0;
523 *store = 0;
524 return next;
527 norev:
528 bufautoend(&t);
529 return 0;
535 static struct hshentry *
536 genbranch(bpoint, revno, length, date, author, state, store)
537 struct hshentry const *bpoint;
538 char const *revno;
539 int length;
540 char const *date, *author, *state;
541 struct hshentries **store;
542 /* Function: given a branchpoint, a revision number, date, author, and state,
543 * genbranch finds the deltas necessary to reconstruct the given revision
544 * from the branch point on.
545 * Pointers to the found deltas are stored in a list beginning with store.
546 * revno must be on a side branch.
547 * Return 0 on error.
550 int field;
551 register struct hshentry * next, * trail;
552 register struct branchhead const *bhead;
553 int result;
554 struct buf t;
555 char datebuf[datesize + zonelenmax];
557 field = 3;
558 bhead = bpoint->branches;
560 do {
561 if (!bhead) {
562 bufautobegin(&t);
563 rcserror("no side branches present for %s",
564 partialno(&t,revno,field-1)
566 bufautoend(&t);
567 return 0;
570 /*find branch head*/
571 /*branches are arranged in increasing order*/
572 while (0 < (result=cmpnumfld(revno,bhead->hsh->num,field))) {
573 bhead = bhead->nextbranch;
574 if (!bhead) {
575 bufautobegin(&t);
576 rcserror("branch number %s too high",
577 partialno(&t,revno,field)
579 bufautoend(&t);
580 return 0;
584 if (result<0) {
585 absent(revno, field);
586 return 0;
589 next = bhead->hsh;
590 if (length==field) {
591 /* pick latest one on that branch */
592 trail = 0;
593 do { if ((!date || cmpdate(date,next->date)>=0) &&
594 (!author || strcmp(author,next->author)==0) &&
595 (!state || strcmp(state,next->state)==0)
596 ) trail = next;
597 next=next->next;
598 } while (next);
600 if (!trail) {
601 cantfindbranch(revno, date, author, state);
602 return 0;
603 } else { /* print up to last one suitable */
604 next = bhead->hsh;
605 while (next!=trail) {
606 store1(&store, next);
607 next=next->next;
609 store1(&store, next);
611 *store = 0;
612 return next;
615 /* length > field */
616 /* find revision */
617 /* check low */
618 if (cmpnumfld(revno,next->num,field+1)<0) {
619 bufautobegin(&t);
620 rcserror("revision number %s too low",
621 partialno(&t,revno,field+1)
623 bufautoend(&t);
624 return 0;
626 do {
627 store1(&store, next);
628 trail = next;
629 next = next->next;
630 } while (next && cmpnumfld(revno,next->num,field+1)>=0);
632 if ((length>field+1) && /*need exact hit */
633 (cmpnumfld(revno,trail->num,field+1) !=0)){
634 absent(revno, field+1);
635 return 0;
637 if (length == field+1) {
638 if (date && cmpdate(date,trail->date)<0) {
639 rcserror("Revision %s has date %s.",
640 trail->num,
641 date2str(trail->date, datebuf)
643 return 0;
645 if (author && strcmp(author,trail->author)!=0) {
646 rcserror("Revision %s has author %s.",
647 trail->num, trail->author
649 return 0;
651 if (state && strcmp(state,trail->state)!=0) {
652 rcserror("Revision %s has state %s.",
653 trail->num,
654 trail->state ? trail->state : "<empty>"
656 return 0;
659 bhead = trail->branches;
661 } while ((field+=2) <= length);
662 *store = 0;
663 return trail;
667 static char const *
668 lookupsym(id)
669 char const *id;
670 /* Function: looks up id in the list of symbolic names starting
671 * with pointer SYMBOLS, and returns a pointer to the corresponding
672 * revision number. Return 0 if not present.
675 register struct assoc const *next;
676 for (next = Symbols; next; next = next->nextassoc)
677 if (strcmp(id, next->symbol)==0)
678 return next->num;
679 return 0;
682 int expandsym(source, target)
683 char const *source;
684 struct buf *target;
685 /* Function: Source points to a revision number. Expandsym copies
686 * the number to target, but replaces all symbolic fields in the
687 * source number with their numeric values.
688 * Expand a branch followed by `.' to the latest revision on that branch.
689 * Ignore `.' after a revision. Remove leading zeros.
690 * returns false on error;
693 return fexpandsym(source, target, (RILE*)0);
697 fexpandsym(source, target, fp)
698 char const *source;
699 struct buf *target;
700 RILE *fp;
701 /* Same as expandsym, except if FP is nonzero, it is used to expand KDELIM. */
703 register char const *sp, *bp;
704 register char *tp;
705 char const *tlim;
706 int dots;
708 sp = source;
709 bufalloc(target, 1);
710 tp = target->string;
711 if (!sp || !*sp) { /* Accept 0 pointer as a legal value. */
712 *tp='\0';
713 return true;
715 if (sp[0] == KDELIM && !sp[1]) {
716 if (!getoldkeys(fp))
717 return false;
718 if (!*prevrev.string) {
719 workerror("working file lacks revision number");
720 return false;
722 bufscpy(target, prevrev.string);
723 return true;
725 tlim = tp + target->size;
726 dots = 0;
728 for (;;) {
729 register char *p = tp;
730 size_t s = tp - target->string;
731 int id = false;
732 for (;;) {
733 switch (ctab[(unsigned char)*sp]) {
734 case IDCHAR:
735 case LETTER:
736 case Letter:
737 id = true;
738 /* fall into */
739 case DIGIT:
740 if (tlim <= p)
741 p = bufenlarge(target, &tlim);
742 *p++ = *sp++;
743 continue;
745 default:
746 break;
748 break;
750 if (tlim <= p)
751 p = bufenlarge(target, &tlim);
752 *p = 0;
753 tp = target->string + s;
755 if (id) {
756 bp = lookupsym(tp);
757 if (!bp) {
758 rcserror("Symbolic name `%s' is undefined.",tp);
759 return false;
761 } else {
762 /* skip leading zeros */
763 for (bp = tp; *bp=='0' && isdigit(bp[1]); bp++)
764 continue;
766 if (!*bp) {
767 if (s || *sp!='.')
768 break;
769 else {
770 /* Insert default branch before initial `.'. */
771 char const *b;
772 if (Dbranch)
773 b = Dbranch;
774 else if (Head)
775 b = Head->num;
776 else
777 break;
778 getbranchno(b, target);
779 bp = tp = target->string;
780 tlim = tp + target->size;
785 while ((*tp++ = *bp++))
786 if (tlim <= tp)
787 tp = bufenlarge(target, &tlim);
789 switch (*sp++) {
790 case '\0':
791 return true;
793 case '.':
794 if (!*sp) {
795 if (dots & 1)
796 break;
797 if (!(bp = branchtip(target->string)))
798 return false;
799 bufscpy(target, bp);
800 return true;
802 ++dots;
803 tp[-1] = '.';
804 continue;
806 break;
809 rcserror("improper revision number: %s", source);
810 return false;
813 char const *
814 namedrev(name, delta)
815 char const *name;
816 struct hshentry *delta;
817 /* Yield NAME if it names DELTA, 0 otherwise. */
819 if (name) {
820 char const *id = 0, *p, *val;
821 for (p = name; ; p++)
822 switch (ctab[(unsigned char)*p]) {
823 case IDCHAR:
824 case LETTER:
825 case Letter:
826 id = name;
827 break;
829 case DIGIT:
830 break;
832 case UNKN:
833 if (!*p && id &&
834 (val = lookupsym(id)) &&
835 strcmp(val, delta->num) == 0
837 return id;
838 /* fall into */
839 default:
840 return 0;
843 return 0;
846 static char const *
847 branchtip(branch)
848 char const *branch;
850 struct hshentry *h;
851 struct hshentries *hs;
853 h = genrevs(branch, (char*)0, (char*)0, (char*)0, &hs);
854 return h ? h->num : (char const*)0;
857 char const *
858 tiprev()
860 return Dbranch ? branchtip(Dbranch) : Head ? Head->num : (char const*)0;
865 #ifdef REVTEST
868 * Test the routines that generate a sequence of delta numbers
869 * needed to regenerate a given delta.
872 char const cmdid[] = "revtest";
875 main(argc,argv)
876 int argc; char * argv[];
878 static struct buf numricrevno;
879 char symrevno[100]; /* used for input of revision numbers */
880 char author[20];
881 char state[20];
882 char date[20];
883 struct hshentries *gendeltas;
884 struct hshentry * target;
885 int i;
887 if (argc<2) {
888 aputs("No input file\n",stderr);
889 exitmain(EXIT_FAILURE);
891 if (!(finptr=Iopen(argv[1], FOPEN_R, (struct stat*)0))) {
892 faterror("can't open input file %s", argv[1]);
894 Lexinit();
895 getadmin();
897 gettree();
899 getdesc(false);
901 do {
902 /* all output goes to stderr, to have diagnostics and */
903 /* errors in sequence. */
904 aputs("\nEnter revision number or <return> or '.': ",stderr);
905 if (!fgets(symrevno, 100, stdin)) break;
906 if (*symrevno == '.') break;
907 aprintf(stderr,"%s;\n",symrevno);
908 expandsym(symrevno,&numricrevno);
909 aprintf(stderr,"expanded number: %s; ",numricrevno.string);
910 aprintf(stderr,"Date: ");
911 fgets(date, 20, stdin); aprintf(stderr,"%s; ",date);
912 aprintf(stderr,"Author: ");
913 fgets(author, 20, stdin); aprintf(stderr,"%s; ",author);
914 aprintf(stderr,"State: ");
915 fgets(state, 20, stdin); aprintf(stderr, "%s;\n", state);
916 target = genrevs(numricrevno.string, *date?date:(char *)0, *author?author:(char *)0,
917 *state?state:(char*)0, &gendeltas);
918 if (target) {
919 while (gendeltas) {
920 aprintf(stderr,"%s\n",gendeltas->first->num);
921 gendeltas = gendeltas->next;
924 } while (true);
925 aprintf(stderr,"done\n");
926 exitmain(EXIT_SUCCESS);
929 void exiterr() { _exit(EXIT_FAILURE); }
931 #endif