configure: SunOS /bin/sh compatibility
[cmus.git] / tabexp_file.c
blob96fb019d82ec378fa985b056aa8505f617a7f3fa
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include <tabexp_file.h>
21 #include <tabexp.h>
22 #include <load_dir.h>
23 #include <misc.h>
24 #include <xmalloc.h>
25 #include <xstrjoin.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <pwd.h>
31 #include <dirent.h>
33 static char *get_home(const char *user)
35 struct passwd *passwd;
36 char *home;
37 int len;
39 if (user[0] == 0) {
40 passwd = getpwuid(getuid());
41 } else {
42 passwd = getpwnam(user);
44 if (passwd == NULL)
45 return NULL;
46 len = strlen(passwd->pw_dir);
47 home = xnew(char, len + 2);
48 memcpy(home, passwd->pw_dir, len);
49 home[len] = '/';
50 home[len + 1] = 0;
51 return home;
54 static char *get_full_dir_name(const char *dir)
56 char *full;
58 if (dir[0] == 0) {
59 full = xstrdup("./");
60 } else if (dir[0] == '~') {
61 char *first_slash, *tmp, *home;
63 first_slash = strchr(dir, '/');
64 tmp = xstrndup(dir, first_slash - dir);
65 home = get_home(tmp + 1);
66 free(tmp);
67 if (home == NULL)
68 return NULL;
69 full = xstrjoin(home, first_slash);
70 free(home);
71 } else {
72 full = xstrdup(dir);
74 return full;
78 * load all directory entries from directory 'dir' starting with 'start' and
79 * filtered with 'filter'
81 static void tabexp_load_dir(const char *dirname, const char *start,
82 int (*filter)(const char *, const struct stat *))
84 int start_len = strlen(start);
85 struct directory dir;
86 struct stat st;
87 PTR_ARRAY(array);
88 const char *name;
89 char *full_dir_name;
91 /* tabexp is reseted */
92 full_dir_name = get_full_dir_name(dirname);
93 if (!full_dir_name)
94 return;
96 if (dir_open(&dir, full_dir_name))
97 goto out;
99 while ((name = dir_read(&dir, &st))) {
100 char *str;
102 if (!start_len) {
103 if (name[0] == '.')
104 continue;
105 } else {
106 if (strncmp(name, start, start_len))
107 continue;
110 if (!filter(name, &st))
111 continue;
113 if (S_ISDIR(st.st_mode)) {
114 int len = strlen(name);
116 str = xnew(char, len + 2);
117 memcpy(str, name, len);
118 str[len++] = '/';
119 str[len] = 0;
120 } else {
121 str = xstrdup(name);
123 ptr_array_add(&array, str);
125 if (array.count) {
126 ptr_array_sort(&array, strptrcmp);
127 ptr_array_plug(&array);
129 tabexp.head = xstrdup(dirname);
130 tabexp.tails = array.ptrs;
131 tabexp.nr_tails = array.count;
133 out:
134 free(full_dir_name);
137 void expand_files_and_dirs(const char *src,
138 int (*filter)(const char *name, const struct stat *s))
140 char *slash;
142 /* split src to dir and file */
143 slash = strrchr(src, '/');
144 if (slash) {
145 char *dir;
146 const char *file;
148 /* split */
149 dir = xstrndup(src, slash - src + 1);
150 file = slash + 1;
151 /* get all dentries starting with file from dir */
152 tabexp_load_dir(dir, file, filter);
153 free(dir);
154 } else {
155 if (src[0] == '~') {
156 char *home = get_home(src + 1);
158 if (home) {
159 tabexp.head = xstrdup("");
160 tabexp.nr_tails = 1;
161 tabexp.tails = xnew(char *, 2);
162 tabexp.tails[0] = home;
163 tabexp.tails[1] = NULL;
165 } else {
166 tabexp_load_dir("", src, filter);