Example #1
0
/*
 * maintains the list of already visited files and dirs
 * returns FAIL if the given file/dir is already in the list
 * returns OK if it is newly added
 */
static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path)
{
  ff_visited_T        *vp;
  bool url = false;

  FileInfo file_info;
  // For a URL we only compare the name, otherwise we compare the
  // device/inode.
  if (path_with_url(fname)) {
    STRLCPY(ff_expand_buffer, fname, MAXPATHL);
    url = true;
  } else {
    ff_expand_buffer[0] = NUL;
    if (!os_get_file_info((char *)fname, &file_info)) {
      return FAIL;
    }
  }

  /* check against list of already visited files */
  for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
    if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0)
        || (!url && vp->ffv_dev_valid
            && vp->ffv_dev == file_info.stat.st_dev
            && vp->ffv_ino == file_info.stat.st_ino)) {
      /* are the wildcard parts equal */
      if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
        /* already visited */
        return FAIL;
    }
  }

  /*
   * New file/dir.  Add it to the list of visited files/dirs.
   */
  vp = xmalloc(sizeof(ff_visited_T) + STRLEN(ff_expand_buffer));

  if (!url) {
    vp->ffv_dev_valid = TRUE;
    vp->ffv_ino = file_info.stat.st_ino;
    vp->ffv_dev = file_info.stat.st_dev;
    vp->ffv_fname[0] = NUL;
  } else {
    vp->ffv_dev_valid = FALSE;
    STRCPY(vp->ffv_fname, ff_expand_buffer);
  }

  if (wc_path != NULL)
    vp->ffv_wc_path = vim_strsave(wc_path);
  else
    vp->ffv_wc_path = NULL;

  vp->ffv_next = *visited_list;
  *visited_list = vp;

  return OK;
}
Example #2
0
/*
 * maintains the list of already visited files and dirs
 * returns FAIL if the given file/dir is already in the list
 * returns OK if it is newly added
 */
static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path)
{
  ff_visited_T        *vp;
  bool url = false;

  FileID file_id;
  // For an URL we only compare the name, otherwise we compare the
  // device/inode.
  if (path_with_url((char *)fname)) {
    STRLCPY(ff_expand_buffer, fname, MAXPATHL);
    url = true;
  } else {
    ff_expand_buffer[0] = NUL;
    if (!os_fileid((char *)fname, &file_id)) {
      return FAIL;
    }
  }

  /* check against list of already visited files */
  for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
    if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0)
        || (!url && vp->file_id_valid
            && os_fileid_equal(&(vp->file_id), &file_id))) {
      // are the wildcard parts equal
      if (ff_wc_equal(vp->ffv_wc_path, wc_path)) {
        // already visited
        return FAIL;
      }
    }
  }

  /*
   * New file/dir.  Add it to the list of visited files/dirs.
   */
  vp = xmalloc(sizeof(ff_visited_T) + STRLEN(ff_expand_buffer));

  if (!url) {
    vp->file_id_valid = true;
    vp->file_id = file_id;
    vp->ffv_fname[0] = NUL;
  } else {
    vp->file_id_valid = false;
    STRCPY(vp->ffv_fname, ff_expand_buffer);
  }

  if (wc_path != NULL)
    vp->ffv_wc_path = vim_strsave(wc_path);
  else
    vp->ffv_wc_path = NULL;

  vp->ffv_next = *visited_list;
  *visited_list = vp;

  return OK;
}
Example #3
0
/*
 * Find a file in a search context.
 * The search context was created with vim_findfile_init() above.
 * Return a pointer to an allocated file name or NULL if nothing found.
 * To get all matching files call this function until you get NULL.
 *
 * If the passed search_context is NULL, NULL is returned.
 *
 * The search algorithm is depth first. To change this replace the
 * stack with a list (don't forget to leave partly searched directories on the
 * top of the list).
 */
