Project

General

Profile

Statistics
| Branch: | Revision:

root / src / scave / scavetool.cc @ a3be1d55

History | View | Annotate | Download (29.9 KB)

1
//=========================================================================
2
//  SCAVETOOL.CC - part of
3
//                  OMNeT++/OMNEST
4
//           Discrete System Simulation in C++
5
//
6
//  Author: Tamas Borbely, Andras Varga
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

    
18
#include <assert.h>
19
#include <sstream>
20
#include "../common/ver.h"
21
#include "linetokenizer.h"
22
#include "resultfilemanager.h"
23
#include "nodetype.h"
24
#include "nodetyperegistry.h"
25
#include "dataflowmanager.h"
26
#include "vectorfilereader.h"
27
#include "vectorfilewriter.h"
28
#include "vectorfileindexer.h"
29
#include "filternodes.h"
30
#include "filewriter.h"
31
#include "arraybuilder.h"
32
#include "export.h"
33
#include "fields.h"
34
#include "stringutil.h"
35
#include "scaveutils.h"
36

    
37
USING_NAMESPACE
38

    
39
using namespace std;
40

    
41
void printUsage()
42
{
43
    printf(
44
       "scavetool -- part of " OMNETPP_PRODUCT ", (C) 2006-2008 Andras Varga, OpenSim Ltd.\n"
45
       "Version: " OMNETPP_VERSION_STR ", build: " OMNETPP_BUILDID ", edition: " OMNETPP_EDITION "\n"
46
       "\n"
47
       "Usage: scavetool <command> [options] <files>...\n"
48
       "\n"
49
       "For processing result files written by simulations: vector files (.vec) and\n"
50
       "scalar files (.sca).\n"
51
       "\n"
52
       "Commands:\n"
53
       "    v, vector   filter and process data in vector files\n"
54
       "    s, scalar   filter and process data in scalar files\n"
55
       "    l, list     list summary info about input files\n"
56
       "    i, info     print list of available functions (to be used with `-a')\n"
57
       "    x, index    generate index files for vector files\n"
58
       "Options:\n"
59
       " `vector' command:\n"
60
       "    -p <pattern>    the filter expression (see syntax below)\n"
61
       "    -a <function>   apply the given processing to the selected vectors (see syntax below);\n"
62
       "                    the `info' command prints the names of available operations. This option\n"
63
       "                    may occur multiple times.\n"
64
       "    -O <filename>   output file name\n"
65
       "    -F <formatname> format of output file: vec (default), splitvec, matlab, octave, csv, splitcsv\n"
66
       "    -V              print info about progress (verbose)\n"
67
       //TODO option: print matching vectorIDs and exit
68
       " `scalar' command:\n"
69
       "    -p <pattern>    the filter expression (see syntax below)\n"
70
       "    -a <function>   apply the given processing to the selected scalars (see syntax below);\n"
71
       "                    the `info' command prints the names of available operations. This option\n"
72
       "                    may occur multiple times.\n"
73
       "    -O <filename>   output file name\n"
74
       "    -F <formatname> format of output file: csv (default), matlab, octave\n" //TODO sca files
75
       "    -V              print info about progress (verbose)\n"
76
       " `list' command:\n"
77
       //TODO allow filtering by patterns here too?
78
       //TODO specifying more than one flag should list tuples e.g. (module,statistic) pairs
79
       // occurring in the input files
80
       "    -n   print list of unique statistics names\n"
81
       "    -m   print list of unique module name\n"
82
       "    -r   print list of unique run Ids\n"
83
       "    -c   print list of unique configuration Ids (aka run numbers)\n"
84
       //TODO other attributes
85
       " `info' command:\n"
86
       "    -b   list filter names only (brief)\n"
87
       "    -s   list filter names with parameter list (summary)\n"
88
       "    -v   include descriptions in the output (default)\n"
89
       " `index' command:\n"
90
       "    -r   rebuild vector file (rearranges records into blocks)\n"
91
       "    -V   print info about progress (verbose)\n"
92
       "\n"
93
       "Function syntax (for `vector -a'): <name>(<parameterlist>).\n"
94
       "Examples: winavg(10), mean()\n"
95
       "\n"
96
       // TODO scalar functions
97
       "Pattern syntax: one or more <fieldname>(<pattern>) pairs, combined with AND,\n"
98
       "OR, NOT operators.\n"
99
       "  <fieldname> is one of:\n"
100
       "    file:             full path of the result file\n"
101
       "    run:              unique run Id\n"
102
       "    module:           module full path\n"
103
       "    name:             name of the statistic\n"
104
       "    attr:experiment:  the experiment attribute of the run\n"
105
       "    attr:measurement: the measurement attribute of the run\n"
106
       "    attr:replication: the replication attribute of the run\n"
107
       "  <pattern> is a glob-like pattern:\n"
108
       "    ?             matches any character except '.'\n"
109
       "    *             matches zero or more characters, except '.'\n"
110
       "    **            matches zero or more characters (any character)\n"
111
       "    {a-z}         matches a character in range a-z\n"
112
       "    {^a-z}        matches a character NOT in range a-z\n"
113
       "    {32..255}     any number (ie. sequence of digits) in range 32..255  (e.g. \"99\")\n"
114
       "    [32..255]     any number in square brackets in range 32..255 (e.g. \"[99]\")\n"
115
       "    \\ (backslash) takes away the special meaning of the subsequent character\n"
116
       "Pattern example:\n"
117
       "    module(\"**.sink\") AND (name(\"queueing time\") OR name(\"transmission time\"))\n"
118
       "\n"
119
       "Examples:\n"
120
       "    scavetool vector -p \"queueing time\" -a winavg(10) -O out.vec *.vec\n"
121
       "        Saves the queueing time vectors to out.vec, after applying a window \n"
122
       "        average filter.\n"
123
       "\n"
124
       "    scavetool scalar -p \"module(sink) OR module(queue)\" -a \"scatter(.,load,queue,\\\"queue length\\\")\" -O out.csv -F csv *.sca\n"
125
       "        Creates a scatter plot with the load attribute on the x axis, and queue length\n"
126
       "        for iso lines.\n"
127
    );
128
}
129

    
130
static void loadFiles(ResultFileManager &manager, const vector<string> &fileNames, bool verbose)
131
{
132
    // load files
133
    ResultFileManager resultFileManager;
134
    for (int i=0; i<(int)fileNames.size(); i++)
135
    {
136
        //TODO on Windows: manual globbing of wildcards
137
        const char *fileName = fileNames[i].c_str();
138
        if (verbose) printf("reading %s...", fileName);
139
        try {
140
            ResultFile *f = manager.loadFile(fileName);
141
            if (!f)
142
            {
143
                if (verbose) printf("\n");
144
                fprintf(stderr, "Error: %s: load() returned null\n", fileName);
145
            }
146
            else if (f->numUnrecognizedLines>0)
147
            {
148
                if (verbose) printf("\n");
149
                fprintf(stderr, "WARNING: %s: %d invalid/incomplete lines out of %d\n", fileName, f->numUnrecognizedLines, f->numLines);
150
            }
151
            else
152
            {
153
                if (verbose) printf(" %d lines\n", f->numLines);
154
            }
155
        }
156
        catch (exception& e) {
157
            fprintf(stdout, "Exception: %s\n", e.what());
158
        }
159
    }
160
    if (verbose) printf("%d file(s) loaded\n", (int)manager.getFiles().size());
161
}
162

    
163
static string rebuildCommandLine(int argc, char **argv)
164
{
165
    // FIXME quotes
166
    string result;
167
    for (int i = 0; i < argc; i++)
168
    {
169
        if (i != 0) result += " ";
170
        result += argv[i];
171
    }
172
    return result;
173
}
174

    
175
int vectorCommand(int argc, char **argv)
176
{
177
    // options
178
    bool opt_verbose = false;
179
    string opt_filterExpression;
180
    string opt_outputFileName = "_out_";
181
    string opt_outputFormat = "vec";  //TBD vec, splitvec, octave, split octave (and for octave: x, y, both),...
182
    string opt_readerNodeType = "vectorfilereader";
183
    vector<string> opt_filterList;
184
    vector<string> opt_fileNames;
185

    
186
    // parse options
187
    bool endOpts = false;
188
    for (int i=2; i<argc; i++)
189
    {
190
        const char *opt = argv[i];
191
        if (endOpts)
192
            opt_fileNames.push_back(argv[i]);
193
        else if (!strcmp(opt, "--"))
194
            endOpts = true;
195
        else if (!strcmp(opt, "-p") && i!=argc-1)
196
            opt_filterExpression = unquoteString(argv[++i]);
197
        else if (!strcmp(opt, "-a") && i!=argc-1)
198
            opt_filterList.push_back(argv[++i]);
199
        else if (!strcmp(opt, "-O") && i!=argc-1)
200
            opt_outputFileName = argv[++i];
201
        else if (!strcmp(opt, "-F") && i!=argc-1)
202
            opt_outputFormat = argv[++i];
203
        else if (!strcmp(opt, "-V"))
204
            opt_verbose = true;
205
        else if (opt[0] != '-')
206
            opt_fileNames.push_back(argv[i]);
207
        else if (!strcmp(opt, "-r") && i!=argc-1) // for testing only
208
            opt_readerNodeType = argv[++i];
209
        else
210
            {fprintf(stderr, "unknown option `%s'", opt);return 1;}
211
    }
212

    
213
    bool opt_writeSeparateFiles = false;
214
    if (opt_outputFormat.find("split") == 0)
215
    {
216
        opt_outputFormat = opt_outputFormat.substr(5);
217
        opt_writeSeparateFiles = true;
218
    }
219

    
220
    try
221
    {
222
        // load files
223
        ResultFileManager resultFileManager;
224
        loadFiles(resultFileManager, opt_fileNames, opt_verbose);
225

    
226
        // filter statistics
227
        IDList vectorIDList = resultFileManager.filterIDList(resultFileManager.getAllVectors(), opt_filterExpression.c_str());
228

    
229
        if (opt_verbose) printf("filter expression matches %d vectors\n", vectorIDList.size());
230
        if (opt_verbose) printf("done collecting inputs\n\n");
231

    
232
        //
233
        // assemble dataflow network for vectors
234
        //
235
        DataflowManager dataflowManager;
236
        NodeTypeRegistry *registry = NodeTypeRegistry::getInstance();
237

    
238
        // create filereader for each vector file
239
        if (opt_verbose) printf("creating vector file reader(s)\n");
240
        ResultFileList& filteredVectorFileList = *resultFileManager.getUniqueFiles(vectorIDList); //FIXME delete after done?
241
        map<ResultFile*, Node*> vectorFileReaders;
242
        NodeType *readerNodeType = registry->getNodeType(opt_readerNodeType.c_str());
243
        if (!readerNodeType)
244
        {
245
            fprintf(stdout, "There is no node type %s in the registry\n", opt_readerNodeType.c_str());
246
            return 1;
247
        }
248

    
249
        // create reader nodes
250
        StringMap attrs;
251
        for (int i=0; i<(int)filteredVectorFileList.size(); i++)
252
        {
253
            ResultFile *resultFile = filteredVectorFileList[i];
254
            attrs["filename"] = resultFile->fileSystemFilePath;
255
            Node *readerNode = readerNodeType->create(&dataflowManager, attrs);
256
            vectorFileReaders[resultFile] = readerNode;
257
        }
258

    
259
        // create writer node, if each vector is written into the same file
260
        VectorFileWriterNode *vectorFileWriterNode = NULL;
261

    
262
        vector<ArrayBuilderNode*> arrayBuilders; // for exporting
263

    
264
        for (int i=0; i<vectorIDList.size(); i++)
265
        {
266
            // create a port for each vector on its reader node
267
            char portName[30];
268
            const VectorResult& vector = resultFileManager.getVector(vectorIDList.get(i));
269
            assert(vectorFileReaders.find(vector.fileRunRef->fileRef) != vectorFileReaders.end());
270
            sprintf(portName, "%d", vector.vectorId);
271
            Node *readerNode = vectorFileReaders[vector.fileRunRef->fileRef];
272
            Port *outPort = readerNodeType->getPort(readerNode, portName);
273

    
274
            // add filters
275
            for (int k=0; k<(int)opt_filterList.size(); k++)
276
            {
277
                //TODO support filter to merge all into a single vector
278
                if (opt_verbose) printf("adding filter to vector: %s\n", opt_filterList[k].c_str());
279
                Node *node = registry->createNode(opt_filterList[k].c_str(), &dataflowManager);
280
                FilterNode *filterNode = dynamic_cast<FilterNode *>(node);
281
                if (!filterNode)
282
                    throw opp_runtime_error("%s is not a filter node", opt_filterList[k].c_str());
283
                dataflowManager.connect(outPort, &(filterNode->in));
284
                outPort = &(filterNode->out);
285
            }
286

    
287
            // create writer getNode(s) and connect
288
            if (opt_outputFormat == "vec")
289
            {
290
                if (opt_writeSeparateFiles)
291
                {
292
                    // every vector goes to its own file, with two columns (time+value) separated by spaces/tab
293
                    if (opt_verbose) printf("adding separate writers for each vector\n");
294
                    char buf[16];
295
                    sprintf(buf, "%d", i);
296
                    string fname = opt_outputFileName+buf+".vec";
297

    
298
                    stringstream header;
299
                    header << "# vector " << vector.vectorId << " " <<
300
                              QUOTE(vector.moduleNameRef->c_str()) << " " <<
301
                              QUOTE(vector.nameRef->c_str()) << "\n";
302
                    header << "# file generated by scavetool\n";
303

    
304
                    FileWriterNode *writerNode = new FileWriterNode(fname.c_str(), header.str().c_str());
305
                    dataflowManager.addNode(writerNode);
306
                    dataflowManager.connect(outPort, &(writerNode->in));
307
                }
308
                else {
309
                    // everything goes to a common vector file
310
                    if (!vectorFileWriterNode)
311
                    {
312
                        if (opt_verbose) printf("adding vector file writer\n");
313
                        string fileName = opt_outputFileName + ".vec";
314
                        vectorFileWriterNode = new VectorFileWriterNode(fileName.c_str(), "# generated by scavetool");
315
                        dataflowManager.addNode(vectorFileWriterNode);
316
                    }
317

    
318
                    Port *writerNodePort = vectorFileWriterNode->addVector(vector); // FIXME: renumber vectors
319
                    dataflowManager.connect(outPort, writerNodePort);
320
                }
321
            }
322
            else
323
            {
324
                // for Octave, we must build arrays
325
                if (opt_verbose) printf("adding array builders for Octave output\n");
326
                ArrayBuilderNode *arrayBuilderNode = new ArrayBuilderNode();
327
                dataflowManager.addNode(arrayBuilderNode);
328
                dataflowManager.connect(outPort, &(arrayBuilderNode->in));
329
                arrayBuilders.push_back(arrayBuilderNode);
330
            }
331
        }
332

    
333
        // run!
334
        if (opt_verbose) printf("running dataflow network...\n");
335
        dataflowManager.execute();
336

    
337
        if (opt_outputFormat != "vec")
338
        {
339
            ScaveExport *exporter = ExporterFactory::createExporter(opt_outputFormat);
340
            if (exporter)
341
            {
342
                try
343
                {
344
                    exporter->setBaseFileName(opt_outputFileName);
345
                    if (opt_writeSeparateFiles)
346
                    {
347
                        // separate vectors
348
                        for (int i=0; i<vectorIDList.size(); i++)
349
                        {
350
                            ID vectorID = vectorIDList.get(i);
351
                            bool computed = opt_filterList.size() > 0;
352
                            const VectorResult& vector = resultFileManager.getVector(vectorID);
353
                            string name = *vector.nameRef;
354
                            string descr = *vector.nameRef + "; "
355
                                              + *vector.moduleNameRef + "; "
356
                                              + vector.fileRunRef->fileRef->fileSystemFilePath + "; "
357
                                              + vector.fileRunRef->runRef->runName;
358
                            XYArray *xyArray = arrayBuilders[i]->getArray();
359
                            exporter->saveVector(name, descr, vectorID, computed, xyArray, resultFileManager);
360
                            delete xyArray;
361
                        }
362
                    }
363
                    else // same file
364
                    {
365
                        if (vectorIDList.size() > 0)
366
                        {
367
                            // all vectors in one file
368
                            vector<XYArray*> xyArrays;
369
                            for (int i=0; i<vectorIDList.size(); i++)
370
                                xyArrays.push_back(arrayBuilders[i]->getArray());
371

    
372
                            string desc = "generated by '" + rebuildCommandLine(argc, argv) + "'";
373
                            exporter->saveVectors("vectors", desc, vectorIDList, xyArrays, resultFileManager);
374

    
375
                            for (int i = 0; i < vectorIDList.size(); i++)
376
                                delete arrayBuilders[i]->getArray();
377
                        }
378
                    }
379

    
380
                    delete exporter;
381
                }
382
                catch (exception&)
383
                {
384
                    delete exporter;
385
                    throw;
386
                }
387
            }
388
            else
389
            {
390
                fprintf(stdout, "Unknown output file format: %s\n", opt_outputFormat.c_str());
391
                return 1;
392
            }
393
        }
394

    
395
        if (opt_verbose) printf("done\n");
396
    }
397
    catch (exception& e)
398
    {
399
        fprintf(stdout, "Exception: %s\n", e.what());
400
        return 1;
401
    }
402

    
403
    return 0;
404
}
405

    
406
static void parseScalarFunction(const string &functionCall, /*out*/string &name, /*out*/ vector<string> &params)
407
{
408
    params.clear();
409
    string::size_type paren = functionCall.find('(');
410
    if (paren == string::npos) {
411
        // no left paren -- treat the whole string as function name
412
        name = functionCall;
413
        return;
414
    }
415

    
416
    // check that string ends in right paren
417
    string::size_type size = functionCall.length();
418
    if (functionCall[size-1]!=')')
419
        throw opp_runtime_error("syntax error in filter spec `%s'", functionCall.c_str());
420

    
421
    // filter name is the part before the left paren
422
    name.assign(functionCall, 0, paren);
423

    
424
    // param list is the part between the parens -- split it up along commas
425
    string paramlist(functionCall, paren+1, size-paren-2);
426
    LineTokenizer tokenizer(paramlist.length()+1, 100, ',', ',');
427
    tokenizer.tokenize(paramlist.c_str(), paramlist.length());
428
    char **tokens = tokenizer.tokens();
429
    for (int i = 0; i < tokenizer.numTokens(); ++i)
430
        params.push_back(unquoteString(tokens[i]));
431
}
432

    
433
int scalarCommand(int argc, char **argv)
434
{
435
    // options
436
    bool opt_verbose = false;
437
    string opt_filterExpression;
438
    string opt_outputFileName = "_out_";
439
    string opt_outputFormat = "csv";
440
    string opt_applyFunction;
441
    vector<string> opt_fileNames;
442

    
443
    // parse options
444
    bool endOpts = false;
445
    for (int i=2; i<argc; i++)
446
    {
447
        const char *opt = argv[i];
448
        if (endOpts)
449
            opt_fileNames.push_back(argv[i]);
450
        else if (!strcmp(opt, "--"))
451
            endOpts = true;
452
        else if (!strcmp(opt, "-p") && i!=argc-1)
453
            opt_filterExpression = unquoteString(argv[++i]);
454
        else if (!strcmp(opt, "-a") && i!=argc-1)
455
            opt_applyFunction = unquoteString(argv[++i]);
456
        else if (!strcmp(opt, "-O") && i!=argc-1)
457
            opt_outputFileName = argv[++i];
458
        else if (!strcmp(opt, "-F") && i!=argc-1)
459
            opt_outputFormat = argv[++i];
460
        else if (!strcmp(opt, "-V"))
461
            opt_verbose = true;
462
        else if (opt[0] != '-')
463
            opt_fileNames.push_back(argv[i]);
464
        else
465
            {cerr << "unknown option `" << opt << "'" << endl; return 1;}
466
    }
467

    
468
    int rc = 0;
469

    
470
    try
471
    {
472
        // load files
473
        ResultFileManager resultFileManager;
474
        loadFiles(resultFileManager, opt_fileNames, opt_verbose);
475

    
476
        // filter scalars
477
        IDList scalarIDList = resultFileManager.filterIDList(resultFileManager.getAllScalars(), opt_filterExpression.c_str());
478
        if (opt_verbose) cout << "filter expression matches " << scalarIDList.size() << "scalars" << endl;
479
        if (opt_verbose) cout << "done collecting inputs" << endl << endl;
480

    
481
        if (!scalarIDList.isEmpty())
482
        {
483
            ScaveExport *exporter = ExporterFactory::createExporter(opt_outputFormat);
484
            if (exporter)
485
            {
486
                try
487
                {
488
                    exporter->setBaseFileName(opt_outputFileName);
489
                    string desc = "generated by '" + rebuildCommandLine(argc, argv) + "'";
490

    
491
                    if (opt_applyFunction.empty())
492
                    {
493
                        ResultItemFields fields(ResultItemField::NAME); // TODO option
494
                        // TODO option to choose columns (allow averaging in cells)
495
                        exporter->saveScalars("scalars", desc, scalarIDList,
496
                            fields.complement(), resultFileManager);
497
                    }
498
                    else
499
                    {
500
                        string function;
501
                        vector<string> params;
502
                        parseScalarFunction(opt_applyFunction, function, params);
503
                        if (function == "scatter")
504
                        {
505
                            if (params.size() >= 2)
506
                            {
507
                                string moduleName = params[0];
508
                                string scalarName = params[1];
509
                                vector<string> rowFields;
510
                                rowFields.push_back(ResultItemField::MODULE);
511
                                rowFields.push_back(ResultItemField::NAME);
512
                                vector<string> isoModuleNames;
513
                                vector<string> isoScalarNames;
514
                                vector<string> isoRunAttributes;
515
                                for (vector<string>::iterator param = params.begin()+2; param != params.end(); ++param)
516
                                {
517
                                    if (RunAttribute::isAttributeName(*param))
518
                                    {
519
                                        isoRunAttributes.push_back(*param);
520
                                    }
521
                                    else
522
                                    {
523
                                        if ((param+1) == params.end())
524
                                        {
525
                                            cout << "Missing scalar name after '" << *param << "'" << endl;
526
                                            rc = 1;
527
                                            break;
528
                                        }
529
                                        isoModuleNames.push_back(*param);
530
                                        isoScalarNames.push_back(*++param);
531
                                    }
532
                                }
533

    
534
                                if (rc == 0)
535
                                {
536
                                    exporter->saveScalars("scalars", desc, scalarIDList,
537
                                        moduleName, scalarName, ResultItemFields(rowFields).complement(),
538
                                        isoModuleNames, isoScalarNames, ResultItemFields(isoRunAttributes),
539
                                        resultFileManager);
540
                                }
541
                            }
542
                            else
543
                            {
544
                                cout << "Missing parameters in: " << opt_applyFunction << endl;
545
                                rc = 1;
546
                            }
547
                        }
548
                        else
549
                        {
550
                            cout << "Unknown scalar function: " << function << endl;
551
                            rc = 1;
552
                        }
553
                    }
554

    
555
                    delete exporter;
556
                }
557
                catch (exception&)
558
                {
559
                    delete exporter;
560
                    throw;
561
                }
562
            }
563
            else
564
            {
565
                cout << "Unknown output file format: " << opt_outputFormat << endl;
566
                rc = 1;
567
            }
568
        }
569

    
570
        if (opt_verbose && rc == 0) cout << "done" << endl;
571
    }
572
    catch (exception& e)
573
    {
574
        cout << "Exception: " << e.what() << endl;
575
        rc = 1;
576
    }
577

    
578
    return rc;
579
}
580

    
581

    
582
//TODO allow filtering by patterns here too?
583
//TODO specifying more than one flag should list tuples e.g. (module,statistic) pairs
584
// occurring in the input files
585
int listCommand(int argc, char **argv)
586
{
587
    bool opt_name = false;
588
    bool opt_module = false;
589
    bool opt_run = false;
590
    bool opt_config = false;
591
    int count = 0;
592
    vector<string> opt_fileNames;
593

    
594
    for (int i=2; i<argc; i++)
595
    {
596
        const char *opt = argv[i];
597
        if (opt[0] == '-')
598
            count++;
599
        if (strcmp(opt, "-n") == 0)
600
            opt_name = true;
601
        else if (strcmp(opt, "-m") == 0)
602
            opt_module = true;
603
        else if (strcmp(opt, "-r") == 0)
604
            opt_run = true;
605
        else if (strcmp(opt, "-c") == 0)
606
            opt_config = true;
607
        else if (opt[0] != '-')
608
            opt_fileNames.push_back(argv[i]);
609
        else
610
            {fprintf(stderr, "unknown option `%s'", opt);return 1;}
611
    }
612
    if (count == 0)
613
        opt_name = true;
614
    else if (count > 1)
615
    {
616
        fprintf(stderr, "expects only one option");
617
        return 1;
618
    }
619

    
620
    ResultFileManager manager;
621
    loadFiles(manager, opt_fileNames, false);
622

    
623
    StringSet *result = NULL;
624
    if (opt_name)
625
    {
626
        IDList ids = manager.getAllItems();
627
        result = manager.getUniqueNames(ids);
628
    }
629
    else if (opt_module)
630
    {
631
        IDList ids = manager.getAllItems();
632
        result = manager.getUniqueModuleNames(ids);
633
    }
634
    else if (opt_run)
635
    {
636
        const RunList &runs = manager.getRuns();
637
        result = new StringSet;
638
        for (RunList::const_iterator it=runs.begin(); it!=runs.end(); ++it)
639
        {
640
            result->insert((*it)->runName);
641
        }
642
    }
643
    else if (opt_config)
644
    {
645
        const RunList &runs = manager.getRuns();
646
        result = manager.getUniqueRunAttributeValues(runs, RunAttribute::CONFIGNAME);
647
    }
648

    
649
    if (result != NULL)
650
    {
651
        for (StringSet::iterator it=result->begin(); it != result->end(); ++it)
652
        {
653
            printf("%s\n", it->c_str());
654
        }
655
        delete result;
656
    }
657

    
658
    return 0;
659
}
660

    
661
int infoCommand(int argc, char **argv)
662
{
663
    // process args
664
    bool opt_brief = false;
665
    bool opt_summary = false;
666
    for (int i=2; i<argc; i++)
667
    {
668
        const char *opt = argv[i];
669
        if (!strcmp(opt, "-b"))
670
            opt_brief = true;
671
        else if (!strcmp(opt, "-s"))
672
            opt_summary = true;
673
        else if (!strcmp(opt, "-v"))
674
            ; // no-op
675
        else
676
            {fprintf(stderr, "unknown option `%s'", opt);return 1;}
677
    }
678

    
679
    printf("\nScalar operations:\n\n");
680
    printf("scatter(module,scalar,...):\n"
681
           "  Create scatter plot. The first two arguments identifys the scalar selected\n"
682
           "  for the X axis. Additional arguments identify the iso attributes; they are\n"
683
           "  (module, scalar) pairs, or names of run attributes.\n");
684

    
685
    printf("\nVector operations:\n\n");
686
    NodeTypeRegistry *registry = NodeTypeRegistry::getInstance();
687
    NodeTypeVector nodeTypes = registry->getNodeTypes();
688
    for (int i=0; i<(int)nodeTypes.size(); i++)
689
    {
690
        NodeType *nodeType = nodeTypes[i];
691
        if (nodeType->isHidden())
692
            continue;
693

    
694
        if (opt_brief)
695
        {
696
            // this is the -b format
697
            printf("%s\n", nodeType->getName());
698
        }
699
        else
700
        {
701
            // print name(parameters,...)
702
            printf("%s", nodeType->getName());
703
            StringMap attrs, attrDefaults;
704
            nodeType->getAttributes(attrs);
705
            nodeType->getAttrDefaults(attrDefaults);
706
            printf("(");
707
            for (StringMap::iterator it=attrs.begin(); it!=attrs.end(); ++it)
708
            {
709
                if (it!=attrs.begin()) printf(",");
710
                printf("%s", it->first.c_str());
711
            }
712
            printf(")");
713

    
714
            if (opt_summary)
715
            {
716
                printf("\n");
717
            }
718
            else
719
            {
720
                // print filter description and parameter descriptions
721
                printf(":\n%s\n", opp_indentlines(opp_breaklines(nodeType->getDescription(),76).c_str(),"  ").c_str());
722
                for (StringMap::iterator it=attrs.begin(); it!=attrs.end(); ++it)
723
                {
724
                    printf("    - %s: %s\n", it->first.c_str(), it->second.c_str());
725
                }
726
                printf("\n");
727
            }
728
        }
729
    }
730
    return 0;
731
}
732

    
733
int indexCommand(int argc, char **argv)
734
{
735
    // process args
736
    bool opt_verbose = false;
737
    bool opt_rebuild = false;
738
    vector<string> opt_fileNames;
739
    for (int i=2; i<argc; i++)
740
    {
741
        const char *opt = argv[i];
742
        if (strcmp(opt, "-V") == 0)
743
            opt_verbose = true;
744
        else if (strcmp(opt, "-r") == 0)
745
            opt_rebuild = true;
746
        else if (opt[0] != '-')
747
            opt_fileNames.push_back(argv[i]);
748
        else
749
            {fprintf(stderr, "unknown option `%s'", opt);return 1;}
750
    }
751

    
752
    VectorFileIndexer indexer;
753
    int rc=0;
754
    for (int i=0; i<(int)opt_fileNames.size(); i++)
755
    {
756
        const char *fileName = opt_fileNames[i].c_str();
757
        if (opt_verbose) printf("indexing %s...\n", fileName);
758
        try
759
        {
760
            if (opt_rebuild)
761
                indexer.rebuildVectorFile(fileName);
762
            else
763
                indexer.generateIndex(fileName);
764
        }
765
        catch (exception& e) {
766
            fprintf(stderr, "Exception: %s\n", e.what());
767
            rc=1;
768
        }
769
    }
770

    
771
    if (opt_verbose) printf("done\n");
772

    
773
    return rc;
774
}
775

    
776
int main(int argc, char **argv)
777
{
778
    if (argc<2)
779
    {
780
        printUsage();
781
        exit(0);
782
    }
783

    
784
    const char *command = argv[1];
785
    if (!strcmp(command, "v") || !strcmp(command, "vector"))
786
        return vectorCommand(argc, argv);
787
    else if (!strcmp(command, "s") || !strcmp(command, "scalar"))
788
        return scalarCommand(argc, argv);
789
    else if (!strcmp(command, "l") || !strcmp(command, "list"))
790
        return listCommand(argc, argv);
791
    else if (!strcmp(command, "i") || !strcmp(command, "info"))
792
        return infoCommand(argc, argv);
793
    else if (!strcmp(command, "x") || !strcmp(command, "index"))
794
        return indexCommand(argc, argv);
795
    else
796
        {fprintf(stderr, "unknown command `%s'", command);return 1;}
797
}
798

    
799