home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / rcs / sources / subr.c < prev    next >
C/C++ Source or Header  |  1992-01-19  |  9KB  |  411 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: subr.c,v 1.14.1.2 91/01/29 19:46:20 berliner Exp $";
  3. #endif
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  * Various useful functions for the CVS support code.
  12.  */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include <stdarg.h>
  18. #include "cvs.h"
  19.  
  20. /*
  21.  * Send a "printf" format string to stderr and die, calling the
  22.  * defined exit function first, if necessary
  23.  */
  24. error(doperror, fmt, ...)
  25.     int doperror;
  26.     char *fmt;
  27. {
  28.     va_list x1;
  29.     int err = errno;
  30.  
  31.     va_start(x1, fmt);
  32.     (void) fprintf(stderr, "%s: ", progname);
  33.     (void) vfprintf(stderr, fmt, x1);
  34.     if (doperror) {
  35.     (void) fprintf(stderr, ": ");
  36.     errno = err;
  37.     perror("");
  38.     errno = 0;
  39.     } else
  40.     (void) fprintf(stderr, "\n");
  41.     va_end(x1);
  42.     Lock_Cleanup(0);
  43.     exit(1);
  44. }
  45.  
  46. /*
  47.  * Like error() above, but just display the message to stderr,
  48.  * without dying or running the exit function.
  49.  */
  50. warn(doperror, fmt, ...)
  51.     int doperror;
  52.     char *fmt;
  53. {
  54.     va_list x1;
  55.     int err = errno;
  56.  
  57.     va_start(x1, fmt);
  58.     (void) fprintf(stderr, "%s: ", progname);
  59.     (void) vfprintf(stderr, fmt, x1);
  60.     if (doperror) {
  61.     (void) fprintf(stderr, ": ");
  62.     errno = err;
  63.     perror("");
  64.     errno = 0;
  65.     } else
  66.     (void) fprintf(stderr, "\n");
  67.     va_end(x1);
  68. }
  69.  
  70. /*
  71.  * Copies "from" to "to".
  72.  * mallocs a buffer large enough to hold the entire file and
  73.  * does one read/one write to do the copy.  This is reasonable,
  74.  * since source files are typically not too large.
  75.  */
  76. copy_file(from, to)
  77.     char *from;
  78.     char *to;
  79. {
  80.     struct stat sb;
  81.     int fdin, fdout, chunk;
  82.     char *buf;
  83.  
  84.     if ((fdin = open(from, O_RDONLY|O_BINARY)) < 0)
  85.     error(1, "cannot open %s for copying", from);
  86.     if (fstat(fdin, &sb) < 0)
  87.     error(1, "cannot fstat %s", from);
  88.     if ((fdout = open(to, O_CREAT|O_EXCL|O_RDWR|O_BINARY,
  89.                       (int) sb.st_mode & 07777)) < 0)
  90.     error(1, "cannot create %s for copying", to);
  91.     if (sb.st_size > 0) {
  92.     buf = xmalloc(COPYBUFFER);
  93.         while ( (chunk = (int) min(sb.st_size, COPYBUFFER)) > 0 ) {
  94.         if (read(fdin, buf, chunk) != chunk)
  95.             error(1, "cannot read file %s for copying", from);
  96.         if (write(fdout, buf, chunk) != chunk)
  97.             error(1, "cannot write file %s for copying", to);
  98.             sb.st_size -= chunk;
  99.         }
  100.     free(buf);
  101.     }
  102.     (void) close(fdin);
  103.     (void) close(fdout);
  104. }
  105.  
  106. /*
  107.  * Returns non-zero if the argument file is a directory, or
  108.  * is a symbolic link which points to a directory.
  109.  */
  110. isdir(file)
  111.     char *file;
  112. {
  113.     struct stat sb;
  114.  
  115.     if (stat(file, &sb) < 0)
  116.     return (0);
  117.     return ((sb.st_mode & S_IFMT) == S_IFDIR);
  118. }
  119.  
  120. /*
  121.  * Returns non-zero if the argument file is a symbolic link.
  122.  */
  123. islink(file)
  124.     char *file;
  125. {
  126.     struct stat sb;
  127.  
  128. #ifdef S_IFLNK
  129.     if (lstat(file, &sb) < 0)
  130.     return (0);
  131.     return ((sb.st_mode & S_IFMT) == S_IFLNK);
  132. #else
  133.     return (0);
  134. #endif
  135. }
  136.  
  137. /*
  138.  * Returns non-zero if the argument file exists.
  139.  */
  140. isfile(file)
  141.     char *file;
  142. {
  143.     struct stat sb;
  144.  
  145.     if (stat(file, &sb) < 0)
  146.     return (0);
  147.     return (1);
  148. }
  149.  
  150. /*
  151.  * Returns non-zero if the argument file is readable.
  152.  * XXX - muct be careful if "cvs" is ever made setuid!
  153.  */
  154. isreadable(file)
  155.     char *file;
  156. {
  157.     return (access(file, R_OK) != -1);
  158. }
  159.  
  160. /*
  161.  * Returns non-zero if the argument file is writable
  162.  * XXX - muct be careful if "cvs" is ever made setuid!
  163.  */
  164. iswritable(file)
  165.     char *file;
  166. {
  167.     return (access(file, W_OK) != -1);
  168. }
  169.  
  170. /*
  171.  * Open a file and die if it fails
  172.  */
  173. FILE *
  174. open_file(name, mode)
  175.     char *name;
  176.     char *mode;
  177. {
  178.     FILE *fp;
  179.  
  180.     if ((fp = fopen(name, mode)) == NULL)
  181.     error(1, "cannot open %s", name);
  182.     return (fp);
  183. }
  184.  
  185. /*
  186.  * Make a directory and die if it fails
  187.  */
  188. make_directory(name)
  189.     char *name;
  190. {
  191.     if (mkdir(name, 0777) < 0)
  192.     error(1, "cannot make directory %s", name);
  193. }
  194.  
  195. /*
  196.  * malloc some data and die if it fails
  197.  */
  198. char *
  199. xmalloc(bytes)
  200.     int bytes;
  201. {
  202.     char *cp;
  203.  
  204.     if (bytes <= 0)
  205.     error(0, "bad malloc size %d", bytes);
  206.     if ((cp = malloc((unsigned)bytes)) == NULL)
  207.     error(0, "malloc failed");
  208.     return (cp);
  209. }
  210.  
  211.  
  212. /*
  213.  * ppstrcmp() is a front-end for strcmp() when the arguments
  214.  * are pointers to pointers to chars.
  215.  */
  216. ppstrcmp(pp1, pp2)
  217.     register char **pp1, **pp2;
  218. {
  219.     return (strcmp(*pp1, *pp2));
  220. }
  221.  
  222. /*
  223.  * ppstrcmp_files() is a front-end for strcmp() when the arguments
  224.  * are pointers to pointers to chars.
  225.  * For some reason, the ppstrcmp() above sorts in reverse order when
  226.  * called from Entries2Files().
  227.  */
  228. ppstrcmp_files(pp1, pp2)
  229.     register char **pp1, **pp2;
  230. {
  231.     /*
  232.      * Reversing the arguments here cause for the
  233.      * correct alphabetical order sort, as we desire.
  234.      */
  235.     return (strcmp(*pp2, *pp1));
  236. }
  237.  
  238. /* Some UNIX distributions don't include these in their stat.h */
  239. #ifndef S_IWRITE
  240. #define    S_IWRITE    0000200        /* write permission, owner */
  241. #endif
  242. #ifndef S_IWGRP
  243. #define    S_IWGRP        0000020        /* write permission, grougroup */
  244. #endif
  245. #ifndef S_IWOTH
  246. #define    S_IWOTH        0000002        /* write permission, other */
  247. #endif
  248.  
  249. /*
  250.  * Change the mode of a file, either adding write permissions, or
  251.  * removing all write permissions.  Adding write permissions honors
  252.  * the current umask setting.
  253.  */
  254. xchmod(fname, writable)
  255.     char *fname;
  256.     int writable;
  257. {
  258.     struct stat sb;
  259.     int mode, oumask;
  260.  
  261.     if (stat(fname, &sb) < 0) {
  262.     warn(1, "cannot stat %s", fname);
  263.     return 0;
  264.     }
  265.     if (writable) {
  266.     oumask = umask(0);
  267.     (void) umask(oumask);
  268.     mode = sb.st_mode | ((S_IWRITE|S_IWGRP|S_IWOTH) & ~oumask);
  269.     } else {
  270.     mode = sb.st_mode & ~(S_IWRITE|S_IWGRP|S_IWOTH);
  271.     }
  272.     if (chmod(fname, mode) < 0)
  273.     warn(1, "cannot change mode of file %s", fname);
  274. }
  275.  
  276. /*
  277.  * Rename a file and die if it fails
  278.  */
  279. rename_file(from, to)
  280.     char *from;
  281.     char *to;
  282. {
  283.     (void) unlink(to);
  284.     if (rename(from, to) < 0)
  285.     error(1, "cannot rename file %s to %s", from, to);
  286. }
  287.  
  288. /*
  289.  * Compare "file1" to "file2".
  290.  * Return non-zero if they don't compare exactly.
  291.  *
  292.  * mallocs a buffer large enough to hold the entire file and
  293.  * does two reads to load the buffer and calls bcmp to do the cmp.
  294.  * This is reasonable, since source files are typically not too large.
  295.  */
  296. xcmp(file1, file2)
  297.     char *file1;
  298.     char *file2;
  299. {
  300.     register char *buf1, *buf2;
  301.     struct stat sb;
  302.     off_t size;
  303.     int ret, fd1, fd2, chunk;
  304.  
  305.     if ((fd1 = open(file1, O_RDONLY|O_BINARY)) < 0)
  306.     error(1, "cannot open file %s for comparing", file1);
  307.     if ((fd2 = open(file2, O_RDONLY|O_BINARY)) < 0)
  308.     error(1, "cannot open file %s for comparing", file2);
  309.     if (fstat(fd1, &sb) < 0)
  310.     error(1, "cannot fstat %s", file1);
  311.     size = sb.st_size;
  312.     if (fstat(fd2, &sb) < 0)
  313.     error(1, "cannot fstat %s", file2);
  314.     if (size == sb.st_size) {
  315.     if (size == 0)
  316.         ret = 0;
  317.     else {
  318.         buf1 = xmalloc(COPYBUFFER);
  319.         buf2 = xmalloc(COPYBUFFER);
  320.             while ( (chunk = (int) min(sb.st_size, COPYBUFFER)) > 0 ) {
  321.             if (read(fd1, buf1, chunk) != chunk)
  322.             error(1, "cannot read file %s cor comparing", file1);
  323.             if (read(fd2, buf2, chunk) != chunk)
  324.             error(1, "cannot read file %s for comparing", file2);
  325.             if ( ret = bcmp(buf1, buf2, chunk) )
  326.                     break;
  327.                 sb.st_size -= chunk;
  328.             }
  329.         free(buf1);
  330.         free(buf2);
  331.     }
  332.     } else
  333.     ret = 1;
  334.     (void) close(fd1);
  335.     (void) close(fd2);
  336.     return (ret);
  337. }
  338.  
  339. /*
  340.  * Recover the space allocated by Find_Names() and line2argv()
  341.  */
  342. free_names(pargc, argv)
  343.     int *pargc;
  344.     char *argv[];
  345. {
  346.     register int i;
  347.  
  348.     for (i = 0; i < *pargc; i++) {    /* only do through *pargc */
  349.     free(argv[i]);
  350.     }
  351.     *pargc = 0;                /* and set it to zero when done */
  352. }
  353.  
  354. /*
  355.  * Convert a line into argc/argv components and return the result in
  356.  * the arguments as passed.  Use free_names() to return the memory
  357.  * allocated here back to the free pool.
  358.  */
  359. line2argv(pargc, argv, line)
  360.     int *pargc;
  361.     char *argv[];
  362.     char *line;
  363. {
  364.     char *cp;
  365.  
  366.     *pargc = 0;
  367.     for (cp = strtok(line, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  368.     argv[*pargc] = xmalloc(strlen(cp) + 1);
  369.     (void) strcpy(argv[*pargc], cp);
  370.     (*pargc)++;
  371.     }
  372. }
  373.  
  374. /*
  375.  * Returns the number of dots ('.') found in an RCS revision number
  376.  */
  377. numdots(s)
  378.     char *s;
  379. {
  380.     char *cp;
  381.     int dots = 0;
  382.  
  383.     for (cp = s; *cp; cp++) {
  384.     if (*cp == '.')
  385.         dots++;
  386.     }
  387.     return (dots);
  388. }
  389.  
  390.  
  391. #ifdef OS2
  392. char *index_sep(char *path)
  393. {
  394.   char *p1 = strchr(path, '\\');
  395.   char *p2 = strchr(path, '/');
  396.   if ( !p1 ) return p2;
  397.   if ( !p2 ) return p1;
  398.   return (p1 > p2) ? p2 : p1;
  399. }
  400.  
  401.  
  402. char *rindex_sep(char *path)
  403. {
  404.   char *p1 = strrchr(path, '\\');
  405.   char *p2 = strrchr(path, '/');
  406.   if ( !p1 ) return p2;
  407.   if ( !p2 ) return p1;
  408.   return (p1 > p2) ? p1 : p2;
  409. }
  410. #endif
  411.