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 /**************************************************************************** 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 47 MODULE_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 51 const char *_nc_progname; 52 53 #if NO_LEAKS 54 #undef ExitProgram 55 static void ExitProgram(int code) GCC_NORETURN; 56 static void 57 ExitProgram(int code) 58 { 59 _nc_free_entries(_nc_head); 60 _nc_free_tic(code); 61 } 62 #endif 63 64 #if USE_HASHED_DB 65 static bool 66 make_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 87 static bool 88 is_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 116 static void 117 deschook(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 129 static void 130 show_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 155 static int 156 typelist(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, <erm); 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, <erm); 230 } 231 _nc_free_termtype(<erm); 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(<erm, 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, <erm); 262 _nc_free_termtype(<erm); 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 318 static void 319 usage(void) 320 { 321 (void) fprintf(stderr, "usage: %s [-ahuUV] [-v n] [file...]\n", _nc_progname); 322 ExitProgram(EXIT_FAILURE); 323 } 324 325 int 326 main(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 } 515