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 / ignore.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  449 lines

  1. /*
  2.  * .cvsignore file support contributed by David G. Grubbs <dgg@odi.com>
  3.  */
  4.  
  5. #include "cvs.h"
  6.  
  7. /*
  8.  * Ignore file section.
  9.  * 
  10.  *    "!" may be included any time to reset the list (i.e. ignore nothing);
  11.  *    "*" may be specified to ignore everything.  It stays as the first
  12.  *        element forever, unless a "!" clears it out.
  13.  */
  14.  
  15. static char **ign_list;            /* List of files to ignore in update
  16.                      * and import */
  17. static char **s_ign_list = NULL;
  18. static int ign_count;            /* Number of active entries */
  19. static int s_ign_count = 0;
  20. static int ign_size;            /* This many slots available (plus
  21.                      * one for a NULL) */
  22. static int ign_hold = -1;        /* Index where first "temporary" item
  23.                      * is held */
  24.  
  25. const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
  26.  .nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
  27.  *.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
  28.  
  29. #define IGN_GROW 16            /* grow the list by 16 elements at a
  30.                      * time */
  31.  
  32. /* Nonzero if we have encountered an -I ! directive, which means one should
  33.    no longer ask the server about what is in CVSROOTADM_IGNORE.  */
  34. int ign_inhibit_server;
  35.  
  36. /*
  37.  * To the "ignore list", add the hard-coded default ignored wildcards above,
  38.  * the wildcards found in $CVSROOT/CVSROOT/cvsignore, the wildcards found in
  39.  * ~/.cvsignore and the wildcards found in the CVSIGNORE environment
  40.  * variable.
  41.  */
  42. void
  43. ign_setup ()
  44. {
  45.     struct passwd *pw;
  46.     char file[PATH_MAX];
  47.     char *tmp;
  48.  
  49.     ign_inhibit_server = 0;
  50.  
  51.     /* Start with default list and special case */
  52.     tmp = xstrdup (ign_default);
  53.     ign_add (tmp, 0);
  54.     free (tmp);
  55.  
  56. #ifdef CLIENT_SUPPORT
  57.     /* The client handles another way, by (after it does its own ignore file
  58.        processing, and only if !ign_inhibit_server), letting the server
  59.        know about the files and letting it decide whether to ignore
  60.        them based on CVSROOOTADM_IGNORE.  */
  61.     if (!client_active)
  62. #endif
  63.     {
  64.     /* Then add entries found in repository, if it exists */
  65.     (void) sprintf (file, "%s/%s/%s", CVSroot_directory,
  66.             CVSROOTADM, CVSROOTADM_IGNORE);
  67.     ign_add_file (file, 0);
  68.     }
  69.  
  70.     /* Then add entries found in home dir, (if user has one) and file exists */
  71.     if ((pw = (struct passwd *) getpwuid (getuid ())) && pw->pw_dir)
  72.     {
  73.     (void) sprintf (file, "%s/%s", pw->pw_dir, CVSDOTIGNORE);
  74.     ign_add_file (file, 0);
  75.     }
  76.  
  77.     /* Then add entries found in CVSIGNORE environment variable. */
  78.     ign_add (getenv (IGNORE_ENV), 0);
  79.  
  80.     /* Later, add ignore entries found in -I arguments */
  81. }
  82.  
  83. /*
  84.  * Open a file and read lines, feeding each line to a line parser. Arrange
  85.  * for keeping a temporary list of wildcards at the end, if the "hold"
  86.  * argument is set.
  87.  */
  88. void
  89. ign_add_file (file, hold)
  90.     char *file;
  91.     int hold;
  92. {
  93.     FILE *fp;
  94.     char line[1024];
  95.  
  96.     /* restore the saved list (if any) */
  97.     if (s_ign_list != NULL)
  98.     {
  99.     int i;
  100.  
  101.     for (i = 0; i < s_ign_count; i++)
  102.         ign_list[i] = s_ign_list[i];
  103.     ign_count = s_ign_count;
  104.     ign_list[ign_count] = NULL;
  105.  
  106.     s_ign_count = 0;
  107.     free (s_ign_list);
  108.     s_ign_list = NULL;
  109.     }
  110.  
  111.     /* is this a temporary ignore file? */
  112.     if (hold)
  113.     {
  114.     /* re-set if we had already done a temporary file */
  115.     if (ign_hold >= 0)
  116.     {
  117.         int i;
  118.  
  119.         for (i = ign_hold; i < ign_count; i++)
  120.         free (ign_list[i]);
  121.         ign_count = ign_hold;
  122.         ign_list[ign_count] = NULL;
  123.     }
  124.     else
  125.     {
  126.         ign_hold = ign_count;
  127.     }
  128.     }
  129.  
  130.     /* load the file */
  131.     fp = CVS_FOPEN (file, "r");
  132.     if (fp == NULL)
  133.     {
  134.     if (! existence_error (errno))
  135.         error (0, errno, "cannot open %s", file);
  136.     return;
  137.     }
  138.     while (fgets (line, sizeof (line), fp))
  139.     ign_add (line, hold);
  140.     if (fclose (fp) < 0)
  141.     error (0, errno, "cannot close %s", file);
  142. }
  143.  
  144. /* Parse a line of space-separated wildcards and add them to the list. */
  145. void
  146. ign_add (ign, hold)
  147.     char *ign;
  148.     int hold;
  149. {
  150.     if (!ign || !*ign)
  151.     return;
  152.  
  153.     for (; *ign; ign++)
  154.     {
  155.     char *mark;
  156.     char save;
  157.  
  158.     /* ignore whitespace before the token */
  159.     if (isspace (*ign))
  160.         continue;
  161.  
  162.     /*
  163.      * if we find a single character !, we must re-set the ignore list
  164.      * (saving it if necessary).  We also catch * as a special case in a
  165.      * global ignore file as an optimization
  166.      */
  167.     if ((!*(ign+1) || isspace (*(ign+1))) && (*ign == '!' || *ign == '*'))
  168.     {
  169.         if (!hold)
  170.         {
  171.         /* permanently reset the ignore list */
  172.         int i;
  173.  
  174.         for (i = 0; i < ign_count; i++)
  175.             free (ign_list[i]);
  176.         ign_count = 0;
  177.         ign_list[0] = NULL;
  178.  
  179.         /* if we are doing a '!', continue; otherwise add the '*' */
  180.         if (*ign == '!')
  181.         {
  182.             ign_inhibit_server = 1;
  183.             continue;
  184.         }
  185.         }
  186.         else if (*ign == '!')
  187.         {
  188.         /* temporarily reset the ignore list */
  189.         int i;
  190.  
  191.         if (ign_hold >= 0)
  192.         {
  193.             for (i = ign_hold; i < ign_count; i++)
  194.             free (ign_list[i]);
  195.             ign_hold = -1;
  196.         }
  197.         s_ign_list = (char **) xmalloc (ign_count * sizeof (char *));
  198.         for (i = 0; i < ign_count; i++)
  199.             s_ign_list[i] = ign_list[i];
  200.         s_ign_count = ign_count;
  201.         ign_count = 0;
  202.         ign_list[0] = NULL;
  203.         continue;
  204.         }
  205.     }
  206.  
  207.     /* If we have used up all the space, add some more */
  208.     if (ign_count >= ign_size)
  209.     {
  210.         ign_size += IGN_GROW;
  211.         ign_list = (char **) xrealloc ((char *) ign_list,
  212.                        (ign_size + 1) * sizeof (char *));
  213.     }
  214.  
  215.     /* find the end of this token */
  216.     for (mark = ign; *mark && !isspace (*mark); mark++)
  217.          /* do nothing */ ;
  218.  
  219.     save = *mark;
  220.     *mark = '\0';
  221.  
  222.     ign_list[ign_count++] = xstrdup (ign);
  223.     ign_list[ign_count] = NULL;
  224.  
  225.     *mark = save;
  226.     if (save)
  227.         ign = mark;
  228.     else
  229.         ign = mark - 1;
  230.     }
  231. }
  232.  
  233. /* Set to 1 if ignore file patterns should be matched in a case-insensitive
  234.    fashion.  */
  235. int ign_case;
  236.  
  237. /* Return 1 if the given filename should be ignored by update or import. */
  238. int
  239. ign_name (name)
  240.     char *name;
  241. {
  242.     char **cpp = ign_list;
  243.  
  244.     if (cpp == NULL)
  245.     return (0);
  246.  
  247.     if (ign_case)
  248.     {
  249.     /* We do a case-insensitive match by calling fnmatch on copies of
  250.        the pattern and the name which have been converted to
  251.        lowercase.  */
  252.     char *name_lower;
  253.     char *pat_lower;
  254.     char *p;
  255.  
  256.     name_lower = xstrdup (name);
  257.     for (p = name_lower; *p != '\0'; ++p)
  258.         *p = tolower (*p);
  259.     while (*cpp)
  260.     {
  261.         pat_lower = xstrdup (*cpp++);
  262.         for (p = pat_lower; *p != '\0'; ++p)
  263.         *p = tolower (*p);
  264.         if (fnmatch (pat_lower, name_lower, 0) == 0)
  265.         goto matched;
  266.         free (pat_lower);
  267.     }
  268.     free (name_lower);
  269.     return 0;
  270.       matched:
  271.     free (name_lower);
  272.     free (pat_lower);
  273.     return 1;
  274.     }
  275.     else
  276.     {
  277.     while (*cpp)
  278.         if (fnmatch (*cpp++, name, 0) == 0)
  279.         return 1;
  280.     return 0;
  281.     }
  282. }
  283.  
  284. /* FIXME: This list of dirs to ignore stuff seems not to be used.  */
  285.  
  286. static char **dir_ign_list = NULL;
  287. static int dir_ign_max = 0;
  288. static int dir_ign_current = 0;
  289.  
  290. /* add a directory to list of dirs to ignore */
  291. void ign_dir_add (name)
  292.      char *name;
  293. {
  294.   /* make sure we've got the space for the entry */
  295.   if (dir_ign_current <= dir_ign_max)
  296.     {
  297.       dir_ign_max += IGN_GROW;
  298.       dir_ign_list = (char **) xrealloc ((char *) dir_ign_list, (dir_ign_max+1) * sizeof(char*));
  299.     }
  300.  
  301.   dir_ign_list[dir_ign_current] = name;
  302.  
  303.   dir_ign_current += 1 ;
  304. }
  305.  
  306.  
  307. /* this function returns 1 (true) if the given directory name is part of
  308.  * the list of directories to ignore
  309.  */
  310.  
  311. int ignore_directory (name)
  312.      char *name;
  313. {
  314.   int i;
  315.  
  316.   if (!dir_ign_list)
  317.     return 0;
  318.  
  319.   i = dir_ign_current;
  320.   while (i--)
  321.     {
  322.       if (strncmp(name, dir_ign_list[i], strlen(dir_ign_list[i])) == 0)
  323.     return 1;
  324.     }
  325.  
  326.   return 0;
  327. }
  328.  
  329. /*
  330.  * Process the current directory, looking for files not in ILIST and
  331.  * not on the global ignore list for this directory.  If we find one,
  332.  * call PROC passing it the name of the file and the update dir.
  333.  * ENTRIES is the entries list, which is used to identify known
  334.  * directories.  ENTRIES may be NULL, in which case we assume that any
  335.  * directory with a CVS administration directory is known.
  336.  */
  337. void
  338. ignore_files (ilist, entries, update_dir, proc)
  339.     List *ilist;
  340.     List *entries;
  341.     char *update_dir;
  342.     Ignore_proc proc;
  343. {
  344.     int subdirs;
  345.     DIR *dirp;
  346.     struct dirent *dp;
  347.     struct stat sb;
  348.     char *file;
  349.     char *xdir;
  350.  
  351.     /* Set SUBDIRS if we have subdirectory information in ENTRIES.  */
  352.     if (entries == NULL)
  353.     subdirs = 0;
  354.     else
  355.     {
  356.     struct stickydirtag *sdtp;
  357.  
  358.     sdtp = (struct stickydirtag *) entries->list->data;
  359.     subdirs = sdtp == NULL || sdtp->subdirs;
  360.     }
  361.  
  362.     /* we get called with update_dir set to "." sometimes... strip it */
  363.     if (strcmp (update_dir, ".") == 0)
  364.     xdir = "";
  365.     else
  366.     xdir = update_dir;
  367.  
  368.     dirp = CVS_OPENDIR (".");
  369.     if (dirp == NULL)
  370.     return;
  371.  
  372.     ign_add_file (CVSDOTIGNORE, 1);
  373.     wrap_add_file (CVSDOTWRAPPER, 1);
  374.  
  375.     while ((dp = readdir (dirp)) != NULL)
  376.     {
  377.     file = dp->d_name;
  378.     if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0)
  379.         continue;
  380.     if (findnode_fn (ilist, file) != NULL)
  381.         continue;
  382.     if (subdirs)
  383.     {
  384.         Node *node;
  385.  
  386.         node = findnode_fn (entries, file);
  387.         if (node != NULL
  388.         && ((Entnode *) node->data)->type == ENT_SUBDIR)
  389.         {
  390.         char *p;
  391.         int dir;
  392.  
  393.         /* For consistency with past behaviour, we only ignore
  394.            this directory if there is a CVS subdirectory.
  395.            This will normally be the case, but the user may
  396.            have messed up the working directory somehow.  */
  397.         p = xmalloc (strlen (file) + sizeof CVSADM + 10);
  398.         sprintf (p, "%s/%s", file, CVSADM);
  399.         dir = isdir (p);
  400.         free (p);
  401.         if (dir)
  402.             continue;
  403.         }
  404.     }
  405.  
  406.     /* We could be ignoring FIFOs and other files which are neither
  407.        regular files nor directories here.  */
  408.     if (ign_name (file))
  409.         continue;
  410.  
  411.     if (
  412. #ifdef DT_DIR
  413.         dp->d_type != DT_UNKNOWN ||
  414. #endif
  415.         lstat(file, &sb) != -1) 
  416.     {
  417.  
  418.         if (
  419. #ifdef DT_DIR
  420.         dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN &&
  421. #endif
  422.         S_ISDIR(sb.st_mode))
  423.         {
  424.         if (! subdirs)
  425.         {
  426.             char temp[PATH_MAX];
  427.  
  428.             (void) sprintf (temp, "%s/%s", file, CVSADM);
  429.             if (isdir (temp))
  430.             continue;
  431.         }
  432.         }
  433. #ifdef S_ISLNK
  434.         else if (
  435. #ifdef DT_DIR
  436.         dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN && 
  437. #endif
  438.         S_ISLNK(sb.st_mode))
  439.         {
  440.         continue;
  441.         }
  442. #endif
  443.         }
  444.  
  445.     (*proc) (file, xdir);
  446.     }
  447.     (void) closedir (dirp);
  448. }
  449.