|
|
1.1 ! root 1: /* ! 2: * RCS stream editor ! 3: */ ! 4: static char rcsid[]= ! 5: "$Header: rcsedit.c,v 3.8 86/05/15 02:15:43 lepreau Exp $ Purdue CS"; ! 6: /********************************************************************************** ! 7: * edits the input file according to a ! 8: * script from stdin, generated by diff -n ! 9: * performs keyword expansion ! 10: ********************************************************************************** ! 11: * ! 12: * Copyright (C) 1982 by Walter F. Tichy ! 13: * Purdue University ! 14: * Computer Science Department ! 15: * West Lafayette, IN 47907 ! 16: * ! 17: * All rights reserved. No part of this software may be sold or distributed ! 18: * in any form or by any means without the prior written permission of the ! 19: * author. ! 20: * Report problems and direct all inquiries to Tichy@purdue (ARPA net). ! 21: */ ! 22: ! 23: ! 24: /* $Log: rcsedit.c,v $ ! 25: * Revision 3.8 86/05/15 02:15:43 lepreau ! 26: * Use "Locked" instead of state in $Head expansion if locked. ! 27: * ! 28: * Revision 3.7 83/05/12 13:04:39 wft ! 29: * *** empty log message *** ! 30: * ! 31: * Revision 3.7 83/05/12 13:04:39 wft ! 32: * Added retry to expandline to resume after failed match which ended in $. ! 33: * Fixed truncation problem for $19chars followed by@@. ! 34: * Log no longer expands full path of RCS file. ! 35: * ! 36: * Revision 3.5 82/12/04 13:20:56 wft ! 37: * Added expansion of keyword Locker. ! 38: * ! 39: * Revision 3.4 82/12/03 12:26:54 wft ! 40: * Added line number correction in case editing does not start at the ! 41: * beginning of the file. ! 42: * Changed keyword expansion to always print a space before closing KDELIM; ! 43: * Expansion for Header shortened. ! 44: * ! 45: * Revision 3.3 82/11/14 14:49:30 wft ! 46: * removed Suffix from keyword expansion. Replaced fclose with ffclose. ! 47: * keyreplace() gets log message from delta, not from curlogmsg. ! 48: * fixed expression overflow in while(c=putc(GETC.... ! 49: * checked nil printing. ! 50: * ! 51: * Revision 3.2 82/10/18 21:13:39 wft ! 52: * I added checks for write errors during the co process, and renamed ! 53: * expandstring() to xpandstring(). ! 54: * ! 55: * Revision 3.1 82/10/13 15:52:55 wft ! 56: * changed type of result of getc() from char to int. ! 57: * made keyword expansion loop in expandline() portable to machines ! 58: * without sign-extension. ! 59: */ ! 60: ! 61: ! 62: #include "rcsbase.h" ! 63: ! 64: ! 65: extern FILE * fopen(); ! 66: extern char * mktempfile(); ! 67: extern FILE * finptr, * frewrite; ! 68: extern int rewriteflag; ! 69: extern int nextc; ! 70: extern char * getfullRCSname(); ! 71: extern char * RCSfilename; ! 72: ! 73: ! 74: FILE * fcopy, * fedit; /* result and edit file descriptors */ ! 75: char *resultfile = nil; /* result file name */ ! 76: char * editfile = nil; /* edit file name */ ! 77: int editline; /*line counter in fedit; starts with 1, is always #lines+1 */ ! 78: int linecorr; /*contains #adds - #deletes in each edit run. */ ! 79: /*used to correct editline in case file is not rewound after */ ! 80: /* applying one delta */ ! 81: ! 82: initeditfiles(dir) ! 83: char * dir; ! 84: /* Function: Initializes resultfile and editfile with temporary filenames ! 85: * in directory dir. Opens resultfile for reading and writing, with fcopy ! 86: * as file descriptor. fedit is set to nil. ! 87: */ ! 88: { ! 89: resultfile=mktempfile(dir,TMPFILE1); ! 90: editfile =mktempfile(dir,TMPFILE2); ! 91: fedit=nil; ! 92: if ((fcopy=fopen(resultfile,"w+"))==NULL) { ! 93: faterror("Can't open working file %s",resultfile); ! 94: } ! 95: } ! 96: ! 97: ! 98: swapeditfiles(tostdout) ! 99: /* Function: swaps resultfile and editfile, assigns fedit=fcopy, ! 100: * rewinds fedit for reading, and opens resultfile for reading and ! 101: * writing, using fcopy. If tostdout, fcopy is set to stdout. ! 102: */ ! 103: { char * tmpptr; ! 104: if(ferror(fcopy)) ! 105: faterror("write failed on %s -- file system full?",resultfile); ! 106: fedit=fcopy; ! 107: rewind(fedit); ! 108: editline = 1; linecorr=0; ! 109: tmpptr=editfile; editfile=resultfile; resultfile=tmpptr; ! 110: if (tostdout) ! 111: fcopy=stdout; ! 112: elsif ((fcopy=fopen(resultfile,"w+"))==NULL) { ! 113: faterror("Can't open working file %s",resultfile); ! 114: } ! 115: } ! 116: ! 117: ! 118: finishedit(delta) ! 119: struct hshentry * delta; ! 120: /* copy the rest of the edit file and close it (if it exists). ! 121: * if delta!=nil, perform keyword substitution at the same time. ! 122: */ ! 123: { ! 124: register int c; ! 125: if (fedit!=nil) { ! 126: if (delta!=nil) { ! 127: while (expandline(fedit,fcopy,delta,false,false)) editline++; ! 128: } else { ! 129: while((c=getc(fedit))!=EOF) { ! 130: putc(c,fcopy); ! 131: if (c=='\n') editline++; ! 132: } ! 133: } ! 134: ffclose(fedit); ! 135: } ! 136: } ! 137: ! 138: ! 139: copylines(line,delta) ! 140: register int line; struct hshentry * delta; ! 141: /* Function: copies input lines editline..line-1 from fedit to fcopy. ! 142: * If delta != nil, keyword expansion is done simultaneously. ! 143: * editline is updated. Rewinds a file only if necessary. ! 144: */ ! 145: { ! 146: ! 147: if (editline>line) { ! 148: /* swap files */ ! 149: finishedit(nil); swapeditfiles(false); ! 150: /* assumes edit only during last pass, from the beginning*/ ! 151: } ! 152: while (editline<line) { ! 153: /*copy another line*/ ! 154: if (delta) ! 155: expandline(fedit,fcopy,delta,false,false); ! 156: else ! 157: while (putc(getc(fedit),fcopy)!='\n'); ! 158: editline++; ! 159: } ! 160: } ! 161: ! 162: ! 163: ! 164: xpandstring(delta) ! 165: struct hshentry * delta; ! 166: /* Function: Reads a string terminated by SDELIM from finptr and writes it ! 167: * to fcopy. Double SDELIM is replaced with single SDELIM. ! 168: * Keyword expansion is performed with data from delta. ! 169: * If rewriteflag==true, the string is also copied unchanged to frewrite. ! 170: * editline is updated. ! 171: */ ! 172: { ! 173: editline=1; ! 174: while (expandline(finptr,fcopy,delta,true,rewriteflag)) editline++; ! 175: nextc='\n'; ! 176: } ! 177: ! 178: ! 179: copystring() ! 180: /* Function: copies a string terminated with a single SDELIM from finptr to ! 181: * fcopy, replacing all double SDELIM with a single SDELIM. ! 182: * If rewriteflag==true, the string also copied unchanged to frewrite. ! 183: * editline is set to (number of lines copied)+1. ! 184: * Assumption: next character read is first string character. ! 185: */ ! 186: { register c, write; ! 187: write=rewriteflag; ! 188: editline=1; ! 189: while ((c=GETC(finptr,frewrite,write)) != EOF) { ! 190: if ((c==SDELIM)&&((c=GETC(finptr,frewrite,write)) != SDELIM)){ ! 191: /* end of string */ ! 192: nextc = c; ! 193: return; ! 194: } ! 195: putc(c,fcopy); ! 196: if (c=='\n') editline++; ! 197: } ! 198: nextc = c; ! 199: serror("Unterminated string"); ! 200: return; ! 201: } ! 202: ! 203: ! 204: ! 205: ! 206: editstring(delta) ! 207: struct hshentry * delta; ! 208: /* Function: reads an edit script from finptr and applies it to ! 209: * file fedit; the result is written to fcopy. ! 210: * If delta!=nil, keyword expansion is performed simultaneously. ! 211: * If frewrite==true, the edit script is also copied verbatim to frewrite. ! 212: * Assumes that all these files are open. ! 213: * If running out of lines in fedit, fedit and fcopy are swapped. ! 214: * resultfile and editfile are the names of the files that go with fcopy ! 215: * and fedit, respectively. ! 216: * Assumes the next input character from finptr is the first character of ! 217: * the edit script. Resets nextc on exit. ! 218: */ ! 219: { ! 220: int ed; /* editor command */ ! 221: register int c; ! 222: register int write, i; ! 223: int line, length; ! 224: ! 225: editline += linecorr; linecorr=0; /*correct line number*/ ! 226: write=rewriteflag; ! 227: for (;;) { ! 228: /* read next command and decode */ ! 229: /* assume next non-white character is command name*/ ! 230: while((ed=GETC(finptr,frewrite,write))=='\n'|| ! 231: ed==' ' || ed=='\t'); ! 232: if (ed==SDELIM) break; ! 233: /* now attempt to read numbers. */ ! 234: /* fscanf causes trouble because of the required echoing */ ! 235: while ((c=GETC(finptr,frewrite,write))==' '); /*skip spaces*/ ! 236: if (!('0'<=c && c<='9')) { ! 237: faterror("missing line number in edit script"); ! 238: break; ! 239: } ! 240: line= c -'0'; ! 241: while ('0'<=(c=GETC(finptr,frewrite,write)) && c<='9') { ! 242: line = line*10 + c-'0'; ! 243: } ! 244: while (c==' ') c=GETC(finptr,frewrite,write); ! 245: if (!('0'<=c && c<='9')) { ! 246: faterror("incorrect range in edit script"); ! 247: break; ! 248: } ! 249: length= c -'0'; ! 250: while ('0'<=(c=GETC(finptr,frewrite,write)) && c<='9') { ! 251: length = length*10 + c-'0'; ! 252: } ! 253: while(c!='\n'&&c!=EOF) c=GETC(finptr,frewrite,write); /* skip to end of line */ ! 254: ! 255: switch (ed) { ! 256: case 'd': ! 257: copylines(line,delta); ! 258: /* skip over unwanted lines */ ! 259: for (i=length;i>0;i--) { ! 260: /*skip next line*/ ! 261: while ((c=getc(fedit))!='\n') ! 262: if (c==EOF) ! 263: faterror("EOF during edit"); ! 264: editline++; ! 265: } ! 266: linecorr -= length; ! 267: break; ! 268: case 'a': ! 269: copylines(line+1,delta); /*copy only; no delete*/ ! 270: for (i=length;i>0;i--) { ! 271: /*copy next line from script*/ ! 272: if (delta!=nil) ! 273: expandline(finptr,fcopy,delta,true,write); ! 274: else { ! 275: c = GETC(finptr,frewrite,write); ! 276: while (putc(c,fcopy)!='\n'){ ! 277: if ((c==SDELIM)&&((c=GETC(finptr,frewrite,write))!=SDELIM)){ ! 278: serror("Missing string delimiter in edit script"); ! 279: putc(c,fcopy); ! 280: } ! 281: c = GETC(finptr,frewrite,write); ! 282: } ! 283: } ! 284: } ! 285: linecorr += length; ! 286: break; ! 287: default: ! 288: faterror("unknown command in edit script: %c", ed); ! 289: break; ! 290: } ! 291: } ! 292: nextc=GETC(finptr,frewrite,write); ! 293: } ! 294: ! 295: ! 296: ! 297: /* The rest if for keyword expansion */ ! 298: ! 299: struct { char * keyword; enum markers marker;} markertable[] = ! 300: {{AUTHOR, Author }, ! 301: {DATE, Date }, ! 302: {HEADER, Header }, ! 303: {LOCKER, Locker }, ! 304: {LOG, Log }, ! 305: {REVISION, Revision}, ! 306: {SOURCE, Source }, ! 307: {STATE, State }, ! 308: {nil, Nomatch }}; ! 309: ! 310: enum markers trymatch(string) ! 311: char * string; ! 312: /* function: Checks whether string is a keyword. ! 313: * If so, returns the appropriate marker, otherwise Nomatch. ! 314: */ ! 315: { ! 316: register int j; ! 317: for (j=0; markertable[j].keyword!=nil; j++ ) { ! 318: if (strcmp(string, markertable[j].keyword) ==0) ! 319: return(markertable[j].marker); ! 320: } ! 321: return(Nomatch); ! 322: } ! 323: ! 324: ! 325: ! 326: expandline(in, out, delta,delimstuffed,write) ! 327: FILE * in, * out; struct hshentry * delta; ! 328: register int delimstuffed, write; ! 329: /* Function: Reads a line from in and writes it to out. ! 330: * If delimstuffed==true, double SDELIM is replaced with single SDELIM. ! 331: * Keyword expansion is performed with data from delta. ! 332: * If write==true, the string is also copied unchanged to frewrite. ! 333: * Returns false if end-of-string or end-of-line is detected, true otherwise. ! 334: */ ! 335: { ! 336: register c, j; ! 337: char keystring[keylength]; ! 338: char keyval[keyvallength]; ! 339: enum markers matchresult; ! 340: ! 341: for (;;) { ! 342: c=GETC(in,frewrite,write); ! 343: if (c==EOF) { ! 344: if(delimstuffed) { ! 345: error("unterminated string"); ! 346: nextc=c; ! 347: } ! 348: return(false); ! 349: } ! 350: ! 351: if (c==SDELIM && delimstuffed) { ! 352: if ((c=GETC(in,frewrite,write))!=SDELIM) { ! 353: /* end of string */ ! 354: nextc=c; ! 355: return false; ! 356: } ! 357: } ! 358: putc(c,out); ! 359: ! 360: if (c=='\n') return true; /* end of line */ ! 361: ! 362: retry: if (c==KDELIM) { ! 363: /* check for keyword */ ! 364: /* first, copy a long enough string into keystring */ ! 365: j=0; ! 366: while (((c=GETC(in,frewrite,write))!=EOF) && (j<keylength-1) && (c!='\n') ! 367: && (c!=KDELIM) && (c!=VDELIM)) { ! 368: putc(c,out); ! 369: keystring[j++] = c; ! 370: if (c==SDELIM && delimstuffed) { /*skip next SDELIM */ ! 371: c=GETC(in,frewrite,write); ! 372: /* Can't be at end of string -- always a '\n' before*/ ! 373: /* closing SDELIM */ ! 374: } ! 375: } ! 376: if (!((c==KDELIM) || (c==VDELIM))) { ! 377: /* no match */ ! 378: /* can get SDELIM here if have $...keylength-1 chars...@@ */ ! 379: if (c==SDELIM && delimstuffed) { ! 380: c=GETC(in,frewrite,write); ! 381: } ! 382: putc(c,out); ! 383: if (c=='\n') return true; /* end of line */ ! 384: } else { ! 385: /* no we have something that looks like a */ ! 386: /* keyword, and is terminated with K/VDELIM*/ ! 387: keystring[j]= '\0'; ! 388: if ((matchresult=trymatch(keystring))==Nomatch) { ! 389: /* no match */ ! 390: putc(c,out); ! 391: if (c==KDELIM) goto retry; ! 392: } elsif (c==VDELIM) { ! 393: /* try to find closing KDELIM, and replace value */ ! 394: j=0; ! 395: while (((c=GETC(in,frewrite,write)) != EOF) ! 396: && (c!='\n') && (c!=KDELIM) && (j<keyvallength-2)) { ! 397: keyval[j++] =c; ! 398: if (c==SDELIM && delimstuffed) { /*skip next SDELIM */ ! 399: c=GETC(in,frewrite,write); ! 400: /* Can't be at end of string -- always a '\n' before*/ ! 401: /* closing SDELIM */ ! 402: } ! 403: } ! 404: keyval[j++] =c; ! 405: if (c!=KDELIM) { ! 406: /* couldn't find closing KDELIM -- give up */ ! 407: putc(VDELIM,out); keyval[j]='\0';fputs(keyval,out); ! 408: if (c=='\n') return true; /* end of line */ ! 409: } else { ! 410: /* found complete pattern -- replace */ ! 411: keyreplace(matchresult,delta,out); ! 412: } ! 413: } else { ! 414: /* string of the form $keyword$ */ ! 415: keyreplace(matchresult,delta,out); ! 416: } ! 417: } ! 418: } ! 419: } /* end for */ ! 420: } ! 421: ! 422: ! 423: ! 424: keyreplace(marker,delta,out) ! 425: enum markers marker; struct hshentry * delta; FILE * out; ! 426: /* function: ouputs the keyword value(s) corresponding to marker. ! 427: * Attributes are derived from delta. ! 428: */ ! 429: { ! 430: char * date; ! 431: register char * sp; ! 432: ! 433: date= delta->date; ! 434: ! 435: switch (marker) { ! 436: case Author: ! 437: fprintf(out,"%c %s %c",VDELIM,delta->author,KDELIM); ! 438: break; ! 439: case Date: ! 440: putc(VDELIM,out);putc(' ',out); ! 441: PRINTDATE(out,date);putc(' ',out); ! 442: PRINTTIME(out,date);putc(' ',out);putc(KDELIM,out); ! 443: break; ! 444: case Header: ! 445: fprintf(out,"%c %s %s ",VDELIM,bindex(RCSfilename,'/'), ! 446: delta->num); ! 447: PRINTDATE(out,date);putc(' ',out);PRINTTIME(out,date); ! 448: if (delta->lockedby == nil) ! 449: fprintf(out, " %s %s ", delta->author, delta->state); ! 450: else ! 451: fprintf(out," %s Locked ", delta->lockedby); ! 452: putc(KDELIM, out); ! 453: break; ! 454: case Locker: ! 455: fprintf(out,"%c %s %c", VDELIM, ! 456: delta->lockedby==nil?"":delta->lockedby,KDELIM); ! 457: break; ! 458: case Log: ! 459: fprintf(out, "%c\t%s %c\n%sRevision %s ", ! 460: VDELIM, bindex(RCSfilename,'/'), KDELIM, Comment, delta->num); ! 461: PRINTDATE(out,date);fputs(" ",out);PRINTTIME(out,date); ! 462: fprintf(out, " %s\n%s",delta->author,Comment); ! 463: /* do not include state here because it may change and is not updated*/ ! 464: sp = delta->log; ! 465: while (*sp) if (putc(*sp++,out)=='\n') fputs(Comment,out); ! 466: /* Comment is the comment leader */ ! 467: break; ! 468: case Revision: ! 469: fprintf(out,"%c %s %c",VDELIM,delta->num,KDELIM); ! 470: break; ! 471: case Source: ! 472: fprintf(out,"%c %s %c",VDELIM,getfullRCSname(),KDELIM); ! 473: break; ! 474: case State: ! 475: fprintf(out,"%c %s %c",VDELIM,delta->state,KDELIM); ! 476: break; ! 477: case Nomatch: ! 478: putc(KDELIM,out); ! 479: break; ! 480: } ! 481: } ! 482: ! 483:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.