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(&copy->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, &copy[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