⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sfldir.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
📖 第 1 页 / 共 4 页
字号:
}


/*  ---------------------------------------------------------------------[<]-
    Function: sort_dir_list

    Synopsis: Sorts the directory list as specified.  Returns the number of
    items in the list.  To specify the sort order you pass a string holding
    one or more of these characters, which are then used in order:
    <TABLE>
    n      Sort by ascending name.
    N      Sort by descending name.
    x      Sort by ascending extension.
    X      Sort by descending extension.
    t      Sort by ascending time and date.
    T      Sort by descending time and date.
    s      Sort by ascending size.
    S      Sort by descending size.
    </TABLE>
    ---------------------------------------------------------------------[>]-*/

void
sort_dir_list (NODE *file_list, const char *sort)
{
    ASSERT (file_list);
    sort_key = (char *) sort;
    list_sort (file_list, compare_dir);
}


/*  ---------------------------------------------------------------------[<]-
    Function: add_dir_list

    Synopsis: Adds a node to the specified directory list.  Returns the
    address of the new node, or NULL if there was insufficient memory.
    ---------------------------------------------------------------------[>]-*/

FILEINFO *
add_dir_list (NODE *file_list, const DIRST *dir)
{
    FILEINFO
        *file_info;

    file_info = (FILEINFO *) node_create (file_list-> prev, sizeof (FILEINFO));
    if (file_info)
      {
        memcpy  (&file_info-> dir, dir, sizeof (DIRST));
        fix_dir (&file_info-> dir);
        file_info-> directory = (dir-> file_attrs & ATTR_SUBDIR) != 0;
      }
    return (file_info);
}


/*  -------------------------------------------------------------------------
 *  compare_dir -- internal
 *
 *  Compare two file info structures and return TRUE if SWAP is needed.
 *  Uses the global variable sort_key to determine sorting method.
 */

static Bool
compare_dir (LIST *p1, LIST *p2)
{
    Bool
        end  = FALSE,
        swap = FALSE;
    char
        *ext1,
        *ext2,
        *p;
    int
        comp;
    long
        date1,
        date2,
        time1,
        time2;

    ASSERT (p1);
    ASSERT (p2);

    if (((FILEINFO *) p1)-> directory != ((FILEINFO *) p2)-> directory)
        return (((FILEINFO *) p2)-> directory);

    for (p = sort_key;
            *p   != '\0'
         && end  == FALSE
         && swap == FALSE;
         p++)
      {
        switch (*p)
          {
            case 'n':
            case 'N':
                comp = lexcmp (((FILEINFO *) p1)-> dir.file_name,
                               ((FILEINFO *) p2)-> dir.file_name);
                if ((*p == 'n' && comp > 0)
                ||  (*p == 'N' && comp < 0))
                    swap = TRUE;
                else
                if (comp != 0)
                    end = TRUE;
                break;
            case 't':
            case 'T':
                /* Use date and time and not time_t for compare to minute,
                   not second                                                */
                date1 = timer_to_date (((FILEINFO *) p1)-> dir.file_time);
                date2 = timer_to_date (((FILEINFO *) p2)-> dir.file_time);
                if ((*p == 't' && date1 > date2)
                ||  (*p == 'T' && date1 < date2))
                    swap = TRUE;
                else
                if (date1 != date2)
                    end = TRUE;
                else
                  {
                    time1 = timer_to_time
                                (((FILEINFO *) p1)-> dir.file_time) / 10000;
                    time2 = timer_to_time
                                (((FILEINFO *) p2)-> dir.file_time) / 10000;
                    if ((*p == 't' && time1 > time2)
                    ||  (*p == 'T' && time1 < time2))
                        swap = TRUE;
                    else
                    if (time1 != time2)
                        end = TRUE;
                  }
                break;
            case 's':
            case 'S':
                if ((*p == 's' && ((FILEINFO *) p1)-> dir.file_size >
                                  ((FILEINFO *) p2)-> dir.file_size)
                ||  (*p == 'S' && ((FILEINFO *) p1)-> dir.file_size <
                                  ((FILEINFO *) p2)-> dir.file_size))
                    swap = TRUE;
                else
                if (((FILEINFO *) p1)-> dir.file_size
                !=  ((FILEINFO *) p2)-> dir.file_size)
                    end = TRUE;
                break;
            case 'x':
            case 'X':
                ext1 = strchr (((FILEINFO *) p1)-> dir.file_name, '.');
                ext2 = strchr (((FILEINFO *) p2)-> dir.file_name, '.');
                if (ext1 && ext2)
                  {
                    comp = lexcmp (ext1, ext2);
                    if ((*p == 'x' && comp > 0)
                    ||  (*p == 'X' && comp < 0))
                        swap = TRUE;
                    else
                    if (comp != 0)
                        end = TRUE;
                  }
                break;

          }
      }
    return (swap);
}


