• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&copy->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, &copy[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