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