Statistics
| Branch: | Revision:

root / src / scave / vectorfilereader.cc @ e1750c09

History | View | Annotate | Download (6.89 KB)

1
//=========================================================================
2
//  VECTORFILEREADER.CC - part of
3
//                  OMNeT++/OMNEST
4
//           Discrete System Simulation in C++
5
//
6
//  Author: Andras Varga
7
//
8
//=========================================================================
9

    
10
/*--------------------------------------------------------------*
11
  Copyright (C) 1992-2008 Andras Varga
12
  Copyright (C) 2006-2008 OpenSim Ltd.
13

14
  This file is distributed WITHOUT ANY WARRANTY. See the file
15
  `license' for details on this and other legal matters.
16
*--------------------------------------------------------------*/
17

    
18
#include <string.h>
19
#include <stdlib.h>
20
#include "opp_ctype.h"
21
#include "channel.h"
22
#include "scaveutils.h"
23
#include "scaveexception.h"
24
#include "vectorfilereader.h"
25

    
26
NAMESPACE_BEGIN
27

    
28
using namespace std;
29

    
30

    
31
VectorFileReaderNode::VectorFileReaderNode(const char *fileName, size_t bufferSize) :
32
  ReaderNode(fileName, bufferSize), fFinished(false)
33
{
34
}
35

    
36
VectorFileReaderNode::~VectorFileReaderNode()
37
{
38
}
39

    
40
Port *VectorFileReaderNode::addVector(const VectorResult &vector)
41
{
42
    PortVector& portvec = ports[vector.vectorId];
43
    portvec.push_back(Port(this));
44
    Port& port = portvec.back();
45
    return &port;
46
}
47

    
48
bool VectorFileReaderNode::isReady() const
49
{
50
    return true;
51
}
52

    
53
/**
54
 * Parses columns of one line in the vector file.
55
 */
