summaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cvs/src/subr.c')
-rw-r--r--contrib/cvs/src/subr.c227
1 files changed, 185 insertions, 42 deletions
diff --git a/contrib/cvs/src/subr.c b/contrib/cvs/src/subr.c
index 7a6acfb..94f5bbd 100644
--- a/contrib/cvs/src/subr.c
+++ b/contrib/cvs/src/subr.c
@@ -8,6 +8,7 @@
* Various useful functions for the CVS support code.
*/
+#include <assert.h>
#include "cvs.h"
#include "getline.h"
@@ -51,7 +52,7 @@ xmalloc (bytes)
/*
* realloc data and die if it fails [I've always wanted to have "realloc" do
* a "malloc" if the argument is NULL, but you can't depend on it. Here, I
- * can *force* it.
+ * can *force* it.]
*/
void *
xrealloc (ptr, bytes)
@@ -149,61 +150,70 @@ xstrdup (str)
return (s);
}
-/* Remove trailing newlines from STRING, destructively. */
-void
+
+
+/* Remove trailing newlines from STRING, destructively.
+ *
+ * RETURNS
+ *
+ * True if any newlines were removed, false otherwise.
+ */
+int
strip_trailing_newlines (str)
- char *str;
+ char *str;
{
- int len;
- len = strlen (str) - 1;
+ size_t index, origlen;
+ index = origlen = strlen (str);
- while (str[len] == '\n')
- str[len--] = '\0';
+ while (index > 0 && str[index-1] == '\n')
+ str[--index] = '\0';
+
+ return index != origlen;
}
-/* Return the number of levels that path ascends above where it starts.
- For example:
- "../../foo" -> 2
- "foo/../../bar" -> 1
- */
-/* FIXME: Should be using ISDIRSEP, last_component, or some other
- mechanism which is more general than just looking at slashes,
- particularly for the client.c caller. The server.c caller might
- want something different, so be careful. */
+
+
+/* Return the number of levels that PATH ascends above where it starts.
+ * For example:
+ *
+ * "../../foo" -> 2
+ * "foo/../../bar" -> 1
+ */
int
-pathname_levels (path)
- char *path;
+pathname_levels (p)
+ const char *p;
{
- char *p;
- char *q;
int level;
int max_level;
+ if (p == NULL) return 0;
+
max_level = 0;
- p = path;
level = 0;
do
{
- q = strchr (p, '/');
- if (q != NULL)
- ++q;
- if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/'))
+ /* Now look for pathname level-ups. */
+ if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || ISDIRSEP (p[2])))
{
--level;
if (-level > max_level)
max_level = -level;
}
- else if (p[0] == '\0' || p[0] == '/' ||
- (p[0] == '.' && (p[1] == '\0' || p[1] == '/')))
+ else if (p[0] == '\0' || ISDIRSEP (p[0]) ||
+ (p[0] == '.' && (p[1] == '\0' || ISDIRSEP (p[1]))))
;
else
++level;
- p = q;
- } while (p != NULL);
+
+ /* q = strchr (p, '/'); but sub ISDIRSEP() for '/': */
+ while (*p != '\0' && !ISDIRSEP (*p)) p++;
+ if (*p != '\0') p++;
+ } while (*p != '\0');
return max_level;
}
-
+
+
/* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1]
are malloc'd and so is *ARGV itself. Such a vector is allocated by
line2argv or expand_wild, for example. */
@@ -283,13 +293,12 @@ compare_revnums (rev1, rev2)
const char *rev1;
const char *rev2;
{
- const char *s, *sp;
- const char *t, *tp;
+ const char *sp, *tp;
char *snext, *tnext;
int result = 0;
- sp = s = rev1;
- tp = t = rev2;
+ sp = rev1;
+ tp = rev2;
while (result == 0)
{
result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
@@ -393,6 +402,71 @@ get_date (date, now)
#endif
#endif
+
+
+/* Given some revision, REV, return the first prior revision that exists in the
+ * RCS file, RCS.
+ *
+ * ASSUMPTIONS
+ * REV exists.
+ *
+ * INPUTS
+ * RCS The RCS node pointer.
+ * REV An existing revision in the RCS file referred to by RCS.
+ *
+ * RETURNS
+ * The first prior revision that exists in the RCS file, or NULL if no prior
+ * revision exists. The caller is responsible for disposing of this string.
+ *
+ * NOTES
+ * This function currently neglects the case where we are on the trunk with
+ * rev = X.1, where X != 1. If rev = X.Y, where X != 1 and Y > 1, then this
+ * function should work fine, as revision X.1 must exist, due to RCS rules.
+ */
+char *
+previous_rev (rcs, rev)
+ RCSNode *rcs;
+ const char *rev;
+{
+ char *p;
+ char *tmp = xstrdup (rev);
+ long r1;
+ char *retval;
+
+ /* Our retval can have no more digits and dots than our input revision. */
+ retval = xmalloc (strlen (rev) + 1);
+ p = strrchr (tmp, '.');
+ *p = '\0';
+ r1 = strtol (p+1, NULL, 10);
+ do {
+ if (--r1 == 0)
+ {
+ /* If r1 == 0, then we must be on a branch and our parent must
+ * exist, or we must be on the trunk with a REV like X.1.
+ * We are neglecting the X.1 with X != 1 case by assuming that
+ * there is no previous revision when we discover we were on
+ * the trunk.
+ */
+ p = strrchr (tmp, '.');
+ if (p == NULL)
+ /* We are on the trunk. */
+ retval = NULL;
+ else
+ {
+ *p = '\0';
+ sprintf (retval, "%s", tmp);
+ }
+ break;
+ }
+ sprintf (retval, "%s.%ld", tmp, r1);
+ } while (!RCS_exist_rev (rcs, retval));
+
+ free (tmp);
+ return retval;
+}
+
+
+
/* Given two revisions, find their greatest common ancestor. If the
two input revisions exist, then rcs guarantees that the gca will
exist. */
@@ -518,9 +592,10 @@ check_numeric (rev, argc, argv)
*/
char *
make_message_rcslegal (message)
- char *message;
+ const char *message;
{
- char *dst, *dp, *mp;
+ char *dst, *dp;
+ const char *mp;
if (message == NULL) message = "";
@@ -553,6 +628,61 @@ make_message_rcslegal (message)
return dst;
}
+
+
+/*
+ * file_has_conflict
+ *
+ * This function compares the timestamp of a file with ts_conflict set
+ * to the timestamp on the actual file and returns TRUE or FALSE based
+ * on the results.
+ *
+ * This function does not check for actual markers in the file and
+ * file_has_markers() function should be called when that is interesting.
+ *
+ * ASSUMPTIONS
+ * The ts_conflict field is not NULL.
+ *
+ * RETURNS
+ * TRUE ts_conflict matches the current timestamp.
+ * FALSE The ts_conflict field does not match the file's
+ * timestamp.
+ */
+int
+file_has_conflict (finfo, ts_conflict)
+ const struct file_info *finfo;
+ const char *ts_conflict;
+{
+ char *filestamp;
+ int retcode;
+
+ /* If ts_conflict is NULL, there was no merge since the last
+ * commit and there can be no conflict.
+ */
+ assert ( ts_conflict );
+
+ /*
+ * If the timestamp has changed and no
+ * conflict indicators are found, it isn't a
+ * conflict any more.
+ */
+
+#ifdef SERVER_SUPPORT
+ if ( server_active )
+ retcode = ts_conflict[0] == '=';
+ else
+#endif /* SERVER_SUPPORT */
+ {
+ filestamp = time_stamp ( finfo->file );
+ retcode = !strcmp ( ts_conflict, filestamp );
+ free ( filestamp );
+ }
+
+ return retcode;
+}
+
+
+
/* Does the file FINFO contain conflict markers? The whole concept
of looking at the contents of the file to figure out whether there are
unresolved conflicts is kind of bogus (people do want to manage files
@@ -695,19 +825,18 @@ void
resolve_symlink (filename)
char **filename;
{
- if ((! filename) || (! *filename))
+ if (filename == NULL || *filename == NULL)
return;
while (islink (*filename))
{
- char *newname;
#ifdef HAVE_READLINK
/* The clean thing to do is probably to have each filesubr.c
implement this (with an error if not supported by the
platform, in which case islink would presumably return 0).
But that would require editing each filesubr.c and so the
expedient hack seems to be looking at HAVE_READLINK. */
- newname = xreadlink (*filename);
+ char *newname = xreadlink (*filename);
if (isabsolute (newname))
{
@@ -716,7 +845,7 @@ resolve_symlink (filename)
}
else
{
- char *oldname = last_component (*filename);
+ const char *oldname = last_component (*filename);
int dirlen = oldname - *filename;
char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
strncpy (fullnewname, *filename, dirlen);
@@ -797,6 +926,8 @@ shell_escape(buf, str)
return buf;
}
+
+
/*
* We can only travel forwards in time, not backwards. :)
*/
@@ -849,7 +980,8 @@ sleep_past (desttime)
struct timeval tv;
tv.tv_sec = s;
tv.tv_usec = us;
- (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &tv);
+ (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
+ &tv);
}
#else
if (us > 0) s++;
@@ -857,3 +989,14 @@ sleep_past (desttime)
#endif
}
}
+
+
+
+/* Return non-zero iff FILENAME is absolute.
+ Trivial under Unix, but more complicated under other systems. */
+int
+isabsolute (filename)
+ const char *filename;
+{
+ return ISABSOLUTE (filename);
+}
OpenPOWER on IntegriCloud