summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/rcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/rcs.c')
-rw-r--r--contrib/cvs/src/rcs.c851
1 files changed, 260 insertions, 591 deletions
diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c
index 48be8e5..7f2094d8 100644
--- a/contrib/cvs/src/rcs.c
+++ b/contrib/cvs/src/rcs.c
@@ -62,6 +62,7 @@ static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp,
static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp));
static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp,
char **valp));
+static int rcsbuf_valcmp PROTO ((struct rcsbuffer *));
static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish,
size_t *lenp));
static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish,
@@ -158,6 +159,7 @@ static const char spacetab[] = {
#define whitespace(c) (spacetab[(unsigned char)c] != 0)
static char *rcs_lockfile;
+static int rcs_lockfd = -1;
/* A few generic thoughts on error handling, in particular the
printing of unexpected characters that we find in the RCS file
@@ -546,9 +548,10 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
if (rdata->other == NULL)
rdata->other = getlist ();
kv = getnode ();
- kv->type = RCSFIELD;
+ kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
kv->key = xstrdup (key);
- kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
+ kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (rdata->other, kv) != 0)
{
error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
@@ -594,9 +597,7 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp)
key, rcsfile);
free (rdata->desc);
}
- /* Don't need to rcsbuf_valcopy `value' because
- getdelta already did that. */
- rdata->desc = xstrdup (value);
+ rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
}
rdata->delta_pos = rcsbuf_ftell (&rcsbuf);
@@ -752,9 +753,10 @@ RCS_fully_parse (rcs)
if (vnode->other == NULL)
vnode->other = getlist ();
kv = getnode ();
- kv->type = RCSFIELD;
+ kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
kv->key = xstrdup (key);
- kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL);
+ kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (vnode->other, kv) != 0)
{
error (0, 0,
@@ -1032,6 +1034,9 @@ rcsbuf_close (rcsbuf)
characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do
appropriate massaging. */
+/* Note that the extreme hair in rcsbuf_getkey is because profiling
+ statistics show that it was worth it. */
+
static int
rcsbuf_getkey (rcsbuf, keyp, valp)
struct rcsbuffer *rcsbuf;
@@ -1287,13 +1292,10 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
}
/* The value extends past the '@' string. We need to undo the
- closing of the '@' done in the default case above. This
+ '@' stripping done in the default case above. This
case never happens in a plain RCS file, but it can happen
if user defined phrases are used. */
- if (rcsbuf->vlen != 0)
- (*valp)[rcsbuf->vlen] = ' ';
- else
- *valp = ptr;
+ ((*valp)--)[rcsbuf->vlen++] = '@';
}
/* Here we have a value which is not a simple '@' string. We need
@@ -1350,8 +1352,8 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
return 1;
}
- /* We found an '@' string in the value. We set
- RCSBUF->AT_STRING, which means that we won't be able to
+ /* We found an '@' string in the value. We set RCSBUF->AT_STRING
+ and RCSBUF->EMBEDDED_AT to indicate that we won't be able to
compress whitespace correctly for this type of value.
Since this type of value never arises in a normal RCS file,
this should not be a big deal. It means that if anybody
@@ -1360,8 +1362,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
themselves. */
rcsbuf->at_string = 1;
-
- *pat = ' ';
+ rcsbuf->embedded_at = -1;
ptr = pat + 1;
@@ -1396,495 +1397,16 @@ rcsbuf_getkey (rcsbuf, keyp, valp)
break;
/* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
ptr = pat + 2;
}
/* Here PAT points to the final '@' in the string. */
-
- *pat = ' ';
-
ptr = pat + 1;
}
#undef my_whitespace
}
-/* TODO: Eliminate redundant code in rcsbuf_getkey, rcsbuf_getid,
- rcsbuf_getstring, rcsbuf_getword. These last three functions were
- all created by hacking monstrous swaths of code from rcsbuf_getkey,
- and some engineering would make the code easier to read and
- maintain.
-
- Note that the extreme hair in rcsbuf_getkey is because profiling
- statistics show that it was worth it.
-
- We probably could be processing "hardlinks" by first calling
- rcsbuf_getkey, and breaking up the value afterwards; the code to
- break it up would not need to be hacked for speed. This would
- remove the need for rcsbuf_getword, rcsbuf_getid, and
- rcsbuf_getstring, as the other calls are easy to remove. */
-
-/* Read an `id' (in the sense of rcsfile(5)) from RCSBUF, and store in
- IDP. */
-
-static int
-rcsbuf_getid (rcsbuf, idp)
- struct rcsbuffer *rcsbuf;
- char **idp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* 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)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- return 0;
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* We've found the start of the key. */
-
- *idp = ptr;
-
- if (c != ';')
- {
- while (1)
- {
- ++ptr;
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, idp, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "EOF in key in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
- c = *ptr;
- if (c == ';' || my_whitespace (c))
- break;
- }
- }
-
- /* Here *IDP points to the id in the buffer, C is the character
- we found at the end of the key, and PTR points to the location in
- the buffer where we found C. We may not set *PTR to \0, because
- it may overwrite a terminating semicolon. The calling function
- must copy and terminate the id on its own. */
-
- rcsbuf->ptr = ptr;
- return 1;
-
-#undef my_whitespace
-}
-
-/* Read an RCS @-delimited string. Store the result in STRP. */
-
-static int
-rcsbuf_getstring (rcsbuf, strp)
- struct rcsbuffer *rcsbuf;
- char **strp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char *pat;
- size_t vlen;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* 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)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* PTR should now point to the start of a string. */
- if (c != '@')
- error (1, 0, "expected @-string at '\\x%x' in %s",
- c, rcsbuf->filename);
-
- /* Optimize the common case of a value composed of a single
- '@' string. */
-
- rcsbuf->at_string = 1;
-
- ++ptr;
-
- *strp = ptr;
-
- while (1)
- {
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to
- the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, strp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
- {
- /* Note that we pass PAT, not PTR, here. */
- pat = rcsbuf_fill (rcsbuf, pat, NULL, strp);
- if (pat == NULL)
- {
- /* 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;
-
- }
- ptrend = rcsbuf->ptrend;
-
- /* Note that the value of PTR is bogus here. This is
- OK, because we don't use it. */
- }
-
- if (pat + 1 >= ptrend || pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
- }
-
- /* Here PAT points to the final '@' in the string. */
-
- *pat = '\0';
-
- vlen = pat - *strp;
- if (vlen == 0)
- *strp = NULL;
- rcsbuf->vlen = vlen;
- rcsbuf->ptr = pat + 1;
-
- return 1;
-
-#undef my_whitespace
-}
-
-/* Read an RCS `word', in the sense of rcsfile(5) (an id, a num, a
- @-delimited string, or `:'). Store the result in WORDP. If a
- `;' is reached without reading any text, the result is NULL. */
-
-static int
-rcsbuf_getword (rcsbuf, wordp)
- struct rcsbuffer *rcsbuf;
- char **wordp;
-{
- register const char * const my_spacetab = spacetab;
- register char *ptr, *ptrend;
- char c;
-
-#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
-
- rcsbuf->vlen = 0;
- rcsbuf->at_string = 0;
- rcsbuf->embedded_at = 0;
-
- ptr = rcsbuf->ptr;
- ptrend = rcsbuf->ptrend;
-
- /* Sanity check. */
- if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size)
- abort ();
-
- /* 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)
- {
- int len;
-
- len = ptrend - ptr;
-
- /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes
- at a time, so we can't have more bytes than that past PTR. */
- if (len > RCSBUF_BUFSIZE)
- abort ();
-
- /* Update the POS field, which holds the file offset of the
- first byte in the RCSBUF_BUFFER buffer. */
- rcsbuf->pos += ptr - rcsbuf_buffer;
-
- memcpy (rcsbuf_buffer, ptr, len);
- ptr = rcsbuf_buffer;
- ptrend = ptr + len;
- rcsbuf->ptrend = ptrend;
- }
-
- /* Skip leading whitespace. */
-
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- c = *ptr;
- if (! my_whitespace (c))
- break;
-
- ++ptr;
- }
-
- /* If we have reached `;', there is no value. */
- if (c == ';')
- {
- *wordp = NULL;
- *ptr++ = '\0';
- rcsbuf->ptr = ptr;
- rcsbuf->vlen = 0;
- return 1;
- }
-
- /* PTR now points to the start of a value. Find out whether it is
- a num, an id, a string or a colon. */
- if (c == ':')
- {
- *wordp = ptr++;
- rcsbuf->ptr = ptr;
- rcsbuf->vlen = 1;
- return 1;
- }
-
- if (c == '@')
- {
- char *pat;
- size_t vlen;
-
- /* Optimize the common case of a value composed of a single
- '@' string. */
-
- rcsbuf->at_string = 1;
-
- ++ptr;
-
- *wordp = ptr;
-
- while (1)
- {
- while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL)
- {
- /* Note that we pass PTREND as the PTR value to
- rcsbuf_fill, so that we will wind up setting PTR to
- the location corresponding to the old PTREND, so
- that we don't search the same bytes again. */
- ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, wordp);
- if (ptr == NULL)
- error (1, 0,
- "EOF while looking for end of string in RCS file %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Handle the special case of an '@' right at the end of
- the known bytes. */
- if (pat + 1 >= ptrend)
- {
- /* Note that we pass PAT, not PTR, here. */
- pat = rcsbuf_fill (rcsbuf, pat, NULL, wordp);
- if (pat == NULL)
- {
- /* 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;
-
- }
- ptrend = rcsbuf->ptrend;
-
- /* Note that the value of PTR is bogus here. This is
- OK, because we don't use it. */
- }
-
- if (pat + 1 >= ptrend || pat[1] != '@')
- break;
-
- /* We found an '@' pair in the string. Keep looking. */
- ++rcsbuf->embedded_at;
- ptr = pat + 2;
- }
-
- /* Here PAT points to the final '@' in the string. */
-
- *pat = '\0';
-
- vlen = pat - *wordp;
- if (vlen == 0)
- *wordp = NULL;
- rcsbuf->vlen = vlen;
- rcsbuf->ptr = pat + 1;
-
- return 1;
- }
-
- /* C is neither `:', `;' nor `@', so it should be the start of a num
- or an id. Make sure it is not another special character. */
- if (c == '$' || c == '.' || c == ',')
- {
- error (1, 0, "illegal special character in RCS field in %s",
- rcsbuf->filename);
- }
-
- *wordp = ptr;
- while (1)
- {
- if (ptr >= ptrend)
- {
- ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, wordp);
- if (ptr == NULL)
- error (1, 0, "unexpected end of file reading %s",
- rcsbuf->filename);
- ptrend = rcsbuf->ptrend;
- }
-
- /* Legitimate ID characters are digits, dots and any `graphic
- printing character that is not a special.' This test ought
- to do the trick. */
- c = *ptr;
- if (isprint ((unsigned char) c) &&
- c != ';' && c != '$' && c != ',' && c != '@' && c != ':')
- {
- ++ptr;
- continue;
- }
- break;
- }
-
- /* PTR points to the last non-id character in this word, and C is
- the character in its memory cell. Check to make sure that it
- is a legitimate word delimiter -- whitespace or semicolon. */
- if (c == ';' || my_whitespace (c))
- {
- rcsbuf->vlen = ptr - *wordp;
- rcsbuf->ptr = ptr;
- return 1;
- }
-
- error (1, 0, "illegal special character in RCS field in %s",
- rcsbuf->filename);
- /* Shut up compiler warnings. */
- return 0;
-
-#undef my_whitespace
-}
-
/* Read an RCS revision number from an RCS file. This sets *REVP to
point to the revision number; it will point to space that is
managed by the rcsbuf functions, and is only good until the next
@@ -1988,6 +1510,8 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp)
koff = *keyp - rcsbuf_buffer;
if (valp != NULL && *valp != NULL)
voff = *valp - rcsbuf_buffer;
+ koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer;
+ voff = valp == NULL ? 0 : *valp - rcsbuf_buffer;
expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size,
rcsbuf_buffer_size + RCSBUF_BUFSIZE);
@@ -2013,6 +1537,16 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp)
return ptr;
}
+/* Test whether the last value returned by rcsbuf_getkey is a composite
+ value or not. */
+
+static int
+rcsbuf_valcmp (rcsbuf)
+ struct rcsbuffer *rcsbuf;
+{
+ return rcsbuf->at_string && rcsbuf->embedded_at < 0;
+}
+
/* Copy the value VAL returned by rcsbuf_getkey into a memory buffer,
returning the memory buffer. Polish the value like
rcsbuf_valpolish, q.v. */
@@ -2036,7 +1570,7 @@ rcsbuf_valcopy (rcsbuf, val, polish, lenp)
}
vlen = rcsbuf->vlen;
- embedded_at = rcsbuf->embedded_at;
+ embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at;
ret = xmalloc (vlen - embedded_at + 1);
@@ -2143,6 +1677,7 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
orig_to = to;
embedded_at = rcsbuf->embedded_at;
+ assert (embedded_at > 0);
if (lenp != NULL)
*lenp = len - embedded_at;
@@ -2191,6 +1726,112 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp)
}
}
+#ifdef PRESERVE_PERMISSIONS_SUPPORT
+
+/* Copy the next word from the value VALP returned by rcsbuf_getkey into a
+ memory buffer, updating VALP and returning the memory buffer. Return
+ NULL when there are no more words. */
+
+static char *
+rcsbuf_valword (rcsbuf, valp)
+ struct rcsbuffer *rcsbuf;
+ char **valp;
+{
+ register const char * const my_spacetab = spacetab;
+ register char *ptr, *pat;
+ char c;
+
+#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0)
+
+ if (*valp == NULL)
+ return NULL;
+
+ for (ptr = *valp; my_whitespace (*ptr); ++ptr) ;
+ if (*ptr == '\0')
+ {
+ assert (ptr - *valp == rcsbuf->vlen);
+ *valp = NULL;
+ rcsbuf->vlen = 0;
+ return NULL;
+ }
+
+ /* PTR now points to the start of a value. Find out whether it is
+ a num, an id, a string or a colon. */
+ c = *ptr;
+ if (c == ':')
+ {
+ rcsbuf->vlen -= ++ptr - *valp;
+ *valp = ptr;
+ return xstrdup (":");
+ }
+
+ if (c == '@')
+ {
+ int embedded_at = 0;
+ size_t vlen;
+
+ pat = ++ptr;
+ while ((pat = strchr (pat, '@')) != NULL)
+ {
+ if (pat[1] != '@')
+ break;
+ ++embedded_at;
+ pat += 2;
+ }
+
+ /* Here PAT points to the final '@' in the string. */
+ *pat++ = '\0';
+ assert (rcsbuf->at_string);
+ vlen = rcsbuf->vlen - (pat - *valp);
+ rcsbuf->vlen = pat - ptr - 1;
+ rcsbuf->embedded_at = embedded_at;
+ ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL);
+ *valp = pat;
+ rcsbuf->vlen = vlen;
+ if (strchr (pat, '@') == NULL)
+ rcsbuf->at_string = 0;
+ else
+ rcsbuf->embedded_at = -1;
+ return ptr;
+ }
+
+ /* *PTR is neither `:', `;' nor `@', so it should be the start of a num
+ or an id. Make sure it is not another special character. */
+ if (c == '$' || c == '.' || c == ',')
+ {
+ error (1, 0, "illegal special character in RCS field in %s",
+ rcsbuf->filename);
+ }
+
+ pat = ptr;
+ while (1)
+ {
+ /* Legitimate ID characters are digits, dots and any `graphic
+ printing character that is not a special.' This test ought
+ to do the trick. */
+ c = *++pat;
+ if (!isprint ((unsigned char) c) ||
+ c == ';' || c == '$' || c == ',' || c == '@' || c == ':')
+ break;
+ }
+
+ /* PAT points to the last non-id character in this word, and C is
+ the character in its memory cell. Check to make sure that it
+ is a legitimate word delimiter -- whitespace or end. */
+ if (c != '\0' && !my_whitespace (c))
+ error (1, 0, "illegal special character in RCS field in %s",
+ rcsbuf->filename);
+
+ *pat = '\0';
+ rcsbuf->vlen -= pat - *valp;
+ *valp = pat;
+ return xstrdup (ptr);
+
+#undef my_whitespace
+}
+
+#endif
+
/* Return the current position of an rcsbuf. */
static unsigned long
@@ -2880,8 +2521,8 @@ RCS_nodeisbranch (rcs, rev)
return (1);
}
free (magic);
- free (version);
}
+ free (version);
return (0);
}
@@ -2930,8 +2571,8 @@ RCS_whatbranch (rcs, rev)
return (magic);
}
free (magic);
- free (version);
}
+ free (version);
return ((char *) NULL);
}
@@ -4102,6 +3743,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
uses for ci -k. */
if (kw == KEYWORD_LOG
&& (sizeof "checked in with -k by " <= loglen
+ || log == NULL
|| strncmp (log, "checked in with -k by ",
sizeof "checked in with -k by " - 1) != 0))
{
@@ -4120,6 +3762,10 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
if (expand != KFLAG_V)
++s;
+ /* CVS never has empty log messages, but old RCS files might. */
+ if (log == NULL)
+ log = "";
+
/* Find the start of the line. */
start = srch;
while (start > buf && start[-1] != '\n')
@@ -4690,6 +4336,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
#ifdef PRESERVE_PERMISSIONS_SUPPORT
else if (special_file)
{
+#ifdef HAVE_MKNOD
char *dest;
/* Can send either to WORKFILE or to SOUT, as long as SOUT is
@@ -4710,6 +4357,11 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (mknod (dest, special_file, devnum) < 0)
error (1, errno, "could not create special file %s",
dest);
+#else
+ error (1, 0,
+"cannot create %s: unable to create special files on this system",
+workfile);
+#endif
}
#endif
else
@@ -5073,8 +4725,10 @@ RCS_addbranch (rcs, branch)
if (nodep == NULL)
{
error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint);
+ free (branchpoint);
return NULL;
}
+ free (branchpoint);
branchnode = (RCSVers *) nodep->data;
/* If BRANCH was a full branch number, make sure it is higher than MAX. */
@@ -5276,6 +4930,7 @@ RCS_checkin (rcs, workfile, message, rev, flags)
if (S_ISLNK (sb.st_mode))
{
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("symlink");
np->data = xreadlink (workfile);
addnode (delta->other_delta, np);
@@ -5284,18 +4939,21 @@ RCS_checkin (rcs, workfile, message, rev, flags)
{
(void) sprintf (buf, "%u", sb.st_uid);
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("owner");
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
(void) sprintf (buf, "%u", sb.st_gid);
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("group");
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
(void) sprintf (buf, "%o", sb.st_mode & 07777);
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("permissions");
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
@@ -5306,7 +4964,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
case S_IFREG: break;
case S_IFCHR:
case S_IFBLK:
+#ifdef HAVE_ST_RDEV
np = getnode();
+ np->type = RCSFIELD;
np->key = xstrdup ("special");
sprintf (buf, "%s %lu",
((sb.st_mode & S_IFMT) == S_IFCHR
@@ -5314,6 +4974,11 @@ RCS_checkin (rcs, workfile, message, rev, flags)
(unsigned long) sb.st_rdev);
np->data = xstrdup (buf);
addnode (delta->other_delta, np);
+#else
+ error (0, 0,
+"can't preserve %s: unable to save device files on this system",
+workfile);
+#endif
break;
default:
@@ -5358,8 +5023,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
delta->version = xstrdup (newrev);
nodep = getnode();
nodep->type = RCSVERS;
- nodep->key = xstrdup (newrev);
+ nodep->delproc = rcsvers_delproc;
nodep->data = (char *) delta;
+ nodep->key = delta->version;
(void) addnode (rcs->versions, nodep);
dtext->version = xstrdup (newrev);
@@ -5393,7 +5059,6 @@ RCS_checkin (rcs, workfile, message, rev, flags)
error (1, errno, "cannot ftell for %s", rcs->path);
putdeltatext (fout, dtext);
rcs_internal_unlockfile (fout, rcs->path);
- freedeltatext (dtext);
if ((flags & RCS_FLAGS_KEEPFILE) == 0)
{
@@ -5405,7 +5070,8 @@ RCS_checkin (rcs, workfile, message, rev, flags)
if (!checkin_quiet)
cvs_output ("done\n", 5);
- return 0;
+ status = 0;
+ goto checkin_done;
}
/* Derive a new revision number. From the `ci' man page:
@@ -5501,6 +5167,13 @@ RCS_checkin (rcs, workfile, message, rev, flags)
goto checkin_done;
}
delta->version = RCS_addbranch (rcs, branch);
+ if (!delta->version)
+ {
+ free (branch);
+ free (newrev);
+ status = 1;
+ goto checkin_done;
+ }
adding_branch = 1;
p = strrchr (branch, '.');
*p = '\0';
@@ -5725,8 +5398,9 @@ RCS_checkin (rcs, workfile, message, rev, flags)
rcs->versions = getlist();
nodep = getnode();
nodep->type = RCSVERS;
- nodep->key = xstrdup (delta->version);
+ nodep->delproc = rcsvers_delproc;
nodep->data = (char *) delta;
+ nodep->key = delta->version;
(void) addnode (rcs->versions, nodep);
/* Write the new RCS file, inserting the new delta at COMMITPT. */
@@ -5749,8 +5423,10 @@ RCS_checkin (rcs, workfile, message, rev, flags)
}
if (unlink_file (tmpfile) < 0)
error (0, errno, "cannot remove %s", tmpfile);
+ free (tmpfile);
if (unlink_file (changefile) < 0)
error (0, errno, "cannot remove %s", changefile);
+ free (changefile);
if (!checkin_quiet)
cvs_output ("done\n", 5);
@@ -5833,6 +5509,7 @@ RCS_cmp_file (rcs, rev, options, filename)
retcode = xcmp (tmp, filename);
if (CVS_UNLINK (tmp) < 0)
error (0, errno, "cannot remove %s", tmp);
+ free (tmp);
return retcode;
}
else
@@ -6193,17 +5870,14 @@ RCS_unlock (rcs, rev, unlock_quiet)
lock = NULL;
for (p = locks->list->next; p != locks->list; p = p->next)
{
- if (STREQ (p->data, user))
+ if (lock != NULL)
{
- if (lock != NULL)
- {
- if (!unlock_quiet)
- error (0, 0, "\
+ if (!unlock_quiet)
+ error (0, 0, "\
%s: multiple revisions locked by %s; please specify one", rcs->path, user);
- return 1;
- }
- lock = p;
+ return 1;
}
+ lock = p;
}
if (lock == NULL)
return 0; /* no lock found, ergo nothing to do */
@@ -6283,6 +5957,7 @@ RCS_addaccess (rcs, user)
return;
}
}
+ free (access);
rcs->access = (char *) xrealloc
(rcs->access, strlen (rcs->access) + strlen (user) + 2);
strcat (rcs->access, " ");
@@ -6306,13 +5981,19 @@ RCS_delaccess (rcs, user)
if (rcs->access == NULL)
return;
+ if (user == NULL)
+ {
+ free (rcs->access);
+ rcs->access = NULL;
+ return;
+ }
+
p = rcs->access;
ulen = strlen (user);
while (p != NULL)
{
- if (p[ulen] == '\0' || p[ulen] == ' ')
- if (strncmp (p, user, ulen) == 0)
- break;
+ if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' '))
+ break;
p = strchr (p, ' ');
if (p != NULL)
++p;
@@ -7711,7 +7392,7 @@ getdelta (rcsbuf, rcsfile, keyp, valp)
char **valp;
{
RCSVers *vnode;
- char *key, *value, *keybuf, *valbuf, *cp;
+ char *key, *value, *cp;
Node *kv;
/* Get revision number if it wasn't passed in. This uses
@@ -7829,81 +7510,32 @@ unable to parse %s; `state' not in the expected place", rcsfile);
*/
while (1)
{
- int len;
- size_t valbuflen;
-
- key = NULL;
-
- if (! rcsbuf_getid (rcsbuf, &keybuf))
+ if (! rcsbuf_getkey (rcsbuf, &key, &value))
error (1, 0, "unexpected end of file reading %s", rcsfile);
- /* rcsbuf_getid did not terminate the key, so copy it to new space. */
- len = rcsbuf->ptr - keybuf;
- key = (char *) xmalloc (sizeof(char) * (len + 1));
- strncpy (key, keybuf, len);
- key[len] = '\0';
-
- /* The `desc' keyword has only a single string value, with no
- trailing semicolon, so it must be handled specially. */
- if (STREQ (key, RCSDESC))
- {
- (void) rcsbuf_getstring (rcsbuf, &valbuf);
- value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
+ /* The `desc' keyword is the end of the deltas. */
+ if (strcmp (key, RCSDESC) == 0)
break;
- }
#ifdef PRESERVE_PERMISSIONS_SUPPORT
+
/* The `hardlinks' value is a group of words, which must
be parsed separately and added as a list to vnode->hardlinks. */
- if (STREQ (key, "hardlinks"))
+ if (strcmp (key, "hardlinks") == 0)
{
- Node *n;
+ char *word;
vnode->hardlinks = getlist();
- while (1)
+ while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL)
{
- if (! rcsbuf_getword (rcsbuf, &valbuf))
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- if (valbuf == NULL)
- break;
- n = getnode();
- n->key = rcsbuf_valcopy (rcsbuf, valbuf, 1, NULL);
+ Node *n = getnode();
+ n->key = word;
addnode (vnode->hardlinks, n);
}
continue;
}
#endif
- /* Get the value. */
- value = NULL;
- while (1)
- {
- if (! rcsbuf_getword (rcsbuf, &valbuf))
- error (1, 0, "unexpected end of file reading %s", rcsfile);
- if (valbuf == NULL)
- break;
-
- /* Copy valbuf to new space so we can polish it, then
- append it to value. */
-
- if (value == NULL)
- {
- value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
- }
- else
- {
- char *temp_value;
-
- temp_value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen);
- len = strlen (value);
- value = (char *) xrealloc
- (value, sizeof(char) * (len + valbuflen + 2));
- value[len] = ' ';
- strcpy (value + len + 1, temp_value);
- free (temp_value);
- }
- }
-
/* Enable use of repositories created by certain obsolete
versions of CVS. This code should remain indefinately;
there is no procedure for converting old repositories, and
@@ -7932,9 +7564,10 @@ unable to parse %s; `state' not in the expected place", rcsfile);
if (vnode->other_delta == NULL)
vnode->other_delta = getlist ();
kv = getnode ();
- kv->type = RCSFIELD;
- kv->key = key;
- kv->data = value;
+ kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
+ kv->key = xstrdup (key);
+ kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (vnode->other_delta, kv) != 0)
{
/* Complaining about duplicate keys in newphrases seems
@@ -8019,9 +7652,10 @@ RCS_getdeltatext (rcs, fp, rcsbuf)
break;
p = getnode();
- p->type = RCSFIELD;
+ p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
p->key = xstrdup (key);
- p->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL);
+ p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD,
+ (size_t *) NULL);
if (addnode (d->other, p) < 0)
{
error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
@@ -8102,8 +7736,8 @@ putrcsfield_proc (node, vfp)
A case where we are wrong in a much more clear-cut way is that
we let through non-graphic characters such as whitespace and
control characters. */
- int n = strcspn (node->data, "$,.:;@");
- if (node->data[n] == 0)
+
+ if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
fputs (node->data, fp);
else
{
@@ -8264,7 +7898,13 @@ RCS_putdtree (rcs, rev, fp)
/* Find the delta node for this revision. */
p = findnode (rcs->versions, rev);
- assert (p != NULL);
+ if (p == NULL)
+ {
+ error (1, 0,
+ "error parsing repository file %s, file may be corrupt.",
+ rcs->path);
+ }
+
versp = (RCSVers *) p->data;
/* Print the delta node and recurse on its `next' node. This prints
@@ -8385,6 +8025,7 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt)
/* If this revision has been outdated, just skip it. */
if (dadmin->outdated)
{
+ freedeltatext (dtext);
--actions;
continue;
}
@@ -8504,7 +8145,7 @@ count_delta_actions (np, ignore)
/*
* Clean up temporary files
*/
-static RETSIGTYPE
+RETSIGTYPE
rcs_cleanup ()
{
/* Note that the checks for existence_error are because we are
@@ -8518,11 +8159,18 @@ rcs_cleanup ()
of a just-created file) reentrancy won't be an issue. */
if (rcs_lockfile != NULL)
{
- if (unlink_file (rcs_lockfile) < 0
+ char *tmp = rcs_lockfile;
+ rcs_lockfile = NULL;
+ if (rcs_lockfd >= 0)
+ {
+ if (close (rcs_lockfd) != 0)
+ error (0, errno, "error closing lock file %s", tmp);
+ rcs_lockfd = -1;
+ }
+ if (unlink_file (tmp) < 0
&& !existence_error (errno))
- error (0, errno, "cannot remove %s", rcs_lockfile);
+ error (0, errno, "cannot remove %s", tmp);
}
- rcs_lockfile = NULL;
}
/* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style
@@ -8556,7 +8204,6 @@ static FILE *
rcs_internal_lockfile (rcsfile)
char *rcsfile;
{
- int fd;
struct stat rstat;
FILE *fp;
static int first_call = 1;
@@ -8565,6 +8212,9 @@ rcs_internal_lockfile (rcsfile)
{
first_call = 0;
/* clean up if we get a signal */
+#ifdef SIGABRT
+ (void) SIG_register (SIGABRT, rcs_cleanup);
+#endif
#ifdef SIGHUP
(void) SIG_register (SIGHUP, rcs_cleanup);
#endif
@@ -8584,6 +8234,7 @@ rcs_internal_lockfile (rcsfile)
/* Get the lock file name: `,file,' for RCS file `file,v'. */
assert (rcs_lockfile == NULL);
+ assert (rcs_lockfd < 0);
rcs_lockfile = rcs_lockfilename (rcsfile);
/* Use the existing RCS file mode, or read-only if this is a new
@@ -8610,11 +8261,11 @@ rcs_internal_lockfile (rcsfile)
rely on O_EXCL these days. This might be true for unix (I
don't really know), but I am still pretty skeptical in the case
of the non-unix systems. */
- fd = open (rcs_lockfile,
- OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
- S_IRUSR | S_IRGRP | S_IROTH);
+ rcs_lockfd = open (rcs_lockfile,
+ OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
+ S_IRUSR | S_IRGRP | S_IROTH);
- if (fd < 0)
+ if (rcs_lockfd < 0)
{
error (1, errno, "could not open lock file `%s'", rcs_lockfile);
}
@@ -8623,10 +8274,10 @@ rcs_internal_lockfile (rcsfile)
/* Because we change the modes later, we don't worry about
this in the non-HAVE_FCHMOD case. */
#ifdef HAVE_FCHMOD
- if (fchmod (fd, rstat.st_mode) < 0)
+ if (fchmod (rcs_lockfd, rstat.st_mode) < 0)
error (1, errno, "cannot change mode for %s", rcs_lockfile);
#endif
- fp = fdopen (fd, FOPEN_BINARY_WRITE);
+ fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE);
if (fp == NULL)
error (1, errno, "cannot fdopen %s", rcs_lockfile);
@@ -8639,6 +8290,7 @@ rcs_internal_unlockfile (fp, rcsfile)
char *rcsfile;
{
assert (rcs_lockfile != NULL);
+ assert (rcs_lockfd >= 0);
/* Abort if we could not write everything successfully to LOCKFILE.
This is not a great error-handling mechanism, but should prevent
@@ -8654,6 +8306,7 @@ rcs_internal_unlockfile (fp, rcsfile)
error (1, 0, "error writing to lock file %s", rcs_lockfile);
if (fclose (fp) == EOF)
error (1, errno, "error closing lock file %s", rcs_lockfile);
+ rcs_lockfd = -1;
rename_file (rcs_lockfile, rcsfile);
@@ -8747,6 +8400,22 @@ RCS_rewrite (rcs, newdtext, insertpt)
rcs_internal_unlockfile (fout, rcs->path);
}
+/* Abandon changes to an RCS file. */
+
+void
+RCS_abandon (rcs)
+ RCSNode *rcs;
+{
+ free_rcsnode_contents (rcs);
+ rcs->symbols_data = NULL;
+ rcs->expand = NULL;
+ rcs->access = NULL;
+ rcs->locks_data = NULL;
+ rcs->comment = NULL;
+ rcs->desc = NULL;
+ rcs->flags |= PARTIAL;
+}
+
/* Annotate command. In rcs.c for historical reasons (from back when
what is now RCS_deltas was part of annotate_fileproc). */
OpenPOWER on IntegriCloud