Line data Source code
1 : #include "wibmod/WIB1/AddressTable.hh"
2 : #include <fstream>
3 : #include "wibmod/WIB1/AddressTableException.hh"
4 : #include <boost/tokenizer.hpp> //tokenizer
5 : #include <stdlib.h> //strtoul & getenv
6 : #include <boost/regex.hpp> //regex
7 : #include <boost/algorithm/string/case_conv.hpp> //to_upper
8 :
9 :
10 : #define MAX_FILE_LEVEL 10
11 :
12 0 : void AddressTable::LoadFile(std::string const & fileName,
13 : std::string const & prefix, uint16_t offset){
14 :
15 0 : std::ifstream inFile(fileName.c_str());
16 0 : if (!inFile.is_open()){
17 0 : std::string envBasedFileName = fileName;
18 : //Try to use address table path if it exists
19 0 : if(getenv("WIBMOD_SHARE") != NULL){
20 0 : envBasedFileName=getenv("WIBMOD_SHARE");
21 0 : envBasedFileName+="/config/WIB1/tables/";
22 0 : envBasedFileName+=fileName;
23 0 : inFile.open(envBasedFileName.c_str());
24 : }
25 0 : if (!inFile.is_open()){
26 0 : BUException::BAD_FILE e;
27 0 : e.Append("File not found: ");
28 0 : e.Append(envBasedFileName.c_str());
29 0 : throw e;
30 0 : }
31 0 : }
32 0 : const size_t bufferSize = 1000;
33 0 : char buffer[bufferSize + 1];
34 0 : memset(buffer,0,bufferSize+1);
35 0 : uint32_t lineNumber = 1;
36 0 : while(! inFile.eof()){
37 0 : inFile.getline(buffer,bufferSize);
38 0 : ProcessLine(std::string(buffer),lineNumber,prefix,offset);
39 0 : lineNumber++;
40 : }
41 0 : }
42 :
43 :
44 0 : void AddressTable::ProcessLine(std::string const & line,size_t lineNumber,
45 : std::string const & prefix, uint16_t offset){
46 : //First, ignore commments
47 0 : std::string activeLine = line.substr(0,line.find('#'));
48 :
49 :
50 : //Tokenize the activeLine
51 0 : boost::char_separator<char> sep(" ");
52 0 : boost::tokenizer<boost::char_separator<char> > tokens(activeLine,sep);
53 0 : boost::tokenizer<boost::char_separator<char> >::iterator itToken = tokens.begin();
54 :
55 :
56 : //crate a new Item;
57 0 : Item * item = new Item;
58 0 : size_t iToken = 0;
59 0 : for(; itToken != tokens.end(); itToken++){
60 0 : switch (iToken){
61 0 : case 0:
62 0 : {// keep name out of everyone else's scope
63 : //Assign name
64 :
65 0 : std::string name(*itToken);
66 0 : if(!prefix.empty()){
67 : //we have a prefix to add on to the name
68 0 : name = prefix+std::string(".")+name;
69 : }
70 :
71 0 : while( (name.size() > 0) && ('.' == name[name.size()-1])) {
72 : //If the trailing entry is a dot (level marker) drop it as this entry just means the prefix
73 0 : name.erase(name.size()-1);
74 : }
75 :
76 :
77 0 : if(name.size() == 0){
78 : //We have an emtpy name, this is bad and we should throw
79 0 : BUException::INVALID_NAME e;
80 0 : e.Append("Empty name");
81 0 : throw e;
82 0 : }
83 :
84 0 : boost::to_upper(name);
85 :
86 : //Assign the name to this item
87 0 : item->name.assign(name);
88 0 : iToken++;
89 0 : }
90 0 : break;
91 0 : case 1:
92 : //Assign address and apply any offset
93 : //itToken means we don't have to check for size of string
94 0 : item->address = strtoul(itToken->c_str(),NULL,0) + offset;
95 0 : iToken++;
96 0 : break;
97 0 : case 2:
98 :
99 : //Check if this is an include line
100 0 : if(!isdigit((itToken->c_str()[0]))){
101 : //we have an include file, append all following tokens together to use as the filename.
102 0 : std::string filename(*itToken);
103 0 : itToken++;
104 0 : while(itToken != tokens.end()){
105 0 : filename+=" ";
106 0 : filename+=*itToken;
107 0 : itToken++;
108 : }
109 0 : fileLevel++;
110 0 : if(fileLevel <= MAX_FILE_LEVEL){
111 0 : LoadFile(filename,item->name,item->address);
112 : }else{
113 0 : BUException::MAX_INCLUDE_FILE_DEPTH e;
114 0 : e.Append("File: ");
115 0 : e.Append(filename);
116 0 : e.Append(" at prefix ");
117 0 : e.Append(item->name);
118 0 : e.Append(" is too deep\n");
119 0 : throw e;
120 0 : }
121 0 : fileLevel--;
122 : //Delete fake partial item
123 0 : delete item;
124 : //return to move on to the next line of the main file
125 0 : return;
126 0 : }
127 :
128 : //Assign mask
129 0 : item->mask = strtoul(itToken->c_str(),NULL,0);
130 : //stolen from https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel
131 : //Find the bitshift offset
132 0 : {
133 0 : unsigned int v = item->mask; // 32-bit word input to count zero bits on right
134 0 : unsigned int c = 32; // c will be the number of zero bits on the right
135 0 : v &= -signed(v);
136 0 : if (v) {c--;}
137 0 : if (v & 0x0000FFFF) {c -= 16;}
138 0 : if (v & 0x00FF00FF) {c -= 8;}
139 0 : if (v & 0x0F0F0F0F) {c -= 4;}
140 0 : if (v & 0x33333333) {c -= 2;}
141 0 : if (v & 0x55555555) {c -= 1;}
142 0 : item->offset = c;
143 : }
144 :
145 0 : iToken++;
146 0 : break;
147 0 : case 3:
148 : //Assign mode
149 0 : item->mode = 0;
150 :
151 : //Read
152 0 : if(itToken->find('r') != std::string::npos){
153 0 : item->mode |= Item::READ;
154 0 : }else if (itToken->find('R') != std::string::npos){
155 0 : item->mode |= Item::READ;
156 : }
157 :
158 : //Write
159 0 : if(itToken->find('w') != std::string::npos){
160 0 : item->mode |= Item::WRITE;
161 0 : }else if (itToken->find('W') != std::string::npos){
162 0 : item->mode |= Item::WRITE;
163 : }
164 :
165 : //Action
166 0 : if(itToken->find('a') != std::string::npos){
167 0 : item->mode |= Item::ACTION;
168 0 : }else if (itToken->find('A') != std::string::npos){
169 0 : item->mode |= Item::ACTION;
170 : }
171 :
172 : iToken++;
173 : break;
174 0 : default:
175 : //parse user arguments
176 : //repeated arguments will be over-written
177 :
178 : //Find if this is an argument or a flag, flags have no equal signs
179 0 : if(itToken->find('=') == std::string::npos){
180 : //Create an entry for this with no data
181 0 : item->user[*itToken];
182 0 : iToken++;
183 : }else{
184 : //Get the name of the user value
185 0 : size_t equalSignPos = itToken->find('=');
186 : //make sure there isn't a """ before the =
187 0 : if(itToken->find('"') != std::string::npos){
188 0 : if(itToken->find('"') < equalSignPos){
189 0 : BUException::BAD_TOKEN e;
190 0 : e.Append("Malformed token : ");
191 0 : e.Append(itToken->c_str());
192 0 : e.Append(" on line ");
193 0 : char numberBuffer[14] = "\0\0\0\0\0\0\0\0\0\0\0\0";
194 0 : snprintf(numberBuffer,12,"%zu\n",lineNumber);
195 0 : e.Append(numberBuffer);
196 0 : e.Append("Bad line: ");
197 0 : e.Append(activeLine);
198 0 : e.Append("\n");
199 0 : throw e;
200 0 : }
201 : }
202 : //cache the name of the user field
203 0 : std::string name = itToken->substr(0,equalSignPos);
204 : //Parse the rest of the user value if there is more size
205 0 : if(itToken->size()-1 == equalSignPos){
206 0 : BUException::BAD_TOKEN e;
207 0 : e.Append("Malformed token : ");
208 0 : e.Append(itToken->c_str());
209 0 : e.Append(" on line ");
210 0 : char numberBuffer[14] = "\0\0\0\0\0\0\0\0\0\0\0\0";
211 0 : snprintf(numberBuffer,12,"%zu\n",lineNumber);
212 0 : e.Append(numberBuffer);
213 0 : throw e;
214 0 : }
215 : //star this user field's data (data after the '=' char)
216 0 : std::string val = itToken->substr(equalSignPos+1);
217 0 : if(val[0] != '"'){
218 : //We have a simple entry that has no quotes
219 0 : item->user[name] = val;
220 0 : iToken++;
221 : }else{
222 : //We have a quoted value
223 0 : val.erase(0,1); //remove the quote
224 :
225 : //Check if this is still a simple entry, but with quotes
226 0 : if(val.find('"') != std::string::npos){
227 : //We have another quote, remove it and everything after it
228 0 : val = val.substr(0,val.find('"'));
229 : }else{
230 : //We have a complicated value
231 0 : itToken++;
232 0 : while(itToken != tokens.end()){
233 0 : val.append(" ");
234 0 : val.append(*itToken);
235 0 : if((*itToken)[itToken->size() -1] == '"'){
236 : //stop now that we've reached the closing quote
237 : //remove it from the string
238 0 : val.erase(val.size()-1);
239 : break;
240 : }
241 0 : iToken++;
242 0 : itToken++;
243 : }
244 : }
245 : //convert "\n" to '\n'
246 0 : while(val.find("\\n") != std::string::npos){
247 0 : val.replace(val.find("\\n"),2,std::string("\n"));
248 : }
249 0 : item->user[name] = val;
250 : }
251 0 : }
252 : break;
253 : }
254 0 : if(itToken == tokens.end()){
255 : break;
256 : }
257 : }
258 :
259 0 : if(iToken >= 4){
260 0 : AddEntry(item);
261 : }else{
262 0 : delete item;
263 : }
264 0 : }
265 :
|