xref: /freebsd/contrib/ncurses/progs/toe.c (revision aae38d10b4eebf81c0942947e8b83a9bb8651d88)
10e3d5408SPeter Wemm /****************************************************************************
2*aae38d10SBaptiste Daroussin  * Copyright (c) 1998-2017,2018 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*aae38d10SBaptiste Daroussin MODULE_ID("$Id: toe.c,v 1.78 2018/11/17 22:41:46 tom Exp $")
4815589c42SPeter Wemm 
4915589c42SPeter Wemm #define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
500e3d5408SPeter Wemm 
5173f0a83dSXin LI typedef struct {
5273f0a83dSXin LI     int db_index;
5373f0a83dSXin LI     unsigned long checksum;
5473f0a83dSXin LI     char *term_name;
5573f0a83dSXin LI     char *description;
5673f0a83dSXin LI } TERMDATA;
5773f0a83dSXin LI 
580e3d5408SPeter Wemm const char *_nc_progname;
590e3d5408SPeter Wemm 
6073f0a83dSXin LI static TERMDATA *ptr_termdata;	/* array of terminal data */
6173f0a83dSXin LI static size_t use_termdata;	/* actual usage in ptr_termdata[] */
6273f0a83dSXin LI static size_t len_termdata;	/* allocated size of ptr_termdata[] */
6373f0a83dSXin 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 
7573f0a83dSXin LI static void failed(const char *) GCC_NORETURN;
7673f0a83dSXin 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 
8473f0a83dSXin LI static char *
8573f0a83dSXin LI strmalloc(const char *value)
8673f0a83dSXin LI {
8773f0a83dSXin LI     char *result = strdup(value);
8873f0a83dSXin LI     if (result == 0) {
8973f0a83dSXin LI 	failed("strmalloc");
9073f0a83dSXin LI     }
9173f0a83dSXin LI     return result;
9273f0a83dSXin LI }
9373f0a83dSXin LI 
9473f0a83dSXin LI static TERMDATA *
9573f0a83dSXin LI new_termdata(void)
9673f0a83dSXin LI {
9773f0a83dSXin LI     size_t want = use_termdata + 1;
9873f0a83dSXin LI 
9973f0a83dSXin LI     if (want >= len_termdata) {
10073f0a83dSXin LI 	len_termdata = (2 * want) + 10;
10173f0a83dSXin LI 	ptr_termdata = typeRealloc(TERMDATA, len_termdata, ptr_termdata);
10273f0a83dSXin LI 	if (ptr_termdata == 0)
10373f0a83dSXin LI 	    failed("ptr_termdata");
10473f0a83dSXin LI     }
10573f0a83dSXin LI 
10673f0a83dSXin LI     return ptr_termdata + use_termdata++;
10773f0a83dSXin LI }
10873f0a83dSXin LI 
10973f0a83dSXin LI static int
11073f0a83dSXin LI compare_termdata(const void *a, const void *b)
11173f0a83dSXin LI {
11273f0a83dSXin LI     const TERMDATA *p = (const TERMDATA *) a;
11373f0a83dSXin LI     const TERMDATA *q = (const TERMDATA *) b;
11473f0a83dSXin LI     int result = strcmp(p->term_name, q->term_name);
11573f0a83dSXin LI 
11673f0a83dSXin LI     if (result == 0) {
11773f0a83dSXin LI 	result = (p->db_index - q->db_index);
11873f0a83dSXin LI     }
11973f0a83dSXin LI     return result;
12073f0a83dSXin LI }
12173f0a83dSXin LI 
12273f0a83dSXin LI /*
12373f0a83dSXin LI  * Sort the array of TERMDATA and print it.  If more than one database is being
12473f0a83dSXin LI  * reported, add a column to show which database has a given entry.
12573f0a83dSXin LI  */
12673f0a83dSXin LI static void
12773f0a83dSXin LI show_termdata(int eargc, char **eargv)
12873f0a83dSXin LI {
12973f0a83dSXin LI     int j, k;
13073f0a83dSXin LI     size_t n;
13173f0a83dSXin LI 
13273f0a83dSXin LI     if (use_termdata) {
13373f0a83dSXin LI 	if (eargc > 1) {
13473f0a83dSXin LI 	    for (j = 0; j < eargc; ++j) {
13573f0a83dSXin LI 		for (k = 0; k <= j; ++k) {
13673f0a83dSXin LI 		    printf("--");
13773f0a83dSXin LI 		}
13873f0a83dSXin LI 		printf("> ");
13973f0a83dSXin LI 		printf("%s\n", eargv[j]);
14073f0a83dSXin LI 	    }
14173f0a83dSXin LI 	}
14273f0a83dSXin LI 	if (use_termdata > 1)
14373f0a83dSXin LI 	    qsort(ptr_termdata, use_termdata, sizeof(TERMDATA), compare_termdata);
14473f0a83dSXin LI 	for (n = 0; n < use_termdata; ++n) {
14573f0a83dSXin LI 
14673f0a83dSXin LI 	    /*
14773f0a83dSXin LI 	     * If there is more than one database, show how they differ.
14873f0a83dSXin LI 	     */
14973f0a83dSXin LI 	    if (eargc > 1) {
15073f0a83dSXin LI 		unsigned long check = 0;
15173f0a83dSXin LI 		k = 0;
15273f0a83dSXin LI 		for (;;) {
15373f0a83dSXin LI 		    for (; k < ptr_termdata[n].db_index; ++k) {
15473f0a83dSXin LI 			printf("--");
15573f0a83dSXin LI 		    }
15673f0a83dSXin LI 
15773f0a83dSXin LI 		    /*
15873f0a83dSXin LI 		     * If this is the first entry, or its checksum differs
15973f0a83dSXin LI 		     * from the first entry's checksum, print "*". Otherwise
16073f0a83dSXin LI 		     * it looks enough like a duplicate to print "+".
16173f0a83dSXin LI 		     */
16273f0a83dSXin LI 		    printf("%c-", ((check == 0
16373f0a83dSXin LI 				    || (check != ptr_termdata[n].checksum))
16473f0a83dSXin LI 				   ? '*'
16573f0a83dSXin LI 				   : '+'));
16673f0a83dSXin LI 		    check = ptr_termdata[n].checksum;
16773f0a83dSXin LI 
16873f0a83dSXin LI 		    ++k;
16973f0a83dSXin LI 		    if ((n + 1) >= use_termdata
17073f0a83dSXin LI 			|| strcmp(ptr_termdata[n].term_name,
17173f0a83dSXin LI 				  ptr_termdata[n + 1].term_name)) {
17273f0a83dSXin LI 			break;
17373f0a83dSXin LI 		    }
17473f0a83dSXin LI 		    ++n;
17573f0a83dSXin LI 		}
17673f0a83dSXin LI 		for (; k < eargc; ++k) {
17773f0a83dSXin LI 		    printf("--");
17873f0a83dSXin LI 		}
17973f0a83dSXin LI 		printf(":\t");
18073f0a83dSXin LI 	    }
18173f0a83dSXin LI 
18273f0a83dSXin LI 	    (void) printf("%-10s\t%s\n",
18373f0a83dSXin LI 			  ptr_termdata[n].term_name,
18473f0a83dSXin LI 			  ptr_termdata[n].description);
18573f0a83dSXin LI 	}
18673f0a83dSXin LI     }
18773f0a83dSXin LI }
18873f0a83dSXin LI 
18973f0a83dSXin LI static void
19073f0a83dSXin LI free_termdata(void)
19173f0a83dSXin LI {
19273f0a83dSXin LI     if (ptr_termdata != 0) {
19373f0a83dSXin LI 	while (use_termdata != 0) {
19473f0a83dSXin LI 	    --use_termdata;
19573f0a83dSXin LI 	    free(ptr_termdata[use_termdata].term_name);
19673f0a83dSXin LI 	    free(ptr_termdata[use_termdata].description);
19773f0a83dSXin LI 	}
19873f0a83dSXin LI 	free(ptr_termdata);
19973f0a83dSXin LI 	ptr_termdata = 0;
20073f0a83dSXin LI     }
20173f0a83dSXin LI     use_termdata = 0;
20273f0a83dSXin LI     len_termdata = 0;
20373f0a83dSXin LI }
20473f0a83dSXin LI 
20573f0a83dSXin LI static char **
20673f0a83dSXin LI allocArgv(size_t count)
20773f0a83dSXin LI {
20873f0a83dSXin LI     char **result = typeCalloc(char *, count + 1);
20973f0a83dSXin LI     if (result == 0)
21073f0a83dSXin LI 	failed("realloc eargv");
21173f0a83dSXin LI 
21273f0a83dSXin LI     assert(result != 0);
21373f0a83dSXin LI     return result;
21473f0a83dSXin LI }
21573f0a83dSXin LI 
21673f0a83dSXin LI static void
21773f0a83dSXin LI freeArgv(char **argv)
21873f0a83dSXin LI {
21973f0a83dSXin LI     if (argv) {
22073f0a83dSXin LI 	int count = 0;
22173f0a83dSXin LI 	while (argv[count]) {
22273f0a83dSXin LI 	    free(argv[count++]);
22373f0a83dSXin LI 	}
22473f0a83dSXin LI 	free(argv);
22573f0a83dSXin LI     }
22673f0a83dSXin LI }
22773f0a83dSXin 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;
23573f0a83dSXin LI     size_t lens = sizeof(suffix) - 1;
23673f0a83dSXin LI     size_t size = strlen(src);
23773f0a83dSXin LI     size_t need = lens + size;
2384a1a9510SRong-En Fan 
2394a1a9510SRong-En Fan     if (need <= limit) {
2404a1a9510SRong-En Fan 	if (size >= lens
24173f0a83dSXin LI 	    && !strcmp(src + size - lens, suffix)) {
24273f0a83dSXin LI 	    _nc_STRCPY(dst, src, PATH_MAX);
24373f0a83dSXin LI 	} else {
24473f0a83dSXin LI 	    _nc_SPRINTF(dst, _nc_SLIMIT(PATH_MAX) "%s%s", src, suffix);
24573f0a83dSXin LI 	}
2464a1a9510SRong-En Fan 	result = TRUE;
24739f2269fSPeter Wemm     }
2484a1a9510SRong-En Fan     return result;
2494a1a9510SRong-En Fan }
2504a1a9510SRong-En Fan #endif
25139f2269fSPeter Wemm 
25273f0a83dSXin LI typedef void (DescHook) (int /* db_index */ ,
25373f0a83dSXin LI 			 int /* db_limit */ ,
25473f0a83dSXin LI 			 const char * /* term_name */ ,
255*aae38d10SBaptiste Daroussin 			 TERMTYPE2 * /* term */ );
25639f2269fSPeter Wemm 
25773f0a83dSXin LI static const char *
258*aae38d10SBaptiste Daroussin term_description(TERMTYPE2 *tp)
25915589c42SPeter Wemm {
2604a1a9510SRong-En Fan     const char *desc;
2614a1a9510SRong-En Fan 
26273f0a83dSXin LI     if (tp->term_names == 0
26373f0a83dSXin LI 	|| (desc = strrchr(tp->term_names, '|')) == 0
26473f0a83dSXin LI 	|| (*++desc == '\0')) {
2654a1a9510SRong-En Fan 	desc = "(No description)";
26615589c42SPeter Wemm     }
2674a1a9510SRong-En Fan 
26873f0a83dSXin LI     return desc;
26973f0a83dSXin LI }
27073f0a83dSXin LI 
27173f0a83dSXin LI /* display a description for the type */
2724a1a9510SRong-En Fan static void
273*aae38d10SBaptiste Daroussin deschook(int db_index, int db_limit, const char *term_name, TERMTYPE2 *tp)
27473f0a83dSXin LI {
27573f0a83dSXin LI     (void) db_index;
27673f0a83dSXin LI     (void) db_limit;
27773f0a83dSXin LI     (void) printf("%-10s\t%s\n", term_name, term_description(tp));
27873f0a83dSXin LI }
27973f0a83dSXin LI 
28073f0a83dSXin LI static unsigned long
28173f0a83dSXin LI string_sum(const char *value)
28273f0a83dSXin LI {
28373f0a83dSXin LI     unsigned long result = 0;
28473f0a83dSXin LI 
28573f0a83dSXin LI     if ((intptr_t) value == (intptr_t) (-1)) {
28673f0a83dSXin LI 	result = ~result;
28773f0a83dSXin LI     } else if (value) {
28873f0a83dSXin LI 	while (*value) {
28973f0a83dSXin LI 	    result += UChar(*value);
29073f0a83dSXin LI 	    ++value;
29173f0a83dSXin LI 	}
29273f0a83dSXin LI     }
29373f0a83dSXin LI     return result;
29473f0a83dSXin LI }
29573f0a83dSXin LI 
29673f0a83dSXin LI static unsigned long
297*aae38d10SBaptiste Daroussin checksum_of(TERMTYPE2 *tp)
29873f0a83dSXin LI {
29973f0a83dSXin LI     unsigned long result = string_sum(tp->term_names);
30073f0a83dSXin LI     unsigned i;
30173f0a83dSXin LI 
30273f0a83dSXin LI     for (i = 0; i < NUM_BOOLEANS(tp); i++) {
30373f0a83dSXin LI 	result += (unsigned long) (tp->Booleans[i]);
30473f0a83dSXin LI     }
30573f0a83dSXin LI     for (i = 0; i < NUM_NUMBERS(tp); i++) {
30673f0a83dSXin LI 	result += (unsigned long) (tp->Numbers[i]);
30773f0a83dSXin LI     }
30873f0a83dSXin LI     for (i = 0; i < NUM_STRINGS(tp); i++) {
30973f0a83dSXin LI 	result += string_sum(tp->Strings[i]);
31073f0a83dSXin LI     }
31173f0a83dSXin LI     return result;
31273f0a83dSXin LI }
31373f0a83dSXin LI 
31473f0a83dSXin LI /* collect data, to sort before display */
31573f0a83dSXin LI static void
316*aae38d10SBaptiste Daroussin sorthook(int db_index, int db_limit, const char *term_name, TERMTYPE2 *tp)
31773f0a83dSXin LI {
31873f0a83dSXin LI     TERMDATA *data = new_termdata();
31973f0a83dSXin LI 
32073f0a83dSXin LI     data->db_index = db_index;
32173f0a83dSXin LI     data->checksum = ((db_limit > 1) ? checksum_of(tp) : 0);
32273f0a83dSXin LI     data->term_name = strmalloc(term_name);
32373f0a83dSXin LI     data->description = strmalloc(term_description(tp));
32473f0a83dSXin LI }
32573f0a83dSXin LI 
32673f0a83dSXin LI #if NCURSES_USE_TERMCAP
32773f0a83dSXin LI static void
32873f0a83dSXin LI show_termcap(int db_index, int db_limit, char *buffer, DescHook hook)
3294a1a9510SRong-En Fan {
330*aae38d10SBaptiste Daroussin     TERMTYPE2 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 
34273f0a83dSXin LI     memset(&data, 0, sizeof(data));
34373f0a83dSXin LI     data.term_names = strmalloc(buffer);
3444a1a9510SRong-En Fan     while ((next = strtok(list, "|")) != 0) {
3454a1a9510SRong-En Fan 	if (next != last)
34673f0a83dSXin 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 
35373f0a83dSXin LI #if NCURSES_USE_DATABASE
35473f0a83dSXin LI static char *
35573f0a83dSXin LI copy_entryname(DIRENT * src)
35673f0a83dSXin LI {
35773f0a83dSXin LI     size_t len = NAMLEN(src);
35873f0a83dSXin LI     char *result = malloc(len + 1);
35973f0a83dSXin LI     if (result == 0)
36073f0a83dSXin LI 	failed("copy entryname");
36173f0a83dSXin LI     memcpy(result, src->d_name, len);
36273f0a83dSXin LI     result[len] = '\0';
36373f0a83dSXin LI 
36473f0a83dSXin LI     return result;
36573f0a83dSXin LI }
36673f0a83dSXin LI #endif
36773f0a83dSXin LI 
3684a1a9510SRong-En Fan static int
3694a1a9510SRong-En Fan typelist(int eargc, char *eargv[],
37073f0a83dSXin LI 	 int verbosity,
37173f0a83dSXin 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++) {
37773f0a83dSXin 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]);
38873f0a83dSXin LI 		continue;
38973f0a83dSXin LI 	    }
39073f0a83dSXin LI 
39173f0a83dSXin 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) {
39573f0a83dSXin LI 		size_t cwd_len;
39673f0a83dSXin LI 		char *name_1;
3974a1a9510SRong-En Fan 		DIR *entrydir;
3984a1a9510SRong-En Fan 		DIRENT *entry;
3994a1a9510SRong-En Fan 
40073f0a83dSXin LI 		name_1 = copy_entryname(subdir);
40173f0a83dSXin LI 		if (isDotname(name_1)) {
40273f0a83dSXin LI 		    free(name_1);
40373f0a83dSXin LI 		    continue;
40473f0a83dSXin LI 		}
40573f0a83dSXin LI 
40673f0a83dSXin 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 
41373f0a83dSXin LI 		_nc_SPRINTF(cwd_buf, _nc_SLIMIT(cwd_len)
41473f0a83dSXin LI 			    "%s/%s/", eargv[i], name_1);
41573f0a83dSXin 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) {
42673f0a83dSXin LI 		    char *name_2;
427*aae38d10SBaptiste Daroussin 		    TERMTYPE2 lterm;
4284a1a9510SRong-En Fan 		    char *cn;
4294a1a9510SRong-En Fan 		    int status;
4304a1a9510SRong-En Fan 
43173f0a83dSXin LI 		    name_2 = copy_entryname(entry);
43273f0a83dSXin LI 		    if (isDotname(name_2) || !_nc_is_file_path(name_2)) {
43373f0a83dSXin LI 			free(name_2);
4344a1a9510SRong-En Fan 			continue;
43573f0a83dSXin 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);
44373f0a83dSXin LI 			free(name_2);
444*aae38d10SBaptiste Daroussin 			continue;
4454a1a9510SRong-En Fan 		    }
4464a1a9510SRong-En Fan 
4474a1a9510SRong-En Fan 		    /* only visit things once, by primary name */
4484a1a9510SRong-En Fan 		    cn = _nc_first_name(lterm.term_names);
4494a1a9510SRong-En Fan 		    if (!strcmp(cn, name_2)) {
4504a1a9510SRong-En Fan 			/* apply the selected hook function */
45173f0a83dSXin LI 			hook(i, eargc, cn, &lterm);
4524a1a9510SRong-En Fan 		    }
453*aae38d10SBaptiste Daroussin 		    _nc_free_termtype2(&lterm);
45473f0a83dSXin LI 		    free(name_2);
4554a1a9510SRong-En Fan 		}
4564a1a9510SRong-En Fan 		closedir(entrydir);
4574a1a9510SRong-En Fan 	    }
4584a1a9510SRong-En Fan 	    closedir(termdir);
4595d08fb1fSRong-En Fan 	    if (cwd_buf != 0)
4605d08fb1fSRong-En Fan 		free(cwd_buf);
46173f0a83dSXin LI 	    continue;
4624a1a9510SRong-En Fan 	}
4634a1a9510SRong-En Fan #if USE_HASHED_DB
4644a1a9510SRong-En Fan 	else {
4654a1a9510SRong-En Fan 	    DB *capdbp;
4664a1a9510SRong-En Fan 	    char filename[PATH_MAX];
4674a1a9510SRong-En Fan 
46873f0a83dSXin LI 	    if (verbosity)
46973f0a83dSXin LI 		(void) printf("#\n#%s:\n#\n", eargv[i]);
47073f0a83dSXin LI 
4714a1a9510SRong-En Fan 	    if (make_db_name(filename, eargv[i], sizeof(filename))) {
4724a1a9510SRong-En Fan 		if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
4734a1a9510SRong-En Fan 		    DBT key, data;
4744a1a9510SRong-En Fan 		    int code;
4754a1a9510SRong-En Fan 
4764a1a9510SRong-En Fan 		    code = _nc_db_first(capdbp, &key, &data);
4774a1a9510SRong-En Fan 		    while (code == 0) {
478*aae38d10SBaptiste Daroussin 			TERMTYPE2 lterm;
4794a1a9510SRong-En Fan 			int used;
4804a1a9510SRong-En Fan 			char *have;
4814a1a9510SRong-En Fan 			char *cn;
4824a1a9510SRong-En Fan 
4834a1a9510SRong-En Fan 			if (_nc_db_have_data(&key, &data, &have, &used)) {
4844a1a9510SRong-En Fan 			    if (_nc_read_termtype(&lterm, have, used) > 0) {
4854a1a9510SRong-En Fan 				/* only visit things once, by primary name */
4864a1a9510SRong-En Fan 				cn = _nc_first_name(lterm.term_names);
4874a1a9510SRong-En Fan 				/* apply the selected hook function */
48873f0a83dSXin LI 				hook(i, eargc, cn, &lterm);
489*aae38d10SBaptiste Daroussin 				_nc_free_termtype2(&lterm);
4904a1a9510SRong-En Fan 			    }
4914a1a9510SRong-En Fan 			}
4924a1a9510SRong-En Fan 			code = _nc_db_next(capdbp, &key, &data);
4934a1a9510SRong-En Fan 		    }
4944a1a9510SRong-En Fan 
4954a1a9510SRong-En Fan 		    _nc_db_close(capdbp);
49673f0a83dSXin LI 		    continue;
4974a1a9510SRong-En Fan 		}
4984a1a9510SRong-En Fan 	    }
4994a1a9510SRong-En Fan 	}
500*aae38d10SBaptiste Daroussin #endif /* USE_HASHED_DB */
501*aae38d10SBaptiste Daroussin #endif /* NCURSES_USE_DATABASE */
50273f0a83dSXin LI #if NCURSES_USE_TERMCAP
5034a1a9510SRong-En Fan #if HAVE_BSD_CGETENT
50473f0a83dSXin LI 	{
50573f0a83dSXin LI 	    CGETENT_CONST char *db_array[2];
5064a1a9510SRong-En Fan 	    char *buffer = 0;
5074a1a9510SRong-En Fan 
5084a1a9510SRong-En Fan 	    if (verbosity)
5094a1a9510SRong-En Fan 		(void) printf("#\n#%s:\n#\n", eargv[i]);
5104a1a9510SRong-En Fan 
5114a1a9510SRong-En Fan 	    db_array[0] = eargv[i];
5124a1a9510SRong-En Fan 	    db_array[1] = 0;
5134a1a9510SRong-En Fan 
51473f0a83dSXin LI 	    if (cgetfirst(&buffer, db_array) > 0) {
51573f0a83dSXin LI 		show_termcap(i, eargc, buffer, hook);
5164a1a9510SRong-En Fan 		free(buffer);
51773f0a83dSXin LI 		while (cgetnext(&buffer, db_array) > 0) {
51873f0a83dSXin LI 		    show_termcap(i, eargc, buffer, hook);
5194a1a9510SRong-En Fan 		    free(buffer);
5204a1a9510SRong-En Fan 		}
5214a1a9510SRong-En Fan 		cgetclose();
52273f0a83dSXin LI 		continue;
52373f0a83dSXin LI 	    }
52473f0a83dSXin LI 	}
5254a1a9510SRong-En Fan #else
5264a1a9510SRong-En Fan 	/* scan termcap text-file only */
5274a1a9510SRong-En Fan 	if (_nc_is_file_path(eargv[i])) {
5284a1a9510SRong-En Fan 	    char buffer[2048];
5294a1a9510SRong-En Fan 	    FILE *fp;
5304a1a9510SRong-En Fan 
53173f0a83dSXin LI 	    if (verbosity)
53273f0a83dSXin LI 		(void) printf("#\n#%s:\n#\n", eargv[i]);
53373f0a83dSXin LI 
5344a1a9510SRong-En Fan 	    if ((fp = fopen(eargv[i], "r")) != 0) {
5354a1a9510SRong-En Fan 		while (fgets(buffer, sizeof(buffer), fp) != 0) {
5364a1a9510SRong-En Fan 		    if (*buffer == '#')
5374a1a9510SRong-En Fan 			continue;
5384a1a9510SRong-En Fan 		    if (isspace(*buffer))
5394a1a9510SRong-En Fan 			continue;
54073f0a83dSXin LI 		    show_termcap(i, eargc, buffer, hook);
5414a1a9510SRong-En Fan 		}
5424a1a9510SRong-En Fan 		fclose(fp);
5434a1a9510SRong-En Fan 	    }
5444a1a9510SRong-En Fan 	}
5454a1a9510SRong-En Fan #endif
5464a1a9510SRong-En Fan #endif
5474a1a9510SRong-En Fan     }
5484a1a9510SRong-En Fan 
54973f0a83dSXin LI     if (hook == sorthook) {
55073f0a83dSXin LI 	show_termdata(eargc, eargv);
55173f0a83dSXin LI 	free_termdata();
55273f0a83dSXin LI     }
55373f0a83dSXin LI 
5544a1a9510SRong-En Fan     return (EXIT_SUCCESS);
5554a1a9510SRong-En Fan }
5564a1a9510SRong-En Fan 
5574a1a9510SRong-En Fan static void
5584a1a9510SRong-En Fan usage(void)
5594a1a9510SRong-En Fan {
56073f0a83dSXin LI     (void) fprintf(stderr, "usage: %s [-ahsuUV] [-v n] [file...]\n", _nc_progname);
5614a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
56215589c42SPeter Wemm }
56315589c42SPeter Wemm 
56415589c42SPeter Wemm int
56515589c42SPeter Wemm main(int argc, char *argv[])
5660e3d5408SPeter Wemm {
5674a1a9510SRong-En Fan     bool all_dirs = FALSE;
5680e3d5408SPeter Wemm     bool direct_dependencies = FALSE;
5690e3d5408SPeter Wemm     bool invert_dependencies = FALSE;
5700e3d5408SPeter Wemm     bool header = FALSE;
571d8977eafSRong-En Fan     char *report_file = 0;
5725d08fb1fSRong-En Fan     unsigned i;
5730e3d5408SPeter Wemm     int code;
5744a1a9510SRong-En Fan     int this_opt, last_opt = '?';
57573f0a83dSXin LI     unsigned v_opt = 0;
57673f0a83dSXin LI     DescHook *hook = deschook;
5770e3d5408SPeter Wemm 
57839f2269fSPeter Wemm     _nc_progname = _nc_rootname(argv[0]);
5790e3d5408SPeter Wemm 
58073f0a83dSXin LI     while ((this_opt = getopt(argc, argv, "0123456789ahsu:vU:V")) != -1) {
5814a1a9510SRong-En Fan 	/* handle optional parameter */
5824a1a9510SRong-En Fan 	if (isdigit(this_opt)) {
5834a1a9510SRong-En Fan 	    switch (last_opt) {
5844a1a9510SRong-En Fan 	    case 'v':
58573f0a83dSXin LI 		v_opt = (unsigned) (this_opt - '0');
5864a1a9510SRong-En Fan 		break;
5874a1a9510SRong-En Fan 	    default:
5884a1a9510SRong-En Fan 		if (isdigit(last_opt))
5894a1a9510SRong-En Fan 		    v_opt *= 10;
5904a1a9510SRong-En Fan 		else
5914a1a9510SRong-En Fan 		    v_opt = 0;
59273f0a83dSXin LI 		v_opt += (unsigned) (this_opt - '0');
5934a1a9510SRong-En Fan 		last_opt = this_opt;
5944a1a9510SRong-En Fan 	    }
5954a1a9510SRong-En Fan 	    continue;
5964a1a9510SRong-En Fan 	}
5974a1a9510SRong-En Fan 	switch (this_opt) {
5984a1a9510SRong-En Fan 	case 'a':
5994a1a9510SRong-En Fan 	    all_dirs = TRUE;
6004a1a9510SRong-En Fan 	    break;
6010e3d5408SPeter Wemm 	case 'h':
6020e3d5408SPeter Wemm 	    header = TRUE;
6030e3d5408SPeter Wemm 	    break;
60473f0a83dSXin LI 	case 's':
60573f0a83dSXin LI 	    hook = sorthook;
60673f0a83dSXin LI 	    break;
6070e3d5408SPeter Wemm 	case 'u':
6080e3d5408SPeter Wemm 	    direct_dependencies = TRUE;
609d8977eafSRong-En Fan 	    report_file = optarg;
6100e3d5408SPeter Wemm 	    break;
6110e3d5408SPeter Wemm 	case 'v':
6124a1a9510SRong-En Fan 	    v_opt = 1;
6130e3d5408SPeter Wemm 	    break;
6140e3d5408SPeter Wemm 	case 'U':
6150e3d5408SPeter Wemm 	    invert_dependencies = TRUE;
616d8977eafSRong-En Fan 	    report_file = optarg;
6170e3d5408SPeter Wemm 	    break;
6180e3d5408SPeter Wemm 	case 'V':
61918259542SPeter Wemm 	    puts(curses_version());
6200e3d5408SPeter Wemm 	    ExitProgram(EXIT_SUCCESS);
6210e3d5408SPeter Wemm 	default:
6224a1a9510SRong-En Fan 	    usage();
6230e3d5408SPeter Wemm 	}
6244a1a9510SRong-En Fan     }
6254a1a9510SRong-En Fan     set_trace_level(v_opt);
6260e3d5408SPeter Wemm 
627d8977eafSRong-En Fan     if (report_file != 0) {
628d8977eafSRong-En Fan 	if (freopen(report_file, "r", stdin) == 0) {
6290e3d5408SPeter Wemm 	    (void) fflush(stdout);
630d8977eafSRong-En Fan 	    fprintf(stderr, "%s: can't open %s\n", _nc_progname, report_file);
6310e3d5408SPeter Wemm 	    ExitProgram(EXIT_FAILURE);
6320e3d5408SPeter Wemm 	}
6330e3d5408SPeter Wemm 
6340e3d5408SPeter Wemm 	/* parse entries out of the source file */
635d8977eafSRong-En Fan 	_nc_set_source(report_file);
63615589c42SPeter Wemm 	_nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
6370e3d5408SPeter Wemm     }
6380e3d5408SPeter Wemm 
6390e3d5408SPeter Wemm     /* maybe we want a direct-dependency listing? */
64015589c42SPeter Wemm     if (direct_dependencies) {
6410e3d5408SPeter Wemm 	ENTRY *qp;
6420e3d5408SPeter Wemm 
6434a1a9510SRong-En Fan 	for_entry_list(qp) {
64415589c42SPeter Wemm 	    if (qp->nuses) {
6455d08fb1fSRong-En Fan 		unsigned j;
6460e3d5408SPeter Wemm 
6470e3d5408SPeter Wemm 		(void) printf("%s:", _nc_first_name(qp->tterm.term_names));
6480e3d5408SPeter Wemm 		for (j = 0; j < qp->nuses; j++)
64915589c42SPeter Wemm 		    (void) printf(" %s", qp->uses[j].name);
6500e3d5408SPeter Wemm 		putchar('\n');
6510e3d5408SPeter Wemm 	    }
6524a1a9510SRong-En Fan 	}
6530e3d5408SPeter Wemm 
6540e3d5408SPeter Wemm 	ExitProgram(EXIT_SUCCESS);
6550e3d5408SPeter Wemm     }
6560e3d5408SPeter Wemm 
6570e3d5408SPeter Wemm     /* maybe we want a reverse-dependency listing? */
65815589c42SPeter Wemm     if (invert_dependencies) {
6590e3d5408SPeter Wemm 	ENTRY *qp, *rp;
6600e3d5408SPeter Wemm 	int matchcount;
6610e3d5408SPeter Wemm 
66215589c42SPeter Wemm 	for_entry_list(qp) {
6630e3d5408SPeter Wemm 	    matchcount = 0;
66415589c42SPeter Wemm 	    for_entry_list(rp) {
6650e3d5408SPeter Wemm 		if (rp->nuses == 0)
6660e3d5408SPeter Wemm 		    continue;
6670e3d5408SPeter Wemm 
6680e3d5408SPeter Wemm 		for (i = 0; i < rp->nuses; i++)
66915589c42SPeter Wemm 		    if (_nc_name_match(qp->tterm.term_names,
67015589c42SPeter Wemm 				       rp->uses[i].name, "|")) {
6710e3d5408SPeter Wemm 			if (matchcount++ == 0)
6720e3d5408SPeter Wemm 			    (void) printf("%s:",
6730e3d5408SPeter Wemm 					  _nc_first_name(qp->tterm.term_names));
6740e3d5408SPeter Wemm 			(void) printf(" %s",
6750e3d5408SPeter Wemm 				      _nc_first_name(rp->tterm.term_names));
6760e3d5408SPeter Wemm 		    }
6770e3d5408SPeter Wemm 	    }
6780e3d5408SPeter Wemm 	    if (matchcount)
6790e3d5408SPeter Wemm 		putchar('\n');
6800e3d5408SPeter Wemm 	}
6810e3d5408SPeter Wemm 
6820e3d5408SPeter Wemm 	ExitProgram(EXIT_SUCCESS);
6830e3d5408SPeter Wemm     }
6840e3d5408SPeter Wemm 
6850e3d5408SPeter Wemm     /*
6860e3d5408SPeter Wemm      * If we get this far, user wants a simple terminal type listing.
6870e3d5408SPeter Wemm      */
6880e3d5408SPeter Wemm     if (optind < argc) {
68973f0a83dSXin LI 	code = typelist(argc - optind, argv + optind, header, hook);
6904a1a9510SRong-En Fan     } else if (all_dirs) {
6914a1a9510SRong-En Fan 	DBDIRS state;
6924a1a9510SRong-En Fan 	int offset;
6934a1a9510SRong-En Fan 	int pass;
6944a1a9510SRong-En Fan 	const char *path;
6954a1a9510SRong-En Fan 	char **eargv = 0;
6960e3d5408SPeter Wemm 
6974a1a9510SRong-En Fan 	code = EXIT_FAILURE;
6984a1a9510SRong-En Fan 	for (pass = 0; pass < 2; ++pass) {
69973f0a83dSXin LI 	    size_t count = 0;
7000e3d5408SPeter Wemm 
7014a1a9510SRong-En Fan 	    _nc_first_db(&state, &offset);
7024a1a9510SRong-En Fan 	    while ((path = _nc_next_db(&state, &offset)) != 0) {
703*aae38d10SBaptiste Daroussin 		if (quick_prefix(path))
704*aae38d10SBaptiste Daroussin 		    continue;
70573f0a83dSXin LI 		if (pass) {
70673f0a83dSXin LI 		    eargv[count] = strmalloc(path);
7070e3d5408SPeter Wemm 		}
7084a1a9510SRong-En Fan 		++count;
7094a1a9510SRong-En Fan 	    }
7104a1a9510SRong-En Fan 	    if (!pass) {
71173f0a83dSXin LI 		eargv = allocArgv(count);
71206bfebdeSXin LI 		if (eargv == 0)
71373f0a83dSXin LI 		    failed("eargv");
7144a1a9510SRong-En Fan 	    } else {
71573f0a83dSXin LI 		code = typelist((int) count, eargv, header, hook);
71673f0a83dSXin LI 		freeArgv(eargv);
7174a1a9510SRong-En Fan 	    }
7184a1a9510SRong-En Fan 	}
7194a1a9510SRong-En Fan     } else {
7204a1a9510SRong-En Fan 	DBDIRS state;
7214a1a9510SRong-En Fan 	int offset;
7224a1a9510SRong-En Fan 	const char *path;
72373f0a83dSXin LI 	char **eargv = allocArgv((size_t) 2);
72473f0a83dSXin LI 	size_t count = 0;
7254a1a9510SRong-En Fan 
72673f0a83dSXin LI 	if (eargv == 0)
72773f0a83dSXin LI 	    failed("eargv");
7284a1a9510SRong-En Fan 	_nc_first_db(&state, &offset);
72973f0a83dSXin LI 	if ((path = _nc_next_db(&state, &offset)) != 0) {
730*aae38d10SBaptiste Daroussin 	    if (!quick_prefix(path))
73173f0a83dSXin LI 		eargv[count++] = strmalloc(path);
7324a1a9510SRong-En Fan 	}
7334a1a9510SRong-En Fan 
73473f0a83dSXin LI 	code = typelist((int) count, eargv, header, hook);
7354a1a9510SRong-En Fan 
73673f0a83dSXin LI 	freeArgv(eargv);
7374a1a9510SRong-En Fan     }
7384a1a9510SRong-En Fan     _nc_last_db();
7390e3d5408SPeter Wemm 
7400e3d5408SPeter Wemm     ExitProgram(code);
7410e3d5408SPeter Wemm }
742