gitee.com/mysnapcore/mysnapd@v0.1.0/cmd/libsnap-confine-private/string-utils.c (about) 1 /* 2 * Copyright (C) 2016-2017 Canonical Ltd 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 */ 17 18 #include "string-utils.h" 19 20 #include <errno.h> 21 #include <stdarg.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 #include "utils.h" 26 27 bool sc_streq(const char *a, const char *b) 28 { 29 if (!a || !b) { 30 return false; 31 } 32 33 return strcmp(a, b) == 0; 34 } 35 36 bool sc_endswith(const char *str, const char *suffix) 37 { 38 if (!str || !suffix) { 39 return false; 40 } 41 42 size_t xlen = strlen(suffix); 43 size_t slen = strlen(str); 44 45 if (slen < xlen) { 46 return false; 47 } 48 49 return strncmp(str - xlen + slen, suffix, xlen) == 0; 50 } 51 52 bool sc_startswith(const char *str, const char *prefix) 53 { 54 if (!str || !prefix) { 55 return false; 56 } 57 58 size_t xlen = strlen(prefix); 59 return strncmp(str, prefix, xlen) == 0; 60 } 61 62 char *sc_strdup(const char *str) 63 { 64 // Set errno in case we die. 65 errno = 0; 66 size_t len; 67 char *copy; 68 if (str == NULL) { 69 die("cannot duplicate NULL string"); 70 } 71 len = strlen(str); 72 copy = malloc(len + 1); 73 if (copy == NULL) { 74 die("cannot allocate string copy (len: %zd)", len); 75 } 76 memcpy(copy, str, len + 1); 77 return copy; 78 } 79 80 int sc_must_snprintf(char *str, size_t size, const char *format, ...) 81 { 82 // Set errno in case we die. 83 errno = 0; 84 int n; 85 86 va_list va; 87 va_start(va, format); 88 n = vsnprintf(str, size, format, va); 89 va_end(va); 90 91 if (n < 0 || (size_t)n >= size) 92 die("cannot format string: %s", str); 93 94 return n; 95 } 96 97 size_t sc_string_append(char *dst, size_t dst_size, const char *str) 98 { 99 // Set errno in case we die. 100 errno = 0; 101 if (dst == NULL) { 102 die("cannot append string: buffer is NULL"); 103 } 104 if (str == NULL) { 105 die("cannot append string: string is NULL"); 106 } 107 size_t dst_len = strnlen(dst, dst_size); 108 if (dst_len == dst_size) { 109 die("cannot append string: dst is unterminated"); 110 } 111 112 size_t max_str_len = dst_size - dst_len; 113 size_t str_len = strnlen(str, max_str_len); 114 if (str_len == max_str_len) { 115 die("cannot append string: str is too long or unterminated"); 116 } 117 // Append the string 118 memcpy(dst + dst_len, str, str_len); 119 // Ensure we are terminated 120 dst[dst_len + str_len] = '\0'; 121 // return the new size 122 return strlen(dst); 123 } 124 125 size_t sc_string_append_char(char *dst, size_t dst_size, char c) 126 { 127 // Set errno in case we die. 128 errno = 0; 129 if (dst == NULL) { 130 die("cannot append character: buffer is NULL"); 131 } 132 size_t dst_len = strnlen(dst, dst_size); 133 if (dst_len == dst_size) { 134 die("cannot append character: dst is unterminated"); 135 } 136 size_t max_str_len = dst_size - dst_len; 137 if (max_str_len < 2) { 138 die("cannot append character: not enough space"); 139 } 140 if (c == 0) { 141 die("cannot append character: cannot append string terminator"); 142 } 143 // Append the character and terminate the string. 144 dst[dst_len + 0] = c; 145 dst[dst_len + 1] = '\0'; 146 // Return the new size 147 return dst_len + 1; 148 } 149 150 size_t sc_string_append_char_pair(char *dst, size_t dst_size, char c1, char c2) 151 { 152 // Set errno in case we die. 153 errno = 0; 154 if (dst == NULL) { 155 die("cannot append character pair: buffer is NULL"); 156 } 157 size_t dst_len = strnlen(dst, dst_size); 158 if (dst_len == dst_size) { 159 die("cannot append character pair: dst is unterminated"); 160 } 161 size_t max_str_len = dst_size - dst_len; 162 if (max_str_len < 3) { 163 die("cannot append character pair: not enough space"); 164 } 165 if (c1 == 0 || c2 == 0) { 166 die("cannot append character pair: cannot append string terminator"); 167 } 168 // Append the two characters and terminate the string. 169 dst[dst_len + 0] = c1; 170 dst[dst_len + 1] = c2; 171 dst[dst_len + 2] = '\0'; 172 // Return the new size 173 return dst_len + 2; 174 } 175 176 void sc_string_init(char *buf, size_t buf_size) 177 { 178 errno = 0; 179 if (buf == NULL) { 180 die("cannot initialize string, buffer is NULL"); 181 } 182 if (buf_size == 0) { 183 die("cannot initialize string, buffer is too small"); 184 } 185 buf[0] = '\0'; 186 } 187 188 void sc_string_quote(char *buf, size_t buf_size, const char *str) 189 { 190 // Set errno in case we die. 191 errno = 0; 192 if (str == NULL) { 193 die("cannot quote string: string is NULL"); 194 } 195 const char *hex = "0123456789abcdef"; 196 // NOTE: this also checks buf/buf_size sanity so that we don't have to. 197 sc_string_init(buf, buf_size); 198 sc_string_append_char(buf, buf_size, '"'); 199 for (unsigned char c; (c = *str) != 0; ++str) { 200 switch (c) { 201 // Pass ASCII letters and digits unmodified. 202 case '0' ... '9': 203 case 'A' ... 'Z': 204 case 'a' ... 'z': 205 // Pass most of the punctuation unmodified. 206 case ' ': 207 case '!': 208 case '#': 209 case '$': 210 case '%': 211 case '&': 212 case '(': 213 case ')': 214 case '*': 215 case '+': 216 case ',': 217 case '-': 218 case '.': 219 case '/': 220 case ':': 221 case ';': 222 case '<': 223 case '=': 224 case '>': 225 case '?': 226 case '@': 227 case '[': 228 case '\'': 229 case ']': 230 case '^': 231 case '_': 232 case '`': 233 case '{': 234 case '|': 235 case '}': 236 case '~': 237 sc_string_append_char(buf, buf_size, c); 238 break; 239 // Escape special whitespace characters. 240 case '\n': 241 sc_string_append_char_pair(buf, buf_size, '\\', 'n'); 242 break; 243 case '\r': 244 sc_string_append_char_pair(buf, buf_size, '\\', 'r'); 245 break; 246 case '\t': 247 sc_string_append_char_pair(buf, buf_size, '\\', 't'); 248 break; 249 case '\v': 250 sc_string_append_char_pair(buf, buf_size, '\\', 'v'); 251 break; 252 // Escape the escape character. 253 case '\\': 254 sc_string_append_char_pair(buf, buf_size, '\\', '\\'); 255 break; 256 // Escape double quote character. 257 case '"': 258 sc_string_append_char_pair(buf, buf_size, '\\', '"'); 259 break; 260 // Escape everything else as a generic hexadecimal escape string. 261 default: 262 sc_string_append_char_pair(buf, buf_size, '\\', 'x'); 263 sc_string_append_char_pair(buf, buf_size, hex[c >> 4], 264 hex[c & 15]); 265 break; 266 } 267 } 268 sc_string_append_char(buf, buf_size, '"'); 269 }