Statistics
| Branch: | Revision:

root / src / eventlog / eventlogtool.cc @ 3e29b8a0

History | View | Annotate | Download (22.2 KB)

1 01873262 Georg Kunz
//=========================================================================
2
//  EVENTLOGTOOL.CC - part of
3
//                  OMNeT++/OMNEST
4
//           Discrete System Simulation in C++
5
//
6
//  Author: Levente Meszaros
7
//
8
//=========================================================================
9
10
/*--------------------------------------------------------------*
11
  Copyright (C) 2006-2008 OpenSim Ltd.
12

13
  This file is distributed WITHOUT ANY WARRANTY. See the file
14
  `license' for details on this and other legal matters.
15
*--------------------------------------------------------------*/
16
17
#include <time.h>
18
#include "../common/ver.h"
19
#include "platmisc.h"
20
#include "filereader.h"
21
#include "linetokenizer.h"
22
#include "eventlogindex.h"
23
#include "eventlog.h"
24
#include "filteredeventlog.h"
25
26
USING_NAMESPACE
27
28
class Options
29
{
30
    public:
31
        char *inputFileName;
32
        char *outputFileName;
33
        FILE *outputFile;
34
35
        eventnumber_t firstEventNumber;
36
        eventnumber_t lastEventNumber;
37
38
        eventnumber_t fromEventNumber;
39
        eventnumber_t toEventNumber;
40
41
        simtime_t fromSimulationTime;
42
        simtime_t toSimulationTime;
43
44
        bool outputInitialization;
45
        bool outputLogLines;
46
        bool traceCauses;
47
        bool traceConsequences;
48
49
        std::vector<file_offset_t> fileOffsets;
50
        std::vector<eventnumber_t> eventNumbers;
51
52
        const char *moduleExpression;
53
        std::vector<std::string> moduleNames;
54
        std::vector<std::string> moduleClassNames;
55
        std::vector<std::string> moduleNEDTypeNames;
56
        std::vector<int> moduleIds;
57
58
        const char *messageExpression;
59
        std::vector<std::string> messageNames;
60
        std::vector<std::string> messageClassNames;
61
        std::vector<long> messageIds;
62
        std::vector<long> messageTreeIds;
63
        std::vector<long> messageEncapsulationIds;
64
        std::vector<long> messageEncapsulationTreeIds;
65
66
        bool verbose;
67
68
    public:
69
        Options();
70
71
        IEventLog *createEventLog(FileReader *fileReader);
72
        void deleteEventLog(IEventLog *eventLog);
73
        eventnumber_t getFirstEventNumber();
74
        eventnumber_t getLastEventNumber();
75
};
76
77
Options::Options()
78
{
79
    inputFileName = NULL;
80
    outputFileName = NULL;
81
    outputFile = NULL;
82
83
    moduleExpression = NULL;
84
    messageExpression = NULL;
85
86
    firstEventNumber = -2;
87
    lastEventNumber = -2;
88
89
    fromEventNumber = -1;
90
    toEventNumber = -1;
91
92
    fromSimulationTime = simtime_nil;
93
    toSimulationTime = simtime_nil;
94
95
    outputInitialization = true;
96
    outputLogLines = true;
97
    traceCauses = true;
98
    traceConsequences = true;
99
100
    verbose = false;
101
}
102
103
IEventLog *Options::createEventLog(FileReader *fileReader)
104
{
105
    if (eventNumbers.empty() &&
106
        !moduleExpression && moduleNames.empty() && moduleClassNames.empty() && moduleNEDTypeNames.empty() &&  moduleIds.empty() &&
107
        !messageExpression && messageNames.empty() && messageClassNames.empty() &&
108
        messageIds.empty() && messageTreeIds.empty() && messageEncapsulationIds.empty() && messageEncapsulationTreeIds.empty())
109
    {
110
        return new EventLog(fileReader);
111
    }
112
    else
113
    {
114
        FilteredEventLog *filteredEventLog = new FilteredEventLog(new EventLog(fileReader));
115
116
        if (!eventNumbers.empty())
117
            filteredEventLog->setTracedEventNumber(eventNumbers.at(0));
118
119
        filteredEventLog->setEnableModuleFilter(moduleExpression || !moduleNames.empty() || !moduleClassNames.empty() || !moduleNEDTypeNames.empty() || !moduleIds.empty());
120
        filteredEventLog->setModuleExpression(moduleExpression);
121
        filteredEventLog->setModuleNames(moduleNames);
122
        filteredEventLog->setModuleClassNames(moduleClassNames);
123
        filteredEventLog->setModuleNEDTypeNames(moduleNEDTypeNames);
124
        filteredEventLog->setModuleIds(moduleIds);
125
126
        filteredEventLog->setEnableMessageFilter(messageExpression || !messageNames.empty() || !messageClassNames.empty() || !messageIds.empty() || !messageTreeIds.empty() || !messageEncapsulationIds.empty() || !messageEncapsulationTreeIds.empty());
127
        filteredEventLog->setMessageExpression(messageExpression);
128
        filteredEventLog->setMessageNames(messageNames);
129
        filteredEventLog->setMessageClassNames(messageClassNames);
130
        filteredEventLog->setMessageIds(messageIds);
131
        filteredEventLog->setMessageTreeIds(messageTreeIds);
132
        filteredEventLog->setMessageEncapsulationIds(messageEncapsulationIds);
133
        filteredEventLog->setMessageEncapsulationTreeIds(messageEncapsulationTreeIds);
134
135
        filteredEventLog->setTraceCauses(traceCauses);
136
        filteredEventLog->setTraceConsequences(traceConsequences);
137
        filteredEventLog->setFirstEventNumber(getFirstEventNumber());
138
        filteredEventLog->setLastEventNumber(getLastEventNumber());
139
140
        return filteredEventLog;
141
    }
142
}
143
144
void Options::deleteEventLog(IEventLog *eventLog)
145
{
146
    FilteredEventLog *filteredEventLog = dynamic_cast<FilteredEventLog *>(eventLog);
147
148
    if (filteredEventLog)
149
        delete filteredEventLog->getEventLog();
150
151
    delete eventLog;
152
}
153
154
eventnumber_t Options::getFirstEventNumber()
155
{
156
    if (firstEventNumber == -2) {
157
        FileReader *fileReader = new FileReader(inputFileName);
158
        EventLog eventLog(fileReader);
159
160
        firstEventNumber = -1;
161
162
        if (fromEventNumber != -1)
163
            firstEventNumber = fromEventNumber;
164
        else if (fromSimulationTime != simtime_nil) {
165
            IEvent *event = eventLog.getEventForSimulationTime(fromSimulationTime, FIRST_OR_NEXT);
166
167
            if (event)
168
                firstEventNumber = event->getEventNumber();
169
            else
170
                firstEventNumber = -1;
171
        }
172
    }
173
174
    return firstEventNumber;
175
}
176
177
eventnumber_t Options::getLastEventNumber()
178
{
179
    if (lastEventNumber == -2) {
180
        FileReader *fileReader = new FileReader(inputFileName);
181
        EventLog eventLog(fileReader);
182
183
        lastEventNumber = -1;
184
185
        if (toEventNumber != -1)
186
            lastEventNumber = toEventNumber;
187
        else if (toSimulationTime != simtime_nil) {
188
            IEvent *event = eventLog.getEventForSimulationTime(toSimulationTime, LAST_OR_PREVIOUS);
189
190
            if (event)
191
                lastEventNumber = event->getEventNumber();
192
            else
193
                lastEventNumber = -1;
194
        }
195
    }
196
197
    return lastEventNumber;
198
}
199
200
void offsets(Options options)
201
{
202
    if (options.verbose)
203
        fprintf(stdout, "# Printing event offsets from log file %s\n", options.inputFileName);
204
205
    FileReader *fileReader = new FileReader(options.inputFileName);
206
    EventLogIndex eventLogIndex(fileReader);
207
208
    long begin = clock();
209
210
    if (!options.eventNumbers.empty()) {
211
        for (std::vector<eventnumber_t>::iterator it = options.eventNumbers.begin(); it != options.eventNumbers.end(); it++) {
212
            file_offset_t offset = eventLogIndex.getOffsetForEventNumber(*it);
213
214
            if (options.verbose)
215
                fprintf(stdout, "# Event #%"EVENTNUMBER_PRINTF_FORMAT"d --> file offset %"INT64_PRINTF_FORMAT"d (0x%"INT64_PRINTF_FORMAT"x)\n", *it, offset, offset);
216
217
            if (offset != -1 && options.verbose) {
218
                fileReader->seekTo(offset);
219
                fprintf(stdout, "#  - line at that offset: %.*s", fileReader->getCurrentLineLength(), fileReader->getNextLineBufferPointer());
220
            }
221
222
            fprintf(options.outputFile, "%"INT64_PRINTF_FORMAT"d\n", offset);
223
        }
224
    }
225
226
    long end = clock();
227
228
    if (options.verbose)
229
        fprintf(stdout, "# Printing offsets for %d events while reading %"INT64_PRINTF_FORMAT"d lines and %"INT64_PRINTF_FORMAT"d bytes from log file %s completed in %g seconds\n", (int)options.eventNumbers.size(), fileReader->getNumReadLines(), fileReader->getNumReadBytes(), options.inputFileName, (double)(end - begin) / CLOCKS_PER_SEC);
230
}
231
232
void events(Options options)
233
{
234
    if (options.verbose)
235
        fprintf(stdout, "# Printing events from log file %s\n", options.inputFileName);
236
237
    FileReader *fileReader = new FileReader(options.inputFileName);
238
    EventLog eventLog(fileReader);
239
240
    long begin = clock();
241
242
    if (!options.fileOffsets.empty()) {
243
        for (std::vector<file_offset_t>::iterator it = options.fileOffsets.begin(); it != options.fileOffsets.end(); it++) {
244
            IEvent *event = eventLog.getEventForBeginOffset(*it);
245
246
            if (options.verbose)
247
                fprintf(stdout, "# Event #%"EVENTNUMBER_PRINTF_FORMAT"d found at file offset %"INT64_PRINTF_FORMAT"d (0x%"INT64_PRINTF_FORMAT"x)\n", event->getEventNumber(), *it, *it);
248
249
            event->print(options.outputFile);
250
        }
251
    }
252
253
    long end = clock();
254
255
    if (options.verbose)
256
        fprintf(stdout, "# Printing events for %d offsets while reading %"INT64_PRINTF_FORMAT"d lines and %"INT64_PRINTF_FORMAT"d bytes from log file %s completed in %g seconds\n", (int)options.fileOffsets.size(), fileReader->getNumReadLines(), fileReader->getNumReadBytes(), options.inputFileName, (double)(end - begin) / CLOCKS_PER_SEC);
257
}
258
259
void ranges(Options options)
260
{
261
    if (options.verbose)
262
        fprintf(stdout, "# Printing continuous ranges from log file %s\n", options.inputFileName);
263
264
    FileReader *fileReader = new FileReader(options.inputFileName);
265
    EventLog eventLog(fileReader);
266
267
    long begin = clock();
268
269
    IEvent *event = eventLog.getFirstEvent();
270
    IEvent *rangeFirstEvent = event;
271
272
    while (event) {
273
        IEvent *nextEvent = event->getNextEvent();
274
275
        if (!nextEvent || event->getEventNumber() != nextEvent->getEventNumber() - 1) {
276
            fprintf(stdout, "#%"EVENTNUMBER_PRINTF_FORMAT"d -> #%"EVENTNUMBER_PRINTF_FORMAT"d\n", rangeFirstEvent->getEventNumber(), event->getEventNumber());
277
            rangeFirstEvent = nextEvent;
278
        }
279
280
        event = nextEvent;
281
    }
282
283
    long end = clock();
284
285
    if (options.verbose)
286
        fprintf(stdout, "# Printing continuous ranges while reading %"INT64_PRINTF_FORMAT"d lines and %"INT64_PRINTF_FORMAT"d bytes from log file %s completed in %g seconds\n", fileReader->getNumReadLines(), fileReader->getNumReadBytes(), options.inputFileName, (double)(end - begin) / CLOCKS_PER_SEC);
287
}
288
289
void echo(Options options)
290
{
291
    if (options.verbose)
292
        fprintf(stdout, "# Echoing events from log file %s from event number #%"EVENTNUMBER_PRINTF_FORMAT"d to event number #%"EVENTNUMBER_PRINTF_FORMAT"d\n", options.inputFileName, options.getFirstEventNumber(), options.getLastEventNumber());
293
294
    FileReader *fileReader = new FileReader(options.inputFileName);
295
    IEventLog *eventLog = options.createEventLog(fileReader);
296
297
    long begin = clock();
298
    eventLog->print(options.outputFile, options.getFirstEventNumber(), options.getLastEventNumber(), options.outputInitialization, options.outputLogLines);
299
    long end = clock();
300
301
    if (options.verbose)
302
        fprintf(stdout, "# Echoing of %"EVENTNUMBER_PRINTF_FORMAT"d events, %"INT64_PRINTF_FORMAT"d lines and %"INT64_PRINTF_FORMAT"d bytes from log file %s completed in %g seconds\n", eventLog->getNumParsedEvents(), fileReader->getNumReadLines(), fileReader->getNumReadBytes(), options.inputFileName, (double)(end - begin) / CLOCKS_PER_SEC);
303
304
    options.deleteEventLog(eventLog);
305
}
306
307
void cat(Options options)
308
{
309
    if (options.verbose)
310
        fprintf(stdout, "# Cating from file %s\n", options.inputFileName);
311
312
    FileReader *fileReader = new FileReader(options.inputFileName);
313
314
    long begin = clock();
315
    char *line;
316
    while ((line = fileReader->getNextLineBufferPointer()))
317
        fprintf(stdout, "%.*s", fileReader->getCurrentLineLength(), line);
318
    long end = clock();
319
320
    if (options.verbose)
321
        fprintf(stdout, "# Cating of %"INT64_PRINTF_FORMAT"d lines and %"INT64_PRINTF_FORMAT"d bytes from log file %s completed in %g seconds\n", fileReader->getNumReadLines(), fileReader->getNumReadBytes(), options.inputFileName, (double)(end - begin) / CLOCKS_PER_SEC);
322
}
323
324
void filter(Options options)
325
{
326
    eventnumber_t tracedEventNumber = options.eventNumbers.empty() ? -1 : options.eventNumbers.at(0);
327
328
    if (options.verbose)
329
        fprintf(stdout, "# Filtering events from log file %s for traced event number #%"EVENTNUMBER_PRINTF_FORMAT"d from event number #%"EVENTNUMBER_PRINTF_FORMAT"d to event number #%"EVENTNUMBER_PRINTF_FORMAT"d\n",
330
            options.inputFileName, tracedEventNumber, options.getFirstEventNumber(), options.getLastEventNumber());
331
332
    FileReader *fileReader = new FileReader(options.inputFileName);
333
    IEventLog *eventLog = options.createEventLog(fileReader);
334
335
    long begin = clock();
336
    eventLog->print(options.outputFile, -1, -1, options.outputInitialization, options.outputLogLines);
337
    long end = clock();
338
339
    if (options.verbose)
340
        fprintf(stdout, "# Filtering of %"EVENTNUMBER_PRINTF_FORMAT"d events, %"INT64_PRINTF_FORMAT"d lines and %"INT64_PRINTF_FORMAT"d bytes from log file %s completed in %g seconds\n", eventLog->getNumParsedEvents(), fileReader->getNumReadLines(), fileReader->getNumReadBytes(), options.inputFileName, (double)(end - begin) / CLOCKS_PER_SEC);
341
342
    options.deleteEventLog(eventLog);
343
}
344
345
void usage(const char *message)
346
{
347
    if (message)
348
        fprintf(stderr, "Error: %s\n\n", message);
349
350
    fprintf(stderr, ""
351
"eventlogtool -- part of " OMNETPP_PRODUCT ", (C) 2006-2008 Andras Varga, OpenSim Ltd.\n"
352
"Version: " OMNETPP_VERSION_STR ", build: " OMNETPP_BUILDID ", edition: " OMNETPP_EDITION "\n"
353
"\n"
354
"Usage:\n"
355
"   eventlogtool <command> [options]* <input-file-name>\n"
356
"\n"
357
"   Commands:\n"
358
"      offsets     - prints the file offsets for the given even numbers (-e) one per line, all other options are ignored.\n"
359
"      events      - prints the events for the given offsets (-f), all other options are ignored.\n"
360
"      ranges      - prints the coherent event number ranges found in the input as event number pairs, all other options are ignored.\n"
361
"      echo        - echos the input to the output, range options are supported.\n"
362
"      filter      - filters the input according to the varios options and outputs the result, only one event number is traced,\n"
363
"                    but it may be outside of the specified event number or simulation time region.\n"
364
"\n"
365
"   Options: Not all options may be used for all commands. Some options optionally accept a list of\n"
366
"            space separated tokens as a single parameter. Name and class name filters may include patterns.\n"
367
"      input-file-name                            <file-name>\n"
368
"      -o      --output                           <file-name>\n"
369
"         defaults to standard output\n"
370
"      -fe     --from-event-number                <integer>\n"
371
"         inclusive\n"
372
"      -te     --to-event-number                  <integer>\n"
373
"         inclusive\n"
374
"      -ft     --from-simulation-time             <number>\n"
375
"         inclusive\n"
376
"      -tt     --to-simulation-time               <number>\n"
377
"         inclusive\n"
378
"      -e      --event-numbers                    <integer>+\n"
379
"         events must be present in the input file\n"
380
"      -f      --file-offsets                     <integer>+\n"
381
"      -me     --module-expression                <pattern>\n"
382
"      -mn     --module-names                     <pattern>+\n"
383
"      -mt     --module-class-names               <pattern>+\n"
384
"      -mi     --module-ids                       <integer>+\n"
385
"         compound module ids are allowed\n"
386
"      -se     --message-expression               <pattern>\n"
387
"      -sn     --message-names                    <pattern>+\n"
388
"      -st     --message-class-names              <pattern>+\n"
389
"      -si     --message-ids                      <integer>+\n"
390
"      -sti    --message-tree-ids                 <integer>+\n"
391
"      -sei    --message-encapsulation-ids        <integer>+\n"
392
"      -seti   --message-encapsulation-tree-ids   <integer>+\n"
393
"      -ob     --omit-causes-trace\n"
394
"      -of     --omit-consequences-trace\n"
395
"      -oi     --omit-initialization\n"
396
"      -ol     --omit-log-lines\n"
397
"      -v      --verbose\n"
398
"         prints performance information\n");
399
}
400
401
void parseIntTokens(std::vector<int> &parameter, char *str)
402
{
403
    LineTokenizer tokenizer;
404
    tokenizer.tokenize(str, strlen(str));
405
    char **tokens = tokenizer.tokens();
406
407
    for (int j = 0; j < tokenizer.numTokens(); j++)
408
        parameter.push_back(atoi(tokens[j]));
409
}
410
411
void parseLongTokens(std::vector<long> &parameter, char *str)
412
{
413
    LineTokenizer tokenizer;
414
    tokenizer.tokenize(str, strlen(str));
415
    char **tokens = tokenizer.tokens();
416
417
    for (int j = 0; j < tokenizer.numTokens(); j++)
418
        parameter.push_back(atol(tokens[j]));
419
}
420
421
void parseEventNumberTokens(std::vector<eventnumber_t> &parameter, char *str)
422
{
423
    char *e;
424
    LineTokenizer tokenizer;
425
    tokenizer.tokenize(str, strlen(str));
426
    char **tokens = tokenizer.tokens();
427
428
    for (int j = 0; j < tokenizer.numTokens(); j++)
429
        parameter.push_back(strtoll(tokens[j], &e, 10));
430
}
431
432
void parseFileOffsetTokens(std::vector<file_offset_t> &parameter, char *str)
433
{
434
    char *e;
435
    LineTokenizer tokenizer;
436
    tokenizer.tokenize(str, strlen(str));
437
    char **tokens = tokenizer.tokens();
438
439
    for (int j = 0; j < tokenizer.numTokens(); j++)
440
        parameter.push_back(strtoll(tokens[j], &e, 10));
441
}
442
443
void parseStringTokens(std::vector<std::string> &parameter, char *str)
444
{
445
    LineTokenizer tokenizer;
446
    tokenizer.tokenize(str, strlen(str));
447
    char **tokens = tokenizer.tokens();
448
449
    for (int j = 0; j < tokenizer.numTokens(); j++)
450
        parameter.push_back((char *)eventLogStringPool.get(tokens[j]));
451
}
452
453
int main(int argc, char **argv)
454
{
455
    if (argc < 3)
456
        usage("Not enough arguments specified");
457
    else {
458
        char *e;
459
        char *command = argv[1];
460
        Options options;
461
462
        for (int i = 2; i < argc; i++) {
463
            if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output"))
464
                options.outputFileName = argv[++i];
465
            else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))
466
                options.verbose = true;
467
            else if (!strcmp(argv[i], "-fe") || !strcmp(argv[i], "--from-event-number"))
468
                options.fromEventNumber = strtoll(argv[++i], &e, 10);
469
            else if (!strcmp(argv[i], "-te") || !strcmp(argv[i], "--to-event-number"))
470
                options.toEventNumber = strtoll(argv[++i], &e, 10);
471
            else if (!strcmp(argv[i], "-ft") || !strcmp(argv[i], "--from-simulation-time"))
472
                options.fromSimulationTime = BigDecimal::parse(argv[++i]);
473
            else if (!strcmp(argv[i], "-tt") || !strcmp(argv[i], "--to-simulation-time"))
474
                options.toSimulationTime = BigDecimal::parse(argv[++i]);
475
            else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--event-numbers"))
476
                parseEventNumberTokens(options.eventNumbers, argv[++i]);
477
            else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file-offsets"))
478
                parseFileOffsetTokens(options.fileOffsets, argv[++i]);
479
            else if (!strcmp(argv[i], "-me") || !strcmp(argv[i], "--module-expression"))
480
                options.moduleExpression = argv[++i];
481
            else if (!strcmp(argv[i], "-mn") || !strcmp(argv[i], "--module-names"))
482
                parseStringTokens(options.moduleNames, argv[++i]);
483
            else if (!strcmp(argv[i], "-mt") || !strcmp(argv[i], "--module-class-names"))
484
                parseStringTokens(options.moduleClassNames, argv[++i]);
485
            else if (!strcmp(argv[i], "-md") || !strcmp(argv[i], "--module-ned-type-names"))
486
                parseStringTokens(options.moduleNEDTypeNames, argv[++i]);
487
            else if (!strcmp(argv[i], "-mi") || !strcmp(argv[i], "--module-ids"))
488
                parseIntTokens(options.moduleIds, argv[++i]);
489
            else if (!strcmp(argv[i], "-se") || !strcmp(argv[i], "--message-expression"))
490
                options.messageExpression = argv[++i];
491
            else if (!strcmp(argv[i], "-sn") || !strcmp(argv[i], "--message-names"))
492
                parseStringTokens(options.messageNames, argv[++i]);
493
            else if (!strcmp(argv[i], "-st") || !strcmp(argv[i], "--message-class-names"))
494
                parseStringTokens(options.messageClassNames, argv[++i]);
495
            else if (!strcmp(argv[i], "-si") || !strcmp(argv[i], "--message-ids"))
496
                parseLongTokens(options.messageIds, argv[++i]);
497
            else if (!strcmp(argv[i], "-sti") || !strcmp(argv[i], "--message-tree-ids"))
498
                parseLongTokens(options.messageTreeIds, argv[++i]);
499
            else if (!strcmp(argv[i], "-sei") || !strcmp(argv[i], "--message-encapsulation-ids"))
500
                parseLongTokens(options.messageEncapsulationIds, argv[++i]);
501
            else if (!strcmp(argv[i], "-seti") || !strcmp(argv[i], "--message-encapsulation-tree-ids"))
502
                parseLongTokens(options.messageEncapsulationTreeIds, argv[++i]);
503
            else if (!strcmp(argv[i], "-ob") || !strcmp(argv[i], "--omit-causes-trace"))
504
                options.traceCauses = false;
505
            else if (!strcmp(argv[i], "-of") || !strcmp(argv[i], "--omit-consequences-trace"))
506
                options.traceConsequences = false;
507
            else if (!strcmp(argv[i], "-oi") || !strcmp(argv[i], "--omit-initialization"))
508
                options.outputInitialization = false;
509
            else if (!strcmp(argv[i], "-ol") || !strcmp(argv[i], "--omit-log-lines"))
510
                options.outputLogLines = false;
511
            else if (i == argc - 1)
512
                options.inputFileName = argv[i];
513
        }
514
515
        if (!options.inputFileName)
516
            usage("No input file specified");
517
        else {
518
            if (options.outputFileName)
519
                options.outputFile = fopen(options.outputFileName, "w");
520
            else
521
                options.outputFile = stdout;
522
523
            try {
524
                if (!strcmp(command, "offsets"))
525
                    offsets(options);
526
                else if (!strcmp(command, "events"))
527
                    events(options);
528
                else if (!strcmp(command, "ranges"))
529
                    ranges(options);
530
                else if (!strcmp(command, "filter"))
531
                    filter(options);
532
                else if (!strcmp(command, "echo"))
533
                    echo(options);
534
                else if (!strcmp(command, "cat"))
535
                    cat(options);
536
                else
537
                    usage("Unknown or invalid command");
538
            }
539
            catch (std::exception& e) {
540
                fprintf(stderr, "Error: %s\n", e.what());
541
                return -1;
542
            }
543
544
            if (options.outputFileName)
545
                fclose(options.outputFile);
546
        }
547
    }
548
549
    return 0;
550
}