source: CMT/v1r25/source/cmt_model.cxx

Last change on this file was 459, checked in by rybkin, 16 years ago

See C.L. 360

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