1 /*
2 * File: dlib.c
3 *
4 * Copyright (C) 2006-2007 Jorge Arellano Cid <jcid@dillo.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 */
11
12 /* Memory allocation, Simple dynamic strings, Lists (simple and sorted),
13 * and a few utility functions
14 */
15
16 /*
17 * TODO: vsnprintf() is in C99, maybe a simple replacement if necessary.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <ctype.h>
27
28 #include "dlib.h"
29
30 static bool_t dLib_show_msg = TRUE;
31
32 /* dlib msgs go to stderr to avoid problems with filter dpis */
33 #define DLIB_MSG(...) \
34 D_STMT_START { \
35 if (dLib_show_msg) \
36 fprintf(stderr, __VA_ARGS__); \
37 } D_STMT_END
38
39 /*
40 *- Memory --------------------------------------------------------------------
41 */
42
dMalloc(size_t size)43 void *dMalloc (size_t size)
44 {
45 void *value = malloc (size);
46 if (value == 0)
47 exit(1);
48 return value;
49 }
50
dRealloc(void * mem,size_t size)51 void *dRealloc (void *mem, size_t size)
52 {
53 void *value = realloc (mem, size);
54 if (value == 0)
55 exit(1);
56 return value;
57 }
58
dMalloc0(size_t size)59 void *dMalloc0 (size_t size)
60 {
61 void *value = dMalloc (size);
62 memset (value, 0, size);
63 return value;
64 }
65
dFree(void * mem)66 void dFree (void *mem)
67 {
68 free(mem);
69 }
70
71 /*
72 *- strings (char *) ----------------------------------------------------------
73 */
74
dStrdup(const char * s)75 char *dStrdup(const char *s)
76 {
77 if (s) {
78 int len = strlen(s)+1;
79 char *ns = dNew(char, len);
80 memcpy(ns, s, len);
81 return ns;
82 }
83 return NULL;
84 }
85
dStrndup(const char * s,size_t sz)86 char *dStrndup(const char *s, size_t sz)
87 {
88 if (s) {
89 char *ns = dNew(char, sz+1);
90 memcpy(ns, s, sz);
91 ns[sz] = 0;
92 return ns;
93 }
94 return NULL;
95 }
96
97 /*
98 * Concatenate a NULL-terminated list of strings
99 */
dStrconcat(const char * s1,...)100 char *dStrconcat(const char *s1, ...)
101 {
102 va_list args;
103 char *s, *ns = NULL;
104
105 if (s1) {
106 Dstr *dstr = dStr_sized_new(64);
107 va_start(args, s1);
108 for (s = (char*)s1; s; s = va_arg(args, char*))
109 dStr_append(dstr, s);
110 va_end(args);
111 ns = dstr->str;
112 dStr_free(dstr, 0);
113 }
114 return ns;
115 }
116
117 /*
118 * Remove leading and trailing whitespace
119 */
dStrstrip(char * s)120 char *dStrstrip(char *s)
121 {
122 char *p;
123 int len;
124
125 if (s && *s) {
126 for (p = s; dIsspace(*p); ++p);
127 for (len = strlen(p); len && dIsspace(p[len-1]); --len);
128 if (p > s)
129 memmove(s, p, len);
130 s[len] = 0;
131 }
132 return s;
133 }
134
135 /*
136 * Clear the contents of the string
137 */
dStrshred(char * s)138 void dStrshred(char *s)
139 {
140 if (s)
141 memset(s, 0, strlen(s));
142 }
143
144 /*
145 * Return a new string of length 'len' filled with 'c' characters
146 */
dStrnfill(size_t len,char c)147 char *dStrnfill(size_t len, char c)
148 {
149 char *ret = dNew(char, len+1);
150 for (ret[len] = 0; len > 0; ret[--len] = c);
151 return ret;
152 }
153
154 /*
155 * strsep() implementation
156 */
dStrsep(char ** orig,const char * delim)157 char *dStrsep(char **orig, const char *delim)
158 {
159 char *str, *p;
160
161 if (!(str = *orig))
162 return NULL;
163
164 p = strpbrk(str, delim);
165 if (p) {
166 *p++ = 0;
167 *orig = p;
168 } else {
169 *orig = NULL;
170 }
171 return str;
172 }
173
174 /*
175 * ASCII functions to avoid the case difficulties introduced by I/i in
176 * Turkic locales.
177 */
178
179 /*
180 * Case insensitive strstr
181 */
dStriAsciiStr(const char * haystack,const char * needle)182 char *dStriAsciiStr(const char *haystack, const char *needle)
183 {
184 int i, j;
185 char *ret = NULL;
186
187 if (haystack && needle) {
188 for (i = 0, j = 0; haystack[i] && needle[j]; ++i)
189 if (D_ASCII_TOLOWER(haystack[i]) == D_ASCII_TOLOWER(needle[j])) {
190 ++j;
191 } else if (j) {
192 i -= j;
193 j = 0;
194 }
195 if (!needle[j]) /* Got all */
196 ret = (char *)(haystack + i - j);
197 }
198 return ret;
199 }
200
dStrAsciiCasecmp(const char * s1,const char * s2)201 int dStrAsciiCasecmp(const char *s1, const char *s2)
202 {
203 int ret = 0;
204
205 while ((*s1 || *s2) &&
206 !(ret = D_ASCII_TOLOWER(*s1) - D_ASCII_TOLOWER(*s2))) {
207 s1++;
208 s2++;
209 }
210 return ret;
211 }
212
dStrnAsciiCasecmp(const char * s1,const char * s2,size_t n)213 int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
214 {
215 int ret = 0;
216
217 while (n-- && (*s1 || *s2) &&
218 !(ret = D_ASCII_TOLOWER(*s1) - D_ASCII_TOLOWER(*s2))) {
219 s1++;
220 s2++;
221 }
222 return ret;
223 }
224
225 /*
226 *- dStr ----------------------------------------------------------------------
227 */
228
229 /*
230 * Private allocator
231 */
dStr_resize(Dstr * ds,int n_sz,int keep)232 static void dStr_resize(Dstr *ds, int n_sz, int keep)
233 {
234 if (n_sz >= 0) {
235 if (keep && n_sz > ds->len) {
236 ds->str = (Dstr_char_t*) dRealloc (ds->str, n_sz*sizeof(Dstr_char_t));
237 ds->sz = n_sz;
238 } else {
239 dFree(ds->str);
240 ds->str = dNew(Dstr_char_t, n_sz);
241 ds->sz = n_sz;
242 ds->len = 0;
243 ds->str[0] = 0;
244 }
245 }
246 }
247
248 /*
249 * Create a new string with a given size.
250 * Initialized to ""
251 */
dStr_sized_new(int sz)252 Dstr *dStr_sized_new (int sz)
253 {
254 Dstr *ds;
255 if (sz < 2)
256 sz = 2;
257
258 ds = dNew(Dstr, 1);
259 ds->str = NULL;
260 dStr_resize(ds, sz + 1, 0); /* (sz + 1) for the extra '\0' */
261 return ds;
262 }
263
264 /*
265 * Return memory if there's too much allocated
266 */
dStr_fit(Dstr * ds)267 void dStr_fit (Dstr *ds)
268 {
269 dStr_resize(ds, ds->len + 1, 1);
270 }
271
272 /*
273 * Insert a C string, at a given position, into a Dstr (providing length).
274 * Note: It also works with embedded nil characters.
275 */
dStr_insert_l(Dstr * ds,int pos_0,const char * s,int l)276 void dStr_insert_l (Dstr *ds, int pos_0, const char *s, int l)
277 {
278 int n_sz;
279
280 if (ds && s && l && pos_0 >= 0 && pos_0 <= ds->len) {
281 for (n_sz = ds->sz; ds->len + l >= n_sz; n_sz *= 2);
282 if (n_sz > ds->sz) {
283 dStr_resize(ds, n_sz, (ds->len > 0) ? 1 : 0);
284 }
285 if (pos_0 < ds->len)
286 memmove(ds->str+pos_0+l, ds->str+pos_0, ds->len-pos_0);
287 memcpy(ds->str+pos_0, s, l);
288 ds->len += l;
289 ds->str[ds->len] = 0;
290 }
291 }
292
293 /*
294 * Insert a C string, at a given position, into a Dstr
295 */
dStr_insert(Dstr * ds,int pos_0,const char * s)296 void dStr_insert (Dstr *ds, int pos_0, const char *s)
297 {
298 if (s)
299 dStr_insert_l(ds, pos_0, s, strlen(s));
300 }
301
302 /*
303 * Append a C string to a Dstr (providing length).
304 * Note: It also works with embedded nil characters.
305 */
dStr_append_l(Dstr * ds,const char * s,int l)306 void dStr_append_l (Dstr *ds, const char *s, int l)
307 {
308 dStr_insert_l(ds, ds->len, s, l);
309 }
310
311 /*
312 * Append a C string to a Dstr.
313 */
dStr_append(Dstr * ds,const char * s)314 void dStr_append (Dstr *ds, const char *s)
315 {
316 dStr_append_l(ds, s, strlen(s));
317 }
318
319 /*
320 * Create a new string.
321 * Initialized to 's' or empty if 's == NULL'
322 */
dStr_new(const char * s)323 Dstr *dStr_new (const char *s)
324 {
325 Dstr *ds = dStr_sized_new(0);
326 if (s && *s)
327 dStr_append(ds, s);
328 return ds;
329 }
330
331 /*
332 * Free a dillo string.
333 * if 'all' free everything, else free the structure only.
334 */
dStr_free(Dstr * ds,int all)335 void dStr_free (Dstr *ds, int all)
336 {
337 if (ds) {
338 if (all)
339 dFree(ds->str);
340 dFree(ds);
341 }
342 }
343
344 /*
345 * Append one character.
346 */
dStr_append_c(Dstr * ds,int c)347 void dStr_append_c (Dstr *ds, int c)
348 {
349 char cs[2];
350
351 if (ds) {
352 if (ds->sz > ds->len + 1) {
353 ds->str[ds->len++] = (Dstr_char_t)c;
354 ds->str[ds->len] = 0;
355 } else {
356 cs[0] = (Dstr_char_t)c;
357 cs[1] = 0;
358 dStr_append_l (ds, cs, 1);
359 }
360 }
361 }
362
363 /*
364 * Truncate a Dstr to be 'len' bytes long.
365 */
dStr_truncate(Dstr * ds,int len)366 void dStr_truncate (Dstr *ds, int len)
367 {
368 if (ds && len < ds->len) {
369 ds->str[len] = 0;
370 ds->len = len;
371 }
372 }
373
374 /*
375 * Clear a Dstr.
376 */
dStr_shred(Dstr * ds)377 void dStr_shred (Dstr *ds)
378 {
379 if (ds && ds->sz > 0)
380 memset(ds->str, '\0', ds->sz);
381 }
382
383 /*
384 * Erase a substring.
385 */
dStr_erase(Dstr * ds,int pos_0,int len)386 void dStr_erase (Dstr *ds, int pos_0, int len)
387 {
388 if (ds && pos_0 >= 0 && len > 0 && pos_0 + len <= ds->len) {
389 memmove(ds->str + pos_0, ds->str + pos_0 + len, ds->len - pos_0 - len);
390 ds->len -= len;
391 ds->str[ds->len] = 0;
392 }
393 }
394
395 /*
396 * vsprintf-like function that appends.
397 * Used by: dStr_vsprintf(), dStr_sprintf() and dStr_sprintfa().
398 */
dStr_vsprintfa(Dstr * ds,const char * format,va_list argp)399 void dStr_vsprintfa (Dstr *ds, const char *format, va_list argp)
400 {
401 int n, n_sz;
402
403 if (ds && format) {
404 va_list argp2; /* Needed in case of looping on non-32bit arch */
405 while (1) {
406 va_copy(argp2, argp);
407 n = vsnprintf(ds->str + ds->len, ds->sz - ds->len, format, argp2);
408 va_end(argp2);
409 #if defined(__sgi)
410 /* IRIX does not conform to C99; if the entire argument did not fit
411 * into the buffer, n = buffer space used (minus 1 for terminator)
412 */
413 if (n > -1 && n + 1 < ds->sz - ds->len) {
414 ds->len += n; /* Success! */
415 break;
416 } else {
417 n_sz = ds->sz * 2;
418 }
419 #else
420 if (n > -1 && n < ds->sz - ds->len) {
421 ds->len += n; /* Success! */
422 break;
423 } else if (n > -1) { /* glibc >= 2.1 */
424 n_sz = ds->len + n + 1;
425 } else { /* old glibc */
426 n_sz = ds->sz * 2;
427 }
428 #endif
429 dStr_resize(ds, n_sz, (ds->len > 0) ? 1 : 0);
430 }
431 }
432 }
433
434 /*
435 * vsprintf-like function.
436 */
dStr_vsprintf(Dstr * ds,const char * format,va_list argp)437 void dStr_vsprintf (Dstr *ds, const char *format, va_list argp)
438 {
439 if (ds) {
440 dStr_truncate(ds, 0);
441 dStr_vsprintfa(ds, format, argp);
442 }
443 }
444
445 /*
446 * Printf-like function
447 */
dStr_sprintf(Dstr * ds,const char * format,...)448 void dStr_sprintf (Dstr *ds, const char *format, ...)
449 {
450 va_list argp;
451
452 if (ds && format) {
453 va_start(argp, format);
454 dStr_vsprintf(ds, format, argp);
455 va_end(argp);
456 }
457 }
458
459 /*
460 * Printf-like function that appends.
461 */
dStr_sprintfa(Dstr * ds,const char * format,...)462 void dStr_sprintfa (Dstr *ds, const char *format, ...)
463 {
464 va_list argp;
465
466 if (ds && format) {
467 va_start(argp, format);
468 dStr_vsprintfa(ds, format, argp);
469 va_end(argp);
470 }
471 }
472
473 /*
474 * Compare two dStrs.
475 */
dStr_cmp(Dstr * ds1,Dstr * ds2)476 int dStr_cmp(Dstr *ds1, Dstr *ds2)
477 {
478 int ret = 0;
479
480 if (ds1 && ds2)
481 ret = memcmp(ds1->str, ds2->str, MIN(ds1->len+1, ds2->len+1));
482 return ret;
483 }
484
485 /*
486 * Return a pointer to the first occurrence of needle in haystack.
487 */
dStr_memmem(Dstr * haystack,Dstr * needle)488 char *dStr_memmem(Dstr *haystack, Dstr *needle)
489 {
490 int i;
491
492 if (needle && haystack) {
493 if (needle->len == 0)
494 return haystack->str;
495
496 for (i = 0; i <= (haystack->len - needle->len); i++) {
497 if (haystack->str[i] == needle->str[0] &&
498 !memcmp(haystack->str + i, needle->str, needle->len))
499 return haystack->str + i;
500 }
501 }
502 return NULL;
503 }
504
505 /*
506 * Return a printable representation of the provided Dstr, limited to a length
507 * of roughly maxlen.
508 *
509 * This is NOT threadsafe.
510 */
dStr_printable(Dstr * in,int maxlen)511 const char *dStr_printable(Dstr *in, int maxlen)
512 {
513 int i;
514 static const char *const HEX = "0123456789ABCDEF";
515 static Dstr *out = NULL;
516
517 if (in == NULL)
518 return NULL;
519
520 if (out)
521 dStr_truncate(out, 0);
522 else
523 out = dStr_sized_new(in->len);
524
525 for (i = 0; (i < in->len) && (out->len < maxlen); ++i) {
526 if (isprint(in->str[i]) || (in->str[i] == '\n')) {
527 dStr_append_c(out, in->str[i]);
528 } else {
529 dStr_append_l(out, "\\x", 2);
530 dStr_append_c(out, HEX[(in->str[i] >> 4) & 15]);
531 dStr_append_c(out, HEX[in->str[i] & 15]);
532 }
533 }
534 if (out->len >= maxlen)
535 dStr_append(out, "...");
536 return out->str;
537 }
538
539 /*
540 *- dList ---------------------------------------------------------------------
541 */
542
543 /*
544 * Create a new empty list
545 */
dList_new(int size)546 Dlist *dList_new(int size)
547 {
548 Dlist *l;
549 if (size <= 0)
550 return NULL;
551
552 l = dNew(Dlist, 1);
553 l->len = 0;
554 l->sz = size;
555 l->list = dNew(void*, l->sz);
556 return l;
557 }
558
559 /*
560 * Free a list (not its elements)
561 */
dList_free(Dlist * lp)562 void dList_free (Dlist *lp)
563 {
564 if (!lp)
565 return;
566
567 dFree(lp->list);
568 dFree(lp);
569 }
570
571 /*
572 * Insert an element at a given position [0 based]
573 */
dList_insert_pos(Dlist * lp,void * data,int pos0)574 void dList_insert_pos (Dlist *lp, void *data, int pos0)
575 {
576 int i;
577
578 if (!lp || pos0 < 0 || pos0 > lp->len)
579 return;
580
581 if (lp->sz == lp->len) {
582 lp->sz *= 2;
583 lp->list = (void**) dRealloc (lp->list, lp->sz*sizeof(void*));
584 }
585 ++lp->len;
586
587 for (i = lp->len - 1; i > pos0; --i)
588 lp->list[i] = lp->list[i - 1];
589 lp->list[pos0] = data;
590 }
591
592 /*
593 * Append a data item to the list
594 */
dList_append(Dlist * lp,void * data)595 void dList_append (Dlist *lp, void *data)
596 {
597 dList_insert_pos(lp, data, lp->len);
598 }
599
600 /*
601 * Prepend a data item to the list
602 */
dList_prepend(Dlist * lp,void * data)603 void dList_prepend (Dlist *lp, void *data)
604 {
605 dList_insert_pos(lp, data, 0);
606 }
607
608 /*
609 * For completing the ADT.
610 */
dList_length(Dlist * lp)611 int dList_length (Dlist *lp)
612 {
613 if (!lp)
614 return 0;
615 return lp->len;
616 }
617
618 /*
619 * Remove a data item without preserving order.
620 */
dList_remove_fast(Dlist * lp,const void * data)621 void dList_remove_fast (Dlist *lp, const void *data)
622 {
623 int i;
624
625 if (!lp)
626 return;
627
628 for (i = 0; i < lp->len; ++i) {
629 if (lp->list[i] == data) {
630 lp->list[i] = lp->list[--lp->len];
631 break;
632 }
633 }
634 }
635
636 /*
637 * Remove a data item preserving order.
638 */
dList_remove(Dlist * lp,const void * data)639 void dList_remove (Dlist *lp, const void *data)
640 {
641 int i, j;
642
643 if (!lp)
644 return;
645
646 for (i = 0; i < lp->len; ++i) {
647 if (lp->list[i] == data) {
648 --lp->len;
649 for (j = i; j < lp->len; ++j)
650 lp->list[j] = lp->list[j + 1];
651 break;
652 }
653 }
654 }
655
656 /*
657 * Return the nth data item,
658 * NULL when not found or 'n0' is out of range
659 */
dList_nth_data(Dlist * lp,int n0)660 void *dList_nth_data (Dlist *lp, int n0)
661 {
662 if (!lp || n0 < 0 || n0 >= lp->len)
663 return NULL;
664 return lp->list[n0];
665 }
666
667 /*
668 * Return the found data item, or NULL if not present.
669 */
dList_find(Dlist * lp,const void * data)670 void *dList_find (Dlist *lp, const void *data)
671 {
672 int i = dList_find_idx(lp, data);
673 return (i >= 0) ? lp->list[i] : NULL;
674 }
675
676 /*
677 * Search a data item.
678 * Return value: its index if found, -1 if not present.
679 * (this is useful for a list of integers, for finding number zero).
680 */
dList_find_idx(Dlist * lp,const void * data)681 int dList_find_idx (Dlist *lp, const void *data)
682 {
683 int i, ret = -1;
684
685 if (!lp)
686 return ret;
687
688 for (i = 0; i < lp->len; ++i) {
689 if (lp->list[i] == data) {
690 ret = i;
691 break;
692 }
693 }
694 return ret;
695 }
696
697 /*
698 * Search a data item using a custom function.
699 * func() is given the list item and the user data as parameters.
700 * Return: data item when found, NULL otherwise.
701 */
dList_find_custom(Dlist * lp,const void * data,dCompareFunc func)702 void *dList_find_custom (Dlist *lp, const void *data, dCompareFunc func)
703 {
704 int i;
705 void *ret = NULL;
706
707 if (!lp)
708 return ret;
709
710 for (i = 0; i < lp->len; ++i) {
711 if (func(lp->list[i], data) == 0) {
712 ret = lp->list[i];
713 break;
714 }
715 }
716 return ret;
717 }
718
719 /*
720 * QuickSort implementation.
721 * This allows for a simple compare function for all the ADT.
722 */
QuickSort(void ** left,void ** right,dCompareFunc compare)723 static void QuickSort(void **left, void **right, dCompareFunc compare)
724 {
725 void **p = left, **q = right, **t = left;
726
727 while (1) {
728 while (p != t && compare(*p, *t) < 0)
729 ++p;
730 while (q != t && compare(*q, *t) > 0)
731 --q;
732 if (p > q)
733 break;
734 if (p < q) {
735 void *tmp = *p;
736 *p = *q;
737 *q = tmp;
738 if (t == p)
739 t = q;
740 else if (t == q)
741 t = p;
742 }
743 if (++p > --q)
744 break;
745 }
746
747 if (left < q)
748 QuickSort(left, q, compare);
749 if (p < right)
750 QuickSort(p, right, compare);
751 }
752
753 /*
754 * Sort the list using a custom function
755 */
dList_sort(Dlist * lp,dCompareFunc func)756 void dList_sort (Dlist *lp, dCompareFunc func)
757 {
758 if (lp && lp->len > 1) {
759 QuickSort(lp->list, lp->list + lp->len - 1, func);
760 }
761 }
762
763 /*
764 * Insert an element into a sorted list.
765 * The comparison function receives two list elements.
766 */
dList_insert_sorted(Dlist * lp,void * data,dCompareFunc func)767 void dList_insert_sorted (Dlist *lp, void *data, dCompareFunc func)
768 {
769 int i, st, min, max;
770
771 if (lp) {
772 min = st = i = 0;
773 max = lp->len - 1;
774 while (min <= max) {
775 i = (min + max) / 2;
776 st = func(lp->list[i], data);
777 if (st < 0) {
778 min = i + 1;
779 } else if (st > 0) {
780 max = i - 1;
781 } else {
782 break;
783 }
784 }
785 dList_insert_pos(lp, data, (st >= 0) ? i : i+1);
786 }
787 }
788
789 /*
790 * Search a sorted list.
791 * Return the found data item, or NULL if not present.
792 * func() is given the list item and the user data as parameters.
793 */
dList_find_sorted(Dlist * lp,const void * data,dCompareFunc func)794 void *dList_find_sorted (Dlist *lp, const void *data, dCompareFunc func)
795 {
796 int i, st, min, max;
797 void *ret = NULL;
798
799 if (lp && lp->len) {
800 min = 0;
801 max = lp->len - 1;
802 while (min <= max) {
803 i = (min + max) / 2;
804 st = func(lp->list[i], data);
805 if (st < 0) {
806 min = i + 1;
807 } else if (st > 0) {
808 max = i - 1;
809 } else {
810 ret = lp->list[i];
811 break;
812 }
813 }
814 }
815
816 return ret;
817 }
818
819 /*
820 *- Parse function ------------------------------------------------------------
821 */
822
823 /*
824 * Take a dillo rc line and return 'name' and 'value' pointers to it.
825 * Notes:
826 * - line is modified!
827 * - it skips blank lines and lines starting with '#'
828 *
829 * Return value: 1 on blank line or comment, 0 on successful value/pair,
830 * -1 otherwise.
831 */
dParser_parse_rc_line(char ** line,char ** name,char ** value)832 int dParser_parse_rc_line(char **line, char **name, char **value)
833 {
834 char *eq, *p;
835 int len, ret = -1;
836
837 dReturn_val_if_fail(*line, ret);
838
839 *name = NULL;
840 *value = NULL;
841 dStrstrip(*line);
842 if (!*line[0] || *line[0] == '#') {
843 /* blank line or comment */
844 ret = 1;
845 } else if ((eq = strchr(*line, '='))) {
846 /* get name */
847 for (p = *line; *p && *p != '=' && !dIsspace(*p); ++p);
848 *p = 0;
849 *name = *line;
850
851 /* skip whitespace */
852 if (p < eq)
853 for (++p; dIsspace(*p); ++p);
854
855 /* get value */
856 if (p == eq) {
857 for (++p; dIsspace(*p); ++p);
858 len = strlen(p);
859 if (len >= 2 && *p == '"' && p[len-1] == '"') {
860 p[len-1] = 0;
861 ++p;
862 }
863 *value = p;
864 ret = 0;
865 }
866 }
867
868 return ret;
869 }
870
871 /*
872 *- Dlib messages -------------------------------------------------------------
873 */
dLib_show_messages(bool_t show)874 void dLib_show_messages(bool_t show)
875 {
876 dLib_show_msg = show;
877 }
878
879 /*
880 *- Misc utility functions ----------------------------------------------------
881 */
882
883 /*
884 * Return the current working directory in a new string
885 */
dGetcwd()886 char *dGetcwd ()
887 {
888 size_t size = 128;
889
890 while (1) {
891 char *buffer = dNew(char, size);
892 if (getcwd (buffer, size) == buffer)
893 return buffer;
894 dFree (buffer);
895 if (errno != ERANGE)
896 return 0;
897 size *= 2;
898 }
899 }
900
901 /*
902 * Return the home directory in a static string (don't free)
903 */
dGethomedir()904 char *dGethomedir ()
905 {
906 static char *homedir = NULL;
907
908 if (!homedir) {
909 if (getenv("HOME")) {
910 homedir = dStrdup(getenv("HOME"));
911
912 } else if (getenv("HOMEDRIVE") && getenv("HOMEPATH")) {
913 homedir = dStrconcat(getenv("HOMEDRIVE"), getenv("HOMEPATH"), NULL);
914 } else {
915 DLIB_MSG("dGethomedir: $HOME not set, using '/'.\n");
916 homedir = dStrdup("/");
917 }
918 }
919 return homedir;
920 }
921
922 /*
923 * Get a line from a FILE stream.
924 * Return value: read line on success, NULL on EOF.
925 */
dGetline(FILE * stream)926 char *dGetline (FILE *stream)
927 {
928 int ch;
929 Dstr *dstr;
930 char *line;
931
932 dReturn_val_if_fail (stream, 0);
933
934 dstr = dStr_sized_new(64);
935 while ((ch = fgetc(stream)) != EOF) {
936 dStr_append_c(dstr, ch);
937 if (ch == '\n')
938 break;
939 }
940
941 line = (dstr->len) ? dstr->str : NULL;
942 dStr_free(dstr, (line) ? 0 : 1);
943 return line;
944 }
945
946 /*
947 * Close a FD handling EINTR.
948 */
dClose(int fd)949 int dClose(int fd)
950 {
951 int st;
952
953 do
954 st = close(fd);
955 while (st == -1 && errno == EINTR);
956 return st;
957 }
958