PageRenderTime 106ms CodeModel.GetById 59ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 1ms

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

https://bitbucket.org/indigopony/omnetproject
C++ | 535 lines | 456 code | 37 blank | 42 comment | 129 complexity | 0d4c7e4f377eda95039889bd75259999 MD5 | raw file
  1//=========================================================================
  2//  STRINGUTIL.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 <stdio.h>
 18#include <stdlib.h>
 19#include <stdarg.h>
 20#include <limits.h>
 21#include <errno.h>
 22#include <math.h>   //HUGE_VAL
 23#include <locale.h>
 24#include "platmisc.h"
 25#include "commonutil.h"
 26#include "opp_ctype.h"
 27#include "stringutil.h"
 28#include "stringtokenizer.h"
 29
 30USING_NAMESPACE
 31
 32
 33bool opp_isblank(const char *txt)
 34{
 35    if (txt!=NULL)
 36        for (const char *s = txt; *s; s++)
 37            if (!opp_isspace(*s))
 38                return false;
 39    return true;
 40}
 41
 42std::string opp_trim(const char *txt)
 43{
 44    if (!txt)
 45        return "";
 46    while (opp_isspace(*txt))
 47        txt++;
 48    const char *end = txt + strlen(txt);
 49    while (end>txt && opp_isspace(*(end-1)))
 50        end--;
 51    return std::string(txt, end-txt);
 52}
 53
 54std::string opp_parsequotedstr(const char *txt)
 55{
 56    const char *endp;
 57    std::string ret = opp_parsequotedstr(txt, endp);
 58    if (*endp)
 59        throw opp_runtime_error("trailing garbage after string literal");
 60    return ret;
 61}
 62
 63inline int h2d(char c)
 64{
 65    if (c>='0' && c<='9') return c-'0';
 66    if (c>='A' && c<='F') return c-'A'+10;
 67    if (c>='a' && c<='f') return c-'a'+10;
 68    return -1;
 69}
 70
 71inline int h2d(const char *&s)
 72{
 73    int a = h2d(*s);
 74    if (a<0) return 0;
 75    s++;
 76    int b = h2d(*s);
 77    if (b<0) return a;
 78    s++;
 79    return a*16+b;
 80}
 81
 82std::string opp_parsequotedstr(const char *txt, const char *&endp)
 83{
 84    const char *s = txt;
 85    while (opp_isspace(*s))
 86        s++;
 87    if (*s++!='"')
 88        throw opp_runtime_error("missing opening quote");
 89    char *buf = new char [strlen(txt)+1];
 90    char *d = buf;
 91    for (; *s && *s!='"'; s++, d++)
 92    {
 93        if (*s=='\\')
 94        {
 95            // allow backslash as quote character, also interpret backslash sequences
 96            s++;
 97            switch(*s)
 98            {
 99                case 'b': *d = '\b'; break;
100                case 'f': *d = '\f'; break;
101                case 'n': *d = '\n'; break;
102                case 'r': *d = '\r'; break;
103                case 't': *d = '\t'; break;
104                case 'x': s++; *d = h2d(s); s--; break; // hex code
105                case '"': *d = '"'; break;  // quote needs to be backslashed
106                case '\\': *d = '\\'; break;  // backslash needs to be backslashed
107                case '\n': d--; break; // don't store line continuation (backslash followed by newline)
108                case '\0': d--; s--; break; // string ends in stray backslash
109                case '=':
110                case ';':
111                case ',': throw opp_runtime_error("illegal escape sequence `\\%c' "
112                          "(Hint: use double backslashes to quote display string "
113                          "special chars: equal sign, comma, semicolon)", *s);
114                default:  throw opp_runtime_error("illegal escape sequence `\\%c'", *s);
115            }
116        }
117        else
118        {
119            *d = *s;
120        }
121    }
122    *d = '\0';
123    if (*s++!='"')
124        {delete [] buf; throw opp_runtime_error("missing closing quote"); }
125    while (opp_isspace(*s))
126        s++;
127    endp = s;  // if (*s!='\0'), something comes after the string
128
129    std::string ret = buf;
130    delete [] buf;
131    return ret;
132}
133
134std::string opp_quotestr(const char *txt)
135{
136    char *buf = new char[4*strlen(txt)+3];  // a conservative guess
137    char *d = buf;
138    *d++ = '"';
139    const char *s = txt;
140    while (*s)
141    {
142        switch (*s)
143        {
144            case '\b': *d++ = '\\'; *d++ = 'b'; s++; break;
145            case '\f': *d++ = '\\'; *d++ = 'f'; s++; break;
146            case '\n': *d++ = '\\'; *d++ = 'n'; s++; break;
147            case '\r': *d++ = '\\'; *d++ = 'r'; s++; break;
148            case '\t': *d++ = '\\'; *d++ = 't'; s++; break;
149            case '"':  *d++ = '\\'; *d++ = '"'; s++; break;
150            case '\\': *d++ = '\\'; *d++ = '\\'; s++; break;
151            default: if (opp_iscntrl(*s)) {*d++='\\'; *d++='x'; sprintf(d,"%2.2X",*s++); d+=2;}
152                     else {*d++ = *s++;}
153        }
154    }
155    *d++ = '"';
156    *d = '\0';
157
158    std::string ret = buf;
159    delete [] buf;
160    return ret;
161}
162
163bool opp_needsquotes(const char *txt)
164{
165    if (!txt[0])
166        return true;
167    for (const char *s = txt; *s; s++)
168        if (opp_isspace(*s) || *s=='\\' || *s=='"' || opp_iscntrl(*s))
169            return true;
170    return false;
171}
172
173#define BUFLEN 1024
174
175std::string opp_stringf(const char *fmt, ...)
176{
177    char buf[BUFLEN];
178    VSNPRINTF(buf, BUFLEN, fmt);
179    return buf;
180}
181
182std::string opp_vstringf(const char *fmt, va_list& args)
183{
184    char buf[BUFLEN];
185    vsnprintf(buf, BUFLEN, fmt, args);
186    buf[BUFLEN-1] = '\0';
187    return buf;
188}
189
190#undef BUFLEN
191
192int opp_vsscanf(const char *s, const char *fmt, va_list va)
193{
194    // A simplified vsscanf implementation, solely for cStatistic::freadvarsf.
195    // Only recognizes %d, %u, %ld, %g and whitespace. '#' terminates scanning
196    setlocale(LC_NUMERIC, "C");
197    int k = 0;
198    while (true)
199    {
200        if (*fmt=='%')
201        {
202            int n;
203            if (fmt[1]=='d')
204            {
205                k+=sscanf(s,"%d%n",va_arg(va,int*),&n);
206                s+=n; fmt+=2;
207            }
208            else if (fmt[1]=='u')
209            {
210                k+=sscanf(s,"%u%n",va_arg(va,unsigned int*),&n);
211                s+=n; fmt+=2;
212            }
213            else if (fmt[1]=='l' && fmt[2]=='d')
214            {
215                k+=sscanf(s,"%ld%n",va_arg(va,long*),&n);
216                s+=n; fmt+=3;
217            }
218            else if (fmt[1]=='l' && fmt[2]=='u')
219            {
220                k+=sscanf(s,"%lu%n",va_arg(va,unsigned long*),&n);
221                s+=n; fmt+=3;
222            }
223            else if (fmt[1]=='l' && fmt[2]=='g')
224            {
225                k+=sscanf(s,"%lg%n",va_arg(va,double*),&n);
226                s+=n; fmt+=3;
227            }
228            else if (fmt[1]=='g')
229            {
230                k+=sscanf(s,"%lg%n",va_arg(va,double*),&n);
231                s+=n; fmt+=2;
232            }
233            else
234            {
235                throw opp_runtime_error("opp_vsscanf: unsupported format '%s'",fmt);
236            }
237        }
238        else if (opp_isspace(*fmt))
239        {
240            while (opp_isspace(*s)) s++;
241            fmt++;
242        }
243        else if (*fmt=='\0' || *fmt=='#')
244        {
245            return k;
246        }
247        else
248        {
249            throw opp_runtime_error("opp_vsscanf: unexpected char in format: '%s'",fmt);
250        }
251    }
252}
253
254std::string opp_replacesubstring(const char *s, const char *substring, const char *replacement, bool replaceAll)
255{
256    std::string text = s;
257    std::string::size_type pos = 0;
258    do {
259        pos = text.find(substring, pos);
260        if (pos == std::string::npos)
261            break;
262        text.replace(pos, strlen(substring), replacement);
263        pos += strlen(replacement);
264    }
265    while (replaceAll);
266    return text;
267}
268
269std::string opp_breaklines(const char *text, int lineLength)
270{
271    char *buf = new char[strlen(text)+1];
272    strcpy(buf, text);
273
274    int leftMargin = 0;
275    int length = strlen(buf);
276    while (true)
277    {
278        int rightMargin = leftMargin + lineLength;
279        if (rightMargin>=length)
280            break; // done
281        bool here = false;
282        int i;
283        if (!here)
284            for (i=leftMargin; i<rightMargin; i++)
285                if (buf[i]=='\n')
286                    {here = true; break;}
287        if (!here)
288            for (; i>=leftMargin; i--)
289                if (buf[i]==' ' || buf[i]=='\n')
290                    {here = true; break;}
291        if (!here)
292            for (i=leftMargin; i<length; i++)
293                if (buf[i]==' ' || buf[i]=='\n')
294                    {here = true; break;}
295        if (!here)
296            break; // done
297        buf[i] = '\n';
298        leftMargin = i+1;
299    }
300
301    std::string tmp = buf;
302    delete[] buf;
303    return tmp;
304}
305
306std::string opp_indentlines(const char *text, const char *indent)
307{
308    return std::string(indent) + opp_replacesubstring(text, "\n", (std::string("\n")+indent).c_str(), true);
309}
310
311bool opp_stringbeginswith(const char *s, const char *prefix)
312{
313    return strlen(s) >= strlen(prefix) && strncmp(s, prefix, strlen(prefix))==0;
314}
315
316bool opp_stringendswith(const char *s, const char *ending)
317{
318    int slen = strlen(s);
319    int endinglen = strlen(ending);
320    return slen >= endinglen && strcmp(s+slen-endinglen, ending)==0;
321}
322
323char *opp_concat(const char *s1,
324                 const char *s2,
325                 const char *s3,
326                 const char *s4)
327{
328    // concatenate strings into a static buffer
329    //FIXME throw error if string overflows!!!
330    static char buf[256];
331    char *bufEnd = buf+255;
332    char *dest=buf;
333    if (s1) while (*s1 && dest!=bufEnd) *dest++ = *s1++;
334    if (s2) while (*s2 && dest!=bufEnd) *dest++ = *s2++;
335    if (s3) while (*s3 && dest!=bufEnd) *dest++ = *s3++;
336    if (s4) while (*s4 && dest!=bufEnd) *dest++ = *s4++;
337    *dest = 0;
338    return buf;
339}
340
341char *opp_strupr(char *s)
342{
343    char *txt = s;
344    while(*s) {
345        *s = opp_toupper(*s);
346        s++;
347    }
348    return txt;
349}
350
351char *opp_strlwr(char *s)
352{
353    char *txt = s;
354    while(*s) {
355        *s = opp_tolower(*s);
356        s++;
357    }
358    return txt;
359}
360
361std::string opp_join(const char *separator, const char *s1, const char *s2)
362{
363    if (opp_isempty(s1))
364        return opp_nulltoempty(s2);
365    else if (opp_isempty(s2))
366        return opp_nulltoempty(s1);
367    else
368        return std::string(s1) + separator + s2;
369}
370
371// returns 0 iff the two strings are equal by strcmp().
372int strdictcmp(const char *s1, const char *s2)
373{
374    int firstdiff = 0;
375    char c1, c2;
376    while ((c1=*s1)!='\0' && (c2=*s2)!='\0')
377    {
378        if (opp_isdigit(c1) && opp_isdigit(c2))
379        {
380            char *s1end, *s2end;
381            double d1 = strtod(s1, &s1end);
382            double d2 = strtod(s2, &s2end);
383            if (d1!=d2)
384                return d1<d2 ? -1 : 1;
385            if (!firstdiff) {
386                if (s1end-s1 < s2end-s2)
387                    firstdiff = strncasecmp(s1, s2, s1end-s1);
388                else
389                    firstdiff = strncasecmp(s1, s2, s2end-s2);
390                if (!firstdiff && (s1end-s1) != (s2end-s2))
391                    firstdiff = (s1end-s1 < s2end-s2) ? -1 : 1;
392            }
393            s1 = s1end;
394            s2 = s2end;
395        }
396        else if (c1==c2) // very frequent in our case
397        {
398            s1++;
399            s2++;
400        }
401        else
402        {
403            char lc1 = opp_tolower(c1);
404            char lc2 = opp_tolower(c2);
405            if (lc1!=lc2)
406                return lc1<lc2 ? -1 : 1;
407            if (c1!=c2 && !firstdiff && opp_isalpha(c1) && opp_isalpha(c2))
408                firstdiff = opp_isupper(c2) ? -1 : 1;
409            s1++;
410            s2++;
411        }
412    }
413    if (!*s1 && !*s2)
414        return firstdiff;
415    return *s2 ? -1 : 1;
416}
417
418/* for testing:
419#include <stdio.h>
420int qsortfunc(const void *a, const void *b)
421{
422    return strdictcmp(*(char**)a, *(char**)b);
423}
424
425int main(int argc, char **argv)
426{
427    qsort(argv+1, argc-1, sizeof(char*), qsortfunc);
428    for (int i=1; i<argc; i++)
429        printf("%s ", argv[i]);
430    printf("\n");
431    return 0;
432}
433
434Expected results:
435 dictcmp a b c d c1 c2 ca cd --> a b c c1 c2 ca cd d
436 dictcmp a aaa aa aaaaa aaaa --> a aa aaa aaaa aaaaa
437 dictcmp a aaa Aa AaAaa aaaa --> a Aa aaa aaaa AaAaa
438 dictcmp a1b a2b a11b a13b a20b --> a1b a2b a11b a13b a20b
439*/
440
441long opp_strtol(const char *s, char **endptr)
442{
443    long d = strtol(s, endptr, 0);
444    if ((d==LONG_MAX || d==LONG_MIN) && errno==ERANGE)
445        throw opp_runtime_error("overflow converting `%s' to long", s);
446    return d;
447}
448
449long opp_atol(const char *s)
450{
451    char *endptr;
452    long d = opp_strtol(s, &endptr);
453    while (opp_isspace(*endptr))
454        endptr++;
455    if (*endptr)
456        throw opp_runtime_error("`%s' is not a valid integer", s);
457    return d;
458}
459
460unsigned long opp_strtoul(const char *s, char **endptr)
461{
462    unsigned long d = strtoul(s, endptr, 0);
463    if (d==ULONG_MAX && errno==ERANGE)
464        throw opp_runtime_error("overflow converting `%s' to unsigned long", s);
465    return d;
466}
467
468unsigned long opp_atoul(const char *s)
469{
470    char *endptr;
471    unsigned long d = opp_strtol(s, &endptr);
472    while (opp_isspace(*endptr))
473        endptr++;
474    if (*endptr)
475        throw opp_runtime_error("`%s' is not a valid unsigned integer", s);
476    return d;
477}
478
479double opp_strtod(const char *s, char **endptr)
480{
481    setlocale(LC_NUMERIC, "C");
482    double d = strtod(s, endptr);
483    if (d==-HUGE_VAL || d==HUGE_VAL)
484        throw opp_runtime_error("overflow converting `%s' to double", s);
485    return d;
486}
487
488double opp_atof(const char *s)
489{
490    char *endptr;
491    setlocale(LC_NUMERIC, "C");
492    double d = opp_strtod(s, &endptr);
493    while (opp_isspace(*endptr))
494        endptr++;
495    if (*endptr)
496        throw opp_runtime_error("`%s' is not a valid double value", s);
497    return d;
498}
499
500const char *opp_findmatchingquote(const char *s)
501{
502    while (opp_isspace(*s))
503        s++;
504    if (*s++!='"')
505        throw opp_runtime_error("missing opening quote");
506    for (; *s && *s!='"'; s++)
507        if (*s=='\\')
508            s++;
509    return *s ? s : NULL;
510}
511
512const char *opp_findmatchingparen(const char *s)
513{
514    while (opp_isspace(*s))
515        s++;
516    if (*s++ != '(')
517        throw opp_runtime_error("missing left parenthesis");
518
519    int parens = 1;
520    while (*s && parens>0)
521    {
522        if (*s == '(')
523            parens++;
524        else if (*s == ')')
525            parens--;
526        else if (*s == '"') {
527            s = opp_findmatchingquote(s);
528            if (!s)
529                return NULL;
530        }
531        s++;
532    }
533    return parens>0 ? NULL : s;
534}
535