micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 1 | /**************************************************************************** |
| 2 | * Copyright 2019-2022,2023 Thomas E. Dickey * |
| 3 | * Copyright 2017 Free Software Foundation, Inc. * |
| 4 | * * |
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a * |
| 6 | * copy of this software and associated documentation files (the * |
| 7 | * "Software"), to deal in the Software without restriction, including * |
| 8 | * without limitation the rights to use, copy, modify, merge, publish, * |
| 9 | * distribute, distribute with modifications, sublicense, and/or sell * |
| 10 | * copies of the Software, and to permit persons to whom the Software is * |
| 11 | * furnished to do so, subject to the following conditions: * |
| 12 | * * |
| 13 | * The above copyright notice and this permission notice shall be included * |
| 14 | * in all copies or substantial portions of the Software. * |
| 15 | * * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
| 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
| 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
| 19 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
| 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
| 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
| 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
| 23 | * * |
| 24 | * Except as contained in this notice, the name(s) of the above copyright * |
| 25 | * holders shall not be used in advertising or otherwise to promote the * |
| 26 | * sale, use or other dealings in this Software without prior written * |
| 27 | * authorization. * |
| 28 | ****************************************************************************/ |
| 29 | |
| 30 | /* |
| 31 | * $Id: sp_tinfo.c,v 1.29 2023/06/24 14:14:56 tom Exp $ |
| 32 | * |
| 33 | * TOTO: add option for non-sp-funcs interface |
| 34 | */ |
| 35 | |
| 36 | #define USE_TINFO |
| 37 | #include <test.priv.h> |
| 38 | |
| 39 | #if HAVE_TPUTS_SP |
| 40 | /* |
| 41 | * The higher-level curses library stores a TERMINAL* inside SCREEN, but the |
| 42 | * latter is opaque. This structure helps us keep the two associated. |
| 43 | */ |
| 44 | typedef struct { |
| 45 | const char *name; |
| 46 | FILE *fp; |
| 47 | SCREEN *sp; |
| 48 | TERMINAL *term; |
| 49 | int (*outc) (SCREEN *, int); |
| 50 | } MYDATA; |
| 51 | |
| 52 | static bool opt_n = FALSE; /* true to suppress new_prescr */ |
| 53 | static bool opt_t = FALSE; /* true to use termcap */ |
| 54 | |
| 55 | static int |
| 56 | my_outc(SCREEN *sp, int ch) |
| 57 | { |
| 58 | (void) sp; |
| 59 | return fputc(ch, stdout); |
| 60 | } |
| 61 | |
| 62 | static int |
| 63 | my_errc(SCREEN *sp, int ch) |
| 64 | { |
| 65 | (void) sp; |
| 66 | return fputc(ch, stderr); |
| 67 | } |
| 68 | |
| 69 | static MYDATA * |
| 70 | initialize(const char *name, FILE *output) |
| 71 | { |
| 72 | MYDATA *result = typeCalloc(MYDATA, 1); |
| 73 | int error; |
| 74 | |
| 75 | result->fp = output; |
| 76 | result->name = name; |
| 77 | result->outc = (fileno(output) == 1) ? my_outc : my_errc; |
| 78 | result->sp = opt_n ? NULL : new_prescr(); |
| 79 | |
| 80 | if (opt_t) { |
| 81 | char *temp = strdup(name); |
| 82 | tgetent_sp(result->sp, temp, name); |
| 83 | free(temp); |
| 84 | } else { |
| 85 | setupterm((NCURSES_CONST char *) name, fileno(output), &error); |
| 86 | } |
| 87 | result->term = cur_term; |
| 88 | |
| 89 | return result; |
| 90 | } |
| 91 | |
| 92 | static void |
| 93 | show_flag(MYDATA * data, const char *name, int value) |
| 94 | { |
| 95 | if (value < 0) { |
| 96 | fprintf(data->fp, " %s = (unknown)\n", name); |
| 97 | } else if (value == 0) { |
| 98 | fprintf(data->fp, " %s = false\n", name); |
| 99 | } else { |
| 100 | fprintf(data->fp, " %s = true\n", name); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | #define TC_PARMS data->sp, (NCURSES_CONST char *)tc |
| 105 | #define TI_PARMS data->sp, (NCURSES_CONST char *)ti |
| 106 | |
| 107 | static void |
| 108 | show_cap_flag(MYDATA * data, const char *ti, const char *tc) |
| 109 | { |
| 110 | const char *name = (opt_t ? tc : ti); |
| 111 | show_flag(data, name, (opt_t |
| 112 | ? tgetflag_sp(TC_PARMS) |
| 113 | : tigetflag_sp(TI_PARMS))); |
| 114 | } |
| 115 | |
| 116 | static void |
| 117 | show_number(MYDATA * data, const char *name, int value) |
| 118 | { |
| 119 | if (value <= -2) { |
| 120 | fprintf(data->fp, " %s = (unknown)\n", name); |
| 121 | } else if (value <= -1) { |
| 122 | fprintf(data->fp, " %s = (missing)\n", name); |
| 123 | } else { |
| 124 | fprintf(data->fp, " %s = %d\n", name, value); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | static void |
| 129 | show_cap_number(MYDATA * data, const char *ti, const char *tc) |
| 130 | { |
| 131 | const char *name = (opt_t ? tc : ti); |
| 132 | show_number(data, name, (opt_t |
| 133 | ? tgetnum_sp(TC_PARMS) |
| 134 | : tigetnum_sp(TI_PARMS))); |
| 135 | } |
| 136 | |
| 137 | static void |
| 138 | show_string(MYDATA * data, const char *name, const char *value) |
| 139 | { |
| 140 | fprintf(data->fp, " %s = ", name); |
| 141 | if (value == 0) { |
| 142 | fprintf(data->fp, "(missing)"); |
| 143 | } else if (value == (char *) -1) { |
| 144 | fprintf(data->fp, "(canceled)"); |
| 145 | } else { |
| 146 | int ch; |
| 147 | while ((ch = UChar(*value++)) != '\0') { |
| 148 | if (ch < 32) { |
| 149 | fprintf(data->fp, "^%c", ch | '@'); |
| 150 | } else if (ch == 127) { |
| 151 | fprintf(data->fp, "^?"); |
| 152 | } else if (ch > 127) { |
| 153 | fprintf(data->fp, "\\%03o", ch); |
| 154 | } else { |
| 155 | fprintf(data->fp, "%c", ch); |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | fprintf(data->fp, "\n"); |
| 160 | } |
| 161 | |
| 162 | static void |
| 163 | show_cap_string(MYDATA * data, const char *ti, const char *tc) |
| 164 | { |
| 165 | const char *name = (opt_t ? tc : ti); |
| 166 | char tcapjunk[1024]; |
| 167 | char *tcap_ptr = tcapjunk; |
| 168 | show_string(data, name, (opt_t |
| 169 | ? tgetstr_sp(TC_PARMS, &tcap_ptr) |
| 170 | : tigetstr_sp(TI_PARMS))); |
| 171 | } |
| 172 | |
| 173 | static void |
| 174 | show_char(MYDATA * data, const char *name, int value) |
| 175 | { |
| 176 | if (value < 0) { |
| 177 | show_string(data, name, "(missing)"); |
| 178 | } else { |
| 179 | char temp[2]; |
| 180 | temp[0] = (char) value; |
| 181 | temp[1] = '\0'; |
| 182 | show_string(data, name, temp); |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | static void |
| 187 | do_stuff(MYDATA * data) |
| 188 | { |
| 189 | SCREEN *sp = data->sp; |
| 190 | #if NCURSES_EXT_FUNCS |
| 191 | char *s; |
| 192 | int my_code = 1234; |
| 193 | const char *my_text = "\033[?m"; |
| 194 | #endif |
| 195 | |
| 196 | set_curterm_sp(sp, data->term); |
| 197 | |
| 198 | /* putp always goes to standard output */ |
| 199 | putp_sp(sp, "Hello "); |
| 200 | putp_sp(sp, data->name); |
| 201 | putp_sp(sp, "!\n"); |
| 202 | |
| 203 | fprintf(data->fp, "Term: %s\n", termname_sp(sp)); |
| 204 | fprintf(data->fp, "Long: %s\n", longname_sp(sp)); |
| 205 | show_cap_flag(data, "am", "am"); |
| 206 | show_cap_number(data, "lines", "li"); |
| 207 | show_cap_string(data, "clear", "cl"); |
| 208 | show_cap_string(data, "tbc", "ct"); |
| 209 | show_flag(data, "has_ic", has_ic_sp(sp)); |
| 210 | show_flag(data, "has_il", has_il_sp(sp)); |
| 211 | show_number(data, "baudrate", baudrate_sp(sp)); |
| 212 | show_char(data, "erase ch", erasechar_sp(sp)); |
| 213 | show_char(data, "kill ch", killchar_sp(sp)); |
| 214 | show_string(data, "unctrl", unctrl_sp(sp, 033)); |
| 215 | fflush(data->fp); |
| 216 | |
| 217 | #if NCURSES_EXT_FUNCS |
| 218 | define_key_sp(sp, my_text, my_code); |
| 219 | has_key_sp(sp, 0); |
| 220 | key_defined_sp(sp, my_text); |
| 221 | if ((s = keybound_sp(sp, my_code, 0)) != 0) |
| 222 | free(s); |
| 223 | #endif |
| 224 | keyname_sp(sp, '?'); |
| 225 | #if NCURSES_EXT_FUNCS |
| 226 | keyok_sp(sp, my_code, FALSE); |
| 227 | keyok_sp(sp, my_code, TRUE); |
| 228 | #endif |
| 229 | |
| 230 | savetty_sp(sp); |
| 231 | |
| 232 | def_shell_mode_sp(sp); |
| 233 | |
| 234 | /* |
| 235 | * These functions are low-level settings for ncurses. |
| 236 | */ |
| 237 | #if NCURSES_EXT_FUNCS |
| 238 | set_tabsize_sp(sp, 5); /* waddch */ |
| 239 | #endif |
| 240 | typeahead_sp(sp, FALSE); /* waddch */ |
| 241 | use_env_sp(sp, FALSE); /* newterm */ |
| 242 | use_tioctl_sp(sp, FALSE); /* newterm */ |
| 243 | intrflush_sp(sp, 0, 0); /* wgetch */ |
| 244 | flushinp_sp(sp); /* waddch */ |
| 245 | halfdelay_sp(sp, 5); /* wgetch */ |
| 246 | |
| 247 | /* |
| 248 | * These manipulate the terminal modes, mainly for wgetch. |
| 249 | */ |
| 250 | cbreak_sp(sp); |
| 251 | raw_sp(sp); |
| 252 | def_prog_mode_sp(sp); |
| 253 | |
| 254 | delay_output_sp(sp, 200); |
| 255 | |
| 256 | napms_sp(sp, 10); |
| 257 | |
| 258 | nocbreak_sp(sp); |
| 259 | noqiflush_sp(sp); |
| 260 | noraw_sp(sp); |
| 261 | qiflush_sp(sp); |
| 262 | |
| 263 | resetty_sp(sp); |
| 264 | |
| 265 | tputs_sp(sp, "{reset-mode}\n", 0, data->outc); |
| 266 | |
| 267 | reset_prog_mode_sp(sp); |
| 268 | |
| 269 | curs_set_sp(sp, 0); |
| 270 | tputs_sp(sp, "{prog-mode}\n", 0, data->outc); |
| 271 | |
| 272 | reset_shell_mode_sp(sp); |
| 273 | |
| 274 | tputs_sp(sp, "{shell-mode}\n", 0, data->outc); |
| 275 | } |
| 276 | |
| 277 | static void |
| 278 | cleanup(MYDATA * data) |
| 279 | { |
| 280 | set_curterm(data->term); |
| 281 | del_curterm(data->term); |
| 282 | free(data); |
| 283 | } |
| 284 | |
| 285 | static void |
| 286 | usage(int ok) |
| 287 | { |
| 288 | static const char *tbl[] = |
| 289 | { |
| 290 | "Usage: sp_tinfo [output] [error]" |
| 291 | ,"" |
| 292 | ,USAGE_COMMON |
| 293 | ,"Options:" |
| 294 | ," -n suppress call to new_prescr()" |
| 295 | ," -t use termcap functions rather than terminfo" |
| 296 | }; |
| 297 | size_t n; |
| 298 | for (n = 0; n < SIZEOF(tbl); ++n) { |
| 299 | fprintf(stderr, "%s\n", tbl[n]); |
| 300 | } |
| 301 | ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE); |
| 302 | } |
| 303 | /* *INDENT-OFF* */ |
| 304 | VERSION_COMMON() |
| 305 | /* *INDENT-ON* */ |
| 306 | |
| 307 | int |
| 308 | main(int argc, char *argv[]) |
| 309 | { |
| 310 | MYDATA *my_out; |
| 311 | MYDATA *my_err; |
| 312 | int ch; |
| 313 | |
| 314 | while ((ch = getopt(argc, argv, OPTS_COMMON "nt")) != -1) { |
| 315 | switch (ch) { |
| 316 | case 'n': |
| 317 | opt_n = TRUE; |
| 318 | break; |
| 319 | case 't': |
| 320 | opt_t = TRUE; |
| 321 | break; |
| 322 | case OPTS_VERSION: |
| 323 | show_version(argv); |
| 324 | ExitProgram(EXIT_SUCCESS); |
| 325 | default: |
| 326 | usage(ch == OPTS_USAGE); |
| 327 | /* NOTREACHED */ |
| 328 | } |
| 329 | } |
| 330 | argv += (optind - 1); |
| 331 | argc -= (optind - 1); |
| 332 | |
| 333 | if (argc > 3) |
| 334 | usage(FALSE); |
| 335 | |
| 336 | my_out = initialize((argc > 1) ? argv[1] : "vt100", stdout); |
| 337 | my_err = initialize((argc > 2) ? argv[2] : "ansi", stderr); |
| 338 | |
| 339 | do_stuff(my_out); |
| 340 | do_stuff(my_err); |
| 341 | |
| 342 | if (my_out != my_err) { |
| 343 | cleanup(my_out); |
| 344 | cleanup(my_err); |
| 345 | } else { |
| 346 | cleanup(my_out); |
| 347 | } |
| 348 | |
| 349 | ExitProgram(EXIT_SUCCESS); |
| 350 | } |
| 351 | #else |
| 352 | int |
| 353 | main(void) |
| 354 | { |
| 355 | fprintf(stderr, |
| 356 | "This program requires the low-level ncurses sp-funcs tputs_sp\n"); |
| 357 | ExitProgram(EXIT_FAILURE); |
| 358 | } |
| 359 | #endif |