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

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

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