source: CMT/v1r19/source/cmt_model.cxx @ 1

Last change on this file since 1 was 1, checked in by arnault, 19 years ago

Import all tags

File size: 13.4 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// See the complete license in cmt_license.txt "http://www.cecill.info".
5//-----------------------------------------------------------
6
7#include "cmt_model.h"
8#include "cmt_fragment.h"
9#include "cmt_symbol.h"
10
11/**
12 *   Filters out all predefined XML constructs.
13 */
14void CmtModel::filter (cmt_string& text)
15{
16  text.replace_all ("<cmt:tab/>",  "\t");
17  text.replace_all ("<cmt:cr/>",   "\r");
18  text.replace_all ("<cmt:lf/>",   "\n");
19}
20
21void CmtModel::display (cmt_string& text)
22{
23  text.replace_all ("&lt;", "<");
24  text.replace_all ("&gt;", ">");
25  text.replace_all ("\\\"", "\"");
26  text.replace_all ("\\\'", "\'");
27  text.replace_all ("<cmt:null/>", "");
28  Symbol::expand (text);
29  cout << text;
30}
31
32void CmtModel::expand (const cmt_string& input_text)
33{
34  int openmarker;
35  int closemarker;
36
37  CmtSystem::cmt_string_vector subargs;
38
39  cmt_string text = input_text;
40  cmt_string remaining;
41
42  filter (text);
43
44  for (;;)
45    {
46      /**
47       *   Look for the next < ... /> pattern
48       *   If not found, then simply dump the text as it is.
49       */
50     
51      openmarker = text.find ("<");
52      if (openmarker == cmt_string::npos) break;
53     
54      closemarker = text.find (openmarker, "/>");
55      if (closemarker == cmt_string::npos) break;
56
57      if (CmtSystem::testenv ("CMTTESTMODEL"))
58        {
59          cerr << "text=[" << text << "]" << endl;
60        }
61         
62
63      /**
64       *  Extract the command from the pattern
65       */
66      cmt_string command;
67      text.substr (openmarker + 1, closemarker - openmarker - 1, command);
68
69      if (CmtSystem::testenv ("CMTTESTMODEL"))
70        {
71          cerr << "command=[" << command << "]" << endl;
72        }
73         
74      /**
75       *   Get what is left from the original text beyond the pattern
76       */
77      text.substr (closemarker + 2, remaining);
78
79      /**
80       *   Cut the original text up to the pattern start
81       */
82      text.erase (openmarker);
83     
84      /**
85       *   Now display it
86       */
87      display (text);
88         
89      /**
90       * Convert the extracted command into words
91       */
92      CmtSystem::split (command, " ", subargs);
93         
94      /**
95       *  Recursively expand it
96       */
97      expand (subargs);
98     
99      /**
100       *  The next iteration will operate on the remaining text
101       */
102      text = remaining;
103    }
104 
105  if (CmtSystem::testenv ("CMTTESTMODEL"))
106    {
107      cerr << "text=[" << text << "]" << endl;
108    }
109         
110  /**
111   *   Display what is left after extracting the last pattern
112   */
113  display (text);
114  cout << endl;
115}
116
117void CmtModel::strict_expand (const cmt_string& input_text)
118{
119  CmtSystem::cmt_string_vector subargs;
120
121  cmt_string text = input_text;
122  cmt_string remaining;
123
124  // The patterns for syntax parsing
125
126  cmt_string open_element = "<cmts:";
127  cmt_string open_elements = "<cmtv:";
128  cmt_string close_element = "/>";
129
130  cmt_string skip_spaces = "[ \t]+";
131  cmt_string word = "[^ \t/>]*";
132
133  cmt_string attribute = "[^=/>]+=((\"([^\"]|\\\\\")*\")|(\'([^\']|\\\\\')*\'))";
134
135  //cout << "attribute=[" << attribute << "]" << endl;
136
137  cmt_regexp exp_open_element (open_element);
138  cmt_regexp exp_open_elements (open_elements);
139  cmt_regexp exp_close_element (close_element);
140
141  cmt_regexp exp_skip_spaces (skip_spaces);
142  cmt_regexp exp_word (word);
143
144  cmt_regexp exp_attribute (attribute);
145
146  cmt_regexp::iterator it;
147  cmt_regexp::iterator its;
148
149  static int expand_level = 0;
150
151  //cout << "Text=[" << text << "]" << endl;
152
153  filter (text);
154
155  //cout << "Text=[" << text << "]" << endl;
156
157  int pos = 0;
158
159  for (;;)
160    {
161      bool multiple = false;
162
163      it = exp_open_element.begin (text, pos);
164      its = exp_open_elements.begin (text, pos);
165
166      if ((it == exp_open_element.end ()) && ((its == exp_open_elements.end ()))) 
167        {
168          // no more opening element
169
170          // Display the remaining text. The parsing is now completed.
171
172          remaining = text.substr (pos);
173          display (remaining);
174
175          break;
176        }
177
178      if (it == exp_open_element.end ())
179        {
180          // no single element -> we have a multiple one
181          it = its;
182          multiple = true;
183        }
184      else if (its == exp_open_elements.end ())
185        {
186          // no multiple element -> we have a single one
187        }
188      else if (it < its)
189        {
190          // the single is before the multiple
191        }
192      else
193        {
194          // the multiple is before the single
195          it = its;
196          multiple = true;
197        }
198
199      remaining = text.substr (pos, it._pos - pos);
200      display (remaining);
201
202      //cout << "pos=" << pos << " open_element -> p=" << it._pos << " l=" << it._length << endl;
203      pos = it._pos + it._length;
204
205      it = exp_word.begin (text, pos);
206      if (it._pos != pos)
207        {
208          cerr << "Syntax error: no element name" << endl;
209          break;
210        }
211
212      //cout << "pos=" << pos << " word -> p=" << it._pos << " l=" << it._length << endl;
213      pos += it._length;
214
215      cmt_string element = it (text);
216      //cout << "pos=" << pos << " element=" << element << endl;
217
218      subargs.clear ();
219
220      {
221        cmt_string& s = subargs.add ();
222        s = element;
223      }
224
225      for (;;)
226        {
227          it = exp_skip_spaces.begin (text, pos);
228          if (it._pos == pos)
229            {
230              //cout << "pos=" << pos << " skip_spaces -> p=" << it._pos << " l=" << it._length << endl;
231              pos += it._length;
232            }
233
234          //cout << "pos=" << pos << endl;
235
236          it = exp_close_element.begin (text, pos);
237          if (it._pos == pos)
238            {
239              //cout << "Recursing to [" << element << "]" << endl;
240
241              int i;
242
243              Variable::VariableVector variables;
244
245              /**
246               *   We start by decoding all [variable=value] pairs from the arguments
247               *   A vector of Variables is filled from them.
248               */
249
250              int multiple_count = 0;
251              CmtSystem::cmt_string_vector values;
252              cmt_string name;
253              cmt_string value;
254
255              for (i = 1; i < subargs.size (); i++)
256                {
257                  const cmt_string& arg = subargs[i];
258
259                  int p = arg.find ("=");
260
261                  arg.substr (0, p, name);
262                  arg.substr (p + 1, value);
263                  if (value[0] == '"') 
264                    {
265                      value.erase (0, 1);
266                      if (value[value.size()-1] == '"') value.erase (value.size ()-1);
267                    }
268                  else if (value[0] == '\'') 
269                    {
270                      value.erase (0, 1);
271                      if (value[value.size()-1] == '\'') value.erase (value.size ()-1);
272                    }
273
274                  //cout << "+ name = [" << value << "]" << endl;
275
276                  if (multiple)
277                    {
278                      values.clear ();
279                      CmtSystem::split (value, " \t", values);
280                      int n = values.size ();
281                      if (n > multiple_count) multiple_count = n;
282                    }
283
284                  Variable* v = Variable::find (variables, name);
285                  if (v == 0)
286                    {
287                      v = &(variables.add ());
288                      v->set (name);
289                    }
290
291                  (*v) = value;
292                }
293
294              cmt_string sub_text;
295
296              FragmentHandle fragment (element);
297
298              if (multiple)
299                {
300                  //cout << "+ count = " << multiple_count << endl;
301                  for (int n = 0; n < multiple_count; n++)
302                    {
303                      for (i = 1; i < subargs.size (); i++)
304                        {
305                          const cmt_string& arg = subargs[i];
306
307                          int p = arg.find ("=");
308
309                          arg.substr (p + 1, value);
310                          if (value[0] == '"') 
311                            {
312                              value.erase (0, 1);
313                              if (value[value.size()-1] == '"') value.erase (value.size ()-1);
314                            }
315                          else if (value[0] == '\'') 
316                            {
317                              value.erase (0, 1);
318                              if (value[value.size()-1] == '\'') value.erase (value.size ()-1);
319                            }
320
321                          //cout << "+ values = [" << value << "]" << endl;
322
323                          values.clear ();
324                          CmtSystem::split (value, " \t", values);
325                          if (n < values.size ())
326                            {
327                              value = values[n];
328                            }
329                          else
330                            {
331                              value = "";
332                            }
333
334                          Variable& v = variables[i-1];
335
336                          //cout << "+ value = [" << value << "]" << endl;
337
338                          v = value;
339                        }
340
341                      fragment.copy (sub_text, variables, 0);
342
343                      expand_level++;
344                      strict_expand (sub_text);
345                      expand_level--;
346                    }
347                }
348              else
349                {
350                  fragment.copy (sub_text, variables, 0);
351
352                  expand_level++;
353                  strict_expand (sub_text);
354                  expand_level--;
355                }
356
357              pos += it._length;
358              break;
359            }
360
361          //cout << "Try attribute at pos=" << pos << " [" << text.substr (pos) << "]" << endl;
362
363          it = exp_attribute.begin (text, pos);
364          if (it._pos != pos)
365            {
366              cerr << "Syntax error : no attribute before closing the element [" << text.substr (pos) << "]" << endl;
367              break;
368            }
369
370          //cout << "pos=" << pos << " attribute -> p=" << it._pos << " l=" << it._length << endl;
371          //cout << "pos=" << pos << " attr=[" << it (text) << "]" << endl;
372
373          {
374            cmt_string& s = subargs.add ();
375            s = it (text);
376          }
377
378          pos += it._length;
379        }
380    }
381
382  if (expand_level == 0) cout << endl;
383}
384
385void CmtModel::test_regexp (const cmt_string& pattern, const cmt_string& input_text)
386{
387  cout << "Testing pattern [" << pattern << "] against [" << input_text << "]" << endl;
388 
389  cmt_regexp exp (pattern);
390
391  cmt_regexp::iterator it;
392
393  for (int pos = 0; pos < 10; pos++)
394    {
395      it = exp.begin (input_text, pos);
396
397      if (it == exp.end ())
398        {
399          cout << "No match" << endl;
400        }
401      else
402        {
403          cout << "p=" << it._pos << " l=" << it._length << " -> [" << it (input_text) << "]" << endl;
404        }
405    }
406}
407
408
409/**
410 *   Expands a model file
411 *   Arguments are :
412 *     model-name   : name of a model file
413 *     var=value    : variable value to be expanded
414 *                    (will take the form ${var} )
415 */
416void CmtModel::expand (const CmtSystem::cmt_string_vector& arguments)
417{
418  int i;
419
420  Variable::VariableVector variables;
421
422  /**
423   *   We start by decoding all [variable=value] pairs from the arguments
424   *   A vector of Variables is filled from them.
425   */
426  for (i = 0; i < arguments.size (); i++)
427    {
428      const cmt_string& arg = arguments[i];
429
430      if (arg.find ("=") != cmt_string::npos)
431        {
432          cmt_string name;
433          cmt_string value;
434          int pos = arg.find ("=");
435
436          arg.substr (0, pos, name);
437          arg.substr (pos + 1, value);
438
439          Variable* v = Variable::find (variables, name);
440          if (v == 0)
441            {
442              v = &(variables.add ());
443              v->set (name);
444            }
445
446          (*v) = value;
447        }
448    }
449
450  /**
451   *   Then model names are extracted.
452   *   Each model may contain a set of <...> patterns.
453   *   The expected syntax for each of them is :
454   *     <model-name variable-name=value ...>
455   *
456   *   Therefore the current expand function is recursively restarted.
457   *
458   *   Text around patterns is displayed after replacements of all
459   *   variable values detected by ${variable-name} patterns
460   */
461  cmt_string text;
462
463  for (i = 0; i < arguments.size (); i++)
464    {
465      const cmt_string& arg = arguments[i];
466
467      if (arg.find ("=") == cmt_string::npos)
468        {
469          FragmentHandle fragment (arg);
470          fragment.copy (text, variables, 0);
471
472          filter (text);
473
474          int openmarker;
475          int closemarker;
476
477          CmtSystem::cmt_string_vector subargs;
478
479          cmt_string remaining;
480
481          for (;;)
482            {
483              /**
484               *   Look for the next <...> pattern
485               *   If not found, then simply dump the text as it is.
486               */
487
488              openmarker = text.find ("<");
489              if (openmarker == cmt_string::npos) break;
490
491              closemarker = text.find (openmarker, "/>");
492              if (closemarker == cmt_string::npos)
493                {
494                  /**
495                   *  The opening < was in the text
496                   */
497
498                  /**
499                   *   Get what is left from the original text beyond the pattern
500                   */
501                  text.substr (openmarker + 1, remaining);
502                  text.erase (openmarker + 1);
503                 
504                  /**
505                   *   Now display it
506                   */
507                  display (text);
508                }
509              else
510                {
511                  /**
512                   *  Extract the command from the pattern
513                   */
514                  cmt_string command;
515                  text.substr (openmarker + 1, closemarker - openmarker - 1, command);
516
517                  /**
518                   *   Get what is left from the original text beyond the pattern
519                   */
520                  text.substr (closemarker + 2, remaining);
521                  text.erase (openmarker);
522                 
523                  /**
524                   *   Now display it
525                   */
526                  display (text);
527
528                  /**
529                   * Convert the extracted command into words
530                   */
531                  CmtSystem::split (command, " ", subargs);
532                 
533                  /**
534                   *  Recursively expand it
535                   */
536                  expand (subargs);
537                }
538
539              /**
540               *  The next iteration will operate on the remaining text
541               */
542              text = remaining;
543            }
544
545          /**
546           *   Display what is left after extracting the last pattern
547           */
548          display (text);
549        }
550    }
551}
552
Note: See TracBrowser for help on using the repository browser.