1 /**************************************************************************** 2 * Copyright 2018-2022,2023 Thomas E. Dickey * 3 * Copyright 1998-2013,2017 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30 /**************************************************************************** 31 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 32 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 33 * and: Thomas E. Dickey 1996-on * 34 ****************************************************************************/ 35 36 /* 37 * alloc_entry.c -- allocation functions for terminfo entries 38 * 39 * _nc_copy_entry() 40 * _nc_init_entry() 41 * _nc_merge_entry() 42 * _nc_save_str() 43 * _nc_wrap_entry() 44 * 45 */ 46 47 #include <curses.priv.h> 48 49 #include <tic.h> 50 51 MODULE_ID("$Id: alloc_entry.c,v 1.79 2023/09/15 08:16:12 tom Exp $") 52 53 #define ABSENT_OFFSET -1 54 #define CANCELLED_OFFSET -2 55 56 static char *stringbuf; /* buffer for string capabilities */ 57 static size_t next_free; /* next free character in stringbuf */ 58 59 NCURSES_EXPORT(void) 60 _nc_init_entry(ENTRY * const tp) 61 /* initialize a terminal type data block */ 62 { 63 DEBUG(2, (T_CALLED("_nc_init_entry(tp=%p)"), (void *) tp)); 64 65 if (tp == NULL) { 66 #if NO_LEAKS 67 if (stringbuf != NULL) { 68 FreeAndNull(stringbuf); 69 } 70 return; 71 #else 72 _nc_err_abort("_nc_init_entry called without initialization"); 73 #endif 74 } 75 76 if (stringbuf == NULL) 77 TYPE_CALLOC(char, (size_t) MAX_ENTRY_SIZE, stringbuf); 78 79 next_free = 0; 80 81 _nc_init_termtype(&(tp->tterm)); 82 83 DEBUG(2, (T_RETURN(""))); 84 } 85 86 NCURSES_EXPORT(ENTRY *) 87 _nc_copy_entry(ENTRY * oldp) 88 { 89 ENTRY *newp; 90 91 DEBUG(2, (T_CALLED("_nc_copy_entry(oldp=%p)"), (void *) oldp)); 92 93 newp = typeCalloc(ENTRY, 1); 94 if (newp != NULL) { 95 *newp = *oldp; 96 _nc_copy_termtype2(&(newp->tterm), &(oldp->tterm)); 97 } 98 99 DEBUG(2, (T_RETURN("%p"), (void *) newp)); 100 return (newp); 101 } 102 103 /* save a copy of string in the string buffer */ 104 NCURSES_EXPORT(char *) 105 _nc_save_str(const char *string) 106 { 107 char *result = 0; 108 size_t old_next_free = next_free; 109 110 if (stringbuf != NULL) { 111 size_t len; 112 113 if (!VALID_STRING(string)) 114 string = ""; 115 len = strlen(string) + 1; 116 117 if (len == 1 && next_free != 0) { 118 /* 119 * Cheat a little by making an empty string point to the end of the 120 * previous string. 121 */ 122 if (next_free < MAX_ENTRY_SIZE) { 123 result = (stringbuf + next_free - 1); 124 } 125 } else if (next_free + len < MAX_ENTRY_SIZE) { 126 _nc_STRCPY(&stringbuf[next_free], string, MAX_ENTRY_SIZE); 127 DEBUG(7, ("Saved string %s", _nc_visbuf(string))); 128 DEBUG(7, ("at location %d", (int) next_free)); 129 next_free += len; 130 result = (stringbuf + old_next_free); 131 } else { 132 _nc_warning("Too much data, some is lost: %s", string); 133 } 134 } 135 return result; 136 } 137 138 NCURSES_EXPORT(void) 139 _nc_wrap_entry(ENTRY * const ep, bool copy_strings) 140 /* copy the string parts to allocated storage, preserving pointers to it */ 141 { 142 int offsets[MAX_ENTRY_SIZE / sizeof(short)]; 143 int useoffsets[MAX_USES]; 144 unsigned i, n; 145 unsigned nuses; 146 TERMTYPE2 *tp; 147 148 DEBUG(2, (T_CALLED("_nc_wrap_entry(ep=%p, copy_strings=%d)"), (void *) 149 ep, copy_strings)); 150 if (ep == NULL || stringbuf == NULL) 151 _nc_err_abort("_nc_wrap_entry called without initialization"); 152 153 nuses = ep->nuses; 154 tp = &(ep->tterm); 155 if (copy_strings) { 156 next_free = 0; /* clear static storage */ 157 158 /* copy term_names, Strings, uses */ 159 tp->term_names = _nc_save_str(tp->term_names); 160 for_each_string(i, tp) { 161 if (VALID_STRING(tp->Strings[i])) { 162 tp->Strings[i] = _nc_save_str(tp->Strings[i]); 163 } 164 } 165 166 for (i = 0; i < nuses; i++) { 167 if (ep->uses[i].name == 0) { 168 ep->uses[i].name = _nc_save_str(ep->uses[i].name); 169 } 170 } 171 172 free(tp->str_table); 173 } 174 175 assert(tp->term_names >= stringbuf); 176 n = (unsigned) (tp->term_names - stringbuf); 177 for_each_string(i, &(ep->tterm)) { 178 if (i < SIZEOF(offsets)) { 179 if (tp->Strings[i] == ABSENT_STRING) { 180 offsets[i] = ABSENT_OFFSET; 181 } else if (tp->Strings[i] == CANCELLED_STRING) { 182 offsets[i] = CANCELLED_OFFSET; 183 } else { 184 offsets[i] = (int) (tp->Strings[i] - stringbuf); 185 } 186 } 187 } 188 189 for (i = 0; i < nuses; i++) { 190 if (ep->uses[i].name == 0) 191 useoffsets[i] = ABSENT_OFFSET; 192 else 193 useoffsets[i] = (int) (ep->uses[i].name - stringbuf); 194 } 195 196 TYPE_MALLOC(char, next_free, tp->str_table); 197 (void) memcpy(tp->str_table, stringbuf, next_free); 198 199 tp->term_names = tp->str_table + n; 200 for_each_string(i, &(ep->tterm)) { 201 if (i < SIZEOF(offsets)) { 202 if (offsets[i] == ABSENT_OFFSET) { 203 tp->Strings[i] = ABSENT_STRING; 204 } else if (offsets[i] == CANCELLED_OFFSET) { 205 tp->Strings[i] = CANCELLED_STRING; 206 } else { 207 tp->Strings[i] = tp->str_table + offsets[i]; 208 } 209 } 210 } 211 212 #if NCURSES_XNAMES 213 if (!copy_strings) { 214 if ((n = (unsigned) NUM_EXT_NAMES(tp)) != 0) { 215 if (n < SIZEOF(offsets)) { 216 size_t length = 0; 217 size_t offset; 218 for (i = 0; i < n; i++) { 219 length += strlen(tp->ext_Names[i]) + 1; 220 offsets[i] = (int) (tp->ext_Names[i] - stringbuf); 221 } 222 TYPE_MALLOC(char, length, tp->ext_str_table); 223 for (i = 0, offset = 0; i < n; i++) { 224 tp->ext_Names[i] = tp->ext_str_table + offset; 225 _nc_STRCPY(tp->ext_Names[i], 226 stringbuf + offsets[i], 227 length - offset); 228 offset += strlen(tp->ext_Names[i]) + 1; 229 } 230 } 231 } 232 } 233 #endif 234 235 for (i = 0; i < nuses; i++) { 236 if (useoffsets[i] == ABSENT_OFFSET) { 237 ep->uses[i].name = 0; 238 } else { 239 ep->uses[i].name = strdup(tp->str_table + useoffsets[i]); 240 } 241 } 242 DEBUG(2, (T_RETURN(""))); 243 } 244 245 NCURSES_EXPORT(void) 246 _nc_merge_entry(ENTRY * const target, ENTRY * const source) 247 /* merge capabilities from `from' entry into `to' entry */ 248 { 249 TERMTYPE2 *to = &(target->tterm); 250 TERMTYPE2 *from = &(source->tterm); 251 #if NCURSES_XNAMES 252 TERMTYPE2 copy; 253 size_t str_size, copy_size; 254 char *str_table; 255 #endif 256 unsigned i; 257 258 if (source == 0 || from == 0 || target == 0 || to == 0) 259 return; 260 261 #if NCURSES_XNAMES 262 _nc_copy_termtype2(©, from); 263 from = © 264 _nc_align_termtype(to, from); 265 /* 266 * compute the maximum size of the string-table. 267 */ 268 str_size = strlen(to->term_names) + 1; 269 for_each_string(i, from) { 270 if (VALID_STRING(from->Strings[i])) 271 str_size += strlen(from->Strings[i]) + 1; 272 } 273 for_each_string(i, to) { 274 if (VALID_STRING(to->Strings[i])) 275 str_size += strlen(to->Strings[i]) + 1; 276 } 277 /* allocate a string-table large enough for both source/target, and 278 * copy all of the strings into that table. In the merge, we will 279 * select from the original source/target lists to construct a new 280 * target list. 281 */ 282 if (str_size != 0) { 283 char *str_copied; 284 if ((str_table = malloc(str_size)) == NULL) 285 _nc_err_abort(MSG_NO_MEMORY); 286 str_copied = str_table; 287 _nc_STRCPY(str_copied, to->term_names, str_size); 288 to->term_names = str_copied; 289 copy_size = strlen(str_copied) + 1; 290 str_copied += copy_size; 291 str_size -= copy_size; 292 for_each_string(i, from) { 293 if (VALID_STRING(from->Strings[i])) { 294 _nc_STRCPY(str_copied, from->Strings[i], str_size); 295 from->Strings[i] = str_copied; 296 copy_size = strlen(str_copied) + 1; 297 str_copied += copy_size; 298 str_size -= copy_size; 299 } 300 } 301 for_each_string(i, to) { 302 if (VALID_STRING(to->Strings[i])) { 303 _nc_STRCPY(str_copied, to->Strings[i], str_size); 304 to->Strings[i] = str_copied; 305 copy_size = strlen(str_copied) + 1; 306 str_copied += copy_size; 307 str_size -= copy_size; 308 } 309 } 310 free(to->str_table); 311 to->str_table = str_table; 312 free(from->str_table); 313 } 314 /* 315 * Do the same for the extended-strings (i.e., lists of capabilities). 316 */ 317 str_size = 0; 318 for (i = 0; i < NUM_EXT_NAMES(from); ++i) { 319 if (VALID_STRING(from->ext_Names[i])) 320 str_size += strlen(from->ext_Names[i]) + 1; 321 } 322 for (i = 0; i < NUM_EXT_NAMES(to); ++i) { 323 if (VALID_STRING(to->ext_Names[i])) 324 str_size += strlen(to->ext_Names[i]) + 1; 325 } 326 /* allocate a string-table large enough for both source/target, and 327 * copy all of the strings into that table. In the merge, we will 328 * select from the original source/target lists to construct a new 329 * target list. 330 */ 331 if (str_size != 0) { 332 char *str_copied; 333 if ((str_table = malloc(str_size)) == NULL) 334 _nc_err_abort(MSG_NO_MEMORY); 335 str_copied = str_table; 336 for (i = 0; i < NUM_EXT_NAMES(from); ++i) { 337 if (VALID_STRING(from->ext_Names[i])) { 338 _nc_STRCPY(str_copied, from->ext_Names[i], str_size); 339 from->ext_Names[i] = str_copied; 340 copy_size = strlen(str_copied) + 1; 341 str_copied += copy_size; 342 str_size -= copy_size; 343 } 344 } 345 for (i = 0; i < NUM_EXT_NAMES(to); ++i) { 346 if (VALID_STRING(to->ext_Names[i])) { 347 _nc_STRCPY(str_copied, to->ext_Names[i], str_size); 348 to->ext_Names[i] = str_copied; 349 copy_size = strlen(str_copied) + 1; 350 str_copied += copy_size; 351 str_size -= copy_size; 352 } 353 } 354 free(to->ext_str_table); 355 to->ext_str_table = str_table; 356 free(from->ext_str_table); 357 } 358 #endif 359 for_each_boolean(i, from) { 360 if (to->Booleans[i] != (NCURSES_SBOOL) CANCELLED_BOOLEAN) { 361 int mergebool = from->Booleans[i]; 362 363 if (mergebool == CANCELLED_BOOLEAN) 364 to->Booleans[i] = FALSE; 365 else if (mergebool == TRUE) 366 to->Booleans[i] = (NCURSES_SBOOL) mergebool; 367 } 368 } 369 370 for_each_number(i, from) { 371 if (to->Numbers[i] != CANCELLED_NUMERIC) { 372 int mergenum = from->Numbers[i]; 373 374 if (mergenum == CANCELLED_NUMERIC) 375 to->Numbers[i] = ABSENT_NUMERIC; 376 else if (mergenum != ABSENT_NUMERIC) 377 to->Numbers[i] = (NCURSES_INT2) mergenum; 378 } 379 } 380 381 /* 382 * Note: the copies of strings this makes don't have their own 383 * storage. This is OK right now, but will be a problem if we 384 * we ever want to deallocate entries. 385 */ 386 for_each_string(i, from) { 387 if (to->Strings[i] != CANCELLED_STRING) { 388 char *mergestring = from->Strings[i]; 389 390 if (mergestring == CANCELLED_STRING) 391 to->Strings[i] = ABSENT_STRING; 392 else if (mergestring != ABSENT_STRING) 393 to->Strings[i] = mergestring; 394 } 395 } 396 #if NCURSES_XNAMES 397 /* cleanup */ 398 free(copy.Booleans); 399 free(copy.Numbers); 400 free(copy.Strings); 401 free(copy.ext_Names); 402 #endif 403 } 404 405 #if NO_LEAKS 406 NCURSES_EXPORT(void) 407 _nc_alloc_entry_leaks(void) 408 { 409 if (stringbuf != NULL) { 410 FreeAndNull(stringbuf); 411 } 412 next_free = 0; 413 } 414 #endif 415