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

Last change on this file since 190 was 190, checked in by garonne, 19 years ago

correct check out operation

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