summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2008-03-19 15:06:50 +0000
committerobrien <obrien@FreeBSD.org>2008-03-19 15:06:50 +0000
commit9452bc826ee03da4235ec394e2cff88c33aaa28c (patch)
tree21b87509d46582e55fbde576abf277ed6d1040ac /contrib/cvs/src
parentf9e077664c53800a8ea97f743323c2eba92cdc60 (diff)
downloadFreeBSD-src-9452bc826ee03da4235ec394e2cff88c33aaa28c.zip
FreeBSD-src-9452bc826ee03da4235ec394e2cff88c33aaa28c.tar.gz
Merge rev 1.28 (CAN-2005-0753 / FreeBSD-SA-05:05.cvs fixes),
rev 1.27 ("iso8601" option keyword) revs 1.12/1.10/1.5/1.4 ($CVSHeader$ support) rev 1.2 ($CVS_LOCAL_BRANCH_NUM support for local commit feature of cvsup) into version 1.11-20080310.
Diffstat (limited to 'contrib/cvs/src')
-rw-r--r--contrib/cvs/src/rcs.c437
1 files changed, 267 insertions, 170 deletions
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index fe51dd0..3358e91 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -32,6 +32,15 @@
# endif
#endif
+#ifdef MMAP_FALLBACK_TEST
+void *my_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+ if (rand() & 1) return mmap(addr, len, prot, flags, fd, offset);
+ return NULL;
+}
+#define mmap my_mmap
+#endif
+
int datesep = '/';
int preserve_perms = 0;
@@ -68,6 +77,8 @@ struct rcsbuffer
this is non-zero, we must search the string for pairs of '@'
and convert them to a single '@'. */
int embedded_at;
+ /* Whether the buffer has been mmap'ed or not. */
+ int mmapped;
};
static RCSNode *RCS_parsercsfile_i PROTO((FILE * fp, const char *rcsfile));
@@ -79,10 +90,8 @@ static void rcsbuf_close PROTO ((struct rcsbuffer *));
static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
char **valp));
static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
-#ifndef HAVE_MMAP
static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
char **valp));
-#endif
static int rcsbuf_valcmp PROTO ((struct rcsbuffer *));
static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
size_t *lenp));
@@ -834,8 +843,8 @@ warning: duplicate key `%s' in version `%s' of RCS file `%s'",
op = *cp++;
if (op != 'a' && op != 'd')
error (1, 0, "\
-unrecognized operation '\\x%x' in %s",
- op, rcs->path);
+unrecognized operation '\\x%x' in %s revision %s",
+ op, rcs->path, vnode->version);
(void) strtoul (cp, (char **) &cp, 10);
if (*cp++ != ' ')
error (1, 0, "space expected in %s revision %s",
@@ -1034,46 +1043,58 @@ rcsbuf_open (rcsbuf, fp, filename, pos)
const char *filename;
unsigned long pos;
{
+#ifdef HAVE_MMAP
+ void *p;
+ struct stat fs;
+ size_t mmap_off = 0;
+#endif
+
if (rcsbuf_inuse)
error (1, 0, "rcsbuf_open: internal error");
rcsbuf_inuse = 1;
#ifdef HAVE_MMAP
- {
- /* When we have mmap, it is much more efficient to let the system do the
- * buffering and caching for us
- */
- struct stat fs;
- size_t mmap_off = 0;
-
- if ( fstat (fileno(fp), &fs) < 0 )
- error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
+ /* When we have mmap, it is much more efficient to let the system do the
+ * buffering and caching for us
+ */
- if (pos)
- {
- size_t ps = getpagesize ();
- mmap_off = ( pos / ps ) * ps;
- }
+ if ( fstat (fileno(fp), &fs) < 0 )
+ error ( 1, errno, "Could not stat RCS archive %s for mapping", filename );
- /* Map private here since this particular buffer is read only */
- rcsbuf_buffer = mmap ( NULL, fs.st_size - mmap_off,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE, fileno(fp), mmap_off );
- if ( rcsbuf_buffer == NULL || rcsbuf_buffer == MAP_FAILED )
- error ( 1, errno, "Could not map memory to RCS archive %s", filename );
+ if (pos)
+ {
+ size_t ps = getpagesize ();
+ mmap_off = ( pos / ps ) * ps;
+ }
+ /* Map private here since this particular buffer is read only */
+ p = mmap ( NULL, fs.st_size - mmap_off, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fileno(fp), mmap_off );
+ if (p != NULL && p != MAP_FAILED)
+ {
+ if (rcsbuf_buffer) free (rcsbuf_buffer);
+ rcsbuf_buffer = p;
rcsbuf_buffer_size = fs.st_size - mmap_off;
+ rcsbuf->mmapped = 1;
rcsbuf->ptr = rcsbuf_buffer + pos - mmap_off;
rcsbuf->ptrend = rcsbuf_buffer + fs.st_size - mmap_off;
rcsbuf->pos = mmap_off;
}
-#else /* HAVE_MMAP */
- if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
+ else
+ {
+#ifndef MMAP_FALLBACK_TEST
+ error (0, errno, "Could not map memory to RCS archive %s", filename);
+#endif
+#endif /* HAVE_MMAP */
+ if (rcsbuf_buffer_size < RCSBUF_BUFSIZE)
expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, RCSBUF_BUFSIZE);
- rcsbuf->ptr = rcsbuf_buffer;
- rcsbuf->ptrend = rcsbuf_buffer;
- rcsbuf->pos = pos;
+ rcsbuf->mmapped = 0;
+ rcsbuf->ptr = rcsbuf_buffer;
+ rcsbuf->ptrend = rcsbuf_buffer;
+ rcsbuf->pos = pos;
+#ifdef HAVE_MMAP
+ }
#endif /* HAVE_MMAP */
rcsbuf->fp = fp;
rcsbuf->filename = filename;
@@ -1091,7 +1112,12 @@ rcsbuf_close (rcsbuf)
if (! rcsbuf_inuse)
error (1, 0, "rcsbuf_close: internal error");
#ifdef HAVE_MMAP
- munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
+ if (rcsbuf->mmapped)
+ {
+ munmap ( rcsbuf_buffer, rcsbuf_buffer_size );
+ rcsbuf_buffer = NULL;
+ rcsbuf_buffer_size = 0;
+ }
#endif
rcsbuf_inuse = 0;
}
@@ -1136,11 +1162,10 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
assert (ptr >= rcsbuf_buffer && ptr <= rcsbuf_buffer + rcsbuf_buffer_size);
assert (ptrend >= rcsbuf_buffer && ptrend <= rcsbuf_buffer + rcsbuf_buffer_size);
-#ifndef HAVE_MMAP
/* If the pointer is more than RCSBUF_BUFSIZE bytes into the
buffer, move back to the start of the buffer. This keeps the
buffer from growing indefinitely. */
- if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
+ if (!rcsbuf->mmapped && ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE)
{
int len;
@@ -1159,23 +1184,18 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
ptrend = ptr + len;
rcsbuf->ptrend = ptrend;
}
-#endif /* ndef HAVE_MMAP */
/* Skip leading whitespace. */
while (1)
{
if (ptr >= ptrend)
-#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
if (ptr == NULL)
-#endif
return 0;
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
c = *ptr;
if (! my_whitespace (c))
@@ -1194,17 +1214,13 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
{
++ptr;
if (ptr >= ptrend)
-#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
if (ptr == NULL)
-#endif
error (1, 0, "EOF in key in RCS file %s",
rcsbuf->filename);
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
c = *ptr;
if (c == ';' || my_whitespace (c))
break;
@@ -1233,17 +1249,13 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
while (1)
{
if (ptr >= ptrend)
-#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, (char **) NULL);
if (ptr == NULL)
-#endif
error (1, 0, "EOF while looking for value in RCS file %s",
rcsbuf->filename);
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
c = *ptr;
if (c == ';')
{
@@ -1278,7 +1290,6 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
while (1)
{
while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
-#ifndef HAVE_MMAP
{
/* Note that we pass PTREND as the PTR value to
rcsbuf_fill, so that we will wind up setting PTR to
@@ -1286,31 +1297,25 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
that we don't search the same bytes again. */
ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
if (ptr == NULL)
-#endif
error (1, 0,
"EOF while looking for end of string in RCS file %s",
rcsbuf->filename);
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
/* Handle the special case of an '@' right at the end of
the known bytes. */
if (pat + 1 >= ptrend)
-#ifndef HAVE_MMAP
{
/* Note that we pass PAT, not PTR, here. */
pat = rcsbuf_fill (rcsbuf, pat, keyp, valp);
if (pat == NULL)
{
-#endif
/* EOF here is OK; it just means that the last
character of the file was an '@' terminating a
value for a key type which does not require a
trailing ';'. */
pat = rcsbuf->ptrend - 1;
-#ifndef HAVE_MMAP
}
ptrend = rcsbuf->ptrend;
@@ -1318,7 +1323,6 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
/* Note that the value of PTR is bogus here. This is
OK, because we don't use it. */
}
-#endif
if (pat + 1 >= ptrend || pat[1] != '@')
break;
@@ -1368,17 +1372,13 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
char n;
if (ptr >= ptrend)
-#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
if (ptr == NULL)
-#endif
error (1, 0, "EOF in value in RCS file %s",
rcsbuf->filename);
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
n = *ptr;
if (n == ';')
{
@@ -1413,7 +1413,6 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
/* Find the ';' which must end the value. */
start = ptr;
while ((psemi = memchr (ptr, ';', ptrend - ptr)) == NULL)
-#ifndef HAVE_MMAP
{
int slen;
@@ -1424,13 +1423,10 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
slen = start - *valp;
ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
if (ptr == NULL)
-#endif
error (1, 0, "EOF in value in RCS file %s", rcsbuf->filename);
-#ifndef HAVE_MMAP
start = *valp + slen;
ptrend = rcsbuf->ptrend;
}
-#endif
/* See if there are any '@' strings in the value. */
pat = memchr (start, '@', psemi - start);
@@ -1474,7 +1470,6 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
while (1)
{
while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
-#ifndef HAVE_MMAP
{
/* Note that we pass PTREND as the PTR value to
rcsbuff_fill, so that we will wind up setting PTR
@@ -1482,29 +1477,22 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
that we don't search the same bytes again. */
ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp);
if (ptr == NULL)
-#endif
error (1, 0,
"EOF while looking for end of string in RCS file %s",
rcsbuf->filename);
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
/* Handle the special case of an '@' right at the end of
the known bytes. */
if (pat + 1 >= ptrend)
-#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp);
if (ptr == NULL)
-#endif
error (1, 0, "EOF in value in RCS file %s",
rcsbuf->filename);
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
if (pat[1] != '@')
break;
@@ -1547,16 +1535,12 @@ rcsbuf_getrevnum (rcsbuf, revp)
while (1)
{
if (ptr >= ptrend)
-#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
if (ptr == NULL)
-#endif
return 0;
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
c = *ptr;
if (! whitespace (c))
@@ -1577,18 +1561,14 @@ unexpected '\\x%x' reading revision number in RCS file %s",
{
++ptr;
if (ptr >= ptrend)
-#ifndef HAVE_MMAP
{
ptr = rcsbuf_fill (rcsbuf, ptr, revp, (char **) NULL);
if (ptr == NULL)
-#endif
error (1, 0,
"unexpected EOF reading revision number in RCS file %s",
rcsbuf->filename);
-#ifndef HAVE_MMAP
ptrend = rcsbuf->ptrend;
}
-#endif
c = *ptr;
}
@@ -1606,7 +1586,6 @@ unexpected '\\x%x' reading revision number in RCS file %s",
return 1;
}
-#ifndef HAVE_MMAP
/* Fill RCSBUF_BUFFER with bytes from the file associated with RCSBUF,
updating PTR and the PTREND field. If KEYP and *KEYP are not NULL,
then *KEYP points into the buffer, and must be adjusted if the
@@ -1622,6 +1601,9 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp)
{
int got;
+ if (rcsbuf->mmapped)
+ return NULL;
+
if (rcsbuf->ptrend - rcsbuf_buffer + RCSBUF_BUFSIZE > rcsbuf_buffer_size)
{
int poff, peoff, koff, voff;
@@ -1654,7 +1636,6 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp)
return ptr;
}
-#endif /* HAVE_MMAP */
/* Test whether the last value returned by rcsbuf_getkey is a composite
value or not. */
@@ -1966,7 +1947,7 @@ static unsigned long
rcsbuf_ftell (rcsbuf)
struct rcsbuffer *rcsbuf;
{
- return rcsbuf->pos + rcsbuf->ptr - rcsbuf_buffer;
+ return rcsbuf->pos + (rcsbuf->ptr - rcsbuf_buffer);
}
/* Return a pointer to any data buffered for RCSBUF, along with the
@@ -2032,8 +2013,7 @@ rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
FILE **pfp;
struct rcsbuffer *prcsbuf;
{
-#ifndef HAVE_MMAP
- if (cached_rcs == rcs)
+ if (cached_rcs == rcs && !cached_rcsbuf.mmapped)
{
if (rcsbuf_ftell (&cached_rcsbuf) != pos)
{
@@ -2063,7 +2043,6 @@ rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
}
else
{
-#endif /* ifndef HAVE_MMAP */
/* FIXME: If these routines can be rewritten to not write to the
* rcs file buffer, there would be a considerably larger memory savings
* from using mmap since the shared file would never need be copied to
@@ -2078,17 +2057,13 @@ rcsbuf_cache_open (rcs, pos, pfp, prcsbuf)
*pfp = CVS_FOPEN (rcs->path, FOPEN_BINARY_READ);
if (*pfp == NULL)
error (1, 0, "unable to reopen `%s'", rcs->path);
-#ifndef HAVE_MMAP
if (pos != 0)
{
if (fseek (*pfp, pos, SEEK_SET) != 0)
error (1, 0, "cannot fseek RCS file %s", rcs->path);
}
-#endif /* ifndef HAVE_MMAP */
rcsbuf_open (prcsbuf, *pfp, rcs->path, pos);
-#ifndef HAVE_MMAP
}
-#endif /* ifndef HAVE_MMAP */
}
@@ -4201,7 +4176,8 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
{
int free_rev = 0;
enum kflag expand;
- FILE *fp, *ofp;
+ FILE *fp;
+ FILE *ofp = NULL;
struct stat sb;
struct rcsbuffer rcsbuf;
char *key;
@@ -6320,6 +6296,25 @@ findtag (node, arg)
return 0;
}
+static int findmagictag PROTO ((Node *, void *));
+
+/* Return a nonzero value if a magic tag rooted at ARG is found. */
+
+static int
+findmagictag (node, arg)
+ Node *node;
+ void *arg;
+{
+ char *rev = (char *)arg;
+ size_t len = strlen (rev);
+
+ if (strncmp (node->data, rev, len) == 0 &&
+ strncmp ((char *)node->data + len, ".0.", 3) == 0)
+ return 1;
+ else
+ return 0;
+}
+
/* Delete revisions between REV1 and REV2. The changes between the two
revisions must be collapsed, and the result stored in the revision
immediately preceding the lower one. Return 0 for successful completion,
@@ -6579,8 +6574,9 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive)
/* Doing this only for the :: syntax is for compatibility.
See cvs.texinfo for somewhat more discussion. */
- if (!inclusive
- && walklist (RCS_symbols (rcs), findtag, revp->version))
+ if (!inclusive &&
+ (walklist (RCS_symbols (rcs), findtag, revp->version) ||
+ walklist (RCS_symbols (rcs), findmagictag, revp->version)))
{
/* We don't print which file this happens to on the theory
that the caller will print the name of the file in a
@@ -7037,31 +7033,6 @@ linevector_add (vec, text, len, vers, pos)
return 1;
}
-static void linevector_delete PROTO ((struct linevector *, unsigned int,
- unsigned int));
-
-/* Remove NLINES lines from VEC at position POS (where line 0 is the
- first line). */
-static void
-linevector_delete (vec, pos, nlines)
- struct linevector *vec;
- unsigned int pos;
- unsigned int nlines;
-{
- unsigned int i;
- unsigned int last;
-
- last = vec->nlines - nlines;
- for (i = pos; i < pos + nlines; ++i)
- {
- if (--vec->vector[i]->refcount == 0)
- free (vec->vector[i]);
- }
- for (i = pos; i < last; ++i)
- vec->vector[i] = vec->vector[i + nlines];
- vec->nlines -= nlines;
-}
-
static void linevector_copy PROTO ((struct linevector *, struct linevector *));
/* Copy FROM to TO, copying the vectors but not the lines pointed to. */
@@ -7105,7 +7076,7 @@ linevector_free (vec)
if (vec->vector != NULL)
{
for (ln = 0; ln < vec->nlines; ++ln)
- if (--vec->vector[ln]->refcount == 0)
+ if (vec->vector[ln] && --vec->vector[ln]->refcount == 0)
free (vec->vector[ln]);
free (vec->vector);
@@ -7140,20 +7111,27 @@ apply_rcs_changes PROTO ((struct linevector *, const char *, size_t,
const char *, RCSVers *, RCSVers *));
/* Apply changes to the line vector LINES. DIFFBUF is a buffer of
- length DIFFLEN holding the change text from an RCS file (the output
- of diff -n). NAME is used in error messages. The VERS field of
- any line added is set to ADDVERS. The VERS field of any line
- deleted is set to DELVERS, unless DELVERS is NULL, in which case
- the VERS field of deleted lines is unchanged. The function returns
- non-zero if the change text is applied successfully. It returns
- zero if the change text does not appear to apply to LINES (e.g., a
- line number is invalid). If the change text is improperly
- formatted (e.g., it is not the output of diff -n), the function
- calls error with a status of 1, causing the program to exit. */
-
+ * length DIFFLEN holding the change text from an RCS file (the output
+ * of diff -n). NAME is used in error messages. The VERS field of
+ * any line added is set to ADDVERS. The VERS field of any line
+ * deleted is set to DELVERS, unless DELVERS is NULL, in which case
+ * the VERS field of deleted lines is unchanged.
+ *
+ * RETURNS
+ * Non-zero if the change text is applied successfully to ORIG_LINES.
+ *
+ * If the change text does not appear to apply to ORIG_LINES (e.g., a
+ * line number is invalid), this function will return zero and ORIG_LINES
+ * will remain unmolested.
+ *
+ * ERRORS
+ * If the change text is improperly formatted (e.g., it is not the output
+ * of diff -n), the function calls error with a status of 1, causing the
+ * program to exit.
+ */
static int
-apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
- struct linevector *lines;
+apply_rcs_changes (orig_lines, diffbuf, difflen, name, addvers, delvers)
+ struct linevector *orig_lines;
const char *diffbuf;
size_t difflen;
const char *name;
@@ -7175,10 +7153,15 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
struct deltafrag *next;
};
struct deltafrag *dfhead;
+ struct deltafrag **dftail;
struct deltafrag *df;
+ unsigned long numlines, lastmodline, offset;
+ struct linevector lines;
int err;
dfhead = NULL;
+ dftail = &dfhead;
+ numlines = orig_lines->nlines; /* start with init # of lines */
for (p = diffbuf; p != NULL && p < diffbuf + difflen; )
{
op = *p++;
@@ -7187,9 +7170,9 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
of op determines the syntax. */
error (1, 0, "unrecognized operation '\\x%x' in %s",
op, name);
- df = (struct deltafrag *) xmalloc (sizeof (struct deltafrag));
- df->next = dfhead;
- dfhead = df;
+ *dftail = df = xmalloc (sizeof *df);
+ *(dftail = &df->next) = NULL;
+
df->pos = strtoul (p, (char **) &q, 10);
if (p == q)
@@ -7230,6 +7213,7 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
df->len = q - p;
p = q;
+ numlines += df->nlines;
}
else
{
@@ -7239,41 +7223,155 @@ apply_rcs_changes (lines, diffbuf, difflen, name, addvers, delvers)
assert (op == 'd');
df->type = FRAG_DELETE;
+ numlines -= df->nlines;
}
}
+ /* New temp data structure to hold new org before
+ copy back into original structure. */
+ lines.nlines = lines.lines_alloced = numlines;
+ lines.vector = xmalloc (numlines * sizeof *lines.vector);
+
+ /* We changed the list order to first to last -- so the
+ list never gets larger than the size numlines. */
+ lastmodline = 0;
+
+ /* offset created when adding/removing lines
+ between new and original structure */
+ offset = 0;
err = 0;
- for (df = dfhead; df != NULL;)
+ for (df = dfhead; df != NULL; )
{
unsigned int ln;
+ unsigned long deltaend;
- /* Once an error is encountered, just free the rest of the list and
- * return.
- */
+ if (df->pos > orig_lines->nlines)
+ err = 1;
+
+ /* On error, just free the rest of the list. */
if (!err)
+ {
+ /* Here we need to get to the line where the next insert will
+ begin, which is DF->pos in ORIG_LINES. We will fill up to
+ DF->pos - OFFSET in LINES with original items. */
+ for (deltaend = df->pos - offset;
+ lastmodline < deltaend;
+ lastmodline++)
+ {
+ /* we need to copy from the orig structure into new one */
+ lines.vector[lastmodline] =
+ orig_lines->vector[lastmodline + offset];
+ lines.vector[lastmodline]->refcount++;
+ }
+
switch (df->type)
{
- case FRAG_ADD:
- if (! linevector_add (lines, df->new_lines, df->len, addvers,
- df->pos))
- err = 1;
- break;
- case FRAG_DELETE:
- if (df->pos > lines->nlines
- || df->pos + df->nlines > lines->nlines)
- return 0;
- if (delvers != NULL)
- for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
- lines->vector[ln]->vers = delvers;
- linevector_delete (lines, df->pos, df->nlines);
- break;
+ case FRAG_ADD:
+ {
+ const char *textend, *p;
+ const char *nextline_text;
+ struct line *q;
+ int nextline_newline;
+ size_t nextline_len;
+
+ textend = df->new_lines + df->len;
+ nextline_newline = 0;
+ nextline_text = df->new_lines;
+ for (p = df->new_lines; p < textend; ++p)
+ {
+ if (*p == '\n')
+ {
+ nextline_newline = 1;
+ if (p + 1 == textend)
+ {
+ /* If there are no characters beyond the
+ last newline, we don't consider it
+ another line. */
+ break;
+ }
+
+ nextline_len = p - nextline_text;
+ q = xmalloc (sizeof *q + nextline_len);
+ q->vers = addvers;
+ q->text = (char *)(q + 1);
+ q->len = nextline_len;
+ q->has_newline = nextline_newline;
+ q->refcount = 1;
+ memcpy (q->text, nextline_text, nextline_len);
+ lines.vector[lastmodline++] = q;
+ offset--;
+
+ nextline_text = (char *)p + 1;
+ nextline_newline = 0;
+ }
+ }
+ nextline_len = p - nextline_text;
+ q = xmalloc (sizeof *q + nextline_len);
+ q->vers = addvers;
+ q->text = (char *)(q + 1);
+ q->len = nextline_len;
+ q->has_newline = nextline_newline;
+ q->refcount = 1;
+ memcpy (q->text, nextline_text, nextline_len);
+ lines.vector[lastmodline++] = q;
+
+ /* For each line we add the offset between the #'s
+ decreases. */
+ offset--;
+ break;
+ }
+
+ case FRAG_DELETE:
+ /* we are removing this many lines from the source. */
+ offset += df->nlines;
+
+ if (df->pos + df->nlines > orig_lines->nlines)
+ err = 1;
+ else if (delvers)
+ for (ln = df->pos; ln < df->pos + df->nlines; ++ln)
+ if (orig_lines->vector[ln]->refcount > 1)
+ /* Annotate needs this but, since the original
+ * vector is disposed of before returning from
+ * this function, we only need keep track if
+ * there are multiple references.
+ */
+ orig_lines->vector[ln]->vers = delvers;
+ break;
}
+ }
df = df->next;
free (dfhead);
dfhead = df;
}
+ if (err)
+ {
+ /* No reason to try and move a half-mutated and known invalid
+ * text into the output buffer.
+ */
+ linevector_free (&lines);
+ }
+ else
+ {
+ /* add the rest of the remaining lines to the data vector */
+ for (; lastmodline < numlines; lastmodline++)
+ {
+ /* we need to copy from the orig structure into new one */
+ lines.vector[lastmodline] = orig_lines->vector[lastmodline
+ + offset];
+ lines.vector[lastmodline]->refcount++;
+ }
+
+ /* Move the lines vector to the original structure for output,
+ * first deleting the old.
+ */
+ linevector_free (orig_lines);
+ orig_lines->vector = lines.vector;
+ orig_lines->lines_alloced = numlines;
+ orig_lines->nlines = lines.nlines;
+ }
+
return !err;
}
@@ -8346,10 +8444,8 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
char *bufrest;
int nls;
size_t buflen;
-#ifndef HAVE_MMAP
char buf[8192];
int got;
-#endif
/* Count the number of versions for which we have to do some
special operation. */
@@ -8463,29 +8559,30 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
fwrite (bufrest, 1, buflen, fout);
}
-#ifndef HAVE_MMAP
- /* This bit isn't necessary when using mmap since the entire file
- * will already be available via the RCS buffer. Besides, the
- * mmap code doesn't always keep the file pointer up to date, so
- * this adds some data twice.
- */
- while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
+ if (!rcsbufin->mmapped)
{
- if (nls > 0
- && got >= nls
- && buf[0] == '\n'
- && strncmp (buf, "\n\n\n", nls) == 0)
- {
- fwrite (buf + 1, 1, got - 1, fout);
- }
- else
+ /* This bit isn't necessary when using mmap since the entire file
+ * will already be available via the RCS buffer. Besides, the
+ * mmap code doesn't always keep the file pointer up to date, so
+ * this adds some data twice.
+ */
+ while ((got = fread (buf, 1, sizeof buf, fin)) != 0)
{
- fwrite (buf, 1, got, fout);
- }
+ if (nls > 0
+ && got >= nls
+ && buf[0] == '\n'
+ && strncmp (buf, "\n\n\n", nls) == 0)
+ {
+ fwrite (buf + 1, 1, got - 1, fout);
+ }
+ else
+ {
+ fwrite (buf, 1, got, fout);
+ }
nls = 0;
+ }
}
-#endif /* HAVE_MMAP */
}
/* A helper procedure for RCS_copydeltas. This is called via walklist
OpenPOWER on IntegriCloud