/****************************************************************************
- * Copyright (c) 1998-2010,2011 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2011,2012 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 *
/*
* tic.c --- Main program for terminfo compiler
* by Eric S. Raymond
+ * and Thomas E Dickey
*
*/
#include <sys/stat.h>
#include <dump_entry.h>
+#include <hashed_db.h>
#include <transform.h>
-MODULE_ID("$Id: tic.c,v 1.151 2011/07/30 21:49:32 tom Exp $")
+MODULE_ID("$Id: tic.c,v 1.160 2012/02/05 01:39:39 tom Exp $")
const char *_nc_progname = "tic";
1\
a\
C\
+D\
c\
f\
G\
#endif
" -K translate entries to termcap source form with BSD syntax",
" -C translate entries to termcap source form",
+ " -D print list of tic's database locations (first must be writable)",
" -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",
#define L_BRACE '{'
#define R_BRACE '}'
-#define S_QUOTE '\'';
+#define S_QUOTE '\''
static void
write_it(ENTRY * ep)
return result;
}
+static const char *
+valid_db_path(const char *nominal)
+{
+ struct stat sb;
+#if USE_HASHED_DB
+ char suffix[] = DBM_SUFFIX;
+ size_t need = strlen(nominal) + sizeof(suffix);
+ char *result = malloc(need);
+
+ strcpy(result, nominal);
+ if (strcmp(result + need - sizeof(suffix), suffix)) {
+ strcat(result, suffix);
+ }
+#else
+ char *result = strdup(nominal);
+#endif
+
+ DEBUG(1, ("** stat(%s)", result));
+ if (stat(result, &sb) >= 0) {
+#if USE_HASHED_DB
+ if (!S_ISREG(sb.st_mode)
+ || access(result, R_OK | W_OK) != 0) {
+ DEBUG(1, ("...not a writable file"));
+ free(result);
+ result = 0;
+ }
+#else
+ if (!S_ISDIR(sb.st_mode)
+ || access(result, R_OK | W_OK | X_OK) != 0) {
+ DEBUG(1, ("...not a writable directory"));
+ free(result);
+ result = 0;
+ }
+#endif
+ } else {
+ /* check if parent is directory and is writable */
+ unsigned leaf = _nc_pathlast(result);
+
+ DEBUG(1, ("...not found"));
+ if (leaf) {
+ char save = result[leaf];
+ result[leaf] = 0;
+ if (stat(result, &sb) >= 0
+ && S_ISDIR(sb.st_mode)
+ && access(result, R_OK | W_OK | X_OK) == 0) {
+ result[leaf] = save;
+ } else {
+ DEBUG(1, ("...parent directory %s is not writable", result));
+ free(result);
+ result = 0;
+ }
+ } else {
+ DEBUG(1, ("... no parent directory"));
+ free(result);
+ result = 0;
+ }
+ }
+ return result;
+}
+
+/*
+ * Show the databases to which tic could write. The location to which it
+ * writes is always the first one. If none are writable, print an error
+ * message.
+ */
+static void
+show_databases(const char *outdir)
+{
+ bool specific = (outdir != 0) || getenv("TERMINFO") != 0;
+ const char *result;
+ const char *tried = 0;
+
+ if (outdir == 0) {
+ outdir = _nc_tic_dir(0);
+ }
+ if ((result = valid_db_path(outdir)) != 0) {
+ printf("%s\n", result);
+ } else {
+ tried = outdir;
+ }
+
+ if ((outdir = _nc_home_terminfo())) {
+ if ((result = valid_db_path(outdir)) != 0) {
+ printf("%s\n", result);
+ } else if (!specific) {
+ tried = outdir;
+ }
+ }
+
+ /*
+ * If we can write in neither location, give an error message.
+ */
+ if (tried) {
+ fflush(stdout);
+ fprintf(stderr, "%s: %s (no permission)\n", _nc_progname, tried);
+ ExitProgram(EXIT_FAILURE);
+ }
+}
+
+#define VtoTrace(opt) (unsigned) ((opt > 0) ? opt : (opt == 0))
+
int
main(int argc, char *argv[])
{
int sortmode = S_TERMINFO; /* sort_mode */
int width = 60;
+ int height = 65535;
bool formatted = FALSE; /* reformat complex strings? */
bool literal = FALSE; /* suppress post-processing? */
int numbers = 0; /* format "%'char'" to/from "%{number}" */
* be optional.
*/
while ((this_opt = getopt(argc, argv,
- "0123456789CIKLNR:TUVace:fGgo:rstvwx")) != -1) {
+ "0123456789CDIKLNR:TUVace:fGgo:rstvwx")) != -1) {
if (isdigit(this_opt)) {
switch (last_opt) {
case 'v':
width = (width * 10) + (this_opt - '0');
break;
default:
- if (this_opt != '1')
+ switch (this_opt) {
+ case '0':
+ last_opt = this_opt;
+ width = 65535;
+ height = 1;
+ break;
+ case '1':
+ last_opt = this_opt;
+ width = 0;
+ break;
+ default:
usage();
- last_opt = this_opt;
- width = 0;
+ }
}
continue;
}
switch (this_opt) {
case 'K':
_nc_strict_bsd = 1;
- /* FALLTHRU */
+ /* the initial version of -K in 20110730 fell-thru here, but the
+ * same flag is useful when reading sources -TD
+ */
+ break;
case 'C':
capdump = TRUE;
outform = F_TERMCAP;
sortmode = S_TERMCAP;
break;
+ case 'D':
+ debug_level = VtoTrace(v_opt);
+ set_trace_level(debug_level);
+ show_databases(outdir);
+ ExitProgram(EXIT_SUCCESS);
+ break;
case 'I':
infodump = TRUE;
outform = F_TERMINFO;
last_opt = this_opt;
}
- debug_level = (unsigned) ((v_opt > 0) ? v_opt : (v_opt == 0));
+ debug_level = VtoTrace(v_opt);
set_trace_level(debug_level);
if (_nc_tracing) {
*/
if (namelst && (!infodump && !capdump)) {
(void) fprintf(stderr,
- "Sorry, -e can't be used without -I or -C\n");
+ "%s: Sorry, -e can't be used without -I or -C\n",
+ _nc_progname);
cleanup(namelst);
ExitProgram(EXIT_FAILURE);
}
smart_defaults
? outform
: F_LITERAL,
- sortmode, width, debug_level, formatted);
+ sortmode, width, height, debug_level, formatted);
else if (capdump)
dump_init(tversion,
outform,
- sortmode, width, debug_level, FALSE);
+ sortmode, width, height, debug_level, FALSE);
/* parse entries out of the source file */
_nc_set_source(source_file);