|
|
1.1 root 1: /*
2: * RCS revision generation
3: */
4: #ifndef lint
5: static char rcsid[]= "$Id: rcsgen.c,v 3.8 89/08/15 21:38:51 bostic Exp $ Purdue CS";
6: #endif
7:
8: /* Copyright (C) 1982, 1988, 1989 Walter Tichy
9: * All rights reserved.
10: *
11: * Redistribution and use in source and binary forms are permitted
12: * provided that the above copyright notice and this paragraph are
13: * duplicated in all such forms and that any documentation,
14: * advertising materials, and other materials related to such
15: * distribution and use acknowledge that the software was developed
16: * by Walter Tichy.
17: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20: *
21: * Report all problems and direct all questions to:
22: * [email protected]
23: *
24:
25:
26:
27:
28:
29:
30:
31: */
32:
33:
34:
35: /* $Log: rcsgen.c,v $
36: * Revision 3.8 89/08/15 21:38:51 bostic
37: * Version 4 from Tom Narten at Purdue
38: *
39: * Revision 4.7 89/05/01 15:12:49 narten
40: * changed copyright header to reflect current distribution rules
41: *
42: * Revision 4.6 88/11/08 12:01:13 narten
43: * changes from [email protected] (Paul Eggert)
44: *
45: * Revision 4.6 88/08/28 14:59:10 eggert
46: * Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin()
47: *
48: * Revision 4.5 87/12/18 11:43:25 narten
49: * additional lint cleanups, and a bug fix from the 4.3BSD version that
50: * keeps "ci" from sticking a '\377' into the description if you run it
51: * with a zero-length file as the description. (Guy Harris)
52: *
53: * Revision 4.4 87/10/18 10:35:10 narten
54: * Updating version numbers. Changes relative to 1.1 actually relative to
55: * 4.2
56: *
57: * Revision 1.3 87/09/24 13:59:51 narten
58: * Sources now pass through lint (if you ignore printf/sprintf/fprintf
59: * warnings)
60: *
61: * Revision 1.2 87/03/27 14:22:27 jenkins
62: * Port to suns
63: *
64: * Revision 1.1 84/01/23 14:50:28 kcs
65: * Initial revision
66: *
67: * Revision 4.2 83/12/02 23:01:39 wft
68: * merged 4.1 and 3.3.1.1 (clearerr(stdin)).
69: *
70: * Revision 4.1 83/05/10 16:03:33 wft
71: * Changed putamin() to abort if trying to reread redirected stdin.
72: * Fixed getdesc() to output a prompt on initial newline.
73: *
74: * Revision 3.3.1.1 83/10/19 04:21:51 lepreau
75: * Added clearerr(stdin) for re-reading description from stdin.
76: *
77: * Revision 3.3 82/11/28 21:36:49 wft
78: * 4.2 prerelease
79: *
80: * Revision 3.3 82/11/28 21:36:49 wft
81: * Replaced ferror() followed by fclose() with ffclose().
82: * Putdesc() now suppresses the prompts if stdin
83: * is not a terminal. A pointer to the current log message is now
84: * inserted into the corresponding delta, rather than leaving it in a
85: * global variable.
86: *
87: * Revision 3.2 82/10/18 21:11:26 wft
88: * I added checks for write errors during editing, and improved
89: * the prompt on putdesc().
90: *
91: * Revision 3.1 82/10/13 15:55:09 wft
92: * corrected type of variables assigned to by getc (char --> int)
93: */
94:
95:
96:
97:
98: #include "rcsbase.h"
99:
100: extern struct hshentry * getnum();
101: extern FILE * fopen();
102: extern savestring();
103: extern editstring();
104:
105: extern int nextc; /* next character from lexical analyzer */
106: extern char Ktext[]; /* keywords from syntax analyzer */
107: extern char Klog[]; /* Keyword "log" */
108: extern char Kdesc[]; /* Keyword for description */
109: extern FILE * frewrite; /* new RCS file */
110: extern FILE * fcopy; /* result file during editing */
111: extern char * resultfile; /* file name for fcopy */
112: extern int rewriteflag; /* indicates whether to rewrite the input file */
113:
114:
115: char curlogmsg[logsize]; /* buffer for current log message */
116:
117: enum stringwork {copy, edit, expand, edit_expand };
118: /* parameter to scandeltatext() */
119:
120:
121:
122:
123: char * buildrevision(deltas, target, dir, expandflag)
124: struct hshentry ** deltas, * target;
125: char * dir; int expandflag;
126: /* Function: Generates the revision given by target
127: * by retrieving all deltas given by parameter deltas and combining them.
128: * If dir==nil, the revision is printed on the standard output,
129: * otherwise written into a temporary file in directory dir.
130: * if expandflag==true, keyword expansion is performed.
131: * returns false on errors, the name of the file with the revision otherwise.
132: *
133: * Algorithm: Copy inital revision unchanged. Then edit all revisions but
134: * the last one into it, alternating input and output files (resultfile and
135: * editfile). The last revision is then edited in, performing simultaneous
136: * keyword substitution (this saves one extra pass).
137: * All this simplifies if only one revision needs to be generated,
138: * or no keyword expansion is necessary, or if output goes to stdout.
139: */
140: {
141: int i;
142:
143: if (deltas[0]==target) {
144: /* only latest revision to generate */
145: if (dir==nil) {/* print directly to stdout */
146: fcopy=stdout;
147: scandeltatext(target,expand);
148: return(char *) true;
149: } else {
150: initeditfiles(dir);
151: scandeltatext(target,expandflag?expand:copy);
152: ffclose(fcopy);
153: return(resultfile);
154: }
155: } else {
156: /* several revisions to generate */
157: initeditfiles(dir?dir:"/tmp/");
158: /* write initial revision into fcopy, no keyword expansion */
159: scandeltatext(deltas[0],copy);
160: i = 1;
161: while (deltas[i+1] != nil) {
162: /* do all deltas except last one */
163: scandeltatext(deltas[i++],edit);
164: }
165: if (!expandflag) {
166: /* no keyword expansion; only invoked from ci */
167: scandeltatext(deltas[i],edit);
168: finishedit((struct hshentry *)nil);
169: ffclose(fcopy);
170: } else {
171: /* perform keyword expansion*/
172: /* first, get to beginning of file*/
173: finishedit((struct hshentry *)nil); swapeditfiles(dir==nil);
174: scandeltatext(deltas[i],edit_expand);
175: finishedit(deltas[i]);
176: if (dir!=nil) ffclose(fcopy);
177: }
178: return(resultfile); /*doesn't matter for dir==nil*/
179: }
180: }
181:
182:
183:
184: scandeltatext(delta,func)
185: struct hshentry * delta; enum stringwork func;
186: /* Function: Scans delta text nodes up to and including the one given
187: * by delta. For the one given by delta, the log message is saved into
188: * curlogmsg and the text is processed according to parameter func.
189: * Assumes the initial lexeme must be read in first.
190: * Does not advance nexttok after it is finished.
191: */
192: { struct hshentry * nextdelta;
193:
194: do {
195: nextlex();
196: if (!(nextdelta=getnum())) {
197: fatserror("Can't find delta for revision %s", delta->num);
198: }
199: if (!getkey(Klog) || nexttok!=STRING)
200: serror("Missing log entry");
201: elsif (delta==nextdelta) {
202: VOID savestring(curlogmsg,logsize);
203: delta->log=curlogmsg;
204: } else {readstring();
205: delta->log= "";
206: }
207: nextlex();
208: if (!getkey(Ktext) || nexttok!=STRING)
209: fatserror("Missing delta text");
210:
211: if(delta==nextdelta)
212: /* got the one we're looking for */
213: switch (func) {
214: case copy: copystring();
215: break;
216: case expand: xpandstring(delta);
217: break;
218: case edit: editstring((struct hshentry *)nil);
219: break;
220: case edit_expand: editstring(delta);
221: break;
222: }
223: else readstring(); /* skip over it */
224:
225: } while (delta!=nextdelta);
226: }
227:
228:
229: int stdinread; /* stdinread>0 if redirected stdin has been read once */
230:
231: int ttystdin()
232: {
233: static int initialized, istty;
234: if (!initialized) {
235: istty = isatty(fileno(stdin));
236: initialized = 1;
237: }
238: return istty;
239: }
240:
241: putdesc(initflag,textflag,textfile,quietflag)
242: int initflag,textflag; char * textfile; int quietflag;
243: /* Function: puts the descriptive text into file frewrite.
244: * if !initflag && !textflag, the text is copied from the old description.
245: * Otherwise, if the textfile!=nil, the text is read from that
246: * file, or from stdin, if textfile==nil.
247: * Increments stdinread if text is read from redirected stdin.
248: * if initflag&&quietflag&&!textflag, an empty text is inserted.
249: * if !initflag, the old descriptive text is discarded.
250: */
251: { register FILE * txt; register int c, old1, old2;
252: register FILE * frew;
253: #ifdef lint
254: if (quietflag == 0) initflag = quietflag; /* silencelint */
255: #endif
256:
257: frew = frewrite;
258: if (!initflag && !textflag) {
259: /* copy old description */
260: VOID fprintf(frew,"\n\n%s%c",Kdesc,nextc);
261: rewriteflag=true; getdesc(false);
262: } else {
263: /* get new description */
264: if (!initflag) {
265: /*skip old description*/
266: rewriteflag=false; getdesc(false);
267: }
268: VOID fprintf(frew,"\n\n%s\n%c",Kdesc,SDELIM);
269: if (textfile) {
270: old1='\n';
271: /* copy textfile */
272: if ((txt=fopen(textfile,"r"))!=NULL) {
273: while ((c=getc(txt))!=EOF) {
274: if (c==SDELIM) VOID putc(c,frew); /*double up*/
275: VOID putc(c,frew);
276: old1=c;
277: }
278: if (old1!='\n') VOID putc('\n',frew);
279: VOID fclose(txt);
280: VOID putc(SDELIM,frew);
281: VOID fputs("\n\n", frew);
282: return;
283: } else {
284: error("Can't open file %s with description",textfile);
285: if (!ttystdin()) return;
286: /* otherwise, get description from terminal */
287: }
288: }
289: /* read text from stdin */
290: if (ttystdin()) {
291: VOID fputs("enter description, terminated with ^D or '.':\n",stderr);
292: VOID fputs("NOTE: This is NOT the log message!\n>> ",stderr);
293: if (feof(stdin))
294: clearerr(stdin);
295: } else { /* redirected stdin */
296: if (stdinread>0)
297: faterror("Can't reread redirected stdin for description; use -t<file>");
298: stdinread++;
299: }
300: c = '\0'; old2= '\n';
301: if ((old1=getchar())==EOF) {
302: if (ttystdin()) {
303: VOID putc('\n',stderr);
304: clearerr(stdin);
305: }
306: } else {
307: if (old1=='\n' && ttystdin())
308: VOID fputs(">> ",stderr);
309: for (;;) {
310: c=getchar();
311: if (c==EOF) {
312: if (ttystdin()) {
313: VOID putc('\n',stderr);
314: clearerr(stdin);
315: }
316: VOID putc(old1,frew);
317: if (old1!='\n') VOID putc('\n',frew);
318: break;
319: }
320: if (c=='\n' && old1=='.' && old2=='\n') {
321: break;
322: }
323: if (c=='\n' && ttystdin()) VOID fputs(">> ",stderr);
324: if(old1==SDELIM) VOID putc(old1,frew); /* double up*/
325: VOID putc(old1,frew);
326: old2=old1;
327: old1=c;
328: } /* end for */
329: }
330: VOID putc(SDELIM,frew); VOID fputs("\n\n",frew);
331: }
332: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.