1 /**************************************************************************** 2 * Copyright 2020 Thomas E. Dickey * 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: Thomas E. Dickey 31 * 32 * $Id: test_tparm.c,v 1.4 2020/05/31 00:51:32 tom Exp $ 33 * 34 * Exercise tparm, either for all possible capabilities with fixed parameters, 35 * or one capability with all possible parameters. 36 * 37 * TODO: incorporate tic.h and _nc_tparm_analyze 38 * TODO: optionally test tiparm 39 * TODO: add checks/logic to handle "%s" in tparm 40 */ 41 #define USE_TINFO 42 #include <test.priv.h> 43 44 static void failed(const char *) GCC_NORETURN; 45 46 static void 47 failed(const char *msg) 48 { 49 fprintf(stderr, "%s\n", msg); 50 ExitProgram(EXIT_FAILURE); 51 } 52 53 #if HAVE_TIGETSTR 54 55 static int a_opt; 56 static int v_opt; 57 58 static int 59 isNumeric(char *source) 60 { 61 char *next = 0; 62 long value = strtol(source, &next, 0); 63 int result = (next == 0 || next == source || *next != '\0') ? 0 : 1; 64 (void) value; 65 return result; 66 } 67 68 static char * 69 validate(const char *name) 70 { 71 char *value = tigetstr(name); 72 if (!VALID_STRING(value)) { 73 if (v_opt > 1) { 74 printf("? %s %s\n", 75 (value == ABSENT_STRING) 76 ? "absent" 77 : "cancel", 78 name); 79 } 80 value = 0; 81 } 82 return value; 83 } 84 85 static int 86 increment(int *all_parms, int *num_parms, int len_parms, int end_parms) 87 { 88 int rc = 0; 89 int n; 90 91 if (len_parms > 9) 92 len_parms = 9; 93 94 if (end_parms < len_parms) { 95 if (all_parms[end_parms]++ >= num_parms[end_parms]) { 96 all_parms[end_parms] = 0; 97 increment(all_parms, num_parms, len_parms, end_parms + 1); 98 } 99 } 100 for (n = 0; n < len_parms; ++n) { 101 if (all_parms[n] != 0) { 102 rc = 1; 103 break; 104 } 105 } 106 /* return 1 until the vector resets to all 0's */ 107 return rc; 108 } 109 110 static void 111 test_tparm(const char *name, int *number) 112 { 113 char *format = tigetstr(name); 114 if ((format = validate(name)) != 0) { 115 char *result = tparm(format, 116 number[0], 117 number[1], 118 number[2], 119 number[3], 120 number[4], 121 number[5], 122 number[6], 123 number[7], 124 number[8]); 125 if (v_opt > 1) 126 printf(".. %2d = %2d %2d %2d %2d %2d %2d %2d %2d %2d %s\n", 127 result != 0 ? (int) strlen(result) : -1, 128 number[0], 129 number[1], 130 number[2], 131 number[3], 132 number[4], 133 number[5], 134 number[6], 135 number[7], 136 number[8], 137 name); 138 } 139 } 140 141 static void 142 usage(void) 143 { 144 static const char *msg[] = 145 { 146 "Usage: test_tparm [options] [capability] [value1 [value2 [...]]]", 147 "", 148 "Print all distinct combinations of given capability.", 149 "", 150 "Options:", 151 " -T TERM override $TERM; this may be a comma-separated list or \"-\"", 152 " to read a list from standard-input", 153 " -a if capability is given, test all combinations of values", 154 " -r NUM repeat tests NUM times", 155 " -v show values and results", 156 }; 157 unsigned n; 158 for (n = 0; n < SIZEOF(msg); ++n) { 159 fprintf(stderr, "%s\n", msg[n]); 160 } 161 ExitProgram(EXIT_FAILURE); 162 } 163 164 #define PLURAL(n) n, (n != 1) ? "s" : "" 165 #define COLONS(n) (n >= 1) ? ":" : "" 166 167 int 168 main(int argc, char *argv[]) 169 { 170 int n; 171 int r_run, t_run, n_run; 172 char *old_term = getenv("TERM"); 173 int r_opt = 1; 174 char *t_opt = 0; 175 int len_names = 0; /* cur # of items in all_names[] */ 176 int use_names = 10; /* max # of items in all_names[] */ 177 char **all_names = typeCalloc(char *, use_names); 178 int all_parms[10]; /* workspace for "-a" option */ 179 int len_terms = 0; /* cur # of items in all_terms[] */ 180 int use_terms = 10; /* max # of items in all_terms[] */ 181 char **all_terms = typeCalloc(char *, use_terms); 182 int len_parms = 0; /* cur # of items in num_parms[], str_parms[] */ 183 int use_parms = argc + 10; /* max # of items in num_parms[], str_parms[] */ 184 int *num_parms = typeCalloc(int, use_parms); 185 char **str_parms = typeCalloc(char *, use_parms); 186 187 if (all_names == 0 || all_terms == 0 || num_parms == 0 || str_parms == 0) 188 failed("no memory"); 189 190 while ((n = getopt(argc, argv, "T:ar:v")) != -1) { 191 switch (n) { 192 case 'T': 193 t_opt = optarg; 194 break; 195 case 'a': 196 ++a_opt; 197 break; 198 case 'r': 199 r_opt = atoi(optarg); 200 break; 201 case 'v': 202 ++v_opt; 203 break; 204 default: 205 usage(); 206 break; 207 } 208 } 209 210 /* 211 * If there is a nonnumeric parameter after the options, use that as the 212 * capability name. 213 */ 214 if (optind < argc) { 215 if (!isNumeric(argv[optind])) { 216 all_names[len_names++] = strdup(argv[optind++]); 217 } 218 } 219 220 /* 221 * Any remaining arguments must be possible parameter values. If numeric, 222 * and "-a" is not set, use those as the maximum values within which the 223 * test parameters should vary. 224 */ 225 while (optind < argc) { 226 if (isNumeric(argv[optind])) { 227 char *dummy = 0; 228 long value = strtol(argv[optind], &dummy, 0); 229 num_parms[len_parms] = (int) value; 230 } 231 str_parms[len_parms] = argv[optind]; 232 ++optind; 233 ++len_parms; 234 } 235 for (n = len_parms; n < use_parms; ++n) { 236 static char dummy[1]; 237 str_parms[n] = dummy; 238 } 239 if (v_opt) { 240 printf("%d parameter%s%s\n", PLURAL(len_parms), COLONS(len_parms)); 241 for (n = 0; n < len_parms; ++n) { 242 printf(" %d: %d (%s)\n", n + 1, num_parms[n], str_parms[n]); 243 } 244 } 245 246 /* 247 * Make a list of values for $TERM. Accept "-" for standard input to 248 * simplify scripting a check of the whole database. 249 */ 250 old_term = strdup((old_term == 0) ? "unknown" : old_term); 251 if (t_opt != 0) { 252 if (!strcmp(t_opt, "-")) { 253 char buffer[BUFSIZ]; 254 while (fgets(buffer, sizeof(buffer) - 1, stdin) != 0) { 255 char *s = buffer; 256 char *t; 257 while (isspace(UChar(s[0]))) 258 ++s; 259 t = s + strlen(s); 260 while (t != s && isspace(UChar(t[-1]))) 261 *--t = '\0'; 262 s = strdup(s); 263 if (len_terms + 2 >= use_terms) { 264 use_terms *= 2; 265 all_terms = typeRealloc(char *, use_terms, all_terms); 266 if (all_terms == 0) 267 failed("no memory: all_terms"); 268 } 269 all_terms[len_terms++] = s; 270 } 271 } else { 272 char *s = t_opt; 273 char *t; 274 while ((t = strtok(s, ",")) != 0) { 275 s = 0; 276 if (len_terms + 2 >= use_terms) { 277 use_terms *= 2; 278 all_terms = typeRealloc(char *, use_terms, all_terms); 279 if (all_terms == 0) 280 failed("no memory: all_terms"); 281 } 282 all_terms[len_terms++] = strdup(t); 283 } 284 } 285 } else { 286 all_terms[len_terms++] = strdup(old_term); 287 } 288 all_terms[len_terms] = 0; 289 if (v_opt) { 290 printf("%d term%s:\n", PLURAL(len_terms)); 291 for (n = 0; n < len_terms; ++n) { 292 printf(" %d: %s\n", n + 1, all_terms[n]); 293 } 294 } 295 296 /* 297 * If no capability name was selected, use the predefined list of string 298 * capabilities. 299 * 300 * TODO: To address the "other" systems which do not follow SVr4, 301 * just use the output from infocmp on $TERM. 302 */ 303 if (len_names == 0) { 304 #if defined(HAVE_CURSES_DATA_BOOLNAMES) || defined(DECL_CURSES_DATA_BOOLNAMES) 305 for (n = 0; strnames[n] != 0; ++n) { 306 if (len_names + 2 >= use_names) { 307 use_names *= 2; 308 all_names = typeRealloc(char *, use_names, all_names); 309 if (all_names == 0) { 310 failed("no memory: all_names"); 311 } 312 } 313 all_names[len_names++] = strdup(strnames[n]); 314 } 315 #else 316 all_names[len_names++] = strdup("cup"); 317 all_names[len_names++] = strdup("sgr"); 318 #endif 319 } 320 all_names[len_names] = 0; 321 if (v_opt) { 322 printf("%d name%s%s\n", PLURAL(len_names), COLONS(len_names)); 323 for (n = 0; n < len_names; ++n) { 324 printf(" %d: %s\n", n + 1, all_names[n]); 325 } 326 } 327 328 if (r_opt <= 0) 329 r_opt = 1; 330 331 for (r_run = 0; r_run < r_opt; ++r_run) { 332 for (t_run = 0; t_run < len_terms; ++t_run) { 333 int errs; 334 335 if (setupterm(all_terms[t_run], fileno(stdout), &errs) != OK) { 336 printf("** skipping %s (errs:%d)\n", all_terms[t_run], errs); 337 } 338 339 if (v_opt) 340 printf("** testing %s\n", all_terms[t_run]); 341 if (len_names == 1) { 342 if (a_opt) { 343 /* for each combination of values */ 344 memset(all_parms, 0, sizeof(all_parms)); 345 do { 346 test_tparm(all_names[0], all_parms); 347 } 348 while (increment(all_parms, num_parms, len_parms, 0)); 349 } else { 350 /* for the given values */ 351 test_tparm(all_names[0], num_parms); 352 } 353 } else { 354 for (n_run = 0; n_run < len_names; ++n_run) { 355 test_tparm(all_names[n_run], num_parms); 356 } 357 } 358 if (cur_term != 0) { 359 del_curterm(cur_term); 360 } else { 361 printf("? no cur_term\n"); 362 } 363 } 364 } 365 #if NO_LEAKS 366 for (n = 0; n < len_names; ++n) { 367 free(all_names[n]); 368 } 369 free(all_names); 370 free(old_term); 371 for (n = 0; n < len_terms; ++n) { 372 free(all_terms[n]); 373 } 374 free(all_terms); 375 free(num_parms); 376 free(str_parms); 377 #endif 378 379 ExitProgram(EXIT_SUCCESS); 380 } 381 382 #else /* !HAVE_TIGETSTR */ 383 int 384 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED) 385 { 386 failed("This program requires the terminfo functions such as tigetstr"); 387 } 388 #endif /* HAVE_TIGETSTR */ 389