Handle streams separately in tree_add_track()
[cmus.git] / tabexp_file.c
blobdb64fd83fa3fa3df3db888f2a8f741c601d5ec4f
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 PTR_ARRAY(array);
87 const char *name;
88 char *full_dir_name;
90 /* tabexp is reseted */
91 full_dir_name = get_full_dir_name(dirname);
92 if (!full_dir_name)
93 return;
95 if (dir_open(&dir, full_dir_name))
96 goto out;
98 while ((name = dir_read(&dir))) {
99 char *str;
101 if (!start_len) {
102 if (name[0] == '.')
103 continue;
104 } else {
105 if (strncmp(name, start, start_len))
106 continue;
109 if (!filter(name, &dir.st))
110 continue;
112 if (S_ISDIR(dir.st.st_mode)) {
113 int len = strlen(name);
115 str = xnew(char, len + 2);
116 memcpy(str, name, len);
117 str[len++] = '/';
118 str[len] = 0;
119 } else {
120 str = xstrdup(name);
122 ptr_array_add(&array, str);
124 dir_close(&dir);
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;
132 out:
133 free(full_dir_name);
136 void expand_files_and_dirs(const char *src,
137 int (*filter)(const char *name, const struct stat *s))
139 char *slash;
141 /* split src to dir and file */
142 slash = strrchr(src, '/');
143 if (slash) {
144 char *dir;
145 const char *file;
147 /* split */
148 dir = xstrndup(src, slash - src + 1);
149 file = slash + 1;
150 /* get all dentries starting with file from dir */
151 tabexp_load_dir(dir, file, filter);
152 free(dir);
153 } else {
154 if (src[0] == '~') {
155 char *home = get_home(src + 1);
157 if (home) {
158 tabexp.head = xstrdup("");
159 tabexp.tails = xnew(char *, 2);
160 tabexp.tails[0] = home;
161 tabexp.tails[1] = NULL;
163 } else {
164 tabexp_load_dir("", src, filter);