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