12 #include "keymap/findfile.h"
14 void lk_fpclose(lkfile_t *fp)
25 #define SIZE(a) (sizeof(a) / sizeof(a[0]))
27 static struct decompressor {
28 const char *ext; /* starts with `.', has no other dots */
31 { ".gz", "gzip -d -c" },
32 { ".bz2", "bzip2 -d -c" },
37 pipe_open(const struct decompressor *dc, lkfile_t *fp)
41 pipe_cmd = malloc(strlen(dc->cmd) + strlen(fp->pathname) + 2);
45 sprintf(pipe_cmd, "%s %s", dc->cmd, fp->pathname);
47 fp->fd = popen(pipe_cmd, "r");
57 /* If a file PATHNAME exists, then open it.
58 If is has a `compressed' extension, then open a pipe reading it */
60 maybe_pipe_open(lkfile_t *fp)
64 struct decompressor *dc;
66 if (stat(fp->pathname, &st) == -1 || !S_ISREG(st.st_mode) ||
67 access(fp->pathname, R_OK) == -1)
70 t = strrchr(fp->pathname, '.');
72 for (dc = &decompressors[0]; dc->cmd; dc++) {
73 if (strcmp(t, dc->ext) == 0)
74 return pipe_open(dc, fp);
77 fp->fd = fopen(fp->pathname, "r");
87 findfile_by_fullname(const char *fnam, const char *const *suffixes, lkfile_t *fp)
91 struct decompressor *dc;
92 size_t fnam_len, sp_len;
95 fnam_len = strlen(fnam);
97 for (i = 0; suffixes[i]; i++) {
99 continue; /* we tried it already */
101 sp_len = strlen(suffixes[i]);
103 if (fnam_len + sp_len + 1 > sizeof(fp->pathname))
106 sprintf(fp->pathname, "%s%s", fnam, suffixes[i]);
108 if (stat(fp->pathname, &st) == 0 && S_ISREG(st.st_mode) && (fp->fd = fopen(fp->pathname, "r")) != NULL)
111 for (dc = &decompressors[0]; dc->cmd; dc++) {
112 if (fnam_len + sp_len + strlen(dc->ext) + 1 > sizeof(fp->pathname))
115 sprintf(fp->pathname, "%s%s%s", fnam, suffixes[i], dc->ext);
117 if (stat(fp->pathname, &st) == 0 && S_ISREG(st.st_mode) && access(fp->pathname, R_OK) == 0)
118 return pipe_open(dc, fp);
126 findfile_in_dir(const char *fnam, const char *dir, const int recdepth, const char *const *suf, lkfile_t *fp)
132 struct decompressor *dc;
133 int i, rc = -1, secondpass = 0;
139 if ((d = opendir(dir)) == NULL)
142 dir_len = strlen(dir);
145 if ((ff = strchr(fnam, '/')) != NULL) {
146 if ((fdir = strndup(fnam, ff - fnam)) == NULL) {
152 /* Scan the directory twice: first for files, then
153 for subdirectories, so that we do never search
154 a subdirectory when the directory itself already
155 contains the file we are looking for. */
157 while ((de = readdir(d)) != NULL) {
162 d_len = strlen(de->d_name);
164 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
168 if (dir_len + d_len + 2 > sizeof(fp->pathname))
171 okdir = (ff && strcmp(de->d_name, fdir) == 0);
173 if ((secondpass && recdepth) || okdir) {
176 if ((a = malloc(dir_len + d_len + 2)) == NULL)
179 sprintf(a, "%s/%s", dir, de->d_name);
181 if (stat(a, &st) == 0 && S_ISDIR(st.st_mode)) {
183 rc = findfile_in_dir(ff + 1, a, 0, suf, fp);
186 rc = findfile_in_dir(fnam, a, recdepth - 1, suf, fp);
199 /* Should we be in a subdirectory? */
203 /* Does d_name start right? */
206 while (*p && *p == *q)
211 sprintf(fp->pathname, "%s/%s", dir, de->d_name);
212 if (stat(fp->pathname, &st) != 0 || !S_ISREG(st.st_mode))
215 /* Does tail consist of a known suffix and possibly
216 a compression suffix? */
217 for (i = 0; suf[i]; i++) {
220 if (!strcmp(p, suf[i])) {
221 rc = maybe_pipe_open(fp);
226 if (!strncmp(p, suf[i], l)) {
227 for (dc = &decompressors[0]; dc->cmd; dc++)
228 if (strcmp(p + l, dc->ext) == 0) {
229 rc = pipe_open(dc, fp);
236 if (recdepth > 0 && !secondpass) {
249 int lk_findfile(const char *fnam, const char *const *dirpath, const char *const *suffixes, lkfile_t *fp)
252 int dl, recdepth, rc, i;
257 /* Try explicitly given name first */
258 strcpy(fp->pathname, fnam);
260 if (!maybe_pipe_open(fp))
263 /* Test for full pathname - opening it failed, so need suffix */
264 /* (This is just nonsense, for backwards compatibility.) */
266 !findfile_by_fullname(fnam, suffixes, fp))
269 /* Search a list of directories and directory hierarchies */
270 for (i = 0; dirpath[i]; i++) {
272 dl = strlen(dirpath[i]);
274 /* trailing stars denote recursion */
275 while (dl && dirpath[i][dl - 1] == '*')
278 /* delete trailing slashes */
279 while (dl && dirpath[i][dl - 1] == '/')
283 dir = strndup(dirpath[i], dl);
290 rc = findfile_in_dir(fnam, dir, recdepth, suffixes, fp);
300 lk_fpopen(const char *filename)
304 fp = malloc(sizeof(lkfile_t));
308 strcpy(fp->pathname, filename);
310 if (maybe_pipe_open(fp) < 0) {