/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred."
 *
 */
/* rcsgen.c */

#ident "$Header: rcsgen.c 1.3 89/10/10 $"

/*
 *                     RCS revision generation
 */
/*********************************************************************************
 *********************************************************************************
 *
 * 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:	rcsgen.c,v $
 */




#include "rcsbase.h"

extern struct hshentry * getnum();
extern char * mktemp();
extern FILE * fopen();
extern savestring();
extern struct hshentry * genrevs();
extern editstring();

extern int nextc;          /* next character from lexical analyzer          */
extern char * RCSfilename, * workfilename;
extern struct hshentry * targetdelta; /* delta to be generated              */
extern char * Ktext;       /* keywords from syntax analyzer                 */
extern char * Klog;        /* Keyword "log"                                 */
extern char * Kdesc;       /* Keyword for description                       */
extern FILE * finptr;      /* RCS input file                                */
extern FILE * frewrite;    /* new RCS file                                  */
extern FILE * fcopy;       /* result file during editing                    */
extern FILE * fedit;       /* edit file                                     */
extern char * resultfile, *editfile;/* file names for fcopy and fedit       */
extern int    rewriteflag; /* indicates whether to rewrite the input file   */


char    curlogmsg[logsize];/* buffer for current log message                */

enum stringwork {copy, edit, expand, edit_expand };
/* parameter to scandeltatext() */




char * buildrevision(deltas, target, dir, expandflag)
struct hshentry ** deltas, * target;
char * dir; int expandflag;
/* Function: Generates the revision given by target
 * by retrieving all deltas given by parameter deltas and combining them.
 * If dir==nil, the revision is printed on the standard output,
 * otherwise written into a temporary file in directory dir.
 * if expandflag==true, keyword expansion is performed.
 * returns false on errors, the name of the file with the revision otherwise.
 *
 * Algorithm: Copy inital revision unchanged. Then edit all revisions but
 * the last one into it, alternating input and output files (resultfile and
 * editfile). The last revision is then edited in, performing simultaneous
 * keyword substitution (this saves one extra pass).
 * All this simplifies if only one revision needs to be generated,
 * or no keyword expansion is necessary, or if output goes to stdout.
 */
{
        int i;

        if (deltas[0]==target) {
                /* only latest revision to generate */
                if (dir==nil) {/* print directly to stdout */
                        fcopy=stdout;
                        scandeltatext(target,expand);
                        return(char *) true;
                } else {
                        initeditfiles(dir);
                        scandeltatext(target,expandflag?expand:copy);
                        ffclose(fcopy);
                        return(resultfile);
                }
        } else {
                /* several revisions to generate */
                initeditfiles(dir?dir:"/tmp/");
                /* write initial revision into fcopy, no keyword expansion */
                scandeltatext(deltas[0],copy);
                i = 1;
                while (deltas[i+1] != nil) {
                        /* do all deltas except last one */
                        scandeltatext(deltas[i++],edit);
                }
                if (!expandflag) {
                        /* no keyword expansion; only invoked from ci */
                        scandeltatext(deltas[i],edit);
                        finishedit((struct hshentry *)nil);
                        ffclose(fcopy);
                } else {
                        /* perform keyword expansion*/
                        /* first, get to beginning of file*/
                        finishedit((struct hshentry *)nil); swapeditfiles(dir==nil);
                        scandeltatext(deltas[i],edit_expand);
                        finishedit(deltas[i]);
                        if (dir!=nil) ffclose(fcopy);
                }
                return(resultfile); /*doesn't matter for dir==nil*/
        }
}



scandeltatext(delta,func)
struct hshentry * delta; enum stringwork func;
/* Function: Scans delta text nodes up to and including the one given
 * by delta. For the one given by delta, the log message is saved into
 * curlogmsg and the text is processed according to parameter func.
 * Assumes the initial lexeme must be read in first.
 * Does not advance nexttok after it is finished.
 */
{       struct hshentry * nextdelta;

        do {
                nextlex();
                if (!(nextdelta=getnum())) {
                        fatserror("Can't find delta for revision %s", delta->num);
                }
                if (!getkey(Klog) || nexttok!=STRING)
                        serror("Missing log entry");
                elsif (delta==nextdelta) {
                        VOID savestring(curlogmsg,logsize);
                        delta->log=curlogmsg;
                } else {readstring();
                        delta->log= "";
                }
                nextlex();
                if (!getkey(Ktext) || nexttok!=STRING)
                        fatserror("Missing delta text");

                if(delta==nextdelta)
                        /* got the one we're looking for */
                        switch (func) {
                        case copy:      copystring();
                                        break;
                        case expand:    xpandstring(delta);
                                        break;
                        case edit:      editstring((struct hshentry *)nil);
                                        break;
                        case edit_expand: editstring(delta);
                                        break;
                        }
                else    readstring(); /* skip over it */

        } while (delta!=nextdelta);
}


