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