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

📄 sfldir.c

📁 短小精悍的C语言标准函数库。提供450个以上的可移植的算法和工具代码。
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  ----------------------------------------------------------------<Prolog>-
    Name:       sfldir.c
    Title:      Directory access functions
    Package:    Standard Function Library (SFL)

    Written:    1996/04/02  iMatix SFL project team <sfl@imatix.com>
    Revised:    2000/01/19

    Copyright:  Copyright (c) 1996-2000 iMatix Corporation
    License:    This is free software; you can redistribute it and/or modify
                it under the terms of the SFL License Agreement as provided
                in the file LICENSE.TXT.  This software is distributed in
                the hope that it will be useful, but without any warranty.
 ------------------------------------------------------------------</Prolog>-*/

#include "prelude.h"                    /*  Universal header file            */
#include "sfldate.h"                    /*  Date handling functions          */
#include "sfluid.h"                     /*  Uid/gid functions                */
#include "sflstr.h"                     /*  String functions                 */
#include "sfllist.h"                    /*  Linked-list functions            */
#include "sflmem.h"                     /*  Memory allocation functions      */
#include "sflnode.h"                    /*  Linked-list functions            */
#include "sflfile.h"                    /*  File-access functions            */
#include "sflcons.h"                    /*  Console display functions        */
#include "sflprint.h"                   /*  snprintf functions               */
#include "sfldir.h"                     /*  Prototypes for functions         */

/*  Static variables used globally in this source file only                  */

static char
    *sort_key;

/*  Function prototypes                                                      */

