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  }