| 1 | /**************************************************************************** | 
|---|
| 2 | * Copyright (c) 1998-2002,2005 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 |  | 
|---|
| 40 | #include <progs.priv.h> | 
|---|
| 41 |  | 
|---|
| 42 | #include <sys/stat.h> | 
|---|
| 43 |  | 
|---|
| 44 | #include <dump_entry.h> | 
|---|
| 45 |  | 
|---|
| 46 | MODULE_ID("$Id: toe.c,v 1.29 2005/09/25 00:39:43 tom Exp $") | 
|---|
| 47 |  | 
|---|
| 48 | #define isDotname(name) (!strcmp(name, ".") || !strcmp(name, "..")) | 
|---|
| 49 |  | 
|---|
| 50 | const char *_nc_progname; | 
|---|
| 51 |  | 
|---|
| 52 | static int typelist(int eargc, char *eargv[], bool, | 
|---|
| 53 | void (*)(const char *, TERMTYPE *)); | 
|---|
| 54 | static void deschook(const char *, TERMTYPE *); | 
|---|
| 55 |  | 
|---|
| 56 | #if NO_LEAKS | 
|---|
| 57 | #undef ExitProgram | 
|---|
| 58 | static void | 
|---|
| 59 | ExitProgram(int code) GCC_NORETURN; | 
|---|
| 60 | static void ExitProgram(int code) | 
|---|
| 61 | { | 
|---|
| 62 | _nc_free_entries(_nc_head); | 
|---|
| 63 | _nc_leaks_dump_entry(); | 
|---|
| 64 | _nc_free_and_exit(code); | 
|---|
| 65 | } | 
|---|
| 66 | #endif | 
|---|
| 67 |  | 
|---|
| 68 | static bool | 
|---|
| 69 | is_a_file(char *path) | 
|---|
| 70 | { | 
|---|
| 71 | struct stat sb; | 
|---|
| 72 | return (stat(path, &sb) == 0 | 
|---|
| 73 | && (sb.st_mode & S_IFMT) == S_IFREG); | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | static bool | 
|---|
| 77 | is_a_directory(char *path) | 
|---|
| 78 | { | 
|---|
| 79 | struct stat sb; | 
|---|
| 80 | return (stat(path, &sb) == 0 | 
|---|
| 81 | && (sb.st_mode & S_IFMT) == S_IFDIR); | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | static char * | 
|---|
| 85 | get_directory(char *path) | 
|---|
| 86 | { | 
|---|
| 87 | if (path != 0) { | 
|---|
| 88 | if (!is_a_directory(path) | 
|---|
| 89 | || access(path, R_OK | X_OK) != 0) | 
|---|
| 90 | path = 0; | 
|---|
| 91 | } | 
|---|
| 92 | return path; | 
|---|
| 93 | } | 
|---|
| 94 |  | 
|---|
| 95 | int | 
|---|
| 96 | main(int argc, char *argv[]) | 
|---|
| 97 | { | 
|---|
| 98 | bool direct_dependencies = FALSE; | 
|---|
| 99 | bool invert_dependencies = FALSE; | 
|---|
| 100 | bool header = FALSE; | 
|---|
| 101 | int i, c; | 
|---|
| 102 | int code; | 
|---|
| 103 |  | 
|---|
| 104 | _nc_progname = _nc_rootname(argv[0]); | 
|---|
| 105 |  | 
|---|
| 106 | while ((c = getopt(argc, argv, "huv:UV")) != EOF) | 
|---|
| 107 | switch (c) { | 
|---|
| 108 | case 'h': | 
|---|
| 109 | header = TRUE; | 
|---|
| 110 | break; | 
|---|
| 111 | case 'u': | 
|---|
| 112 | direct_dependencies = TRUE; | 
|---|
| 113 | break; | 
|---|
| 114 | case 'v': | 
|---|
| 115 | set_trace_level(atoi(optarg)); | 
|---|
| 116 | break; | 
|---|
| 117 | case 'U': | 
|---|
| 118 | invert_dependencies = TRUE; | 
|---|
| 119 | break; | 
|---|
| 120 | case 'V': | 
|---|
| 121 | puts(curses_version()); | 
|---|
| 122 | ExitProgram(EXIT_SUCCESS); | 
|---|
| 123 | default: | 
|---|
| 124 | (void) fprintf(stderr, "usage: toe [-huUV] [-v n] [file...]\n"); | 
|---|
| 125 | ExitProgram(EXIT_FAILURE); | 
|---|
| 126 | } | 
|---|
| 127 |  | 
|---|
| 128 | if (direct_dependencies || invert_dependencies) { | 
|---|
| 129 | if (freopen(argv[optind], "r", stdin) == 0) { | 
|---|
| 130 | (void) fflush(stdout); | 
|---|
| 131 | fprintf(stderr, "%s: can't open %s\n", _nc_progname, argv[optind]); | 
|---|
| 132 | ExitProgram(EXIT_FAILURE); | 
|---|
| 133 | } | 
|---|
| 134 |  | 
|---|
| 135 | /* parse entries out of the source file */ | 
|---|
| 136 | _nc_set_source(argv[optind]); | 
|---|
| 137 | _nc_read_entry_source(stdin, 0, FALSE, FALSE, NULLHOOK); | 
|---|
| 138 | } | 
|---|
| 139 |  | 
|---|
| 140 | /* maybe we want a direct-dependency listing? */ | 
|---|
| 141 | if (direct_dependencies) { | 
|---|
| 142 | ENTRY *qp; | 
|---|
| 143 |  | 
|---|
| 144 | for_entry_list(qp) { | 
|---|
| 145 | if (qp->nuses) { | 
|---|
| 146 | int j; | 
|---|
| 147 |  | 
|---|
| 148 | (void) printf("%s:", _nc_first_name(qp->tterm.term_names)); | 
|---|
| 149 | for (j = 0; j < qp->nuses; j++) | 
|---|
| 150 | (void) printf(" %s", qp->uses[j].name); | 
|---|
| 151 | putchar('\n'); | 
|---|
| 152 | } | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|
| 155 | ExitProgram(EXIT_SUCCESS); | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | /* maybe we want a reverse-dependency listing? */ | 
|---|
| 159 | if (invert_dependencies) { | 
|---|
| 160 | ENTRY *qp, *rp; | 
|---|
| 161 | int matchcount; | 
|---|
| 162 |  | 
|---|
| 163 | for_entry_list(qp) { | 
|---|
| 164 | matchcount = 0; | 
|---|
| 165 | for_entry_list(rp) { | 
|---|
| 166 | if (rp->nuses == 0) | 
|---|
| 167 | continue; | 
|---|
| 168 |  | 
|---|
| 169 | for (i = 0; i < rp->nuses; i++) | 
|---|
| 170 | if (_nc_name_match(qp->tterm.term_names, | 
|---|
| 171 | rp->uses[i].name, "|")) { | 
|---|
| 172 | if (matchcount++ == 0) | 
|---|
| 173 | (void) printf("%s:", | 
|---|
| 174 | _nc_first_name(qp->tterm.term_names)); | 
|---|
| 175 | (void) printf(" %s", | 
|---|
| 176 | _nc_first_name(rp->tterm.term_names)); | 
|---|
| 177 | } | 
|---|
| 178 | } | 
|---|
| 179 | if (matchcount) | 
|---|
| 180 | putchar('\n'); | 
|---|
| 181 | } | 
|---|
| 182 |  | 
|---|
| 183 | ExitProgram(EXIT_SUCCESS); | 
|---|
| 184 | } | 
|---|
| 185 |  | 
|---|
| 186 | /* | 
|---|
| 187 | * If we get this far, user wants a simple terminal type listing. | 
|---|
| 188 | */ | 
|---|
| 189 | if (optind < argc) { | 
|---|
| 190 | code = typelist(argc - optind, argv + optind, header, deschook); | 
|---|
| 191 | } else { | 
|---|
| 192 | char *home, *eargv[3]; | 
|---|
| 193 | char personal[PATH_MAX]; | 
|---|
| 194 | int j; | 
|---|
| 195 |  | 
|---|
| 196 | j = 0; | 
|---|
| 197 | if ((eargv[j] = get_directory(getenv("TERMINFO"))) != 0) { | 
|---|
| 198 | j++; | 
|---|
| 199 | } else { | 
|---|
| 200 | if ((home = getenv("HOME")) != 0) { | 
|---|
| 201 | (void) sprintf(personal, PRIVATE_INFO, home); | 
|---|
| 202 | if ((eargv[j] = get_directory(personal)) != 0) | 
|---|
| 203 | j++; | 
|---|
| 204 | } | 
|---|
| 205 | if ((eargv[j] = get_directory(strcpy(personal, TERMINFO))) != 0) | 
|---|
| 206 | j++; | 
|---|
| 207 | } | 
|---|
| 208 | eargv[j] = 0; | 
|---|
| 209 |  | 
|---|
| 210 | code = typelist(j, eargv, header, deschook); | 
|---|
| 211 | } | 
|---|
| 212 |  | 
|---|
| 213 | ExitProgram(code); | 
|---|
| 214 | } | 
|---|
| 215 |  | 
|---|
| 216 | static void | 
|---|
| 217 | deschook(const char *cn, TERMTYPE * tp) | 
|---|
| 218 | /* display a description for the type */ | 
|---|
| 219 | { | 
|---|
| 220 | const char *desc; | 
|---|
| 221 |  | 
|---|
| 222 | if ((desc = strrchr(tp->term_names, '|')) == 0) | 
|---|
| 223 | desc = "(No description)"; | 
|---|
| 224 | else | 
|---|
| 225 | ++desc; | 
|---|
| 226 |  | 
|---|
| 227 | (void) printf("%-10s\t%s\n", cn, desc); | 
|---|
| 228 | } | 
|---|
| 229 |  | 
|---|
| 230 | static int | 
|---|
| 231 | typelist(int eargc, char *eargv[], | 
|---|
| 232 | bool verbosity, | 
|---|
| 233 | void (*hook) (const char *, TERMTYPE * tp)) | 
|---|
| 234 | /* apply a function to each entry in given terminfo directories */ | 
|---|
| 235 | { | 
|---|
| 236 | int i; | 
|---|
| 237 |  | 
|---|
| 238 | for (i = 0; i < eargc; i++) { | 
|---|
| 239 | DIR *termdir; | 
|---|
| 240 | DIRENT *subdir; | 
|---|
| 241 |  | 
|---|
| 242 | if ((termdir = opendir(eargv[i])) == 0) { | 
|---|
| 243 | (void) fflush(stdout); | 
|---|
| 244 | (void) fprintf(stderr, | 
|---|
| 245 | "%s: can't open terminfo directory %s\n", | 
|---|
| 246 | _nc_progname, eargv[i]); | 
|---|
| 247 | return (EXIT_FAILURE); | 
|---|
| 248 | } else if (verbosity) | 
|---|
| 249 | (void) printf("#\n#%s:\n#\n", eargv[i]); | 
|---|
| 250 |  | 
|---|
| 251 | while ((subdir = readdir(termdir)) != 0) { | 
|---|
| 252 | size_t len = NAMLEN(subdir); | 
|---|
| 253 | char buf[PATH_MAX]; | 
|---|
| 254 | char name_1[PATH_MAX]; | 
|---|
| 255 | DIR *entrydir; | 
|---|
| 256 | DIRENT *entry; | 
|---|
| 257 |  | 
|---|
| 258 | strncpy(name_1, subdir->d_name, len)[len] = '\0'; | 
|---|
| 259 | if (isDotname(name_1)) | 
|---|
| 260 | continue; | 
|---|
| 261 |  | 
|---|
| 262 | (void) sprintf(buf, "%s/%s/", eargv[i], name_1); | 
|---|
| 263 | if (chdir(buf) != 0) | 
|---|
| 264 | continue; | 
|---|
| 265 |  | 
|---|
| 266 | entrydir = opendir("."); | 
|---|
| 267 | while ((entry = readdir(entrydir)) != 0) { | 
|---|
| 268 | char name_2[PATH_MAX]; | 
|---|
| 269 | TERMTYPE lterm; | 
|---|
| 270 | char *cn; | 
|---|
| 271 | int status; | 
|---|
| 272 |  | 
|---|
| 273 | len = NAMLEN(entry); | 
|---|
| 274 | strncpy(name_2, entry->d_name, len)[len] = '\0'; | 
|---|
| 275 | if (isDotname(name_2) || !is_a_file(name_2)) | 
|---|
| 276 | continue; | 
|---|
| 277 |  | 
|---|
| 278 | status = _nc_read_file_entry(name_2, <erm); | 
|---|
| 279 | if (status <= 0) { | 
|---|
| 280 | (void) fflush(stdout); | 
|---|
| 281 | (void) fprintf(stderr, | 
|---|
| 282 | "toe: couldn't open terminfo file %s.\n", | 
|---|
| 283 | name_2); | 
|---|
| 284 | return (EXIT_FAILURE); | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 | /* only visit things once, by primary name */ | 
|---|
| 288 | cn = _nc_first_name(lterm.term_names); | 
|---|
| 289 | if (!strcmp(cn, name_2)) { | 
|---|
| 290 | /* apply the selected hook function */ | 
|---|
| 291 | (*hook) (cn, <erm); | 
|---|
| 292 | } | 
|---|
| 293 | if (lterm.term_names) { | 
|---|
| 294 | free(lterm.term_names); | 
|---|
| 295 | lterm.term_names = 0; | 
|---|
| 296 | } | 
|---|
| 297 | if (lterm.str_table) { | 
|---|
| 298 | free(lterm.str_table); | 
|---|
| 299 | lterm.str_table = 0; | 
|---|
| 300 | } | 
|---|
| 301 | } | 
|---|
| 302 | closedir(entrydir); | 
|---|
| 303 | } | 
|---|
| 304 | closedir(termdir); | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | return (EXIT_SUCCESS); | 
|---|
| 308 | } | 
|---|