xref: /openbsd/gnu/usr.bin/cvs/src/subr.c (revision f2dfb0a4)
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * Copyright (c) 1989-1992, Brian Berliner
4  *
5  * You may distribute under the terms of the GNU General Public License as
6  * specified in the README file that comes with the CVS source distribution.
7  *
8  * Various useful functions for the CVS support code.
9  */
10 
11 #include "cvs.h"
12 #include "getline.h"
13 
14 extern char *getlogin ();
15 
16 /*
17  * malloc some data and die if it fails
18  */
19 char *
20 xmalloc (bytes)
21     size_t bytes;
22 {
23     char *cp;
24 
25     /* Parts of CVS try to xmalloc zero bytes and then free it.  Some
26        systems have a malloc which returns NULL for zero byte
27        allocations but a free which can't handle NULL, so compensate. */
28     if (bytes == 0)
29 	bytes = 1;
30 
31     cp = malloc (bytes);
32     if (cp == NULL)
33 	error (1, 0, "out of memory; can not allocate %lu bytes",
34 	       (unsigned long) bytes);
35     return (cp);
36 }
37 
38 /*
39  * realloc data and die if it fails [I've always wanted to have "realloc" do
40  * a "malloc" if the argument is NULL, but you can't depend on it.  Here, I
41  * can *force* it.
42  */
43 void *
44 xrealloc (ptr, bytes)
45     void *ptr;
46     size_t bytes;
47 {
48     char *cp;
49 
50     if (!ptr)
51 	cp = malloc (bytes);
52     else
53 	cp = realloc (ptr, bytes);
54 
55     if (cp == NULL)
56 	error (1, 0, "can not reallocate %lu bytes", (unsigned long) bytes);
57     return (cp);
58 }
59 
60 /* Two constants which tune expand_string.  Having MIN_INCR as large
61    as 1024 might waste a bit of memory, but it shouldn't be too bad
62    (CVS used to allocate arrays of, say, 3000, PATH_MAX (8192, often),
63    or other such sizes).  Probably anything which is going to allocate
64    memory which is likely to get as big as MAX_INCR shouldn't be doing
65    it in one block which must be contiguous, but since getrcskey does
66    so, we might as well limit the wasted memory to MAX_INCR or so
67    bytes.  */
68 
69 #define MIN_INCR 1024
70 #define MAX_INCR (2*1024*1024)
71 
72 /* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N
73    characters of space.  Reallocate it so that points to at least
74    NEWSIZE bytes of space.  Gives a fatal error if out of memory;
75    if it returns it was successful.  */
76 void
77 expand_string (strptr, n, newsize)
78     char **strptr;
79     size_t *n;
80     size_t newsize;
81 {
82     if (*n < newsize)
83     {
84 	while (*n < newsize)
85 	{
86 	    if (*n < MIN_INCR)
87 		*n += MIN_INCR;
88 	    else if (*n > MAX_INCR)
89 		*n += MAX_INCR;
90 	    else
91 		*n *= 2;
92 	}
93 	*strptr = xrealloc (*strptr, *n);
94     }
95 }
96 
97 /*
98  * Duplicate a string, calling xmalloc to allocate some dynamic space
99  */
100 char *
101 xstrdup (str)
102     const char *str;
103 {
104     char *s;
105 
106     if (str == NULL)
107 	return ((char *) NULL);
108     s = xmalloc (strlen (str) + 1);
109     (void) strcpy (s, str);
110     return (s);
111 }
112 
113 /* Remove trailing newlines from STRING, destructively. */
114 void
115 strip_trailing_newlines (str)
116      char *str;
117 {
118     int len;
119     len = strlen (str) - 1;
120 
121     while (str[len] == '\n')
122 	str[len--] = '\0';
123 }
124 
125 /* Return the number of levels that path ascends above where it starts.
126    For example:
127    "../../foo" -> 2
128    "foo/../../bar" -> 1
129    */
130 /* FIXME: Should be using ISDIRSEP, last_component, or some other
131    mechanism which is more general than just looking at slashes,
132    particularly for the client.c caller.  The server.c caller might
133    want something different, so be careful.  */
134 int
135 pathname_levels (path)
136     char *path;
137 {
138     char *p;
139     char *q;
140     int level;
141     int max_level;
142 
143     max_level = 0;
144     p = path;
145     level = 0;
146     do
147     {
148 	q = strchr (p, '/');
149 	if (q != NULL)
150 	    ++q;
151 	if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/'))
152 	{
153 	    --level;
154 	    if (-level > max_level)
155 		max_level = -level;
156 	}
157 	else if (p[0] == '.' && (p[1] == '\0' || p[1] == '/'))
158 	    ;
159 	else
160 	    ++level;
161 	p = q;
162     } while (p != NULL);
163     return max_level;
164 }
165 
166 
167 /* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1]
168    are malloc'd and so is *ARGV itself.  Such a vector is allocated by
169    line2argv or expand_wild, for example.  */
170 void
171 free_names (pargc, argv)
172     int *pargc;
173     char **argv;
174 {
175     register int i;
176 
177     for (i = 0; i < *pargc; i++)
178     {					/* only do through *pargc */
179 	free (argv[i]);
180     }
181     free (argv);
182     *pargc = 0;				/* and set it to zero when done */
183 }
184 
185 /* Convert LINE into arguments separated by SEPCHARS.  Set *ARGC
186    to the number of arguments found, and (*ARGV)[0] to the first argument,
187    (*ARGV)[1] to the second, etc.  *ARGV is malloc'd and so are each of
188    (*ARGV)[0], (*ARGV)[1], ...  Use free_names() to return the memory
189    allocated here back to the free pool.  */
190 void
191 line2argv (pargc, argv, line, sepchars)
192     int *pargc;
193     char ***argv;
194     char *line;
195     char *sepchars;
196 {
197     char *cp;
198     /* Could make a case for size_t or some other unsigned type, but
199        we'll stick with int to avoid signed/unsigned warnings when
200        comparing with *pargc.  */
201     int argv_allocated;
202 
203     /* Small for testing.  */
204     /* argv_allocated must be at least 3 because at some places
205        (e.g. checkout_proc) cvs alters argv[2].  */
206     argv_allocated = 4;
207     *argv = (char **) xmalloc (argv_allocated * sizeof (**argv));
208 
209     *pargc = 0;
210     for (cp = strtok (line, sepchars); cp; cp = strtok ((char *) NULL, sepchars))
211     {
212 	if (*pargc == argv_allocated)
213 	{
214 	    argv_allocated *= 2;
215 	    *argv = xrealloc (*argv, argv_allocated * sizeof (**argv));
216 	}
217 	(*argv)[*pargc] = xstrdup (cp);
218 	(*pargc)++;
219     }
220 }
221 
222 /*
223  * Returns the number of dots ('.') found in an RCS revision number
224  */
225 int
226 numdots (s)
227     const char *s;
228 {
229     int dots = 0;
230 
231     for (; *s; s++)
232     {
233 	if (*s == '.')
234 	    dots++;
235     }
236     return (dots);
237 }
238 
239 /* Compare revision numbers REV1 and REV2 by consecutive fields.
240    Return negative, zero, or positive in the manner of strcmp.  The
241    two revision numbers must have the same number of fields, or else
242    compare_revnums will return an inaccurate result. */
243 int
244 compare_revnums (rev1, rev2)
245     const char *rev1;
246     const char *rev2;
247 {
248     const char *s, *sp;
249     const char *t, *tp;
250     char *snext, *tnext;
251     int result = 0;
252 
253     sp = s = rev1;
254     tp = t = rev2;
255     while (result == 0)
256     {
257 	result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
258 	if (*snext == '\0' || *tnext == '\0')
259 	    break;
260 	sp = snext + 1;
261 	tp = tnext + 1;
262     }
263 
264     return result;
265 }
266 
267 char *
268 increment_revnum (rev)
269     const char *rev;
270 {
271     char *newrev, *p;
272     int lastfield;
273     size_t len = strlen (rev);
274 
275     newrev = (char *) xmalloc (len + 2);
276     memcpy (newrev, rev, len + 1);
277     p = strrchr (newrev, '.');
278     if (p == NULL)
279     {
280 	free (newrev);
281 	return NULL;
282     }
283     lastfield = atoi (++p);
284     sprintf (p, "%d", lastfield + 1);
285 
286     return newrev;
287 }
288 
289 /* Return the username by which the caller should be identified in
290    CVS, in contexts such as the author field of RCS files, various
291    logs, etc.  */
292 char *
293 getcaller ()
294 {
295 #ifndef SYSTEM_GETCALLER
296     static char *cache;
297     struct passwd *pw;
298     uid_t uid;
299 #endif
300 
301     /* If there is a CVS username, return it.  */
302 #ifdef AUTH_SERVER_SUPPORT
303     if (CVS_Username != NULL)
304 	return CVS_Username;
305 #endif
306 
307 #ifdef SYSTEM_GETCALLER
308     return SYSTEM_GETCALLER ();
309 #else
310     /* Get the caller's login from his uid.  If the real uid is "root"
311        try LOGNAME USER or getlogin(). If getlogin() and getpwuid()
312        both fail, return the uid as a string.  */
313 
314     if (cache != NULL)
315 	return cache;
316 
317     uid = getuid ();
318     if (uid == (uid_t) 0)
319     {
320 	char *name;
321 
322 	/* super-user; try getlogin() to distinguish */
323 	if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
324 	     (name = getenv("USER"))) && *name)
325 	{
326 	    cache = xstrdup (name);
327 	    return cache;
328 	}
329     }
330     if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
331     {
332 	char uidname[20];
333 
334 	(void) sprintf (uidname, "uid%lu", (unsigned long) uid);
335 	cache = xstrdup (uidname);
336 	return cache;
337     }
338     cache = xstrdup (pw->pw_name);
339     return cache;
340 #endif
341 }
342 
343 #ifdef lint
344 #ifndef __GNUC__
345 /* ARGSUSED */
346 time_t
347 get_date (date, now)
348     char *date;
349     struct timeb *now;
350 {
351     time_t foo = 0;
352 
353     return (foo);
354 }
355 #endif
356 #endif
357 
358 /* Given two revisions, find their greatest common ancestor.  If the
359    two input revisions exist, then rcs guarantees that the gca will
360    exist.  */
361 
362 char *
363 gca (rev1, rev2)
364     const char *rev1;
365     const char *rev2;
366 {
367     int dots;
368     char *gca;
369     const char *p[2];
370     int j[2];
371     char *retval;
372 
373     if (rev1 == NULL || rev2 == NULL)
374     {
375 	error (0, 0, "sanity failure in gca");
376 	abort();
377     }
378 
379     /* The greatest common ancestor will have no more dots, and numbers
380        of digits for each component no greater than the arguments.  Therefore
381        this string will be big enough.  */
382     gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
383 
384     /* walk the strings, reading the common parts. */
385     gca[0] = '\0';
386     p[0] = rev1;
387     p[1] = rev2;
388     do
389     {
390 	int i;
391 	char c[2];
392 	char *s[2];
393 
394 	for (i = 0; i < 2; ++i)
395 	{
396 	    /* swap out the dot */
397 	    s[i] = strchr (p[i], '.');
398 	    if (s[i] != NULL) {
399 		c[i] = *s[i];
400 	    }
401 
402 	    /* read an int */
403 	    j[i] = atoi (p[i]);
404 
405 	    /* swap back the dot... */
406 	    if (s[i] != NULL) {
407 		*s[i] = c[i];
408 		p[i] = s[i] + 1;
409 	    }
410 	    else
411 	    {
412 		/* or mark us at the end */
413 		p[i] = NULL;
414 	    }
415 
416 	}
417 
418 	/* use the lowest. */
419 	(void) sprintf (gca + strlen (gca), "%d.",
420 			j[0] < j[1] ? j[0] : j[1]);
421 
422     } while (j[0] == j[1]
423 	     && p[0] != NULL
424 	     && p[1] != NULL);
425 
426     /* back up over that last dot. */
427     gca[strlen(gca) - 1] = '\0';
428 
429     /* numbers differ, or we ran out of strings.  we're done with the
430        common parts.  */
431 
432     dots = numdots (gca);
433     if (dots == 0)
434     {
435 	/* revisions differ in trunk major number.  */
436 
437 	char *q;
438 	const char *s;
439 
440 	s = (j[0] < j[1]) ? p[0] : p[1];
441 
442 	if (s == NULL)
443 	{
444 	    /* we only got one number.  this is strange.  */
445 	    error (0, 0, "bad revisions %s or %s", rev1, rev2);
446 	    abort();
447 	}
448 	else
449 	{
450 	    /* we have a minor number.  use it.  */
451 	    q = gca + strlen (gca);
452 
453 	    *q++ = '.';
454 	    for ( ; *s != '.' && *s != '\0'; )
455 		*q++ = *s++;
456 
457 	    *q = '\0';
458 	}
459     }
460     else if ((dots & 1) == 0)
461     {
462 	/* if we have an even number of dots, then we have a branch.
463 	   remove the last number in order to make it a revision.  */
464 
465 	char *s;
466 
467 	s = strrchr(gca, '.');
468 	*s = '\0';
469     }
470 
471     retval = xstrdup (gca);
472     free (gca);
473     return retval;
474 }
475 
476 /* Give fatal error if REV is numeric and ARGC,ARGV imply we are
477    planning to operate on more than one file.  The current directory
478    should be the working directory.  Note that callers assume that we
479    will only be checking the first character of REV; it need not have
480    '\0' at the end of the tag name and other niceties.  Right now this
481    is only called from admin.c, but if people like the concept it probably
482    should also be called from diff -r, update -r, get -r, and log -r.  */
483 
484 void
485 check_numeric (rev, argc, argv)
486     const char *rev;
487     int argc;
488     char **argv;
489 {
490     if (rev == NULL || !isdigit (*rev))
491 	return;
492 
493     /* Note that the check for whether we are processing more than one
494        file is (basically) syntactic; that is, we don't behave differently
495        depending on whether a directory happens to contain only a single
496        file or whether it contains more than one.  I strongly suspect this
497        is the least confusing behavior.  */
498     if (argc != 1
499 	|| (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0])))
500     {
501 	error (0, 0, "while processing more than one file:");
502 	error (1, 0, "attempt to specify a numeric revision");
503     }
504 }
505 
506 /*
507  *  Sanity checks and any required fix-up on message passed to RCS via '-m'.
508  *  RCS 5.7 requires that a non-total-whitespace, non-null message be provided
509  *  with '-m'.  Returns a newly allocated, non-empty buffer with whitespace
510  *  stripped from end of lines and end of buffer.
511  *
512  *  TODO: We no longer use RCS to manage repository files, so maybe this
513  *  nonsense about non-empty log fields can be dropped.
514  */
515 char *
516 make_message_rcslegal (message)
517      char *message;
518 {
519     char *dst, *dp, *mp;
520 
521     if (message == NULL) message = "";
522 
523     /* Strip whitespace from end of lines and end of string. */
524     dp = dst = (char *) xmalloc (strlen (message) + 1);
525     for (mp = message; *mp != '\0'; ++mp)
526     {
527 	if (*mp == '\n')
528 	{
529 	    /* At end-of-line; backtrack to last non-space. */
530 	    while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t'))
531 		--dp;
532 	}
533 	*dp++ = *mp;
534     }
535 
536     /* Backtrack to last non-space at end of string, and truncate. */
537     while (dp > dst && isspace (dp[-1]))
538 	--dp;
539     *dp = '\0';
540 
541     /* After all that, if there was no non-space in the string,
542        substitute a non-empty message. */
543     if (*dst == '\0')
544     {
545 	free (dst);
546 	dst = xstrdup ("*** empty log message ***");
547     }
548 
549     return dst;
550 }
551 
552 /* Does the file FINFO contain conflict markers?  The whole concept
553    of looking at the contents of the file to figure out whether there are
554    unresolved conflicts is kind of bogus (people do want to manage files
555    which contain those patterns not as conflict markers), but for now it
556    is what we do.  */
557 int
558 file_has_markers (finfo)
559     const struct file_info *finfo;
560 {
561     FILE *fp;
562     char *line = NULL;
563     size_t line_allocated = 0;
564     int result;
565 
566     result = 0;
567     fp = CVS_FOPEN (finfo->file, "r");
568     if (fp == NULL)
569 	error (1, errno, "cannot open %s", finfo->fullname);
570     while (getline (&line, &line_allocated, fp) > 0)
571     {
572 	if (strncmp (line, RCS_MERGE_PAT, sizeof RCS_MERGE_PAT - 1) == 0)
573 	{
574 	    result = 1;
575 	    goto out;
576 	}
577     }
578     if (ferror (fp))
579 	error (0, errno, "cannot read %s", finfo->fullname);
580 out:
581     if (fclose (fp) < 0)
582 	error (0, errno, "cannot close %s", finfo->fullname);
583     if (line != NULL)
584 	free (line);
585     return result;
586 }
587 
588 /* Read the entire contents of the file NAME into *BUF.
589    If NAME is NULL, read from stdin.  *BUF
590    is a pointer returned from malloc (or NULL), pointing to *BUFSIZE
591    bytes of space.  The actual size is returned in *LEN.  On error,
592    give a fatal error.  The name of the file to use in error messages
593    (typically will include a directory if we have changed directory)
594    is FULLNAME.  MODE is "r" for text or "rb" for binary.  */
595 
596 void
597 get_file (name, fullname, mode, buf, bufsize, len)
598     const char *name;
599     const char *fullname;
600     const char *mode;
601     char **buf;
602     size_t *bufsize;
603     size_t *len;
604 {
605     struct stat s;
606     size_t nread;
607     char *tobuf;
608     FILE *e;
609     size_t filesize;
610 
611     if (name == NULL)
612     {
613 	e = stdin;
614 	filesize = 100;	/* force allocation of minimum buffer */
615     }
616     else
617     {
618 	if (CVS_LSTAT (name, &s) < 0)
619 	    error (1, errno, "can't stat %s", fullname);
620 
621 	/* Don't attempt to read special files or symlinks. */
622 	if (!S_ISREG (s.st_mode))
623 	{
624 	    *len = 0;
625 	    return;
626 	}
627 
628 	/* Convert from signed to unsigned.  */
629 	filesize = s.st_size;
630 
631 	e = open_file (name, mode);
632     }
633 
634     if (*bufsize < filesize)
635     {
636 	*bufsize = filesize;
637 	*buf = xrealloc (*buf, *bufsize);
638     }
639 
640     tobuf = *buf;
641     nread = 0;
642     while (1)
643     {
644 	size_t got;
645 
646 	got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
647 	if (ferror (e))
648 	    error (1, errno, "can't read %s", fullname);
649 	nread += got;
650 	tobuf += got;
651 
652 	if (feof (e))
653 	    break;
654 
655 	/* It's probably paranoid to think S.ST_SIZE might be
656 	   too small to hold the entire file contents, but we
657 	   handle it just in case.  */
658 	if (tobuf == *buf + *bufsize)
659 	{
660 	    int c;
661 	    long off;
662 
663 	    c = getc (e);
664 	    if (c == EOF)
665 		break;
666 	    off = tobuf - *buf;
667 	    expand_string (buf, bufsize, *bufsize + 100);
668 	    tobuf = *buf + off;
669 	    *tobuf++ = c;
670 	    ++nread;
671 	}
672     }
673 
674     if (e != stdin && fclose (e) < 0)
675 	error (0, errno, "cannot close %s", fullname);
676 
677     *len = nread;
678 
679     /* Force *BUF to be large enough to hold a null terminator. */
680     if (*buf != NULL)
681     {
682 	if (nread == *bufsize)
683 	    expand_string (buf, bufsize, *bufsize + 1);
684 	(*buf)[nread] = '\0';
685     }
686 }
687