xref: /freebsd/contrib/ncurses/progs/toe.c (revision 21817992b3314c908ab50f0bb88d2ee750b9c4ac)
10e3d5408SPeter Wemm /****************************************************************************
2*21817992SBaptiste Daroussin  * Copyright 2018-2022,2023 Thomas E. Dickey                                *
3e1865124SBaptiste Daroussin  * Copyright 1998-2013,2017 Free Software Foundation, Inc.                  *
40e3d5408SPeter Wemm  *                                                                          *
50e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
60e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
70e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
80e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
90e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
100e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
110e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
120e3d5408SPeter Wemm  *                                                                          *
130e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
140e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
150e3d5408SPeter Wemm  *                                                                          *
160e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
170e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
180e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
190e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
200e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
210e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
220e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
230e3d5408SPeter Wemm  *                                                                          *
240e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
250e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
260e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
270e3d5408SPeter Wemm  * authorization.                                                           *
280e3d5408SPeter Wemm  ****************************************************************************/
290e3d5408SPeter Wemm 
300e3d5408SPeter Wemm /****************************************************************************
310e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
320e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
334a1a9510SRong-En Fan  *     and: Thomas E. Dickey                        1996-on                 *
340e3d5408SPeter Wemm  ****************************************************************************/
350e3d5408SPeter Wemm 
360e3d5408SPeter Wemm /*
370e3d5408SPeter Wemm  *	toe.c --- table of entries report generator
380e3d5408SPeter Wemm  */
390e3d5408SPeter Wemm 
400e3d5408SPeter Wemm #include <progs.priv.h>
410e3d5408SPeter Wemm 
420e3d5408SPeter Wemm #include <sys/stat.h>
430e3d5408SPeter Wemm 
444a1a9510SRong-En Fan #if USE_HASHED_DB
454a1a9510SRong-En Fan #include <hashed_db.h>
464a1a9510SRong-En Fan #endif
474a1a9510SRong-En Fan 
48*21817992SBaptiste Daroussin MODULE_ID("$Id: toe.c,v 1.89 2023/07/01 17:04:46 tom Exp $")
4915589c42SPeter Wemm 
5015589c42SPeter Wemm #define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
510e3d5408SPeter Wemm 
5273f0a83dSXin LI typedef struct {
5373f0a83dSXin LI     int db_index;
5473f0a83dSXin LI     unsigned long checksum;
5573f0a83dSXin LI     char *term_name;
5673f0a83dSXin LI     char *description;
5773f0a83dSXin LI } TERMDATA;
5873f0a83dSXin LI 
590e3d5408SPeter Wemm const char *_nc_progname;
600e3d5408SPeter Wemm 
6173f0a83dSXin LI static TERMDATA *ptr_termdata;	/* array of terminal data */
6273f0a83dSXin LI static size_t use_termdata;	/* actual usage in ptr_termdata[] */
6373f0a83dSXin LI static size_t len_termdata;	/* allocated size of ptr_termdata[] */
6473f0a83dSXin LI 
650e3d5408SPeter Wemm #if NO_LEAKS
660e3d5408SPeter Wemm #undef ExitProgram
67*21817992SBaptiste Daroussin static GCC_NORETURN void ExitProgram(int code);
6815589c42SPeter Wemm static void
ExitProgram(int code)694a1a9510SRong-En Fan ExitProgram(int code)
700e3d5408SPeter Wemm {
710e3d5408SPeter Wemm     _nc_free_entries(_nc_head);
725ca44d1cSRong-En Fan     _nc_free_tic(code);
730e3d5408SPeter Wemm }
740e3d5408SPeter Wemm #endif
750e3d5408SPeter Wemm 
76*21817992SBaptiste Daroussin static GCC_NORETURN void failed(const char *);
7773f0a83dSXin LI 
7806bfebdeSXin LI static void
failed(const char * msg)7906bfebdeSXin LI failed(const char *msg)
8006bfebdeSXin LI {
8106bfebdeSXin LI     perror(msg);
8206bfebdeSXin LI     ExitProgram(EXIT_FAILURE);
8306bfebdeSXin LI }
8406bfebdeSXin LI 
8573f0a83dSXin LI static char *
strmalloc(const char * value)8673f0a83dSXin LI strmalloc(const char *value)
8773f0a83dSXin LI {
8873f0a83dSXin LI     char *result = strdup(value);
8973f0a83dSXin LI     if (result == 0) {
9073f0a83dSXin LI 	failed("strmalloc");
9173f0a83dSXin LI     }
9273f0a83dSXin LI     return result;
9373f0a83dSXin LI }
9473f0a83dSXin LI 
9573f0a83dSXin LI static TERMDATA *
new_termdata(void)9673f0a83dSXin LI new_termdata(void)
9773f0a83dSXin LI {
9873f0a83dSXin LI     size_t want = use_termdata + 1;
9973f0a83dSXin LI 
10073f0a83dSXin LI     if (want >= len_termdata) {
10173f0a83dSXin LI 	len_termdata = (2 * want) + 10;
10273f0a83dSXin LI 	ptr_termdata = typeRealloc(TERMDATA, len_termdata, ptr_termdata);
10373f0a83dSXin LI 	if (ptr_termdata == 0)
10473f0a83dSXin LI 	    failed("ptr_termdata");
10573f0a83dSXin LI     }
10673f0a83dSXin LI 
10773f0a83dSXin LI     return ptr_termdata + use_termdata++;
10873f0a83dSXin LI }
10973f0a83dSXin LI 
11073f0a83dSXin LI static int
compare_termdata(const void * a,const void * b)11173f0a83dSXin LI compare_termdata(const void *a, const void *b)
11273f0a83dSXin LI {
11373f0a83dSXin LI     const TERMDATA *p = (const TERMDATA *) a;
11473f0a83dSXin LI     const TERMDATA *q = (const TERMDATA *) b;
11573f0a83dSXin LI     int result = strcmp(p->term_name, q->term_name);
11673f0a83dSXin LI 
11773f0a83dSXin LI     if (result == 0) {
11873f0a83dSXin LI 	result = (p->db_index - q->db_index);
11973f0a83dSXin LI     }
12073f0a83dSXin LI     return result;
12173f0a83dSXin LI }
12273f0a83dSXin LI 
12373f0a83dSXin LI /*
12473f0a83dSXin LI  * Sort the array of TERMDATA and print it.  If more than one database is being
12573f0a83dSXin LI  * reported, add a column to show which database has a given entry.
12673f0a83dSXin LI  */
12773f0a83dSXin LI static void
show_termdata(int eargc,char ** eargv)12873f0a83dSXin LI show_termdata(int eargc, char **eargv)
12973f0a83dSXin LI {
130*21817992SBaptiste Daroussin     if (use_termdata) {
13173f0a83dSXin LI 	size_t n;
13273f0a83dSXin LI 
13373f0a83dSXin LI 	if (eargc > 1) {
134*21817992SBaptiste Daroussin 	    int j;
135*21817992SBaptiste Daroussin 
13673f0a83dSXin LI 	    for (j = 0; j < eargc; ++j) {
137*21817992SBaptiste Daroussin 		int k;
138*21817992SBaptiste Daroussin 
13973f0a83dSXin LI 		for (k = 0; k <= j; ++k) {
14073f0a83dSXin LI 		    printf("--");
14173f0a83dSXin LI 		}
14273f0a83dSXin LI 		printf("> ");
14373f0a83dSXin LI 		printf("%s\n", eargv[j]);
14473f0a83dSXin LI 	    }
14573f0a83dSXin LI 	}
14673f0a83dSXin LI 	if (use_termdata > 1)
14773f0a83dSXin LI 	    qsort(ptr_termdata, use_termdata, sizeof(TERMDATA), compare_termdata);
14873f0a83dSXin LI 	for (n = 0; n < use_termdata; ++n) {
149*21817992SBaptiste Daroussin 	    int nk = -1;
15073f0a83dSXin LI 
15173f0a83dSXin LI 	    /*
15273f0a83dSXin LI 	     * If there is more than one database, show how they differ.
15373f0a83dSXin LI 	     */
15473f0a83dSXin LI 	    if (eargc > 1) {
15573f0a83dSXin LI 		unsigned long check = 0;
156*21817992SBaptiste Daroussin 		int k = 0;
15773f0a83dSXin LI 		for (;;) {
158*21817992SBaptiste Daroussin 		    char mark = ((check == 0
159*21817992SBaptiste Daroussin 				  || (check != ptr_termdata[n].checksum))
160*21817992SBaptiste Daroussin 				 ? '*'
161*21817992SBaptiste Daroussin 				 : '+');
162*21817992SBaptiste Daroussin 
16373f0a83dSXin LI 		    for (; k < ptr_termdata[n].db_index; ++k) {
16473f0a83dSXin LI 			printf("--");
16573f0a83dSXin LI 		    }
16673f0a83dSXin LI 
16773f0a83dSXin LI 		    /*
16873f0a83dSXin LI 		     * If this is the first entry, or its checksum differs
16973f0a83dSXin LI 		     * from the first entry's checksum, print "*". Otherwise
17073f0a83dSXin LI 		     * it looks enough like a duplicate to print "+".
17173f0a83dSXin LI 		     */
172*21817992SBaptiste Daroussin 		    printf("%c-", mark);
17373f0a83dSXin LI 		    check = ptr_termdata[n].checksum;
174*21817992SBaptiste Daroussin 		    if (mark == '*' && nk < 0)
175*21817992SBaptiste Daroussin 			nk = (int) n;
17673f0a83dSXin LI 
17773f0a83dSXin LI 		    ++k;
17873f0a83dSXin LI 		    if ((n + 1) >= use_termdata
17973f0a83dSXin LI 			|| strcmp(ptr_termdata[n].term_name,
18073f0a83dSXin LI 				  ptr_termdata[n + 1].term_name)) {
18173f0a83dSXin LI 			break;
18273f0a83dSXin LI 		    }
18373f0a83dSXin LI 		    ++n;
18473f0a83dSXin LI 		}
18573f0a83dSXin LI 		for (; k < eargc; ++k) {
18673f0a83dSXin LI 		    printf("--");
18773f0a83dSXin LI 		}
18873f0a83dSXin LI 		printf(":\t");
18973f0a83dSXin LI 	    }
190*21817992SBaptiste Daroussin 	    if (nk < 0)
191*21817992SBaptiste Daroussin 		nk = (int) n;
19273f0a83dSXin LI 
19373f0a83dSXin LI 	    (void) printf("%-10s\t%s\n",
19473f0a83dSXin LI 			  ptr_termdata[n].term_name,
195*21817992SBaptiste Daroussin 			  ptr_termdata[nk].description);
19673f0a83dSXin LI 	}
19773f0a83dSXin LI     }
19873f0a83dSXin LI }
19973f0a83dSXin LI 
20073f0a83dSXin LI static void
free_termdata(void)20173f0a83dSXin LI free_termdata(void)
20273f0a83dSXin LI {
20373f0a83dSXin LI     if (ptr_termdata != 0) {
20473f0a83dSXin LI 	while (use_termdata != 0) {
20573f0a83dSXin LI 	    --use_termdata;
20673f0a83dSXin LI 	    free(ptr_termdata[use_termdata].term_name);
20773f0a83dSXin LI 	    free(ptr_termdata[use_termdata].description);
20873f0a83dSXin LI 	}
20973f0a83dSXin LI 	free(ptr_termdata);
21073f0a83dSXin LI 	ptr_termdata = 0;
21173f0a83dSXin LI     }
21273f0a83dSXin LI     use_termdata = 0;
21373f0a83dSXin LI     len_termdata = 0;
21473f0a83dSXin LI }
21573f0a83dSXin LI 
21673f0a83dSXin LI static char **
allocArgv(size_t count)21773f0a83dSXin LI allocArgv(size_t count)
21873f0a83dSXin LI {
21973f0a83dSXin LI     char **result = typeCalloc(char *, count + 1);
22073f0a83dSXin LI     if (result == 0)
22173f0a83dSXin LI 	failed("realloc eargv");
22273f0a83dSXin LI 
22373f0a83dSXin LI     assert(result != 0);
22473f0a83dSXin LI     return result;
22573f0a83dSXin LI }
22673f0a83dSXin LI 
22773f0a83dSXin LI static void
freeArgv(char ** argv)22873f0a83dSXin LI freeArgv(char **argv)
22973f0a83dSXin LI {
23073f0a83dSXin LI     if (argv) {
23173f0a83dSXin LI 	int count = 0;
23273f0a83dSXin LI 	while (argv[count]) {
23373f0a83dSXin LI 	    free(argv[count++]);
23473f0a83dSXin LI 	}
23573f0a83dSXin LI 	free(argv);
23673f0a83dSXin LI     }
23773f0a83dSXin LI }
23873f0a83dSXin LI 
2394a1a9510SRong-En Fan #if USE_HASHED_DB
24039f2269fSPeter Wemm static bool
make_db_name(char * dst,const char * src,unsigned limit)2414a1a9510SRong-En Fan make_db_name(char *dst, const char *src, unsigned limit)
24239f2269fSPeter Wemm {
2434a1a9510SRong-En Fan     static const char suffix[] = DBM_SUFFIX;
2444a1a9510SRong-En Fan 
2454a1a9510SRong-En Fan     bool result = FALSE;
24673f0a83dSXin LI     size_t lens = sizeof(suffix) - 1;
24773f0a83dSXin LI     size_t size = strlen(src);
24873f0a83dSXin LI     size_t need = lens + size;
2494a1a9510SRong-En Fan 
2504a1a9510SRong-En Fan     if (need <= limit) {
2514a1a9510SRong-En Fan 	if (size >= lens
25273f0a83dSXin LI 	    && !strcmp(src + size - lens, suffix)) {
25373f0a83dSXin LI 	    _nc_STRCPY(dst, src, PATH_MAX);
25473f0a83dSXin LI 	} else {
255*21817992SBaptiste Daroussin 	    _nc_SPRINTF(dst, _nc_SLIMIT(PATH_MAX) "%.*s%s",
256*21817992SBaptiste Daroussin 			(int) (PATH_MAX - sizeof(suffix)),
257*21817992SBaptiste Daroussin 			src, suffix);
25873f0a83dSXin LI 	}
2594a1a9510SRong-En Fan 	result = TRUE;
26039f2269fSPeter Wemm     }
2614a1a9510SRong-En Fan     return result;
2624a1a9510SRong-En Fan }
2634a1a9510SRong-En Fan #endif
26439f2269fSPeter Wemm 
26573f0a83dSXin LI typedef void (DescHook) (int /* db_index */ ,
26673f0a83dSXin LI 			 int /* db_limit */ ,
26773f0a83dSXin LI 			 const char * /* term_name */ ,
268aae38d10SBaptiste Daroussin 			 TERMTYPE2 * /* term */ );
26939f2269fSPeter Wemm 
27073f0a83dSXin LI static const char *
term_description(TERMTYPE2 * tp)271aae38d10SBaptiste Daroussin term_description(TERMTYPE2 *tp)
27215589c42SPeter Wemm {
2734a1a9510SRong-En Fan     const char *desc;
2744a1a9510SRong-En Fan 
27573f0a83dSXin LI     if (tp->term_names == 0
27673f0a83dSXin LI 	|| (desc = strrchr(tp->term_names, '|')) == 0
27773f0a83dSXin LI 	|| (*++desc == '\0')) {
2784a1a9510SRong-En Fan 	desc = "(No description)";
27915589c42SPeter Wemm     }
2804a1a9510SRong-En Fan 
28173f0a83dSXin LI     return desc;
28273f0a83dSXin LI }
28373f0a83dSXin LI 
28473f0a83dSXin LI /* display a description for the type */
2854a1a9510SRong-En Fan static void
deschook(int db_index,int db_limit,const char * term_name,TERMTYPE2 * tp)286aae38d10SBaptiste Daroussin deschook(int db_index, int db_limit, const char *term_name, TERMTYPE2 *tp)
28773f0a83dSXin LI {
28873f0a83dSXin LI     (void) db_index;
28973f0a83dSXin LI     (void) db_limit;
29073f0a83dSXin LI     (void) printf("%-10s\t%s\n", term_name, term_description(tp));
29173f0a83dSXin LI }
29273f0a83dSXin LI 
29373f0a83dSXin LI static unsigned long
string_sum(const char * value)29473f0a83dSXin LI string_sum(const char *value)
29573f0a83dSXin LI {
29673f0a83dSXin LI     unsigned long result = 0;
29773f0a83dSXin LI 
29873f0a83dSXin LI     if ((intptr_t) value == (intptr_t) (-1)) {
29973f0a83dSXin LI 	result = ~result;
30073f0a83dSXin LI     } else if (value) {
30173f0a83dSXin LI 	while (*value) {
30273f0a83dSXin LI 	    result += UChar(*value);
30373f0a83dSXin LI 	    ++value;
30473f0a83dSXin LI 	}
30573f0a83dSXin LI     }
30673f0a83dSXin LI     return result;
30773f0a83dSXin LI }
30873f0a83dSXin LI 
30973f0a83dSXin LI static unsigned long
checksum_of(TERMTYPE2 * tp)310aae38d10SBaptiste Daroussin checksum_of(TERMTYPE2 *tp)
31173f0a83dSXin LI {
31273f0a83dSXin LI     unsigned long result = string_sum(tp->term_names);
31373f0a83dSXin LI     unsigned i;
31473f0a83dSXin LI 
31573f0a83dSXin LI     for (i = 0; i < NUM_BOOLEANS(tp); i++) {
31673f0a83dSXin LI 	result += (unsigned long) (tp->Booleans[i]);
31773f0a83dSXin LI     }
31873f0a83dSXin LI     for (i = 0; i < NUM_NUMBERS(tp); i++) {
31973f0a83dSXin LI 	result += (unsigned long) (tp->Numbers[i]);
32073f0a83dSXin LI     }
32173f0a83dSXin LI     for (i = 0; i < NUM_STRINGS(tp); i++) {
32273f0a83dSXin LI 	result += string_sum(tp->Strings[i]);
32373f0a83dSXin LI     }
32473f0a83dSXin LI     return result;
32573f0a83dSXin LI }
32673f0a83dSXin LI 
32773f0a83dSXin LI /* collect data, to sort before display */
32873f0a83dSXin LI static void
sorthook(int db_index,int db_limit,const char * term_name,TERMTYPE2 * tp)329aae38d10SBaptiste Daroussin sorthook(int db_index, int db_limit, const char *term_name, TERMTYPE2 *tp)
33073f0a83dSXin LI {
33173f0a83dSXin LI     TERMDATA *data = new_termdata();
33273f0a83dSXin LI 
33373f0a83dSXin LI     data->db_index = db_index;
33473f0a83dSXin LI     data->checksum = ((db_limit > 1) ? checksum_of(tp) : 0);
33573f0a83dSXin LI     data->term_name = strmalloc(term_name);
33673f0a83dSXin LI     data->description = strmalloc(term_description(tp));
33773f0a83dSXin LI }
33873f0a83dSXin LI 
33973f0a83dSXin LI #if NCURSES_USE_TERMCAP
340*21817992SBaptiste Daroussin /*
341*21817992SBaptiste Daroussin  * Check if the buffer contents are printable ASCII, ensuring that we do not
342*21817992SBaptiste Daroussin  * accidentally pick up incompatible binary content from a hashed database.
343*21817992SBaptiste Daroussin  */
344*21817992SBaptiste Daroussin static bool
is_termcap(char * buffer)345*21817992SBaptiste Daroussin is_termcap(char *buffer)
346*21817992SBaptiste Daroussin {
347*21817992SBaptiste Daroussin     bool result = TRUE;
348*21817992SBaptiste Daroussin     while (*buffer != '\0') {
349*21817992SBaptiste Daroussin 	int ch = UChar(*buffer++);
350*21817992SBaptiste Daroussin 	if (ch == '\t')
351*21817992SBaptiste Daroussin 	    continue;
352*21817992SBaptiste Daroussin 	if (ch < ' ' || ch > '~') {
353*21817992SBaptiste Daroussin 	    result = FALSE;
354*21817992SBaptiste Daroussin 	    break;
355*21817992SBaptiste Daroussin 	}
356*21817992SBaptiste Daroussin     }
357*21817992SBaptiste Daroussin     return result;
358*21817992SBaptiste Daroussin }
359*21817992SBaptiste Daroussin 
36073f0a83dSXin LI static void
show_termcap(int db_index,int db_limit,char * buffer,DescHook hook)36173f0a83dSXin LI show_termcap(int db_index, int db_limit, char *buffer, DescHook hook)
3624a1a9510SRong-En Fan {
363aae38d10SBaptiste Daroussin     TERMTYPE2 data;
3644a1a9510SRong-En Fan     char *next = strchr(buffer, ':');
3654a1a9510SRong-En Fan     char *last;
3664a1a9510SRong-En Fan     char *list = buffer;
3674a1a9510SRong-En Fan 
3684a1a9510SRong-En Fan     if (next)
3694a1a9510SRong-En Fan 	*next = '\0';
3704a1a9510SRong-En Fan 
3714a1a9510SRong-En Fan     last = strrchr(buffer, '|');
3724a1a9510SRong-En Fan     if (last)
3734a1a9510SRong-En Fan 	++last;
3744a1a9510SRong-En Fan 
37573f0a83dSXin LI     memset(&data, 0, sizeof(data));
37673f0a83dSXin LI     data.term_names = strmalloc(buffer);
3774a1a9510SRong-En Fan     while ((next = strtok(list, "|")) != 0) {
3784a1a9510SRong-En Fan 	if (next != last)
37973f0a83dSXin LI 	    hook(db_index, db_limit, next, &data);
3804a1a9510SRong-En Fan 	list = 0;
3814a1a9510SRong-En Fan     }
3824a1a9510SRong-En Fan     free(data.term_names);
3834a1a9510SRong-En Fan }
3844a1a9510SRong-En Fan #endif
3854a1a9510SRong-En Fan 
38673f0a83dSXin LI #if NCURSES_USE_DATABASE
38773f0a83dSXin LI static char *
copy_entryname(DIRENT * src)38873f0a83dSXin LI copy_entryname(DIRENT * src)
38973f0a83dSXin LI {
39073f0a83dSXin LI     size_t len = NAMLEN(src);
39173f0a83dSXin LI     char *result = malloc(len + 1);
39273f0a83dSXin LI     if (result == 0)
39373f0a83dSXin LI 	failed("copy entryname");
39473f0a83dSXin LI     memcpy(result, src->d_name, len);
39573f0a83dSXin LI     result[len] = '\0';
39673f0a83dSXin LI 
39773f0a83dSXin LI     return result;
39873f0a83dSXin LI }
39973f0a83dSXin LI #endif
40073f0a83dSXin LI 
4014a1a9510SRong-En Fan static int
typelist(int eargc,char * eargv[],int verbosity,DescHook hook)4024a1a9510SRong-En Fan typelist(int eargc, char *eargv[],
40373f0a83dSXin LI 	 int verbosity,
40473f0a83dSXin LI 	 DescHook hook)
4054a1a9510SRong-En Fan /* apply a function to each entry in given terminfo directories */
4064a1a9510SRong-En Fan {
4074a1a9510SRong-En Fan     int i;
4084a1a9510SRong-En Fan 
4094a1a9510SRong-En Fan     for (i = 0; i < eargc; i++) {
41073f0a83dSXin LI #if NCURSES_USE_DATABASE
4114a1a9510SRong-En Fan 	if (_nc_is_dir_path(eargv[i])) {
4125d08fb1fSRong-En Fan 	    char *cwd_buf = 0;
4134a1a9510SRong-En Fan 	    DIR *termdir;
4144a1a9510SRong-En Fan 	    DIRENT *subdir;
4154a1a9510SRong-En Fan 
4164a1a9510SRong-En Fan 	    if ((termdir = opendir(eargv[i])) == 0) {
4174a1a9510SRong-En Fan 		(void) fflush(stdout);
4184a1a9510SRong-En Fan 		(void) fprintf(stderr,
4194a1a9510SRong-En Fan 			       "%s: can't open terminfo directory %s\n",
4204a1a9510SRong-En Fan 			       _nc_progname, eargv[i]);
42173f0a83dSXin LI 		continue;
42273f0a83dSXin LI 	    }
42373f0a83dSXin LI 
42473f0a83dSXin LI 	    if (verbosity)
4254a1a9510SRong-En Fan 		(void) printf("#\n#%s:\n#\n", eargv[i]);
4264a1a9510SRong-En Fan 
4274a1a9510SRong-En Fan 	    while ((subdir = readdir(termdir)) != 0) {
42873f0a83dSXin LI 		size_t cwd_len;
42973f0a83dSXin LI 		char *name_1;
4304a1a9510SRong-En Fan 		DIR *entrydir;
4314a1a9510SRong-En Fan 		DIRENT *entry;
4324a1a9510SRong-En Fan 
43373f0a83dSXin LI 		name_1 = copy_entryname(subdir);
43473f0a83dSXin LI 		if (isDotname(name_1)) {
43573f0a83dSXin LI 		    free(name_1);
43673f0a83dSXin LI 		    continue;
43773f0a83dSXin LI 		}
43873f0a83dSXin LI 
43973f0a83dSXin LI 		cwd_len = NAMLEN(subdir) + strlen(eargv[i]) + 3;
4405d08fb1fSRong-En Fan 		cwd_buf = typeRealloc(char, cwd_len, cwd_buf);
44106bfebdeSXin LI 		if (cwd_buf == 0)
44206bfebdeSXin LI 		    failed("realloc cwd_buf");
44306bfebdeSXin LI 
44406bfebdeSXin LI 		assert(cwd_buf != 0);
4455d08fb1fSRong-En Fan 
44673f0a83dSXin LI 		_nc_SPRINTF(cwd_buf, _nc_SLIMIT(cwd_len)
44773f0a83dSXin LI 			    "%s/%s/", eargv[i], name_1);
44873f0a83dSXin LI 		free(name_1);
4494a1a9510SRong-En Fan 
4505d08fb1fSRong-En Fan 		if (chdir(cwd_buf) != 0)
4514a1a9510SRong-En Fan 		    continue;
4524a1a9510SRong-En Fan 
4534a1a9510SRong-En Fan 		entrydir = opendir(".");
4545d08fb1fSRong-En Fan 		if (entrydir == 0) {
4555d08fb1fSRong-En Fan 		    perror(cwd_buf);
4565d08fb1fSRong-En Fan 		    continue;
4575d08fb1fSRong-En Fan 		}
4584a1a9510SRong-En Fan 		while ((entry = readdir(entrydir)) != 0) {
45973f0a83dSXin LI 		    char *name_2;
460aae38d10SBaptiste Daroussin 		    TERMTYPE2 lterm;
4614a1a9510SRong-En Fan 		    char *cn;
4624a1a9510SRong-En Fan 		    int status;
4634a1a9510SRong-En Fan 
46473f0a83dSXin LI 		    name_2 = copy_entryname(entry);
46573f0a83dSXin LI 		    if (isDotname(name_2) || !_nc_is_file_path(name_2)) {
46673f0a83dSXin LI 			free(name_2);
4674a1a9510SRong-En Fan 			continue;
46873f0a83dSXin LI 		    }
4694a1a9510SRong-En Fan 
4704a1a9510SRong-En Fan 		    status = _nc_read_file_entry(name_2, &lterm);
4714a1a9510SRong-En Fan 		    if (status <= 0) {
4724a1a9510SRong-En Fan 			(void) fflush(stdout);
4734a1a9510SRong-En Fan 			(void) fprintf(stderr,
4744a1a9510SRong-En Fan 				       "%s: couldn't open terminfo file %s.\n",
4754a1a9510SRong-En Fan 				       _nc_progname, name_2);
47673f0a83dSXin LI 			free(name_2);
477aae38d10SBaptiste Daroussin 			continue;
4784a1a9510SRong-En Fan 		    }
4794a1a9510SRong-En Fan 
4804a1a9510SRong-En Fan 		    /* only visit things once, by primary name */
4814a1a9510SRong-En Fan 		    cn = _nc_first_name(lterm.term_names);
4824a1a9510SRong-En Fan 		    if (!strcmp(cn, name_2)) {
4834a1a9510SRong-En Fan 			/* apply the selected hook function */
48473f0a83dSXin LI 			hook(i, eargc, cn, &lterm);
4854a1a9510SRong-En Fan 		    }
486aae38d10SBaptiste Daroussin 		    _nc_free_termtype2(&lterm);
48773f0a83dSXin LI 		    free(name_2);
4884a1a9510SRong-En Fan 		}
4894a1a9510SRong-En Fan 		closedir(entrydir);
4904a1a9510SRong-En Fan 	    }
4914a1a9510SRong-En Fan 	    closedir(termdir);
4925d08fb1fSRong-En Fan 	    if (cwd_buf != 0)
4935d08fb1fSRong-En Fan 		free(cwd_buf);
49473f0a83dSXin LI 	    continue;
4954a1a9510SRong-En Fan 	}
4964a1a9510SRong-En Fan #if USE_HASHED_DB
4974a1a9510SRong-En Fan 	else {
4984a1a9510SRong-En Fan 	    DB *capdbp;
4994a1a9510SRong-En Fan 	    char filename[PATH_MAX];
5004a1a9510SRong-En Fan 
50173f0a83dSXin LI 	    if (verbosity)
50273f0a83dSXin LI 		(void) printf("#\n#%s:\n#\n", eargv[i]);
50373f0a83dSXin LI 
5044a1a9510SRong-En Fan 	    if (make_db_name(filename, eargv[i], sizeof(filename))) {
5054a1a9510SRong-En Fan 		if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
5064a1a9510SRong-En Fan 		    DBT key, data;
5074a1a9510SRong-En Fan 		    int code;
5084a1a9510SRong-En Fan 
5094a1a9510SRong-En Fan 		    code = _nc_db_first(capdbp, &key, &data);
5104a1a9510SRong-En Fan 		    while (code == 0) {
511aae38d10SBaptiste Daroussin 			TERMTYPE2 lterm;
5124a1a9510SRong-En Fan 			int used;
5134a1a9510SRong-En Fan 			char *have;
5144a1a9510SRong-En Fan 			char *cn;
5154a1a9510SRong-En Fan 
5164a1a9510SRong-En Fan 			if (_nc_db_have_data(&key, &data, &have, &used)) {
5174a1a9510SRong-En Fan 			    if (_nc_read_termtype(&lterm, have, used) > 0) {
5184a1a9510SRong-En Fan 				/* only visit things once, by primary name */
5194a1a9510SRong-En Fan 				cn = _nc_first_name(lterm.term_names);
5204a1a9510SRong-En Fan 				/* apply the selected hook function */
52173f0a83dSXin LI 				hook(i, eargc, cn, &lterm);
522aae38d10SBaptiste Daroussin 				_nc_free_termtype2(&lterm);
5234a1a9510SRong-En Fan 			    }
5244a1a9510SRong-En Fan 			}
5254a1a9510SRong-En Fan 			code = _nc_db_next(capdbp, &key, &data);
5264a1a9510SRong-En Fan 		    }
5274a1a9510SRong-En Fan 
5284a1a9510SRong-En Fan 		    _nc_db_close(capdbp);
52973f0a83dSXin LI 		    continue;
5304a1a9510SRong-En Fan 		}
5314a1a9510SRong-En Fan 	    }
5324a1a9510SRong-En Fan 	}
533aae38d10SBaptiste Daroussin #endif /* USE_HASHED_DB */
534aae38d10SBaptiste Daroussin #endif /* NCURSES_USE_DATABASE */
53573f0a83dSXin LI #if NCURSES_USE_TERMCAP
5364a1a9510SRong-En Fan #if HAVE_BSD_CGETENT
53773f0a83dSXin LI 	{
53873f0a83dSXin LI 	    CGETENT_CONST char *db_array[2];
5394a1a9510SRong-En Fan 	    char *buffer = 0;
5404a1a9510SRong-En Fan 
5414a1a9510SRong-En Fan 	    if (verbosity)
5424a1a9510SRong-En Fan 		(void) printf("#\n#%s:\n#\n", eargv[i]);
5434a1a9510SRong-En Fan 
5444a1a9510SRong-En Fan 	    db_array[0] = eargv[i];
5454a1a9510SRong-En Fan 	    db_array[1] = 0;
5464a1a9510SRong-En Fan 
54773f0a83dSXin LI 	    if (cgetfirst(&buffer, db_array) > 0) {
548*21817992SBaptiste Daroussin 		if (is_termcap(buffer)) {
54973f0a83dSXin LI 		    show_termcap(i, eargc, buffer, hook);
5504a1a9510SRong-En Fan 		    free(buffer);
55173f0a83dSXin LI 		    while (cgetnext(&buffer, db_array) > 0) {
55273f0a83dSXin LI 			show_termcap(i, eargc, buffer, hook);
5534a1a9510SRong-En Fan 			free(buffer);
5544a1a9510SRong-En Fan 		    }
555*21817992SBaptiste Daroussin 		}
5564a1a9510SRong-En Fan 		cgetclose();
55773f0a83dSXin LI 		continue;
55873f0a83dSXin LI 	    }
55973f0a83dSXin LI 	}
5604a1a9510SRong-En Fan #else
5614a1a9510SRong-En Fan 	/* scan termcap text-file only */
5624a1a9510SRong-En Fan 	if (_nc_is_file_path(eargv[i])) {
5634a1a9510SRong-En Fan 	    char buffer[2048];
5644a1a9510SRong-En Fan 	    FILE *fp;
5654a1a9510SRong-En Fan 
56673f0a83dSXin LI 	    if (verbosity)
56773f0a83dSXin LI 		(void) printf("#\n#%s:\n#\n", eargv[i]);
56873f0a83dSXin LI 
569*21817992SBaptiste Daroussin 	    if ((fp = safe_fopen(eargv[i], "r")) != 0) {
5704a1a9510SRong-En Fan 		while (fgets(buffer, sizeof(buffer), fp) != 0) {
571*21817992SBaptiste Daroussin 		    if (!is_termcap(buffer))
572*21817992SBaptiste Daroussin 			break;
5734a1a9510SRong-En Fan 		    if (*buffer == '#')
5744a1a9510SRong-En Fan 			continue;
575*21817992SBaptiste Daroussin 		    if (isspace(UChar(*buffer)))
5764a1a9510SRong-En Fan 			continue;
57773f0a83dSXin LI 		    show_termcap(i, eargc, buffer, hook);
5784a1a9510SRong-En Fan 		}
5794a1a9510SRong-En Fan 		fclose(fp);
5804a1a9510SRong-En Fan 	    }
5814a1a9510SRong-En Fan 	}
5824a1a9510SRong-En Fan #endif
5834a1a9510SRong-En Fan #endif
5844a1a9510SRong-En Fan     }
5854a1a9510SRong-En Fan 
58673f0a83dSXin LI     if (hook == sorthook) {
58773f0a83dSXin LI 	show_termdata(eargc, eargv);
58873f0a83dSXin LI 	free_termdata();
58973f0a83dSXin LI     }
59073f0a83dSXin LI 
5914a1a9510SRong-En Fan     return (EXIT_SUCCESS);
5924a1a9510SRong-En Fan }
5934a1a9510SRong-En Fan 
5944a1a9510SRong-En Fan static void
usage(void)5954a1a9510SRong-En Fan usage(void)
5964a1a9510SRong-En Fan {
59773f0a83dSXin LI     (void) fprintf(stderr, "usage: %s [-ahsuUV] [-v n] [file...]\n", _nc_progname);
5984a1a9510SRong-En Fan     ExitProgram(EXIT_FAILURE);
59915589c42SPeter Wemm }
60015589c42SPeter Wemm 
60115589c42SPeter Wemm int
main(int argc,char * argv[])60215589c42SPeter Wemm main(int argc, char *argv[])
6030e3d5408SPeter Wemm {
6044a1a9510SRong-En Fan     bool all_dirs = FALSE;
6050e3d5408SPeter Wemm     bool direct_dependencies = FALSE;
6060e3d5408SPeter Wemm     bool invert_dependencies = FALSE;
6070e3d5408SPeter Wemm     bool header = FALSE;
608d8977eafSRong-En Fan     char *report_file = 0;
6090e3d5408SPeter Wemm     int code;
6104a1a9510SRong-En Fan     int this_opt, last_opt = '?';
61173f0a83dSXin LI     unsigned v_opt = 0;
61273f0a83dSXin LI     DescHook *hook = deschook;
6130e3d5408SPeter Wemm 
61439f2269fSPeter Wemm     _nc_progname = _nc_rootname(argv[0]);
6150e3d5408SPeter Wemm 
61673f0a83dSXin LI     while ((this_opt = getopt(argc, argv, "0123456789ahsu:vU:V")) != -1) {
6174a1a9510SRong-En Fan 	/* handle optional parameter */
6184a1a9510SRong-En Fan 	if (isdigit(this_opt)) {
6194a1a9510SRong-En Fan 	    switch (last_opt) {
6204a1a9510SRong-En Fan 	    case 'v':
62173f0a83dSXin LI 		v_opt = (unsigned) (this_opt - '0');
6224a1a9510SRong-En Fan 		break;
6234a1a9510SRong-En Fan 	    default:
6244a1a9510SRong-En Fan 		if (isdigit(last_opt))
6254a1a9510SRong-En Fan 		    v_opt *= 10;
6264a1a9510SRong-En Fan 		else
6274a1a9510SRong-En Fan 		    v_opt = 0;
62873f0a83dSXin LI 		v_opt += (unsigned) (this_opt - '0');
6294a1a9510SRong-En Fan 		last_opt = this_opt;
6304a1a9510SRong-En Fan 	    }
6314a1a9510SRong-En Fan 	    continue;
6324a1a9510SRong-En Fan 	}
6334a1a9510SRong-En Fan 	switch (this_opt) {
6344a1a9510SRong-En Fan 	case 'a':
6354a1a9510SRong-En Fan 	    all_dirs = TRUE;
6364a1a9510SRong-En Fan 	    break;
6370e3d5408SPeter Wemm 	case 'h':
6380e3d5408SPeter Wemm 	    header = TRUE;
6390e3d5408SPeter Wemm 	    break;
64073f0a83dSXin LI 	case 's':
64173f0a83dSXin LI 	    hook = sorthook;
64273f0a83dSXin LI 	    break;
6430e3d5408SPeter Wemm 	case 'u':
6440e3d5408SPeter Wemm 	    direct_dependencies = TRUE;
645d8977eafSRong-En Fan 	    report_file = optarg;
6460e3d5408SPeter Wemm 	    break;
6470e3d5408SPeter Wemm 	case 'v':
6484a1a9510SRong-En Fan 	    v_opt = 1;
6490e3d5408SPeter Wemm 	    break;
6500e3d5408SPeter Wemm 	case 'U':
6510e3d5408SPeter Wemm 	    invert_dependencies = TRUE;
652d8977eafSRong-En Fan 	    report_file = optarg;
6530e3d5408SPeter Wemm 	    break;
6540e3d5408SPeter Wemm 	case 'V':
65518259542SPeter Wemm 	    puts(curses_version());
6560e3d5408SPeter Wemm 	    ExitProgram(EXIT_SUCCESS);
6570e3d5408SPeter Wemm 	default:
6584a1a9510SRong-En Fan 	    usage();
6590e3d5408SPeter Wemm 	}
6604a1a9510SRong-En Fan     }
661*21817992SBaptiste Daroussin     use_verbosity(v_opt);
6620e3d5408SPeter Wemm 
663d8977eafSRong-En Fan     if (report_file != 0) {
664d8977eafSRong-En Fan 	if (freopen(report_file, "r", stdin) == 0) {
6650e3d5408SPeter Wemm 	    (void) fflush(stdout);
666d8977eafSRong-En Fan 	    fprintf(stderr, "%s: can't open %s\n", _nc_progname, report_file);
6670e3d5408SPeter Wemm 	    ExitProgram(EXIT_FAILURE);
6680e3d5408SPeter Wemm 	}
6690e3d5408SPeter Wemm 
6700e3d5408SPeter Wemm 	/* parse entries out of the source file */
671d8977eafSRong-En Fan 	_nc_set_source(report_file);
67215589c42SPeter Wemm 	_nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
6730e3d5408SPeter Wemm     }
6740e3d5408SPeter Wemm 
6750e3d5408SPeter Wemm     /* maybe we want a direct-dependency listing? */
67615589c42SPeter Wemm     if (direct_dependencies) {
6770e3d5408SPeter Wemm 	ENTRY *qp;
6780e3d5408SPeter Wemm 
6794a1a9510SRong-En Fan 	for_entry_list(qp) {
68015589c42SPeter Wemm 	    if (qp->nuses) {
6815d08fb1fSRong-En Fan 		unsigned j;
6820e3d5408SPeter Wemm 
6830e3d5408SPeter Wemm 		(void) printf("%s:", _nc_first_name(qp->tterm.term_names));
6840e3d5408SPeter Wemm 		for (j = 0; j < qp->nuses; j++)
68515589c42SPeter Wemm 		    (void) printf(" %s", qp->uses[j].name);
6860e3d5408SPeter Wemm 		putchar('\n');
6870e3d5408SPeter Wemm 	    }
6884a1a9510SRong-En Fan 	}
6890e3d5408SPeter Wemm 
6900e3d5408SPeter Wemm 	ExitProgram(EXIT_SUCCESS);
6910e3d5408SPeter Wemm     }
6920e3d5408SPeter Wemm 
6930e3d5408SPeter Wemm     /* maybe we want a reverse-dependency listing? */
69415589c42SPeter Wemm     if (invert_dependencies) {
6950e3d5408SPeter Wemm 	ENTRY *qp, *rp;
6960e3d5408SPeter Wemm 
69715589c42SPeter Wemm 	for_entry_list(qp) {
698*21817992SBaptiste Daroussin 	    int matchcount = 0;
699*21817992SBaptiste Daroussin 
70015589c42SPeter Wemm 	    for_entry_list(rp) {
701*21817992SBaptiste Daroussin 		unsigned i;
702*21817992SBaptiste Daroussin 
7030e3d5408SPeter Wemm 		if (rp->nuses == 0)
7040e3d5408SPeter Wemm 		    continue;
7050e3d5408SPeter Wemm 
7060e3d5408SPeter Wemm 		for (i = 0; i < rp->nuses; i++)
70715589c42SPeter Wemm 		    if (_nc_name_match(qp->tterm.term_names,
70815589c42SPeter Wemm 				       rp->uses[i].name, "|")) {
7090e3d5408SPeter Wemm 			if (matchcount++ == 0)
7100e3d5408SPeter Wemm 			    (void) printf("%s:",
7110e3d5408SPeter Wemm 					  _nc_first_name(qp->tterm.term_names));
7120e3d5408SPeter Wemm 			(void) printf(" %s",
7130e3d5408SPeter Wemm 				      _nc_first_name(rp->tterm.term_names));
7140e3d5408SPeter Wemm 		    }
7150e3d5408SPeter Wemm 	    }
7160e3d5408SPeter Wemm 	    if (matchcount)
7170e3d5408SPeter Wemm 		putchar('\n');
7180e3d5408SPeter Wemm 	}
7190e3d5408SPeter Wemm 
7200e3d5408SPeter Wemm 	ExitProgram(EXIT_SUCCESS);
7210e3d5408SPeter Wemm     }
7220e3d5408SPeter Wemm 
7230e3d5408SPeter Wemm     /*
7240e3d5408SPeter Wemm      * If we get this far, user wants a simple terminal type listing.
7250e3d5408SPeter Wemm      */
7260e3d5408SPeter Wemm     if (optind < argc) {
72773f0a83dSXin LI 	code = typelist(argc - optind, argv + optind, header, hook);
7284a1a9510SRong-En Fan     } else if (all_dirs) {
7294a1a9510SRong-En Fan 	DBDIRS state;
7304a1a9510SRong-En Fan 	int offset;
7314a1a9510SRong-En Fan 	int pass;
7324a1a9510SRong-En Fan 	char **eargv = 0;
7330e3d5408SPeter Wemm 
7344a1a9510SRong-En Fan 	code = EXIT_FAILURE;
7354a1a9510SRong-En Fan 	for (pass = 0; pass < 2; ++pass) {
73673f0a83dSXin LI 	    size_t count = 0;
737*21817992SBaptiste Daroussin 	    const char *path;
7380e3d5408SPeter Wemm 
7394a1a9510SRong-En Fan 	    _nc_first_db(&state, &offset);
7404a1a9510SRong-En Fan 	    while ((path = _nc_next_db(&state, &offset)) != 0) {
741aae38d10SBaptiste Daroussin 		if (quick_prefix(path))
742aae38d10SBaptiste Daroussin 		    continue;
74373f0a83dSXin LI 		if (pass) {
74473f0a83dSXin LI 		    eargv[count] = strmalloc(path);
7450e3d5408SPeter Wemm 		}
7464a1a9510SRong-En Fan 		++count;
7474a1a9510SRong-En Fan 	    }
7484a1a9510SRong-En Fan 	    if (!pass) {
74973f0a83dSXin LI 		eargv = allocArgv(count);
75006bfebdeSXin LI 		if (eargv == 0)
75173f0a83dSXin LI 		    failed("eargv");
7524a1a9510SRong-En Fan 	    } else {
75373f0a83dSXin LI 		code = typelist((int) count, eargv, header, hook);
75473f0a83dSXin LI 		freeArgv(eargv);
7554a1a9510SRong-En Fan 	    }
7564a1a9510SRong-En Fan 	}
7574a1a9510SRong-En Fan     } else {
7584a1a9510SRong-En Fan 	DBDIRS state;
7594a1a9510SRong-En Fan 	int offset;
7604a1a9510SRong-En Fan 	const char *path;
76173f0a83dSXin LI 	char **eargv = allocArgv((size_t) 2);
76273f0a83dSXin LI 	size_t count = 0;
7634a1a9510SRong-En Fan 
76473f0a83dSXin LI 	if (eargv == 0)
76573f0a83dSXin LI 	    failed("eargv");
7664a1a9510SRong-En Fan 	_nc_first_db(&state, &offset);
76773f0a83dSXin LI 	if ((path = _nc_next_db(&state, &offset)) != 0) {
768aae38d10SBaptiste Daroussin 	    if (!quick_prefix(path))
76973f0a83dSXin LI 		eargv[count++] = strmalloc(path);
7704a1a9510SRong-En Fan 	}
7714a1a9510SRong-En Fan 
77273f0a83dSXin LI 	code = typelist((int) count, eargv, header, hook);
7734a1a9510SRong-En Fan 
77473f0a83dSXin LI 	freeArgv(eargv);
7754a1a9510SRong-En Fan     }
7764a1a9510SRong-En Fan     _nc_last_db();
7770e3d5408SPeter Wemm 
7780e3d5408SPeter Wemm     ExitProgram(code);
7790e3d5408SPeter Wemm }
780