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