1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1988 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 /* 34 * NAME 35 * captoinfo - convert a termcap description to a terminfo description 36 * 37 * SYNOPSIS 38 * captoinfo [-1vV] [-w width] [ filename ... ] 39 * 40 * AUTHOR 41 * Tony Hansen, January 22, 1984. 42 */ 43 44 #include "curses.h" 45 #include <ctype.h> 46 #include <stdlib.h> 47 #include "otermcap.h" 48 #include "print.h" 49 50 #define trace stderr /* send trace messages to stderr */ 51 52 /* extra termcap variables no longer in terminfo */ 53 char *oboolcodes[] = 54 { 55 "bs", /* Terminal can backspace with "^H" */ 56 "nc", /* No correctly working carriage return (DM2500,H2000) */ 57 "ns", /* Terminal is a CRT but does not scroll. */ 58 "pt", /* Has hardware tabs (may need to be set with "is") */ 59 "MT", /* Has meta key, alternate code. */ 60 "xr", /* Return acts like ce \r \n (Delta Data) */ 61 0 62 }; 63 int cap_bs = 0, cap_nc = 1, cap_ns = 2, cap_pt = 3, cap_MT = 4, cap_xr = 5; 64 char *onumcodes[] = 65 { 66 "dB", /* Number of millisec of bs delay needed */ 67 "dC", /* Number of millisec of cr delay needed */ 68 "dF", /* Number of millisec of ff delay needed */ 69 "dN", /* Number of millisec of nl delay needed */ 70 "dT", /* Number of millisec of tab delay needed */ 71 "ug", /* Number of blank chars left by us or ue */ 72 /* Ignore the 'kn' number. It was ill-defined and never used. */ 73 "kn", /* Number of "other" keys */ 74 0 75 }; 76 int cap_dB = 0, cap_dC = 1, cap_dF = 2, cap_dN = 3, cap_dT = 4, cap_ug = 5; 77 78 char *ostrcodes[] = 79 { 80 "bc", /* Backspace if not "^H" */ 81 "ko", /* Termcap entries for other non-function keys */ 82 "ma", /* Arrow key map, used by vi version 2 only */ 83 "nl", /* Newline character (default "\n") */ 84 "rs", /* undocumented reset string, like is (info is2) */ 85 /* Ignore the 'ml' and 'mu' strings. */ 86 "ml", /* Memory lock on above cursor. */ 87 "mu", /* Memory unlock (turn off memory lock). */ 88 0 89 }; 90 int cap_bc = 0, cap_ko = 1, cap_ma = 2, cap_nl = 3, cap_rs = 4; 91 92 #define numelements(x) (sizeof (x)/sizeof (x[0])) 93 char oboolval[2][numelements(oboolcodes)]; 94 short onumval[2][numelements(onumcodes)]; 95 char *ostrval[2][numelements(ostrcodes)]; 96 97 /* externs from libcurses.a */ 98 extern char *boolnames[], *boolcodes[]; 99 extern char *numnames[], *numcodes[]; 100 extern char *strnames[], *strcodes[]; 101 102 /* externs from libc.a */ 103 extern char *getenv(); 104 extern void exit(); 105 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */ 106 extern char *getcwd(); 107 #else 108 extern char *getwd(); 109 #endif /* SYSV || USG */ 110 extern int getopt(); 111 extern int optind; 112 extern char *optarg; 113 extern int strncmp(), strcmp(); 114 extern char *strcpy(); 115 116 /* globals for this file */ 117 char *progname; /* argv [0], the name of the program */ 118 static char *term_name; /* the name of the terminal being worked on */ 119 static int uselevel; /* whether we're dealing with use= info */ 120 static int boolcount, /* the maximum numbers of each name array */ 121 numcount, 122 strcount; 123 124 /* globals dealing with the environment */ 125 extern char **environ; 126 static char TERM[100]; 127 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */ 128 static char dirname[BUFSIZ]; 129 #else 130 #include <sys/param.h> 131 static char dirname[MAXPATHLEN]; 132 #endif /* SYSV || USG */ 133 static char TERMCAP[BUFSIZ+15]; 134 static char *newenviron[] = { &TERM[0], &TERMCAP[0], 0 }; 135 136 /* dynamic arrays */ 137 static char *boolval[2]; /* dynamic array of boolean values */ 138 static short *numval[2]; /* dynamic array of numeric values */ 139 static char **strval[2]; /* dynamic array of string pointers */ 140 141 /* data buffers */ 142 static char *capbuffer; /* string table, pointed at by strval */ 143 static char *nextstring; /* pointer into string table */ 144 static char *bp; /* termcap raw string table */ 145 static char *buflongname; /* place to copy the long names */ 146 147 /* flags */ 148 static int verbose = 0; /* debugging printing level */ 149 static int copycomments = 0; /* copy comments from tercap source */ 150 151 #define ispadchar(c) (isdigit(c) || (c) == '.' || (c) == '*') 152 153 static void getlongname(); 154 static void handleko(); 155 static void handlema(); 156 static void print_no_use_entry(); 157 static void print_use_entry(char *); 158 static void captoinfo(); 159 static void use_etc_termcap(); 160 static void initdirname(); 161 static void setfilename(char *); 162 static void setterm_name(); 163 static void use_file(char *); 164 static void sorttable(char *[], char *[]); 165 static void inittables(); 166 167 /* 168 * Verify that the names given in the termcap entry are all valid. 169 */ 170 171 int 172 capsearch(char *codes[], char *ocodes[], char *cap) 173 { 174 for (; *codes; codes++) 175 if (((*codes)[0] == cap[0]) && ((*codes)[1] == cap[1])) 176 return (1); 177 178 for (; *ocodes; ocodes++) 179 if (((*ocodes)[0] == cap[0]) && ((*ocodes)[1] == cap[1])) 180 return (1); 181 182 return (0); 183 } 184 185 void 186 checktermcap() 187 { 188 char *tbuf = bp; 189 enum { tbool, tnum, tstr, tcancel, tunknown } type; 190 191 for (;;) { 192 tbuf = tskip(tbuf); 193 while (*tbuf == '\t' || *tbuf == ' ' || *tbuf == ':') 194 tbuf++; 195 196 if (*tbuf == 0) 197 return; 198 199 /* commented out entry? */ 200 if (*tbuf == '.') { 201 if (verbose) 202 (void) fprintf(trace, "termcap string '%c%c' " 203 "commented out.\n", tbuf[1], tbuf[2]); 204 if (!capsearch(boolcodes, oboolcodes, tbuf + 1) && 205 !capsearch(numcodes, onumcodes, tbuf + 1) && 206 !capsearch(strcodes, ostrcodes, tbuf + 1)) 207 (void) fprintf(stderr, 208 "%s: TERM=%s: commented out code '%.2s' " 209 "is unknown.\n", progname, term_name, 210 tbuf+1); 211 continue; 212 } 213 214 if (verbose) 215 (void) fprintf(trace, "looking at termcap string " 216 "'%.2s'.\n", tbuf); 217 218 switch (tbuf[2]) { 219 case ':': case '\0': type = tbool; break; 220 case '#': type = tnum; break; 221 case '=': type = tstr; break; 222 case '@': type = tcancel; break; 223 default: 224 (void) fprintf(stderr, 225 "%s: TERM=%s: unknown type given for the " 226 "termcap code '%.2s'.\n", progname, 227 term_name, tbuf); 228 type = tunknown; 229 } 230 231 if (verbose > 1) 232 (void) fprintf(trace, "type of '%.2s' is %s.\n", tbuf, 233 (type == tbool) ? "boolean" : 234 (type == tnum) ? "numeric" : 235 (type = tstr) ? "string" : 236 (type = tcancel) ? "canceled" : "unknown"); 237 238 /* look for the name in bools */ 239 if (capsearch(boolcodes, oboolcodes, tbuf)) { 240 if (type != tbool && type != tcancel) 241 (void) fprintf(stderr, 242 "%s: TERM=%s: wrong type given for the " 243 "boolean termcap code '%.2s'.\n", progname, 244 term_name, tbuf); 245 continue; 246 } 247 248 /* look for the name in nums */ 249 if (capsearch(numcodes, onumcodes, tbuf)) { 250 if (type != tnum && type != tcancel) 251 (void) fprintf(stderr, 252 "%s: TERM=%s: wrong type given for the " 253 "numeric termcap code '%.2s'.\n", progname, 254 term_name, tbuf); 255 continue; 256 } 257 258 /* look for the name in strs */ 259 if (capsearch(strcodes, ostrcodes, tbuf)) { 260 if (type != tstr && type != tcancel) 261 (void) fprintf(stderr, 262 "%s: TERM=%s: wrong type given for the " 263 "string termcap code '%.2s'.\n", progname, 264 term_name, tbuf); 265 continue; 266 } 267 268 (void) fprintf(stderr, 269 "%s: TERM=%s: the %s termcap code '%.2s' is not a valid " 270 "name.\n", progname, term_name, 271 (type == tbool) ? "boolean" : 272 (type == tnum) ? "numeric" : 273 (type = tstr) ? "string" : 274 (type = tcancel) ? "canceled" : "(unknown type)", tbuf); 275 } 276 } 277 278 /* 279 * Fill up the termcap tables. 280 */ 281 int 282 filltables() 283 { 284 int i, tret; 285 286 /* Retrieve the termcap entry. */ 287 if ((tret = otgetent(bp, term_name)) != 1) { 288 (void) fprintf(stderr, 289 "%s: TERM=%s: tgetent failed with return code %d (%s).\n", 290 progname, term_name, tret, 291 (tret == 0) ? "non-existent or invalid entry" : 292 (tret == -1) ? "cannot open $TERMCAP" : "unknown reason"); 293 return (0); 294 } 295 296 if (verbose) { 297 (void) fprintf(trace, "bp="); 298 (void) cpr(trace, bp); 299 (void) fprintf(trace, ".\n"); 300 } 301 302 if (uselevel == 0) 303 checktermcap(); 304 305 /* Retrieve the values that are in terminfo. */ 306 307 /* booleans */ 308 for (i = 0; boolcodes[i]; i++) { 309 boolval[uselevel][i] = otgetflag(boolcodes[i]); 310 if (verbose > 1) { 311 (void) fprintf(trace, "boolcodes=%s, ", boolcodes[i]); 312 (void) fprintf(trace, "boolnames=%s, ", boolnames[i]); 313 (void) fprintf(trace, 314 "flag=%d.\n", boolval[uselevel][i]); 315 } 316 } 317 318 /* numbers */ 319 for (i = 0; numcodes[i]; i++) { 320 numval[uselevel][i] = otgetnum(numcodes[i]); 321 if (verbose > 1) { 322 (void) fprintf(trace, "numcodes=%s, ", numcodes[i]); 323 (void) fprintf(trace, "numnames=%s, ", numnames[i]); 324 (void) fprintf(trace, "num=%d.\n", numval[uselevel][i]); 325 } 326 } 327 328 if (uselevel == 0) 329 nextstring = capbuffer; 330 331 /* strings */ 332 for (i = 0; strcodes[i]; i++) { 333 strval[uselevel][i] = otgetstr(strcodes[i], &nextstring); 334 if (verbose > 1) { 335 (void) fprintf(trace, "strcodes=%s, ", strcodes [i]); 336 (void) fprintf(trace, "strnames=%s, ", strnames [i]); 337 if (strval[uselevel][i]) { 338 (void) fprintf(trace, "str="); 339 tpr(trace, strval[uselevel][i]); 340 (void) fprintf(trace, ".\n"); 341 } 342 else 343 (void) fprintf(trace, "str=NULL.\n"); 344 } 345 /* remove zero length strings */ 346 if (strval[uselevel][i] && (strval[uselevel][i][0] == '\0')) { 347 (void) fprintf(stderr, 348 "%s: TERM=%s: cap %s (info %s) is NULL: REMOVED\n", 349 progname, term_name, strcodes[i], strnames[i]); 350 strval[uselevel][i] = NULL; 351 } 352 } 353 354 /* Retrieve the values not found in terminfo anymore. */ 355 356 /* booleans */ 357 for (i = 0; oboolcodes[i]; i++) { 358 oboolval[uselevel][i] = otgetflag(oboolcodes[i]); 359 if (verbose > 1) { 360 (void) fprintf(trace, "oboolcodes=%s, ", 361 oboolcodes[i]); 362 (void) fprintf(trace, "flag=%d.\n", 363 oboolval[uselevel][i]); 364 } 365 } 366 367 /* numbers */ 368 for (i = 0; onumcodes[i]; i++) { 369 onumval[uselevel][i] = otgetnum(onumcodes[i]); 370 if (verbose > 1) { 371 (void) fprintf(trace, "onumcodes=%s, ", onumcodes[i]); 372 (void) fprintf(trace, "num=%d.\n", 373 onumval[uselevel][i]); 374 } 375 } 376 377 /* strings */ 378 for (i = 0; ostrcodes[i]; i++) { 379 ostrval[uselevel][i] = otgetstr(ostrcodes[i], &nextstring); 380 if (verbose > 1) { 381 (void) fprintf(trace, "ostrcodes=%s, ", ostrcodes[i]); 382 if (ostrval[uselevel][i]) { 383 (void) fprintf(trace, "ostr="); 384 tpr(trace, ostrval[uselevel][i]); 385 (void) fprintf(trace, ".\n"); 386 } 387 else 388 (void) fprintf(trace, "ostr=NULL.\n"); 389 } 390 /* remove zero length strings */ 391 if (ostrval[uselevel][i] && (ostrval[uselevel][i][0] == '\0')) { 392 (void) fprintf(stderr, 393 "%s: TERM=%s: cap %s (no terminfo name) is NULL: " 394 "REMOVED\n", progname, term_name, ostrcodes[i]); 395 ostrval[uselevel][i] = NULL; 396 } 397 } 398 return (1); 399 } 400 401 /* 402 * This routine copies the set of names from the termcap entry into 403 * a separate buffer, getting rid of the old obsolete two character 404 * names. 405 */ 406 static void 407 getlongname() 408 { 409 char *b = &bp[0], *l = buflongname; 410 411 /* Skip the two character name */ 412 if (bp[2] == '|') 413 b = &bp[3]; 414 415 /* Copy the rest of the names */ 416 while (*b && *b != ':') 417 *l++ = *b++; 418 *l = '\0'; 419 420 if (b != &bp[0]) { 421 (void) fprintf(stderr, "%s: obsolete 2 character name " 422 "'%2.2s' removed.\n", progname, bp); 423 (void) fprintf(stderr, "\tsynonyms are: '%s'\n", buflongname); 424 } 425 } 426 427 /* 428 * Return the value of the termcap string 'capname' as stored in our list. 429 */ 430 char 431 *getcapstr(char *capname) 432 { 433 int i; 434 435 if (verbose > 1) 436 (void) fprintf(trace, "looking for termcap value of %s.\n", 437 capname); 438 439 /* Check the old termcap list. */ 440 for (i = 0; ostrcodes[i]; i++) 441 if (strcmp(ostrcodes[i], capname) == 0) { 442 if (verbose > 1) { 443 (void) fprintf(trace, "\tvalue is:"); 444 tpr(trace, ostrval[uselevel][i]); 445 (void) fprintf(trace, ".\n"); 446 } 447 return (ostrval[uselevel][i]); 448 } 449 450 if (verbose > 1) 451 (void) fprintf(trace, "termcap name '%s' not found in " 452 "ostrcodes.\n", capname); 453 454 /* Check the terminfo list. */ 455 for (i = 0; strcodes[i]; i++) 456 if (strcmp(strcodes[i], capname) == 0) { 457 if (verbose > 1) { 458 (void) fprintf(trace, "\tvalue is:"); 459 tpr(trace, strval[uselevel][i]); 460 (void) fprintf(trace, ".\n"); 461 } 462 return (strval[uselevel][i]); 463 } 464 465 (void) fprintf(stderr, "%s: TERM=%s: termcap name '%s' not found.\n", 466 progname, term_name, capname); 467 468 return ((char *)NULL); 469 } 470 471 /* 472 * Search for a name in the given table and 473 * return the index. 474 * Someday I'll redo this to use bsearch(). 475 */ 476 /* ARGSUSED */ 477 int 478 search(char *names[], int max, char *infoname) 479 { 480 #ifndef BSEARCH 481 int i; 482 for (i = 0; names [i] != NULL; i++) 483 if (strcmp(names [i], infoname) == 0) 484 return (i); 485 return (-1); 486 #else /* this doesn't work for some reason */ 487 extern char *bsearch(); 488 char **bret; 489 490 bret = (char **)bsearch(infoname, (char *)names, max, 491 sizeof (char *), strcmp); 492 (void) fprintf(trace, "search looking for %s.\n", infoname); 493 (void) fprintf(trace, "base=%#x, bret=%#x, nel=%d.\n", names, 494 bret, max); 495 (void) fprintf(trace, "returning %d.\n", bret == NULL ? -1 : 496 bret - names); 497 if (bret == NULL) 498 return (-1); 499 else 500 return (bret - names); 501 #endif /* OLD */ 502 } 503 504 /* 505 * return the value of the terminfo string 'infoname' 506 */ 507 char 508 *getinfostr(char *infoname) 509 { 510 int i; 511 512 if (verbose > 1) 513 (void) fprintf(trace, "looking for terminfo value of %s.\n", 514 infoname); 515 516 i = search(strnames, strcount, infoname); 517 if (i != -1) { 518 if (verbose > 1) { 519 (void) fprintf(trace, "\tvalue is:"); 520 tpr(trace, strval[uselevel][i]); 521 (void) fprintf(trace, ".\n"); 522 } 523 return (strval[uselevel][i]); 524 } 525 526 if (verbose > 1) 527 (void) fprintf(trace, "terminfo name '%s' not found.\n", 528 infoname); 529 530 return ((char *)NULL); 531 } 532 533 /* 534 * Replace the value stored for the terminfo boolean 535 * capability 'infoname' with the newvalue. 536 */ 537 void 538 putbool(char *infoname, int newvalue) 539 { 540 int i; 541 542 if (verbose > 1) 543 (void) fprintf(trace, "changing value for %s to %d.\n", 544 infoname, newvalue); 545 546 i = search(boolnames, boolcount, infoname); 547 if (i != -1) { 548 if (verbose > 1) 549 (void) fprintf(trace, "value was: %d.\n", 550 boolval[uselevel][i]); 551 552 boolval[uselevel][i] = newvalue; 553 return; 554 } 555 556 (void) fprintf(stderr, "%s: TERM=%s: the boolean name '%s' was not " 557 "found!\n", progname, term_name, infoname); 558 } 559 560 /* 561 * Replace the value stored for the terminfo number 562 * capability 'infoname' with the newvalue. 563 */ 564 void 565 putnum(char *infoname, int newvalue) 566 { 567 int i; 568 569 if (verbose > 1) 570 (void) fprintf(trace, "changing value for %s to %d.\n", 571 infoname, newvalue); 572 573 i = search(numnames, numcount, infoname); 574 if (i != -1) { 575 if (verbose > 1) 576 (void) fprintf(trace, "value was: %d.\n", 577 numval[uselevel][i]); 578 579 numval[uselevel][i] = newvalue; 580 return; 581 } 582 583 (void) fprintf(stderr, "%s: TERM=%s: the numeric name '%s' was not " 584 "found!\n", 585 progname, term_name, infoname); 586 } 587 588 /* 589 * replace the value stored for the terminfo string capability 'infoname' 590 * with the newvalue. 591 */ 592 void 593 putstr(char *infoname, char *newvalue) 594 { 595 int i; 596 597 if (verbose > 1) { 598 (void) fprintf(trace, "changing value for %s to ", infoname); 599 tpr(trace, newvalue); 600 (void) fprintf(trace, ".\n"); 601 } 602 603 i = search(strnames, strcount, infoname); 604 if (i != -1) { 605 if (verbose > 1) { 606 (void) fprintf(trace, "value was:"); 607 tpr(trace, strval[uselevel][i]); 608 (void) fprintf(trace, ".\n"); 609 } 610 strval[uselevel][i] = nextstring; 611 while (*newvalue) 612 *nextstring++ = *newvalue++; 613 *nextstring++ = '\0'; 614 return; 615 } 616 617 (void) fprintf(stderr, "%s: TERM=%s: the string name '%s' was not " 618 "found!\n", 619 progname, term_name, infoname); 620 } 621 622 /* 623 * Add in extra delays if they are not recorded already. 624 * This is done before the padding information has been modified by 625 * changecalculations() below, so the padding information, if there 626 * already, is still at the beginning of the string in termcap format. 627 */ 628 void 629 addpadding(int cappadding, char *infostr) 630 { 631 char *cap; 632 char tempbuffer [100]; 633 634 /* Is there padding to add? */ 635 if (cappadding > 0) 636 /* Is there a string to add it to? */ 637 if (cap = getinfostr(infostr)) 638 /* Is there any padding info already? */ 639 if (ispadchar(*cap)) { 640 /* EMPTY */; 641 /* Assume that the padding info that is there is correct. */ 642 } else { 643 /* Add the padding at the end of the present string. */ 644 (void) snprintf(tempbuffer, sizeof (tempbuffer), 645 "%s$<%d>", cap, cappadding); 646 putstr(infostr, tempbuffer); 647 } else { 648 /* Create a new string that only has the padding. */ 649 (void) sprintf(tempbuffer, "$<%d>", cappadding); 650 putstr(infostr, tempbuffer); 651 } 652 } 653 654 struct 655 { 656 char *capname; 657 char *keyedinfoname; 658 } ko_map[] = { 659 "al", "kil1", 660 "bs", "kbs", /* special addition */ 661 "bt", "kcbt", 662 "cd", "ked", 663 "ce", "kel", 664 "cl", "kclr", 665 "ct", "ktbc", 666 "dc", "kdch1", 667 "dl", "kdl1", 668 "do", "kcud1", 669 "ei", "krmir", 670 "ho", "khome", 671 "ic", "kich1", 672 "im", "kich1", /* special addition */ 673 "le", "kcub1", 674 "ll", "kll", 675 "nd", "kcuf1", 676 "sf", "kind", 677 "sr", "kri", 678 "st", "khts", 679 "up", "kcuu1", 680 /* "", "kctab", */ 681 /* "", "knp", */ 682 /* "", "kpp", */ 683 0, 0 684 }; 685 686 /* 687 * Work with the ko string. It is a comma separated list of keys for which 688 * the keyboard has a key by the same name that emits the same sequence. 689 * For example, ko = dc, im, ei means that there are keys called 690 * delete-character, enter-insert-mode and exit-insert-mode on the keyboard, 691 * and they emit the same sequences as specified in the dc, im and ei 692 * capabilities. 693 */ 694 static void 695 handleko() 696 { 697 char capname[3]; 698 char *capstr; 699 int i, j, found; 700 char *infostr; 701 702 if (verbose > 1) 703 (void) fprintf(trace, "working on termcap ko string.\n"); 704 705 if (ostrval[uselevel][cap_ko] == NULL) 706 return; 707 708 capname[2] = '\0'; 709 for (i = 0; ostrval[uselevel][cap_ko][i] != '\0'; ) { 710 /* isolate the termcap name */ 711 capname[0] = ostrval[uselevel][cap_ko][i++]; 712 if (ostrval[uselevel][cap_ko][i] == '\0') 713 break; 714 capname[1] = ostrval[uselevel][cap_ko][i++]; 715 if (ostrval[uselevel][cap_ko][i] == ',') 716 i++; 717 718 if (verbose > 1) { 719 (void) fprintf(trace, "key termcap name is '"); 720 tpr(trace, capname); 721 (void) fprintf(trace, "'.\n"); 722 } 723 724 /* match it up into our list */ 725 found = 0; 726 for (j = 0; !found && ko_map[j].keyedinfoname != NULL; j++) { 727 if (verbose > 1) 728 (void) fprintf(trace, "looking at termcap name %s.\n", 729 ko_map[j].capname); 730 if (capname[0] == ko_map[j].capname[0] && 731 capname[1] == ko_map[j].capname[1]) { 732 /* add the value to our database */ 733 if ((capstr = getcapstr(capname)) != NULL) { 734 infostr = getinfostr 735 (ko_map[j].keyedinfoname); 736 if (infostr == NULL) { 737 /* skip any possible padding */ 738 /* information */ 739 while (ispadchar(*capstr)) 740 capstr++; 741 putstr(ko_map[j].keyedinfoname, capstr); 742 } else 743 if (strcmp(capstr, infostr) != 0) { 744 (void) fprintf(stderr, 745 "%s: TERM=%s: a function " 746 "key for '%s' was " 747 "specified with the " 748 "value ", progname, 749 term_name, capname); 750 tpr(stderr, capstr); 751 (void) fprintf(stderr, 752 ", but it already has the " 753 "value '"); 754 tpr(stderr, infostr); 755 (void) fprintf(stderr, "'.\n"); 756 } 757 } 758 found = 1; 759 } 760 } 761 762 if (!found) { 763 (void) fprintf(stderr, "%s: TERM=%s: the unknown " 764 "termcap name '%s' was\n", progname, term_name, 765 capname); 766 (void) fprintf(stderr, "specified in the 'ko' " 767 "termcap capability.\n"); 768 } 769 } 770 } 771 772 #define CONTROL(x) ((x) & 037) 773 struct 774 { 775 char vichar; 776 char *keyedinfoname; 777 } ma_map[] = { 778 CONTROL('J'), "kcud1", /* down */ 779 CONTROL('N'), "kcud1", 780 'j', "kcud1", 781 CONTROL('P'), "kcuu1", /* up */ 782 'k', "kcuu1", 783 'h', "kcub1", /* left */ 784 CONTROL('H'), "kcub1", 785 ' ', "kcuf1", /* right */ 786 'l', "kcuf1", 787 'H', "khome", /* home */ 788 CONTROL('L'), "kclr", /* clear */ 789 0, 0 790 }; 791 792 /* 793 * Work with the ma string. This is a list of pairs of characters. 794 * The first character is the what a function key sends. The second 795 * character is the equivalent vi function that should be done when 796 * it receives that character. Note that only function keys that send 797 * a single character could be defined by this list. 798 */ 799 800 void 801 prchar(FILE *stream, int c) 802 { 803 char xbuf[2]; 804 xbuf[0] = c; 805 xbuf[1] = '\0'; 806 (void) fprintf(stream, "%s", iexpand(xbuf)); 807 } 808 809 static void 810 handlema() 811 { 812 char vichar; 813 char cap[2]; 814 int i, j, found; 815 char *infostr; 816 817 if (verbose > 1) 818 (void) fprintf(trace, "working on termcap ma string.\n"); 819 820 if (ostrval[uselevel][cap_ma] == NULL) 821 return; 822 823 cap[1] = '\0'; 824 for (i = 0; ostrval[uselevel][cap_ma][i] != '\0'; ) { 825 /* isolate the key's value */ 826 cap[0] = ostrval[uselevel][cap_ma][i++]; 827 if (verbose > 1) { 828 (void) fprintf(trace, "key value is '"); 829 tpr(trace, cap); 830 (void) fprintf(trace, "'.\n"); 831 } 832 833 if (ostrval[uselevel][cap_ma][i] == '\0') 834 break; 835 836 /* isolate the vi key name */ 837 vichar = ostrval[uselevel][cap_ma][i++]; 838 if (verbose > 1) { 839 (void) fprintf(trace, "the vi key is '"); 840 prchar(trace, vichar); 841 (void) fprintf(trace, "'.\n"); 842 } 843 844 /* match up the vi name in our list */ 845 found = 0; 846 for (j = 0; !found && ma_map[j].keyedinfoname != NULL; j++) { 847 if (verbose > 1) { 848 (void) fprintf(trace, "looking at vi " 849 "character '"); 850 prchar(trace, ma_map[j].vichar); 851 (void) fprintf(trace, "'\n"); 852 } 853 if (vichar == ma_map[j].vichar) { 854 infostr = getinfostr(ma_map[j].keyedinfoname); 855 if (infostr == NULL) 856 putstr(ma_map[j].keyedinfoname, cap); 857 else if (strcmp(cap, infostr) != 0) { 858 (void) fprintf(stderr, "%s: TERM=%s: " 859 "the vi character '", progname, 860 term_name); 861 prchar(stderr, vichar); 862 (void) fprintf(stderr, 863 "' (info '%s') has the value '", 864 ma_map[j].keyedinfoname); 865 tpr(stderr, infostr); 866 (void) fprintf(stderr, "', but 'ma' " 867 "gives '"); 868 prchar(stderr, cap[0]); 869 (void) fprintf(stderr, "'.\n"); 870 } 871 found = 1; 872 } 873 } 874 875 if (!found) { 876 (void) fprintf(stderr, "%s: the unknown vi key '", 877 progname); 878 prchar(stderr, vichar); 879 (void) fprintf(stderr, "' was\n"); 880 (void) fprintf(stderr, "specified in the 'ma' termcap " 881 "capability.\n"); 882 } 883 } 884 } 885 886 /* 887 * Many capabilities were defaulted in termcap which must now be explicitly 888 * given. We'll assume that the defaults are in effect for this terminal. 889 */ 890 void 891 adddefaults() 892 { 893 char *cap; 894 int sg; 895 896 if (verbose > 1) 897 (void) fprintf(trace, "assigning defaults.\n"); 898 899 /* cr was assumed to be ^M, unless nc was given, */ 900 /* which meant it could not be done. */ 901 /* Also, xr meant that ^M acted strangely. */ 902 if ((getinfostr("cr") == NULL) && !oboolval[uselevel][cap_nc] && 903 !oboolval[uselevel][cap_xr]) 904 if ((cap = getcapstr("cr")) == NULL) 905 putstr("cr", "\r"); 906 else 907 putstr("cr", cap); 908 909 /* cursor down was assumed to be ^J if not specified by nl */ 910 if (getinfostr("cud1") == NULL) 911 if (ostrval[uselevel][cap_nl] != NULL) 912 putstr("cud1", ostrval[uselevel][cap_nl]); 913 else 914 putstr("cud1", "\n"); 915 916 /* ind was assumed to be ^J, unless ns was given, */ 917 /* which meant it could not be done. */ 918 if ((getinfostr("ind") == NULL) && !oboolval[uselevel][cap_ns]) 919 if (ostrval[uselevel][cap_nl] == NULL) 920 putstr("ind", "\n"); 921 else 922 putstr("ind", ostrval[uselevel][cap_nl]); 923 924 /* bel was assumed to be ^G */ 925 if (getinfostr("bel") == NULL) 926 putstr("bel", "\07"); 927 928 /* if bs, then could do backspacing, */ 929 /* with value of bc, default of ^H */ 930 if ((getinfostr("cub1") == NULL) && oboolval[uselevel][cap_bs]) 931 if (ostrval[uselevel][cap_bc] != NULL) 932 putstr("cub1", ostrval[uselevel][cap_bc]); 933 else 934 putstr("cub1", "\b"); 935 936 /* default xon to true */ 937 if (!otgetflag("xo")) 938 putbool("xon", 1); 939 940 /* if pt, then hardware tabs are allowed, */ 941 /* with value of ta, default of ^I */ 942 if ((getinfostr("ht") == NULL) && oboolval[uselevel][cap_pt]) 943 if ((cap = getcapstr("ta")) == NULL) 944 putstr("ht", "\t"); 945 else 946 putstr("ht", cap); 947 948 /* The dX numbers are now stored as padding */ 949 /* in the appropriate terminfo string. */ 950 addpadding(onumval[uselevel][cap_dB], "cub1"); 951 addpadding(onumval[uselevel][cap_dC], "cr"); 952 addpadding(onumval[uselevel][cap_dF], "ff"); 953 addpadding(onumval[uselevel][cap_dN], "cud1"); 954 addpadding(onumval[uselevel][cap_dT], "ht"); 955 956 /* The ug and sg caps were essentially identical, */ 957 /* so ug almost never got used. We set sg from ug */ 958 /* if it hasn't already been set. */ 959 if (onumval[uselevel][cap_ug] >= 0 && (sg = otgetnum("sg")) < 0) 960 putnum("xmc", onumval[uselevel][cap_ug]); 961 else if ((onumval[uselevel][cap_ug] >= 0) && 962 (sg >= 0) && (onumval[uselevel][cap_ug] != sg)) 963 (void) fprintf(stderr, 964 "%s: TERM=%s: Warning: termcap sg and ug had different " 965 "values (%d<->%d).\n", progname, term_name, sg, 966 onumval[uselevel][cap_ug]); 967 968 /* The MT boolean was never really part of termcap, */ 969 /* but we can check for it anyways. */ 970 if (oboolval[uselevel][cap_MT] && !otgetflag("km")) 971 putbool("km", 1); 972 973 /* the rs string was renamed r2 (info rs2) */ 974 if ((ostrval[uselevel][cap_rs] != NULL) && 975 (ostrval[uselevel][cap_rs][0] != NULL)) 976 putstr("rs2", ostrval[uselevel][cap_rs]); 977 978 handleko(); 979 handlema(); 980 } 981 982 #define caddch(x) *to++ = (x) 983 984 /* 985 * add the string to the string table 986 */ 987 char 988 *caddstr(char *to, char *str) 989 { 990 while (*str) 991 *to++ = *str++; 992 return (to); 993 } 994 995 /* If there is no padding info or parmed strings, */ 996 /* then we do not need to copy the string. */ 997 int 998 needscopying(char *string) 999 { 1000 /* any string at all? */ 1001 if (string == NULL) 1002 return (0); 1003 1004 /* any padding info? */ 1005 if (ispadchar(*string)) 1006 return (1); 1007 1008 /* any parmed info? */ 1009 while (*string) 1010 if (*string++ == '%') 1011 return (1); 1012 1013 return (0); 1014 } 1015 1016 /* 1017 * Certain manipulations of the stack require strange manipulations of the 1018 * values that are on the stack. To handle these, we save the values of the 1019 * parameters in registers at the very beginning and make the changes in 1020 * the registers. We don't want to do this in the general case because of the 1021 * potential performance loss. 1022 */ 1023 int 1024 fancycap(char *string) 1025 { 1026 int parmset = 0; 1027 1028 while (*string) 1029 if (*string++ == '%') { 1030 switch (*string) { 1031 /* These manipulate just the top value on */ 1032 /* the stack, so we only have to do */ 1033 /* something strange if a %r follows. */ 1034 case '>': case 'B': case 'D': 1035 parmset = 1; 1036 break; 1037 /* If the parm has already been been */ 1038 /* pushed onto the stack by %>, then we */ 1039 /* can not reverse the parms and must get */ 1040 /* them from the registers. */ 1041 case 'r': 1042 if (parmset) 1043 return (1); 1044 break; 1045 /* This manipulates both parameters, so we */ 1046 /* cannot just do one and leave the value */ 1047 /* on the stack like we can with %>, */ 1048 /* %B or %D. */ 1049 case 'n': 1050 return (1); 1051 } 1052 string++; 1053 } 1054 return (0); 1055 } 1056 1057 /* 1058 * Change old style of doing calculations to the new stack style. 1059 * Note that this will not necessarily produce the most efficient string, 1060 * but it will work. 1061 */ 1062 void 1063 changecalculations() 1064 { 1065 int i, currentparm; 1066 char *from, *to = nextstring; 1067 int ch; 1068 int parmset, parmsaved; 1069 char padding[100], *saveto; 1070 1071 for (i = 0; strnames[i]; i++) 1072 if (needscopying(strval[uselevel][i])) { 1073 if (verbose) { 1074 (void) fprintf(trace, "%s needs copying, " 1075 "was:", strnames [i]); 1076 tpr(trace, strval[uselevel][i]); 1077 (void) fprintf(trace, ".\n"); 1078 } 1079 1080 from = strval[uselevel][i]; 1081 strval[uselevel][i] = to; 1082 currentparm = 1; 1083 parmset = 0; 1084 1085 /* Handle padding information. Save it so that it can be */ 1086 /* placed at the end of the string where it should */ 1087 /* have been in the first place. */ 1088 if (ispadchar(*from)) { 1089 saveto = to; 1090 to = padding; 1091 to = caddstr(to, "$<"); 1092 while (isdigit(*from) || *from == '.') 1093 caddch(*from++); 1094 if (*from == '*') 1095 caddch(*from++); 1096 caddch('>'); 1097 caddch('\0'); 1098 to = saveto; 1099 } else 1100 padding[0] = '\0'; 1101 1102 if (fancycap(from)) { 1103 to = caddstr(to, "%p1%Pa%p2%Pb"); 1104 parmsaved = 1; 1105 (void) fprintf(stderr, 1106 "%s: TERM=%s: Warning: the string " 1107 "produced for '%s' may be inefficient.\n", 1108 progname, term_name, strnames[i]); 1109 (void) fprintf(stderr, "It should be " 1110 "looked at by hand.\n"); 1111 } else 1112 parmsaved = 0; 1113 1114 while ((ch = *from++) != '\0') 1115 if (ch != '%') 1116 caddch(ch); 1117 else 1118 switch (ch = *from++) { 1119 case '.': /* %. -> %p1%c */ 1120 case 'd': /* %d -> %p1%d */ 1121 case '2': /* %2 -> %p1%2.2d */ 1122 case '3': /* %3 -> %p1%3.3d */ 1123 case '+': 1124 /* %+x -> %p1%'x'%+%c */ 1125 1126 case '>': 1127 /* %>xy -> %p1%Pc%?%'x'%> */ 1128 /* %t%gc%'y'%+ */ 1129 /* if current value > x, then add y. */ 1130 /* No output. */ 1131 1132 case 'B': 1133 /* %B: BCD */ 1134 /* (16*(x/10))+(x%10) */ 1135 /* No output. */ 1136 /* (Adds Regent 100) */ 1137 1138 case 'D': 1139 /* %D: Reverse coding */ 1140 /* (x-2*(x%16)) */ 1141 /* No output. */ 1142 /* (Delta Data) */ 1143 1144 if (!parmset) 1145 if (parmsaved) { 1146 to = caddstr(to, "%g"); 1147 if (currentparm == 1) 1148 caddch('a'); 1149 else 1150 caddch('b'); 1151 } else { 1152 to = caddstr(to, "%p"); 1153 if (currentparm == 1) 1154 caddch('1'); 1155 else 1156 caddch('2'); 1157 } 1158 currentparm = 3 - currentparm; 1159 parmset = 0; 1160 switch (ch) { 1161 case '.': 1162 to = caddstr(to, "%c"); 1163 break; 1164 case 'd': 1165 to = caddstr(to, "%d"); 1166 break; 1167 case '2': case '3': 1168 #ifdef USG /* Vr2==USG, Vr3==SYSV. Use %02d for Vr2, %2.2d for Vr3 */ 1169 caddch('%'); 1170 caddch('0'); 1171 #else 1172 caddch('%'); 1173 caddch(ch); 1174 caddch('.'); 1175 #endif /* USG vs. SYSV */ 1176 caddch(ch); 1177 caddch('d'); 1178 break; 1179 case '+': 1180 to = caddstr(to, "%'"); 1181 caddch(*from++); 1182 to = caddstr(to, 1183 "'%+%c"); 1184 break; 1185 case '>': 1186 to = caddstr(to, 1187 "%Pc%?%'"); 1188 caddch(*from++); 1189 to = caddstr(to, 1190 "'%>%t%gc%'"); 1191 caddch(*from++); 1192 to = caddstr(to, 1193 "'%+"); 1194 parmset = 1; 1195 break; 1196 case 'B': 1197 to = caddstr(to, 1198 "%Pc%gc%{10}%/%{16}%*%gc%{10}%m%+"); 1199 parmset = 1; 1200 break; 1201 1202 case 'D': 1203 to = caddstr(to, 1204 "%Pc%gc%gc%{16}%m%{2}%*%-"); 1205 parmset = 1; 1206 break; 1207 } 1208 break; 1209 1210 /* %r reverses current parameter */ 1211 case 'r': 1212 currentparm = 3 - currentparm; 1213 break; 1214 1215 /* %n: exclusive-or row AND column */ 1216 /* with 0140, 96 decimal, no output */ 1217 /* (Datamedia 2500, Exidy Sorceror) */ 1218 case 'n': 1219 to = caddstr(to, 1220 "%ga%'`'%^%Pa"); 1221 to = caddstr(to, 1222 "%gb%'`'%^%Pb"); 1223 break; 1224 1225 /* assume %x means %x */ 1226 /* this includes %i and %% */ 1227 default: 1228 caddch('%'); 1229 caddch(ch); 1230 } 1231 to = caddstr(to, padding); 1232 caddch('\0'); 1233 1234 if (verbose) { 1235 (void) fprintf(trace, "and has become:"); 1236 tpr(trace, strval[uselevel][i]); 1237 (void) fprintf(trace, ".\n"); 1238 } 1239 } 1240 nextstring = to; 1241 } 1242 1243 static void 1244 print_no_use_entry() 1245 { 1246 int i; 1247 1248 pr_heading("", buflongname); 1249 pr_bheading(); 1250 1251 for (i = 0; boolcodes[i]; i++) 1252 if (boolval[0][i]) 1253 pr_boolean(boolnames[i], (char *)0, (char *)0, 1); 1254 1255 pr_bfooting(); 1256 pr_sheading(); 1257 1258 for (i = 0; numcodes[i]; i++) 1259 if (numval[0][i] > -1) 1260 pr_number(numnames[i], (char *)0, (char *)0, 1261 numval[0][i]); 1262 1263 pr_nfooting(); 1264 pr_sheading(); 1265 1266 for (i = 0; strcodes[i]; i++) 1267 if (strval[0][i]) 1268 pr_string(strnames[i], (char *)0, (char *)0, 1269 strval[0][i]); 1270 1271 pr_sfooting(); 1272 } 1273 1274 static void 1275 print_use_entry(char *usename) 1276 { 1277 int i; 1278 1279 pr_heading("", buflongname); 1280 pr_bheading(); 1281 1282 for (i = 0; boolcodes[i]; i++) 1283 if (boolval[0][i] && !boolval[1][i]) 1284 pr_boolean(boolnames[i], (char *)0, (char *)0, 1); 1285 else if (!boolval[0][i] && boolval[1][i]) 1286 pr_boolean(boolnames[i], (char *)0, (char *)0, -1); 1287 1288 pr_bfooting(); 1289 pr_nheading(); 1290 1291 for (i = 0; numcodes[i]; i++) 1292 if ((numval[0][i] > -1) && (numval[0][i] != numval[1][i])) 1293 pr_number(numnames[i], (char *)0, (char *)0, 1294 numval[0][i]); 1295 else if ((numval [0] [i] == -1) && (numval [1] [i] > -1)) 1296 pr_number(numnames[i], (char *)0, (char *)0, -1); 1297 1298 pr_nfooting(); 1299 pr_sheading(); 1300 1301 for (i = 0; strcodes[i]; i++) 1302 /* print out str[0] if: */ 1303 /* str[0] != NULL and str[1] == NULL, or str[0] != str[1] */ 1304 if (strval[0][i] && ((strval[1][i] == NULL) || 1305 (strcmp(strval[0][i], strval[1][i]) != 0))) 1306 pr_string(strnames[i], (char *)0, (char *)0, 1307 strval[0][i]); 1308 /* print out @ if str[0] == NULL and str[1] != NULL */ 1309 else if (strval[0][i] == NULL && strval[1][i] != NULL) 1310 pr_string(strnames[i], (char *)0, (char *)0, 1311 (char *)0); 1312 1313 pr_sfooting(); 1314 1315 (void) printf("\tuse=%s,\n", usename); 1316 } 1317 1318 static void 1319 captoinfo() 1320 { 1321 char usename[512]; 1322 char *sterm_name; 1323 1324 if (term_name == NULL) { 1325 (void) fprintf(stderr, "%s: Null term_name given.\n", 1326 progname); 1327 return; 1328 } 1329 1330 if (verbose) 1331 (void) fprintf(trace, "changing cap to info, TERM=%s.\n", 1332 term_name); 1333 1334 uselevel = 0; 1335 if (filltables() == 0) 1336 return; 1337 getlongname(); 1338 adddefaults(); 1339 changecalculations(); 1340 if (TLHtcfound != 0) { 1341 uselevel = 1; 1342 if (verbose) 1343 (void) fprintf(trace, "use= found, %s uses %s.\n", 1344 term_name, TLHtcname); 1345 (void) strcpy(usename, TLHtcname); 1346 sterm_name = term_name; 1347 term_name = usename; 1348 if (filltables() == 0) 1349 return; 1350 adddefaults(); 1351 changecalculations(); 1352 term_name = sterm_name; 1353 print_use_entry(usename); 1354 } else 1355 print_no_use_entry(); 1356 } 1357 1358 1359 #include <signal.h> /* use this file to determine if this is SVR4.0 system */ 1360 1361 static void 1362 use_etc_termcap() 1363 { 1364 if (verbose) 1365 #ifdef SIGSTOP 1366 (void) fprintf(trace, "reading from /usr/share/lib/termcap\n"); 1367 #else /* SIGSTOP */ 1368 (void) fprintf(trace, "reading from /etc/termcap\n"); 1369 #endif /* SIGSTOP */ 1370 term_name = getenv("TERM"); 1371 captoinfo(); 1372 } 1373 1374 static void 1375 initdirname() 1376 { 1377 #if defined(SYSV) || defined(USG) /* handle both Sys Vr2 and Vr3 curses */ 1378 (void) getcwd(dirname, BUFSIZ-2); 1379 #else 1380 (void) getwd(dirname); 1381 #endif /* SYSV || USG */ 1382 if (verbose) 1383 (void) fprintf(trace, "current directory name=%s.\n", dirname); 1384 environ = newenviron; 1385 } 1386 1387 static void 1388 setfilename(char *capfile) 1389 { 1390 if (capfile [0] == '/') 1391 (void) snprintf(TERMCAP, sizeof (TERMCAP), 1392 "TERMCAP=%s", capfile); 1393 else 1394 (void) snprintf(TERMCAP, sizeof (TERMCAP), 1395 "TERMCAP=%s/%s", dirname, capfile); 1396 if (verbose) 1397 (void) fprintf(trace, "setting the environment for %s.\n", 1398 TERMCAP); 1399 } 1400 1401 static void 1402 setterm_name() 1403 { 1404 if (verbose) 1405 (void) fprintf(trace, "setting the environment " 1406 "for TERM=%s.\n", term_name); 1407 (void) snprintf(TERM, sizeof (TERM), "TERM=%s", term_name); 1408 } 1409 1410 /* Look at the current line to see if it is a list of names. */ 1411 /* If it is, return the first name in the list, else NULL. */ 1412 /* As a side-effect, comment lines and blank lines */ 1413 /* are copied to standard output. */ 1414 1415 char 1416 *getterm_name(char *line) 1417 { 1418 char *lineptr = line; 1419 1420 if (verbose) 1421 (void) fprintf(trace, "extracting name from '%s'.\n", line); 1422 1423 /* Copy comment lines out. */ 1424 if (*line == '#') { 1425 if (copycomments) 1426 (void) printf("%s", line); 1427 } 1428 /* Blank lines get copied too. */ 1429 else if (isspace (*line)) { 1430 if (copycomments) { 1431 for (; *lineptr; lineptr++) 1432 if (!isspace(*lineptr)) 1433 break; 1434 if (*lineptr == '\0') 1435 (void) printf("\n"); 1436 } 1437 } 1438 else 1439 for (; *lineptr; lineptr++) 1440 if (*lineptr == '|' || *lineptr == ':') { 1441 *lineptr = '\0'; 1442 if (verbose) 1443 (void) fprintf(trace, 1444 "returning %s.\n", line); 1445 return (line); 1446 } 1447 if (verbose) 1448 (void) fprintf(trace, "returning NULL.\n"); 1449 return (NULL); 1450 } 1451 1452 static void 1453 use_file(char *filename) 1454 { 1455 FILE *termfile; 1456 char buffer[BUFSIZ]; 1457 1458 if (verbose) 1459 (void) fprintf(trace, "reading from %s.\n", filename); 1460 1461 if ((termfile = fopen(filename, "r")) == NULL) { 1462 (void) fprintf(stderr, "%s: cannot open %s for reading.\n", 1463 progname, filename); 1464 return; 1465 } 1466 1467 copycomments++; 1468 setfilename(filename); 1469 1470 while (fgets(buffer, BUFSIZ, termfile) != NULL) { 1471 if ((term_name = getterm_name(buffer)) != NULL) { 1472 setterm_name(); 1473 captoinfo(); 1474 } 1475 } 1476 } 1477 1478 /* 1479 * Sort a name and code table pair according to the name table. 1480 * Use a simple bubble sort for now. Too bad I can't call qsort(3). 1481 * At least I only have to do it once for each table. 1482 */ 1483 static void 1484 sorttable(char *nametable[], char *codetable[]) 1485 { 1486 int i, j; 1487 char *c; 1488 1489 for (i = 0; nametable[i]; i++) 1490 for (j = 0; j < i; j++) 1491 if (strcmp(nametable[i], nametable[j]) < 0) { 1492 c = nametable[i]; 1493 nametable[i] = nametable[j]; 1494 nametable[j] = c; 1495 c = codetable[i]; 1496 codetable[i] = codetable[j]; 1497 codetable[j] = c; 1498 } 1499 } 1500 1501 /* 1502 * Initialize and sort the name and code tables. Allocate space for the 1503 * value tables. 1504 */ 1505 static void 1506 inittables() 1507 { 1508 unsigned int i; 1509 1510 for (i = 0; boolnames [i]; i++) 1511 ; 1512 boolval[0] = (char *)malloc(i * sizeof (char)); 1513 boolval[1] = (char *)malloc(i * sizeof (char)); 1514 boolcount = i; 1515 sorttable(boolnames, boolcodes); 1516 1517 for (i = 0; numcodes [i]; i++) 1518 ; 1519 numval[0] = (short *)malloc(i * sizeof (short)); 1520 numval[1] = (short *)malloc(i * sizeof (short)); 1521 numcount = i; 1522 sorttable(numnames, numcodes); 1523 1524 for (i = 0; strcodes [i]; i++) 1525 ; 1526 strval[0] = (char **)malloc(i * sizeof (char *)); 1527 strval[1] = (char **)malloc(i * sizeof (char *)); 1528 strcount = i; 1529 sorttable(strnames, strcodes); 1530 } 1531 1532 main(int argc, char **argv) 1533 { 1534 int c; 1535 char _capbuffer [8192]; 1536 char _bp [TBUFSIZE]; 1537 char _buflongname [128]; 1538 1539 capbuffer = &_capbuffer[0]; 1540 bp = &_bp[0]; 1541 buflongname = &_buflongname[0]; 1542 progname = argv[0]; 1543 1544 while ((c = getopt(argc, argv, "1vVw:")) != EOF) 1545 switch (c) { 1546 case '1': 1547 pr_onecolumn(1); 1548 break; 1549 case 'w': 1550 pr_width(atoi(optarg)); 1551 break; 1552 case 'v': 1553 verbose++; 1554 break; 1555 case 'V': 1556 (void) printf("%s: version %s\n", progname, 1557 "@(#)curses:screen/captoinfo.c 1.12"); 1558 (void) fflush(stdout); 1559 exit(0); 1560 /* FALLTHROUGH (not really) */ 1561 case '?': 1562 (void) fprintf(stderr, 1563 "usage: %s [-1Vv] [-w width] " 1564 "[filename ...]\n", progname); 1565 (void) fprintf(stderr, "\t-1\tsingle column " 1566 "output\n"); 1567 (void) fprintf(stderr, 1568 "\t-v\tverbose debugging output\n"); 1569 (void) fprintf(stderr, 1570 "\t-V\tprint program version\n"); 1571 exit(-1); 1572 } 1573 1574 /* initialize */ 1575 pr_init(pr_terminfo); 1576 inittables(); 1577 1578 if (optind >= argc) 1579 use_etc_termcap(); 1580 else { 1581 initdirname(); 1582 for (; optind < argc; optind++) 1583 use_file(argv [optind]); 1584 } 1585 1586 return (0); 1587 } 1588 1589 /* fake out the modules in print.c so we don't have to load in */ 1590 /* cexpand.c and infotocap.c */ 1591 /* ARGSUSED */ 1592 int cpr(stream, string) FILE *stream; char *string; { return 0; } 1593