github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/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  	size_t alen = strlen(a);
    34  	size_t blen = strlen(b);
    35  
    36  	if (alen != blen) {
    37  		return false;
    38  	}
    39  
    40  	return strncmp(a, b, alen) == 0;
    41  }
    42  
    43  bool sc_endswith(const char *str, const char *suffix)
    44  {
    45  	if (!str || !suffix) {
    46  		return false;
    47  	}
    48  
    49  	size_t xlen = strlen(suffix);
    50  	size_t slen = strlen(str);
    51  
    52  	if (slen < xlen) {
    53  		return false;
    54  	}
    55  
    56  	return strncmp(str - xlen + slen, suffix, xlen) == 0;
    57  }
    58  
    59  bool sc_startswith(const char *str, const char *prefix)
    60  {
    61  	if (!str || !prefix) {
    62  		return false;
    63  	}
    64  
    65  	size_t xlen = strlen(prefix);
    66  	size_t slen = strlen(str);
    67  
    68  	if (slen < xlen) {
    69  		return false;
    70  	}
    71  
    72  	return strncmp(str, prefix, xlen) == 0;
    73  }
    74  
    75  char *sc_strdup(const char *str)
    76  {
    77  	size_t len;
    78  	char *copy;
    79  	if (str == NULL) {
    80  		die("cannot duplicate NULL string");
    81  	}
    82  	len = strlen(str);
    83  	copy = malloc(len + 1);
    84  	if (copy == NULL) {
    85  		die("cannot allocate string copy (len: %zd)", len);
    86  	}
    87  	memcpy(copy, str, len + 1);
    88  	return copy;
    89  }
    90  
    91  int sc_must_snprintf(char *str, size_t size, const char *format, ...)
    92  {
    93  	int n;
    94  
    95  	va_list va;
    96  	va_start(va, format);
    97  	n = vsnprintf(str, size, format, va);
    98  	va_end(va);
    99  
   100  	if (n < 0 || (size_t)n >= size)
   101  		die("cannot format string: %s", str);
   102  
   103  	return n;
   104  }
   105  
   106  size_t sc_string_append(char *dst, size_t dst_size, const char *str)
   107  {
   108  	// Set errno in case we die.
   109  	errno = 0;
   110  	if (dst == NULL) {
   111  		die("cannot append string: buffer is NULL");
   112  	}
   113  	if (str == NULL) {
   114  		die("cannot append string: string is NULL");
   115  	}
   116  	size_t dst_len = strnlen(dst, dst_size);
   117  	if (dst_len == dst_size) {
   118  		die("cannot append string: dst is unterminated");
   119  	}
   120  
   121  	size_t max_str_len = dst_size - dst_len;
   122  	size_t str_len = strnlen(str, max_str_len);
   123  	if (str_len == max_str_len) {
   124  		die("cannot append string: str is too long or unterminated");
   125  	}
   126  	// Append the string
   127  	memcpy(dst + dst_len, str, str_len);
   128  	// Ensure we are terminated
   129  	dst[dst_len + str_len] = '\0';
   130  	// return the new size
   131  	return strlen(dst);
   132  }
   133  
   134  size_t sc_string_append_char(char *dst, size_t dst_size, char c)
   135  {
   136  	// Set errno in case we die.
   137  	errno = 0;
   138  	if (dst == NULL) {
   139  		die("cannot append character: buffer is NULL");
   140  	}
   141  	size_t dst_len = strnlen(dst, dst_size);
   142  	if (dst_len == dst_size) {
   143  		die("cannot append character: dst is unterminated");
   144  	}
   145  	size_t max_str_len = dst_size - dst_len;
   146  	if (max_str_len < 2) {
   147  		die("cannot append character: not enough space");
   148  	}
   149  	if (c == 0) {
   150  		die("cannot append character: cannot append string terminator");
   151  	}
   152  	// Append the character and terminate the string.
   153  	dst[dst_len + 0] = c;
   154  	dst[dst_len + 1] = '\0';
   155  	// Return the new size
   156  	return dst_len + 1;
   157  }
   158  
   159  size_t sc_string_append_char_pair(char *dst, size_t dst_size, char c1, char c2)
   160  {
   161  	// Set errno in case we die.
   162  	errno = 0;
   163  	if (dst == NULL) {
   164  		die("cannot append character pair: buffer is NULL");
   165  	}
   166  	size_t dst_len = strnlen(dst, dst_size);
   167  	if (dst_len == dst_size) {
   168  		die("cannot append character pair: dst is unterminated");
   169  	}
   170  	size_t max_str_len = dst_size - dst_len;
   171  	if (max_str_len < 3) {
   172  		die("cannot append character pair: not enough space");
   173  	}
   174  	if (c1 == 0 || c2 == 0) {
   175  		die("cannot append character pair: cannot append string terminator");
   176  	}
   177  	// Append the two characters and terminate the string.
   178  	dst[dst_len + 0] = c1;
   179  	dst[dst_len + 1] = c2;
   180  	dst[dst_len + 2] = '\0';
   181  	// Return the new size
   182  	return dst_len + 2;
   183  }
   184  
   185  void sc_string_init(char *buf, size_t buf_size)
   186  {
   187  	errno = 0;
   188  	if (buf == NULL) {
   189  		die("cannot initialize string, buffer is NULL");
   190  	}
   191  	if (buf_size == 0) {
   192  		die("cannot initialize string, buffer is too small");
   193  	}
   194  	buf[0] = '\0';
   195  }
   196  
   197  void sc_string_quote(char *buf, size_t buf_size, const char *str)
   198  {
   199  	if (str == NULL) {
   200  		die("cannot quote string: string is NULL");
   201  	}
   202  	const char *hex = "0123456789abcdef";
   203  	// NOTE: this also checks buf/buf_size sanity so that we don't have to.
   204  	sc_string_init(buf, buf_size);
   205  	sc_string_append_char(buf, buf_size, '"');
   206  	for (unsigned char c; (c = *str) != 0; ++str) {
   207  		switch (c) {
   208  			// Pass ASCII letters and digits unmodified.
   209  		case '0' ... '9':
   210  		case 'A' ... 'Z':
   211  		case 'a' ... 'z':
   212  			// Pass most of the punctuation unmodified.
   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  		case '^':
   238  		case '_':
   239  		case '`':
   240  		case '{':
   241  		case '|':
   242  		case '}':
   243  		case '~':
   244  			sc_string_append_char(buf, buf_size, c);
   245  			break;
   246  			// Escape special whitespace characters.
   247  		case '\n':
   248  			sc_string_append_char_pair(buf, buf_size, '\\', 'n');
   249  			break;
   250  		case '\r':
   251  			sc_string_append_char_pair(buf, buf_size, '\\', 'r');
   252  			break;
   253  		case '\t':
   254  			sc_string_append_char_pair(buf, buf_size, '\\', 't');
   255  			break;
   256  		case '\v':
   257  			sc_string_append_char_pair(buf, buf_size, '\\', 'v');
   258  			break;
   259  			// Escape the escape character.
   260  		case '\\':
   261  			sc_string_append_char_pair(buf, buf_size, '\\', '\\');
   262  			break;
   263  			// Escape double quote character.
   264  		case '"':
   265  			sc_string_append_char_pair(buf, buf_size, '\\', '"');
   266  			break;
   267  			// Escape everything else as a generic hexadecimal escape string.
   268  		default:
   269  			sc_string_append_char_pair(buf, buf_size, '\\', 'x');
   270  			sc_string_append_char_pair(buf, buf_size, hex[c >> 4],
   271  						   hex[c & 15]);
   272  			break;
   273  		}
   274  	}
   275  	sc_string_append_char(buf, buf_size, '"');
   276  }