home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XFM / XFM-1.3 / XFM-1 / xfm-1.3 / xfm / FmOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-16  |  8.8 KB  |  406 lines

  1. /*---------------------------------------------------------------------------
  2.   Module FmOps
  3.  
  4.   (c) Simon Marlow 1990-92
  5.   (c) Albert Graef 1994
  6.  
  7.   Various file manipulation operations and other useful routines
  8. ---------------------------------------------------------------------------*/
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <fcntl.h>
  13. #include <errno.h>
  14. #include <unistd.h>
  15. #include <X11/Intrinsic.h>
  16.  
  17. #include "Fm.h"
  18.  
  19. /* split a string into substrings delimited by a given character */
  20.  
  21. char *split(char *s, char c)
  22. {
  23.   static char *t;
  24.   if (!s)
  25.     s = t;
  26.   t = s;
  27.   if (t)
  28.     while ((t = strchr(t, c)) && t>s && t[-1]=='\\') t++;
  29.   if (t)
  30.     *t++ = '\0';
  31.   return s;
  32. }
  33.  
  34. /*-------------------------------------------------------------------------*/
  35.  
  36. /* expand escapes in a string */
  37.  
  38. char *expand(char *s, char *t, char *c)
  39. {
  40.   char *s0 = s;
  41.   for (; *t; t++) {
  42.     if (strchr(c, *t))
  43.       *s++ = '\\';
  44.     *s++ = *t;
  45.   }
  46.   *s = '\0';
  47.   return s0;
  48. }
  49.  
  50. /*-------------------------------------------------------------------------*/
  51.  
  52. /* remove escapes from a string */
  53.  
  54. char *strparse(char *s, char *t, char *c)
  55. {
  56.   char *s0 = s;
  57.   for (; *t; t++)
  58.     if (*t != '\\')
  59.       *s++ = *t;
  60.     else if (*++t) {
  61.       if (!strchr(c, *t))
  62.     *s++ = '\\';
  63.       *s++ = *t;
  64.     } else
  65.       break;
  66.   *s = '\0';
  67.   return s0;
  68. }
  69.       
  70. /*-------------------------------------------------------------------------*/
  71.  
  72. /* expand filename */
  73.  
  74. char *fnexpand(char *fn)
  75. {
  76.   char s[MAXPATHLEN];
  77.   int l;
  78.  
  79.   if (!fn || !user.home)
  80.     return NULL;
  81.   else if (fn[0] != '~' || (fn[1] != '\0' && fn[1] != '/'))
  82.     return fn;
  83.  
  84.   l = strlen(user.home);
  85.  
  86.   if (l+strlen(fn)-1 >= MAXPATHLEN)
  87.     return NULL;
  88.  
  89.   strcpy(s, user.home);
  90.   strcpy(s+l, fn+1);
  91.   return(strcpy(fn, s));
  92. }
  93.  
  94. /*---------------------------------------------------------------------------*/
  95.  
  96. /* match a pattern with a filename, returning nonzero if the match was
  97.    correct */
  98.  
  99. /* Currently only *, ? and [...] (character classes) are recognized, no curly
  100.    braces. An escape mechanism for metacharacters is also missing. This could
  101.    be implemented more efficiently, but the present simple backtracking
  102.    routine does reasonably well for the usual kinds of patterns. -ag */
  103.  
  104. int fnmatch(char *pattern, char *fn)
  105. {
  106.   char *start;
  107.   
  108.   for (;; fn++, pattern++) {
  109.     
  110.     switch (*pattern) {
  111.       
  112.     case '?':
  113.       if (!*fn)
  114.     return 0;
  115.       break;
  116.       
  117.     case '*':
  118.       pattern++;
  119.       do
  120.     if (fnmatch(pattern,fn))
  121.       return 1;
  122.       while (*fn++);
  123.       return 0;
  124.       
  125.     case '[':
  126.       start = pattern+1;
  127.       do {
  128.       next:
  129.     pattern++;
  130.     if (*pattern == ']')
  131.       return 0;
  132.     else if (pattern[0] == '-' && pattern > start && pattern[1] != ']')
  133.       if (pattern[-1] <= *fn && *fn <= pattern[1])
  134.         break;
  135.       else {
  136.         start = (++pattern)+1;
  137.         goto next;
  138.       }
  139.       } while (*fn != *pattern);
  140.       while (*pattern != ']')
  141.     if (!*pattern++)
  142.       return 0;
  143.       break;
  144.       
  145.     default:
  146.       if (*fn != *pattern)
  147.     return 0;
  148.     }
  149.     
  150.     if (!*fn)
  151.       return 1;
  152.   };
  153. }
  154.  
  155. /*-------------------------------------------------------------------------*/
  156.  
  157. /* check whether one path is the prefix of another */
  158.  
  159. int prefix(char *s, char *t)
  160. {
  161.   int l = strlen(s);
  162.  
  163.   return !strncmp(s, t, l) && (s[l-1] == '/' || t[l] == '\0' || t[l] == '/');
  164. }
  165.  
  166. /*-------------------------------------------------------------------------*/
  167.  
  168. /* check whether a file exists */
  169.  
  170. int exists(char *path)
  171. {
  172.   struct stat stats;
  173.  
  174.   return (!lstat(path, &stats));
  175. }
  176.  
  177. /*-------------------------------------------------------------------------*/
  178.  
  179. /* find file on given search path */
  180.  
  181. char *searchPath(char *s1, char *p, char *s2)
  182. {
  183.   char           *s, *t;
  184.  
  185.   if (*s2 == '/' || !p)
  186.     return (strcpy(s1, s2));
  187.   for (s = p; *s; s = t) {
  188.     int l;
  189.     if (!(t = strchr(s, ':')))
  190.       t = strchr(s, 0);
  191.     if (s == t) goto next;
  192.     if (s[0] == '.')
  193.       if (t = s+1)
  194.     s = t;
  195.       else if (s[1] == '/')
  196.     s += 2;
  197.     l = t-s;
  198.     strncpy(s1, s, l);
  199.     if (l > 0 && s1[l - 1] != '/')
  200.       s1[l] = '/', l++;
  201.     strcpy(s1+l, s2);
  202.     if (exists(s1))
  203.       return s1;
  204.   next:
  205.     if (*t) t++;
  206.   }
  207.   return (strcpy(s1, s2));
  208. }
  209.  
  210. /* The following operations return zero on success and -1 on error, with errno
  211.    set appropriately */
  212.  
  213. /*-------------------------------------------------------------------------*/
  214.  
  215. /* create a new file */
  216.  
  217. int create(char *path, mode_t mode)
  218. {
  219.   int file = open(path, O_WRONLY|O_CREAT|O_EXCL, mode);
  220.  
  221.   if (file == -1 || close(file))
  222.     return -1;
  223.   else
  224.     return 0;
  225. }
  226.  
  227. /*-------------------------------------------------------------------------*/
  228.  
  229. /* recursive copy operation */
  230.  
  231. static int copyfile(char *oldpath, char *newpath);
  232. static int copydir(ino_t *inodes, int n_inodes, struct stat *oldstats,
  233.            char *oldpath, char *newpath);
  234. static int copy(ino_t *inodes, int n_inodes, char *oldpath, char *newpath);
  235.  
  236. int rcopy(char *oldpath, char *newpath)
  237. {
  238.   return copy((ino_t *)NULL, 0, oldpath, newpath);
  239. }
  240.  
  241. static int copyfile(char *oldpath, char *newpath)
  242. {
  243.   struct stat stats;
  244.   int src = -1, dest = -1, n, errno_ret;
  245.   char buf[BUFSIZ];
  246.  
  247.   if ((src = open(oldpath, O_RDONLY)) == -1 || stat(oldpath, &stats))
  248.     goto err;
  249.   else if ((dest = creat(newpath, stats.st_mode)) == -1)
  250.     goto err;
  251.  
  252.   while ( (n = read(src, buf, BUFSIZ)) != 0)
  253.     if ( n == -1 || write(dest, buf, n) != n )
  254.       goto err;
  255.  
  256.   if (close(src)) {
  257.     src = -1;
  258.     goto err;
  259.   } else
  260.     return close(dest);
  261.  
  262.  err:
  263.  
  264.   errno_ret = errno;
  265.   if (src != -1) close(src);
  266.   if (dest != -1) close(dest);
  267.   errno = errno_ret;
  268.   return -1;
  269. }
  270.  
  271. static int copydir(ino_t *inodes, int n_inodes, struct stat *oldstats,
  272.            char *oldpath, char *newpath)
  273. {
  274.   DIR *dir;
  275.   struct dirent *entry;
  276.   int i, ol = strlen(oldpath), nl = strlen(newpath);
  277.   struct stat newstats;
  278.  
  279.   for (i = n_inodes-1; i >= 0; i--)
  280.     if (inodes[i] == oldstats->st_ino) {
  281.       errno = EINVAL;
  282.       return -1;
  283.     }
  284.  
  285.   if (mkdir(newpath, user.umask & 0777) < 0 && errno != EEXIST ||
  286.       lstat(newpath, &newstats) ||
  287.       !(dir = opendir(oldpath)))
  288.     return -1;
  289.  
  290.   inodes = (ino_t *) XTREALLOC(inodes, (n_inodes+1)*sizeof(ino_t));
  291.   inodes[n_inodes++] = newstats.st_ino;
  292.  
  293.   for(i = 0; entry = readdir(dir); i++)
  294.     if (entry->d_name[0] != '.' || (entry->d_name[1] != '\0'
  295.                     && (entry->d_name[1] != '.' ||
  296.                     entry->d_name[2] != '\0'))) {
  297.       int ol1 = ol, nl1 = nl, l = strlen(entry->d_name);
  298.       char *oldpath1 = alloca(ol1+l+2), *newpath1 = alloca(nl1+l+2);
  299.  
  300.       strcpy(oldpath1, oldpath);
  301.       strcpy(newpath1, newpath);
  302.       if (oldpath1[ol1-1] != '/')
  303.     oldpath1[ol1++] = '/';
  304.       if (newpath1[nl1-1] != '/')
  305.     newpath1[nl1++] = '/';
  306.       strcpy(oldpath1+ol1, entry->d_name);
  307.       strcpy(newpath1+nl1, entry->d_name);
  308.       if (copy(inodes, n_inodes, oldpath1, newpath1)) {
  309.     /* take care of recursive errors */
  310.     char s[0xff];
  311.     sprintf(s, "Error copying %s:", oldpath1);
  312.     sysError(s);
  313.       }
  314.     }
  315.  
  316.   return closedir(dir);
  317. }
  318.  
  319. static int copy(ino_t *inodes, int n_inodes, char *oldpath, char *newpath)
  320. {
  321.   struct stat stats;
  322.  
  323.   if (lstat(oldpath, &stats))
  324.     return -1;
  325.  
  326.   /* Directory: copy recursively */
  327.   if (S_ISDIR(stats.st_mode))
  328.     return copydir(inodes, n_inodes, &stats, oldpath, newpath);
  329.  
  330.   /* Regular file: copy block by block */
  331.   else if (S_ISREG(stats.st_mode))
  332.     return copyfile(oldpath, newpath);
  333.  
  334.   /* Fifo: make a new one */
  335.   else if (S_ISFIFO(stats.st_mode))
  336.     return mkfifo(newpath, user.umask & 0666);
  337.  
  338.   /* Device: make a new one */
  339.   else if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode) ||
  340.          S_ISSOCK(stats.st_mode))
  341.     return mknod(newpath, user.umask & 0666, stats.st_rdev);
  342.  
  343.   /* Symbolic link: make a new one */
  344.   else if (S_ISLNK(stats.st_mode)) {
  345.     char lnk[MAXPATHLEN+1];
  346.     int l = readlink(oldpath, lnk, MAXPATHLEN);
  347.  
  348.     if (l<0)
  349.       return -1;
  350.     lnk[l] = '\0';
  351.     return(symlink(lnk, newpath));
  352.   }
  353.  
  354.   /* This shouldn't happen */
  355.   else {
  356.     error("Unrecognized file type:", oldpath);
  357.     return 0;
  358.   }
  359. }
  360.  
  361. /*-------------------------------------------------------------------------*/
  362.  
  363. /* recursive delete */
  364.  
  365. int rdel(char *path)
  366. {
  367.   struct stat stats;
  368.  
  369.   if (lstat(path, &stats))
  370.     return -1;
  371.  
  372.   if (S_ISDIR(stats.st_mode)) {
  373.     DIR *dir;
  374.     struct dirent *entry;
  375.     int i, pl = strlen(path);
  376.   
  377.     if (!(dir = opendir(path)))
  378.       return -1;
  379.  
  380.     for(i = 0; entry = readdir(dir); i++)
  381.       if (entry->d_name[0] != '.' || (entry->d_name[1] != '\0'
  382.                       && (entry->d_name[1] != '.' ||
  383.                       entry->d_name[2] != '\0'))) {
  384.     int pl1 = pl, l = strlen(entry->d_name);
  385.     char *path1 = alloca(pl1+l+2);
  386.  
  387.     strcpy(path1, path);
  388.     if (path1[pl1-1] != '/')
  389.       path1[pl1++] = '/';
  390.     strcpy(path1+pl1, entry->d_name);
  391.     if (rdel(path1)) {
  392.       /* take care of recursive errors */
  393.       char s[0xff];
  394.       sprintf(s, "Error deleting %s:", path);
  395.       sysError(s);
  396.     }
  397.     }
  398.  
  399.     if (closedir(dir))
  400.       return -1;
  401.     else
  402.       return rmdir(path);
  403.   } else
  404.     return unlink(path);
  405. }
  406.