1// field.cpp --
2// $Id: field.cpp 1230 2007-03-09 15:58:53Z jcw $
3// This is part of Metakit, the homepage is http://www.equi4.com/metakit.html
4
5/** @file
6 * Implementation of the field structure tree
7 */
8
9#include "header.h"
10#include "field.h"
11
12#include <stdlib.h>   // strtol
13
14#if !q4_INLINE
15#include "field.inl"
16#endif
17
18/////////////////////////////////////////////////////////////////////////////
19// Implemented in this file
20
21class c4_Field;
22
23/////////////////////////////////////////////////////////////////////////////
24// c4_Field
25
26c4_Field::c4_Field(const char * &description_, c4_Field *parent_): _type(0) {
27    _indirect = this;
28
29    size_t n = strcspn(description_, ",[]");
30    const char *p = strchr(description_, ':');
31
32    if (p != 0 && p < description_ + n) {
33        _name = c4_String(description_, p - description_);
34        _type = p[1] &~0x20; // force to upper case
35    } else {
36        _name = c4_String(description_, n);
37        _type = 'S';
38    }
39
40    description_ += n;
41
42    if (*description_ == '[') {
43        ++description_;
44        _type = 'V';
45
46        if (*description_ == '^') {
47            ++description_;
48            _indirect = parent_;
49            d4_assert(*description_ == ']');
50        }
51
52        if (*description_ == ']')
53          ++description_;
54        else
55        do {
56            // 2004-01-20 ignore duplicate property names
57            // (since there is no good way to report errors at this point)
58            c4_Field *sf = d4_new c4_Field(description_, this);
59            for (int i = 0; i < NumSubFields(); ++i)
60            if (SubField(i).Name().CompareNoCase(sf->Name()) == 0) {
61                delete sf;
62                sf = 0;
63                break;
64            }
65            if (sf != 0)
66              _subFields.Add(sf);
67        } while (*description_++ == ',');
68    }
69}
70
71c4_Field::~c4_Field() {
72  if (_indirect == this) {
73    //better? for (int i = NumSubFields(); --i >= 0 ;)
74    for (int i = 0; i < NumSubFields(); ++i) {
75      c4_Field *sf = &SubField(i);
76      if (sf != this)
77      // careful with recursive subfields
78        delete sf;
79    }
80  }
81}
82
83c4_String c4_Field::Description(bool anonymous_)const {
84  c4_String s = anonymous_ ? "?" : (const char*)Name();
85
86  if (Type() == 'V')
87    s += "[" + DescribeSubFields(anonymous_) + "]";
88  else {
89    s += ":";
90    s += (c4_String)Type();
91  }
92
93  return s;
94}
95
96c4_String c4_Field::DescribeSubFields(bool)const {
97  d4_assert(Type() == 'V');
98
99  if (_indirect != this)
100    return "^";
101
102  c4_String s;
103  char c = 0;
104
105  for (int i = 0; i < NumSubFields(); ++i) {
106    if (c != 0)
107      s += (c4_String)c;
108    s += SubField(i).Description();
109    c = ',';
110  }
111
112  return s;
113}
114
115/////////////////////////////////////////////////////////////////////////////
116