1  /*
   2   * \brief  String utilities
   3   * \author Norman Feske
   4   * \author Sebastian Sumpf
   5   * \date   2006-05-10
   6   */

   7  
   8  /*
   9   * Copyright (C) 2006-2013 Genode Labs GmbH
  10   *
  11   * This file is part of the Genode OS framework, which is distributed
  12   * under the terms of the GNU General Public License version 2.
  13   */

  14  
  15  #ifndef _INCLUDE__UTIL__STRING_H_
  16  #define _INCLUDE__UTIL__STRING_H_
  17  
  18  #include <base/stdint.h>
  19  #include <util/misc_math.h>
  20  #include <cpu/string.h>
  21  
  22  namespace Genode {
  23  
  24     class Number_of_bytes;
  25     template <Genode::size_t> class String;
  26  }

  27  
  28  
  29  /**
  30   * Wrapper of `size_t` for selecting the `ascii_to` function to parse byte values
  31   */

  32  class Genode::Number_of_bytes
  33  {
  34     size_t _n;
  35  
  36     public:
  37  
  38        /**
  39         * Default constructor
  40         */

  41        Number_of_bytes() : _n(0) { }

  42  
  43        /**
  44         * Constructor, to be used implicitly via assignment operator
  45         */

  46        Number_of_bytes(size_t n) : _n(n) { }

  47  
  48        /**
  49         * Convert number of bytes to `size_t` value
  50         */

  51        operator size_t() const { return _n; }
  52  }
