1 /*
2 * Copyright (c) 2000 Andrew Ferguson <andrew@owsla.cjb.net>
3 * Copyright (c) 1998 Sasha Vasko <sasha at aftercode.net>
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 */
20
21 #undef LOCAL_DEBUG
22 #undef DO_CLOCKING
23 #undef UNKNOWN_KEYWORD_WARNING
24
25 #include "../configure.h"
26
27 #include <fcntl.h>
28 #if HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #if HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34 #include <unistd.h>
35
36 #ifdef DO_CLOCKING
37 #if TIME_WITH_SYS_TIME
38 #include <sys/time.h>
39 #include <time.h>
40 #else
41 #if HAVE_SYS_TIME_H
42 #include <sys/time.h>
43 #else
44 #include <time.h>
45 #endif
46 #endif
47 #endif
48 #include "asapp.h"
49 #include "afterstep.h"
50 #include "parser.h"
51 #include "freestor.h"
52 #include "functions.h"
53 #include "../libAfterBase/xml.h"
54
55 char *_disabled_keyword = DISABLED_KEYWORD;
56 char *_unknown_keyword = "unknown";
57
58 static ASHashTable *Keyword2IDHash = NULL;
59
60
register_keyword_id(const char * keyword,int id)61 void register_keyword_id (const char *keyword, int id)
62 {
63 ASHashData hdata = { 0 };
64
65 if (Keyword2IDHash == NULL)
66 Keyword2IDHash = create_ashash (0, NULL, NULL, NULL);
67
68 hdata.cptr = (char *)keyword;
69 add_hash_item (Keyword2IDHash, AS_HASHABLE (id), hdata.vptr);
70 }
71
keyword_id2keyword(int id)72 const char *keyword_id2keyword (int id)
73 {
74 ASHashData hdata = { 0 };
75
76 if (Keyword2IDHash == NULL)
77 return _unknown_keyword;
78
79 if (get_hash_item (Keyword2IDHash, AS_HASHABLE (id), &hdata.vptr) ==
80 ASH_Success)
81 return hdata.cptr;
82
83 return _unknown_keyword;
84 }
85
86
flush_keyword_ids()87 void flush_keyword_ids ()
88 {
89 if (Keyword2IDHash != NULL)
90 destroy_ashash (&Keyword2IDHash);
91 }
92
BuildHash(SyntaxDef * syntax)93 void BuildHash (SyntaxDef * syntax)
94 {
95 register int i;
96
97 LOCAL_DEBUG_CALLER_OUT ("syntax = \"%s\"", syntax->display_name);
98
99 if (syntax->term_hash_size <= 0)
100 syntax->term_hash_size = TERM_HASH_SIZE;
101 if (syntax->term_hash == NULL) {
102 syntax->term_hash =
103 create_ashash (syntax->term_hash_size, option_hash_value,
104 option_compare, NULL);
105 LOCAL_DEBUG_OUT ("created hash %p", syntax->term_hash);
106 }
107 LOCAL_DEBUG_OUT ("adding hash entries ... %s", "");
108 for (i = 0; syntax->terms[i].keyword; i++) {
109 add_hash_item (syntax->term_hash,
110 AS_HASHABLE (syntax->terms[i].keyword),
111 (void *)&(syntax->terms[i]));
112 register_keyword_id (syntax->terms[i].keyword, syntax->terms[i].id);
113 }
114 LOCAL_DEBUG_OUT ("%d hash entries added.", i);
115 }
116
PrepareSyntax(SyntaxDef * syntax)117 void PrepareSyntax (SyntaxDef * syntax)
118 {
119 if (syntax) {
120 register int i;
121
122 LOCAL_DEBUG_OUT ("syntax = \"%s\", recursion = %d",
123 syntax->display_name, syntax->recursion);
124 if (syntax->recursion > 0)
125 return;
126 syntax->recursion++;
127
128 if (syntax->term_hash == NULL)
129 BuildHash (syntax);
130
131 for (i = 0; syntax->terms[i].keyword; i++)
132 if (syntax->terms[i].sub_syntax)
133 PrepareSyntax (syntax->terms[i].sub_syntax);
134
135 syntax->recursion--;
136 }
137 }
138
FreeSyntaxHash(SyntaxDef * syntax)139 void FreeSyntaxHash (SyntaxDef * syntax)
140 {
141 if (syntax) {
142 register int i;
143
144 LOCAL_DEBUG_CALLER_OUT ("syntax = \"%s\", recursion = %d",
145 syntax->display_name, syntax->recursion);
146
147 if (syntax->recursion > 0)
148 return;
149 syntax->recursion++;
150
151 if (syntax->term_hash)
152 destroy_ashash (&(syntax->term_hash));
153
154 for (i = 0; syntax->terms[i].keyword; i++)
155 if (syntax->terms[i].sub_syntax)
156 /* this should prevent us from endless recursion */
157 if (syntax->terms[i].sub_syntax->term_hash != NULL)
158 FreeSyntaxHash (syntax->terms[i].sub_syntax);
159
160 syntax->recursion--;
161
162 }
163 }
164
165 /* Syntax and storage stack operations */
PushSyntax(ConfigDef * config,SyntaxDef * syntax)166 void PushSyntax (ConfigDef * config, SyntaxDef * syntax)
167 {
168 SyntaxStack *pnew = (SyntaxStack *) safecalloc (1, sizeof (SyntaxStack));
169
170 /* saving our status to be able to come back to it later */
171 if (config->current_syntax) {
172 config->current_syntax->current_term = config->current_term;
173 config->current_syntax->current_flags = config->current_flags;
174 }
175 config->current_flags = CF_NONE;
176 config->current_term = NULL;
177 pnew->next = config->current_syntax;
178 pnew->syntax = syntax;
179 if (config->syntax && syntax->terminator == '\n') { /* handling prepending */
180 SyntaxDef *csyntax = config->syntax;
181 int len = strlen (csyntax->prepend_sub);
182 register int i;
183 char *tmp;
184
185 if (config->current_prepend_allocated - config->current_prepend_size <=
186 len) {
187 config->current_prepend_allocated += len + 1;
188 tmp = safemalloc (config->current_prepend_allocated);
189 if (config->current_prepend) {
190 strcpy (tmp, config->current_prepend);
191 free (config->current_prepend);
192 }
193 config->current_prepend = tmp;
194 }
195 tmp = &(config->current_prepend[config->current_prepend_size]);
196
197 for (i = 0; i <= len; i++)
198 tmp[i] = csyntax->prepend_sub[i];
199
200 config->current_prepend_size += len;
201
202 }
203 LOCAL_DEBUG_OUT ("%p: \"%s\", old is %p: current_prepend = [%s]\n",
204 syntax, syntax->display_name, config->syntax,
205 config->current_prepend);
206 config->current_syntax = pnew;
207 config->syntax = syntax;
208 }
209
PopSyntax(ConfigDef * config)210 int PopSyntax (ConfigDef * config)
211 {
212 if (config->current_syntax->next) {
213 SyntaxStack *pold = config->current_syntax;
214
215 config->current_syntax = config->current_syntax->next;
216 config->syntax = config->current_syntax->syntax;
217
218 /* restoring our status */
219 config->current_term = config->current_syntax->current_term;
220 config->current_flags = config->current_syntax->current_flags;
221
222 LOCAL_DEBUG_OUT ("%p: \"%s\", old is %p: term = \"%s\"\n",
223 config->syntax, config->syntax->display_name,
224 pold->syntax,
225 config->current_term ? config->
226 current_term->keyword : "");
227
228 if (pold->syntax->terminator == '\n') {
229 if ((config->current_prepend_size -=
230 strlen (config->syntax->prepend_sub)) >= 0)
231 config->current_prepend[config->current_prepend_size] = '\0';
232 }
233 /*fprintf( stderr, "PopSyntax(%s) current_prepend = [%s]\n", pold->syntax->display_name, config->current_prepend );
234 */
235 free (pold);
236 return 1;
237 }
238 return 0;
239 }
240
PushStorage(ConfigDef * config,void * storage)241 void PushStorage (ConfigDef * config, void *storage)
242 {
243 StorageStack *pnew =
244 (StorageStack *) safecalloc (1, sizeof (StorageStack));
245
246 pnew->storage = storage;
247 pnew->next = config->current_tail;
248 config->current_tail = pnew;
249 }
250
PopStorage(ConfigDef * config)251 int PopStorage (ConfigDef * config)
252 {
253 if (config->current_tail)
254 if (config->current_tail->next) {
255 StorageStack *pold = config->current_tail;
256
257 config->current_tail = config->current_tail->next;
258 free (pold);
259 return 1;
260 }
261 return 0;
262 }
263
264
config_error(ConfigDef * config,char * err_text)265 void config_error (ConfigDef * config, char *err_text)
266 {
267 if (config) {
268 char *eol = strchr (config->tline, '\n');
269
270 if (eol)
271 *eol = '\0';
272 show_error ("in %s (line %d):%s[%.50s]",
273 config->current_syntax->syntax->display_name,
274 config->line_count, err_text, config->tline);
275 if (eol)
276 *eol = '\n';
277 }
278 }
279
280 /* Creating and Initializing new ConfigDef */
NewConfig(char * myname,SyntaxDef * syntax,ConfigDataType type,ConfigData source,SpecialFunc special,int create)281 ConfigDef *NewConfig (char *myname, SyntaxDef * syntax,
282 ConfigDataType type, ConfigData source,
283 SpecialFunc special, int create)
284 {
285 ConfigDef *new_conf;
286
287 if (myname == NULL)
288 return NULL;
289
290 new_conf = (ConfigDef *) safecalloc (1, sizeof (ConfigDef));
291 new_conf->special = special;
292 new_conf->fd = -1;
293 new_conf->fp = NULL;
294 new_conf->flags = 0;
295 if (source.vptr != NULL)
296 switch (type) {
297 case CDT_Filename:
298 {
299 char *realfilename = put_file_home (source.filename);
300
301 if (!realfilename) {
302 free (new_conf);
303 return NULL;
304 }
305 new_conf->fd =
306 #ifdef __CYGWIN__
307 open (realfilename,
308 create ? O_CREAT | O_RDONLY | O_BINARY : O_RDONLY,
309 S_IRUSR | S_IWUSR | S_IRGRP | O_BINARY);
310 #else
311 open (realfilename, create ? O_CREAT | O_RDONLY : O_RDONLY,
312 S_IRUSR | S_IWUSR | S_IRGRP);
313 #endif
314 free (realfilename);
315 set_flags (new_conf->flags, CP_NeedToCloseFile);
316 }
317 break;
318 case CDT_FilePtr:
319 new_conf->fp = source.fileptr;
320 new_conf->fd = fileno (new_conf->fp);
321 break;
322 case CDT_FileDesc:
323 new_conf->fd = *source.filedesc;
324 break;
325 case CDT_Data:
326 break;
327 case CDT_FilePtrAndData:
328 new_conf->fp = source.fileptranddata->fp;
329 new_conf->fd = fileno (new_conf->fp);
330 set_flags (new_conf->flags, CP_ReadLines);
331 break;
332
333 }
334
335 if (new_conf->fd != -1 && new_conf->fp == NULL) {
336 new_conf->fp =
337 fdopen (new_conf->fd,
338 get_flags (new_conf->flags, CP_ReadLines) ? "rt" : "rb");
339 set_flags (new_conf->flags, CP_NeedToFCloseFile);
340 }
341
342
343 new_conf->myname = mystrdup (myname);
344 new_conf->current_syntax = NULL;
345 new_conf->current_tail = NULL;
346 new_conf->current_prepend = NULL;
347 new_conf->current_prepend_size = 0;
348 new_conf->current_prepend_allocated = 0;
349
350 PushSyntax (new_conf, syntax);
351
352 PrepareSyntax (syntax);
353
354 /* allocated to store lines read from the file */
355 new_conf->buffer = NULL;
356 new_conf->buffer_size = 0;
357 new_conf->bytes_in = 0;
358
359 /* this is the current parsing information */
360 new_conf->tline = new_conf->tdata = new_conf->tline_start = NULL;
361 new_conf->current_term = NULL;
362 new_conf->current_data_size = MAXLINELENGTH + 1;
363 new_conf->current_data =
364 (char *)safemalloc (new_conf->current_data_size);
365 new_conf->current_data_len = 0;
366 new_conf->cursor = NULL;
367 return new_conf;
368 }
369
370 /* reader initialization */
InitConfigReader(char * myname,SyntaxDef * syntax,ConfigDataType type,ConfigData source,SpecialFunc special)371 ConfigDef *InitConfigReader (char *myname, SyntaxDef * syntax,
372 ConfigDataType type, ConfigData source,
373 SpecialFunc special)
374 {
375 ConfigDef *new_conf =
376 NewConfig (myname, syntax, type, source, special, False);
377
378 if (new_conf == NULL)
379 return NULL;
380 if (source.vptr == NULL) {
381 DestroyConfig (new_conf);
382 return NULL;
383 }
384
385 if (type == CDT_Data) {
386 /* allocate to store entire data */
387 new_conf->buffer_size = strlen (source.data) + 1;
388 new_conf->buffer = (char *)safemalloc (new_conf->buffer_size);
389 strcpy (new_conf->buffer, source.data);
390 new_conf->bytes_in = new_conf->buffer_size - 1;
391 } else if (type == CDT_FilePtrAndData) {
392 FilePtrAndData *fpd = source.fileptranddata;
393 int buf_len = fpd->data ? strlen (fpd->data) : 0;
394
395 if (buf_len < MAXLINELENGTH)
396 buf_len = MAXLINELENGTH;
397 new_conf->buffer_size = buf_len;
398 new_conf->buffer = (char *)safemalloc (buf_len + 1);
399 if (fpd->data)
400 strcpy (new_conf->buffer, fpd->data);
401 else
402 new_conf->buffer[0] = '\0';
403 } else {
404 new_conf->buffer_size = MAXLINELENGTH + 1;
405 new_conf->buffer = (char *)safemalloc (new_conf->buffer_size);
406 new_conf->buffer[0] = '\0';
407 }
408
409 /* this is the current parsing information */
410 new_conf->cursor = &(new_conf->buffer[0]);
411 new_conf->line_count = 1;
412
413 return new_conf;
414 }
415
416 /* debugging stuff */
417 #ifdef DEBUG_PARSER
PrintSyntax(SyntaxDef * syntax)418 void PrintSyntax (SyntaxDef * syntax)
419 {
420 if (syntax->recursion > 0)
421 return;
422 syntax->recursion++;
423
424 fprintf (stderr, "\nSentence Terminator: [0x%2.2x]", syntax->terminator);
425 fprintf (stderr, "\nConfig Terminator: [0x%2.2x]",
426 syntax->file_terminator);
427 syntax->recursion--;
428 }
429
430
PrintConfigReader(ConfigDef * config)431 void PrintConfigReader (ConfigDef * config)
432 {
433 PrintSyntax (config->syntax);
434 }
435
436 #endif
437
438
439 /* reader de-initialization */
DestroyConfig(ConfigDef * config)440 void DestroyConfig (ConfigDef * config)
441 {
442 free (config->myname);
443 if (config->buffer)
444 free (config->buffer);
445 if (config->current_data)
446 free (config->current_data);
447 while (PopSyntax (config)) ;
448 if (config->current_syntax)
449 free (config->current_syntax);
450 while (PopStorage (config)) ;
451 if (config->current_prepend)
452 free (config->current_prepend);
453 if (config->current_tail)
454 free (config->current_tail);
455 if (config->syntax)
456 FreeSyntaxHash (config->syntax);
457 if (get_flags (config->flags, CP_NeedToCloseFile) && config->fd != -1)
458 close (config->fd);
459 if (get_flags (config->flags, CP_NeedToFCloseFile) && config->fp != NULL)
460 fclose (config->fp);
461 free (config);
462 }
463
print_trimmed_str(char * prompt,char * str)464 void print_trimmed_str (char *prompt, char *str)
465 {
466 #ifdef LOCAL_DEBUG
467 int i = 0;
468 char tmp;
469
470 while (str[i] && i < 20) {
471 if (str[i] == '\n')
472 str[i] = '}';
473 ++i;
474 }
475 tmp = str[i];
476 str[i] = '\0';
477 LOCAL_DEBUG_OUT ("first %d chars of %s:\"%s\"", i, prompt, str);
478 str[i] = tmp;
479 while (--i >= 0)
480 if (str[i] == '}')
481 str[i] = '\n';
482 #endif
483 }
484
485 void
ProcessSubSyntax(ConfigDef * config,void * storage,SyntaxDef * syntax)486 ProcessSubSyntax (ConfigDef * config, void *storage, SyntaxDef * syntax)
487 {
488 PushStorage (config, storage);
489 LOCAL_DEBUG_OUT ("Old_syntax = \"%s\", new_syntax = \"%s\"",
490 config->syntax->display_name, syntax->display_name);
491 if (config->syntax->terminator == syntax->file_terminator) { /* need to push back term's data into config buffer */
492 int skip_tokens = 0;
493
494 config->cursor = config->tdata;
495 skip_tokens = GetTermUseTokensCount (config->current_term);
496 if (get_flags
497 (config->current_term->flags,
498 TF_NAMED | TF_INDEXED | TF_DIRECTION_INDEXED))
499 ++skip_tokens;
500 if (skip_tokens > 0)
501 config->cursor = tokenskip (config->cursor, skip_tokens);
502 } else if (config->syntax->terminator == syntax->terminator) { /* need to push back entire term's line into config buffer */
503 config->cursor = config->tline_start;
504 }
505
506 /* fprintf( stderr, "\nprocessing as subsyntax: [%s]", config->cursor );
507 */
508 PushSyntax (config, syntax);
509 }
510
ProcessStatement(ConfigDef * config)511 void ProcessStatement (ConfigDef * config)
512 {
513 if (config && config->statement_handler)
514 config->statement_handler (config);
515 }
516
GetToNextLine(ConfigDef * config)517 char *GetToNextLine (ConfigDef * config)
518 {
519 register char terminator = config->syntax->terminator;
520 register char file_terminator = config->syntax->file_terminator;
521 register char *cur = config->cursor, *buffer_end =
522 &(config->buffer[config->bytes_in]);
523
524 for (; *cur != '\0' && cur < buffer_end; cur++) {
525 if (*cur == '\n')
526 config->line_count++;
527 if (*cur == terminator)
528 break;
529 if (*cur == file_terminator)
530 break;
531 }
532 if (cur < buffer_end && *cur != '\0')
533 cur++;
534
535 config->cursor = cur;
536
537 if (cur >= buffer_end) {
538 if (config->fp) {
539 if (get_flags (config->flags, CP_ReadLines)) {
540 LOCAL_DEBUG_OUT ("Reading Lines ...%s", "");
541 if (!fgets (config->buffer, config->buffer_size - 1, config->fp))
542 return NULL;
543 config->bytes_in = strlen (config->buffer);
544 config->cursor = &(config->buffer[0]);
545 } else {
546 register int i;
547 register char *ptr = config->buffer;
548
549 LOCAL_DEBUG_OUT ("Reading Buffer ...%s", "");
550 config->bytes_in = read (config->fd, ptr, config->buffer_size - 1);
551 if (config->bytes_in <= 0)
552 return NULL;
553 print_trimmed_str ("new data begins with", ptr);
554 /* now we want to get back to the last end-of-line
555 so not to break statements in half */
556 for (i = config->bytes_in - 1; i >= 0; i--)
557 if (ptr[i] == '\n')
558 break;
559 i++;
560 if (i > 0) {
561 lseek (config->fd, i - (config->bytes_in), SEEK_CUR);
562 config->bytes_in = i;
563 }
564 ptr[config->bytes_in] = '\0';
565 #ifdef __CYGWIN__ /* fuck Microsoft !!!!! */
566 while (--i >= 0)
567 if (ptr[i] == 0x0D)
568 ptr[i] = 0x0A;
569 #endif
570 }
571 config->cursor = &(config->buffer[0]);
572 } else
573 return NULL;
574 } else if (*cur == file_terminator)
575 return NULL;
576
577 return (config->cursor);
578 }
579
580 /* this function finds next valid statement:
581 - not comments,
582 - not an empty line,
583 - if prepended with * - should have MyName at the beginning
584 and :
585 - sets tline to the beginning of the keyword (not MyName),
586 - copies arguments into the current_data
587 - sets current_data_len
588 it will read data from the file as needed untill the end of file
589 or config->syntax.file_terminator or EOF is reached
590 Return: NULL if end of config reached, otherwise same as tline.
591 */
GetNextStatement(ConfigDef * config)592 char *GetNextStatement (ConfigDef * config)
593 {
594 char *cur = config->cursor; /* don't forget to save it back ! */
595 register char *data;
596 char terminator = config->syntax->terminator;
597 char file_terminator = config->syntax->file_terminator;
598
599 while (1) {
600 config->tline_start = cur; /* remember beginning of the entire config option */
601 for (; *cur != '\0' && *cur != terminator; cur++) {
602 if (*cur == file_terminator)
603 return NULL;
604 #ifdef __CYGWIN__
605 if (!isspace ((int)*cur) && *cur != 0x0D)
606 #else
607 if (!isspace ((int)*cur))
608 #endif
609 {
610 register int i;
611
612 config->current_flags = CF_NONE;
613
614 if (*cur == COMMENTS_CHAR) { /* let's check for DISABLE keyword */
615 print_trimmed_str ("comments at", cur);
616 for (i = 1; i < DISABLED_KEYWORD_SIZE; i++)
617 if (cur[i] == '\0' || cur[i] != _disabled_keyword[i])
618 break;
619 if (i == DISABLED_KEYWORD_SIZE) { /* comments - skip entire line */
620 config->current_flags |= CF_DISABLED_OPTION;
621 /* let's skip few spaces here */
622 while (isspace ((int)cur[i]) && cur[i] != terminator)
623 ++i;
624 if (cur[i] == '\0' || cur[i] == terminator)
625 break; /* not a valid option */
626 cur = &cur[i];
627 } else
628 set_flags (config->current_flags, CF_PUBLIC_OPTION); /* comments are always public */
629 }
630
631 if (*cur == MYNAME_CHAR) { /* check if we have MyName here */
632 register char *mname = config->myname;
633
634 print_trimmed_str ("private option at", cur);
635 ++cur;
636 for (i = 0; mname[i] != '\0' && cur[i] != '\0'; ++i)
637 if (tolower (mname[i]) != tolower (cur[i]))
638 break;
639 if (mname[i] != '\0') { /* that was a foreign optiion - belongs to the other executable */
640 if (get_flags (config->flags, CP_IgnoreForeign))
641 break;
642 set_flags (config->current_flags, CF_FOREIGN_OPTION);
643 /* keeping *MyName part of the token without leading * for foreign options */
644 } else
645 cur += i; /* skipping *MyName part of the token */
646 } else {
647 if (*cur == terminator || *cur == file_terminator) /* public option keyword may not be empty ! */
648 break;
649 if (get_flags (config->flags, CP_IgnorePublic))
650 break;
651 set_flags (config->current_flags, CF_PUBLIC_OPTION);
652 print_trimmed_str ("public option at", cur);
653 }
654 config->tline = cur; /*that will be the begginnig of the term */
655
656 /* now we should copy everything from after the first space to
657 config->current_data and set current_data_len ; (unless its a comment) */
658 if (*cur != COMMENTS_CHAR) {
659 i = 0;
660 while (cur[i] && !isspace ((int)cur[i]) && cur[i] != terminator
661 && cur[i] != file_terminator)
662 ++i;
663 while (isspace ((int)cur[i]) && cur[i] != terminator
664 && cur[i] != file_terminator)
665 ++i;
666 } else
667 i = 1;
668
669 cur = &(cur[i]); /* that will be the beginning of our data */
670 config->tdata = cur;
671 print_trimmed_str ("data start at :", cur);
672 data = config->current_data;
673 for (i = 0;
674 cur[i] && cur[i] != terminator && cur[i] != file_terminator;
675 ++i) {
676 /* buffer overrun prevention */
677 if (i >= config->current_data_size) {
678 config->current_data_size += MAXLINELENGTH >> 3;
679 config->current_data =
680 (char *)realloc (config->current_data,
681 config->current_data_size);
682 if (config->current_data == NULL) {
683 config_error (config,
684 "Not enough memory to hold option's arguments");
685 return NULL;
686 }
687 data = config->current_data;
688 }
689 data[i] = cur[i];
690 }
691 LOCAL_DEBUG_OUT ("%d bytes of data stored", i);
692 cur = &(cur[i]);
693 /* now let's go back and remove trailing spaces */
694 if (config->tdata[0] == file_terminator)
695 set_flags (config->current_flags, CF_LAST_OPTION);
696 else {
697 while (--i >= 0) {
698 if (config->tdata[i] == file_terminator)
699 set_flags (config->current_flags, CF_LAST_OPTION);
700 if (!isspace ((int)data[i]))
701 break;
702 }
703 i++;
704 }
705 /* since \0 is our normal data terminator we really should trigger
706 end of the configuration when the file ends : */
707 if (file_terminator == '\0')
708 clear_flags (config->current_flags, CF_LAST_OPTION);
709 LOCAL_DEBUG_OUT ("%d bytes of clean data stored", i);
710 config->current_data_len = i;
711 config->current_data[i] = '\0';
712
713 if (*cur && *cur == terminator)
714 cur++;
715 config->cursor = cur; /* Saving position for future use */
716 return config->tline;
717 }
718 }
719 /* reading file here */
720 if ((cur = GetToNextLine (config)) == NULL)
721 return NULL;
722 }
723 return NULL;
724 }
725
726
727 TermDef _as_comments_term =
728 { TF_NO_MYNAME_PREPENDING, "#", 1, TT_COMMENT, TT_COMMENT, NULL };
729 TermDef _as_unknown_term_public =
730 { TF_NO_MYNAME_PREPENDING, "unknown", 7, TT_ANY, TT_ANY, NULL };
731 TermDef _as_unknown_term_private =
732 { 0, "unknown", 7, TT_ANY, TT_ANY, NULL };
733
FindStatementTerm(char * tline,SyntaxDef * syntax)734 TermDef *FindStatementTerm (char *tline, SyntaxDef * syntax)
735 {
736 ASHashData hdata = { 0 };
737 LOCAL_DEBUG_OUT
738 ("looking for pterm for [%c%c%c...]in hash table %p of the syntax %s ",
739 tline[0], tline[1], tline[2], syntax->term_hash,
740 syntax->display_name);
741 if (tline[0] == COMMENTS_CHAR)
742 return &_as_comments_term;
743
744 if (isspace (tline[0])) {
745 int i = 0;
746
747 while (isspace (tline[i]))
748 ++i;
749 if (tline[i] == '~')
750 if (get_hash_item
751 (syntax->term_hash, AS_HASHABLE (&tline[i]),
752 &hdata.vptr) == ASH_Success)
753 return hdata.vptr;
754 }
755 if (get_hash_item (syntax->term_hash, AS_HASHABLE (tline), &hdata.vptr)
756 != ASH_Success)
757 hdata.vptr = NULL;
758 LOCAL_DEBUG_OUT ("FOUND pterm %p", hdata.vptr);
759 return hdata.vptr;
760 }
761
762
763
764 /* main parsing procedure */
config2tree_storage(ConfigDef * config,ASTreeStorageModel ** tail)765 int config2tree_storage (ConfigDef * config, ASTreeStorageModel ** tail)
766 {
767 int TopLevel = 0;
768
769 PushStorage (config, tail);
770 /* get line */
771 while (!TopLevel) {
772 while (GetNextStatement (config)) { /* untill not end of text */
773 TermDef *pterm = NULL;
774 unsigned long flags = 0;
775
776 #ifdef DEBUG_PARSER
777 fprintf (stderr, "\nSentence Found:[%.50s ...]\n,\tData=\t[%s]",
778 config->tline, config->current_data);
779 fprintf (stderr, "\nLooking for the Term...");
780 #endif
781 /* find term */
782 if (get_flags (config->current_flags, CF_FOREIGN_OPTION)) {
783 int i = 0;
784
785 do {
786 ++i; /* it's ok - we can start with 1, since myname should have at least 1 char */
787 pterm = FindStatementTerm (&(config->tline[i]), config->syntax);
788 }
789 while (pterm == NULL && !isspace (config->tline[i])
790 && config->tline[i] != '\0');
791 } else
792 pterm = FindStatementTerm (config->tline, config->syntax);
793
794 if (pterm == NULL)
795 pterm = get_flags (config->current_flags, CF_PUBLIC_OPTION) ?
796 &_as_unknown_term_public : &_as_unknown_term_private;
797
798 config->current_term = pterm;
799
800 LOCAL_DEBUG_OUT ("Term:[%s]", config->current_term->keyword);
801 if (isspace (config->tline[0]) && pterm->keyword_len > 0 && mystrncasecmp (pterm->keyword, config->current_data, pterm->keyword_len) == 0) { /* we need to skip one token in current_data : */
802 char *src = tokenskip (config->current_data, 1);
803 char *dst = config->current_data;
804
805 if (src != dst) {
806 int i = 0;
807
808 do {
809 dst[i] = src[i];
810 }
811 while (src[++i]);
812 dst[i] = '\0';
813 }
814 }
815 if (get_flags (pterm->flags, TF_OBSOLETE))
816 config_error (config,
817 "Heh, It seems that I've encountered obsolete config option. I'll ignore it for now, Ok ?!");
818 if (get_flags (pterm->flags, TF_PHONY))
819 set_flags (config->flags, CF_PHONY_OPTION);
820 if (get_flags (pterm->flags, TF_SPECIAL_PROCESSING)) {
821 if (config->special) {
822 flags = (*(config->special)) (config);
823 if (get_flags (flags, SPECIAL_BREAK))
824 break;
825 if (get_flags (flags, SPECIAL_STORAGE_ADDED)) {
826 ASTreeStorageModel **ctail = config->current_tail->storage;
827
828 while (*ctail)
829 ctail = &((*ctail)->next);
830 tail = config->current_tail->storage = ctail;
831 }
832 }
833 }
834 if (!get_flags (flags, SPECIAL_SKIP))
835 ProcessStatement (config);
836 /* Process Statement may alter config's state as it may dive into subconfig -
837 * must make sure that did not happen : */
838 if (config->current_term) {
839 if (get_flags (config->current_term->flags, TF_SYNTAX_TERMINATOR)
840 || IsLastOption (config))
841 break;
842 }
843 } /* end while( GetNextStatement() ) */
844 /* trying to see if we can get to higher level syntax */
845 if (!PopSyntax (config))
846 TopLevel = 1;
847 if (!PopStorage (config))
848 TopLevel = 1;
849 while ((TopLevel != 1) &&
850 ((config->current_term &&
851 (config->current_term->flags & TF_SYNTAX_TERMINATOR))
852 || IsLastOption (config))) {
853 if (!PopSyntax (config))
854 TopLevel = 1;
855 if (!PopStorage (config))
856 TopLevel = 1;
857 }
858 } /* end while( !TopLevel ) */
859
860 return 1;
861 }
862
863
864
865 /****************************************************************************************/
866 /* Assorted utility functions */
867 /****************************************************************************************/
868 /* service functions */
FlushConfigBuffer(ConfigDef * config)869 void FlushConfigBuffer (ConfigDef * config)
870 {
871 config->buffer[0] = '\0';
872 config->cursor = &(config->buffer[0]);
873 }
874
875 /***************************************************************************/
876 /***************************************************************************/
877 /* config Writing stuff */
878 /***************************************************************************/
879 /* writer initialization */
InitConfigWriter(char * myname,SyntaxDef * syntax,ConfigDataType type,ConfigData source)880 ConfigDef *InitConfigWriter (char *myname, SyntaxDef * syntax,
881 ConfigDataType type, ConfigData source)
882 {
883 #ifdef WITH_CONFIG_WRITER
884 ConfigDef *new_conf =
885 NewConfig (myname, syntax, type, source, NULL, True);
886
887 if (new_conf == NULL)
888 return NULL;
889 if (source.vptr != NULL) {
890 if (type == CDT_Data) {
891 if ((new_conf->buffer_size = strlen (source.data)) > 0) {
892 new_conf->buffer = safemalloc (++(new_conf->buffer_size));
893 strcpy (new_conf->buffer, source.data);
894 }
895 } else { /* reading entire file in memory here */
896 struct stat file_stats;
897
898 if (new_conf->fd != -1)
899 if (fstat (new_conf->fd, &file_stats) == 0) {
900 if ((new_conf->buffer_size = file_stats.st_size) > 0) {
901 int bytes_read;
902
903 new_conf->buffer =
904 (char *)safemalloc (++new_conf->buffer_size);
905 if ((bytes_read =
906 read (new_conf->fd, new_conf->buffer,
907 file_stats.st_size)) > 0)
908 new_conf->buffer[bytes_read] = '\0';
909 else {
910 free (new_conf->buffer);
911 new_conf->buffer = NULL;
912 new_conf->buffer_size = 0;
913 }
914 } else { /* file is empty, so continuing onto creating a new file */
915 new_conf->buffer = safemalloc (1);
916 new_conf->buffer[0] = '\0';
917 new_conf->buffer_size = 1;
918 }
919 }
920 }
921 if (new_conf->buffer == NULL) {
922 DestroyConfig (new_conf);
923 return NULL;
924 }
925 new_conf->bytes_in = new_conf->buffer_size - 1;
926
927 new_conf->cursor = &(new_conf->buffer[0]);
928 }
929
930 return new_conf;
931 #else
932 return NULL;
933 #endif
934 }
935
936 /***************************************************************************/
937 /* writes block of text in to the output buffer, enlarging it if needed.
938 * it starts with block_start and end with block_end or '\0'
939 * if block_end is NULL
940 */
941
942 void
WriteBlock(struct WriteBuffer * t_buffer,char * block_start,char * block_end)943 WriteBlock (struct WriteBuffer *t_buffer, char *block_start,
944 char *block_end)
945 {
946 size_t bytes_to_add;
947
948 if (t_buffer == NULL || block_start == NULL)
949 return;
950 bytes_to_add =
951 (block_end == NULL) ? strlen (block_start) : block_end - block_start;
952 if (bytes_to_add <= 0)
953 return;
954 /*make sure we always have 1 byte left at the end ( for trailing 0 ) */
955 /* and 1 byte left for file terminator */
956 if (t_buffer->allocated < t_buffer->used + bytes_to_add + 2) { /* growing buffer by 1/8 of it's size */
957 size_t add_size =
958 t_buffer->used + bytes_to_add + 2 - t_buffer->allocated;
959
960 if (add_size < (t_buffer->allocated >> 3))
961 add_size = (t_buffer->allocated >> 3);
962 if (t_buffer->buffer != NULL && t_buffer->allocated > 0)
963 t_buffer->buffer =
964 realloc (t_buffer->buffer, t_buffer->allocated + add_size);
965 else
966 t_buffer->buffer = safemalloc (t_buffer->allocated + add_size);
967 t_buffer->allocated += add_size;
968 }
969 memcpy (t_buffer->buffer + t_buffer->used, block_start, bytes_to_add);
970 t_buffer->used += bytes_to_add;
971 }
972
973
parser_add_terminator(char * ptr,char terminator)974 char *parser_add_terminator (char *ptr, char terminator)
975 {
976 if (*ptr != terminator && (*ptr == '\0' && *(ptr - 1) != terminator))
977 *(ptr++) = terminator;
978 return ptr;
979 }
980
981
982 int
WriteFreeStorageToFile(const char * filename,const char * myname,SyntaxDef * syntax,FreeStorageElem * fs,ASFlagType flags)983 WriteFreeStorageToFile (const char *filename, const char *myname,
984 SyntaxDef * syntax, FreeStorageElem * fs,
985 ASFlagType flags)
986 {
987 ConfigDef *Writer = NULL;
988 ConfigData cd;
989
990 cd.filename = filename;
991 if ((Writer =
992 InitConfigWriter ((char *)myname, syntax, CDT_Filename,
993 cd)) == NULL)
994 return 2;
995
996 cd.filename = filename;
997 WriteConfig (Writer, fs, CDT_Filename, &cd, flags);
998 DestroyConfig (Writer);
999
1000 return 0;
1001 }
1002