1/****************************************************************************
2 * Copyright (c) 1998-2002,2005 Free Software Foundation, Inc.              *
3 *                                                                          *
4 * Permission is hereby granted, free of charge, to any person obtaining a  *
5 * copy of this software and associated documentation files (the            *
6 * "Software"), to deal in the Software without restriction, including      *
7 * without limitation the rights to use, copy, modify, merge, publish,      *
8 * distribute, distribute with modifications, sublicense, and/or sell       *
9 * copies of the Software, and to permit persons to whom the Software is    *
10 * furnished to do so, subject to the following conditions:                 *
11 *                                                                          *
12 * The above copyright notice and this permission notice shall be included  *
13 * in all copies or substantial portions of the Software.                   *
14 *                                                                          *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22 *                                                                          *
23 * Except as contained in this notice, the name(s) of the above copyright   *
24 * holders shall not be used in advertising or otherwise to promote the     *
25 * sale, use or other dealings in this Software without prior written       *
26 * authorization.                                                           *
27 ****************************************************************************/
28
29/****************************************************************************
30 *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31 *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32 *     and: Thomas E. Dickey                        1996-on                 *
33 ****************************************************************************/
34
35/*
36 *	toe.c --- table of entries report generator
37 *
38 */
39
40#include <progs.priv.h>
41
42#include <sys/stat.h>
43
44#include <dump_entry.h>
45
46MODULE_ID("$Id: toe.c,v 1.29 2005/09/25 00:39:43 tom Exp $")
47
48#define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
49
50const char *_nc_progname;
51
52static int typelist(int eargc, char *eargv[], bool,
53		    void (*)(const char *, TERMTYPE *));
54static void deschook(const char *, TERMTYPE *);
55
56#if NO_LEAKS
57#undef ExitProgram
58static void
59ExitProgram(int code) GCC_NORETURN;
60     static void ExitProgram(int code)
61{
62    _nc_free_entries(_nc_head);
63    _nc_leaks_dump_entry();
64    _nc_free_and_exit(code);
65}
66#endif
67
68static bool
69is_a_file(char *path)
70{
71    struct stat sb;
72    return (stat(path, &sb) == 0
73	    && (sb.st_mode & S_IFMT) == S_IFREG);
74}
75
76static bool
77is_a_directory(char *path)
78{
79    struct stat sb;
80    return (stat(path, &sb) == 0
81	    && (sb.st_mode & S_IFMT) == S_IFDIR);
82}
83
84static char *
85get_directory(char *path)
86{
87    if (path != 0) {
88	if (!is_a_directory(path)
89	    || access(path, R_OK | X_OK) != 0)
90	    path = 0;
91    }
92    return path;
93}
94
95int
96main(int argc, char *argv[])
97{
98    bool direct_dependencies = FALSE;
99    bool invert_dependencies = FALSE;
100    bool header = FALSE;
101    int i, c;
102    int code;
103
104    _nc_progname = _nc_rootname(argv[0]);
105
106    while ((c = getopt(argc, argv, "huv:UV")) != EOF)
107	switch (c) {
108	case 'h':
109	    header = TRUE;
110	    break;
111	case 'u':
112	    direct_dependencies = TRUE;
113	    break;
114	case 'v':
115	    set_trace_level(atoi(optarg));
116	    break;
117	case 'U':
118	    invert_dependencies = TRUE;
119	    break;
120	case 'V':
121	    puts(curses_version());
122	    ExitProgram(EXIT_SUCCESS);
123	default:
124	    (void) fprintf(stderr, "usage: toe [-huUV] [-v n] [file...]\n");
125	    ExitProgram(EXIT_FAILURE);
126	}
127
128    if (direct_dependencies || invert_dependencies) {
129	if (freopen(argv[optind], "r", stdin) == 0) {
130	    (void) fflush(stdout);
131	    fprintf(stderr, "%s: can't open %s\n", _nc_progname, argv[optind]);
132	    ExitProgram(EXIT_FAILURE);
133	}
134
135	/* parse entries out of the source file */
136	_nc_set_source(argv[optind]);
137	_nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
138    }
139
140    /* maybe we want a direct-dependency listing? */
141    if (direct_dependencies) {
142	ENTRY *qp;
143
144	for_entry_list(qp) {
145	    if (qp->nuses) {
146		int j;
147
148		(void) printf("%s:", _nc_first_name(qp->tterm.term_names));
149		for (j = 0; j < qp->nuses; j++)
150		    (void) printf(" %s", qp->uses[j].name);
151		putchar('\n');
152	    }
153	}
154
155	ExitProgram(EXIT_SUCCESS);
156    }
157
158    /* maybe we want a reverse-dependency listing? */
159    if (invert_dependencies) {
160	ENTRY *qp, *rp;
161	int matchcount;
162
163	for_entry_list(qp) {
164	    matchcount = 0;
165	    for_entry_list(rp) {
166		if (rp->nuses == 0)
167		    continue;
168
169		for (i = 0; i < rp->nuses; i++)
170		    if (_nc_name_match(qp->tterm.term_names,
171				       rp->uses[i].name, "|")) {
172			if (matchcount++ == 0)
173			    (void) printf("%s:",
174					  _nc_first_name(qp->tterm.term_names));
175			(void) printf(" %s",
176				      _nc_first_name(rp->tterm.term_names));
177		    }
178	    }
179	    if (matchcount)
180		putchar('\n');
181	}
182
183	ExitProgram(EXIT_SUCCESS);
184    }
185
186    /*
187     * If we get this far, user wants a simple terminal type listing.
188     */
189    if (optind < argc) {
190	code = typelist(argc - optind, argv + optind, header, deschook);
191    } else {
192	char *home, *eargv[3];
193	char personal[PATH_MAX];
194	int j;
195
196	j = 0;
197	if ((eargv[j] = get_directory(getenv("TERMINFO"))) != 0) {
198	    j++;
199	} else {
200	    if ((home = getenv("HOME")) != 0) {
201		(void) sprintf(personal, PRIVATE_INFO, home);
202		if ((eargv[j] = get_directory(personal)) != 0)
203		    j++;
204	    }
205	    if ((eargv[j] = get_directory(strcpy(personal, TERMINFO))) != 0)
206		j++;
207	}
208	eargv[j] = 0;
209
210	code = typelist(j, eargv, header, deschook);
211    }
212
213    ExitProgram(code);
214}
215
216static void
217deschook(const char *cn, TERMTYPE * tp)
218/* display a description for the type */
219{
220    const char *desc;
221
222    if ((desc = strrchr(tp->term_names, '|')) == 0)
223	desc = "(No description)";
224    else
225	++desc;
226
227    (void) printf("%-10s\t%s\n", cn, desc);
228}
229
230static int
231typelist(int eargc, char *eargv[],
232	 bool verbosity,
233	 void (*hook) (const char *, TERMTYPE * tp))
234/* apply a function to each entry in given terminfo directories */
235{
236    int i;
237
238    for (i = 0; i < eargc; i++) {
239	DIR *termdir;
240	DIRENT *subdir;
241
242	if ((termdir = opendir(eargv[i])) == 0) {
243	    (void) fflush(stdout);
244	    (void) fprintf(stderr,
245			   "%s: can't open terminfo directory %s\n",
246			   _nc_progname, eargv[i]);
247	    return (EXIT_FAILURE);
248	} else if (verbosity)
249	    (void) printf("#\n#%s:\n#\n", eargv[i]);
250
251	while ((subdir = readdir(termdir)) != 0) {
252	    size_t len = NAMLEN(subdir);
253	    char buf[PATH_MAX];
254	    char name_1[PATH_MAX];
255	    DIR *entrydir;
256	    DIRENT *entry;
257
258	    strncpy(name_1, subdir->d_name, len)[len] = '\0';
259	    if (isDotname(name_1))
260		continue;
261
262	    (void) sprintf(buf, "%s/%s/", eargv[i], name_1);
263	    if (chdir(buf) != 0)
264		continue;
265
266	    entrydir = opendir(".");
267	    while ((entry = readdir(entrydir)) != 0) {
268		char name_2[PATH_MAX];
269		TERMTYPE lterm;
270		char *cn;
271		int status;
272
273		len = NAMLEN(entry);
274		strncpy(name_2, entry->d_name, len)[len] = '\0';
275		if (isDotname(name_2) || !is_a_file(name_2))
276		    continue;
277
278		status = _nc_read_file_entry(name_2, &lterm);
279		if (status <= 0) {
280		    (void) fflush(stdout);
281		    (void) fprintf(stderr,
282				   "toe: couldn't open terminfo file %s.\n",
283				   name_2);
284		    return (EXIT_FAILURE);
285		}
286
287		/* only visit things once, by primary name */
288		cn = _nc_first_name(lterm.term_names);
289		if (!strcmp(cn, name_2)) {
290		    /* apply the selected hook function */
291		    (*hook) (cn, &lterm);
292		}
293		if (lterm.term_names) {
294		    free(lterm.term_names);
295		    lterm.term_names = 0;
296		}
297		if (lterm.str_table) {
298		    free(lterm.str_table);
299		    lterm.str_table = 0;
300		}
301	    }
302	    closedir(entrydir);
303	}
304	closedir(termdir);
305    }
306
307    return (EXIT_SUCCESS);
308}
309