[The attached e-mail message describes line-level accounting in RCS-5.6. Paul Eggert (the RCS maintainer) has the patches, but they haven't made it into recent releases. If you want them in a real realease, send him mail. If someone applies these patches to a more recent version of RCS, please take a new patch and forward it to me (and maybe Paul :-). My e-mail address is now johnh@isi.edu. - John, 11-Mar-96.] ---------------------------------------------------------------------- To: eggert@twinsun.com Subject: rcs patch to do line-level accounting Date: Fri, 02 Apr 1993 22:05:03 -0800 From: John Heidemann Enclosed is a patch to rcs-5.6 to do line-level accounting. I did things as a patch to co--- "co -t -p filename" now shows tags as we discussed. Most of the new code is in rcstag.c. I had to make a few changes to other modules, mostly making static variables (like the line list) extern'able. You may want to shift the code around so these changes are no longer necessary. The basic strategy I took to solve the problem was to apply the algorithm in rcsedit, but rather than working on a list of lines, I manipulate a list of line version numbers. I wasn't quite sure how to deal with the "#ifdef !large_memory", so I ignored the problem. It's not clear to me what kind of memory constraint is implied by this def (other than perhaps PC-style constraints). If this means that one cannot maintain a long per file line in main memory then my algorithm will need changing. Let me know what you think. -John ---------------------------------------------------------------------- (You may need to do a "touch rcstag.c" before applying the patch.) =================================================================== RCS file: RCS/Makefile,v retrieving revision 1.1 retrieving revision 1.3 diff -c -r1.1 -r1.3 *** Makefile- 1993/03/25 01:36:45 --- Makefile 1993/04/03 03:05:41 *************** *** 1,4 **** ! # $Id: Makefile,v 1.1 1993/03/25 01:36:45 johnh Exp $ # Copyright (C) 1982, 1988, 1989 Walter Tichy # Copyright 1990, 1991 by Paul Eggert # Distributed under license by the Free Software Foundation, Inc. --- 1,4 ---- ! # $Id: Makefile,v 1.3 1993/04/03 03:05:41 johnh Exp $ # Copyright (C) 1982, 1988, 1989 Walter Tichy # Copyright 1990, 1991 by Paul Eggert # Distributed under license by the Free Software Foundation, Inc. *************** *** 178,190 **** #) ci = ci$o rcslex$o rcssyn$o rcsgen$o rcsedit$o rcskeys$o rcsmap$o \ ! rcsrev$o rcsutil$o rcsfnms$o partime$o maketime$o rcskeep$o \ rcsfcmp$o $(OTHER_OBJECT) ci$x : $(ci) $(LINK) $(ci) $(LDLIBS) -o $@ co = co$o rcslex$o rcssyn$o rcsgen$o rcsedit$o rcskeys$o rcsmap$o \ ! rcsrev$o rcsutil$o rcsfnms$o partime$o maketime$o rcskeep$o $(OTHER_OBJECT) co$x : $(co) $(LINK) $(co) $(LDLIBS) -o $@ --- 178,191 ---- #) ci = ci$o rcslex$o rcssyn$o rcsgen$o rcsedit$o rcskeys$o rcsmap$o \ ! rcsrev$o rcsutil$o rcsfnms$o partime$o maketime$o rcskeep$o rcstag$o \ rcsfcmp$o $(OTHER_OBJECT) ci$x : $(ci) $(LINK) $(ci) $(LDLIBS) -o $@ co = co$o rcslex$o rcssyn$o rcsgen$o rcsedit$o rcskeys$o rcsmap$o \ ! rcsrev$o rcsutil$o rcsfnms$o partime$o maketime$o rcskeep$o rcstag$o \ ! $(OTHER_OBJECT) co$x : $(co) $(LINK) $(co) $(LDLIBS) -o $@ *************** *** 204,210 **** $(LINK) $(rlog) $(LDLIBS) -o $@ rcs = rcs$o rcslex$o rcssyn$o rcsrev$o rcsutil$o rcsgen$o rcsedit$o rcskeys$o \ ! rcsmap$o rcsfnms$o rcskeep$o $(OTHER_OBJECT) rcs$x : $(rcs) $(LINK) $(rcs) $(LDLIBS) -o $@ --- 205,211 ---- $(LINK) $(rlog) $(LDLIBS) -o $@ rcs = rcs$o rcslex$o rcssyn$o rcsrev$o rcsutil$o rcsgen$o rcsedit$o rcskeys$o \ ! rcsmap$o rcsfnms$o rcskeep$o rcstag$o $(OTHER_OBJECT) rcs$x : $(rcs) $(LINK) $(rcs) $(LDLIBS) -o $@ *************** *** 230,236 **** OBJECT= ci$o co$o ident$o maketime$o merge$o merger$o partime$o rcs$o \ rcsclean$o rcsdiff$o rcsedit$o rcsfcmp$o rcsfnms$o rcsgen$o \ rcskeep$o rcskeys$o rcslex$o rcsmap$o rcsmerge$o rcsrev$o rcssyn$o \ ! rcsutil$o rlog$o lint :: conf.h $(LINT) $(CC_D) -Dlint=1 $(SOURCE) --- 231,238 ---- OBJECT= ci$o co$o ident$o maketime$o merge$o merger$o partime$o rcs$o \ rcsclean$o rcsdiff$o rcsedit$o rcsfcmp$o rcsfnms$o rcsgen$o \ rcskeep$o rcskeys$o rcslex$o rcsmap$o rcsmerge$o rcsrev$o rcssyn$o \ ! rcsutil$o rlog$o \ ! rcsedit$o lint :: conf.h $(LINT) $(CC_D) -Dlint=1 $(SOURCE) =================================================================== RCS file: RCS/co.c,v retrieving revision 1.1 retrieving revision 1.2 diff -c -r1.1 -r1.2 *** co.c- 1993/03/25 01:36:45 --- co.c 1993/03/26 01:52:55 *************** *** 34,41 **** /* $Log: co.c,v $ ! * Revision 1.1 1993/03/25 01:36:45 johnh ! * Initial revision * * Revision 5.9 1991/10/07 17:32:46 eggert * ci -u src/RCS/co.c,v src/co.c <<\. --- 34,41 ---- /* $Log: co.c,v $ ! * Revision 1.2 1993/03/26 01:52:55 johnh ! * patches for tagging * * Revision 5.9 1991/10/07 17:32:46 eggert * ci -u src/RCS/co.c,v src/co.c <<\. *************** *** 163,173 **** static int lastjoin; /* index of last element in joinlist */ static int lockflag; /* -1 -> unlock, 0 -> do nothing, 1 -> lock */ static int mtimeflag; static struct hshentries *gendeltas; /* deltas to be generated */ static struct hshentry *targetdelta; /* final delta to be generated */ static struct stat workstat; ! mainProg(coId, "co", "$Id: co.c,v 1.1 1993/03/25 01:36:45 johnh Exp $") { static char const cmdusage[] = "\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ..."; --- 163,174 ---- static int lastjoin; /* index of last element in joinlist */ static int lockflag; /* -1 -> unlock, 0 -> do nothing, 1 -> lock */ static int mtimeflag; + extern int taglinesflag; /* Boolean: tag lines with their version */ static struct hshentries *gendeltas; /* deltas to be generated */ static struct hshentry *targetdelta; /* final delta to be generated */ static struct stat workstat; ! mainProg(coId, "co", "$Id: co.c,v 1.2 1993/03/26 01:52:55 johnh Exp $") { static char const cmdusage[] = "\nco usage: co -{flpqru}[rev] -ddate -jjoinlist -sstate -w[login] -Vn file ..."; *************** *** 273,278 **** --- 274,283 ---- setRCSversion(versionarg); break; + case 't': + taglinesflag = true; + break; + case 'k': /* set keyword expand mode */ expandarg = *argv; if (0 <= expmode) redefined('k'); *************** *** 392,398 **** getdesc(false); /* don't echo*/ locker_expansion = 0 < lockflag; ! joinfilename = buildrevision( gendeltas, targetdelta, join&&tostdout ? (FILE*)0 : neworkptr, Expand!=OLD_EXPAND --- 397,409 ---- getdesc(false); /* don't echo*/ locker_expansion = 0 < lockflag; ! if (taglinesflag) ! joinfilename = buildtaggedrevision( ! gendeltas, targetdelta, ! join&&tostdout ? (FILE*)0 : neworkptr, ! Expand!=OLD_EXPAND ! ); ! else joinfilename = buildrevision( gendeltas, targetdelta, join&&tostdout ? (FILE*)0 : neworkptr, Expand!=OLD_EXPAND =================================================================== RCS file: RCS/rcsbase.h,v retrieving revision 1.1 retrieving revision 1.2 diff -c -r1.1 -r1.2 *** rcsbase.h- 1993/03/25 01:36:45 --- rcsbase.h 1993/03/26 01:52:55 *************** *** 2,8 **** /* * RCS common definitions and data structures */ ! #define RCSBASE "$Id: rcsbase.h,v 1.1 1993/03/25 01:36:45 johnh Exp $" /* Copyright (C) 1982, 1988, 1989 Walter Tichy Copyright 1990, 1991 by Paul Eggert --- 2,8 ---- /* * RCS common definitions and data structures */ ! #define RCSBASE "$Id: rcsbase.h,v 1.2 1993/03/26 01:52:55 johnh Exp $" /* Copyright (C) 1982, 1988, 1989 Walter Tichy Copyright 1990, 1991 by Paul Eggert *************** *** 43,50 **** /* $Log: rcsbase.h,v $ ! * Revision 1.1 1993/03/25 01:36:45 johnh ! * Initial revision * * Revision 5.11 1991/10/07 17:32:46 eggert * Support piece tables even if !has_mmap. --- 43,50 ---- /* $Log: rcsbase.h,v $ ! * Revision 1.2 1993/03/26 01:52:55 johnh ! * patches for tagging * * Revision 5.11 1991/10/07 17:32:46 eggert * Support piece tables even if !has_mmap. *************** *** 432,437 **** --- 432,438 ---- void copystring P((void)); void dirtempunlink P((void)); void enterstring P((void)); + void tagenterstring P((void)); void finishedit P((struct hshentry const*,FILE*,int)); void keepdirtemp P((char const*)); void openfcopy P((FILE*)); *************** *** 445,452 **** --- 446,456 ---- #if large_memory void edit_string P((void)); # define editstring(delta) edit_string() + void tag_edit_string P((void)); + # define tageditstring(delta) tag_edit_string() #else void editstring P((struct hshentry const*)); + void tageditstring P((struct hshentry const*)); #endif /* rcsfcmp */ =================================================================== RCS file: RCS/rcsedit.c,v retrieving revision 1.1 retrieving revision 1.2 diff -c -r1.1 -r1.2 *** rcsedit.c- 1993/03/25 01:36:45 --- rcsedit.c 1993/03/26 01:52:55 *************** *** 36,43 **** /* $Log: rcsedit.c,v $ ! * Revision 1.1 1993/03/25 01:36:45 johnh ! * Initial revision * * Revision 5.11 1991/11/03 01:11:44 eggert * Move the warning about link breaking to where they're actually being broken. --- 36,43 ---- /* $Log: rcsedit.c,v $ ! * Revision 1.2 1993/03/26 01:52:55 johnh ! * patches for tagging * * Revision 5.11 1991/11/03 01:11:44 eggert * Move the warning about link breaking to where they're actually being broken. *************** *** 157,163 **** #include "rcsbase.h" ! libId(editId, "$Id: rcsedit.c,v 1.1 1993/03/25 01:36:45 johnh Exp $") static void keyreplace P((enum markers,struct hshentry const*,FILE*)); --- 157,163 ---- #include "rcsbase.h" ! libId(editId, "$Id: rcsedit.c,v 1.2 1993/03/26 01:52:55 johnh Exp $") static void keyreplace P((enum markers,struct hshentry const*,FILE*)); *************** *** 287,294 **** * Any @s in lines are duplicated. * Lines are terminated by \n, or (for a last partial line only) by single @. */ ! static Iptr_type *line; ! static unsigned long gap, gapsize, linelim; static void --- 287,294 ---- * Any @s in lines are duplicated. * Lines are terminated by \n, or (for a last partial line only) by single @. */ ! Iptr_type *line; ! unsigned long gap, gapsize, linelim; static void *************** *** 781,787 **** /* The rest is for keyword expansion */ - int --- 781,786 ---- =================================================================== RCS file: RCS/rcsgen.c,v retrieving revision 1.1 retrieving revision 1.3 diff -c -r1.1 -r1.3 *** rcsgen.c- 1993/03/25 01:36:45 --- rcsgen.c 1993/04/03 03:05:41 *************** *** 31,39 **** /* $Log: rcsgen.c,v $ ! * Revision 1.1 1993/03/25 01:36:45 johnh ! * Initial revision * * Revision 5.10 1991/10/07 17:32:46 eggert * Fix log bugs, e.g. ci -t/dev/null when has_mmap. * --- 31,42 ---- /* $Log: rcsgen.c,v $ ! * Revision 1.3 1993/04/03 03:05:41 johnh ! * a cleaned up version * + * Revision 1.2 1993/03/26 01:52:55 johnh + * patches for tagging + * * Revision 5.10 1991/10/07 17:32:46 eggert * Fix log bugs, e.g. ci -t/dev/null when has_mmap. * *************** *** 125,138 **** #include "rcsbase.h" ! libId(genId, "$Id: rcsgen.c,v 1.1 1993/03/25 01:36:45 johnh Exp $") int interactiveflag; /* Should we act as if stdin is a tty? */ struct buf curlogbuf; /* buffer for current log message */ - enum stringwork { enter, copy, edit, expand, edit_expand }; - static void scandeltatext P((struct hshentry*,enum stringwork,int)); - --- 128,138 ---- #include "rcsbase.h" ! libId(genId, "$Id: rcsgen.c,v 1.3 1993/04/03 03:05:41 johnh Exp $") int interactiveflag; /* Should we act as if stdin is a tty? */ struct buf curlogbuf; /* buffer for current log message */ *************** *** 158,164 **** * or no keyword expansion is necessary, or if output goes to stdout. */ { ! if (deltas->first == target) { /* only latest revision to generate */ openfcopy(outfile); scandeltatext(target, expandflag?expand:copy, true); --- 158,166 ---- * or no keyword expansion is necessary, or if output goes to stdout. */ { ! extern int taglinesflag; ! ! if (deltas->first == target && !taglinesflag) { /* only latest revision to generate */ openfcopy(outfile); scandeltatext(target, expandflag?expand:copy, true); *************** *** 194,200 **** ! static void scandeltatext(delta, func, needlog) struct hshentry * delta; enum stringwork func; --- 196,202 ---- ! void scandeltatext(delta, func, needlog) struct hshentry * delta; enum stringwork func; *************** *** 238,243 **** --- 240,247 ---- case expand: xpandstring(delta); break; case edit: editstring((struct hshentry *)nil); break; case edit_expand: editstring(delta); break; + case tag_enter: tagenterstring(); break; + case tag_edits: tageditstring(delta); break; } } =================================================================== RCS file: RCS/rcstag.c,v retrieving revision 1.1 retrieving revision 1.3 diff -c -r1.1 -r1.3 *** rcstag.c- 1993/03/25 01:40:19 --- rcstag.c 1993/04/03 03:05:41 *************** *** 0 **** --- 1,542 ---- + /* + * RCS tagged line handling + */ + /* Copyright 1993 by Paul Eggert + Distributed under license by the Free Software Foundation, Inc. + + Portions of this file are contributed to Paul Eggert by John Heidemann + of the UCLA Ficus Project. + + This file is part of RCS. + + RCS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + RCS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with RCS; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + Report problems and direct all questions to: + + rcs-bugs@cs.purdue.edu + + */ + + #include "rcsbase.h" + + + /* + * We need to save a list of who owns each line. + */ + static struct hshentry **lineowner; + static int unimportant_line; /* index of a "don't care" line */ + + /* + * We manipulate the lineowner list indirectly through these tag_* + * variables. The algorithm is the same as that for managing lines + * as described in rcsedit.c. + */ + static int *tag_line; /* offset into lineowner */ + static unsigned long tag_gap, tag_gapsize, tag_linelim; + static unsigned long tag_editline; /* edit line counter; #lines before cursor */ + static long tag_linecorr; /* #adds - #deletes in each edit run. */ + + static struct hshentry *tag_olddelta; + + + + + static exiting void + tag_editEndsPrematurely() + { + fatserror("edit script ends prematurely"); + } + + static exiting void + tag_editLineNumberOverflow() + { + fatserror("edit script refers to line past end of file"); + } + + + + + static void + tag_savelines(oldestrev) + struct hshentry *oldestrev; + /* + * We no longer save the lines, but we do set up our line-ownership + * information at this point. + * Never do expansion. + */ + { + unsigned long i; + unsigned long duplinelim; + extern unsigned long gap, gapsize, linelim; + + /* + * Remember how many lines are in our desired revision. + */ + duplinelim = gap + linelim-gapsize-gap; /* BeforeGap + AfterGap */ + + /* + * Init line ownership, defaulting to the oldest possible. + */ + lineowner = testalloc(sizeof(int) * (duplinelim + 1)); + for (i = 0; i < duplinelim; i++) + lineowner[i] = oldestrev; + /* We save a dummy owner for our own vile purposes. */ + lineowner[i] = NULL; + unimportant_line = i; + } + + + static void + tag_savestate() + /* + * Associate our current tag_line buffer with the saved + * revision. + */ + { + int i; + int *ip, *ilim; + + for (i = 0, ip = tag_line, ilim = tag_line+tag_gap; ip < ilim; ) + *ip++ = i++; + for (ip += tag_gapsize, ilim = tag_line + tag_linelim; ip < ilim; ) + *ip++ = i++; + + } + + + static void + tag_showsavedlines(out) + FILE *out; + { + extern Iptr_type *line; + extern unsigned long gap, gapsize, linelim; + Iptr_type *p, *lim, *l = line; + Iptr_type cp; + int i; + + /* + * Dump the file, handling the gap. + */ + for (i=0, p=l, lim=l+gap; pnum); + cp = *p++; + do { + aputc(*cp, out); + } while (*cp++ != '\n'); + }; + for (p+=gapsize, lim=l+linelim; pnum); + cp = *p++; + do { + aputc(*cp, out); + } while (*cp++ != '\n'); + }; + } + + + + + + + + /* NEEDSWORK: this should go somewhere else. */ + int taglinesflag = false; /* Boolean: tag lines with their version */ + + char const * + buildtaggedrevision(deltas, target, outfile, expandflag) + struct hshentries const *deltas; + struct hshentry *target; + FILE *outfile; + int expandflag; + /* Function: Generates the revision given by target + * by retrieving all deltas given by parameter deltas and combining them. + * If outfile is set, the revision is output to it, + * otherwise written into a temporary file. + * Temporary files are allocated by maketemp(). + * if expandflag is set, keyword expansion is performed. + * Return nil if outfile is set, the name of the temporary file otherwise. + * + * Algorithm: Copy initial 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. + */ + { + struct hshentries *deltatree; + struct hshentry *oldestdelta; + Iptr_type here; /* remember where we are */ + int marking_changes; + int initial_delta; + + /* + * Go through all but the last revision. + */ + here = Itell(finptr); + if (deltas->first == target) { + scandeltatext(deltas->first, enter, false); + } else { + /* several revisions to generate */ + /* Get initial revision without keyword expansion. */ + scandeltatext(deltas->first, enter, false); + while ((deltas=deltas->rest)->rest) { + /* do all deltas except last one */ + scandeltatext(deltas->first, edit, false); + } + if (expandflag || outfile) { + /* first, get to beginning of file*/ + /* NEEDSWORK: since done==false, why bother to call this fn? */ + finishedit((struct hshentry *)nil, outfile, false); + } + scandeltatext(deltas->first, expandflag?edit_expand:edit, true); + }; + + /* + * Now we'll go back in time. First plot our path. + */ + if (!(oldestdelta = genrevs("1.1",NULL,NULL,NULL,&deltatree))) { + return NULL; + }; + + /* + * Now we've got the revision. + * Save our version of the file and setup the ownership tags. + */ + tag_savelines(oldestdelta); + + /* + * Now scan the changes. + */ + Iseek(finptr, here); + marking_changes = 0; + initial_delta = 1; + tag_olddelta = oldestdelta; /* default to ownership by 1.1 */ + do { + scandeltatext(deltatree->first, + (initial_delta ? tag_enter : tag_edits), + false); + initial_delta = 0; + tag_olddelta = deltatree->first; + if (deltatree->first == target) { + marking_changes = 1; + tag_savestate(); + }; + } while (deltatree = deltatree->rest); + + /* + * Finally output the changes. + */ + tag_showsavedlines(outfile); + + return NULL; + } + + + + + #if large_memory + # define tag_copylines(upto,delta) (tag_editline = (upto)) + #else + static void + tag_copylines(upto,delta) + register unsigned long upto; + struct hshentry const *delta; + { + faterror("tag_copylines: !large_memory"); + } + #endif + + + + + #if has_memmove + # define tag_movelines(s1, s2, n) VOID memmove(s1, s2, (n)*sizeof(int)) + #else + static void + tag_movelines(s1, s2, n) + register int *s1; + register int const *s2; + register unsigned long n; + { + if (s1 < s2) + do { + *s1++ = *s2++; + } while (--n); + else { + s1 += n; + s2 += n; + do { + *--s1 = *--s2; + } while (--n); + } + } + #endif + + + + static void + tag_insertline(n, l) + unsigned long n; + int l; + /* Before line N, insert line L. N is 0-origin. */ + { + if (tag_linelim-tag_gapsize < n) + tag_editLineNumberOverflow(); + if (!tag_gapsize) + tag_line = + !tag_linelim ? + tnalloc(int, tag_linelim = tag_gapsize = 1024) + : ( + tag_gap = tag_gapsize = tag_linelim, + trealloc(int, tag_line, tag_linelim <<= 1) + ); + if (n < tag_gap) + tag_movelines(tag_line+n+tag_gapsize, tag_line+n, tag_gap-n); + else if (tag_gap < n) + tag_movelines(tag_line+tag_gap, tag_line+tag_gap+tag_gapsize, n-tag_gap); + + tag_line[n] = l; + tag_gap = n + 1; + tag_gapsize--; + } + + + static void + tag_deletelines(n, nlines, olddelta) + unsigned long n, nlines; + struct hshentry *olddelta; + /* Delete lines N through N+NLINES-1. N is 0-origin. + * When we delete lines, that means they were created by delta "olddelta". + */ + { + unsigned long l = n + nlines; + unsigned long i; + + /* + * First mark the lines by their creator. + */ + if (l < tag_gap) { + for (i = n; i < l; i++) { + lineowner[tag_line[i]] = olddelta; + }; + } else if (tag_gap < n) { + for (i = n + tag_gapsize; i < l + tag_gapsize; i++) { + lineowner[tag_line[i]] = olddelta; + }; + } else { + for (i = n; i < tag_gap; i++) { + lineowner[tag_line[i]] = olddelta; + }; + for (i = tag_gap + tag_gapsize; i < l + tag_gapsize; i++) { + lineowner[tag_line[i]] = olddelta; + }; + }; + + /* + * Delete the lines. + */ + if (tag_linelim-tag_gapsize < l || l < n) + tag_editLineNumberOverflow(); + if (l < tag_gap) + tag_movelines(tag_line+l+tag_gapsize, tag_line+l, tag_gap-l); + else if (tag_gap < n) + tag_movelines(tag_line+tag_gap, tag_line+tag_gap+tag_gapsize, n-tag_gap); + + tag_gap = n; + tag_gapsize += nlines; + } + + + + + + void + tagenterstring() + { + #if !large_memory + faterror("tag_enter: not implemented for !large_memory.\n"); + #if 0 + editfile = 0; + fedit = 0; + editline = linecorr = 0; + resultfile = maketemp(1); + if (!(fcopy = fopen_update_truncate(resultfile))) + efaterror(resultfile); + copystring(); + #endif + #else + register int c; + declarecache; + register FILE *frew; + register unsigned long e, oe; + register int amidline, oamidline; + register Iptr_type optr; + register RILE *fin; + + e = 0; + tag_gap = 0; + tag_gapsize = tag_linelim; + fin = finptr; + setupcache(fin); cache(fin); + advise_access(fin, MADV_NORMAL); + frew = foutptr; + amidline = false; + for (;;) { + optr = cachetell(); + GETC(frew,c); + oamidline = amidline; + oe = e; + switch (c) { + case '\n': + ++e; + ++rcsline; + amidline = false; + break; + case SDELIM: + GETC(frew,c); + if (c != SDELIM) { + /* end of string */ + nextc = c; + tag_editline = e + amidline; + tag_linecorr = 0; + uncache(fin); + return; + } + /* fall into */ + default: + amidline = true; + break; + } + if (!oamidline) + tag_insertline(oe, unimportant_line); + } + #endif + } + + + + + + /* + * tag_edit_string grabs the current delta out of the global + * variable "tag_olddelta". I did this because paramater passing to + * tag_edit_string is already ugly enough, I don't want to make + * it worse. -JSH 10-Mar-93 + */ + void + #if large_memory + tag_edit_string() + #else + tageditstring(delta) + struct hshentry const *delta; + #endif + { + int ed; /* editor command */ + register int c; + declarecache; + register FILE *frew; + # if !large_memory + register FILE *f; + unsigned long line_lim = ULONG_MAX; + register RILE *fe; + # endif + register unsigned long i; + register RILE *fin; + # if large_memory + register unsigned long j; + # endif + struct diffcmd dc; + + tag_editline += tag_linecorr; tag_linecorr=0; /*correct line number*/ + frew = foutptr; + fin = finptr; + setupcache(fin); + initdiffcmd(&dc); + while (0 <= (ed = getdiffcmd(fin,true,frew,&dc))) + #if !large_memory + if (line_lim <= dc.line1) + tag_editLineNumberOverflow(); + else + #endif + if (!ed) { /* delete */ + tag_copylines(dc.line1-1, delta); + /* skip over unwanted lines */ + i = dc.nlines; + tag_linecorr -= i; + tag_editline += i; + # if large_memory + tag_deletelines(tag_editline+tag_linecorr, i, tag_olddelta); + # else + fe = fedit; + do { + /*skip next line*/ + do { + Igeteof(fe, c, { if (i!=1) tag_editLineNumberOverflow(); line_lim = dc.dafter; break; } ); + } while (c != '\n'); + } while (--i); + # endif + } else { + tag_copylines(dc.line1, delta); /*copy only; no delete*/ + i = dc.nlines; + # if large_memory + j = tag_editline+tag_linecorr; + # endif + tag_linecorr += i; + #if !large_memory + f = fcopy; + if (delta) + do { + switch (expandline(fin,f,delta,true,frew)) { + case 0: case 1: + if (i==1) + return; + /* fall into */ + case -1: + tag_editEndsPrematurely(); + } + } while (--i); + else + #endif + { + cache(fin); + do { + # if large_memory + tag_insertline(j++, unimportant_line); + # endif + for (;;) { + GETC(frew, c); + # if !large_memory + aputc(c, f); + # endif + if (c == '\n') + break; + if (c==SDELIM) { + GETC(frew, c); + if (c!=SDELIM) { + if (--i) + tag_editEndsPrematurely(); + nextc = c; + uncache(fin); + return; + } + } + } + ++rcsline; + } while (--i); + uncache(fin); + } + } + }