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