Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cdisplaystring.cc @ a3be1d55

History | View | Annotate | Download (13 KB)

1 01873262 Georg Kunz
//==========================================================================
2
//   CDISPLAYSTRING.CC  - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//
7
//==========================================================================
8
9
/*--------------------------------------------------------------*
10
  Copyright (C) 1992-2008 Andras Varga
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 <string.h>
18
#include <stdio.h>
19
#include "opp_ctype.h"
20
#include "cenvir.h"
21
#include "cmodule.h"
22
#include "cchannel.h"
23
#include "cgate.h"
24
#include "cdisplaystring.h"
25
#include "stringutil.h"
26
#include "cmodelchange.h"
27
28
USING_NAMESPACE
29
30
31
cDisplayString::cDisplayString()
32
{
33
    dispstr = NULL;
34
    buffer = NULL;
35
    bufferend = NULL;
36
    tags = NULL;
37
    numtags = 0;
38
    needsassemble = false;
39
40
    ownercomponent = NULL;
41
}
42
43
44
cDisplayString::cDisplayString(const char *displaystr)
45
{
46
    dispstr = opp_strdup(displaystr);
47
    buffer = NULL;
48
    bufferend = NULL;
49
    tags = NULL;
50
    numtags = 0;
51
    needsassemble = false;
52
53
    ownercomponent = NULL;
54
55
    // doParse() should be the last one, as it may throw an error
56
    doParse();
57
}
58
59
cDisplayString::cDisplayString(const cDisplayString& ds)
60
{
61
    dispstr = NULL;
62
    buffer = NULL;
63
    bufferend = NULL;
64
    tags = NULL;
65
    numtags = 0;
66
    needsassemble = false;
67
68
    ownercomponent = NULL;
69
70
    operator=(ds);
71
}
72
73
cDisplayString::~cDisplayString()
74
{
75
    delete [] dispstr;
76
    clearTags();
77
}
78
79
void cDisplayString::beforeChange()
80
{
81
    // notify pre-change listeners
82
    if (ownercomponent && ownercomponent->hasListeners(PRE_MODEL_CHANGE)) {
83
        cPreDisplayStringChangeNotification tmp;
84
        tmp.displayString = this;
85
        ownercomponent->emit(PRE_MODEL_CHANGE, &tmp);
86
    }
87
}
88
89
void cDisplayString::afterChange()
90
{
91
    needsassemble = true;
92
    EVCB.displayStringChanged(ownercomponent);
93
94
    // notify post-change listeners
95
    if (ownercomponent && ownercomponent->hasListeners(POST_MODEL_CHANGE)) {
96
        cPostDisplayStringChangeNotification tmp;
97
        tmp.displayString = this;
98
        ownercomponent->emit(POST_MODEL_CHANGE, &tmp);
99
    }
100
}
101
102
const char *cDisplayString::str() const
103
{
104
    if (needsassemble)
105
        assemble();
106
    return dispstr ? dispstr : "";
107
}
108
109
void cDisplayString::parse(const char *displaystr)
110
{
111
    beforeChange();
112
    doParse(displaystr);
113
    afterChange();
114
}
115
116
void cDisplayString::doParse(const char *displaystr)
117
{
118
    // if it's the same, nothing to do
119
    if (needsassemble)
120
        assemble();
121
    if (!opp_strcmp(dispstr,displaystr))
122
        return;
123
124
    // parse and store new string
125
    delete [] dispstr;
126
    clearTags();
127
    dispstr = opp_strdup(displaystr);
128
    doParse();
129
}
130
131
void cDisplayString::updateWith(const char *s)
132
{
133
    cDisplayString ds(s);
134
    updateWith(ds);
135
}
136
137
void cDisplayString::updateWith(const cDisplayString& ds)
138
{
139
    beforeChange();
140
    doUpdateWith(ds);
141
    afterChange();
142
}
143
144
void cDisplayString::doUpdateWith(const cDisplayString& ds)
145
{
146
    // elements in "ds" take precedence
147
    int n = ds.getNumTags();
148
    for (int i=0; i<n; i++)
149
    {
150
        int m = ds.getNumArgs(i);
151
        for (int j=0; j<m; j++)
152
        {
153
            const char *arg = ds.getTagArg(i,j);
154
            if (arg[0]=='-' && !arg[1])  // "-" is the "antivalue"
155
                doSetTagArg(ds.getTagName(i), j, "");
156
            else if (arg[0])
157
                doSetTagArg(ds.getTagName(i), j, arg);
158
        }
159
    }
160
161
    // optimize storage
162
    doParse(str());
163
}
164
165
bool cDisplayString::containsTag(const char *tagname) const
166
{
167
    int t = getTagIndex(tagname);
168
    return t!=-1;
169
}
170
171
int cDisplayString::getNumArgs(const char *tagname) const
172
{
173
    return getNumArgs(getTagIndex(tagname));
174
}
175
176
const char *cDisplayString::getTagArg(const char *tagname, int index) const
177
{
178
    return getTagArg(getTagIndex(tagname), index);
179
}
180
181
bool cDisplayString::setTagArg(const char *tagname, int index, long value)
182
{
183
    char buf[32];
184
    sprintf(buf, "%ld", value);
185
    return setTagArg(tagname, index, buf);
186
}
187
188
bool cDisplayString::setTagArg(const char *tagname, int index, const char *value)
189
{
190
    beforeChange();
191
    bool result = doSetTagArg(tagname, index, value);
192
    afterChange();
193
    return result;
194
}
195
196
bool cDisplayString::doSetTagArg(const char *tagname, int index, const char *value)
197
{
198
    int t = getTagIndex(tagname);
199
    if (t==-1)
200
        t = doInsertTag(tagname);
201
    return doSetTagArg(t, index, value);
202
}
203
204
bool cDisplayString::removeTag(const char *tagname)
205
{
206
    return removeTag(getTagIndex(tagname));
207
}
208
209
int cDisplayString::getNumTags() const
210
{
211
    return numtags;
212
}
213
214
const char *cDisplayString::getTagName(int tagindex) const
215
{
216
    if (tagindex<0 || tagindex>=numtags) return NULL;
217
    return tags[tagindex].name;
218
}
219
220
int cDisplayString::getNumArgs(int tagindex) const
221
{
222
    if (tagindex<0 || tagindex>=numtags) return -1;
223
    return tags[tagindex].numargs;
224
}
225
226
const char *cDisplayString::getTagArg(int tagindex, int index) const
227
{
228
    if (tagindex<0 || tagindex>=numtags) return "";
229
    if (index<0 || index>=tags[tagindex].numargs) return "";
230
    return opp_nulltoempty(tags[tagindex].args[index]);
231
}
232
233
bool cDisplayString::setTagArg(int tagindex, int index, const char *value)
234
{
235
    beforeChange();
236
    bool result = doSetTagArg(tagindex, index, value);
237
    afterChange();
238
    return result;
239
}
240
241
bool cDisplayString::doSetTagArg(int tagindex, int index, const char *value)
242
{
243
    // check indices
244
    if (tagindex<0 || tagindex>=numtags) return false;
245
    if (index<0 || index>=MAXARGS) return false;
246
    Tag& tag = tags[tagindex];
247
248
    // adjust numargs if necessary
249
    if (index>=tag.numargs)
250
        tag.numargs = index+1;
251
252
    // if it's the same, nothing to do
253
    char *&slot = tag.args[index];
254
    if (!opp_strcmp(slot,value))
255
        return true;
256
257
    // set value
258
    if (slot && !pointsIntoBuffer(slot))
259
        delete [] slot;
260
    slot = opp_strdup(value);
261
262
    // get rid of possible empty trailing args, throw out tag if it became empty
263
    while (tag.numargs>0 && tag.args[tag.numargs-1]==NULL)
264
        tag.numargs--;
265
    if (tag.numargs==0)
266
        doRemoveTag(tagindex);
267
    return true;
268
}
269
270
271
int cDisplayString::insertTag(const char *tagname, int atindex)
272
{
273
    beforeChange();
274
    int result = doInsertTag(tagname, atindex);
275
    afterChange();
276
    return result;
277
}
278
279
int cDisplayString::doInsertTag(const char *tagname, int atindex)
280
{
281
    // check name validity
282
    if (!tagname || !tagname[0])
283
        throw cRuntimeError("Error adding a new display string tag: tag name is empty");
284
    for (const char *s=tagname; *s; s++)
285
        if (!opp_isalnum(*s) && *s!=':')
286
            throw cRuntimeError("Error adding a new display string tag: tag name \"%s\" "
287
                                "contains invalid character", tagname);
288
289
    // check uniqueness
290
    int t = getTagIndex(tagname);
291
    if (t!=-1)
292
        return t;
293
294
    // check index
295
    if (atindex<0) atindex=0;
296
    if (atindex>numtags) atindex=numtags;
297
298
    // create new tags[] array with hole at atindex
299
    Tag *newtags = new Tag[numtags+1];
300
    for (int s=0,d=0; s<numtags; s++,d++)
301
    {
302
       if (d==atindex) d++; // make room for new item
303
       newtags[d] = tags[s];
304
    }
305
    delete [] tags;
306
    tags = newtags;
307
    numtags++;
308
309
    // fill in new tag
310
    tags[atindex].name = opp_strdup(tagname);
311
    tags[atindex].numargs = 0;
312
    for (int i=0; i<MAXARGS; i++) tags[atindex].args[i] = NULL;
313
314
    // success
315
    return atindex;
316
}
317
318
319
bool cDisplayString::removeTag(int tagindex)
320
{
321
    beforeChange();
322
    bool result = doRemoveTag(tagindex);
323
    afterChange();
324
    return result;
325
}
326
327
bool cDisplayString::doRemoveTag(int tagindex)
328
{
329
    if (tagindex<0 || tagindex>=numtags) return false;
330
331
    // dealloc strings in tag
332
    if (!pointsIntoBuffer(tags[tagindex].name))
333
        delete [] tags[tagindex].name;
334
    for (int i=0; i<tags[tagindex].numargs; i++)
335
        if (!pointsIntoBuffer(tags[tagindex].args[i]))
336
            delete [] tags[tagindex].args[i];
337
338
    // eliminate hole in tags[] array
339
    for (int t=tagindex; t<numtags-1; t++)
340
        tags[t] = tags[t+1];
341
    numtags--;
342
343
    // success
344
    return true;
345
}
346
347
348
int cDisplayString::getTagIndex(const char *tagname) const
349
{
350
    for (int t=0; t<numtags; t++)
351
        if (!strcmp(tagname,tags[t].name))
352
            return t;
353
    return -1;
354
}
355
356
void cDisplayString::clearTags()
357
{
358
    // delete tags array. string pointers that do not point inside the
359
    // buffer were allocated individually via new char[] and have to be
360
    // deleted.
361
    for (int t=0; t<numtags; t++)
362
    {
363
        if (!pointsIntoBuffer(tags[t].name))
364
            delete [] tags[t].name;
365
        for (int i=0; i<tags[t].numargs; i++)
366
            if (!pointsIntoBuffer(tags[t].args[i]))
367
                delete [] tags[t].args[i];
368
    }
369
    delete [] tags;
370
    tags = NULL;
371
    numtags = 0;
372
373
    // must be done after deleting tags[] because of pointsIntoBuffer()
374
    delete [] buffer;
375
    buffer = bufferend = NULL;
376
}
377
378
void cDisplayString::doParse()
379
{
380
    clearTags();
381
    if (dispstr==NULL)
382
        return;
383
384
    buffer = new char[opp_strlen(dispstr)+1];
385
    bufferend = buffer + opp_strlen(dispstr);
386
387
    // count tags (#(';')+1) & allocate tags[] array
388
    int n = 1;
389
    for (char *s1 = dispstr; *s1; s1++)
390
        if (*s1==';')
391
            n++;
392
    tags = new Tag[n];
393
394
    // parse string into tags[]. To avoid several small allocations,
395
    // pointers in tags[] will point into the buffer.
396
    numtags = 1;
397
    tags[0].name = buffer;
398
    tags[0].numargs = 0;
399
    for (int i=0; i<MAXARGS; i++)
400
        tags[0].args[i] = NULL;
401
402
    char *s, *d;
403
    for (s=dispstr,d=buffer; *s; s++,d++)
404
    {
405
        if (*s=='\\' && *(s+1))
406
        {
407
            // allow escaping display string special chars (=,;) with backslash.
408
            // No need to deal with "\t", "\n" etc here, since they already got
409
            // interpreted by opp_parsequotedstr().
410
            *d = *++s;
411
        }
412
        else if (*s==';')
413
        {
414
            // new tag begins
415
            *d = '\0';
416
            numtags++;
417
            tags[numtags-1].name = d+1;
418
            tags[numtags-1].numargs = 0;
419
            for (int i=0; i<MAXARGS; i++)
420
                tags[numtags-1].args[i] = NULL;
421
        }
422
        else if (*s=='=')
423
        {
424
            // first argument of new tag begins
425
            *d = '\0';
426
            tags[numtags-1].numargs = 1;
427
            tags[numtags-1].args[0] = d+1;
428
        }
429
        else if (*s==',')
430
        {
431
            // new argument of current tag begins
432
            *d = '\0';
433
            if (tags[numtags-1].numargs>=MAXARGS)
434
                throw cRuntimeError("Error parsing display string: too many parameters for a tag, "
435
                                    "max %d allowed in \"%s\"", MAXARGS, dispstr);
436
            tags[numtags-1].numargs++;
437
            tags[numtags-1].args[ tags[numtags-1].numargs-1 ] = d+1;
438
        }
439
        else
440
        {
441
            *d = *s;
442
        }
443
    }
444
    *d = '\0';
445
446
    // check tag names are OK (matching [a-zA-Z0-9:]+)
447
    for (int i=0; i<numtags; i++)
448
    {
449
        if (!tags[i].name[0]) {
450
            if (tags[i].numargs==0)
451
                ; // empty tag (occurs when there're redundant semicolons, or the display string is empty) -- XXX remove it
452
            else
453
                throw cRuntimeError("Error parsing display string: missing tag name in \"%s\"", dispstr);
454
        }
455
        for (const char *s=tags[i].name; *s; s++)
456
            if (!opp_isalnum(*s) && *s!=':')
457
                throw cRuntimeError("Error parsing display string: tag name \"%s\" contains invalid character in  \"%s\"", tags[i].name, dispstr);
458
    }
459
}
460
461
void cDisplayString::assemble() const
462
{
463
    // calculate length of display string
464
    int size = 0;
465
    for (int t0=0; t0<numtags; t0++)
466
    {
467
        size += opp_strlen(tags[t0].name)+2;
468
        for (int i=0; i<tags[t0].numargs; i++)
469
            size += opp_strlen(tags[t0].args[i])+1;
470
    }
471
    size = 2*size+1;  // 2* for worst case if every char has to be escaped
472
473
    // allocate display string
474
    delete [] dispstr;
475
    dispstr = new char[size];
476
    dispstr[0] = '\0';
477
478
    // assemble string
479
    for (int t=0; t<numtags; t++)
480
    {
481
        if (t!=0)
482
            strcat(dispstr, ";");
483
        strcatescaped(dispstr, tags[t].name);
484
        if (tags[t].numargs>0)
485
            strcat(dispstr, "=");
486
        for (int i=0; i<tags[t].numargs; i++)
487
        {
488
            if (i!=0) strcat(dispstr, ",");
489
            strcatescaped(dispstr, tags[t].args[i]);
490
        }
491
    }
492
    needsassemble = false;
493
}
494
495
void cDisplayString::strcatescaped(char *d, const char *s)
496
{
497
    if (!s) return;
498
499
    d += strlen(d);
500
    while (*s)
501
    {
502
        // quoting \t, \n etc is the job of opp_quotestr()
503
        if (*s==';' || *s==',' || *s=='=')
504
            *d++ = '\\';
505
        *d++ = *s++;
506
    }
507
    *d = '\0';
508
}
509
510
void cDisplayString::dump() const
511
{
512
    for (int t=0; t<numtags; t++)
513
    {
514
        if (t!=0) printf("; ");
515
        printf("tags[%d]:\"%s\"=", t, tags[t].name);
516
        for (int i=0; i<tags[t].numargs; i++)
517
        {
518
            if (i!=0) printf(",");
519
            printf("\"%s\"", tags[t].args[i]);
520
        }
521
    }
522
    printf(" ==> \"%s\"\n", str());
523
}