1  /*
   2   * \brief  String utility functions
   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     /**
  25      * Determine length of null-terminated string
  26      */

  27     inline size_t strlen(const char *s)
  28     {
  29        size_t res = 0;
  30        for (; s && *s; s++, res++);
  31        return res;

  32     }

  33  
  34  
  35     /**
  36      * Compare two strings
  37      *
  38      * \param len   maximum number of characters to compare,
  39      *              default is unlimited
  40      *
  41      * \retval   0  strings are equal
  42      * \retval  >0  s1 is higher than s2
  43      * \retval  <0  s1 is lower than s2
  44      */

  45     inline int strcmp(const char *s1, const char *s2, size_t len = ~0UL)
  46     {
  47        for (*s1 && *s1 == *s2 && len; s1++, s2++, len--) ;
  48        return len ? *s1 - *s2 : 0;

  49     }

  50  
  51  
  52     /**
  53      * Simple memmove
  54      *
  55      * \param dst   destination memory block
  56      * \param src   source memory block
  57      * \param size  number of bytes to move
  58      *
  59      * \return      pointer to destination memory block
  60      */

  61     inline void *memmove(void *dst, const void *src, size_t size)
  62     {
  63        char *= (char *)dst, *= (char *)src;
  64        size_t i;
  65  
  66        if (> d)
  67           for (= 0; i < size; i++, *d++ = *s++);
  68        else
  69           for (+= size - 1, d += size - 1, i = size; i-- > 0; *d-- = *s--);

  70  
  71        return dst;

  72     }

  73  
  74  
  75     /**
  76      * Copy memory block
  77      *
  78      * \param dst   destination memory block
  79      * \param src   source memory block
  80      * \param size  number of bytes to copy
  81      *
  82      * \return      pointer to destination memory block
  83      */

  84     inline void *memcpy(void *dst, const void *src, size_t size)
  85     {
  86        char *= (char *)dst, *= (char *)src;
  87        size_t i;
  88  
  89        /* check for overlap */

  90        if ((+ size > s) && (+ size > d))
  91           return memmove(dst, src, size);

  92  
  93        /* try cpu specific version first */
  94        if ((= size - memcpy_cpu(dst, src, size)) == size)
  95           return dst;

  96  
  97        += i; += i; size -= i;
  98  
  99        /* copy eight byte chunks */
 100        for (= size >> 3; i > 0; i--, *d++ = *s++,
 101                                        *d++ = *s++,
 102                                        *d++ = *s++,
 103                                        *d++ = *s++,
 104                                        *d++ = *s++,
 105                                        *d++ = *s++,
 106                                        *d++ = *s++,
 107                                        *d++ = *s++)
;

 108  
 109        /* copy left over */
 110        for (= 0; i < (size & 0x7); i++, *d++ = *s++);
 111  
 112        return dst;

 113     }

 114  
 115  
 116     /**
 117      * Copy string
 118      *
 119      * \param dst   destination buffer
 120      * \param src   buffer holding the null-terminated source string
 121      * \param size  maximum number of characters to copy
 122      * \return      pointer to destination string
 123      *
 124      * This function is not fully compatible to the C standard, in particular
 125      * there is no zero-padding if the length of `src` is smaller than `size`.
 126      * Furthermore, in contrast to the libc version, this function always
 127      * produces a null-terminated string in the `dst` buffer if the `size`
 128      * argument is greater than 0.
 129      */

 130     inline char *strncpy(char *dst, const char *src, size_t size)
 131     {
 132        /* sanity check for corner case of a zero-size destination buffer */
 133        if (size == 0) return dst;
 134  
 135        /* backup original `dst` for the use as return value */

 136        char *orig_dst = dst;
 137  
 138        /*
 139         * Copy characters from `src` to `dst` respecting the `size` limit.
 140         * In each iteration, the `size` variable holds the maximum remaining
 141         * size. We have to leave at least one character free to add the null
 142         * termination afterwards.
 143         */

 144        while ((size-- > 1UL) && *src)
 145           *dst++ = *src++;

 146  
 147        /* append null termination to the destination buffer */
 148        *dst = 0;
 149  
 150        return orig_dst;

 151     }

 152  
 153  
 154     /**
 155      * Compare memory blocks
 156      *
 157      * \retval  0  memory blocks are equal
 158      * \retval <0  first memory block is less than second one
 159      * \retval >0  first memory block is greater than second one
 160      */

 161     inline int memcmp(const void *p0, const void *p1, size_t size)
 162     {
 163        const unsigned char *c0 = (const unsigned char *)p0;
 164        const unsigned char *c1 = (const unsigned char *)p1;
 165  
 166        size_t i;
 167        for (= 0; i < size; i++)
 168           if (c0[i] != c1[i]) return c0[i] - c1[i];

 169  
 170        return 0;

 171     }

 172  
 173  
 174     /**
 175      * Memset
 176      */

 177     inline void *memset(void *dst, int i, size_t size)
 178     {
 179        while (size--) ((char *)dst)[size] = i;
 180        return dst;

 181     }

 182  
 183  
 184     /**
 185      * Convert ASCII character to digit
 186      *
 187      * \param hex   consider hexadecimals
 188      * \return      digit or -1 on error
 189      */

 190     inline int digit(char c, bool hex = false)
 191     {
 192        if (>= `0` && c <= `9`) return c - `0`;
 193        if (hex && c >= `a` && c <= `f`) return c - `a` + 10;
 194        if (hex && c >= `A` && c <= `F`) return c - `A` + 10;
 195        return -1;

 196     }

 197  
 198  
 199     /**
 200      * Return true if character is a letter
 201      */

 202     inline bool is_letter(char c)
 203     {
 204        return (((>= `a`) && (<= `z`)) || ((>= `A`) && (<= `Z`)));
 205     }

 206  
 207  
 208     /**
 209      * Return true if character is a digit
 210      */

 211     inline bool is_digit(char c, bool hex = false)
 212     {
 213        return (digit(c, hex) >= 0);
 214     }

 215  
 216  
 217     /**
 218      * Return true if character is whitespace
 219      */

 220     inline bool is_whitespace(char c)
 221     {
 222        return (== `\t` || c == ` ` || c == `\n`);
 223     }

 224  
 225  
 226     /**
 227      * Convert ASCII string to another type
 228      *
 229      * \param T       destination type of conversion
 230      * \param s       null-terminated source string
 231      * \param result  destination pointer to conversion result
 232      * \param base    base, autodetected if set to 0
 233      * \return        number of consumed characters
 234      *
 235      * Please note that `base` and `s_max_len` are not evaluated by all
 236      * template specializations.
 237      */

 238     template <typename T>
 239     inline size_t ascii_to(const char *s, *result, unsigned base = 0);

 240  
 241  
 242     /**
 243      * Read unsigned long value from string
 244      */

 245     template <>
 246     inline size_t ascii_to<unsigned long>(const char *s, unsigned long *result,
 247                                           unsigned base)

 248     {
 249        unsigned long i = 0, value = 0;
 250  
 251        if (!*s) return i;
 252  
 253        /* autodetect hexadecimal base, default is a base of 10 */
 254        if (base == 0) {
 255  
 256           /* read `0x` prefix */
 257           if (*== `0` && (s[1] == `x` || s[1] == `X`)) {
 258              += 2; += 2;
 259              base = 16;

 260           }
 else
 261              base = 10;

 262        }

 263  
 264        /* read number */
 265        for (int d; ; s++, i++) {
 266  
 267           /* read digit, stop when hitting a non-digit character */
 268           if ((= digit(*s, base == 16)) < 0) break;
 269  
 270           /* append digit to integer value */
 271           value = value*base + d;

 272        }

 273  
 274        *result = value;
 275        return i;

 276     }

 277  
 278  
 279     /**
 280      * Read unsigned int value from string
 281      */

 282     template <>
 283     inline size_t ascii_to<unsigned int>(const char *s, unsigned int *result,
 284                                          unsigned base)

 285     {
 286        unsigned long result_long = 0;
 287        size_t ret = ascii_to<unsigned long>(s, &result_long, base);
 288        *result = result_long;
 289        return ret;

 290     }

 291  
 292  
 293     /**
 294      * Read signed long value from string
 295      */

 296     template <>
 297     inline size_t ascii_to<long>(const char *s, long *result, unsigned base)
 298     {
 299        int i = 0;
 300  
 301        /* read sign */

 302        int sign = (*== `-`) ? -1 : 1;
 303  
 304        if (*== `-` || *== `+`) { s++; i++; }
 305  
 306        int j = 0;
 307        unsigned long value = 0;
 308  
 309        = ascii_to(s, &value, base);
 310  
 311        if (!j) return i;
 312  
 313        *result = sign*value;
 314        return i + j;

 315     }

 316  
 317  
 318     /**
 319      * Wrapper of `size_t` for selecting `ascii_to` specialization
 320      */

 321     class Number_of_bytes
 322     {
 323        size_t _n;
 324  
 325        public:
 326  
 327           /**
 328            * Default constructor
 329            */

 330           Number_of_bytes() : _n(0) { }

 331  
 332           /**
 333            * Constructor, to be used implicitly via assignment operator
 334            */

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

 336  
 337           /**
 338            * Convert number of bytes to `size_t` value
 339            */

 340           operator size_t() const { return _n; }

 341     }
