150276Speter/****************************************************************************
2176187Srafan * Copyright (c) 1998-2007,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/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996-on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter *	toe.c --- table of entries report generator
3750276Speter */
3850276Speter
3950276Speter#include <progs.priv.h>
4050276Speter
4150276Speter#include <sys/stat.h>
4250276Speter
43166124Srafan#if USE_HASHED_DB
44166124Srafan#include <hashed_db.h>
45166124Srafan#endif
4650276Speter
47184989SrafanMODULE_ID("$Id: toe.c,v 1.51 2008/08/16 21:53:25 tom Exp $")
48166124Srafan
4962449Speter#define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
5062449Speter
5150276Speterconst char *_nc_progname;
5250276Speter
5350276Speter#if NO_LEAKS
5450276Speter#undef ExitProgram
55166124Srafanstatic void ExitProgram(int code) GCC_NORETURN;
5662449Speterstatic void
57166124SrafanExitProgram(int code)
5850276Speter{
5962449Speter    _nc_free_entries(_nc_head);
60174993Srafan    _nc_free_tic(code);
6150276Speter}
6250276Speter#endif
6350276Speter
64166124Srafan#if USE_HASHED_DB
6597049Speterstatic bool
66166124Srafanmake_db_name(char *dst, const char *src, unsigned limit)
6797049Speter{
68166124Srafan    static const char suffix[] = DBM_SUFFIX;
69166124Srafan
70166124Srafan    bool result = FALSE;
71166124Srafan    unsigned lens = sizeof(suffix) - 1;
72166124Srafan    unsigned size = strlen(src);
73166124Srafan    unsigned need = lens + size;
74166124Srafan
75166124Srafan    if (need <= limit) {
76166124Srafan	if (size >= lens
77166124Srafan	    && !strcmp(src + size - lens, suffix))
78166124Srafan	    (void) strcpy(dst, src);
79166124Srafan	else
80166124Srafan	    (void) sprintf(dst, "%s%s", src, suffix);
81166124Srafan	result = TRUE;
82166124Srafan    }
83166124Srafan    return result;
8497049Speter}
85166124Srafan#endif
8697049Speter
8797049Speterstatic bool
88166124Srafanis_database(const char *path)
8997049Speter{
90166124Srafan    bool result = FALSE;
91166124Srafan#if USE_DATABASE
92166124Srafan    if (_nc_is_dir_path(path) && access(path, R_OK | X_OK) == 0) {
93166124Srafan	result = TRUE;
94166124Srafan    }
95166124Srafan#endif
96166124Srafan#if USE_TERMCAP
97166124Srafan    if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
98166124Srafan	result = TRUE;
99166124Srafan    }
100166124Srafan#endif
101166124Srafan#if USE_HASHED_DB
102166124Srafan    if (!result) {
103166124Srafan	char filename[PATH_MAX];
104166124Srafan	if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
105166124Srafan	    result = TRUE;
106166124Srafan	} else if (make_db_name(filename, path, sizeof(filename))) {
107166124Srafan	    if (_nc_is_file_path(filename) && access(filename, R_OK) == 0) {
108166124Srafan		result = TRUE;
109166124Srafan	    }
110166124Srafan	}
111166124Srafan    }
112166124Srafan#endif
113166124Srafan    return result;
11497049Speter}
11597049Speter
116166124Srafanstatic void
117166124Srafandeschook(const char *cn, TERMTYPE *tp)
118166124Srafan/* display a description for the type */
11950276Speter{
120166124Srafan    const char *desc;
121166124Srafan
122166124Srafan    if ((desc = strrchr(tp->term_names, '|')) == 0 || *++desc == '\0')
123166124Srafan	desc = "(No description)";
124166124Srafan
125166124Srafan    (void) printf("%-10s\t%s\n", cn, desc);
126166124Srafan}
127166124Srafan
128166124Srafan#if USE_TERMCAP
129166124Srafanstatic void
130166124Srafanshow_termcap(char *buffer,
131166124Srafan	     void (*hook) (const char *, TERMTYPE *tp))
132166124Srafan{
133166124Srafan    TERMTYPE data;
134166124Srafan    char *next = strchr(buffer, ':');
135166124Srafan    char *last;
136166124Srafan    char *list = buffer;
137166124Srafan
138166124Srafan    if (next)
139166124Srafan	*next = '\0';
140166124Srafan
141166124Srafan    last = strrchr(buffer, '|');
142166124Srafan    if (last)
143166124Srafan	++last;
144166124Srafan
145166124Srafan    data.term_names = strdup(buffer);
146166124Srafan    while ((next = strtok(list, "|")) != 0) {
147166124Srafan	if (next != last)
148166124Srafan	    hook(next, &data);
149166124Srafan	list = 0;
15062449Speter    }
151166124Srafan    free(data.term_names);
15262449Speter}
153166124Srafan#endif
15450276Speter
155166124Srafanstatic int
156166124Srafantypelist(int eargc, char *eargv[],
157166124Srafan	 bool verbosity,
158166124Srafan	 void (*hook) (const char *, TERMTYPE *tp))
159166124Srafan/* apply a function to each entry in given terminfo directories */
160166124Srafan{
161166124Srafan    int i;
162166124Srafan
163166124Srafan    for (i = 0; i < eargc; i++) {
164166124Srafan#if USE_DATABASE
165166124Srafan	if (_nc_is_dir_path(eargv[i])) {
166184989Srafan	    char *cwd_buf = 0;
167166124Srafan	    DIR *termdir;
168166124Srafan	    DIRENT *subdir;
169166124Srafan
170166124Srafan	    if ((termdir = opendir(eargv[i])) == 0) {
171166124Srafan		(void) fflush(stdout);
172166124Srafan		(void) fprintf(stderr,
173166124Srafan			       "%s: can't open terminfo directory %s\n",
174166124Srafan			       _nc_progname, eargv[i]);
175166124Srafan		return (EXIT_FAILURE);
176166124Srafan	    } else if (verbosity)
177166124Srafan		(void) printf("#\n#%s:\n#\n", eargv[i]);
178166124Srafan
179166124Srafan	    while ((subdir = readdir(termdir)) != 0) {
180166124Srafan		size_t len = NAMLEN(subdir);
181184989Srafan		size_t cwd_len = len + strlen(eargv[i]) + 3;
182166124Srafan		char name_1[PATH_MAX];
183166124Srafan		DIR *entrydir;
184166124Srafan		DIRENT *entry;
185166124Srafan
186184989Srafan		cwd_buf = typeRealloc(char, cwd_len, cwd_buf);
187184989Srafan		if (cwd_buf == 0) {
188184989Srafan		    perror("realloc cwd_buf");
189184989Srafan		    continue;
190184989Srafan		}
191184989Srafan
192166124Srafan		strncpy(name_1, subdir->d_name, len)[len] = '\0';
193166124Srafan		if (isDotname(name_1))
194166124Srafan		    continue;
195166124Srafan
196184989Srafan		(void) sprintf(cwd_buf, "%s/%.*s/", eargv[i], (int) len, name_1);
197184989Srafan		if (chdir(cwd_buf) != 0)
198166124Srafan		    continue;
199166124Srafan
200166124Srafan		entrydir = opendir(".");
201184989Srafan		if (entrydir == 0) {
202184989Srafan		    perror(cwd_buf);
203184989Srafan		    continue;
204184989Srafan		}
205166124Srafan		while ((entry = readdir(entrydir)) != 0) {
206166124Srafan		    char name_2[PATH_MAX];
207166124Srafan		    TERMTYPE lterm;
208166124Srafan		    char *cn;
209166124Srafan		    int status;
210166124Srafan
211166124Srafan		    len = NAMLEN(entry);
212166124Srafan		    strncpy(name_2, entry->d_name, len)[len] = '\0';
213166124Srafan		    if (isDotname(name_2) || !_nc_is_file_path(name_2))
214166124Srafan			continue;
215166124Srafan
216166124Srafan		    status = _nc_read_file_entry(name_2, &lterm);
217166124Srafan		    if (status <= 0) {
218166124Srafan			(void) fflush(stdout);
219166124Srafan			(void) fprintf(stderr,
220166124Srafan				       "%s: couldn't open terminfo file %s.\n",
221166124Srafan				       _nc_progname, name_2);
222166124Srafan			return (EXIT_FAILURE);
223166124Srafan		    }
224166124Srafan
225166124Srafan		    /* only visit things once, by primary name */
226166124Srafan		    cn = _nc_first_name(lterm.term_names);
227166124Srafan		    if (!strcmp(cn, name_2)) {
228166124Srafan			/* apply the selected hook function */
229166124Srafan			(*hook) (cn, &lterm);
230166124Srafan		    }
231166124Srafan		    _nc_free_termtype(&lterm);
232166124Srafan		}
233166124Srafan		closedir(entrydir);
234166124Srafan	    }
235166124Srafan	    closedir(termdir);
236184989Srafan	    if (cwd_buf != 0)
237184989Srafan		free(cwd_buf);
238166124Srafan	}
239166124Srafan#if USE_HASHED_DB
240166124Srafan	else {
241166124Srafan	    DB *capdbp;
242166124Srafan	    char filename[PATH_MAX];
243166124Srafan
244166124Srafan	    if (make_db_name(filename, eargv[i], sizeof(filename))) {
245166124Srafan		if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
246166124Srafan		    DBT key, data;
247166124Srafan		    int code;
248166124Srafan
249166124Srafan		    code = _nc_db_first(capdbp, &key, &data);
250166124Srafan		    while (code == 0) {
251166124Srafan			TERMTYPE lterm;
252166124Srafan			int used;
253166124Srafan			char *have;
254166124Srafan			char *cn;
255166124Srafan
256166124Srafan			if (_nc_db_have_data(&key, &data, &have, &used)) {
257166124Srafan			    if (_nc_read_termtype(&lterm, have, used) > 0) {
258166124Srafan				/* only visit things once, by primary name */
259166124Srafan				cn = _nc_first_name(lterm.term_names);
260166124Srafan				/* apply the selected hook function */
261166124Srafan				(*hook) (cn, &lterm);
262166124Srafan				_nc_free_termtype(&lterm);
263166124Srafan			    }
264166124Srafan			}
265166124Srafan			code = _nc_db_next(capdbp, &key, &data);
266166124Srafan		    }
267166124Srafan
268166124Srafan		    _nc_db_close(capdbp);
269166124Srafan		}
270166124Srafan	    }
271166124Srafan	}
272166124Srafan#endif
273166124Srafan#endif
274166124Srafan#if USE_TERMCAP
275166124Srafan#if HAVE_BSD_CGETENT
276166124Srafan	char *db_array[2];
277166124Srafan	char *buffer = 0;
278166124Srafan
279166124Srafan	if (verbosity)
280166124Srafan	    (void) printf("#\n#%s:\n#\n", eargv[i]);
281166124Srafan
282166124Srafan	db_array[0] = eargv[i];
283166124Srafan	db_array[1] = 0;
284166124Srafan
285166124Srafan	if (cgetfirst(&buffer, db_array)) {
286166124Srafan	    show_termcap(buffer, hook);
287166124Srafan	    free(buffer);
288166124Srafan	    while (cgetnext(&buffer, db_array)) {
289166124Srafan		show_termcap(buffer, hook);
290166124Srafan		free(buffer);
291166124Srafan	    }
292166124Srafan	}
293166124Srafan	cgetclose();
294166124Srafan#else
295166124Srafan	/* scan termcap text-file only */
296166124Srafan	if (_nc_is_file_path(eargv[i])) {
297166124Srafan	    char buffer[2048];
298166124Srafan	    FILE *fp;
299166124Srafan
300166124Srafan	    if ((fp = fopen(eargv[i], "r")) != 0) {
301166124Srafan		while (fgets(buffer, sizeof(buffer), fp) != 0) {
302166124Srafan		    if (*buffer == '#')
303166124Srafan			continue;
304166124Srafan		    if (isspace(*buffer))
305166124Srafan			continue;
306166124Srafan		    show_termcap(buffer, hook);
307166124Srafan		}
308166124Srafan		fclose(fp);
309166124Srafan	    }
310166124Srafan	}
311166124Srafan#endif
312166124Srafan#endif
313166124Srafan    }
314166124Srafan
315166124Srafan    return (EXIT_SUCCESS);
316166124Srafan}
317166124Srafan
318166124Srafanstatic void
319166124Srafanusage(void)
320166124Srafan{
321166124Srafan    (void) fprintf(stderr, "usage: %s [-ahuUV] [-v n] [file...]\n", _nc_progname);
322166124Srafan    ExitProgram(EXIT_FAILURE);
323166124Srafan}
324166124Srafan
32562449Speterint
32662449Spetermain(int argc, char *argv[])
32762449Speter{
328166124Srafan    bool all_dirs = FALSE;
32962449Speter    bool direct_dependencies = FALSE;
33062449Speter    bool invert_dependencies = FALSE;
33162449Speter    bool header = FALSE;
332176187Srafan    char *report_file = 0;
333184989Srafan    unsigned i;
33462449Speter    int code;
335166124Srafan    int this_opt, last_opt = '?';
336166124Srafan    int v_opt = 0;
33762449Speter
33897049Speter    _nc_progname = _nc_rootname(argv[0]);
33950276Speter
340176187Srafan    while ((this_opt = getopt(argc, argv, "0123456789ahu:vU:V")) != -1) {
341166124Srafan	/* handle optional parameter */
342166124Srafan	if (isdigit(this_opt)) {
343166124Srafan	    switch (last_opt) {
344166124Srafan	    case 'v':
345166124Srafan		v_opt = (this_opt - '0');
346166124Srafan		break;
347166124Srafan	    default:
348166124Srafan		if (isdigit(last_opt))
349166124Srafan		    v_opt *= 10;
350166124Srafan		else
351166124Srafan		    v_opt = 0;
352166124Srafan		v_opt += (this_opt - '0');
353166124Srafan		last_opt = this_opt;
354166124Srafan	    }
355166124Srafan	    continue;
356166124Srafan	}
357166124Srafan	switch (this_opt) {
358166124Srafan	case 'a':
359166124Srafan	    all_dirs = TRUE;
360166124Srafan	    break;
36150276Speter	case 'h':
36250276Speter	    header = TRUE;
36350276Speter	    break;
36450276Speter	case 'u':
36550276Speter	    direct_dependencies = TRUE;
366176187Srafan	    report_file = optarg;
36750276Speter	    break;
36850276Speter	case 'v':
369166124Srafan	    v_opt = 1;
37050276Speter	    break;
37150276Speter	case 'U':
37250276Speter	    invert_dependencies = TRUE;
373176187Srafan	    report_file = optarg;
37450276Speter	    break;
37550276Speter	case 'V':
37666963Speter	    puts(curses_version());
37750276Speter	    ExitProgram(EXIT_SUCCESS);
37850276Speter	default:
379166124Srafan	    usage();
38050276Speter	}
381166124Srafan    }
382166124Srafan    set_trace_level(v_opt);
38350276Speter
384176187Srafan    if (report_file != 0) {
385176187Srafan	if (freopen(report_file, "r", stdin) == 0) {
38650276Speter	    (void) fflush(stdout);
387176187Srafan	    fprintf(stderr, "%s: can't open %s\n", _nc_progname, report_file);
38850276Speter	    ExitProgram(EXIT_FAILURE);
38950276Speter	}
39050276Speter
39150276Speter	/* parse entries out of the source file */
392176187Srafan	_nc_set_source(report_file);
39362449Speter	_nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
39450276Speter    }
39550276Speter
39650276Speter    /* maybe we want a direct-dependency listing? */
39762449Speter    if (direct_dependencies) {
39862449Speter	ENTRY *qp;
39950276Speter
400166124Srafan	for_entry_list(qp) {
40162449Speter	    if (qp->nuses) {
402184989Srafan		unsigned j;
40350276Speter
404166124Srafan		(void) printf("%s:", _nc_first_name(qp->tterm.term_names));
405166124Srafan		for (j = 0; j < qp->nuses; j++)
406166124Srafan		    (void) printf(" %s", qp->uses[j].name);
407166124Srafan		putchar('\n');
408166124Srafan	    }
40962449Speter	}
41050276Speter
41150276Speter	ExitProgram(EXIT_SUCCESS);
41250276Speter    }
41350276Speter
41450276Speter    /* maybe we want a reverse-dependency listing? */
41562449Speter    if (invert_dependencies) {
41662449Speter	ENTRY *qp, *rp;
41762449Speter	int matchcount;
41850276Speter
41962449Speter	for_entry_list(qp) {
42050276Speter	    matchcount = 0;
42162449Speter	    for_entry_list(rp) {
42250276Speter		if (rp->nuses == 0)
42350276Speter		    continue;
42450276Speter
42550276Speter		for (i = 0; i < rp->nuses; i++)
42662449Speter		    if (_nc_name_match(qp->tterm.term_names,
42797049Speter				       rp->uses[i].name, "|")) {
42850276Speter			if (matchcount++ == 0)
42950276Speter			    (void) printf("%s:",
43097049Speter					  _nc_first_name(qp->tterm.term_names));
43150276Speter			(void) printf(" %s",
43297049Speter				      _nc_first_name(rp->tterm.term_names));
43350276Speter		    }
43450276Speter	    }
43550276Speter	    if (matchcount)
43650276Speter		putchar('\n');
43750276Speter	}
43850276Speter
43950276Speter	ExitProgram(EXIT_SUCCESS);
44050276Speter    }
44150276Speter
44250276Speter    /*
44350276Speter     * If we get this far, user wants a simple terminal type listing.
44450276Speter     */
44550276Speter    if (optind < argc) {
44662449Speter	code = typelist(argc - optind, argv + optind, header, deschook);
447166124Srafan    } else if (all_dirs) {
448166124Srafan	DBDIRS state;
449166124Srafan	int offset;
450166124Srafan	int pass;
451166124Srafan	const char *path;
452166124Srafan	char **eargv = 0;
45350276Speter
454166124Srafan	code = EXIT_FAILURE;
455166124Srafan	for (pass = 0; pass < 2; ++pass) {
456166124Srafan	    unsigned count = 0;
45750276Speter
458166124Srafan	    _nc_first_db(&state, &offset);
459166124Srafan	    while ((path = _nc_next_db(&state, &offset)) != 0) {
460166124Srafan		if (!is_database(path)) {
461166124Srafan		    ;
462166124Srafan		} else if (eargv != 0) {
463166124Srafan		    unsigned n;
464166124Srafan		    int found = FALSE;
46550276Speter
466166124Srafan		    /* eliminate duplicates */
467166124Srafan		    for (n = 0; n < count; ++n) {
468166124Srafan			if (!strcmp(path, eargv[n])) {
469166124Srafan			    found = TRUE;
470166124Srafan			    break;
471166124Srafan			}
472166124Srafan		    }
473166124Srafan		    if (!found) {
474166124Srafan			eargv[count] = strdup(path);
475166124Srafan			++count;
476166124Srafan		    }
477166124Srafan		} else {
478166124Srafan		    ++count;
47950276Speter		}
480166124Srafan	    }
481166124Srafan	    if (!pass) {
482166124Srafan		eargv = typeCalloc(char *, count + 1);
483166124Srafan	    } else {
484166124Srafan		code = typelist((int) count, eargv, header, deschook);
485166124Srafan		while (count-- > 0)
486166124Srafan		    free(eargv[count]);
487166124Srafan		free(eargv);
488166124Srafan	    }
489166124Srafan	}
490166124Srafan    } else {
491166124Srafan	DBDIRS state;
492166124Srafan	int offset;
493166124Srafan	const char *path;
494166124Srafan	char *eargv[3];
495166124Srafan	int count = 0;
49650276Speter
497166124Srafan	_nc_first_db(&state, &offset);
498166124Srafan	while ((path = _nc_next_db(&state, &offset)) != 0) {
499166124Srafan	    if (is_database(path)) {
500166124Srafan		eargv[count++] = strdup(path);
501166124Srafan		break;
50250276Speter	    }
50350276Speter	}
504166124Srafan	eargv[count] = 0;
505166124Srafan
506166124Srafan	code = typelist(count, eargv, header, deschook);
507166124Srafan
508166124Srafan	while (count-- > 0)
509166124Srafan	    free(eargv[count]);
51050276Speter    }
511166124Srafan    _nc_last_db();
51250276Speter
513166124Srafan    ExitProgram(code);
51450276Speter}
515