2 * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/types.h>
39 #include "cmdline_parse.h"
40 #include "cmdline_parse_file.h"
42 struct cmdline_complete_file_callback {
48 cmdline_parse_file(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
51 struct cmdline_token_file *tk2 = (struct cmdline_token_file *)tk;
52 struct cmdline_token_file_data *sd = &tk2->file_data;;
53 unsigned int token_len;
58 if (res && ressize < FILENAME_SIZE)
61 token_len = strlen(buf);
62 if (token_len >= (FILENAME_SIZE - 1) || token_len == 0)
67 if (flags & PARSE_FILE_F_CREATE) {
68 /* the directory must exist */
71 ret = stat(dname, &st);
73 ret = lstat(dname, &st);
77 if (!S_ISDIR(st.st_mode))
84 if (flags & PARSE_FILE_F_DIRECTORY)
85 if (!S_ISDIR(st.st_mode))
89 /* we already checked that token_len is < FILENAME_SIZE-1 */
97 * This function is quite similar to dirname(3) except that:
98 * - it allocates the returned string and don't modify the argument
99 * - the result of dirname2() is not exactly the same than dirname()
104 * "usr" "." or "" if allow_empty == 1
105 * "" "." or "" if allow_empty == 1
107 * "." "." or "" if allow_empty == 1
109 * ".." "." or "" if allow_empty == 1
113 dirname2(const char *path, int allow_empty)
120 if (len == 0 && allow_empty == 0) {
126 last_slash = strrchr(s, '/');
127 if (last_slash == NULL) {
133 else if (last_slash == s)
143 cmdline_complete_file_start(cmdline_parse_token_hdr_t *tk,
144 const char *tokstr, void **opaque)
147 struct cmdline_complete_file_callback *cb;
150 cb = malloc(sizeof(*cb));
153 memset(cb, 0, sizeof(*cb));
156 cb->token = strdup(tokstr);
157 /* we need to copy again tokstr because dirname() alters the string */
158 dname = dirname2(tokstr, 0);
159 cb->dir = opendir(dname);
169 cmdline_complete_file_iterate(cmdline_parse_token_hdr_t *tk, void **opaque,
170 char *dstbuf, unsigned int size)
172 struct cmdline_token_file *tk2 = (struct cmdline_token_file *)tk;
173 struct cmdline_token_file_data *sd = &tk2->file_data;
174 struct cmdline_complete_file_callback *cb;
179 int need_join_slash = 1;
180 int flags = sd->flags;
183 /* read next dir name, skipping "." and ".." */
185 de = readdir(cb->dir);
188 if (strcmp(de->d_name, ".") == 0 ||
189 strcmp(de->d_name, "..") == 0)
193 /* do we need a / to join dirname and basename ? */
194 dname = dirname2(cb->token, 1);
196 if (len == 0 || dname[len - 1] == '/')
199 /* keep one byte for potential '/' */
200 len = snprintf(dstbuf, size-1, "%s%s%s", dname,
201 need_join_slash ? "/" : "", de->d_name);
203 if (len < 0 || len >= size-1)
206 /* append '/' if it's a directory */
207 if (stat(dstbuf, &st) != 0) {
208 if (lstat(dstbuf, &st) != 0)
211 if (S_ISDIR(st.st_mode)) {
213 return 1; /* intermediate completion */
215 /* skip non-directories */
216 else if (flags & PARSE_FILE_F_DIRECTORY)
225 cmdline_complete_file_end(cmdline_parse_token_hdr_t *tk, void **opaque)
227 struct cmdline_complete_file_callback *cb;
244 cmdline_help_file(cmdline_parse_token_hdr_t *tk, char *dstbuf,
247 struct cmdline_token_file *tk2 = (struct cmdline_token_file *)tk;
248 struct cmdline_token_file_data *sd = &tk2->file_data;;
252 if (flags & PARSE_FILE_F_DIRECTORY)
253 snprintf(dstbuf, size, "DIR");
255 snprintf(dstbuf, size, "FILE");
260 struct cmdline_token_ops cmdline_token_file_ops = {
261 .parse = cmdline_parse_file,
262 .complete_start = cmdline_complete_file_start,
263 .complete_iterate = cmdline_complete_file_iterate,
264 .complete_end = cmdline_complete_file_end,
265 .help = cmdline_help_file,