;

  53  
  54  
  55  /***********************
  56   ** Utility functions **
  57   ***********************/

  58  
  59  namespace Genode {
  60  
  61     /**
  62      * Return length of null-terminated string in bytes
  63      */

  64     inline size_t strlen(const char *s)
  65     {
  66        size_t res = 0;
  67        for (; s && *s; s++, res++);
  68        return res;

  69     }

  70  
  71  
  72     /**
  73      * Compare two strings
  74      *
  75      * \param len   maximum number of characters to compare,
  76      *              default is unlimited
  77      *
  78      * \return   0 if both strings are equal, or
  79      *           a positive number if s1 is higher than s2, or
  80      *           a negative number if s1 is lower than s2
  81      */

  82     inline int strcmp(const char *s1, const char *s2, size_t len = ~0UL)
  83     {
  84        for (*s1 && *s1 == *s2 && len; s1++, s2++, len--) ;
  85        return len ? *s1 - *s2 : 0;

  86     }

  87  
  88  
  89     /**
  90      * Copy memory buffer to a potentially overlapping destination buffer
  91      *
  92      * \param dst   destination memory block
  93      * \param src   source memory block
  94      * \param size  number of bytes to move
  95      *
  96      * \return      pointer to destination memory block
  97      */

  98     inline void *memmove(void *dst, const void *src, size_t size)
  99     {
 100        char *= (char *)dst, *= (char *)src;
 101        size_t i;
 102  
 103        if (> d)
 104           for (= 0; i < size; i++, *d++ = *s++);
 105        else
 106           for (+= size - 1, d += size - 1, i = size; i-- > 0; *d-- = *s--);

 107  
 108        return dst;

 109     }

 110  
 111  
 112     /**
 113      * Copy memory buffer to a non-overlapping destination buffer
 114      *
 115      * \param dst   destination memory block
 116      * \param src   source memory block
 117      * \param size  number of bytes to copy
 118      *
 119      * \return      pointer to destination memory block
 120      */

 121     inline void *memcpy(void *dst, const void *src, size_t size)
 122     {
 123        char *= (char *)dst, *= (char *)src;
 124        size_t i;
 125  
 126        /* check for overlap */

 127        if ((+ size > s) && (+ size > d))
 128           return memmove(dst, src, size);

 129  
 130        /* try cpu specific version first */
 131        if ((= size - memcpy_cpu(dst, src, size)) == size)
 132           return dst;

 133  
 134        += i; += i; size -= i;
 135  
 136        /* copy eight byte chunks */
 137        for (= size >> 3; i > 0; i--, *d++ = *s++,
 138                                        *d++ = *s++,
 139                                        *d++ = *s++,
 140                                        *d++ = *s++,
 141                                        *d++ = *s++,
 142                                        *d++ = *s++,
 143                                        *d++ = *s++,
 144                                        *d++ = *s++)
;

 145  
 146        /* copy left over */
 147        for (= 0; i < (size & 0x7); i++, *d++ = *s++);
 148  
 149        return dst;

 150     }

 151  
 152  
 153     /**
 154      * Copy string
 155      *
 156      * \param dst   destination buffer
 157      * \param src   buffer holding the null-terminated source string
 158      * \param size  maximum number of characters to copy
 159      * \return      pointer to destination string
 160      *
 161      * Note that this function is not fully compatible to the C standard, in
 162      * particular there is no zero-padding if the length of `src` is smaller
 163      * than `size`. Furthermore, in contrast to the libc version, this function
 164      * always produces a null-terminated string in the `dst` buffer if the
 165      * `size` argument is greater than 0.
 166      */

 167     inline char *strncpy(char *dst, const char *src, size_t size)
 168     {
 169        /* sanity check for corner case of a zero-size destination buffer */
 170        if (size == 0) return dst;
 171  
 172        /* backup original `dst` for the use as return value */

 173        char *orig_dst = dst;
 174  
 175        /*
 176         * Copy characters from `src` to `dst` respecting the `size` limit.
 177         * In each iteration, the `size` variable holds the maximum remaining
 178         * size. We have to leave at least one character free to add the null
 179         * termination afterwards.
 180         */

 181        while ((size-- > 1UL) && *src)
 182           *dst++ = *src++;

 183  
 184        /* append null termination to the destination buffer */
 185        *dst = 0;
 186  
 187        return orig_dst;

 188     }

 189  
 190  
 191     /**
 192      * Compare memory blocks
 193      *
 194      * \return  0 if both memory blocks are equal, or
 195      *          a negative number if `p0` is less than `p1`, or
 196      *          a positive number if `p0` is greater than `p1`
 197      */

 198     inline int memcmp(const void *p0, const void *p1, size_t size)
 199     {
 200        const unsigned char *c0 = (const unsigned char *)p0;
 201        const unsigned char *c1 = (const unsigned char *)p1;
 202  
 203        size_t i;
 204        for (= 0; i < size; i++)
 205           if (c0[i] != c1[i]) return c0[i] - c1[i];

 206  
 207        return 0;

 208     }

 209  
 210  
 211     /**
 212      * Fill destination buffer with given value
 213      *
 214      * \param dst   destination buffer
 215      * \param i     byte value
 216      * \param size  buffer size in bytes
 217      */

 218     inline void *memset(void *dst, int i, size_t size)
 219     {
 220        while (size--) ((char *)dst)[size] = i;
 221        return dst;

 222     }

 223  
 224  
 225     /**
 226      * Convert ASCII character to digit
 227      *
 228      * \param hex   consider hexadecimals
 229      * \return      digit or -1 on error
 230      */

 231     inline int digit(char c, bool hex = false)
 232     {
 233        if (>= `0` && c <= `9`) return c - `0`;
 234        if (hex && c >= `a` && c <= `f`) return c - `a` + 10;
 235        if (hex && c >= `A` && c <= `F`) return c - `A` + 10;
 236        return -1;

 237     }

 238  
 239  
 240     /**
 241      * Return true if character is a letter
 242      */

 243     inline bool is_letter(char c)
 244     {
 245        return (((>= `a`) && (<= `z`)) || ((>= `A`) && (<= `Z`)));
 246     }

 247  
 248  
 249     /**
 250      * Return true if character is a digit
 251      */

 252     inline bool is_digit(char c, bool hex = false)
 253     {
 254        return (digit(c, hex) >= 0);
 255     }

 256  
 257  
 258     /**
 259      * Return true if character is whitespace
 260      */

 261     inline bool is_whitespace(char c)
 262     {
 263        return (== `\t` || c == ` ` || c == `\n`);
 264     }

 265  
 266  
 267     /**
 268      * Read unsigned long value from string
 269      *
 270      * \param s       source string
 271      * \param result  destination variable
 272      * \param base    integer base
 273      * \return        number of consumed characters
 274      *
 275      * If the base argument is 0, the integer base is detected based on the
 276      * characters in front of the number. If the number is prefixed with "0x",
 277      * a base of 16 is used, otherwise a base of 10.
 278      */

 279     template <typename T>
 280     inline size_t ascii_to_unsigned(const char *s, &result, unsigned base)
 281     {
 282        T i = 0, value = 0;
 283  
 284        if (!*s) return i;
 285  
 286        /* autodetect hexadecimal base, default is a base of 10 */
 287        if (base == 0) {
 288  
 289           /* read `0x` prefix */
 290           if (*== `0` && (s[1] == `x` || s[1] == `X`)) {
 291              += 2; += 2;
 292              base = 16;

 293           }
 else
 294              base = 10;

 295        }

 296  
 297        /* read number */
 298        for (int d; ; s++, i++) {
 299  
 300           /* read digit, stop when hitting a non-digit character */
 301           if ((= digit(*s, base == 16)) < 0) break;
 302  
 303           /* append digit to integer value */
 304           value = value*base + d;

 305        }

 306  
 307        result = value;
 308        return i;

 309     }

 310  
 311  
 312     /**
 313      * Read boolean value from string
 314      *
 315      * \return number of consumed characters
 316      */

 317     inline size_t ascii_to(char const *s, bool &result)
 318     {
 319        if (!strcmp(s, "yes",   3)) { result = true;  return 3; }
 320        if (!strcmp(s, "true",  4)) { result = true;  return 4; }
 321        if (!strcmp(s, "on",    2)) { result = true;  return 2; }
 322        if (!strcmp(s, "no",    2)) { result = false; return 2; }
 323        if (!strcmp(s, "false", 5)) { result = false; return 5; }
 324        if (!strcmp(s, "off",   3)) { result = false; return 3; }
 325  
 326        return 0;

 327     }

 328  
 329  
 330     /**
 331      * Read unsigned long value from string
 332      *
 333      * \return number of consumed characters
 334      */

 335     inline size_t ascii_to(const char *s, unsigned long &result)
 336     {
 337        return ascii_to_unsigned(s, result, 0);
 338     }

 339  
 340  
 341     /**
 342      * Read unsigned long long value from string
 343      *
 344      * \return number of consumed characters
 345      */

 346     inline size_t ascii_to(const char *s, unsigned long long &result)
 347     {
 348        return ascii_to_unsigned(s, result, 0);
 349     }

 350  
 351  
 352  
 353     /**
 354      * Read unsigned int value from string
 355      *
 356      * \return number of consumed characters
 357      */

 358     inline size_t ascii_to(const char *s, unsigned int &result)
 359     {
 360        return ascii_to_unsigned(s, result, 0);
 361     }

 362  
 363  
 364     /**
 365      * Read signed long value from string
 366      *
 367      * \return number of consumed characters
 368      */

 369     inline size_t ascii_to(const char *s, long &result)
 370     {
 371        int i = 0;
 372  
 373        /* read sign */

 374        int sign = (*== `-`) ? -1 : 1;
 375  
 376        if (*== `-` || *== `+`) { s++; i++; }
 377  
 378        int j = 0;
 379        unsigned long value = 0;
 380  
 381        = ascii_to_unsigned(s, value, 10);
 382  
 383        if (!j) return i;
 384  
 385        result = sign*value;
 386        return i + j;

 387     }

 388  
 389  
 390     /**
 391      * Read `Number_of_bytes` value from string and handle the size suffixes
 392      *
 393      * This function scales the resulting size value according to the suffixes
 394      * for G (2^30), M (2^20), and K (2^10) if present.
 395      *
 396      * \return number of consumed characters
 397      */

 398     inline size_t ascii_to(const char *s, Number_of_bytes &result)
 399     {
 400        unsigned long res = 0;
 401  
 402        /* convert numeric part of string */

 403        int i = ascii_to_unsigned(s, res, 0);
 404  
 405        /* handle suffixes */

 406        if (> 0)
 407           switch (s[i]) {
 408           case `G`: res *= 1024;
 409           case `M`: res *= 1024;
 410           case `K`: res *= 1024; i++;
 411           default: break;
 412           }

 413  
 414        result = res;
 415        return i;

 416     }

 417  
 418  
 419     /**
 420      * Read double float value from string
 421      *
 422      * \return number of consumed characters
 423      */

 424     inline size_t ascii_to(const char *s, double &result)
 425     {
 426        double v = 0.0;    /* decimal part              */
 427        double d = 0.1;    /* power of fractional digit */
 428        bool neg = false;  /* sign                      */
 429        int    i = 0;      /* character counter         */
 430  
 431        if (s[i] == `-`) {
 432           neg = true;
 433           i++;

 434        }

 435  
 436        /* parse decimal part of number */
 437        for (; s[i] && is_digit(s[i]); i++)
 438           = 10*+ digit(s[i], false);

 439  
 440        /* if no fractional part exists, return current value */
 441        if (s[i] != `.`) {
 442           result = neg ? -v : v;
 443           return i;

 444        }

 445  
 446        /* skip comma */
 447        i++;
 448  
 449        /* parse fractional part of number */
 450        for (; s[i] && is_digit(s[i]); i++, d *= 0.1)
 451           += d*digit(s[i], false);

 452  
 453        result = neg ? -v : v;
 454        return i;

 455     }

 456  
 457  
 458     /**
 459      * Check for end of quotation
 460      *
 461      * Checks if next character is non-backslashed quotation mark.
 462      */

 463     inline bool end_of_quote(const char *s) {
 464        return s[0] != `\\` && s[1] == `\"`; }

 465  
 466  
 467     /**
 468      * Unpack quoted string
 469      *
 470      * \param src   source string including the quotation marks ("...")
 471      * \param dst   destination buffer
 472      *
 473      * \return      number of characters or negative error code
 474      */

 475     inline int unpack_string(const char *src, char *dst, int dst_len)
 476     {
 477        /* check if quoted string */
 478        if (*src != `"`) return -1;
 479  
 480        src++;
 481  
 482        int i = 0;
 483        for (*src && !end_of_quote(src - 1) && (< dst_len - 1); i++) {
 484  
 485           /* transform `\"` to `"` */
 486           if (src[0] == `\\` && src[1] == `\"`) {
 487              *dst++ = `"`;
 488              src += 2;

 489           }
 else
 490              *dst++ = *src++;

 491        }

 492  
 493        /* write terminating null */
 494        *dst = 0;
 495  
 496        return i;

 497     }

 498  }

 499  
 500  
 501  /**
 502   * Buffer that contains a null-terminated string
 503   *
 504   * \param CAPACITY  buffer size including the terminating zero
 505   */

 506  template <Genode::size_t CAPACITY>
 507  class Genode::String
 508  {
 509     private:
 510  
 511        char   _buf[CAPACITY];
 512        size_t _length;

 513  
 514     public:
 515  
 516        constexpr static size_t size() { return CAPACITY; }
 517  
 518        String() : _length(0) { }
 519  
 520        String(char const *str, size_t len = ~0UL - 1)
 521        :
 522           _length(min(len + 1, min(strlen(str) + 1, CAPACITY)))

 523        {
 524           strncpy(_buf, str, _length);
 525        }

 526  
 527        size_t length() const { return _length; }
 528  
 529        static constexpr size_t capacity() { return CAPACITY; }
 530  
 531        bool valid() const {
 532           return (_length <= CAPACITY) && (_length != 0) && (_buf[_length - 1] == `\0`); }

 533  
 534        char const *string() const { return valid() ? _buf : ""; }
 535  
 536        bool operator == (char const *other) const
 537        {
 538           return strcmp(string(), other) == 0;
 539        }

 540  
 541        bool operator != (char const *other) const
 542        {
 543           return strcmp(string(), other) != 0;
 544        }

 545  
 546        template <size_t OTHER_CAPACITY>
 547        bool operator == (String<OTHER_CAPACITY> const &other) const
 548        {
 549           return strcmp(string(), other.string()) == 0;
 550        }

 551  
 552        template <size_t OTHER_CAPACITY>
 553        bool operator != (String<OTHER_CAPACITY> const &other) const
 554        {
 555           return strcmp(string(), other.string()) != 0;
 556        }

 557  }
;

 558  
 559  #endif /* _INCLUDE__UTIL__STRING_H_ */