|
|
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.