/* * dir.c - files and directories handler * * Developed by Ondrej Jombik * Copyright (c) 2003 Platon SDG, http://platon.sk/ * Licensed under terms of GNU General Public License. * All rights reserved. * * Changelog: * 19/05/2003 - created * 27/06/2003 - added Win32 support * 15/07/2003 - smart memory allocation for files and directories data */ /* $Platon: games/3do-view/dir.c,v 1.7 2003/07/15 15:45:34 nepto Exp $ */ #include #include #include #define DIR_SMART_ALLOCATION (1) /* 1 or 0 */ #define DIR_REALLOC_IDX_STEP (15) #if DIR_SMART_ALLOCATION # define DIR_REALLOC_DATA_STEP (255) #endif #if PLATON_SYSTEM_SVGALIB # include # include # include # include # define DIR_DIRECTORY_CONDITION (S_ISDIR(st.st_mode)) # define DIR_FILENAME (dp->d_name) # define DIR_INIT_CONDITION (! ((dirp = opendir(".")) == NULL \ && !chdir("/") && (dirp = opendir(".")) == NULL)) /* If current directory cannot be opened, fallback to root directory. */ #endif #if PLATON_SYSTEM_WIN32 # include # define DIR_DIRECTORY_CONDITION (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) # define DIR_FILENAME (FindFileData.cFileName) # define DIR_NEXT_CONDITION (FindNextFile(hFind, &FindFileData)) # define DIR_INIT_CONDITION ((hFind = FindFirstFile("*.*", &FindFileData)) != INVALID_HANDLE_VALUE) #endif #if PLATON_SYSTEM_MSDOS # include # include # define DIR_DIRECTORY_CONDITION (ffblk.ff_attrib & FA_DIREC) # define DIR_FILENAME (ffblk.ff_name) # define DIR_NEXT_CONDITION (! findnext(&ffblk)) # define DIR_INIT_CONDITION (! (findfirst("*.*", &ffblk, \ FA_DIREC + FA_HIDDEN + FA_RDONLY + FA_SYSTEM))) #endif static int compare_function(const void *ptr1, const void *ptr2) /* {{{ */ { #if 0 fprintf(stderr, "comparing %s[%p]:%s[%p]\n", *(char **) ptr1, ptr1, *(char **) ptr2, ptr2); #endif return strcmp(*(char **) ptr1, *(char **) ptr2); } /* }}} */ void get_directories_and_files(char ***directories, char ***files) /* {{{ */ { #if DIR_SMART_ALLOCATION register int *alloc_bytes; register int *free_bytes; int directories_alloc_bytes = 0; int directories_free_bytes = 0; int files_alloc_bytes = 0; int files_free_bytes = 0; #endif #if PLATON_SYSTEM_SVGALIB DIR *dirp; struct dirent *dp; struct stat st; #endif #if PLATON_SYSTEM_WIN32 WIN32_FIND_DATA FindFileData; HANDLE hFind; #endif #if PLATON_SYSTEM_MSDOS struct ffblk ffblk; #endif register char ***ptr; int directories_size, files_size, *size; if (directories != NULL) *directories = NULL; if (files != NULL) *files = NULL; if (! DIR_INIT_CONDITION) return; directories_size = 0; files_size = 0; #if PLATON_SYSTEM_SVGALIB for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if (stat(DIR_FILENAME, &st)) continue; #endif #if PLATON_SYSTEM_MSDOS || PLATON_SYSTEM_WIN32 do { #endif if (DIR_DIRECTORY_CONDITION) { if (directories == NULL || ! strcmp(DIR_FILENAME, ".")) continue; ptr = directories; size = &directories_size; #if DIR_SMART_ALLOCATION alloc_bytes = &directories_alloc_bytes; free_bytes = &directories_free_bytes; #endif } else { if (files == NULL) continue; ptr = files; size = &files_size; #if DIR_SMART_ALLOCATION alloc_bytes = &files_alloc_bytes; free_bytes = &files_free_bytes; #endif } if (! *size || !((*size + 1) % DIR_REALLOC_IDX_STEP)) { register char **new_ptr; new_ptr = (char **) realloc((void *) *ptr, sizeof(char *) * (*size + 1 + DIR_REALLOC_IDX_STEP)); if (new_ptr == NULL) break; /* take what we recentry have and go away if memory allocation failed */ *ptr = new_ptr; if (! *size) (*ptr)[0] = NULL; } #if DIR_SMART_ALLOCATION while (strlen(DIR_FILENAME) + 1 > *free_bytes) { register char *new_ptr; register int i, diff; new_ptr = (char *) realloc((void *) **ptr, sizeof(char) * (*alloc_bytes + DIR_REALLOC_DATA_STEP)); if (new_ptr == NULL) break; /* skip this entry if memory allocation failed */ diff = new_ptr - **ptr; for (i = 0; i <= *size; i++) (*ptr)[i] += diff; *free_bytes += DIR_REALLOC_DATA_STEP; *alloc_bytes += DIR_REALLOC_DATA_STEP; } if (strlen(DIR_FILENAME) + 1 <= *free_bytes) { (*ptr)[*size] = **ptr + *alloc_bytes - *free_bytes; strcpy((*ptr)[*size], DIR_FILENAME); *free_bytes -= (strlen(DIR_FILENAME) + 1); } #else if (((*ptr)[*size] = strdup(DIR_FILENAME)) == NULL) break; #endif (*size)++; (*ptr)[*size] = NULL; #if PLATON_SYSTEM_SVGALIB } closedir(dirp); #endif #if PLATON_SYSTEM_MSDOS || PLATON_SYSTEM_WIN32 } while (DIR_NEXT_CONDITION); #endif #if DIR_SMART_ALLOCATION /* Sorting currently does not work in smart allocation mode. */ #else if (*directories != NULL) qsort(*directories, directories_size, sizeof(char *), compare_function); if (*files != NULL) qsort(*files, files_size, sizeof(char *), compare_function); #endif } /* }}} */ void free_directories_or_files(char **ar) /* {{{ */ { #if DIR_SMART_ALLOCATION if (ar[0] != NULL) free(ar[0]); #else register int i; for (i = 0; ar[i] != NULL; i++) free(ar[i]); #endif free(ar); } /* }}} */ #if defined(SELF) || defined(SELFTEST) || defined(SELF_DIR) #include int main(int argc, char **argv) /* {{{ */ { register int k; char **dirs, **files; get_directories_and_files(&dirs, &files); printf("Directories: [%p]\n", dirs); for (k = 0; dirs != NULL && dirs[k] != NULL; k++) printf("%03d: %s\n", k, dirs[k]); printf("Files: [%p]\n", files); for (k = 0; files != NULL && files[k] != NULL; k++) printf("%03d: %s\n", k, files[k]); if (dirs != NULL) free_directories_or_files(dirs); if (files != NULL) free_directories_or_files(files); return 0; } /* }}} */ #endif /* #if defined(SELF) || defined(SELFTEST) || defined(SELF_DIR) */ /* Modeline for ViM {{{ * vim: set ts=4: * vim600: fdm=marker fdl=0 fdc=0: * }}} */