Version bump.
[doldaconnect.git] / common / utils.c
CommitLineData
d3372da9 1/*
2 * Dolda Connect - Modular multiuser Direct Connect-style client
3 * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
b5010caa 19#include <stdlib.h>
d3372da9 20#include <stdarg.h>
21#include <stdio.h>
22#include <wchar.h>
23#include <iconv.h>
24#include <errno.h>
25#include <string.h>
26#include <wctype.h>
27#include <langinfo.h>
28#include <pwd.h>
29#include <unistd.h>
30#include <sys/time.h>
31#include <netinet/in.h>
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
8b17e919 36#include <utils.h>
37#include <log.h>
d3372da9 38
39static char *base64set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
40static int base64rev[] = {
41 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
42 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
44 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
45 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
46 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
47 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
48 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
49 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
50 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
51 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
55 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
56 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
57};
58static char *base32set = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
59static int base32rev[] = {
60 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
61 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63 -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1,
64 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
65 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
66 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
67 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
68 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
69 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
70 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
71 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
72 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
75 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
76};
77
78char *vsprintf2(char *format, va_list al)
79{
80 int ret;
81 char *buf;
82
83 ret = vsnprintf(NULL, 0, format, al);
84 if((buf = malloc(ret + 1)) == NULL)
85 {
86 LOGOOM(ret + 1);
87 return(NULL);
88 }
89 vsnprintf(buf, ret + 1, format, al);
90 return(buf);
91}
92
93char *sprintf2(char *format, ...)
94{
95 va_list args;
96 char *buf;
97
98 va_start(args, format);
99 buf = vsprintf2(format, args);
100 va_end(args);
101 return(buf);
102}
103
104wchar_t *vswprintf2(wchar_t *format, va_list al)
105{
106 int ret;
107 wchar_t *buf;
108 size_t bufsize;
109
110 buf = smalloc(sizeof(wchar_t) * (bufsize = 1024));
111 while((ret = vswprintf(buf, bufsize, format, al)) < 0)
112 buf = srealloc(buf, sizeof(wchar_t) * (bufsize *= 2));
113 if(bufsize > ret + 1)
114 buf = srealloc(buf, sizeof(wchar_t) * (ret + 1));
115 return(buf);
116}
117
118wchar_t *swprintf2(wchar_t *format, ...)
119{
120 va_list args;
121 wchar_t *buf;
122
123 va_start(args, format);
124 buf = vswprintf2(format, args);
125 va_end(args);
126 return(buf);
127}
128
edccab15 129int havecharset(char *charset)
130{
131 iconv_t cd;
132
133 if((cd = iconv_open("wchar_t", charset)) == (iconv_t)-1)
134 return(0);
135 iconv_close(cd);
136 if((cd = iconv_open(charset, "wchar_t")) == (iconv_t)-1)
137 return(0);
138 iconv_close(cd);
139 return(1);
140}
141
d3372da9 142wchar_t *icmbstowcs(char *mbs, char *charset)
143{
144 int ret;
145 char *buf;
146 char *p, *p2;
147 size_t len1, len2, bufsize, data;
148 iconv_t cd;
149
150 len1 = strlen(mbs) + 1;
151 bufsize = len2 = len1 * sizeof(wchar_t);
152 if((buf = malloc(bufsize)) == NULL)
153 {
154 LOGOOM(bufsize);
155 return(NULL);
156 }
157 if(charset == NULL)
158 charset = nl_langinfo(CODESET);
159 if((cd = iconv_open("wchar_t", charset)) == (iconv_t)-1)
160 {
8b17e919 161#ifdef DAEMON
d3372da9 162 flog(LOG_ERR, "icmbstowcs: could not open iconv structure for %s: %s", charset, strerror(errno));
8b17e919 163#endif
d3372da9 164 free(buf);
165 return(NULL);
166 }
167 p = buf;
168 while(len1 > 0)
169 {
170 ret = iconv(cd, &mbs, &len1, &p, &len2);
171 if(ret < 0)
172 {
173 if(errno == E2BIG)
174 {
175 data = p - buf;
176 len2 += 128;
177 bufsize += 128;
178 if((p2 = realloc(buf, bufsize)) == NULL)
179 {
180 LOGOOM(bufsize);
181 free(buf);
182 iconv_close(cd);
183 return(NULL);
184 }
185 buf = p2;
186 p = buf + data;
187 } else {
188 free(buf);
189 iconv_close(cd);
190 return(NULL);
191 }
192 }
193 }
194 if(len2 > 0)
195 buf = realloc(buf, p - buf);
196 iconv_close(cd);
197 return((wchar_t *)buf);
198}
199
200wchar_t *icsmbstowcs(char *mbs, char *charset, wchar_t *def)
201{
202 static wchar_t *buf = NULL;
203
204 if(buf != NULL)
205 free(buf);
206 if((buf = icmbstowcs(mbs, charset)) == NULL)
207 {
96cf7d1f 208 if((def != NULL) && (*def == L'~'))
d3372da9 209 {
8b17e919 210#ifdef DAEMON
d3372da9 211 flog(LOG_WARNING, "icsmbstowcs: could not convert wcs string into charset %s: %s", charset, strerror(errno));
8b17e919 212#endif
d3372da9 213 def++;
214 }
215 return(def);
216 }
217 return(buf);
218}
219
220char *icwcstombs(wchar_t *wcs, char *charset)
221{
222 int ret;
223 char *buf;
224 char *p, *p2;
225 size_t len1, len2, bufsize, data;
226 iconv_t cd;
227
228 len1 = sizeof(wchar_t) * (wcslen(wcs) + 1);
229 bufsize = len2 = len1;
230 if((buf = malloc(bufsize)) == NULL)
231 {
8b17e919 232#ifdef DAEMON
d3372da9 233 LOGOOM(bufsize);
8b17e919 234#endif
d3372da9 235 return(NULL);
236 }
237 if(charset == NULL)
238 charset = nl_langinfo(CODESET);
239 if((cd = iconv_open(charset, "wchar_t")) == (iconv_t)-1)
240 {
8b17e919 241#ifdef DAEMON
d3372da9 242 flog(LOG_ERR, "icwcstombs: could not open iconv structure for %s: %s", charset, strerror(errno));
8b17e919 243#endif
d3372da9 244 free(buf);
245 return(NULL);
246 }
247 p = buf;
248 while(len1 > 0)
249 {
250 ret = iconv(cd, (char **)&wcs, &len1, &p, &len2);
251 if(ret < 0)
252 {
253 if(errno == E2BIG)
254 {
255 data = p - buf;
256 len2 += 128;
257 bufsize += 128;
258 if((p2 = realloc(buf, bufsize)) == NULL)
259 {
260 LOGOOM(bufsize);
261 free(buf);
262 iconv_close(cd);
263 return(NULL);
264 }
265 buf = p2;
266 p = buf + data;
267 } else {
268 free(buf);
269 iconv_close(cd);
270 return(NULL);
271 }
272 }
273 }
274 if(len2 > 0)
275 buf = realloc(buf, p - buf);
276 iconv_close(cd);
277 return(buf);
278}
279
280char *icswcstombs(wchar_t *wcs, char *charset, char *def)
281{
282 static char *buf = NULL;
283
284 if(buf != NULL)
285 free(buf);
286 if((buf = icwcstombs(wcs, charset)) == NULL)
287 {
96cf7d1f 288 if((def != NULL) && (*def == '~'))
d3372da9 289 {
8b17e919 290#ifdef DAEMON
d3372da9 291 flog(LOG_WARNING, "icswcstombs: could not convert mbs string from charset %s: %s", charset, strerror(errno));
8b17e919 292#endif
d3372da9 293 def++;
294 }
295 return(def);
296 }
297 return(buf);
298}
299
300wchar_t *wcstolower(wchar_t *wcs)
301{
302 wchar_t *p;
303
304 for(p = wcs; *p != L'\0'; p++)
305 *p = towlower(*p);
306 return(wcs);
307}
308
309wchar_t ucptowc(int ucp)
310{
311 int ret;
312 unsigned long ucpbuf;
313 char *buf;
314 char *mbsp, *p, *p2;
315 wchar_t res;
316 size_t len1, len2, bufsize, data;
317 iconv_t cd;
318
319 ucpbuf = htonl(ucp);
320 mbsp = (char *)&ucpbuf;
321 len1 = 4;
322 bufsize = len2 = len1 * sizeof(wchar_t);
323 if((buf = malloc(bufsize)) == NULL)
324 {
325 LOGOOM(bufsize);
326 return(L'\0');
327 }
328 if((cd = iconv_open("wchar_t", "UCS-4BE")) == (iconv_t)-1)
329 {
8b17e919 330#ifdef DAEMON
d3372da9 331 flog(LOG_ERR, "ucptowc: could not open iconv structure for UCS-4BE: %s", strerror(errno));
8b17e919 332#endif
d3372da9 333 free(buf);
334 return(L'\0');
335 }
336 p = buf;
337 while(len1 > 0)
338 {
339 ret = iconv(cd, &mbsp, &len1, &p, &len2);
340 if(ret < 0)
341 {
342 if(errno == E2BIG)
343 {
344 data = p - buf;
345 len2 += 128;
346 bufsize += 128;
347 if((p2 = realloc(buf, bufsize)) == NULL)
348 {
349 LOGOOM(bufsize);
350 free(buf);
351 iconv_close(cd);
352 return(L'\0');
353 }
354 buf = p2;
355 p = buf + data;
356 } else {
357 free(buf);
358 iconv_close(cd);
359 return(L'\0');
360 }
361 }
362 }
363 if(len2 > 0)
364 buf = realloc(buf, p - buf);
365 iconv_close(cd);
366 res = *(wchar_t *)buf;
367 free(buf);
368 return(res);
369}
370
371void _sizebuf(void **buf, size_t *bufsize, size_t reqsize, size_t elsize, int algo)
372{
373 if(*bufsize >= reqsize)
374 return;
375 switch(algo)
376 {
377 case 0:
378 *buf = srealloc(*buf, elsize * ((*bufsize) = reqsize));
379 break;
380 case 1:
381 if(*bufsize == 0)
382 *bufsize = 1;
383 while(*bufsize < reqsize)
384 *bufsize <<= 1;
385 *buf = srealloc(*buf, elsize * (*bufsize));
386 break;
387 }
388}
389
390double ntime(void)
391{
392 struct timeval tv;
393
394 gettimeofday(&tv, NULL);
395 return((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
396}
397
398int wcsexists(wchar_t *h, wchar_t *n)
399{
400 int i, o, nl, hl;
401 wchar_t *ln, *lh;
402
403 ln = alloca(sizeof(*ln) * (nl = wcslen(n)));
404 for(i = 0; i < nl; i++)
405 ln[i] = towlower(n[i]);
406 lh = alloca(sizeof(*lh) * (hl = wcslen(h)));
407 if(nl > hl)
408 return(0);
409 for(i = 0; i < nl; i++)
410 lh[i] = towlower(h[i]);
411 i = 0;
412 while(1)
413 {
414 for(o = 0; o < nl; o++)
415 {
416 if(lh[i + o] != ln[o])
417 break;
418 }
419 if(o == nl)
420 return(1);
421 if(i == hl - nl)
422 return(0);
423 lh[i + nl] = towlower(h[i + nl]);
424 i++;
425 }
426}
427
428#ifndef HAVE_WCSCASECMP
429int wcscasecmp(const wchar_t *s1, const wchar_t *s2)
430{
431 while(towlower(*s1) == towlower(*s2))
432 {
433 if(*s1 == L'\0')
434 return(0);
435 }
436 return(towlower(*s1) - towlower(*s2));
437}
438#endif
439
440char *hexencode(char *data, size_t datalen)
441{
442 char *buf, this;
443 size_t bufsize, bufdata;
444 int dig;
445
446 buf = NULL;
447 bufsize = bufdata = 0;
448 for(; datalen > 0; datalen--, data++)
449 {
450 dig = (*data & 0xF0) >> 4;
451 if(dig > 9)
452 this = 'A' + dig - 10;
453 else
454 this = dig + '0';
455 addtobuf(buf, this);
456 dig = *data & 0x0F;
457 if(dig > 9)
458 this = 'A' + dig - 10;
459 else
460 this = dig + '0';
461 addtobuf(buf, this);
462 }
463 addtobuf(buf, 0);
464 return(buf);
465}
466
467char *hexdecode(char *data, size_t *len)
468{
469 char *buf, this;
470 size_t bufsize, bufdata;
471
472 buf = NULL;
473 bufsize = bufdata = 0;
474 for(; *data; data++)
475 {
476 if((*data >= 'A') && (*data <= 'F'))
477 {
478 this = (this & 0x0F) | ((*data - 'A' + 10) << 4);
479 } else if((*data >= '0') && (*data <= '9')) {
480 this = (this & 0x0F) | ((*data - '0') << 4);
481 } else {
482 if(buf != NULL)
483 free(buf);
484 return(NULL);
485 }
486 data++;
487 if(!*data)
488 {
489 if(buf != NULL)
490 free(buf);
491 return(NULL);
492 }
493 if((*data >= 'A') && (*data <= 'F'))
494 {
495 this = (this & 0xF0) | (*data - 'A' + 10);
496 } else if((*data >= '0') && (*data <= '9')) {
497 this = (this & 0xF0) | (*data - '0');
498 } else {
499 if(buf != NULL)
500 free(buf);
501 return(NULL);
502 }
503 addtobuf(buf, this);
504 }
505 addtobuf(buf, 0);
506 if(len != NULL)
507 *len = bufdata - 1;
508 return(buf);
509}
510
511char *base64encode(char *data, size_t datalen)
512{
513 char *buf;
514 size_t bufsize, bufdata;
515
516 if(datalen == 0)
517 return(sstrdup(""));
518 buf = NULL;
519 bufsize = bufdata = 0;
520 while(datalen >= 3)
521 {
522 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
523 addtobuf(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
524 addtobuf(buf, base64set[((data[1] & 0x0f) << 2) | ((data[2] & 0xc0) >> 6)]);
525 addtobuf(buf, base64set[data[2] & 0x3f]);
526 datalen -= 3;
527 data += 3;
528 }
529 if(datalen == 1)
530 {
531 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
532 addtobuf(buf, base64set[(data[0] & 0x03) << 4]);
533 bufcat(buf, "==", 2);
534 }
535 if(datalen == 2)
536 {
537 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
538 addtobuf(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
539 addtobuf(buf, base64set[(data[1] & 0x0f) << 2]);
540 addtobuf(buf, '=');
541 }
542 addtobuf(buf, 0);
543 return(buf);
544}
545
546char *base64decode(char *data, size_t *datalen)
547{
548 int b, c;
549 char *buf, cur;
550 size_t bufsize, bufdata;
551
552 buf = NULL;
553 bufsize = bufdata = 0;
554 cur = 0;
555 b = 8;
556 for(; *data > 0; data++)
557 {
558 c = (int)(unsigned char)*data;
559 if(c == '=')
560 break;
65399bc2 561 if(c == '\n')
562 continue;
d3372da9 563 if(base64rev[c] == -1)
564 {
565 if(buf != NULL)
566 free(buf);
567 return(NULL);
568 }
569 b -= 6;
570 if(b <= 0)
571 {
572 cur |= base64rev[c] >> -b;
573 addtobuf(buf, cur);
574 b += 8;
575 cur = 0;
576 }
577 cur |= base64rev[c] << b;
578 }
579 if(datalen != NULL)
580 *datalen = bufdata;
581 addtobuf(buf, 0);
582 return(buf);
583}
584
585char *base32encode(char *data, size_t datalen)
586{
587 char *buf;
588 size_t bufsize, bufdata;
589
590 if(datalen == 0)
591 return(sstrdup(""));
592 buf = NULL;
593 bufsize = bufdata = 0;
594 while(datalen >= 5)
595 {
596 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
597 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
598 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
599 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
600 addtobuf(buf, base32set[((data[2] & 0x0f) << 1) | ((data[3] & 0x80) >> 7)]);
601 addtobuf(buf, base32set[((data[3] & 0x7c) >> 2)]);
602 addtobuf(buf, base32set[((data[3] & 0x03) << 3) | ((data[4] & 0xe0) >> 5)]);
603 addtobuf(buf, base32set[data[4] & 0x1f]);
604 datalen -= 5;
605 data += 5;
606 }
607 if(datalen == 1)
608 {
609 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
610 addtobuf(buf, base32set[((data[0] & 0x07) << 2)]);
611 bufcat(buf, "======", 6);
612 }
613 if(datalen == 2)
614 {
615 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
616 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
617 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
618 addtobuf(buf, base32set[((data[1] & 0x01) << 4)]);
619 bufcat(buf, "====", 4);
620 }
621 if(datalen == 3)
622 {
623 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
624 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
625 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
626 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
627 addtobuf(buf, base32set[((data[2] & 0x0f) << 1)]);
628 bufcat(buf, "===", 3);
629 }
630 if(datalen == 4)
631 {
632 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
633 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
634 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
635 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
636 addtobuf(buf, base32set[((data[2] & 0x0f) << 1) | ((data[3] & 0x80) >> 7)]);
637 addtobuf(buf, base32set[((data[3] & 0x7c) >> 2)]);
638 addtobuf(buf, base32set[((data[3] & 0x03) << 3)]);
639 bufcat(buf, "=", 1);
640 }
641 addtobuf(buf, 0);
642 return(buf);
643}
644
645char *base32decode(char *data, size_t *datalen)
646{
647 int b, c;
648 char *buf, cur;
649 size_t bufsize, bufdata;
650
651 buf = NULL;
652 bufsize = bufdata = 0;
653 cur = 0;
654 b = 8;
655 for(; *data > 0; data++)
656 {
657 c = (int)(unsigned char)*data;
658 if(c == '=')
659 break;
65399bc2 660 if(c == '\n')
661 continue;
d3372da9 662 if(base32rev[c] == -1)
663 {
664 if(buf != NULL)
665 free(buf);
666 return(NULL);
667 }
668 b -= 5;
669 if(b <= 0)
670 {
671 cur |= base32rev[c] >> -b;
672 addtobuf(buf, cur);
673 b += 8;
674 cur = 0;
675 }
676 cur |= base32rev[c] << b;
677 }
678 if(datalen != NULL)
679 *datalen = bufdata;
680 addtobuf(buf, 0);
681 return(buf);
682}
683
684void _freeparr(void **arr)
685{
686 void **buf;
687
688 if(arr == NULL)
689 return;
690 for(buf = arr; *buf != NULL; buf++)
691 free(*buf);
692 free(arr);
693}
694
695int _parrlen(void **arr)
696{
697 int i;
698
699 if(arr == NULL)
700 return(0);
701 for(i = 0; *arr != NULL; arr++)
702 i++;
703 return(i);
704}
705
706char *getetcpath(char *binpath)
707{
73247114 708 int f;
d3372da9 709 char *etcpath, *p;
710 size_t etcpathsize, etcpathdata;
711
712 etcpath = NULL;
713 etcpathsize = etcpathdata = 0;
73247114 714 f = 1;
d3372da9 715 do
716 {
73247114 717 if(f)
718 f = 0;
719 else
720 binpath++;
d3372da9 721 for(p = binpath; *p && (*p != ':'); p++);
722 for(; (p >= binpath) && (*p != '/'); p--);
723 if(p >= binpath)
724 {
725 if(etcpathdata > 0)
726 addtobuf(etcpath, ':');
727 bufcat(etcpath, binpath, p - binpath + 1);
728 bufcat(etcpath, "etc", 3);
729 }
730 } while((binpath = strchr(binpath, ':')) != NULL);
731 addtobuf(etcpath, 0);
732 return(etcpath);
733}
734
1df8650c 735char *findfile(char *name, char *homedir, int filldef)
d3372da9 736{
737 char *path, *binpath, *etcpath, *p;
48b2d6d1 738 struct passwd *pw;
1df8650c 739 int mode, homeonly;
d3372da9 740
1df8650c 741 if(name == NULL)
742 return(NULL);
743
41ac4371 744 mode = R_OK | (filldef ? W_OK : 0);
1df8650c 745 homeonly = homedir != NULL;
746
747 if(!strchr(name, '/'))
748 {
41ac4371 749 if(homedir == NULL)
750 homedir = getenv("HOME");
48b2d6d1 751 if((homedir == NULL) && ((pw = getpwuid(getuid())) != NULL))
752 homedir = pw->pw_dir;
1df8650c 753 if((homedir != NULL) && ((path = sprintf2("%s/.%s", homedir, name)) != NULL))
48b2d6d1 754 {
41ac4371 755 if(!access(path, mode))
48b2d6d1 756 return(path);
757 free(path);
758 }
d3372da9 759 }
1df8650c 760
761 if(!homeonly)
d3372da9 762 {
1df8650c 763 if(strchr(name, '/') != NULL)
d3372da9 764 {
1df8650c 765 if(!access(name, mode))
766 return(sstrdup(name));
d3372da9 767 } else {
768 if((binpath = getenv("PATH")) == NULL)
769 etcpath = sstrdup("/usr/local/etc:/etc:/usr/etc");
770 else
771 etcpath = getetcpath(binpath);
772 for(p = strtok(etcpath, ":"); p != NULL; p = strtok(NULL, ":"))
773 {
1df8650c 774 if((path = sprintf2("%s/%s", p, name)) != NULL)
d3372da9 775 {
41ac4371 776 if(!access(path, mode))
d3372da9 777 {
778 free(etcpath);
779 return(path);
780 }
781 free(path);
782 }
783 }
784 free(etcpath);
785 }
786 }
1df8650c 787
48b2d6d1 788 if(filldef) {
1df8650c 789 if(homedir)
790 return(sprintf2("%s/.%s", homedir, name));
791 return(sprintf2("/etc/%s", name));
48b2d6d1 792 } else {
793 return(NULL);
794 }
d3372da9 795}
9ec790e8 796
797struct wcspair *newwcspair(wchar_t *key, wchar_t *val, struct wcspair **list)
798{
799 struct wcspair *pair;
800
801 pair = smalloc(sizeof(*pair));
802 memset(pair, 0, sizeof(*pair));
803 if(key != NULL)
804 pair->key = swcsdup(key);
805 if(val != NULL)
806 pair->val = swcsdup(val);
807 if(list == NULL)
808 {
809 pair->next = NULL;
810 } else {
811 pair->next = *list;
812 *list = pair;
813 }
814 return(pair);
815}
816
817void freewcspair(struct wcspair *pair, struct wcspair **list)
818{
497fe07b 819 struct wcspair *cur;
820
821 for(cur = *list; cur != NULL; list = &(cur->next), cur = cur->next)
9ec790e8 822 {
497fe07b 823 if(cur == pair)
824 {
825 *list = cur->next;
826 break;
827 }
9ec790e8 828 }
829 free(pair->key);
830 free(pair->val);
831 free(pair);
832}
a2761258 833
834wchar_t *wpfind(struct wcspair *list, wchar_t *key)
835{
836 for(; list != NULL; list = list->next)
837 {
838 if(!wcscmp(list->key, key))
839 return(list->val);
840 }
841 return(NULL);
842}