Improve freewcspair.
[doldaconnect.git] / daemon / 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*/
19#include <malloc.h>
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
36#include "utils.h"
37#include "log.h"
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
129wchar_t *icmbstowcs(char *mbs, char *charset)
130{
131 int ret;
132 char *buf;
133 char *p, *p2;
134 size_t len1, len2, bufsize, data;
135 iconv_t cd;
136
137 len1 = strlen(mbs) + 1;
138 bufsize = len2 = len1 * sizeof(wchar_t);
139 if((buf = malloc(bufsize)) == NULL)
140 {
141 LOGOOM(bufsize);
142 return(NULL);
143 }
144 if(charset == NULL)
145 charset = nl_langinfo(CODESET);
146 if((cd = iconv_open("wchar_t", charset)) == (iconv_t)-1)
147 {
148 flog(LOG_ERR, "icmbstowcs: could not open iconv structure for %s: %s", charset, strerror(errno));
149 free(buf);
150 return(NULL);
151 }
152 p = buf;
153 while(len1 > 0)
154 {
155 ret = iconv(cd, &mbs, &len1, &p, &len2);
156 if(ret < 0)
157 {
158 if(errno == E2BIG)
159 {
160 data = p - buf;
161 len2 += 128;
162 bufsize += 128;
163 if((p2 = realloc(buf, bufsize)) == NULL)
164 {
165 LOGOOM(bufsize);
166 free(buf);
167 iconv_close(cd);
168 return(NULL);
169 }
170 buf = p2;
171 p = buf + data;
172 } else {
173 free(buf);
174 iconv_close(cd);
175 return(NULL);
176 }
177 }
178 }
179 if(len2 > 0)
180 buf = realloc(buf, p - buf);
181 iconv_close(cd);
182 return((wchar_t *)buf);
183}
184
185wchar_t *icsmbstowcs(char *mbs, char *charset, wchar_t *def)
186{
187 static wchar_t *buf = NULL;
188
189 if(buf != NULL)
190 free(buf);
191 if((buf = icmbstowcs(mbs, charset)) == NULL)
192 {
193 if(*def == '~')
194 {
195 flog(LOG_WARNING, "icsmbstowcs: could not convert wcs string into charset %s: %s", charset, strerror(errno));
196 def++;
197 }
198 return(def);
199 }
200 return(buf);
201}
202
203char *icwcstombs(wchar_t *wcs, char *charset)
204{
205 int ret;
206 char *buf;
207 char *p, *p2;
208 size_t len1, len2, bufsize, data;
209 iconv_t cd;
210
211 len1 = sizeof(wchar_t) * (wcslen(wcs) + 1);
212 bufsize = len2 = len1;
213 if((buf = malloc(bufsize)) == NULL)
214 {
215 LOGOOM(bufsize);
216 return(NULL);
217 }
218 if(charset == NULL)
219 charset = nl_langinfo(CODESET);
220 if((cd = iconv_open(charset, "wchar_t")) == (iconv_t)-1)
221 {
222 flog(LOG_ERR, "icwcstombs: could not open iconv structure for %s: %s", charset, strerror(errno));
223 free(buf);
224 return(NULL);
225 }
226 p = buf;
227 while(len1 > 0)
228 {
229 ret = iconv(cd, (char **)&wcs, &len1, &p, &len2);
230 if(ret < 0)
231 {
232 if(errno == E2BIG)
233 {
234 data = p - buf;
235 len2 += 128;
236 bufsize += 128;
237 if((p2 = realloc(buf, bufsize)) == NULL)
238 {
239 LOGOOM(bufsize);
240 free(buf);
241 iconv_close(cd);
242 return(NULL);
243 }
244 buf = p2;
245 p = buf + data;
246 } else {
247 free(buf);
248 iconv_close(cd);
249 return(NULL);
250 }
251 }
252 }
253 if(len2 > 0)
254 buf = realloc(buf, p - buf);
255 iconv_close(cd);
256 return(buf);
257}
258
259char *icswcstombs(wchar_t *wcs, char *charset, char *def)
260{
261 static char *buf = NULL;
262
263 if(buf != NULL)
264 free(buf);
265 if((buf = icwcstombs(wcs, charset)) == NULL)
266 {
267 if(*def == '~')
268 {
269 flog(LOG_WARNING, "icswcstombs: could not convert mbs string from charset %s: %s", charset, strerror(errno));
270 def++;
271 }
272 return(def);
273 }
274 return(buf);
275}
276
277wchar_t *wcstolower(wchar_t *wcs)
278{
279 wchar_t *p;
280
281 for(p = wcs; *p != L'\0'; p++)
282 *p = towlower(*p);
283 return(wcs);
284}
285
286wchar_t ucptowc(int ucp)
287{
288 int ret;
289 unsigned long ucpbuf;
290 char *buf;
291 char *mbsp, *p, *p2;
292 wchar_t res;
293 size_t len1, len2, bufsize, data;
294 iconv_t cd;
295
296 ucpbuf = htonl(ucp);
297 mbsp = (char *)&ucpbuf;
298 len1 = 4;
299 bufsize = len2 = len1 * sizeof(wchar_t);
300 if((buf = malloc(bufsize)) == NULL)
301 {
302 LOGOOM(bufsize);
303 return(L'\0');
304 }
305 if((cd = iconv_open("wchar_t", "UCS-4BE")) == (iconv_t)-1)
306 {
307 flog(LOG_ERR, "ucptowc: could not open iconv structure for UCS-4BE: %s", strerror(errno));
308 free(buf);
309 return(L'\0');
310 }
311 p = buf;
312 while(len1 > 0)
313 {
314 ret = iconv(cd, &mbsp, &len1, &p, &len2);
315 if(ret < 0)
316 {
317 if(errno == E2BIG)
318 {
319 data = p - buf;
320 len2 += 128;
321 bufsize += 128;
322 if((p2 = realloc(buf, bufsize)) == NULL)
323 {
324 LOGOOM(bufsize);
325 free(buf);
326 iconv_close(cd);
327 return(L'\0');
328 }
329 buf = p2;
330 p = buf + data;
331 } else {
332 free(buf);
333 iconv_close(cd);
334 return(L'\0');
335 }
336 }
337 }
338 if(len2 > 0)
339 buf = realloc(buf, p - buf);
340 iconv_close(cd);
341 res = *(wchar_t *)buf;
342 free(buf);
343 return(res);
344}
345
346void _sizebuf(void **buf, size_t *bufsize, size_t reqsize, size_t elsize, int algo)
347{
348 if(*bufsize >= reqsize)
349 return;
350 switch(algo)
351 {
352 case 0:
353 *buf = srealloc(*buf, elsize * ((*bufsize) = reqsize));
354 break;
355 case 1:
356 if(*bufsize == 0)
357 *bufsize = 1;
358 while(*bufsize < reqsize)
359 *bufsize <<= 1;
360 *buf = srealloc(*buf, elsize * (*bufsize));
361 break;
362 }
363}
364
365double ntime(void)
366{
367 struct timeval tv;
368
369 gettimeofday(&tv, NULL);
370 return((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
371}
372
373int wcsexists(wchar_t *h, wchar_t *n)
374{
375 int i, o, nl, hl;
376 wchar_t *ln, *lh;
377
378 ln = alloca(sizeof(*ln) * (nl = wcslen(n)));
379 for(i = 0; i < nl; i++)
380 ln[i] = towlower(n[i]);
381 lh = alloca(sizeof(*lh) * (hl = wcslen(h)));
382 if(nl > hl)
383 return(0);
384 for(i = 0; i < nl; i++)
385 lh[i] = towlower(h[i]);
386 i = 0;
387 while(1)
388 {
389 for(o = 0; o < nl; o++)
390 {
391 if(lh[i + o] != ln[o])
392 break;
393 }
394 if(o == nl)
395 return(1);
396 if(i == hl - nl)
397 return(0);
398 lh[i + nl] = towlower(h[i + nl]);
399 i++;
400 }
401}
402
403#ifndef HAVE_WCSCASECMP
404int wcscasecmp(const wchar_t *s1, const wchar_t *s2)
405{
406 while(towlower(*s1) == towlower(*s2))
407 {
408 if(*s1 == L'\0')
409 return(0);
410 }
411 return(towlower(*s1) - towlower(*s2));
412}
413#endif
414
415char *hexencode(char *data, size_t datalen)
416{
417 char *buf, this;
418 size_t bufsize, bufdata;
419 int dig;
420
421 buf = NULL;
422 bufsize = bufdata = 0;
423 for(; datalen > 0; datalen--, data++)
424 {
425 dig = (*data & 0xF0) >> 4;
426 if(dig > 9)
427 this = 'A' + dig - 10;
428 else
429 this = dig + '0';
430 addtobuf(buf, this);
431 dig = *data & 0x0F;
432 if(dig > 9)
433 this = 'A' + dig - 10;
434 else
435 this = dig + '0';
436 addtobuf(buf, this);
437 }
438 addtobuf(buf, 0);
439 return(buf);
440}
441
442char *hexdecode(char *data, size_t *len)
443{
444 char *buf, this;
445 size_t bufsize, bufdata;
446
447 buf = NULL;
448 bufsize = bufdata = 0;
449 for(; *data; data++)
450 {
451 if((*data >= 'A') && (*data <= 'F'))
452 {
453 this = (this & 0x0F) | ((*data - 'A' + 10) << 4);
454 } else if((*data >= '0') && (*data <= '9')) {
455 this = (this & 0x0F) | ((*data - '0') << 4);
456 } else {
457 if(buf != NULL)
458 free(buf);
459 return(NULL);
460 }
461 data++;
462 if(!*data)
463 {
464 if(buf != NULL)
465 free(buf);
466 return(NULL);
467 }
468 if((*data >= 'A') && (*data <= 'F'))
469 {
470 this = (this & 0xF0) | (*data - 'A' + 10);
471 } else if((*data >= '0') && (*data <= '9')) {
472 this = (this & 0xF0) | (*data - '0');
473 } else {
474 if(buf != NULL)
475 free(buf);
476 return(NULL);
477 }
478 addtobuf(buf, this);
479 }
480 addtobuf(buf, 0);
481 if(len != NULL)
482 *len = bufdata - 1;
483 return(buf);
484}
485
486char *base64encode(char *data, size_t datalen)
487{
488 char *buf;
489 size_t bufsize, bufdata;
490
491 if(datalen == 0)
492 return(sstrdup(""));
493 buf = NULL;
494 bufsize = bufdata = 0;
495 while(datalen >= 3)
496 {
497 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
498 addtobuf(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
499 addtobuf(buf, base64set[((data[1] & 0x0f) << 2) | ((data[2] & 0xc0) >> 6)]);
500 addtobuf(buf, base64set[data[2] & 0x3f]);
501 datalen -= 3;
502 data += 3;
503 }
504 if(datalen == 1)
505 {
506 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
507 addtobuf(buf, base64set[(data[0] & 0x03) << 4]);
508 bufcat(buf, "==", 2);
509 }
510 if(datalen == 2)
511 {
512 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
513 addtobuf(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
514 addtobuf(buf, base64set[(data[1] & 0x0f) << 2]);
515 addtobuf(buf, '=');
516 }
517 addtobuf(buf, 0);
518 return(buf);
519}
520
521char *base64decode(char *data, size_t *datalen)
522{
523 int b, c;
524 char *buf, cur;
525 size_t bufsize, bufdata;
526
527 buf = NULL;
528 bufsize = bufdata = 0;
529 cur = 0;
530 b = 8;
531 for(; *data > 0; data++)
532 {
533 c = (int)(unsigned char)*data;
534 if(c == '=')
535 break;
65399bc2 536 if(c == '\n')
537 continue;
d3372da9 538 if(base64rev[c] == -1)
539 {
540 if(buf != NULL)
541 free(buf);
542 return(NULL);
543 }
544 b -= 6;
545 if(b <= 0)
546 {
547 cur |= base64rev[c] >> -b;
548 addtobuf(buf, cur);
549 b += 8;
550 cur = 0;
551 }
552 cur |= base64rev[c] << b;
553 }
554 if(datalen != NULL)
555 *datalen = bufdata;
556 addtobuf(buf, 0);
557 return(buf);
558}
559
560char *base32encode(char *data, size_t datalen)
561{
562 char *buf;
563 size_t bufsize, bufdata;
564
565 if(datalen == 0)
566 return(sstrdup(""));
567 buf = NULL;
568 bufsize = bufdata = 0;
569 while(datalen >= 5)
570 {
571 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
572 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
573 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
574 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
575 addtobuf(buf, base32set[((data[2] & 0x0f) << 1) | ((data[3] & 0x80) >> 7)]);
576 addtobuf(buf, base32set[((data[3] & 0x7c) >> 2)]);
577 addtobuf(buf, base32set[((data[3] & 0x03) << 3) | ((data[4] & 0xe0) >> 5)]);
578 addtobuf(buf, base32set[data[4] & 0x1f]);
579 datalen -= 5;
580 data += 5;
581 }
582 if(datalen == 1)
583 {
584 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
585 addtobuf(buf, base32set[((data[0] & 0x07) << 2)]);
586 bufcat(buf, "======", 6);
587 }
588 if(datalen == 2)
589 {
590 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
591 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
592 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
593 addtobuf(buf, base32set[((data[1] & 0x01) << 4)]);
594 bufcat(buf, "====", 4);
595 }
596 if(datalen == 3)
597 {
598 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
599 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
600 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
601 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
602 addtobuf(buf, base32set[((data[2] & 0x0f) << 1)]);
603 bufcat(buf, "===", 3);
604 }
605 if(datalen == 4)
606 {
607 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
608 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
609 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
610 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
611 addtobuf(buf, base32set[((data[2] & 0x0f) << 1) | ((data[3] & 0x80) >> 7)]);
612 addtobuf(buf, base32set[((data[3] & 0x7c) >> 2)]);
613 addtobuf(buf, base32set[((data[3] & 0x03) << 3)]);
614 bufcat(buf, "=", 1);
615 }
616 addtobuf(buf, 0);
617 return(buf);
618}
619
620char *base32decode(char *data, size_t *datalen)
621{
622 int b, c;
623 char *buf, cur;
624 size_t bufsize, bufdata;
625
626 buf = NULL;
627 bufsize = bufdata = 0;
628 cur = 0;
629 b = 8;
630 for(; *data > 0; data++)
631 {
632 c = (int)(unsigned char)*data;
633 if(c == '=')
634 break;
65399bc2 635 if(c == '\n')
636 continue;
d3372da9 637 if(base32rev[c] == -1)
638 {
639 if(buf != NULL)
640 free(buf);
641 return(NULL);
642 }
643 b -= 5;
644 if(b <= 0)
645 {
646 cur |= base32rev[c] >> -b;
647 addtobuf(buf, cur);
648 b += 8;
649 cur = 0;
650 }
651 cur |= base32rev[c] << b;
652 }
653 if(datalen != NULL)
654 *datalen = bufdata;
655 addtobuf(buf, 0);
656 return(buf);
657}
658
659void _freeparr(void **arr)
660{
661 void **buf;
662
663 if(arr == NULL)
664 return;
665 for(buf = arr; *buf != NULL; buf++)
666 free(*buf);
667 free(arr);
668}
669
670int _parrlen(void **arr)
671{
672 int i;
673
674 if(arr == NULL)
675 return(0);
676 for(i = 0; *arr != NULL; arr++)
677 i++;
678 return(i);
679}
680
681char *getetcpath(char *binpath)
682{
73247114 683 int f;
d3372da9 684 char *etcpath, *p;
685 size_t etcpathsize, etcpathdata;
686
687 etcpath = NULL;
688 etcpathsize = etcpathdata = 0;
73247114 689 f = 1;
d3372da9 690 do
691 {
73247114 692 if(f)
693 f = 0;
694 else
695 binpath++;
d3372da9 696 for(p = binpath; *p && (*p != ':'); p++);
697 for(; (p >= binpath) && (*p != '/'); p--);
698 if(p >= binpath)
699 {
700 if(etcpathdata > 0)
701 addtobuf(etcpath, ':');
702 bufcat(etcpath, binpath, p - binpath + 1);
703 bufcat(etcpath, "etc", 3);
704 }
705 } while((binpath = strchr(binpath, ':')) != NULL);
706 addtobuf(etcpath, 0);
707 return(etcpath);
708}
709
710char *findfile(char *gname, char *uname, char *homedir)
711{
712 char *path, *binpath, *etcpath, *p;
713
714 if((homedir != NULL) && ((path = sprintf2("%s/.%s", homedir, uname)) != NULL))
715 {
716 if(!access(path, F_OK))
717 return(path);
718 free(path);
719 }
720 if(gname != NULL)
721 {
722 if(strchr(gname, '/') != NULL)
723 {
724 if(!access(gname, F_OK))
725 return(sstrdup(gname));
726 } else {
727 if((binpath = getenv("PATH")) == NULL)
728 etcpath = sstrdup("/usr/local/etc:/etc:/usr/etc");
729 else
730 etcpath = getetcpath(binpath);
731 for(p = strtok(etcpath, ":"); p != NULL; p = strtok(NULL, ":"))
732 {
733 if((path = sprintf2("%s/%s", p, gname)) != NULL)
734 {
735 if(!access(path, F_OK))
736 {
737 free(etcpath);
738 return(path);
739 }
740 free(path);
741 }
742 }
743 free(etcpath);
744 }
745 }
746 return(NULL);
747}
9ec790e8 748
749struct wcspair *newwcspair(wchar_t *key, wchar_t *val, struct wcspair **list)
750{
751 struct wcspair *pair;
752
753 pair = smalloc(sizeof(*pair));
754 memset(pair, 0, sizeof(*pair));
755 if(key != NULL)
756 pair->key = swcsdup(key);
757 if(val != NULL)
758 pair->val = swcsdup(val);
759 if(list == NULL)
760 {
761 pair->next = NULL;
762 } else {
763 pair->next = *list;
764 *list = pair;
765 }
766 return(pair);
767}
768
769void freewcspair(struct wcspair *pair, struct wcspair **list)
770{
497fe07b 771 struct wcspair *cur;
772
773 for(cur = *list; cur != NULL; list = &(cur->next), cur = cur->next)
9ec790e8 774 {
497fe07b 775 if(cur == pair)
776 {
777 *list = cur->next;
778 break;
779 }
9ec790e8 780 }
781 free(pair->key);
782 free(pair->val);
783 free(pair);
784}
a2761258 785
786wchar_t *wpfind(struct wcspair *list, wchar_t *key)
787{
788 for(; list != NULL; list = list->next)
789 {
790 if(!wcscmp(list->key, key))
791 return(list->val);
792 }
793 return(NULL);
794}