home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / src / subr.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  6KB  |  319 lines

  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 1.4 kit.
  7.  * 
  8.  * Various useful functions for the CVS support code.
  9.  */
  10.  
  11. #include "cvs.h"
  12.  
  13. extern char *getlogin ();
  14.  
  15. /*
  16.  * malloc some data and die if it fails
  17.  */
  18. char *
  19. xmalloc (bytes)
  20.     size_t bytes;
  21. {
  22.     char *cp;
  23.  
  24.     /* Parts of CVS try to xmalloc zero bytes and then free it.  Some
  25.        systems have a malloc which returns NULL for zero byte
  26.        allocations but a free which can't handle NULL, so compensate. */
  27.     if (bytes == 0)
  28.     bytes = 1;
  29.  
  30.     cp = malloc (bytes);
  31.     if (cp == NULL)
  32.     error (1, 0, "can not allocate %lu bytes", (unsigned long) bytes);
  33.     return (cp);
  34. }
  35.  
  36. /*
  37.  * realloc data and die if it fails [I've always wanted to have "realloc" do
  38.  * a "malloc" if the argument is NULL, but you can't depend on it.  Here, I
  39.  * can *force* it.
  40.  */
  41. void *
  42. xrealloc (ptr, bytes)
  43.     void *ptr;
  44.     size_t bytes;
  45. {
  46.     char *cp;
  47.  
  48.     if (!ptr)
  49.     cp = malloc (bytes);
  50.     else
  51.     cp = realloc (ptr, bytes);
  52.  
  53.     if (cp == NULL)
  54.     error (1, 0, "can not reallocate %lu bytes", (unsigned long) bytes);
  55.     return (cp);
  56. }
  57.  
  58. /*
  59.  * Duplicate a string, calling xmalloc to allocate some dynamic space
  60.  */
  61. char *
  62. xstrdup (str)
  63.     const char *str;
  64. {
  65.     char *s;
  66.  
  67.     if (str == NULL)
  68.     return ((char *) NULL);
  69.     s = xmalloc (strlen (str) + 1);
  70.     (void) strcpy (s, str);
  71.     return (s);
  72. }
  73.  
  74. /* Remove trailing newlines from STRING, destructively. */
  75. void
  76. strip_trailing_newlines (str)
  77.      char *str;
  78. {
  79.   int len;
  80.   len = strlen (str) - 1;
  81.  
  82.   while (str[len] == '\n')
  83.     str[len--] = '\0';
  84. }
  85.  
  86. /*
  87.  * Recover the space allocated by Find_Names() and line2argv()
  88.  */
  89. void
  90. free_names (pargc, argv)
  91.     int *pargc;
  92.     char **argv;
  93. {
  94.     register int i;
  95.  
  96.     for (i = 0; i < *pargc; i++)
  97.     {                    /* only do through *pargc */
  98.     free (argv[i]);
  99.     }
  100.     *pargc = 0;                /* and set it to zero when done */
  101. }
  102.  
  103. /*
  104.  * Convert a line into argc/argv components and return the result in the
  105.  * arguments as passed.  Use free_names() to return the memory allocated here
  106.  * back to the free pool.
  107.  */
  108. void
  109. line2argv (pargc, argv, line)
  110.     int *pargc;
  111.     char **argv;
  112.     char *line;
  113. {
  114.     char *cp;
  115.  
  116.     *pargc = 0;
  117.     for (cp = strtok (line, " \t"); cp; cp = strtok ((char *) NULL, " \t"))
  118.     {
  119.     argv[*pargc] = xstrdup (cp);
  120.     (*pargc)++;
  121.     }
  122. }
  123.  
  124. /*
  125.  * Returns the number of dots ('.') found in an RCS revision number
  126.  */
  127. int
  128. numdots (s)
  129.     const char *s;
  130. {
  131.     int dots = 0;
  132.  
  133.     for (; *s; s++)
  134.     {
  135.     if (*s == '.')
  136.         dots++;
  137.     }
  138.     return (dots);
  139. }
  140.  
  141. /*
  142.  * Get the caller's login from his uid. If the real uid is "root" try LOGNAME
  143.  * USER or getlogin(). If getlogin() and getpwuid() both fail, return
  144.  * the uid as a string.
  145.  */
  146. char *
  147. getcaller ()
  148. {
  149.     static char uidname[20];
  150.     struct passwd *pw;
  151.     char *name;
  152.     uid_t uid;
  153.  
  154.     uid = getuid ();
  155.     if (uid == (uid_t) 0)
  156.     {
  157.     /* super-user; try getlogin() to distinguish */
  158.     if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
  159.          (name = getenv("USER"))) && *name)
  160.         return (name);
  161.     }
  162.     if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
  163.     {
  164.     (void) sprintf (uidname, "uid%lu", (unsigned long) uid);
  165.     return (uidname);
  166.     }
  167.     return (pw->pw_name);
  168. }
  169.  
  170. #ifdef lint
  171. #ifndef __GNUC__
  172. /* ARGSUSED */
  173. time_t
  174. get_date (date, now)
  175.     char *date;
  176.     struct timeb *now;
  177. {
  178.     time_t foo = 0;
  179.  
  180.     return (foo);
  181. }
  182. #endif
  183. #endif
  184.  
  185. /* Given two revisions, find their greatest common ancestor.  If the
  186.    two input revisions exist, then rcs guarantees that the gca will
  187.    exist.  */
  188.  
  189. char *
  190. gca (rev1, rev2)
  191.     char *rev1;
  192.     char *rev2;
  193. {
  194.     int dots;
  195.     char gca[PATH_MAX];
  196.     char *p[2];
  197.     int j[2];
  198.  
  199.     if (rev1 == NULL || rev2 == NULL)
  200.     {
  201.     error (0, 0, "sanity failure in gca");
  202.     abort();
  203.     }
  204.  
  205.     /* walk the strings, reading the common parts. */
  206.     gca[0] = '\0';
  207.     p[0] = rev1;
  208.     p[1] = rev2;
  209.     do
  210.     {
  211.     int i;
  212.     char c[2];
  213.     char *s[2];
  214.     
  215.     for (i = 0; i < 2; ++i)
  216.     {
  217.         /* swap out the dot */
  218.         s[i] = strchr (p[i], '.');
  219.         if (s[i] != NULL) {
  220.         c[i] = *s[i];
  221.         }
  222.         
  223.         /* read an int */
  224.         j[i] = atoi (p[i]);
  225.         
  226.         /* swap back the dot... */
  227.         if (s[i] != NULL) {
  228.         *s[i] = c[i];
  229.         p[i] = s[i] + 1;
  230.         }
  231.         else
  232.         {
  233.         /* or mark us at the end */
  234.         p[i] = NULL;
  235.         }
  236.         
  237.     }
  238.     
  239.     /* use the lowest. */
  240.     (void) sprintf (gca + strlen (gca), "%d.",
  241.             j[0] < j[1] ? j[0] : j[1]);
  242.  
  243.     } while (j[0] == j[1]
  244.          && p[0] != NULL
  245.          && p[1] != NULL);
  246.  
  247.     /* back up over that last dot. */
  248.     gca[strlen(gca) - 1] = '\0';
  249.  
  250.     /* numbers differ, or we ran out of strings.  we're done with the
  251.        common parts.  */
  252.  
  253.     dots = numdots (gca);
  254.     if (dots == 0)
  255.     {
  256.     /* revisions differ in trunk major number.  */
  257.  
  258.     char *q;
  259.     char *s;
  260.  
  261.     s = (j[0] < j[1]) ? p[0] : p[1];
  262.  
  263.     if (s == NULL)
  264.     {
  265.         /* we only got one number.  this is strange.  */
  266.         error (0, 0, "bad revisions %s or %s", rev1, rev2);
  267.         abort();
  268.     }
  269.     else
  270.     {
  271.         /* we have a minor number.  use it.  */
  272.         q = gca + strlen (gca);
  273.         
  274.         *q++ = '.';
  275.         for ( ; *s != '.' && *s != '\0'; )
  276.         *q++ = *s++;
  277.         
  278.         *q = '\0';
  279.     }
  280.     }
  281.     else if ((dots & 1) == 0)
  282.     {
  283.     /* if we have an even number of dots, then we have a branch.
  284.        remove the last number in order to make it a revision.  */
  285.     
  286.     char *s;
  287.  
  288.     s = strrchr(gca, '.');
  289.     *s = '\0';
  290.     }
  291.  
  292.     return (xstrdup (gca));
  293. }
  294.  
  295. /*
  296.  *  Sanity checks and any required fix-up on message passed to RCS via '-m'.
  297.  *  RCS 5.7 requires that a non-total-whitespace, non-null message be provided
  298.  *  with '-m'.  Returns the original argument or a pointer to readonly
  299.  *  static storage.
  300.  */
  301. char *
  302. make_message_rcslegal (message)
  303.      char *message;
  304. {
  305.     if ((message == NULL) || (*message == '\0') || isspace (*message))
  306.     {
  307.         char *t;
  308.  
  309.     if (message)
  310.         for (t = message; *t; t++)
  311.             if (!isspace (*t))
  312.             return message;
  313.  
  314.     return "*** empty log message ***\n";
  315.     }
  316.  
  317.     return message;
  318. }
  319.