117721Speter/*
2175261Sobrien * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3175261Sobrien *
4175261Sobrien * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5175261Sobrien *                                  and others.
6175261Sobrien *
7175261Sobrien * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8175261Sobrien * Portions Copyright (C) 1989-1992, Brian Berliner
917721Speter *
1017721Speter * You may distribute under the terms of the GNU General Public License as
1132785Speter * specified in the README file that comes with the CVS source distribution.
1217721Speter *
1317721Speter * Various useful functions for the CVS support code.
1417721Speter */
1517721Speter
16128266Speter#include <assert.h>
1717721Speter#include "cvs.h"
1825839Speter#include "getline.h"
1917721Speter
2081404Speter#ifdef HAVE_NANOSLEEP
2181404Speter# include "xtime.h"
2281404Speter#else /* HAVE_NANOSLEEP */
2381404Speter# if !defined HAVE_USLEEP && defined HAVE_SELECT
2481404Speter    /* use select as a workaround */
2581404Speter#   include "xselect.h"
2681404Speter# endif /* !defined HAVE_USLEEP && defined HAVE_SELECT */
2781404Speter#endif /* !HAVE_NANOSLEEP */
2881404Speter
2917721Speterextern char *getlogin ();
3017721Speter
3117721Speter/*
3217721Speter * malloc some data and die if it fails
3317721Speter */
3454427Spetervoid *
3517721Speterxmalloc (bytes)
3617721Speter    size_t bytes;
3717721Speter{
3817721Speter    char *cp;
3917721Speter
4017721Speter    /* Parts of CVS try to xmalloc zero bytes and then free it.  Some
4117721Speter       systems have a malloc which returns NULL for zero byte
4217721Speter       allocations but a free which can't handle NULL, so compensate. */
4317721Speter    if (bytes == 0)
4417721Speter	bytes = 1;
4517721Speter
4617721Speter    cp = malloc (bytes);
4717721Speter    if (cp == NULL)
4854427Speter    {
4954427Speter	char buf[80];
5054427Speter	sprintf (buf, "out of memory; can not allocate %lu bytes",
5154427Speter		 (unsigned long) bytes);
5254427Speter	error (1, 0, buf);
5354427Speter    }
5417721Speter    return (cp);
5517721Speter}
5617721Speter
5717721Speter/*
5817721Speter * realloc data and die if it fails [I've always wanted to have "realloc" do
5917721Speter * a "malloc" if the argument is NULL, but you can't depend on it.  Here, I
60128266Speter * can *force* it.]
6117721Speter */
6217721Spetervoid *
6317721Speterxrealloc (ptr, bytes)
6417721Speter    void *ptr;
6517721Speter    size_t bytes;
6617721Speter{
6717721Speter    char *cp;
6817721Speter
6917721Speter    if (!ptr)
7017721Speter	cp = malloc (bytes);
7117721Speter    else
7217721Speter	cp = realloc (ptr, bytes);
7317721Speter
7417721Speter    if (cp == NULL)
7554427Speter    {
7654427Speter	char buf[80];
7754427Speter	sprintf (buf, "out of memory; can not reallocate %lu bytes",
7854427Speter		 (unsigned long) bytes);
7954427Speter	error (1, 0, buf);
8054427Speter    }
8117721Speter    return (cp);
8217721Speter}
8317721Speter
8425839Speter/* Two constants which tune expand_string.  Having MIN_INCR as large
8525839Speter   as 1024 might waste a bit of memory, but it shouldn't be too bad
8625839Speter   (CVS used to allocate arrays of, say, 3000, PATH_MAX (8192, often),
8725839Speter   or other such sizes).  Probably anything which is going to allocate
8825839Speter   memory which is likely to get as big as MAX_INCR shouldn't be doing
8925839Speter   it in one block which must be contiguous, but since getrcskey does
9025839Speter   so, we might as well limit the wasted memory to MAX_INCR or so
9154427Speter   bytes.
9225839Speter
9354427Speter   MIN_INCR and MAX_INCR should both be powers of two and we generally
9454427Speter   try to keep our allocations to powers of two for the most part.
9554427Speter   Most malloc implementations these days tend to like that.  */
9654427Speter
9725839Speter#define MIN_INCR 1024
9825839Speter#define MAX_INCR (2*1024*1024)
9925839Speter
10025839Speter/* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N
10125839Speter   characters of space.  Reallocate it so that points to at least
10225839Speter   NEWSIZE bytes of space.  Gives a fatal error if out of memory;
10325839Speter   if it returns it was successful.  */
10425839Spetervoid
10525839Speterexpand_string (strptr, n, newsize)
10625839Speter    char **strptr;
10725839Speter    size_t *n;
10825839Speter    size_t newsize;
10925839Speter{
11025839Speter    if (*n < newsize)
11125839Speter    {
11225839Speter	while (*n < newsize)
11325839Speter	{
11425839Speter	    if (*n < MIN_INCR)
11554427Speter		*n = MIN_INCR;
11654427Speter	    else if (*n >= MAX_INCR)
11725839Speter		*n += MAX_INCR;
11825839Speter	    else
11954427Speter	    {
12025839Speter		*n *= 2;
12154427Speter		if (*n > MAX_INCR)
12254427Speter		    *n = MAX_INCR;
12354427Speter	    }
12425839Speter	}
12525839Speter	*strptr = xrealloc (*strptr, *n);
12625839Speter    }
12725839Speter}
12825839Speter
12981404Speter/* *STR is a pointer to a malloc'd string.  *LENP is its allocated
13081404Speter   length.  Add SRC to the end of it, reallocating if necessary.  */
13181404Spetervoid
132102840Speterxrealloc_and_strcat (str, lenp, src)
13381404Speter    char **str;
13481404Speter    size_t *lenp;
13581404Speter    const char *src;
13681404Speter{
13781404Speter
13881404Speter    expand_string (str, lenp, strlen (*str) + strlen (src) + 1);
13981404Speter    strcat (*str, src);
14081404Speter}
14181404Speter
14217721Speter/*
14317721Speter * Duplicate a string, calling xmalloc to allocate some dynamic space
14417721Speter */
14517721Speterchar *
14617721Speterxstrdup (str)
14717721Speter    const char *str;
14817721Speter{
14917721Speter    char *s;
15017721Speter
15117721Speter    if (str == NULL)
15217721Speter	return ((char *) NULL);
15317721Speter    s = xmalloc (strlen (str) + 1);
15417721Speter    (void) strcpy (s, str);
15517721Speter    return (s);
15617721Speter}
15717721Speter
158128266Speter
159128266Speter
160128266Speter/* Remove trailing newlines from STRING, destructively.
161128266Speter *
162128266Speter * RETURNS
163128266Speter *
164128266Speter *   True if any newlines were removed, false otherwise.
165128266Speter */
166128266Speterint
16717721Speterstrip_trailing_newlines (str)
168128266Speter    char *str;
16917721Speter{
170128266Speter    size_t index, origlen;
171128266Speter    index = origlen = strlen (str);
17217721Speter
173128266Speter    while (index > 0 && str[index-1] == '\n')
174128266Speter	str[--index] = '\0';
175128266Speter
176128266Speter    return index != origlen;
17717721Speter}
17817721Speter
179128266Speter
180128266Speter
181128266Speter/* Return the number of levels that PATH ascends above where it starts.
182128266Speter * For example:
183128266Speter *
184128266Speter *   "../../foo" -> 2
185128266Speter *   "foo/../../bar" -> 1
186128266Speter */
18725839Speterint
188128266Speterpathname_levels (p)
189128266Speter    const char *p;
19025839Speter{
19125839Speter    int level;
19225839Speter    int max_level;
19325839Speter
194128266Speter    if (p == NULL) return 0;
195128266Speter
19625839Speter    max_level = 0;
19725839Speter    level = 0;
19825839Speter    do
19925839Speter    {
200128266Speter	/* Now look for pathname level-ups.  */
201128266Speter	if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || ISDIRSEP (p[2])))
20225839Speter	{
20325839Speter	    --level;
20425839Speter	    if (-level > max_level)
20525839Speter		max_level = -level;
20625839Speter	}
207128266Speter	else if (p[0] == '\0' || ISDIRSEP (p[0]) ||
208128266Speter		 (p[0] == '.' && (p[1] == '\0' || ISDIRSEP (p[1]))))
20925839Speter	    ;
21025839Speter	else
21125839Speter	    ++level;
212128266Speter
213128266Speter	/* q = strchr (p, '/'); but sub ISDIRSEP() for '/': */
214128266Speter	while (*p != '\0' && !ISDIRSEP (*p)) p++;
215128266Speter	if (*p != '\0') p++;
216128266Speter    } while (*p != '\0');
21725839Speter    return max_level;
21825839Speter}
21925839Speter
220128266Speter
221128266Speter
22226065Speter/* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1]
22326065Speter   are malloc'd and so is *ARGV itself.  Such a vector is allocated by
22426065Speter   line2argv or expand_wild, for example.  */
22517721Spetervoid
22617721Speterfree_names (pargc, argv)
22717721Speter    int *pargc;
22817721Speter    char **argv;
22917721Speter{
23017721Speter    register int i;
23117721Speter
23217721Speter    for (i = 0; i < *pargc; i++)
23317721Speter    {					/* only do through *pargc */
23417721Speter	free (argv[i]);
23517721Speter    }
23625839Speter    free (argv);
23717721Speter    *pargc = 0;				/* and set it to zero when done */
23817721Speter}
23917721Speter
24032785Speter/* Convert LINE into arguments separated by SEPCHARS.  Set *ARGC
24125839Speter   to the number of arguments found, and (*ARGV)[0] to the first argument,
24225839Speter   (*ARGV)[1] to the second, etc.  *ARGV is malloc'd and so are each of
24325839Speter   (*ARGV)[0], (*ARGV)[1], ...  Use free_names() to return the memory
24425839Speter   allocated here back to the free pool.  */
24517721Spetervoid
24632785Speterline2argv (pargc, argv, line, sepchars)
24717721Speter    int *pargc;
24825839Speter    char ***argv;
24917721Speter    char *line;
25032785Speter    char *sepchars;
25117721Speter{
25217721Speter    char *cp;
25325839Speter    /* Could make a case for size_t or some other unsigned type, but
25425839Speter       we'll stick with int to avoid signed/unsigned warnings when
25525839Speter       comparing with *pargc.  */
25625839Speter    int argv_allocated;
25717721Speter
25825839Speter    /* Small for testing.  */
25966525Speter    argv_allocated = 1;
26025839Speter    *argv = (char **) xmalloc (argv_allocated * sizeof (**argv));
26125839Speter
26217721Speter    *pargc = 0;
26332785Speter    for (cp = strtok (line, sepchars); cp; cp = strtok ((char *) NULL, sepchars))
26417721Speter    {
26525839Speter	if (*pargc == argv_allocated)
26625839Speter	{
26725839Speter	    argv_allocated *= 2;
26825839Speter	    *argv = xrealloc (*argv, argv_allocated * sizeof (**argv));
26925839Speter	}
27025839Speter	(*argv)[*pargc] = xstrdup (cp);
27117721Speter	(*pargc)++;
27217721Speter    }
27317721Speter}
27417721Speter
27517721Speter/*
27617721Speter * Returns the number of dots ('.') found in an RCS revision number
27717721Speter */
27817721Speterint
27917721Speternumdots (s)
28017721Speter    const char *s;
28117721Speter{
28217721Speter    int dots = 0;
28317721Speter
28417721Speter    for (; *s; s++)
28517721Speter    {
28617721Speter	if (*s == '.')
28717721Speter	    dots++;
28817721Speter    }
28917721Speter    return (dots);
29017721Speter}
29117721Speter
29232785Speter/* Compare revision numbers REV1 and REV2 by consecutive fields.
29332785Speter   Return negative, zero, or positive in the manner of strcmp.  The
29432785Speter   two revision numbers must have the same number of fields, or else
29532785Speter   compare_revnums will return an inaccurate result. */
29632785Speterint
29732785Spetercompare_revnums (rev1, rev2)
29832785Speter    const char *rev1;
29932785Speter    const char *rev2;
30032785Speter{
301128266Speter    const char *sp, *tp;
30232785Speter    char *snext, *tnext;
30332785Speter    int result = 0;
30432785Speter
305128266Speter    sp = rev1;
306128266Speter    tp = rev2;
30732785Speter    while (result == 0)
30832785Speter    {
30932785Speter	result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
31032785Speter	if (*snext == '\0' || *tnext == '\0')
31132785Speter	    break;
31232785Speter	sp = snext + 1;
31332785Speter	tp = tnext + 1;
31432785Speter    }
31532785Speter
31632785Speter    return result;
31732785Speter}
31832785Speter
319130303Speter/* Increment a revision number.  Working on the string is a bit awkward,
320130303Speter   but it avoid problems with integer overflow should the revision numbers
321130303Speter   get really big.  */
32232785Speterchar *
32332785Speterincrement_revnum (rev)
32432785Speter    const char *rev;
32532785Speter{
32632785Speter    char *newrev, *p;
32732785Speter    size_t len = strlen (rev);
32832785Speter
329130303Speter    newrev = xmalloc (len + 2);
33032785Speter    memcpy (newrev, rev, len + 1);
331130303Speter    for (p = newrev + len; p != newrev; )
33232785Speter    {
333130303Speter	--p;
334130303Speter	if (!isdigit(*p))
335130303Speter	{
336130303Speter	    ++p;
337130303Speter	    break;
338130303Speter	}
339130303Speter	if (*p != '9')
340130303Speter	{
341130303Speter	    ++*p;
342130303Speter	    return newrev;
343130303Speter	}
344130303Speter	*p = '0';
34532785Speter    }
346130303Speter    /* The number was all 9s, so change the first character to 1 and add
347130303Speter       a 0 to the end.  */
348130303Speter    *p = '1';
349130303Speter    p = newrev + len;
350130303Speter    *p++ = '0';
351130303Speter    *p = '\0';
35232785Speter    return newrev;
35332785Speter}
35432785Speter
35526801Speter/* Return the username by which the caller should be identified in
35626801Speter   CVS, in contexts such as the author field of RCS files, various
35734461Speter   logs, etc.  */
35817721Speterchar *
35917721Spetergetcaller ()
36017721Speter{
36132785Speter#ifndef SYSTEM_GETCALLER
36234461Speter    static char *cache;
36317721Speter    struct passwd *pw;
36417721Speter    uid_t uid;
36532785Speter#endif
36617721Speter
36726801Speter    /* If there is a CVS username, return it.  */
36826801Speter#ifdef AUTH_SERVER_SUPPORT
36926801Speter    if (CVS_Username != NULL)
37026801Speter	return CVS_Username;
37126801Speter#endif
37226801Speter
37332785Speter#ifdef SYSTEM_GETCALLER
37432785Speter    return SYSTEM_GETCALLER ();
37532785Speter#else
37626801Speter    /* Get the caller's login from his uid.  If the real uid is "root"
37726801Speter       try LOGNAME USER or getlogin(). If getlogin() and getpwuid()
37826801Speter       both fail, return the uid as a string.  */
37926801Speter
38034461Speter    if (cache != NULL)
38134461Speter	return cache;
38234461Speter
38317721Speter    uid = getuid ();
38417721Speter    if (uid == (uid_t) 0)
38517721Speter    {
38634461Speter	char *name;
38734461Speter
38817721Speter	/* super-user; try getlogin() to distinguish */
38917721Speter	if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
39017721Speter	     (name = getenv("USER"))) && *name)
39134461Speter	{
39234461Speter	    cache = xstrdup (name);
39334461Speter	    return cache;
39434461Speter	}
39517721Speter    }
39617721Speter    if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
39717721Speter    {
39834461Speter	char uidname[20];
39934461Speter
40017721Speter	(void) sprintf (uidname, "uid%lu", (unsigned long) uid);
40134461Speter	cache = xstrdup (uidname);
40234461Speter	return cache;
40317721Speter    }
40434461Speter    cache = xstrdup (pw->pw_name);
40534461Speter    return cache;
40632785Speter#endif
40717721Speter}
40817721Speter
40917721Speter#ifdef lint
41017721Speter#ifndef __GNUC__
41117721Speter/* ARGSUSED */
41217721Spetertime_t
41317721Speterget_date (date, now)
41417721Speter    char *date;
41517721Speter    struct timeb *now;
41617721Speter{
41717721Speter    time_t foo = 0;
41817721Speter
41917721Speter    return (foo);
42017721Speter}
42117721Speter#endif
42217721Speter#endif
42317721Speter
424128266Speter
425128266Speter
426128266Speter/* Given some revision, REV, return the first prior revision that exists in the
427128266Speter * RCS file, RCS.
428128266Speter *
429128266Speter * ASSUMPTIONS
430128266Speter *   REV exists.
431128266Speter *
432128266Speter * INPUTS
433128266Speter *   RCS	The RCS node pointer.
434128266Speter *   REV	An existing revision in the RCS file referred to by RCS.
435128266Speter *
436128266Speter * RETURNS
437128266Speter *   The first prior revision that exists in the RCS file, or NULL if no prior
438128266Speter *   revision exists.  The caller is responsible for disposing of this string.
439128266Speter *
440128266Speter * NOTES
441128266Speter *   This function currently neglects the case where we are on the trunk with
442128266Speter *   rev = X.1, where X != 1.  If rev = X.Y, where X != 1 and Y > 1, then this
443128266Speter *   function should work fine, as revision X.1 must exist, due to RCS rules.
444128266Speter */
445128266Speterchar *
446128266Speterprevious_rev (rcs, rev)
447128266Speter    RCSNode *rcs;
448128266Speter    const char *rev;
449128266Speter{
450128266Speter    char *p;
451128266Speter    char *tmp = xstrdup (rev);
452128266Speter    long r1;
453128266Speter    char *retval;
454128266Speter
455128266Speter    /* Our retval can have no more digits and dots than our input revision.  */
456128266Speter    retval = xmalloc (strlen (rev) + 1);
457128266Speter    p = strrchr (tmp, '.');
458128266Speter    *p = '\0';
459128266Speter    r1 = strtol (p+1, NULL, 10);
460128266Speter    do {
461128266Speter	if (--r1 == 0)
462128266Speter	{
463128266Speter		/* If r1 == 0, then we must be on a branch and our parent must
464128266Speter		 * exist, or we must be on the trunk with a REV like X.1.
465128266Speter		 * We are neglecting the X.1 with X != 1 case by assuming that
466128266Speter		 * there is no previous revision when we discover we were on
467128266Speter		 * the trunk.
468128266Speter		 */
469128266Speter		p = strrchr (tmp, '.');
470128266Speter		if (p == NULL)
471128266Speter		    /* We are on the trunk.  */
472128266Speter		    retval = NULL;
473128266Speter		else
474128266Speter		{
475128266Speter		    *p = '\0';
476128266Speter		    sprintf (retval, "%s", tmp);
477128266Speter		}
478128266Speter		break;
479128266Speter	}
480128266Speter	sprintf (retval, "%s.%ld", tmp, r1);
481128266Speter    } while (!RCS_exist_rev (rcs, retval));
482128266Speter
483128266Speter    free (tmp);
484128266Speter    return retval;
485128266Speter}
486128266Speter
487128266Speter
488128266Speter
48917721Speter/* Given two revisions, find their greatest common ancestor.  If the
49017721Speter   two input revisions exist, then rcs guarantees that the gca will
49117721Speter   exist.  */
49217721Speter
49317721Speterchar *
49417721Spetergca (rev1, rev2)
49532785Speter    const char *rev1;
49632785Speter    const char *rev2;
49717721Speter{
49817721Speter    int dots;
499107484Speter    char *gca, *g;
500107484Speter    const char *p1, *p2;
501107484Speter    int r1, r2;
50225839Speter    char *retval;
50317721Speter
50417721Speter    if (rev1 == NULL || rev2 == NULL)
50517721Speter    {
50617721Speter	error (0, 0, "sanity failure in gca");
50717721Speter	abort();
50817721Speter    }
50917721Speter
51025839Speter    /* The greatest common ancestor will have no more dots, and numbers
51125839Speter       of digits for each component no greater than the arguments.  Therefore
51225839Speter       this string will be big enough.  */
513107484Speter    g = gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
51425839Speter
51517721Speter    /* walk the strings, reading the common parts. */
516107484Speter    p1 = rev1;
517107484Speter    p2 = rev2;
51817721Speter    do
51917721Speter    {
520107484Speter	r1 = strtol (p1, (char **) &p1, 10);
521107484Speter	r2 = strtol (p2, (char **) &p2, 10);
52217721Speter
52317721Speter	/* use the lowest. */
524107484Speter	(void) sprintf (g, "%d.", r1 < r2 ? r1 : r2);
525107484Speter	g += strlen (g);
526107484Speter	if (*p1 == '.') ++p1;
527107484Speter	else break;
528107484Speter	if (*p2 == '.') ++p2;
529107484Speter	else break;
530107484Speter    } while (r1 == r2);
53117721Speter
532107484Speter    /* erase that last dot. */
533107484Speter    *--g = '\0';
53417721Speter
53517721Speter    /* numbers differ, or we ran out of strings.  we're done with the
53617721Speter       common parts.  */
53717721Speter
53817721Speter    dots = numdots (gca);
53917721Speter    if (dots == 0)
54017721Speter    {
54117721Speter	/* revisions differ in trunk major number.  */
54217721Speter
543107484Speter	if (r2 < r1) p1 = p2;
544107484Speter	if (*p1 == '\0')
54517721Speter	{
54617721Speter	    /* we only got one number.  this is strange.  */
54717721Speter	    error (0, 0, "bad revisions %s or %s", rev1, rev2);
54817721Speter	    abort();
54917721Speter	}
55017721Speter	else
55117721Speter	{
55217721Speter	    /* we have a minor number.  use it.  */
553107484Speter	    *g++ = '.';
554107484Speter	    while (*p1 != '.' && *p1 != '\0')
555107484Speter		*g++ = *p1++;
556107484Speter	    *g = '\0';
55717721Speter	}
55817721Speter    }
55917721Speter    else if ((dots & 1) == 0)
56017721Speter    {
56117721Speter	/* if we have an even number of dots, then we have a branch.
56217721Speter	   remove the last number in order to make it a revision.  */
56317721Speter
564107484Speter	g = strrchr (gca, '.');
565107484Speter	*g = '\0';
56617721Speter    }
56717721Speter
56825839Speter    retval = xstrdup (gca);
56925839Speter    free (gca);
57025839Speter    return retval;
57117721Speter}
57217721Speter
57332785Speter/* Give fatal error if REV is numeric and ARGC,ARGV imply we are
57432785Speter   planning to operate on more than one file.  The current directory
57532785Speter   should be the working directory.  Note that callers assume that we
57632785Speter   will only be checking the first character of REV; it need not have
57732785Speter   '\0' at the end of the tag name and other niceties.  Right now this
57832785Speter   is only called from admin.c, but if people like the concept it probably
57932785Speter   should also be called from diff -r, update -r, get -r, and log -r.  */
58032785Speter
58132785Spetervoid
58232785Spetercheck_numeric (rev, argc, argv)
58332785Speter    const char *rev;
58432785Speter    int argc;
58532785Speter    char **argv;
58632785Speter{
58754427Speter    if (rev == NULL || !isdigit ((unsigned char) *rev))
58832785Speter	return;
58932785Speter
59032785Speter    /* Note that the check for whether we are processing more than one
59132785Speter       file is (basically) syntactic; that is, we don't behave differently
59232785Speter       depending on whether a directory happens to contain only a single
59332785Speter       file or whether it contains more than one.  I strongly suspect this
59432785Speter       is the least confusing behavior.  */
59532785Speter    if (argc != 1
59632785Speter	|| (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0])))
59732785Speter    {
59832785Speter	error (0, 0, "while processing more than one file:");
59932785Speter	error (1, 0, "attempt to specify a numeric revision");
60032785Speter    }
60132785Speter}
60232785Speter
60317721Speter/*
60417721Speter *  Sanity checks and any required fix-up on message passed to RCS via '-m'.
60517721Speter *  RCS 5.7 requires that a non-total-whitespace, non-null message be provided
60632785Speter *  with '-m'.  Returns a newly allocated, non-empty buffer with whitespace
60732785Speter *  stripped from end of lines and end of buffer.
60832785Speter *
60932785Speter *  TODO: We no longer use RCS to manage repository files, so maybe this
61032785Speter *  nonsense about non-empty log fields can be dropped.
61117721Speter */
61217721Speterchar *
61317721Spetermake_message_rcslegal (message)
614128266Speter     const char *message;
61517721Speter{
616128266Speter    char *dst, *dp;
617128266Speter    const char *mp;
61832785Speter
61932785Speter    if (message == NULL) message = "";
62032785Speter
62132785Speter    /* Strip whitespace from end of lines and end of string. */
62232785Speter    dp = dst = (char *) xmalloc (strlen (message) + 1);
62332785Speter    for (mp = message; *mp != '\0'; ++mp)
62417721Speter    {
62532785Speter	if (*mp == '\n')
62632785Speter	{
62732785Speter	    /* At end-of-line; backtrack to last non-space. */
62832785Speter	    while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t'))
62932785Speter		--dp;
63032785Speter	}
63132785Speter	*dp++ = *mp;
63232785Speter    }
63317721Speter
63432785Speter    /* Backtrack to last non-space at end of string, and truncate. */
63554427Speter    while (dp > dst && isspace ((unsigned char) dp[-1]))
63632785Speter	--dp;
63732785Speter    *dp = '\0';
63817721Speter
63932785Speter    /* After all that, if there was no non-space in the string,
64032785Speter       substitute a non-empty message. */
64132785Speter    if (*dst == '\0')
64232785Speter    {
64332785Speter	free (dst);
64432785Speter	dst = xstrdup ("*** empty log message ***");
64517721Speter    }
64617721Speter
64732785Speter    return dst;
64817721Speter}
64925839Speter
650128266Speter
651128266Speter
65225839Speter/* Does the file FINFO contain conflict markers?  The whole concept
65325839Speter   of looking at the contents of the file to figure out whether there are
65425839Speter   unresolved conflicts is kind of bogus (people do want to manage files
65525839Speter   which contain those patterns not as conflict markers), but for now it
65625839Speter   is what we do.  */
65725839Speterint
65825839Speterfile_has_markers (finfo)
65932785Speter    const struct file_info *finfo;
66025839Speter{
66125839Speter    FILE *fp;
66225839Speter    char *line = NULL;
66325839Speter    size_t line_allocated = 0;
66425839Speter    int result;
66525839Speter
66625839Speter    result = 0;
66725839Speter    fp = CVS_FOPEN (finfo->file, "r");
66825839Speter    if (fp == NULL)
66925839Speter	error (1, errno, "cannot open %s", finfo->fullname);
67025839Speter    while (getline (&line, &line_allocated, fp) > 0)
67125839Speter    {
67266525Speter	if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 ||
67366525Speter	    strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 ||
67466525Speter	    strncmp (line, RCS_MERGE_PAT_3, sizeof RCS_MERGE_PAT_3 - 1) == 0)
67525839Speter	{
67625839Speter	    result = 1;
67725839Speter	    goto out;
67825839Speter	}
67925839Speter    }
68025839Speter    if (ferror (fp))
68125839Speter	error (0, errno, "cannot read %s", finfo->fullname);
68225839Speterout:
68325839Speter    if (fclose (fp) < 0)
68425839Speter	error (0, errno, "cannot close %s", finfo->fullname);
68525839Speter    if (line != NULL)
68625839Speter	free (line);
68725839Speter    return result;
68825839Speter}
68932785Speter
69032785Speter/* Read the entire contents of the file NAME into *BUF.
69132785Speter   If NAME is NULL, read from stdin.  *BUF
69232785Speter   is a pointer returned from malloc (or NULL), pointing to *BUFSIZE
69332785Speter   bytes of space.  The actual size is returned in *LEN.  On error,
69432785Speter   give a fatal error.  The name of the file to use in error messages
69532785Speter   (typically will include a directory if we have changed directory)
69632785Speter   is FULLNAME.  MODE is "r" for text or "rb" for binary.  */
69732785Speter
69832785Spetervoid
69932785Speterget_file (name, fullname, mode, buf, bufsize, len)
70032785Speter    const char *name;
70132785Speter    const char *fullname;
70232785Speter    const char *mode;
70332785Speter    char **buf;
70432785Speter    size_t *bufsize;
70532785Speter    size_t *len;
70632785Speter{
70732785Speter    struct stat s;
70832785Speter    size_t nread;
70932785Speter    char *tobuf;
71032785Speter    FILE *e;
71132785Speter    size_t filesize;
71232785Speter
71332785Speter    if (name == NULL)
71432785Speter    {
71532785Speter	e = stdin;
71632785Speter	filesize = 100;	/* force allocation of minimum buffer */
71732785Speter    }
71832785Speter    else
71932785Speter    {
72054427Speter	/* Although it would be cleaner in some ways to just read
72154427Speter	   until end of file, reallocating the buffer, this function
72254427Speter	   does get called on files in the working directory which can
72354427Speter	   be of arbitrary size, so I think we better do all that
72454427Speter	   extra allocation.  */
72554427Speter
72654427Speter	if (CVS_STAT (name, &s) < 0)
72732785Speter	    error (1, errno, "can't stat %s", fullname);
72834461Speter
72932785Speter	/* Convert from signed to unsigned.  */
73032785Speter	filesize = s.st_size;
73132785Speter
73232785Speter	e = open_file (name, mode);
73332785Speter    }
73432785Speter
73566525Speter    if (*buf == NULL || *bufsize <= filesize)
73632785Speter    {
73766525Speter	*bufsize = filesize + 1;
73832785Speter	*buf = xrealloc (*buf, *bufsize);
73932785Speter    }
74032785Speter
74132785Speter    tobuf = *buf;
74232785Speter    nread = 0;
74332785Speter    while (1)
74432785Speter    {
74532785Speter	size_t got;
74632785Speter
74732785Speter	got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
74832785Speter	if (ferror (e))
74932785Speter	    error (1, errno, "can't read %s", fullname);
75032785Speter	nread += got;
75132785Speter	tobuf += got;
75232785Speter
75332785Speter	if (feof (e))
75432785Speter	    break;
75532785Speter
75654427Speter	/* Allocate more space if needed.  */
75732785Speter	if (tobuf == *buf + *bufsize)
75832785Speter	{
75932785Speter	    int c;
76032785Speter	    long off;
76132785Speter
76232785Speter	    c = getc (e);
76332785Speter	    if (c == EOF)
76432785Speter		break;
76532785Speter	    off = tobuf - *buf;
76632785Speter	    expand_string (buf, bufsize, *bufsize + 100);
76732785Speter	    tobuf = *buf + off;
76832785Speter	    *tobuf++ = c;
76932785Speter	    ++nread;
77032785Speter	}
77132785Speter    }
77232785Speter
77332785Speter    if (e != stdin && fclose (e) < 0)
77432785Speter	error (0, errno, "cannot close %s", fullname);
77532785Speter
77632785Speter    *len = nread;
77732785Speter
77832785Speter    /* Force *BUF to be large enough to hold a null terminator. */
77966525Speter    if (nread == *bufsize)
78066525Speter	expand_string (buf, bufsize, *bufsize + 1);
78166525Speter    (*buf)[nread] = '\0';
78232785Speter}
78354427Speter
78454427Speter
78554427Speter/* Follow a chain of symbolic links to its destination.  FILENAME
78654427Speter   should be a handle to a malloc'd block of memory which contains the
78754427Speter   beginning of the chain.  This routine will replace the contents of
78854427Speter   FILENAME with the destination (a real file).  */
78954427Speter
79054427Spetervoid
79154427Speterresolve_symlink (filename)
79254427Speter     char **filename;
79354427Speter{
794128266Speter    if (filename == NULL || *filename == NULL)
79554427Speter	return;
79654427Speter
79754427Speter    while (islink (*filename))
79854427Speter    {
79954427Speter#ifdef HAVE_READLINK
80054427Speter	/* The clean thing to do is probably to have each filesubr.c
80154427Speter	   implement this (with an error if not supported by the
80254427Speter	   platform, in which case islink would presumably return 0).
80354427Speter	   But that would require editing each filesubr.c and so the
80454427Speter	   expedient hack seems to be looking at HAVE_READLINK.  */
805128266Speter	char *newname = xreadlink (*filename);
80654427Speter
80754427Speter	if (isabsolute (newname))
80854427Speter	{
80954427Speter	    free (*filename);
81054427Speter	    *filename = newname;
81154427Speter	}
81254427Speter	else
81354427Speter	{
814128266Speter	    const char *oldname = last_component (*filename);
81554427Speter	    int dirlen = oldname - *filename;
81654427Speter	    char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
81754427Speter	    strncpy (fullnewname, *filename, dirlen);
81854427Speter	    strcpy (fullnewname + dirlen, newname);
81954427Speter	    free (newname);
82054427Speter	    free (*filename);
82154427Speter	    *filename = fullnewname;
82254427Speter	}
823102840Speter#else
824102840Speter	error (1, 0, "internal error: islink doesn't like readlink");
825102840Speter#endif
82654427Speter    }
82754427Speter}
82866525Speter
82966525Speter/*
83066525Speter * Rename a file to an appropriate backup name based on BAKPREFIX.
83166525Speter * If suffix non-null, then ".<suffix>" is appended to the new name.
83266525Speter *
83366525Speter * Returns the new name, which caller may free() if desired.
83466525Speter */
83566525Speterchar *
83666525Speterbackup_file (filename, suffix)
83766525Speter     const char *filename;
83866525Speter     const char *suffix;
83966525Speter{
84066525Speter    char *backup_name;
84166525Speter
84266525Speter    if (suffix == NULL)
84366525Speter    {
84466525Speter        backup_name = xmalloc (sizeof (BAKPREFIX) + strlen (filename) + 1);
84566525Speter        sprintf (backup_name, "%s%s", BAKPREFIX, filename);
84666525Speter    }
84766525Speter    else
84866525Speter    {
84966525Speter        backup_name = xmalloc (sizeof (BAKPREFIX)
85066525Speter                               + strlen (filename)
85166525Speter                               + strlen (suffix)
85266525Speter                               + 2);  /* one for dot, one for trailing '\0' */
85366525Speter        sprintf (backup_name, "%s%s.%s", BAKPREFIX, filename, suffix);
85466525Speter    }
85566525Speter
85666525Speter    if (isfile (filename))
85766525Speter        copy_file (filename, backup_name);
85866525Speter
85966525Speter    return backup_name;
86066525Speter}
86166525Speter
86281404Speter/*
86381404Speter * Copy a string into a buffer escaping any shell metacharacters.  The
86481404Speter * buffer should be at least twice as long as the string.
86581404Speter *
86681404Speter * Returns a pointer to the terminating NUL byte in buffer.
86781404Speter */
86881404Speter
86981404Speterchar *
87081404Spetershell_escape(buf, str)
87181404Speter    char *buf;
87281404Speter    const char *str;
87381404Speter{
87481404Speter    static const char meta[] = "$`\\\"";
87581404Speter    const char *p;
87681404Speter
87781404Speter    for (;;)
87881404Speter    {
87981404Speter	p = strpbrk(str, meta);
88081404Speter	if (!p) p = str + strlen(str);
88181404Speter	if (p > str)
88281404Speter	{
88381404Speter	    memcpy(buf, str, p - str);
88481404Speter	    buf += p - str;
88581404Speter	}
88681404Speter	if (!*p) break;
88781404Speter	*buf++ = '\\';
88881404Speter	*buf++ = *p++;
88981404Speter	str = p;
89081404Speter    }
89181404Speter    *buf = '\0';
89281404Speter    return buf;
89381404Speter}
89481404Speter
895128266Speter
896128266Speter
89781404Speter/*
89881404Speter * We can only travel forwards in time, not backwards.  :)
89981404Speter */
90081404Spetervoid
90181404Spetersleep_past (desttime)
90281404Speter    time_t desttime;
90381404Speter{
90481404Speter    time_t t;
90581404Speter    long s;
90681404Speter    long us;
90781404Speter
90881404Speter    while (time (&t) <= desttime)
90981404Speter    {
91081404Speter#ifdef HAVE_GETTIMEOFDAY
91181404Speter	struct timeval tv;
91281404Speter	gettimeofday (&tv, NULL);
91381404Speter	if (tv.tv_sec > desttime)
91481404Speter	    break;
91581404Speter	s = desttime - tv.tv_sec;
91681404Speter	if (tv.tv_usec > 0)
91781404Speter	    us = 1000000 - tv.tv_usec;
91881404Speter	else
91981404Speter	{
92081404Speter	    s++;
92181404Speter	    us = 0;
92281404Speter	}
92381404Speter#else
92481404Speter	/* default to 20 ms increments */
92581404Speter	s = desttime - t;
92681404Speter	us = 20000;
92781404Speter#endif
92881404Speter
92981404Speter#if defined(HAVE_NANOSLEEP)
93081404Speter	{
93181404Speter	    struct timespec ts;
93281404Speter	    ts.tv_sec = s;
93381404Speter	    ts.tv_nsec = us * 1000;
93481404Speter	    (void)nanosleep (&ts, NULL);
93581404Speter	}
93681404Speter#elif defined(HAVE_USLEEP)
93781404Speter	if (s > 0)
93881404Speter	    (void)sleep (s);
93981404Speter	else
94081404Speter	    (void)usleep (us);
94181404Speter#elif defined(HAVE_SELECT)
94281404Speter	{
94381404Speter	    /* use select instead of sleep since it is a fairly portable way of
94481404Speter	     * sleeping for ms.
94581404Speter	     */
94681404Speter	    struct timeval tv;
94781404Speter	    tv.tv_sec = s;
94881404Speter	    tv.tv_usec = us;
949128266Speter	    (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
950128266Speter                          &tv);
95181404Speter	}
95281404Speter#else
95381404Speter	if (us > 0) s++;
95481404Speter	(void)sleep(s);
95581404Speter#endif
95681404Speter    }
95781404Speter}
958128266Speter
959128266Speter
960128266Speter
961128266Speter/* Return non-zero iff FILENAME is absolute.
962128266Speter   Trivial under Unix, but more complicated under other systems.  */
963128266Speterint
964128266Speterisabsolute (filename)
965128266Speter    const char *filename;
966128266Speter{
967128266Speter    return ISABSOLUTE (filename);
968128266Speter}
969