#include <assert.h>
#include "cvs.h"
#include "getline.h"
#ifdef HAVE_NANOSLEEP
# include "xtime.h"
#else
# if !defined HAVE_USLEEP && defined HAVE_SELECT
# include "xselect.h"
# endif
#endif
extern char *getlogin ();
void *
xmalloc (bytes)
size_t bytes;
{
char *cp;
if (bytes == 0)
bytes = 1;
cp = malloc (bytes);
if (cp == NULL)
{
char buf[80];
sprintf (buf, "out of memory; can not allocate %lu bytes",
(unsigned long) bytes);
error (1, 0, buf);
}
return (cp);
}
void *
xrealloc (ptr, bytes)
void *ptr;
size_t bytes;
{
char *cp;
if (!ptr)
cp = malloc (bytes);
else
cp = realloc (ptr, bytes);
if (cp == NULL)
{
char buf[80];
sprintf (buf, "out of memory; can not reallocate %lu bytes",
(unsigned long) bytes);
error (1, 0, buf);
}
return (cp);
}
#define MIN_INCR 1024
#define MAX_INCR (2*1024*1024)
void
expand_string (strptr, n, newsize)
char **strptr;
size_t *n;
size_t newsize;
{
if (*n < newsize)
{
while (*n < newsize)
{
if (*n < MIN_INCR)
*n = MIN_INCR;
else if (*n >= MAX_INCR)
*n += MAX_INCR;
else
{
*n *= 2;
if (*n > MAX_INCR)
*n = MAX_INCR;
}
}
*strptr = xrealloc (*strptr, *n);
}
}
void
xrealloc_and_strcat (str, lenp, src)
char **str;
size_t *lenp;
const char *src;
{
expand_string (str, lenp, strlen (*str) + strlen (src) + 1);
strcat (*str, src);
}
char *
xstrdup (str)
const char *str;
{
char *s;
if (str == NULL)
return ((char *) NULL);
s = xmalloc (strlen (str) + 1);
(void) strcpy (s, str);
return (s);
}
int
strip_trailing_newlines (str)
char *str;
{
size_t index, origlen;
index = origlen = strlen (str);
while (index > 0 && str[index-1] == '\n')
str[--index] = '\0';
return index != origlen;
}
int
pathname_levels (p)
const char *p;
{
int level;
int max_level;
if (p == NULL) return 0;
max_level = 0;
level = 0;
do
{
if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || ISDIRSEP (p[2])))
{
--level;
if (-level > max_level)
max_level = -level;
}
else if (p[0] == '\0' || ISDIRSEP (p[0]) ||
(p[0] == '.' && (p[1] == '\0' || ISDIRSEP (p[1]))))
;
else
++level;
while (*p != '\0' && !ISDIRSEP (*p)) p++;
if (*p != '\0') p++;
} while (*p != '\0');
return max_level;
}
void
free_names (pargc, argv)
int *pargc;
char **argv;
{
register int i;
for (i = 0; i < *pargc; i++)
{
free (argv[i]);
}
free (argv);
*pargc = 0;
}
void
line2argv (pargc, argv, line, sepchars)
int *pargc;
char ***argv;
char *line;
char *sepchars;
{
char *cp;
int argv_allocated;
argv_allocated = 1;
*argv = (char **) xmalloc (argv_allocated * sizeof (**argv));
*pargc = 0;
for (cp = strtok (line, sepchars); cp; cp = strtok ((char *) NULL, sepchars))
{
if (*pargc == argv_allocated)
{
argv_allocated *= 2;
*argv = xrealloc (*argv, argv_allocated * sizeof (**argv));
}
(*argv)[*pargc] = xstrdup (cp);
(*pargc)++;
}
}
int
numdots (s)
const char *s;
{
int dots = 0;
for (; *s; s++)
{
if (*s == '.')
dots++;
}
return (dots);
}
int
compare_revnums (rev1, rev2)
const char *rev1;
const char *rev2;
{
const char *sp, *tp;
char *snext, *tnext;
int result = 0;
sp = rev1;
tp = rev2;
while (result == 0)
{
result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
if (*snext == '\0' || *tnext == '\0')
break;
sp = snext + 1;
tp = tnext + 1;
}
return result;
}
char *
increment_revnum (rev)
const char *rev;
{
char *newrev, *p;
int lastfield;
size_t len = strlen (rev);
newrev = xmalloc (len + 2);
memcpy (newrev, rev, len + 1);
for (p = newrev + len; p != newrev; )
{
--p;
if (!isdigit(*p))
{
++p;
break;
}
if (*p != '9')
{
++*p;
return newrev;
}
*p = '0';
}
*p = '1';
p = newrev + len;
*p++ = '0';
*p = '\0';
return newrev;
}
char *
getcaller ()
{
#ifndef SYSTEM_GETCALLER
static char *cache;
struct passwd *pw;
uid_t uid;
#endif
#ifdef AUTH_SERVER_SUPPORT
if (CVS_Username != NULL)
return CVS_Username;
#endif
#ifdef SYSTEM_GETCALLER
return SYSTEM_GETCALLER ();
#else
if (cache != NULL)
return cache;
uid = getuid ();
if (uid == (uid_t) 0)
{
char *name;
if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
(name = getenv("USER"))) && *name)
{
cache = xstrdup (name);
return cache;
}
}
if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
{
char uidname[20];
(void) sprintf (uidname, "uid%lu", (unsigned long) uid);
cache = xstrdup (uidname);
return cache;
}
cache = xstrdup (pw->pw_name);
return cache;
#endif
}
#ifdef lint
#ifndef __GNUC__
time_t
get_date (date, now)
char *date;
struct timeb *now;
{
time_t foo = 0;
return (foo);
}
#endif
#endif
char *
previous_rev (rcs, rev)
RCSNode *rcs;
const char *rev;
{
char *p;
char *tmp = xstrdup (rev);
long r1;
char *retval;
retval = xmalloc (strlen (rev) + 1);
p = strrchr (tmp, '.');
*p = '\0';
r1 = strtol (p+1, NULL, 10);
do {
if (--r1 == 0)
{
p = strrchr (tmp, '.');
if (p == NULL)
retval = NULL;
else
{
*p = '\0';
sprintf (retval, "%s", tmp);
}
break;
}
sprintf (retval, "%s.%ld", tmp, r1);
} while (!RCS_exist_rev (rcs, retval));
free (tmp);
return retval;
}
char *
gca (rev1, rev2)
const char *rev1;
const char *rev2;
{
int dots;
char *gca, *g;
const char *p1, *p2;
int r1, r2;
char *retval;
if (rev1 == NULL || rev2 == NULL)
{
error (0, 0, "sanity failure in gca");
abort();
}
g = gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
p1 = rev1;
p2 = rev2;
do
{
r1 = strtol (p1, (char **) &p1, 10);
r2 = strtol (p2, (char **) &p2, 10);
(void) sprintf (g, "%d.", r1 < r2 ? r1 : r2);
g += strlen (g);
if (*p1 == '.') ++p1;
else break;
if (*p2 == '.') ++p2;
else break;
} while (r1 == r2);
*--g = '\0';
dots = numdots (gca);
if (dots == 0)
{
if (r2 < r1) p1 = p2;
if (*p1 == '\0')
{
error (0, 0, "bad revisions %s or %s", rev1, rev2);
abort();
}
else
{
*g++ = '.';
while (*p1 != '.' && *p1 != '\0')
*g++ = *p1++;
*g = '\0';
}
}
else if ((dots & 1) == 0)
{
g = strrchr (gca, '.');
*g = '\0';
}
retval = xstrdup (gca);
free (gca);
return retval;
}
void
check_numeric (rev, argc, argv)
const char *rev;
int argc;
char **argv;
{
if (rev == NULL || !isdigit ((unsigned char) *rev))
return;
if (argc != 1
|| (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0])))
{
error (0, 0, "while processing more than one file:");
error (1, 0, "attempt to specify a numeric revision");
}
}
char *
make_message_rcslegal (message)
const char *message;
{
char *dst, *dp;
const char *mp;
if (message == NULL) message = "";
dp = dst = (char *) xmalloc (strlen (message) + 1);
for (mp = message; *mp != '\0'; ++mp)
{
if (*mp == '\n')
{
while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t'))
--dp;
}
*dp++ = *mp;
}
while (dp > dst && isspace ((unsigned char) dp[-1]))
--dp;
*dp = '\0';
if (*dst == '\0')
{
free (dst);
dst = xstrdup ("*** empty log message ***");
}
return dst;
}
int
file_has_conflict (finfo, ts_conflict)
const struct file_info *finfo;
const char *ts_conflict;
{
char *filestamp;
int retcode;
assert (ts_conflict);
#ifdef SERVER_SUPPORT
if (server_active)
retcode = ts_conflict[0] == '=';
else
#endif
{
filestamp = time_stamp (finfo->file);
retcode = !strcmp (ts_conflict, filestamp);
free (filestamp);
}
return retcode;
}
int
file_has_markers (finfo)
const struct file_info *finfo;
{
FILE *fp;
char *line = NULL;
size_t line_allocated = 0;
int result;
result = 0;
fp = CVS_FOPEN (finfo->file, "r");
if (fp == NULL)
error (1, errno, "cannot open %s", finfo->fullname);
while (getline (&line, &line_allocated, fp) > 0)
{
if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 ||
strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 ||
strncmp (line, RCS_MERGE_PAT_3, sizeof RCS_MERGE_PAT_3 - 1) == 0)
{
result = 1;
goto out;
}
}
if (ferror (fp))
error (0, errno, "cannot read %s", finfo->fullname);
out:
if (fclose (fp) < 0)
error (0, errno, "cannot close %s", finfo->fullname);
if (line != NULL)
free (line);
return result;
}
void
get_file (name, fullname, mode, buf, bufsize, len)
const char *name;
const char *fullname;
const char *mode;
char **buf;
size_t *bufsize;
size_t *len;
{
struct stat s;
size_t nread;
char *tobuf;
FILE *e;
size_t filesize;
if (name == NULL)
{
e = stdin;
filesize = 100;
}
else
{
if (CVS_STAT (name, &s) < 0)
error (1, errno, "can't stat %s", fullname);
filesize = s.st_size;
e = open_file (name, mode);
}
if (*buf == NULL || *bufsize <= filesize)
{
*bufsize = filesize + 1;
*buf = xrealloc (*buf, *bufsize);
}
tobuf = *buf;
nread = 0;
while (1)
{
size_t got;
got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
if (ferror (e))
error (1, errno, "can't read %s", fullname);
nread += got;
tobuf += got;
if (feof (e))
break;
if (tobuf == *buf + *bufsize)
{
int c;
long off;
c = getc (e);
if (c == EOF)
break;
off = tobuf - *buf;
expand_string (buf, bufsize, *bufsize + 100);
tobuf = *buf + off;
*tobuf++ = c;
++nread;
}
}
if (e != stdin && fclose (e) < 0)
error (0, errno, "cannot close %s", fullname);
*len = nread;
if (nread == *bufsize)
expand_string (buf, bufsize, *bufsize + 1);
(*buf)[nread] = '\0';
}
void
resolve_symlink (filename)
char **filename;
{
if (filename == NULL || *filename == NULL)
return;
while (islink (*filename))
{
#ifdef HAVE_READLINK
char *newname = xreadlink (*filename);
if (isabsolute (newname))
{
free (*filename);
*filename = newname;
}
else
{
const char *oldname = last_component (*filename);
int dirlen = oldname - *filename;
char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
strncpy (fullnewname, *filename, dirlen);
strcpy (fullnewname + dirlen, newname);
free (newname);
free (*filename);
*filename = fullnewname;
}
#else
error (1, 0, "internal error: islink doesn't like readlink");
#endif
}
}
char *
backup_file (filename, suffix)
const char *filename;
const char *suffix;
{
char *backup_name;
if (suffix == NULL)
{
backup_name = xmalloc (sizeof (BAKPREFIX) + strlen (filename) + 1);
sprintf (backup_name, "%s%s", BAKPREFIX, filename);
}
else
{
backup_name = xmalloc (sizeof (BAKPREFIX)
+ strlen (filename)
+ strlen (suffix)
+ 2);
sprintf (backup_name, "%s%s.%s", BAKPREFIX, filename, suffix);
}
if (isfile (filename))
copy_file (filename, backup_name);
return backup_name;
}
char *
shell_escape(buf, str)
char *buf;
const char *str;
{
static const char meta[] = "$`\\\"";
const char *p;
for (;;)
{
p = strpbrk(str, meta);
if (!p) p = str + strlen(str);
if (p > str)
{
memcpy(buf, str, p - str);
buf += p - str;
}
if (!*p) break;
*buf++ = '\\';
*buf++ = *p++;
str = p;
}
*buf = '\0';
return buf;
}
void
sleep_past (desttime)
time_t desttime;
{
time_t t;
long s;
long us;
while (time (&t) <= desttime)
{
#ifdef HAVE_GETTIMEOFDAY
struct timeval tv;
gettimeofday (&tv, NULL);
if (tv.tv_sec > desttime)
break;
s = desttime - tv.tv_sec;
if (tv.tv_usec > 0)
us = 1000000 - tv.tv_usec;
else
{
s++;
us = 0;
}
#else
s = desttime - t;
us = 20000;
#endif
#if defined(HAVE_NANOSLEEP)
{
struct timespec ts;
ts.tv_sec = s;
ts.tv_nsec = us * 1000;
(void)nanosleep (&ts, NULL);
}
#elif defined(HAVE_USLEEP)
if (s > 0)
(void)sleep (s);
else
(void)usleep (us);
#elif defined(HAVE_SELECT)
{
struct timeval tv;
tv.tv_sec = s;
tv.tv_usec = us;
(void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
&tv);
}
#else
if (us > 0) s++;
(void)sleep(s);
#endif
}
}
int
isabsolute (filename)
const char *filename;
{
return ISABSOLUTE (filename);
}