xref: /openbsd/lib/libcurses/tinfo/alloc_ttype.c (revision c7ef0cfc)
1 /* $OpenBSD: alloc_ttype.c,v 1.7 2023/10/17 09:52:09 nicm Exp $ */
2 
3 /****************************************************************************
4  * Copyright 2018-2022,2023 Thomas E. Dickey                                *
5  * Copyright 1999-2016,2017 Free Software Foundation, Inc.                  *
6  *                                                                          *
7  * Permission is hereby granted, free of charge, to any person obtaining a  *
8  * copy of this software and associated documentation files (the            *
9  * "Software"), to deal in the Software without restriction, including      *
10  * without limitation the rights to use, copy, modify, merge, publish,      *
11  * distribute, distribute with modifications, sublicense, and/or sell       *
12  * copies of the Software, and to permit persons to whom the Software is    *
13  * furnished to do so, subject to the following conditions:                 *
14  *                                                                          *
15  * The above copyright notice and this permission notice shall be included  *
16  * in all copies or substantial portions of the Software.                   *
17  *                                                                          *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
21  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
24  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
25  *                                                                          *
26  * Except as contained in this notice, the name(s) of the above copyright   *
27  * holders shall not be used in advertising or otherwise to promote the     *
28  * sale, use or other dealings in this Software without prior written       *
29  * authorization.                                                           *
30  ****************************************************************************/
31 
32 /****************************************************************************
33  *  Author: Thomas E. Dickey <dickey@clark.net> 1999-on                     *
34  ****************************************************************************/
35 
36 /*
37  * align_ttype.c --  functions for TERMTYPE
38  *
39  *	_nc_align_termtype()
40  *	_nc_copy_termtype()
41  *
42  */
43 
44 #include <curses.priv.h>
45 
46 #include <tic.h>
47 
48 MODULE_ID("$Id: alloc_ttype.c,v 1.7 2023/10/17 09:52:09 nicm Exp $")
49 
50 #if NCURSES_XNAMES
51 /*
52  * Merge the a/b lists into dst.  Both a/b are sorted (see _nc_extend_names()),
53  * so we do not have to worry about order dependencies.
54  */
55 static int
merge_names(char ** dst,char ** a,int na,char ** b,int nb)56 merge_names(char **dst, char **a, int na, char **b, int nb)
57 {
58     int n = 0;
59     while (na > 0 && nb > 0) {
60 	int cmp = strcmp(*a, *b);
61 	if (cmp < 0) {
62 	    dst[n++] = *a++;
63 	    na--;
64 	} else if (cmp > 0) {
65 	    dst[n++] = *b++;
66 	    nb--;
67 	} else {
68 	    dst[n++] = *a;
69 	    a++, b++;
70 	    na--, nb--;
71 	}
72     }
73     while (na-- > 0) {
74 	dst[n++] = *a++;
75     }
76     while (nb-- > 0) {
77 	dst[n++] = *b++;
78     }
79     DEBUG(4, ("merge_names -> %d", n));
80     return n;
81 }
82 
83 static bool
find_name(char ** table,int item,int length,const char * name)84 find_name(char **table, int item, int length, const char *name)
85 {
86     int n;
87     int result = -1;
88 
89     for (n = item; n < length; ++n) {
90 	if (!strcmp(table[n], name)) {
91 	    DEBUG(4, ("found name '%s' @%d", name, n));
92 	    result = n;
93 	    break;
94 	}
95     }
96     if (result < 0) {
97 	DEBUG(4, ("did not find name '%s'", name));
98     }
99     return (result >= 0);
100 }
101 
102 #define EXTEND_NUM(num, ext) \
103 	DEBUG(4, ("extending " #num " from %d to %d", \
104 	 to->num, (unsigned short) (to->num + (ext - to->ext)))); \
105 	to->num = (unsigned short) (to->num + (ext - to->ext))
106 
107 static void
realign_data(TERMTYPE2 * to,char ** ext_Names,int ext_Booleans,int ext_Numbers,int ext_Strings)108 realign_data(TERMTYPE2 *to, char **ext_Names,
109 	     int ext_Booleans,
110 	     int ext_Numbers,
111 	     int ext_Strings)
112 {
113     int n, m, base;
114     int to_Booleans = to->ext_Booleans;
115     int to_Numbers = to->ext_Numbers;
116     int to_Strings = to->ext_Strings;
117     int to1, to2, from;
118 
119     DEBUG(4, ("realign_data %d/%d/%d vs %d/%d/%d",
120 	      ext_Booleans,
121 	      ext_Numbers,
122 	      ext_Strings,
123 	      to->ext_Booleans,
124 	      to->ext_Numbers,
125 	      to->ext_Strings));
126 
127     if (to->ext_Booleans != ext_Booleans) {
128 	to1 = 0;
129 	to2 = to_Booleans + to1;
130 	from = 0;
131 	EXTEND_NUM(num_Booleans, ext_Booleans);
132 	TYPE_REALLOC(NCURSES_SBOOL, to->num_Booleans, to->Booleans);
133 	for (n = to->ext_Booleans - 1,
134 	     m = ext_Booleans - 1,
135 	     base = to->num_Booleans - (m + 1); m >= 0; m--) {
136 	    if (find_name(to->ext_Names, to1, to2, ext_Names[m + from])) {
137 		to->Booleans[base + m] = to->Booleans[base + n--];
138 	    } else {
139 		to->Booleans[base + m] = FALSE;
140 	    }
141 	}
142 	to->ext_Booleans = UShort(ext_Booleans);
143     }
144 
145     if (to->ext_Numbers != ext_Numbers) {
146 	to1 = to_Booleans;
147 	to2 = to_Numbers + to1;
148 	from = ext_Booleans;
149 	EXTEND_NUM(num_Numbers, ext_Numbers);
150 	TYPE_REALLOC(NCURSES_INT2, to->num_Numbers, to->Numbers);
151 	for (n = to->ext_Numbers - 1,
152 	     m = ext_Numbers - 1,
153 	     base = to->num_Numbers - (m + 1); m >= 0; m--) {
154 	    if (find_name(to->ext_Names, to1, to2, ext_Names[m + from])) {
155 		to->Numbers[base + m] = to->Numbers[base + n--];
156 	    } else {
157 		to->Numbers[base + m] = ABSENT_NUMERIC;
158 	    }
159 	}
160 	to->ext_Numbers = UShort(ext_Numbers);
161     }
162 
163     if (to->ext_Strings != ext_Strings) {
164 	to1 = to_Booleans + to_Numbers;
165 	to2 = to_Strings + to1;
166 	from = ext_Booleans + ext_Numbers;
167 	EXTEND_NUM(num_Strings, ext_Strings);
168 	TYPE_REALLOC(char *, to->num_Strings, to->Strings);
169 	for (n = to->ext_Strings - 1,
170 	     m = ext_Strings - 1,
171 	     base = to->num_Strings - (m + 1); m >= 0; m--) {
172 	    if (find_name(to->ext_Names, to1, to2, ext_Names[m + from])) {
173 		to->Strings[base + m] = to->Strings[base + n--];
174 	    } else {
175 		to->Strings[base + m] = ABSENT_STRING;
176 	    }
177 	}
178 	to->ext_Strings = UShort(ext_Strings);
179     }
180 }
181 
182 /*
183  * Returns the first index in ext_Names[] for the given token-type
184  */
185 static unsigned
_nc_first_ext_name(TERMTYPE2 * tp,int token_type)186 _nc_first_ext_name(TERMTYPE2 *tp, int token_type)
187 {
188     unsigned first;
189 
190     switch (token_type) {
191     case BOOLEAN:
192 	first = 0;
193 	break;
194     case NUMBER:
195 	first = tp->ext_Booleans;
196 	break;
197     case STRING:
198 	first = (unsigned) (tp->ext_Booleans + tp->ext_Numbers);
199 	break;
200     default:
201 	first = 0;
202 	break;
203     }
204     return first;
205 }
206 
207 /*
208  * Returns the last index in ext_Names[] for the given token-type
209  */
210 static unsigned
_nc_last_ext_name(TERMTYPE2 * tp,int token_type)211 _nc_last_ext_name(TERMTYPE2 *tp, int token_type)
212 {
213     unsigned last;
214 
215     switch (token_type) {
216     case BOOLEAN:
217 	last = tp->ext_Booleans;
218 	break;
219     case NUMBER:
220 	last = (unsigned) (tp->ext_Booleans + tp->ext_Numbers);
221 	break;
222     default:
223     case STRING:
224 	last = NUM_EXT_NAMES(tp);
225 	break;
226     }
227     return last;
228 }
229 
230 /*
231  * Lookup an entry from extended-names, returning -1 if not found
232  */
233 static int
_nc_find_ext_name(TERMTYPE2 * tp,char * name,int token_type)234 _nc_find_ext_name(TERMTYPE2 *tp, char *name, int token_type)
235 {
236     unsigned j;
237     unsigned first = _nc_first_ext_name(tp, token_type);
238     unsigned last = _nc_last_ext_name(tp, token_type);
239 
240     for (j = first; j < last; j++) {
241 	if (!strcmp(name, tp->ext_Names[j])) {
242 	    return (int) j;
243 	}
244     }
245     return -1;
246 }
247 
248 /*
249  * Translate an index into ext_Names[] into the corresponding index into data
250  * (e.g., Booleans[]).
251  */
252 static int
_nc_ext_data_index(TERMTYPE2 * tp,int n,int token_type)253 _nc_ext_data_index(TERMTYPE2 *tp, int n, int token_type)
254 {
255     switch (token_type) {
256     case BOOLEAN:
257 	n += (tp->num_Booleans - tp->ext_Booleans);
258 	break;
259     case NUMBER:
260 	n += (tp->num_Numbers - tp->ext_Numbers)
261 	    - (tp->ext_Booleans);
262 	break;
263     default:
264     case STRING:
265 	n += (tp->num_Strings - tp->ext_Strings)
266 	    - (tp->ext_Booleans + tp->ext_Numbers);
267     }
268     return n;
269 }
270 
271 /*
272  * Adjust tables to remove (not free) an extended name and its corresponding
273  * data.
274  */
275 static bool
_nc_del_ext_name(TERMTYPE2 * tp,char * name,int token_type)276 _nc_del_ext_name(TERMTYPE2 *tp, char *name, int token_type)
277 {
278     int first;
279 
280     if ((first = _nc_find_ext_name(tp, name, token_type)) >= 0) {
281 	int j;
282 	int last = (int) NUM_EXT_NAMES(tp) - 1;
283 
284 	for (j = first; j < last; j++) {
285 	    tp->ext_Names[j] = tp->ext_Names[j + 1];
286 	}
287 	first = _nc_ext_data_index(tp, first, token_type);
288 	switch (token_type) {
289 	case BOOLEAN:
290 	    last = tp->num_Booleans - 1;
291 	    for (j = first; j < last; j++)
292 		tp->Booleans[j] = tp->Booleans[j + 1];
293 	    tp->ext_Booleans--;
294 	    tp->num_Booleans--;
295 	    break;
296 	case NUMBER:
297 	    last = tp->num_Numbers - 1;
298 	    for (j = first; j < last; j++)
299 		tp->Numbers[j] = tp->Numbers[j + 1];
300 	    tp->ext_Numbers--;
301 	    tp->num_Numbers--;
302 	    break;
303 	case STRING:
304 	    last = tp->num_Strings - 1;
305 	    for (j = first; j < last; j++)
306 		tp->Strings[j] = tp->Strings[j + 1];
307 	    tp->ext_Strings--;
308 	    tp->num_Strings--;
309 	    break;
310 	}
311 	return TRUE;
312     }
313     return FALSE;
314 }
315 
316 /*
317  * Adjust tables to insert an extended name, making room for new data.  The
318  * index into the corresponding data array is returned.
319  */
320 static int
_nc_ins_ext_name(TERMTYPE2 * tp,char * name,int token_type)321 _nc_ins_ext_name(TERMTYPE2 *tp, char *name, int token_type)
322 {
323     unsigned first = _nc_first_ext_name(tp, token_type);
324     unsigned last = _nc_last_ext_name(tp, token_type);
325     unsigned total = NUM_EXT_NAMES(tp) + 1;
326     unsigned j, k;
327 
328     for (j = first; j < last; j++) {
329 	int cmp = strcmp(name, tp->ext_Names[j]);
330 	if (cmp == 0)
331 	    /* already present */
332 	    return _nc_ext_data_index(tp, (int) j, token_type);
333 	if (cmp < 0) {
334 	    break;
335 	}
336     }
337 
338     TYPE_REALLOC(char *, total, tp->ext_Names);
339     for (k = total - 1; k > j; k--)
340 	tp->ext_Names[k] = tp->ext_Names[k - 1];
341     tp->ext_Names[j] = name;
342     j = (unsigned) _nc_ext_data_index(tp, (int) j, token_type);
343 
344     switch (token_type) {
345     case BOOLEAN:
346 	tp->ext_Booleans++;
347 	tp->num_Booleans++;
348 	TYPE_REALLOC(NCURSES_SBOOL, tp->num_Booleans, tp->Booleans);
349 	for (k = (unsigned) (tp->num_Booleans - 1); k > j; k--)
350 	    tp->Booleans[k] = tp->Booleans[k - 1];
351 	break;
352     case NUMBER:
353 	tp->ext_Numbers++;
354 	tp->num_Numbers++;
355 	TYPE_REALLOC(NCURSES_INT2, tp->num_Numbers, tp->Numbers);
356 	for (k = (unsigned) (tp->num_Numbers - 1); k > j; k--)
357 	    tp->Numbers[k] = tp->Numbers[k - 1];
358 	break;
359     case STRING:
360 	tp->ext_Strings++;
361 	tp->num_Strings++;
362 	TYPE_REALLOC(char *, tp->num_Strings, tp->Strings);
363 	for (k = (unsigned) (tp->num_Strings - 1); k > j; k--)
364 	    tp->Strings[k] = tp->Strings[k - 1];
365 	break;
366     }
367     return (int) j;
368 }
369 
370 /*
371  * Look for strings that are marked cancelled, which happen to be the same name
372  * as a boolean or number.  We'll get this as a special case when we get a
373  * cancellation of a name that is inherited from another entry.
374  */
375 static void
adjust_cancels(TERMTYPE2 * to,TERMTYPE2 * from)376 adjust_cancels(TERMTYPE2 *to, TERMTYPE2 *from)
377 {
378     int first = to->ext_Booleans + to->ext_Numbers;
379     int last = first + to->ext_Strings;
380     int j, k;
381 
382     DEBUG(3, (T_CALLED("adjust_cancels(%s), from(%s)"),
383 	      NonNull(to->term_names),
384 	      NonNull(from->term_names)));
385     for (j = first; j < last;) {
386 	char *name = to->ext_Names[j];
387 	int j_str = to->num_Strings - first - to->ext_Strings;
388 
389 	if (to->Strings[j + j_str] == CANCELLED_STRING) {
390 	    if (_nc_find_ext_name(from, to->ext_Names[j], BOOLEAN) >= 0) {
391 		if (_nc_del_ext_name(to, name, STRING)
392 		    || _nc_del_ext_name(to, name, NUMBER)) {
393 		    k = _nc_ins_ext_name(to, name, BOOLEAN);
394 		    to->Booleans[k] = FALSE;
395 		} else {
396 		    j++;
397 		}
398 	    } else if (_nc_find_ext_name(from, to->ext_Names[j], NUMBER) >= 0) {
399 		if (_nc_del_ext_name(to, name, STRING)
400 		    || _nc_del_ext_name(to, name, BOOLEAN)) {
401 		    k = _nc_ins_ext_name(to, name, NUMBER);
402 		    to->Numbers[k] = CANCELLED_NUMERIC;
403 		} else {
404 		    j++;
405 		}
406 	    } else if (_nc_find_ext_name(from, to->ext_Names[j], STRING) >= 0) {
407 		if (_nc_del_ext_name(to, name, NUMBER)
408 		    || _nc_del_ext_name(to, name, BOOLEAN)) {
409 		    k = _nc_ins_ext_name(to, name, STRING);
410 		    to->Strings[k] = CANCELLED_STRING;
411 		} else {
412 		    j++;
413 		}
414 	    } else {
415 		j++;
416 	    }
417 	} else {
418 	    j++;
419 	}
420     }
421     DEBUG(3, (T_RETURN("")));
422 }
423 
424 NCURSES_EXPORT(void)
_nc_align_termtype(TERMTYPE2 * to,TERMTYPE2 * from)425 _nc_align_termtype(TERMTYPE2 *to, TERMTYPE2 *from)
426 {
427     int na;
428     int nb;
429     char **ext_Names;
430 
431     na = to ? ((int) NUM_EXT_NAMES(to)) : 0;
432     nb = from ? ((int) NUM_EXT_NAMES(from)) : 0;
433 
434     DEBUG(2, (T_CALLED("_nc_align_termtype to(%d:%s), from(%d:%s)"),
435 	      na, to ? NonNull(to->term_names) : "?",
436 	      nb, from ? NonNull(from->term_names) : "?"));
437 
438     if (to != NULL && from != NULL && (na != 0 || nb != 0)) {
439 	int ext_Booleans, ext_Numbers, ext_Strings;
440 	bool used_ext_Names = FALSE;
441 
442 	if ((na == nb)		/* check if the arrays are equivalent */
443 	    &&(to->ext_Booleans == from->ext_Booleans)
444 	    && (to->ext_Numbers == from->ext_Numbers)
445 	    && (to->ext_Strings == from->ext_Strings)) {
446 	    int n;
447 	    bool same;
448 
449 	    for (n = 0, same = TRUE; n < na; n++) {
450 		if (strcmp(to->ext_Names[n], from->ext_Names[n])) {
451 		    same = FALSE;
452 		    break;
453 		}
454 	    }
455 	    if (same) {
456 		DEBUG(2, (T_RETURN("")));
457 		return;
458 	    }
459 	}
460 	/*
461 	 * This is where we pay for having a simple extension representation.
462 	 * Allocate a new ext_Names array and merge the two ext_Names arrays
463 	 * into it, updating to's counts for booleans, etc.  Fortunately we do
464 	 * this only for the terminfo compiler (tic) and comparer (infocmp).
465 	 */
466 	TYPE_MALLOC(char *, (size_t)(na + nb), ext_Names);
467 
468 	if (to->ext_Strings && (from->ext_Booleans + from->ext_Numbers))
469 	    adjust_cancels(to, from);
470 
471 	if (from->ext_Strings && (to->ext_Booleans + to->ext_Numbers))
472 	    adjust_cancels(from, to);
473 
474 	ext_Booleans = merge_names(ext_Names,
475 				   to->ext_Names,
476 				   to->ext_Booleans,
477 				   from->ext_Names,
478 				   from->ext_Booleans);
479 	ext_Numbers = merge_names(ext_Names + ext_Booleans,
480 				  to->ext_Names
481 				  + to->ext_Booleans,
482 				  to->ext_Numbers,
483 				  from->ext_Names
484 				  + from->ext_Booleans,
485 				  from->ext_Numbers);
486 	ext_Strings = merge_names(ext_Names + ext_Numbers + ext_Booleans,
487 				  to->ext_Names
488 				  + to->ext_Booleans
489 				  + to->ext_Numbers,
490 				  to->ext_Strings,
491 				  from->ext_Names
492 				  + from->ext_Booleans
493 				  + from->ext_Numbers,
494 				  from->ext_Strings);
495 	/*
496 	 * Now we must reallocate the Booleans, etc., to allow the data to be
497 	 * overlaid.
498 	 */
499 	if (na != (ext_Booleans + ext_Numbers + ext_Strings)) {
500 	    realign_data(to, ext_Names, ext_Booleans, ext_Numbers, ext_Strings);
501 	    FreeIfNeeded(to->ext_Names);
502 	    to->ext_Names = ext_Names;
503 	    DEBUG(2, ("realigned %d extended names for '%s' (to)",
504 		      NUM_EXT_NAMES(to), to->term_names));
505 	    used_ext_Names = TRUE;
506 	}
507 	if (nb != (ext_Booleans + ext_Numbers + ext_Strings)) {
508 	    nb = (ext_Booleans + ext_Numbers + ext_Strings);
509 	    realign_data(from, ext_Names, ext_Booleans, ext_Numbers, ext_Strings);
510 	    TYPE_REALLOC(char *, (size_t) nb, from->ext_Names);
511 	    memcpy(from->ext_Names, ext_Names, sizeof(char *) * (size_t) nb);
512 	    DEBUG(2, ("realigned %d extended names for '%s' (from)",
513 		      NUM_EXT_NAMES(from), from->term_names));
514 	}
515 	if (!used_ext_Names)
516 	    free(ext_Names);
517     }
518     DEBUG(2, (T_RETURN("")));
519 }
520 #endif
521 
522 #define srcINT 1
523 #define dstINT 2
524 
525 /*
526  * TERMTYPE and TERMTYPE2 differ only with regard to the values in Numbers.
527  * Use 'mode' to decide which to use.
528  */
529 static void
copy_termtype(TERMTYPE2 * dst,const TERMTYPE2 * src,int mode)530 copy_termtype(TERMTYPE2 *dst, const TERMTYPE2 *src, int mode)
531 {
532     unsigned i;
533     int pass;
534     char *new_table;
535     size_t new_table_size;
536 #if NCURSES_EXT_NUMBERS
537     short *oldptr = 0;
538     int *newptr = 0;
539 #endif
540 
541     DEBUG(2, (T_CALLED("copy_termtype(dst=%p, src=%p, mode=%d)"), (void *)
542 	      dst, (const void *) src, mode));
543     *dst = *src;		/* ...to copy the sizes and string-tables */
544 
545     TYPE_MALLOC(NCURSES_SBOOL, NUM_BOOLEANS(dst), dst->Booleans);
546     TYPE_MALLOC(char *, NUM_STRINGS(dst), dst->Strings);
547 
548     memcpy(dst->Booleans,
549 	   src->Booleans,
550 	   NUM_BOOLEANS(dst) * sizeof(dst->Booleans[0]));
551     memcpy(dst->Strings,
552 	   src->Strings,
553 	   NUM_STRINGS(dst) * sizeof(dst->Strings[0]));
554 
555     new_table = NULL;
556     new_table_size = 0;
557     for (pass = 0; pass < 2; ++pass) {
558 	size_t str_size = 0;
559 	if (src->term_names != NULL) {
560 	    if (pass) {
561 		dst->term_names = new_table + str_size;
562 		_nc_STRCPY(dst->term_names + str_size,
563 			   src->term_names,
564 			   new_table_size - str_size);
565 	    }
566 	    str_size += strlen(src->term_names) + 1;
567 	}
568 	for_each_string(i, src) {
569 	    if (VALID_STRING(src->Strings[i])) {
570 		if (pass) {
571 		    _nc_STRCPY(new_table + str_size,
572 			       src->Strings[i],
573 			       new_table_size - str_size);
574 		    dst->Strings[i] = new_table + str_size;
575 		}
576 		str_size += strlen(src->Strings[i]) + 1;
577 	    }
578 	}
579 	if (pass) {
580 	    dst->str_table = new_table;
581 	} else {
582 	    ++str_size;
583 	    if ((new_table = malloc(str_size)) == NULL)
584 		_nc_err_abort(MSG_NO_MEMORY);
585 	    new_table_size = str_size;
586 	}
587     }
588 
589 #if NCURSES_EXT_NUMBERS
590     if ((mode & dstINT) == 0) {
591 	DEBUG(2, ("...convert int ->short"));
592 	TYPE_MALLOC(short, NUM_NUMBERS(dst), oldptr);
593 	((TERMTYPE *) dst)->Numbers = oldptr;
594     } else {
595 	DEBUG(2, ("...copy without changing size"));
596 	TYPE_MALLOC(int, NUM_NUMBERS(dst), newptr);
597 	dst->Numbers = newptr;
598     }
599     if ((mode == srcINT) && (oldptr != 0)) {
600 	DEBUG(2, ("...copy int ->short"));
601 	for (i = 0; i < NUM_NUMBERS(dst); ++i) {
602 	    if (src->Numbers[i] > MAX_OF_TYPE(short)) {
603 		oldptr[i] = MAX_OF_TYPE(short);
604 	    } else {
605 		oldptr[i] = (short) src->Numbers[i];
606 	    }
607 	}
608     } else if ((mode == dstINT) && (newptr != 0)) {
609 	DEBUG(2, ("...copy short ->int"));
610 	for (i = 0; i < NUM_NUMBERS(dst); ++i) {
611 	    newptr[i] = ((const short *) (src->Numbers))[i];
612 	}
613     } else {
614 	DEBUG(2, ("...copy %s without change",
615 		  (mode & dstINT)
616 		  ? "int"
617 		  : "short"));
618 	memcpy(dst->Numbers,
619 	       src->Numbers,
620 	       NUM_NUMBERS(dst) * ((mode & dstINT)
621 				   ? sizeof(int)
622 				   : sizeof(short)));
623     }
624 #else
625     (void) mode;
626     TYPE_MALLOC(short, NUM_NUMBERS(dst), dst->Numbers);
627     memcpy(dst->Numbers,
628 	   src->Numbers,
629 	   NUM_NUMBERS(dst) * sizeof(dst->Numbers[0]));
630 #endif
631 
632 #if NCURSES_XNAMES
633     if ((i = NUM_EXT_NAMES(src)) != 0) {
634 	TYPE_MALLOC(char *, i, dst->ext_Names);
635 	memcpy(dst->ext_Names, src->ext_Names, i * sizeof(char *));
636 
637 	new_table = NULL;
638 	new_table_size = 0;
639 	for (pass = 0; pass < 2; ++pass) {
640 	    size_t str_size = 0;
641 	    char *raw_data = src->ext_str_table;
642 	    if (raw_data != NULL) {
643 		for (i = 0; i < src->ext_Strings; ++i) {
644 		    size_t skip = strlen(raw_data) + 1;
645 		    if (skip != 1) {
646 			if (pass) {
647 			    _nc_STRCPY(new_table + str_size,
648 				       raw_data,
649 				       new_table_size - str_size);
650 			}
651 			str_size += skip;
652 			raw_data += skip;
653 		    }
654 		}
655 	    }
656 	    for (i = 0; i < NUM_EXT_NAMES(dst); ++i) {
657 		if (VALID_STRING(src->ext_Names[i])) {
658 		    if (pass) {
659 			_nc_STRCPY(new_table + str_size,
660 				   src->ext_Names[i],
661 				   new_table_size - str_size);
662 			dst->ext_Names[i] = new_table + str_size;
663 		    }
664 		    str_size += strlen(src->ext_Names[i]) + 1;
665 		}
666 	    }
667 	    if (pass) {
668 		dst->ext_str_table = new_table;
669 	    } else {
670 		++str_size;
671 		if ((new_table = calloc(str_size, 1)) == NULL)
672 		    _nc_err_abort(MSG_NO_MEMORY);
673 		new_table_size = str_size;
674 	    }
675 	}
676     } else {
677 	dst->ext_Names = 0;
678     }
679 #endif
680     DEBUG(2, (T_RETURN("")));
681 }
682 
683 NCURSES_EXPORT(void)
_nc_copy_termtype(TERMTYPE * dst,const TERMTYPE * src)684 _nc_copy_termtype(TERMTYPE *dst, const TERMTYPE *src)
685 {
686     DEBUG(2, (T_CALLED("_nc_copy_termtype(dst=%p, src=%p)"), (void *) dst,
687 	      (const void *) src));
688     copy_termtype((TERMTYPE2 *) dst, (const TERMTYPE2 *) src, 0);
689     DEBUG(2, (T_RETURN("")));
690 }
691 
692 #if NCURSES_EXT_NUMBERS
693 NCURSES_EXPORT(void)
_nc_copy_termtype2(TERMTYPE2 * dst,const TERMTYPE2 * src)694 _nc_copy_termtype2(TERMTYPE2 *dst, const TERMTYPE2 *src)
695 {
696     DEBUG(2, (T_CALLED("_nc_copy_termtype2(dst=%p, src=%p)"), (void *) dst,
697 	      (const void *) src));
698     copy_termtype(dst, src, srcINT | dstINT);
699     DEBUG(2, (T_RETURN("")));
700 }
701 
702 /*
703  * Use this for exporting the internal TERMTYPE2 to the legacy format used via
704  * the CUR macro by applications.
705  */
706 NCURSES_EXPORT(void)
_nc_export_termtype2(TERMTYPE * dst,const TERMTYPE2 * src)707 _nc_export_termtype2(TERMTYPE *dst, const TERMTYPE2 *src)
708 {
709     DEBUG(2, (T_CALLED("_nc_export_termtype2(dst=%p, src=%p)"), (void *)
710 	      dst, (const void *) src));
711     copy_termtype((TERMTYPE2 *) dst, src, srcINT);
712     DEBUG(2, (T_RETURN("")));
713 }
714 #endif /* NCURSES_EXT_NUMBERS */
715