1 // This is core/vul/vul_awk.cxx
2 //:
3 // \file
4 // \author Andrew W. Fitzgibbon, Oxford RRG
5 // \date   17 May 1997
6 // \verbatim
7 //  Modifications
8 //   AWF (Oxford)     17 May 1997: Initial version.
9 //   Eric Moyer       15 Jul 2009: Added strip comment functionality
10 // \endverbatim
11 //
12 //-----------------------------------------------------------------------------
13 
14 #include <cctype>
15 #include <cstring>
16 #include <iostream>
17 #include <cstdio>
18 #include "vul_awk.h"
19 
20 #ifdef _MSC_VER
21 #  include "vcl_msvc_warnings.h"
22 #endif
23 
24 //: Construct from input stream
vul_awk(std::istream & s,ModeFlags mode)25 vul_awk::vul_awk(std::istream & s, ModeFlags mode)
26   : fd_(s)
27   , mode_(mode)
28 {
29   done_ = false;
30   line_number_ = 0;
31   split_line_ = nullptr;
32 
33   next();
34 }
35 
~vul_awk()36 vul_awk::~vul_awk()
37 {
38   delete[] split_line_;
39 }
40 
41 void
next()42 vul_awk::next()
43 {
44   bool do_strip_comments = (((int)mode_) & ((int)strip_comments)) != 0;
45 #if 0
46   bool do_backslash_continuations = (int(mode_) & int(backslash_continuations)) != 0;
47 #endif
48   bool discard_current_line = true;
49   while (discard_current_line)
50   {
51     bool extract_fields = true;
52     discard_current_line = false;
53 
54     // Read line -- should be quite fast after the first one.
55     line_.erase();
56 
57     while (true)
58     {
59       int c = fd_.get();
60       if (c == EOF || fd_.eof())
61       {
62         done_ = true;
63         break;
64       }
65       if (c == '\n')
66         break;
67       line_ += char(c);
68     }
69 
70     char const * linep = line_.c_str();
71 
72     // copy string
73     delete[] split_line_;
74     split_line_ = new char[line_.size() + 1];
75     std::strcpy(split_line_, linep);
76 
77     // strip comments
78     if (do_strip_comments)
79     {
80       // find the first # character
81       char * comment_char = split_line_;
82       while (*comment_char != '#' && *comment_char != '\0')
83         ++comment_char;
84       // replace the # with a single space and terminate the string.  I
85       // use a single space since that will help the backslash
86       // continuation if it is ever implemented
87       if (*comment_char == '#')
88       {
89         // Replace with a space
90         *comment_char = ' ';
91         ++comment_char;
92         // Terminate the string
93         if (*comment_char != '\0')
94         {
95           *comment_char = '\0';
96         }
97         if (comment_char - split_line_ == 1)
98         {
99           // The line was only a comment -- don't try to extract
100           // records, just discard the current line and go to the next
101           extract_fields = false;
102           discard_current_line = true;
103         }
104       }
105     }
106 
107     if (extract_fields)
108     {
109       // Chop line up into fields
110       fields_.clear();
111       char * cp = split_line_;
112 
113       while (true)
114       {
115         // Eat white
116         while (*cp && std::isspace(*cp))
117           ++cp;
118         if (!*cp)
119           break;
120 
121         // Push
122         fields_.push_back(cp);
123 
124         // Find nonwhite
125         while (*cp && !std::isspace(*cp))
126           ++cp;
127         if (!*cp)
128           break;
129 
130         // Zap space
131         *cp++ = '\0';
132       }
133     }
134     // Increment line number
135     ++line_number_;
136   }
137 }
138 
139 char const *
line_from(int field_number) const140 vul_awk::line_from(int field_number) const
141 {
142   char const * p = line_.c_str();
143   if (field_number >= NF())
144     field_number = NF() - 1;
145   if (field_number < 0)
146   {
147     std::cerr << "vul_awk::line_from(" << field_number << ") -- ZOIKS\n";
148     return line();
149   }
150 
151   return p + (fields_[field_number] - split_line_);
152 }
153 
154 void
testvul_awk()155 testvul_awk()
156 {
157   std::cout << "Start\n";
158   for (vul_awk awk(std::cin); awk; ++awk)
159   {
160     std::cout << awk.NF() << ':' << awk[2] << std::endl;
161   }
162 }
163