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