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.c168
1 files changed, 154 insertions, 14 deletions
diff --git a/contrib/cvs/src/subr.c b/contrib/cvs/src/subr.c
index 8ed9177..6a88849 100644
--- a/contrib/cvs/src/subr.c
+++ b/contrib/cvs/src/subr.c
@@ -9,6 +9,7 @@
*/
#include "cvs.h"
+#include "getline.h"
extern char *getlogin ();
@@ -55,6 +56,43 @@ xrealloc (ptr, bytes)
return (cp);
}
+/* Two constants which tune expand_string. Having MIN_INCR as large
+ as 1024 might waste a bit of memory, but it shouldn't be too bad
+ (CVS used to allocate arrays of, say, 3000, PATH_MAX (8192, often),
+ or other such sizes). Probably anything which is going to allocate
+ memory which is likely to get as big as MAX_INCR shouldn't be doing
+ it in one block which must be contiguous, but since getrcskey does
+ so, we might as well limit the wasted memory to MAX_INCR or so
+ bytes. */
+
+#define MIN_INCR 1024
+#define MAX_INCR (2*1024*1024)
+
+/* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N
+ characters of space. Reallocate it so that points to at least
+ NEWSIZE bytes of space. Gives a fatal error if out of memory;
+ if it returns it was successful. */
+void
+expand_string (strptr, n, newsize)
+ char **strptr;
+ size_t *n;
+ size_t newsize;
+{
+ if (*n < newsize)
+ {
+ while (*n < newsize)
+ {
+ if (*n < MIN_INCR)
+ *n += MIN_INCR;
+ else if (*n > MAX_INCR)
+ *n += MAX_INCR;
+ else
+ *n *= 2;
+ }
+ *strptr = xrealloc (*strptr, *n);
+ }
+}
+
/*
* Duplicate a string, calling xmalloc to allocate some dynamic space
*/
@@ -76,15 +114,57 @@ void
strip_trailing_newlines (str)
char *str;
{
- int len;
- len = strlen (str) - 1;
+ int len;
+ len = strlen (str) - 1;
- while (str[len] == '\n')
- str[len--] = '\0';
+ while (str[len] == '\n')
+ str[len--] = '\0';
}
+/* 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. */
+int
+pathname_levels (path)
+ char *path;
+{
+ char *p;
+ char *q;
+ int level;
+ int max_level;
+
+ 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] == '/'))
+ {
+ --level;
+ if (-level > max_level)
+ max_level = -level;
+ }
+ else if (p[0] == '.' && (p[1] == '\0' || p[1] == '/'))
+ ;
+ else
+ ++level;
+ p = q;
+ } while (p != NULL);
+ return max_level;
+}
+
+
/*
- * Recover the space allocated by Find_Names() and line2argv()
+ * Recover the space allocated by line2argv()
*/
void
free_names (pargc, argv)
@@ -97,26 +177,42 @@ free_names (pargc, argv)
{ /* only do through *pargc */
free (argv[i]);
}
+ free (argv);
*pargc = 0; /* and set it to zero when done */
}
-/*
- * Convert a line into argc/argv components and return the result in the
- * arguments as passed. Use free_names() to return the memory allocated here
- * back to the free pool.
- */
+/* Convert LINE into arguments separated by space and tab. Set *ARGC
+ to the number of arguments found, and (*ARGV)[0] to the first argument,
+ (*ARGV)[1] to the second, etc. *ARGV is malloc'd and so are each of
+ (*ARGV)[0], (*ARGV)[1], ... Use free_names() to return the memory
+ allocated here back to the free pool. */
void
line2argv (pargc, argv, line)
int *pargc;
- char **argv;
+ char ***argv;
char *line;
{
char *cp;
+ /* Could make a case for size_t or some other unsigned type, but
+ we'll stick with int to avoid signed/unsigned warnings when
+ comparing with *pargc. */
+ int argv_allocated;
+
+ /* Small for testing. */
+ /* argv_allocated must be at least 3 because at some places
+ (e.g. checkout_proc) cvs alters argv[2]. */
+ argv_allocated = 4;
+ *argv = (char **) xmalloc (argv_allocated * sizeof (**argv));
*pargc = 0;
for (cp = strtok (line, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
{
- argv[*pargc] = xstrdup (cp);
+ if (*pargc == argv_allocated)
+ {
+ argv_allocated *= 2;
+ *argv = xrealloc (*argv, argv_allocated * sizeof (**argv));
+ }
+ (*argv)[*pargc] = xstrdup (cp);
(*pargc)++;
}
}
@@ -192,9 +288,10 @@ gca (rev1, rev2)
char *rev2;
{
int dots;
- char gca[PATH_MAX];
+ char *gca;
char *p[2];
int j[2];
+ char *retval;
if (rev1 == NULL || rev2 == NULL)
{
@@ -202,6 +299,11 @@ gca (rev1, rev2)
abort();
}
+ /* The greatest common ancestor will have no more dots, and numbers
+ of digits for each component no greater than the arguments. Therefore
+ this string will be big enough. */
+ gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
+
/* walk the strings, reading the common parts. */
gca[0] = '\0';
p[0] = rev1;
@@ -289,7 +391,9 @@ gca (rev1, rev2)
*s = '\0';
}
- return (xstrdup (gca));
+ retval = xstrdup (gca);
+ free (gca);
+ return retval;
}
/*
@@ -316,3 +420,39 @@ make_message_rcslegal (message)
return message;
}
+
+/* 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
+ which contain those patterns not as conflict markers), but for now it
+ is what we do. */
+int
+file_has_markers (finfo)
+ struct file_info *finfo;
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t line_allocated = 0;
+ int result;
+
+ result = 0;
+ fp = CVS_FOPEN (finfo->file, "r");
+ if (fp == NULL)
+ error (1, errno, "cannot open %s", finfo->fullname);
+ while (getline (&line, &line_allocated, fp) > 0)
+ {
+ if (strncmp (line, RCS_MERGE_PAT, sizeof RCS_MERGE_PAT - 1) == 0)
+ {
+ result = 1;
+ goto out;
+ }
+ }
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", finfo->fullname);
+out:
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", finfo->fullname);
+ if (line != NULL)
+ free (line);
+ return result;
+}
OpenPOWER on IntegriCloud