#include "cvs.h"
#include "getline.h"
extern char *getlogin ();
char *
xmalloc (bytes)
size_t bytes;
{
char *cp;
if (bytes == 0)
bytes = 1;
cp = malloc (bytes);
if (cp == NULL)
error (1, 0, "out of memory; can not allocate %lu bytes",
(unsigned long) bytes);
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)
error (1, 0, "can not reallocate %lu bytes", (unsigned long) bytes);
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;
}
*strptr = xrealloc (*strptr, *n);
}
}
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);
}
void
strip_trailing_newlines (str)
char *str;
{
int len;
len = strlen (str) - 1;
while (str[len] == '\n')
str[len--] = '\0';
}
int
pathname_levels (path)
char *path;
{
char *p;
char *q;
int level;
int max_level;
max_level = 0;
p = path;
level = 0;
do
{
q = strchr (p, '/');
if (q != NULL)
++q;
if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/'))
{
--level;
if (-level > max_level)
max_level = -level;
}
else if (p[0] == '.' && (p[1] == '\0' || p[1] == '/'))
;
else
++level;
p = q;
} while (p != NULL);
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 = 4;
*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 *s, *sp;
const char *t, *tp;
char *snext, *tnext;
int result = 0;
sp = s = rev1;
tp = t = rev2;
while (result == 0)
{
result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
if (*snext == '\0' || *tnext == '\0')
break;
sp = snext + 1;
tp = tnext + 1;
}
return result;
}
char *
increment_revnum (rev)
const char *rev;
{
char *newrev, *p;
int lastfield;
size_t len = strlen (rev);
newrev = (char *) xmalloc (len + 2);
memcpy (newrev, rev, len + 1);
p = strrchr (newrev, '.');
if (p == NULL)
{
free (newrev);
return NULL;
}
lastfield = atoi (++p);
sprintf (p, "%d", lastfield + 1);
return newrev;
}
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 *
gca (rev1, rev2)
const char *rev1;
const char *rev2;
{
int dots;
char *gca;
const char *p[2];
int j[2];
char *retval;
if (rev1 == NULL || rev2 == NULL)
{
error (0, 0, "sanity failure in gca");
abort();
}
gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
gca[0] = '\0';
p[0] = rev1;
p[1] = rev2;
do
{
int i;
char c[2];
char *s[2];
for (i = 0; i < 2; ++i)
{
s[i] = strchr (p[i], '.');
if (s[i] != NULL) {
c[i] = *s[i];
}
j[i] = atoi (p[i]);
if (s[i] != NULL) {
*s[i] = c[i];
p[i] = s[i] + 1;
}
else
{
p[i] = NULL;
}
}
(void) sprintf (gca + strlen (gca), "%d.",
j[0] < j[1] ? j[0] : j[1]);
} while (j[0] == j[1]
&& p[0] != NULL
&& p[1] != NULL);
gca[strlen(gca) - 1] = '\0';
dots = numdots (gca);
if (dots == 0)
{
char *q;
const char *s;
s = (j[0] < j[1]) ? p[0] : p[1];
if (s == NULL)
{
error (0, 0, "bad revisions %s or %s", rev1, rev2);
abort();
}
else
{
q = gca + strlen (gca);
*q++ = '.';
for ( ; *s != '.' && *s != '\0'; )
*q++ = *s++;
*q = '\0';
}
}
else if ((dots & 1) == 0)
{
char *s;
s = strrchr(gca, '.');
*s = '\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 (*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)
char *message;
{
char *dst, *dp, *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 (dp[-1]))
--dp;
*dp = '\0';
if (*dst == '\0')
{
free (dst);
dst = xstrdup ("*** empty log message ***");
}
return dst;
}
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, sizeof RCS_MERGE_PAT - 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_LSTAT (name, &s) < 0)
error (1, errno, "can't stat %s", fullname);
if (!S_ISREG (s.st_mode))
{
*len = 0;
return;
}
filesize = s.st_size;
e = open_file (name, mode);
}
if (*bufsize < filesize)
{
*bufsize = filesize;
*buf = xrealloc (*buf, *bufsize);
}
tobuf = *buf;
nread = 0;
while (1)
{
size_t got;
got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
if (ferror (e))
error (1, errno, "can't read %s", fullname);
nread += got;
tobuf += got;
if (feof (e))
break;
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 (*buf != NULL)
{
if (nread == *bufsize)
expand_string (buf, bufsize, *bufsize + 1);
(*buf)[nread] = '\0';
}
}