string.c (5037B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21 22#include "guacamole/mem.h" 23 24#include <stddef.h> 25#include <string.h> 26 27/** 28 * Returns the space remaining in a buffer assuming that the given number of 29 * bytes have already been written. If the number of bytes exceeds the size 30 * of the buffer, zero is returned. 31 * 32 * @param n 33 * The size of the buffer in bytes. 34 * 35 * @param length 36 * The number of bytes which have been written to the buffer so far. If 37 * the routine writing the bytes will automatically truncate its writes, 38 * this value may exceed the size of the buffer. 39 * 40 * @return 41 * The number of bytes remaining in the buffer. This value will always 42 * be non-negative. If the number of bytes written already exceeds the 43 * size of the buffer, zero will be returned. 44 */ 45#define REMAINING(n, length) (((n) < (length)) ? 0 : ((n) - (length))) 46 47size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n) { 48 49#ifdef HAVE_STRLCPY 50 return strlcpy(dest, src, n); 51#else 52 /* Calculate actual length of desired string */ 53 size_t length = strlen(src); 54 55 /* Copy nothing if there is no space */ 56 if (n == 0) 57 return length; 58 59 /* Calculate length of the string which will be copied */ 60 size_t copy_length = length; 61 if (copy_length >= n) 62 copy_length = n - 1; 63 64 /* Copy only as much of string as possible, manually adding a null 65 * terminator */ 66 memcpy(dest, src, copy_length); 67 dest[copy_length] = '\0'; 68 69 /* Return the overall length of the desired string */ 70 return length; 71#endif 72 73} 74 75size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n) { 76 77#ifdef HAVE_STRLCPY 78 return strlcat(dest, src, n); 79#else 80 size_t length = strnlen(dest, n); 81 return length + guac_strlcpy(dest + length, src, REMAINING(n, length)); 82#endif 83 84} 85 86char* guac_strnstr(const char *haystack, const char *needle, size_t len) { 87 88#ifdef HAVE_STRNSTR 89 return strnstr(haystack, needle, len); 90#else 91 char* chr; 92 size_t nlen = strlen(needle), off = 0; 93 94 /* Follow documented API: return haystack if needle is the empty string. */ 95 if (nlen == 0) 96 return (char *)haystack; 97 98 /* Use memchr to find candidates. It might be optimized in asm. */ 99 while (off < len && NULL != (chr = memchr(haystack + off, needle[0], len - off))) { 100 /* chr is guaranteed to be in bounds of and >= haystack. */ 101 off = chr - haystack; 102 /* If needle would go beyond provided len, it doesn't exist in haystack. */ 103 if (off + nlen > len) 104 return NULL; 105 /* Now that we know we have at least nlen bytes, compare them. */ 106 if (!memcmp(chr, needle, nlen)) 107 return chr; 108 /* Make sure we make progress. */ 109 off += 1; 110 } 111 112 /* memchr ran out of candidates, needle wasn't found. */ 113 return NULL; 114#endif 115 116} 117 118char* guac_strdup(const char* str) { 119 120 /* Return NULL if no string provided */ 121 if (str == NULL) 122 return NULL; 123 124 /* Do not attempt to duplicate if the length is somehow magically so 125 * obscenely large that it will not be possible to add a null terminator */ 126 size_t length; 127 if (guac_mem_ckd_add(&length, strlen(str), 1)) 128 return NULL; 129 130 /* Otherwise just copy to a new string in same manner as strdup() */ 131 void* new_str = guac_mem_alloc(length); 132 if (new_str != NULL) 133 memcpy(new_str, str, length); 134 135 return new_str; 136 137} 138 139size_t guac_strljoin(char* restrict dest, const char* restrict const* elements, 140 int nmemb, const char* restrict delim, size_t n) { 141 142 size_t length = 0; 143 const char* restrict const* current = elements; 144 145 /* If no elements are provided, nothing to do but ensure the destination 146 * buffer is null terminated */ 147 if (nmemb <= 0) 148 return guac_strlcpy(dest, "", n); 149 150 /* Initialize destination buffer with first element */ 151 length += guac_strlcpy(dest, *current, n); 152 153 /* Copy all remaining elements, separated by delimiter */ 154 for (current++; nmemb > 1; current++, nmemb--) { 155 length += guac_strlcat(dest + length, delim, REMAINING(n, length)); 156 length += guac_strlcat(dest + length, *current, REMAINING(n, length)); 157 } 158 159 return length; 160 161} 162