xref: /freebsd/contrib/ncurses/progs/toe.c (revision 73f0a83d68863a383fd8953972cd36eb6420ec7d)
10e3d5408SPeter Wemm /****************************************************************************
2*73f0a83dSXin LI  * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc.              *
30e3d5408SPeter Wemm  *                                                                          *
40e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
50e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
60e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
70e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
80e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
90e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
100e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
110e3d5408SPeter Wemm  *                                                                          *
120e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
130e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
140e3d5408SPeter Wemm  *                                                                          *
150e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
160e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
170e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
180e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
190e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
200e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
210e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
220e3d5408SPeter Wemm  *                                                                          *
230e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
240e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
250e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
260e3d5408SPeter Wemm  * authorization.                                                           *
270e3d5408SPeter Wemm  ****************************************************************************/
280e3d5408SPeter Wemm 
290e3d5408SPeter Wemm /****************************************************************************
300e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
310e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
324a1a9510SRong-En Fan  *     and: Thomas E. Dickey                        1996-on                 *
330e3d5408SPeter Wemm  ****************************************************************************/
340e3d5408SPeter Wemm 
350e3d5408SPeter Wemm /*
360e3d5408SPeter Wemm  *	toe.c --- table of entries report generator
370e3d5408SPeter Wemm  */
380e3d5408SPeter Wemm 
390e3d5408SPeter Wemm #include <progs.priv.h>
400e3d5408SPeter Wemm 
410e3d5408SPeter Wemm #include <sys/stat.h>
420e3d5408SPeter Wemm 
434a1a9510SRong-En Fan #if USE_HASHED_DB
444a1a9510SRong-En Fan #include <hashed_db.h>
454a1a9510SRong-En Fan #endif
464a1a9510SRong-En Fan 
47*73f0a83dSXin LI MODULE_ID("$Id: toe.c,v 1.74 2013/12/15 01:08:28 tom Exp $")
4815589c42SPeter Wemm 
4915589c42SPeter Wemm #define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
500e3d5408SPeter Wemm 
51*73f0a83dSXin LI typedef struct {
52*73f0a83dSXin LI     int db_index;
53*73f0a83dSXin LI     unsigned long checksum;
54*73f0a83dSXin LI     char *term_name;
55*73f0a83dSXin LI     char *description;
56*73f0a83dSXin LI } TERMDATA;
57*73f0a83dSXin LI 
580e3d5408SPeter Wemm const char *_nc_progname;
590e3d5408SPeter Wemm 
60*73f0a83dSXin LI static TERMDATA *ptr_termdata;	/* array of terminal data */
61*73f0a83dSXin LI static size_t use_termdata;	/* actual usage in ptr_termdata[] */
62*73f0a83dSXin LI static size_t len_termdata;	/* allocated size of ptr_termdata[] */
63*73f0a83dSXin LI 
640e3d5408SPeter Wemm #if NO_LEAKS
650e3d5408SPeter Wemm #undef ExitProgram
664a1a9510SRong-En Fan static void ExitProgram(int code) GCC_NORETURN;
6715589c42SPeter Wemm static void
684a1a9510SRong-En Fan ExitProgram(int code)
690e3d5408SPeter Wemm {
700e3d5408SPeter Wemm     _nc_free_entries(_nc_head);
715ca44d1cSRong-En Fan     _nc_free_tic(code);
720e3d5408SPeter Wemm }
730e3d5408SPeter Wemm #endif
740e3d5408SPeter Wemm 
75*73f0a83dSXin LI static void failed(const char *) GCC_NORETURN;
76*73f0a83dSXin LI 
7706bfebdeSXin LI static void
7806bfebdeSXin LI failed(const char *msg)
7906bfebdeSXin LI {
8006bfebdeSXin LI     perror(msg);
8106bfebdeSXin LI     ExitProgram(EXIT_FAILURE);
8206bfebdeSXin LI }
8306bfebdeSXin LI 
84*73f0a83dSXin LI static char *
85*73f0a83dSXin LI strmalloc(const char *value)
86*73f0a83dSXin LI {
87*73f0a83dSXin LI     char *result = strdup(value);
88*73f0a83dSXin LI     if (result == 0) {
89*73f0a83dSXin LI 	failed("strmalloc");
90*73f0a83dSXin LI     }
91*73f0a83dSXin LI     return result;
92*73f0a83dSXin LI }
93*73f0a83dSXin LI 
94*73f0a83dSXin LI static TERMDATA *
95*73f0a83dSXin LI new_termdata(void)
96*73f0a83dSXin LI {
97*73f0a83dSXin LI     size_t want = use_termdata + 1;
98*73f0a83dSXin LI 
99*73f0a83dSXin LI     if (want >= len_termdata) {
100*73f0a83dSXin LI 	len_termdata = (2 * want) + 10;
101*73f0a83dSXin LI 	ptr_termdata = typeRealloc(TERMDATA, len_termdata, ptr_termdata);
102*73f0a83dSXin LI 	if (ptr_termdata == 0)
103*73f0a83dSXin LI 	    failed("ptr_termdata");
104*73f0a83dSXin LI     }
105*73f0a83dSXin LI 
106*73f0a83dSXin LI     return ptr_termdata + use_termdata++;
107*73f0a83dSXin LI }
108*73f0a83dSXin LI 
109*73f0a83dSXin LI static int
110*73f0a83dSXin LI compare_termdata(const void *a, const void *b)
111*73f0a83dSXin LI {
112*73f0a83dSXin LI     const TERMDATA *p = (const TERMDATA *) a;
113*73f0a83dSXin LI     const TERMDATA *q = (const TERMDATA *) b;
114*73f0a83dSXin LI     int result = strcmp(p->term_name, q->term_name);
115*73f0a83dSXin LI 
116*73f0a83dSXin LI     if (result == 0) {
117*73f0a83dSXin LI 	result = (p->db_index - q->db_index);
118*73f0a83dSXin LI     }
119*73f0a83dSXin LI     return result;
120*73f0a83dSXin LI }
121*73f0a83dSXin LI 
122*73f0a83dSXin LI /*
123*73f0a83dSXin LI  * Sort the array of TERMDATA and print it.  If more than one database is being
124*73f0a83dSXin LI  * reported, add a column to show which database has a given entry.
125*73f0a83dSXin LI  */
126*73f0a83dSXin LI static void
127*73f0a83dSXin LI show_termdata(int eargc, char **eargv)
128*73f0a83dSXin LI {
129*73f0a83dSXin LI     int j, k;
130*73f0a83dSXin LI     size_t n;
131*73f0a83dSXin LI 
132*73f0a83dSXin LI     if (use_termdata) {
133*73f0a83dSXin LI 	if (eargc > 1) {
134*73f0a83dSXin LI 	    for (j = 0; j < eargc; ++j) {
135*73f0a83dSXin LI 		for (k = 0; k <= j; ++k) {
136*73f0a83dSXin LI 		    printf("--");
137*73f0a83dSXin LI 		}
138*73f0a83dSXin LI 		printf("> ");
139*73f0a83dSXin LI 		printf("%s\n", eargv[j]);
140*73f0a83dSXin LI 	    }
141*73f0a83dSXin LI 	}
142*73f0a83dSXin LI 	if (use_termdata > 1)
143*73f0a83dSXin LI 	    qsort(ptr_termdata, use_termdata, sizeof(TERMDATA), compare_termdata);
144*73f0a83dSXin LI 	for (n = 0; n < use_termdata; ++n) {
145*73f0a83dSXin LI 
146*73f0a83dSXin LI 	    /*
147*73f0a83dSXin LI 	     * If there is more than one database, show how they differ.
148*73f0a83dSXin LI 	     */
149*73f0a83dSXin LI 	    if (eargc > 1) {
150*73f0a83dSXin LI 		unsigned long check = 0;
151*73f0a83dSXin LI 		k = 0;
152*73f0a83dSXin LI 		for (;;) {
153*73f0a83dSXin LI 		    for (; k < ptr_termdata[n].db_index; ++k) {
154*73f0a83dSXin LI 			printf("--");
155*73f0a83dSXin LI 		    }
156*73f0a83dSXin LI 
157*73f0a83dSXin LI 		    /*
158*73f0a83dSXin LI 		     * If this is the first entry, or its checksum differs
159*73f0a83dSXin LI 		     * from the first entry's checksum, print "*". Otherwise
160*73f0a83dSXin LI 		     * it looks enough like a duplicate to print "+".
161*73f0a83dSXin LI 		     */
162*73f0a83dSXin LI 		    printf("%c-", ((check == 0
163*73f0a83dSXin LI 				    || (check != ptr_termdata[n].checksum))
164*73f0a83dSXin LI 				   ? '*'
165*73f0a83dSXin LI 				   : '+'));
166*73f0a83dSXin LI 		    check = ptr_termdata[n].checksum;
167*73f0a83dSXin LI 
168*73f0a83dSXin LI 		    ++k;
169*73f0a83dSXin LI 		    if ((n + 1) >= use_termdata
170*73f0a83dSXin LI 			|| strcmp(ptr_termdata[n].term_name,
171*73f0a83dSXin LI 				  ptr_termdata[n + 1].term_name)) {
172*73f0a83dSXin LI 			break;
173*73f0a83dSXin LI 		    }
174*73f0a83dSXin LI 		    ++n;
175*73f0a83dSXin LI 		}
176*73f0a83dSXin LI 		for (; k < eargc; ++k) {
177*73f0a83dSXin LI 		    printf("--");
178*73f0a83dSXin LI 		}
179*73f0a83dSXin LI 		printf(":\t");
180*73f0a83dSXin LI 	    }
181*73f0a83dSXin LI 
182*73f0a83dSXin LI 	    (void) printf("%-10s\t%s\n",
183*73f0a83dSXin LI 			  ptr_termdata[n].term_name,
184*73f0a83dSXin LI 			  ptr_termdata[n].description);
185*73f0a83dSXin LI 	}
186*73f0a83dSXin LI     }
187*73f0a83dSXin LI }
188*73f0a83dSXin LI 
189*73f0a83dSXin LI static void
190*73f0a83dSXin LI free_termdata(void)
191*73f0a83dSXin LI {
192*73f0a83dSXin LI     if (ptr_termdata != 0) {
193*73f0a83dSXin LI 	while (use_termdata != 0) {
194*73f0a83dSXin LI 	    --use_termdata;
195*73f0a83dSXin LI 	    free(ptr_termdata[use_termdata].term_name);
196*73f0a83dSXin LI 	    free(ptr_termdata[use_termdata].description);
197*73f0a83dSXin LI 	}
198*73f0a83dSXin LI 	free(ptr_termdata);
199*73f0a83dSXin LI 	ptr_termdata = 0;
200*73f0a83dSXin LI     }
201*73f0a83dSXin LI     use_termdata = 0;
202*73f0a83dSXin LI     len_termdata = 0;
203*73f0a83dSXin LI }
204*73f0a83dSXin LI 
205*73f0a83dSXin LI static char **
206*73f0a83dSXin LI allocArgv(size_t count)
207*73f0a83dSXin LI {
208*73f0a83dSXin LI     char **result = typeCalloc(char *, count + 1);
209*73f0a83dSXin LI     if (result == 0)
210*73f0a83dSXin LI 	failed("realloc eargv");
211*73f0a83dSXin LI 
212*73f0a83dSXin LI     assert(result != 0);
213*73f0a83dSXin LI     return result;
214*73f0a83dSXin LI }
215*73f0a83dSXin LI 
216*73f0a83dSXin LI static void
217*73f0a83dSXin LI freeArgv(char **argv)
218*73f0a83dSXin LI {
219*73f0a83dSXin LI     if (argv) {
220*73f0a83dSXin LI 	int count = 0;
221*73f0a83dSXin LI 	while (argv[count]) {
222*73f0a83dSXin LI 	    free(argv[count++]);
223*73f0a83dSXin LI 	}
224*73f0a83dSXin LI 	free(argv);
225*73f0a83dSXin LI     }
226*73f0a83dSXin LI }
227*73f0a83dSXin LI 
2284a1a9510SRong-En Fan #if USE_HASHED_DB
22939f2269fSPeter Wemm static bool
2304a1a9510SRong-En Fan make_db_name(char *dst, const char *src, unsigned limit)
23139f2269fSPeter Wemm {
2324a1a9510SRong-En Fan     static const char suffix[] = DBM_SUFFIX;
2334a1a9510SRong-En Fan 
2344a1a9510SRong-En Fan     bool result = FALSE;
235*73f0a83dSXin LI     size_t lens = sizeof(suffix) - 1;
236*73f0a83dSXin LI     size_t size = strlen(src);
237*73f0a83dSXin LI     size_t need = lens + size;
2384a1a9510SRong-En Fan 
2394a1a9510SRong-En Fan     if (need <= limit) {
2404a1a9510SRong-En Fan 	if (size >= lens
241*73f0a83dSXin LI 	    && !strcmp(src + size - lens, suffix)) {
242*73f0a83dSXin LI 	    _nc_STRCPY(dst, src, PATH_MAX);
243*73f0a83dSXin LI 	} else {
244*73f0a83dSXin LI 	    _nc_SPRINTF(dst, _nc_SLIMIT(PATH_MAX) "%s%s", src, suffix);
245*73f0a83dSXin LI 	}
2464a1a9510SRong-En Fan 	result = TRUE;
24739f2269fSPeter Wemm     }
2484a1a9510SRong-En Fan     return result;
2494a1a9510SRong-En Fan }
2504a1a9510SRong-En Fan #endif
25139f2269fSPeter Wemm 
252*73f0a83dSXin LI typedef void (DescHook) (int /* db_index */ ,
253*73f0a83dSXin LI 			 int /* db_limit */ ,
254*73f0a83dSXin LI 			 const char * /* term_name */ ,
255*73f0a83dSXin LI 			 TERMTYPE * /* term */ );
25639f2269fSPeter Wemm 
257*73f0a83dSXin LI static const char *
258*73f0a83dSXin LI term_description(TERMTYPE *tp)
25915589c42SPeter Wemm {
2604a1a9510SRong-En Fan     const char *desc;
2614a1a9510SRong-En Fan 
262*73f0a83dSXin LI     if (tp->term_names == 0
263*73f0a83dSXin LI 	|| (desc = strrchr(tp->term_names, '|')) == 0
264*73f0a83dSXin LI 	|| (*++desc == '\0')) {
2654a1a9510SRong-En Fan 	desc = "(No description)";
26615589c42SPeter Wemm     }
2674a1a9510SRong-En Fan 
268*73f0a83dSXin LI     return desc;
269*73f0a83dSXin LI }
270*73f0a83dSXin LI 
271*73f0a83dSXin LI /* display a description for the type */
2724a1a9510SRong-En Fan static void
273*73f0a83dSXin LI deschook(int db_index, int db_limit, const char *term_name, TERMTYPE *tp)
274*73f0a83dSXin LI {
275*73f0a83dSXin LI     (void) db_index;
276*73f0a83dSXin LI     (void) db_limit;
277*73f0a83dSXin LI     (void) printf("%-10s\t%s\n", term_name, term_description(tp));
278*73f0a83dSXin LI }
279*73f0a83dSXin LI 
280*73f0a83dSXin LI static unsigned long
281*73f0a83dSXin LI string_sum(const char *value)
282*73f0a83dSXin LI {
283*73f0a83dSXin LI     unsigned long result = 0;
284*73f0a83dSXin LI 
285*73f0a83dSXin LI     if ((intptr_t) value == (intptr_t) (-1)) {
286*73f0a83dSXin LI 	result = ~result;
287*73f0a83dSXin LI     } else if (value) {
288*73f0a83dSXin LI 	while (*value) {
289*73f0a83dSXin LI 	    result += UChar(*value);
290*73f0a83dSXin LI 	    ++value;
291*73f0a83dSXin LI 	}
292*73f0a83dSXin LI     }
293*73f0a83dSXin LI     return result;
294*73f0a83dSXin LI }
295*73f0a83dSXin LI 
296*73f0a83dSXin LI static unsigned long
297*73f0a83dSXin LI checksum_of(TERMTYPE *tp)
298*73f0a83dSXin LI {
299*73f0a83dSXin LI     unsigned long result = string_sum(tp->term_names);
300*73f0a83dSXin LI     unsigned i;
301*73f0a83dSXin LI 
302*73f0a83dSXin LI     for (i = 0; i < NUM_BOOLEANS(tp); i++) {
303*73f0a83dSXin LI 	result += (unsigned long) (tp->Booleans[i]);
304*73f0a83dSXin LI     }
305*73f0a83dSXin LI     for (i = 0; i < NUM_NUMBERS(tp); i++) {
306*73f0a83dSXin LI 	result += (unsigned long) (tp->Numbers[i]);
307*73f0a83dSXin LI     }
308*73f0a83dSXin LI     for (i = 0; i < NUM_STRINGS(tp); i++) {
309*73f0a83dSXin LI 	result += string_sum(tp->Strings[i]);
310*73f0a83dSXin LI     }
311*73f0a83dSXin LI     return result;
312*73f0a83dSXin LI }
313*73f0a83dSXin LI 
314*73f0a83dSXin LI /* collect data, to sort before display */
315*73f0a83dSXin LI static void
316*73f0a83dSXin LI sorthook(int db_index, int db_limit, const char *term_name, TERMTYPE *tp)
317*73f0a83dSXin LI {
318*73f0a83dSXin LI     TERMDATA *data = new_termdata();
319*73f0a83dSXin LI 
320*73f0a83dSXin LI     data->db_index = db_index;
321*73f0a83dSXin LI     data->checksum = ((db_limit > 1) ? checksum_of(tp) : 0);
322*73f0a83dSXin LI     data->term_name = strmalloc(term_name);
323*73f0a83dSXin LI     data->description = strmalloc(term_description(tp));
324*73f0a83dSXin LI }
325*73f0a83dSXin LI 
326*73f0a83dSXin LI #if NCURSES_USE_TERMCAP
327*73f0a83dSXin LI static void
328*73f0a83dSXin LI show_termcap(int db_index, int db_limit, char *buffer, DescHook hook)
3294a1a9510SRong-En Fan {
3304a1a9510SRong-En Fan     TERMTYPE data;
3314a1a9510SRong-En Fan     char *next = strchr(buffer, ':');
3324a1a9510SRong-En Fan     char *last;
3334a1a9510SRong-En Fan     char *list = buffer;
3344a1a9510SRong-En Fan 
3354a1a9510SRong-En Fan     if (next)
3364a1a9510SRong-En Fan 	*next = '\0';
3374a1a9510SRong-En Fan 
3384a1a9510SRong-En Fan     last = strrchr(buffer, '|');
3394a1a9510SRong-En Fan     if (last)
3404a1a9510SRong-En Fan 	++last;
3414a1a9510SRong-En Fan 
342*73f0a83dSXin LI     memset(&data, 0, sizeof(data));
343*73f0a83dSXin LI     data.term_names = strmalloc(buffer);
3444a1a9510SRong-En Fan     while ((next = strtok(list, "|")) != 0) {
3454a1a9510SRong-En Fan 	if (next != last)
346*73f0a83dSXin LI 	    hook(db_index, db_limit, next, &data);
3474a1a9510SRong-En Fan 	list = 0;
3484a1a9510SRong-En Fan     }
3494a1a9510SRong-En Fan     free(data.term_names);
3504a1a9510SRong-En Fan }
3514a1a9510SRong-En Fan #endif
3524a1a9510SRong-En Fan 
353*73f0a83dSXin LI #if NCURSES_USE_DATABASE
354*73f0a83dSXin LI static char *
355*73f0a83dSXin LI copy_entryname(DIRENT * src)
356*73f0a83dSXin LI {
357*73f0a83dSXin LI     size_t len = NAMLEN(src);
358*73f0a83dSXin LI     char *result = malloc(len + 1);
359*73f0a83dSXin LI     if (result == 0)
360*73f0a83dSXin LI 	failed("copy entryname");
361*73f0a83dSXin LI     memcpy(result, src->d_name, len);
362*73f0a83dSXin LI     result[len] = '\0';
363*73f0a83dSXin LI 
364*73f0a83dSXin LI     return result;
365*73f0a83dSXin LI }
366*73f0a83dSXin LI #endif
367*73f0a83dSXin LI 
3684a1a9510SRong-En Fan static int
3694a1a9510SRong-En Fan typelist(int eargc, char *eargv[],
370*73f0a83dSXin LI 	 int verbosity,
371*73f0a83dSXin LI 	 DescHook hook)
3724a1a9510SRong-En Fan /* apply a function to each entry in given terminfo directories */
3734a1a9510SRong-En Fan {
3744a1a9510SRong-En Fan     int i;
3754a1a9510SRong-En Fan 
3764a1a9510SRong-En Fan     for (i = 0; i < eargc; i++) {
377*73f0a83dSXin LI #if NCURSES_USE_DATABASE
3784a1a9510SRong-En Fan 	if (_nc_is_dir_path(eargv[i])) {
3795d08fb1fSRong-En Fan 	    char *cwd_buf = 0;
3804a1a9510SRong-En Fan 	    DIR *termdir;
3814a1a9510SRong-En Fan 	    DIRENT *subdir;
3824a1a9510SRong-En Fan 
3834a1a9510SRong-En Fan 	    if ((termdir = opendir(eargv[i])) == 0) {
3844a1a9510SRong-En Fan 		(void) fflush(stdout);
3854a1a9510SRong-En Fan 		(void) fprintf(stderr,
3864a1a9510SRong-En Fan 			       "%s: can't open terminfo directory %s\n",
3874a1a9510SRong-En Fan 			       _nc_progname, eargv[i]);
388*73f0a83dSXin LI 		continue;
389*73f0a83dSXin LI 	    }
390*73f0a83dSXin LI 
391*73f0a83dSXin LI 	    if (verbosity)
3924a1a9510SRong-En Fan 		(void) printf("#\n#%s:\n#\n", eargv[i]);
3934a1a9510SRong-En Fan 
3944a1a9510SRong-En Fan 	    while ((subdir = readdir(termdir)) != 0) {
395*73f0a83dSXin LI 		size_t cwd_len;
396*73f0a83dSXin LI 		char *name_1;
3974a1a9510SRong-En Fan 		DIR *entrydir;
3984a1a9510SRong-En Fan 		DIRENT *entry;
3994a1a9510SRong-En Fan 
400*73f0a83dSXin LI 		name_1 = copy_entryname(subdir);
401*73f0a83dSXin LI 		if (isDotname(name_1)) {
402*73f0a83dSXin LI 		    free(name_1);
403*73f0a83dSXin LI 		    continue;
404*73f0a83dSXin LI 		}
405*73f0a83dSXin LI 
406*73f0a83dSXin LI 		cwd_len = NAMLEN(subdir) + strlen(eargv[i]) + 3;
4075d08fb1fSRong-En Fan 		cwd_buf = typeRealloc(char, cwd_len, cwd_buf);
40806bfebdeSXin LI 		if (cwd_buf == 0)
40906bfebdeSXin LI 		    failed("realloc cwd_buf");
41006bfebdeSXin LI 
41106bfebdeSXin LI 		assert(cwd_buf != 0);
4125d08fb1fSRong-En Fan 
413*73f0a83dSXin LI 		_nc_SPRINTF(cwd_buf, _nc_SLIMIT(cwd_len)
414*73f0a83dSXin LI 			    "%s/%s/", eargv[i], name_1);
415*73f0a83dSXin LI 		free(name_1);
4164a1a9510SRong-En Fan 
4175d08fb1fSRong-En Fan 		if (chdir(cwd_buf) != 0)
4184a1a9510SRong-En Fan 		    continue;
4194a1a9510SRong-En Fan 
4204a1a9510SRong-En Fan 		entrydir = opendir(".");
4215d08fb1fSRong-En Fan 		if (entrydir == 0) {
4225d08fb1fSRong-En Fan 		    perror(cwd_buf);
4235d08fb1fSRong-En Fan 		    continue;
4245d08fb1fSRong-En Fan 		}
4254a1a9510SRong-En Fan 		while ((entry = readdir(entrydir)) != 0) {
426*73f0a83dSXin LI 		    char *name_2;
4274a1a9510SRong-En Fan 		    TERMTYPE lterm;
4284a1a9510SRong-En Fan 		    char *cn;
4294a1a9510SRong-En Fan 		    int status;
4304a1a9510SRong-En Fan 
431*73f0a83dSXin LI 		    name_2 = copy_entryname(entry);
432*73f0a83dSXin LI 		    if (isDotname(name_2) || !_nc_is_file_path(name_2)) {
433*73f0a83dSXin LI 			free(name_2);
4344a1a9510SRong-En Fan 			continue;
435*73f0a83dSXin LI 		    }
4364a1a9510SRong-En Fan 
4374a1a9510SRong-En Fan 		    status = _nc_read_file_entry(name_2, &lterm);
4384a1a9510SRong-En Fan 		    if (status <= 0) {
4394a1a9510SRong-En Fan 			(void) fflush(stdout);
4404a1a9510SRong-En Fan 			(void) fprintf(stderr,
4414a1a9510SRong-En Fan 				       "%s: couldn't open terminfo file %s.\n",
4424a1a9510SRong-En Fan 				       _nc_progname, name_2);
443*73f0a83dSXin LI 			free(cwd_buf);
444*73f0a83dSXin LI 			free(name_2);
445*73f0a83dSXin LI 			closedir(entrydir);
446*73f0a83dSXin LI 			closedir(termdir);
4474a1a9510SRong-En Fan 			return (EXIT_FAILURE);
4484a1a9510SRong-En Fan 		    }
4494a1a9510SRong-En Fan 
4504a1a9510SRong-En Fan 		    /* only visit things once, by primary name */
4514a1a9510SRong-En Fan 		    cn = _nc_first_name(lterm.term_names);
4524a1a9510SRong-En Fan 		    if (!strcmp(cn, name_2)) {
4534a1a9510SRong-En Fan 			/* apply the selected hook function */
454*73f0a83dSXin LI 			hook(i, eargc, cn, &lterm);
4554a1a9510SRong-En Fan 		    }
4564a1a9510SRong-En Fan 		    _nc_free_termtype(&lterm);
457*73f0a83dSXin LI 		    free(name_2);
4584a1a9510SRong-En Fan 		}
4594a1a9510SRong-En Fan 		closedir(entrydir);
4604a1a9510SRong-En Fan 	    }
4614a1a9510SRong-En Fan 	    closedir(termdir);
4625d08fb1fSRong-En Fan 	    if (cwd_buf != 0)
4635d08fb1fSRong-En Fan 		free(cwd_buf);
464*73f0a83dSXin LI 	    continue;
4654a1a9510SRong-En Fan 	}
4664a1a9510SRong-En Fan #if USE_HASHED_DB
4674a1a9510SRong-En Fan 	else {
4684a1a9510SRong-En Fan 	    DB *capdbp;
4694a1a9510SRong-En Fan 	    char filename[PATH_MAX];
4704a1a9510SRong-En Fan 
471*73f0a83dSXin LI 	    if (verbosity)
472*73f0a83dSXin LI 		(void) printf("#\n#%s:\n#\n", eargv[i]);
473*73f0a83dSXin LI 
4744a1a9510SRong-En Fan 	    if (make_db_name(filename, eargv[i], sizeof(filename))) {
4754a1a9510SRong-En Fan 		if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
4764a1a9510SRong-En Fan 		    DBT key, data;
4774a1a9510SRong-En Fan 		    int code;
4784a1a9510SRong-En Fan 
4794a1a9510SRong-En Fan 		    code = _nc_db_first(capdbp, &key, &data);
4804a1a9510SRong-En Fan 		    while (code == 0) {
4814a1a9510SRong-En Fan 			TERMTYPE lterm;
4824a1a9510SRong-En Fan 			int used;
4834a1a9510SRong-En Fan 			char *have;
4844a1a9510SRong-En Fan 			char *cn;
4854a1a9510SRong-En Fan 
4864a1a9510SRong-En Fan 			if (_nc_db_have_data(&key, &data, &have, &used)) {
4874a1a9510SRong-En Fan 			    if (_nc_read_termtype(&lterm, have, used) > 0) {
4884a1a9510SRong-En Fan 				/* only visit things once, by primary name */
4894a1a9510SRong-En Fan 				cn = _nc_first_name(lterm.term_names);
4904a1a9510SRong-En Fan 				/* apply the selected hook function */
491*73f0a83dSXin LI 				hook(i, eargc, cn, &lterm);
4924a1a9510SRong-En Fan 				_nc_free_termtype(&lterm);
4934a1a9510SRong-En Fan 			    }
4944a1a9510SRong-En Fan 			}
4954a1a9510SRong-En Fan 			code = _nc_db_next(capdbp, &key, &data);
4964a1a9510SRong-En Fan 		    }
4974a1a9510SRong-En Fan 
4984a1a9510SRong-En Fan 		    _nc_db_close(capdbp);
499*73f0a83dSXin LI 		    continue;
5004a1a9510SRong-En Fan 		}
5014a1a9510SRong-En Fan 	    }
5024a1a9510SRong-En Fan 	}
5034a1a9510SRong-En Fan #endif
5044a1a9510SRong-En Fan #endif
505*73f0a83dSXin LI #if NCURSES_USE_TERMCAP
5064a1a9510SRong-En Fan #if HAVE_BSD_CGETENT
507*73f0a83dSXin LI 	{
508*73f0a83dSXin LI 	    CGETENT_CONST char *db_array[2];
5094a1a9510SRong-En Fan 	    char *buffer = 0;
5104a1a9510SRong-En Fan 
5114a1a9510SRong-En Fan 	    if (verbosity)
5124a1a9510SRong-En Fan 		(void) printf("#\n#%s:\n#\n", eargv[i]);
5134a1a9510SRong-En Fan 
5144a1a9510SRong-En Fan 	    db_array[0] = eargv[i];
5154a1a9510SRong-En Fan 	    db_array[1] = 0;
5164a1a9510SRong-En Fan 
517*73f0a83dSXin LI 	    if (cgetfirst(&buffer, db_array) > 0) {
518*73f0a83dSXin LI 		show_termcap(i, eargc, buffer, hook);
5194a1a9510SRong-En Fan 		free(buffer);
520*73f0a83dSXin LI 		while (cgetnext(&buffer, db_array) > 0) {
521*73f0a83dSXin LI 		    show_termcap(i, eargc, buffer, hook);
5224a1a9510SRong-En Fan 		    free(buffer);
5234a1a9510SRong-En Fan 		}
5244a1a9510SRong-En Fan 		cgetclose();
525*73f0a83dSXin LI 		continue;
526*73f0a83dSXin LI 	    }
527*73f0a83dSXin LI 	}
5284a1a9510SRong-En Fan #else
5294a1a9510SRong-En Fan 	/* scan termcap text-file only */
5304a1a9510SRong-En Fan 	if (_nc_is_file_path(eargv[i])) {
5314a1a9510SRong-En Fan 	    char buffer[2048];
5324a1a9510SRong-En Fan 	    FILE *fp;
5334a1a9510SRong-En Fan 
534*73f0a83dSXin LI 	    if (verbosity)
535*73f0a83dSXin LI 		(void) printf("#\n#%s:\n#\n", eargv[i]);
536*73f0a83dSXin LI 
5374a1a9510SRong-En Fan 	    if ((fp = fopen(eargv[i], "r")) != 0) {
5384a1a9510SRong-En Fan 		while (fgets(buffer, sizeof(buffer), fp) != 0) {
5394a1a9510SRong-En Fan 		    if (*buffer == '#')
5404a1a9510SRong-En Fan 			continue;
5414a1a9510SRong-En Fan 		    if (isspace(*buffer))
5424a1a9510SRong-En Fan 			continue;
543*73f0a83dSXin LI 		    show_termcap(i, eargc, buffer, hook);
5444a1a9510SRong-En Fan 		}
5454a1a9510SRong-En Fan 		fclose(fp);
5464a1a9510SRong-En Fan 	    }
5474a1a9510SRong-En Fan 	}
5484a1a9510SRong-En Fan #endif
5494a1a9510SRong-En Fan #endif
5504a1a9510SRong-En Fan     }
5514a1a9510SRong-En Fan 
552*73f0a83dSXin LI     if (hook == sorthook) {
553*73f0a83dSXin LI 	show_termdata(eargc, eargv);
554*73f0a83dSXin LI 	free_termdata();
555*73f0a83dSXin LI     }
556*73f0a83dSXin LI 
5574a1a9510SRong-En Fan     return (EXIT_SUCCESS);
5584a1a9510SRong-En Fan }
5594a1a9510SRong-En Fan 
5604a1a9510SRong-En Fan static void
5614a1a9510SRong-En Fan usage(void)
5624a1a9510SRong-En Fan {
563*73f0a83dSXin LI     (void) fprintf(stderr, "usage: %s [-ahsuUV] [-v n] [file...]\n", _nc_progname);
5644a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
56515589c42SPeter Wemm }
56615589c42SPeter Wemm 
56715589c42SPeter Wemm int
56815589c42SPeter Wemm main(int argc, char *argv[])
5690e3d5408SPeter Wemm {
5704a1a9510SRong-En Fan     bool all_dirs = FALSE;
5710e3d5408SPeter Wemm     bool direct_dependencies = FALSE;
5720e3d5408SPeter Wemm     bool invert_dependencies = FALSE;
5730e3d5408SPeter Wemm     bool header = FALSE;
574d8977eafSRong-En Fan     char *report_file = 0;
5755d08fb1fSRong-En Fan     unsigned i;
5760e3d5408SPeter Wemm     int code;
5774a1a9510SRong-En Fan     int this_opt, last_opt = '?';
578*73f0a83dSXin LI     unsigned v_opt = 0;
579*73f0a83dSXin LI     DescHook *hook = deschook;
5800e3d5408SPeter Wemm 
58139f2269fSPeter Wemm     _nc_progname = _nc_rootname(argv[0]);
5820e3d5408SPeter Wemm 
583*73f0a83dSXin LI     while ((this_opt = getopt(argc, argv, "0123456789ahsu:vU:V")) != -1) {
5844a1a9510SRong-En Fan 	/* handle optional parameter */
5854a1a9510SRong-En Fan 	if (isdigit(this_opt)) {
5864a1a9510SRong-En Fan 	    switch (last_opt) {
5874a1a9510SRong-En Fan 	    case 'v':
588*73f0a83dSXin LI 		v_opt = (unsigned) (this_opt - '0');
5894a1a9510SRong-En Fan 		break;
5904a1a9510SRong-En Fan 	    default:
5914a1a9510SRong-En Fan 		if (isdigit(last_opt))
5924a1a9510SRong-En Fan 		    v_opt *= 10;
5934a1a9510SRong-En Fan 		else
5944a1a9510SRong-En Fan 		    v_opt = 0;
595*73f0a83dSXin LI 		v_opt += (unsigned) (this_opt - '0');
5964a1a9510SRong-En Fan 		last_opt = this_opt;
5974a1a9510SRong-En Fan 	    }
5984a1a9510SRong-En Fan 	    continue;
5994a1a9510SRong-En Fan 	}
6004a1a9510SRong-En Fan 	switch (this_opt) {
6014a1a9510SRong-En Fan 	case 'a':
6024a1a9510SRong-En Fan 	    all_dirs = TRUE;
6034a1a9510SRong-En Fan 	    break;
6040e3d5408SPeter Wemm 	case 'h':
6050e3d5408SPeter Wemm 	    header = TRUE;
6060e3d5408SPeter Wemm 	    break;
607*73f0a83dSXin LI 	case 's':
608*73f0a83dSXin LI 	    hook = sorthook;
609*73f0a83dSXin LI 	    break;
6100e3d5408SPeter Wemm 	case 'u':
6110e3d5408SPeter Wemm 	    direct_dependencies = TRUE;
612d8977eafSRong-En Fan 	    report_file = optarg;
6130e3d5408SPeter Wemm 	    break;
6140e3d5408SPeter Wemm 	case 'v':
6154a1a9510SRong-En Fan 	    v_opt = 1;
6160e3d5408SPeter Wemm 	    break;
6170e3d5408SPeter Wemm 	case 'U':
6180e3d5408SPeter Wemm 	    invert_dependencies = TRUE;
619d8977eafSRong-En Fan 	    report_file = optarg;
6200e3d5408SPeter Wemm 	    break;
6210e3d5408SPeter Wemm 	case 'V':
62218259542SPeter Wemm 	    puts(curses_version());
6230e3d5408SPeter Wemm 	    ExitProgram(EXIT_SUCCESS);
6240e3d5408SPeter Wemm 	default:
6254a1a9510SRong-En Fan 	    usage();
6260e3d5408SPeter Wemm 	}
6274a1a9510SRong-En Fan     }
6284a1a9510SRong-En Fan     set_trace_level(v_opt);
6290e3d5408SPeter Wemm 
630d8977eafSRong-En Fan     if (report_file != 0) {
631d8977eafSRong-En Fan 	if (freopen(report_file, "r", stdin) == 0) {
6320e3d5408SPeter Wemm 	    (void) fflush(stdout);
633d8977eafSRong-En Fan 	    fprintf(stderr, "%s: can't open %s\n", _nc_progname, report_file);
6340e3d5408SPeter Wemm 	    ExitProgram(EXIT_FAILURE);
6350e3d5408SPeter Wemm 	}
6360e3d5408SPeter Wemm 
6370e3d5408SPeter Wemm 	/* parse entries out of the source file */
638d8977eafSRong-En Fan 	_nc_set_source(report_file);
63915589c42SPeter Wemm 	_nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
6400e3d5408SPeter Wemm     }
6410e3d5408SPeter Wemm 
6420e3d5408SPeter Wemm     /* maybe we want a direct-dependency listing? */
64315589c42SPeter Wemm     if (direct_dependencies) {
6440e3d5408SPeter Wemm 	ENTRY *qp;
6450e3d5408SPeter Wemm 
6464a1a9510SRong-En Fan 	for_entry_list(qp) {
64715589c42SPeter Wemm 	    if (qp->nuses) {
6485d08fb1fSRong-En Fan 		unsigned j;
6490e3d5408SPeter Wemm 
6500e3d5408SPeter Wemm 		(void) printf("%s:", _nc_first_name(qp->tterm.term_names));
6510e3d5408SPeter Wemm 		for (j = 0; j < qp->nuses; j++)
65215589c42SPeter Wemm 		    (void) printf(" %s", qp->uses[j].name);
6530e3d5408SPeter Wemm 		putchar('\n');
6540e3d5408SPeter Wemm 	    }
6554a1a9510SRong-En Fan 	}
6560e3d5408SPeter Wemm 
6570e3d5408SPeter Wemm 	ExitProgram(EXIT_SUCCESS);
6580e3d5408SPeter Wemm     }
6590e3d5408SPeter Wemm 
6600e3d5408SPeter Wemm     /* maybe we want a reverse-dependency listing? */
66115589c42SPeter Wemm     if (invert_dependencies) {
6620e3d5408SPeter Wemm 	ENTRY *qp, *rp;
6630e3d5408SPeter Wemm 	int matchcount;
6640e3d5408SPeter Wemm 
66515589c42SPeter Wemm 	for_entry_list(qp) {
6660e3d5408SPeter Wemm 	    matchcount = 0;
66715589c42SPeter Wemm 	    for_entry_list(rp) {
6680e3d5408SPeter Wemm 		if (rp->nuses == 0)
6690e3d5408SPeter Wemm 		    continue;
6700e3d5408SPeter Wemm 
6710e3d5408SPeter Wemm 		for (i = 0; i < rp->nuses; i++)
67215589c42SPeter Wemm 		    if (_nc_name_match(qp->tterm.term_names,
67315589c42SPeter Wemm 				       rp->uses[i].name, "|")) {
6740e3d5408SPeter Wemm 			if (matchcount++ == 0)
6750e3d5408SPeter Wemm 			    (void) printf("%s:",
6760e3d5408SPeter Wemm 					  _nc_first_name(qp->tterm.term_names));
6770e3d5408SPeter Wemm 			(void) printf(" %s",
6780e3d5408SPeter Wemm 				      _nc_first_name(rp->tterm.term_names));
6790e3d5408SPeter Wemm 		    }
6800e3d5408SPeter Wemm 	    }
6810e3d5408SPeter Wemm 	    if (matchcount)
6820e3d5408SPeter Wemm 		putchar('\n');
6830e3d5408SPeter Wemm 	}
6840e3d5408SPeter Wemm 
6850e3d5408SPeter Wemm 	ExitProgram(EXIT_SUCCESS);
6860e3d5408SPeter Wemm     }
6870e3d5408SPeter Wemm 
6880e3d5408SPeter Wemm     /*
6890e3d5408SPeter Wemm      * If we get this far, user wants a simple terminal type listing.
6900e3d5408SPeter Wemm      */
6910e3d5408SPeter Wemm     if (optind < argc) {
692*73f0a83dSXin LI 	code = typelist(argc - optind, argv + optind, header, hook);
6934a1a9510SRong-En Fan     } else if (all_dirs) {
6944a1a9510SRong-En Fan 	DBDIRS state;
6954a1a9510SRong-En Fan 	int offset;
6964a1a9510SRong-En Fan 	int pass;
6974a1a9510SRong-En Fan 	const char *path;
6984a1a9510SRong-En Fan 	char **eargv = 0;
6990e3d5408SPeter Wemm 
7004a1a9510SRong-En Fan 	code = EXIT_FAILURE;
7014a1a9510SRong-En Fan 	for (pass = 0; pass < 2; ++pass) {
702*73f0a83dSXin LI 	    size_t count = 0;
7030e3d5408SPeter Wemm 
7044a1a9510SRong-En Fan 	    _nc_first_db(&state, &offset);
7054a1a9510SRong-En Fan 	    while ((path = _nc_next_db(&state, &offset)) != 0) {
706*73f0a83dSXin LI 		if (pass) {
707*73f0a83dSXin LI 		    eargv[count] = strmalloc(path);
7080e3d5408SPeter Wemm 		}
7094a1a9510SRong-En Fan 		++count;
7104a1a9510SRong-En Fan 	    }
7114a1a9510SRong-En Fan 	    if (!pass) {
712*73f0a83dSXin LI 		eargv = allocArgv(count);
71306bfebdeSXin LI 		if (eargv == 0)
714*73f0a83dSXin LI 		    failed("eargv");
7154a1a9510SRong-En Fan 	    } else {
716*73f0a83dSXin LI 		code = typelist((int) count, eargv, header, hook);
717*73f0a83dSXin LI 		freeArgv(eargv);
7184a1a9510SRong-En Fan 	    }
7194a1a9510SRong-En Fan 	}
7204a1a9510SRong-En Fan     } else {
7214a1a9510SRong-En Fan 	DBDIRS state;
7224a1a9510SRong-En Fan 	int offset;
7234a1a9510SRong-En Fan 	const char *path;
724*73f0a83dSXin LI 	char **eargv = allocArgv((size_t) 2);
725*73f0a83dSXin LI 	size_t count = 0;
7264a1a9510SRong-En Fan 
727*73f0a83dSXin LI 	if (eargv == 0)
728*73f0a83dSXin LI 	    failed("eargv");
7294a1a9510SRong-En Fan 	_nc_first_db(&state, &offset);
730*73f0a83dSXin LI 	if ((path = _nc_next_db(&state, &offset)) != 0) {
731*73f0a83dSXin LI 	    eargv[count++] = strmalloc(path);
7324a1a9510SRong-En Fan 	}
7334a1a9510SRong-En Fan 
734*73f0a83dSXin LI 	code = typelist((int) count, eargv, header, hook);
7354a1a9510SRong-En Fan 
736*73f0a83dSXin LI 	freeArgv(eargv);
7374a1a9510SRong-En Fan     }
7384a1a9510SRong-En Fan     _nc_last_db();
7390e3d5408SPeter Wemm 
7400e3d5408SPeter Wemm     ExitProgram(code);
7410e3d5408SPeter Wemm }
742