X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=progs%2Ftic.c;h=5f08270963715febfc3c27a3ddda3966efa5107d;hp=6163e32961c39900dc60aa1c815d76c044ef6169;hb=refs%2Ftags%2Fv5.0;hpb=661078ddbde3ce0f3b06e95642fbb9b5fef7dca1 diff --git a/progs/tic.c b/progs/tic.c index 6163e329..5f082709 100644 --- a/progs/tic.c +++ b/progs/tic.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998 Free Software Foundation, Inc. * + * Copyright (c) 1998,1999 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 * @@ -42,14 +42,39 @@ #include #include -MODULE_ID("$Id: tic.c,v 1.28 1998/02/11 12:14:02 tom Exp $") +MODULE_ID("$Id: tic.c,v 1.52 1999/09/25 22:47:54 tom Exp $") const char *_nc_progname = "tic"; static FILE *log_fp; +static FILE *tmp_fp; static bool showsummary = FALSE; +static const char *to_remove; -static const char usage_string[] = "[-hc] [-v[n]] [-e names] [-CILNRTrsw1] source-file\n"; +static void (*save_check_termtype)(TERMTYPE *); +static void check_termtype(TERMTYPE *tt); + +static const char usage_string[] = "[-h] [-v[n]] [-e names] [-CILNRTcfrswx1] source-file\n"; + +static void cleanup(void) +{ + if (tmp_fp != 0) + fclose(tmp_fp); + if (to_remove != 0) { +#if HAVE_REMOVE + remove(to_remove); +#else + unlink(to_remove); +#endif + } +} + +static void failed(const char *msg) +{ + perror(msg); + cleanup(); + exit(EXIT_FAILURE); +} static void usage(void) { @@ -63,12 +88,18 @@ static void usage(void) " -R restrict translation to given terminfo/termcap version", " -T remove size-restrictions on compiled description", " -c check only, validate input without compiling or translating", + " -f format complex strings for readability", + " -G format %{number} to %'char'", + " -g format %'char' to %{number}", " -e translate/compile only entries named by comma-separated list", " -o set output directory for compiled entry writes", " -r force resolution of all use entries in source translation", " -s print summary statistics", " -v[n] set verbosity level", " -w[n] set format width for translation output", +#if NCURSES_XNAMES + " -x treat unknown capabilities as user-defined", +#endif "", "Parameters:", " file to translate or compile" @@ -81,7 +112,60 @@ static void usage(void) exit(EXIT_FAILURE); } -static bool immedhook(ENTRY *ep) +#define L_BRACE '{' +#define R_BRACE '}' +#define S_QUOTE '\''; + +static void write_it(ENTRY *ep) +{ + unsigned n; + int ch; + char *s, *d, *t; + char result[MAX_ENTRY_SIZE]; + + /* + * Look for strings that contain %{number}, convert them to %'char', + * which is shorter and runs a little faster. + */ + for (n = 0; n < STRCOUNT; n++) { + s = ep->tterm.Strings[n]; + if (VALID_STRING(s) + && strchr(s, L_BRACE) != 0) { + d = result; + t = s; + while ((ch = *t++) != 0) { + *d++ = ch; + if (ch == '\\') { + *d++ = *t++; + } else if ((ch == '%') + && (*t == L_BRACE)) { + char *v = 0; + long value = strtol(t+1, &v, 0); + if (v != 0 + && *v == R_BRACE + && value > 0 + && value != '\\' /* FIXME */ + && value < 127 + && isprint((int)value)) { + *d++ = S_QUOTE; + *d++ = (int)value; + *d++ = S_QUOTE; + t = (v + 1); + } + } + } + *d = 0; + if (strlen(result) < strlen(s)) + strcpy(s, result); + } + } + + _nc_set_type(_nc_first_name(ep->tterm.term_names)); + _nc_curr_line = ep->startline; + _nc_write_entry(&ep->tterm); +} + +static bool immedhook(ENTRY *ep GCC_UNUSED) /* write out entries with no use capabilities immediately to save storage */ { #ifndef HAVE_BIG_CORE @@ -122,16 +206,13 @@ static bool immedhook(ENTRY *ep) { int oldline = _nc_curr_line; - _nc_set_type(_nc_first_name(ep->tterm.term_names)); - _nc_curr_line = ep->startline; - _nc_write_entry(&ep->tterm); + write_it(ep); _nc_curr_line = oldline; free(ep->tterm.str_table); return(TRUE); } - else #endif /* HAVE_BIG_CORE */ - return(FALSE); + return(FALSE); } static void put_translate(int c) @@ -217,15 +298,16 @@ static const char **make_namelist(char *src) const char **dst = 0; char *s, *base; - size_t pass, n, nn; + unsigned pass, n, nn; char buffer[BUFSIZ]; - if (strchr(src, '/') != 0) { /* a filename */ + if (src == 0) { + /* EMPTY */; + } else if (strchr(src, '/') != 0) { /* a filename */ FILE *fp = fopen(src, "r"); - if (fp == 0) { - perror(src); - exit(EXIT_FAILURE); - } + if (fp == 0) + failed(src); + for (pass = 1; pass <= 2; pass++) { nn = 0; while (fgets(buffer, sizeof(buffer), fp) != 0) { @@ -294,6 +376,7 @@ static bool matches(const char **needle, const char *haystack) int main (int argc, char *argv[]) { +char my_tmpname[PATH_MAX]; int v_opt = -1, debug_level; int smart_defaults = TRUE; char *termcap; @@ -305,6 +388,8 @@ int outform = F_TERMINFO; /* output format */ int sortmode = S_TERMINFO; /* sort_mode */ int width = 60; +bool formatted = FALSE; /* reformat complex strings? */ +int numbers = 0; /* format "%'char'" to/from "%{number}" */ bool infodump = FALSE; /* running as captoinfo? */ bool capdump = FALSE; /* running as infotocap? */ bool forceresolve = FALSE; /* force resolution */ @@ -324,13 +409,16 @@ bool check_only = FALSE; infodump = (strcmp(_nc_progname, "captoinfo") == 0); capdump = (strcmp(_nc_progname, "infotocap") == 0); +#if NCURSES_XNAMES + use_extended_names(FALSE); +#endif /* * Processing arguments is a little complicated, since someone made a * design decision to allow the numeric values for -w, -v options to * be optional. */ - while ((this_opt = getopt(argc, argv, "0123456789CILNR:TVce:o:rsvw")) != EOF) { + while ((this_opt = getopt(argc, argv, "0123456789CILNR:TVce:fGgo:rsvwx")) != EOF) { if (isdigit(this_opt)) { switch (last_opt) { case 'v': @@ -381,6 +469,15 @@ bool check_only = FALSE; case 'e': namelst = make_namelist(optarg); break; + case 'f': + formatted = TRUE; + break; + case 'G': + numbers = 1; + break; + case 'g': + numbers = -1; + break; case 'o': outdir = optarg; break; @@ -396,6 +493,11 @@ bool check_only = FALSE; case 'w': width = 0; break; +#if NCURSES_XNAMES + case 'x': + use_extended_names(TRUE); + break; +#endif default: usage(); } @@ -405,6 +507,32 @@ bool check_only = FALSE; debug_level = (v_opt > 0) ? v_opt : (v_opt == 0); _nc_tracing = (1 << debug_level) - 1; + if (_nc_tracing) + { + save_check_termtype = _nc_check_termtype; + _nc_check_termtype = check_termtype; + } + +#ifndef HAVE_BIG_CORE + /* + * Aaargh! immedhook seriously hoses us! + * + * One problem with immedhook is it means we can't do -e. Problem + * is that we can't guarantee that for each terminal listed, all the + * terminals it depends on will have been kept in core for reference + * resolution -- in fact it's certain the primitive types at the end + * of reference chains *won't* be in core unless they were explicitly + * in the select list themselves. + */ + if (namelst && (!infodump && !capdump)) + { + (void) fprintf(stderr, + "Sorry, -e can't be used without -I or -C\n"); + cleanup(); + return EXIT_FAILURE; + } +#endif /* HAVE_BIG_CORE */ + if (optind < argc) { source_file = argv[optind++]; if (optind < argc) { @@ -419,10 +547,20 @@ bool check_only = FALSE; if (infodump == TRUE) { /* captoinfo's no-argument case */ source_file = "/etc/termcap"; - if ((termcap = getenv("TERMCAP")) != NULL) { + if ((termcap = getenv("TERMCAP")) != 0 + && (namelst = make_namelist(getenv("TERM"))) != 0) { if (access(termcap, F_OK) == 0) { /* file exists */ source_file = termcap; + } else + if ((source_file = tmpnam(my_tmpname)) != 0 + && (tmp_fp = fopen(source_file, "w")) != 0) { + fprintf(tmp_fp, "%s\n", termcap); + fclose(tmp_fp); + tmp_fp = fopen(source_file, "r"); + to_remove = source_file; + } else { + failed("tmpnam"); } } } else { @@ -432,11 +570,13 @@ bool check_only = FALSE; _nc_progname, _nc_progname, usage_string); + cleanup(); return EXIT_FAILURE; } } - if (freopen(source_file, "r", stdin) == NULL) { + if (tmp_fp == 0 + && (tmp_fp = fopen(source_file, "r")) == 0) { fprintf (stderr, "%s: Can't open %s\n", _nc_progname, source_file); return EXIT_FAILURE; } @@ -446,11 +586,11 @@ bool check_only = FALSE; smart_defaults ? outform : F_LITERAL, - sortmode, width, debug_level); + sortmode, width, debug_level, formatted); else if (capdump) dump_init(tversion, outform, - sortmode, width, debug_level); + sortmode, width, debug_level, FALSE); /* parse entries out of the source file */ _nc_set_source(source_file); @@ -458,33 +598,17 @@ bool check_only = FALSE; if (!(check_only || infodump || capdump)) _nc_set_writedir(outdir); #endif /* HAVE_BIG_CORE */ - _nc_read_entry_source(stdin, (char *)NULL, + _nc_read_entry_source(tmp_fp, (char *)NULL, !smart_defaults, FALSE, (check_only || infodump || capdump) ? NULLHOOK : immedhook); /* do use resolution */ - if (check_only || (!infodump && !capdump) || forceresolve) - if (!_nc_resolve_uses() && !check_only) + if (check_only || (!infodump && !capdump) || forceresolve) { + if (!_nc_resolve_uses() && !check_only) { + cleanup(); return EXIT_FAILURE; - -#ifndef HAVE_BIG_CORE - /* - * Aaargh! immedhook seriously hoses us! - * - * One problem with immedhook is it means we can't do -e. Problem - * is that we can't guarantee that for each terminal listed, all the - * terminals it depends on will have been kept in core for reference - * resolution -- in fact it's certain the primitive types at the end - * of reference chains *won't* be in core unless they were explicitly - * in the select list themselves. - */ - if (namelst && (!infodump && !capdump)) - { - (void) fprintf(stderr, - "Sorry, -e can't be used without -I or -C\n"); - return EXIT_FAILURE; + } } -#endif /* HAVE_BIG_CORE */ /* length check */ if (check_only && (capdump || infodump)) @@ -493,7 +617,7 @@ bool check_only = FALSE; { if (matches(namelst, qp->tterm.term_names)) { - int len = fmt_entry(&qp->tterm, NULL, TRUE, infodump); + int len = fmt_entry(&qp->tterm, NULL, TRUE, infodump, numbers); if (len>(infodump?MAX_TERMINFO_LENGTH:MAX_TERMCAP_LENGTH)) (void) fprintf(stderr, @@ -512,11 +636,7 @@ bool check_only = FALSE; _nc_set_writedir(outdir); for_entry_list(qp) if (matches(namelst, qp->tterm.term_names)) - { - _nc_set_type(_nc_first_name(qp->tterm.term_names)); - _nc_curr_line = qp->startline; - _nc_write_entry(&qp->tterm); - } + write_it(qp); } else { @@ -532,16 +652,16 @@ bool check_only = FALSE; /* this is in case infotocap() generates warnings */ _nc_set_type(_nc_first_name(qp->tterm.term_names)); - (void) fseek(stdin, qp->cstart, SEEK_SET); + (void) fseek(tmp_fp, qp->cstart, SEEK_SET); while (j-- ) if (infodump) - (void) putchar(getchar()); + (void) putchar(fgetc(tmp_fp)); else - put_translate(getchar()); + put_translate(fgetc(tmp_fp)); - len = dump_entry(&qp->tterm, limited, NULL); + len = dump_entry(&qp->tterm, limited, numbers, NULL); for (j = 0; j < qp->nuses; j++) - len += dump_uses((char *)(qp->uses[j].parent), infodump); + len += dump_uses((char *)(qp->uses[j].parent), !capdump); (void) putchar('\n'); if (debug_level != 0 && !limited) printf("# length=%d\n", len); @@ -552,8 +672,8 @@ bool check_only = FALSE; bool in_comment = FALSE; bool trailing_comment = FALSE; - (void) fseek(stdin, _nc_tail->cend, SEEK_SET); - while ((c = getchar()) != EOF) + (void) fseek(tmp_fp, _nc_tail->cend, SEEK_SET); + while ((c = fgetc(tmp_fp)) != EOF) { if (oldc == '\n') { if (c == '#') { @@ -585,5 +705,108 @@ bool check_only = FALSE; else fprintf(log_fp, "No entries written\n"); } + cleanup(); return(EXIT_SUCCESS); } + +/* + * This bit of legerdemain turns all the terminfo variable names into + * references to locations in the arrays Booleans, Numbers, and Strings --- + * precisely what's needed (see comp_parse.c). + */ + +TERMINAL *cur_term; /* tweak to avoid linking lib_cur_term.c */ + +#undef CUR +#define CUR tp-> + +/* other sanity-checks (things that we don't want in the normal + * logic that reads a terminfo entry) + */ +static void check_termtype(TERMTYPE *tp) +{ + bool conflict = FALSE; + unsigned j, k; + char fkeys[STRCOUNT]; + + /* + * A terminal entry may contain more than one keycode assigned to + * a given string (e.g., KEY_END and KEY_LL). But curses will only + * return one (the last one assigned). + */ + memset(fkeys, 0, sizeof(fkeys)); + for (j = 0; _nc_tinfo_fkeys[j].code; j++) { + char *a = tp->Strings[_nc_tinfo_fkeys[j].offset]; + bool first = TRUE; + if (!VALID_STRING(a)) + continue; + for (k = j+1; _nc_tinfo_fkeys[k].code; k++) { + char *b = tp->Strings[_nc_tinfo_fkeys[k].offset]; + if (!VALID_STRING(b) + || fkeys[k]) + continue; + if (!strcmp(a,b)) { + fkeys[j] = 1; + fkeys[k] = 1; + if (first) { + if (!conflict) { + _nc_warning("Conflicting key definitions (using the last)"); + conflict = TRUE; + } + fprintf(stderr, "... %s is the same as %s", + keyname(_nc_tinfo_fkeys[j].code), + keyname(_nc_tinfo_fkeys[k].code)); + first = FALSE; + } else { + fprintf(stderr, ", %s", + keyname(_nc_tinfo_fkeys[k].code)); + } + } + } + if (!first) + fprintf(stderr, "\n"); + } + + /* + * Quick check for color. We could also check if the ANSI versus + * non-ANSI strings are misused. + */ + if ((max_colors > 0) != (max_pairs > 0) + || (max_colors > max_pairs)) + _nc_warning("inconsistent values for max_colors and max_pairs"); + + PAIRED(set_foreground, set_background) + PAIRED(set_a_foreground, set_a_background) + + /* + * These may be mismatched because the terminal description relies on + * restoring the cursor visibility by resetting it. + */ + ANDMISSING(cursor_invisible, cursor_normal) + ANDMISSING(cursor_visible, cursor_normal) + + /* + * From XSI & O'Reilly, we gather that sc/rc are required if csr is + * given, because the cursor position after the scrolling operation is + * performed is undefined. + */ + ANDMISSING(change_scroll_region, save_cursor) + ANDMISSING(change_scroll_region, restore_cursor) + + /* + * Some standard applications (e.g., vi) and some non-curses + * applications (e.g., jove) get confused if we have both ich/ich1 and + * smir/rmir. Let's be nice and warn about that, too, even though + * ncurses handles it. + */ + if ((PRESENT(enter_insert_mode) || PRESENT(exit_insert_mode)) + && (PRESENT(insert_character) || PRESENT(parm_ich))) { + _nc_warning("non-curses applications may be confused by ich/ich1 with smir/rmir"); + } + + /* + * Finally, do the non-verbose checks + */ + if (save_check_termtype != 0) + save_check_termtype(tp); +}