/*  ---------------------------------------------------------------------[<]-
    Function: resolve_path

    Synopsis: Accepts a path consisting of zero or more directory names and
    optionally a filename plus extension. Removes '.' and '..' if they occur
    in the path. '..' is resolved by also removing the preceding directory
    name, if any.  Returns a freshly-allocated string containing the
    resulting path.  The caller must free this string using mem_free() when
    finished with it.  The returned path may be empty.  Under OS/2 and DOS,
    treats '\' and '/' both as directory separators. A '..' directory at the
    start of the path resolves into nothing. If the input path started with
    '/', the returned path also does, else it does not.  For compatibility
    with DOS-based systems, '...' is treated as '../..', '....' as
    '../../..', and so on.
    ---------------------------------------------------------------------[>]-*/

char *
resolve_path (
    const char *old_path)
{
#if (defined (__UNIX__) || defined (MSDOS_FILESYSTEM) || defined (__VMS__))
    char
        *new_path,                      /*  Newly-allocated path             */
        *new_ptr,                       /*  Pointer into new_path            */
        last_char = '/';                /*  Start of path counts as delim    */
    int
        nbr_dots;                       /*  Size of '..', '...' specifier    */

    ASSERT (old_path);

    new_path = mem_strdup (old_path);
    new_ptr  = new_path;
    while (*old_path)
      {
        if (path_delimiter (last_char) && *old_path == '.')
          {
            /*  Handle one or more dots followed by a path delimiter         */
            nbr_dots = 0;               /*  Count number of dots             */
            while (old_path [nbr_dots] == '.')
                nbr_dots++;

            if (path_delimiter (old_path [nbr_dots]))
              {
                old_path += nbr_dots;   /*  Skip past dots                   */
                if (*old_path)
                    old_path++;         /*    and past / if any              */

                /*  Now backtrack in new path, dropping directories as       */
                /*  many times as needed (0 or more times)                   */
                while (nbr_dots > 1)
                  {
                    if (new_ptr > new_path + 1)
                      {
                        new_ptr--;      /*  Drop delimiter                   */
                        while (new_ptr > new_path)
                          {
                            if (path_delimiter (*(new_ptr - 1)))
                                break;  /*    and end after delimiter        */
                            new_ptr--;
                          }
                      }
                    else
                        break;          /*  At start of name - finish        */
                    nbr_dots--;
                  }
              }
            else
                /*  Handle '.something'                                      */
                last_char = *new_ptr++ = *old_path++;
          }
        else
            last_char = *new_ptr++ = *old_path++;
      }

    *new_ptr = '\0';                    /*  Terminate string nicely          */
    return (new_path);
#else

    return (mem_strdup (old_path));     /*  Path resolution not supported    */
#endif
}

static Bool
path_delimiter (char delim)
{
#if (defined (MSDOS_FILESYSTEM))
    if (delim == '\\' || delim == '/' || delim == '\0')
        return (TRUE);
    else
#elif (defined (__UNIX__) || defined (__VMS__))
    if (delim == '/' || delim == '\0')
        return (TRUE);
    else
#endif
        return (FALSE);
}


