Branch data Line data Source code
1 : : /* constructor-helpers.c - Helper library for the constructor test 2 : : * 3 : : * Copyright © 2023 Luca Bacci 4 : : * 5 : : * SPDX-License-Identifier: LGPL-2.1-or-later 6 : : * 7 : : * This library is free software; you can redistribute it and/or 8 : : * modify it under the terms of the GNU Lesser General Public 9 : : * License as published by the Free Software Foundation; either 10 : : * version 2.1 of the License, or (at your option) any later version. 11 : : * 12 : : * This library is distributed in the hope that it will be useful, 13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 : : * Lesser General Public License for more details. 16 : : * 17 : : * You should have received a copy of the GNU Lesser General Public License 18 : : * along with this library; if not, see <http://www.gnu.org/licenses/>. 19 : : */ 20 : : 21 : : /* This helper library manages a set of strings. Strings can be added, 22 : : * removed and checked for presence. This library does not call into 23 : : * libc, so can be used from module constructors in a safe manner on 24 : : * a wide range of operating systems. 25 : : * 26 : : * GLib is used only for assertions or hard errors; in such cases we 27 : : * don't really care about supported libc calls, as the test ought to 28 : : * fail anyway. 29 : : */ 30 : : 31 : : #include <stddef.h> /* for size_t */ 32 : : 33 : : #include <glib.h> 34 : : 35 : : #if defined (_MSC_VER) 36 : : # pragma optimize ("", off) 37 : : #else 38 : : # if defined (__clang__) 39 : : # pragma clang optimize off 40 : : # elif defined (__GNUC__) 41 : : # pragma GCC optimize ("O0") 42 : : # endif 43 : : #endif 44 : : 45 : : #if defined(_WIN32) 46 : : #define MODULE_EXPORT \ 47 : : __declspec (dllexport) 48 : : #elif defined (__GNUC__) 49 : : #define MODULE_EXPORT \ 50 : : __attribute__((visibility("default"))) 51 : : #else 52 : : #define MODULE_EXPORT 53 : : #endif 54 : : 55 : : char buffer[500]; 56 : : size_t position; 57 : : 58 : : MODULE_EXPORT 59 : : void string_add (const char *string); 60 : : 61 : : MODULE_EXPORT 62 : : void string_add_exclusive (const char *string); 63 : : 64 : : MODULE_EXPORT 65 : : int string_remove (const char *string); 66 : : 67 : : MODULE_EXPORT 68 : : int string_find (const char *string); 69 : : 70 : : MODULE_EXPORT 71 : : void string_check (const char *string); 72 : : 73 : : static size_t 74 : 0 : strlen_ (const char *string) 75 : : { 76 : 0 : size_t i = 0; 77 : : 78 : 0 : g_assert_nonnull (string); 79 : : 80 [ # # ]: 0 : while (string[i] != 0) 81 : 0 : i++; 82 : : 83 : 0 : return i; 84 : : } 85 : : 86 : : static void 87 : 0 : memmove_ (char *buf, 88 : : size_t from, 89 : : size_t size, 90 : : size_t to) 91 : : { 92 : 0 : g_assert_true (to <= from); 93 : : 94 [ # # ]: 0 : for (size_t i = 0; i < size; i++) 95 : 0 : buffer[to + i] = buffer[from + i]; 96 : 0 : } 97 : : 98 : : static void 99 : 0 : memcpy_ (char *dst, 100 : : const char *src, 101 : : size_t size) 102 : : { 103 [ # # ]: 0 : for (size_t i = 0; i < size; i++) 104 : 0 : dst[i] = src[i]; 105 : 0 : } 106 : : 107 : : static void 108 : 0 : memset_ (char *dst, 109 : : char val, 110 : : size_t size) 111 : : { 112 [ # # ]: 0 : for (size_t i = 0; i < size; i++) 113 : 0 : dst[i] = val; 114 : 0 : } 115 : : 116 : : static size_t 117 : 0 : string_find_index_ (const char *string) 118 : : { 119 : : size_t string_len; 120 : 0 : size_t i = 0; 121 : : 122 : 0 : g_assert_nonnull (string); 123 : 0 : g_assert_true ((string_len = strlen_ (string)) > 0); 124 : : 125 [ # # # # ]: 0 : for (i = 0; (i < sizeof (buffer) - position) && (buffer[i] != 0);) 126 : : { 127 : 0 : const char *iter = &buffer[i]; 128 : 0 : size_t len = strlen_ (iter); 129 : : 130 [ # # # # ]: 0 : if (len == string_len && strcmp (iter, string) == 0) 131 : 0 : return i; 132 : : 133 : 0 : i += len + 1; 134 : : } 135 : : 136 : 0 : return sizeof (buffer); 137 : : } 138 : : 139 : : /**< private > 140 : : * string_add: 141 : : * 142 : : * @string: NULL-terminated string. Must not be empty 143 : : * 144 : : * Adds @string to the set 145 : : */ 146 : : MODULE_EXPORT 147 : : void 148 : 0 : string_add (const char *string) 149 : : { 150 : : size_t len, size; 151 : : 152 : 0 : g_assert_nonnull (string); 153 : 0 : g_assert_true ((len = strlen_ (string)) > 0); 154 : : 155 : 0 : size = len + 1; 156 : : 157 [ # # ]: 0 : if (size > sizeof (buffer) - position) 158 : 0 : g_error ("Not enough space in the buffer"); 159 : : 160 : 0 : memcpy_ (buffer + position, string, size); 161 : : 162 : 0 : position += size; 163 : 0 : } 164 : : 165 : : /**< private > 166 : : * string_add_exclusive: 167 : : * 168 : : * @string: NULL-terminated string. Must not be empty 169 : : * 170 : : * Adds @string to the set, asserting that it's not already present. 171 : : */ 172 : : MODULE_EXPORT 173 : : void 174 : 0 : string_add_exclusive (const char *string) 175 : : { 176 [ # # ]: 0 : if (string_find_index_ (string) < sizeof (buffer)) 177 : 0 : g_error ("string %s already set", string); 178 : : 179 : 0 : string_add (string); 180 : 0 : } 181 : : 182 : : /**< private > 183 : : * string_remove: 184 : : * 185 : : * @string: NULL-terminated string. Must not be empty 186 : : * 187 : : * Removes the first occurrence of @string from the set. 188 : : * 189 : : * Returns: 1 if the string was removed, 0 otherwise. 190 : : */ 191 : : MODULE_EXPORT 192 : : int 193 : 0 : string_remove (const char *string) 194 : : { 195 : 0 : size_t index = string_find_index_ (string); 196 : : size_t len, size; 197 : : 198 [ # # ]: 0 : if (index >= sizeof (buffer)) 199 : 0 : return 0; 200 : : 201 : 0 : g_assert_true ((len = strlen_ (string)) > 0); 202 : 0 : size = len + 1; 203 : : 204 : 0 : memmove_ (buffer, index + size, index, position - (index + size)); 205 : : 206 : 0 : position -= size; 207 : : 208 : 0 : memset_ (buffer + position, 0, size); 209 : : 210 : 0 : return 1; 211 : : } 212 : : 213 : : /**< private > 214 : : * string_find: 215 : : * 216 : : * @string: NULL-terminated string. Must not be empty 217 : : * 218 : : * Returns 1 if the string is present, 0 otherwise 219 : : */ 220 : : MODULE_EXPORT 221 : 0 : int string_find (const char *string) 222 : : { 223 : 0 : return string_find_index_ (string) < sizeof (buffer); 224 : : } 225 : : 226 : : /**< private > 227 : : * string_check: 228 : : * 229 : : * @string: NULL-terminated string. Must not be empty 230 : : * 231 : : * Asserts that @string is present in the set 232 : : */ 233 : : MODULE_EXPORT 234 : : void 235 : 0 : string_check (const char *string) 236 : : { 237 [ # # ]: 0 : if (string_find_index_ (string) >= sizeof (buffer)) 238 : 0 : g_error ("String %s not present", string); 239 : 0 : }