1 /*
2 * Get full filename
3 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include <config.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <assert.h>
25
26 /**
27 * \brief Get the full file name
28 * \param file The file name string to parse
29 * \param result The pointer to store the resultant file name
30 * \return 0 if successful, or a negative error code
31 *
32 * Parses the given file name with POSIX-Shell-like expansion and
33 * stores the first matchine one. The returned string is strdup'ed.
34 */
35
36 #ifdef HAVE_WORDEXP
37 #include <wordexp.h>
snd_user_file(const char * file,char ** result)38 int snd_user_file(const char *file, char **result)
39 {
40 wordexp_t we;
41 int err;
42
43 assert(file && result);
44 err = wordexp(file, &we, WRDE_NOCMD);
45 switch (err) {
46 case WRDE_NOSPACE:
47 wordfree(&we);
48 return -ENOMEM;
49 case 0:
50 if (we.we_wordc == 1)
51 break;
52 wordfree(&we);
53 /* fall thru */
54 default:
55 return -EINVAL;
56 }
57 *result = strdup(we.we_wordv[0]);
58 wordfree(&we);
59 if (*result == NULL)
60 return -ENOMEM;
61 return 0;
62 }
63
64 #else /* !HAVE_WORDEX */
65
66 #include <sys/types.h>
67 #include <unistd.h>
68 #include <pwd.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71
snd_user_file(const char * file,char ** result)72 int snd_user_file(const char *file, char **result)
73 {
74 int err;
75 size_t len;
76 char *buf = NULL;
77
78 assert(file && result);
79 *result = NULL;
80
81 /* expand ~/ if needed */
82 if (file[0] == '~' && file[1] == '/') {
83 const char *home = getenv("HOME");
84 if (home == NULL) {
85 struct passwd pwent, *p = NULL;
86 uid_t id = getuid();
87 size_t bufsize = 1024;
88
89 buf = malloc(bufsize);
90 if (buf == NULL)
91 goto out;
92
93 while ((err = getpwuid_r(id, &pwent, buf, bufsize, &p)) == ERANGE) {
94 char *newbuf;
95 bufsize += 1024;
96 if (bufsize < 1024)
97 break;
98 newbuf = realloc(buf, bufsize);
99 if (newbuf == NULL)
100 goto out;
101 buf = newbuf;
102 }
103 home = err ? "" : pwent.pw_dir;
104 }
105 len = strlen(home) + strlen(&file[2]) + 2;
106 *result = malloc(len);
107 if (*result)
108 snprintf(*result, len, "%s/%s", home, &file[2]);
109 } else {
110 *result = strdup(file);
111 }
112
113 out:
114 if (buf)
115 free(buf);
116
117 if (*result == NULL)
118 return -ENOMEM;
119 return 0;
120 }
121
122 #endif /* HAVE_WORDEXP */
123