1*86d7f5d3SJohn Marino /* RCS file syntactic analysis */
2*86d7f5d3SJohn Marino
3*86d7f5d3SJohn Marino /******************************************************************************
4*86d7f5d3SJohn Marino * Syntax Analysis.
5*86d7f5d3SJohn Marino * Keyword table
6*86d7f5d3SJohn Marino * Testprogram: define SYNTEST
7*86d7f5d3SJohn Marino * Compatibility with Release 2: define COMPAT2=1
8*86d7f5d3SJohn Marino ******************************************************************************
9*86d7f5d3SJohn Marino */
10*86d7f5d3SJohn Marino
11*86d7f5d3SJohn Marino /* Copyright 1982, 1988, 1989 Walter Tichy
12*86d7f5d3SJohn Marino Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
13*86d7f5d3SJohn Marino Distributed under license by the Free Software Foundation, Inc.
14*86d7f5d3SJohn Marino
15*86d7f5d3SJohn Marino This file is part of RCS.
16*86d7f5d3SJohn Marino
17*86d7f5d3SJohn Marino RCS is free software; you can redistribute it and/or modify
18*86d7f5d3SJohn Marino it under the terms of the GNU General Public License as published by
19*86d7f5d3SJohn Marino the Free Software Foundation; either version 2, or (at your option)
20*86d7f5d3SJohn Marino any later version.
21*86d7f5d3SJohn Marino
22*86d7f5d3SJohn Marino RCS is distributed in the hope that it will be useful,
23*86d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
24*86d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25*86d7f5d3SJohn Marino GNU General Public License for more details.
26*86d7f5d3SJohn Marino
27*86d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
28*86d7f5d3SJohn Marino along with RCS; see the file COPYING.
29*86d7f5d3SJohn Marino If not, write to the Free Software Foundation,
30*86d7f5d3SJohn Marino 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31*86d7f5d3SJohn Marino
32*86d7f5d3SJohn Marino Report problems and direct all questions to:
33*86d7f5d3SJohn Marino
34*86d7f5d3SJohn Marino rcs-bugs@cs.purdue.edu
35*86d7f5d3SJohn Marino
36*86d7f5d3SJohn Marino */
37*86d7f5d3SJohn Marino
38*86d7f5d3SJohn Marino /*
39*86d7f5d3SJohn Marino * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcssyn.c,v 1.7 1999/08/27 23:36:48 peter Exp $
40*86d7f5d3SJohn Marino * $DragonFly: src/gnu/usr.bin/rcs/lib/rcssyn.c,v 1.4 2007/01/21 17:58:42 pavalos Exp $
41*86d7f5d3SJohn Marino *
42*86d7f5d3SJohn Marino * Revision 5.15 1995/06/16 06:19:24 eggert
43*86d7f5d3SJohn Marino * Update FSF address.
44*86d7f5d3SJohn Marino *
45*86d7f5d3SJohn Marino * Revision 5.14 1995/06/01 16:23:43 eggert
46*86d7f5d3SJohn Marino * (expand_names): Add "b" for -kb.
47*86d7f5d3SJohn Marino * (getdelta): Don't strip leading "19" from MKS RCS dates; see cmpdate.
48*86d7f5d3SJohn Marino *
49*86d7f5d3SJohn Marino * Revision 5.13 1994/03/20 04:52:58 eggert
50*86d7f5d3SJohn Marino * Remove lint.
51*86d7f5d3SJohn Marino *
52*86d7f5d3SJohn Marino * Revision 5.12 1993/11/03 17:42:27 eggert
53*86d7f5d3SJohn Marino * Parse MKS RCS dates; ignore \r in diff control lines.
54*86d7f5d3SJohn Marino * Don't discard ignored phrases. Improve quality of diagnostics.
55*86d7f5d3SJohn Marino *
56*86d7f5d3SJohn Marino * Revision 5.11 1992/07/28 16:12:44 eggert
57*86d7f5d3SJohn Marino * Avoid `unsigned'. Statement macro names now end in _.
58*86d7f5d3SJohn Marino *
59*86d7f5d3SJohn Marino * Revision 5.10 1992/01/24 18:44:19 eggert
60*86d7f5d3SJohn Marino * Move put routines to rcsgen.c.
61*86d7f5d3SJohn Marino *
62*86d7f5d3SJohn Marino * Revision 5.9 1992/01/06 02:42:34 eggert
63*86d7f5d3SJohn Marino * ULONG_MAX/10 -> ULONG_MAX_OVER_10
64*86d7f5d3SJohn Marino * while (E) ; -> while (E) continue;
65*86d7f5d3SJohn Marino *
66*86d7f5d3SJohn Marino * Revision 5.8 1991/08/19 03:13:55 eggert
67*86d7f5d3SJohn Marino * Tune.
68*86d7f5d3SJohn Marino *
69*86d7f5d3SJohn Marino * Revision 5.7 1991/04/21 11:58:29 eggert
70*86d7f5d3SJohn Marino * Disambiguate names on shortname hosts.
71*86d7f5d3SJohn Marino * Fix errno bug. Add MS-DOS support.
72*86d7f5d3SJohn Marino *
73*86d7f5d3SJohn Marino * Revision 5.6 1991/02/28 19:18:51 eggert
74*86d7f5d3SJohn Marino * Fix null termination bug in reporting keyword expansion.
75*86d7f5d3SJohn Marino *
76*86d7f5d3SJohn Marino * Revision 5.5 1991/02/25 07:12:44 eggert
77*86d7f5d3SJohn Marino * Check diff output more carefully; avoid overflow.
78*86d7f5d3SJohn Marino *
79*86d7f5d3SJohn Marino * Revision 5.4 1990/11/01 05:28:48 eggert
80*86d7f5d3SJohn Marino * When ignoring unknown phrases, copy them to the output RCS file.
81*86d7f5d3SJohn Marino * Permit arbitrary data in logs and comment leaders.
82*86d7f5d3SJohn Marino * Don't check for nontext on initial checkin.
83*86d7f5d3SJohn Marino *
84*86d7f5d3SJohn Marino * Revision 5.3 1990/09/20 07:58:32 eggert
85*86d7f5d3SJohn Marino * Remove the test for non-text bytes; it caused more pain than it cured.
86*86d7f5d3SJohn Marino *
87*86d7f5d3SJohn Marino * Revision 5.2 1990/09/04 08:02:30 eggert
88*86d7f5d3SJohn Marino * Parse RCS files with no revisions.
89*86d7f5d3SJohn Marino * Don't strip leading white space from diff commands. Count RCS lines better.
90*86d7f5d3SJohn Marino *
91*86d7f5d3SJohn Marino * Revision 5.1 1990/08/29 07:14:06 eggert
92*86d7f5d3SJohn Marino * Add -kkvl. Clean old log messages too.
93*86d7f5d3SJohn Marino *
94*86d7f5d3SJohn Marino * Revision 5.0 1990/08/22 08:13:44 eggert
95*86d7f5d3SJohn Marino * Try to parse future RCS formats without barfing.
96*86d7f5d3SJohn Marino * Add -k. Don't require final newline.
97*86d7f5d3SJohn Marino * Remove compile-time limits; use malloc instead.
98*86d7f5d3SJohn Marino * Don't output branch keyword if there's no default branch,
99*86d7f5d3SJohn Marino * because RCS version 3 doesn't understand it.
100*86d7f5d3SJohn Marino * Tune. Remove lint.
101*86d7f5d3SJohn Marino * Add support for ISO 8859. Ansify and Posixate.
102*86d7f5d3SJohn Marino * Check that a newly checked-in file is acceptable as input to 'diff'.
103*86d7f5d3SJohn Marino * Check diff's output.
104*86d7f5d3SJohn Marino *
105*86d7f5d3SJohn Marino * Revision 4.6 89/05/01 15:13:32 narten
106*86d7f5d3SJohn Marino * changed copyright header to reflect current distribution rules
107*86d7f5d3SJohn Marino *
108*86d7f5d3SJohn Marino * Revision 4.5 88/08/09 19:13:21 eggert
109*86d7f5d3SJohn Marino * Allow cc -R; remove lint.
110*86d7f5d3SJohn Marino *
111*86d7f5d3SJohn Marino * Revision 4.4 87/12/18 11:46:16 narten
112*86d7f5d3SJohn Marino * more lint cleanups (Guy Harris)
113*86d7f5d3SJohn Marino *
114*86d7f5d3SJohn Marino * Revision 4.3 87/10/18 10:39:36 narten
115*86d7f5d3SJohn Marino * Updating version numbers. Changes relative to 1.1 actually relative to
116*86d7f5d3SJohn Marino * 4.1
117*86d7f5d3SJohn Marino *
118*86d7f5d3SJohn Marino * Revision 1.3 87/09/24 14:00:49 narten
119*86d7f5d3SJohn Marino * Sources now pass through lint (if you ignore printf/sprintf/fprintf
120*86d7f5d3SJohn Marino * warnings)
121*86d7f5d3SJohn Marino *
122*86d7f5d3SJohn Marino * Revision 1.2 87/03/27 14:22:40 jenkins
123*86d7f5d3SJohn Marino * Port to suns
124*86d7f5d3SJohn Marino *
125*86d7f5d3SJohn Marino * Revision 4.1 83/03/28 11:38:49 wft
126*86d7f5d3SJohn Marino * Added parsing and printing of default branch.
127*86d7f5d3SJohn Marino *
128*86d7f5d3SJohn Marino * Revision 3.6 83/01/15 17:46:50 wft
129*86d7f5d3SJohn Marino * Changed readdelta() to initialize selector and log-pointer.
130*86d7f5d3SJohn Marino * Changed puttree to check for selector==DELETE; putdtext() uses DELNUMFORM.
131*86d7f5d3SJohn Marino *
132*86d7f5d3SJohn Marino * Revision 3.5 82/12/08 21:58:58 wft
133*86d7f5d3SJohn Marino * renamed Commentleader to Commleader.
134*86d7f5d3SJohn Marino *
135*86d7f5d3SJohn Marino * Revision 3.4 82/12/04 13:24:40 wft
136*86d7f5d3SJohn Marino * Added routine gettree(), which updates keeplock after reading the
137*86d7f5d3SJohn Marino * delta tree.
138*86d7f5d3SJohn Marino *
139*86d7f5d3SJohn Marino * Revision 3.3 82/11/28 21:30:11 wft
140*86d7f5d3SJohn Marino * Reading and printing of Suffix removed; version COMPAT2 skips the
141*86d7f5d3SJohn Marino * Suffix for files of release 2 format. Fixed problems with printing nil.
142*86d7f5d3SJohn Marino *
143*86d7f5d3SJohn Marino * Revision 3.2 82/10/18 21:18:25 wft
144*86d7f5d3SJohn Marino * renamed putdeltatext to putdtext.
145*86d7f5d3SJohn Marino *
146*86d7f5d3SJohn Marino * Revision 3.1 82/10/11 19:45:11 wft
147*86d7f5d3SJohn Marino * made sure getc() returns into an integer.
148*86d7f5d3SJohn Marino */
149*86d7f5d3SJohn Marino
150*86d7f5d3SJohn Marino
151*86d7f5d3SJohn Marino
152*86d7f5d3SJohn Marino /* version COMPAT2 reads files of the format of release 2 and 3, but
153*86d7f5d3SJohn Marino * generates files of release 3 format. Need not be defined if no
154*86d7f5d3SJohn Marino * old RCS files generated with release 2 exist.
155*86d7f5d3SJohn Marino */
156*86d7f5d3SJohn Marino
157*86d7f5d3SJohn Marino #include "rcsbase.h"
158*86d7f5d3SJohn Marino
159*86d7f5d3SJohn Marino libId(synId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcssyn.c,v 1.4 2007/01/21 17:58:42 pavalos Exp $")
160*86d7f5d3SJohn Marino
161*86d7f5d3SJohn Marino static char const *getkeyval P((char const*,enum tokens,int));
162*86d7f5d3SJohn Marino static int getdelta P((void));
163*86d7f5d3SJohn Marino static int strn2expmode P((char const*,size_t));
164*86d7f5d3SJohn Marino static struct hshentry *getdnum P((void));
165*86d7f5d3SJohn Marino static void badDiffOutput P((char const*)) exiting;
166*86d7f5d3SJohn Marino static void diffLineNumberTooLarge P((char const*)) exiting;
167*86d7f5d3SJohn Marino static void getsemi P((char const*));
168*86d7f5d3SJohn Marino
169*86d7f5d3SJohn Marino /* keyword table */
170*86d7f5d3SJohn Marino
171*86d7f5d3SJohn Marino char const
172*86d7f5d3SJohn Marino Kaccess[] = "access",
173*86d7f5d3SJohn Marino Kauthor[] = "author",
174*86d7f5d3SJohn Marino Kbranch[] = "branch",
175*86d7f5d3SJohn Marino Kcomment[] = "comment",
176*86d7f5d3SJohn Marino Kcommitid[] = "commitid",
177*86d7f5d3SJohn Marino Kdate[] = "date",
178*86d7f5d3SJohn Marino Kdesc[] = "desc",
179*86d7f5d3SJohn Marino Kexpand[] = "expand",
180*86d7f5d3SJohn Marino Khead[] = "head",
181*86d7f5d3SJohn Marino Klocks[] = "locks",
182*86d7f5d3SJohn Marino Klog[] = "log",
183*86d7f5d3SJohn Marino Knext[] = "next",
184*86d7f5d3SJohn Marino Kstate[] = "state",
185*86d7f5d3SJohn Marino Kstrict[] = "strict",
186*86d7f5d3SJohn Marino Ksymbols[] = "symbols",
187*86d7f5d3SJohn Marino Ktext[] = "text";
188*86d7f5d3SJohn Marino
189*86d7f5d3SJohn Marino static char const
190*86d7f5d3SJohn Marino #if COMPAT2
191*86d7f5d3SJohn Marino Ksuffix[] = "suffix",
192*86d7f5d3SJohn Marino #endif
193*86d7f5d3SJohn Marino K_branches[]= "branches";
194*86d7f5d3SJohn Marino
195*86d7f5d3SJohn Marino static struct buf Commleader;
196*86d7f5d3SJohn Marino struct cbuf Comment;
197*86d7f5d3SJohn Marino struct cbuf Ignored;
198*86d7f5d3SJohn Marino struct access * AccessList;
199*86d7f5d3SJohn Marino struct assoc * Symbols;
200*86d7f5d3SJohn Marino struct rcslock *Locks;
201*86d7f5d3SJohn Marino int Expand;
202*86d7f5d3SJohn Marino int StrictLocks;
203*86d7f5d3SJohn Marino struct hshentry * Head;
204*86d7f5d3SJohn Marino char const * Dbranch;
205*86d7f5d3SJohn Marino int TotalDeltas;
206*86d7f5d3SJohn Marino
207*86d7f5d3SJohn Marino
208*86d7f5d3SJohn Marino static void
getsemi(key)209*86d7f5d3SJohn Marino getsemi(key)
210*86d7f5d3SJohn Marino char const *key;
211*86d7f5d3SJohn Marino /* Get a semicolon to finish off a phrase started by KEY. */
212*86d7f5d3SJohn Marino {
213*86d7f5d3SJohn Marino if (!getlex(SEMI))
214*86d7f5d3SJohn Marino fatserror("missing ';' after '%s'", key);
215*86d7f5d3SJohn Marino }
216*86d7f5d3SJohn Marino
217*86d7f5d3SJohn Marino static struct hshentry *
getdnum()218*86d7f5d3SJohn Marino getdnum()
219*86d7f5d3SJohn Marino /* Get a delta number. */
220*86d7f5d3SJohn Marino {
221*86d7f5d3SJohn Marino register struct hshentry *delta = getnum();
222*86d7f5d3SJohn Marino if (delta && countnumflds(delta->num)&1)
223*86d7f5d3SJohn Marino fatserror("%s isn't a delta number", delta->num);
224*86d7f5d3SJohn Marino return delta;
225*86d7f5d3SJohn Marino }
226*86d7f5d3SJohn Marino
227*86d7f5d3SJohn Marino
228*86d7f5d3SJohn Marino void
getadmin()229*86d7f5d3SJohn Marino getadmin()
230*86d7f5d3SJohn Marino /* Read an <admin> and initialize the appropriate global variables. */
231*86d7f5d3SJohn Marino {
232*86d7f5d3SJohn Marino register char const *id;
233*86d7f5d3SJohn Marino struct access * newaccess;
234*86d7f5d3SJohn Marino struct assoc * newassoc;
235*86d7f5d3SJohn Marino struct rcslock *newlock;
236*86d7f5d3SJohn Marino struct hshentry * delta;
237*86d7f5d3SJohn Marino struct access **LastAccess;
238*86d7f5d3SJohn Marino struct assoc **LastSymbol;
239*86d7f5d3SJohn Marino struct rcslock **LastLock;
240*86d7f5d3SJohn Marino struct buf b;
241*86d7f5d3SJohn Marino struct cbuf cb;
242*86d7f5d3SJohn Marino
243*86d7f5d3SJohn Marino TotalDeltas=0;
244*86d7f5d3SJohn Marino
245*86d7f5d3SJohn Marino getkey(Khead);
246*86d7f5d3SJohn Marino Head = getdnum();
247*86d7f5d3SJohn Marino getsemi(Khead);
248*86d7f5d3SJohn Marino
249*86d7f5d3SJohn Marino Dbranch = 0;
250*86d7f5d3SJohn Marino if (getkeyopt(Kbranch)) {
251*86d7f5d3SJohn Marino if ((delta = getnum()))
252*86d7f5d3SJohn Marino Dbranch = delta->num;
253*86d7f5d3SJohn Marino getsemi(Kbranch);
254*86d7f5d3SJohn Marino }
255*86d7f5d3SJohn Marino
256*86d7f5d3SJohn Marino
257*86d7f5d3SJohn Marino #if COMPAT2
258*86d7f5d3SJohn Marino /* read suffix. Only in release 2 format */
259*86d7f5d3SJohn Marino if (getkeyopt(Ksuffix)) {
260*86d7f5d3SJohn Marino if (nexttok==STRING) {
261*86d7f5d3SJohn Marino readstring(); nextlex(); /* Throw away the suffix. */
262*86d7f5d3SJohn Marino } else if (nexttok==ID) {
263*86d7f5d3SJohn Marino nextlex();
264*86d7f5d3SJohn Marino }
265*86d7f5d3SJohn Marino getsemi(Ksuffix);
266*86d7f5d3SJohn Marino }
267*86d7f5d3SJohn Marino #endif
268*86d7f5d3SJohn Marino
269*86d7f5d3SJohn Marino getkey(Kaccess);
270*86d7f5d3SJohn Marino LastAccess = &AccessList;
271*86d7f5d3SJohn Marino while ((id = getid())) {
272*86d7f5d3SJohn Marino newaccess = ftalloc(struct access);
273*86d7f5d3SJohn Marino newaccess->login = id;
274*86d7f5d3SJohn Marino *LastAccess = newaccess;
275*86d7f5d3SJohn Marino LastAccess = &newaccess->nextaccess;
276*86d7f5d3SJohn Marino }
277*86d7f5d3SJohn Marino *LastAccess = 0;
278*86d7f5d3SJohn Marino getsemi(Kaccess);
279*86d7f5d3SJohn Marino
280*86d7f5d3SJohn Marino getkey(Ksymbols);
281*86d7f5d3SJohn Marino LastSymbol = &Symbols;
282*86d7f5d3SJohn Marino while ((id = getid())) {
283*86d7f5d3SJohn Marino if (!getlex(COLON))
284*86d7f5d3SJohn Marino fatserror("missing ':' in symbolic name definition");
285*86d7f5d3SJohn Marino if (!(delta=getnum())) {
286*86d7f5d3SJohn Marino fatserror("missing number in symbolic name definition");
287*86d7f5d3SJohn Marino } else { /*add new pair to association list*/
288*86d7f5d3SJohn Marino newassoc = ftalloc(struct assoc);
289*86d7f5d3SJohn Marino newassoc->symbol=id;
290*86d7f5d3SJohn Marino newassoc->num = delta->num;
291*86d7f5d3SJohn Marino *LastSymbol = newassoc;
292*86d7f5d3SJohn Marino LastSymbol = &newassoc->nextassoc;
293*86d7f5d3SJohn Marino }
294*86d7f5d3SJohn Marino }
295*86d7f5d3SJohn Marino *LastSymbol = 0;
296*86d7f5d3SJohn Marino getsemi(Ksymbols);
297*86d7f5d3SJohn Marino
298*86d7f5d3SJohn Marino getkey(Klocks);
299*86d7f5d3SJohn Marino LastLock = &Locks;
300*86d7f5d3SJohn Marino while ((id = getid())) {
301*86d7f5d3SJohn Marino if (!getlex(COLON))
302*86d7f5d3SJohn Marino fatserror("missing ':' in lock");
303*86d7f5d3SJohn Marino if (!(delta=getdnum())) {
304*86d7f5d3SJohn Marino fatserror("missing number in lock");
305*86d7f5d3SJohn Marino } else { /*add new pair to lock list*/
306*86d7f5d3SJohn Marino newlock = ftalloc(struct rcslock);
307*86d7f5d3SJohn Marino newlock->login=id;
308*86d7f5d3SJohn Marino newlock->delta=delta;
309*86d7f5d3SJohn Marino *LastLock = newlock;
310*86d7f5d3SJohn Marino LastLock = &newlock->nextlock;
311*86d7f5d3SJohn Marino }
312*86d7f5d3SJohn Marino }
313*86d7f5d3SJohn Marino *LastLock = 0;
314*86d7f5d3SJohn Marino getsemi(Klocks);
315*86d7f5d3SJohn Marino
316*86d7f5d3SJohn Marino if ((StrictLocks = getkeyopt(Kstrict)))
317*86d7f5d3SJohn Marino getsemi(Kstrict);
318*86d7f5d3SJohn Marino
319*86d7f5d3SJohn Marino clear_buf(&Comment);
320*86d7f5d3SJohn Marino if (getkeyopt(Kcomment)) {
321*86d7f5d3SJohn Marino if (nexttok==STRING) {
322*86d7f5d3SJohn Marino Comment = savestring(&Commleader);
323*86d7f5d3SJohn Marino nextlex();
324*86d7f5d3SJohn Marino }
325*86d7f5d3SJohn Marino getsemi(Kcomment);
326*86d7f5d3SJohn Marino }
327*86d7f5d3SJohn Marino
328*86d7f5d3SJohn Marino Expand = KEYVAL_EXPAND;
329*86d7f5d3SJohn Marino if (getkeyopt(Kexpand)) {
330*86d7f5d3SJohn Marino if (nexttok==STRING) {
331*86d7f5d3SJohn Marino bufautobegin(&b);
332*86d7f5d3SJohn Marino cb = savestring(&b);
333*86d7f5d3SJohn Marino if ((Expand = strn2expmode(cb.string,cb.size)) < 0)
334*86d7f5d3SJohn Marino fatserror("unknown expand mode %.*s",
335*86d7f5d3SJohn Marino (int)cb.size, cb.string
336*86d7f5d3SJohn Marino );
337*86d7f5d3SJohn Marino bufautoend(&b);
338*86d7f5d3SJohn Marino nextlex();
339*86d7f5d3SJohn Marino }
340*86d7f5d3SJohn Marino getsemi(Kexpand);
341*86d7f5d3SJohn Marino }
342*86d7f5d3SJohn Marino Ignored = getphrases(Kdesc);
343*86d7f5d3SJohn Marino }
344*86d7f5d3SJohn Marino
345*86d7f5d3SJohn Marino char const *const expand_names[] = {
346*86d7f5d3SJohn Marino /* These must agree with *_EXPAND in rcsbase.h. */
347*86d7f5d3SJohn Marino "kv", "kvl", "k", "v", "o", "b",
348*86d7f5d3SJohn Marino 0
349*86d7f5d3SJohn Marino };
350*86d7f5d3SJohn Marino
351*86d7f5d3SJohn Marino int
str2expmode(s)352*86d7f5d3SJohn Marino str2expmode(s)
353*86d7f5d3SJohn Marino char const *s;
354*86d7f5d3SJohn Marino /* Yield expand mode corresponding to S, or -1 if bad. */
355*86d7f5d3SJohn Marino {
356*86d7f5d3SJohn Marino return strn2expmode(s, strlen(s));
357*86d7f5d3SJohn Marino }
358*86d7f5d3SJohn Marino
359*86d7f5d3SJohn Marino static int
strn2expmode(s,n)360*86d7f5d3SJohn Marino strn2expmode(s, n)
361*86d7f5d3SJohn Marino char const *s;
362*86d7f5d3SJohn Marino size_t n;
363*86d7f5d3SJohn Marino {
364*86d7f5d3SJohn Marino char const *const *p;
365*86d7f5d3SJohn Marino
366*86d7f5d3SJohn Marino for (p = expand_names; *p; ++p)
367*86d7f5d3SJohn Marino if (memcmp(*p,s,n) == 0 && !(*p)[n])
368*86d7f5d3SJohn Marino return p - expand_names;
369*86d7f5d3SJohn Marino return -1;
370*86d7f5d3SJohn Marino }
371*86d7f5d3SJohn Marino
372*86d7f5d3SJohn Marino
373*86d7f5d3SJohn Marino void
ignorephrases(key)374*86d7f5d3SJohn Marino ignorephrases(key)
375*86d7f5d3SJohn Marino const char *key;
376*86d7f5d3SJohn Marino /*
377*86d7f5d3SJohn Marino * Ignore a series of phrases that do not start with KEY.
378*86d7f5d3SJohn Marino * Stop when the next phrase starts with a token that is not an identifier,
379*86d7f5d3SJohn Marino * or is KEY.
380*86d7f5d3SJohn Marino */
381*86d7f5d3SJohn Marino {
382*86d7f5d3SJohn Marino for (;;) {
383*86d7f5d3SJohn Marino nextlex();
384*86d7f5d3SJohn Marino if (nexttok != ID || strcmp(NextString,key) == 0)
385*86d7f5d3SJohn Marino break;
386*86d7f5d3SJohn Marino warnignore();
387*86d7f5d3SJohn Marino hshenter=false;
388*86d7f5d3SJohn Marino for (;; nextlex()) {
389*86d7f5d3SJohn Marino switch (nexttok) {
390*86d7f5d3SJohn Marino case SEMI: hshenter=true; break;
391*86d7f5d3SJohn Marino case ID:
392*86d7f5d3SJohn Marino case NUM: ffree1(NextString); continue;
393*86d7f5d3SJohn Marino case STRING: readstring(); continue;
394*86d7f5d3SJohn Marino default: continue;
395*86d7f5d3SJohn Marino }
396*86d7f5d3SJohn Marino break;
397*86d7f5d3SJohn Marino }
398*86d7f5d3SJohn Marino }
399*86d7f5d3SJohn Marino }
400*86d7f5d3SJohn Marino
401*86d7f5d3SJohn Marino
402*86d7f5d3SJohn Marino static int
getdelta()403*86d7f5d3SJohn Marino getdelta()
404*86d7f5d3SJohn Marino /* Function: reads a delta block.
405*86d7f5d3SJohn Marino * returns false if the current block does not start with a number.
406*86d7f5d3SJohn Marino */
407*86d7f5d3SJohn Marino {
408*86d7f5d3SJohn Marino register struct hshentry * Delta, * num;
409*86d7f5d3SJohn Marino struct branchhead **LastBranch, *NewBranch;
410*86d7f5d3SJohn Marino
411*86d7f5d3SJohn Marino if (!(Delta = getdnum()))
412*86d7f5d3SJohn Marino return false;
413*86d7f5d3SJohn Marino
414*86d7f5d3SJohn Marino hshenter = false; /*Don't enter dates into hashtable*/
415*86d7f5d3SJohn Marino Delta->date = getkeyval(Kdate, NUM, false);
416*86d7f5d3SJohn Marino hshenter=true; /*reset hshenter for revision numbers.*/
417*86d7f5d3SJohn Marino
418*86d7f5d3SJohn Marino Delta->author = getkeyval(Kauthor, ID, false);
419*86d7f5d3SJohn Marino
420*86d7f5d3SJohn Marino Delta->state = getkeyval(Kstate, ID, true);
421*86d7f5d3SJohn Marino
422*86d7f5d3SJohn Marino getkey(K_branches);
423*86d7f5d3SJohn Marino LastBranch = &Delta->branches;
424*86d7f5d3SJohn Marino while ((num = getdnum())) {
425*86d7f5d3SJohn Marino NewBranch = ftalloc(struct branchhead);
426*86d7f5d3SJohn Marino NewBranch->hsh = num;
427*86d7f5d3SJohn Marino *LastBranch = NewBranch;
428*86d7f5d3SJohn Marino LastBranch = &NewBranch->nextbranch;
429*86d7f5d3SJohn Marino }
430*86d7f5d3SJohn Marino *LastBranch = 0;
431*86d7f5d3SJohn Marino getsemi(K_branches);
432*86d7f5d3SJohn Marino
433*86d7f5d3SJohn Marino getkey(Knext);
434*86d7f5d3SJohn Marino Delta->next = num = getdnum();
435*86d7f5d3SJohn Marino getsemi(Knext);
436*86d7f5d3SJohn Marino Delta->lockedby = 0;
437*86d7f5d3SJohn Marino Delta->log.string = 0;
438*86d7f5d3SJohn Marino Delta->selector = true;
439*86d7f5d3SJohn Marino
440*86d7f5d3SJohn Marino if (getkeyopt(Kcommitid)) {
441*86d7f5d3SJohn Marino Delta->commitid = NextString;
442*86d7f5d3SJohn Marino nextlex();
443*86d7f5d3SJohn Marino getsemi(Kcommitid);
444*86d7f5d3SJohn Marino } else {
445*86d7f5d3SJohn Marino Delta->commitid = NULL;
446*86d7f5d3SJohn Marino }
447*86d7f5d3SJohn Marino
448*86d7f5d3SJohn Marino Delta->ig = getphrases(Kdesc);
449*86d7f5d3SJohn Marino TotalDeltas++;
450*86d7f5d3SJohn Marino return (true);
451*86d7f5d3SJohn Marino }
452*86d7f5d3SJohn Marino
453*86d7f5d3SJohn Marino
454*86d7f5d3SJohn Marino void
gettree()455*86d7f5d3SJohn Marino gettree()
456*86d7f5d3SJohn Marino /* Function: Reads in the delta tree with getdelta(), then
457*86d7f5d3SJohn Marino * updates the lockedby fields.
458*86d7f5d3SJohn Marino */
459*86d7f5d3SJohn Marino {
460*86d7f5d3SJohn Marino struct rcslock const *currlock;
461*86d7f5d3SJohn Marino
462*86d7f5d3SJohn Marino while (getdelta())
463*86d7f5d3SJohn Marino continue;
464*86d7f5d3SJohn Marino currlock=Locks;
465*86d7f5d3SJohn Marino while (currlock) {
466*86d7f5d3SJohn Marino currlock->delta->lockedby = currlock->login;
467*86d7f5d3SJohn Marino currlock = currlock->nextlock;
468*86d7f5d3SJohn Marino }
469*86d7f5d3SJohn Marino }
470*86d7f5d3SJohn Marino
471*86d7f5d3SJohn Marino
472*86d7f5d3SJohn Marino void
getdesc(prdesc)473*86d7f5d3SJohn Marino getdesc(prdesc)
474*86d7f5d3SJohn Marino int prdesc;
475*86d7f5d3SJohn Marino /* Function: read in descriptive text
476*86d7f5d3SJohn Marino * nexttok is not advanced afterwards.
477*86d7f5d3SJohn Marino * If prdesc is set, the text is printed to stdout.
478*86d7f5d3SJohn Marino */
479*86d7f5d3SJohn Marino {
480*86d7f5d3SJohn Marino
481*86d7f5d3SJohn Marino getkeystring(Kdesc);
482*86d7f5d3SJohn Marino if (prdesc)
483*86d7f5d3SJohn Marino printstring(); /*echo string*/
484*86d7f5d3SJohn Marino else readstring(); /*skip string*/
485*86d7f5d3SJohn Marino }
486*86d7f5d3SJohn Marino
487*86d7f5d3SJohn Marino
488*86d7f5d3SJohn Marino
489*86d7f5d3SJohn Marino
490*86d7f5d3SJohn Marino
491*86d7f5d3SJohn Marino
492*86d7f5d3SJohn Marino static char const *
getkeyval(keyword,token,optional)493*86d7f5d3SJohn Marino getkeyval(keyword, token, optional)
494*86d7f5d3SJohn Marino char const *keyword;
495*86d7f5d3SJohn Marino enum tokens token;
496*86d7f5d3SJohn Marino int optional;
497*86d7f5d3SJohn Marino /* reads a pair of the form
498*86d7f5d3SJohn Marino * <keyword> <token> ;
499*86d7f5d3SJohn Marino * where token is one of <id> or <num>. optional indicates whether
500*86d7f5d3SJohn Marino * <token> is optional. A pointer to
501*86d7f5d3SJohn Marino * the actual character string of <id> or <num> is returned.
502*86d7f5d3SJohn Marino */
503*86d7f5d3SJohn Marino {
504*86d7f5d3SJohn Marino register char const *val = 0;
505*86d7f5d3SJohn Marino
506*86d7f5d3SJohn Marino getkey(keyword);
507*86d7f5d3SJohn Marino if (nexttok==token) {
508*86d7f5d3SJohn Marino val = NextString;
509*86d7f5d3SJohn Marino nextlex();
510*86d7f5d3SJohn Marino } else {
511*86d7f5d3SJohn Marino if (!optional)
512*86d7f5d3SJohn Marino fatserror("missing %s", keyword);
513*86d7f5d3SJohn Marino }
514*86d7f5d3SJohn Marino getsemi(keyword);
515*86d7f5d3SJohn Marino return(val);
516*86d7f5d3SJohn Marino }
517*86d7f5d3SJohn Marino
518*86d7f5d3SJohn Marino
519*86d7f5d3SJohn Marino void
unexpected_EOF()520*86d7f5d3SJohn Marino unexpected_EOF()
521*86d7f5d3SJohn Marino {
522*86d7f5d3SJohn Marino rcsfaterror("unexpected EOF in diff output");
523*86d7f5d3SJohn Marino }
524*86d7f5d3SJohn Marino
525*86d7f5d3SJohn Marino void
initdiffcmd(dc)526*86d7f5d3SJohn Marino initdiffcmd(dc)
527*86d7f5d3SJohn Marino register struct diffcmd *dc;
528*86d7f5d3SJohn Marino /* Initialize *dc suitably for getdiffcmd(). */
529*86d7f5d3SJohn Marino {
530*86d7f5d3SJohn Marino dc->adprev = 0;
531*86d7f5d3SJohn Marino dc->dafter = 0;
532*86d7f5d3SJohn Marino }
533*86d7f5d3SJohn Marino
534*86d7f5d3SJohn Marino static void
badDiffOutput(buf)535*86d7f5d3SJohn Marino badDiffOutput(buf)
536*86d7f5d3SJohn Marino char const *buf;
537*86d7f5d3SJohn Marino {
538*86d7f5d3SJohn Marino rcsfaterror("bad diff output line: %s", buf);
539*86d7f5d3SJohn Marino }
540*86d7f5d3SJohn Marino
541*86d7f5d3SJohn Marino static void
diffLineNumberTooLarge(buf)542*86d7f5d3SJohn Marino diffLineNumberTooLarge(buf)
543*86d7f5d3SJohn Marino char const *buf;
544*86d7f5d3SJohn Marino {
545*86d7f5d3SJohn Marino rcsfaterror("diff line number too large: %s", buf);
546*86d7f5d3SJohn Marino }
547*86d7f5d3SJohn Marino
548*86d7f5d3SJohn Marino int
getdiffcmd(finfile,delimiter,foutfile,dc)549*86d7f5d3SJohn Marino getdiffcmd(finfile, delimiter, foutfile, dc)
550*86d7f5d3SJohn Marino RILE *finfile;
551*86d7f5d3SJohn Marino FILE *foutfile;
552*86d7f5d3SJohn Marino int delimiter;
553*86d7f5d3SJohn Marino struct diffcmd *dc;
554*86d7f5d3SJohn Marino /* Get a editing command output by 'diff -n' from fin.
555*86d7f5d3SJohn Marino * The input is delimited by SDELIM if delimiter is set, EOF otherwise.
556*86d7f5d3SJohn Marino * Copy a clean version of the command to fout (if nonnull).
557*86d7f5d3SJohn Marino * Yield 0 for 'd', 1 for 'a', and -1 for EOF.
558*86d7f5d3SJohn Marino * Store the command's line number and length into dc->line1 and dc->nlines.
559*86d7f5d3SJohn Marino * Keep dc->adprev and dc->dafter up to date.
560*86d7f5d3SJohn Marino */
561*86d7f5d3SJohn Marino {
562*86d7f5d3SJohn Marino register int c;
563*86d7f5d3SJohn Marino declarecache;
564*86d7f5d3SJohn Marino register FILE *fout;
565*86d7f5d3SJohn Marino register char *p;
566*86d7f5d3SJohn Marino register RILE *fin;
567*86d7f5d3SJohn Marino long line1, nlines, t;
568*86d7f5d3SJohn Marino char buf[BUFSIZ];
569*86d7f5d3SJohn Marino
570*86d7f5d3SJohn Marino fin = finfile;
571*86d7f5d3SJohn Marino fout = foutfile;
572*86d7f5d3SJohn Marino setupcache(fin); cache(fin);
573*86d7f5d3SJohn Marino cachegeteof_(c, { if (delimiter) unexpected_EOF(); return -1; } )
574*86d7f5d3SJohn Marino if (delimiter) {
575*86d7f5d3SJohn Marino if (c==SDELIM) {
576*86d7f5d3SJohn Marino cacheget_(c)
577*86d7f5d3SJohn Marino if (c==SDELIM) {
578*86d7f5d3SJohn Marino buf[0] = c;
579*86d7f5d3SJohn Marino buf[1] = 0;
580*86d7f5d3SJohn Marino badDiffOutput(buf);
581*86d7f5d3SJohn Marino }
582*86d7f5d3SJohn Marino uncache(fin);
583*86d7f5d3SJohn Marino nextc = c;
584*86d7f5d3SJohn Marino if (fout)
585*86d7f5d3SJohn Marino aprintf(fout, "%c%c", SDELIM, c);
586*86d7f5d3SJohn Marino return -1;
587*86d7f5d3SJohn Marino }
588*86d7f5d3SJohn Marino }
589*86d7f5d3SJohn Marino p = buf;
590*86d7f5d3SJohn Marino do {
591*86d7f5d3SJohn Marino if (buf+BUFSIZ-2 <= p) {
592*86d7f5d3SJohn Marino rcsfaterror("diff output command line too long");
593*86d7f5d3SJohn Marino }
594*86d7f5d3SJohn Marino *p++ = c;
595*86d7f5d3SJohn Marino cachegeteof_(c, unexpected_EOF();)
596*86d7f5d3SJohn Marino } while (c != '\n');
597*86d7f5d3SJohn Marino uncache(fin);
598*86d7f5d3SJohn Marino if (delimiter)
599*86d7f5d3SJohn Marino ++rcsline;
600*86d7f5d3SJohn Marino *p = '\0';
601*86d7f5d3SJohn Marino for (p = buf+1; (c = *p++) == ' '; )
602*86d7f5d3SJohn Marino continue;
603*86d7f5d3SJohn Marino line1 = 0;
604*86d7f5d3SJohn Marino while (isdigit(c)) {
605*86d7f5d3SJohn Marino if (
606*86d7f5d3SJohn Marino LONG_MAX/10 < line1 ||
607*86d7f5d3SJohn Marino (t = line1 * 10, (line1 = t + (c - '0')) < t)
608*86d7f5d3SJohn Marino )
609*86d7f5d3SJohn Marino diffLineNumberTooLarge(buf);
610*86d7f5d3SJohn Marino c = *p++;
611*86d7f5d3SJohn Marino }
612*86d7f5d3SJohn Marino while (c == ' ')
613*86d7f5d3SJohn Marino c = *p++;
614*86d7f5d3SJohn Marino nlines = 0;
615*86d7f5d3SJohn Marino while (isdigit(c)) {
616*86d7f5d3SJohn Marino if (
617*86d7f5d3SJohn Marino LONG_MAX/10 < nlines ||
618*86d7f5d3SJohn Marino (t = nlines * 10, (nlines = t + (c - '0')) < t)
619*86d7f5d3SJohn Marino )
620*86d7f5d3SJohn Marino diffLineNumberTooLarge(buf);
621*86d7f5d3SJohn Marino c = *p++;
622*86d7f5d3SJohn Marino }
623*86d7f5d3SJohn Marino if (c == '\r')
624*86d7f5d3SJohn Marino c = *p++;
625*86d7f5d3SJohn Marino if (c || !nlines) {
626*86d7f5d3SJohn Marino badDiffOutput(buf);
627*86d7f5d3SJohn Marino }
628*86d7f5d3SJohn Marino if (line1+nlines < line1)
629*86d7f5d3SJohn Marino diffLineNumberTooLarge(buf);
630*86d7f5d3SJohn Marino switch (buf[0]) {
631*86d7f5d3SJohn Marino case 'a':
632*86d7f5d3SJohn Marino if (line1 < dc->adprev) {
633*86d7f5d3SJohn Marino rcsfaterror("backward insertion in diff output: %s", buf);
634*86d7f5d3SJohn Marino }
635*86d7f5d3SJohn Marino dc->adprev = line1 + 1;
636*86d7f5d3SJohn Marino break;
637*86d7f5d3SJohn Marino case 'd':
638*86d7f5d3SJohn Marino if (line1 < dc->adprev || line1 < dc->dafter) {
639*86d7f5d3SJohn Marino rcsfaterror("backward deletion in diff output: %s", buf);
640*86d7f5d3SJohn Marino }
641*86d7f5d3SJohn Marino dc->adprev = line1;
642*86d7f5d3SJohn Marino dc->dafter = line1 + nlines;
643*86d7f5d3SJohn Marino break;
644*86d7f5d3SJohn Marino default:
645*86d7f5d3SJohn Marino badDiffOutput(buf);
646*86d7f5d3SJohn Marino }
647*86d7f5d3SJohn Marino if (fout) {
648*86d7f5d3SJohn Marino aprintf(fout, "%s\n", buf);
649*86d7f5d3SJohn Marino }
650*86d7f5d3SJohn Marino dc->line1 = line1;
651*86d7f5d3SJohn Marino dc->nlines = nlines;
652*86d7f5d3SJohn Marino return buf[0] == 'a';
653*86d7f5d3SJohn Marino }
654*86d7f5d3SJohn Marino
655*86d7f5d3SJohn Marino
656*86d7f5d3SJohn Marino
657*86d7f5d3SJohn Marino #ifdef SYNTEST
658*86d7f5d3SJohn Marino
659*86d7f5d3SJohn Marino /* Input an RCS file and print its internal data structures. */
660*86d7f5d3SJohn Marino
661*86d7f5d3SJohn Marino char const cmdid[] = "syntest";
662*86d7f5d3SJohn Marino
663*86d7f5d3SJohn Marino int
main(argc,argv)664*86d7f5d3SJohn Marino main(argc,argv)
665*86d7f5d3SJohn Marino int argc; char * argv[];
666*86d7f5d3SJohn Marino {
667*86d7f5d3SJohn Marino
668*86d7f5d3SJohn Marino if (argc<2) {
669*86d7f5d3SJohn Marino aputs("No input file\n",stderr);
670*86d7f5d3SJohn Marino exitmain(EXIT_FAILURE);
671*86d7f5d3SJohn Marino }
672*86d7f5d3SJohn Marino if (!(finptr = Iopen(argv[1], FOPEN_R, (struct stat*)0))) {
673*86d7f5d3SJohn Marino faterror("can't open input file %s", argv[1]);
674*86d7f5d3SJohn Marino }
675*86d7f5d3SJohn Marino Lexinit();
676*86d7f5d3SJohn Marino getadmin();
677*86d7f5d3SJohn Marino fdlock = STDOUT_FILENO;
678*86d7f5d3SJohn Marino putadmin();
679*86d7f5d3SJohn Marino
680*86d7f5d3SJohn Marino gettree();
681*86d7f5d3SJohn Marino
682*86d7f5d3SJohn Marino getdesc(true);
683*86d7f5d3SJohn Marino
684*86d7f5d3SJohn Marino nextlex();
685*86d7f5d3SJohn Marino
686*86d7f5d3SJohn Marino if (!eoflex()) {
687*86d7f5d3SJohn Marino fatserror("expecting EOF");
688*86d7f5d3SJohn Marino }
689*86d7f5d3SJohn Marino exitmain(EXIT_SUCCESS);
690*86d7f5d3SJohn Marino }
691*86d7f5d3SJohn Marino
exiterr()692*86d7f5d3SJohn Marino void exiterr() { _exit(EXIT_FAILURE); }
693*86d7f5d3SJohn Marino
694*86d7f5d3SJohn Marino #endif
695