File: | src/gnu/usr.bin/cvs/src/expand_path.c |
Warning: | line 149, column 3 Value stored to 'd' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* expand_path.c -- expand environmental variables in passed in string |
2 | * |
3 | * The main routine is expand_path(), it is the routine that handles |
4 | * the '~' character in four forms: |
5 | * ~name |
6 | * ~name/ |
7 | * ~/ |
8 | * ~ |
9 | * and handles environment variables contained within the pathname |
10 | * which are defined by: |
11 | * ${var_name} (var_name is the name of the environ variable) |
12 | * $var_name (var_name ends w/ non-alphanumeric char other than '_') |
13 | */ |
14 | |
15 | #include "cvs.h" |
16 | #include <sys/types.h> |
17 | |
18 | static char *expand_variable PROTO((char *env, char *file, int line))(char *env, char *file, int line); |
19 | |
20 | |
21 | /* User variables. */ |
22 | |
23 | List *variable_list = NULL((void*)0); |
24 | |
25 | static void variable_delproc PROTO ((Node *))(Node *); |
26 | |
27 | static void |
28 | variable_delproc (node) |
29 | Node *node; |
30 | { |
31 | free (node->data); |
32 | } |
33 | |
34 | /* Currently used by -s option; we might want a way to set user |
35 | variables in a file in the $CVSROOT/CVSROOT directory too. */ |
36 | |
37 | void |
38 | variable_set (nameval) |
39 | char *nameval; |
40 | { |
41 | char *p; |
42 | char *name; |
43 | Node *node; |
44 | |
45 | p = nameval; |
46 | while (isalnum ((unsigned char) *p) || *p == '_') |
47 | ++p; |
48 | if (*p != '=') |
49 | error (1, 0, "illegal character in user variable name in %s", nameval); |
50 | if (p == nameval) |
51 | error (1, 0, "empty user variable name in %s", nameval); |
52 | name = xmalloc (p - nameval + 1); |
53 | strncpy (name, nameval, p - nameval); |
54 | name[p - nameval] = '\0'; |
55 | /* Make p point to the value. */ |
56 | ++p; |
57 | if (strchr (p, '\012') != NULL((void*)0)) |
58 | error (1, 0, "linefeed in user variable value in %s", nameval); |
59 | |
60 | if (variable_list == NULL((void*)0)) |
61 | variable_list = getlist (); |
62 | |
63 | node = findnode (variable_list, name); |
64 | if (node == NULL((void*)0)) |
65 | { |
66 | node = getnode (); |
67 | node->type = VARIABLE; |
68 | node->delproc = variable_delproc; |
69 | node->key = name; |
70 | node->data = xstrdup (p); |
71 | (void) addnode (variable_list, node); |
72 | } |
73 | else |
74 | { |
75 | /* Replace the old value. For example, this means that -s |
76 | options on the command line override ones from .cvsrc. */ |
77 | free (node->data); |
78 | node->data = xstrdup (p); |
79 | free (name); |
80 | } |
81 | } |
82 | |
83 | /* This routine will expand the pathname to account for ~ and $ |
84 | characters as described above. Returns a pointer to a newly |
85 | malloc'd string. If an error occurs, an error message is printed |
86 | via error() and NULL is returned. FILE and LINE are the filename |
87 | and linenumber to include in the error message. FILE must point |
88 | to something; LINE can be zero to indicate the line number is not |
89 | known. */ |
90 | char * |
91 | expand_path (name, file, line) |
92 | char *name; |
93 | char *file; |
94 | int line; |
95 | { |
96 | char *s; |
97 | char *d; |
98 | |
99 | char *mybuf = NULL((void*)0); |
100 | size_t mybuf_size = 0; |
101 | char *buf = NULL((void*)0); |
102 | size_t buf_size = 0; |
103 | |
104 | size_t doff; |
105 | |
106 | char *result; |
107 | |
108 | /* Sorry this routine is so ugly; it is a head-on collision |
109 | between the `traditional' unix *d++ style and the need to |
110 | dynamically allocate. It would be much cleaner (and probably |
111 | faster, not that this is a bottleneck for CVS) with more use of |
112 | strcpy & friends, but I haven't taken the effort to rewrite it |
113 | thusly. */ |
114 | |
115 | /* First copy from NAME to MYBUF, expanding $<foo> as we go. */ |
116 | s = name; |
117 | d = mybuf; |
118 | doff = d - mybuf; |
119 | expand_string (&mybuf, &mybuf_size, doff + 1); |
120 | d = mybuf + doff; |
121 | while ((*d++ = *s)) |
122 | { |
123 | if (*s++ == '$') |
124 | { |
125 | char *p = d; |
126 | char *e; |
127 | int flag = (*s == '{'); |
128 | |
129 | doff = d - mybuf; |
130 | expand_string (&mybuf, &mybuf_size, doff + 1); |
131 | d = mybuf + doff; |
132 | for (; (*d++ = *s); s++) |
133 | { |
134 | if (flag |
135 | ? *s =='}' |
136 | : isalnum ((unsigned char) *s) == 0 && *s != '_') |
137 | break; |
138 | doff = d - mybuf; |
139 | expand_string (&mybuf, &mybuf_size, doff + 1); |
140 | d = mybuf + doff; |
141 | } |
142 | *--d = '\0'; |
143 | e = expand_variable (&p[flag], file, line); |
144 | |
145 | if (e) |
146 | { |
147 | doff = d - mybuf; |
148 | expand_string (&mybuf, &mybuf_size, doff + 1); |
149 | d = mybuf + doff; |
Value stored to 'd' is never read | |
150 | for (d = &p[-1]; (*d++ = *e++);) |
151 | { |
152 | doff = d - mybuf; |
153 | expand_string (&mybuf, &mybuf_size, doff + 1); |
154 | d = mybuf + doff; |
155 | } |
156 | --d; |
157 | if (flag && *s) |
158 | s++; |
159 | } |
160 | else |
161 | /* expand_variable has already printed an error message. */ |
162 | goto error_exit; |
163 | } |
164 | doff = d - mybuf; |
165 | expand_string (&mybuf, &mybuf_size, doff + 1); |
166 | d = mybuf + doff; |
167 | } |
168 | doff = d - mybuf; |
169 | expand_string (&mybuf, &mybuf_size, doff + 1); |
170 | d = mybuf + doff; |
171 | *d = '\0'; |
172 | |
173 | /* Then copy from MYBUF to BUF, expanding ~. */ |
174 | s = mybuf; |
175 | d = buf; |
176 | /* If you don't want ~username ~/ to be expanded simply remove |
177 | * This entire if statement including the else portion |
178 | */ |
179 | if (*s++ == '~') |
180 | { |
181 | char *t; |
182 | char *p=s; |
183 | if (*s=='/' || *s==0) |
184 | t = get_homedir (); |
185 | else |
186 | { |
187 | #ifdef GETPWNAM_MISSING |
188 | for (; *p!='/' && *p; p++) |
189 | ; |
190 | *p = 0; |
191 | if (line != 0) |
192 | error (0, 0, |
193 | "%s:%d:tilde expansion not supported on this system", |
194 | file, line); |
195 | else |
196 | error (0, 0, "%s:tilde expansion not supported on this system", |
197 | file); |
198 | return NULL((void*)0); |
199 | #else |
200 | struct passwd *ps; |
201 | for (; *p!='/' && *p; p++) |
202 | ; |
203 | *p = 0; |
204 | ps = getpwnam (s); |
205 | if (ps == 0) |
206 | { |
207 | if (line != 0) |
208 | error (0, 0, "%s:%d: no such user %s", |
209 | file, line, s); |
210 | else |
211 | error (0, 0, "%s: no such user %s", file, s); |
212 | return NULL((void*)0); |
213 | } |
214 | t = ps->pw_dir; |
215 | #endif |
216 | } |
217 | if (t == NULL((void*)0)) |
218 | error (1, 0, "cannot find home directory"); |
219 | |
220 | doff = d - buf; |
221 | expand_string (&buf, &buf_size, doff + 1); |
222 | d = buf + doff; |
223 | while ((*d++ = *t++)) |
224 | { |
225 | doff = d - buf; |
226 | expand_string (&buf, &buf_size, doff + 1); |
227 | d = buf + doff; |
228 | } |
229 | --d; |
230 | if (*p == 0) |
231 | *p = '/'; /* always add / */ |
232 | s=p; |
233 | } |
234 | else |
235 | --s; |
236 | /* Kill up to here */ |
237 | doff = d - buf; |
238 | expand_string (&buf, &buf_size, doff + 1); |
239 | d = buf + doff; |
240 | while ((*d++ = *s++)) |
241 | { |
242 | doff = d - buf; |
243 | expand_string (&buf, &buf_size, doff + 1); |
244 | d = buf + doff; |
245 | } |
246 | doff = d - buf; |
247 | expand_string (&buf, &buf_size, doff + 1); |
248 | d = buf + doff; |
249 | *d = '\0'; |
250 | |
251 | /* OK, buf contains the value we want to return. Clean up and return |
252 | it. */ |
253 | free (mybuf); |
254 | /* Save a little memory with xstrdup; buf will tend to allocate |
255 | more than it needs to. */ |
256 | result = xstrdup (buf); |
257 | free (buf); |
258 | return result; |
259 | |
260 | error_exit: |
261 | if (mybuf != NULL((void*)0)) |
262 | free (mybuf); |
263 | if (buf != NULL((void*)0)) |
264 | free (buf); |
265 | return NULL((void*)0); |
266 | } |
267 | |
268 | static char * |
269 | expand_variable (name, file, line) |
270 | char *name; |
271 | char *file; |
272 | int line; |
273 | { |
274 | if (strcmp (name, CVSROOT_ENV"CVSROOT") == 0) |
275 | return current_parsed_root->original; |
276 | else if (strcmp (name, "RCSBIN") == 0) |
277 | { |
278 | error (0, 0, "RCSBIN internal variable is no longer supported"); |
279 | return NULL((void*)0); |
280 | } |
281 | else if (strcmp (name, EDITOR1_ENV"CVSEDITOR") == 0) |
282 | return Editor; |
283 | else if (strcmp (name, EDITOR2_ENV"VISUAL") == 0) |
284 | return Editor; |
285 | else if (strcmp (name, EDITOR3_ENV"EDITOR") == 0) |
286 | return Editor; |
287 | else if (strcmp (name, "USER") == 0) |
288 | return getcaller (); |
289 | else if (strcmp (name, "SESSIONID") == 0 || strcmp (name, "COMMITID") == 0) |
290 | return global_session_id; |
291 | else if (isalpha ((unsigned char) name[0])) |
292 | { |
293 | /* These names are reserved for future versions of CVS, |
294 | so that is why it is an error. */ |
295 | if (line != 0) |
296 | error (0, 0, "%s:%d: no such internal variable $%s", |
297 | file, line, name); |
298 | else |
299 | error (0, 0, "%s: no such internal variable $%s", |
300 | file, name); |
301 | return NULL((void*)0); |
302 | } |
303 | else if (name[0] == '=') |
304 | { |
305 | Node *node; |
306 | /* Crazy syntax for a user variable. But we want |
307 | *something* that lets the user name a user variable |
308 | anything he wants, without interference from |
309 | (existing or future) internal variables. */ |
310 | node = findnode (variable_list, name + 1); |
311 | if (node == NULL((void*)0)) |
312 | { |
313 | if (line != 0) |
314 | error (0, 0, "%s:%d: no such user variable ${%s}", |
315 | file, line, name); |
316 | else |
317 | error (0, 0, "%s: no such user variable ${%s}", |
318 | file, name); |
319 | return NULL((void*)0); |
320 | } |
321 | return node->data; |
322 | } |
323 | else |
324 | { |
325 | /* It is an unrecognized character. We return an error to |
326 | reserve these for future versions of CVS; it is plausible |
327 | that various crazy syntaxes might be invented for inserting |
328 | information about revisions, branches, etc. */ |
329 | if (line != 0) |
330 | error (0, 0, "%s:%d: unrecognized variable syntax %s", |
331 | file, line, name); |
332 | else |
333 | error (0, 0, "%s: unrecognized variable syntax %s", |
334 | file, name); |
335 | return NULL((void*)0); |
336 | } |
337 | } |