/*  ---------------------------------------------------------------------[<]-
    Function: locate_path

    Synopsis: Accepts a root directory and a path and locates the path with
    respect to the root.  If the path looks like an absolute directory,
    returns the path after cleaning it up.  Otherwise appends the path to
    the root, and returns the result.  In any case, the resulting directory
    does not need to exist.  Cleans-up the returned path by appending a '/'
    if necessary, and resolving any '..' subpaths.  The returned value is
    held in a freshly-allocated string which the caller must free using
    mem_free() when finished with..
    ---------------------------------------------------------------------[>]-*/

char *
locate_path (
    const char *root,
    const char *path)
{
#if (defined (__UNIX__) || defined (MSDOS_FILESYSTEM) || defined (__VMS__))
    char
        *new_path,                      /*  Returned path value              */
        *resolved;                      /*  and after .. resolution          */

    ASSERT (root);
    ASSERT (path);

#if (defined (MSDOS_FILESYSTEM))
    /*  Under MSDOS, OS/2, or Windows we have a full path if we have any of:
     *  /directory
     *  D:/directory
     *  the variations of those with backslashes.
     */
    if (path [0] == '\\'   || path [0] == '/'
    || (isalpha (path [0]) && path [1] == ':'
    && (path [2] == '\\'   || path [2] == '/')))

#else
    /*  Under UNIX or VMS we have a full path if the path starts with the
     *  directory marker.
     */
    if (path [0] == PATHEND)
#endif
        new_path = mem_strdup (path);   /*  Use path as supplied             */
    else
      {
        xstrcpy_debug ();
        if (path_delimiter (strlast (root)))
            new_path = xstrcpy (NULL, root, path, NULL);
        else
            new_path = xstrcpy (NULL, root, "/", path, NULL);
      }
    resolved = resolve_path (new_path);
    mem_free (new_path);
    /*  Append slash if necessary                                            */
    if (!path_delimiter (strlast (resolved)))
      {
        new_path = resolved;
        xstrcpy_debug ();
        resolved = xstrcpy (NULL, new_path, "/", NULL);
        mem_free (new_path);
      }
    return (resolved);
#else

    return (mem_strdup (path));         /*  Unknown system                   */
#endif
}


/*  ---------------------------------------------------------------------[<]-
    Function: clean_path

    Synopsis: Returns a clean directory name; i.e. resolves the path,
    removes a trailing slash unless the name consists just of '/'; on a
    MS-DOS file system, cleans-up a directory name consisting of a disk
    specifier.  The cleaned-up directory path is in a static area that is
    overwritten by each call.
    ---------------------------------------------------------------------[>]-*/

char *
clean_path (
    const char *path)
{
#if (defined (__UNIX__) || defined (MSDOS_FILESYSTEM) || defined (__VMS__))
    static char
        new_path [PATH_MAX + 1];        /*  Returned path value              */
    char
        *slash;

    strncpy (new_path, path, PATH_MAX);
    new_path [PATH_MAX] = '\0';
#   if (defined (MSDOS_FILESYSTEM))
    /*  For DOS filesystems, use only back slashes                           */
    strconvch (new_path, '/', '\\');
#   endif
    slash = strrchr (new_path, PATHEND);    /*  Find last slash              */

#   if (defined (MSDOS_FILESYSTEM))
    /*  If slash is last character in string, maybe squash it                */
    if (slash && slash [1] == '\0')
      {
        if (slash > new_path && slash [-1] != ':')
            *slash = '\0';
      }
    else                                /*  Turn X: into X:\                 */
    if (new_path [1] == ':' && new_path [2] == '\0')
      {
        new_path [2] = '\\';
        new_path [3] = '\0';
      }
#   else
    /*  If slash is last character in string, maybe squash it                */
    if (slash && slash [1] == '\0')
        if (slash > new_path)
            *slash = '\0';
#   endif
    return (new_path);
#else
    return ((char *) path);
#endif
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -