summaryrefslogtreecommitdiffstats
path: root/gnu/lib/libodialog/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/lib/libodialog/dir.c')
-rw-r--r--gnu/lib/libodialog/dir.c549
1 files changed, 549 insertions, 0 deletions
diff --git a/gnu/lib/libodialog/dir.c b/gnu/lib/libodialog/dir.c
new file mode 100644
index 0000000..5348c2f
--- /dev/null
+++ b/gnu/lib/libodialog/dir.c
@@ -0,0 +1,549 @@
+/****************************************************************************
+ *
+ * Program: dir.c
+ * Author: Marc van Kempen
+ * desc: Directory routines, sorting and reading
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ ****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h> /* XXX for _POSIX_VERSION ifdefs */
+
+#if !defined sgi && !defined _POSIX_VERSION
+#include <sys/dir.h>
+#endif
+#if defined __sun__
+#include <sys/dirent.h>
+#endif
+#if defined sgi || defined _POSIX_VERSION
+#include <dirent.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fnmatch.h>
+#include <sys/param.h>
+#include "dir.h"
+
+/****************************************************************************
+ *
+ * local prototypes
+ *
+ ****************************************************************************/
+
+void toggle_dotfiles(void);
+int show_dotfiles(void);
+int dir_alphasort(const void *d1, const void *d2);
+int dir_sizesort(const void *d1, const void *d2);
+int dir_datesort(const void *d1, const void *d2);
+int dir_extsort(const void *d1, const void *d2);
+
+/****************************************************************************
+ *
+ * global variables
+ *
+ ****************************************************************************/
+
+
+/* This is user-selectable, I've set them fixed for now however */
+
+void *_sort_func = dir_alphasort;
+static int _showdotfiles = TRUE;
+
+/****************************************************************************
+ *
+ * Functions
+ *
+ ****************************************************************************/
+
+int
+dir_select_nd(
+#if defined __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory and other dot-files
+ * keep '..' however.
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name != "." else FALSE
+ */
+{
+ if (strcmp(d->d_name, ".")==0 ||
+ (d->d_name[0] == '.' && strlen(d->d_name) > 1 && d->d_name[1] != '.')) {
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+}/* dir_select_nd() */
+
+
+int
+dir_select(
+#ifdef __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name != "." else FALSE
+ */
+{
+ if (strcmp(d->d_name, ".")==0) { /* don't include the current directory */
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+} /* dir_select() */
+
+int
+dir_select_root_nd(
+#ifdef __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory and the parent directory.
+ * Also skip any other dot-files.
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name[0] != "." else FALSE
+ */
+{
+ if (d->d_name[0] == '.') { /* don't include the current directory */
+ return(FALSE); /* nor the parent directory */
+ } else {
+ return(TRUE);
+ }
+} /* dir_select_root_nd() */
+
+
+int
+dir_select_root(
+#ifdef __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory and the parent directory
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name[0] != "." else FALSE
+ */
+{
+ if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+}/* dir_select_root() */
+
+
+#ifdef NO_ALPHA_SORT
+int
+alphasort(const void *d1, const void *d2)
+/*
+ * desc: a replacement for what should be in the library
+ */
+{
+ return(strcmp(((struct dirent *) d1)->d_name,
+ ((struct dirent *) d2)->d_name));
+} /* alphasort() */
+#endif
+
+int
+dir_alphasort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2, but put directories always first
+ * put '..' always on top
+ *
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+ /* put directories first */
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ return(strcmp(f1->filename, f2->filename));
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ return(strcmp(f1->filename, f2->filename));
+
+} /* dir_alphasort() */
+
+
+int
+dir_sizesort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2, but put directories always first
+ *
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+ /* put directories first */
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ return(s1->st_size < s2->st_size ?
+ -1
+ :
+ s1->st_size >= s2->st_size);
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ return(s1->st_size < s2->st_size ?
+ -1
+ :
+ s1->st_size >= s2->st_size);
+
+} /* dir_sizesort() */
+
+int
+dir_datesort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2 on date, but put directories always first
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+ /* put directories first */
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ return(s1->st_mtime < s2->st_mtime ?
+ -1
+ :
+ s1->st_mtime >= s2->st_mtime);
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ return(s1->st_mtime < s2->st_mtime ?
+ -1
+ :
+ s1->st_mtime >= s2->st_mtime);
+
+} /* dir_datesort() */
+
+
+int
+null_strcmp(char *s1, char *s2)
+/*
+ * desc: compare strings allowing NULL pointers
+ */
+{
+ if ((s1 == NULL) && (s2 == NULL)) {
+ return(0);
+ }
+ if (s1 == NULL) {
+ return(-1);
+ }
+ if (s2 == NULL) {
+ return(1);
+ }
+ return(strcmp(s1, s2));
+} /* null_strcmp() */
+
+
+int
+dir_extsort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2 on extension, but put directories always first
+ * extension = "the characters after the last dot in the filename"
+ * pre: d1 and d2 are pointers to DirList type records
+ * post: see code
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+ char *ext1, *ext2;
+ int extf, ret;
+
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+
+ /* find the first extension */
+
+ ext1 = f1->filename + strlen(f1->filename);
+ extf = FALSE;
+ while (!extf && (ext1 > f1->filename)) {
+ extf = (*--ext1 == '.');
+ }
+ if (!extf) {
+ ext1 = NULL;
+ } else {
+ ext1++;
+ }
+ /* ext1 == NULL if there's no "extension" else ext1 points */
+ /* to the first character of the extension string */
+
+ /* find the second extension */
+
+ ext2 = f2->filename + strlen(f2->filename);
+ extf = FALSE;
+ while (!extf && (ext2 > f2->filename)) {
+ extf = (*--ext2 == '.');
+ }
+ if (!extf) {
+ ext2 = NULL;
+ } else {
+ ext2++;
+ }
+ /* idem as for ext1 */
+
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ ret = null_strcmp(ext1, ext2);
+ if (ret == 0) {
+ return(strcmp(f1->filename, f2->filename));
+ } else {
+ return(ret);
+ }
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ ret = null_strcmp(ext1, ext2);
+ if (ret == 0) {
+ return(strcmp(f1->filename, f2->filename));
+ } else {
+ return(ret);
+ }
+
+} /* dir_extsort() */
+
+
+void
+get_dir(char *dirname, char *fmask, DirList **dir, int *n)
+/*
+ * desc: get the files in the current directory
+ * pre: <dir> == NULL
+ * post: <dir> contains <n> dir-entries
+ */
+{
+ char cwd[MAXPATHLEN];
+ char buf[256];
+ struct dirent **dire;
+ struct stat status;
+ int i, j, nb;
+ long d;
+
+
+ getcwd(cwd, MAXPATHLEN);
+ if (strcmp(cwd, "/") == 0) { /* we are in the root directory */
+ if (show_dotfiles()) {
+ *n = scandir(dirname, &dire, dir_select_root, alphasort);
+ } else {
+ *n = scandir(dirname, &dire, dir_select_root_nd, alphasort);
+ }
+ } else {
+ if (show_dotfiles()) {
+ *n = scandir(dirname, &dire, dir_select, alphasort);
+ } else {
+ *n = scandir(dirname, &dire, dir_select_nd, alphasort);
+ }
+ }
+
+ /* There is the possibility that we have entered a directory */
+ /* which we are not allowed to read, scandir thus returning */
+ /* -1 for *n. */
+ /* Actually I should also check for lack of memory, but I'll */
+ /* let my application happily crash if this is the case */
+ /* Solution: */
+ /* manually insert the parent directory as the only */
+ /* directory entry, and return. */
+
+ if (*n == -1) {
+ *n = 1;
+ *dir = (DirList *) malloc(sizeof(DirList));
+ strcpy((*dir)[0].filename, "..");
+ lstat("..", &status);
+ (*dir)[0].filestatus = status;
+ (*dir)[0].link = FALSE;
+ return;
+ }
+
+ *dir = (DirList *) malloc( *n * sizeof(DirList) );
+ d = 0;
+ i = 0;
+ j = 0;
+ while (j<*n) {
+ lstat(dire[j]->d_name, &status);
+ /* check if this file is to be included */
+ /* always include directories, the rest is subject to fmask */
+ if (S_ISDIR(status.st_mode)
+ || fnmatch(fmask, dire[j]->d_name, FNM_NOESCAPE) != FNM_NOMATCH) {
+ strcpy((*dir)[i].filename, dire[j]->d_name);
+ (*dir)[i].filestatus = status;
+ if ((S_IFMT & status.st_mode) == S_IFLNK) { /* handle links */
+ (*dir)[i].link = TRUE;
+ stat(dire[j]->d_name, &status);
+ nb = readlink(dire[j]->d_name, buf, sizeof(buf) - 1);
+ if (nb == -1) {
+ printf("get_dir(): Error reading link: %s\n", dire[j]->d_name);
+ exit(-1);
+ } else {
+ (*dir)[i].linkname = malloc(sizeof(char) * nb + 1);
+ strncpy((*dir)[i].linkname, buf, nb);
+ (*dir)[i].linkname[nb] = 0;
+ }
+ (*dir)[i].filestatus = status;
+ } else {
+ (*dir)[i].link = FALSE;
+ (*dir)[i].linkname = NULL;
+ }
+ i++;
+ } else {
+ /* skip this entry */
+ }
+ j++;
+ }
+ *n = i;
+
+ /* sort the directory with the directory names on top */
+ qsort((*dir), *n, sizeof(DirList), _sort_func);
+
+ /* Free the allocated memory */
+ for (i=0; i<*n; i++) {
+ free(dire[i]);
+ }
+ free(dire);
+
+ return;
+}/* get_dir() */
+
+
+void
+FreeDir(DirList *d, int n)
+/*
+ * desc: free the dirlist d
+ * pre: d != NULL
+ * post: memory allocated to d has been released
+ */
+{
+ int i;
+
+ if (d) {
+ for (i=0; i<n; i++) {
+ if (d[i].linkname) {
+ free(d[i].linkname);
+ }
+ }
+ free(d);
+ } else {
+ printf("dir.c:FreeDir(): d == NULL\n");
+ exit(-1);
+ }
+
+ return;
+} /* FreeDir() */
+
+void
+toggle_dotfiles(void)
+/*
+ * desc: toggle visibility of dot-files
+ */
+{
+ _showdotfiles = !_showdotfiles;
+
+ return;
+} /* toggle_dotfiles() */
+
+int
+show_dotfiles(void)
+/*
+ * desc: return the value of _showdotfiles
+ */
+{
+ return(_showdotfiles);
+} /* show_dotfiles() */
+
+void
+set_dotfiles(int b)
+/*
+ * desc: set the value of _showdotfiles
+ */
+{
+ _showdotfiles = b;
+
+ return;
+} /* set_dotfiles() */
OpenPOWER on IntegriCloud