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