linux/tools/lib/string.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  linux/tools/lib/string.c
   4 *
   5 *  Copied from linux/lib/string.c, where it is:
   6 *
   7 *  Copyright (C) 1991, 1992  Linus Torvalds
   8 *
   9 *  More specifically, the first copied function was strtobool, which
  10 *  was introduced by:
  11 *
  12 *  d0f1fed29e6e ("Add a strtobool function matching semantics of existing in kernel equivalents")
  13 *  Author: Jonathan Cameron <jic23@cam.ac.uk>
  14 */
  15
  16#include <stdlib.h>
  17#include <string.h>
  18#include <errno.h>
  19#include <linux/string.h>
  20#include <linux/ctype.h>
  21#include <linux/compiler.h>
  22
  23/**
  24 * memdup - duplicate region of memory
  25 *
  26 * @src: memory region to duplicate
  27 * @len: memory region length
  28 */
  29void *memdup(const void *src, size_t len)
  30{
  31        void *p = malloc(len);
  32
  33        if (p)
  34                memcpy(p, src, len);
  35
  36        return p;
  37}
  38
  39/**
  40 * strtobool - convert common user inputs into boolean values
  41 * @s: input string
  42 * @res: result
  43 *
  44 * This routine returns 0 iff the first character is one of 'Yy1Nn0', or
  45 * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL.  Value
  46 * pointed to by res is updated upon finding a match.
  47 */
  48int strtobool(const char *s, bool *res)
  49{
  50        if (!s)
  51                return -EINVAL;
  52
  53        switch (s[0]) {
  54        case 'y':
  55        case 'Y':
  56        case '1':
  57                *res = true;
  58                return 0;
  59        case 'n':
  60        case 'N':
  61        case '0':
  62                *res = false;
  63                return 0;
  64        case 'o':
  65        case 'O':
  66                switch (s[1]) {
  67                case 'n':
  68                case 'N':
  69                        *res = true;
  70                        return 0;
  71                case 'f':
  72                case 'F':
  73                        *res = false;
  74                        return 0;
  75                default:
  76                        break;
  77                }
  78        default:
  79                break;
  80        }
  81
  82        return -EINVAL;
  83}
  84
  85/**
  86 * strlcpy - Copy a C-string into a sized buffer
  87 * @dest: Where to copy the string to
  88 * @src: Where to copy the string from
  89 * @size: size of destination buffer
  90 *
  91 * Compatible with *BSD: the result is always a valid
  92 * NUL-terminated string that fits in the buffer (unless,
  93 * of course, the buffer size is zero). It does not pad
  94 * out the result like strncpy() does.
  95 *
  96 * If libc has strlcpy() then that version will override this
  97 * implementation:
  98 */
  99#ifdef __clang__
 100#pragma clang diagnostic push
 101#pragma clang diagnostic ignored "-Wignored-attributes"
 102#endif
 103size_t __weak strlcpy(char *dest, const char *src, size_t size)
 104{
 105        size_t ret = strlen(src);
 106
 107        if (size) {
 108                size_t len = (ret >= size) ? size - 1 : ret;
 109                memcpy(dest, src, len);
 110                dest[len] = '\0';
 111        }
 112        return ret;
 113}
 114#ifdef __clang__
 115#pragma clang diagnostic pop
 116#endif
 117
 118/**
 119 * skip_spaces - Removes leading whitespace from @str.
 120 * @str: The string to be stripped.
 121 *
 122 * Returns a pointer to the first non-whitespace character in @str.
 123 */
 124char *skip_spaces(const char *str)
 125{
 126        while (isspace(*str))
 127                ++str;
 128        return (char *)str;
 129}
 130
 131/**
 132 * strim - Removes leading and trailing whitespace from @s.
 133 * @s: The string to be stripped.
 134 *
 135 * Note that the first trailing whitespace is replaced with a %NUL-terminator
 136 * in the given string @s. Returns a pointer to the first non-whitespace
 137 * character in @s.
 138 */
 139char *strim(char *s)
 140{
 141        size_t size;
 142        char *end;
 143
 144        size = strlen(s);
 145        if (!size)
 146                return s;
 147
 148        end = s + size - 1;
 149        while (end >= s && isspace(*end))
 150                end--;
 151        *(end + 1) = '\0';
 152
 153        return skip_spaces(s);
 154}
 155
 156/**
 157 * strreplace - Replace all occurrences of character in string.
 158 * @s: The string to operate on.
 159 * @old: The character being replaced.
 160 * @new: The character @old is replaced with.
 161 *
 162 * Returns pointer to the nul byte at the end of @s.
 163 */
 164char *strreplace(char *s, char old, char new)
 165{
 166        for (; *s; ++s)
 167                if (*s == old)
 168                        *s = new;
 169        return s;
 170}
 171
 172static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes)
 173{
 174        while (bytes) {
 175                if (*start != value)
 176                        return (void *)start;
 177                start++;
 178                bytes--;
 179        }
 180        return NULL;
 181}
 182
 183/**
 184 * memchr_inv - Find an unmatching character in an area of memory.
 185 * @start: The memory area
 186 * @c: Find a character other than c
 187 * @bytes: The size of the area.
 188 *
 189 * returns the address of the first character other than @c, or %NULL
 190 * if the whole buffer contains just @c.
 191 */
 192void *memchr_inv(const void *start, int c, size_t bytes)
 193{
 194        u8 value = c;
 195        u64 value64;
 196        unsigned int words, prefix;
 197
 198        if (bytes <= 16)
 199                return check_bytes8(start, value, bytes);
 200
 201        value64 = value;
 202        value64 |= value64 << 8;
 203        value64 |= value64 << 16;
 204        value64 |= value64 << 32;
 205
 206        prefix = (unsigned long)start % 8;
 207        if (prefix) {
 208                u8 *r;
 209
 210                prefix = 8 - prefix;
 211                r = check_bytes8(start, value, prefix);
 212                if (r)
 213                        return r;
 214                start += prefix;
 215                bytes -= prefix;
 216        }
 217
 218        words = bytes / 8;
 219
 220        while (words) {
 221                if (*(u64 *)start != value64)
 222                        return check_bytes8(start, value, 8);
 223                start += 8;
 224                words--;
 225        }
 226
 227        return check_bytes8(start, value, bytes % 8);
 228}
 229