Sync usage with man page.
[netbsd-mini2440.git] / usr.bin / rcs / src / rcsgen.c
blob5cbe448be2386cb12726f56e31de023e87c91661
1 /*
2 * RCS revision generation
3 */
4 #ifndef lint
5 static char rcsid[]= "$Id: rcsgen.c,v 1.1 1993/03/21 09:58:08 cgd Exp $ Purdue CS";
6 #endif
8 /* Copyright (C) 1982, 1988, 1989 Walter Tichy
9 * All rights reserved.
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.
21 * Report all problems and direct all questions to:
22 * rcs-bugs@cs.purdue.edu
35 /* $Log: rcsgen.c,v $
36 * Revision 3.8 89/08/15 21:38:51 bostic
37 * Version 4 from Tom Narten at Purdue
39 * Revision 4.7 89/05/01 15:12:49 narten
40 * changed copyright header to reflect current distribution rules
42 * Revision 4.6 88/11/08 12:01:13 narten
43 * changes from eggert@sm.unisys.com (Paul Eggert)
45 * Revision 4.6 88/08/28 14:59:10 eggert
46 * Shrink stdio code size; allow cc -R; remove lint; isatty() -> ttystdin()
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)
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
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)
61 * Revision 1.2 87/03/27 14:22:27 jenkins
62 * Port to suns
64 * Revision 1.1 84/01/23 14:50:28 kcs
65 * Initial revision
67 * Revision 4.2 83/12/02 23:01:39 wft
68 * merged 4.1 and 3.3.1.1 (clearerr(stdin)).
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.
74 * Revision 3.3.1.1 83/10/19 04:21:51 lepreau
75 * Added clearerr(stdin) for re-reading description from stdin.
77 * Revision 3.3 82/11/28 21:36:49 wft
78 * 4.2 prerelease
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.
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().
91 * Revision 3.1 82/10/13 15:55:09 wft
92 * corrected type of variables assigned to by getc (char --> int)
98 #include "rcsbase.h"
100 extern struct hshentry * getnum();
101 extern FILE * fopen();
102 extern savestring();
103 extern editstring();
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 */
115 char curlogmsg[logsize]; /* buffer for current log message */
117 enum stringwork {copy, edit, expand, edit_expand };
118 /* parameter to scandeltatext() */
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.
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.
141 int i;
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);
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);
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);
178 return(resultfile); /*doesn't matter for dir==nil*/
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.
192 { struct hshentry * nextdelta;
194 do {
195 nextlex();
196 if (!(nextdelta=getnum())) {
197 fatserror("Can't find delta for revision %s", delta->num);
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= "";
207 nextlex();
208 if (!getkey(Ktext) || nexttok!=STRING)
209 fatserror("Missing delta text");
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;
223 else readstring(); /* skip over it */
225 } while (delta!=nextdelta);
229 int stdinread; /* stdinread>0 if redirected stdin has been read once */
231 int ttystdin()
233 static int initialized, istty;
234 if (!initialized) {
235 istty = isatty(fileno(stdin));
236 initialized = 1;
238 return istty;
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.
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
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);
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;
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 */
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++;
300 c = '\0'; old2= '\n';
301 if ((old1=getchar())==EOF) {
302 if (ttystdin()) {
303 VOID putc('\n',stderr);
304 clearerr(stdin);
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);
316 VOID putc(old1,frew);
317 if (old1!='\n') VOID putc('\n',frew);
318 break;
320 if (c=='\n' && old1=='.' && old2=='\n') {
321 break;
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 */
330 VOID putc(SDELIM,frew); VOID fputs("\n\n",frew);