diff options
author | peter <peter@FreeBSD.org> | 1998-01-26 03:09:57 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1998-01-26 03:09:57 +0000 |
commit | e6e45661e44f15cb8c5c6f063080509bd910b98d (patch) | |
tree | a9812ba7ade0fde6f62c1626b45d522ba104c314 /contrib/cvs/src/subr.c | |
parent | 571cfa0005d94d99d1341bf8ab02be04d4df5f9f (diff) | |
download | FreeBSD-src-e6e45661e44f15cb8c5c6f063080509bd910b98d.zip FreeBSD-src-e6e45661e44f15cb8c5c6f063080509bd910b98d.tar.gz |
Import cvs-1.9.23 as at 19980123. There are a number of really nice
things fixed in here, including the '-ko' vs. -A problem with
remote cvs which caused all files with -ko to be resent each time
(which is damn painful over a modem, I can tell you). It also found a
heap of stray empty directories that should have been pruned with the -P
flag to cvs update but were not for some reason.
It also has the fully integrated rcs and diff, so no more fork/exec
overheads for rcs,ci,patch,diff,etc. This means that it parses the control
data in the rcs files only once rather than twice or more.
If the 'cvs diff' vs. Index thing is going to be fixed for future patch
compatability, this is the place to do it.
Diffstat (limited to 'contrib/cvs/src/subr.c')
-rw-r--r-- | contrib/cvs/src/subr.c | 241 |
1 files changed, 221 insertions, 20 deletions
diff --git a/contrib/cvs/src/subr.c b/contrib/cvs/src/subr.c index d29942b..61b3103 100644 --- a/contrib/cvs/src/subr.c +++ b/contrib/cvs/src/subr.c @@ -3,7 +3,7 @@ * Copyright (c) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS 1.4 kit. + * specified in the README file that comes with the CVS source distribution. * * Various useful functions for the CVS support code. */ @@ -30,7 +30,8 @@ xmalloc (bytes) cp = malloc (bytes); if (cp == NULL) - error (1, 0, "can not allocate %lu bytes", (unsigned long) bytes); + error (1, 0, "out of memory; can not allocate %lu bytes", + (unsigned long) bytes); return (cp); } @@ -181,16 +182,17 @@ free_names (pargc, argv) *pargc = 0; /* and set it to zero when done */ } -/* Convert LINE into arguments separated by space and tab. Set *ARGC +/* Convert LINE into arguments separated by SEPCHARS. 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) +line2argv (pargc, argv, line, sepchars) int *pargc; char ***argv; char *line; + char *sepchars; { char *cp; /* Could make a case for size_t or some other unsigned type, but @@ -205,7 +207,7 @@ line2argv (pargc, argv, line) *argv = (char **) xmalloc (argv_allocated * sizeof (**argv)); *pargc = 0; - for (cp = strtok (line, " \t"); cp; cp = strtok ((char *) NULL, " \t")) + for (cp = strtok (line, sepchars); cp; cp = strtok ((char *) NULL, sepchars)) { if (*pargc == argv_allocated) { @@ -234,6 +236,56 @@ numdots (s) return (dots); } +/* Compare revision numbers REV1 and REV2 by consecutive fields. + Return negative, zero, or positive in the manner of strcmp. The + two revision numbers must have the same number of fields, or else + compare_revnums will return an inaccurate result. */ +int +compare_revnums (rev1, rev2) + const char *rev1; + const char *rev2; +{ + const char *s, *sp; + const char *t, *tp; + char *snext, *tnext; + int result = 0; + + sp = s = rev1; + tp = t = rev2; + while (result == 0) + { + result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10); + if (*snext == '\0' || *tnext == '\0') + break; + sp = snext + 1; + tp = tnext + 1; + } + + return result; +} + +char * +increment_revnum (rev) + const char *rev; +{ + char *newrev, *p; + int lastfield; + size_t len = strlen (rev); + + newrev = (char *) xmalloc (len + 2); + memcpy (newrev, rev, len + 1); + p = strrchr (newrev, '.'); + if (p == NULL) + { + free (newrev); + return NULL; + } + lastfield = atoi (++p); + sprintf (p, "%d", lastfield + 1); + + return newrev; +} + /* Return the username by which the caller should be identified in CVS, in contexts such as the author field of RCS files, various logs, etc. @@ -244,10 +296,12 @@ numdots (s) char * getcaller () { +#ifndef SYSTEM_GETCALLER static char uidname[20]; struct passwd *pw; char *name; uid_t uid; +#endif /* If there is a CVS username, return it. */ #ifdef AUTH_SERVER_SUPPORT @@ -255,6 +309,9 @@ getcaller () return CVS_Username; #endif +#ifdef SYSTEM_GETCALLER + return SYSTEM_GETCALLER (); +#else /* Get the caller's login from his uid. If the real uid is "root" try LOGNAME USER or getlogin(). If getlogin() and getpwuid() both fail, return the uid as a string. */ @@ -273,6 +330,7 @@ getcaller () return (uidname); } return (pw->pw_name); +#endif } #ifdef lint @@ -296,12 +354,12 @@ get_date (date, now) char * gca (rev1, rev2) - char *rev1; - char *rev2; + const char *rev1; + const char *rev2; { int dots; char *gca; - char *p[2]; + const char *p[2]; int j[2]; char *retval; @@ -370,7 +428,7 @@ gca (rev1, rev2) /* revisions differ in trunk major number. */ char *q; - char *s; + const char *s; s = (j[0] < j[1]) ? p[0] : p[1]; @@ -408,29 +466,80 @@ gca (rev1, rev2) return retval; } +/* Give fatal error if REV is numeric and ARGC,ARGV imply we are + planning to operate on more than one file. The current directory + should be the working directory. Note that callers assume that we + will only be checking the first character of REV; it need not have + '\0' at the end of the tag name and other niceties. Right now this + is only called from admin.c, but if people like the concept it probably + should also be called from diff -r, update -r, get -r, and log -r. */ + +void +check_numeric (rev, argc, argv) + const char *rev; + int argc; + char **argv; +{ + if (rev == NULL || !isdigit (*rev)) + return; + + /* Note that the check for whether we are processing more than one + file is (basically) syntactic; that is, we don't behave differently + depending on whether a directory happens to contain only a single + file or whether it contains more than one. I strongly suspect this + is the least confusing behavior. */ + if (argc != 1 + || (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0]))) + { + error (0, 0, "while processing more than one file:"); + error (1, 0, "attempt to specify a numeric revision"); + } +} + /* * Sanity checks and any required fix-up on message passed to RCS via '-m'. * RCS 5.7 requires that a non-total-whitespace, non-null message be provided - * with '-m'. Returns the original argument or a pointer to readonly - * static storage. + * with '-m'. Returns a newly allocated, non-empty buffer with whitespace + * stripped from end of lines and end of buffer. + * + * TODO: We no longer use RCS to manage repository files, so maybe this + * nonsense about non-empty log fields can be dropped. */ char * make_message_rcslegal (message) char *message; { - if ((message == NULL) || (*message == '\0') || isspace (*message)) + char *dst, *dp, *mp; + + if (message == NULL) message = ""; + + /* Strip whitespace from end of lines and end of string. */ + dp = dst = (char *) xmalloc (strlen (message) + 1); + for (mp = message; *mp != '\0'; ++mp) { - char *t; + if (*mp == '\n') + { + /* At end-of-line; backtrack to last non-space. */ + while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t')) + --dp; + } + *dp++ = *mp; + } - if (message) - for (t = message; *t; t++) - if (!isspace (*t)) - return message; + /* Backtrack to last non-space at end of string, and truncate. */ + while (dp > dst && isspace (dp[-1])) + --dp; + *dp = '\0'; - return "*** empty log message ***\n"; + /* After all that, if there was no non-space in the string, + substitute a non-empty message. */ + if (*dst == '\0') + { + free (dst); + dst = xstrdup ("*** empty log message ***"); } - return message; + return dst; } /* Does the file FINFO contain conflict markers? The whole concept @@ -440,7 +549,7 @@ make_message_rcslegal (message) is what we do. */ int file_has_markers (finfo) - struct file_info *finfo; + const struct file_info *finfo; { FILE *fp; char *line = NULL; @@ -468,3 +577,95 @@ out: free (line); return result; } + +/* Read the entire contents of the file NAME into *BUF. + If NAME is NULL, read from stdin. *BUF + is a pointer returned from malloc (or NULL), pointing to *BUFSIZE + bytes of space. The actual size is returned in *LEN. On error, + give a fatal error. The name of the file to use in error messages + (typically will include a directory if we have changed directory) + is FULLNAME. MODE is "r" for text or "rb" for binary. */ + +void +get_file (name, fullname, mode, buf, bufsize, len) + const char *name; + const char *fullname; + const char *mode; + char **buf; + size_t *bufsize; + size_t *len; +{ + struct stat s; + size_t nread; + char *tobuf; + FILE *e; + size_t filesize; + + if (name == NULL) + { + e = stdin; + filesize = 100; /* force allocation of minimum buffer */ + } + else + { + if (CVS_STAT (name, &s) < 0) + error (1, errno, "can't stat %s", fullname); + /* Convert from signed to unsigned. */ + filesize = s.st_size; + + e = open_file (name, mode); + } + + if (*bufsize < filesize) + { + *bufsize = filesize; + *buf = xrealloc (*buf, *bufsize); + } + + tobuf = *buf; + nread = 0; + while (1) + { + size_t got; + + got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e); + if (ferror (e)) + error (1, errno, "can't read %s", fullname); + nread += got; + tobuf += got; + + if (feof (e)) + break; + + /* It's probably paranoid to think S.ST_SIZE might be + too small to hold the entire file contents, but we + handle it just in case. */ + if (tobuf == *buf + *bufsize) + { + int c; + long off; + + c = getc (e); + if (c == EOF) + break; + off = tobuf - *buf; + expand_string (buf, bufsize, *bufsize + 100); + tobuf = *buf + off; + *tobuf++ = c; + ++nread; + } + } + + if (e != stdin && fclose (e) < 0) + error (0, errno, "cannot close %s", fullname); + + *len = nread; + + /* Force *BUF to be large enough to hold a null terminator. */ + if (*buf != NULL) + { + if (nread == *bufsize) + expand_string (buf, bufsize, *bufsize + 1); + (*buf)[nread] = '\0'; + } +} |