;

 342  
 343  
 344     /**
 345      * Read `Number_of_bytes` value from string and handle the size suffixes
 346      *
 347      * This function scales the resulting size value according to the suffixes
 348      * for G (2^30), M (2^20), and K (2^10) if present.
 349      */

 350     template <>
 351     inline size_t ascii_to(const char *s, Number_of_bytes *result, unsigned)
 352     {
 353        unsigned long res = 0;
 354  
 355        /* convert numeric part of string */

 356        int i = ascii_to(s, &res, 0);
 357  
 358        /* handle suffixes */

 359        if (> 0)
 360           switch (s[i]) {
 361           case `G`: res *= 1024;
 362           case `M`: res *= 1024;
 363           case `K`: res *= 1024; i++;
 364           default: break;
 365           }

 366  
 367        *result = res;
 368        return i;

 369     }

 370  
 371  
 372     /**
 373      * Read double float value from string
 374      */

 375     template <>
 376     inline size_t ascii_to<double>(const char *s, double *result, unsigned)
 377     {
 378        double v = 0.0;    /* decimal part              */
 379        double d = 0.1;    /* power of fractional digit */
 380        bool neg = false;  /* sign                      */
 381        int    i = 0;      /* character counter         */
 382  
 383        if (s[i] == `-`) {
 384           neg = true;
 385           i++;

 386        }

 387  
 388        /* parse decimal part of number */
 389        for (; s[i] && is_digit(s[i]); i++)
 390           = 10*+ digit(s[i], false);

 391  
 392        /* if no fractional part exists, return current value */
 393        if (s[i] != `.`) {
 394           *result = neg ? -v : v;
 395           return i;

 396        }

 397  
 398        /* skip comma */
 399        i++;
 400  
 401        /* parse fractional part of number */
 402        for (; s[i] && is_digit(s[i]); i++, d *= 0.1)
 403           += d*digit(s[i], false);

 404  
 405        *result = neg ? -v : v;
 406        return i;

 407     }

 408  
 409  
 410     /**
 411      * Check for end of quotation
 412      *
 413      * Checks if next character is non-backslashed quotation mark.
 414      */

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

 417  
 418  
 419     /**
 420      * Unpack quoted string
 421      *
 422      * \param src   source string including the quotation marks ("...")
 423      * \param dst   destination buffer
 424      *
 425      * \return      number of characters or negative error code
 426      */

 427     inline int unpack_string(const char *src, char *dst, int dst_len)
 428     {
 429        /* check if quoted string */
 430        if (*src != `"`) return -1;
 431  
 432        src++;
 433  
 434        int i = 0;
 435        for (*src && !end_of_quote(src - 1) && (< dst_len - 1); i++) {
 436  
 437           /* transform `\"` to `"` */
 438           if (src[0] == `\\` && src[1] == `\"`) {
 439              *dst++ = `"`;
 440              src += 2;

 441           }
 else
 442              *dst++ = *src++;

 443        }

 444  
 445        /* write terminating null */
 446        *dst = 0;
 447  
 448        return i;

 449     }

 450  
 451     /**
 452      * Buffer that contains a null-terminated string
 453      *
 454      * \param CAPACITY  buffer size including the terminating zero
 455      */

 456     template <size_t CAPACITY>
 457     class String
 458     {
 459        private:
 460  
 461           char   _buf[CAPACITY];
 462           size_t _length;

 463  
 464        public:
 465  
 466           constexpr static size_t size() { return CAPACITY; }
 467  
 468           String() : _length(0) { }
 469  
 470           String(char const *str, size_t len = ~0UL - 1)
 471           :
 472              _length(min(len + 1, min(strlen(str) + 1, CAPACITY)))

 473           {
 474              strncpy(_buf, str, _length);
 475           }

 476  
 477           size_t length() const { return _length; }

 478  
 479           static constexpr size_t capacity() { return CAPACITY; }
 480  
 481           bool valid() const {
 482              return (_length <= CAPACITY) && (_length != 0) && (_buf[_length - 1] == `\0`); }

 483  
 484           char const *string() const { return valid() ? _buf : ""; }
 485  
 486           template <size_t OTHER_CAPACITY>
 487           bool operator == (String<OTHER_CAPACITY> const &other) const
 488           
{
 489              return strcmp(string(), other.string()) == 0;
 490           }

 491     }
;

 492  }

 493  
 494  #endif /* _INCLUDE__UTIL__STRING_H_ */