📄 tic.c
字号:
/**************************************************************************** * Copyright (c) 1998-2004,2005 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 * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, distribute with modifications, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name(s) of the above copyright * * holders shall not be used in advertising or otherwise to promote the * * sale, use or other dealings in this Software without prior written * * authorization. * ****************************************************************************//**************************************************************************** * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * * and: Eric S. Raymond <esr@snark.thyrsus.com> * * and: Thomas E. Dickey 1996 on * ****************************************************************************//* * tic.c --- Main program for terminfo compiler * by Eric S. Raymond * */#include <progs.priv.h>#include <sys/stat.h>#include <dump_entry.h>#include <transform.h>MODULE_ID("$Id: tic.c,v 1.125 2005/09/25 00:39:43 tom Exp $")const char *_nc_progname = "tic";static FILE *log_fp;static FILE *tmp_fp;static bool capdump = FALSE; /* running as infotocap? */static bool infodump = FALSE; /* running as captoinfo? */static bool showsummary = FALSE;static const char *to_remove;static void (*save_check_termtype) (TERMTYPE *, bool);static void check_termtype(TERMTYPE *tt, bool);static const char usage_string[] = "\[-e names] \[-o dir] \[-R name] \[-v[n]] \[-V] \[-w[n]] \[-\1\a\C\c\f\G\g\I\L\N\r\s\T\t\U\x\] \source-file\n";static voidcleanup(void){ if (tmp_fp != 0) fclose(tmp_fp); if (to_remove != 0) {#if HAVE_REMOVE remove(to_remove);#else unlink(to_remove);#endif }}static voidfailed(const char *msg){ perror(msg); cleanup(); ExitProgram(EXIT_FAILURE);}static voidusage(void){ static const char *const tbl[] = { "Options:", " -1 format translation output one capability per line",#if NCURSES_XNAMES " -a retain commented-out capabilities (sets -x also)",#endif " -C translate entries to termcap source form", " -c check only, validate input without compiling or translating", " -e<names> translate/compile only entries named by comma-separated list", " -f format complex strings for readability", " -G format %{number} to %'char'", " -g format %'char' to %{number}", " -I translate entries to terminfo source form", " -L translate entries to full terminfo source form", " -N disable smart defaults for source translation", " -o<dir> set output directory for compiled entry writes", " -R<name> restrict translation to given terminfo/termcap version", " -r force resolution of all use entries in source translation", " -s print summary statistics", " -T remove size-restrictions on compiled description",#if NCURSES_XNAMES " -t suppress commented-out capabilities",#endif " -U suppress post-processing of entries", " -V print version", " -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> file to translate or compile" }; size_t j; fprintf(stderr, "Usage: %s %s\n", _nc_progname, usage_string); for (j = 0; j < SIZEOF(tbl); j++) { fputs(tbl[j], stderr); putc('\n', stderr); } ExitProgram(EXIT_FAILURE);}#define L_BRACE '{'#define R_BRACE '}'#define S_QUOTE '\'';static voidwrite_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 boolimmedhook(ENTRY * ep GCC_UNUSED)/* write out entries with no use capabilities immediately to save storage */{#if !HAVE_BIG_CORE /* * This is strictly a core-economy kluge. The really clean way to handle * compilation is to slurp the whole file into core and then do all the * name-collision checks and entry writes in one swell foop. But the * terminfo master file is large enough that some core-poor systems swap * like crazy when you compile it this way...there have been reports of * this process taking *three hours*, rather than the twenty seconds or * less typical on my development box. * * So. This hook *immediately* writes out the referenced entry if it * has no use capabilities. The compiler main loop refrains from * adding the entry to the in-core list when this hook fires. If some * other entry later needs to reference an entry that got written * immediately, that's OK; the resolution code will fetch it off disk * when it can't find it in core. * * Name collisions will still be detected, just not as cleanly. The * write_entry() code complains before overwriting an entry that * postdates the time of tic's first call to write_entry(). Thus * it will complain about overwriting entries newly made during the * tic run, but not about overwriting ones that predate it. * * The reason this is a hook, and not in line with the rest of the * compiler code, is that the support for termcap fallback cannot assume * it has anywhere to spool out these entries! * * The _nc_set_type() call here requires a compensating one in * _nc_parse_entry(). * * If you define HAVE_BIG_CORE, you'll disable this kluge. This will * make tic a bit faster (because the resolution code won't have to do * disk I/O nearly as often). */ if (ep->nuses == 0) { int oldline = _nc_curr_line; write_it(ep); _nc_curr_line = oldline; free(ep->tterm.str_table); return (TRUE); }#endif /* HAVE_BIG_CORE */ return (FALSE);}static voidput_translate(int c)/* emit a comment char, translating terminfo names to termcap names */{ static bool in_name = FALSE; static size_t have, used; static char *namebuf, *suffix; if (in_name) { if (used + 1 >= have) { have += 132; namebuf = typeRealloc(char, have, namebuf); suffix = typeRealloc(char, have, suffix); } if (c == '\n' || c == '@') { namebuf[used++] = '\0'; (void) putchar('<'); (void) fputs(namebuf, stdout); putchar(c); in_name = FALSE; } else if (c != '>') { namebuf[used++] = c; } else { /* ah! candidate name! */ char *up; NCURSES_CONST char *tp; namebuf[used++] = '\0'; in_name = FALSE; suffix[0] = '\0'; if ((up = strchr(namebuf, '#')) != 0 || (up = strchr(namebuf, '=')) != 0 || ((up = strchr(namebuf, '@')) != 0 && up[1] == '>')) { (void) strcpy(suffix, up); *up = '\0'; } if ((tp = nametrans(namebuf)) != 0) { (void) putchar(':'); (void) fputs(tp, stdout); (void) fputs(suffix, stdout); (void) putchar(':'); } else { /* couldn't find a translation, just dump the name */ (void) putchar('<'); (void) fputs(namebuf, stdout); (void) fputs(suffix, stdout); (void) putchar('>'); } } } else { used = 0; if (c == '<') { in_name = TRUE; } else { putchar(c); } }}/* Returns a string, stripped of leading/trailing whitespace */static char *stripped(char *src){ while (isspace(UChar(*src))) src++; if (*src != '\0') { char *dst = strcpy((char *) malloc(strlen(src) + 1), src); size_t len = strlen(dst); while (--len != 0 && isspace(UChar(dst[len]))) dst[len] = '\0'; return dst; } return 0;}static FILE *open_input(const char *filename){ FILE *fp = fopen(filename, "r"); struct stat sb; if (fp == 0) { fprintf(stderr, "%s: Can't open %s\n", _nc_progname, filename); ExitProgram(EXIT_FAILURE); } if (fstat(fileno(fp), &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFREG) { fprintf(stderr, "%s: %s is not a file\n", _nc_progname, filename); ExitProgram(EXIT_FAILURE); } return fp;}/* Parse the "-e" option-value into a list of names */static const char **make_namelist(char *src){ const char **dst = 0; char *s, *base; unsigned pass, n, nn; char buffer[BUFSIZ]; if (src == 0) { /* EMPTY */ ; } else if (strchr(src, '/') != 0) { /* a filename */ FILE *fp = open_input(src); for (pass = 1; pass <= 2; pass++) { nn = 0; while (fgets(buffer, sizeof(buffer), fp) != 0) { if ((s = stripped(buffer)) != 0) { if (dst != 0) dst[nn] = s; nn++; } } if (pass == 1) { dst = typeCalloc(const char *, nn + 1); rewind(fp); } } fclose(fp); } else { /* literal list of names */ for (pass = 1; pass <= 2; pass++) { for (n = nn = 0, base = src;; n++) { int mark = src[n]; if (mark == ',' || mark == '\0') { if (pass == 1) { nn++; } else { src[n] = '\0'; if ((s = stripped(base)) != 0) dst[nn++] = s; base = &src[n + 1]; } } if (mark == '\0') break; } if (pass == 1) dst = typeCalloc(const char *, nn + 1); } } if (showsummary) { fprintf(log_fp, "Entries that will be compiled:\n"); for (n = 0; dst[n] != 0; n++) fprintf(log_fp, "%u:%s\n", n + 1, dst[n]); } return dst;}static boolmatches(const char **needle, const char *haystack)/* does entry in needle list match |-separated field in haystack? */{ bool code = FALSE; size_t n; if (needle != 0) { for (n = 0; needle[n] != 0; n++) { if (_nc_name_match(haystack, needle[n], "|")) { code = TRUE; break; } } } else code = TRUE; return (code);}static FILE *open_tempfile(char *name){ FILE *result = 0;#if HAVE_MKSTEMP int fd = mkstemp(name); if (fd >= 0) result = fdopen(fd, "w");#else if (tmpnam(name) != 0) result = fopen(name, "w");#endif return result;}intmain(int argc, char *argv[]){ char my_tmpname[PATH_MAX]; int v_opt = -1, debug_level; int smart_defaults = TRUE; char *termcap; ENTRY *qp; int this_opt, last_opt = '?'; int outform = F_TERMINFO; /* output format */ int sortmode = S_TERMINFO; /* sort_mode */ int width = 60; bool formatted = FALSE; /* reformat complex strings? */ bool literal = FALSE; /* suppress post-processing? */ int numbers = 0; /* format "%'char'" to/from "%{number}" */ bool forceresolve = FALSE; /* force resolution */ bool limited = TRUE; char *tversion = (char *) NULL; const char *source_file = "terminfo"; const char **namelst = 0; char *outdir = (char *) NULL; bool check_only = FALSE; bool suppress_untranslatable = FALSE; log_fp = stderr; _nc_progname = _nc_rootname(argv[0]); if ((infodump = (strcmp(_nc_progname, PROG_CAPTOINFO) == 0)) != FALSE) { outform = F_TERMINFO; sortmode = S_TERMINFO; } if ((capdump = (strcmp(_nc_progname, PROG_INFOTOCAP) == 0)) != FALSE) { outform = F_TERMCAP; sortmode = S_TERMCAP; }#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:TUVace:fGgo:rstvwx")) != EOF) { if (isdigit(this_opt)) { switch (last_opt) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -