Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / scan_dir.c
blobd9ea107a8d056a03a6d4a8fafca69feaff38811a
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* scan_dir 3
6 /* SUMMARY
7 /* directory scanning
8 /* SYNOPSIS
9 /* #include <scan_dir.h>
11 /* SCAN_DIR *scan_dir_open(path)
12 /* const char *path;
14 /* char *scan_dir_next(scan)
15 /* SCAN_DIR *scan;
17 /* char *scan_dir_path(scan)
18 /* SCAN_DIR *scan;
20 /* void scan_push(scan, entry)
21 /* SCAN_DIR *scan;
22 /* const char *entry;
24 /* SCAN_DIR *scan_pop(scan)
25 /* SCAN_DIR *scan;
27 /* SCAN_DIR *scan_dir_close(scan)
28 /* SCAN_DIR *scan;
29 /* DESCRIPTION
30 /* These functions scan directories for names. The "." and
31 /* ".." names are skipped. Essentially, this is <dirent>
32 /* extended with error handling and with knowledge of the
33 /* name of the directory being scanned.
35 /* scan_dir_open() opens the named directory and
36 /* returns a handle for subsequent use.
38 /* scan_dir_close() terminates the directory scan, cleans up
39 /* and returns a null pointer.
41 /* scan_dir_next() returns the next requested object in the specified
42 /* directory. It skips the "." and ".." entries.
44 /* scan_dir_path() returns the name of the directory being scanned.
46 /* scan_dir_push() causes the specified directory scan to enter the
47 /* named subdirectory.
49 /* scan_dir_pop() leaves the directory being scanned and returns
50 /* to the previous one. The result is the argument, null if no
51 /* previous directory information is available.
52 /* DIAGNOSTICS
53 /* All errors are fatal.
54 /* LICENSE
55 /* .ad
56 /* .fi
57 /* The Secure Mailer license must be distributed with this software.
58 /* AUTHOR(S)
59 /* Wietse Venema
60 /* IBM T.J. Watson Research
61 /* P.O. Box 704
62 /* Yorktown Heights, NY 10598, USA
63 /*--*/
65 /* System library. */
67 #include <sys_defs.h>
68 #ifdef HAVE_DIRENT_H
69 #include <dirent.h>
70 #else
71 #define dirent direct
72 #ifdef HAVE_SYS_NDIR_H
73 #include <sys/ndir.h>
74 #endif
75 #ifdef HAVE_SYS_DIR_H
76 #include <sys/dir.h>
77 #endif
78 #ifdef HAVE_NDIR_H
79 #include <ndir.h>
80 #endif
81 #endif
82 #include <string.h>
84 /* Utility library. */
86 #include "msg.h"
87 #include "mymalloc.h"
88 #include "stringops.h"
89 #include "vstring.h"
90 #include "scan_dir.h"
93 * The interface is based on an opaque structure, so we don't have to expose
94 * the user to the guts. Subdirectory info sits in front of parent directory
95 * info: a simple last-in, first-out list.
97 typedef struct SCAN_INFO SCAN_INFO;
99 struct SCAN_INFO {
100 char *path; /* directory name */
101 DIR *dir; /* directory structure */
102 SCAN_INFO *parent; /* linkage */
104 struct SCAN_DIR {
105 SCAN_INFO *current; /* current scan */
108 #define SCAN_DIR_PATH(scan) (scan->current->path)
109 #define STR(x) vstring_str(x)
111 /* scan_dir_path - return the path of the directory being read. */
113 char *scan_dir_path(SCAN_DIR *scan)
115 return (SCAN_DIR_PATH(scan));
118 /* scan_dir_push - enter directory */
120 void scan_dir_push(SCAN_DIR *scan, const char *path)
122 const char *myname = "scan_dir_push";
123 SCAN_INFO *info;
125 info = (SCAN_INFO *) mymalloc(sizeof(*info));
126 if (scan->current)
127 info->path = concatenate(SCAN_DIR_PATH(scan), "/", path, (char *) 0);
128 else
129 info->path = mystrdup(path);
130 if ((info->dir = opendir(info->path)) == 0)
131 msg_fatal("%s: open directory %s: %m", myname, info->path);
132 if (msg_verbose > 1)
133 msg_info("%s: open %s", myname, info->path);
134 info->parent = scan->current;
135 scan->current = info;
138 /* scan_dir_pop - leave directory */
140 SCAN_DIR *scan_dir_pop(SCAN_DIR *scan)
142 const char *myname = "scan_dir_pop";
143 SCAN_INFO *info = scan->current;
144 SCAN_INFO *parent;
146 if (info == 0)
147 return (0);
148 parent = info->parent;
149 if (closedir(info->dir))
150 msg_fatal("%s: close directory %s: %m", myname, info->path);
151 if (msg_verbose > 1)
152 msg_info("%s: close %s", myname, info->path);
153 myfree(info->path);
154 myfree((char *) info);
155 scan->current = parent;
156 return (parent ? scan : 0);
159 /* scan_dir_open - start directory scan */
161 SCAN_DIR *scan_dir_open(const char *path)
163 SCAN_DIR *scan;
165 scan = (SCAN_DIR *) mymalloc(sizeof(*scan));
166 scan->current = 0;
167 scan_dir_push(scan, path);
168 return (scan);
171 /* scan_dir_next - find next entry */
173 char *scan_dir_next(SCAN_DIR *scan)
175 const char *myname = "scan_dir_next";
176 SCAN_INFO *info = scan->current;
177 struct dirent *dp;
179 #define STREQ(x,y) (strcmp((x),(y)) == 0)
181 if (info) {
182 while ((dp = readdir(info->dir)) != 0) {
183 if (STREQ(dp->d_name, ".") || STREQ(dp->d_name, "..")) {
184 if (msg_verbose > 1)
185 msg_info("%s: skip %s", myname, dp->d_name);
186 continue;
187 } else {
188 if (msg_verbose > 1)
189 msg_info("%s: found %s", myname, dp->d_name);
190 return (dp->d_name);
194 return (0);
197 /* scan_dir_close - terminate directory scan */
199 SCAN_DIR *scan_dir_close(SCAN_DIR *scan)
201 while (scan->current)
202 scan_dir_pop(scan);
203 myfree((char *) scan);
204 return (0);