OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * |
| 3 * Copyright 2015, Google Inc. |
| 4 * All rights reserved. |
| 5 * |
| 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions are |
| 8 * met: |
| 9 * |
| 10 * * Redistributions of source code must retain the above copyright |
| 11 * notice, this list of conditions and the following disclaimer. |
| 12 * * Redistributions in binary form must reproduce the above |
| 13 * copyright notice, this list of conditions and the following disclaimer |
| 14 * in the documentation and/or other materials provided with the |
| 15 * distribution. |
| 16 * * Neither the name of Google Inc. nor the names of its |
| 17 * contributors may be used to endorse or promote products derived from |
| 18 * this software without specific prior written permission. |
| 19 * |
| 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 * |
| 32 */ |
| 33 |
| 34 #include "src/core/support/string.h" |
| 35 |
| 36 #include <ctype.h> |
| 37 #include <stddef.h> |
| 38 #include <string.h> |
| 39 |
| 40 #include <grpc/support/alloc.h> |
| 41 #include <grpc/support/log.h> |
| 42 #include <grpc/support/port_platform.h> |
| 43 #include <grpc/support/useful.h> |
| 44 |
| 45 char *gpr_strdup(const char *src) { |
| 46 char *dst; |
| 47 size_t len; |
| 48 |
| 49 if (!src) { |
| 50 return NULL; |
| 51 } |
| 52 |
| 53 len = strlen(src) + 1; |
| 54 dst = gpr_malloc(len); |
| 55 |
| 56 memcpy(dst, src, len); |
| 57 |
| 58 return dst; |
| 59 } |
| 60 |
| 61 typedef struct { |
| 62 size_t capacity; |
| 63 size_t length; |
| 64 char *data; |
| 65 } dump_out; |
| 66 |
| 67 static dump_out dump_out_create(void) { |
| 68 dump_out r = {0, 0, NULL}; |
| 69 return r; |
| 70 } |
| 71 |
| 72 static void dump_out_append(dump_out *out, char c) { |
| 73 if (out->length == out->capacity) { |
| 74 out->capacity = GPR_MAX(8, 2 * out->capacity); |
| 75 out->data = gpr_realloc(out->data, out->capacity); |
| 76 } |
| 77 out->data[out->length++] = c; |
| 78 } |
| 79 |
| 80 static void hexdump(dump_out *out, const char *buf, size_t len) { |
| 81 static const char hex[16] = "0123456789abcdef"; |
| 82 |
| 83 const uint8_t *const beg = (const uint8_t *)buf; |
| 84 const uint8_t *const end = beg + len; |
| 85 const uint8_t *cur; |
| 86 |
| 87 for (cur = beg; cur != end; ++cur) { |
| 88 if (cur != beg) dump_out_append(out, ' '); |
| 89 dump_out_append(out, hex[*cur >> 4]); |
| 90 dump_out_append(out, hex[*cur & 0xf]); |
| 91 } |
| 92 } |
| 93 |
| 94 static void asciidump(dump_out *out, const char *buf, size_t len) { |
| 95 const uint8_t *const beg = (const uint8_t *)buf; |
| 96 const uint8_t *const end = beg + len; |
| 97 const uint8_t *cur; |
| 98 int out_was_empty = (out->length == 0); |
| 99 if (!out_was_empty) { |
| 100 dump_out_append(out, ' '); |
| 101 dump_out_append(out, '\''); |
| 102 } |
| 103 for (cur = beg; cur != end; ++cur) { |
| 104 dump_out_append(out, (char)(isprint(*cur) ? *(char *)cur : '.')); |
| 105 } |
| 106 if (!out_was_empty) { |
| 107 dump_out_append(out, '\''); |
| 108 } |
| 109 } |
| 110 |
| 111 char *gpr_dump(const char *buf, size_t len, uint32_t flags) { |
| 112 dump_out out = dump_out_create(); |
| 113 if (flags & GPR_DUMP_HEX) { |
| 114 hexdump(&out, buf, len); |
| 115 } |
| 116 if (flags & GPR_DUMP_ASCII) { |
| 117 asciidump(&out, buf, len); |
| 118 } |
| 119 dump_out_append(&out, 0); |
| 120 return out.data; |
| 121 } |
| 122 |
| 123 char *gpr_dump_slice(gpr_slice s, uint32_t flags) { |
| 124 return gpr_dump((const char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s), |
| 125 flags); |
| 126 } |
| 127 |
| 128 int gpr_parse_bytes_to_uint32(const char *buf, size_t len, uint32_t *result) { |
| 129 uint32_t out = 0; |
| 130 uint32_t new; |
| 131 size_t i; |
| 132 |
| 133 if (len == 0) return 0; /* must have some bytes */ |
| 134 |
| 135 for (i = 0; i < len; i++) { |
| 136 if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */ |
| 137 new = 10 * out + (uint32_t)(buf[i] - '0'); |
| 138 if (new < out) return 0; /* overflow */ |
| 139 out = new; |
| 140 } |
| 141 |
| 142 *result = out; |
| 143 return 1; |
| 144 } |
| 145 |
| 146 void gpr_reverse_bytes(char *str, int len) { |
| 147 char *p1, *p2; |
| 148 for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) { |
| 149 char temp = *p1; |
| 150 *p1 = *p2; |
| 151 *p2 = temp; |
| 152 } |
| 153 } |
| 154 |
| 155 int gpr_ltoa(long value, char *string) { |
| 156 long sign; |
| 157 int i = 0; |
| 158 |
| 159 if (value == 0) { |
| 160 string[0] = '0'; |
| 161 string[1] = 0; |
| 162 return 1; |
| 163 } |
| 164 |
| 165 sign = value < 0 ? -1 : 1; |
| 166 while (value) { |
| 167 string[i++] = (char)('0' + sign * (value % 10)); |
| 168 value /= 10; |
| 169 } |
| 170 if (sign < 0) string[i++] = '-'; |
| 171 gpr_reverse_bytes(string, i); |
| 172 string[i] = 0; |
| 173 return i; |
| 174 } |
| 175 |
| 176 int int64_ttoa(int64_t value, char *string) { |
| 177 int64_t sign; |
| 178 int i = 0; |
| 179 |
| 180 if (value == 0) { |
| 181 string[0] = '0'; |
| 182 string[1] = 0; |
| 183 return 1; |
| 184 } |
| 185 |
| 186 sign = value < 0 ? -1 : 1; |
| 187 while (value) { |
| 188 string[i++] = (char)('0' + sign * (value % 10)); |
| 189 value /= 10; |
| 190 } |
| 191 if (sign < 0) string[i++] = '-'; |
| 192 gpr_reverse_bytes(string, i); |
| 193 string[i] = 0; |
| 194 return i; |
| 195 } |
| 196 |
| 197 char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) { |
| 198 return gpr_strjoin_sep(strs, nstrs, "", final_length); |
| 199 } |
| 200 |
| 201 char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep, |
| 202 size_t *final_length) { |
| 203 const size_t sep_len = strlen(sep); |
| 204 size_t out_length = 0; |
| 205 size_t i; |
| 206 char *out; |
| 207 for (i = 0; i < nstrs; i++) { |
| 208 out_length += strlen(strs[i]); |
| 209 } |
| 210 out_length += 1; /* null terminator */ |
| 211 if (nstrs > 0) { |
| 212 out_length += sep_len * (nstrs - 1); /* separators */ |
| 213 } |
| 214 out = gpr_malloc(out_length); |
| 215 out_length = 0; |
| 216 for (i = 0; i < nstrs; i++) { |
| 217 const size_t slen = strlen(strs[i]); |
| 218 if (i != 0) { |
| 219 memcpy(out + out_length, sep, sep_len); |
| 220 out_length += sep_len; |
| 221 } |
| 222 memcpy(out + out_length, strs[i], slen); |
| 223 out_length += slen; |
| 224 } |
| 225 out[out_length] = 0; |
| 226 if (final_length != NULL) { |
| 227 *final_length = out_length; |
| 228 } |
| 229 return out; |
| 230 } |
| 231 |
| 232 /** Finds the initial (\a begin) and final (\a end) offsets of the next |
| 233 * substring from \a str + \a read_offset until the next \a sep or the end of \a |
| 234 * str. |
| 235 * |
| 236 * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */ |
| 237 static int slice_find_separator_offset(const gpr_slice str, const char *sep, |
| 238 const size_t read_offset, size_t *begin, |
| 239 size_t *end) { |
| 240 size_t i; |
| 241 const uint8_t *str_ptr = GPR_SLICE_START_PTR(str) + read_offset; |
| 242 const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset; |
| 243 const size_t sep_len = strlen(sep); |
| 244 if (str_len < sep_len) { |
| 245 return 0; |
| 246 } |
| 247 |
| 248 for (i = 0; i <= str_len - sep_len; i++) { |
| 249 if (memcmp(str_ptr + i, sep, sep_len) == 0) { |
| 250 *begin = read_offset; |
| 251 *end = read_offset + i; |
| 252 return 1; |
| 253 } |
| 254 } |
| 255 return 0; |
| 256 } |
| 257 |
| 258 void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) { |
| 259 const size_t sep_len = strlen(sep); |
| 260 size_t begin, end; |
| 261 |
| 262 GPR_ASSERT(sep_len > 0); |
| 263 |
| 264 if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) { |
| 265 do { |
| 266 gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end)); |
| 267 } while (slice_find_separator_offset(str, sep, end + sep_len, &begin, |
| 268 &end) != 0); |
| 269 gpr_slice_buffer_add_indexed( |
| 270 dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str))); |
| 271 } else { /* no sep found, add whole input */ |
| 272 gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str)); |
| 273 } |
| 274 } |
| 275 |
| 276 void gpr_strvec_init(gpr_strvec *sv) { memset(sv, 0, sizeof(*sv)); } |
| 277 |
| 278 void gpr_strvec_destroy(gpr_strvec *sv) { |
| 279 size_t i; |
| 280 for (i = 0; i < sv->count; i++) { |
| 281 gpr_free(sv->strs[i]); |
| 282 } |
| 283 gpr_free(sv->strs); |
| 284 } |
| 285 |
| 286 void gpr_strvec_add(gpr_strvec *sv, char *str) { |
| 287 if (sv->count == sv->capacity) { |
| 288 sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2); |
| 289 sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity); |
| 290 } |
| 291 sv->strs[sv->count++] = str; |
| 292 } |
| 293 |
| 294 char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) { |
| 295 return gpr_strjoin((const char **)sv->strs, sv->count, final_length); |
| 296 } |
OLD | NEW |