int stdinread = 0; /* stdinread>0 if redirected stdin has been read once */

int putdesc(initflag,textflag,textfile,quietflag)
int initflag,textflag; char * textfile; int quietflag;
/* Function: puts the descriptive text into file frewrite.
 * if !initflag && !textflag, the text is simply copied from finptr.
 * Otherwise, if the textfile!=nil, the text is read from that
 * file, or from stdin, if textfile==nil.
 * Increments stdinread if text is read from redirected stdin.
 * if initflag&&quietflag&&!textflag, an empty text is inserted.
 * if !initflag, the old descriptive text is discarded.
 * Returns true is successful, false otherwise.
 */
{       FILE * txt; register int c, old1, old2;
#ifdef lint
	if (quietflag ==  0) initflag = quietflag; /* silencelint */
#endif	
        if (!initflag && !textflag) {
                /* copy old description */
                VOID fprintf(frewrite,"\n\n%s%c",Kdesc,nextc);
                rewriteflag=true; getdesc(false);
                return true;
        } else {
                /* get new description */
               if (!initflag) {
                        /*skip old description*/
                        rewriteflag=false; getdesc(false);
                }
                VOID fprintf(frewrite,"\n\n%s\n%c",Kdesc,SDELIM);
                if (textfile) {
                        old1='\n';
                        /* copy textfile */
                        if ((txt=fopen(textfile,"r"))!=NULL) {
                                while ((c=getc(txt))!=EOF) {
                                        if (c==SDELIM) VOID putc(c,frewrite); /*double up*/
                                        VOID putc(c,frewrite);
                                        old1=c;
                                }
                                if (old1!='\n') VOID putc('\n',frewrite);
                                VOID fclose(txt);
                                VOID putc(SDELIM,frewrite);
				VOID fputs("\n\n", frewrite);
                                return true;
                        } else {
                                error("Can't open file %s with description",textfile);
                                if (!isatty(fileno(stdin))) return false;
                                /* otherwise, get description from terminal */
                        }
                }
                /* read text from stdin */
                if (isatty(fileno(stdin))) {
                    VOID fputs("enter description, terminated with ^D or '.':\n",stderr);
                    VOID fputs("NOTE: This is NOT the log message!\n>> ",stderr);
		    if (feof(stdin))
		            clearerr(stdin);
                } else {  /* redirected stdin */
                    if (stdinread>0)
                        faterror("Can't reread redirected stdin for description; use -t<file>");
                    stdinread++;
                }
                c = '\0'; old2= '\n';
                if ((old1=getchar())==EOF) {
                        if (isatty(fileno(stdin))) {
                             VOID putc('\n',stderr);
                             clearerr(stdin);
			}
		} else {
		     if (old1=='\n' && isatty(fileno(stdin)))
			 VOID fputs(">> ",stderr);
		     for (;;) {
                            c=getchar();
                            if (c==EOF) {
                                    if (isatty(fileno(stdin))) {
                                            VOID putc('\n',stderr);
                                            clearerr(stdin);
				    }
                                    VOID putc(old1,frewrite);
                                    if (old1!='\n') VOID putc('\n',frewrite);
                                    break;
                            }
                            if (c=='\n' && old1=='.' && old2=='\n') {
                                    break;
                            }
                            if (c=='\n' && isatty(fileno(stdin))) VOID fputs(">> ",stderr);
                            if(old1==SDELIM) VOID putc(old1,frewrite); /* double up*/
                            VOID putc(old1,frewrite);
                            old2=old1;
                            old1=c;
                    } /* end for */
		}
                VOID putc(SDELIM,frewrite);VOID fputs("\n\n",frewrite);
                return true;
        }
}
