/* * RCS stream editor */ static char rcsid[]= "$Header: rcsedit.c,v 3.8 86/05/15 02:15:43 lepreau Exp $ Purdue CS"; /********************************************************************************** * edits the input file according to a * script from stdin, generated by diff -n * performs keyword expansion ********************************************************************************** * * Copyright (C) 1982 by Walter F. Tichy * Purdue University * Computer Science Department * West Lafayette, IN 47907 * * All rights reserved. No part of this software may be sold or distributed * in any form or by any means without the prior written permission of the * author. * Report problems and direct all inquiries to Tichy@purdue (ARPA net). */ /* $Log: rcsedit.c,v $ * Revision 3.8 86/05/15 02:15:43 lepreau * Use "Locked" instead of state in $Head expansion if locked. * * Revision 3.7 83/05/12 13:04:39 wft * *** empty log message *** * * Revision 3.7 83/05/12 13:04:39 wft * Added retry to expandline to resume after failed match which ended in $. * Fixed truncation problem for $19chars followed by@@. * Log no longer expands full path of RCS file. * * Revision 3.5 82/12/04 13:20:56 wft * Added expansion of keyword Locker. * * Revision 3.4 82/12/03 12:26:54 wft * Added line number correction in case editing does not start at the * beginning of the file. * Changed keyword expansion to always print a space before closing KDELIM; * Expansion for Header shortened. * * Revision 3.3 82/11/14 14:49:30 wft * removed Suffix from keyword expansion. Replaced fclose with ffclose. * keyreplace() gets log message from delta, not from curlogmsg. * fixed expression overflow in while(c=putc(GETC.... * checked nil printing. * * Revision 3.2 82/10/18 21:13:39 wft * I added checks for write errors during the co process, and renamed * expandstring() to xpandstring(). * * Revision 3.1 82/10/13 15:52:55 wft * changed type of result of getc() from char to int. * made keyword expansion loop in expandline() portable to machines * without sign-extension. */ #include "rcsbase.h" extern FILE * fopen(); extern char * mktempfile(); extern FILE * finptr, * frewrite; extern int rewriteflag; extern int nextc; extern char * getfullRCSname(); extern char * RCSfilename; FILE * fcopy, * fedit; /* result and edit file descriptors */ char *resultfile = nil; /* result file name */ char * editfile = nil; /* edit file name */ int editline; /*line counter in fedit; starts with 1, is always #lines+1 */ int linecorr; /*contains #adds - #deletes in each edit run. */ /*used to correct editline in case file is not rewound after */ /* applying one delta */ initeditfiles(dir) char * dir; /* Function: Initializes resultfile and editfile with temporary filenames * in directory dir. Opens resultfile for reading and writing, with fcopy * as file descriptor. fedit is set to nil. */ { resultfile=mktempfile(dir,TMPFILE1); editfile =mktempfile(dir,TMPFILE2); fedit=nil; if ((fcopy=fopen(resultfile,"w+"))==NULL) { faterror("Can't open working file %s",resultfile); } } swapeditfiles(tostdout) /* Function: swaps resultfile and editfile, assigns fedit=fcopy, * rewinds fedit for reading, and opens resultfile for reading and * writing, using fcopy. If tostdout, fcopy is set to stdout. */ { char * tmpptr; if(ferror(fcopy)) faterror("write failed on %s -- file system full?",resultfile); fedit=fcopy; rewind(fedit); editline = 1; linecorr=0; tmpptr=editfile; editfile=resultfile; resultfile=tmpptr; if (tostdout) fcopy=stdout; elsif ((fcopy=fopen(resultfile,"w+"))==NULL) { faterror("Can't open working file %s",resultfile); } } finishedit(delta) struct hshentry * delta; /* copy the rest of the edit file and close it (if it exists). * if delta!=nil, perform keyword substitution at the same time. */ { register int c; if (fedit!=nil) { if (delta!=nil) { while (expandline(fedit,fcopy,delta,false,false)) editline++; } else { while((c=getc(fedit))!=EOF) { putc(c,fcopy); if (c=='\n') editline++; } } ffclose(fedit); } } copylines(line,delta) register int line; struct hshentry * delta; /* Function: copies input lines editline..line-1 from fedit to fcopy. * If delta != nil, keyword expansion is done simultaneously. * editline is updated. Rewinds a file only if necessary. */ { if (editline>line) { /* swap files */ finishedit(nil); swapeditfiles(false); /* assumes edit only during last pass, from the beginning*/ } while (editline0;i--) { /*skip next line*/ while ((c=getc(fedit))!='\n') if (c==EOF) faterror("EOF during edit"); editline++; } linecorr -= length; break; case 'a': copylines(line+1,delta); /*copy only; no delete*/ for (i=length;i>0;i--) { /*copy next line from script*/ if (delta!=nil) expandline(finptr,fcopy,delta,true,write); else { c = GETC(finptr,frewrite,write); while (putc(c,fcopy)!='\n'){ if ((c==SDELIM)&&((c=GETC(finptr,frewrite,write))!=SDELIM)){ serror("Missing string delimiter in edit script"); putc(c,fcopy); } c = GETC(finptr,frewrite,write); } } } linecorr += length; break; default: faterror("unknown command in edit script: %c", ed); break; } } nextc=GETC(finptr,frewrite,write); } /* The rest if for keyword expansion */ struct { char * keyword; enum markers marker;} markertable[] = {{AUTHOR, Author }, {DATE, Date }, {HEADER, Header }, {LOCKER, Locker }, {LOG, Log }, {REVISION, Revision}, {SOURCE, Source }, {STATE, State }, {nil, Nomatch }}; enum markers trymatch(string) char * string; /* function: Checks whether string is a keyword. * If so, returns the appropriate marker, otherwise Nomatch. */ { register int j; for (j=0; markertable[j].keyword!=nil; j++ ) { if (strcmp(string, markertable[j].keyword) ==0) return(markertable[j].marker); } return(Nomatch); } expandline(in, out, delta,delimstuffed,write) FILE * in, * out; struct hshentry * delta; register int delimstuffed, write; /* Function: Reads a line from in and writes it to out. * If delimstuffed==true, double SDELIM is replaced with single SDELIM. * Keyword expansion is performed with data from delta. * If write==true, the string is also copied unchanged to frewrite. * Returns false if end-of-string or end-of-line is detected, true otherwise. */ { register c, j; char keystring[keylength]; char keyval[keyvallength]; enum markers matchresult; for (;;) { c=GETC(in,frewrite,write); if (c==EOF) { if(delimstuffed) { error("unterminated string"); nextc=c; } return(false); } if (c==SDELIM && delimstuffed) { if ((c=GETC(in,frewrite,write))!=SDELIM) { /* end of string */ nextc=c; return false; } } putc(c,out); if (c=='\n') return true; /* end of line */ retry: if (c==KDELIM) { /* check for keyword */ /* first, copy a long enough string into keystring */ j=0; while (((c=GETC(in,frewrite,write))!=EOF) && (jdate; switch (marker) { case Author: fprintf(out,"%c %s %c",VDELIM,delta->author,KDELIM); break; case Date: putc(VDELIM,out);putc(' ',out); PRINTDATE(out,date);putc(' ',out); PRINTTIME(out,date);putc(' ',out);putc(KDELIM,out); break; case Header: fprintf(out,"%c %s %s ",VDELIM,bindex(RCSfilename,'/'), delta->num); PRINTDATE(out,date);putc(' ',out);PRINTTIME(out,date); if (delta->lockedby == nil) fprintf(out, " %s %s ", delta->author, delta->state); else fprintf(out," %s Locked ", delta->lockedby); putc(KDELIM, out); break; case Locker: fprintf(out,"%c %s %c", VDELIM, delta->lockedby==nil?"":delta->lockedby,KDELIM); break; case Log: fprintf(out, "%c\t%s %c\n%sRevision %s ", VDELIM, bindex(RCSfilename,'/'), KDELIM, Comment, delta->num); PRINTDATE(out,date);fputs(" ",out);PRINTTIME(out,date); fprintf(out, " %s\n%s",delta->author,Comment); /* do not include state here because it may change and is not updated*/ sp = delta->log; while (*sp) if (putc(*sp++,out)=='\n') fputs(Comment,out); /* Comment is the comment leader */ break; case Revision: fprintf(out,"%c %s %c",VDELIM,delta->num,KDELIM); break; case Source: fprintf(out,"%c %s %c",VDELIM,getfullRCSname(),KDELIM); break; case State: fprintf(out,"%c %s %c",VDELIM,delta->state,KDELIM); break; case Nomatch: putc(KDELIM,out); break; } }