source: CMT/v1r16p20040901/src/cmt_awk.cxx @ 1

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

Import all tags

File size: 22.8 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#ifdef WIN32
8#include <direct.h>
9#define popen _popen
10#define pclose _pclose
11#endif
12
13#include "cmt_awk.h"
14#include "cmt_system.h"
15
16class Parser
17{
18public:
19  Parser (Awk* awk, const cmt_string pattern, const cmt_regexp* expression) :
20          m_pattern (pattern), m_expression (expression), m_awk(awk)
21      {
22      }
23
24    /**
25     *  this first level parsing function extracts individual lines
26     *  from the text, taking care of both Unix and Windows EOL styles.
27     *
28     *   Then the second level parsing function parse_line is called.
29     */
30  Awk::condition parse (const cmt_string& text)
31      {
32        Awk::condition result = Awk::ok;
33
34        cmt_string line;
35        int pos;
36        int max_pos;
37
38        pos = 0;
39        max_pos = text.size ();
40
41        m_accumulator.erase (0);
42
43        for (pos = 0; pos < max_pos;)
44          {
45            int eol = text.find (pos, '\n');
46           
47            if (eol == cmt_string::npos)
48              {
49                  // Last line, since there is no eol at all
50                text.substr (pos, line);
51                pos = max_pos;
52              }
53            else
54              {
55                int length = 1;
56
57                int cr = text.find (pos, "\r\n");
58
59                if (cr == (eol-1))
60                  {
61                    eol = cr;
62                    length = 2;
63                  }
64
65                if (eol == pos)
66                  {
67                      // this is an empty line
68                    line = "";
69                    pos += length;
70                  }
71                else
72                  {
73                      // The eol was found beyond the current position
74                      // (ie. this is a non empty line)
75                    text.substr (pos, eol - pos, line);
76                    pos = eol + length;
77                  }
78              }
79
80            if (m_awk != 0) m_awk->inc_line_number ();
81
82              //cout << "parse> line=[" << line << "]" << endl;
83
84            result = parse_line (line);
85            if (result != Awk::ok) break;
86          }
87
88        return (result);
89      }
90
91    /**
92     *   This second level parsing function accumulates individual lines
93     *   with real trailing back slashes.
94     *    Eventually the possible text pattern or regular expression is
95     *   checked and the Awk::filter function is called in case of
96     *   succesful match onto the accumulated line.
97     */
98  Awk::condition parse_line (const cmt_string& line)
99      {
100        Awk::condition result = Awk::ok;
101        int length;
102        cmt_string temp_line = line;
103
104          //
105          // We scan the line for handling backslashes.
106          //
107          // Really terminating backslashes (ie those only followed by spaces/tabs
108          // mean continued line
109          //
110          //
111
112        bool finished = true;
113
114        length = temp_line.size ();
115
116        if (length == 0)
117          {
118              // An empty line following a backslash terminates the continuation.
119            finished = true;
120          }
121        else
122          {
123            int back_slash = temp_line.find_last_of ('\\');
124       
125            if (back_slash != cmt_string::npos)
126              {
127                  //
128                  // This is the last backslash
129                  // check if there are only space chars after it
130                  //
131           
132                bool at_end = true;
133           
134                for (int i = (back_slash + 1); i < length; i++)
135                  {
136                    char c = temp_line[i];
137                    if ((c != ' ') && (c != '\t'))
138                      {
139                        at_end = false;
140                        break;
141                      }
142                  }
143               
144                if (at_end)
145                  {
146                    temp_line.erase (back_slash);
147                    finished = false;
148                  }
149                else
150                  {
151                      // This was not a trailing backslash.
152                    finished = true;
153                  }
154              }
155       
156            m_accumulator += temp_line;
157          }
158
159          //cout << "parse_line1> accumulator=[" << m_accumulator << "]" << endl;
160          //cout << "parse_line1> finished=[" << finished << "]" << endl;
161
162        if (!finished)
163          {
164              // We still need to accumulate forthcoming lines
165              // before parsing the resulting text.
166            return (Awk::ok);
167          }
168
169          // now filter the complete accumulated line (if non empty)
170
171        if (m_accumulator != "")
172          {
173            bool ok = false;
174           
175            if (m_expression != 0)
176              {
177                if (m_expression->match (m_accumulator))
178                  {
179                    ok = true;
180                  }
181              }
182            else
183              {
184                if ((m_pattern == "") ||
185                    (m_accumulator.find (m_pattern) != cmt_string::npos))
186                  {
187                    ok = true;
188                  }
189              }
190           
191            if (ok && (m_awk != 0))
192              {
193                  //cout << "parse_line> accumulator=[" << m_accumulator << "]" << endl;
194
195                m_awk->filter (m_accumulator);
196                result = m_awk->get_last_condition ();
197              }
198
199            m_accumulator.erase (0);
200          }
201       
202        return (result);
203      }
204
205private:
206
207  cmt_string m_accumulator;
208  cmt_string m_pattern;
209  const cmt_regexp* m_expression;
210  Awk* m_awk;
211};
212
213//------------------------------------------------
214Awk::Awk ()
215{
216  m_condition = ok;
217}
218
219//------------------------------------------------
220Awk::~Awk ()
221{
222}
223
224//------------------------------------------------
225Awk::condition Awk::run (const cmt_string& text,
226                         const cmt_string& pattern)
227{
228  m_line_number = 0;
229  m_condition = ok;
230
231  begin ();
232  if (m_condition != ok) return (m_condition);
233
234  if (CmtSystem::testenv ("CMTTESTAWK"))
235    {
236      Parser p (this, pattern, 0);
237
238      m_condition = p.parse (text);
239      if (m_condition != ok) return (m_condition);
240    }
241  else
242    {
243      cmt_string line;
244      int pos = 0;
245      int max_pos;
246
247      max_pos = text.size ();
248
249      for (pos = 0; pos < max_pos;)
250        {
251          int cr = text.find (pos, "\r\n");
252          int nl = text.find (pos, '\n');
253         
254            // Get the first end-of-line (either lf or cr-lf)
255
256            //--------------------
257            //
258            //     cr    1    0
259            //   nl
260            //
261            //    1      a    b
262            //
263            //    0      c    d
264            //
265            //--------------------
266         
267          int first = nl;
268         
269          if (cr != cmt_string::npos)
270            {
271                // cases a or c
272
273              if (nl == cmt_string::npos)
274                {
275                    // case a
276                  first = cr;
277                }
278              else
279                {
280                    // case c
281                  first = (nl < cr) ? nl : cr;
282                }
283            }
284         
285          if (first == cmt_string::npos)
286            {
287                // This is likely the last line since there is no end-of-line
288              text.substr (pos, line);
289              pos = max_pos;
290            }
291          else if (first > pos)
292            {
293                // The eol was found beyond the current position
294                // (ie. this is a non empty line)
295              text.substr (pos, first - pos, line);
296              pos = first + 1;
297            }
298          else
299            {
300                // an empty line
301              line = "";
302              pos++;
303            }
304         
305          m_line_number++;
306         
307          if (line != "")
308            {
309              if ((pattern == "") ||
310                  (line.find (pattern) != cmt_string::npos))
311                {
312                  filter (line);
313                  if (m_condition != ok) return (m_condition);
314                }
315            }
316        }
317    }
318
319  end ();
320
321  return (m_condition);
322}
323
324//------------------------------------------------
325Awk::condition Awk::run (const cmt_string& text,
326                         const cmt_regexp& expression)
327{
328  m_line_number = 0;
329  m_condition = ok;
330
331  begin ();
332  if (m_condition != ok) return (m_condition);
333
334  Parser p (this, "", &expression);
335
336  m_condition = p.parse (text);
337  if (m_condition != ok) return (m_condition);
338
339    /*
340  if (CmtSystem::testenv ("CMTTESTAWK"))
341    {
342    }
343  else
344    {
345      cmt_string line;
346      int pos = 0;
347      int max_pos;
348
349      max_pos = text.size ();
350
351      for (pos = 0; pos < max_pos;)
352        {
353          int cr = text.find (pos, "\r\n");
354          int nl = text.find (pos, '\n');
355         
356            // Get the first end-of-line (either lf or cr-lf)
357         
358          int first = nl;
359         
360          if (cr != cmt_string::npos)
361            {
362              if (nl == cmt_string::npos)
363                {
364                  first = cr;
365                }
366              else
367                {
368                  first = (nl < cr) ? nl : cr;
369                }
370            }
371         
372          if (first == cmt_string::npos)
373            {
374                // This is likely the last line since there is no end-of-line
375              text.substr (pos, line);
376              pos = max_pos;
377            }
378          else if (first > pos)
379            {
380                // The eol was found beyond the current position
381                // (ie. this is a non empty line)
382              text.substr (pos, first - pos, line);
383              pos = first + 1;
384            }
385          else
386            {
387                // an empty line
388              line = "";
389              pos++;
390            }
391         
392          m_line_number++;
393         
394          if (line != "")
395            {
396              if (expression.match (line))
397                {
398                  filter (line);
399                  if (m_condition != ok) return (m_condition);
400                }
401            }
402        }
403    }
404    */
405
406  end ();
407
408  return (m_condition);
409}
410
411//------------------------------------------------
412void Awk::stop ()
413{
414  m_condition = stopped;
415}
416
417//------------------------------------------------
418void Awk::abort ()
419{
420  m_condition = failed;
421}
422
423//------------------------------------------------
424void Awk::allow_continuation ()
425{
426  m_continuation_allowed = true;
427}
428
429//------------------------------------------------
430Awk::condition Awk::get_last_condition () const
431{
432  return (m_condition);
433}
434
435//------------------------------------------------
436void Awk::begin ()
437{
438}
439
440//------------------------------------------------
441void Awk::filter (const cmt_string& /*line*/)
442{
443    //cout << "awk> " << line << endl;
444}
445
446//------------------------------------------------
447void Awk::end ()
448{
449}
450
451//------------------------------------------------
452void Awk::inc_line_number ()
453{
454  m_line_number++;
455}
456
457//------------------------------------------------
458Awk::condition FAwk::run (const cmt_string& file_name,
459                          const cmt_string& pattern)
460{
461  if (!CmtSystem::test_file (file_name)) return (failed);
462
463  CmtSystem::basename (file_name, m_file_name);
464  CmtSystem::dirname (file_name, m_dir_name);
465
466  cmt_string text;
467
468  text.read (file_name);
469
470  return (Awk::run (text, pattern));
471}
472
473//------------------------------------------------
474Awk::condition FAwk::run (const cmt_string& file_name,
475                          const cmt_regexp& expression)
476{
477  if (!CmtSystem::test_file (file_name)) return (failed);
478
479  CmtSystem::basename (file_name, m_file_name);
480  CmtSystem::dirname (file_name, m_dir_name);
481
482  cmt_string text;
483
484  text.read (file_name);
485
486  return (Awk::run (text, expression));
487}
488
489//------------------------------------------------
490Awk::condition PAwk::run (const cmt_string& command, 
491                          const cmt_string& pattern)
492{
493  cmt_string line;
494
495  m_line_number = 0;
496  m_condition = ok;
497
498  begin ();
499  if (m_condition != ok) return (m_condition);
500
501  FILE* f = popen (command.c_str (), "r"); 
502 
503  if (f == 0) return (failed);
504
505  char buffer[8192]; 
506  char* ptr;
507
508  while ((ptr = fgets (buffer, sizeof (buffer), f)) != NULL) 
509    {
510      line = ptr;
511
512      if (line.find ("\n") == cmt_string::npos)
513        {
514          cerr << "#CMT> Warning: Line too long and truncated in PAwk::run for command " << command << endl;
515        }
516
517      line.replace ("\n", "");
518
519      m_line_number++;
520
521      if (line != "")
522        {
523          if ((pattern == "") ||
524              (line.find (pattern) != cmt_string::npos))
525            {
526              filter (line);
527              if (m_condition != ok) return (m_condition);
528            }
529        }
530    }
531
532  pclose (f);
533
534  end ();
535
536  return (m_condition);
537}
538
539//------------------------------------------------
540Awk::condition PAwk::run (const cmt_string& command, 
541                          const cmt_regexp& expression)
542{
543  cmt_string line;
544
545  m_line_number = 0;
546  m_condition = ok;
547
548  begin ();
549  if (m_condition != ok) return (m_condition);
550
551  FILE* f = popen (command.c_str (), "r"); 
552 
553  if (f == 0) return (failed);
554
555  char buffer[256]; 
556  char* ptr;
557
558  while ((ptr = fgets (buffer, sizeof (buffer), f)) != NULL) 
559    {
560      line = ptr;
561
562      line.replace ("\n", "");
563
564      m_line_number++;
565
566      if (line != "")
567        {
568          if (expression.match (line))
569            {
570              filter (line);
571              if (m_condition != ok) return (m_condition);
572            }
573        }
574    }
575
576  pclose (f);
577
578  end ();
579
580  return (m_condition);
581}
582
583//----------------------------------------------------------
584PathScanner::PathScanner ()
585{
586  _running = false;
587  _level = 0;
588}
589
590//----------------------------------------------------------
591bool PathScanner::scan_path (const cmt_string& path, actor& a)
592{
593  if (_running) return (false);
594
595  _level = 0;
596  _running = true;
597
598  cmt_string compressed_path = path;
599  CmtSystem::compress_path (compressed_path);
600  scan_path (compressed_path, 0, a);
601
602  _running = false;
603  _level = 0;
604
605  return (true);
606}
607
608//----------------------------------------------------------
609void PathScanner::scan_path (const cmt_string& path, int level, actor& a)
610{
611  if (level > 10)
612    {
613      cout << "#PathScanner::scan_path> too deep search path=" << path << endl;
614    }
615
616  //
617  // Only do something if it is a directory.
618  //
619
620  if (!CmtSystem::test_directory (path)) return;
621
622  CmtSystem::cmt_string_vector list;
623  CmtSystem::cmt_string_vector entrylist;
624
625  CmtSystem::scan_dir (path, list);
626
627  if (list.size () == 0) return;
628
629  _level++;
630
631  // Will be set if at least one directory is a version directory
632  bool has_package = false;
633
634  cmt_string name;
635  cmt_string version;
636  cmt_string where;
637
638  int i;
639
640  for (i = 0; i < list.size (); i++)
641    {
642      const cmt_string& here = list[i];
643
644      if (!CmtSystem::test_directory (here)) continue;
645
646      name = "";
647      version = "";
648
649      cmt_string entry;
650      CmtSystem::basename (here, entry);
651      CmtSystem::dirname (path, where);
652
653      // cout << "## here=" << here << " entry=" << entry << " where=" << where << endl;
654
655      if ((level == 0) && (entry == "InstallArea")) continue;
656
657      cmt_string req;
658
659      req = here;
660      req += CmtSystem::file_separator ();
661      req += "mgr";
662      req += CmtSystem::file_separator ();
663      req += "requirements";
664
665      if (CmtSystem::test_file (req))
666        {
667          // We have found <path>/mgr/requirements
668          // this is an old directory convention.
669          // The version directory is the directory above
670
671          version = entry;
672          CmtSystem::basename (path, name);
673
674          // cout << "#1" << endl;
675
676          a.run (name, version, where);
677          has_package = true;
678
679          continue;
680        }
681
682      req = here;
683      req += CmtSystem::file_separator ();
684      req += "cmt";
685      req += CmtSystem::file_separator ();
686      req += "requirements";
687
688      if (CmtSystem::test_file (req))
689        {
690          // We have found <path>/cmt/requirements
691          // Question now is to detect the directory structure:
692          //
693          // if cmt/version.cmt exists it's a non-version-directory structure
694          // else
695          //   if there is a package statement in the requirements file we find it upward
696          //   else
697          //     if up is a version directory
698          //     else
699          //
700
701          cmt_string vreq;
702          vreq = here;
703          vreq += CmtSystem::file_separator ();
704          vreq += "cmt";
705          vreq += CmtSystem::file_separator ();
706          vreq += "version.cmt";
707
708          if (CmtSystem::test_file (vreq))
709            {
710              version.read (vreq);
711              int pos;
712              pos = version.find ('\n');
713              if (pos != cmt_string::npos) version.erase (pos);
714              pos = version.find ('\r');
715              if (pos != cmt_string::npos) version.erase (pos);
716
717              //cout << "#2" << endl;
718
719              a.run (entry, version, path);
720              has_package = true;
721             
722              continue;
723            }
724
725          cmt_string p;
726
727          p.read (req);
728          int pos;
729          pos = p.find ("package");
730          if (pos != cmt_string::npos)
731            {
732              p.erase (0, pos+8);
733              pos = p.find ('\n');
734              if (pos != cmt_string::npos) p.erase (pos);
735              pos = p.find ('\r');
736              if (pos != cmt_string::npos) p.erase (pos);
737              p.replace_all (" ", "");
738              p.replace_all ("\t", "");
739              if (p != "") name = p;
740            }
741
742          if (name != "")
743            {
744              // The package name was specified in the requirements file
745
746              if (entry == name)
747                {
748                  // The structure is without the version directory.
749
750                  //cout << "#3" << endl;
751
752                  a.run (name, "v1", path);
753                  has_package = true;
754                 
755                  continue;
756                }
757             
758              version = entry;
759              CmtSystem::basename (path, entry);
760             
761              if (entry == name)
762                {
763                  // The structure is with the version directory.
764                 
765                  //cout << "#4" << endl;
766
767                  a.run (name, version, where);
768                  has_package = true;
769                 
770                  continue;
771                }
772
773              // No directory structure matches the package name
774              // Is it a typo in the requirements file ?
775              // probably we should display it and quit...
776            }
777          else
778            {
779              version = entry;
780              CmtSystem::basename (path, entry);
781            }
782
783          // The package name is not specified in the requirements file
784          // or did not match the directory structure
785          // We'll have to guess it from the structure
786             
787          if (CmtSystem::is_version_directory (version))
788            {
789              // cout << "#5" << endl;
790
791              a.run (entry, version, where);
792              has_package = true;
793             
794              continue;
795            }
796
797          name = version;
798
799          where += CmtSystem::file_separator ();
800          where += entry;
801
802          // cout << "#6" << endl;
803
804          a.run (name, "v1", where);
805          has_package = true;
806         
807          continue;
808        }
809
810      //cout << "#7" << endl;
811
812      scan_path (here, level + 1, a);
813    }
814
815  if (has_package)
816    {
817      //
818      // At least one version was found here. Thus we want to scan further down.
819      //
820
821      for (i = 0; i < entrylist.size (); i++)
822        {
823          const cmt_string& e = entrylist[i];
824
825          cmt_string p = path;
826          p += CmtSystem::file_separator ();
827          p += e;
828
829            /*
830          for (j = 1; j < _level; j++) cout << "  ";
831          cout << "Restarting scan_path on p=" << p << endl;
832            */
833
834          cout << "#PathScanner::scan_path> Restarting scan_path on p=" << p << endl;
835
836
837          scan_path (p, 1, a);
838        }
839    }
840
841  _level--;
842}
843
844
845//----------------------------------------------------------
846bool PathScanner::scan_package (const cmt_string& path,
847                                const cmt_string& package)
848{
849  //
850  // Only do something if it is a directory.
851  //
852
853  if (!CmtSystem::test_directory (path)) return (false);
854
855  cmt_string pattern = path;
856  pattern += CmtSystem::file_separator ();
857  pattern += package;
858
859  if (!CmtSystem::test_directory (pattern)) return (false);
860
861  CmtSystem::cmt_string_vector list;
862
863  CmtSystem::scan_dir (pattern, list);
864
865  if (list.size () == 0) 
866    {
867      return (false);
868    }
869
870  bool result = false;
871
872  int i;
873  for (i = 0; i < list.size (); i++)
874    {
875      const cmt_string& name = list[i];
876
877      cmt_string version;
878      CmtSystem::basename (name, version);
879
880      if (version == "cmt")
881        {
882          cmt_string req;
883
884          req = name;
885          req += CmtSystem::file_separator ();
886          req += "requirements";
887
888          if (CmtSystem::test_file (req))
889            {
890              //cout << " -> no version" << endl;
891
892              cmt_string req;
893             
894              req = name;
895              req += CmtSystem::file_separator ();
896              req += "version.cmt";
897
898              cmt_string version;
899              if (CmtSystem::test_file (req))
900                {
901                  version.read (req);
902                  int pos;
903                  pos = version.find ('\n');
904                  if (pos != cmt_string::npos) version.erase (pos);
905                  pos = version.find ('\r');
906                  if (pos != cmt_string::npos) version.erase (pos);
907                }
908              else
909                {
910                  version = "v*";
911                }
912
913              cout << package << " " << version << " " << path << endl;
914
915              result = true;
916            }
917        }
918      else if (CmtSystem::is_version_directory (version))
919        {
920          cmt_string req;
921
922          req = name;
923          req += CmtSystem::file_separator ();
924          req += "cmt";
925          req += CmtSystem::file_separator ();
926          req += "requirements";
927
928          if (CmtSystem::test_file (req))
929            {
930              //cout << " -> cmt" << endl;
931
932              cout << package << " " << version << " " << path << endl;
933
934              result = true;
935            }
936          else
937            {
938              //cout << " -> no cmt" << endl;
939
940              req = name;
941              req += CmtSystem::file_separator ();
942              req += "mgr";
943              req += CmtSystem::file_separator ();
944              req += "requirements";
945
946              if (CmtSystem::test_file (req))
947                {
948                  //cout << " -> mgr" << endl;
949
950                  cout << package << " " << version << " " << path << endl;
951
952                  result = true;
953                }
954              else
955                {
956                  //cout << " -> no mgr" << endl;
957                }
958            }
959        }
960      else
961        {
962          //cout << " -> stop" << endl;
963        }
964    }
965
966  return (result);
967}
968
Note: See TracBrowser for help on using the repository browser.