/src/gnupg/common/stringhelp.c
Line | Count | Source |
1 | | /* stringhelp.c - standard string helper functions |
2 | | * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, |
3 | | * 2008, 2009, 2010 Free Software Foundation, Inc. |
4 | | * Copyright (C) 2014 Werner Koch |
5 | | * Copyright (C) 2015, 2021, 2025 g10 Code GmbH |
6 | | * |
7 | | * This file is part of GnuPG. |
8 | | * |
9 | | * GnuPG is free software; you can redistribute and/or modify this |
10 | | * part of GnuPG under the terms of either |
11 | | * |
12 | | * - the GNU Lesser General Public License as published by the Free |
13 | | * Software Foundation; either version 3 of the License, or (at |
14 | | * your option) any later version. |
15 | | * |
16 | | * or |
17 | | * |
18 | | * - the GNU General Public License as published by the Free |
19 | | * Software Foundation; either version 2 of the License, or (at |
20 | | * your option) any later version. |
21 | | * |
22 | | * or both in parallel, as here. |
23 | | * |
24 | | * GnuPG is distributed in the hope that it will be useful, but |
25 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
27 | | * General Public License for more details. |
28 | | * |
29 | | * You should have received a copies of the GNU General Public License |
30 | | * and the GNU Lesser General Public License along with this program; |
31 | | * if not, see <https://www.gnu.org/licenses/>. |
32 | | * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later) |
33 | | */ |
34 | | |
35 | | #include <config.h> |
36 | | #include <stdlib.h> |
37 | | #include <string.h> |
38 | | #include <stdarg.h> |
39 | | #include <ctype.h> |
40 | | #include <errno.h> |
41 | | #ifdef HAVE_PWD_H |
42 | | # include <pwd.h> |
43 | | #endif |
44 | | #include <unistd.h> |
45 | | #include <sys/types.h> |
46 | | #ifdef HAVE_W32_SYSTEM |
47 | | # ifdef HAVE_WINSOCK2_H |
48 | | # include <winsock2.h> |
49 | | # endif |
50 | | # include <windows.h> |
51 | | #endif |
52 | | #include <limits.h> |
53 | | |
54 | | #include "util.h" |
55 | | #include "common-defs.h" |
56 | | #include "utf8conv.h" |
57 | | #include "sysutils.h" |
58 | | #include "stringhelp.h" |
59 | | |
60 | 0 | #define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a')) |
61 | | |
62 | | |
63 | | /* Sometimes we want to avoid mixing slashes and backslashes on W32 |
64 | | and prefer backslashes. There is usual no problem with mixing |
65 | | them, however a very few W32 API calls can't grok plain slashes. |
66 | | Printing filenames with mixed slashes also looks a bit strange. |
67 | | This function has no effext on POSIX. */ |
68 | | static inline char * |
69 | | change_slashes (char *name) |
70 | 5 | { |
71 | | #ifdef HAVE_DOSISH_SYSTEM |
72 | | char *p; |
73 | | |
74 | | if (windows_semihosted_by_wine) |
75 | | return name; |
76 | | |
77 | | if (strchr (name, '\\')) |
78 | | { |
79 | | for (p=name; *p; p++) |
80 | | if (*p == '/') |
81 | | *p = '\\'; |
82 | | } |
83 | | #endif /*HAVE_DOSISH_SYSTEM*/ |
84 | 5 | return name; |
85 | 5 | } |
86 | | |
87 | | |
88 | | /* |
89 | | * Check whether STRING starts with KEYWORD. The keyword is |
90 | | * delimited by end of string, a space or a tab. Returns NULL if not |
91 | | * found or a pointer into STRING to the next non-space character |
92 | | * after the KEYWORD (which may be end of string). |
93 | | */ |
94 | | char * |
95 | | has_leading_keyword (const char *string, const char *keyword) |
96 | 0 | { |
97 | 0 | size_t n = strlen (keyword); |
98 | |
|
99 | 0 | if (!strncmp (string, keyword, n) |
100 | 0 | && (!string[n] || string[n] == ' ' || string[n] == '\t')) |
101 | 0 | { |
102 | 0 | string += n; |
103 | 0 | while (*string == ' ' || *string == '\t') |
104 | 0 | string++; |
105 | 0 | return (char*)string; |
106 | 0 | } |
107 | 0 | return NULL; |
108 | 0 | } |
109 | | |
110 | | |
111 | | /* |
112 | | * Look for the substring SUB in buffer and return a pointer to that |
113 | | * substring in BUFFER or NULL if not found. |
114 | | * Comparison is case-insensitive. |
115 | | */ |
116 | | const char * |
117 | | memistr (const void *buffer, size_t buflen, const char *sub) |
118 | 0 | { |
119 | 0 | const unsigned char *buf = buffer; |
120 | 0 | const unsigned char *t = (const unsigned char *)buffer; |
121 | 0 | const unsigned char *s = (const unsigned char *)sub; |
122 | 0 | size_t n = buflen; |
123 | |
|
124 | 0 | for ( ; n ; t++, n-- ) |
125 | 0 | { |
126 | 0 | if ( toupper (*t) == toupper (*s) ) |
127 | 0 | { |
128 | 0 | for ( buf=t++, buflen = n--, s++; |
129 | 0 | n && toupper (*t) == toupper (*s); t++, s++, n-- ) |
130 | 0 | ; |
131 | 0 | if (!*s) |
132 | 0 | return (const char*)buf; |
133 | 0 | t = buf; |
134 | 0 | s = (const unsigned char *)sub ; |
135 | 0 | n = buflen; |
136 | 0 | } |
137 | 0 | } |
138 | 0 | return NULL; |
139 | 0 | } |
140 | | |
141 | | const char * |
142 | | ascii_memistr ( const void *buffer, size_t buflen, const char *sub ) |
143 | 0 | { |
144 | 0 | const unsigned char *buf = buffer; |
145 | 0 | const unsigned char *t = (const unsigned char *)buf; |
146 | 0 | const unsigned char *s = (const unsigned char *)sub; |
147 | 0 | size_t n = buflen; |
148 | |
|
149 | 0 | for ( ; n ; t++, n-- ) |
150 | 0 | { |
151 | 0 | if (ascii_toupper (*t) == ascii_toupper (*s) ) |
152 | 0 | { |
153 | 0 | for ( buf=t++, buflen = n--, s++; |
154 | 0 | n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- ) |
155 | 0 | ; |
156 | 0 | if (!*s) |
157 | 0 | return (const char*)buf; |
158 | 0 | t = (const unsigned char *)buf; |
159 | 0 | s = (const unsigned char *)sub ; |
160 | 0 | n = buflen; |
161 | 0 | } |
162 | 0 | } |
163 | 0 | return NULL; |
164 | 0 | } |
165 | | |
166 | | |
167 | | /* This is a case-sensitive version of our memistr. I wonder why no |
168 | | * standard function memstr exists but we better do not use the name |
169 | | * memstr to avoid future conflicts. |
170 | | */ |
171 | | const char * |
172 | | gnupg_memstr (const void *buffer, size_t buflen, const char *sub) |
173 | 1.02k | { |
174 | 1.02k | const unsigned char *buf = buffer; |
175 | 1.02k | const unsigned char *t = (const unsigned char *)buf; |
176 | 1.02k | const unsigned char *s = (const unsigned char *)sub; |
177 | 1.02k | size_t n = buflen; |
178 | | |
179 | 3.61k | for ( ; n ; t++, n-- ) |
180 | 3.33k | { |
181 | 3.33k | if (*t == *s) |
182 | 1.30k | { |
183 | 2.05k | for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--) |
184 | 750 | ; |
185 | 1.30k | if (!*s) |
186 | 750 | return (const char*)buf; |
187 | 552 | t = (const unsigned char *)buf; |
188 | 552 | s = (const unsigned char *)sub ; |
189 | 552 | n = buflen; |
190 | 552 | } |
191 | 3.33k | } |
192 | 278 | return NULL; |
193 | 1.02k | } |
194 | | |
195 | | |
196 | | /* This function is similar to strncpy(). However it won't copy more |
197 | | * than N - 1 characters and makes sure that a '\0' is appended. With |
198 | | * N given as 0, nothing will happen. With DEST given as NULL, memory |
199 | | * will be allocated using xmalloc (i.e. if it runs out of core the |
200 | | * function terminates). Returns DEST or a pointer to the allocated |
201 | | * memory. |
202 | | */ |
203 | | char * |
204 | | mem2str (char *dest, const void *src, size_t n) |
205 | 74.7k | { |
206 | 74.7k | char *d; |
207 | 74.7k | const char *s; |
208 | | |
209 | 74.7k | if (n) |
210 | 74.7k | { |
211 | 74.7k | if (!dest) |
212 | 0 | dest = xmalloc (n); |
213 | 74.7k | d = dest; |
214 | 74.7k | s = src ; |
215 | 1.56M | for (n--; n && *s; n--) |
216 | 1.49M | *d++ = *s++; |
217 | 74.7k | *d = '\0' ; |
218 | 74.7k | } |
219 | | |
220 | 74.7k | return dest; |
221 | 74.7k | } |
222 | | |
223 | | |
224 | | /**************** |
225 | | * remove leading and trailing white spaces |
226 | | */ |
227 | | char * |
228 | | trim_spaces( char *str ) |
229 | 0 | { |
230 | 0 | char *string, *p, *mark; |
231 | |
|
232 | 0 | string = str; |
233 | | /* find first non space character */ |
234 | 0 | for( p=string; *p && isspace( *(byte*)p ) ; p++ ) |
235 | 0 | ; |
236 | | /* move characters */ |
237 | 0 | for( (mark = NULL); (*string = *p); string++, p++ ) |
238 | 0 | if( isspace( *(byte*)p ) ) { |
239 | 0 | if( !mark ) |
240 | 0 | mark = string ; |
241 | 0 | } |
242 | 0 | else |
243 | 0 | mark = NULL ; |
244 | 0 | if( mark ) |
245 | 0 | *mark = '\0' ; /* remove trailing spaces */ |
246 | |
|
247 | 0 | return str ; |
248 | 0 | } |
249 | | |
250 | | |
251 | | /* Same as trim_spaces but only consider, space, tab, cr and lf as space. */ |
252 | | char * |
253 | | ascii_trim_spaces (char *str) |
254 | 0 | { |
255 | 0 | char *string, *p, *mark; |
256 | |
|
257 | 0 | string = str; |
258 | | |
259 | | /* Find first non-ascii space character. */ |
260 | 0 | for (p=string; *p && ascii_isspace (*p); p++) |
261 | 0 | ; |
262 | | /* Move characters. */ |
263 | 0 | for (mark=NULL; (*string = *p); string++, p++ ) |
264 | 0 | { |
265 | 0 | if (ascii_isspace (*p)) |
266 | 0 | { |
267 | 0 | if (!mark) |
268 | 0 | mark = string; |
269 | 0 | } |
270 | 0 | else |
271 | 0 | mark = NULL ; |
272 | 0 | } |
273 | 0 | if (mark) |
274 | 0 | *mark = '\0' ; /* Remove trailing spaces. */ |
275 | |
|
276 | 0 | return str ; |
277 | 0 | } |
278 | | |
279 | | |
280 | | /**************** |
281 | | * remove trailing white spaces |
282 | | */ |
283 | | char * |
284 | | trim_trailing_spaces( char *string ) |
285 | 0 | { |
286 | 0 | char *p, *mark; |
287 | |
|
288 | 0 | for( mark = NULL, p = string; *p; p++ ) { |
289 | 0 | if( isspace( *(byte*)p ) ) { |
290 | 0 | if( !mark ) |
291 | 0 | mark = p; |
292 | 0 | } |
293 | 0 | else |
294 | 0 | mark = NULL; |
295 | 0 | } |
296 | 0 | if( mark ) |
297 | 0 | *mark = '\0' ; |
298 | |
|
299 | 0 | return string ; |
300 | 0 | } |
301 | | |
302 | | |
303 | | unsigned |
304 | | trim_trailing_chars( byte *line, unsigned len, const char *trimchars ) |
305 | 896k | { |
306 | 896k | byte *p, *mark; |
307 | 896k | unsigned n; |
308 | | |
309 | 5.52M | for(mark=NULL, p=line, n=0; n < len; n++, p++ ) { |
310 | 4.63M | if( strchr(trimchars, *p ) ) { |
311 | 2.47M | if( !mark ) |
312 | 1.64M | mark = p; |
313 | 2.47M | } |
314 | 2.16M | else |
315 | 2.16M | mark = NULL; |
316 | 4.63M | } |
317 | | |
318 | 896k | if( mark ) { |
319 | 896k | *mark = 0; |
320 | 896k | return mark - line; |
321 | 896k | } |
322 | 439 | return len; |
323 | 896k | } |
324 | | |
325 | | /**************** |
326 | | * remove trailing white spaces and return the length of the buffer |
327 | | */ |
328 | | unsigned |
329 | | trim_trailing_ws( byte *line, unsigned len ) |
330 | 0 | { |
331 | 0 | return trim_trailing_chars( line, len, " \t\r\n" ); |
332 | 0 | } |
333 | | |
334 | | size_t |
335 | | length_sans_trailing_chars (const unsigned char *line, size_t len, |
336 | | const char *trimchars ) |
337 | 58.8k | { |
338 | 58.8k | const unsigned char *p, *mark; |
339 | 58.8k | size_t n; |
340 | | |
341 | 623k | for( mark=NULL, p=line, n=0; n < len; n++, p++ ) |
342 | 564k | { |
343 | 564k | if (strchr (trimchars, *p )) |
344 | 159k | { |
345 | 159k | if( !mark ) |
346 | 92.2k | mark = p; |
347 | 159k | } |
348 | 405k | else |
349 | 405k | mark = NULL; |
350 | 564k | } |
351 | | |
352 | 58.8k | if (mark) |
353 | 57.9k | return mark - line; |
354 | 870 | return len; |
355 | 58.8k | } |
356 | | |
357 | | /* |
358 | | * Return the length of line ignoring trailing white-space. |
359 | | */ |
360 | | size_t |
361 | | length_sans_trailing_ws (const unsigned char *line, size_t len) |
362 | 58.8k | { |
363 | 58.8k | return length_sans_trailing_chars (line, len, " \t\r\n"); |
364 | 58.8k | } |
365 | | |
366 | | |
367 | | |
368 | | /* |
369 | | * Extract from a given path the filename component. This function |
370 | | * terminates the process on memory shortage. |
371 | | */ |
372 | | char * |
373 | | make_basename(const char *filepath, const char *inputpath) |
374 | 0 | { |
375 | | #ifdef __riscos__ |
376 | | return riscos_make_basename(filepath, inputpath); |
377 | | #else |
378 | 0 | char *p; |
379 | |
|
380 | 0 | (void)inputpath; /* Only required for riscos. */ |
381 | |
|
382 | 0 | if ( !(p=strrchr(filepath, '/')) ) |
383 | | #ifdef HAVE_DOSISH_SYSTEM |
384 | | if ( !(p=strrchr(filepath, '\\')) ) |
385 | | #endif |
386 | | #ifdef HAVE_DRIVE_LETTERS |
387 | | if ( !(p=strrchr(filepath, ':')) ) |
388 | | #endif |
389 | 0 | { |
390 | 0 | return xstrdup(filepath); |
391 | 0 | } |
392 | | |
393 | 0 | return xstrdup(p+1); |
394 | 0 | #endif |
395 | 0 | } |
396 | | |
397 | | |
398 | | |
399 | | /* |
400 | | * Extract from a given filename the path prepended to it. If there |
401 | | * isn't a path prepended to the filename, a dot is returned ('.'). |
402 | | * This function terminates the process on memory shortage. |
403 | | */ |
404 | | char * |
405 | | make_dirname(const char *filepath) |
406 | 0 | { |
407 | 0 | char *dirname; |
408 | 0 | int dirname_length; |
409 | 0 | char *p; |
410 | |
|
411 | 0 | if ( !(p=strrchr(filepath, '/')) ) |
412 | | #ifdef HAVE_DOSISH_SYSTEM |
413 | | if ( !(p=strrchr(filepath, '\\')) ) |
414 | | #endif |
415 | | #ifdef HAVE_DRIVE_LETTERS |
416 | | if ( !(p=strrchr(filepath, ':')) ) |
417 | | #endif |
418 | 0 | { |
419 | 0 | return xstrdup("."); |
420 | 0 | } |
421 | | |
422 | 0 | dirname_length = p-filepath; |
423 | 0 | dirname = xmalloc(dirname_length+1); |
424 | 0 | strncpy(dirname, filepath, dirname_length); |
425 | 0 | dirname[dirname_length] = 0; |
426 | |
|
427 | 0 | return dirname; |
428 | 0 | } |
429 | | |
430 | | |
431 | | |
432 | | static char * |
433 | | get_pwdir (int xmode, const char *name) |
434 | 0 | { |
435 | 0 | char *result = NULL; |
436 | 0 | #ifdef HAVE_PWD_H |
437 | 0 | struct passwd *pwd = NULL; |
438 | |
|
439 | 0 | if (name) |
440 | 0 | { |
441 | 0 | #ifdef HAVE_GETPWNAM |
442 | | /* Fixme: We should use getpwnam_r if available. */ |
443 | 0 | pwd = getpwnam (name); |
444 | 0 | #endif |
445 | 0 | } |
446 | 0 | else |
447 | 0 | { |
448 | 0 | #ifdef HAVE_GETPWUID |
449 | | /* Fixme: We should use getpwuid_r if available. */ |
450 | 0 | pwd = getpwuid (getuid()); |
451 | 0 | #endif |
452 | 0 | } |
453 | 0 | if (pwd) |
454 | 0 | { |
455 | 0 | if (xmode) |
456 | 0 | result = xstrdup (pwd->pw_dir); |
457 | 0 | else |
458 | 0 | result = xtrystrdup (pwd->pw_dir); |
459 | 0 | } |
460 | | #else /*!HAVE_PWD_H*/ |
461 | | /* No support at all. */ |
462 | | (void)xmode; |
463 | | (void)name; |
464 | | #endif /*HAVE_PWD_H*/ |
465 | 0 | return result; |
466 | 0 | } |
467 | | |
468 | | |
469 | | /* xmode 0 := Return NULL on error |
470 | | 1 := Terminate on error |
471 | | 2 := Make sure that name is absolute; return NULL on error |
472 | | 3 := Make sure that name is absolute; terminate on error |
473 | | */ |
474 | | static char * |
475 | | do_make_filename (int xmode, const char *first_part, va_list arg_ptr) |
476 | 5 | { |
477 | 5 | const char *argv[32]; |
478 | 5 | int argc; |
479 | 5 | size_t n; |
480 | 5 | int skip = 1; |
481 | 5 | char *home_buffer = NULL; |
482 | 5 | char *name, *home, *p; |
483 | 5 | int want_abs; |
484 | | |
485 | 5 | want_abs = !!(xmode & 2); |
486 | 5 | xmode &= 1; |
487 | | |
488 | 5 | n = strlen (first_part) + 1; |
489 | 5 | argc = 0; |
490 | 7 | while ( (argv[argc] = va_arg (arg_ptr, const char *)) ) |
491 | 2 | { |
492 | 2 | n += strlen (argv[argc]) + 1; |
493 | 2 | if (argc >= DIM (argv)-1) |
494 | 0 | { |
495 | 0 | if (xmode) |
496 | 0 | BUG (); |
497 | 0 | gpg_err_set_errno (EINVAL); |
498 | 0 | return NULL; |
499 | 0 | } |
500 | 2 | argc++; |
501 | 2 | } |
502 | 5 | n++; |
503 | | |
504 | 5 | home = NULL; |
505 | 5 | if (*first_part == '~') |
506 | 1 | { |
507 | 1 | if (first_part[1] == '/' || !first_part[1]) |
508 | 1 | { |
509 | | /* This is the "~/" or "~" case. */ |
510 | 1 | home = getenv("HOME"); |
511 | 1 | if (!home) |
512 | 0 | home = home_buffer = get_pwdir (xmode, NULL); |
513 | 1 | if (home && *home) |
514 | 1 | n += strlen (home); |
515 | 1 | } |
516 | 0 | else |
517 | 0 | { |
518 | | /* This is the "~username/" or "~username" case. */ |
519 | 0 | char *user; |
520 | |
|
521 | 0 | if (xmode) |
522 | 0 | user = xstrdup (first_part+1); |
523 | 0 | else |
524 | 0 | { |
525 | 0 | user = xtrystrdup (first_part+1); |
526 | 0 | if (!user) |
527 | 0 | return NULL; |
528 | 0 | } |
529 | 0 | p = strchr (user, '/'); |
530 | 0 | if (p) |
531 | 0 | *p = 0; |
532 | 0 | skip = 1 + strlen (user); |
533 | |
|
534 | 0 | home = home_buffer = get_pwdir (xmode, user); |
535 | 0 | xfree (user); |
536 | 0 | if (home) |
537 | 0 | n += strlen (home); |
538 | 0 | else |
539 | 0 | skip = 1; |
540 | 0 | } |
541 | 1 | } |
542 | | |
543 | 5 | if (xmode) |
544 | 5 | name = xmalloc (n); |
545 | 0 | else |
546 | 0 | { |
547 | 0 | name = xtrymalloc (n); |
548 | 0 | if (!name) |
549 | 0 | { |
550 | 0 | xfree (home_buffer); |
551 | 0 | return NULL; |
552 | 0 | } |
553 | 0 | } |
554 | | |
555 | 5 | if (home) |
556 | 1 | p = stpcpy (stpcpy (name, home), first_part + skip); |
557 | 4 | else |
558 | 4 | p = stpcpy (name, first_part); |
559 | | |
560 | 5 | xfree (home_buffer); |
561 | 7 | for (argc=0; argv[argc]; argc++) |
562 | 2 | { |
563 | | /* Avoid a leading double slash if the first part was "/". */ |
564 | 2 | if (!argc && name[0] == '/' && !name[1]) |
565 | 0 | p = stpcpy (p, argv[argc]); |
566 | 2 | else |
567 | 2 | p = stpcpy (stpcpy (p, "/"), argv[argc]); |
568 | 2 | } |
569 | | |
570 | 5 | if (want_abs) |
571 | 3 | { |
572 | | #ifdef HAVE_DRIVE_LETTERS |
573 | | p = strchr (name, ':'); |
574 | | if (p) |
575 | | p++; |
576 | | else |
577 | | p = name; |
578 | | #else |
579 | 3 | p = name; |
580 | 3 | #endif |
581 | 3 | if (*p != '/' |
582 | | #ifdef HAVE_DRIVE_LETTERS |
583 | | && *p != '\\' |
584 | | #endif |
585 | 3 | ) |
586 | 0 | { |
587 | 0 | home = gnupg_getcwd (); |
588 | 0 | if (!home) |
589 | 0 | { |
590 | 0 | if (xmode) |
591 | 0 | { |
592 | 0 | fprintf (stderr, "\nfatal: getcwd failed: %s\n", |
593 | 0 | strerror (errno)); |
594 | 0 | exit(2); |
595 | 0 | } |
596 | 0 | xfree (name); |
597 | 0 | return NULL; |
598 | 0 | } |
599 | 0 | n = strlen (home) + 1 + strlen (name) + 1; |
600 | 0 | if (xmode) |
601 | 0 | home_buffer = xmalloc (n); |
602 | 0 | else |
603 | 0 | { |
604 | 0 | home_buffer = xtrymalloc (n); |
605 | 0 | if (!home_buffer) |
606 | 0 | { |
607 | 0 | xfree (home); |
608 | 0 | xfree (name); |
609 | 0 | return NULL; |
610 | 0 | } |
611 | 0 | } |
612 | 0 | if (p == name) |
613 | 0 | p = home_buffer; |
614 | 0 | else /* Windows case. */ |
615 | 0 | { |
616 | 0 | memcpy (home_buffer, p, p - name + 1); |
617 | 0 | p = home_buffer + (p - name + 1); |
618 | 0 | } |
619 | | |
620 | | /* Avoid a leading double slash if the cwd is "/". */ |
621 | 0 | if (home[0] == '/' && !home[1]) |
622 | 0 | strcpy (stpcpy (p, "/"), name); |
623 | 0 | else |
624 | 0 | strcpy (stpcpy (stpcpy (p, home), "/"), name); |
625 | |
|
626 | 0 | xfree (home); |
627 | 0 | xfree (name); |
628 | 0 | name = home_buffer; |
629 | | /* Let's do a simple compression to catch the most common |
630 | | case of using "." for gpg's --homedir option. */ |
631 | 0 | n = strlen (name); |
632 | 0 | if (n > 2 && name[n-2] == '/' && name[n-1] == '.') |
633 | 0 | name[n-2] = 0; |
634 | 0 | } |
635 | 3 | } |
636 | 5 | return change_slashes (name); |
637 | 5 | } |
638 | | |
639 | | /* Construct a filename from the NULL terminated list of parts. Tilde |
640 | | expansion is done for the first argument. This function terminates |
641 | | the process on memory shortage. */ |
642 | | char * |
643 | | make_filename (const char *first_part, ... ) |
644 | 2 | { |
645 | 2 | va_list arg_ptr; |
646 | 2 | char *result; |
647 | | |
648 | 2 | va_start (arg_ptr, first_part); |
649 | 2 | result = do_make_filename (1, first_part, arg_ptr); |
650 | 2 | va_end (arg_ptr); |
651 | 2 | return result; |
652 | 2 | } |
653 | | |
654 | | /* Construct a filename from the NULL terminated list of parts. Tilde |
655 | | expansion is done for the first argument. This function may return |
656 | | NULL on error. */ |
657 | | char * |
658 | | make_filename_try (const char *first_part, ... ) |
659 | 0 | { |
660 | 0 | va_list arg_ptr; |
661 | 0 | char *result; |
662 | |
|
663 | 0 | va_start (arg_ptr, first_part); |
664 | 0 | result = do_make_filename (0, first_part, arg_ptr); |
665 | 0 | va_end (arg_ptr); |
666 | 0 | return result; |
667 | 0 | } |
668 | | |
669 | | /* Construct an absolute filename from the NULL terminated list of |
670 | | parts. Tilde expansion is done for the first argument. This |
671 | | function terminates the process on memory shortage. */ |
672 | | char * |
673 | | make_absfilename (const char *first_part, ... ) |
674 | 3 | { |
675 | 3 | va_list arg_ptr; |
676 | 3 | char *result; |
677 | | |
678 | 3 | va_start (arg_ptr, first_part); |
679 | 3 | result = do_make_filename (3, first_part, arg_ptr); |
680 | 3 | va_end (arg_ptr); |
681 | 3 | return result; |
682 | 3 | } |
683 | | |
684 | | /* Construct an absolute filename from the NULL terminated list of |
685 | | parts. Tilde expansion is done for the first argument. This |
686 | | function may return NULL on error. */ |
687 | | char * |
688 | | make_absfilename_try (const char *first_part, ... ) |
689 | 0 | { |
690 | 0 | va_list arg_ptr; |
691 | 0 | char *result; |
692 | |
|
693 | 0 | va_start (arg_ptr, first_part); |
694 | 0 | result = do_make_filename (2, first_part, arg_ptr); |
695 | 0 | va_end (arg_ptr); |
696 | 0 | return result; |
697 | 0 | } |
698 | | |
699 | | |
700 | | |
701 | | /* Compare whether the filenames are identical. This is a |
702 | | special version of strcmp() taking the semantics of filenames in |
703 | | account. Note that this function works only on the supplied names |
704 | | without considering any context like the current directory. See |
705 | | also same_file_p(). */ |
706 | | int |
707 | | compare_filenames (const char *a, const char *b) |
708 | 1 | { |
709 | | #ifdef HAVE_DOSISH_SYSTEM |
710 | | for ( ; *a && *b; a++, b++ ) |
711 | | { |
712 | | if (*a != *b |
713 | | && (toupper (*(const unsigned char*)a) |
714 | | != toupper (*(const unsigned char*)b) ) |
715 | | && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))) |
716 | | break; |
717 | | } |
718 | | if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')) |
719 | | return 0; |
720 | | else |
721 | | return (toupper (*(const unsigned char*)a) |
722 | | - toupper (*(const unsigned char*)b)); |
723 | | #else |
724 | 1 | return strcmp(a,b); |
725 | 1 | #endif |
726 | 1 | } |
727 | | |
728 | | |
729 | | /* Convert a base-10 number in STRING into a 64 bit unsigned int |
730 | | * value. Leading white spaces are skipped but no error checking is |
731 | | * done. Thus it is similar to atoi(). See also scan_secondsstr. */ |
732 | | uint64_t |
733 | | string_to_u64 (const char *string) |
734 | 0 | { |
735 | 0 | uint64_t val = 0; |
736 | |
|
737 | 0 | while (spacep (string)) |
738 | 0 | string++; |
739 | 0 | for (; digitp (string); string++) |
740 | 0 | { |
741 | 0 | val *= 10; |
742 | 0 | val += *string - '0'; |
743 | 0 | } |
744 | 0 | return val; |
745 | 0 | } |
746 | | |
747 | | |
748 | | /* Convert 2 hex characters at S to a byte value. Return this value |
749 | | or -1 if there is an error. */ |
750 | | int |
751 | | hextobyte (const char *s) |
752 | 0 | { |
753 | 0 | int c; |
754 | |
|
755 | 0 | if ( *s >= '0' && *s <= '9' ) |
756 | 0 | c = 16 * (*s - '0'); |
757 | 0 | else if ( *s >= 'A' && *s <= 'F' ) |
758 | 0 | c = 16 * (10 + *s - 'A'); |
759 | 0 | else if ( *s >= 'a' && *s <= 'f' ) |
760 | 0 | c = 16 * (10 + *s - 'a'); |
761 | 0 | else |
762 | 0 | return -1; |
763 | 0 | s++; |
764 | 0 | if ( *s >= '0' && *s <= '9' ) |
765 | 0 | c += *s - '0'; |
766 | 0 | else if ( *s >= 'A' && *s <= 'F' ) |
767 | 0 | c += 10 + *s - 'A'; |
768 | 0 | else if ( *s >= 'a' && *s <= 'f' ) |
769 | 0 | c += 10 + *s - 'a'; |
770 | 0 | else |
771 | 0 | return -1; |
772 | 0 | return c; |
773 | 0 | } |
774 | | |
775 | | /* Given a string containing an UTF-8 encoded text, return the number |
776 | | of characters in this string. It differs from strlen in that it |
777 | | only counts complete UTF-8 characters. SIZE is the maximum length |
778 | | of the string in bytes. If SIZE is -1, then a NUL character is |
779 | | taken to be the end of the string. Note, that this function does |
780 | | not take combined characters into account. */ |
781 | | size_t |
782 | | utf8_charcount (const char *s, int len) |
783 | 0 | { |
784 | 0 | size_t n; |
785 | |
|
786 | 0 | if (len == 0) |
787 | 0 | return 0; |
788 | | |
789 | 0 | for (n=0; *s; s++) |
790 | 0 | { |
791 | 0 | if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */ |
792 | 0 | n++; |
793 | |
|
794 | 0 | if (len != -1) |
795 | 0 | { |
796 | 0 | len --; |
797 | 0 | if (len == 0) |
798 | 0 | break; |
799 | 0 | } |
800 | 0 | } |
801 | |
|
802 | 0 | return n; |
803 | 0 | } |
804 | | |
805 | | |
806 | | /**************************************************** |
807 | | ********** W32 specific functions **************** |
808 | | ****************************************************/ |
809 | | |
810 | | #ifdef HAVE_W32_SYSTEM |
811 | | const char * |
812 | | w32_strerror (int ec) |
813 | | { |
814 | | static char strerr[256]; |
815 | | |
816 | | if (ec == -1) |
817 | | ec = (int)GetLastError (); |
818 | | FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec, |
819 | | MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), |
820 | | strerr, DIM (strerr)-1, NULL); |
821 | | { |
822 | | /* Strip the CR,LF - we want just the string. */ |
823 | | size_t n = strlen (strerr); |
824 | | if (n > 2 && strerr[n-2] == '\r' && strerr[n-1] == '\n' ) |
825 | | strerr[n-2] = 0; |
826 | | } |
827 | | return strerr; |
828 | | } |
829 | | #endif /*HAVE_W32_SYSTEM*/ |
830 | | |
831 | | |
832 | | /**************************************************** |
833 | | ******** Locale insensitive ctype functions ******** |
834 | | ****************************************************/ |
835 | | /* FIXME: replace them by a table lookup and macros */ |
836 | | int |
837 | | ascii_isupper (int c) |
838 | 0 | { |
839 | 0 | return c >= 'A' && c <= 'Z'; |
840 | 0 | } |
841 | | |
842 | | int |
843 | | ascii_islower (int c) |
844 | 0 | { |
845 | 0 | return c >= 'a' && c <= 'z'; |
846 | 0 | } |
847 | | |
848 | | int |
849 | | ascii_toupper (int c) |
850 | 615 | { |
851 | 615 | if (c >= 'a' && c <= 'z') |
852 | 258 | c &= ~0x20; |
853 | 615 | return c; |
854 | 615 | } |
855 | | |
856 | | int |
857 | | ascii_tolower (int c) |
858 | 0 | { |
859 | 0 | if (c >= 'A' && c <= 'Z') |
860 | 0 | c |= 0x20; |
861 | 0 | return c; |
862 | 0 | } |
863 | | |
864 | | /* Lowercase all ASCII characters in S. */ |
865 | | char * |
866 | | ascii_strlwr (char *s) |
867 | 931 | { |
868 | 931 | char *p = s; |
869 | | |
870 | 6.95k | for (p=s; *p; p++ ) |
871 | 6.02k | if (isascii (*p) && *p >= 'A' && *p <= 'Z') |
872 | 294 | *p |= 0x20; |
873 | | |
874 | 931 | return s; |
875 | 931 | } |
876 | | |
877 | | /* Upcase all ASCII characters in S. */ |
878 | | char * |
879 | | ascii_strupr (char *s) |
880 | 0 | { |
881 | 0 | char *p = s; |
882 | |
|
883 | 0 | for (p=s; *p; p++ ) |
884 | 0 | if (isascii (*p) && *p >= 'a' && *p <= 'z') |
885 | 0 | *p &= ~0x20; |
886 | |
|
887 | 0 | return s; |
888 | 0 | } |
889 | | |
890 | | int |
891 | | ascii_strcasecmp( const char *a, const char *b ) |
892 | 0 | { |
893 | 0 | if (a == b) |
894 | 0 | return 0; |
895 | | |
896 | 0 | for (; *a && *b; a++, b++) { |
897 | 0 | if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b)) |
898 | 0 | break; |
899 | 0 | } |
900 | 0 | return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b)); |
901 | 0 | } |
902 | | |
903 | | int |
904 | | ascii_strncasecmp (const char *a, const char *b, size_t n) |
905 | 0 | { |
906 | 0 | const unsigned char *p1 = (const unsigned char *)a; |
907 | 0 | const unsigned char *p2 = (const unsigned char *)b; |
908 | 0 | unsigned char c1, c2; |
909 | |
|
910 | 0 | if (p1 == p2 || !n ) |
911 | 0 | return 0; |
912 | | |
913 | 0 | do |
914 | 0 | { |
915 | 0 | c1 = ascii_tolower (*p1); |
916 | 0 | c2 = ascii_tolower (*p2); |
917 | |
|
918 | 0 | if ( !--n || c1 == '\0') |
919 | 0 | break; |
920 | | |
921 | 0 | ++p1; |
922 | 0 | ++p2; |
923 | 0 | } |
924 | 0 | while (c1 == c2); |
925 | |
|
926 | 0 | return c1 - c2; |
927 | 0 | } |
928 | | |
929 | | |
930 | | int |
931 | | ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n ) |
932 | 0 | { |
933 | 0 | const char *a = a_arg; |
934 | 0 | const char *b = b_arg; |
935 | |
|
936 | 0 | if (a == b) |
937 | 0 | return 0; |
938 | 0 | for ( ; n; n--, a++, b++ ) |
939 | 0 | { |
940 | 0 | if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) ) |
941 | 0 | return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b)); |
942 | 0 | } |
943 | 0 | return 0; |
944 | 0 | } |
945 | | |
946 | | int |
947 | | ascii_strcmp( const char *a, const char *b ) |
948 | 0 | { |
949 | 0 | if (a == b) |
950 | 0 | return 0; |
951 | | |
952 | 0 | for (; *a && *b; a++, b++) { |
953 | 0 | if (*a != *b ) |
954 | 0 | break; |
955 | 0 | } |
956 | 0 | return *a == *b? 0 : (*(signed char *)a - *(signed char *)b); |
957 | 0 | } |
958 | | |
959 | | |
960 | | void * |
961 | | ascii_memcasemem (const void *haystack, size_t nhaystack, |
962 | | const void *needle, size_t nneedle) |
963 | 0 | { |
964 | |
|
965 | 0 | if (!nneedle) |
966 | 0 | return (void*)haystack; /* finding an empty needle is really easy */ |
967 | 0 | if (nneedle <= nhaystack) |
968 | 0 | { |
969 | 0 | const char *a = haystack; |
970 | 0 | const char *b = a + nhaystack - nneedle; |
971 | |
|
972 | 0 | for (; a <= b; a++) |
973 | 0 | { |
974 | 0 | if ( !ascii_memcasecmp (a, needle, nneedle) ) |
975 | 0 | return (void *)a; |
976 | 0 | } |
977 | 0 | } |
978 | 0 | return NULL; |
979 | 0 | } |
980 | | |
981 | | /********************************************* |
982 | | ********** missing string functions ********* |
983 | | *********************************************/ |
984 | | |
985 | | #ifndef HAVE_STPCPY |
986 | | char * |
987 | | stpcpy(char *a,const char *b) |
988 | | { |
989 | | while( *b ) |
990 | | *a++ = *b++; |
991 | | *a = 0; |
992 | | |
993 | | return (char*)a; |
994 | | } |
995 | | #endif |
996 | | |
997 | | #ifndef HAVE_STRPBRK |
998 | | /* Find the first occurrence in S of any character in ACCEPT. |
999 | | Code taken from glibc-2.6/string/strpbrk.c (LGPLv2.1+) and modified. */ |
1000 | | char * |
1001 | | strpbrk (const char *s, const char *accept) |
1002 | | { |
1003 | | while (*s != '\0') |
1004 | | { |
1005 | | const char *a = accept; |
1006 | | while (*a != '\0') |
1007 | | if (*a++ == *s) |
1008 | | return (char *) s; |
1009 | | ++s; |
1010 | | } |
1011 | | |
1012 | | return NULL; |
1013 | | } |
1014 | | #endif /*!HAVE_STRPBRK*/ |
1015 | | |
1016 | | |
1017 | | #ifndef HAVE_STRSEP |
1018 | | /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */ |
1019 | | char * |
1020 | | strsep (char **stringp, const char *delim) |
1021 | | { |
1022 | | char *begin, *end; |
1023 | | |
1024 | | begin = *stringp; |
1025 | | if (begin == NULL) |
1026 | | return NULL; |
1027 | | |
1028 | | /* A frequent case is when the delimiter string contains only one |
1029 | | character. Here we don't need to call the expensive 'strpbrk' |
1030 | | function and instead work using 'strchr'. */ |
1031 | | if (delim[0] == '\0' || delim[1] == '\0') |
1032 | | { |
1033 | | char ch = delim[0]; |
1034 | | |
1035 | | if (ch == '\0') |
1036 | | end = NULL; |
1037 | | else |
1038 | | { |
1039 | | if (*begin == ch) |
1040 | | end = begin; |
1041 | | else if (*begin == '\0') |
1042 | | end = NULL; |
1043 | | else |
1044 | | end = strchr (begin + 1, ch); |
1045 | | } |
1046 | | } |
1047 | | else |
1048 | | /* Find the end of the token. */ |
1049 | | end = strpbrk (begin, delim); |
1050 | | |
1051 | | if (end) |
1052 | | { |
1053 | | /* Terminate the token and set *STRINGP past NUL character. */ |
1054 | | *end++ = '\0'; |
1055 | | *stringp = end; |
1056 | | } |
1057 | | else |
1058 | | /* No more delimiters; this is the last token. */ |
1059 | | *stringp = NULL; |
1060 | | |
1061 | | return begin; |
1062 | | } |
1063 | | #endif /*HAVE_STRSEP*/ |
1064 | | |
1065 | | |
1066 | | #ifndef HAVE_STRLWR |
1067 | | char * |
1068 | | strlwr(char *s) |
1069 | 0 | { |
1070 | 0 | char *p; |
1071 | 0 | for(p=s; *p; p++ ) |
1072 | 0 | *p = tolower(*p); |
1073 | 0 | return s; |
1074 | 0 | } |
1075 | | #endif |
1076 | | |
1077 | | |
1078 | | #ifndef HAVE_STRCASECMP |
1079 | | int |
1080 | | strcasecmp( const char *a, const char *b ) |
1081 | | { |
1082 | | for( ; *a && *b; a++, b++ ) { |
1083 | | if( *a != *b && toupper(*a) != toupper(*b) ) |
1084 | | break; |
1085 | | } |
1086 | | return *(const byte*)a - *(const byte*)b; |
1087 | | } |
1088 | | #endif |
1089 | | |
1090 | | |
1091 | | /**************** |
1092 | | * mingw32/cpd has a memicmp() |
1093 | | */ |
1094 | | #ifndef HAVE_MEMICMP |
1095 | | int |
1096 | | memicmp( const char *a, const char *b, size_t n ) |
1097 | 0 | { |
1098 | 0 | for( ; n; n--, a++, b++ ) |
1099 | 0 | if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) ) |
1100 | 0 | return *(const byte *)a - *(const byte*)b; |
1101 | 0 | return 0; |
1102 | 0 | } |
1103 | | #endif |
1104 | | |
1105 | | |
1106 | | #ifndef HAVE_MEMRCHR |
1107 | | void * |
1108 | | memrchr (const void *buffer, int c, size_t n) |
1109 | | { |
1110 | | const unsigned char *p = buffer; |
1111 | | |
1112 | | for (p += n; n ; n--) |
1113 | | if (*--p == c) |
1114 | | return (void *)p; |
1115 | | return NULL; |
1116 | | } |
1117 | | #endif /*HAVE_MEMRCHR*/ |
1118 | | |
1119 | | |
1120 | | /* Percent-escape the string STR by replacing colons with '%3a'. If |
1121 | | EXTRA is not NULL all characters in EXTRA are also escaped. */ |
1122 | | static char * |
1123 | | do_percent_escape (const char *str, const char *extra, int die) |
1124 | 0 | { |
1125 | 0 | int i, j; |
1126 | 0 | char *ptr; |
1127 | |
|
1128 | 0 | if (!str) |
1129 | 0 | return NULL; |
1130 | | |
1131 | 0 | for (i=j=0; str[i]; i++) |
1132 | 0 | if (str[i] == ':' || str[i] == '%' || str[i] == '\n' |
1133 | 0 | || (extra && strchr (extra, str[i]))) |
1134 | 0 | j++; |
1135 | 0 | if (die) |
1136 | 0 | ptr = xmalloc (i + 2 * j + 1); |
1137 | 0 | else |
1138 | 0 | { |
1139 | 0 | ptr = xtrymalloc (i + 2 * j + 1); |
1140 | 0 | if (!ptr) |
1141 | 0 | return NULL; |
1142 | 0 | } |
1143 | 0 | i = 0; |
1144 | 0 | while (*str) |
1145 | 0 | { |
1146 | 0 | if (*str == ':') |
1147 | 0 | { |
1148 | 0 | ptr[i++] = '%'; |
1149 | 0 | ptr[i++] = '3'; |
1150 | 0 | ptr[i++] = 'a'; |
1151 | 0 | } |
1152 | 0 | else if (*str == '%') |
1153 | 0 | { |
1154 | 0 | ptr[i++] = '%'; |
1155 | 0 | ptr[i++] = '2'; |
1156 | 0 | ptr[i++] = '5'; |
1157 | 0 | } |
1158 | 0 | else if (*str == '\n') |
1159 | 0 | { |
1160 | | /* The newline is problematic in a line-based format. */ |
1161 | 0 | ptr[i++] = '%'; |
1162 | 0 | ptr[i++] = '0'; |
1163 | 0 | ptr[i++] = 'a'; |
1164 | 0 | } |
1165 | 0 | else if (extra && strchr (extra, *str)) |
1166 | 0 | { |
1167 | 0 | ptr[i++] = '%'; |
1168 | 0 | ptr[i++] = tohex_lower ((*str>>4)&15); |
1169 | 0 | ptr[i++] = tohex_lower (*str&15); |
1170 | 0 | } |
1171 | 0 | else |
1172 | 0 | ptr[i++] = *str; |
1173 | 0 | str++; |
1174 | 0 | } |
1175 | 0 | ptr[i] = '\0'; |
1176 | |
|
1177 | 0 | return ptr; |
1178 | 0 | } |
1179 | | |
1180 | | /* Percent-escape the string STR by replacing colons with '%3a'. If |
1181 | | EXTRA is not NULL all characters in EXTRA are also escaped. This |
1182 | | function terminates the process on memory shortage. */ |
1183 | | char * |
1184 | | percent_escape (const char *str, const char *extra) |
1185 | 0 | { |
1186 | 0 | return do_percent_escape (str, extra, 1); |
1187 | 0 | } |
1188 | | |
1189 | | /* Same as percent_escape but return NULL instead of exiting on memory |
1190 | | error. */ |
1191 | | char * |
1192 | | try_percent_escape (const char *str, const char *extra) |
1193 | 0 | { |
1194 | 0 | return do_percent_escape (str, extra, 0); |
1195 | 0 | } |
1196 | | |
1197 | | |
1198 | | /* Same as strconcat but takes a va_list. Returns EINVAL if the list |
1199 | | * is too long, all other errors are due to an ENOMEM condition. */ |
1200 | | char * |
1201 | | vstrconcat (const char *s1, va_list arg_ptr) |
1202 | 0 | { |
1203 | 0 | const char *argv[48]; |
1204 | 0 | size_t argc; |
1205 | 0 | size_t needed; |
1206 | 0 | char *buffer, *p; |
1207 | |
|
1208 | 0 | argc = 0; |
1209 | 0 | argv[argc++] = s1; |
1210 | 0 | needed = strlen (s1); |
1211 | 0 | while (((argv[argc] = va_arg (arg_ptr, const char *)))) |
1212 | 0 | { |
1213 | 0 | needed += strlen (argv[argc]); |
1214 | 0 | if (argc >= DIM (argv)-1) |
1215 | 0 | { |
1216 | 0 | gpg_err_set_errno (EINVAL); |
1217 | 0 | return NULL; |
1218 | 0 | } |
1219 | 0 | argc++; |
1220 | 0 | } |
1221 | 0 | needed++; |
1222 | 0 | buffer = xtrymalloc (needed); |
1223 | 0 | if (buffer) |
1224 | 0 | { |
1225 | 0 | for (p = buffer, argc=0; argv[argc]; argc++) |
1226 | 0 | p = stpcpy (p, argv[argc]); |
1227 | 0 | } |
1228 | 0 | return buffer; |
1229 | 0 | } |
1230 | | |
1231 | | |
1232 | | /* Concatenate the string S1 with all the following strings up to a |
1233 | | NULL. Returns a malloced buffer with the new string or NULL on a |
1234 | | malloc error or if too many arguments are given. */ |
1235 | | char * |
1236 | | strconcat (const char *s1, ...) |
1237 | 0 | { |
1238 | 0 | va_list arg_ptr; |
1239 | 0 | char *result; |
1240 | |
|
1241 | 0 | if (!s1) |
1242 | 0 | result = xtrystrdup (""); |
1243 | 0 | else |
1244 | 0 | { |
1245 | 0 | va_start (arg_ptr, s1); |
1246 | 0 | result = vstrconcat (s1, arg_ptr); |
1247 | 0 | va_end (arg_ptr); |
1248 | 0 | } |
1249 | 0 | return result; |
1250 | 0 | } |
1251 | | |
1252 | | /* Same as strconcat but terminate the process with an error message |
1253 | | if something goes wrong. */ |
1254 | | char * |
1255 | | xstrconcat (const char *s1, ...) |
1256 | 0 | { |
1257 | 0 | va_list arg_ptr; |
1258 | 0 | char *result; |
1259 | |
|
1260 | 0 | if (!s1) |
1261 | 0 | result = xstrdup (""); |
1262 | 0 | else |
1263 | 0 | { |
1264 | 0 | va_start (arg_ptr, s1); |
1265 | 0 | result = vstrconcat (s1, arg_ptr); |
1266 | 0 | va_end (arg_ptr); |
1267 | 0 | } |
1268 | 0 | if (!result) |
1269 | 0 | { |
1270 | 0 | if (errno == EINVAL) |
1271 | 0 | fputs ("\nfatal: too many args for xstrconcat\n", stderr); |
1272 | 0 | else |
1273 | 0 | fputs ("\nfatal: out of memory\n", stderr); |
1274 | 0 | exit (2); |
1275 | 0 | } |
1276 | 0 | return result; |
1277 | 0 | } |
1278 | | |
1279 | | /* Split a string into fields at DELIM. REPLACEMENT is the character |
1280 | | to replace the delimiter with (normally: '\0' so that each field is |
1281 | | NUL terminated). The caller is responsible for freeing the result. |
1282 | | Note: this function modifies STRING! If you need the original |
1283 | | value, then you should pass a copy to this function. |
1284 | | |
1285 | | If malloc fails, this function returns NULL. */ |
1286 | | char ** |
1287 | | strsplit (char *string, char delim, char replacement, int *count) |
1288 | 0 | { |
1289 | 0 | int fields = 1; |
1290 | 0 | char *t; |
1291 | 0 | char **result; |
1292 | | |
1293 | | /* First, count the number of fields. */ |
1294 | 0 | for (t = strchr (string, delim); t; t = strchr (t + 1, delim)) |
1295 | 0 | fields ++; |
1296 | |
|
1297 | 0 | result = xtrycalloc ((fields + 1), sizeof (*result)); |
1298 | 0 | if (! result) |
1299 | 0 | return NULL; |
1300 | | |
1301 | 0 | result[0] = string; |
1302 | 0 | fields = 1; |
1303 | 0 | for (t = strchr (string, delim); t; t = strchr (t + 1, delim)) |
1304 | 0 | { |
1305 | 0 | result[fields ++] = t + 1; |
1306 | 0 | *t = replacement; |
1307 | 0 | } |
1308 | |
|
1309 | 0 | if (count) |
1310 | 0 | *count = fields; |
1311 | |
|
1312 | 0 | return result; |
1313 | 0 | } |
1314 | | |
1315 | | |
1316 | | /* Tokenize STRING using the set of delimiters in DELIM. Leading |
1317 | | * spaces and tabs are removed from all tokens. The caller must xfree |
1318 | | * the result. |
1319 | | * |
1320 | | * Returns: A malloced and NULL delimited array with the tokens. On |
1321 | | * memory error NULL is returned and ERRNO is set. |
1322 | | */ |
1323 | | static char ** |
1324 | | do_strtokenize (const char *string, const char *delim, int trim) |
1325 | 0 | { |
1326 | 0 | const char *s; |
1327 | 0 | size_t fields; |
1328 | 0 | size_t bytes, n; |
1329 | 0 | char *buffer; |
1330 | 0 | char *p, *px, *pend; |
1331 | 0 | char **result; |
1332 | | |
1333 | | /* Count the number of fields. */ |
1334 | 0 | for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim)) |
1335 | 0 | fields++; |
1336 | 0 | fields++; /* Add one for the terminating NULL. */ |
1337 | | |
1338 | | /* Allocate an array for all fields, a terminating NULL, and space |
1339 | | for a copy of the string. */ |
1340 | 0 | bytes = fields * sizeof *result; |
1341 | 0 | if (bytes / sizeof *result != fields) |
1342 | 0 | { |
1343 | 0 | gpg_err_set_errno (ENOMEM); |
1344 | 0 | return NULL; |
1345 | 0 | } |
1346 | 0 | n = strlen (string) + 1; |
1347 | 0 | bytes += n; |
1348 | 0 | if (bytes < n) |
1349 | 0 | { |
1350 | 0 | gpg_err_set_errno (ENOMEM); |
1351 | 0 | return NULL; |
1352 | 0 | } |
1353 | 0 | result = xtrymalloc (bytes); |
1354 | 0 | if (!result) |
1355 | 0 | return NULL; |
1356 | 0 | buffer = (char*)(result + fields); |
1357 | | |
1358 | | /* Copy and parse the string. */ |
1359 | 0 | strcpy (buffer, string); |
1360 | 0 | for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1) |
1361 | 0 | { |
1362 | 0 | *pend = 0; |
1363 | 0 | if (trim) |
1364 | 0 | { |
1365 | 0 | while (spacep (p)) |
1366 | 0 | p++; |
1367 | 0 | for (px = pend - 1; px >= p && spacep (px); px--) |
1368 | 0 | *px = 0; |
1369 | 0 | } |
1370 | 0 | result[n++] = p; |
1371 | 0 | } |
1372 | 0 | if (trim) |
1373 | 0 | { |
1374 | 0 | while (spacep (p)) |
1375 | 0 | p++; |
1376 | 0 | for (px = p + strlen (p) - 1; px >= p && spacep (px); px--) |
1377 | 0 | *px = 0; |
1378 | 0 | } |
1379 | 0 | result[n++] = p; |
1380 | 0 | result[n] = NULL; |
1381 | |
|
1382 | 0 | log_assert ((char*)(result + n + 1) == buffer); |
1383 | | |
1384 | 0 | return result; |
1385 | 0 | } |
1386 | | |
1387 | | /* Tokenize STRING using the set of delimiters in DELIM. Leading |
1388 | | * spaces and tabs are removed from all tokens. The caller must xfree |
1389 | | * the result. |
1390 | | * |
1391 | | * Returns: A malloced and NULL delimited array with the tokens. On |
1392 | | * memory error NULL is returned and ERRNO is set. |
1393 | | */ |
1394 | | char ** |
1395 | | strtokenize (const char *string, const char *delim) |
1396 | 0 | { |
1397 | 0 | return do_strtokenize (string, delim, 1); |
1398 | 0 | } |
1399 | | |
1400 | | /* Same as strtokenize but does not trim leading and trailing spaces |
1401 | | * from the fields. */ |
1402 | | char ** |
1403 | | strtokenize_nt (const char *string, const char *delim) |
1404 | 0 | { |
1405 | 0 | return do_strtokenize (string, delim, 0); |
1406 | 0 | } |
1407 | | |
1408 | | |
1409 | | /* Split a string into space delimited fields and remove leading and |
1410 | | * trailing spaces from each field. A pointer to each field is stored |
1411 | | * in ARRAY. Stop splitting at ARRAYSIZE fields. The function |
1412 | | * modifies STRING. The number of parsed fields is returned. |
1413 | | * Example: |
1414 | | * |
1415 | | * char *fields[2]; |
1416 | | * if (split_fields (string, fields, DIM (fields)) < 2) |
1417 | | * return // Not enough args. |
1418 | | * foo (fields[0]); |
1419 | | * foo (fields[1]); |
1420 | | */ |
1421 | | int |
1422 | | split_fields (char *string, const char **array, int arraysize) |
1423 | 0 | { |
1424 | 0 | int n = 0; |
1425 | 0 | const char *p; |
1426 | 0 | char *pend; |
1427 | |
|
1428 | 0 | for (p = string; *p == ' '; p++) |
1429 | 0 | ; |
1430 | 0 | do |
1431 | 0 | { |
1432 | 0 | if (n == arraysize) |
1433 | 0 | break; |
1434 | 0 | array[n++] = p; |
1435 | 0 | pend = strchr (p, ' '); |
1436 | 0 | if (!pend) |
1437 | 0 | break; |
1438 | 0 | *pend++ = 0; |
1439 | 0 | for (p = pend; *p == ' '; p++) |
1440 | 0 | ; |
1441 | 0 | } |
1442 | 0 | while (*p); |
1443 | |
|
1444 | 0 | return n; |
1445 | 0 | } |
1446 | | |
1447 | | |
1448 | | /* Split a string into colon delimited fields A pointer to each field |
1449 | | * is stored in ARRAY. Stop splitting at ARRAYSIZE fields. The |
1450 | | * function modifies STRING. The number of parsed fields is returned. |
1451 | | * Note that leading and trailing spaces are not removed from the fields. |
1452 | | * Example: |
1453 | | * |
1454 | | * char *fields[2]; |
1455 | | * if (split_fields (string, fields, DIM (fields)) < 2) |
1456 | | * return // Not enough args. |
1457 | | * foo (fields[0]); |
1458 | | * foo (fields[1]); |
1459 | | */ |
1460 | | int |
1461 | | split_fields_colon (char *string, const char **array, int arraysize) |
1462 | 0 | { |
1463 | 0 | int n = 0; |
1464 | 0 | const char *p; |
1465 | 0 | char *pend; |
1466 | |
|
1467 | 0 | p = string; |
1468 | 0 | do |
1469 | 0 | { |
1470 | 0 | if (n == arraysize) |
1471 | 0 | break; |
1472 | 0 | array[n++] = p; |
1473 | 0 | pend = strchr (p, ':'); |
1474 | 0 | if (!pend) |
1475 | 0 | break; |
1476 | 0 | *pend++ = 0; |
1477 | 0 | p = pend; |
1478 | 0 | } |
1479 | 0 | while (*p); |
1480 | |
|
1481 | 0 | return n; |
1482 | 0 | } |
1483 | | |
1484 | | |
1485 | | |
1486 | | /* Version number parsing. */ |
1487 | | |
1488 | | /* This function parses the first portion of the version number S and |
1489 | | stores it in *NUMBER. On success, this function returns a pointer |
1490 | | into S starting with the first character, which is not part of the |
1491 | | initial number portion; on failure, NULL is returned. */ |
1492 | | static const char* |
1493 | | parse_version_number (const char *s, int *number) |
1494 | 0 | { |
1495 | 0 | int val = 0; |
1496 | |
|
1497 | 0 | if (*s == '0' && digitp (s+1)) |
1498 | 0 | return NULL; /* Leading zeros are not allowed. */ |
1499 | 0 | for (; digitp (s); s++) |
1500 | 0 | { |
1501 | 0 | val *= 10; |
1502 | 0 | val += *s - '0'; |
1503 | 0 | } |
1504 | 0 | *number = val; |
1505 | 0 | return val < 0 ? NULL : s; |
1506 | 0 | } |
1507 | | |
1508 | | |
1509 | | /* This function breaks up the complete string-representation of the |
1510 | | version number S, which is of the following structure: <major |
1511 | | number>.<minor number>[.<micro number>]<patch level>. The major, |
1512 | | minor, and micro number components will be stored in *MAJOR, *MINOR |
1513 | | and *MICRO. If MICRO is not given 0 is used instead. |
1514 | | |
1515 | | On success, the last component, the patch level, will be returned; |
1516 | | in failure, NULL will be returned. */ |
1517 | | static const char * |
1518 | | parse_version_string (const char *s, int *major, int *minor, int *micro) |
1519 | 0 | { |
1520 | 0 | s = parse_version_number (s, major); |
1521 | 0 | if (!s || *s != '.') |
1522 | 0 | return NULL; |
1523 | 0 | s++; |
1524 | 0 | s = parse_version_number (s, minor); |
1525 | 0 | if (!s) |
1526 | 0 | return NULL; |
1527 | 0 | if (*s == '.') |
1528 | 0 | { |
1529 | 0 | s++; |
1530 | 0 | s = parse_version_number (s, micro); |
1531 | 0 | if (!s) |
1532 | 0 | return NULL; |
1533 | 0 | } |
1534 | 0 | else |
1535 | 0 | *micro = 0; |
1536 | 0 | return s; /* Patchlevel. */ |
1537 | 0 | } |
1538 | | |
1539 | | |
1540 | | /* Compare the version string MY_VERSION to the version string |
1541 | | * REQ_VERSION. Returns -1, 0, or 1 if MY_VERSION is found, |
1542 | | * respectively, to be less than, to match, or be greater than |
1543 | | * REQ_VERSION. This function works for three and two part version |
1544 | | * strings; for a two part version string the micro part is assumed to |
1545 | | * be 0. Patch levels are compared as strings. If a version number |
1546 | | * is invalid INT_MIN is returned. If REQ_VERSION is given as NULL |
1547 | | * the function returns 0 if MY_VERSION is parsable version string. */ |
1548 | | int |
1549 | | compare_version_strings (const char *my_version, const char *req_version) |
1550 | 0 | { |
1551 | 0 | int my_major, my_minor, my_micro; |
1552 | 0 | int rq_major, rq_minor, rq_micro; |
1553 | 0 | const char *my_patch, *rq_patch; |
1554 | 0 | int result; |
1555 | |
|
1556 | 0 | if (!my_version) |
1557 | 0 | return INT_MIN; |
1558 | | |
1559 | 0 | my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro); |
1560 | 0 | if (!my_patch) |
1561 | 0 | return INT_MIN; |
1562 | 0 | if (!req_version) |
1563 | 0 | return 0; /* MY_VERSION can be parsed. */ |
1564 | 0 | rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro); |
1565 | 0 | if (!rq_patch) |
1566 | 0 | return INT_MIN; |
1567 | | |
1568 | 0 | if (my_major == rq_major) |
1569 | 0 | { |
1570 | 0 | if (my_minor == rq_minor) |
1571 | 0 | { |
1572 | 0 | if (my_micro == rq_micro) |
1573 | 0 | result = strcmp (my_patch, rq_patch); |
1574 | 0 | else |
1575 | 0 | result = my_micro - rq_micro; |
1576 | 0 | } |
1577 | 0 | else |
1578 | 0 | result = my_minor - rq_minor; |
1579 | 0 | } |
1580 | 0 | else |
1581 | 0 | result = my_major - rq_major; |
1582 | |
|
1583 | 0 | return !result? 0 : result < 0 ? -1 : 1; |
1584 | 0 | } |
1585 | | |
1586 | | |
1587 | | |
1588 | | /* Format a string so that it fits within about TARGET_COLS columns. |
1589 | | * TEXT_IN is copied to a new buffer, which is returned. Normally, |
1590 | | * target_cols will be 72 and max_cols is 80. On error NULL is |
1591 | | * returned and ERRNO is set. */ |
1592 | | char * |
1593 | | format_text (const char *text_in, int target_cols, int max_cols) |
1594 | 0 | { |
1595 | | /* const int do_debug = 0; */ |
1596 | | |
1597 | | /* The character under consideration. */ |
1598 | 0 | char *p; |
1599 | | /* The start of the current line. */ |
1600 | 0 | char *line; |
1601 | | /* The last space that we saw. */ |
1602 | 0 | char *last_space = NULL; |
1603 | 0 | int last_space_cols = 0; |
1604 | 0 | int copied_last_space = 0; |
1605 | 0 | char *text; |
1606 | |
|
1607 | 0 | text = xtrystrdup (text_in); |
1608 | 0 | if (!text) |
1609 | 0 | return NULL; |
1610 | | |
1611 | 0 | p = line = text; |
1612 | 0 | while (1) |
1613 | 0 | { |
1614 | | /* The number of columns including any trailing space. */ |
1615 | 0 | int cols; |
1616 | |
|
1617 | 0 | p = p + strcspn (p, "\n "); |
1618 | 0 | if (! p) |
1619 | | /* P now points to the NUL character. */ |
1620 | 0 | p = &text[strlen (text)]; |
1621 | |
|
1622 | 0 | if (*p == '\n') |
1623 | | /* Pass through any newlines. */ |
1624 | 0 | { |
1625 | 0 | p ++; |
1626 | 0 | line = p; |
1627 | 0 | last_space = NULL; |
1628 | 0 | last_space_cols = 0; |
1629 | 0 | copied_last_space = 1; |
1630 | 0 | continue; |
1631 | 0 | } |
1632 | | |
1633 | | /* Have a space or a NUL. Note: we don't count the trailing |
1634 | | space. */ |
1635 | 0 | cols = utf8_charcount (line, (uintptr_t) p - (uintptr_t) line); |
1636 | 0 | if (cols < target_cols) |
1637 | 0 | { |
1638 | 0 | if (! *p) |
1639 | | /* Nothing left to break. */ |
1640 | 0 | break; |
1641 | | |
1642 | 0 | last_space = p; |
1643 | 0 | last_space_cols = cols; |
1644 | 0 | p ++; |
1645 | | /* Skip any immediately following spaces. If we break: |
1646 | | "... foo bar ..." between "foo" and "bar" then we want: |
1647 | | "... foo\nbar ...", which means that the left space has |
1648 | | to be the first space after foo, not the last space |
1649 | | before bar. */ |
1650 | 0 | while (*p == ' ') |
1651 | 0 | p ++; |
1652 | 0 | } |
1653 | 0 | else |
1654 | 0 | { |
1655 | 0 | int cols_with_left_space; |
1656 | 0 | int cols_with_right_space; |
1657 | 0 | int left_penalty; |
1658 | 0 | int right_penalty; |
1659 | |
|
1660 | 0 | cols_with_left_space = last_space_cols; |
1661 | 0 | cols_with_right_space = cols; |
1662 | | |
1663 | | /* if (do_debug) */ |
1664 | | /* log_debug ("Breaking: '%.*s'\n", */ |
1665 | | /* (int) ((uintptr_t) p - (uintptr_t) line), line); */ |
1666 | | |
1667 | | /* The number of columns away from TARGET_COLS. We prefer |
1668 | | to underflow than to overflow. */ |
1669 | 0 | left_penalty = target_cols - cols_with_left_space; |
1670 | 0 | right_penalty = 2 * (cols_with_right_space - target_cols); |
1671 | |
|
1672 | 0 | if (cols_with_right_space > max_cols) |
1673 | | /* Add a large penalty for each column that exceeds |
1674 | | max_cols. */ |
1675 | 0 | right_penalty += 4 * (cols_with_right_space - max_cols); |
1676 | | |
1677 | | /* if (do_debug) */ |
1678 | | /* log_debug ("Left space => %d cols (penalty: %d); " */ |
1679 | | /* "right space => %d cols (penalty: %d)\n", */ |
1680 | | /* cols_with_left_space, left_penalty, */ |
1681 | | /* cols_with_right_space, right_penalty); */ |
1682 | 0 | if (last_space_cols && left_penalty <= right_penalty) |
1683 | 0 | { |
1684 | | /* Prefer the left space. */ |
1685 | | /* if (do_debug) */ |
1686 | | /* log_debug ("Breaking at left space.\n"); */ |
1687 | 0 | p = last_space; |
1688 | 0 | } |
1689 | 0 | else |
1690 | 0 | { |
1691 | | /* if (do_debug) */ |
1692 | | /* log_debug ("Breaking at right space.\n"); */ |
1693 | 0 | } |
1694 | |
|
1695 | 0 | if (! *p) |
1696 | 0 | break; |
1697 | | |
1698 | 0 | *p = '\n'; |
1699 | 0 | p ++; |
1700 | 0 | if (*p == ' ') |
1701 | 0 | { |
1702 | 0 | int spaces; |
1703 | 0 | for (spaces = 1; p[spaces] == ' '; spaces ++) |
1704 | 0 | ; |
1705 | 0 | memmove (p, &p[spaces], strlen (&p[spaces]) + 1); |
1706 | 0 | } |
1707 | 0 | line = p; |
1708 | 0 | last_space = NULL; |
1709 | 0 | last_space_cols = 0; |
1710 | 0 | copied_last_space = 0; |
1711 | 0 | } |
1712 | 0 | } |
1713 | | |
1714 | | /* Chop off any trailing space. */ |
1715 | 0 | trim_trailing_chars (text, strlen (text), " "); |
1716 | | /* If we inserted the trailing newline, then remove it. */ |
1717 | 0 | if (! copied_last_space && *text && text[strlen (text) - 1] == '\n') |
1718 | 0 | text[strlen (text) - 1] = '\0'; |
1719 | |
|
1720 | 0 | return text; |
1721 | 0 | } |
1722 | | |
1723 | | |
1724 | | /* In STRING replace the first occurance of SUBSTR by the string |
1725 | | * REPLACE. Return a new malloced string or set ERRNO and set NULL on |
1726 | | * error. If SUBSTR is not found a verbatim copy of STRING is |
1727 | | * returned. */ |
1728 | | char * |
1729 | | replace_substr (const char *string, const char *substr, const char *replace) |
1730 | 0 | { |
1731 | 0 | size_t stringlen, substrlen, replacelen, n; |
1732 | 0 | const char *s; |
1733 | 0 | char *buffer; |
1734 | |
|
1735 | 0 | stringlen = strlen (string); |
1736 | 0 | substrlen = strlen (substr); |
1737 | 0 | replacelen = strlen (replace); |
1738 | |
|
1739 | 0 | if (stringlen < substrlen || !(s = strstr (string, substr))) |
1740 | 0 | return xtrystrdup (string); |
1741 | | |
1742 | 0 | stringlen -= substrlen; /* Found thus sryinglen >= substrlen */ |
1743 | 0 | buffer = xtrymalloc (stringlen + replacelen +1); |
1744 | 0 | if (!buffer) |
1745 | 0 | return NULL; |
1746 | 0 | memcpy (buffer, string, n=(s-string)); |
1747 | 0 | memcpy (buffer+n, replace, replacelen); |
1748 | 0 | strcpy (buffer+n+replacelen, s+substrlen); |
1749 | | |
1750 | |
|
1751 | 0 | return buffer; |
1752 | 0 | } |
1753 | | |
1754 | | |
1755 | | /* Substitute variables in STRING and return a new string. GETVAL is |
1756 | | * a function which maps NAME to its value; that value is a string |
1757 | | * which may not change during the execution time of this function. |
1758 | | * If GETVAL returns NULL substitute_vars returns NULL and the caller |
1759 | | * may inspect ERRNO for the reason. In all other error cases this |
1760 | | * function also returns NULL. Caller must free the returned string. */ |
1761 | | char * |
1762 | | substitute_vars (const char *string, |
1763 | | const char *(*getval)(void *cookie, const char *name), |
1764 | | void *cookie) |
1765 | 0 | { |
1766 | 0 | char *line, *p, *pend; |
1767 | 0 | const char *value; |
1768 | 0 | size_t valuelen, n; |
1769 | 0 | char *result = NULL; |
1770 | |
|
1771 | 0 | result = line = xtrystrdup (string); |
1772 | 0 | if (!result) |
1773 | 0 | return NULL; /* Ooops */ |
1774 | | |
1775 | 0 | while (*line) |
1776 | 0 | { |
1777 | 0 | p = strchr (line, '$'); |
1778 | 0 | if (!p) |
1779 | 0 | goto leave; /* No or no more variables. */ |
1780 | | |
1781 | 0 | if (p[1] == '$') /* Escaped dollar sign. */ |
1782 | 0 | { |
1783 | 0 | memmove (p, p+1, strlen (p+1)+1); |
1784 | 0 | line = p + 1; |
1785 | 0 | continue; |
1786 | 0 | } |
1787 | | |
1788 | 0 | if (p[1] == '{') |
1789 | 0 | { |
1790 | 0 | int count = 0; |
1791 | |
|
1792 | 0 | for (pend=p+2; *pend; pend++) |
1793 | 0 | { |
1794 | 0 | if (*pend == '{') |
1795 | 0 | count++; |
1796 | 0 | else if (*pend == '}') |
1797 | 0 | { |
1798 | 0 | if (--count < 0) |
1799 | 0 | break; |
1800 | 0 | } |
1801 | 0 | } |
1802 | 0 | if (!*pend) |
1803 | 0 | goto leave; /* Unclosed - don't substitute. */ |
1804 | 0 | } |
1805 | 0 | else |
1806 | 0 | { |
1807 | 0 | for (pend = p+1; *pend && (alnump (pend) || *pend == '_'); pend++) |
1808 | 0 | ; |
1809 | 0 | } |
1810 | | |
1811 | 0 | if (p[1] == '{' && *pend == '}') |
1812 | 0 | { |
1813 | 0 | int save = *pend; |
1814 | 0 | *pend = 0; |
1815 | 0 | value = getval (cookie, p+2); |
1816 | 0 | *pend++ = save; |
1817 | 0 | } |
1818 | 0 | else |
1819 | 0 | { |
1820 | 0 | int save = *pend; |
1821 | 0 | *pend = 0; |
1822 | 0 | value = getval (cookie, p+1); |
1823 | 0 | *pend = save; |
1824 | 0 | } |
1825 | |
|
1826 | 0 | if (!value) |
1827 | 0 | { |
1828 | 0 | xfree (result); |
1829 | 0 | return NULL; |
1830 | 0 | } |
1831 | 0 | valuelen = strlen (value); |
1832 | 0 | if (valuelen <= pend - p) |
1833 | 0 | { |
1834 | 0 | memcpy (p, value, valuelen); |
1835 | 0 | p += valuelen; |
1836 | 0 | n = pend - p; |
1837 | 0 | if (n) |
1838 | 0 | memmove (p, p+n, strlen (p+n)+1); |
1839 | 0 | line = p; |
1840 | 0 | } |
1841 | 0 | else |
1842 | 0 | { |
1843 | 0 | char *src = result; |
1844 | 0 | char *dst; |
1845 | |
|
1846 | 0 | dst = xtrymalloc (strlen (src) + valuelen + 1); |
1847 | 0 | if (!dst) |
1848 | 0 | { |
1849 | 0 | xfree (result); |
1850 | 0 | return NULL; |
1851 | 0 | } |
1852 | 0 | n = p - src; |
1853 | 0 | memcpy (dst, src, n); |
1854 | 0 | memcpy (dst + n, value, valuelen); |
1855 | 0 | n += valuelen; |
1856 | 0 | strcpy (dst + n, pend); |
1857 | 0 | line = dst + n; |
1858 | 0 | xfree (result); |
1859 | 0 | result = dst; |
1860 | 0 | } |
1861 | 0 | } |
1862 | | |
1863 | 0 | leave: |
1864 | 0 | return result; |
1865 | 0 | } |
1866 | | |
1867 | | |
1868 | | /* Helper for substitute_envvars. */ |
1869 | | static const char * |
1870 | | subst_getenv (void *cookie, const char *name) |
1871 | 0 | { |
1872 | 0 | const char *s; |
1873 | |
|
1874 | 0 | (void)cookie; |
1875 | |
|
1876 | 0 | s = getenv (name); |
1877 | 0 | return s? s : ""; |
1878 | 0 | } |
1879 | | |
1880 | | |
1881 | | /* Substitute environment variables in STRING and return a new string. |
1882 | | * On error the function returns NULL. */ |
1883 | | char * |
1884 | | substitute_envvars (const char *string) |
1885 | 0 | { |
1886 | 0 | return substitute_vars (string, subst_getenv, NULL); |
1887 | |
|
1888 | 0 | } |