ARB
aisc_var_ref.c
Go to the documentation of this file.
1 // ================================================================
2 /* */
3 // File : aisc_var_ref.c
4 // Purpose :
5 /* */
6 // Institute of Microbiology (Technical University Munich)
7 // http://www.arb-home.de/
8  /* */
9  // ================================================================
10 
11 #include "aisc_token.h"
12 #include "aisc_inline.h"
13 #include "aisc_interpreter.h"
14 
15 
16 class TokenMatcher : virtual Noncopyable {
17  char *key; // NULp matches "any key"
18  char *value; // NULp matches "any value"
19 
20  char *copy_expression_part(const char *start, const char *end) {
21  if (start >= end || (end == (start+1) && start[0] == '*')) return NULp;
22  return copy_string_part(start, end);
23  }
24 
25  public:
26  TokenMatcher(const char *search_expr) {
27  // search_expr is "key.value"
28  //
29  // "*.value" searches value (regardless of key)
30  // "key.*" searches key (regardless of value)
31  //
32  // "key" = "key." = "key.*"
33  // ".value" = "*.value"
34 
35  const char *dot = strchr(search_expr, '.');
36  if (!dot) {
37  key = strdup(search_expr);
38  value = NULp;
39  }
40  else {
41  const char *end = strchr(dot+1, 0);
42 
43  key = copy_expression_part(search_expr, dot-1);
44  value = copy_expression_part(dot+1, end-1);
45  }
46  }
47 
49  free(key);
50  free(value);
51  }
52 
53  bool matchesKeyOf(const Token *token) const {
54  return !key || strcmp(token->get_key(), key) == 0;
55  }
56  bool matchesValueOf(const Token *token) const {
57  return !value || (!token->is_block() && strcmp(value, token->get_value()) == 0);
58  }
59  bool matches(const Token *token) const {
60  return matchesKeyOf(token) && matchesValueOf(token);
61  }
62 };
63 
64 static const Token *nextToken(const Token *tok, bool cont_in_next_list) {
65  const Token *next_token = tok->next_token();
66  if (!next_token && cont_in_next_list) {
67  const TokenList *next_list = tok->parent_list()->next_list();
68  if (next_list) next_token = next_list->first_token();
69  }
70  return next_token;
71 }
72 
73 static const Token *nextTokenMatching(const Token *tok, const TokenMatcher& wanted, bool cont_in_next_list) {
74  while (tok) {
75  if (wanted.matches(tok)) break;
76  tok = nextToken(tok, cont_in_next_list);
77  }
78  return tok;
79 }
80 
81 const Token *Data::find_token(const Token *curs, const char *str, LookupScope scope) const {
82  if (!curs) {
83  const TokenListBlock *tokens = get_tokens();
84  if (!tokens) return NULp;
85  curs = tokens->first_token();
86  }
87 
88  TokenMatcher wanted(str);
89  const Token *found = NULp;
90 
91  while (curs && !found) {
92  bool cont_in_next_list = false;
93  switch (scope) {
95  case LOOKUP_LIST:
96  curs = curs->parent_list()->first_token();
97  break;
98  case LOOKUP_BLOCK:
99  curs = curs->parent_list()->parent_block()->first_token();
100  cont_in_next_list = true;
101  break;
102  case LOOKUP_BLOCK_REST:
103  curs = nextToken(curs, true);
104  cont_in_next_list = true;
105  break;
106  }
107 
108  found = nextTokenMatching(curs, wanted, cont_in_next_list);
109 
110  if (scope == LOOKUP_LIST_OR_PARENT_LIST) {
111  curs = curs->parent_block_token();
112  }
113  else {
114  curs = NULp;
115  }
116  }
117 
118  return found;
119 }
120 
121 const Token *Data::find_qualified_token(const char *str, LookupScope scope) const {
122  const Token *at = cursor;
123  if (*str == '/') {
124  at = NULp;
125  str++;
126  }
127 
128  const char *slash = strchr(str, '/');
129  while (slash) {
130  char *name = copy_string_part(str, slash-1);
131  const Token *found = find_token(at, name, scope);
132  free(name);
133 
134  if (!found || !found->is_block()) return NULp;
135 
136  at = found->get_content()->first_token();
137 
138  str = slash+1;
139  slash = strchr(str, '/');
140  scope = LOOKUP_BLOCK;
141  }
142 
143  return find_token(at, str, scope);
144 }
145 
146 
147 char *get_var_string(const Data& data, char *var, bool allow_missing_var) {
148  // Calculates result for an expression like '$(IDENT:fdg|"sdfg")'
149  SKIP_SPACE_LF(var);
150  int use_path = 0;
151  while (var[0] == '&') {
152  use_path++;
153  var++;
154  SKIP_SPACE_LF(var);
155  }
156 
157  char *doppelpunkt = strchr(var, ':'); if (doppelpunkt) *(doppelpunkt++) = 0;
158  char *bar = strchr(var, '|'); if (bar) *(bar++) = 0;
159 
160  const char *val = Interpreter::instance->read_local(var);
161  char *in = NULp;
162  if (val) {
163  in = strdup(val);
164  }
165  else {
166  const Token *cur = data.find_qualified_token(var, LOOKUP_LIST_OR_PARENT_LIST);
167  if (!cur) {
168  if (!bar) {
169  if (!allow_missing_var) {
170  const Code *at = Interpreter::instance->at();
171  printf_error(at, "Ident '%s' not found", var);
172  }
173  return NULp;
174  }
175  return strdup(bar);
176  }
177  if (use_path) {
178  in = strdup(cur->get_key());
179  if (use_path>1) {
180  while (1) {
181  const Token *up = cur->parent_block_token();
182  if (!up) break;
183 
184  cur = up;
185  int len = strlen(in) + strlen(cur->get_key());
186  char *buf1 = (char *) calloc(sizeof(char), len + 2);
187  sprintf(buf1, "%s/%s", cur->get_key(), in);
188 
189  free(in);
190  in = buf1;
191  }
192 
193  }
194  }
195  else {
196  if (cur->is_block()) {
197  printf_error(Interpreter::instance->at(), "Ident '%s' is a hierarchical type", var);
198  return NULp;
199  }
200  else {
201  in = strdup(cur->has_value() ? cur->get_value() : "");
202  }
203  }
204  }
205 
206  aisc_assert(in); // 'in' has to point to a heap copy
207 
208  if (doppelpunkt) {
209  int len = strlen(in);
210  bool err = false;
211  while (doppelpunkt && !err) {
212  char *nextdp = strchr(doppelpunkt, ':');
213  if (nextdp) *(nextdp++) = 0;
214  if (!doppelpunkt[0]) {
215  print_error(Interpreter::instance->at(), "Ident replacement is missing an ':'");
216  err = true;
217  }
218  else {
219  bar = strchr(doppelpunkt+1, '=');
220  if (!bar) {
221  print_error(Interpreter::instance->at(), "Ident replacement is missing an '='");
222  err = true;
223  }
224  else {
225  *(bar++) = 0;
226  int findl = strlen(doppelpunkt);
227  int replacel = strlen(bar);
228 
229  char *buf2;
230  for (char *finds = strstr(in, doppelpunkt); finds; finds = strstr(buf2, doppelpunkt)) {
231  len += replacel - findl;
232 
233  char *buf1 = (char *) calloc(sizeof(char), len + 1);
234  int offset = finds - in;
235 
236  memcpy(buf1, in, offset);
237  memcpy(buf1 + offset, bar, replacel);
238 
239  buf2 = buf1 + offset + replacel;
240  memcpy(buf2, in + offset + findl, len - replacel - offset);
241 
242  free(in);
243  in = buf1;
244 
245  buf2 = in + offset + replacel;
246  }
247  doppelpunkt = nextdp;
248  }
249  }
250  }
251  if (err) {
252  free(in);
253  in = NULp;
254  }
255  }
256  return in;
257 }
258 
259 static void dump_token_recursive(const Token *tok, FILE *out) {
260  const Token *block = tok->parent_block_token();
261  if (block) {
262  const TokenList *parent = block->parent_list();
263  if (parent) {
264  const Token *first = parent->first_token();
265  if (first) {
266  dump_token_recursive(first, out);
267  fputc('/', out);
268  }
269  }
270  }
271 
272  fputc('@', out);
273  fputs(tok->get_key(), out);
274 
275  if (tok->has_value()) {
276  fputc('=', out);
277  fputs(tok->get_value(), out);
278  }
279 }
280 
281 void Data::dump_cursor_pos(FILE *out) const {
282  dump_token_recursive(cursor, out);
283 }
char * copy_string_part(const char *first, const char *last)
Definition: aisc_inline.h:49
const TokenList * parent_list() const
Definition: aisc_token.h:73
static void dot(double **i, double **j, double **k)
Definition: trnsprob.cxx:59
static void dump_token_recursive(const Token *tok, FILE *out)
Definition: aisc_var_ref.c:259
const Code * at() const
LookupScope
Definition: aisc_def.h:23
static const Interpreter * instance
const TokenListBlock * parent_block() const
Definition: aisc_token.h:111
static HelixNrInfo * start
static const Token * nextTokenMatching(const Token *tok, const TokenMatcher &wanted, bool cont_in_next_list)
Definition: aisc_var_ref.c:73
bool matches(const Token *token) const
Definition: aisc_var_ref.c:59
const Token * find_token(const Token *curs, const char *str, LookupScope scope) const
Definition: aisc_var_ref.c:81
#define print_error(code_or_loc, err)
Definition: aisc_def.h:47
const TokenList * next_list() const
Definition: aisc_token.h:110
fputc('\n', stderr)
static const Token * nextToken(const Token *tok, bool cont_in_next_list)
Definition: aisc_var_ref.c:64
const char * get_key() const
Definition: aisc_token.h:64
const Token * next_token() const
Definition: aisc_token.h:72
TokenMatcher(const char *search_expr)
Definition: aisc_var_ref.c:26
fputs(TRACE_PREFIX, stderr)
char * get_var_string(const Data &data, char *var, bool allow_missing_var)
Definition: aisc_var_ref.c:147
const char * get_value() const
Definition: aisc_token.h:70
const Token * first_token() const
Definition: aisc_token.h:109
#define printf_error(code_or_loc, format, arg)
Definition: aisc_def.h:50
const Token * parent_block_token() const
Definition: aisc_token.h:165
const Token * first_token() const
Definition: aisc_token.h:141
#define NULp
Definition: cxxforward.h:97
bool has_value() const
Definition: aisc_token.h:69
#define offset(field)
Definition: GLwDrawA.c:73
static ED4_block block
Definition: ED4_block.cxx:73
const char * read_local(const char *key) const
Definition: aisc_mix.c:266
bool matchesValueOf(const Token *token) const
Definition: aisc_var_ref.c:56
const TokenListBlock * get_tokens() const
void dump_cursor_pos(FILE *out) const
Definition: aisc_var_ref.c:281
#define aisc_assert(cond)
Definition: aisc_def.h:11
const TokenListBlock * get_content() const
Definition: aisc_token.h:67
bool matchesKeyOf(const Token *token) const
Definition: aisc_var_ref.c:53
void SKIP_SPACE_LF(const char *&var)
Definition: aisc_inline.h:32
const Token * find_qualified_token(const char *str, LookupScope scope) const
Definition: aisc_var_ref.c:121
bool is_block() const
Definition: aisc_token.h:66