1 /* util.c
2 *
3 * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
4 * Copyright (C) 2008 Lars Uebernickel <larsuebernickel@gmx.de>
5 *
6 * This file is part of foomatic-rip.
7 *
8 * Foomatic-rip is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Foomatic-rip is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24 #include "util.h"
25 #include "foomaticrip.h"
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31 #include <assert.h>
32
33
34 const char* shellescapes = "|;<>&!$\'\"`#*?()[]{}";
35
temp_dir()36 const char * temp_dir()
37 {
38 static const char *tmpdir = NULL;
39
40 if (!tmpdir)
41 {
42 const char *dirs[] = { getenv("TMPDIR"), P_tmpdir, "/tmp" };
43 int i;
44
45 for (i = 0; i < (sizeof(dirs) / sizeof(dirs[0])); i++) {
46 if (access(dirs[i], W_OK) == 0) {
47 tmpdir = dirs[i];
48 break;
49 }
50 }
51 if (tmpdir)
52 {
53 _log("Storing temporary files in %s\n", tmpdir);
54 setenv("TMPDIR", tmpdir, 1); /* for child processes */
55 }
56 else
57 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
58 "Cannot find a writable temp dir.");
59 }
60
61 return tmpdir;
62 }
63
prefixcmp(const char * str,const char * prefix)64 int prefixcmp(const char *str, const char *prefix)
65 {
66 return strncmp(str, prefix, strlen(prefix));
67 }
68
prefixcasecmp(const char * str,const char * prefix)69 int prefixcasecmp(const char *str, const char *prefix)
70 {
71 return strncasecmp(str, prefix, strlen(prefix));
72 }
73
startswith(const char * str,const char * prefix)74 int startswith(const char *str, const char *prefix)
75 {
76 return str ? (strncmp(str, prefix, strlen(prefix)) == 0) : 0;
77 }
78
endswith(const char * str,const char * postfix)79 int endswith(const char *str, const char *postfix)
80 {
81 int slen = strlen(str);
82 int plen = strlen(postfix);
83 const char *pstr;
84
85 if (slen < plen)
86 return 0;
87
88 pstr = &str[slen - plen];
89 return strcmp(str, postfix) == 0;
90 }
91
skip_whitespace(const char * str)92 const char * skip_whitespace(const char *str)
93 {
94 while (*str && isspace(*str))
95 str++;
96 return str;
97 }
98
strlower(char * dest,size_t destlen,const char * src)99 void strlower(char *dest, size_t destlen, const char *src)
100 {
101 char *pdest = dest;
102 const char *psrc = src;
103 while (*psrc && --destlen > 0)
104 {
105 *pdest = tolower(*psrc);
106 pdest++;
107 psrc++;
108 }
109 *pdest = '\0';
110 }
111
isempty(const char * string)112 int isempty(const char *string)
113 {
114 return !string || string[0] == '\0';
115 }
116
strncpy_omit(char * dest,const char * src,size_t n,int (* omit_func)(int))117 const char * strncpy_omit(char* dest, const char* src, size_t n, int (*omit_func)(int))
118 {
119 const char* psrc = src;
120 char* pdest = dest;
121 int cnt = n -1;
122 if (!pdest)
123 return NULL;
124 if (psrc) {
125 while (*psrc != 0 && cnt > 0) {
126 if (!omit_func(*psrc)) {
127 *pdest = *psrc;
128 pdest++;
129 cnt--;
130 }
131 psrc++;
132 }
133 }
134 *pdest = '\0';
135 return psrc;
136 }
omit_unprintables(int c)137 int omit_unprintables(int c) { return c>= '\x00' && c <= '\x1f'; }
omit_shellescapes(int c)138 int omit_shellescapes(int c) { return strchr(shellescapes, c) != NULL; }
omit_specialchars(int c)139 int omit_specialchars(int c) { return omit_unprintables(c) || omit_shellescapes(c); }
omit_whitespace(int c)140 int omit_whitespace(int c) { return c == ' ' || c == '\t'; }
omit_whitespace_newline(int c)141 int omit_whitespace_newline(int c) { return omit_whitespace(c) || c == '\n'; }
142
143 #ifndef HAVE_STRCASESTR
144 char *
strcasestr(const char * haystack,const char * needle)145 strcasestr (const char *haystack, const char *needle)
146 {
147 char *p, *startn = 0, *np = 0;
148
149 for (p = haystack; *p; p++) {
150 if (np) {
151 if (toupper(*p) == toupper(*np)) {
152 if (!*++np)
153 return startn;
154 } else
155 np = 0;
156 } else if (toupper(*p) == toupper(*needle)) {
157 np = needle + 1;
158 startn = p;
159 }
160 }
161
162 return 0;
163 }
164 #endif
165
166 #ifndef __OpenBSD__
strlcpy(char * dest,const char * src,size_t size)167 size_t strlcpy(char *dest, const char *src, size_t size)
168 {
169 char *pdest = dest;
170 const char *psrc = src;
171
172 if (!src) {
173 dest[0] = '\0';
174 return 0;
175 }
176
177 if (size) {
178 while (--size && (*pdest++ = *psrc++) != '\0');
179 *pdest = '\0';
180 }
181 if (!size)
182 while (*psrc++);
183 return (psrc - src -1);
184 }
185
strlcat(char * dest,const char * src,size_t size)186 size_t strlcat(char *dest, const char *src, size_t size)
187 {
188 char *pdest = dest;
189 const char *psrc = src;
190 size_t i = size;
191 size_t len;
192
193 while (--i && *pdest)
194 pdest++;
195 len = pdest - dest;
196
197 if (!i)
198 return strlen(src) + len;
199
200 while (i-- && *psrc)
201 *pdest++ = *psrc++;
202 *pdest = '\0';
203
204 return len + (psrc - src);
205 }
206 #endif /* ! __OpenBSD__ */
207
strrepl(char * str,const char * chars,char repl)208 void strrepl(char *str, const char *chars, char repl)
209 {
210 char *p = str;
211
212 while (*p) {
213 if (strchr(chars, *p))
214 *p = repl;
215 p++;
216 }
217 }
218
strrepl_nodups(char * str,const char * chars,char repl)219 void strrepl_nodups(char *str, const char *chars, char repl)
220 {
221 char *pstr = str;
222 char *p = str;
223 int prev = 0;
224
225 while (*pstr) {
226 if (strchr(chars, *pstr) || *pstr == repl) {
227 if (!prev) {
228 *p = repl;
229 p++;
230 prev = 1;
231 }
232 }
233 else {
234 *p = *pstr;
235 p++;
236 prev = 0;
237 }
238 pstr++;
239 }
240 *p = '\0';
241 }
242
strclr(char * str)243 void strclr(char *str)
244 {
245 while (*str) {
246 *str = '\0';
247 str++;
248 }
249 }
250
strnchr(const char * str,int c,size_t n)251 char * strnchr(const char *str, int c, size_t n)
252 {
253 char *p = (char*)str;
254
255 while (*p && --n > 0) {
256 if (*p == (char)c)
257 return p;
258 p++;
259 }
260 return p;
261 }
262
escapechars(char * dest,size_t size,const char * src,const char * esc_chars)263 void escapechars(char *dest, size_t size, const char *src, const char *esc_chars)
264 {
265 const char *psrc = src;
266
267 while (*psrc && --size > 0) {
268 if (strchr(esc_chars, *psrc))
269 *dest++ = '\\';
270 *dest++ = *psrc++;
271 }
272 }
273
strncpy_tochar(char * dest,const char * src,size_t max,const char * stopchars)274 const char * strncpy_tochar(char *dest, const char *src, size_t max, const char *stopchars)
275 {
276 const char *psrc = src;
277 char *pdest = dest;
278 if (isempty(psrc)) {
279 return NULL;
280 }
281 while (*psrc && --max > 0 && !strchr(stopchars, *psrc)) {
282 *pdest = *psrc;
283 pdest++;
284 psrc++;
285 }
286 *pdest = '\0';
287 return psrc +1;
288 }
289
find_in_path(const char * progname,const char * paths,char * found_in)290 int find_in_path(const char *progname, const char *paths, char *found_in)
291 {
292 char *pathscopy;
293 char *path;
294 char filepath[PATH_MAX];
295
296 if (access(progname, X_OK) == 0)
297 return 1;
298
299 pathscopy = strdup(paths);
300 for (path = strtok(pathscopy, ":"); path; path = strtok(NULL, ":")) {
301 strlcpy(filepath, path, PATH_MAX);
302 strlcat(filepath, "/", PATH_MAX);
303 strlcat(filepath, progname, PATH_MAX);
304
305 if (access(filepath, X_OK) == 0) {
306 if (found_in)
307 strlcpy(found_in, path, PATH_MAX);
308 free(pathscopy);
309 return 1;
310 }
311 }
312
313 if (found_in)
314 found_in[0] = '\0';
315 free(pathscopy);
316 return 0;
317 }
318
file_basename(char * dest,const char * path,size_t dest_size)319 void file_basename(char *dest, const char *path, size_t dest_size)
320 {
321 const char *p = strrchr(path, '/');
322 char *pdest = dest;
323 if (!pdest)
324 return;
325 if (p)
326 p += 1;
327 else
328 p = path;
329 while (*p != 0 && *p != '.' && --dest_size > 0) {
330 *pdest++ = *p++;
331 }
332 *pdest = '\0';
333 }
334
make_absolute_path(char * path,int len)335 void make_absolute_path(char *path, int len)
336 {
337 char *tmp, *cwd;
338
339 if (path[0] != '/') {
340 tmp = malloc(len +1);
341 strlcpy(tmp, path, len);
342
343 cwd = malloc(len);
344 getcwd(cwd, len);
345 strlcpy(path, cwd, len);
346 strlcat(path, "/", len);
347 strlcat(path, tmp, len);
348
349 free(tmp);
350 free(cwd);
351 }
352 }
353
is_true_string(const char * str)354 int is_true_string(const char *str)
355 {
356 return str && (!strcmp(str, "1") || !strcasecmp(str, "Yes") ||
357 !strcasecmp(str, "On") || !strcasecmp(str, "True"));
358 }
359
is_false_string(const char * str)360 int is_false_string(const char *str)
361 {
362 return str && (!strcmp(str, "0") || !strcasecmp(str, "No") ||
363 !strcasecmp(str, "Off") || !strcasecmp(str, "False") ||
364 !strcasecmp(str, "None"));
365 }
366
digit(char c)367 int digit(char c)
368 {
369 if (c >= '0' && c <= '9')
370 return (int)c - (int)'0';
371 return -1;
372 }
373
next_token(const char * string,const char * separators)374 static const char * next_token(const char *string, const char *separators)
375 {
376 if (!string)
377 return NULL;
378
379 while (*string && !strchr(separators, *string))
380 string++;
381
382 while (*string && strchr(separators, *string))
383 string++;
384
385 return string;
386 }
387
count_separators(const char * string,const char * separators)388 static unsigned count_separators(const char *string, const char *separators)
389 {
390 const char *p;
391 unsigned cnt = 0;
392
393 if (!string)
394 return 0;
395
396 for (p = string; *p; p = next_token(p, separators))
397 cnt++;
398
399 return cnt;
400 }
401
402 /*
403 * Returns a zero terminated array of strings
404 */
argv_split(const char * string,const char * separators,int * cntp)405 char ** argv_split(const char *string, const char *separators, int *cntp)
406 {
407 unsigned cnt;
408 int i;
409 char **argv;
410
411 if (!string)
412 return NULL;
413
414 if ((cnt = count_separators(string, separators)) == 0)
415 return NULL;
416
417 argv = malloc((cnt +1) * sizeof(char *));
418 argv[cnt] = NULL;
419
420 for (i = 0; i < cnt; i++)
421 {
422 size_t len = strcspn(string, separators);
423 char *s;
424 s = malloc(len + 1);
425 strncpy(s, string, len);
426 s[len] = '\0';
427 argv[i] = s;
428 string = next_token(string, separators);
429 }
430
431 if (cntp)
432 *cntp = cnt;
433 return argv;
434 }
435
argv_count(char ** argv)436 size_t argv_count(char **argv)
437 {
438 size_t cnt = 0;
439
440 if (!argv)
441 return 0;
442
443 while (*argv++)
444 cnt++;
445
446 return cnt;
447 }
448
argv_free(char ** argv)449 void argv_free(char **argv)
450 {
451 char **p;
452
453 if (!argv)
454 return;
455
456 for (p = argv; *p; p++)
457 free(*p);
458
459 free(argv);
460 }
461
line_count(const char * str)462 int line_count(const char *str)
463 {
464 int cnt = 0;
465 while (*str) {
466 if (*str == '\n')
467 cnt++;
468 str++;
469 }
470 return cnt;
471 }
472
line_start(const char * str,int line_number)473 int line_start(const char *str, int line_number)
474 {
475 const char *p = str;
476 while (*p && line_number > 0) {
477 if (*p == '\n')
478 line_number--;
479 p++;
480 }
481 return p - str;
482 }
483
unhexify(char * dest,size_t size,const char * src)484 void unhexify(char *dest, size_t size, const char *src)
485 {
486 char *pdest = dest;
487 const char *psrc = src;
488 char cstr[3];
489
490 cstr[2] = '\0';
491
492 while (*psrc && pdest - dest < size -1) {
493 if (*psrc == '<') {
494 psrc++;
495 do {
496 cstr[0] = *psrc++;
497 cstr[1] = *psrc++;
498 if (!isxdigit(cstr[0]) || !isxdigit(cstr[1])) {
499 printf("Error replacing hex notation in %s!\n", src);
500 break;
501 }
502 *pdest++ = (char)strtol(cstr, NULL, 16);
503 } while (*psrc != '>');
504 psrc++;
505 }
506 else
507 *pdest++ = *psrc++;
508 }
509 *pdest = '\0';
510 }
511
extract_command(size_t * start,size_t * end,const char * cmdline,const char * cmd)512 void extract_command(size_t *start, size_t *end, const char *cmdline, const char *cmd)
513 {
514 char *copy = strdup(cmdline);
515 char *tok = NULL;
516 const char *delim = "|;";
517
518 *start = *end = 0;
519 for (tok = strtok(copy, delim); tok; tok = strtok(NULL, delim)) {
520 while (*tok && isspace(*tok))
521 tok++;
522 if (startswith(tok, cmd)) {
523 *start = tok - copy;
524 *end = tok + strlen(tok) - copy;
525 break;
526 }
527 }
528
529 free(copy);
530 }
531
contains_command(const char * cmdline,const char * cmd)532 int contains_command(const char *cmdline, const char *cmd)
533 {
534 size_t start = 0, end = 0;
535
536 extract_command(&start, &end, cmdline, cmd);
537 if (start == 0 && end == 0)
538 return 0;
539
540 return 1;
541 }
542
543 /*
544 * Dynamic strings
545 */
create_dstr()546 dstr_t * create_dstr()
547 {
548 dstr_t *ds = malloc(sizeof(dstr_t));
549 ds->len = 0;
550 ds->alloc = 32;
551 ds->data = malloc(ds->alloc);
552 ds->data[0] = '\0';
553 return ds;
554 }
555
free_dstr(dstr_t * ds)556 void free_dstr(dstr_t *ds)
557 {
558 free(ds->data);
559 free(ds);
560 }
561
dstrclear(dstr_t * ds)562 void dstrclear(dstr_t *ds)
563 {
564 ds->len = 0;
565 ds->data[0] = '\0';
566 }
567
dstrassure(dstr_t * ds,size_t alloc)568 void dstrassure(dstr_t *ds, size_t alloc)
569 {
570 if (ds->alloc < alloc) {
571 ds->alloc = alloc;
572 ds->data = realloc(ds->data, ds->alloc);
573 }
574 }
575
dstrcpy(dstr_t * ds,const char * src)576 void dstrcpy(dstr_t *ds, const char *src)
577 {
578 size_t srclen;
579
580 if (!src) {
581 ds->len = 0;
582 ds->data[0] = '\0';
583 return;
584 }
585
586 srclen = strlen(src);
587
588 if (srclen >= ds->alloc) {
589 do {
590 ds->alloc *= 2;
591 } while (srclen >= ds->alloc);
592 ds->data = realloc(ds->data, ds->alloc);
593 }
594
595 strcpy(ds->data, src);
596 ds->len = srclen;
597 }
598
dstrncpy(dstr_t * ds,const char * src,size_t n)599 void dstrncpy(dstr_t *ds, const char *src, size_t n)
600 {
601 if (n >= ds->alloc) {
602 do {
603 ds->alloc *= 2;
604 } while (n >= ds->alloc);
605 ds->data = realloc(ds->data, ds->alloc);
606 }
607
608 strncpy(ds->data, src, n);
609 ds->len = n;
610 ds->data[ds->len] = '\0';
611 }
612
dstrncat(dstr_t * ds,const char * src,size_t n)613 void dstrncat(dstr_t *ds, const char *src, size_t n)
614 {
615 size_t needed = ds->len + n;
616
617 if (needed >= ds->alloc) {
618 do {
619 ds->alloc *= 2;
620 } while (needed >= ds->alloc);
621 ds->data = realloc(ds->data, ds->alloc);
622 }
623
624 strncpy(&ds->data[ds->len], src, n);
625 ds->len = needed;
626 ds->data[ds->len] = '\0';
627 }
628
dstrcpyf(dstr_t * ds,const char * src,...)629 void dstrcpyf(dstr_t *ds, const char *src, ...)
630 {
631 va_list ap;
632 size_t srclen;
633
634 va_start(ap, src);
635 srclen = vsnprintf(ds->data, ds->alloc, src, ap);
636 va_end(ap);
637
638 if (srclen >= ds->alloc) {
639 do {
640 ds->alloc *= 2;
641 } while (srclen >= ds->alloc);
642 ds->data = realloc(ds->data, ds->alloc);
643
644 va_start(ap, src);
645 vsnprintf(ds->data, ds->alloc, src, ap);
646 va_end(ap);
647 }
648
649 ds->len = srclen;
650 }
651
dstrputc(dstr_t * ds,int c)652 void dstrputc(dstr_t *ds, int c)
653 {
654 if (ds->len +1 >= ds->alloc) {
655 ds->alloc *= 2;
656 ds->data = realloc(ds->data, ds->alloc);
657 }
658 ds->data[ds->len++] = c;
659 ds->data[ds->len] = '\0';
660 }
661
dstrcat(dstr_t * ds,const char * src)662 void dstrcat(dstr_t *ds, const char *src)
663 {
664 size_t srclen = strlen(src);
665 size_t newlen = ds->len + srclen;
666
667 if (newlen >= ds->alloc) {
668 do {
669 ds->alloc *= 2;
670 } while (newlen >= ds->alloc);
671 ds->data = realloc(ds->data, ds->alloc);
672 }
673
674 memcpy(&ds->data[ds->len], src, srclen +1);
675 ds->len = newlen;
676 }
677
dstrcatf(dstr_t * ds,const char * src,...)678 void dstrcatf(dstr_t *ds, const char *src, ...)
679 {
680 va_list ap;
681 size_t restlen = ds->alloc - ds->len;
682 size_t srclen;
683
684 va_start(ap, src);
685 srclen = vsnprintf(&ds->data[ds->len], restlen, src, ap);
686 va_end(ap);
687
688 if (srclen >= restlen) {
689 do {
690 ds->alloc *= 2;
691 restlen = ds->alloc - ds->len;
692 } while (srclen >= restlen);
693 ds->data = realloc(ds->data, ds->alloc);
694
695 va_start(ap, src);
696 srclen = vsnprintf(&ds->data[ds->len], restlen, src, ap);
697 va_end(ap);
698 }
699
700 ds->len += srclen;
701 }
702
fgetdstr(dstr_t * ds,FILE * stream)703 size_t fgetdstr(dstr_t *ds, FILE *stream)
704 {
705 int c;
706 size_t cnt = 0;
707
708 ds->len = 0;
709 if (ds->alloc == 0) {
710 ds->alloc = 256;
711 ds->data = malloc(ds->alloc);
712 }
713
714 while ((c = fgetc(stream)) != EOF) {
715 if (ds->len +1 == ds->alloc) {
716 ds->alloc *= 2;
717 ds->data = realloc(ds->data, ds->alloc);
718 }
719 ds->data[ds->len++] = (char)c;
720 cnt ++;
721 if (c == '\n')
722 break;
723 }
724 ds->data[ds->len] = '\0';
725 return cnt;
726 }
727
728 /*
729 * Replace the first occurrence of 'find' after the index 'start' with 'repl'
730 * Returns the position right after the replaced string
731 */
dstrreplace(dstr_t * ds,const char * find,const char * repl,int start)732 int dstrreplace(dstr_t *ds, const char *find, const char *repl, int start)
733 {
734 char *p;
735 dstr_t *copy = create_dstr();
736 int end = -1;
737
738 dstrcpy(copy, ds->data);
739
740 if ((p = strstr(©->data[start], find)))
741 {
742 dstrncpy(ds, copy->data, p - copy->data);
743 dstrcatf(ds, "%s", repl);
744 end = ds->len;
745 dstrcatf(ds, "%s", p + strlen(find));
746 }
747
748 free_dstr(copy);
749 return end;
750 }
751
dstrprepend(dstr_t * ds,const char * str)752 void dstrprepend(dstr_t *ds, const char *str)
753 {
754 dstr_t *copy = create_dstr();
755 dstrcpy(copy, ds->data);
756 dstrcpy(ds, str);
757 dstrcatf(ds, "%s", copy->data);
758 free_dstr(copy);
759 }
760
dstrinsert(dstr_t * ds,int idx,const char * str)761 void dstrinsert(dstr_t *ds, int idx, const char *str)
762 {
763 char * copy = strdup(ds->data);
764 size_t len = strlen(str);
765
766 if (idx >= ds->len)
767 idx = ds->len;
768 else if (idx < 0)
769 idx = 0;
770
771 if (ds->len + len >= ds->alloc) {
772 do {
773 ds->alloc *= 2;
774 } while (ds->len + len >= ds->alloc);
775 free(ds->data);
776 ds->data = malloc(ds->alloc);
777 }
778
779 strncpy(ds->data, copy, idx);
780 ds->data[idx] = '\0';
781 strcat(ds->data, str);
782 strcat(ds->data, ©[idx]);
783 ds->len += len;
784 free(copy);
785 }
786
dstrinsertf(dstr_t * ds,int idx,const char * str,...)787 void dstrinsertf(dstr_t *ds, int idx, const char *str, ...)
788 {
789 va_list ap;
790 char *strf;
791 size_t len;
792
793 va_start(ap, str);
794 len = vsnprintf(NULL, 0, str, ap);
795 va_end(ap);
796
797 strf = malloc(len +1);
798 va_start(ap, str);
799 vsnprintf(strf, len +1, str, ap);
800 va_end(ap);
801
802 dstrinsert(ds, idx, strf);
803
804 free(strf);
805 }
806
dstrremove(dstr_t * ds,int idx,size_t count)807 void dstrremove(dstr_t *ds, int idx, size_t count)
808 {
809 char *p1, *p2;
810
811 if (idx + count >= ds->len)
812 return;
813
814 p1 = &ds->data[idx];
815 p2 = &ds->data[idx + count];
816
817 while (*p2) {
818 *p1 = *p2;
819 p1++;
820 p2++;
821 }
822 *p1 = '\0';
823 }
824
isnewline(int c)825 static inline int isnewline(int c)
826 {
827 return c == '\n' || c == '\r';
828 }
829
dstrcatline(dstr_t * ds,const char * str)830 void dstrcatline(dstr_t *ds, const char *str)
831 {
832 size_t eol = strcspn(str, "\n\r");
833 if (isnewline(str[eol]))
834 eol++;
835 dstrncat(ds, str, eol);
836 }
837
dstrendswith(dstr_t * ds,const char * str)838 int dstrendswith(dstr_t *ds, const char *str)
839 {
840 int len = strlen(str);
841 char *pstr;
842
843 if (ds->len < len)
844 return 0;
845 pstr = &ds->data[ds->len - len];
846 return strcmp(pstr, str) == 0;
847
848 }
849
dstrfixnewlines(dstr_t * ds)850 void dstrfixnewlines(dstr_t *ds)
851 {
852 if (ds->data[ds->len -1] == '\r') {
853 ds->data[ds->len -1] = '\n';
854 }
855 else if (ds->data[ds->len -2] == '\r') {
856 ds->data[ds->len -1] = '\n';
857 ds->data[ds->len -2] = '\0';
858 ds->len -= 1;
859 }
860 }
861
dstrremovenewline(dstr_t * ds)862 void dstrremovenewline(dstr_t *ds)
863 {
864 if (!ds->len)
865 return;
866
867 if (ds->data[ds->len -1] == '\r' || ds->data[ds->len -1] == '\n') {
868 ds->data[ds->len -1] = '\0';
869 ds->len -= 1;
870 }
871
872 if (ds->len < 2)
873 return;
874
875 if (ds->data[ds->len -2] == '\r') {
876 ds->data[ds->len -2] = '\0';
877 ds->len -= 2;
878 }
879 }
880
dstrtrim(dstr_t * ds)881 void dstrtrim(dstr_t *ds)
882 {
883 int pos = 0;
884
885 while (pos < ds->len && isspace(ds->data[pos]))
886 pos++;
887
888 if (pos > 0) {
889 ds->len -= pos;
890 memmove(ds->data, &ds->data[pos], ds->len +1);
891 }
892 }
893
dstrtrim_right(dstr_t * ds)894 void dstrtrim_right(dstr_t *ds)
895 {
896 if (!ds->len)
897 return;
898
899 while (isspace(ds->data[ds->len -1]))
900 ds->len -= 1;
901 ds->data[ds->len] = '\0';
902 }
903
904
905
906 /*
907 * LIST
908 */
909
list_create()910 list_t * list_create()
911 {
912 list_t *l = malloc(sizeof(list_t));
913 l->first = NULL;
914 l->last = NULL;
915 return l;
916 }
917
list_create_from_array(int count,void ** data)918 list_t * list_create_from_array(int count, void ** data)
919 {
920 int i;
921 list_t *l = list_create();
922
923 for (i = 0; i < count; i++)
924 list_append(l, data[i]);
925
926 return l;
927 }
928
list_free(list_t * list)929 void list_free(list_t *list)
930 {
931 listitem_t *i = list->first, *tmp;
932 while (i) {
933 tmp = i->next;
934 free(i);
935 i = tmp;
936 }
937 }
938
list_item_count(list_t * list)939 size_t list_item_count(list_t *list)
940 {
941 size_t cnt = 0;
942 listitem_t *i;
943 for (i = list->first; i; i = i->next)
944 cnt++;
945 return cnt;
946 }
947
list_copy(list_t * list)948 list_t * list_copy(list_t *list)
949 {
950 list_t *l = list_create();
951 listitem_t *i;
952
953 for (i = list->first; i; i = i->next)
954 list_append(l, i->data);
955 return l;
956 }
957
list_prepend(list_t * list,void * data)958 void list_prepend(list_t *list, void *data)
959 {
960 listitem_t *item;
961
962 assert(list);
963
964 item = malloc(sizeof(listitem_t));
965 item->data = data;
966 item->prev = NULL;
967
968 if (list->first) {
969 item->next = list->first;
970 list->first->next = item;
971 list->first = item;
972 }
973 else {
974 item->next = NULL;
975 list->first = item;
976 list->last = item;
977 }
978 }
979
list_append(list_t * list,void * data)980 void list_append(list_t *list, void *data)
981 {
982 listitem_t *item;
983
984 assert(list);
985
986 item = malloc(sizeof(listitem_t));
987 item->data = data;
988 item->next = NULL;
989
990 if (list->last) {
991 item->prev = list->last;
992 list->last->next = item;
993 list->last = item;
994 }
995 else {
996 item->prev = NULL;
997 list->first = item;
998 list->last = item;
999 }
1000 }
1001
list_remove(list_t * list,listitem_t * item)1002 void list_remove(list_t *list, listitem_t *item)
1003 {
1004 assert(item);
1005
1006 if (item->prev)
1007 item->prev->next = item->next;
1008 if (item->next)
1009 item->next->prev = item->prev;
1010 if (item == list->first)
1011 list->first = item->next;
1012 if (item == list->last)
1013 list->last = item->prev;
1014
1015 free(item);
1016 }
1017
list_get(list_t * list,int idx)1018 listitem_t * list_get(list_t *list, int idx)
1019 {
1020 listitem_t *i;
1021 for (i = list->first; i && idx; i = i->next)
1022 idx--;
1023 return i;
1024 }
1025
arglist_find(list_t * list,const char * name)1026 listitem_t * arglist_find(list_t *list, const char *name)
1027 {
1028 listitem_t *i;
1029 for (i = list->first; i; i = i->next) {
1030 if (!strcmp((const char*)i->data, name))
1031 return i;
1032 }
1033 return NULL;
1034 }
1035
arglist_find_prefix(list_t * list,const char * name)1036 listitem_t * arglist_find_prefix(list_t *list, const char *name)
1037 {
1038 listitem_t *i;
1039 for (i = list->first; i; i= i->next) {
1040 if (!prefixcmp((const char*)i->data, name))
1041 return i;
1042 }
1043 return NULL;
1044 }
1045
1046
arglist_get_value(list_t * list,const char * name)1047 char * arglist_get_value(list_t *list, const char *name)
1048 {
1049 listitem_t *i;
1050 char *p;
1051
1052 for (i = list->first; i; i = i->next) {
1053 if (i->next && !strcmp(name, (char*)i->data))
1054 return (char*)i->next->data;
1055 else if (!prefixcmp((char*)i->data, name)) {
1056 p = &((char*)i->data)[strlen(name)];
1057 return *p == '=' ? p +1 : p;
1058 }
1059 }
1060 return NULL;
1061 }
1062
arglist_get(list_t * list,int idx)1063 char * arglist_get(list_t *list, int idx)
1064 {
1065 listitem_t *i = list_get(list, idx);
1066 return i ? (char*)i->data : NULL;
1067 }
1068
arglist_remove(list_t * list,const char * name)1069 int arglist_remove(list_t *list, const char *name)
1070 {
1071 listitem_t *i;
1072 char *i_name;
1073
1074 for (i = list->first; i; i = i->next) {
1075 i_name = (char*)i->data;
1076 if (i->next && !strcmp(name, i_name)) {
1077 list_remove(list, i->next);
1078 list_remove(list, i);
1079 return 1;
1080 }
1081 else if (!prefixcmp(i_name, name)) {
1082 list_remove(list, i);
1083 return 1;
1084 }
1085 }
1086 return 0;
1087 }
1088
arglist_remove_flag(list_t * list,const char * name)1089 int arglist_remove_flag(list_t *list, const char *name)
1090 {
1091 listitem_t *i = arglist_find(list, name);
1092 if (i) {
1093 list_remove(list, i);
1094 return 1;
1095 }
1096 return 0;
1097 }
1098
copy_file(FILE * dest,FILE * src,const char * alreadyread,size_t alreadyread_len)1099 int copy_file(FILE *dest,
1100 FILE *src,
1101 const char *alreadyread,
1102 size_t alreadyread_len)
1103 {
1104 char buf[8192];
1105 size_t bytes;
1106
1107 if (alreadyread && alreadyread_len)
1108 {
1109 if (fwrite(alreadyread, 1, alreadyread_len, dest) < alreadyread_len)
1110 {
1111 _log("Could not write to temp file\n");
1112 return 0;
1113 }
1114 }
1115
1116 while ((bytes = fread(buf, 1, 8192, src)))
1117 fwrite(buf, 1, bytes, dest);
1118
1119 return !ferror(src) && !ferror(dest);
1120 }
1121
1122