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