150276Speter/**************************************************************************** 2184989Srafan * Copyright (c) 1999-2006,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 30166124Srafan * Author: Thomas E. Dickey <dickey@clark.net> 1999-on * 3150276Speter ****************************************************************************/ 3250276Speter 3350276Speter/* 3450276Speter * align_ttype.c -- functions for TERMTYPE 3550276Speter * 3650276Speter * _nc_align_termtype() 3750276Speter * _nc_copy_termtype() 3850276Speter * 3950276Speter */ 4050276Speter 4150276Speter#include <curses.priv.h> 4250276Speter 4350276Speter#include <tic.h> 4450276Speter#include <term_entry.h> 4550276Speter 46184989SrafanMODULE_ID("$Id: alloc_ttype.c,v 1.17 2008/10/12 16:12:00 tom Exp $") 4750276Speter 4850276Speter#if NCURSES_XNAMES 4950276Speter/* 5050276Speter * Merge the a/b lists into dst. Both a/b are sorted (see _nc_extend_names()), 5150276Speter * so we do not have to worry about order dependencies. 5250276Speter */ 5362449Speterstatic int 5462449Spetermerge_names(char **dst, char **a, int na, char **b, int nb) 5550276Speter{ 5650276Speter int n = 0; 5766963Speter while (na > 0 && nb > 0) { 5850276Speter int cmp = strcmp(*a, *b); 5950276Speter if (cmp < 0) { 6050276Speter dst[n++] = *a++; 6150276Speter na--; 6250276Speter } else if (cmp > 0) { 6350276Speter dst[n++] = *b++; 6450276Speter nb--; 6550276Speter } else if (cmp == 0) { 6650276Speter dst[n++] = *a; 6750276Speter a++, b++; 6850276Speter na--, nb--; 6950276Speter } 7050276Speter } 7150276Speter while (na-- > 0) { 7250276Speter dst[n++] = *a++; 7350276Speter } 7450276Speter while (nb-- > 0) { 7550276Speter dst[n++] = *b++; 7650276Speter } 7750276Speter DEBUG(4, ("merge_names -> %d", n)); 7850276Speter return n; 7950276Speter} 8050276Speter 8162449Speterstatic bool 8262449Speterfind_name(char **table, int length, char *name) 8350276Speter{ 8450276Speter while (length-- > 0) { 8550276Speter if (!strcmp(*table++, name)) { 8650276Speter DEBUG(4, ("found name '%s'", name)); 8750276Speter return TRUE; 8850276Speter } 8950276Speter } 9050276Speter DEBUG(4, ("did not find name '%s'", name)); 9150276Speter return FALSE; 9250276Speter} 9350276Speter 9462449Speterstatic void 95166124Srafanrealign_data(TERMTYPE *to, char **ext_Names, 96166124Srafan int ext_Booleans, 97166124Srafan int ext_Numbers, 98166124Srafan int ext_Strings) 9950276Speter{ 10050276Speter int n, m, base; 10150276Speter int limit = (to->ext_Booleans + to->ext_Numbers + to->ext_Strings); 10250276Speter 10350276Speter if (to->ext_Booleans != ext_Booleans) { 10450276Speter to->num_Booleans += (ext_Booleans - to->ext_Booleans); 105166124Srafan to->Booleans = typeRealloc(NCURSES_SBOOL, to->num_Booleans, to->Booleans); 10662449Speter for (n = to->ext_Booleans - 1, 10766963Speter m = ext_Booleans - 1, 10866963Speter base = to->num_Booleans - (m + 1); m >= 0; m--) { 10950276Speter if (find_name(to->ext_Names, limit, ext_Names[m])) { 11050276Speter to->Booleans[base + m] = to->Booleans[base + n--]; 11150276Speter } else { 11250276Speter to->Booleans[base + m] = FALSE; 11350276Speter } 11450276Speter } 11550276Speter to->ext_Booleans = ext_Booleans; 11650276Speter } 11750276Speter if (to->ext_Numbers != ext_Numbers) { 11850276Speter to->num_Numbers += (ext_Numbers - to->ext_Numbers); 11950276Speter to->Numbers = typeRealloc(short, to->num_Numbers, to->Numbers); 12062449Speter for (n = to->ext_Numbers - 1, 12166963Speter m = ext_Numbers - 1, 12266963Speter base = to->num_Numbers - (m + 1); m >= 0; m--) { 12362449Speter if (find_name(to->ext_Names, limit, ext_Names[m + ext_Booleans])) { 12450276Speter to->Numbers[base + m] = to->Numbers[base + n--]; 12550276Speter } else { 12650276Speter to->Numbers[base + m] = ABSENT_NUMERIC; 12750276Speter } 12850276Speter } 12962449Speter to->ext_Numbers = ext_Numbers; 13050276Speter } 13150276Speter if (to->ext_Strings != ext_Strings) { 13250276Speter to->num_Strings += (ext_Strings - to->ext_Strings); 13362449Speter to->Strings = typeRealloc(char *, to->num_Strings, to->Strings); 13462449Speter for (n = to->ext_Strings - 1, 13566963Speter m = ext_Strings - 1, 13666963Speter base = to->num_Strings - (m + 1); m >= 0; m--) { 13762449Speter if (find_name(to->ext_Names, limit, ext_Names[m + ext_Booleans + ext_Numbers])) { 13850276Speter to->Strings[base + m] = to->Strings[base + n--]; 13950276Speter } else { 14050276Speter to->Strings[base + m] = ABSENT_STRING; 14150276Speter } 14250276Speter } 14350276Speter to->ext_Strings = ext_Strings; 14450276Speter } 14550276Speter} 14650276Speter 14750276Speter/* 14850276Speter * Returns the first index in ext_Names[] for the given token-type 14950276Speter */ 15062449Speterstatic int 151166124Srafan_nc_first_ext_name(TERMTYPE *tp, int token_type) 15250276Speter{ 15350276Speter int first; 15450276Speter 15550276Speter switch (token_type) { 15650276Speter case BOOLEAN: 15750276Speter first = 0; 15850276Speter break; 15950276Speter case NUMBER: 16050276Speter first = tp->ext_Booleans; 16150276Speter break; 16250276Speter case STRING: 16350276Speter first = tp->ext_Booleans + tp->ext_Numbers; 16450276Speter break; 16550276Speter default: 16650276Speter first = 0; 16750276Speter break; 16850276Speter } 16950276Speter return first; 17050276Speter} 17150276Speter 17250276Speter/* 17350276Speter * Returns the last index in ext_Names[] for the given token-type 17450276Speter */ 17562449Speterstatic int 176166124Srafan_nc_last_ext_name(TERMTYPE *tp, int token_type) 17750276Speter{ 17850276Speter int last; 17950276Speter 18050276Speter switch (token_type) { 18150276Speter case BOOLEAN: 18262449Speter last = tp->ext_Booleans; 18350276Speter break; 18450276Speter case NUMBER: 18562449Speter last = tp->ext_Booleans + tp->ext_Numbers; 18650276Speter break; 18750276Speter default: 18850276Speter case STRING: 18962449Speter last = NUM_EXT_NAMES(tp); 19050276Speter break; 19150276Speter } 19250276Speter return last; 19350276Speter} 19450276Speter 19550276Speter/* 19650276Speter * Lookup an entry from extended-names, returning -1 if not found 19750276Speter */ 19862449Speterstatic int 199166124Srafan_nc_find_ext_name(TERMTYPE *tp, char *name, int token_type) 20050276Speter{ 20150276Speter unsigned j; 20250276Speter unsigned first = _nc_first_ext_name(tp, token_type); 20362449Speter unsigned last = _nc_last_ext_name(tp, token_type); 20450276Speter 20550276Speter for (j = first; j < last; j++) { 20650276Speter if (!strcmp(name, tp->ext_Names[j])) { 20750276Speter return j; 20850276Speter } 20950276Speter } 21050276Speter return -1; 21150276Speter} 21250276Speter 21350276Speter/* 21450276Speter * Translate an index into ext_Names[] into the corresponding index into data 21550276Speter * (e.g., Booleans[]). 21650276Speter */ 21762449Speterstatic int 218166124Srafan_nc_ext_data_index(TERMTYPE *tp, int n, int token_type) 21950276Speter{ 22050276Speter switch (token_type) { 22150276Speter case BOOLEAN: 22250276Speter n += (tp->num_Booleans - tp->ext_Booleans); 22350276Speter break; 22450276Speter case NUMBER: 22550276Speter n += (tp->num_Numbers - tp->ext_Numbers) 22662449Speter - (tp->ext_Booleans); 22750276Speter break; 22850276Speter default: 22950276Speter case STRING: 23050276Speter n += (tp->num_Strings - tp->ext_Strings) 23162449Speter - (tp->ext_Booleans + tp->ext_Numbers); 23250276Speter } 23350276Speter return n; 23450276Speter} 23550276Speter 23650276Speter/* 23750276Speter * Adjust tables to remove (not free) an extended name and its corresponding 23850276Speter * data. 23950276Speter */ 24066963Speterstatic bool 241166124Srafan_nc_del_ext_name(TERMTYPE *tp, char *name, int token_type) 24250276Speter{ 24350276Speter int j; 24450276Speter int first, last; 24550276Speter 24650276Speter if ((first = _nc_find_ext_name(tp, name, token_type)) >= 0) { 24750276Speter last = NUM_EXT_NAMES(tp) - 1; 24850276Speter for (j = first; j < last; j++) { 24962449Speter tp->ext_Names[j] = tp->ext_Names[j + 1]; 25050276Speter } 25150276Speter first = _nc_ext_data_index(tp, first, token_type); 25250276Speter switch (token_type) { 25350276Speter case BOOLEAN: 25450276Speter last = tp->num_Booleans - 1; 25550276Speter for (j = first; j < last; j++) 25662449Speter tp->Booleans[j] = tp->Booleans[j + 1]; 25750276Speter tp->ext_Booleans -= 1; 25850276Speter tp->num_Booleans -= 1; 25950276Speter break; 26050276Speter case NUMBER: 26150276Speter last = tp->num_Numbers - 1; 26250276Speter for (j = first; j < last; j++) 26362449Speter tp->Numbers[j] = tp->Numbers[j + 1]; 26450276Speter tp->ext_Numbers -= 1; 26550276Speter tp->num_Numbers -= 1; 26650276Speter break; 26750276Speter case STRING: 26850276Speter last = tp->num_Strings - 1; 26950276Speter for (j = first; j < last; j++) 27062449Speter tp->Strings[j] = tp->Strings[j + 1]; 27150276Speter tp->ext_Strings -= 1; 27250276Speter tp->num_Strings -= 1; 27350276Speter break; 27450276Speter } 27566963Speter return TRUE; 27650276Speter } 27766963Speter return FALSE; 27850276Speter} 27950276Speter 28050276Speter/* 28150276Speter * Adjust tables to insert an extended name, making room for new data. The 28250276Speter * index into the corresponding data array is returned. 28350276Speter */ 28462449Speterstatic int 285166124Srafan_nc_ins_ext_name(TERMTYPE *tp, char *name, int token_type) 28650276Speter{ 28750276Speter unsigned first = _nc_first_ext_name(tp, token_type); 28862449Speter unsigned last = _nc_last_ext_name(tp, token_type); 28950276Speter unsigned total = NUM_EXT_NAMES(tp) + 1; 29050276Speter unsigned j, k; 29150276Speter 29250276Speter for (j = first; j < last; j++) { 29350276Speter int cmp = strcmp(name, tp->ext_Names[j]); 29450276Speter if (cmp == 0) 29550276Speter /* already present */ 296166124Srafan return _nc_ext_data_index(tp, (int) j, token_type); 29750276Speter if (cmp < 0) { 29850276Speter break; 29950276Speter } 30050276Speter } 30150276Speter 30250276Speter tp->ext_Names = typeRealloc(char *, total, tp->ext_Names); 30362449Speter for (k = total - 1; k > j; k--) 30462449Speter tp->ext_Names[k] = tp->ext_Names[k - 1]; 30550276Speter tp->ext_Names[j] = name; 306166124Srafan j = _nc_ext_data_index(tp, (int) j, token_type); 30750276Speter 30850276Speter switch (token_type) { 30950276Speter case BOOLEAN: 31050276Speter tp->ext_Booleans += 1; 31150276Speter tp->num_Booleans += 1; 312166124Srafan tp->Booleans = typeRealloc(NCURSES_SBOOL, tp->num_Booleans, tp->Booleans); 31362449Speter for (k = tp->num_Booleans - 1; k > j; k--) 31462449Speter tp->Booleans[k] = tp->Booleans[k - 1]; 31550276Speter break; 31650276Speter case NUMBER: 31750276Speter tp->ext_Numbers += 1; 31850276Speter tp->num_Numbers += 1; 31950276Speter tp->Numbers = typeRealloc(short, tp->num_Numbers, tp->Numbers); 32062449Speter for (k = tp->num_Numbers - 1; k > j; k--) 32162449Speter tp->Numbers[k] = tp->Numbers[k - 1]; 32250276Speter break; 32350276Speter case STRING: 32450276Speter tp->ext_Strings += 1; 32550276Speter tp->num_Strings += 1; 32650276Speter tp->Strings = typeRealloc(char *, tp->num_Strings, tp->Strings); 32762449Speter for (k = tp->num_Strings - 1; k > j; k--) 32862449Speter tp->Strings[k] = tp->Strings[k - 1]; 32950276Speter break; 33050276Speter } 33150276Speter return j; 33250276Speter} 33350276Speter 33450276Speter/* 33550276Speter * Look for strings that are marked cancelled, which happen to be the same name 33650276Speter * as a boolean or number. We'll get this as a special case when we get a 33750276Speter * cancellation of a name that is inherited from another entry. 33850276Speter */ 33962449Speterstatic void 340166124Srafanadjust_cancels(TERMTYPE *to, TERMTYPE *from) 34150276Speter{ 34250276Speter int first = to->ext_Booleans + to->ext_Numbers; 34362449Speter int last = first + to->ext_Strings; 34450276Speter int j, k; 34550276Speter 34662449Speter for (j = first; j < last;) { 34750276Speter char *name = to->ext_Names[j]; 34850276Speter unsigned j_str = to->num_Strings - first - to->ext_Strings; 34950276Speter 35050276Speter if (to->Strings[j + j_str] == CANCELLED_STRING) { 35150276Speter if ((k = _nc_find_ext_name(from, to->ext_Names[j], BOOLEAN)) >= 0) { 35266963Speter if (_nc_del_ext_name(to, name, STRING) 35366963Speter || _nc_del_ext_name(to, name, NUMBER)) { 35466963Speter k = _nc_ins_ext_name(to, name, BOOLEAN); 35566963Speter to->Booleans[k] = FALSE; 35666963Speter } else { 35766963Speter j++; 35866963Speter } 35962449Speter } else if ((k = _nc_find_ext_name(from, to->ext_Names[j], 36066963Speter NUMBER)) >= 0) { 36166963Speter if (_nc_del_ext_name(to, name, STRING) 36266963Speter || _nc_del_ext_name(to, name, BOOLEAN)) { 36366963Speter k = _nc_ins_ext_name(to, name, NUMBER); 36466963Speter to->Numbers[k] = CANCELLED_NUMERIC; 36566963Speter } else { 36666963Speter j++; 36766963Speter } 368184989Srafan } else if ((k = _nc_find_ext_name(from, to->ext_Names[j], 369184989Srafan STRING)) >= 0) { 370184989Srafan if (_nc_del_ext_name(to, name, NUMBER) 371184989Srafan || _nc_del_ext_name(to, name, BOOLEAN)) { 372184989Srafan k = _nc_ins_ext_name(to, name, STRING); 373184989Srafan to->Strings[k] = CANCELLED_STRING; 374184989Srafan } else { 375184989Srafan j++; 376184989Srafan } 377184989Srafan } else { 378184989Srafan j++; 37950276Speter } 38050276Speter } else { 38150276Speter j++; 38250276Speter } 38350276Speter } 38450276Speter} 38550276Speter 38676726SpeterNCURSES_EXPORT(void) 387166124Srafan_nc_align_termtype(TERMTYPE *to, TERMTYPE *from) 38850276Speter{ 38950276Speter int na = NUM_EXT_NAMES(to); 39050276Speter int nb = NUM_EXT_NAMES(from); 39150276Speter int n; 39250276Speter bool same; 39350276Speter char **ext_Names; 39450276Speter int ext_Booleans, ext_Numbers, ext_Strings; 395166124Srafan bool used_ext_Names = FALSE; 39650276Speter 39762449Speter DEBUG(2, ("align_termtype to(%d:%s), from(%d:%s)", na, to->term_names, 39866963Speter nb, from->term_names)); 39950276Speter 40050276Speter if (na != 0 || nb != 0) { 40150276Speter if ((na == nb) /* check if the arrays are equivalent */ 40262449Speter &&(to->ext_Booleans == from->ext_Booleans) 40362449Speter && (to->ext_Numbers == from->ext_Numbers) 40462449Speter && (to->ext_Strings == from->ext_Strings)) { 40550276Speter for (n = 0, same = TRUE; n < na; n++) { 40650276Speter if (strcmp(to->ext_Names[n], from->ext_Names[n])) { 40750276Speter same = FALSE; 40850276Speter break; 40950276Speter } 41050276Speter } 41150276Speter if (same) 41250276Speter return; 41350276Speter } 41450276Speter /* 41550276Speter * This is where we pay for having a simple extension representation. 41650276Speter * Allocate a new ext_Names array and merge the two ext_Names arrays 41750276Speter * into it, updating to's counts for booleans, etc. Fortunately we do 41850276Speter * this only for the terminfo compiler (tic) and comparer (infocmp). 41950276Speter */ 42062449Speter ext_Names = typeMalloc(char *, na + nb); 42150276Speter 42250276Speter if (to->ext_Strings && (from->ext_Booleans + from->ext_Numbers)) 42350276Speter adjust_cancels(to, from); 42450276Speter 42550276Speter if (from->ext_Strings && (to->ext_Booleans + to->ext_Numbers)) 42650276Speter adjust_cancels(from, to); 42750276Speter 42850276Speter ext_Booleans = merge_names(ext_Names, 42966963Speter to->ext_Names, 43066963Speter to->ext_Booleans, 43166963Speter from->ext_Names, 43266963Speter from->ext_Booleans); 43362449Speter ext_Numbers = merge_names(ext_Names + ext_Booleans, 43466963Speter to->ext_Names 43566963Speter + to->ext_Booleans, 43666963Speter to->ext_Numbers, 43766963Speter from->ext_Names 43866963Speter + from->ext_Booleans, 43966963Speter from->ext_Numbers); 44062449Speter ext_Strings = merge_names(ext_Names + ext_Numbers + ext_Booleans, 44166963Speter to->ext_Names 44266963Speter + to->ext_Booleans 44366963Speter + to->ext_Numbers, 44466963Speter to->ext_Strings, 44566963Speter from->ext_Names 44666963Speter + from->ext_Booleans 44766963Speter + from->ext_Numbers, 44866963Speter from->ext_Strings); 44950276Speter /* 45050276Speter * Now we must reallocate the Booleans, etc., to allow the data to be 45150276Speter * overlaid. 45250276Speter */ 45350276Speter if (na != (ext_Booleans + ext_Numbers + ext_Strings)) { 45450276Speter realign_data(to, ext_Names, ext_Booleans, ext_Numbers, ext_Strings); 45562449Speter FreeIfNeeded(to->ext_Names); 45650276Speter to->ext_Names = ext_Names; 45762449Speter DEBUG(2, ("realigned %d extended names for '%s' (to)", 45866963Speter NUM_EXT_NAMES(to), to->term_names)); 459166124Srafan used_ext_Names = TRUE; 46050276Speter } 46150276Speter if (nb != (ext_Booleans + ext_Numbers + ext_Strings)) { 46250276Speter nb = (ext_Booleans + ext_Numbers + ext_Strings); 46350276Speter realign_data(from, ext_Names, ext_Booleans, ext_Numbers, ext_Strings); 46450276Speter from->ext_Names = typeRealloc(char *, nb, from->ext_Names); 46550276Speter memcpy(from->ext_Names, ext_Names, sizeof(char *) * nb); 46662449Speter DEBUG(2, ("realigned %d extended names for '%s' (from)", 46766963Speter NUM_EXT_NAMES(from), from->term_names)); 46850276Speter } 469166124Srafan if (!used_ext_Names) 470166124Srafan free(ext_Names); 47150276Speter } 47250276Speter} 47350276Speter#endif 47450276Speter 47576726SpeterNCURSES_EXPORT(void) 476166124Srafan_nc_copy_termtype(TERMTYPE *dst, TERMTYPE *src) 47750276Speter{ 478166124Srafan unsigned i; 47950276Speter 48062449Speter *dst = *src; /* ...to copy the sizes and string-tables */ 481166124Srafan dst->Booleans = typeMalloc(NCURSES_SBOOL, NUM_BOOLEANS(dst)); 48262449Speter dst->Numbers = typeMalloc(short, NUM_NUMBERS(dst)); 48362449Speter dst->Strings = typeMalloc(char *, NUM_STRINGS(dst)); 48450276Speter 48550276Speter /* FIXME: use memcpy for these and similar loops */ 48662449Speter for_each_boolean(i, dst) 48750276Speter dst->Booleans[i] = src->Booleans[i]; 48862449Speter for_each_number(i, dst) 48950276Speter dst->Numbers[i] = src->Numbers[i]; 49062449Speter for_each_string(i, dst) 49150276Speter dst->Strings[i] = src->Strings[i]; 49250276Speter 49350276Speter /* FIXME: we probably should also copy str_table and ext_str_table, 49450276Speter * but tic and infocmp are not written to exploit that (yet). 49550276Speter */ 49650276Speter 49750276Speter#if NCURSES_XNAMES 49850276Speter if ((i = NUM_EXT_NAMES(src)) != 0) { 49950276Speter dst->ext_Names = typeMalloc(char *, i); 50050276Speter memcpy(dst->ext_Names, src->ext_Names, i * sizeof(char *)); 50162449Speter } else { 50262449Speter dst->ext_Names = 0; 50350276Speter } 50450276Speter#endif 50550276Speter 50650276Speter} 507