PageRenderTime 52ms CodeModel.GetById 19ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/omnetpp-4.1/src/sim/cdisplaystring.cc

https://bitbucket.org/indigopony/omnetproject
C++ | 524 lines | 398 code | 73 blank | 53 comment | 93 complexity | f94ec88ee696baa81e82fcbea0d7ba3a MD5 | raw file
  1//==========================================================================
  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
 28USING_NAMESPACE
 29
 30
 31cDisplayString::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
 44cDisplayString::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
 59cDisplayString::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
 73cDisplayString::~cDisplayString()
 74{
 75    delete [] dispstr;
 76    clearTags();
 77}
 78
 79void 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
 89void 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
102const char *cDisplayString::str() const
103{
104    if (needsassemble)
105        assemble();
106    return dispstr ? dispstr : "";
107}
108
109void cDisplayString::parse(const char *displaystr)
110{
111    beforeChange();
112    doParse(displaystr);
113    afterChange();
114}
115
116void 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
131void cDisplayString::updateWith(const char *s)
132{
133    cDisplayString ds(s);
134    updateWith(ds);
135}
136
137void cDisplayString::updateWith(const cDisplayString& ds)
138{
139    beforeChange();
140    doUpdateWith(ds);
141    afterChange();
142}
143
144void 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
165bool cDisplayString::containsTag(const char *tagname) const
166{
167    int t = getTagIndex(tagname);
168    return t!=-1;
169}
170
171int cDisplayString::getNumArgs(const char *tagname) const
172{
173    return getNumArgs(getTagIndex(tagname));
174}
175
176const char *cDisplayString::getTagArg(const char *tagname, int index) const
177{
178    return getTagArg(getTagIndex(tagname), index);
179}
180
181bool 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
188bool 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
196bool 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
204bool cDisplayString::removeTag(const char *tagname)
205{
206    return removeTag(getTagIndex(tagname));
207}
208
209int cDisplayString::getNumTags() const
210{
211    return numtags;
212}
213
214const char *cDisplayString::getTagName(int tagindex) const
215{
216    if (tagindex<0 || tagindex>=numtags) return NULL;
217    return tags[tagindex].name;
218}
219
220int cDisplayString::getNumArgs(int tagindex) const
221{
222    if (tagindex<0 || tagindex>=numtags) return -1;
223    return tags[tagindex].numargs;
224}
225
226const 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
233bool 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
241bool 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
271int cDisplayString::insertTag(const char *tagname, int atindex)
272{
273    beforeChange();
274    int result = doInsertTag(tagname, atindex);
275    afterChange();
276    return result;
277}
278
279int 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
319bool cDisplayString::removeTag(int tagindex)
320{
321    beforeChange();
322    bool result = doRemoveTag(tagindex);
323    afterChange();
324    return result;
325}
326
327bool 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
348int 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
356void 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
378void 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
461void 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
495void 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
510void 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}
524