X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Fcomp_parse.c;h=8acdbdd4eafc64e89e57b1b5d67994634be521d4;hp=7284b02d51bf79bd9038d06cf5ac05a566b62505;hb=d761c922d94448b16b71061ee5efeb346b744f13;hpb=93ed44d781ca36f55021e0ad55f1ce33de62f7ba diff --git a/ncurses/tinfo/comp_parse.c b/ncurses/tinfo/comp_parse.c index 7284b02d..8acdbdd4 100644 --- a/ncurses/tinfo/comp_parse.c +++ b/ncurses/tinfo/comp_parse.c @@ -1,5 +1,6 @@ /**************************************************************************** - * Copyright (c) 1998-2016,2017 Free Software Foundation, Inc. * + * Copyright 2018-2021,2022 Thomas E. Dickey * + * Copyright 1998-2016,2017 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -47,10 +48,10 @@ #include -MODULE_ID("$Id: comp_parse.c,v 1.100 2017/09/20 00:37:08 tom Exp $") +MODULE_ID("$Id: comp_parse.c,v 1.123 2022/09/03 20:02:45 tom Exp $") static void sanity_check2(TERMTYPE2 *, bool); -NCURSES_IMPEXP void NCURSES_API(*_nc_check_termtype2) (TERMTYPE2 *, bool) = sanity_check2; +NCURSES_IMPEXP void (NCURSES_API *_nc_check_termtype2) (TERMTYPE2 *, bool) = sanity_check2; static void fixup_acsc(TERMTYPE2 *, int); @@ -58,8 +59,11 @@ static void enqueue(ENTRY * ep) /* add an entry to the in-core list */ { - ENTRY *newp = _nc_copy_entry(ep); + ENTRY *newp; + DEBUG(2, (T_CALLED("enqueue(ep=%p)"), (void *) ep)); + + newp = _nc_copy_entry(ep); if (newp == 0) _nc_err_abort(MSG_NO_MEMORY); @@ -69,6 +73,7 @@ enqueue(ENTRY * ep) newp->next = 0; if (newp->last) newp->last->next = newp; + DEBUG(2, (T_RETURN(""))); } #define NAMEBUFFER_SIZE (MAX_NAME_SIZE + 2) @@ -80,7 +85,7 @@ force_bar(char *dst, char *src) size_t len = strlen(src); if (len > MAX_NAME_SIZE) len = MAX_NAME_SIZE; - _nc_STRNCPY(dst, src, len); + _nc_STRNCPY(dst, src, MAX_NAME_SIZE); _nc_STRCPY(dst + len, "|", NAMEBUFFER_SIZE - len); src = dst; } @@ -180,11 +185,11 @@ remove_collision(char *n1, char *n2) ++qend; while ((*qstart++ = *qend++) != '\0') ; fprintf(stderr, "...now\t%s\n", p2); + removed = TRUE; } else { fprintf(stderr, "Cannot remove alias '%.*s'\n", (int) (qend - qstart), qstart); } - removed = TRUE; break; } } @@ -216,6 +221,10 @@ _nc_read_entry_source(FILE *fp, char *buf, bool oldsuppress = _nc_suppress_warnings; int immediate = 0; + DEBUG(2, + (T_CALLED("_nc_read_entry_source(file=%p, buf=%p, literal=%d, silent=%d, hook=%p)"), + (void *) fp, buf, literal, silent, (void *) hook)); + if (silent) _nc_suppress_warnings = TRUE; /* shut the lexer up, too */ @@ -245,6 +254,7 @@ _nc_read_entry_source(FILE *fp, char *buf, FreeIfNeeded(thisentry.tterm.Strings); #if NCURSES_XNAMES FreeIfNeeded(thisentry.tterm.ext_Names); + FreeIfNeeded(thisentry.tterm.ext_str_table); #endif } } @@ -254,27 +264,145 @@ _nc_read_entry_source(FILE *fp, char *buf, for (_nc_head = _nc_tail; _nc_head->last; _nc_head = _nc_head->last) continue; - DEBUG(1, ("head = %s", _nc_head->tterm.term_names)); - DEBUG(1, ("tail = %s", _nc_tail->tterm.term_names)); + DEBUG(2, ("head = %s", _nc_head->tterm.term_names)); + DEBUG(2, ("tail = %s", _nc_tail->tterm.term_names)); } #ifdef TRACE else if (!immediate) - DEBUG(1, ("no entries parsed")); + DEBUG(2, ("no entries parsed")); #endif _nc_suppress_warnings = oldsuppress; + DEBUG(2, (T_RETURN(""))); +} + +#if 0 && NCURSES_XNAMES +static unsigned +find_capname(TERMTYPE2 *p, const char *name) +{ + unsigned num_names = NUM_EXT_NAMES(p); + unsigned n; + if (name != 0) { + for (n = 0; n < num_names; ++n) { + if (!strcmp(p->ext_Names[n], name)) + break; + } + } else { + n = num_names + 1; + } + return n; +} + +static int +extended_captype(TERMTYPE2 *p, unsigned which) +{ + int result = UNDEF; + unsigned limit = 0; + limit += p->ext_Booleans; + if (limit != 0 && which < limit) { + result = BOOLEAN; + } else { + limit += p->ext_Numbers; + if (limit != 0 && which < limit) { + result = NUMBER; + } else { + limit += p->ext_Strings; + if (limit != 0 && which < limit) { + result = ((p->Strings[STRCOUNT + which] != CANCELLED_STRING) + ? STRING + : CANCEL); + } else if (which >= limit) { + result = CANCEL; + } + } + } + return result; } +static const char * +name_of_captype(int which) +{ + const char *result = "?"; + switch (which) { + case BOOLEAN: + result = "boolean"; + break; + case NUMBER: + result = "number"; + break; + case STRING: + result = "string"; + break; + } + return result; +} + +#define valid_TERMTYPE2(p) \ + ((p) != 0 && \ + (p)->term_names != 0 && \ + (p)->ext_Names != 0) + +/* + * Disallow changing the type of an extended capability when doing a "use" + * if one or the other is a string. + */ +static int +invalid_merge(TERMTYPE2 *to, TERMTYPE2 *from) +{ + int rc = FALSE; + if (valid_TERMTYPE2(to) + && valid_TERMTYPE2(from)) { + char *to_name = _nc_first_name(to->term_names); + char *from_name = strdup(_nc_first_name(from->term_names)); + unsigned num_names = NUM_EXT_NAMES(from); + unsigned n; + + for (n = 0; n < num_names; ++n) { + const char *capname = from->ext_Names[n]; + int tt = extended_captype(to, find_capname(to, capname)); + int tf = extended_captype(from, n); + + if (tt <= STRING + && tf <= STRING + && (tt == STRING) != (tf == STRING)) { + if (from_name != 0 && strcmp(to_name, from_name)) { + _nc_warning("merge of %s to %s changes type of %s from %s to %s", + from_name, + to_name, + from->ext_Names[n], + name_of_captype(tf), + name_of_captype(tt)); + } else { + _nc_warning("merge of %s changes type of %s from %s to %s", + to_name, + from->ext_Names[n], + name_of_captype(tf), + name_of_captype(tt)); + } + rc = TRUE; + } + } + free(from_name); + } + return rc; +} +#define validate_merge(p, q) \ + if (invalid_merge(&((p)->tterm), &((q)->tterm))) \ + return FALSE +#else +#define validate_merge(p, q) /* nothing */ +#endif + NCURSES_EXPORT(int) _nc_resolve_uses2(bool fullresolve, bool literal) /* try to resolve all use capabilities */ { ENTRY *qp, *rp, *lastread = 0; bool keepgoing; - unsigned i; + unsigned i, j; int unresolved, total_unresolved, multiples; - DEBUG(2, ("RESOLUTION BEGINNING")); + DEBUG(2, (T_CALLED("_nc_resolve_uses2"))); /* * Check for multiple occurrences of the same name. @@ -299,8 +427,10 @@ _nc_resolve_uses2(bool fullresolve, bool literal) } } } - if (multiples > 0) + if (multiples > 0) { + DEBUG(2, (T_RETURN("false"))); return (FALSE); + } DEBUG(2, ("NO MULTIPLE NAME OCCURRENCES")); @@ -317,6 +447,9 @@ _nc_resolve_uses2(bool fullresolve, bool literal) char *lookfor = qp->uses[i].name; long lookline = qp->uses[i].line; + if (lookfor == 0) + continue; + foundit = FALSE; _nc_set_type(child); @@ -325,11 +458,21 @@ _nc_resolve_uses2(bool fullresolve, bool literal) for_entry_list(rp) { if (rp != qp && _nc_name_match(rp->tterm.term_names, lookfor, "|")) { - DEBUG(2, ("%s: resolving use=%s (in core)", - child, lookfor)); + DEBUG(2, ("%s: resolving use=%s %p (in core)", + child, lookfor, lookfor)); qp->uses[i].link = rp; foundit = TRUE; + + /* verify that there are no earlier uses */ + for (j = 0; j < i; ++j) { + if (qp->uses[j].link != NULL + && !strcmp(qp->uses[j].link->tterm.term_names, + rp->tterm.term_names)) { + _nc_warning("duplicate use=%s", lookfor); + break; + } + } } } @@ -351,6 +494,16 @@ _nc_resolve_uses2(bool fullresolve, bool literal) qp->uses[i].link = rp; foundit = TRUE; + + /* verify that there are no earlier uses */ + for (j = 0; j < i; ++j) { + if (qp->uses[j].link != NULL + && !strcmp(qp->uses[j].link->tterm.term_names, + rp->tterm.term_names)) { + _nc_warning("duplicate use=%s", lookfor); + break; + } + } } } @@ -368,6 +521,7 @@ _nc_resolve_uses2(bool fullresolve, bool literal) if (total_unresolved) { /* free entries read in off disk */ _nc_free_entries(lastread); + DEBUG(2, (T_RETURN("false"))); return (FALSE); } @@ -386,19 +540,22 @@ _nc_resolve_uses2(bool fullresolve, bool literal) for_entry_list(qp) { if (qp->nuses > 0) { - DEBUG(2, ("%s: attempting merge", - _nc_first_name(qp->tterm.term_names))); + DEBUG(2, ("%s: attempting merge of %d entries", + _nc_first_name(qp->tterm.term_names), + qp->nuses)); /* * If any of the use entries we're looking for is * incomplete, punt. We'll catch this entry on a * subsequent pass. */ - for (i = 0; i < qp->nuses; i++) - if (qp->uses[i].link->nuses) { + for (i = 0; i < qp->nuses; i++) { + if (qp->uses[i].link + && qp->uses[i].link->nuses) { DEBUG(2, ("%s: use entry %d unresolved", _nc_first_name(qp->tterm.term_names), i)); goto incomplete; } + } /* * First, make sure there is no garbage in the @@ -412,13 +569,17 @@ _nc_resolve_uses2(bool fullresolve, bool literal) * Now merge in each use entry in the proper * (reverse) order. */ - for (; qp->nuses; qp->nuses--) + for (; qp->nuses; qp->nuses--) { + validate_merge(&merged, + qp->uses[qp->nuses - 1].link); _nc_merge_entry(&merged, qp->uses[qp->nuses - 1].link); + } /* * Now merge in the original entry. */ + validate_merge(&merged, qp); _nc_merge_entry(&merged, qp); /* @@ -427,8 +588,10 @@ _nc_resolve_uses2(bool fullresolve, bool literal) FreeIfNeeded(qp->tterm.Booleans); FreeIfNeeded(qp->tterm.Numbers); FreeIfNeeded(qp->tterm.Strings); + FreeIfNeeded(qp->tterm.str_table); #if NCURSES_XNAMES FreeIfNeeded(qp->tterm.ext_Names); + FreeIfNeeded(qp->tterm.ext_str_table); #endif qp->tterm = merged.tterm; _nc_wrap_entry(qp, TRUE); @@ -485,6 +648,14 @@ _nc_resolve_uses2(bool fullresolve, bool literal) _nc_check_termtype2(&qp->tterm, literal); + /* + * Checking calls tparm, which can allocate memory. Fix leaks. + */ +#define TPS(name) fake_tm.tparm_state.name + FreeAndNull(TPS(out_buff)); + FreeAndNull(TPS(fmt_buff)); +#undef TPS + _nc_set_screen(save_SP); set_curterm(save_tm); } else { @@ -494,6 +665,7 @@ _nc_resolve_uses2(bool fullresolve, bool literal) DEBUG(2, ("SANITY CHECK FINISHED")); } + DEBUG(2, (T_RETURN("true"))); return (TRUE); } @@ -580,7 +752,7 @@ sanity_check2(TERMTYPE2 *tp, bool literal) NCURSES_EXPORT(void) _nc_leaks_tic(void) { - T((T_CALLED("_nc_free_tic()"))); + T((T_CALLED("_nc_leaks_tic()"))); _nc_globals.leak_checking = TRUE; _nc_alloc_entry_leaks(); _nc_captoinfo_leaks(); @@ -590,12 +762,14 @@ _nc_leaks_tic(void) _nc_codes_leaks(); #endif _nc_tic_expand(0, FALSE, 0); + T((T_RETURN(""))); } NCURSES_EXPORT(void) _nc_free_tic(int code) { + T((T_CALLED("_nc_free_tic(%d)"), code)); _nc_leaks_tic(); - _nc_free_tinfo(code); + exit_terminfo(code); } #endif