char_u *vim_findfile(void *search_ctx_arg)
{
  char_u      *file_path;
  char_u      *rest_of_wildcards;
  char_u      *path_end = NULL;
  ff_stack_T  *stackp;
  int len;
  int i;
  char_u      *p;
  char_u      *suf;
  ff_search_ctx_T *search_ctx;

  if (search_ctx_arg == NULL)
    return NULL;

  search_ctx = (ff_search_ctx_T *)search_ctx_arg;

  /*
   * filepath is used as buffer for various actions and as the storage to
   * return a found filename.
   */
  file_path = xmalloc(MAXPATHL);

  /* store the end of the start dir -- needed for upward search */
  if (search_ctx->ffsc_start_dir != NULL)
    path_end = &search_ctx->ffsc_start_dir[
      STRLEN(search_ctx->ffsc_start_dir)];

  /* upward search loop */
  for (;; ) {
    /* downward search loop */
    for (;; ) {
      /* check if user user wants to stop the search*/
      ui_breakcheck();
      if (got_int)
        break;

      /* get directory to work on from stack */
      stackp = ff_pop(search_ctx);
      if (stackp == NULL)
        break;

      /*
       * TODO: decide if we leave this test in
       *
       * GOOD: don't search a directory(-tree) twice.
       * BAD:  - check linked list for every new directory entered.
       *       - check for double files also done below
       *
       * Here we check if we already searched this directory.
       * We already searched a directory if:
       * 1) The directory is the same.
       * 2) We would use the same wildcard string.
       *
       * Good if you have links on same directory via several ways
       *  or you have selfreferences in directories (e.g. SuSE Linux 6.3:
       *  /etc/rc.d/init.d is linked to /etc/rc.d -> endless loop)
       *
       * This check is only needed for directories we work on for the
       * first time (hence stackp->ff_filearray == NULL)
       */
      if (stackp->ffs_filearray == NULL
          && ff_check_visited(&search_ctx->ffsc_dir_visited_list
              ->ffvl_visited_list,
              stackp->ffs_fix_path
              , stackp->ffs_wc_path
              ) == FAIL) {
#ifdef FF_VERBOSE
        if (p_verbose >= 5) {
          verbose_enter_scroll();
          smsg((char_u *)"Already Searched: %s (%s)",
              stackp->ffs_fix_path, stackp->ffs_wc_path);
          /* don't overwrite this either */
          msg_puts((char_u *)"\n");
          verbose_leave_scroll();
        }
#endif
        ff_free_stack_element(stackp);
        continue;
      }
#ifdef FF_VERBOSE
      else if (p_verbose >= 5) {
        verbose_enter_scroll();
        smsg((char_u *)"Searching: %s (%s)",
            stackp->ffs_fix_path, stackp->ffs_wc_path);
        /* don't overwrite this either */
        msg_puts((char_u *)"\n");
        verbose_leave_scroll();
      }
#endif

      /* check depth */
      if (stackp->ffs_level <= 0) {
        ff_free_stack_element(stackp);
        continue;
      }

      file_path[0] = NUL;

      /*
       * If no filearray till now expand wildcards
       * The function expand_wildcards() can handle an array of paths
       * and all possible expands are returned in one array. We use this
       * to handle the expansion of '**' into an empty string.
       */
      if (stackp->ffs_filearray == NULL) {
        char_u *dirptrs[2];

        /* we use filepath to build the path expand_wildcards() should
         * expand.
         */
        dirptrs[0] = file_path;
        dirptrs[1] = NULL;

        /* if we have a start dir copy it in */
        if (!vim_isAbsName(stackp->ffs_fix_path)
            && search_ctx->ffsc_start_dir) {
          STRCPY(file_path, search_ctx->ffsc_start_dir);
          add_pathsep(file_path);
        }

        /* append the fix part of the search path */
        STRCAT(file_path, stackp->ffs_fix_path);
        add_pathsep(file_path);

        rest_of_wildcards = stackp->ffs_wc_path;
        if (*rest_of_wildcards != NUL) {
          len = (int)STRLEN(file_path);
          if (STRNCMP(rest_of_wildcards, "**", 2) == 0) {
            /* pointer to the restrict byte
             * The restrict byte is not a character!
             */
            p = rest_of_wildcards + 2;

            if (*p > 0) {
              (*p)--;
              file_path[len++] = '*';
            }

            if (*p == 0) {
              /* remove '**<numb> from wildcards */
              STRMOVE(rest_of_wildcards, rest_of_wildcards + 3);
            } else
              rest_of_wildcards += 3;

            if (stackp->ffs_star_star_empty == 0) {
              /* if not done before, expand '**' to empty */
              stackp->ffs_star_star_empty = 1;
              dirptrs[1] = stackp->ffs_fix_path;
            }
          }

          /*
           * Here we copy until the next path separator or the end of
           * the path. If we stop at a path separator, there is
           * still something else left. This is handled below by
           * pushing every directory returned from expand_wildcards()
           * on the stack again for further search.
           */
          while (*rest_of_wildcards
                 && !vim_ispathsep(*rest_of_wildcards))
            file_path[len++] = *rest_of_wildcards++;

          file_path[len] = NUL;
          if (vim_ispathsep(*rest_of_wildcards))
            rest_of_wildcards++;
        }

        /*
         * Expand wildcards like "*" and "$VAR".
         * If the path is a URL don't try this.
         */
        if (path_with_url(dirptrs[0])) {
          stackp->ffs_filearray = (char_u **)xmalloc(sizeof(char *));
          stackp->ffs_filearray[0] = vim_strsave(dirptrs[0]);
          stackp->ffs_filearray_size = 1;
        } else
          /* Add EW_NOTWILD because the expanded path may contain
           * wildcard characters that are to be taken literally.
           * This is a bit of a hack. */
          expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs,
              &stackp->ffs_filearray_size,
              &stackp->ffs_filearray,
              EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD);

        stackp->ffs_filearray_cur = 0;
        stackp->ffs_stage = 0;
      } else
        rest_of_wildcards = &stackp->ffs_wc_path[
          STRLEN(stackp->ffs_wc_path)];

      if (stackp->ffs_stage == 0) {
        /* this is the first time we work on this directory */
        if (*rest_of_wildcards == NUL) {
          /*
           * We don't have further wildcards to expand, so we have to
           * check for the final file now.
           */
          for (i = stackp->ffs_filearray_cur;
               i < stackp->ffs_filearray_size; ++i) {
            if (!path_with_url(stackp->ffs_filearray[i])
                && !os_isdir(stackp->ffs_filearray[i]))
              continue;                 /* not a directory */

            /* prepare the filename to be checked for existence
             * below */
            STRCPY(file_path, stackp->ffs_filearray[i]);
            add_pathsep(file_path);
            STRCAT(file_path, search_ctx->ffsc_file_to_search);

            /*
             * Try without extra suffix and then with suffixes
             * from 'suffixesadd'.
             */
            len = (int)STRLEN(file_path);
            if (search_ctx->ffsc_tagfile)
              suf = (char_u *)"";
            else
              suf = curbuf->b_p_sua;
            for (;; ) {
              /* if file exists and we didn't already find it */
              if ((path_with_url(file_path)
                   || (os_file_exists(file_path)
                       && (search_ctx->ffsc_find_what
                           == FINDFILE_BOTH
                           || ((search_ctx->ffsc_find_what
                                == FINDFILE_DIR)
                               == os_isdir(file_path)))))
#ifndef FF_VERBOSE
                  && (ff_check_visited(
                          &search_ctx->ffsc_visited_list->ffvl_visited_list,
                          file_path
                          , (char_u *)""
                          ) == OK)
#endif
                  ) {
#ifdef FF_VERBOSE
                if (ff_check_visited(
                        &search_ctx->ffsc_visited_list->ffvl_visited_list,
                        file_path
                        , (char_u *)""
                        ) == FAIL) {
                  if (p_verbose >= 5) {
                    verbose_enter_scroll();
                    smsg((char_u *)"Already: %s",
                        file_path);
                    /* don't overwrite this either */
                    msg_puts((char_u *)"\n");
                    verbose_leave_scroll();
                  }
                  continue;
                }
#endif

                /* push dir to examine rest of subdirs later */
                stackp->ffs_filearray_cur = i + 1;
                ff_push(search_ctx, stackp);

                if (!path_with_url(file_path))
                  simplify_filename(file_path);
                if (os_dirname(ff_expand_buffer, MAXPATHL)
                    == OK) {
                  p = path_shorten_fname(file_path,
                      ff_expand_buffer);
                  if (p != NULL)
                    STRMOVE(file_path, p);
                }
#ifdef FF_VERBOSE
                if (p_verbose >= 5) {
                  verbose_enter_scroll();
                  smsg((char_u *)"HIT: %s", file_path);
                  /* don't overwrite this either */
                  msg_puts((char_u *)"\n");
                  verbose_leave_scroll();
                }
#endif
                return file_path;
              }

              /* Not found or found already, try next suffix. */
              if (*suf == NUL)
                break;
              copy_option_part(&suf, file_path + len,
                  MAXPATHL - len, ",");
            }
          }
        } else {
          /*
           * still wildcards left, push the directories for further
           * search
           */
          for (i = stackp->ffs_filearray_cur;
               i < stackp->ffs_filearray_size; ++i) {
            if (!os_isdir(stackp->ffs_filearray[i]))
              continue;                 /* not a directory */

            ff_push(search_ctx,
                ff_create_stack_element(
                    stackp->ffs_filearray[i],
                    rest_of_wildcards,
                    stackp->ffs_level - 1, 0));
          }
        }
        stackp->ffs_filearray_cur = 0;
        stackp->ffs_stage = 1;
      }

      /*
       * if wildcards contains '**' we have to descent till we reach the
       * leaves of the directory tree.
       */
      if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0) {
        for (i = stackp->ffs_filearray_cur;
             i < stackp->ffs_filearray_size; ++i) {
          if (fnamecmp(stackp->ffs_filearray[i],
                  stackp->ffs_fix_path) == 0)
            continue;             /* don't repush same directory */
          if (!os_isdir(stackp->ffs_filearray[i]))
            continue;               /* not a directory */
          ff_push(search_ctx,
              ff_create_stack_element(stackp->ffs_filearray[i],
                  stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
        }
      }

      /* we are done with the current directory */
      ff_free_stack_element(stackp);

    }

    /* If we reached this, we didn't find anything downwards.
     * Let's check if we should do an upward search.
     */
    if (search_ctx->ffsc_start_dir
        && search_ctx->ffsc_stopdirs_v != NULL && !got_int) {
      ff_stack_T  *sptr;

      /* is the last starting directory in the stop list? */
      if (ff_path_in_stoplist(search_ctx->ffsc_start_dir,
              (int)(path_end - search_ctx->ffsc_start_dir),
              search_ctx->ffsc_stopdirs_v) == TRUE)
        break;

      /* cut of last dir */
      while (path_end > search_ctx->ffsc_start_dir
             && vim_ispathsep(*path_end))
        path_end--;
      while (path_end > search_ctx->ffsc_start_dir
             && !vim_ispathsep(path_end[-1]))
        path_end--;
      *path_end = 0;
      path_end--;

      if (*search_ctx->ffsc_start_dir == 0)
        break;

      STRCPY(file_path, search_ctx->ffsc_start_dir);
      add_pathsep(file_path);
      STRCAT(file_path, search_ctx->ffsc_fix_path);

      /* create a new stack entry */
      sptr = ff_create_stack_element(file_path,
          search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
      ff_push(search_ctx, sptr);
    } else
      break;
  }

  free(file_path);
  return NULL;
}
Example #4
0
/*
 * maintains the list of already visited files and dirs
 * returns FAIL if the given file/dir is already in the list
 * returns OK if it is newly added
 *
 * TODO: What to do on memory allocation problems?
 *	 -> return TRUE - Better the file is found several times instead of
 *	    never.
 */
static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path)
{
  ff_visited_T        *vp;
#ifdef UNIX
  struct stat st;
  int url = FALSE;
#endif

  /* For an URL we only compare the name, otherwise we compare the
   * device/inode (unix) or the full path name (not Unix). */
  if (path_with_url(fname)) {
    vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
#ifdef UNIX
    url = TRUE;
#endif
  } else   {
    ff_expand_buffer[0] = NUL;
#ifdef UNIX
    if (mch_stat((char *)fname, &st) < 0)
#else
    if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
#endif
      return FAIL;
  }

  /* check against list of already visited files */
  for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
    if (
#ifdef UNIX
      !url ? (vp->ffv_dev_valid && vp->ffv_dev == st.st_dev
              && vp->ffv_ino == st.st_ino)
      :
#endif
      fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
      ) {
      /* are the wildcard parts equal */
      if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
        /* already visited */
        return FAIL;
    }
  }

  /*
   * New file/dir.  Add it to the list of visited files/dirs.
   */
  vp = (ff_visited_T *)alloc((unsigned)(sizeof(ff_visited_T)
                                        + STRLEN(ff_expand_buffer)));

  if (vp != NULL) {
#ifdef UNIX
    if (!url) {
      vp->ffv_dev_valid = TRUE;
      vp->ffv_ino = st.st_ino;
      vp->ffv_dev = st.st_dev;
      vp->ffv_fname[0] = NUL;
    } else   {
      vp->ffv_dev_valid = FALSE;
#endif
    STRCPY(vp->ffv_fname, ff_expand_buffer);
#ifdef UNIX
  }
#endif
    if (wc_path != NULL)
      vp->ffv_wc_path = vim_strsave(wc_path);
    else
      vp->ffv_wc_path = NULL;

    vp->ffv_next = *visited_list;
    *visited_list = vp;
  }

  return OK;
}