1 /*
2
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
16 *
17 * Author : Richard GAYRAUD - 04 Nov 2003
18 * From Hewlett Packard Company.
19 * Charles P. Wright from IBM Research
20 */
21
22 #include "sipp.hpp"
23 #include "screen.hpp"
24 #include "stat.hpp"
25 #include "infile.hpp"
26 #include <iostream>
27 #include <assert.h>
28
29 /* Read MAX_CHAR_BUFFER_SIZE size lines from the "fileName" and populate it in
30 * the fileContents vector. Each line should be terminated with a '\n'
31 */
FileContents(const char * fileName)32 FileContents::FileContents(const char *fileName)
33 {
34 ifstream *inFile = new ifstream(fileName);
35 char line[MAX_CHAR_BUFFER_SIZE];
36 int virtualLines = 0;
37
38 if (!inFile->good()) {
39 ERROR("Unable to open file %s", fileName);
40 }
41
42 this->fileName = fileName;
43
44 realLinesInFile = lineCounter = numLinesInFile = 0;
45 /* Initialize printf info. */
46 printfFile = false;
47 printfOffset = 0;
48 printfMultiple = 1;
49
50
51 line[0] = '\0';
52 inFile->getline(line, MAX_CHAR_BUFFER_SIZE);
53
54 if (NULL != strstr(line, "RANDOM")) {
55 usage = InputFileRandomOrder;
56 } else if (NULL != strstr(line, "SEQUENTIAL")) {
57 usage = InputFileSequentialOrder;
58 } else if (NULL != strstr(line, "USER")) {
59 usage = InputFileUser;
60 } else {
61 ERROR("Unknown file type (valid values are RANDOM, SEQUENTIAL, and USER) for %s:%s\n", fileName, line);
62 }
63
64 char *useprintf;
65 if ((useprintf = strstr(line, "PRINTF"))) {
66 /* We are going to operate in printf mode, which uses the line as a format
67 * string for printf with the line number. */
68 useprintf += strlen("PRINTF");
69 if (*useprintf != '=') {
70 ERROR("Invalid file printf specification (requires =) for %s:%s\n", fileName, line);
71 }
72 useprintf++;
73 char *endptr;
74 virtualLines = strtoul(useprintf, &endptr, 0);
75 if (*endptr && *endptr != '\r' && *endptr != '\n' && *endptr != ',') {
76 ERROR("Invalid file printf specification for (invalid end character '%c') %s:%s\n", *endptr, fileName, line);
77 }
78 if (virtualLines == 0) {
79 ERROR("A printf file must have at least one virtual line %s:%s\n", fileName, line);
80 }
81 printfFile = true;
82 }
83
84 if ((useprintf = strstr(line, "PRINTFOFFSET"))) {
85 useprintf += strlen("PRINTFOFFSET");
86 if (*useprintf != '=') {
87 ERROR("Invalid file PRINTFOFFSET specification (requires =) for %s:%s\n", fileName, line);
88 }
89 useprintf++;
90 char *endptr;
91 printfOffset = strtoul(useprintf, &endptr, 0);
92 if (*endptr && *endptr != '\n' && *endptr != ',') {
93 ERROR("Invalid PRINTFOFFSET specification for (invalid end character '%c') %s:%s\n", *endptr, fileName, line);
94 }
95 }
96
97 if ((useprintf = strstr(line, "PRINTFMULTIPLE"))) {
98 useprintf += strlen("PRINTFMULTIPLE");
99 if (*useprintf != '=') {
100 ERROR("Invalid PRINTFMULTIPLE specification (requires =) for %s:%s\n", fileName, line);
101 }
102 useprintf++;
103 char *endptr;
104 printfMultiple = strtoul(useprintf, &endptr, 0);
105 if (*endptr && *endptr != '\n' && *endptr != ',') {
106 ERROR("Invalid PRINTFOFFSET specification for (invalid end character '%c') %s:%s\n", *endptr, fileName, line);
107 }
108 }
109
110 while (!inFile->eof()) {
111 line[0] = '\0';
112 inFile->getline(line, MAX_CHAR_BUFFER_SIZE);
113 if (line[0]) {
114 if ('#' != line[0]) {
115 fileLines.push_back(line);
116 realLinesInFile++; /* this counts number of valid data lines */
117 }
118 } else {
119 break;
120 }
121 }
122
123 if (realLinesInFile == 0) {
124 ERROR("Input file has zero lines: %s\n", fileName);
125 }
126
127 if (printfFile) {
128 numLinesInFile = virtualLines;
129 } else {
130 numLinesInFile = realLinesInFile;
131 }
132
133 delete inFile;
134
135 indexMap = NULL;
136 indexField = -1;
137 }
138
getLine(int line,char * dest,int len)139 int FileContents::getLine(int line, char *dest, int len)
140 {
141 if (printfFile) {
142 line %= realLinesInFile;
143 }
144 return snprintf(dest, len, "%s", fileLines[line].c_str());
145 }
146
getField(int lineNum,int field,char * dest,int len)147 int FileContents::getField(int lineNum, int field, char *dest, int len)
148 {
149 int curfield = field;
150 int curline = lineNum;
151
152 dest[0] = '\0';
153 if (lineNum >= numLinesInFile) {
154 return 0;
155 }
156
157 if (printfFile) {
158 curline %= realLinesInFile;
159 }
160 const string & line = fileLines[curline];
161
162 size_t pos(0), oldpos(0);
163
164 do {
165 oldpos = pos;
166 size_t localpos = line.find(';', oldpos);
167
168 if (localpos != string::npos) {
169 pos = localpos + 1;
170 } else {
171 pos = localpos;
172 break;
173 }
174
175 if (curfield == 0) {
176 break;
177 }
178
179 curfield --;
180 } while (oldpos != string::npos);
181
182
183 if (curfield) {
184 WARNING("Field %d not found in the file %s", field, fileName);
185 return 0;
186 }
187
188
189 if (string::npos == oldpos) {
190 return 0;
191 }
192
193 if (string::npos != pos) {
194 // should not be decremented for fieldN
195 pos -= (oldpos + 1);
196 }
197
198 string x = line.substr(oldpos, pos);
199 if (x.length()) {
200 if (printfFile) {
201 const char *s = x.c_str();
202 int l = strlen(s);
203 int copied = 0;
204 for (int i = 0; i < l; i++) {
205 if (s[i] == '%') {
206 if (s[i + 1] == '%') {
207 dest[copied++] = s[i];
208 } else {
209 const char *format = s + i;
210 i++;
211 while (s[i] != 'd') {
212 if (i == l) {
213 ERROR("Invalid printf injection field (ran off end of line): %s", s);
214 }
215 if (!(isdigit(s[i]) || s[i] == '.' || s[i] == '-')) {
216 ERROR("Invalid printf injection field (only decimal values allowed '%c'): %s", s[i], s);
217 }
218 i++;
219 }
220 assert(s[i] == 'd');
221 char *tmp = (char *)malloc(s + i + 2 - format);
222 if (!tmp) {
223 ERROR("Out of memory!\n");
224 }
225 memcpy(tmp, format, s + i + 1 - format);
226 tmp[s + i + 1 - format] = '\0';
227 copied += sprintf(dest + copied, tmp, printfOffset + (lineNum * printfMultiple));
228 free(tmp);
229 }
230 } else {
231 dest[copied++] = s[i];
232 }
233 }
234 dest[copied] = '\0';
235 return copied;
236 } else {
237 return snprintf(dest, len, "%s", x.c_str());
238 }
239 } else {
240 return 0;
241 }
242 }
243
numLines()244 int FileContents::numLines()
245 {
246 return numLinesInFile;
247 }
248
nextLine(int userId)249 int FileContents::nextLine(int userId)
250 {
251 switch(usage) {
252 case InputFileRandomOrder:
253 return rand() % numLinesInFile;
254 case InputFileSequentialOrder: {
255 int ret = lineCounter;
256 lineCounter = (lineCounter + 1) % numLinesInFile;
257 return ret;
258 }
259 case InputFileUser:
260 if (userId == 0) {
261 return -1;
262 }
263 if ((userId - 1) >= numLinesInFile) {
264 ERROR("%s has only %d lines, yet user %d was requested.", fileName, numLinesInFile, userId);
265 }
266 return userId - 1;
267 default:
268 ERROR("Internal error: unknown file usage mode!");
269 return -1;
270 }
271 }
272
dump(void)273 void FileContents::dump(void)
274 {
275 WARNING("Line choosing strategy is [%s]. m_counter [%d] numLinesInFile [%d] realLinesInFile [%d]",
276 usage == InputFileSequentialOrder ? "SEQUENTIAL" :
277 usage == InputFileRandomOrder ? "RANDOM" :
278 usage == InputFileUser ? "USER" : "UNKNOWN",
279 lineCounter, numLinesInFile, realLinesInFile);
280
281 for (int i = 0; i < realLinesInFile && fileLines[i][0]; i++) {
282 WARNING("%s:%d reads [%s]", fileName, i, fileLines[i].c_str());
283 }
284 }
285
index(int field)286 void FileContents::index(int field)
287 {
288 this->indexField = field;
289
290 indexMap = new str_int_map;
291 for (int line = 0; line < numLines(); line++) {
292 reIndex(line);
293 }
294 }
295
lookup(char * key)296 int FileContents::lookup(char *key)
297 {
298 if (indexField == -1) {
299 ERROR("Invalid Index File: %s", fileName);
300 }
301 if (!indexMap) {
302 ERROR("Invalid Index File: %s", fileName);
303 }
304
305 str_int_map::iterator index_it = indexMap->find(key);
306 if (index_it == indexMap->end()) {
307 return -1;
308 }
309 return index_it->second;
310 }
311
312
insert(char * value)313 void FileContents::insert(char *value)
314 {
315 if (printfFile) {
316 ERROR("Can not insert or replace into a printf file: %s", fileName);
317 }
318 fileLines.push_back(value);
319 realLinesInFile++;
320 numLinesInFile++;
321 if (indexField != -1) {
322 reIndex(realLinesInFile - 1);
323 }
324 char line[1024];
325 getLine(realLinesInFile - 1, line, sizeof(line));
326 char tmp[1024];
327 getField(realLinesInFile - 1, 0, tmp, sizeof(tmp));
328 }
329
replace(int line,char * value)330 void FileContents::replace(int line, char *value)
331 {
332 if (printfFile) {
333 ERROR("Can not insert or replace into a printf file: %s", fileName);
334 }
335 if (line >= realLinesInFile || line < 0) {
336 ERROR("Invalid line number (%d) for file: %s (%d lines)", line, fileName, realLinesInFile);
337 }
338 deIndex(line);
339 fileLines[line] = value;
340 reIndex(line);
341 }
342
reIndex(int line)343 void FileContents::reIndex(int line)
344 {
345 if (indexField == -1) {
346 return;
347 }
348 assert(line >= 0);
349 assert(line < realLinesInFile);
350
351 char tmp[SIPP_MAX_MSG_SIZE];
352 getField(line, indexField, tmp, SIPP_MAX_MSG_SIZE);
353 str_int_map::iterator index_it = indexMap->find(str_int_map::key_type(tmp));
354 if (index_it != indexMap->end()) {
355 indexMap->erase(index_it);
356 }
357 indexMap->insert(pair<str_int_map::key_type,int>(str_int_map::key_type(tmp), line));
358 }
359
deIndex(int line)360 void FileContents::deIndex(int line)
361 {
362 if (indexField == -1) {
363 return;
364 }
365 assert(line >= 0);
366 assert(line < realLinesInFile);
367
368 char tmp[SIPP_MAX_MSG_SIZE];
369 getField(line, indexField, tmp, SIPP_MAX_MSG_SIZE);
370 str_int_map::iterator index_it = indexMap->find(str_int_map::key_type(tmp));
371 if (index_it != indexMap->end()) {
372 if (index_it->second == line) {
373 indexMap->erase(index_it);
374 }
375 }
376 }
377