diff options
Diffstat (limited to 'contrib/cvs/src/subr.c')
-rw-r--r-- | contrib/cvs/src/subr.c | 168 |
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; +} |