subr.c revision 66525
117721Speter/* 217721Speter * Copyright (c) 1992, Brian Berliner and Jeff Polk 317721Speter * Copyright (c) 1989-1992, Brian Berliner 417721Speter * 517721Speter * You may distribute under the terms of the GNU General Public License as 632785Speter * specified in the README file that comes with the CVS source distribution. 717721Speter * 817721Speter * Various useful functions for the CVS support code. 917721Speter */ 1017721Speter 1117721Speter#include "cvs.h" 1225839Speter#include "getline.h" 1317721Speter 1417721Speterextern char *getlogin (); 1517721Speter 1617721Speter/* 1717721Speter * malloc some data and die if it fails 1817721Speter */ 1954427Spetervoid * 2017721Speterxmalloc (bytes) 2117721Speter size_t bytes; 2217721Speter{ 2317721Speter char *cp; 2417721Speter 2517721Speter /* Parts of CVS try to xmalloc zero bytes and then free it. Some 2617721Speter systems have a malloc which returns NULL for zero byte 2717721Speter allocations but a free which can't handle NULL, so compensate. */ 2817721Speter if (bytes == 0) 2917721Speter bytes = 1; 3017721Speter 3117721Speter cp = malloc (bytes); 3217721Speter if (cp == NULL) 3354427Speter { 3454427Speter char buf[80]; 3554427Speter sprintf (buf, "out of memory; can not allocate %lu bytes", 3654427Speter (unsigned long) bytes); 3754427Speter error (1, 0, buf); 3854427Speter } 3917721Speter return (cp); 4017721Speter} 4117721Speter 4217721Speter/* 4317721Speter * realloc data and die if it fails [I've always wanted to have "realloc" do 4417721Speter * a "malloc" if the argument is NULL, but you can't depend on it. Here, I 4517721Speter * can *force* it. 4617721Speter */ 4717721Spetervoid * 4817721Speterxrealloc (ptr, bytes) 4917721Speter void *ptr; 5017721Speter size_t bytes; 5117721Speter{ 5217721Speter char *cp; 5317721Speter 5417721Speter if (!ptr) 5517721Speter cp = malloc (bytes); 5617721Speter else 5717721Speter cp = realloc (ptr, bytes); 5817721Speter 5917721Speter if (cp == NULL) 6054427Speter { 6154427Speter char buf[80]; 6254427Speter sprintf (buf, "out of memory; can not reallocate %lu bytes", 6354427Speter (unsigned long) bytes); 6454427Speter error (1, 0, buf); 6554427Speter } 6617721Speter return (cp); 6717721Speter} 6817721Speter 6925839Speter/* Two constants which tune expand_string. Having MIN_INCR as large 7025839Speter as 1024 might waste a bit of memory, but it shouldn't be too bad 7125839Speter (CVS used to allocate arrays of, say, 3000, PATH_MAX (8192, often), 7225839Speter or other such sizes). Probably anything which is going to allocate 7325839Speter memory which is likely to get as big as MAX_INCR shouldn't be doing 7425839Speter it in one block which must be contiguous, but since getrcskey does 7525839Speter so, we might as well limit the wasted memory to MAX_INCR or so 7654427Speter bytes. 7725839Speter 7854427Speter MIN_INCR and MAX_INCR should both be powers of two and we generally 7954427Speter try to keep our allocations to powers of two for the most part. 8054427Speter Most malloc implementations these days tend to like that. */ 8154427Speter 8225839Speter#define MIN_INCR 1024 8325839Speter#define MAX_INCR (2*1024*1024) 8425839Speter 8525839Speter/* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N 8625839Speter characters of space. Reallocate it so that points to at least 8725839Speter NEWSIZE bytes of space. Gives a fatal error if out of memory; 8825839Speter if it returns it was successful. */ 8925839Spetervoid 9025839Speterexpand_string (strptr, n, newsize) 9125839Speter char **strptr; 9225839Speter size_t *n; 9325839Speter size_t newsize; 9425839Speter{ 9525839Speter if (*n < newsize) 9625839Speter { 9725839Speter while (*n < newsize) 9825839Speter { 9925839Speter if (*n < MIN_INCR) 10054427Speter *n = MIN_INCR; 10154427Speter else if (*n >= MAX_INCR) 10225839Speter *n += MAX_INCR; 10325839Speter else 10454427Speter { 10525839Speter *n *= 2; 10654427Speter if (*n > MAX_INCR) 10754427Speter *n = MAX_INCR; 10854427Speter } 10925839Speter } 11025839Speter *strptr = xrealloc (*strptr, *n); 11125839Speter } 11225839Speter} 11325839Speter 11417721Speter/* 11517721Speter * Duplicate a string, calling xmalloc to allocate some dynamic space 11617721Speter */ 11717721Speterchar * 11817721Speterxstrdup (str) 11917721Speter const char *str; 12017721Speter{ 12117721Speter char *s; 12217721Speter 12317721Speter if (str == NULL) 12417721Speter return ((char *) NULL); 12517721Speter s = xmalloc (strlen (str) + 1); 12617721Speter (void) strcpy (s, str); 12717721Speter return (s); 12817721Speter} 12917721Speter 13017721Speter/* Remove trailing newlines from STRING, destructively. */ 13117721Spetervoid 13217721Speterstrip_trailing_newlines (str) 13317721Speter char *str; 13417721Speter{ 13525839Speter int len; 13625839Speter len = strlen (str) - 1; 13717721Speter 13825839Speter while (str[len] == '\n') 13925839Speter str[len--] = '\0'; 14017721Speter} 14117721Speter 14225839Speter/* Return the number of levels that path ascends above where it starts. 14325839Speter For example: 14425839Speter "../../foo" -> 2 14525839Speter "foo/../../bar" -> 1 14625839Speter */ 14725839Speter/* FIXME: Should be using ISDIRSEP, last_component, or some other 14825839Speter mechanism which is more general than just looking at slashes, 14925839Speter particularly for the client.c caller. The server.c caller might 15025839Speter want something different, so be careful. */ 15125839Speterint 15225839Speterpathname_levels (path) 15325839Speter char *path; 15425839Speter{ 15525839Speter char *p; 15625839Speter char *q; 15725839Speter int level; 15825839Speter int max_level; 15925839Speter 16025839Speter max_level = 0; 16125839Speter p = path; 16225839Speter level = 0; 16325839Speter do 16425839Speter { 16525839Speter q = strchr (p, '/'); 16625839Speter if (q != NULL) 16725839Speter ++q; 16825839Speter if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/')) 16925839Speter { 17025839Speter --level; 17125839Speter if (-level > max_level) 17225839Speter max_level = -level; 17325839Speter } 17466525Speter else if (p[0] == '\0' || p[0] == '/' || 17566525Speter (p[0] == '.' && (p[1] == '\0' || p[1] == '/'))) 17625839Speter ; 17725839Speter else 17825839Speter ++level; 17925839Speter p = q; 18025839Speter } while (p != NULL); 18125839Speter return max_level; 18225839Speter} 18325839Speter 18425839Speter 18526065Speter/* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1] 18626065Speter are malloc'd and so is *ARGV itself. Such a vector is allocated by 18726065Speter line2argv or expand_wild, for example. */ 18817721Spetervoid 18917721Speterfree_names (pargc, argv) 19017721Speter int *pargc; 19117721Speter char **argv; 19217721Speter{ 19317721Speter register int i; 19417721Speter 19517721Speter for (i = 0; i < *pargc; i++) 19617721Speter { /* only do through *pargc */ 19717721Speter free (argv[i]); 19817721Speter } 19925839Speter free (argv); 20017721Speter *pargc = 0; /* and set it to zero when done */ 20117721Speter} 20217721Speter 20332785Speter/* Convert LINE into arguments separated by SEPCHARS. Set *ARGC 20425839Speter to the number of arguments found, and (*ARGV)[0] to the first argument, 20525839Speter (*ARGV)[1] to the second, etc. *ARGV is malloc'd and so are each of 20625839Speter (*ARGV)[0], (*ARGV)[1], ... Use free_names() to return the memory 20725839Speter allocated here back to the free pool. */ 20817721Spetervoid 20932785Speterline2argv (pargc, argv, line, sepchars) 21017721Speter int *pargc; 21125839Speter char ***argv; 21217721Speter char *line; 21332785Speter char *sepchars; 21417721Speter{ 21517721Speter char *cp; 21625839Speter /* Could make a case for size_t or some other unsigned type, but 21725839Speter we'll stick with int to avoid signed/unsigned warnings when 21825839Speter comparing with *pargc. */ 21925839Speter int argv_allocated; 22017721Speter 22125839Speter /* Small for testing. */ 22266525Speter argv_allocated = 1; 22325839Speter *argv = (char **) xmalloc (argv_allocated * sizeof (**argv)); 22425839Speter 22517721Speter *pargc = 0; 22632785Speter for (cp = strtok (line, sepchars); cp; cp = strtok ((char *) NULL, sepchars)) 22717721Speter { 22825839Speter if (*pargc == argv_allocated) 22925839Speter { 23025839Speter argv_allocated *= 2; 23125839Speter *argv = xrealloc (*argv, argv_allocated * sizeof (**argv)); 23225839Speter } 23325839Speter (*argv)[*pargc] = xstrdup (cp); 23417721Speter (*pargc)++; 23517721Speter } 23617721Speter} 23717721Speter 23817721Speter/* 23917721Speter * Returns the number of dots ('.') found in an RCS revision number 24017721Speter */ 24117721Speterint 24217721Speternumdots (s) 24317721Speter const char *s; 24417721Speter{ 24517721Speter int dots = 0; 24617721Speter 24717721Speter for (; *s; s++) 24817721Speter { 24917721Speter if (*s == '.') 25017721Speter dots++; 25117721Speter } 25217721Speter return (dots); 25317721Speter} 25417721Speter 25532785Speter/* Compare revision numbers REV1 and REV2 by consecutive fields. 25632785Speter Return negative, zero, or positive in the manner of strcmp. The 25732785Speter two revision numbers must have the same number of fields, or else 25832785Speter compare_revnums will return an inaccurate result. */ 25932785Speterint 26032785Spetercompare_revnums (rev1, rev2) 26132785Speter const char *rev1; 26232785Speter const char *rev2; 26332785Speter{ 26432785Speter const char *s, *sp; 26532785Speter const char *t, *tp; 26632785Speter char *snext, *tnext; 26732785Speter int result = 0; 26832785Speter 26932785Speter sp = s = rev1; 27032785Speter tp = t = rev2; 27132785Speter while (result == 0) 27232785Speter { 27332785Speter result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10); 27432785Speter if (*snext == '\0' || *tnext == '\0') 27532785Speter break; 27632785Speter sp = snext + 1; 27732785Speter tp = tnext + 1; 27832785Speter } 27932785Speter 28032785Speter return result; 28132785Speter} 28232785Speter 28332785Speterchar * 28432785Speterincrement_revnum (rev) 28532785Speter const char *rev; 28632785Speter{ 28732785Speter char *newrev, *p; 28832785Speter int lastfield; 28932785Speter size_t len = strlen (rev); 29032785Speter 29132785Speter newrev = (char *) xmalloc (len + 2); 29232785Speter memcpy (newrev, rev, len + 1); 29332785Speter p = strrchr (newrev, '.'); 29432785Speter if (p == NULL) 29532785Speter { 29632785Speter free (newrev); 29732785Speter return NULL; 29832785Speter } 29932785Speter lastfield = atoi (++p); 30032785Speter sprintf (p, "%d", lastfield + 1); 30132785Speter 30232785Speter return newrev; 30332785Speter} 30432785Speter 30526801Speter/* Return the username by which the caller should be identified in 30626801Speter CVS, in contexts such as the author field of RCS files, various 30734461Speter logs, etc. */ 30817721Speterchar * 30917721Spetergetcaller () 31017721Speter{ 31132785Speter#ifndef SYSTEM_GETCALLER 31234461Speter static char *cache; 31317721Speter struct passwd *pw; 31417721Speter uid_t uid; 31532785Speter#endif 31617721Speter 31726801Speter /* If there is a CVS username, return it. */ 31826801Speter#ifdef AUTH_SERVER_SUPPORT 31926801Speter if (CVS_Username != NULL) 32026801Speter return CVS_Username; 32126801Speter#endif 32226801Speter 32332785Speter#ifdef SYSTEM_GETCALLER 32432785Speter return SYSTEM_GETCALLER (); 32532785Speter#else 32626801Speter /* Get the caller's login from his uid. If the real uid is "root" 32726801Speter try LOGNAME USER or getlogin(). If getlogin() and getpwuid() 32826801Speter both fail, return the uid as a string. */ 32926801Speter 33034461Speter if (cache != NULL) 33134461Speter return cache; 33234461Speter 33317721Speter uid = getuid (); 33417721Speter if (uid == (uid_t) 0) 33517721Speter { 33634461Speter char *name; 33734461Speter 33817721Speter /* super-user; try getlogin() to distinguish */ 33917721Speter if (((name = getlogin ()) || (name = getenv("LOGNAME")) || 34017721Speter (name = getenv("USER"))) && *name) 34134461Speter { 34234461Speter cache = xstrdup (name); 34334461Speter return cache; 34434461Speter } 34517721Speter } 34617721Speter if ((pw = (struct passwd *) getpwuid (uid)) == NULL) 34717721Speter { 34834461Speter char uidname[20]; 34934461Speter 35017721Speter (void) sprintf (uidname, "uid%lu", (unsigned long) uid); 35134461Speter cache = xstrdup (uidname); 35234461Speter return cache; 35317721Speter } 35434461Speter cache = xstrdup (pw->pw_name); 35534461Speter return cache; 35632785Speter#endif 35717721Speter} 35817721Speter 35917721Speter#ifdef lint 36017721Speter#ifndef __GNUC__ 36117721Speter/* ARGSUSED */ 36217721Spetertime_t 36317721Speterget_date (date, now) 36417721Speter char *date; 36517721Speter struct timeb *now; 36617721Speter{ 36717721Speter time_t foo = 0; 36817721Speter 36917721Speter return (foo); 37017721Speter} 37117721Speter#endif 37217721Speter#endif 37317721Speter 37417721Speter/* Given two revisions, find their greatest common ancestor. If the 37517721Speter two input revisions exist, then rcs guarantees that the gca will 37617721Speter exist. */ 37717721Speter 37817721Speterchar * 37917721Spetergca (rev1, rev2) 38032785Speter const char *rev1; 38132785Speter const char *rev2; 38217721Speter{ 38317721Speter int dots; 38425839Speter char *gca; 38532785Speter const char *p[2]; 38617721Speter int j[2]; 38725839Speter char *retval; 38817721Speter 38917721Speter if (rev1 == NULL || rev2 == NULL) 39017721Speter { 39117721Speter error (0, 0, "sanity failure in gca"); 39217721Speter abort(); 39317721Speter } 39417721Speter 39525839Speter /* The greatest common ancestor will have no more dots, and numbers 39625839Speter of digits for each component no greater than the arguments. Therefore 39725839Speter this string will be big enough. */ 39825839Speter gca = xmalloc (strlen (rev1) + strlen (rev2) + 100); 39925839Speter 40017721Speter /* walk the strings, reading the common parts. */ 40117721Speter gca[0] = '\0'; 40217721Speter p[0] = rev1; 40317721Speter p[1] = rev2; 40417721Speter do 40517721Speter { 40617721Speter int i; 40717721Speter char c[2]; 40817721Speter char *s[2]; 40917721Speter 41017721Speter for (i = 0; i < 2; ++i) 41117721Speter { 41217721Speter /* swap out the dot */ 41317721Speter s[i] = strchr (p[i], '.'); 41417721Speter if (s[i] != NULL) { 41517721Speter c[i] = *s[i]; 41617721Speter } 41717721Speter 41817721Speter /* read an int */ 41917721Speter j[i] = atoi (p[i]); 42017721Speter 42117721Speter /* swap back the dot... */ 42217721Speter if (s[i] != NULL) { 42317721Speter *s[i] = c[i]; 42417721Speter p[i] = s[i] + 1; 42517721Speter } 42617721Speter else 42717721Speter { 42817721Speter /* or mark us at the end */ 42917721Speter p[i] = NULL; 43017721Speter } 43117721Speter 43217721Speter } 43317721Speter 43417721Speter /* use the lowest. */ 43517721Speter (void) sprintf (gca + strlen (gca), "%d.", 43617721Speter j[0] < j[1] ? j[0] : j[1]); 43717721Speter 43817721Speter } while (j[0] == j[1] 43917721Speter && p[0] != NULL 44017721Speter && p[1] != NULL); 44117721Speter 44217721Speter /* back up over that last dot. */ 44317721Speter gca[strlen(gca) - 1] = '\0'; 44417721Speter 44517721Speter /* numbers differ, or we ran out of strings. we're done with the 44617721Speter common parts. */ 44717721Speter 44817721Speter dots = numdots (gca); 44917721Speter if (dots == 0) 45017721Speter { 45117721Speter /* revisions differ in trunk major number. */ 45217721Speter 45317721Speter char *q; 45432785Speter const char *s; 45517721Speter 45617721Speter s = (j[0] < j[1]) ? p[0] : p[1]; 45717721Speter 45817721Speter if (s == NULL) 45917721Speter { 46017721Speter /* we only got one number. this is strange. */ 46117721Speter error (0, 0, "bad revisions %s or %s", rev1, rev2); 46217721Speter abort(); 46317721Speter } 46417721Speter else 46517721Speter { 46617721Speter /* we have a minor number. use it. */ 46717721Speter q = gca + strlen (gca); 46817721Speter 46917721Speter *q++ = '.'; 47017721Speter for ( ; *s != '.' && *s != '\0'; ) 47117721Speter *q++ = *s++; 47217721Speter 47317721Speter *q = '\0'; 47417721Speter } 47517721Speter } 47617721Speter else if ((dots & 1) == 0) 47717721Speter { 47817721Speter /* if we have an even number of dots, then we have a branch. 47917721Speter remove the last number in order to make it a revision. */ 48017721Speter 48117721Speter char *s; 48217721Speter 48317721Speter s = strrchr(gca, '.'); 48417721Speter *s = '\0'; 48517721Speter } 48617721Speter 48725839Speter retval = xstrdup (gca); 48825839Speter free (gca); 48925839Speter return retval; 49017721Speter} 49117721Speter 49232785Speter/* Give fatal error if REV is numeric and ARGC,ARGV imply we are 49332785Speter planning to operate on more than one file. The current directory 49432785Speter should be the working directory. Note that callers assume that we 49532785Speter will only be checking the first character of REV; it need not have 49632785Speter '\0' at the end of the tag name and other niceties. Right now this 49732785Speter is only called from admin.c, but if people like the concept it probably 49832785Speter should also be called from diff -r, update -r, get -r, and log -r. */ 49932785Speter 50032785Spetervoid 50132785Spetercheck_numeric (rev, argc, argv) 50232785Speter const char *rev; 50332785Speter int argc; 50432785Speter char **argv; 50532785Speter{ 50654427Speter if (rev == NULL || !isdigit ((unsigned char) *rev)) 50732785Speter return; 50832785Speter 50932785Speter /* Note that the check for whether we are processing more than one 51032785Speter file is (basically) syntactic; that is, we don't behave differently 51132785Speter depending on whether a directory happens to contain only a single 51232785Speter file or whether it contains more than one. I strongly suspect this 51332785Speter is the least confusing behavior. */ 51432785Speter if (argc != 1 51532785Speter || (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0]))) 51632785Speter { 51732785Speter error (0, 0, "while processing more than one file:"); 51832785Speter error (1, 0, "attempt to specify a numeric revision"); 51932785Speter } 52032785Speter} 52132785Speter 52217721Speter/* 52317721Speter * Sanity checks and any required fix-up on message passed to RCS via '-m'. 52417721Speter * RCS 5.7 requires that a non-total-whitespace, non-null message be provided 52532785Speter * with '-m'. Returns a newly allocated, non-empty buffer with whitespace 52632785Speter * stripped from end of lines and end of buffer. 52732785Speter * 52832785Speter * TODO: We no longer use RCS to manage repository files, so maybe this 52932785Speter * nonsense about non-empty log fields can be dropped. 53017721Speter */ 53117721Speterchar * 53217721Spetermake_message_rcslegal (message) 53317721Speter char *message; 53417721Speter{ 53532785Speter char *dst, *dp, *mp; 53632785Speter 53732785Speter if (message == NULL) message = ""; 53832785Speter 53932785Speter /* Strip whitespace from end of lines and end of string. */ 54032785Speter dp = dst = (char *) xmalloc (strlen (message) + 1); 54132785Speter for (mp = message; *mp != '\0'; ++mp) 54217721Speter { 54332785Speter if (*mp == '\n') 54432785Speter { 54532785Speter /* At end-of-line; backtrack to last non-space. */ 54632785Speter while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t')) 54732785Speter --dp; 54832785Speter } 54932785Speter *dp++ = *mp; 55032785Speter } 55117721Speter 55232785Speter /* Backtrack to last non-space at end of string, and truncate. */ 55354427Speter while (dp > dst && isspace ((unsigned char) dp[-1])) 55432785Speter --dp; 55532785Speter *dp = '\0'; 55617721Speter 55732785Speter /* After all that, if there was no non-space in the string, 55832785Speter substitute a non-empty message. */ 55932785Speter if (*dst == '\0') 56032785Speter { 56132785Speter free (dst); 56232785Speter dst = xstrdup ("*** empty log message ***"); 56317721Speter } 56417721Speter 56532785Speter return dst; 56617721Speter} 56725839Speter 56825839Speter/* Does the file FINFO contain conflict markers? The whole concept 56925839Speter of looking at the contents of the file to figure out whether there are 57025839Speter unresolved conflicts is kind of bogus (people do want to manage files 57125839Speter which contain those patterns not as conflict markers), but for now it 57225839Speter is what we do. */ 57325839Speterint 57425839Speterfile_has_markers (finfo) 57532785Speter const struct file_info *finfo; 57625839Speter{ 57725839Speter FILE *fp; 57825839Speter char *line = NULL; 57925839Speter size_t line_allocated = 0; 58025839Speter int result; 58125839Speter 58225839Speter result = 0; 58325839Speter fp = CVS_FOPEN (finfo->file, "r"); 58425839Speter if (fp == NULL) 58525839Speter error (1, errno, "cannot open %s", finfo->fullname); 58625839Speter while (getline (&line, &line_allocated, fp) > 0) 58725839Speter { 58866525Speter if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 || 58966525Speter strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 || 59066525Speter strncmp (line, RCS_MERGE_PAT_3, sizeof RCS_MERGE_PAT_3 - 1) == 0) 59125839Speter { 59225839Speter result = 1; 59325839Speter goto out; 59425839Speter } 59525839Speter } 59625839Speter if (ferror (fp)) 59725839Speter error (0, errno, "cannot read %s", finfo->fullname); 59825839Speterout: 59925839Speter if (fclose (fp) < 0) 60025839Speter error (0, errno, "cannot close %s", finfo->fullname); 60125839Speter if (line != NULL) 60225839Speter free (line); 60325839Speter return result; 60425839Speter} 60532785Speter 60632785Speter/* Read the entire contents of the file NAME into *BUF. 60732785Speter If NAME is NULL, read from stdin. *BUF 60832785Speter is a pointer returned from malloc (or NULL), pointing to *BUFSIZE 60932785Speter bytes of space. The actual size is returned in *LEN. On error, 61032785Speter give a fatal error. The name of the file to use in error messages 61132785Speter (typically will include a directory if we have changed directory) 61232785Speter is FULLNAME. MODE is "r" for text or "rb" for binary. */ 61332785Speter 61432785Spetervoid 61532785Speterget_file (name, fullname, mode, buf, bufsize, len) 61632785Speter const char *name; 61732785Speter const char *fullname; 61832785Speter const char *mode; 61932785Speter char **buf; 62032785Speter size_t *bufsize; 62132785Speter size_t *len; 62232785Speter{ 62332785Speter struct stat s; 62432785Speter size_t nread; 62532785Speter char *tobuf; 62632785Speter FILE *e; 62732785Speter size_t filesize; 62832785Speter 62932785Speter if (name == NULL) 63032785Speter { 63132785Speter e = stdin; 63232785Speter filesize = 100; /* force allocation of minimum buffer */ 63332785Speter } 63432785Speter else 63532785Speter { 63654427Speter /* Although it would be cleaner in some ways to just read 63754427Speter until end of file, reallocating the buffer, this function 63854427Speter does get called on files in the working directory which can 63954427Speter be of arbitrary size, so I think we better do all that 64054427Speter extra allocation. */ 64154427Speter 64254427Speter if (CVS_STAT (name, &s) < 0) 64332785Speter error (1, errno, "can't stat %s", fullname); 64434461Speter 64532785Speter /* Convert from signed to unsigned. */ 64632785Speter filesize = s.st_size; 64732785Speter 64832785Speter e = open_file (name, mode); 64932785Speter } 65032785Speter 65166525Speter if (*buf == NULL || *bufsize <= filesize) 65232785Speter { 65366525Speter *bufsize = filesize + 1; 65432785Speter *buf = xrealloc (*buf, *bufsize); 65532785Speter } 65632785Speter 65732785Speter tobuf = *buf; 65832785Speter nread = 0; 65932785Speter while (1) 66032785Speter { 66132785Speter size_t got; 66232785Speter 66332785Speter got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e); 66432785Speter if (ferror (e)) 66532785Speter error (1, errno, "can't read %s", fullname); 66632785Speter nread += got; 66732785Speter tobuf += got; 66832785Speter 66932785Speter if (feof (e)) 67032785Speter break; 67132785Speter 67254427Speter /* Allocate more space if needed. */ 67332785Speter if (tobuf == *buf + *bufsize) 67432785Speter { 67532785Speter int c; 67632785Speter long off; 67732785Speter 67832785Speter c = getc (e); 67932785Speter if (c == EOF) 68032785Speter break; 68132785Speter off = tobuf - *buf; 68232785Speter expand_string (buf, bufsize, *bufsize + 100); 68332785Speter tobuf = *buf + off; 68432785Speter *tobuf++ = c; 68532785Speter ++nread; 68632785Speter } 68732785Speter } 68832785Speter 68932785Speter if (e != stdin && fclose (e) < 0) 69032785Speter error (0, errno, "cannot close %s", fullname); 69132785Speter 69232785Speter *len = nread; 69332785Speter 69432785Speter /* Force *BUF to be large enough to hold a null terminator. */ 69566525Speter if (nread == *bufsize) 69666525Speter expand_string (buf, bufsize, *bufsize + 1); 69766525Speter (*buf)[nread] = '\0'; 69832785Speter} 69954427Speter 70054427Speter 70154427Speter/* Follow a chain of symbolic links to its destination. FILENAME 70254427Speter should be a handle to a malloc'd block of memory which contains the 70354427Speter beginning of the chain. This routine will replace the contents of 70454427Speter FILENAME with the destination (a real file). */ 70554427Speter 70654427Spetervoid 70754427Speterresolve_symlink (filename) 70854427Speter char **filename; 70954427Speter{ 71054427Speter if ((! filename) || (! *filename)) 71154427Speter return; 71254427Speter 71354427Speter while (islink (*filename)) 71454427Speter { 71554427Speter char *newname; 71654427Speter#ifdef HAVE_READLINK 71754427Speter /* The clean thing to do is probably to have each filesubr.c 71854427Speter implement this (with an error if not supported by the 71954427Speter platform, in which case islink would presumably return 0). 72054427Speter But that would require editing each filesubr.c and so the 72154427Speter expedient hack seems to be looking at HAVE_READLINK. */ 72254427Speter newname = xreadlink (*filename); 72354427Speter#else 72454427Speter error (1, 0, "internal error: islink doesn't like readlink"); 72554427Speter#endif 72654427Speter 72754427Speter if (isabsolute (newname)) 72854427Speter { 72954427Speter free (*filename); 73054427Speter *filename = newname; 73154427Speter } 73254427Speter else 73354427Speter { 73454427Speter char *oldname = last_component (*filename); 73554427Speter int dirlen = oldname - *filename; 73654427Speter char *fullnewname = xmalloc (dirlen + strlen (newname) + 1); 73754427Speter strncpy (fullnewname, *filename, dirlen); 73854427Speter strcpy (fullnewname + dirlen, newname); 73954427Speter free (newname); 74054427Speter free (*filename); 74154427Speter *filename = fullnewname; 74254427Speter } 74354427Speter } 74454427Speter} 74566525Speter 74666525Speter/* 74766525Speter * Rename a file to an appropriate backup name based on BAKPREFIX. 74866525Speter * If suffix non-null, then ".<suffix>" is appended to the new name. 74966525Speter * 75066525Speter * Returns the new name, which caller may free() if desired. 75166525Speter */ 75266525Speterchar * 75366525Speterbackup_file (filename, suffix) 75466525Speter const char *filename; 75566525Speter const char *suffix; 75666525Speter{ 75766525Speter char *backup_name; 75866525Speter 75966525Speter if (suffix == NULL) 76066525Speter { 76166525Speter backup_name = xmalloc (sizeof (BAKPREFIX) + strlen (filename) + 1); 76266525Speter sprintf (backup_name, "%s%s", BAKPREFIX, filename); 76366525Speter } 76466525Speter else 76566525Speter { 76666525Speter backup_name = xmalloc (sizeof (BAKPREFIX) 76766525Speter + strlen (filename) 76866525Speter + strlen (suffix) 76966525Speter + 2); /* one for dot, one for trailing '\0' */ 77066525Speter sprintf (backup_name, "%s%s.%s", BAKPREFIX, filename, suffix); 77166525Speter } 77266525Speter 77366525Speter if (isfile (filename)) 77466525Speter copy_file (filename, backup_name); 77566525Speter 77666525Speter return backup_name; 77766525Speter} 77866525Speter 779