56
Datum parseColumns(char **tokens, int numtokens, const string &columns, const char *file, int64 lineno, file_offset_t offset)
57
{
58
    Datum a;
59
    int colno = columns.size();
60

    
61
    if (colno > numtokens - 1)
62
        throw ResultFileFormatException("invalid vector file syntax: missing columns", file, lineno, offset);
63
    if (numtokens - 1 > colno)
64
        throw ResultFileFormatException("invalid vector file syntax: extra columns", file, lineno, offset);
65

    
66
    // optimization:
67
    //   first process the two most common case, then the general case
68

    
69
    if (colno == 2 && columns[0] == 'T' && columns[1] == 'V')
70
    {
71
        // parse time and value
72
        if (!parseSimtime(tokens[1],a.xp) || !parseDouble(tokens[2],a.y))
73
            throw ResultFileFormatException("invalid vector file syntax: invalid time or value column", file, lineno, offset);
74
        a.eventNumber = -1;
75
        a.x = a.xp.dbl();
76
    }
77
    else if (colno == 3 && columns[0] == 'E' && columns[1] == 'T' && columns[2] == 'V')
78
    {
79
        // parse event number, time and value
80
        if (!parseInt64(tokens[1], a.eventNumber) || !parseSimtime(tokens[2],a.xp) || !parseDouble(tokens[3],a.y))
81
            throw ResultFileFormatException("invalid vector file syntax: invalid event number, time or value column", file, lineno, offset);
82
        a.x = a.xp.dbl();
83
    }
84
    else // interpret general case
85
    {
86
        a.eventNumber = -1;
87
        for (int i = 0; i < (int)columns.size(); ++i)
88
        {
89
            switch (columns[i])
90
            {
91
            case 'E':
92
                if (!parseInt64(tokens[i+1], a.eventNumber))
93
                    throw ResultFileFormatException("invalid vector file syntax: invalid event number", file, lineno, offset);
94
                break;
95
            case 'T':
96
                if (!parseSimtime(tokens[i+1], a.xp))
97
                    throw ResultFileFormatException("invalid vector file syntax: invalid time", file, lineno, offset);
98
                a.x = a.xp.dbl();
99
                break;
100
            case 'V':
101
                if (!parseDouble(tokens[i+1], a.y))
102
                    throw ResultFileFormatException("invalid vector file syntax: invalid value", file, lineno, offset);
103
                break;
104
            default:
105
                throw ResultFileFormatException("invalid vector file syntax: unknown column type", file, lineno, offset);
106
            }
107
        }
108
    }
109

    
110
    return a;
111
}
112

    
113
#ifdef CHECK
114
#undef CHECK
115
#endif
116
#define CHECK(cond,msg) if (!(cond)) { throw ResultFileFormatException("vector file reader" msg, file, lineNo); }
117

    
118
void VectorFileReaderNode::process()
119
{
120
    const char *file = filename.c_str();
121
    char *line;
122
    for (int k=0; k<1000 && (line=reader.getNextLineBufferPointer())!=NULL; k++)
123
    {
124
        int64 lineNo = reader.getNumReadLines();
125
        int length = reader.getCurrentLineLength();
126
        tokenizer.tokenize(line, length);
127

    
128
        int numtokens = tokenizer.numTokens();
129
        char **vec = tokenizer.tokens();
130

    
131
        if (vec[0][0] == 'v' && strcmp(vec[0], "vector") == 0)
132
        {
133
            CHECK(numtokens >= 4, "broken vector declaration");
134

    
135
            int vectorId;
136
            CHECK(parseInt(vec[1], vectorId), "malformed vector in vector declaration");
137
            if (ports.find(vectorId) != ports.end())
138
                columns[vectorId] = (numtokens < 5 || opp_isdigit(vec[4][0]) ? "TV" : vec[4]);
139
        }
140
        else if (vec[0][0] == 'v' && strcmp(vec[0], "version") == 0)
141
        {
142
            int version;
143
            CHECK(numtokens >= 2, "missing version number");
144
            CHECK(parseInt(vec[1], version), "version is not a number");
145
            CHECK(version <= 2, "expects version 2 or lower");
146
        }
147
        else if (numtokens>=3 && opp_isdigit(vec[0][0]))  // silently ignore incomplete lines
148
        {
149
            // extract vector id
150
            int vectorId;
151
            CHECK(parseInt(vec[0], vectorId), "invalid vector id column");
152

    
153
            Portmap::iterator portvec = ports.find(vectorId);
154
            if (portvec!=ports.end())
155
            {
156
                ColumnMap::iterator columnSpec = columns.find(vectorId);
157
                CHECK(columnSpec != columns.end(), "missing vector declaration");
158

    
159
                // parse columns
160
                Datum a = parseColumns(vec, numtokens, columnSpec->second, file, lineNo, -1);
161

    
162
                // write to port(s)
163
                for (PortVector::iterator p=portvec->second.begin(); p!=portvec->second.end(); ++p)
164
                    p->getChannel()->write(&a,1);
165

    
166
                //DBG(("vectorfilereader: written id=%d (%"LL"d,%g,%g)\n", vectorId, a.eventNumber, a.x, a.y));
167
            }
168
        }
169
    }
170

    
171
    if (line == NULL) {
172
        fFinished = true;
173
    }
174
}
175

    
176
bool VectorFileReaderNode::isFinished() const
177
{
178
    return fFinished;
179
}
180

    
181
//-----
182

    
183
const char *VectorFileReaderNodeType::getDescription() const
184
{
185
    return "Reads output vector files.";
186
}
187

    
188
void VectorFileReaderNodeType::getAttributes(StringMap& attrs) const
189
{
190
    attrs["filename"] = "name of the output vector file (.vec)";
191
}
192

    
193
Node *VectorFileReaderNodeType::create(DataflowManager *mgr, StringMap& attrs) const
194
{
195
    checkAttrNames(attrs);
196

    
197
    const char *fname = attrs["filename"].c_str();
198

    
199
    Node *node = new VectorFileReaderNode(fname);
200
    node->setNodeType(this);
201
    mgr->addNode(node);
202
    return node;
203
}
204

    
205
Port *VectorFileReaderNodeType::getPort(Node *node, const char *portname) const
206
{
207
    // vector id is used as port name
208
    VectorFileReaderNode *node1 = dynamic_cast<VectorFileReaderNode *>(node);
209
    VectorResult vector;
210
    vector.vectorId = atoi(portname);  // FIXME check it's numeric at all
211
    return node1->addVector(vector);
212
}
213

    
214
NAMESPACE_END
215

    
216