toe.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /****************************************************************************
  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. * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
  30. * and: Eric S. Raymond <esr@snark.thyrsus.com> *
  31. * and: Thomas E. Dickey 1996-on *
  32. ****************************************************************************/
  33. /*
  34. * toe.c --- table of entries report generator
  35. */
  36. #include <progs.priv.h>
  37. #include <sys/stat.h>
  38. #if USE_HASHED_DB
  39. #include <hashed_db.h>
  40. #endif
  41. MODULE_ID("$Id: toe.c,v 1.51 2008/08/16 21:53:25 tom Exp $")
  42. #define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
  43. const char *_nc_progname;
  44. #if NO_LEAKS
  45. #undef ExitProgram
  46. static void ExitProgram(int code) GCC_NORETURN;
  47. static void
  48. ExitProgram(int code)
  49. {
  50. _nc_free_entries(_nc_head);
  51. _nc_free_tic(code);
  52. }
  53. #endif
  54. #if USE_HASHED_DB
  55. static bool
  56. make_db_name(char *dst, const char *src, unsigned limit)
  57. {
  58. static const char suffix[] = DBM_SUFFIX;
  59. bool result = FALSE;
  60. unsigned lens = sizeof(suffix) - 1;
  61. unsigned size = strlen(src);
  62. unsigned need = lens + size;
  63. if (need <= limit) {
  64. if (size >= lens
  65. && !strcmp(src + size - lens, suffix))
  66. (void) strcpy(dst, src);
  67. else
  68. (void) sprintf(dst, "%s%s", src, suffix);
  69. result = TRUE;
  70. }
  71. return result;
  72. }
  73. #endif
  74. static bool
  75. is_database(const char *path)
  76. {
  77. bool result = FALSE;
  78. #if USE_DATABASE
  79. if (_nc_is_dir_path(path) && access(path, R_OK | X_OK) == 0) {
  80. result = TRUE;
  81. }
  82. #endif
  83. #if USE_TERMCAP
  84. if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
  85. result = TRUE;
  86. }
  87. #endif
  88. #if USE_HASHED_DB
  89. if (!result) {
  90. char filename[PATH_MAX];
  91. if (_nc_is_file_path(path) && access(path, R_OK) == 0) {
  92. result = TRUE;
  93. } else if (make_db_name(filename, path, sizeof(filename))) {
  94. if (_nc_is_file_path(filename) && access(filename, R_OK) == 0) {
  95. result = TRUE;
  96. }
  97. }
  98. }
  99. #endif
  100. return result;
  101. }
  102. static void
  103. deschook(const char *cn, TERMTYPE *tp)
  104. /* display a description for the type */
  105. {
  106. const char *desc;
  107. if ((desc = strrchr(tp->term_names, '|')) == 0 || *++desc == '\0')
  108. desc = "(No description)";
  109. (void) printf("%-10s\t%s\n", cn, desc);
  110. }
  111. #if USE_TERMCAP
  112. static void
  113. show_termcap(char *buffer,
  114. void (*hook) (const char *, TERMTYPE *tp))
  115. {
  116. TERMTYPE data;
  117. char *next = strchr(buffer, ':');
  118. char *last;
  119. char *list = buffer;
  120. if (next)
  121. *next = '\0';
  122. last = strrchr(buffer, '|');
  123. if (last)
  124. ++last;
  125. data.term_names = strdup(buffer);
  126. while ((next = strtok(list, "|")) != 0) {
  127. if (next != last)
  128. hook(next, &data);
  129. list = 0;
  130. }
  131. free(data.term_names);
  132. }
  133. #endif
  134. static int
  135. typelist(int eargc, char *eargv[],
  136. bool verbosity,
  137. void (*hook) (const char *, TERMTYPE *tp))
  138. /* apply a function to each entry in given terminfo directories */
  139. {
  140. int i;
  141. for (i = 0; i < eargc; i++) {
  142. #if USE_DATABASE
  143. if (_nc_is_dir_path(eargv[i])) {
  144. char *cwd_buf = 0;
  145. DIR *termdir;
  146. DIRENT *subdir;
  147. if ((termdir = opendir(eargv[i])) == 0) {
  148. (void) fflush(stdout);
  149. (void) fprintf(stderr,
  150. "%s: can't open terminfo directory %s\n",
  151. _nc_progname, eargv[i]);
  152. return (EXIT_FAILURE);
  153. } else if (verbosity)
  154. (void) printf("#\n#%s:\n#\n", eargv[i]);
  155. while ((subdir = readdir(termdir)) != 0) {
  156. size_t len = NAMLEN(subdir);
  157. size_t cwd_len = len + strlen(eargv[i]) + 3;
  158. char name_1[PATH_MAX];
  159. DIR *entrydir;
  160. DIRENT *entry;
  161. cwd_buf = typeRealloc(char, cwd_len, cwd_buf);
  162. if (cwd_buf == 0) {
  163. perror("realloc cwd_buf");
  164. continue;
  165. }
  166. strncpy(name_1, subdir->d_name, len)[len] = '\0';
  167. if (isDotname(name_1))
  168. continue;
  169. (void) sprintf(cwd_buf, "%s/%.*s/", eargv[i], (int) len, name_1);
  170. if (chdir(cwd_buf) != 0)
  171. continue;
  172. entrydir = opendir(".");
  173. if (entrydir == 0) {
  174. perror(cwd_buf);
  175. continue;
  176. }
  177. while ((entry = readdir(entrydir)) != 0) {
  178. char name_2[PATH_MAX];
  179. TERMTYPE lterm;
  180. char *cn;
  181. int status;
  182. len = NAMLEN(entry);
  183. strncpy(name_2, entry->d_name, len)[len] = '\0';
  184. if (isDotname(name_2) || !_nc_is_file_path(name_2))
  185. continue;
  186. status = _nc_read_file_entry(name_2, &lterm);
  187. if (status <= 0) {
  188. (void) fflush(stdout);
  189. (void) fprintf(stderr,
  190. "%s: couldn't open terminfo file %s.\n",
  191. _nc_progname, name_2);
  192. return (EXIT_FAILURE);
  193. }
  194. /* only visit things once, by primary name */
  195. cn = _nc_first_name(lterm.term_names);
  196. if (!strcmp(cn, name_2)) {
  197. /* apply the selected hook function */
  198. (*hook) (cn, &lterm);
  199. }
  200. _nc_free_termtype(&lterm);
  201. }
  202. closedir(entrydir);
  203. }
  204. closedir(termdir);
  205. if (cwd_buf != 0)
  206. free(cwd_buf);
  207. }
  208. #if USE_HASHED_DB
  209. else {
  210. DB *capdbp;
  211. char filename[PATH_MAX];
  212. if (make_db_name(filename, eargv[i], sizeof(filename))) {
  213. if ((capdbp = _nc_db_open(filename, FALSE)) != 0) {
  214. DBT key, data;
  215. int code;
  216. code = _nc_db_first(capdbp, &key, &data);
  217. while (code == 0) {
  218. TERMTYPE lterm;
  219. int used;
  220. char *have;
  221. char *cn;
  222. if (_nc_db_have_data(&key, &data, &have, &used)) {
  223. if (_nc_read_termtype(&lterm, have, used) > 0) {
  224. /* only visit things once, by primary name */
  225. cn = _nc_first_name(lterm.term_names);
  226. /* apply the selected hook function */
  227. (*hook) (cn, &lterm);
  228. _nc_free_termtype(&lterm);
  229. }
  230. }
  231. code = _nc_db_next(capdbp, &key, &data);
  232. }
  233. _nc_db_close(capdbp);
  234. }
  235. }
  236. }
  237. #endif
  238. #endif
  239. #if USE_TERMCAP
  240. #if HAVE_BSD_CGETENT
  241. char *db_array[2];
  242. char *buffer = 0;
  243. if (verbosity)
  244. (void) printf("#\n#%s:\n#\n", eargv[i]);
  245. db_array[0] = eargv[i];
  246. db_array[1] = 0;
  247. if (cgetfirst(&buffer, db_array)) {
  248. show_termcap(buffer, hook);
  249. free(buffer);
  250. while (cgetnext(&buffer, db_array)) {
  251. show_termcap(buffer, hook);
  252. free(buffer);
  253. }
  254. }
  255. cgetclose();
  256. #else
  257. /* scan termcap text-file only */
  258. if (_nc_is_file_path(eargv[i])) {
  259. char buffer[2048];
  260. FILE *fp;
  261. if ((fp = fopen(eargv[i], "r")) != 0) {
  262. while (fgets(buffer, sizeof(buffer), fp) != 0) {
  263. if (*buffer == '#')
  264. continue;
  265. if (isspace(*buffer))
  266. continue;
  267. show_termcap(buffer, hook);
  268. }
  269. fclose(fp);
  270. }
  271. }
  272. #endif
  273. #endif
  274. }
  275. return (EXIT_SUCCESS);
  276. }
  277. static void
  278. usage(void)
  279. {
  280. (void) fprintf(stderr, "usage: %s [-ahuUV] [-v n] [file...]\n", _nc_progname);
  281. ExitProgram(EXIT_FAILURE);
  282. }
  283. int
  284. main(int argc, char *argv[])
  285. {
  286. bool all_dirs = FALSE;
  287. bool direct_dependencies = FALSE;
  288. bool invert_dependencies = FALSE;
  289. bool header = FALSE;
  290. char *report_file = 0;
  291. unsigned i;
  292. int code;
  293. int this_opt, last_opt = '?';
  294. int v_opt = 0;
  295. _nc_progname = _nc_rootname(argv[0]);
  296. while ((this_opt = getopt(argc, argv, "0123456789ahu:vU:V")) != -1) {
  297. /* handle optional parameter */
  298. if (isdigit(this_opt)) {
  299. switch (last_opt) {
  300. case 'v':
  301. v_opt = (this_opt - '0');
  302. break;
  303. default:
  304. if (isdigit(last_opt))
  305. v_opt *= 10;
  306. else
  307. v_opt = 0;
  308. v_opt += (this_opt - '0');
  309. last_opt = this_opt;
  310. }
  311. continue;
  312. }
  313. switch (this_opt) {
  314. case 'a':
  315. all_dirs = TRUE;
  316. break;
  317. case 'h':
  318. header = TRUE;
  319. break;
  320. case 'u':
  321. direct_dependencies = TRUE;
  322. report_file = optarg;
  323. break;
  324. case 'v':
  325. v_opt = 1;
  326. break;
  327. case 'U':
  328. invert_dependencies = TRUE;
  329. report_file = optarg;
  330. break;
  331. case 'V':
  332. puts(curses_version());
  333. ExitProgram(EXIT_SUCCESS);
  334. default:
  335. usage();
  336. }
  337. }
  338. set_trace_level(v_opt);
  339. if (report_file != 0) {
  340. if (freopen(report_file, "r", stdin) == 0) {
  341. (void) fflush(stdout);
  342. fprintf(stderr, "%s: can't open %s\n", _nc_progname, report_file);
  343. ExitProgram(EXIT_FAILURE);
  344. }
  345. /* parse entries out of the source file */
  346. _nc_set_source(report_file);
  347. _nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK);
  348. }
  349. /* maybe we want a direct-dependency listing? */
  350. if (direct_dependencies) {
  351. ENTRY *qp;
  352. for_entry_list(qp) {
  353. if (qp->nuses) {
  354. unsigned j;
  355. (void) printf("%s:", _nc_first_name(qp->tterm.term_names));
  356. for (j = 0; j < qp->nuses; j++)
  357. (void) printf(" %s", qp->uses[j].name);
  358. putchar('\n');
  359. }
  360. }
  361. ExitProgram(EXIT_SUCCESS);
  362. }
  363. /* maybe we want a reverse-dependency listing? */
  364. if (invert_dependencies) {
  365. ENTRY *qp, *rp;
  366. int matchcount;
  367. for_entry_list(qp) {
  368. matchcount = 0;
  369. for_entry_list(rp) {
  370. if (rp->nuses == 0)
  371. continue;
  372. for (i = 0; i < rp->nuses; i++)
  373. if (_nc_name_match(qp->tterm.term_names,
  374. rp->uses[i].name, "|")) {
  375. if (matchcount++ == 0)
  376. (void) printf("%s:",
  377. _nc_first_name(qp->tterm.term_names));
  378. (void) printf(" %s",
  379. _nc_first_name(rp->tterm.term_names));
  380. }
  381. }
  382. if (matchcount)
  383. putchar('\n');
  384. }
  385. ExitProgram(EXIT_SUCCESS);
  386. }
  387. /*
  388. * If we get this far, user wants a simple terminal type listing.
  389. */
  390. if (optind < argc) {
  391. code = typelist(argc - optind, argv + optind, header, deschook);
  392. } else if (all_dirs) {
  393. DBDIRS state;
  394. int offset;
  395. int pass;
  396. const char *path;
  397. char **eargv = 0;
  398. code = EXIT_FAILURE;
  399. for (pass = 0; pass < 2; ++pass) {
  400. unsigned count = 0;
  401. _nc_first_db(&state, &offset);
  402. while ((path = _nc_next_db(&state, &offset)) != 0) {
  403. if (!is_database(path)) {
  404. ;
  405. } else if (eargv != 0) {
  406. unsigned n;
  407. int found = FALSE;
  408. /* eliminate duplicates */
  409. for (n = 0; n < count; ++n) {
  410. if (!strcmp(path, eargv[n])) {
  411. found = TRUE;
  412. break;
  413. }
  414. }
  415. if (!found) {
  416. eargv[count] = strdup(path);
  417. ++count;
  418. }
  419. } else {
  420. ++count;
  421. }
  422. }
  423. if (!pass) {
  424. eargv = typeCalloc(char *, count + 1);
  425. } else {
  426. code = typelist((int) count, eargv, header, deschook);
  427. while (count-- > 0)
  428. free(eargv[count]);
  429. free(eargv);
  430. }
  431. }
  432. } else {
  433. DBDIRS state;
  434. int offset;
  435. const char *path;
  436. char *eargv[3];
  437. int count = 0;
  438. _nc_first_db(&state, &offset);
  439. while ((path = _nc_next_db(&state, &offset)) != 0) {
  440. if (is_database(path)) {
  441. eargv[count++] = strdup(path);
  442. break;
  443. }
  444. }
  445. eargv[count] = 0;
  446. code = typelist(count, eargv, header, deschook);
  447. while (count-- > 0)
  448. free(eargv[count]);
  449. }
  450. _nc_last_db();
  451. ExitProgram(code);
  452. }