5 static char rcsid
[]= "$Id: rcsedit.c,v 1.1 1993/03/21 09:58:07 cgd Exp $ Purdue CS";
7 /**********************************************************************************
8 * edits the input file according to a
9 * script from stdin, generated by diff -n
10 * performs keyword expansion
11 **********************************************************************************
14 /* Copyright (C) 1982, 1988, 1989 Walter Tichy
15 * All rights reserved.
17 * Redistribution and use in source and binary forms are permitted
18 * provided that the above copyright notice and this paragraph are
19 * duplicated in all such forms and that any documentation,
20 * advertising materials, and other materials related to such
21 * distribution and use acknowledge that the software was developed
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27 * Report all problems and direct all questions to:
28 * rcs-bugs@cs.purdue.edu
40 /* $Log: rcsedit.c,v $
41 * Revision 3.11 89/08/15 21:37:31 bostic
42 * Version 4 from Tom Narten at Purdue
44 * Revision 4.8 89/05/01 15:12:35 narten
45 * changed copyright header to reflect current distribution rules
47 * Revision 4.7 88/11/08 13:54:14 narten
48 * misplaced semicolon caused infinite loop
50 * Revision 4.6 88/11/08 12:01:41 narten
51 * changes from eggert@sm.unisys.com (Paul Eggert)
53 * Revision 4.6 88/08/09 19:12:45 eggert
54 * Shrink stdio code size; allow cc -R.
56 * Revision 4.5 87/12/18 11:38:46 narten
57 * Changes from the 43. version. Don't know the significance of the
58 * first change involving "rewind". Also, additional "lint" cleanup.
61 * Revision 4.4 87/10/18 10:32:21 narten
62 * Updating version numbers. Changes relative to version 1.1 actually
65 * Revision 1.4 87/09/24 13:59:29 narten
66 * Sources now pass through lint (if you ignore printf/sprintf/fprintf
69 * Revision 1.3 87/09/15 16:39:39 shepler
70 * added an initializatin of the variables editline and linecorr
71 * this will be done each time a file is processed.
72 * (there was an obscure bug where if co was used to retrieve multiple files
74 * fix attributed to Roy Morris @FileNet Corp ...!felix!roy
76 * Revision 1.2 87/03/27 14:22:17 jenkins
79 * Revision 1.1 84/01/23 14:50:20 kcs
82 * Revision 4.1 83/05/12 13:10:30 wft
83 * Added new markers Id and RCSfile; added locker to Header and Id.
84 * Overhauled expandline completely() (problem with $01234567890123456789@).
85 * Moved trymatch() and marker table to rcskeys.c.
87 * Revision 3.7 83/05/12 13:04:39 wft
88 * Added retry to expandline to resume after failed match which ended in $.
89 * Fixed truncation problem for $19chars followed by@@.
90 * Log no longer expands full path of RCS file.
92 * Revision 3.6 83/05/11 16:06:30 wft
93 * added retry to expandline to resume after failed match which ended in $.
94 * Fixed truncation problem for $19chars followed by@@.
96 * Revision 3.5 82/12/04 13:20:56 wft
97 * Added expansion of keyword Locker.
99 * Revision 3.4 82/12/03 12:26:54 wft
100 * Added line number correction in case editing does not start at the
101 * beginning of the file.
102 * Changed keyword expansion to always print a space before closing KDELIM;
103 * Expansion for Header shortened.
105 * Revision 3.3 82/11/14 14:49:30 wft
106 * removed Suffix from keyword expansion. Replaced fclose with ffclose.
107 * keyreplace() gets log message from delta, not from curlogmsg.
108 * fixed expression overflow in while(c=putc(GETC....
109 * checked nil printing.
111 * Revision 3.2 82/10/18 21:13:39 wft
112 * I added checks for write errors during the co process, and renamed
113 * expandstring() to xpandstring().
115 * Revision 3.1 82/10/13 15:52:55 wft
116 * changed type of result of getc() from char to int.
117 * made keyword expansion loop in expandline() portable to machines
118 * without sign-extension.
125 extern FILE * fopen();
126 extern char * mktempfile();
127 extern char * bindex();
128 extern FILE * finptr
, * frewrite
;
129 extern int rewriteflag
;
131 extern char * RCSfilename
, * workfilename
;
132 extern char * bindex();
133 extern char * getfullRCSname();
134 extern enum markers
trymatch();
137 FILE * fcopy
, * fedit
; /* result and edit file descriptors */
138 char *resultfile
; /* result file name */
139 char * editfile
; /* edit file name */
140 int editline
; /*line counter in fedit; starts with 1, is always #lines+1 */
141 int linecorr
; /*contains #adds - #deletes in each edit run. */
142 /*used to correct editline in case file is not rewound after */
143 /* applying one delta */
147 /* Function: Initializes resultfile and editfile with temporary filenames
148 * in directory dir. Opens resultfile for reading and writing, with fcopy
149 * as file descriptor. fedit is set to nil.
152 editline
= linecorr
= 0; /* make sure we start from the beginning*/
153 resultfile
=mktempfile(dir
,TMPFILE1
);
154 editfile
=mktempfile(dir
,TMPFILE2
);
156 if ((fcopy
=fopen(resultfile
,"w+"))==NULL
) {
157 faterror("Can't open working file %s",resultfile
);
162 swapeditfiles(tostdout
)
163 /* Function: swaps resultfile and editfile, assigns fedit=fcopy,
164 * rewinds fedit for reading, and opens resultfile for reading and
165 * writing, using fcopy. If tostdout, fcopy is set to stdout.
169 faterror("write failed on %s -- file system full?",resultfile
);
172 editline
= 1; linecorr
=0;
173 tmpptr
=editfile
; editfile
=resultfile
; resultfile
=tmpptr
;
176 elsif ((fcopy
=fopen(resultfile
,"w+"))==NULL
) {
177 faterror("Can't open working file %s",resultfile
);
183 struct hshentry
* delta
;
184 /* copy the rest of the edit file and close it (if it exists).
185 * if delta!=nil, perform keyword substitution at the same time.
191 while (expandline(fedit
,fcopy
,delta
,false,false)) editline
++;
193 while((c
=getc(fedit
))!=EOF
) {
195 if (c
=='\n') editline
++;
203 copylines(line
,delta
)
204 register int line
; struct hshentry
* delta
;
205 /* Function: copies input lines editline..line-1 from fedit to fcopy.
206 * If delta != nil, keyword expansion is done simultaneously.
207 * editline is updated. Rewinds a file only if necessary.
213 finishedit((struct hshentry
*)nil
); swapeditfiles(false);
214 /* assumes edit only during last pass, from the beginning*/
216 while (editline
<line
) {
217 /*copy another line*/
219 VOID
expandline(fedit
,fcopy
,delta
,false,false);
221 while (putc(getc(fedit
),fcopy
)!='\n');
229 struct hshentry
* delta
;
230 /* Function: Reads a string terminated by SDELIM from finptr and writes it
231 * to fcopy. Double SDELIM is replaced with single SDELIM.
232 * Keyword expansion is performed with data from delta.
233 * If rewriteflag==true, the string is also copied unchanged to frewrite.
234 * editline is updated.
238 while (expandline(finptr
,fcopy
,delta
,true,rewriteflag
)) editline
++;
244 /* Function: copies a string terminated with a single SDELIM from finptr to
245 * fcopy, replacing all double SDELIM with a single SDELIM.
246 * If rewriteflag==true, the string also copied unchanged to frewrite.
247 * editline is set to (number of lines copied)+1.
248 * Assumption: next character read is first string character.
251 register FILE *fin
, *frew
, *fcop
;
254 fin
=finptr
; frew
=frewrite
; fcop
=fcopy
;
257 while ((c
=GETC(fin
,frew
,write
)) != EOF
) {
258 if ((c
==SDELIM
)&&((c
=GETC(fin
,frew
,write
)) != SDELIM
)){
264 if (c
=='\n') editline
++;
267 serror("Unterminated string");
275 struct hshentry
* delta
;
276 /* Function: reads an edit script from finptr and applies it to
277 * file fedit; the result is written to fcopy.
278 * If delta!=nil, keyword expansion is performed simultaneously.
279 * If frewrite==true, the edit script is also copied verbatim to frewrite.
280 * Assumes that all these files are open.
281 * If running out of lines in fedit, fedit and fcopy are swapped.
282 * resultfile and editfile are the names of the files that go with fcopy
283 * and fedit, respectively.
284 * Assumes the next input character from finptr is the first character of
285 * the edit script. Resets nextc on exit.
288 int ed
; /* editor command */
290 register FILE *fin
, *frew
;
291 register int write
, i
;
294 fin
=finptr
; frew
=frewrite
;
295 editline
+= linecorr
; linecorr
=0; /*correct line number*/
298 /* read next command and decode */
299 /* assume next non-white character is command name*/
300 while((ed
=GETC(fin
,frew
,write
))=='\n'||
301 ed
==' ' || ed
=='\t');
302 if (ed
==SDELIM
) break;
303 /* now attempt to read numbers. */
304 /* fscanf causes trouble because of the required echoing */
305 while ((c
=GETC(fin
,frew
,write
))==' '); /*skip spaces*/
306 if (!('0'<=c
&& c
<='9')) {
307 faterror("missing line number in edit script");
311 while ('0'<=(c
=GETC(fin
,frew
,write
)) && c
<='9') {
312 line
= line
*10 + c
-'0';
314 while (c
==' ') c
=GETC(fin
,frew
,write
);
315 if (!('0'<=c
&& c
<='9')) {
316 faterror("incorrect range in edit script");
320 while ('0'<=(c
=GETC(fin
,frew
,write
)) && c
<='9') {
321 length
= length
*10 + c
-'0';
323 while(c
!='\n'&&c
!=EOF
) c
=GETC(fin
,frew
,write
); /* skip to end of line */
327 copylines(line
,delta
);
328 /* skip over unwanted lines */
329 for (i
=length
;i
>0;i
--) {
331 while ((c
=getc(fedit
))!='\n')
333 faterror("EOF during edit");
339 copylines(line
+1,delta
); /*copy only; no delete*/
340 for (i
=length
;i
>0;i
--) {
341 /*copy next line from script*/
343 VOID
expandline(fin
,fcopy
,delta
,true,write
);
345 c
= GETC(fin
,frew
,write
);
346 while (putc(c
,fcopy
)!='\n'){
347 if ((c
==SDELIM
)&&((c
=GETC(fin
,frew
,write
))!=SDELIM
)){
348 serror("Missing string delimiter in edit script");
351 c
= GETC(fin
,frew
,write
);
358 faterror("unknown command in edit script: %c", ed
);
362 nextc
=GETC(fin
,frew
,write
);
367 /* The rest is for keyword expansion */
371 expandline(in
, out
, delta
,delimstuffed
,write
)
372 register FILE * in
, * out
; struct hshentry
* delta
;
373 int delimstuffed
, write
;
374 /* Function: Reads a line from in and writes it to out.
375 * If delimstuffed==true, double SDELIM is replaced with single SDELIM.
376 * Keyword expansion is performed with data from delta.
377 * If write==true, the string is also copied unchanged to frewrite.
378 * Returns false if end-of-string or end-of-line is detected, true otherwise.
382 register FILE * frew
;
385 char keystring
[keylength
+2];
386 char keyval
[keyvallength
+2];
387 enum markers matchresult
;
396 error("unterminated string");
402 if (c
==SDELIM
&& ds
) {
403 if ((c
=GETC(in
,frew
,w
))!=SDELIM
) {
411 if (c
=='\n') return true; /* end of line */
414 /* check for keyword */
415 /* first, copy a long enough string into keystring */
417 while (((c
=GETC(in
,frew
,w
))!=EOF
) && (tp
<keystring
+keylength
) && (c
!='\n')
418 && (c
!=SDELIM
) && (c
!=KDELIM
) && (c
!=VDELIM
)) {
422 *tp
++ = c
; *tp
= '\0';
423 matchresult
=trymatch(keystring
,false);
424 if (matchresult
==Nomatch
) continue;
425 /* last c will be dealt with properly by continue*/
427 /* Now we have a keyword terminated with a K/VDELIM */
429 /* try to find closing KDELIM, and replace value */
431 while (((c
=GETC(in
,frew
,w
)) != EOF
)
432 && (c
!='\n') && (c
!=KDELIM
) && (tp
<keyval
+keyvallength
)) {
434 if (c
==SDELIM
&& ds
) { /*skip next SDELIM */
436 /* Can't be at end of string.
437 /* always a \n before closing SDELIM */
441 /* couldn't find closing KDELIM -- give up */
442 VOID
putc(VDELIM
,out
); *tp
='\0';
443 VOID
fputs(keyval
,out
);
444 continue; /* last c handled properly */
447 /* now put out the new keyword value */
448 keyreplace(matchresult
,delta
,out
);
456 keyreplace(marker
,delta
,out
)
457 enum markers marker
; struct hshentry
* delta
; register FILE * out
;
458 /* function: ouputs the keyword value(s) corresponding to marker.
459 * Attributes are derived from delta.
469 VOID
fprintf(out
,"%c %s %c",VDELIM
,delta
->author
,KDELIM
);
472 VOID
putc(VDELIM
,out
);VOID
putc(' ',out
);
473 VOID
PRINTDATE(out
,date
);VOID
putc(' ',out
);
474 VOID
PRINTTIME(out
,date
);VOID
putc(' ',out
);VOID
putc(KDELIM
,out
);
478 VOID
putc(VDELIM
,out
); VOID
putc(' ',out
);
480 VOID
fputs(bindex(RCSfilename
,'/'),out
);
481 else VOID
fputs(getfullRCSname(),out
);
482 VOID
fprintf(out
," %s ", delta
->num
);
483 VOID
PRINTDATE(out
,date
);VOID
putc(' ',out
);VOID
PRINTTIME(out
,date
);
484 VOID
fprintf(out
, " %s %s ",delta
->author
,delta
->state
);
485 if (delta
->lockedby
!=nil
)
486 VOID
fprintf(out
,"Locker: %s ",delta
->lockedby
);
487 VOID
putc(KDELIM
,out
);
490 VOID
fprintf(out
,"%c %s %c", VDELIM
,
491 delta
->lockedby
==nil
?"":delta
->lockedby
,KDELIM
);
494 VOID
fprintf(out
, "%c\t%s %c\n%sRevision %s ",
495 VDELIM
, bindex(RCSfilename
,'/'), KDELIM
, Comment
, delta
->num
);
496 VOID
PRINTDATE(out
,date
);VOID
fputs(" ",out
);VOID
PRINTTIME(out
,date
);
497 VOID
fprintf(out
, " %s\n%s",delta
->author
,Comment
);
498 /* do not include state here because it may change and is not updated*/
500 while (*sp
) if (putc(*sp
++,out
)=='\n') VOID
fputs(Comment
,out
);
501 /* Comment is the comment leader */
504 VOID
fprintf(out
,"%c %s %c",VDELIM
,bindex(RCSfilename
,'/'),KDELIM
);
507 VOID
fprintf(out
,"%c %s %c",VDELIM
,delta
->num
,KDELIM
);
510 VOID
fprintf(out
,"%c %s %c",VDELIM
,getfullRCSname(),KDELIM
);
513 VOID
fprintf(out
,"%c %s %c",VDELIM
,delta
->state
,KDELIM
);
516 VOID
putc(KDELIM
,out
);