source: rtems/tools/cpu/nios2/ptf.c @ c83bad2f

5
Last change on this file since c83bad2f was 439d0ae6, checked in by Joel Sherrill <joel.sherrill@…>, on 03/21/15 at 19:45:42

tools/cpu/nios2/ptf.c: Add include of <ctype.h>

  • Property mode set to 100644
File size: 19.2 KB
Line 
1/*
2 *  Copyright (c) 2006 Kolja Waschk rtemsdev/ixo.de
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <errno.h>
13#include <ctype.h>
14#include "ptf.h"
15
16#define PTFPARSER_MAXDEPTH 20
17#define PTFPARSER_NAMEBUFSIZE 1024
18#define PTFPARSER_VALUEBUFSIZE 4096
19
20#define DEBUG_EXPECTATIONS 1
21#define DEBUG_READVALUES 2
22#define DEBUG_FINDER 4
23#define DEBUG 0
24
25struct ptf_parser_state
26{
27  struct ptf *tree;
28  struct ptf *current_in[PTFPARSER_MAXDEPTH];
29  struct ptf *current_item;
30
31  long line;  /* starts with 1, increments whenever a LF (ASCII 10) passes */
32  int section_level; /* starts at 0, incremented at {, decremented at } */
33  char *filename;
34  char name_buffer[PTFPARSER_NAMEBUFSIZE];
35  int name_length;
36  char value_buffer[PTFPARSER_VALUEBUFSIZE];
37  int value_length;
38  struct
39  {
40    unsigned error:1;
41    unsigned escaped:1;
42    unsigned single_quoted:1;
43    unsigned double_quoted:1;
44  } flag;
45
46  enum
47  {
48    section_or_item_specification,
49    more_section_type_or_item_name_chars,
50    whitespace_after_section_specification,
51    whitespace_after_section_or_item_name,
52    whitespace_before_item_value,
53    more_section_name_chars,
54    more_item_value_chars,
55  } expectation;
56};
57
58/***************************************************************************/
59struct ptf *ptf_alloc_item(ptf_item_type t, char *name, char *value)
60{
61  struct ptf *new_item;
62  new_item = (struct ptf *)malloc(sizeof(struct ptf));
63  if(!new_item) return NULL;
64
65  new_item->type = t;
66  new_item->sub = NULL;
67  new_item->next = NULL;
68  new_item->name = NULL;
69  new_item->value = NULL;
70
71  if(name != NULL)
72  {
73    int n = strlen(name);
74    if(n > 0)
75    {
76      new_item->name = (char *)malloc(n + 1);
77      if(new_item->name == NULL)
78      {
79        free(new_item);
80        return NULL;
81      };
82      strcpy(new_item->name, name);
83    }
84  };
85
86  if(value != NULL)
87  {
88    int n = strlen(value);
89    if(n > 0)
90    {
91      new_item->value = (char *)malloc(n + 1);
92      if(new_item->value == NULL)
93      {
94        if(name != NULL) free(new_item->name);
95        free(new_item);
96        return NULL;
97      };
98      strcpy(new_item->value, value);
99    };
100  };
101
102  return new_item;
103}
104
105/***************************************************************************/
106void add_ptf_item(struct ptf_parser_state *state, struct ptf *item)
107{
108   if(state->current_item == NULL)
109   {
110     if(state->section_level > 0)
111       state->current_in[state->section_level-1]->sub = item;
112     else
113       state->tree = item;
114   }
115   else
116     state->current_item->next = item;
117}
118
119
120/***************************************************************************/
121void parse_error(struct ptf_parser_state *state, char *errmsg)
122{
123  fprintf(stderr, "Error while parsing %s (line %lu): %s\n",
124    state->filename, state->line, errmsg);
125
126  state->flag.error = 1;
127}
128
129/***************************************************************************/
130void init_parser(struct ptf_parser_state *state, char *filename)
131{
132  int i;
133
134  state->line = 1;
135  state->flag.error = 0;
136  state->flag.escaped = 0;
137  state->flag.double_quoted = 0;
138  state->flag.single_quoted = 0;
139  state->section_level = 0;
140
141  state->filename = (char *)malloc(strlen(filename)+1);
142  if(state->filename != NULL) strcpy(state->filename, filename);
143
144  state->expectation = section_or_item_specification;
145
146  state->tree = NULL;
147  state->current_item = NULL;
148  for(i=1; i<PTFPARSER_MAXDEPTH; i++) state->current_in[i] = NULL;
149}
150
151/***************************************************************************/
152void ptf_free(struct ptf *ptf)
153{
154  struct ptf *this, *next;
155  for(this = ptf; this != NULL; this = next)
156  {
157    next = this->next;
158    if(this->value != NULL) free(this->value);
159    if(this->name != NULL) free(this->name);
160    if(this->type == section) ptf_free(this->sub);
161    free(this);
162  };
163}
164
165/***************************************************************************/
166void abort_parsing(struct ptf_parser_state *state)
167{
168  if(state->filename != NULL) free(state->filename);
169  ptf_free(state->tree);
170}
171
172/***************************************************************************/
173int add_char_to_buffer(int *len, char *buf, int maxlen, char c)
174{
175  if(*len >= maxlen) return 0;
176
177  buf[(*len)++] = c;
178
179  return 1;
180}
181
182/***************************************************************************/
183void parse_char(struct ptf_parser_state *state, int c)
184{
185  int is_not_quoted;
186  int is_no_space;
187  enum { item_parsed, section_opened, section_closed, none } parser_event;
188
189  switch(c)
190  {
191    case '\\':
192    {
193      if(state->flag.escaped == 0)
194      {
195        state->flag.escaped = 1;
196        return;
197      };
198      break;
199    };
200    case '"':
201    {
202      if(!state->flag.escaped && !state->flag.single_quoted)
203      {
204        state->flag.double_quoted = 1 - state->flag.double_quoted;
205        return;
206      }
207      break;
208    };
209    case '\'':
210    {
211      if(!state->flag.escaped && !state->flag.double_quoted)
212      {
213        state->flag.single_quoted = 1 - state->flag.single_quoted;
214        return;
215      }
216      break;
217    };
218    case '\n':
219    {
220      state->line++;
221      break;
222    };
223    default:
224      break;
225  };
226
227  parser_event = none;
228
229  is_not_quoted = !(state->flag.escaped ||
230    state->flag.single_quoted || state->flag.double_quoted);
231  is_no_space = (!is_not_quoted || !isspace(c));
232  state->flag.escaped = 0;
233
234  switch(state->expectation)
235  {
236    case section_or_item_specification:
237    {
238#if DEBUG&DEBUG_EXPECTATIONS
239      printf("Expectation: section_or_item_specification\n");
240#endif
241
242      if(is_not_quoted && c == '}')
243      {
244        parser_event = section_closed;
245      }
246      else if(is_no_space)
247      {
248        state->name_length = 1;
249        state->name_buffer[0] = c;
250        state->expectation = more_section_type_or_item_name_chars;
251      };
252      break;
253    };
254
255    case more_section_type_or_item_name_chars:
256    {
257#if DEBUG&DEBUG_EXPECTATIONS
258      printf("Expectation: more_section_type_or_item_name_chars\n");
259#endif
260
261      /* Item name is stored in name_buffer */
262      /* Section type is stored in name_buffer */
263      if(is_no_space)
264      {
265        if(!add_char_to_buffer(&state->name_length, state->name_buffer, PTFPARSER_NAMEBUFSIZE, c))
266          parse_error(state, "First word is too long; I expected a shorter section type or item name");
267      }
268      else
269      {
270        state->expectation = whitespace_after_section_or_item_name;
271      }
272      break;
273    };
274
275    case whitespace_after_section_specification:
276    {
277#if DEBUG&DEBUG_EXPECTATIONS
278      printf("Expectation: whitespace_after_section_specification\n");
279#endif
280
281      if(c == '{')
282        parser_event = section_opened;
283      else if(is_no_space)
284        parse_error(state, "Expected section content within brackets {...}");
285      break;
286    };
287
288    case whitespace_after_section_or_item_name:
289    {
290#if DEBUG&DEBUG_EXPECTATIONS
291      printf("Expectation: whitespace_after_section_or_item_name\n");
292#endif
293
294      if(c == '{')
295      {
296        state->value_length = 0;
297        parser_event = section_opened;
298      }
299      else if(c == '=')
300        state->expectation = whitespace_before_item_value;
301      else if(is_no_space)
302      {
303        state->value_length = 1;
304        state->value_buffer[0] = c;
305        state->expectation = more_section_name_chars;
306      };
307      break;
308    };
309
310    case more_section_name_chars:
311    {
312#if DEBUG&DEBUG_EXPECTATIONS
313      printf("Expectation: more_section_name_chars\n");
314#endif
315
316      /* Section name is stored in value_buffer */
317      if(is_no_space)
318      {
319        if(!add_char_to_buffer(&state->value_length, state->value_buffer, PTFPARSER_VALUEBUFSIZE, c))
320          parse_error(state, "Section name is too long");
321      }
322      else
323        state->expectation = whitespace_after_section_specification;
324      break;
325    }
326
327    case whitespace_before_item_value:
328    {
329#if DEBUG&DEBUG_EXPECTATIONS
330      printf("Expectation: whitespace_before_item_value\n");
331#endif
332
333      if(is_not_quoted && c == ';')
334      {
335        state->value_length = 0;
336        parser_event = item_parsed;
337      }
338      else if(is_no_space)
339      {
340        state->value_length = 1;
341        state->value_buffer[0] = c;
342        state->expectation = more_item_value_chars;
343      };
344      break;
345    };
346
347    case more_item_value_chars:
348    {
349#if DEBUG&DEBUG_EXPECTATIONS
350      printf("Expectation: more_item_value_chars\n");
351#endif
352
353      /* Item value is stored in value_buffer */
354      if(is_not_quoted && c == ';')
355        parser_event = item_parsed;
356      else if(is_no_space)
357      {
358        if(!add_char_to_buffer(&state->value_length, state->value_buffer, PTFPARSER_VALUEBUFSIZE, c))
359          parse_error(state, "Item value is too long");
360      }
361      else
362        parser_event = item_parsed;
363      break;
364    }
365
366    default:
367#if DEBUG&DEBUG_EXPECTATIONS
368      printf("Expectation: %d (?)\n", state->expectation);
369#endif
370
371      parse_error(state, "Internal error: Unhandled state of expectation");
372  };
373
374  switch(parser_event)
375  {
376    /* TODO: pointer tuff */
377
378    case item_parsed:
379    {
380      struct ptf *new_item;
381      state->name_buffer[state->name_length] = 0;
382      state->value_buffer[state->value_length] = 0;
383#if DEBUG&DEBUG_READVALUES
384      printf("== Item %s is '%s' ==\n", state->name_buffer, state->value_buffer);
385#endif
386
387      new_item = ptf_alloc_item(item, state->name_buffer, state->value_buffer);
388      if(new_item == NULL)
389      {
390        parse_error(state, "Internal error: "
391            "Could not allocate memory for new item");
392        return;
393      };
394
395      add_ptf_item(state, new_item);
396      state->current_item = new_item;
397      state->expectation = section_or_item_specification;
398
399      break;
400    };
401    case section_opened:
402    {
403      struct ptf *new_section;
404      state->name_buffer[state->name_length] = 0;
405      state->value_buffer[state->value_length] = 0;
406#if DEBUG&DEBUG_READVALUES
407      printf("== New %s section '%s' opened ==\n", state->name_buffer, state->value_buffer);
408#endif
409
410      if(state->section_level >= PTFPARSER_MAXDEPTH-1)
411      {
412        parse_error(state, "Internal error: "
413             "cannot handle sections nested as deep as here.");
414        return;
415      };
416
417      new_section = ptf_alloc_item(section, state->name_buffer, state->value_buffer);
418      if(new_section == NULL)
419      {
420        parse_error(state, "Internal error: "
421            "Could not allocate memory for new section");
422        return;
423      };
424
425      add_ptf_item(state, new_section);
426      state->current_item = NULL;
427      state->current_in[state->section_level] = new_section;
428      state->section_level++;
429
430      state->expectation = section_or_item_specification;
431      break;
432    };
433    case section_closed:
434    {
435      if(state->section_level < 1)
436      {
437        parse_error(state, "Found closing '}' without opening '{' before");
438        return;
439      };
440
441      state->section_level--;
442      state->current_item = state->current_in[state->section_level];
443      state->expectation = section_or_item_specification;
444#if DEBUG&DEBUG_READVALUES
445      printf("-- Closed section --\n");
446#endif
447      break;
448    };
449    default:
450      break;
451  };
452}
453
454/***************************************************************************/
455struct ptf *ptf_parse_file(char *filename)
456{
457  FILE *f;
458  char buffer[1024];
459
460  struct ptf *root;
461  struct ptf_parser_state state;
462
463  if(filename == NULL)
464  {
465    fprintf(stderr, "Internal error: "
466                    "No filename was given to ptf_read()\n");
467    return NULL;
468  };
469
470  f = fopen(filename, "r");
471  if(f == NULL)
472  {
473    perror(filename);
474    return NULL;
475  };
476
477  init_parser(&state, filename);
478
479  while(!feof(f))
480  {
481    size_t r, n;
482
483    if(ferror(f))
484    {
485      perror(filename);
486      abort_parsing(&state);
487      fclose(f);
488      return NULL;
489    };
490
491    n = fread(buffer, 1, 1024, f);
492    for(r=0; r<n && (state.flag.error==0); r++) parse_char(&state, buffer[r]);
493  };
494
495  fclose(f);
496
497  if(state.section_level != 0)
498  {
499    parse_error(&state, "Input file seems to be incomplete, "
500                        "one or more sections are not closed with '}'\n");
501  };
502
503  if(state.flag.error)
504  {
505    abort_parsing(&state);
506    return NULL;
507  };
508
509  return state.tree;
510}
511
512/***************************************************************************/
513
514struct ptf *ptf_concat(struct ptf *a, struct ptf *b)
515{
516  struct ptf *leaf = a;
517
518  if(!a) return b;
519  if(!b) return a;
520
521  for(leaf = a; leaf->next != NULL; leaf = leaf->next);
522  leaf->next = b;
523  return a;
524}
525
526/***************************************************************************/
527
528void ptf_dump_ptf_item(FILE *f, struct ptf_item *pi)
529{
530  int i;
531  fprintf(f, "level=%d in %p\n", pi->level, pi);
532  for(i=pi->level;i>=0;i--)
533  {
534    if(pi->item[i] != NULL)
535    {
536      fprintf(f, "  %d: %s name=%s value=%s\n",
537        i,
538        pi->item[i]->type == item ? "item":"section",
539        pi->item[i]->name,
540        pi->item[i]->value);
541    }
542    else
543    {
544        fprintf(f, "  %d: NULL\n", i);
545    }
546    fflush(f);
547  }
548}
549
550/***************************************************************************/
551
552void ptf_printf(FILE *s, struct ptf *tree, char *prefix)
553{
554  struct ptf *leaf;
555
556  for(leaf = tree; leaf != NULL; leaf = leaf->next)
557  {
558    switch(leaf->type)
559    {
560      case section:
561      {
562        char *new_prefix;
563        int new_prefix_len;
564        new_prefix_len = strlen(prefix) + strlen(leaf->name) + 2;
565        if(leaf->value != NULL && leaf->value[0] != 0)
566        {
567          new_prefix_len += strlen(leaf->value) + 1;
568        };
569        new_prefix = (char *)malloc(new_prefix_len);
570        strcpy(new_prefix, prefix);
571        strcat(new_prefix, leaf->name);
572        if(leaf->value != NULL && leaf->value[0] != 0)
573        {
574          strcat(new_prefix, ":");
575          strcat(new_prefix, leaf->value);
576        };
577        strcat(new_prefix, "/");
578        fputs(new_prefix, s);
579        fputs("\n", s);
580        ptf_printf(s, leaf->sub, new_prefix);
581        break;
582      };
583
584      case item:
585      {
586        char *c;
587        fputs(prefix, s);
588        fputs(leaf->name, s);
589        fputs(" = \"", s);
590        if(leaf->value == NULL)
591        {
592          fputs("(NULL)", s);
593        }
594        else
595        {
596          for(c=leaf->value; *c; c++)
597          {
598            if(*c=='\\' || *c=='"') putc('\\', s);
599            putc(*c, s);
600          };
601        }
602        fprintf(s, "\"\n");
603        break;
604      };
605
606      default:
607        break;
608    };
609  };
610}
611
612/***************************************************************************/
613
614int ptf_advance_one(struct ptf_item *item)
615{
616  int d;
617  struct ptf *leaf;
618
619  d = item->level;
620  leaf = item->item[d];
621
622  if(leaf != NULL)
623  {
624    if(leaf->type == section && leaf->sub != NULL)
625    {
626      if(item->level >= MAX_SECTION_NESTING-1)
627      {
628        /* raise an error? hm, for now we silently ignore the subtree */
629      }
630      else
631      {
632        d++;
633        item->item[d] = leaf->sub;
634        item->level = d;
635        return 0;
636      }
637    }
638    item->item[item->level] = leaf->next;
639  };
640
641  while(item->item[d] == NULL)
642  {
643    if(d == 0)
644    {
645      item->level = 0;
646      item->item[0] = NULL;
647      errno = ENOENT;
648      return -1;
649    }
650    d --;
651    leaf = item->item[d];
652    if(leaf != NULL) item->item[d] = leaf->next;
653  };
654
655  item->level = d;
656  return 0;
657}
658
659/***************************************************************************/
660
661int ptf_advance_until(
662  struct ptf_item *item,
663  ptf_item_type ttype,
664  char *name,
665  char *value)
666{
667  int r;
668  struct ptf *leaf;
669
670  do
671  {
672    leaf = item->item[item->level];
673#if DEBUG&DEBUG_FINDER
674    printf(" Does %s/%s match %s/%s?\n", leaf->name, leaf->value, name, value);
675#endif
676
677    if(leaf->type == ttype)
678    {
679      if(name == NULL)
680      {
681        if(value == NULL)
682        {
683          return 0; /* got it (any value) */
684        }
685        else if (leaf->value != NULL)
686        {
687          if(strcmp(leaf->value, value) == 0) return 0; /* got it */
688        }
689      }
690      else if(leaf->name != NULL)
691      {
692        if(strcmp(leaf->name, name) == 0)
693        {
694          if(value == NULL)
695          {
696            return 0; /* got it (any value) */
697          }
698          else if(leaf->value != NULL)
699          {
700            if(strcmp(leaf->value, value) == 0) return 0; /* got it */
701          }
702        }
703      }
704    };
705    r = ptf_advance_one(item);
706
707  } while(r == 0);
708
709  return r;
710}
711
712/***************************************************************************/
713
714struct ptf *ptf_find(
715  struct ptf *tree,
716  struct ptf_item *item,
717  ptf_item_type ttype,
718  char *name,
719  char *value)
720{
721  int r;
722
723  if(item == NULL) { errno = EINVAL; return NULL; };
724  if(tree == NULL) { errno = ENOENT; return NULL; };
725
726  item->level = 0;
727  item->item[0] = tree;
728
729  if(ptf_advance_until(item, ttype, name, value) != 0) return NULL;
730
731  r = item->level;
732  item->level++; /* To match ptf_match */
733  return item->item[r];
734}
735
736/***************************************************************************/
737
738struct ptf *ptf_next(
739  struct ptf_item *item,
740  ptf_item_type ttype,
741  char *name,
742  char *value)
743{
744  int r;
745  struct ptf *leaf;
746
747  if(item == NULL) { errno = EINVAL; return NULL; };
748
749  if(item->level < 1) return NULL;
750  item->level--; /* To match ptf_match */
751
752  r = ptf_advance_one(item);
753
754  if(r == 0) r = ptf_advance_until(item, ttype, name, value);
755
756  if(r != 0) return NULL;
757
758  r = item->level;
759  item->level++; /* To match ptf_match */
760  return item->item[r];
761}
762
763/***************************************************************************/
764
765int ptf_match(
766  struct ptf *const ptf,
767  struct ptf_item *const match,
768  const ptf_match_action action,
769  void *arg)
770{
771    int count;
772    struct ptf *p;
773    struct ptf_item pi;
774
775    p = ptf;
776    count = 0;
777    pi.level = 0;
778
779    while(p != NULL)
780    {
781        ptf_item_type mtype = match->item[pi.level]->type;
782        char *mname = match->item[pi.level]->name;
783        char *mvalue = match->item[pi.level]->value;
784
785#if DEBUG&DEBUG_FINDER
786        printf("Looking for %s/%s, checking %s/%s\n",
787          mname, mvalue, p->name, p->value);
788#endif
789
790        if(mtype == p->type &&
791           (mname==NULL || p->name==NULL || strcmp(mname, p->name)==0) &&
792           (mvalue==NULL || p->value==NULL || strcmp(mvalue, p->value)==0))
793        {
794            pi.item[pi.level] = p;
795
796            if(pi.level == match->level - 1)
797            {
798                if(action != NULL) action(&pi, arg);
799                p = p->next;
800                count++;
801            }
802            else
803            {
804                if(p->sub != NULL && pi.level < MAX_SECTION_NESTING-1)
805                {
806                    pi.item[pi.level] = p;
807                    pi.level++;
808                    p = p->sub;
809                }
810                else
811                {
812                    p = p->next;
813                };
814            };
815        }
816        else
817        {
818            p = p->next;
819        };
820
821        while(p == NULL && pi.level > 0)
822        {
823            pi.level--;
824            p = pi.item[pi.level]->next;
825        };
826    };
827    return count;
828}
829
830/***************************************************************************/
831
832char *ptf_defused_name(char *orig_name)
833{
834  int i,j;
835  char *s = (char *)malloc(1+strlen(orig_name));
836
837  if(!s) return NULL;
838
839  for(i=j=0;orig_name[i];i++)
840  {
841    if(!isalnum(orig_name[i]))
842    {
843      if(j>0) if(s[j-1]!='_') s[j++]='_';
844    }
845    else
846    {
847      s[j++] = toupper(orig_name[i]);
848    };
849  };
850  s[j] = 0;
851  return s;
852}
853
Note: See TracBrowser for help on using the repository browser.