]>
Commit | Line | Data |
---|---|---|
d02b48c6 | 1 | /* crypto/conf/conf.c */ |
58964a49 | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
d02b48c6 RE |
3 | * All rights reserved. |
4 | * | |
5 | * This package is an SSL implementation written | |
6 | * by Eric Young (eay@cryptsoft.com). | |
7 | * The implementation was written so as to conform with Netscapes SSL. | |
8 | * | |
9 | * This library is free for commercial and non-commercial use as long as | |
10 | * the following conditions are aheared to. The following conditions | |
11 | * apply to all code found in this distribution, be it the RC4, RSA, | |
12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
13 | * included with this distribution is covered by the same copyright terms | |
14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
15 | * | |
16 | * Copyright remains Eric Young's, and as such any Copyright notices in | |
17 | * the code are not to be removed. | |
18 | * If this package is used in a product, Eric Young should be given attribution | |
19 | * as the author of the parts of the library used. | |
20 | * This can be in the form of a textual message at program startup or | |
21 | * in documentation (online or textual) provided with the package. | |
22 | * | |
23 | * Redistribution and use in source and binary forms, with or without | |
24 | * modification, are permitted provided that the following conditions | |
25 | * are met: | |
26 | * 1. Redistributions of source code must retain the copyright | |
27 | * notice, this list of conditions and the following disclaimer. | |
28 | * 2. Redistributions in binary form must reproduce the above copyright | |
29 | * notice, this list of conditions and the following disclaimer in the | |
30 | * documentation and/or other materials provided with the distribution. | |
31 | * 3. All advertising materials mentioning features or use of this software | |
32 | * must display the following acknowledgement: | |
33 | * "This product includes cryptographic software written by | |
34 | * Eric Young (eay@cryptsoft.com)" | |
35 | * The word 'cryptographic' can be left out if the rouines from the library | |
36 | * being used are not cryptographic related :-). | |
37 | * 4. If you include any Windows specific code (or a derivative thereof) from | |
38 | * the apps directory (application code) you must include an acknowledgement: | |
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
40 | * | |
41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | |
42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
45 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
46 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
47 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 | * SUCH DAMAGE. | |
52 | * | |
53 | * The licence and distribution terms for any publically available version or | |
54 | * derivative of this code cannot be changed. i.e. this code cannot simply be | |
55 | * copied and put under another distribution licence | |
56 | * [including the GNU Public Licence.] | |
57 | */ | |
58 | ||
59 | #include <stdio.h> | |
60 | #include <errno.h> | |
61 | #include "cryptlib.h" | |
ec577822 BM |
62 | #include <openssl/stack.h> |
63 | #include <openssl/lhash.h> | |
64 | #include <openssl/conf.h> | |
65 | #include <openssl/buffer.h> | |
66 | #include <openssl/err.h> | |
d02b48c6 RE |
67 | |
68 | #include "conf_lcl.h" | |
69 | ||
d02b48c6 RE |
70 | static void value_free_hash(CONF_VALUE *a, LHASH *conf); |
71 | static void value_free_stack(CONF_VALUE *a,LHASH *conf); | |
72 | static unsigned long hash(CONF_VALUE *v); | |
73 | static int cmp(CONF_VALUE *a,CONF_VALUE *b); | |
74 | static char *eat_ws(char *p); | |
75 | static char *eat_alpha_numeric(char *p); | |
76 | static void clear_comments(char *p); | |
77 | static int str_copy(LHASH *conf,char *section,char **to, char *from); | |
78 | static char *scan_quote(char *p); | |
79 | static CONF_VALUE *new_section(LHASH *conf,char *section); | |
80 | static CONF_VALUE *get_section(LHASH *conf,char *section); | |
dfeab068 | 81 | #define scan_esc(p) ((((p)[1] == '\0')?(p++):(p+=2)),p) |
d02b48c6 | 82 | |
e778802f | 83 | const char *CONF_version="CONF" OPENSSL_VERSION_PTEXT; |
d02b48c6 | 84 | |
8623f693 DSH |
85 | |
86 | LHASH *CONF_load(LHASH *h, const char *file, long *line) | |
d02b48c6 | 87 | { |
8623f693 | 88 | LHASH *ltmp; |
d02b48c6 | 89 | FILE *in=NULL; |
8623f693 DSH |
90 | |
91 | #ifdef VMS | |
92 | in=fopen(file,"r"); | |
93 | #else | |
94 | in=fopen(file,"rb"); | |
95 | #endif | |
96 | if (in == NULL) | |
97 | { | |
98 | SYSerr(SYS_F_FOPEN,get_last_sys_error()); | |
99 | ERR_set_error_data(BUF_strdup(file), | |
100 | ERR_TXT_MALLOCED|ERR_TXT_STRING); | |
101 | CONFerr(CONF_F_CONF_LOAD,ERR_R_SYS_LIB); | |
102 | return NULL; | |
103 | } | |
104 | ||
105 | ltmp = CONF_load_fp(h, in, line); | |
106 | fclose(in); | |
107 | ||
108 | return ltmp; | |
109 | } | |
110 | ||
111 | LHASH *CONF_load_fp(LHASH *h, FILE *in, long *line) | |
112 | { | |
113 | BIO *btmp; | |
114 | LHASH *ltmp; | |
115 | if(!(btmp = BIO_new_fp(in, BIO_NOCLOSE))) { | |
116 | CONFerr(CONF_F_CONF_LOAD_FP,ERR_R_BUF_LIB); | |
117 | return NULL; | |
118 | } | |
119 | ltmp = CONF_load_bio(h, btmp, line); | |
120 | BIO_free(btmp); | |
121 | return ltmp; | |
122 | } | |
123 | ||
124 | LHASH *CONF_load_bio(LHASH *h, BIO *in, long *line) | |
125 | { | |
126 | LHASH *ret=NULL; | |
d02b48c6 | 127 | #define BUFSIZE 512 |
dfeab068 | 128 | char btmp[16]; |
d02b48c6 RE |
129 | int bufnum=0,i,ii; |
130 | BUF_MEM *buff=NULL; | |
131 | char *s,*p,*end; | |
dfeab068 RE |
132 | int again,n; |
133 | long eline=0; | |
d02b48c6 RE |
134 | CONF_VALUE *v=NULL,*vv,*tv; |
135 | CONF_VALUE *sv=NULL; | |
136 | char *section=NULL,*buf; | |
137 | STACK *section_sk=NULL,*ts; | |
138 | char *start,*psection,*pname; | |
139 | ||
140 | if ((buff=BUF_MEM_new()) == NULL) | |
141 | { | |
8623f693 | 142 | CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_BUF_LIB); |
d02b48c6 RE |
143 | goto err; |
144 | } | |
145 | ||
146 | section=(char *)Malloc(10); | |
147 | if (section == NULL) | |
148 | { | |
8623f693 | 149 | CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_MALLOC_FAILURE); |
d02b48c6 RE |
150 | goto err; |
151 | } | |
152 | strcpy(section,"default"); | |
153 | ||
154 | if (h == NULL) | |
155 | { | |
156 | if ((ret=lh_new(hash,cmp)) == NULL) | |
157 | { | |
8623f693 | 158 | CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_MALLOC_FAILURE); |
d02b48c6 RE |
159 | goto err; |
160 | } | |
161 | } | |
162 | else | |
163 | ret=h; | |
164 | ||
165 | sv=new_section(ret,section); | |
166 | if (sv == NULL) | |
167 | { | |
8623f693 DSH |
168 | CONFerr(CONF_F_CONF_LOAD_BIO, |
169 | CONF_R_UNABLE_TO_CREATE_NEW_SECTION); | |
d02b48c6 RE |
170 | goto err; |
171 | } | |
172 | section_sk=(STACK *)sv->value; | |
173 | ||
174 | bufnum=0; | |
175 | for (;;) | |
176 | { | |
177 | again=0; | |
178 | if (!BUF_MEM_grow(buff,bufnum+BUFSIZE)) | |
179 | { | |
8623f693 | 180 | CONFerr(CONF_F_CONF_LOAD_BIO,ERR_R_BUF_LIB); |
d02b48c6 RE |
181 | goto err; |
182 | } | |
183 | p= &(buff->data[bufnum]); | |
184 | *p='\0'; | |
8623f693 | 185 | BIO_gets(in, p, BUFSIZE-1); |
d02b48c6 RE |
186 | p[BUFSIZE-1]='\0'; |
187 | ii=i=strlen(p); | |
188 | if (i == 0) break; | |
189 | while (i > 0) | |
190 | { | |
191 | if ((p[i-1] != '\r') && (p[i-1] != '\n')) | |
192 | break; | |
193 | else | |
194 | i--; | |
195 | } | |
196 | /* we removed some trailing stuff so there is a new | |
197 | * line on the end. */ | |
198 | if (i == ii) | |
199 | again=1; /* long line */ | |
200 | else | |
201 | { | |
202 | p[i]='\0'; | |
203 | eline++; /* another input line */ | |
204 | } | |
205 | ||
206 | /* we now have a line with trailing \r\n removed */ | |
207 | ||
208 | /* i is the number of bytes */ | |
209 | bufnum+=i; | |
210 | ||
211 | v=NULL; | |
212 | /* check for line continuation */ | |
213 | if (bufnum >= 1) | |
214 | { | |
215 | /* If we have bytes and the last char '\\' and | |
216 | * second last char is not '\\' */ | |
217 | p= &(buff->data[bufnum-1]); | |
218 | if ( IS_ESC(p[0]) && | |
219 | ((bufnum <= 1) || !IS_ESC(p[-1]))) | |
220 | { | |
221 | bufnum--; | |
222 | again=1; | |
223 | } | |
224 | } | |
225 | if (again) continue; | |
226 | bufnum=0; | |
227 | buf=buff->data; | |
228 | ||
229 | clear_comments(buf); | |
230 | n=strlen(buf); | |
231 | s=eat_ws(buf); | |
232 | if (IS_EOF(*s)) continue; /* blank line */ | |
233 | if (*s == '[') | |
234 | { | |
dfeab068 RE |
235 | char *ss; |
236 | ||
d02b48c6 RE |
237 | s++; |
238 | start=eat_ws(s); | |
dfeab068 RE |
239 | ss=start; |
240 | again: | |
241 | end=eat_alpha_numeric(ss); | |
d02b48c6 RE |
242 | p=eat_ws(end); |
243 | if (*p != ']') | |
244 | { | |
dfeab068 RE |
245 | if (*p != '\0') |
246 | { | |
247 | ss=p; | |
248 | goto again; | |
249 | } | |
8623f693 DSH |
250 | CONFerr(CONF_F_CONF_LOAD_BIO, |
251 | CONF_R_MISSING_CLOSE_SQUARE_BRACKET); | |
d02b48c6 RE |
252 | goto err; |
253 | } | |
254 | *end='\0'; | |
255 | if (!str_copy(ret,NULL,§ion,start)) goto err; | |
256 | if ((sv=get_section(ret,section)) == NULL) | |
257 | sv=new_section(ret,section); | |
258 | if (sv == NULL) | |
259 | { | |
8623f693 DSH |
260 | CONFerr(CONF_F_CONF_LOAD_BIO, |
261 | CONF_R_UNABLE_TO_CREATE_NEW_SECTION); | |
d02b48c6 RE |
262 | goto err; |
263 | } | |
264 | section_sk=(STACK *)sv->value; | |
265 | continue; | |
266 | } | |
267 | else | |
268 | { | |
269 | pname=s; | |
270 | psection=NULL; | |
271 | end=eat_alpha_numeric(s); | |
272 | if ((end[0] == ':') && (end[1] == ':')) | |
273 | { | |
274 | *end='\0'; | |
275 | end+=2; | |
276 | psection=pname; | |
277 | pname=end; | |
278 | end=eat_alpha_numeric(end); | |
279 | } | |
280 | p=eat_ws(end); | |
281 | if (*p != '=') | |
282 | { | |
8623f693 DSH |
283 | CONFerr(CONF_F_CONF_LOAD_BIO, |
284 | CONF_R_MISSING_EQUAL_SIGN); | |
d02b48c6 RE |
285 | goto err; |
286 | } | |
287 | *end='\0'; | |
288 | p++; | |
289 | start=eat_ws(p); | |
290 | while (!IS_EOF(*p)) | |
291 | p++; | |
292 | p--; | |
293 | while ((p != start) && (IS_WS(*p))) | |
294 | p--; | |
295 | p++; | |
296 | *p='\0'; | |
297 | ||
298 | if ((v=(CONF_VALUE *)Malloc(sizeof(CONF_VALUE))) == NULL) | |
299 | { | |
8623f693 DSH |
300 | CONFerr(CONF_F_CONF_LOAD_BIO, |
301 | ERR_R_MALLOC_FAILURE); | |
d02b48c6 RE |
302 | goto err; |
303 | } | |
304 | if (psection == NULL) psection=section; | |
305 | v->name=(char *)Malloc(strlen(pname)+1); | |
306 | v->value=NULL; | |
307 | if (v->name == NULL) | |
308 | { | |
8623f693 DSH |
309 | CONFerr(CONF_F_CONF_LOAD_BIO, |
310 | ERR_R_MALLOC_FAILURE); | |
d02b48c6 RE |
311 | goto err; |
312 | } | |
313 | strcpy(v->name,pname); | |
314 | if (!str_copy(ret,psection,&(v->value),start)) goto err; | |
315 | ||
316 | if (strcmp(psection,section) != 0) | |
317 | { | |
318 | if ((tv=get_section(ret,psection)) | |
319 | == NULL) | |
320 | tv=new_section(ret,psection); | |
321 | if (tv == NULL) | |
322 | { | |
8623f693 DSH |
323 | CONFerr(CONF_F_CONF_LOAD_BIO, |
324 | CONF_R_UNABLE_TO_CREATE_NEW_SECTION); | |
d02b48c6 RE |
325 | goto err; |
326 | } | |
327 | ts=(STACK *)tv->value; | |
328 | } | |
329 | else | |
330 | { | |
331 | tv=sv; | |
332 | ts=section_sk; | |
333 | } | |
334 | v->section=tv->section; | |
335 | if (!sk_push(ts,(char *)v)) | |
336 | { | |
8623f693 DSH |
337 | CONFerr(CONF_F_CONF_LOAD_BIO, |
338 | ERR_R_MALLOC_FAILURE); | |
d02b48c6 RE |
339 | goto err; |
340 | } | |
341 | vv=(CONF_VALUE *)lh_insert(ret,(char *)v); | |
342 | if (vv != NULL) | |
343 | { | |
344 | sk_delete_ptr(ts,(char *)vv); | |
345 | Free(vv->name); | |
346 | Free(vv->value); | |
347 | Free(vv); | |
348 | } | |
349 | v=NULL; | |
350 | } | |
351 | } | |
352 | if (buff != NULL) BUF_MEM_free(buff); | |
353 | if (section != NULL) Free(section); | |
d02b48c6 RE |
354 | return(ret); |
355 | err: | |
356 | if (buff != NULL) BUF_MEM_free(buff); | |
357 | if (section != NULL) Free(section); | |
358 | if (line != NULL) *line=eline; | |
dfeab068 RE |
359 | sprintf(btmp,"%ld",eline); |
360 | ERR_add_error_data(2,"line ",btmp); | |
d02b48c6 RE |
361 | if ((h != ret) && (ret != NULL)) CONF_free(ret); |
362 | if (v != NULL) | |
363 | { | |
364 | if (v->name != NULL) Free(v->name); | |
365 | if (v->value != NULL) Free(v->value); | |
366 | if (v != NULL) Free(v); | |
367 | } | |
368 | return(NULL); | |
369 | } | |
8623f693 | 370 | |
6b691a5c | 371 | char *CONF_get_string(LHASH *conf, char *section, char *name) |
d02b48c6 RE |
372 | { |
373 | CONF_VALUE *v,vv; | |
374 | char *p; | |
375 | ||
376 | if (name == NULL) return(NULL); | |
377 | if (conf != NULL) | |
378 | { | |
379 | if (section != NULL) | |
380 | { | |
381 | vv.name=name; | |
382 | vv.section=section; | |
383 | v=(CONF_VALUE *)lh_retrieve(conf,(char *)&vv); | |
384 | if (v != NULL) return(v->value); | |
385 | if (strcmp(section,"ENV") == 0) | |
386 | { | |
387 | p=Getenv(name); | |
388 | if (p != NULL) return(p); | |
389 | } | |
390 | } | |
f3c75106 | 391 | vv.section="default"; |
d02b48c6 RE |
392 | vv.name=name; |
393 | v=(CONF_VALUE *)lh_retrieve(conf,(char *)&vv); | |
394 | if (v != NULL) | |
395 | return(v->value); | |
396 | else | |
397 | return(NULL); | |
398 | } | |
399 | else | |
400 | return(Getenv(name)); | |
401 | } | |
402 | ||
6b691a5c | 403 | static CONF_VALUE *get_section(LHASH *conf, char *section) |
d02b48c6 RE |
404 | { |
405 | CONF_VALUE *v,vv; | |
406 | ||
407 | if ((conf == NULL) || (section == NULL)) return(NULL); | |
408 | vv.name=NULL; | |
409 | vv.section=section; | |
410 | v=(CONF_VALUE *)lh_retrieve(conf,(char *)&vv); | |
411 | return(v); | |
412 | } | |
413 | ||
6b691a5c | 414 | STACK *CONF_get_section(LHASH *conf, char *section) |
d02b48c6 RE |
415 | { |
416 | CONF_VALUE *v; | |
417 | ||
418 | v=get_section(conf,section); | |
419 | if (v != NULL) | |
420 | return((STACK *)v->value); | |
421 | else | |
422 | return(NULL); | |
423 | } | |
424 | ||
6b691a5c | 425 | long CONF_get_number(LHASH *conf, char *section, char *name) |
d02b48c6 RE |
426 | { |
427 | char *str; | |
428 | long ret=0; | |
429 | ||
430 | str=CONF_get_string(conf,section,name); | |
431 | if (str == NULL) return(0); | |
432 | for (;;) | |
433 | { | |
434 | if (IS_NUMER(*str)) | |
435 | ret=ret*10+(*str -'0'); | |
436 | else | |
437 | return(ret); | |
438 | str++; | |
439 | } | |
440 | } | |
441 | ||
6b691a5c | 442 | void CONF_free(LHASH *conf) |
d02b48c6 RE |
443 | { |
444 | if (conf == NULL) return; | |
445 | ||
446 | conf->down_load=0; /* evil thing to make sure the 'Free()' | |
447 | * works as expected */ | |
448 | lh_doall_arg(conf,(void (*)())value_free_hash,(char *)conf); | |
449 | ||
450 | /* We now have only 'section' entries in the hash table. | |
451 | * Due to problems with */ | |
452 | ||
453 | lh_doall_arg(conf,(void (*)())value_free_stack,(char *)conf); | |
454 | lh_free(conf); | |
455 | } | |
456 | ||
6b691a5c | 457 | static void value_free_hash(CONF_VALUE *a, LHASH *conf) |
d02b48c6 RE |
458 | { |
459 | if (a->name != NULL) | |
460 | { | |
461 | a=(CONF_VALUE *)lh_delete(conf,(char *)a); | |
462 | } | |
463 | } | |
464 | ||
6b691a5c | 465 | static void value_free_stack(CONF_VALUE *a, LHASH *conf) |
d02b48c6 RE |
466 | { |
467 | CONF_VALUE *vv; | |
468 | STACK *sk; | |
469 | int i; | |
470 | ||
471 | if (a->name != NULL) return; | |
472 | ||
473 | sk=(STACK *)a->value; | |
474 | for (i=sk_num(sk)-1; i>=0; i--) | |
475 | { | |
476 | vv=(CONF_VALUE *)sk_value(sk,i); | |
477 | Free(vv->value); | |
478 | Free(vv->name); | |
479 | Free(vv); | |
480 | } | |
481 | if (sk != NULL) sk_free(sk); | |
482 | Free(a->section); | |
483 | Free(a); | |
484 | } | |
485 | ||
6b691a5c | 486 | static void clear_comments(char *p) |
d02b48c6 RE |
487 | { |
488 | char *to; | |
489 | ||
490 | to=p; | |
491 | for (;;) | |
492 | { | |
493 | if (IS_COMMENT(*p)) | |
494 | { | |
495 | *p='\0'; | |
496 | return; | |
497 | } | |
498 | if (IS_QUOTE(*p)) | |
499 | { | |
500 | p=scan_quote(p); | |
501 | continue; | |
502 | } | |
503 | if (IS_ESC(*p)) | |
504 | { | |
505 | p=scan_esc(p); | |
506 | continue; | |
507 | } | |
508 | if (IS_EOF(*p)) | |
509 | return; | |
510 | else | |
511 | p++; | |
512 | } | |
513 | } | |
514 | ||
6b691a5c | 515 | static int str_copy(LHASH *conf, char *section, char **pto, char *from) |
d02b48c6 RE |
516 | { |
517 | int q,r,rr=0,to=0,len=0; | |
518 | char *s,*e,*rp,*p,*rrp,*np,*cp,v; | |
519 | BUF_MEM *buf; | |
520 | ||
521 | if ((buf=BUF_MEM_new()) == NULL) return(0); | |
522 | ||
523 | len=strlen(from)+1; | |
524 | if (!BUF_MEM_grow(buf,len)) goto err; | |
525 | ||
526 | for (;;) | |
527 | { | |
528 | if (IS_QUOTE(*from)) | |
529 | { | |
530 | q= *from; | |
531 | from++; | |
532 | while ((*from != '\0') && (*from != q)) | |
533 | { | |
534 | if (*from == '\\') | |
535 | { | |
536 | from++; | |
537 | if (*from == '\0') break; | |
538 | } | |
539 | buf->data[to++]= *(from++); | |
540 | } | |
541 | } | |
542 | else if (*from == '\\') | |
543 | { | |
544 | from++; | |
545 | v= *(from++); | |
546 | if (v == '\0') break; | |
547 | else if (v == 'r') v='\r'; | |
548 | else if (v == 'n') v='\n'; | |
549 | else if (v == 'b') v='\b'; | |
550 | else if (v == 't') v='\t'; | |
551 | buf->data[to++]= v; | |
552 | } | |
553 | else if (*from == '\0') | |
554 | break; | |
555 | else if (*from == '$') | |
556 | { | |
557 | /* try to expand it */ | |
558 | rrp=NULL; | |
559 | s= &(from[1]); | |
560 | if (*s == '{') | |
561 | q='}'; | |
562 | else if (*s == '(') | |
563 | q=')'; | |
564 | else q=0; | |
565 | ||
566 | if (q) s++; | |
567 | cp=section; | |
568 | e=np=s; | |
569 | while (IS_ALPHA_NUMERIC(*e)) | |
570 | e++; | |
571 | if ((e[0] == ':') && (e[1] == ':')) | |
572 | { | |
573 | cp=np; | |
574 | rrp=e; | |
575 | rr= *e; | |
576 | *rrp='\0'; | |
577 | e+=2; | |
578 | np=e; | |
579 | while (IS_ALPHA_NUMERIC(*e)) | |
580 | e++; | |
581 | } | |
582 | r= *e; | |
583 | *e='\0'; | |
584 | rp=e; | |
585 | if (q) | |
586 | { | |
587 | if (r != q) | |
588 | { | |
589 | CONFerr(CONF_F_STR_COPY,CONF_R_NO_CLOSE_BRACE); | |
590 | goto err; | |
591 | } | |
592 | e++; | |
593 | } | |
594 | /* So at this point we have | |
595 | * ns which is the start of the name string which is | |
596 | * '\0' terminated. | |
597 | * cs which is the start of the section string which is | |
598 | * '\0' terminated. | |
599 | * e is the 'next point after'. | |
600 | * r and s are the chars replaced by the '\0' | |
601 | * rp and sp is where 'r' and 's' came from. | |
602 | */ | |
603 | p=CONF_get_string(conf,cp,np); | |
604 | if (rrp != NULL) *rrp=rr; | |
605 | *rp=r; | |
606 | if (p == NULL) | |
607 | { | |
608 | CONFerr(CONF_F_STR_COPY,CONF_R_VARIABLE_HAS_NO_VALUE); | |
609 | goto err; | |
610 | } | |
611 | BUF_MEM_grow(buf,(strlen(p)+len-(e-from))); | |
612 | while (*p) | |
613 | buf->data[to++]= *(p++); | |
614 | from=e; | |
615 | } | |
616 | else | |
617 | buf->data[to++]= *(from++); | |
618 | } | |
619 | buf->data[to]='\0'; | |
620 | if (*pto != NULL) Free(*pto); | |
621 | *pto=buf->data; | |
622 | Free(buf); | |
623 | return(1); | |
624 | err: | |
625 | if (buf != NULL) BUF_MEM_free(buf); | |
626 | return(0); | |
627 | } | |
628 | ||
6b691a5c | 629 | static char *eat_ws(char *p) |
d02b48c6 RE |
630 | { |
631 | while (IS_WS(*p) && (!IS_EOF(*p))) | |
632 | p++; | |
633 | return(p); | |
634 | } | |
635 | ||
6b691a5c | 636 | static char *eat_alpha_numeric(char *p) |
d02b48c6 RE |
637 | { |
638 | for (;;) | |
639 | { | |
640 | if (IS_ESC(*p)) | |
641 | { | |
642 | p=scan_esc(p); | |
643 | continue; | |
644 | } | |
645 | if (!IS_ALPHA_NUMERIC_PUNCT(*p)) | |
646 | return(p); | |
647 | p++; | |
648 | } | |
649 | } | |
650 | ||
6b691a5c | 651 | static unsigned long hash(CONF_VALUE *v) |
d02b48c6 RE |
652 | { |
653 | return((lh_strhash(v->section)<<2)^lh_strhash(v->name)); | |
654 | } | |
655 | ||
6b691a5c | 656 | static int cmp(CONF_VALUE *a, CONF_VALUE *b) |
d02b48c6 RE |
657 | { |
658 | int i; | |
659 | ||
660 | if (a->section != b->section) | |
661 | { | |
662 | i=strcmp(a->section,b->section); | |
663 | if (i) return(i); | |
664 | } | |
665 | ||
666 | if ((a->name != NULL) && (b->name != NULL)) | |
667 | { | |
668 | i=strcmp(a->name,b->name); | |
669 | return(i); | |
670 | } | |
671 | else if (a->name == b->name) | |
672 | return(0); | |
673 | else | |
674 | return((a->name == NULL)?-1:1); | |
675 | } | |
676 | ||
6b691a5c | 677 | static char *scan_quote(char *p) |
d02b48c6 RE |
678 | { |
679 | int q= *p; | |
680 | ||
681 | p++; | |
682 | while (!(IS_EOF(*p)) && (*p != q)) | |
683 | { | |
684 | if (IS_ESC(*p)) | |
685 | { | |
686 | p++; | |
687 | if (IS_EOF(*p)) return(p); | |
688 | } | |
689 | p++; | |
690 | } | |
691 | if (*p == q) p++; | |
692 | return(p); | |
693 | } | |
694 | ||
6b691a5c | 695 | static CONF_VALUE *new_section(LHASH *conf, char *section) |
d02b48c6 RE |
696 | { |
697 | STACK *sk=NULL; | |
698 | int ok=0,i; | |
699 | CONF_VALUE *v=NULL,*vv; | |
700 | ||
701 | if ((sk=sk_new_null()) == NULL) | |
702 | goto err; | |
703 | if ((v=(CONF_VALUE *)Malloc(sizeof(CONF_VALUE))) == NULL) | |
704 | goto err; | |
705 | i=strlen(section)+1; | |
706 | if ((v->section=(char *)Malloc(i)) == NULL) | |
707 | goto err; | |
708 | ||
709 | memcpy(v->section,section,i); | |
710 | v->name=NULL; | |
711 | v->value=(char *)sk; | |
712 | ||
713 | vv=(CONF_VALUE *)lh_insert(conf,(char *)v); | |
d02b48c6 RE |
714 | if (vv != NULL) |
715 | { | |
58964a49 | 716 | #if !defined(NO_STDIO) && !defined(WIN16) |
d02b48c6 | 717 | fprintf(stderr,"internal fault\n"); |
58964a49 | 718 | #endif |
d02b48c6 RE |
719 | abort(); |
720 | } | |
d02b48c6 RE |
721 | ok=1; |
722 | err: | |
723 | if (!ok) | |
724 | { | |
725 | if (sk != NULL) sk_free(sk); | |
726 | if (v != NULL) Free(v); | |
727 | v=NULL; | |
728 | } | |
729 | return(v); | |
730 | } |