source: CMT/HEAD/source/cmt_awk.cxx@ 79

Last change on this file since 79 was 79, checked in by arnault, 20 years ago

Fixing session - see CL#275

  • Property svn:eol-style set to native
File size: 21.8 KB
RevLine 
[2]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
[79]654 //cout << "## here=" << here << " entry=" << entry << " where=" << where << endl;
[2]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.