#include <sys_defs.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#else
#define dirent direct
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
#endif
#include <string.h>
#include "msg.h"
#include "mymalloc.h"
#include "stringops.h"
#include "vstring.h"
#include "scan_dir.h"
typedef struct SCAN_INFO SCAN_INFO;
struct SCAN_INFO {
char *path;
DIR *dir;
SCAN_INFO *parent;
};
struct SCAN_DIR {
SCAN_INFO *current;
};
#define SCAN_DIR_PATH(scan) (scan->current->path)
#define STR(x) vstring_str(x)
char *scan_dir_path(SCAN_DIR *scan)
{
return (SCAN_DIR_PATH(scan));
}
void scan_dir_push(SCAN_DIR *scan, const char *path)
{
const char *myname = "scan_dir_push";
SCAN_INFO *info;
info = (SCAN_INFO *) mymalloc(sizeof(*info));
if (scan->current)
info->path = concatenate(SCAN_DIR_PATH(scan), "/", path, (char *) 0);
else
info->path = mystrdup(path);
if ((info->dir = opendir(info->path)) == 0)
msg_fatal("%s: open directory %s: %m", myname, info->path);
if (msg_verbose > 1)
msg_info("%s: open %s", myname, info->path);
info->parent = scan->current;
scan->current = info;
}
SCAN_DIR *scan_dir_pop(SCAN_DIR *scan)
{
const char *myname = "scan_dir_pop";
SCAN_INFO *info = scan->current;
SCAN_INFO *parent;
if (info == 0)
return (0);
parent = info->parent;
if (closedir(info->dir))
msg_fatal("%s: close directory %s: %m", myname, info->path);
if (msg_verbose > 1)
msg_info("%s: close %s", myname, info->path);
myfree(info->path);
myfree((char *) info);
scan->current = parent;
return (parent ? scan : 0);
}
SCAN_DIR *scan_dir_open(const char *path)
{
SCAN_DIR *scan;
scan = (SCAN_DIR *) mymalloc(sizeof(*scan));
scan->current = 0;
scan_dir_push(scan, path);
return (scan);
}
char *scan_dir_next(SCAN_DIR *scan)
{
const char *myname = "scan_dir_next";
SCAN_INFO *info = scan->current;
struct dirent *dp;
#define STREQ(x,y) (strcmp((x),(y)) == 0)
if (info) {
while ((dp = readdir(info->dir)) != 0) {
if (STREQ(dp->d_name, ".") || STREQ(dp->d_name, "..")) {
if (msg_verbose > 1)
msg_info("%s: skip %s", myname, dp->d_name);
continue;
} else {
if (msg_verbose > 1)
msg_info("%s: found %s", myname, dp->d_name);
return (dp->d_name);
}
}
}
return (0);
}
SCAN_DIR *scan_dir_close(SCAN_DIR *scan)
{
while (scan->current)
scan_dir_pop(scan);
myfree((char *) scan);
return (0);
}