|
|
1.1 root 1: /*
2: * RCS stream editor
3: */
4: #ifndef lint
5: static char rcsid[]= "$Id: rcsedit.c,v 3.11 89/08/15 21:37:31 bostic Exp $ Purdue CS";
6: #endif
7: /**********************************************************************************
8: * edits the input file according to a
9: * script from stdin, generated by diff -n
10: * performs keyword expansion
11: **********************************************************************************
12: */
13:
14: /* Copyright (C) 1982, 1988, 1989 Walter Tichy
15: * All rights reserved.
16: *
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
22: * by Walter Tichy.
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.
26: *
27: * Report all problems and direct all questions to:
28: * [email protected]
29: *
30:
31:
32:
33:
34:
35:
36:
37: */
38:
39:
40: /* $Log: rcsedit.c,v $
41: * Revision 3.11 89/08/15 21:37:31 bostic
42: * Version 4 from Tom Narten at Purdue
43: *
44: * Revision 4.8 89/05/01 15:12:35 narten
45: * changed copyright header to reflect current distribution rules
46: *
47: * Revision 4.7 88/11/08 13:54:14 narten
48: * misplaced semicolon caused infinite loop
49: *
50: * Revision 4.6 88/11/08 12:01:41 narten
51: * changes from [email protected] (Paul Eggert)
52: *
53: * Revision 4.6 88/08/09 19:12:45 eggert
54: * Shrink stdio code size; allow cc -R.
55: *
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.
59: * (Guy Harris)
60: *
61: * Revision 4.4 87/10/18 10:32:21 narten
62: * Updating version numbers. Changes relative to version 1.1 actually
63: * relative to 4.1
64: *
65: * Revision 1.4 87/09/24 13:59:29 narten
66: * Sources now pass through lint (if you ignore printf/sprintf/fprintf
67: * warnings)
68: *
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
73: * it would dump)
74: * fix attributed to Roy Morris @FileNet Corp ...!felix!roy
75: *
76: * Revision 1.2 87/03/27 14:22:17 jenkins
77: * Port to suns
78: *
79: * Revision 1.1 84/01/23 14:50:20 kcs
80: * Initial revision
81: *
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.
86: *
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.
91: *
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@@.
95: *
96: * Revision 3.5 82/12/04 13:20:56 wft
97: * Added expansion of keyword Locker.
98: *
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.
104: *
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.
110: *
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().
114: *
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.
119: */
120:
121:
122: #include "rcsbase.h"
123:
124:
125: extern FILE * fopen();
126: extern char * mktempfile();
127: extern char * bindex();
128: extern FILE * finptr, * frewrite;
129: extern int rewriteflag;
130: extern int nextc;
131: extern char * RCSfilename, * workfilename;
132: extern char * bindex();
133: extern char * getfullRCSname();
134: extern enum markers trymatch();
135:
136:
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 */
144:
145: initeditfiles(dir)
146: char * dir;
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.
150: */
151: {
152: editline = linecorr = 0; /* make sure we start from the beginning*/
153: resultfile=mktempfile(dir,TMPFILE1);
154: editfile =mktempfile(dir,TMPFILE2);
155: fedit=nil;
156: if ((fcopy=fopen(resultfile,"w+"))==NULL) {
157: faterror("Can't open working file %s",resultfile);
158: }
159: }
160:
161:
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.
166: */
167: { char * tmpptr;
168: if(ferror(fcopy))
169: faterror("write failed on %s -- file system full?",resultfile);
170: fedit=fcopy;
171: rewind(fedit);
172: editline = 1; linecorr=0;
173: tmpptr=editfile; editfile=resultfile; resultfile=tmpptr;
174: if (tostdout)
175: fcopy=stdout;
176: elsif ((fcopy=fopen(resultfile,"w+"))==NULL) {
177: faterror("Can't open working file %s",resultfile);
178: }
179: }
180:
181:
182: finishedit(delta)
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.
186: */
187: {
188: register int c;
189: if (fedit!=nil) {
190: if (delta!=nil) {
191: while (expandline(fedit,fcopy,delta,false,false)) editline++;
192: } else {
193: while((c=getc(fedit))!=EOF) {
194: VOID putc(c,fcopy);
195: if (c=='\n') editline++;
196: }
197: }
198: ffclose(fedit);
199: }
200: }
201:
202:
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.
208: */
209: {
210:
211: if (editline>line) {
212: /* swap files */
213: finishedit((struct hshentry *)nil); swapeditfiles(false);
214: /* assumes edit only during last pass, from the beginning*/
215: }
216: while (editline<line) {
217: /*copy another line*/
218: if (delta)
219: VOID expandline(fedit,fcopy,delta,false,false);
220: else
221: while (putc(getc(fedit),fcopy)!='\n');
222: editline++;
223: }
224: }
225:
226:
227:
228: xpandstring(delta)
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.
235: */
236: {
237: editline=1;
238: while (expandline(finptr,fcopy,delta,true,rewriteflag)) editline++;
239: nextc='\n';
240: }
241:
242:
243: copystring()
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.
249: */
250: { register c;
251: register FILE *fin, *frew, *fcop;
252: register write;
253:
254: fin=finptr; frew=frewrite; fcop=fcopy;
255: write=rewriteflag;
256: editline=1;
257: while ((c=GETC(fin,frew,write)) != EOF) {
258: if ((c==SDELIM)&&((c=GETC(fin,frew,write)) != SDELIM)){
259: /* end of string */
260: nextc = c;
261: return;
262: }
263: VOID putc(c,fcop);
264: if (c=='\n') editline++;
265: }
266: nextc = c;
267: serror("Unterminated string");
268: return;
269: }
270:
271:
272:
273:
274: editstring(delta)
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.
286: */
287: {
288: int ed; /* editor command */
289: register int c;
290: register FILE *fin, *frew;
291: register int write, i;
292: int line, length;
293:
294: fin=finptr; frew=frewrite;
295: editline += linecorr; linecorr=0; /*correct line number*/
296: write=rewriteflag;
297: for (;;) {
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");
308: break;
309: }
310: line= c -'0';
311: while ('0'<=(c=GETC(fin,frew,write)) && c<='9') {
312: line = line*10 + c-'0';
313: }
314: while (c==' ') c=GETC(fin,frew,write);
315: if (!('0'<=c && c<='9')) {
316: faterror("incorrect range in edit script");
317: break;
318: }
319: length= c -'0';
320: while ('0'<=(c=GETC(fin,frew,write)) && c<='9') {
321: length = length*10 + c-'0';
322: }
323: while(c!='\n'&&c!=EOF) c=GETC(fin,frew,write); /* skip to end of line */
324:
325: switch (ed) {
326: case 'd':
327: copylines(line,delta);
328: /* skip over unwanted lines */
329: for (i=length;i>0;i--) {
330: /*skip next line*/
331: while ((c=getc(fedit))!='\n')
332: if (c==EOF)
333: faterror("EOF during edit");
334: editline++;
335: }
336: linecorr -= length;
337: break;
338: case 'a':
339: copylines(line+1,delta); /*copy only; no delete*/
340: for (i=length;i>0;i--) {
341: /*copy next line from script*/
342: if (delta!=nil)
343: VOID expandline(fin,fcopy,delta,true,write);
344: else {
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");
349: VOID putc(c,fcopy);
350: }
351: c = GETC(fin,frew,write);
352: }
353: }
354: }
355: linecorr += length;
356: break;
357: default:
358: faterror("unknown command in edit script: %c", ed);
359: break;
360: }
361: }
362: nextc=GETC(fin,frew,write);
363: }
364:
365:
366:
367: /* The rest is for keyword expansion */
368:
369:
370:
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.
379: */
380: {
381: register c;
382: register FILE * frew;
383: register w, ds;
384: register char * tp;
385: char keystring[keylength+2];
386: char keyval[keyvallength+2];
387: enum markers matchresult;
388:
389: frew = frewrite;
390: w = write;
391: ds = delimstuffed;
392: c=GETC(in,frew,w);
393: for (;;) {
394: if (c==EOF) {
395: if(ds) {
396: error("unterminated string");
397: nextc=c;
398: }
399: return(false);
400: }
401:
402: if (c==SDELIM && ds) {
403: if ((c=GETC(in,frew,w))!=SDELIM) {
404: /* end of string */
405: nextc=c;
406: return false;
407: }
408: }
409: VOID putc(c,out);
410:
411: if (c=='\n') return true; /* end of line */
412:
413: if (c==KDELIM) {
414: /* check for keyword */
415: /* first, copy a long enough string into keystring */
416: tp=keystring;
417: while (((c=GETC(in,frew,w))!=EOF) && (tp<keystring+keylength) && (c!='\n')
418: && (c!=SDELIM) && (c!=KDELIM) && (c!=VDELIM)) {
419: VOID putc(c,out);
420: *tp++ = c;
421: }
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*/
426:
427: /* Now we have a keyword terminated with a K/VDELIM */
428: if (c==VDELIM) {
429: /* try to find closing KDELIM, and replace value */
430: tp=keyval;
431: while (((c=GETC(in,frew,w)) != EOF)
432: && (c!='\n') && (c!=KDELIM) && (tp<keyval+keyvallength)) {
433: *tp++ =c;
434: if (c==SDELIM && ds) { /*skip next SDELIM */
435: c=GETC(in,frew,w);
436: /* Can't be at end of string.
437: /* always a \n before closing SDELIM */
438: }
439: }
440: if (c!=KDELIM) {
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 */
445: }
446: }
447: /* now put out the new keyword value */
448: keyreplace(matchresult,delta,out);
449: }
450: c=GETC(in,frew,w);
451: } /* end for */
452: }
453:
454:
455:
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.
460: */
461: {
462: char * date;
463: register char * sp;
464:
465: date= delta->date;
466:
467: switch (marker) {
468: case Author:
469: VOID fprintf(out,"%c %s %c",VDELIM,delta->author,KDELIM);
470: break;
471: case Date:
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);
475: break;
476: case Id:
477: case Header:
478: VOID putc(VDELIM,out); VOID putc(' ',out);
479: if (marker==Id)
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);
488: break;
489: case Locker:
490: VOID fprintf(out,"%c %s %c", VDELIM,
491: delta->lockedby==nil?"":delta->lockedby,KDELIM);
492: break;
493: case Log:
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*/
499: sp = delta->log;
500: while (*sp) if (putc(*sp++,out)=='\n') VOID fputs(Comment,out);
501: /* Comment is the comment leader */
502: break;
503: case RCSfile:
504: VOID fprintf(out,"%c %s %c",VDELIM,bindex(RCSfilename,'/'),KDELIM);
505: break;
506: case Revision:
507: VOID fprintf(out,"%c %s %c",VDELIM,delta->num,KDELIM);
508: break;
509: case Source:
510: VOID fprintf(out,"%c %s %c",VDELIM,getfullRCSname(),KDELIM);
511: break;
512: case State:
513: VOID fprintf(out,"%c %s %c",VDELIM,delta->state,KDELIM);
514: break;
515: case Nomatch:
516: VOID putc(KDELIM,out);
517: break;
518: }
519: }
520:
521:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.