H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 1 | /* ----------------------------------------------------------------------- * |
| 2 | * |
H. Peter Anvin (Intel) | f21b2ba | 2020-06-30 09:54:01 -0700 | [diff] [blame] | 3 | * Copyright 1996-2020 The NASM Authors - All Rights Reserved |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 4 | * See the file AUTHORS included with the NASM distribution for |
| 5 | * the specific copyright holders. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following |
| 9 | * conditions are met: |
| 10 | * |
| 11 | * * Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * * Redistributions in binary form must reproduce the above |
| 14 | * copyright notice, this list of conditions and the following |
| 15 | * disclaimer in the documentation and/or other materials provided |
| 16 | * with the distribution. |
| 17 | * |
| 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
| 19 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
| 20 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| 23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 29 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| 30 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | * |
| 32 | * ----------------------------------------------------------------------- */ |
| 33 | |
| 34 | /* |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 35 | * strlist.c - list of ordered strings, optionally made unique |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 36 | */ |
| 37 | |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 38 | #include "strlist.h" |
| 39 | |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 40 | /* |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 41 | * Create a string list. The list can be uniqizing or not. |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 42 | */ |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 43 | struct strlist *strlist_alloc(bool uniq) |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 44 | { |
Cyrill Gorcunov | b7bb5ac | 2018-11-11 21:33:52 +0300 | [diff] [blame] | 45 | struct strlist *list = nasm_zalloc(sizeof(*list)); |
Cyrill Gorcunov | b7bb5ac | 2018-11-11 21:33:52 +0300 | [diff] [blame] | 46 | list->tailp = &list->head; |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 47 | list->uniq = uniq; |
Cyrill Gorcunov | b7bb5ac | 2018-11-11 21:33:52 +0300 | [diff] [blame] | 48 | return list; |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | /* |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 52 | * Append a string to a string list. Return the entry pointer, which |
| 53 | * may be a pre-existing entry for a uniqizing list. |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 54 | */ |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 55 | |
| 56 | static const struct strlist_entry * |
| 57 | strlist_add_common(struct strlist *list, struct strlist_entry *e, |
| 58 | struct hash_insert *hi) |
| 59 | { |
| 60 | e->offset = list->size; |
| 61 | e->next = NULL; |
| 62 | |
| 63 | *list->tailp = e; |
| 64 | list->tailp = &e->next; |
| 65 | list->nstr++; |
| 66 | list->size += e->size; |
| 67 | |
| 68 | if (list->uniq) |
| 69 | hash_add(hi, e->str, (void *)e); |
| 70 | |
| 71 | return e; |
| 72 | } |
| 73 | |
| 74 | const struct strlist_entry * |
| 75 | strlist_add(struct strlist *list, const char *str) |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 76 | { |
Cyrill Gorcunov | b7bb5ac | 2018-11-11 21:33:52 +0300 | [diff] [blame] | 77 | struct strlist_entry *e; |
| 78 | struct hash_insert hi; |
H. Peter Anvin (Intel) | ebb05a0 | 2018-12-11 12:30:25 -0800 | [diff] [blame] | 79 | size_t size; |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 80 | |
Cyrill Gorcunov | b7bb5ac | 2018-11-11 21:33:52 +0300 | [diff] [blame] | 81 | if (!list) |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 82 | return NULL; |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 83 | |
H. Peter Anvin (Intel) | ebb05a0 | 2018-12-11 12:30:25 -0800 | [diff] [blame] | 84 | size = strlen(str) + 1; |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 85 | if (list->uniq) { |
| 86 | void **dp = hash_findb(&list->hash, str, size, &hi); |
| 87 | if (dp) |
| 88 | return *dp; |
| 89 | } |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 90 | |
Cyrill Gorcunov | b7bb5ac | 2018-11-11 21:33:52 +0300 | [diff] [blame] | 91 | /* Structure already has char[1] as EOS */ |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 92 | e = nasm_malloc(sizeof(*e) - 1 + size); |
H. Peter Anvin (Intel) | ebb05a0 | 2018-12-11 12:30:25 -0800 | [diff] [blame] | 93 | e->size = size; |
| 94 | memcpy(e->str, str, size); |
H. Peter Anvin (Intel) | f7106d0 | 2018-10-25 12:33:58 -0700 | [diff] [blame] | 95 | |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 96 | return strlist_add_common(list, e, &hi); |
| 97 | } |
Cyrill Gorcunov | b7bb5ac | 2018-11-11 21:33:52 +0300 | [diff] [blame] | 98 | |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 99 | /* |
| 100 | * printf() to a string list |
| 101 | */ |
| 102 | const struct strlist_entry * |
| 103 | strlist_vprintf(struct strlist *list, const char *fmt, va_list ap) |
| 104 | { |
H. Peter Anvin (Intel) | f21b2ba | 2020-06-30 09:54:01 -0700 | [diff] [blame] | 105 | /* clang miscompiles offsetin() unless e is initialized here */ |
| 106 | struct strlist_entry *e = NULL; |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 107 | struct hash_insert hi; |
| 108 | |
| 109 | if (!list) |
| 110 | return NULL; |
| 111 | |
H. Peter Anvin (Intel) | ce19a52 | 2018-12-14 00:27:59 -0800 | [diff] [blame] | 112 | e = nasm_vaxprintf(offsetin(*e, str), fmt, ap); |
H. Peter Anvin (Intel) | 1c21a53 | 2019-08-09 02:34:21 -0700 | [diff] [blame] | 113 | e->size = nasm_last_string_size(); |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 114 | |
| 115 | if (list->uniq) { |
| 116 | void **dp = hash_findb(&list->hash, e->str, e->size, &hi); |
| 117 | if (dp) { |
| 118 | nasm_free(e); |
| 119 | return *dp; |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | return strlist_add_common(list, e, &hi); |
| 124 | } |
| 125 | |
| 126 | const struct strlist_entry * |
| 127 | strlist_printf(struct strlist *list, const char *fmt, ...) |
| 128 | { |
| 129 | va_list ap; |
| 130 | const struct strlist_entry *e; |
| 131 | |
| 132 | va_start(ap, fmt); |
| 133 | e = strlist_vprintf(list, fmt, ap); |
| 134 | va_end(ap); |
| 135 | |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 136 | return e; |
H. Peter Anvin | 436e367 | 2016-10-04 01:12:28 -0700 | [diff] [blame] | 137 | } |
H. Peter Anvin (Intel) | f7106d0 | 2018-10-25 12:33:58 -0700 | [diff] [blame] | 138 | |
| 139 | /* |
H. Peter Anvin (Intel) | 374312c | 2018-12-14 00:17:13 -0800 | [diff] [blame] | 140 | * Free a string list. Sets the pointed to pointer to NULL. |
H. Peter Anvin (Intel) | f7106d0 | 2018-10-25 12:33:58 -0700 | [diff] [blame] | 141 | */ |
H. Peter Anvin (Intel) | 374312c | 2018-12-14 00:17:13 -0800 | [diff] [blame] | 142 | void strlist_free(struct strlist **listp) |
H. Peter Anvin (Intel) | f7106d0 | 2018-10-25 12:33:58 -0700 | [diff] [blame] | 143 | { |
H. Peter Anvin (Intel) | 374312c | 2018-12-14 00:17:13 -0800 | [diff] [blame] | 144 | struct strlist *list = *listp; |
| 145 | struct strlist_entry *e, *tmp; |
H. Peter Anvin (Intel) | 6ddc62f | 2018-12-13 22:58:35 -0800 | [diff] [blame] | 146 | |
H. Peter Anvin (Intel) | 374312c | 2018-12-14 00:17:13 -0800 | [diff] [blame] | 147 | if (!list) |
| 148 | return; |
H. Peter Anvin (Intel) | 6ddc62f | 2018-12-13 22:58:35 -0800 | [diff] [blame] | 149 | |
H. Peter Anvin (Intel) | 374312c | 2018-12-14 00:17:13 -0800 | [diff] [blame] | 150 | if (list->uniq) |
| 151 | hash_free(&list->hash); |
H. Peter Anvin (Intel) | 6ddc62f | 2018-12-13 22:58:35 -0800 | [diff] [blame] | 152 | |
H. Peter Anvin (Intel) | 374312c | 2018-12-14 00:17:13 -0800 | [diff] [blame] | 153 | list_for_each_safe(e, tmp, list->head) |
| 154 | nasm_free(e); |
| 155 | |
| 156 | nasm_free(list); |
| 157 | *listp = NULL; |
H. Peter Anvin (Intel) | f7106d0 | 2018-10-25 12:33:58 -0700 | [diff] [blame] | 158 | } |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 159 | |
| 160 | /* |
| 161 | * Search the string list for an entry. If found, return the entry pointer. |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 162 | * Only possible on a uniqizing list. |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 163 | */ |
| 164 | const struct strlist_entry * |
| 165 | strlist_find(const struct strlist *list, const char *str) |
| 166 | { |
| 167 | void **hf; |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 168 | |
| 169 | nasm_assert(list->uniq); |
| 170 | |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 171 | hf = hash_find((struct hash_table *)&list->hash, str, NULL); |
| 172 | return hf ? *hf : NULL; |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | * Produce a linearized buffer containing the whole list, in order; |
| 177 | * The character "sep" is the separator between strings; this is |
| 178 | * typically either 0 or '\n'. strlist_size() will give the size of |
| 179 | * the returned buffer. |
| 180 | */ |
| 181 | void *strlist_linearize(const struct strlist *list, char sep) |
| 182 | { |
| 183 | const struct strlist_entry *sl; |
| 184 | char *buf = nasm_malloc(list->size); |
| 185 | char *p = buf; |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 186 | |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 187 | strlist_for_each(sl, list) { |
| 188 | p = mempcpy(p, sl->str, sl->size); |
| 189 | p[-1] = sep; |
| 190 | } |
H. Peter Anvin (Intel) | 7bb13ea | 2018-12-13 22:48:14 -0800 | [diff] [blame] | 191 | |
H. Peter Anvin (Intel) | 6447109 | 2018-12-11 13:06:14 -0800 | [diff] [blame] | 192 | return buf; |
| 193 | } |
H. Peter Anvin (Intel) | 374312c | 2018-12-14 00:17:13 -0800 | [diff] [blame] | 194 | |
| 195 | /* |
| 196 | * Output a string list to a file. The separator can be any string. |
| 197 | */ |
| 198 | void strlist_write(const struct strlist *list, const char *sep, FILE *f) |
| 199 | { |
| 200 | const struct strlist_entry *sl; |
| 201 | size_t seplen = strlen(sep); |
| 202 | |
| 203 | strlist_for_each(sl, list) { |
| 204 | fwrite(sl->str, 1, sl->size - 1, f); |
| 205 | fwrite(sep, 1, seplen, f); |
| 206 | } |
| 207 | } |