blob: 8af6f371b77b7adb5bb881338af79a5fe0f9b74e [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
2 * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. *
3 * *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
11 * *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
14 * *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 * *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
26 * authorization. *
27 ****************************************************************************/
28
29/****************************************************************************
30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
31 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
32 * and: Thomas E. Dickey 1996-on *
33 ****************************************************************************/
34
35/*
36 * toe.c --- table of entries report generator
37 */
38
39#include <progs.priv.h>
40
41#include <sys/stat.h>
42
43#if USE_HASHED_DB
44#include <hashed_db.h>
45#endif
46
47MODULE_ID("$Id: toe.c,v 1.51 2008/08/16 21:53:25 tom Exp $")
48
49#define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
50
51const char *_nc_progname;
52
53#if NO_LEAKS
54#undef ExitProgram
55static void ExitProgram(int code) GCC_NORETURN;
56static void
57ExitProgram(int code)
58{
59 _nc_free_entries(_nc_head);
60 _nc_free_tic(code);
61}
62#endif
63
64#if USE_HASHED_DB
65static bool
66make_db_name(char *dst, const char *src, unsigned limit)
67{
68 static const char suffix[] = DBM_SUFFIX;
69
70 bool result = FALSE;
71 unsigned lens = sizeof(suffix) - 1;
72 unsigned size = strlen(src);
73 unsigned need = lens + size;
74
75 if (need <= limit) {
76 if (size >= lens
77 && !strcmp(src + size - lens, suffix))
78 (void) strcpy(dst, src);
79 else
80 (void) sprintf(dst, "%s%s", src, suffix);
81 result = TRUE;
82 }
83 return result;
84}
85#endif
86
87static bool
88is_database(const char *path)
89{
90 bool result = FALSE;
91#if USE_DATABASE
92 if (_nc_is_dir_path(path) && access(path, R_OK | X_OK) == 0) {
93 result = TRUE;
94 }
95#endif
96#if USE_TERMCAP
97 if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
98 result = TRUE;
99 }
100#endif
101#if USE_HASHED_DB
102 if (!result) {
103 char filename[PATH_MAX];
104 if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
105 result = TRUE;
106 } else if (make_db_name(filename, path, sizeof(filename))) {
107 if (_nc_is_file_path(filename) && access(filename, R_OK) == 0) {
108 result = TRUE;
109 }
110 }
111 }
112#endif
113 return result;
114}
115
116static void
117deschook(const char *cn, TERMTYPE *tp)
118/* display a description for the type */
119{
120 const char *desc;
121
122 if ((desc = strrchr(tp->term_names, '|')) == 0 || *++desc == '\0')
123 desc = "(No description)";
124
125 (void) printf("%-10s\t%s\n", cn, desc);
126}
127
128#if USE_TERMCAP
129static void
130show_termcap(char *buffer,
131 void (*hook) (const char *, TERMTYPE *tp))
132{
133 TERMTYPE data;
134 char *next = strchr(buffer, ':');
135 char *last;
136 char *list = buffer;
137
138 if (next)
139 *next = '\0';
140
141 last = strrchr(buffer, '|');
142 if (last)
143 ++last;
144
145 data.term_names = strdup(buffer);
146 while ((next = strtok(list, "|")) != 0) {
147 if (next != last)
148 hook(next, &data);
149 list = 0;
150 }
151 free(data.term_names);
152}
153#endif
154
155static int
156typelist(int eargc, char *eargv[],
157 bool verbosity,
158 void (*hook) (const char *, TERMTYPE *tp))
159/* apply a function to each entry in given terminfo directories */
160{
161 int i;
162
163 for (i = 0; i < eargc; i++) {
164#if USE_DATABASE
165 if (_nc_is_dir_path(eargv[i])) {
166 char *cwd_buf = 0;
167 DIR *termdir;
168 DIRENT *subdir;
169
170 if ((termdir = opendir(eargv[i])) == 0) {
171 (void) fflush(stdout);
172 (void) fprintf(stderr,
173 "%s: can't open terminfo directory %s\n",
174 _nc_progname, eargv[i]);
175 return (EXIT_FAILURE);
176 } else if (verbosity)
177 (void) printf("#\n#%s:\n#\n", eargv[i]);
178
179 while ((subdir = readdir(termdir)) != 0) {
180 size_t len = NAMLEN(subdir);
181 size_t cwd_len = len + strlen(eargv[i]) + 3;
182 char name_1[PATH_MAX];
183 DIR *entrydir;
184 DIRENT *entry;
185
186 cwd_buf = typeRealloc(char, cwd_len, cwd_buf);
187 if (cwd_buf == 0) {
188 perror("realloc cwd_buf");
189 continue;
190 }
191
192 strncpy(name_1, subdir->d_name, len)[len] = '\0';
193 if (isDotname(name_1))
194 continue;
195
196 (void) sprintf(cwd_buf, "%s/%.*s/", eargv[i], (int) len, name_1);
197 if (chdir(cwd_buf) != 0)
198 continue;
199
200 entrydir = opendir(".");
201 if (entrydir == 0) {
202 perror(cwd_buf);
203 continue;
204 }
205 while ((entry = readdir(entrydir)) != 0) {
206 char name_2[PATH_MAX];
207 TERMTYPE lterm;
208 char *cn;
209 int status;
210
211 len = NAMLEN(entry);
212 strncpy(name_2, entry->d_name, len)[len] = '\0';
213 if (isDotname(name_2) || !_nc_is_file_path(name_2))
214 continue;
215
216 status = _nc_read_file_entry(name_2, &lterm);
217 if (status <= 0) {
218 (void) fflush(stdout);
219 (void) fprintf(stderr,
220 "%s: couldn't open terminfo file %s.\n",
221 _nc_progname, name_2);
222 return (EXIT_FAILURE);
223 }
224
225 /* only visit things once, by primary name */
226 cn = _nc_first_name(lterm.term_names);
227 if (!strcmp(cn, name_2)) {
228 /* apply the selected hook function */
229 (*hook) (cn, &lterm);
230 }
231 _nc_free_termtype(&lterm);
232 }
233 closedir(entrydir);
234 }
235 closedir(termdir);
236 if (cwd_buf != 0)
237 free(cwd_buf);
238 }
239#if USE_HASHED_DB
240 else {
241 DB *capdbp;
242 char filename[PATH_MAX];
243
244 if (make_db_name(filename, eargv[i], sizeof(filename))) {
245 if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
246 DBT key, data;
247 int code;
248
249 code = _nc_db_first(capdbp, &key, &data);
250 while (code == 0) {
251 TERMTYPE lterm;
252 int used;
253 char *have;
254 char *cn;
255
256 if (_nc_db_have_data(&key, &data, &have, &used)) {
257 if (_nc_read_termtype(&lterm, have, used) > 0) {
258 /* only visit things once, by primary name */
259 cn = _nc_first_name(lterm.term_names);
260 /* apply the selected hook function */
261 (*hook) (cn, &lterm);
262 _nc_free_termtype(&lterm);
263 }
264 }
265 code = _nc_db_next(capdbp, &key, &data);
266 }
267
268 _nc_db_close(capdbp);
269 }
270 }
271 }
272#endif
273#endif
274#if USE_TERMCAP
275#if HAVE_BSD_CGETENT
276 char *db_array[2];
277 char *buffer = 0;
278
279 if (verbosity)
280 (void) printf("#\n#%s:\n#\n", eargv[i]);
281
282 db_array[0] = eargv[i];
283 db_array[1] = 0;
284
285 if (cgetfirst(&buffer, db_array)) {
286 show_termcap(buffer, hook);
287 free(buffer);
288 while (cgetnext(&buffer, db_array)) {
289 show_termcap(buffer, hook);
290 free(buffer);
291 }
292 }
293 cgetclose();
294#else
295 /* scan termcap text-file only */
296 if (_nc_is_file_path(eargv[i])) {
297 char buffer[2048];
298 FILE *fp;
299
300 if ((fp = fopen(eargv[i], "r")) != 0) {
301 while (fgets(buffer, sizeof(buffer), fp) != 0) {
302 if (*buffer == '#')
303 continue;
304 if (isspace(*buffer))
305 continue;
306 show_termcap(buffer, hook);
307 }
308 fclose(fp);
309 }
310 }
311#endif
312#endif
313 }
314
315 return (EXIT_SUCCESS);
316}
317
318static void
319usage(void)
320{
321 (void) fprintf(stderr, "usage: %s [-ahuUV] [-v n] [file...]\n", _nc_progname);
322 ExitProgram(EXIT_FAILURE);
323}
324
325int
326main(int argc, char *argv[])
327{
328 bool all_dirs = FALSE;
329 bool direct_dependencies = FALSE;
330 bool invert_dependencies = FALSE;
331 bool header = FALSE;
332 char *report_file = 0;
333 unsigned i;
334 int code;
335 int this_opt, last_opt = '?';
336 int v_opt = 0;
337
338 _nc_progname = _nc_rootname(argv[0]);
339
340 while ((this_opt = getopt(argc, argv, "0123456789ahu:vU:V")) != -1) {
341 /* handle optional parameter */
342 if (isdigit(this_opt)) {
343 switch (last_opt) {
344 case 'v':
345 v_opt = (this_opt - '0');
346 break;
347 default:
348 if (isdigit(last_opt))
349 v_opt *= 10;
350 else
351 v_opt = 0;
352 v_opt += (this_opt - '0');
353 last_opt = this_opt;
354 }
355 continue;
356 }
357 switch (this_opt) {
358 case 'a':
359 all_dirs = TRUE;
360 break;
361 case 'h':
362 header = TRUE;
363 break;
364 case 'u':
365 direct_dependencies = TRUE;
366 report_file = optarg;
367 break;
368 case 'v':
369 v_opt = 1;
370 break;
371 case 'U':
372 invert_dependencies = TRUE;
373 report_file = optarg;
374 break;
375 case 'V':
376 puts(curses_version());
377 ExitProgram(EXIT_SUCCESS);
378 default:
379 usage();
380 }
381 }
382 set_trace_level(v_opt);
383
384 if (report_file != 0) {
385 if (freopen(report_file, "r", stdin) == 0) {
386 (void) fflush(stdout);
387 fprintf(stderr, "%s: can't open %s\n", _nc_progname, report_file);
388 ExitProgram(EXIT_FAILURE);
389 }
390
391 /* parse entries out of the source file */
392 _nc_set_source(report_file);
393 _nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
394 }
395
396 /* maybe we want a direct-dependency listing? */
397 if (direct_dependencies) {
398 ENTRY *qp;
399
400 for_entry_list(qp) {
401 if (qp->nuses) {
402 unsigned j;
403
404 (void) printf("%s:", _nc_first_name(qp->tterm.term_names));
405 for (j = 0; j < qp->nuses; j++)
406 (void) printf(" %s", qp->uses[j].name);
407 putchar('\n');
408 }
409 }
410
411 ExitProgram(EXIT_SUCCESS);
412 }
413
414 /* maybe we want a reverse-dependency listing? */
415 if (invert_dependencies) {
416 ENTRY *qp, *rp;
417 int matchcount;
418
419 for_entry_list(qp) {
420 matchcount = 0;
421 for_entry_list(rp) {
422 if (rp->nuses == 0)
423 continue;
424
425 for (i = 0; i < rp->nuses; i++)
426 if (_nc_name_match(qp->tterm.term_names,
427 rp->uses[i].name, "|")) {
428 if (matchcount++ == 0)
429 (void) printf("%s:",
430 _nc_first_name(qp->tterm.term_names));
431 (void) printf(" %s",
432 _nc_first_name(rp->tterm.term_names));
433 }
434 }
435 if (matchcount)
436 putchar('\n');
437 }
438
439 ExitProgram(EXIT_SUCCESS);
440 }
441
442 /*
443 * If we get this far, user wants a simple terminal type listing.
444 */
445 if (optind < argc) {
446 code = typelist(argc - optind, argv + optind, header, deschook);
447 } else if (all_dirs) {
448 DBDIRS state;
449 int offset;
450 int pass;
451 const char *path;
452 char **eargv = 0;
453
454 code = EXIT_FAILURE;
455 for (pass = 0; pass < 2; ++pass) {
456 unsigned count = 0;
457
458 _nc_first_db(&state, &offset);
459 while ((path = _nc_next_db(&state, &offset)) != 0) {
460 if (!is_database(path)) {
461 ;
462 } else if (eargv != 0) {
463 unsigned n;
464 int found = FALSE;
465
466 /* eliminate duplicates */
467 for (n = 0; n < count; ++n) {
468 if (!strcmp(path, eargv[n])) {
469 found = TRUE;
470 break;
471 }
472 }
473 if (!found) {
474 eargv[count] = strdup(path);
475 ++count;
476 }
477 } else {
478 ++count;
479 }
480 }
481 if (!pass) {
482 eargv = typeCalloc(char *, count + 1);
483 } else {
484 code = typelist((int) count, eargv, header, deschook);
485 while (count-- > 0)
486 free(eargv[count]);
487 free(eargv);
488 }
489 }
490 } else {
491 DBDIRS state;
492 int offset;
493 const char *path;
494 char *eargv[3];
495 int count = 0;
496
497 _nc_first_db(&state, &offset);
498 while ((path = _nc_next_db(&state, &offset)) != 0) {
499 if (is_database(path)) {
500 eargv[count++] = strdup(path);
501 break;
502 }
503 }
504 eargv[count] = 0;
505
506 code = typelist(count, eargv, header, deschook);
507
508 while (count-- > 0)
509 free(eargv[count]);
510 }
511 _nc_last_db();
512
513 ExitProgram(code);
514}