static Bool   populate_entry     (DIRST *dir);
static time_t get_six_months_ago (void);
static char  *format_mode        (DIRST *dir);
static char  *format_name        (DIRST *dir, Bool full);
static char  *format_time        (DIRST *dir);
static Bool  compare_dir         (LIST *p1, LIST *p2);
static Bool  path_delimiter      (char delim);


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

    Synopsis:
    Creates a directory stream and returns the first entry in the directory.
    The order of entries is arbitrary, and it is undefined whether you will
    get entries like '.' and '..' or not.  Returns TRUE if something was
    found, else FALSE.  If TRUE, fills-in the values in the directory stream
    block.  Use the same directory stream block for the read_dir and
    close_dir() functions.

    You must supply a DIRST block when calling open_dir().  If you do not
    supply a dir_name (i.e. it is NULL or ""), open_dir() assumes you want
    to read from the current working directory.  You must call close_dir()
    after an open_dir(), even if it fails.

    The strings in DIRST all point to static areas that may change after a
    further call to read_dir.  If you need persistent data (i.e. because
    you want to collect a set of DIRSTs and then sort them, call fix_dir()
    after each call to open_dir and read_dir.  You should then call
    free_dir() to release each DIRST when you are finished.
    ---------------------------------------------------------------------[>]-*/

Bool
open_dir (
    DIRST *dir,
    const char *dir_name)
{
    char
        *dir_spec,                      /*  Directory to search through      */
        *dir_spec_end;                  /*  Points to NULL in dir_spec       */

    ASSERT (dir != NULL);
    memset (dir, 0, sizeof (DIRST));

    /*  Copy and prepare the directory specification                         */
    dir_spec = mem_alloc (NAME_MAX);
    if (dir_name == NULL || *dir_name == 0)
        strcpy (dir_spec, DEFAULT_DIR);
    else
        strcpy (dir_spec, dir_name);

#if (defined (MSDOS_FILESYSTEM))
    strconvch (dir_spec, '/', '\\');
#endif
    /*  Remove a trailing slash from the directory name                      */
    dir_spec_end = dir_spec + strlen (dir_spec);
    if (dir_spec_end [-1] == PATHEND)
      {
        dir_spec_end [-1] = '\0';
        dir_spec_end--;
      }

    /*  Open directory stream or find first directory entry                  */
#if (defined (__UNIX__) || defined (__VMS_XOPEN) || defined (__OS2__))
    if (strnull (dir_spec))
        strcpy (dir_spec, "/");
#   if (defined (__OS2__))
    if (dir_spec_end [-1] == ':')                /*  Special case d: to d:\  */
        strcat (dir_spec, "\\");
#  endif         
    if ((dir-> _dir_handle = opendir (dir_spec)) == NULL)

#elif (defined (WIN32))
    strcat (dir_spec, "\\*");
    if ((dir-> _dir_handle = FindFirstFile (dir_spec, &dir-> _dir_entry))
                           == INVALID_HANDLE_VALUE)

#elif (defined (_MSC_VER))
    strcat (dir_spec, "\\*.*");
    if ((dir-> _dir_handle = _dos_findfirst (dir_spec, _A_NORMAL | _A_SUBDIR,
                                             &dir-> _dir_entry)) != 0)

#elif (defined (__TURBOC__) || defined (__DJGPP__))
    strcat (dir_spec, "\\*.*");
    if (findfirst (dir_spec, &dir-> _dir_entry, 255 - FA_LABEL) == -1)
#endif
      {
        mem_free (dir_spec);
        return (FALSE);                 /*  Could not open directory         */
      }

    /*  Save the directory name in directory stream structure                */
#if (defined (__MSDOS__) || defined (__OS2__))
    *dir_spec_end = '\0';               /*  Kill the \*.* again              */
#endif
    dir-> dir_name = dir_spec;          /*  Now owned by DIRST structure     */

#if (defined (__UNIX__) || defined (__VMS_XOPEN) || defined (__OS2__))
    /*  Under UNIX & VMS we still need to fetch the first file entry         */
    return (read_dir (dir));

#elif (defined (WIN32))
    /*  Under Win32 we have read an entry, so return those values            */
    return (populate_entry (dir));

#elif (defined (_MSC_VER))
    /*  Under MSC we have read an entry, so return those values              */
    return (populate_entry (dir));

#elif (defined (__TURBOC__) || defined (__DJGPP__))
    /*  Under Borland C we have read an entry, so return those values        */
    return (populate_entry (dir));
#else

    return (FALSE);                     /*  Directory access not supported   */
#endif
}


/*  -------------------------------------------------------------------------
 *  populate_entry -- internal
 *
 *  Sets the various public fields in the directory stream from the system-
 *  specific values in the private fields.  Returns TRUE if okay, FALSE if
 *  there was a problem getting the file status information.
 */

static Bool
populate_entry (DIRST *dir)
{

#if (defined (WIN32))
    static char
        *default_user = "user";
#else
    char
        *full_path;                    /*  Full path name of the file        */
    struct stat
        stat_buf;                      /*  File status structure             */
    int
        rc;
#endif

    ASSERT (dir != NULL);
    if (dir-> _fixed)
        free_dir (dir);                /*  De-allocate old strings if reqd   */

    /*  Get name of file from directory structure                            */
#if (defined (__UNIX__) || defined (__VMS_XOPEN) || defined (__OS2__))
    dir-> file_name = dir-> _dir_entry-> d_name;

#elif (defined (WIN32))
    dir-> file_name = dir-> _dir_entry.cFileName;

#elif (defined (_MSC_VER))
    dir-> file_name = dir-> _dir_entry.name;

#elif (defined (__TURBOC__) || defined (__DJGPP__))
    dir-> file_name = dir-> _dir_entry.ff_name;
#endif

#if (defined (__UNIX__) || defined (MSDOS_FILESYSTEM))
    /*  If the filename is . or .., skip this entry and do the next.  We     */
    /*  use a little bit of a recursive call to make this code simple.       */

    if (dir-> file_name [0] == '.' && (dir-> file_name [1] == '\0'
    || (dir-> file_name [1] == '.' &&  dir-> file_name [2] == '\0')))
        return (read_dir (dir));
#endif

    /*  Prepare full path and get file status information.  Most systems have
     *  some kind of stat() function; we call this, even if similar info is
     *  already available in the _dir_entry structures.  Except for Win32
     *  where we use the native Win32 API to support compilers which may not
     *  have all the C wrapper functions (e.g. RSXNT).
     */

#if (defined (WIN32))
    /*  Get file info using Win32 calls                                      */
    {
        unsigned long thi, tlo;
        double   dthi, dtlo;
        double   secs_since_1601;
        double   delta = 11644473600.;
        double   two_to_32 = 4294967296.;

        thi = dir-> _dir_entry.ftLastWriteTime.dwHighDateTime;
        tlo = dir-> _dir_entry.ftLastWriteTime.dwLowDateTime;
        dthi = (double) thi;
        dtlo = (double) tlo;
        secs_since_1601 = (dthi * two_to_32 + dtlo) / 1.0e7;

        dir-> file_time = (unsigned long) (secs_since_1601 - delta);
        dir-> file_size = dir->_dir_entry.nFileSizeLow;
        dir-> file_mode = 0;
        if (dir-> _dir_entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            dir-> file_mode |= S_IFDIR;
        else
            dir-> file_mode |= S_IFREG;
        if (!(dir-> _dir_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
            dir-> file_mode |= S_IREAD;
        if (!(dir-> _dir_entry.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
            dir-> file_mode |= S_IWRITE;
        dir-> file_nlink = 1;
        dir-> owner = NULL;
        dir-> group = NULL;
    }

#else
    full_path = xstrcpy (NULL, dir-> dir_name, "/", dir-> file_name, NULL);
    rc = stat (full_path , &stat_buf);
    mem_free (full_path);
    if (rc == -1)
        return (FALSE);

    dir-> file_time  = stat_buf.st_mtime;   /*  Modification time            */
    dir-> file_size  = stat_buf.st_size;    /*  Size in bytes                */
    dir-> file_mode  = stat_buf.st_mode;    /*  UNIX-ish permissions         */
    dir-> file_nlink = stat_buf.st_nlink;   /*  Number of links to file      */

    /*  Get owner and group names                                            */
    dir-> owner = get_uid_name (stat_buf.st_uid);
    dir-> group = get_gid_name (stat_buf.st_gid);
#endif

    /*  Prepare DOS-ish permission bits                                      */
#if (defined (__UNIX__) || defined (__VMS_XOPEN) || defined (__OS2__))
    dir-> file_attrs = 0;
    if ((stat_buf.st_mode & S_IREAD)  == 0)
        dir-> file_attrs |= ATTR_HIDDEN;
    if ((stat_buf.st_mode & S_IWRITE) == 0)
        dir-> file_attrs |= ATTR_RDONLY;
    if ((stat_buf.st_mode & S_IFDIR)  != 0)
        dir-> file_attrs |= ATTR_SUBDIR;

#elif (defined (WIN32))
    dir-> file_attrs = 0;
    if (dir-> _dir_entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        dir-> file_attrs |= ATTR_SUBDIR;
    if (dir-> _dir_entry.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
        dir-> file_attrs |= ATTR_RDONLY;
    if (dir-> _dir_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
        dir-> file_attrs |= ATTR_HIDDEN;
    if (dir-> _dir_entry.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
        dir-> file_attrs |= ATTR_SYSTEM;
    dir-> owner = dir-> group = default_user;

#elif (defined (_MSC_VER))
    dir-> file_attrs = (byte) dir-> _dir_entry.attrib & ATTR_MASK;

#elif (defined (__TURBOC__) || defined (__DJGPP__))
    dir-> file_attrs = (byte) dir-> _dir_entry.ff_attrib & ATTR_MASK;
#endif

    return (TRUE);                      /*  No errors                        */
}


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

    Synopsis:
    Reads the next entry from the directory stream.  Returns TRUE if there
    was more data to read; returns FALSE if there was nothing more to read.
    Updates the fields in the directory structure when it returns TRUE.
    The strings in DIRST all point to static areas that may change after a
    further call to read_dir.  If you need persistent data (i.e. because
    you want to collect a set of DIRSTs and then sort them, call fix_dir()
    after each call to open_dir and read_dir.  You should then call
    free_dir() to release each DIRST when you are finished.
    ---------------------------------------------------------------------[>]-*/

Bool
read_dir (
    DIRST *dir)
{
    ASSERT (dir != NULL);

#if (defined (__UNIX__) || defined (__VMS_XOPEN) || defined (__OS2__))
    if ((dir-> _dir_entry =
        (struct Dirent *) readdir (dir-> _dir_handle)) != NULL)
        return (populate_entry (dir));
    else

#elif (defined (WIN32))
    if (FindNextFile (dir-> _dir_handle, &dir-> _dir_entry))
        return (populate_entry (dir));
    else

#elif (defined (_MSC_VER))
    if (_dos_findnext (&dir-> _dir_entry) == 0)
        return (populate_entry (dir));
    else

#elif (defined (__TURBOC__) || defined (__DJGPP__))
    if (findnext (&dir-> _dir_entry) == 0)
        return (populate_entry (dir));
    else
#endif

    return (FALSE);
}


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

    Synopsis:
    Close the directory stream, and free any allocated memory.  You should
    call this function when you are done reading a directory, or you will
    get memory leaks.  Returns TRUE if okay, FALSE if there was an error.
    ---------------------------------------------------------------------[>]-*/

Bool
close_dir (
    DIRST *dir)
{
    Bool
        rc;

    ASSERT (dir != NULL);

    mem_free (dir-> dir_name);          /*  Free dynamically-allocated name  */
#if (defined (__UNIX__) || defined (__VMS_XOPEN) || defined (__OS2__))
    ASSERT (dir-> _dir_handle);
    rc = (closedir (dir-> _dir_handle) == 0);

#elif (defined (WIN32))
    rc = FindClose (dir-> _dir_handle);

#elif (defined (_MSC_VER))
    rc = TRUE;                          /*  No function to close a dir       */

#elif (defined (__TURBOC__) || defined (__DJGPP__))
    rc = TRUE;                          /*  No function to close a dir       */
#else

    rc = FALSE;                         /*  Directory access not supported   */
#endif

    return (rc);
}


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

    Synopsis:
    Formats the directory entry information using the same conventions as

⌨️ 快捷键说明

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