1: /* 2: * RCS revision generation 3: */ 4: static char rcsid[]= 5: "$Header: rcsgen.c,v 3.4 86/05/15 02:18:42 lepreau Exp $ Purdue CS"; 6: /********************************************************************************* 7: ********************************************************************************* 8: * 9: * Copyright (C) 1982 by Walter F. Tichy 10: * Purdue University 11: * Computer Science Department 12: * West Lafayette, IN 47907 13: * 14: * All rights reserved. No part of this software may be sold or distributed 15: * in any form or by any means without the prior written permission of the 16: * author. 17: * Report problems and direct all inquiries to Tichy@purdue (ARPA net). 18: */ 19: 20: 21: /* $Log: rcsgen.c,v $ 22: * Revision 3.4 86/05/15 02:18:42 lepreau 23: * Fix immediate EOF from non-tty files: avoid 0377's in description. 24: * 25: * Revision 3.3 82/11/28 21:36:49 wft 26: * *** empty log message *** 27: * 28: * Revision 3.3 82/11/28 21:36:49 wft 29: * Replaced ferror() followed by fclose() with ffclose(). 30: * Putdesc() now suppresses the prompts if stdin 31: * is not a terminal. A pointer to the current log message is now 32: * inserted into the corresponding delta, rather than leaving it in a 33: * global variable. 34: * 35: * Revision 3.2 82/10/18 21:11:26 wft 36: * I added checks for write errors during editing, and improved 37: * the prompt on putdesc(). 38: * 39: * Revision 3.1 82/10/13 15:55:09 wft 40: * corrected type of variables assigned to by getc (char --> int) 41: */ 42: 43: 44: 45: 46: #include "rcsbase.h" 47: 48: extern struct hshentry * getnum(); 49: extern char * mktemp(); 50: extern FILE * fopen(); 51: extern savestring(); 52: extern struct hshentry * genrevs(); 53: extern editstring(); 54: 55: extern int nextc; /* next character from lexical analyzer */ 56: extern char * RCSfilename, * workfilename; 57: extern struct hshentry * targetdelta; /* delta to be generated */ 58: extern char * Ktext; /* keywords from syntax analyzer */ 59: extern char * Klog; /* Keyword "log" */ 60: extern char * Kdesc; /* Keyword for description */ 61: extern FILE * finptr; /* RCS input file */ 62: extern FILE * frewrite; /* new RCS file */ 63: extern FILE * fcopy; /* result file during editing */ 64: extern FILE * fedit; /* edit file */ 65: extern char * resultfile, *editfile;/* file names for fcopy and fedit */ 66: extern int rewriteflag; /* indicates whether to rewrite the input file */ 67: 68: 69: char curlogmsg[logsize] /* buffer for current log message */ 70: ='\0'; 71: 72: enum stringwork {copy, edit, expand, edit_expand }; 73: /* parameter to scandeltatext() */ 74: 75: 76: 77: 78: char * buildrevision(deltas, target, dir, expandflag) 79: struct hshentry ** deltas, * target; 80: char * dir; int expandflag; 81: /* Function: Generates the revision given by target 82: * by retrieving all deltas given by parameter deltas and combining them. 83: * If dir==nil, the revision is printed on the standard output, 84: * otherwise written into a temporary file in directory dir. 85: * if expandflag==true, keyword expansion is performed. 86: * returns false on errors, the name of the file with the revision otherwise. 87: * 88: * Algorithm: Copy inital revision unchanged. Then edit all revisions but 89: * the last one into it, alternating input and output files (resultfile and 90: * editfile). The last revision is then edited in, performing simultaneous 91: * keyword substitution (this saves one extra pass). 92: * All this simplifies if only one revision needs to be generated, 93: * or no keyword expansion is necessary, or if output goes to stdout. 94: */ 95: { 96: int i; 97: 98: if (deltas[0]==target) { 99: /* only latest revision to generate */ 100: if (dir==nil) {/* print directly to stdout */ 101: fcopy=stdout; 102: scandeltatext(target,expand); 103: return(char *) true; 104: } else { 105: initeditfiles(dir); 106: scandeltatext(target,expandflag?expand:copy); 107: ffclose(fcopy); 108: return(resultfile); 109: } 110: } else { 111: /* several revisions to generate */ 112: initeditfiles(dir?dir:"/tmp/"); 113: /* write initial revision into fcopy, no keyword expansion */ 114: scandeltatext(deltas[0],copy); 115: i = 1; 116: while (deltas[i+1] != nil) { 117: /* do all deltas except last one */ 118: scandeltatext(deltas[i++],edit); 119: } 120: if (!expandflag) { 121: /* no keyword expansion; only invoked from ci */ 122: scandeltatext(deltas[i],edit); 123: finishedit(nil); 124: ffclose(fcopy); 125: } else { 126: /* perform keyword expansion*/ 127: /* first, get to beginning of file*/ 128: finishedit(nil); swapeditfiles(dir==nil); 129: scandeltatext(deltas[i],edit_expand); 130: finishedit(deltas[i]); 131: if (dir!=nil) ffclose(fcopy); 132: } 133: return(resultfile); /*doesn't matter for dir==nil*/ 134: } 135: } 136: 137: 138: 139: scandeltatext(delta,func) 140: struct hshentry * delta; enum stringwork func; 141: /* Function: Scans delta text nodes up to and including the one given 142: * by delta. For the one given by delta, the log message is saved into 143: * curlogmsg and the text is processed according to parameter func. 144: * Assumes the initial lexeme must be read in first. 145: * Does not advance nexttok after it is finished. 146: */ 147: { struct hshentry * nextdelta; 148: 149: do { 150: nextlex(); 151: if (!(nextdelta=getnum())) { 152: fatserror("Can't find delta for revision %s", delta->num); 153: } 154: if (!getkey(Klog) || nexttok!=STRING) 155: serror("Missing log entry"); 156: elsif (delta==nextdelta) { 157: savestring(curlogmsg,logsize); 158: delta->log=curlogmsg; 159: } else {readstring(); 160: delta->log= ""; 161: } 162: nextlex(); 163: if (!getkey(Ktext) || nexttok!=STRING) 164: fatserror("Missing delta text"); 165: 166: if(delta==nextdelta) 167: /* got the one we're looking for */ 168: switch (func) { 169: case copy: copystring(); 170: break; 171: case expand: xpandstring(delta); 172: break; 173: case edit: editstring(nil); 174: break; 175: case edit_expand: editstring(delta); 176: break; 177: } 178: else readstring(); /* skip over it */ 179: 180: } while (delta!=nextdelta); 181: } 182: 183: 184: int putdesc(initflag,textflag,textfile,quietflag) 185: int initflag,textflag; char * textfile; int quietflag; 186: /* Function: puts the descriptive text into file frewrite. 187: * if !initflag && !textflag, the text is simply copied from finptr. 188: * Otherwise, if the textfile!=nil, the text is read from that 189: * file, or from stdin, if textfile==nil. 190: * if initflag&&quietflag&&!textflag, an empty text is inserted. 191: * if !initflag, the old descriptive text is discarded. 192: * Returns true is successful, false otherwise. 193: */ 194: { FILE * txt; register int c, old1, old2; 195: 196: if (!initflag && !textflag) { 197: /* copy old description */ 198: fprintf(frewrite,"\n\n%s%c",Kdesc,nextc); 199: rewriteflag=true; getdesc(false); 200: return true; 201: } else { 202: /* get new description */ 203: if (!initflag) { 204: /*skip old description*/ 205: rewriteflag=false; getdesc(false); 206: } 207: fprintf(frewrite,"\n\n%s\n%c",Kdesc,SDELIM); 208: if (textfile) { 209: old1='\n'; 210: /* copy textfile */ 211: if ((txt=fopen(textfile,"r"))!=NULL) { 212: while ((c=getc(txt))!=EOF) { 213: if (c==SDELIM) putc(c,frewrite); /*double up*/ 214: putc(c,frewrite); 215: old1=c; 216: } 217: if (old1!='\n') putc('\n',frewrite); 218: fclose(txt); 219: putc(SDELIM,frewrite);fputs("\n\n", frewrite); 220: return true; 221: } else { 222: error("Can't open file with description%s",textfile); 223: } 224: } 225: if (initflag&&quietflag) { 226: warn("empty descriptive text"); 227: putc(SDELIM,frewrite);fputs("\n\n", frewrite); 228: return true; 229: } 230: /* read text from stdin */ 231: if (isatty(fileno(stdin))) { 232: fputs("enter description, terminated with ^D or '.':\n",stdout); 233: fputs("NOTE: This is NOT the log message!\n>> ",stdout); 234: } 235: c = '\0'; old2= '\n'; 236: if ((old1=getchar())==EOF) { 237: if (isatty(fileno(stdin))) { 238: putc('\n',stdout); 239: clearerr(stdin); 240: } 241: } 242: else for (;;) { 243: c=getchar(); 244: if (c==EOF) { 245: if (isatty(fileno(stdin))) { 246: putc('\n',stdout); 247: clearerr(stdin); 248: } 249: putc(old1,frewrite); 250: if (old1!='\n') putc('\n',frewrite); 251: break; 252: } 253: if (c=='\n' && old1=='.' && old2=='\n') { 254: break; 255: } 256: if (c=='\n' && isatty(fileno(stdin))) fputs(">> ",stdout); 257: if(old1==SDELIM) putc(old1,frewrite); /* double up*/ 258: putc(old1,frewrite); 259: old2=old1; 260: old1=c; 261: } /* end for */ 262: putc(SDELIM,frewrite);fputs("\n\n",frewrite); 263: return true; 264: } 265: }