PageRenderTime 54ms CodeModel.GetById 20ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/omnetpp-4.1/src/common/displaystring.cc

https://bitbucket.org/indigopony/omnetproject
C++ | 436 lines | 314 code | 73 blank | 49 comment | 75 complexity | 4a4b545cf936778464abccb522d1d7dd MD5 | raw file
  1//==========================================================================
  2//   DISPLAYSTRING.CC  - part of
  3//                     OMNeT++/OMNEST
  4//            Discrete System Simulation in C++
  5//
  6//  Author: 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#include <string.h>
 18#include <stdio.h>
 19#include "opp_ctype.h"
 20#include "displaystring.h"
 21#include "stringutil.h"
 22
 23USING_NAMESPACE
 24
 25
 26DisplayString::DisplayString()
 27{
 28    dispstr = NULL;
 29    buffer = NULL;
 30    bufferend = NULL;
 31    tags = NULL;
 32    numtags = 0;
 33    needsassemble = false;
 34}
 35
 36
 37DisplayString::DisplayString(const char *displaystr)
 38{
 39    dispstr = opp_strdup(displaystr);
 40    buffer = NULL;
 41    bufferend = NULL;
 42    tags = NULL;
 43    numtags = 0;
 44    needsassemble = false;
 45
 46    parse();
 47}
 48
 49DisplayString::DisplayString(const DisplayString& ds)
 50{
 51    dispstr = NULL;
 52    buffer = NULL;
 53    bufferend = NULL;
 54    tags = NULL;
 55    numtags = 0;
 56    needsassemble = false;
 57
 58    operator=(ds);
 59}
 60
 61DisplayString::~DisplayString()
 62{
 63    delete [] dispstr;
 64    cleartags();
 65}
 66
 67const char *DisplayString::str() const
 68{
 69    if (needsassemble)
 70        assemble();
 71    return dispstr ? dispstr : "";
 72}
 73
 74
 75bool DisplayString::parse(const char *displaystr)
 76{
 77    // if it's the same, nothing to do
 78    if (needsassemble)
 79        assemble();
 80    if (!opp_strcmp(dispstr,displaystr))
 81        return true;
 82
 83    // parse and store new string
 84    delete [] dispstr;
 85    cleartags();
 86    dispstr = opp_strdup(displaystr);
 87    bool fullyOK = parse();
 88
 89    return fullyOK;
 90}
 91
 92
 93void DisplayString::updateWith(const DisplayString& ds)
 94{
 95    // elements in "ds" take precedence
 96    int n = ds.getNumTags();
 97    for (int i=0; i<n; i++)
 98    {
 99        int m = ds.getNumArgs(i);
100        for (int j=0; j<m; j++)
101        {
102            const char *arg = ds.getTagArg(i,j);
103            if (arg[0])
104                setTagArg(ds.getTagName(i), j, arg);
105        }
106    }
107
108    // optimize storage
109    parse(str());
110}
111
112void DisplayString::updateWith(const char *s)
113{
114    DisplayString ds(s);
115    updateWith(ds);
116}
117
118bool DisplayString::containsTag(const char *tagname) const
119{
120    int t = gettagindex(tagname);
121    return t!=-1;
122}
123
124
125int DisplayString::getNumArgs(const char *tagname) const
126{
127    return getNumArgs(gettagindex(tagname));
128}
129
130
131const char *DisplayString::getTagArg(const char *tagname, int index) const
132{
133    return getTagArg(gettagindex(tagname), index);
134}
135
136
137bool DisplayString::setTagArg(const char *tagname, int index, const char *value)
138{
139    int t = gettagindex(tagname);
140    if (t==-1)
141        t = insertTag(tagname);
142    return setTagArg(t, index, value);
143}
144
145bool DisplayString::setTagArg(const char *tagname, int index, long value)
146{
147    char buf[32];
148    sprintf(buf, "%ld", value);
149    return setTagArg(tagname, index, buf);
150}
151
152bool DisplayString::removeTag(const char *tagname)
153{
154    return removeTag(gettagindex(tagname));
155}
156
157
158int DisplayString::getNumTags() const
159{
160    return numtags;
161}
162
163
164const char *DisplayString::getTagName(int tagindex) const
165{
166    if (tagindex<0 || tagindex>=numtags) return NULL;
167    return tags[tagindex].name;
168}
169
170
171int DisplayString::getNumArgs(int tagindex) const
172{
173    if (tagindex<0 || tagindex>=numtags) return -1;
174    return tags[tagindex].numargs;
175}
176
177
178const char *DisplayString::getTagArg(int tagindex, int index) const
179{
180    if (tagindex<0 || tagindex>=numtags) return "";
181    if (index<0 || index>=tags[tagindex].numargs) return "";
182    return opp_nulltoempty(tags[tagindex].args[index]);
183}
184
185
186bool DisplayString::setTagArg(int tagindex, int index, const char *value)
187{
188    // check indices
189    if (tagindex<0 || tagindex>=numtags) return false;
190    if (index<0 || index>=MAXARGS) return false;
191    Tag& tag = tags[tagindex];
192
193    // adjust numargs if necessary
194    if (index>=tag.numargs)
195        tag.numargs = index+1;
196
197    // if it's the same, nothing to do
198    char *&slot = tag.args[index];
199    if (!opp_strcmp(slot,value))
200        return true;
201
202    // set value
203    if (slot && !isinbuffer(slot))
204        delete [] slot;
205    slot = opp_strdup(value);
206
207    // get rid of possible empty trailing args
208    while (tag.numargs>0 && tag.args[tag.numargs-1]==NULL)
209        tag.numargs--;
210
211    needsassemble = true;
212    return true;
213}
214
215
216int DisplayString::insertTag(const char *tagname, int atindex)
217{
218    // check uniqueness
219    int t = gettagindex(tagname);
220    if (t!=-1)
221        return t;
222
223    // check index
224    if (atindex<0) atindex=0;
225    if (atindex>numtags) atindex=numtags;
226
227    // create new tags[] array with hole at atindex
228    Tag *newtags = new Tag[numtags+1];
229    for (int s=0,d=0; s<numtags; s++,d++)
230    {
231       if (d==atindex) d++; // make room for new item
232       newtags[d] = tags[s];
233    }
234    delete [] tags;
235    tags = newtags;
236    numtags++;
237
238    // fill in new tag
239    tags[atindex].name = opp_strdup(tagname);
240    tags[atindex].numargs = 0;
241    for (int i=0; i<MAXARGS; i++) tags[atindex].args[i] = NULL;
242
243    // success
244    needsassemble = true;
245    return atindex;
246}
247
248
249bool DisplayString::removeTag(int tagindex)
250{
251    if (tagindex<0 || tagindex>=numtags) return false;
252
253    // dealloc strings in tag
254    if (!isinbuffer(tags[tagindex].name))
255        delete [] tags[tagindex].name;
256    for (int i=0; i<tags[tagindex].numargs; i++)
257        if (!isinbuffer(tags[tagindex].args[i]))
258            delete [] tags[tagindex].args[i];
259
260    // eliminate hole in tags[] array
261    for (int t=tagindex; t<numtags-1; t++)
262        tags[t] = tags[t+1];
263    numtags--;
264
265    // success
266    needsassemble = true;
267    return true;
268}
269
270
271int DisplayString::gettagindex(const char *tagname) const
272{
273    for (int t=0; t<numtags; t++)
274        if (!strcmp(tagname,tags[t].name))
275            return t;
276    return -1;
277}
278
279void DisplayString::cleartags()
280{
281    // delete tags array. string pointers that do not point inside the
282    // buffer were allocated individually via new char[] and have to be
283    // deleted.
284    for (int t=0; t<numtags; t++)
285    {
286        if (!isinbuffer(tags[t].name))
287            delete [] tags[t].name;
288        for (int i=0; i<tags[t].numargs; i++)
289            if (!isinbuffer(tags[t].args[i]))
290                delete [] tags[t].args[i];
291    }
292    delete [] tags;
293    tags = NULL;
294    numtags = 0;
295
296    // must be done after deleting tags[] because of isinbuffer()
297    delete [] buffer;
298    buffer = bufferend = NULL;
299    needsassemble = true;
300}
301
302bool DisplayString::parse()
303{
304    cleartags();
305    if (dispstr==NULL)
306        return true;
307
308    bool fully_ok = true;
309
310    buffer = new char[opp_strlen(dispstr)+1];
311    bufferend = buffer + opp_strlen(dispstr);
312
313    // count tags (#(';')+1) & allocate tags[] array
314    int n = 1;
315    for (char *s1 = dispstr; *s1; s1++)
316        if (*s1==';')
317            n++;
318    tags = new Tag[n];
319
320    // parse string into tags[]. To avoid several small allocations,
321    // pointers in tags[] will point into the buffer.
322    numtags = 1;
323    tags[0].name = buffer;
324    tags[0].numargs = 0;
325    for (int i=0; i<MAXARGS; i++)
326        tags[0].args[i] = NULL;
327
328    char *s, *d;
329    for (s=dispstr,d=buffer; *s; s++,d++)
330    {
331        if (*s=='\\' && *(s+1))
332        {
333            // allow escaping display string special chars (=,;) with backslash.
334            // No need to deal with "\t", "\n" etc here, since they already got
335            // interpreted by opp_parsequotedstr().
336            *d = *++s;
337        }
338        else if (*s==';')
339        {
340            // new tag begins
341            *d = '\0';
342            numtags++;
343            tags[numtags-1].name = d+1;
344            tags[numtags-1].numargs = 0;
345            for (int i=0; i<MAXARGS; i++) tags[numtags-1].args[i] = NULL;
346        }
347        else if (*s=='=')
348        {
349            // first argument of new tag begins
350            *d = '\0';
351            tags[numtags-1].numargs = 1;
352            tags[numtags-1].args[0] = d+1;
353        }
354        else if (*s==',')
355        {
356            // new argument of current tag begins
357            *d = '\0';
358            if (tags[numtags-1].numargs>=MAXARGS)
359            {
360                fully_ok = false; // extra args ignored (there were too many)
361            }
362            else
363            {
364                tags[numtags-1].numargs++;
365                tags[numtags-1].args[ tags[numtags-1].numargs-1 ] = d+1;
366            }
367        }
368        else
369        {
370            *d = *s;
371        }
372    }
373    *d = '\0';
374
375    // check tag names are OK (matching [a-zA-Z0-9:]+)
376    for (int i=0; i<numtags; i++)
377    {
378        if (!tags[i].name[0])
379            fully_ok = false; // empty string as tagname
380        for (const char *s=tags[i].name; *s; s++)
381            if (!opp_isalnum(*s) && *s!=':')
382                fully_ok = false; // tagname contains invalid character
383    }
384    return fully_ok;
385}
386
387void DisplayString::assemble() const
388{
389    // calculate length of display string
390    int size = 0;
391    for (int t0=0; t0<numtags; t0++)
392    {
393        size += opp_strlen(tags[t0].name)+2;
394        for (int i=0; i<tags[t0].numargs; i++)
395            size += opp_strlen(tags[t0].args[i])+1;
396    }
397    size = 2*size+1;  // 2* for worst case if every char has to be escaped
398
399    // allocate display string
400    delete [] dispstr;
401    dispstr = new char[size];
402    dispstr[0] = '\0';
403
404    // assemble string
405    for (int t=0; t<numtags; t++)
406    {
407        if (t!=0)
408            strcat(dispstr, ";");
409        strcatescaped(dispstr, tags[t].name);
410        if (tags[t].numargs>0)
411            strcat(dispstr, "=");
412        for (int i=0; i<tags[t].numargs; i++)
413        {
414            if (i!=0) strcat(dispstr, ",");
415            strcatescaped(dispstr, tags[t].args[i]);
416        }
417    }
418    needsassemble = false;
419}
420
421void DisplayString::strcatescaped(char *d, const char *s)
422{
423    if (!s) return;
424
425    d += strlen(d);
426    while (*s)
427    {
428        // quoting \t, \n etc is the job of opp_quotestr()
429        if (*s==';' || *s==',' || *s=='=')
430            *d++ = '\\';
431        *d++ = *s++;
432    }
433    *d = '\0';
434}
435
436