source: CMT/v1r18p20041201/source/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      return;
615    }
616
617  //
618  // Only do something if it is a directory.
619  //
620
621  if (!CmtSystem::test_directory (path)) return;
622
623  CmtSystem::cmt_string_vector list;
624  CmtSystem::cmt_string_vector entrylist;
625
626  CmtSystem::scan_dir (path, list);
627
628  if (list.size () == 0) return;
629
630  _level++;
631
632  // Will be set if at least one directory is a version directory
633  bool has_package = false;
634
635  cmt_string name;
636  cmt_string version;
637  cmt_string where;
638
639  int i;
640
641  for (i = 0; i < list.size (); i++)
642    {
643      const cmt_string& here = list[i];
644
645      if (!CmtSystem::test_directory (here)) continue;
646
647      name = "";
648      version = "";
649
650      cmt_string entry;
651      CmtSystem::basename (here, entry);
652      CmtSystem::dirname (path, where);
653
654      // cout << "## here=" << here << " entry=" << entry << " where=" << where << endl;
655
656      if ((level == 0) && (entry == "InstallArea")) continue;
657
658      cmt_string req;
659
660      req = here;
661      req += CmtSystem::file_separator ();
662      req += "mgr";
663      req += CmtSystem::file_separator ();
664      req += "requirements";
665
666      if (CmtSystem::test_file (req))
667        {
668          // We have found <path>/mgr/requirements
669          // this is an old directory convention.
670          // The version directory is the directory above
671
672          version = entry;
673          CmtSystem::basename (path, name);
674
675          // cout << "#1" << endl;
676
677          a.run (name, version, where);
678          has_package = true;
679
680          continue;
681        }
682
683      req = here;
684      req += CmtSystem::file_separator ();
685      req += "cmt";
686      req += CmtSystem::file_separator ();
687      req += "requirements";
688
689      if (CmtSystem::test_file (req))
690        {
691          // We have found <path>/cmt/requirements
692          // Question now is to detect the directory structure:
693          //
694          // if cmt/version.cmt exists it's a non-version-directory structure
695          // else
696          //   if there is a package statement in the requirements file we find it upward
697          //   else
698          //     if up is a version directory
699          //     else
700          //
701
702          cmt_string vreq;
703          vreq = here;
704          vreq += CmtSystem::file_separator ();
705          vreq += "cmt";
706          vreq += CmtSystem::file_separator ();
707          vreq += "version.cmt";
708
709          if (CmtSystem::test_file (vreq))
710            {
711              version.read (vreq);
712              int pos;
713              pos = version.find ('\n');
714              if (pos != cmt_string::npos) version.erase (pos);
715              pos = version.find ('\r');
716              if (pos != cmt_string::npos) version.erase (pos);
717
718              //cout << "#2" << endl;
719
720              a.run (entry, version, path);
721              has_package = true;
722             
723              continue;
724            }
725
726          cmt_string p;
727
728          p.read (req);
729          int pos;
730          pos = p.find ("package");
731          if (pos != cmt_string::npos)
732            {
733              p.erase (0, pos+8);
734              pos = p.find ('\n');
735              if (pos != cmt_string::npos) p.erase (pos);
736              pos = p.find ('\r');
737              if (pos != cmt_string::npos) p.erase (pos);
738              p.replace_all (" ", "");
739              p.replace_all ("\t", "");
740              if (p != "") name = p;
741            }
742
743          if (name != "")
744            {
745              // The package name was specified in the requirements file
746
747              if (entry == name)
748                {
749                  // The structure is without the version directory.
750
751                  //cout << "#3" << endl;
752
753                  a.run (name, "v1", path);
754                  has_package = true;
755                 
756                  continue;
757                }
758             
759              version = entry;
760              CmtSystem::basename (path, entry);
761             
762              if (entry == name)
763                {
764                  // The structure is with the version directory.
765                 
766                  //cout << "#4" << endl;
767
768                  a.run (name, version, where);
769                  has_package = true;
770                 
771                  continue;
772                }
773
774              // No directory structure matches the package name
775              // Is it a typo in the requirements file ?
776              // probably we should display it and quit...
777            }
778          else
779            {
780              version = entry;
781              CmtSystem::basename (path, entry);
782            }
783
784          // The package name is not specified in the requirements file
785          // or did not match the directory structure
786          // We'll have to guess it from the structure
787             
788          if (CmtSystem::is_version_directory (version))
789            {
790              // cout << "#5" << endl;
791
792              a.run (entry, version, where);
793              has_package = true;
794             
795              continue;
796            }
797
798          name = version;
799
800          where += CmtSystem::file_separator ();
801          where += entry;
802
803          // cout << "#6" << endl;
804
805          a.run (name, "v1", where);
806          has_package = true;
807         
808          continue;
809        }
810
811      //cout << "#7" << endl;
812
813      scan_path (here, level + 1, a);
814    }
815
816  if (has_package)
817    {
818      //
819      // At least one version was found here. Thus we want to scan further down.
820      //
821
822      for (i = 0; i < entrylist.size (); i++)
823        {
824          const cmt_string& e = entrylist[i];
825
826          cmt_string p = path;
827          p += CmtSystem::file_separator ();
828          p += e;
829
830            /*
831          for (j = 1; j < _level; j++) cout << "  ";
832          cout << "Restarting scan_path on p=" << p << endl;
833            */
834
835          cout << "#PathScanner::scan_path> Restarting scan_path on p=" << p << endl;
836
837
838          scan_path (p, 1, a);
839        }
840    }
841
842  _level--;
843}
844
845
846//----------------------------------------------------------
847bool PathScanner::scan_package (const cmt_string& path,
848                                const cmt_string& package)
849{
850  //
851  // Only do something if it is a directory.
852  //
853
854  if (!CmtSystem::test_directory (path)) return (false);
855
856  cmt_string pattern = path;
857  pattern += CmtSystem::file_separator ();
858  pattern += package;
859
860  if (!CmtSystem::test_directory (pattern)) return (false);
861
862  CmtSystem::cmt_string_vector list;
863
864  CmtSystem::scan_dir (pattern, list);
865
866  if (list.size () == 0) 
867    {
868      return (false);
869    }
870
871  bool result = false;
872
873  int i;
874  for (i = 0; i < list.size (); i++)
875    {
876      const cmt_string& name = list[i];
877
878      cmt_string version;
879      CmtSystem::basename (name, version);
880
881      if (version == "cmt")
882        {
883          cmt_string req;
884
885          req = name;
886          req += CmtSystem::file_separator ();
887          req += "requirements";
888
889          if (CmtSystem::test_file (req))
890            {
891              //cout << " -> no version" << endl;
892
893              cmt_string req;
894             
895              req = name;
896              req += CmtSystem::file_separator ();
897              req += "version.cmt";
898
899              cmt_string version;
900              if (CmtSystem::test_file (req))
901                {
902                  version.read (req);
903                  int pos;
904                  pos = version.find ('\n');
905                  if (pos != cmt_string::npos) version.erase (pos);
906                  pos = version.find ('\r');
907                  if (pos != cmt_string::npos) version.erase (pos);
908                }
909              else
910                {
911                  version = "v*";
912                }
913
914              cout << package << " " << version << " " << path << endl;
915
916              result = true;
917            }
918        }
919      else if (CmtSystem::is_version_directory (version))
920        {
921          cmt_string req;
922
923          req = name;
924          req += CmtSystem::file_separator ();
925          req += "cmt";
926          req += CmtSystem::file_separator ();
927          req += "requirements";
928
929          if (CmtSystem::test_file (req))
930            {
931              //cout << " -> cmt" << endl;
932
933              cout << package << " " << version << " " << path << endl;
934
935              result = true;
936            }
937          else
938            {
939              //cout << " -> no cmt" << endl;
940
941              req = name;
942              req += CmtSystem::file_separator ();
943              req += "mgr";
944              req += CmtSystem::file_separator ();
945              req += "requirements";
946
947              if (CmtSystem::test_file (req))
948                {
949                  //cout << " -> mgr" << endl;
950
951                  cout << package << " " << version << " " << path << endl;
952
953                  result = true;
954                }
955              else
956                {
957                  //cout << " -> no mgr" << endl;
958                }
959            }
960        }
961      else
962        {
963          //cout << " -> stop" << endl;
964        }
965    }
966
967  return (result);
968}
969
Note: See TracBrowser for help on using the repository browser.