cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

dirent.h (26800B)


      1/*
      2 * Dirent interface for Microsoft Visual Studio
      3 *
      4 * Copyright (C) 1998-2019 Toni Ronkko
      5 * This file is part of dirent.  Dirent may be freely distributed
      6 * under the MIT license.  For all details and documentation, see
      7 * https://github.com/tronkko/dirent
      8 */
      9#ifndef DIRENT_H
     10#define DIRENT_H
     11
     12/* Hide warnings about unreferenced local functions */
     13#if defined(__clang__)
     14#   pragma clang diagnostic ignored "-Wunused-function"
     15#elif defined(_MSC_VER)
     16#   pragma warning(disable:4505)
     17#elif defined(__GNUC__)
     18#   pragma GCC diagnostic ignored "-Wunused-function"
     19#endif
     20
     21/*
     22 * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
     23 * Windows Sockets 2.0.
     24 */
     25#ifndef WIN32_LEAN_AND_MEAN
     26#   define WIN32_LEAN_AND_MEAN
     27#endif
     28#include <windows.h>
     29
     30#include <stdio.h>
     31#include <stdarg.h>
     32#include <wchar.h>
     33#include <string.h>
     34#include <stdlib.h>
     35#include <malloc.h>
     36#include <sys/types.h>
     37#include <sys/stat.h>
     38#include <errno.h>
     39
     40/* Indicates that d_type field is available in dirent structure */
     41#define _DIRENT_HAVE_D_TYPE
     42
     43/* Indicates that d_namlen field is available in dirent structure */
     44#define _DIRENT_HAVE_D_NAMLEN
     45
     46/* Entries missing from MSVC 6.0 */
     47#if !defined(FILE_ATTRIBUTE_DEVICE)
     48#   define FILE_ATTRIBUTE_DEVICE 0x40
     49#endif
     50
     51/* File type and permission flags for stat(), general mask */
     52#if !defined(S_IFMT)
     53#   define S_IFMT _S_IFMT
     54#endif
     55
     56/* Directory bit */
     57#if !defined(S_IFDIR)
     58#   define S_IFDIR _S_IFDIR
     59#endif
     60
     61/* Character device bit */
     62#if !defined(S_IFCHR)
     63#   define S_IFCHR _S_IFCHR
     64#endif
     65
     66/* Pipe bit */
     67#if !defined(S_IFFIFO)
     68#   define S_IFFIFO _S_IFFIFO
     69#endif
     70
     71/* Regular file bit */
     72#if !defined(S_IFREG)
     73#   define S_IFREG _S_IFREG
     74#endif
     75
     76/* Read permission */
     77#if !defined(S_IREAD)
     78#   define S_IREAD _S_IREAD
     79#endif
     80
     81/* Write permission */
     82#if !defined(S_IWRITE)
     83#   define S_IWRITE _S_IWRITE
     84#endif
     85
     86/* Execute permission */
     87#if !defined(S_IEXEC)
     88#   define S_IEXEC _S_IEXEC
     89#endif
     90
     91/* Pipe */
     92#if !defined(S_IFIFO)
     93#   define S_IFIFO _S_IFIFO
     94#endif
     95
     96/* Block device */
     97#if !defined(S_IFBLK)
     98#   define S_IFBLK 0
     99#endif
    100
    101/* Link */
    102#if !defined(S_IFLNK)
    103#   define S_IFLNK 0
    104#endif
    105
    106/* Socket */
    107#if !defined(S_IFSOCK)
    108#   define S_IFSOCK 0
    109#endif
    110
    111/* Read user permission */
    112#if !defined(S_IRUSR)
    113#   define S_IRUSR S_IREAD
    114#endif
    115
    116/* Write user permission */
    117#if !defined(S_IWUSR)
    118#   define S_IWUSR S_IWRITE
    119#endif
    120
    121/* Execute user permission */
    122#if !defined(S_IXUSR)
    123#   define S_IXUSR 0
    124#endif
    125
    126/* Read group permission */
    127#if !defined(S_IRGRP)
    128#   define S_IRGRP 0
    129#endif
    130
    131/* Write group permission */
    132#if !defined(S_IWGRP)
    133#   define S_IWGRP 0
    134#endif
    135
    136/* Execute group permission */
    137#if !defined(S_IXGRP)
    138#   define S_IXGRP 0
    139#endif
    140
    141/* Read others permission */
    142#if !defined(S_IROTH)
    143#   define S_IROTH 0
    144#endif
    145
    146/* Write others permission */
    147#if !defined(S_IWOTH)
    148#   define S_IWOTH 0
    149#endif
    150
    151/* Execute others permission */
    152#if !defined(S_IXOTH)
    153#   define S_IXOTH 0
    154#endif
    155
    156/* Maximum length of file name */
    157#if !defined(PATH_MAX)
    158#   define PATH_MAX MAX_PATH
    159#endif
    160#if !defined(FILENAME_MAX)
    161#   define FILENAME_MAX MAX_PATH
    162#endif
    163#if !defined(NAME_MAX)
    164#   define NAME_MAX FILENAME_MAX
    165#endif
    166
    167/* File type flags for d_type */
    168#define DT_UNKNOWN 0
    169#define DT_REG S_IFREG
    170#define DT_DIR S_IFDIR
    171#define DT_FIFO S_IFIFO
    172#define DT_SOCK S_IFSOCK
    173#define DT_CHR S_IFCHR
    174#define DT_BLK S_IFBLK
    175#define DT_LNK S_IFLNK
    176
    177/* Macros for converting between st_mode and d_type */
    178#define IFTODT(mode) ((mode) & S_IFMT)
    179#define DTTOIF(type) (type)
    180
    181/*
    182 * File type macros.  Note that block devices, sockets and links cannot be
    183 * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
    184 * only defined for compatibility.  These macros should always return false
    185 * on Windows.
    186 */
    187#if !defined(S_ISFIFO)
    188#   define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
    189#endif
    190#if !defined(S_ISDIR)
    191#   define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
    192#endif
    193#if !defined(S_ISREG)
    194#   define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
    195#endif
    196#if !defined(S_ISLNK)
    197#   define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
    198#endif
    199#if !defined(S_ISSOCK)
    200#   define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
    201#endif
    202#if !defined(S_ISCHR)
    203#   define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
    204#endif
    205#if !defined(S_ISBLK)
    206#   define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
    207#endif
    208
    209/* Return the exact length of the file name without zero terminator */
    210#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
    211
    212/* Return the maximum size of a file name */
    213#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
    214
    215
    216#ifdef __cplusplus
    217extern "C" {
    218#endif
    219
    220
    221/* Wide-character version */
    222struct _wdirent {
    223    /* Always zero */
    224    long d_ino;
    225
    226    /* File position within stream */
    227    long d_off;
    228
    229    /* Structure size */
    230    unsigned short d_reclen;
    231
    232    /* Length of name without \0 */
    233    size_t d_namlen;
    234
    235    /* File type */
    236    int d_type;
    237
    238    /* File name */
    239    wchar_t d_name[PATH_MAX+1];
    240};
    241typedef struct _wdirent _wdirent;
    242
    243struct _WDIR {
    244    /* Current directory entry */
    245    struct _wdirent ent;
    246
    247    /* Private file data */
    248    WIN32_FIND_DATAW data;
    249
    250    /* True if data is valid */
    251    int cached;
    252
    253    /* Win32 search handle */
    254    HANDLE handle;
    255
    256    /* Initial directory name */
    257    wchar_t *patt;
    258};
    259typedef struct _WDIR _WDIR;
    260
    261/* Multi-byte character version */
    262struct dirent {
    263    /* Always zero */
    264    long d_ino;
    265
    266    /* File position within stream */
    267    long d_off;
    268
    269    /* Structure size */
    270    unsigned short d_reclen;
    271
    272    /* Length of name without \0 */
    273    size_t d_namlen;
    274
    275    /* File type */
    276    int d_type;
    277
    278    /* File name */
    279    char d_name[PATH_MAX+1];
    280};
    281typedef struct dirent dirent;
    282
    283struct DIR {
    284    struct dirent ent;
    285    struct _WDIR *wdirp;
    286};
    287typedef struct DIR DIR;
    288
    289
    290/* Dirent functions */
    291static DIR *opendir (const char *dirname);
    292static _WDIR *_wopendir (const wchar_t *dirname);
    293
    294static struct dirent *readdir (DIR *dirp);
    295static struct _wdirent *_wreaddir (_WDIR *dirp);
    296
    297static int readdir_r(
    298    DIR *dirp, struct dirent *entry, struct dirent **result);
    299static int _wreaddir_r(
    300    _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
    301
    302static int closedir (DIR *dirp);
    303static int _wclosedir (_WDIR *dirp);
    304
    305static void rewinddir (DIR* dirp);
    306static void _wrewinddir (_WDIR* dirp);
    307
    308static int scandir (const char *dirname, struct dirent ***namelist,
    309    int (*filter)(const struct dirent*),
    310    int (*compare)(const struct dirent**, const struct dirent**));
    311
    312static int alphasort (const struct dirent **a, const struct dirent **b);
    313
    314static int versionsort (const struct dirent **a, const struct dirent **b);
    315
    316
    317/* For compatibility with Symbian */
    318#define wdirent _wdirent
    319#define WDIR _WDIR
    320#define wopendir _wopendir
    321#define wreaddir _wreaddir
    322#define wclosedir _wclosedir
    323#define wrewinddir _wrewinddir
    324
    325
    326/* Internal utility functions */
    327static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
    328static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
    329
    330static int dirent_mbstowcs_s(
    331    size_t *pReturnValue,
    332    wchar_t *wcstr,
    333    size_t sizeInWords,
    334    const char *mbstr,
    335    size_t count);
    336
    337static int dirent_wcstombs_s(
    338    size_t *pReturnValue,
    339    char *mbstr,
    340    size_t sizeInBytes,
    341    const wchar_t *wcstr,
    342    size_t count);
    343
    344static void dirent_set_errno (int error);
    345
    346
    347/*
    348 * Open directory stream DIRNAME for read and return a pointer to the
    349 * internal working area that is used to retrieve individual directory
    350 * entries.
    351 */
    352static _WDIR*
    353_wopendir(
    354    const wchar_t *dirname)
    355{
    356    _WDIR *dirp;
    357    DWORD n;
    358    wchar_t *p;
    359
    360    /* Must have directory name */
    361    if (dirname == NULL  ||  dirname[0] == '\0') {
    362        dirent_set_errno (ENOENT);
    363        return NULL;
    364    }
    365
    366    /* Allocate new _WDIR structure */
    367    dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
    368    if (!dirp) {
    369        return NULL;
    370    }
    371
    372    /* Reset _WDIR structure */
    373    dirp->handle = INVALID_HANDLE_VALUE;
    374    dirp->patt = NULL;
    375    dirp->cached = 0;
    376
    377    /*
    378     * Compute the length of full path plus zero terminator
    379     *
    380     * Note that on WinRT there's no way to convert relative paths
    381     * into absolute paths, so just assume it is an absolute path.
    382     */
    383#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
    384    /* Desktop */
    385    n = GetFullPathNameW (dirname, 0, NULL, NULL);
    386#else
    387    /* WinRT */
    388    n = wcslen (dirname);
    389#endif
    390
    391    /* Allocate room for absolute directory name and search pattern */
    392    dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
    393    if (dirp->patt == NULL) {
    394        goto exit_closedir;
    395    }
    396
    397    /*
    398     * Convert relative directory name to an absolute one.  This
    399     * allows rewinddir() to function correctly even when current
    400     * working directory is changed between opendir() and rewinddir().
    401     *
    402     * Note that on WinRT there's no way to convert relative paths
    403     * into absolute paths, so just assume it is an absolute path.
    404     */
    405#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
    406    /* Desktop */
    407    n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
    408    if (n <= 0) {
    409        goto exit_closedir;
    410    }
    411#else
    412    /* WinRT */
    413    wcsncpy_s (dirp->patt, n+1, dirname, n);
    414#endif
    415
    416    /* Append search pattern \* to the directory name */
    417    p = dirp->patt + n;
    418    switch (p[-1]) {
    419    case '\\':
    420    case '/':
    421    case ':':
    422        /* Directory ends in path separator, e.g. c:\temp\ */
    423        /*NOP*/;
    424        break;
    425
    426    default:
    427        /* Directory name doesn't end in path separator */
    428        *p++ = '\\';
    429    }
    430    *p++ = '*';
    431    *p = '\0';
    432
    433    /* Open directory stream and retrieve the first entry */
    434    if (!dirent_first (dirp)) {
    435        goto exit_closedir;
    436    }
    437
    438    /* Success */
    439    return dirp;
    440
    441    /* Failure */
    442exit_closedir:
    443    _wclosedir (dirp);
    444    return NULL;
    445}
    446
    447/*
    448 * Read next directory entry.
    449 *
    450 * Returns pointer to static directory entry which may be overwritten by
    451 * subsequent calls to _wreaddir().
    452 */
    453static struct _wdirent*
    454_wreaddir(
    455    _WDIR *dirp)
    456{
    457    struct _wdirent *entry;
    458
    459    /*
    460     * Read directory entry to buffer.  We can safely ignore the return value
    461     * as entry will be set to NULL in case of error.
    462     */
    463    (void) _wreaddir_r (dirp, &dirp->ent, &entry);
    464
    465    /* Return pointer to statically allocated directory entry */
    466    return entry;
    467}
    468
    469/*
    470 * Read next directory entry.
    471 *
    472 * Returns zero on success.  If end of directory stream is reached, then sets
    473 * result to NULL and returns zero.
    474 */
    475static int
    476_wreaddir_r(
    477    _WDIR *dirp,
    478    struct _wdirent *entry,
    479    struct _wdirent **result)
    480{
    481    WIN32_FIND_DATAW *datap;
    482
    483    /* Read next directory entry */
    484    datap = dirent_next (dirp);
    485    if (datap) {
    486        size_t n;
    487        DWORD attr;
    488
    489        /*
    490         * Copy file name as wide-character string.  If the file name is too
    491         * long to fit in to the destination buffer, then truncate file name
    492         * to PATH_MAX characters and zero-terminate the buffer.
    493         */
    494        n = 0;
    495        while (n < PATH_MAX  &&  datap->cFileName[n] != 0) {
    496            entry->d_name[n] = datap->cFileName[n];
    497            n++;
    498        }
    499        entry->d_name[n] = 0;
    500
    501        /* Length of file name excluding zero terminator */
    502        entry->d_namlen = n;
    503
    504        /* File type */
    505        attr = datap->dwFileAttributes;
    506        if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
    507            entry->d_type = DT_CHR;
    508        } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
    509            entry->d_type = DT_DIR;
    510        } else {
    511            entry->d_type = DT_REG;
    512        }
    513
    514        /* Reset dummy fields */
    515        entry->d_ino = 0;
    516        entry->d_off = 0;
    517        entry->d_reclen = sizeof (struct _wdirent);
    518
    519        /* Set result address */
    520        *result = entry;
    521
    522    } else {
    523
    524        /* Return NULL to indicate end of directory */
    525        *result = NULL;
    526
    527    }
    528
    529    return /*OK*/0;
    530}
    531
    532/*
    533 * Close directory stream opened by opendir() function.  This invalidates the
    534 * DIR structure as well as any directory entry read previously by
    535 * _wreaddir().
    536 */
    537static int
    538_wclosedir(
    539    _WDIR *dirp)
    540{
    541    int ok;
    542    if (dirp) {
    543
    544        /* Release search handle */
    545        if (dirp->handle != INVALID_HANDLE_VALUE) {
    546            FindClose (dirp->handle);
    547        }
    548
    549        /* Release search pattern */
    550        free (dirp->patt);
    551
    552        /* Release directory structure */
    553        free (dirp);
    554        ok = /*success*/0;
    555
    556    } else {
    557
    558        /* Invalid directory stream */
    559        dirent_set_errno (EBADF);
    560        ok = /*failure*/-1;
    561
    562    }
    563    return ok;
    564}
    565
    566/*
    567 * Rewind directory stream such that _wreaddir() returns the very first
    568 * file name again.
    569 */
    570static void
    571_wrewinddir(
    572    _WDIR* dirp)
    573{
    574    if (dirp) {
    575        /* Release existing search handle */
    576        if (dirp->handle != INVALID_HANDLE_VALUE) {
    577            FindClose (dirp->handle);
    578        }
    579
    580        /* Open new search handle */
    581        dirent_first (dirp);
    582    }
    583}
    584
    585/* Get first directory entry (internal) */
    586static WIN32_FIND_DATAW*
    587dirent_first(
    588    _WDIR *dirp)
    589{
    590    WIN32_FIND_DATAW *datap;
    591    DWORD error;
    592
    593    /* Open directory and retrieve the first entry */
    594    dirp->handle = FindFirstFileExW(
    595        dirp->patt, FindExInfoStandard, &dirp->data,
    596        FindExSearchNameMatch, NULL, 0);
    597    if (dirp->handle != INVALID_HANDLE_VALUE) {
    598
    599        /* a directory entry is now waiting in memory */
    600        datap = &dirp->data;
    601        dirp->cached = 1;
    602
    603    } else {
    604
    605        /* Failed to open directory: no directory entry in memory */
    606        dirp->cached = 0;
    607        datap = NULL;
    608
    609        /* Set error code */
    610        error = GetLastError ();
    611        switch (error) {
    612        case ERROR_ACCESS_DENIED:
    613            /* No read access to directory */
    614            dirent_set_errno (EACCES);
    615            break;
    616
    617        case ERROR_DIRECTORY:
    618            /* Directory name is invalid */
    619            dirent_set_errno (ENOTDIR);
    620            break;
    621
    622        case ERROR_PATH_NOT_FOUND:
    623        default:
    624            /* Cannot find the file */
    625            dirent_set_errno (ENOENT);
    626        }
    627
    628    }
    629    return datap;
    630}
    631
    632/*
    633 * Get next directory entry (internal).
    634 *
    635 * Returns
    636 */
    637static WIN32_FIND_DATAW*
    638dirent_next(
    639    _WDIR *dirp)
    640{
    641    WIN32_FIND_DATAW *p;
    642
    643    /* Get next directory entry */
    644    if (dirp->cached != 0) {
    645
    646        /* A valid directory entry already in memory */
    647        p = &dirp->data;
    648        dirp->cached = 0;
    649
    650    } else if (dirp->handle != INVALID_HANDLE_VALUE) {
    651
    652        /* Get the next directory entry from stream */
    653        if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
    654            /* Got a file */
    655            p = &dirp->data;
    656        } else {
    657            /* The very last entry has been processed or an error occurred */
    658            FindClose (dirp->handle);
    659            dirp->handle = INVALID_HANDLE_VALUE;
    660            p = NULL;
    661        }
    662
    663    } else {
    664
    665        /* End of directory stream reached */
    666        p = NULL;
    667
    668    }
    669
    670    return p;
    671}
    672
    673/*
    674 * Open directory stream using plain old C-string.
    675 */
    676static DIR*
    677opendir(
    678    const char *dirname)
    679{
    680    struct DIR *dirp;
    681
    682    /* Must have directory name */
    683    if (dirname == NULL  ||  dirname[0] == '\0') {
    684        dirent_set_errno (ENOENT);
    685        return NULL;
    686    }
    687
    688    /* Allocate memory for DIR structure */
    689    dirp = (DIR*) malloc (sizeof (struct DIR));
    690    if (!dirp) {
    691        return NULL;
    692    }
    693    {
    694        int error;
    695        wchar_t wname[PATH_MAX + 1];
    696        size_t n;
    697
    698        /* Convert directory name to wide-character string */
    699        error = dirent_mbstowcs_s(
    700            &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
    701        if (error) {
    702            /*
    703             * Cannot convert file name to wide-character string.  This
    704             * occurs if the string contains invalid multi-byte sequences or
    705             * the output buffer is too small to contain the resulting
    706             * string.
    707             */
    708            goto exit_free;
    709        }
    710
    711
    712        /* Open directory stream using wide-character name */
    713        dirp->wdirp = _wopendir (wname);
    714        if (!dirp->wdirp) {
    715            goto exit_free;
    716        }
    717
    718    }
    719
    720    /* Success */
    721    return dirp;
    722
    723    /* Failure */
    724exit_free:
    725    free (dirp);
    726    return NULL;
    727}
    728
    729/*
    730 * Read next directory entry.
    731 */
    732static struct dirent*
    733readdir(
    734    DIR *dirp)
    735{
    736    struct dirent *entry;
    737
    738    /*
    739     * Read directory entry to buffer.  We can safely ignore the return value
    740     * as entry will be set to NULL in case of error.
    741     */
    742    (void) readdir_r (dirp, &dirp->ent, &entry);
    743
    744    /* Return pointer to statically allocated directory entry */
    745    return entry;
    746}
    747
    748/*
    749 * Read next directory entry into called-allocated buffer.
    750 *
    751 * Returns zero on success.  If the end of directory stream is reached, then
    752 * sets result to NULL and returns zero.
    753 */
    754static int
    755readdir_r(
    756    DIR *dirp,
    757    struct dirent *entry,
    758    struct dirent **result)
    759{
    760    WIN32_FIND_DATAW *datap;
    761
    762    /* Read next directory entry */
    763    datap = dirent_next (dirp->wdirp);
    764    if (datap) {
    765        size_t n;
    766        int error;
    767
    768        /* Attempt to convert file name to multi-byte string */
    769        error = dirent_wcstombs_s(
    770            &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
    771
    772        /*
    773         * If the file name cannot be represented by a multi-byte string,
    774         * then attempt to use old 8+3 file name.  This allows traditional
    775         * Unix-code to access some file names despite of unicode
    776         * characters, although file names may seem unfamiliar to the user.
    777         *
    778         * Be ware that the code below cannot come up with a short file
    779         * name unless the file system provides one.  At least
    780         * VirtualBox shared folders fail to do this.
    781         */
    782        if (error  &&  datap->cAlternateFileName[0] != '\0') {
    783            error = dirent_wcstombs_s(
    784                &n, entry->d_name, PATH_MAX + 1,
    785                datap->cAlternateFileName, PATH_MAX + 1);
    786        }
    787
    788        if (!error) {
    789            DWORD attr;
    790
    791            /* Length of file name excluding zero terminator */
    792            entry->d_namlen = n - 1;
    793
    794            /* File attributes */
    795            attr = datap->dwFileAttributes;
    796            if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
    797                entry->d_type = DT_CHR;
    798            } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
    799                entry->d_type = DT_DIR;
    800            } else {
    801                entry->d_type = DT_REG;
    802            }
    803
    804            /* Reset dummy fields */
    805            entry->d_ino = 0;
    806            entry->d_off = 0;
    807            entry->d_reclen = sizeof (struct dirent);
    808
    809        } else {
    810
    811            /*
    812             * Cannot convert file name to multi-byte string so construct
    813             * an erroneous directory entry and return that.  Note that
    814             * we cannot return NULL as that would stop the processing
    815             * of directory entries completely.
    816             */
    817            entry->d_name[0] = '?';
    818            entry->d_name[1] = '\0';
    819            entry->d_namlen = 1;
    820            entry->d_type = DT_UNKNOWN;
    821            entry->d_ino = 0;
    822            entry->d_off = -1;
    823            entry->d_reclen = 0;
    824
    825        }
    826
    827        /* Return pointer to directory entry */
    828        *result = entry;
    829
    830    } else {
    831
    832        /* No more directory entries */
    833        *result = NULL;
    834
    835    }
    836
    837    return /*OK*/0;
    838}
    839
    840/*
    841 * Close directory stream.
    842 */
    843static int
    844closedir(
    845    DIR *dirp)
    846{
    847    int ok;
    848    if (dirp) {
    849
    850        /* Close wide-character directory stream */
    851        ok = _wclosedir (dirp->wdirp);
    852        dirp->wdirp = NULL;
    853
    854        /* Release multi-byte character version */
    855        free (dirp);
    856
    857    } else {
    858
    859        /* Invalid directory stream */
    860        dirent_set_errno (EBADF);
    861        ok = /*failure*/-1;
    862
    863    }
    864    return ok;
    865}
    866
    867/*
    868 * Rewind directory stream to beginning.
    869 */
    870static void
    871rewinddir(
    872    DIR* dirp)
    873{
    874    /* Rewind wide-character string directory stream */
    875    _wrewinddir (dirp->wdirp);
    876}
    877
    878/*
    879 * Scan directory for entries.
    880 */
    881static int
    882scandir(
    883    const char *dirname,
    884    struct dirent ***namelist,
    885    int (*filter)(const struct dirent*),
    886    int (*compare)(const struct dirent**, const struct dirent**))
    887{
    888    struct dirent **files = NULL;
    889    size_t size = 0;
    890    size_t allocated = 0;
    891    const size_t init_size = 1;
    892    DIR *dir = NULL;
    893    struct dirent *entry;
    894    struct dirent *tmp = NULL;
    895    size_t i;
    896    int result = 0;
    897
    898    /* Open directory stream */
    899    dir = opendir (dirname);
    900    if (dir) {
    901
    902        /* Read directory entries to memory */
    903        while (1) {
    904
    905            /* Enlarge pointer table to make room for another pointer */
    906            if (size >= allocated) {
    907                void *p;
    908                size_t num_entries;
    909
    910                /* Compute number of entries in the enlarged pointer table */
    911                if (size < init_size) {
    912                    /* Allocate initial pointer table */
    913                    num_entries = init_size;
    914                } else {
    915                    /* Double the size */
    916                    num_entries = size * 2;
    917                }
    918
    919                /* Allocate first pointer table or enlarge existing table */
    920                p = realloc (files, sizeof (void*) * num_entries);
    921                if (p != NULL) {
    922                    /* Got the memory */
    923                    files = (dirent**) p;
    924                    allocated = num_entries;
    925                } else {
    926                    /* Out of memory */
    927                    result = -1;
    928                    break;
    929                }
    930
    931            }
    932
    933            /* Allocate room for temporary directory entry */
    934            if (tmp == NULL) {
    935                tmp = (struct dirent*) malloc (sizeof (struct dirent));
    936                if (tmp == NULL) {
    937                    /* Cannot allocate temporary directory entry */
    938                    result = -1;
    939                    break;
    940                }
    941            }
    942
    943            /* Read directory entry to temporary area */
    944            if (readdir_r (dir, tmp, &entry) == /*OK*/0) {
    945
    946                /* Did we get an entry? */
    947                if (entry != NULL) {
    948                    int pass;
    949
    950                    /* Determine whether to include the entry in result */
    951                    if (filter) {
    952                        /* Let the filter function decide */
    953                        pass = filter (tmp);
    954                    } else {
    955                        /* No filter function, include everything */
    956                        pass = 1;
    957                    }
    958
    959                    if (pass) {
    960                        /* Store the temporary entry to pointer table */
    961                        files[size++] = tmp;
    962                        tmp = NULL;
    963
    964                        /* Keep up with the number of files */
    965                        result++;
    966                    }
    967
    968                } else {
    969
    970                    /*
    971                     * End of directory stream reached => sort entries and
    972                     * exit.
    973                     */
    974                    qsort (files, size, sizeof (void*),
    975                        (int (*) (const void*, const void*)) compare);
    976                    break;
    977
    978                }
    979
    980            } else {
    981                /* Error reading directory entry */
    982                result = /*Error*/ -1;
    983                break;
    984            }
    985
    986        }
    987
    988    } else {
    989        /* Cannot open directory */
    990        result = /*Error*/ -1;
    991    }
    992
    993    /* Release temporary directory entry */
    994    free (tmp);
    995
    996    /* Release allocated memory on error */
    997    if (result < 0) {
    998        for (i = 0; i < size; i++) {
    999            free (files[i]);
   1000        }
   1001        free (files);
   1002        files = NULL;
   1003    }
   1004
   1005    /* Close directory stream */
   1006    if (dir) {
   1007        closedir (dir);
   1008    }
   1009
   1010    /* Pass pointer table to caller */
   1011    if (namelist) {
   1012        *namelist = files;
   1013    }
   1014    return result;
   1015}
   1016
   1017/* Alphabetical sorting */
   1018static int
   1019alphasort(
   1020    const struct dirent **a, const struct dirent **b)
   1021{
   1022    return strcoll ((*a)->d_name, (*b)->d_name);
   1023}
   1024
   1025/* Sort versions */
   1026static int
   1027versionsort(
   1028    const struct dirent **a, const struct dirent **b)
   1029{
   1030    /* FIXME: implement strverscmp and use that */
   1031    return alphasort (a, b);
   1032}
   1033
   1034/* Convert multi-byte string to wide character string */
   1035static int
   1036dirent_mbstowcs_s(
   1037    size_t *pReturnValue,
   1038    wchar_t *wcstr,
   1039    size_t sizeInWords,
   1040    const char *mbstr,
   1041    size_t count)
   1042{
   1043    int error;
   1044
   1045#if defined(_MSC_VER)  &&  _MSC_VER >= 1400
   1046
   1047    /* Microsoft Visual Studio 2005 or later */
   1048    error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
   1049
   1050#else
   1051
   1052    /* Older Visual Studio or non-Microsoft compiler */
   1053    size_t n;
   1054
   1055    /* Convert to wide-character string (or count characters) */
   1056    n = mbstowcs (wcstr, mbstr, sizeInWords);
   1057    if (!wcstr  ||  n < count) {
   1058
   1059        /* Zero-terminate output buffer */
   1060        if (wcstr  &&  sizeInWords) {
   1061            if (n >= sizeInWords) {
   1062                n = sizeInWords - 1;
   1063            }
   1064            wcstr[n] = 0;
   1065        }
   1066
   1067        /* Length of resulting multi-byte string WITH zero terminator */
   1068        if (pReturnValue) {
   1069            *pReturnValue = n + 1;
   1070        }
   1071
   1072        /* Success */
   1073        error = 0;
   1074
   1075    } else {
   1076
   1077        /* Could not convert string */
   1078        error = 1;
   1079
   1080    }
   1081
   1082#endif
   1083    return error;
   1084}
   1085
   1086/* Convert wide-character string to multi-byte string */
   1087static int
   1088dirent_wcstombs_s(
   1089    size_t *pReturnValue,
   1090    char *mbstr,
   1091    size_t sizeInBytes, /* max size of mbstr */
   1092    const wchar_t *wcstr,
   1093    size_t count)
   1094{
   1095    int error;
   1096
   1097#if defined(_MSC_VER)  &&  _MSC_VER >= 1400
   1098
   1099    /* Microsoft Visual Studio 2005 or later */
   1100    error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
   1101
   1102#else
   1103
   1104    /* Older Visual Studio or non-Microsoft compiler */
   1105    size_t n;
   1106
   1107    /* Convert to multi-byte string (or count the number of bytes needed) */
   1108    n = wcstombs (mbstr, wcstr, sizeInBytes);
   1109    if (!mbstr  ||  n < count) {
   1110
   1111        /* Zero-terminate output buffer */
   1112        if (mbstr  &&  sizeInBytes) {
   1113            if (n >= sizeInBytes) {
   1114                n = sizeInBytes - 1;
   1115            }
   1116            mbstr[n] = '\0';
   1117        }
   1118
   1119        /* Length of resulting multi-bytes string WITH zero-terminator */
   1120        if (pReturnValue) {
   1121            *pReturnValue = n + 1;
   1122        }
   1123
   1124        /* Success */
   1125        error = 0;
   1126
   1127    } else {
   1128
   1129        /* Cannot convert string */
   1130        error = 1;
   1131
   1132    }
   1133
   1134#endif
   1135    return error;
   1136}
   1137
   1138/* Set errno variable */
   1139static void
   1140dirent_set_errno(
   1141    int error)
   1142{
   1143#if defined(_MSC_VER)  &&  _MSC_VER >= 1400
   1144
   1145    /* Microsoft Visual Studio 2005 and later */
   1146    _set_errno (error);
   1147
   1148#else
   1149
   1150    /* Non-Microsoft compiler or older Microsoft compiler */
   1151    errno = error;
   1152
   1153#endif
   1154}
   1155
   1156
   1157#ifdef __cplusplus
   1158}
   1159#endif
   1160#endif /*DIRENT_H*/