📄 rcsedit.c
字号:
/* * RCS stream editor *//********************************************************************************** * edits the input file according to a * script from stdin, generated by diff -n * performs keyword expansion ********************************************************************************** *//* Copyright (C) 1982, 1988, 1989 Walter Tichy Copyright 1990, 1991 by Paul Eggert Distributed under license by the Free Software Foundation, Inc.This file is part of RCS.RCS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with RCS; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.Report problems and direct all questions to: rcs-bugs@cs.purdue.edu*//* $Log: rcsedit.c,v $ * Revision 5.11 1991/11/03 01:11:44 eggert * Move the warning about link breaking to where they're actually being broken. * * Revision 5.10 1991/10/07 17:32:46 eggert * Support piece tables even if !has_mmap. Fix rare NFS bugs. * * Revision 5.9 1991/09/17 19:07:40 eggert * SGI readlink() yields ENXIO, not EINVAL, for nonlinks. * * Revision 5.8 1991/08/19 03:13:55 eggert * Add piece tables, NFS bug workarounds. Catch odd filenames. Tune. * * Revision 5.7 1991/04/21 11:58:21 eggert * Fix errno bugs. Add -x, RCSINIT, MS-DOS support. * * Revision 5.6 1991/02/25 07:12:40 eggert * Fix setuid bug. Support new link behavior. Work around broken "w+" fopen. * * Revision 5.5 1990/12/30 05:07:35 eggert * Fix report of busy RCS files when !defined(O_CREAT) | !defined(O_EXCL). * * Revision 5.4 1990/11/01 05:03:40 eggert * Permit arbitrary data in comment leaders. * * Revision 5.3 1990/09/11 02:41:13 eggert * Tune expandline(). * * Revision 5.2 1990/09/04 08:02:21 eggert * Count RCS lines better. Improve incomplete line handling. * * Revision 5.1 1990/08/29 07:13:56 eggert * Add -kkvl. * Fix bug when getting revisions to files ending in incomplete lines. * Fix bug in comment leader expansion. * * Revision 5.0 1990/08/22 08:12:47 eggert * Don't require final newline. * Don't append "checked in with -k by " to logs, * so that checking in a program with -k doesn't change it. * Don't generate trailing white space for empty comment leader. * Remove compile-time limits; use malloc instead. Add -k, -V. * Permit dates past 1999/12/31. Make lock and temp files faster and safer. * Ansify and Posixate. Check diff's output. * * Revision 4.8 89/05/01 15:12:35 narten * changed copyright header to reflect current distribution rules * * Revision 4.7 88/11/08 13:54:14 narten * misplaced semicolon caused infinite loop * * Revision 4.6 88/08/09 19:12:45 eggert * Shrink stdio code size; allow cc -R. * * Revision 4.5 87/12/18 11:38:46 narten * Changes from the 43. version. Don't know the significance of the * first change involving "rewind". Also, additional "lint" cleanup. * (Guy Harris) * * Revision 4.4 87/10/18 10:32:21 narten * Updating version numbers. Changes relative to version 1.1 actually * relative to 4.1 * * Revision 1.4 87/09/24 13:59:29 narten * Sources now pass through lint (if you ignore printf/sprintf/fprintf * warnings) * * Revision 1.3 87/09/15 16:39:39 shepler * added an initializatin of the variables editline and linecorr * this will be done each time a file is processed. * (there was an obscure bug where if co was used to retrieve multiple files * it would dump) * fix attributed to Roy Morris @FileNet Corp ...!felix!roy * * Revision 1.2 87/03/27 14:22:17 jenkins * Port to suns * * Revision 4.1 83/05/12 13:10:30 wft * Added new markers Id and RCSfile; added locker to Header and Id. * Overhauled expandline completely() (problem with $01234567890123456789@). * Moved trymatch() and marker table to rcskeys.c. * * 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.6 83/05/11 16:06:30 wft * added retry to expandline to resume after failed match which ended in $. * Fixed truncation problem for $19chars followed by@@. * * 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"libId(editId, "$Id: rcsedit.c,v 5.11 1991/11/03 01:11:44 eggert Exp $")static void keyreplace P((enum markers,struct hshentry const*,FILE*));FILE *fcopy; /* result file descriptor */char const *resultfile; /* result file name */int locker_expansion; /* should the locker name be appended to Id val? */#if !large_memory static RILE *fedit; /* edit file descriptor */ static char const *editfile; /* edit pathname */#endifstatic unsigned long editline; /* edit line counter; #lines before cursor */static long linecorr; /* #adds - #deletes in each edit run. */ /*used to correct editline in case file is not rewound after */ /* applying one delta */#define DIRTEMPNAMES 2enum maker {notmade, real, effective};struct buf dirtfname[DIRTEMPNAMES]; /* unlink these when done */static enum maker volatile dirtfmaker[DIRTEMPNAMES]; /* if these are set */#if has_NFS || bad_unlink intun_link(s) char const *s;/* * Remove S, even if it is unwritable. * Ignore unlink() ENOENT failures; NFS generates bogus ones. */{# if bad_unlink int e; if (unlink(s) == 0) return 0; e = errno;# if has_NFS if (e == ENOENT) return 0;# endif if (chmod(s, S_IWUSR) != 0) { errno = e; return -1; }# endif# if has_NFS return unlink(s)==0 || errno==ENOENT ? 0 : -1;# else return unlink(s);# endif}#endif#if !has_rename# if !has_NFS# define do_link(s,t) link(s,t)# else static intdo_link(s, t) char const *s, *t;/* Link S to T, ignoring bogus EEXIST problems due to NFS failures. */{ struct stat sb, tb; if (link(s,t) == 0) return 0; if (errno != EEXIST) return -1; if ( stat(s, &sb) == 0 && stat(t, &tb) == 0 && sb.st_ino == tb.st_ino && sb.st_dev == tb.st_dev ) return 0; errno = EEXIST; return -1;}# endif#endif static exiting voideditEndsPrematurely(){ fatserror("edit script ends prematurely");} static exiting voideditLineNumberOverflow(){ fatserror("edit script refers to line past end of file");}#if large_memory#if has_memmove# define movelines(s1, s2, n) VOID memmove(s1, s2, (n)*sizeof(Iptr_type))#else static voidmovelines(s1, s2, n) register Iptr_type *s1; register Iptr_type 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/* * `line' contains pointers to the lines in the currently `edited' file. * It is a 0-origin array that represents linelim-gapsize lines. * line[0..gap-1] and line[gap+gapsize..linelim-1] contain pointers to lines. * line[gap..gap+gapsize-1] contains garbage. * * 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 voidinsertline(n, l) unsigned long n; Iptr_type l;/* Before line N, insert line L. N is 0-origin. */{ if (linelim-gapsize < n) editLineNumberOverflow(); if (!gapsize) line = !linelim ? tnalloc(Iptr_type, linelim = gapsize = 1024) : ( gap = gapsize = linelim, trealloc(Iptr_type, line, linelim <<= 1) ); if (n < gap) movelines(line+n+gapsize, line+n, gap-n); else if (gap < n) movelines(line+gap, line+gap+gapsize, n-gap); line[n] = l; gap = n + 1; gapsize--;} static voiddeletelines(n, nlines) unsigned long n, nlines;/* Delete lines N through N+NLINES-1. N is 0-origin. */{ unsigned long l = n + nlines; if (linelim-gapsize < l || l < n) editLineNumberOverflow(); if (l < gap) movelines(line+l+gapsize, line+l, gap-l); else if (gap < n) movelines(line+gap, line+gap+gapsize, n-gap); gap = n; gapsize += nlines;} static voidsnapshotline(f, l) register FILE *f; register Iptr_type l;{ register int c; do { if ((c = *l++) == SDELIM && *l++ != SDELIM) return; aputc(c, f); } while (c != '\n');} voidsnapshotedit(f) FILE *f;/* Copy the current state of the edits to F. */{ register Iptr_type *p, *lim, *l=line; for (p=l, lim=l+gap; p<lim; ) snapshotline(f, *p++); for (p+=gapsize, lim=l+linelim; p<lim; ) snapshotline(f, *p++);} static voidfinisheditline(fin, fout, l, delta) RILE *fin; FILE *fout; Iptr_type l; struct hshentry const *delta;{ Iseek(fin, l); if (expandline(fin, fout, delta, true, (FILE*)0) < 0) faterror("finisheditline internal error");} voidfinishedit(delta, outfile, done) struct hshentry const *delta; FILE *outfile; int done;/* * Doing expansion if DELTA is set, output the state of the edits to OUTFILE. * But do nothing unless DONE is set (which means we are on the last pass). */{ if (done) { openfcopy(outfile); outfile = fcopy; if (!delta) snapshotedit(outfile); else { register Iptr_type *p, *lim, *l = line; register RILE *fin = finptr; Iptr_type here = Itell(fin); for (p=l, lim=l+gap; p<lim; ) finisheditline(fin, outfile, *p++, delta); for (p+=gapsize, lim=l+linelim; p<lim; ) finisheditline(fin, outfile, *p++, delta); Iseek(fin, here); } }}/* Open a temporary FILENAME for output, truncating any previous contents. */# define fopen_update_truncate(filename) fopen(filename, FOPEN_W_WORK)#else /* !large_memory */ static FILE *fopen_update_truncate(filename) char const *filename;{# if bad_fopen_wplus if (un_link(filename) != 0) efaterror(filename);# endif return fopen(filename, FOPEN_WPLUS_WORK);}#endif voidopenfcopy(f) FILE *f;{ if (!(fcopy = f)) { if (!resultfile) resultfile = maketemp(2); if (!(fcopy = fopen_update_truncate(resultfile))) efaterror(resultfile); }}#if !large_memory static voidswapeditfiles(outfile) FILE *outfile;/* Function: swaps resultfile and editfile, assigns fedit=fcopy, * and rewinds fedit for reading. Set fcopy to outfile if nonnull; * otherwise, set fcopy to be resultfile opened for reading and writing. */{ char const *tmpptr; editline = 0; linecorr = 0; if (fseek(fcopy, 0L, SEEK_SET) != 0) Oerror(); fedit = fcopy; tmpptr=editfile; editfile=resultfile; resultfile=tmpptr; openfcopy(outfile);} voidsnapshotedit(f) FILE *f;/* Copy the current state of the edits to F. */{ finishedit((struct hshentry *)nil, (FILE*)0, false); fastcopy(fedit, f); Irewind(fedit);} voidfinishedit(delta, outfile, done) struct hshentry const *delta; FILE *outfile; int done;/* copy the rest of the edit file and close it (if it exists). * if delta!=nil, perform keyword substitution at the same time. * If DONE is set, we are finishing the last pass. */{ register RILE *fe; register FILE *fc; fe = fedit; if (fe) { fc = fcopy; if (delta!=nil) { while (1 < expandline(fe,fc,delta,false,(FILE*)0)) ; } else { fastcopy(fe,fc); } Ifclose(fe); } if (!done) swapeditfiles(outfile);}#endif#if large_memory# define copylines(upto,delta) (editline = (upto))#else static voidcopylines(upto,delta) register unsigned long upto; struct hshentry const *delta;/* * Copy input lines editline+1..upto from fedit to fcopy. * If delta != nil, keyword expansion is done simultaneously. * editline is updated. Rewinds a file only if necessary. */{ register int c; declarecache; register FILE *fc; register RILE *fe; if (upto < editline) { /* swap files */ finishedit((struct hshentry *)nil, (FILE*)0, false); /* assumes edit only during last pass, from the beginning*/ } fe = fedit; fc = fcopy; if (editline < upto) if (delta) do { if (expandline(fe,fc,delta,false,(FILE*)0) <= 1) editLineNumberOverflow(); } while (++editline < upto); else { setupcache(fe); cache(fe); do { do { cachegeteof(c, editLineNumberOverflow();); aputc(c, fc); } while (c != '\n'); } while (++editline < upto); uncache(fe); }}#endif voidxpandstring(delta) struct hshentry const *delta;/* Function: Reads a string terminated by SDELIM from finptr and writes it * to fcopy. Double SDELIM is replaced with single SDELIM. * Keyword expansion is performed with data from delta. * If foutptr is nonnull, the string is also copied unchanged to foutptr. */{ while (1 < expandline(finptr,fcopy,delta,true,foutptr)) ;} voidcopystring()/* Function: copies a string terminated with a single SDELIM from finptr to * fcopy, replacing all double SDELIM with a single SDELIM. * If foutptr is nonnull, the string also copied unchanged to foutptr.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -