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: }

Defined functions

copylines defined in line 139; used 2 times
copystring defined in line 179; used 2 times
editstring defined in line 206; used 4 times
expandline defined in line 326; used 5 times
finishedit defined in line 118; used 6 times
initeditfiles defined in line 82; used 3 times
keyreplace defined in line 424; used 2 times
swapeditfiles defined in line 98; used 3 times
trymatch defined in line 310; used 1 times
xpandstring defined in line 164; used 1 times

Defined variables

editfile defined in line 76; used 3 times
editline defined in line 77; used 12 times
linecorr defined in line 78; used 5 times
rcsid defined in line 4; never used
resultfile defined in line 75; used 12 times
Last modified: 1986-05-15
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1182
Valid CSS Valid XHTML 1.0 Strict