Home | History | Annotate | Download | only in gpr
      1 /*
      2  *
      3  * Copyright 2015 gRPC authors.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  */
     18 
     19 #include <grpc/support/port_platform.h>
     20 
     21 #include "src/core/lib/gpr/string.h"
     22 
     23 #include <ctype.h>
     24 #include <limits.h>
     25 #include <stddef.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <time.h>
     30 
     31 #include <grpc/support/alloc.h>
     32 #include <grpc/support/log.h>
     33 #include <grpc/support/string_util.h>
     34 
     35 #include "src/core/lib/gpr/useful.h"
     36 
     37 char* gpr_strdup(const char* src) {
     38   char* dst;
     39   size_t len;
     40 
     41   if (!src) {
     42     return nullptr;
     43   }
     44 
     45   len = strlen(src) + 1;
     46   dst = static_cast<char*>(gpr_malloc(len));
     47 
     48   memcpy(dst, src, len);
     49 
     50   return dst;
     51 }
     52 
     53 typedef struct {
     54   size_t capacity;
     55   size_t length;
     56   char* data;
     57 } dump_out;
     58 
     59 char* gpr_format_timespec(gpr_timespec tm) {
     60   char time_buffer[35];
     61   char ns_buffer[11];  // '.' + 9 digits of precision
     62   struct tm* tm_info = localtime((const time_t*)&tm.tv_sec);
     63   strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", tm_info);
     64   snprintf(ns_buffer, 11, ".%09d", tm.tv_nsec);
     65   // This loop trims off trailing zeros by inserting a null character that the
     66   // right point. We iterate in chunks of three because we want 0, 3, 6, or 9
     67   // fractional digits.
     68   for (int i = 7; i >= 1; i -= 3) {
     69     if (ns_buffer[i] == '0' && ns_buffer[i + 1] == '0' &&
     70         ns_buffer[i + 2] == '0') {
     71       ns_buffer[i] = '\0';
     72       // Edge case in which all fractional digits were 0.
     73       if (i == 1) {
     74         ns_buffer[0] = '\0';
     75       }
     76     } else {
     77       break;
     78     }
     79   }
     80   char* full_time_str;
     81   gpr_asprintf(&full_time_str, "%s%sZ", time_buffer, ns_buffer);
     82   return full_time_str;
     83 }
     84 
     85 static dump_out dump_out_create(void) {
     86   dump_out r = {0, 0, nullptr};
     87   return r;
     88 }
     89 
     90 static void dump_out_append(dump_out* out, char c) {
     91   if (out->length == out->capacity) {
     92     out->capacity = GPR_MAX(8, 2 * out->capacity);
     93     out->data = static_cast<char*>(gpr_realloc(out->data, out->capacity));
     94   }
     95   out->data[out->length++] = c;
     96 }
     97 
     98 static void hexdump(dump_out* out, const char* buf, size_t len) {
     99   static const char* hex = "0123456789abcdef";
    100 
    101   const uint8_t* const beg = reinterpret_cast<const uint8_t*>(buf);
    102   const uint8_t* const end = beg + len;
    103   const uint8_t* cur;
    104 
    105   for (cur = beg; cur != end; ++cur) {
    106     if (cur != beg) dump_out_append(out, ' ');
    107     dump_out_append(out, hex[*cur >> 4]);
    108     dump_out_append(out, hex[*cur & 0xf]);
    109   }
    110 }
    111 
    112 static void asciidump(dump_out* out, const char* buf, size_t len) {
    113   const uint8_t* const beg = reinterpret_cast<const uint8_t*>(buf);
    114   const uint8_t* const end = beg + len;
    115   const uint8_t* cur;
    116   int out_was_empty = (out->length == 0);
    117   if (!out_was_empty) {
    118     dump_out_append(out, ' ');
    119     dump_out_append(out, '\'');
    120   }
    121   for (cur = beg; cur != end; ++cur) {
    122     dump_out_append(out, (isprint(*cur) ? *(char*)cur : '.'));
    123   }
    124   if (!out_was_empty) {
    125     dump_out_append(out, '\'');
    126   }
    127 }
    128 
    129 char* gpr_dump(const char* buf, size_t len, uint32_t flags) {
    130   dump_out out = dump_out_create();
    131   if (flags & GPR_DUMP_HEX) {
    132     hexdump(&out, buf, len);
    133   }
    134   if (flags & GPR_DUMP_ASCII) {
    135     asciidump(&out, buf, len);
    136   }
    137   dump_out_append(&out, 0);
    138   return out.data;
    139 }
    140 
    141 int gpr_parse_bytes_to_uint32(const char* buf, size_t len, uint32_t* result) {
    142   uint32_t out = 0;
    143   uint32_t new_val;
    144   size_t i;
    145 
    146   if (len == 0) return 0; /* must have some bytes */
    147 
    148   for (i = 0; i < len; i++) {
    149     if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */
    150     new_val = 10 * out + static_cast<uint32_t>(buf[i] - '0');
    151     if (new_val < out) return 0; /* overflow */
    152     out = new_val;
    153   }
    154 
    155   *result = out;
    156   return 1;
    157 }
    158 
    159 void gpr_reverse_bytes(char* str, int len) {
    160   char *p1, *p2;
    161   for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) {
    162     char temp = *p1;
    163     *p1 = *p2;
    164     *p2 = temp;
    165   }
    166 }
    167 
    168 int gpr_ltoa(long value, char* string) {
    169   long sign;
    170   int i = 0;
    171 
    172   if (value == 0) {
    173     string[0] = '0';
    174     string[1] = 0;
    175     return 1;
    176   }
    177 
    178   sign = value < 0 ? -1 : 1;
    179   while (value) {
    180     string[i++] = static_cast<char>('0' + sign * (value % 10));
    181     value /= 10;
    182   }
    183   if (sign < 0) string[i++] = '-';
    184   gpr_reverse_bytes(string, i);
    185   string[i] = 0;
    186   return i;
    187 }
    188 
    189 int int64_ttoa(int64_t value, char* string) {
    190   int64_t sign;
    191   int i = 0;
    192 
    193   if (value == 0) {
    194     string[0] = '0';
    195     string[1] = 0;
    196     return 1;
    197   }
    198 
    199   sign = value < 0 ? -1 : 1;
    200   while (value) {
    201     string[i++] = static_cast<char>('0' + sign * (value % 10));
    202     value /= 10;
    203   }
    204   if (sign < 0) string[i++] = '-';
    205   gpr_reverse_bytes(string, i);
    206   string[i] = 0;
    207   return i;
    208 }
    209 
    210 int gpr_parse_nonnegative_int(const char* value) {
    211   char* end;
    212   long result = strtol(value, &end, 0);
    213   if (*end != '\0' || result < 0 || result > INT_MAX) return -1;
    214   return static_cast<int>(result);
    215 }
    216 
    217 char* gpr_leftpad(const char* str, char flag, size_t length) {
    218   const size_t str_length = strlen(str);
    219   const size_t out_length = str_length > length ? str_length : length;
    220   char* out = static_cast<char*>(gpr_malloc(out_length + 1));
    221   memset(out, flag, out_length - str_length);
    222   memcpy(out + out_length - str_length, str, str_length);
    223   out[out_length] = 0;
    224   return out;
    225 }
    226 
    227 char* gpr_strjoin(const char** strs, size_t nstrs, size_t* final_length) {
    228   return gpr_strjoin_sep(strs, nstrs, "", final_length);
    229 }
    230 
    231 char* gpr_strjoin_sep(const char** strs, size_t nstrs, const char* sep,
    232                       size_t* final_length) {
    233   const size_t sep_len = strlen(sep);
    234   size_t out_length = 0;
    235   size_t i;
    236   char* out;
    237   for (i = 0; i < nstrs; i++) {
    238     out_length += strlen(strs[i]);
    239   }
    240   out_length += 1; /* null terminator */
    241   if (nstrs > 0) {
    242     out_length += sep_len * (nstrs - 1); /* separators */
    243   }
    244   out = static_cast<char*>(gpr_malloc(out_length));
    245   out_length = 0;
    246   for (i = 0; i < nstrs; i++) {
    247     const size_t slen = strlen(strs[i]);
    248     if (i != 0) {
    249       memcpy(out + out_length, sep, sep_len);
    250       out_length += sep_len;
    251     }
    252     memcpy(out + out_length, strs[i], slen);
    253     out_length += slen;
    254   }
    255   out[out_length] = 0;
    256   if (final_length != nullptr) {
    257     *final_length = out_length;
    258   }
    259   return out;
    260 }
    261 
    262 void gpr_strvec_init(gpr_strvec* sv) { memset(sv, 0, sizeof(*sv)); }
    263 
    264 void gpr_strvec_destroy(gpr_strvec* sv) {
    265   size_t i;
    266   for (i = 0; i < sv->count; i++) {
    267     gpr_free(sv->strs[i]);
    268   }
    269   gpr_free(sv->strs);
    270 }
    271 
    272 void gpr_strvec_add(gpr_strvec* sv, char* str) {
    273   if (sv->count == sv->capacity) {
    274     sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2);
    275     sv->strs = static_cast<char**>(
    276         gpr_realloc(sv->strs, sizeof(char*) * sv->capacity));
    277   }
    278   sv->strs[sv->count++] = str;
    279 }
    280 
    281 char* gpr_strvec_flatten(gpr_strvec* sv, size_t* final_length) {
    282   return gpr_strjoin((const char**)sv->strs, sv->count, final_length);
    283 }
    284 
    285 int gpr_stricmp(const char* a, const char* b) {
    286   int ca, cb;
    287   do {
    288     ca = tolower(*a);
    289     cb = tolower(*b);
    290     ++a;
    291     ++b;
    292   } while (ca == cb && ca && cb);
    293   return ca - cb;
    294 }
    295 
    296 static void add_string_to_split(const char* beg, const char* end, char*** strs,
    297                                 size_t* nstrs, size_t* capstrs) {
    298   char* out =
    299       static_cast<char*>(gpr_malloc(static_cast<size_t>(end - beg) + 1));
    300   memcpy(out, beg, static_cast<size_t>(end - beg));
    301   out[end - beg] = 0;
    302   if (*nstrs == *capstrs) {
    303     *capstrs = GPR_MAX(8, 2 * *capstrs);
    304     *strs = static_cast<char**>(gpr_realloc(*strs, sizeof(*strs) * *capstrs));
    305   }
    306   (*strs)[*nstrs] = out;
    307   ++*nstrs;
    308 }
    309 
    310 void gpr_string_split(const char* input, const char* sep, char*** strs,
    311                       size_t* nstrs) {
    312   const char* next;
    313   *strs = nullptr;
    314   *nstrs = 0;
    315   size_t capstrs = 0;
    316   while ((next = strstr(input, sep))) {
    317     add_string_to_split(input, next, strs, nstrs, &capstrs);
    318     input = next + strlen(sep);
    319   }
    320   add_string_to_split(input, input + strlen(input), strs, nstrs, &capstrs);
    321 }
    322 
    323 void* gpr_memrchr(const void* s, int c, size_t n) {
    324   if (s == nullptr) return nullptr;
    325   char* b = (char*)s;
    326   size_t i;
    327   for (i = 0; i < n; i++) {
    328     if (b[n - i - 1] == c) {
    329       return &b[n - i - 1];
    330     }
    331   }
    332   return nullptr;
    333 }
    334 
    335 bool gpr_is_true(const char* s) {
    336   size_t i;
    337   if (s == nullptr) {
    338     return false;
    339   }
    340   static const char* truthy[] = {"yes", "true", "1"};
    341   for (i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
    342     if (0 == gpr_stricmp(s, truthy[i])) {
    343       return true;
    344     }
    345   }
    346   return false;
    347 }
    348