source: CMT/v1r20p20070720/source/cmt_model.cxx

Last change on this file was 400, checked in by arnault, 17 years ago

Text formatting
Sending warnings & errors to stderr
Using internally PWD for every cd/pwd
CL 327

  • Property svn:eol-style set to native
File size: 11.9 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  cmt_regexp exp_open_element (open_element);
136  cmt_regexp exp_open_elements (open_elements);
137  cmt_regexp exp_close_element (close_element);
138
139  cmt_regexp exp_skip_spaces (skip_spaces);
140  cmt_regexp exp_word (word);
141
142  cmt_regexp exp_attribute (attribute);
143
144  cmt_regexp::iterator it;
145  cmt_regexp::iterator its;
146
147  static int expand_level = 0;
148
149  filter (text);
150
151  int pos = 0;
152
153  for (;;)
154    {
155      bool multiple = false;
156
157      it = exp_open_element.begin (text, pos);
158      its = exp_open_elements.begin (text, pos);
159
160      if ((it == exp_open_element.end ()) && ((its == exp_open_elements.end ()))) 
161        {
162          // no more opening element
163
164          // Display the remaining text. The parsing is now completed.
165
166          remaining = text.substr (pos);
167          display (remaining);
168
169          break;
170        }
171
172      if (it == exp_open_element.end ())
173        {
174          // no single element -> we have a multiple one
175          it = its;
176          multiple = true;
177        }
178      else if (its == exp_open_elements.end ())
179        {
180          // no multiple element -> we have a single one
181        }
182      else if (it < its)
183        {
184          // the single is before the multiple
185        }
186      else
187        {
188          // the multiple is before the single
189          it = its;
190          multiple = true;
191        }
192
193      remaining = text.substr (pos, it._pos - pos);
194      display (remaining);
195
196      pos = it._pos + it._length;
197
198      it = exp_word.begin (text, pos);
199      if (it._pos != pos)
200        {
201          cerr << "Syntax error: no element name" << endl;
202          break;
203        }
204
205      pos += it._length;
206
207      cmt_string element = it (text);
208
209      subargs.clear ();
210
211      {
212        cmt_string& s = subargs.add ();
213        s = element;
214      }
215
216      for (;;)
217        {
218          it = exp_skip_spaces.begin (text, pos);
219          if (it._pos == pos)
220            {
221              pos += it._length;
222            }
223
224          it = exp_close_element.begin (text, pos);
225          if (it._pos == pos)
226            {
227              int i;
228
229              Variable::VariableVector variables;
230
231              /**
232               *   We start by decoding all [variable=value] pairs from the arguments
233               *   A vector of Variables is filled from them.
234               */
235
236              int multiple_count = 0;
237              CmtSystem::cmt_string_vector values;
238              cmt_string name;
239              cmt_string value;
240
241              for (i = 1; i < subargs.size (); i++)
242                {
243                  const cmt_string& arg = subargs[i];
244
245                  int p = arg.find ("=");
246
247                  arg.substr (0, p, name);
248                  arg.substr (p + 1, value);
249                  if (value[0] == '"') 
250                    {
251                      value.erase (0, 1);
252                      if (value[value.size()-1] == '"') value.erase (value.size ()-1);
253                    }
254                  else if (value[0] == '\'') 
255                    {
256                      value.erase (0, 1);
257                      if (value[value.size()-1] == '\'') value.erase (value.size ()-1);
258                    }
259
260                  if (multiple)
261                    {
262                      values.clear ();
263                      CmtSystem::split (value, " \t", values);
264                      int n = values.size ();
265                      if (n > multiple_count) multiple_count = n;
266                    }
267
268                  Variable* v = Variable::find (variables, name);
269                  if (v == 0)
270                    {
271                      v = &(variables.add ());
272                      v->set (name);
273                    }
274
275                  (*v) = value;
276                }
277
278              cmt_string sub_text;
279
280              FragmentHandle fragment (element);
281
282              if (multiple)
283                {
284                  for (int n = 0; n < multiple_count; n++)
285                    {
286                      for (i = 1; i < subargs.size (); i++)
287                        {
288                          const cmt_string& arg = subargs[i];
289
290                          int p = arg.find ("=");
291
292                          arg.substr (p + 1, value);
293                          if (value[0] == '"') 
294                            {
295                              value.erase (0, 1);
296                              if (value[value.size()-1] == '"') value.erase (value.size ()-1);
297                            }
298                          else if (value[0] == '\'') 
299                            {
300                              value.erase (0, 1);
301                              if (value[value.size()-1] == '\'') value.erase (value.size ()-1);
302                            }
303
304                          values.clear ();
305                          CmtSystem::split (value, " \t", values);
306                          if (n < values.size ())
307                            {
308                              value = values[n];
309                            }
310                          else
311                            {
312                              value = "";
313                            }
314
315                          Variable& v = variables[i-1];
316
317                          v = value;
318                        }
319
320                      fragment.copy (sub_text, variables, 0);
321
322                      expand_level++;
323                      strict_expand (sub_text);
324                      expand_level--;
325                    }
326                }
327              else
328                {
329                  fragment.copy (sub_text, variables, 0);
330
331                  expand_level++;
332                  strict_expand (sub_text);
333                  expand_level--;
334                }
335
336              pos += it._length;
337              break;
338            }
339
340          it = exp_attribute.begin (text, pos);
341          if (it._pos != pos)
342            {
343              cerr << "Syntax error : no attribute before closing the element [" << text.substr (pos) << "]" << endl;
344              break;
345            }
346
347          {
348            cmt_string& s = subargs.add ();
349            s = it (text);
350          }
351
352          pos += it._length;
353        }
354    }
355
356  if (expand_level == 0) cout << endl;
357}
358
359void CmtModel::test_regexp (const cmt_string& pattern, const cmt_string& input_text)
360{
361  cerr << "Testing pattern [" << pattern << "] against [" << input_text << "]" << endl;
362 
363  cmt_regexp exp (pattern);
364
365  cmt_regexp::iterator it;
366
367  for (int pos = 0; pos < 10; pos++)
368    {
369      it = exp.begin (input_text, pos);
370
371      if (it == exp.end ())
372        {
373          cerr << "No match" << endl;
374        }
375      else
376        {
377          cerr << "p=" << it._pos << " l=" << it._length << " -> [" << it (input_text) << "]" << endl;
378        }
379    }
380}
381
382
383/**
384 *   Expands a model file
385 *   Arguments are :
386 *     model-name   : name of a model file
387 *     var=value    : variable value to be expanded
388 *                    (will take the form ${var} )
389 */
390void CmtModel::expand (const CmtSystem::cmt_string_vector& arguments)
391{
392  int i;
393
394  Variable::VariableVector variables;
395
396  /**
397   *   We start by decoding all [variable=value] pairs from the arguments
398   *   A vector of Variables is filled from them.
399   */
400  for (i = 0; i < arguments.size (); i++)
401    {
402      const cmt_string& arg = arguments[i];
403
404      if (arg.find ("=") != cmt_string::npos)
405        {
406          cmt_string name;
407          cmt_string value;
408          int pos = arg.find ("=");
409
410          arg.substr (0, pos, name);
411          arg.substr (pos + 1, value);
412
413          Variable* v = Variable::find (variables, name);
414          if (v == 0)
415            {
416              v = &(variables.add ());
417              v->set (name);
418            }
419
420          (*v) = value;
421        }
422    }
423
424  /**
425   *   Then model names are extracted.
426   *   Each model may contain a set of <...> patterns.
427   *   The expected syntax for each of them is :
428   *     <model-name variable-name=value ...>
429   *
430   *   Therefore the current expand function is recursively restarted.
431   *
432   *   Text around patterns is displayed after replacements of all
433   *   variable values detected by ${variable-name} patterns
434   */
435  cmt_string text;
436
437  for (i = 0; i < arguments.size (); i++)
438    {
439      const cmt_string& arg = arguments[i];
440
441      if (arg.find ("=") == cmt_string::npos)
442        {
443          FragmentHandle fragment (arg);
444          fragment.copy (text, variables, 0);
445
446          filter (text);
447
448          int openmarker;
449          int closemarker;
450
451          CmtSystem::cmt_string_vector subargs;
452
453          cmt_string remaining;
454
455          for (;;)
456            {
457              /**
458               *   Look for the next <...> pattern
459               *   If not found, then simply dump the text as it is.
460               */
461
462              openmarker = text.find ("<");
463              if (openmarker == cmt_string::npos) break;
464
465              closemarker = text.find (openmarker, "/>");
466              if (closemarker == cmt_string::npos)
467                {
468                  /**
469                   *  The opening < was in the text
470                   */
471
472                  /**
473                   *   Get what is left from the original text beyond the pattern
474                   */
475                  text.substr (openmarker + 1, remaining);
476                  text.erase (openmarker + 1);
477                 
478                  /**
479                   *   Now display it
480                   */
481                  display (text);
482                }
483              else
484                {
485                  /**
486                   *  Extract the command from the pattern
487                   */
488                  cmt_string command;
489                  text.substr (openmarker + 1, closemarker - openmarker - 1, command);
490
491                  /**
492                   *   Get what is left from the original text beyond the pattern
493                   */
494                  text.substr (closemarker + 2, remaining);
495                  text.erase (openmarker);
496                 
497                  /**
498                   *   Now display it
499                   */
500                  display (text);
501
502                  /**
503                   * Convert the extracted command into words
504                   */
505                  CmtSystem::split (command, " ", subargs);
506                 
507                  /**
508                   *  Recursively expand it
509                   */
510                  expand (subargs);
511                }
512
513              /**
514               *  The next iteration will operate on the remaining text
515               */
516              text = remaining;
517            }
518
519          /**
520           *   Display what is left after extracting the last pattern
521           */
522          display (text);
523        }
524    }
525}
526
Note: See TracBrowser for help on using the repository browser.