source: rtems/tools/cpu/nios2/ptf.c @ 9147a82

Last change on this file since 9147a82 was 9147a82, checked in by Martin Galvan <martin.galvan@…>, on Sep 2, 2015 at 9:54:23 PM

tools/cpu/nios2/ptf.c: Fix leak of memory pointed to by new_prefix

Updates #2405.

  • Property mode set to 100644
File size: 19.3 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        if (new_prefix != NULL)
571        {
572          strcpy(new_prefix, prefix);
573          strcat(new_prefix, leaf->name);
574          if(leaf->value != NULL && leaf->value[0] != 0)
575          {
576            strcat(new_prefix, ":");
577            strcat(new_prefix, leaf->value);
578          };
579          strcat(new_prefix, "/");
580          fputs(new_prefix, s);
581          fputs("\n", s);
582          ptf_printf(s, leaf->sub, new_prefix);
583          free(new_prefix);
584        }
585        break;
586      };
587
588      case item:
589      {
590        char *c;
591        fputs(prefix, s);
592        fputs(leaf->name, s);
593        fputs(" = \"", s);
594        if(leaf->value == NULL)
595        {
596          fputs("(NULL)", s);
597        }
598        else
599        {
600          for(c=leaf->value; *c; c++)
601          {
602            if(*c=='\\' || *c=='"') putc('\\', s);
603            putc(*c, s);
604          };
605        }
606        fprintf(s, "\"\n");
607        break;
608      };
609
610      default:
611        break;
612    };
613  };
614}
615
616/***************************************************************************/
617
618int ptf_advance_one(struct ptf_item *item)
619{
620  int d;
621  struct ptf *leaf;
622
623  d = item->level;
624  leaf = item->item[d];
625
626  if(leaf != NULL)
627  {
628    if(leaf->type == section && leaf->sub != NULL)
629    {
630      if(item->level >= MAX_SECTION_NESTING-1)
631      {
632        /* raise an error? hm, for now we silently ignore the subtree */
633      }
634      else
635      {
636        d++;
637        item->item[d] = leaf->sub;
638        item->level = d;
639        return 0;
640      }
641    }
642    item->item[item->level] = leaf->next;
643  };
644
645  while(item->item[d] == NULL)
646  {
647    if(d == 0)
648    {
649      item->level = 0;
650      item->item[0] = NULL;
651      errno = ENOENT;
652      return -1;
653    }
654    d --;
655    leaf = item->item[d];
656    if(leaf != NULL) item->item[d] = leaf->next;
657  };
658
659  item->level = d;
660  return 0;
661}
662
663/***************************************************************************/
664
665int ptf_advance_until(
666  struct ptf_item *item,
667  ptf_item_type ttype,
668  char *name,
669  char *value)
670{
671  int r;
672  struct ptf *leaf;
673
674  do
675  {
676    leaf = item->item[item->level];
677#if DEBUG&DEBUG_FINDER
678    printf(" Does %s/%s match %s/%s?\n", leaf->name, leaf->value, name, value);
679#endif
680
681    if(leaf->type == ttype)
682    {
683      if(name == NULL)
684      {
685        if(value == NULL)
686        {
687          return 0; /* got it (any value) */
688        }
689        else if (leaf->value != NULL)
690        {
691          if(strcmp(leaf->value, value) == 0) return 0; /* got it */
692        }
693      }
694      else if(leaf->name != NULL)
695      {
696        if(strcmp(leaf->name, name) == 0)
697        {
698          if(value == NULL)
699          {
700            return 0; /* got it (any value) */
701          }
702          else if(leaf->value != NULL)
703          {
704            if(strcmp(leaf->value, value) == 0) return 0; /* got it */
705          }
706        }
707      }
708    };
709    r = ptf_advance_one(item);
710
711  } while(r == 0);
712
713  return r;
714}
715
716/***************************************************************************/
717
718struct ptf *ptf_find(
719  struct ptf *tree,
720  struct ptf_item *item,
721  ptf_item_type ttype,
722  char *name,
723  char *value)
724{
725  int r;
726
727  if(item == NULL) { errno = EINVAL; return NULL; };
728  if(tree == NULL) { errno = ENOENT; return NULL; };
729
730  item->level = 0;
731  item->item[0] = tree;
732
733  if(ptf_advance_until(item, ttype, name, value) != 0) return NULL;
734
735  r = item->level;
736  item->level++; /* To match ptf_match */
737  return item->item[r];
738}
739
740/***************************************************************************/
741
742struct ptf *ptf_next(
743  struct ptf_item *item,
744  ptf_item_type ttype,
745  char *name,
746  char *value)
747{
748  int r;
749  struct ptf *leaf;
750
751  if(item == NULL) { errno = EINVAL; return NULL; };
752
753  if(item->level < 1) return NULL;
754  item->level--; /* To match ptf_match */
755
756  r = ptf_advance_one(item);
757
758  if(r == 0) r = ptf_advance_until(item, ttype, name, value);
759
760  if(r != 0) return NULL;
761
762  r = item->level;
763  item->level++; /* To match ptf_match */
764  return item->item[r];
765}
766
767/***************************************************************************/
768
769int ptf_match(
770  struct ptf *const ptf,
771  struct ptf_item *const match,
772  const ptf_match_action action,
773  void *arg)
774{
775    int count;
776    struct ptf *p;
777    struct ptf_item pi;
778
779    p = ptf;
780    count = 0;
781    pi.level = 0;
782
783    while(p != NULL)
784    {
785        ptf_item_type mtype = match->item[pi.level]->type;
786        char *mname = match->item[pi.level]->name;
787        char *mvalue = match->item[pi.level]->value;
788
789#if DEBUG&DEBUG_FINDER
790        printf("Looking for %s/%s, checking %s/%s\n",
791          mname, mvalue, p->name, p->value);
792#endif
793
794        if(mtype == p->type &&
795           (mname==NULL || p->name==NULL || strcmp(mname, p->name)==0) &&
796           (mvalue==NULL || p->value==NULL || strcmp(mvalue, p->value)==0))
797        {
798            pi.item[pi.level] = p;
799
800            if(pi.level == match->level - 1)
801            {
802                if(action != NULL) action(&pi, arg);
803                p = p->next;
804                count++;
805            }
806            else
807            {
808                if(p->sub != NULL && pi.level < MAX_SECTION_NESTING-1)
809                {
810                    pi.item[pi.level] = p;
811                    pi.level++;
812                    p = p->sub;
813                }
814                else
815                {
816                    p = p->next;
817                };
818            };
819        }
820        else
821        {
822            p = p->next;
823        };
824
825        while(p == NULL && pi.level > 0)
826        {
827            pi.level--;
828            p = pi.item[pi.level]->next;
829        };
830    };
831    return count;
832}
833
834/***************************************************************************/
835
836char *ptf_defused_name(char *orig_name)
837{
838  int i,j;
839  char *s = (char *)malloc(1+strlen(orig_name));
840
841  if(!s) return NULL;
842
843  for(i=j=0;orig_name[i];i++)
844  {
845    if(!isalnum(orig_name[i]))
846    {
847      if(j>0) if(s[j-1]!='_') s[j++]='_';
848    }
849    else
850    {
851      s[j++] = toupper(orig_name[i]);
852    };
853  };
854  s[j] = 0;
855  return s;
856}
857
Note: See TracBrowser for help on using the repository browser.