source: CMT/HEAD/source/cmt_model.cxx @ 663

Last change on this file since 663 was 663, checked in by rybkin, 10 years ago

See C.L. 522

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