1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2002 Jonathan Belson <jon@witchspace.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <sys/queue.h> 34 #include <sys/sysctl.h> 35 36 #include <assert.h> 37 #include <ctype.h> 38 #include <dirent.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <stringlist.h> 44 #include <unistd.h> 45 46 #include "kbdmap.h" 47 48 49 static const char *lang_default = DEFAULT_LANG; 50 static const char *font; 51 static const char *lang; 52 static const char *program; 53 static const char *keymapdir = DEFAULT_VT_KEYMAP_DIR; 54 static const char *fontdir = DEFAULT_VT_FONT_DIR; 55 static const char *font_default = DEFAULT_VT_FONT; 56 static const char *sysconfig = DEFAULT_SYSCONFIG; 57 static const char *font_current; 58 static const char *dir; 59 static const char *menu = ""; 60 61 static int x11; 62 static int using_vt; 63 static int show; 64 static int verbose; 65 static int print; 66 67 68 struct keymap { 69 char *desc; 70 char *keym; 71 int mark; 72 SLIST_ENTRY(keymap) entries; 73 }; 74 static SLIST_HEAD(slisthead, keymap) head = SLIST_HEAD_INITIALIZER(head); 75 76 77 /* 78 * Get keymap entry for 'key', or NULL of not found 79 */ 80 static struct keymap * 81 get_keymap(const char *key) 82 { 83 struct keymap *km; 84 85 SLIST_FOREACH(km, &head, entries) 86 if (!strcmp(km->keym, key)) 87 return km; 88 89 return NULL; 90 } 91 92 /* 93 * Count the number of keymaps we found 94 */ 95 static int 96 get_num_keymaps(void) 97 { 98 struct keymap *km; 99 int count = 0; 100 101 SLIST_FOREACH(km, &head, entries) 102 count++; 103 104 return count; 105 } 106 107 /* 108 * Remove any keymap with given keym 109 */ 110 static void 111 remove_keymap(const char *keym) 112 { 113 struct keymap *km; 114 115 SLIST_FOREACH(km, &head, entries) { 116 if (!strcmp(keym, km->keym)) { 117 SLIST_REMOVE(&head, km, keymap, entries); 118 free(km); 119 break; 120 } 121 } 122 } 123 124 /* 125 * Add to hash with 'key' 126 */ 127 static void 128 add_keymap(const char *desc, int mark, const char *keym) 129 { 130 struct keymap *km, *km_new; 131 132 /* Is there already an entry with this key? */ 133 SLIST_FOREACH(km, &head, entries) { 134 if (!strcmp(km->keym, keym)) { 135 /* Reuse this entry */ 136 free(km->desc); 137 km->desc = strdup(desc); 138 km->mark = mark; 139 return; 140 } 141 } 142 143 km_new = (struct keymap *) malloc (sizeof(struct keymap)); 144 km_new->desc = strdup(desc); 145 km_new->keym = strdup(keym); 146 km_new->mark = mark; 147 148 /* Add to keymap list */ 149 SLIST_INSERT_HEAD(&head, km_new, entries); 150 } 151 152 /* 153 * Return 0 if syscons is in use (to select legacy defaults). 154 */ 155 static int 156 check_vt(void) 157 { 158 size_t len; 159 char term[3]; 160 161 len = 3; 162 if (sysctlbyname("kern.vty", &term, &len, NULL, 0) != 0 || 163 strcmp(term, "vt") != 0) 164 return 0; 165 return 1; 166 } 167 168 /* 169 * Figure out the default language to use. 170 */ 171 static const char * 172 get_locale(void) 173 { 174 const char *locale; 175 176 if ((locale = getenv("LC_ALL")) == NULL && 177 (locale = getenv("LC_CTYPE")) == NULL && 178 (locale = getenv("LANG")) == NULL) 179 locale = lang_default; 180 181 /* Check for alias */ 182 if (!strcmp(locale, "C")) 183 locale = DEFAULT_LANG; 184 185 return locale; 186 } 187 188 /* 189 * Extract filename part 190 */ 191 static const char * 192 extract_name(const char *name) 193 { 194 char *p; 195 196 p = strrchr(name, '/'); 197 if (p != NULL && p[1] != '\0') 198 return p + 1; 199 200 return name; 201 } 202 203 /* 204 * Return file extension or NULL 205 */ 206 static char * 207 get_extension(const char *name) 208 { 209 char *p; 210 211 p = strrchr(name, '.'); 212 213 if (p != NULL && p[1] != '\0') 214 return p; 215 216 return NULL; 217 } 218 219 /* 220 * Read font from /etc/rc.conf else return default. 221 * Freeing the memory is the caller's responsibility. 222 */ 223 static char * 224 get_font(void) 225 { 226 char line[256], buf[20]; 227 char *fnt = NULL; 228 229 FILE *fp = fopen(sysconfig, "r"); 230 if (fp) { 231 while (fgets(line, sizeof(line), fp)) { 232 int a, b, matches; 233 234 if (line[0] == '#') 235 continue; 236 237 matches = sscanf(line, 238 " font%dx%d = \"%20[-.0-9a-zA-Z_]", 239 &a, &b, buf); 240 if (matches==3) { 241 if (strcmp(buf, "NO")) { 242 if (fnt) 243 free(fnt); 244 fnt = (char *) malloc(strlen(buf) + 1); 245 strcpy(fnt, buf); 246 } 247 } 248 } 249 fclose(fp); 250 } else 251 fprintf(stderr, "Could not open %s for reading\n", sysconfig); 252 253 return fnt; 254 } 255 256 /* 257 * Set a font using 'vidcontrol' 258 */ 259 static void 260 vidcontrol(const char *fnt) 261 { 262 char *tmp, *p, *q, *cmd; 263 char ch; 264 int i; 265 266 /* syscons test failed */ 267 if (x11) 268 return; 269 270 if (using_vt) { 271 asprintf(&cmd, "vidcontrol -f %s", fnt); 272 system(cmd); 273 free(cmd); 274 return; 275 } 276 277 tmp = strdup(fnt); 278 279 /* Extract font size */ 280 p = strrchr(tmp, '-'); 281 if (p && p[1] != '\0') { 282 p++; 283 /* Remove any '.fnt' extension */ 284 if ((q = strstr(p, ".fnt"))) 285 *q = '\0'; 286 287 /* 288 * Check font size is valid, with no trailing characters 289 * ('&ch' should not be matched) 290 */ 291 if (sscanf(p, "%dx%d%c", &i, &i, &ch) != 2) 292 fprintf(stderr, "Which font size? %s\n", fnt); 293 else { 294 asprintf(&cmd, "vidcontrol -f %s %s", p, fnt); 295 if (verbose) 296 fprintf(stderr, "%s\n", cmd); 297 system(cmd); 298 free(cmd); 299 } 300 } else 301 fprintf(stderr, "Which font size? %s\n", fnt); 302 303 free(tmp); 304 } 305 306 /* 307 * Execute 'kbdcontrol' with the appropriate arguments 308 */ 309 static void 310 do_kbdcontrol(struct keymap *km) 311 { 312 char *kbd_cmd; 313 asprintf(&kbd_cmd, "kbdcontrol -l %s/%s", dir, km->keym); 314 315 if (!x11) 316 system(kbd_cmd); 317 318 fprintf(stderr, "keymap=\"%s\"\n", km->keym); 319 free(kbd_cmd); 320 } 321 322 /* 323 * Call 'vidcontrol' with the appropriate arguments 324 */ 325 static void 326 do_vidfont(struct keymap *km) 327 { 328 char *vid_cmd, *tmp, *p, *q; 329 330 asprintf(&vid_cmd, "%s/%s", dir, km->keym); 331 vidcontrol(vid_cmd); 332 free(vid_cmd); 333 334 tmp = strdup(km->keym); 335 p = strrchr(tmp, '-'); 336 if (p && p[1]!='\0') { 337 p++; 338 q = get_extension(p); 339 if (q) { 340 *q = '\0'; 341 printf("font%s=%s\n", p, km->keym); 342 } 343 } 344 free(tmp); 345 } 346 347 /* 348 * Display dialog from 'keymaps[]' 349 */ 350 static void 351 show_dialog(struct keymap **km_sorted, int num_keymaps) 352 { 353 FILE *fp; 354 char *cmd, *dialog; 355 char tmp_name[] = "/tmp/_kbd_lang.XXXX"; 356 int fd, i, size; 357 358 fd = mkstemp(tmp_name); 359 if (fd == -1) { 360 fprintf(stderr, "Could not open temporary file \"%s\"\n", 361 tmp_name); 362 exit(1); 363 } 364 asprintf(&dialog, "/usr/bin/dialog --clear --title \"Keyboard Menu\" " 365 "--menu \"%s\" 0 0 0", menu); 366 367 /* start right font, assume that current font is equal 368 * to default font in /etc/rc.conf 369 * 370 * $font is the font which require the language $lang; e.g. 371 * russian *need* a koi8 font 372 * $font_current is the current font from /etc/rc.conf 373 */ 374 if (font && strcmp(font, font_current)) 375 vidcontrol(font); 376 377 /* Build up the command */ 378 size = 0; 379 for (i=0; i<num_keymaps; i++) { 380 /* 381 * Each 'font' is passed as ' "font" ""', so allow the 382 * extra space 383 */ 384 size += strlen(km_sorted[i]->desc) + 6; 385 } 386 387 /* Allow the space for '2> tmpfilename' redirection */ 388 size += strlen(tmp_name) + 3; 389 390 cmd = (char *) malloc(strlen(dialog) + size + 1); 391 strcpy(cmd, dialog); 392 393 for (i=0; i<num_keymaps; i++) { 394 strcat(cmd, " \""); 395 strcat(cmd, km_sorted[i]->desc); 396 strcat(cmd, "\""); 397 strcat(cmd, " \"\""); 398 } 399 400 strcat(cmd, " 2>"); 401 strcat(cmd, tmp_name); 402 403 /* Show the dialog.. */ 404 system(cmd); 405 406 fp = fopen(tmp_name, "r"); 407 if (fp) { 408 char choice[64]; 409 if (fgets(choice, sizeof(choice), fp) != NULL) { 410 /* Find key for desc */ 411 for (i=0; i<num_keymaps; i++) { 412 if (!strcmp(choice, km_sorted[i]->desc)) { 413 if (!strcmp(program, "kbdmap")) 414 do_kbdcontrol(km_sorted[i]); 415 else 416 do_vidfont(km_sorted[i]); 417 break; 418 } 419 } 420 } else { 421 if (font != NULL && strcmp(font, font_current)) 422 /* Cancelled, restore old font */ 423 vidcontrol(font_current); 424 } 425 fclose(fp); 426 } else 427 fprintf(stderr, "Failed to open temporary file"); 428 429 /* Tidy up */ 430 remove(tmp_name); 431 free(cmd); 432 free(dialog); 433 close(fd); 434 } 435 436 /* 437 * Search for 'token' in comma delimited array 'buffer'. 438 * Return true for found, false for not found. 439 */ 440 static int 441 find_token(const char *buffer, const char *token) 442 { 443 char *buffer_tmp, *buffer_copy, *inputstring; 444 char **ap; 445 int found; 446 447 buffer_copy = strdup(buffer); 448 buffer_tmp = buffer_copy; 449 inputstring = buffer_copy; 450 ap = &buffer_tmp; 451 452 found = 0; 453 454 while ((*ap = strsep(&inputstring, ",")) != NULL) { 455 if (strcmp(buffer_tmp, token) == 0) { 456 found = 1; 457 break; 458 } 459 } 460 461 free(buffer_copy); 462 463 return found; 464 } 465 466 /* 467 * Compare function for qsort 468 */ 469 static int 470 compare_keymap(const void *a, const void *b) 471 { 472 473 /* We've been passed pointers to pointers, so: */ 474 const struct keymap *km1 = *((const struct keymap * const *) a); 475 const struct keymap *km2 = *((const struct keymap * const *) b); 476 477 return strcmp(km1->desc, km2->desc); 478 } 479 480 /* 481 * Compare function for qsort 482 */ 483 static int 484 compare_lang(const void *a, const void *b) 485 { 486 const char *l1 = *((const char * const *) a); 487 const char *l2 = *((const char * const *) b); 488 489 return strcmp(l1, l2); 490 } 491 492 /* 493 * Change '8x8' to '8x08' so qsort will put it before eg. '8x14' 494 */ 495 static void 496 kludge_desc(struct keymap **km_sorted, int num_keymaps) 497 { 498 int i; 499 500 for (i=0; i<num_keymaps; i++) { 501 char *p; 502 char *km = km_sorted[i]->desc; 503 if ((p = strstr(km, "8x8")) != NULL) { 504 int len; 505 int j; 506 int offset; 507 508 offset = p - km; 509 510 /* Make enough space for the extra '0' */ 511 len = strlen(km); 512 km = realloc(km, len + 2); 513 514 for (j=len; j!=offset+1; j--) 515 km[j + 1] = km[j]; 516 517 km[offset+2] = '0'; 518 519 km_sorted[i]->desc = km; 520 } 521 } 522 } 523 524 /* 525 * Reverse 'kludge_desc()' - change '8x08' back to '8x8' 526 */ 527 static void 528 unkludge_desc(struct keymap **km_sorted, int num_keymaps) 529 { 530 int i; 531 532 for (i=0; i<num_keymaps; i++) { 533 char *p; 534 char *km = km_sorted[i]->desc; 535 if ((p = strstr(km, "8x08")) != NULL) { 536 p += 2; 537 while (*p++) 538 p[-1] = p[0]; 539 540 km = realloc(km, p - km - 1); 541 km_sorted[i]->desc = km; 542 } 543 } 544 } 545 546 /* 547 * Return 0 if file exists and is readable, else -1 548 */ 549 static int 550 check_file(const char *keym) 551 { 552 int status = 0; 553 554 if (access(keym, R_OK) == -1) { 555 char *fn; 556 asprintf(&fn, "%s/%s", dir, keym); 557 if (access(fn, R_OK) == -1) { 558 if (verbose) 559 fprintf(stderr, "%s not found!\n", fn); 560 status = -1; 561 } 562 free(fn); 563 } else { 564 if (verbose) 565 fprintf(stderr, "No read permission for %s!\n", keym); 566 status = -1; 567 } 568 569 return status; 570 } 571 572 /* 573 * Read options from the relevant configuration file, then 574 * present to user. 575 */ 576 static void 577 menu_read(void) 578 { 579 const char *lg; 580 char *p; 581 int mark, num_keymaps, items, i; 582 char buffer[256], filename[PATH_MAX]; 583 char keym[64], lng[64], desc[256]; 584 char dialect[64], lang_abk[64]; 585 struct keymap *km; 586 struct keymap **km_sorted; 587 struct dirent *dp; 588 StringList *lang_list; 589 FILE *fp; 590 DIR *dirp; 591 592 lang_list = sl_init(); 593 594 sprintf(filename, "%s/INDEX.%s", dir, extract_name(dir)); 595 596 /* en_US.ISO8859-1 -> en_..\.ISO8859-1 */ 597 strlcpy(dialect, lang, sizeof(dialect)); 598 if (strlen(dialect) >= 6 && dialect[2] == '_') { 599 dialect[3] = '.'; 600 dialect[4] = '.'; 601 } 602 603 604 /* en_US.ISO8859-1 -> en */ 605 strlcpy(lang_abk, lang, sizeof(lang_abk)); 606 if (strlen(lang_abk) >= 3 && lang_abk[2] == '_') 607 lang_abk[2] = '\0'; 608 609 fprintf(stderr, "lang_default = %s\n", lang_default); 610 fprintf(stderr, "dialect = %s\n", dialect); 611 fprintf(stderr, "lang_abk = %s\n", lang_abk); 612 613 fp = fopen(filename, "r"); 614 if (fp) { 615 int matches; 616 while (fgets(buffer, sizeof(buffer), fp)) { 617 p = buffer; 618 if (p[0] == '#') 619 continue; 620 621 while (isspace(*p)) 622 p++; 623 624 if (*p == '\0') 625 continue; 626 627 /* Parse input, removing newline */ 628 matches = sscanf(p, "%64[^:]:%64[^:]:%256[^:\n]", 629 keym, lng, desc); 630 if (matches == 3) { 631 if (strcmp(keym, "FONT") 632 && strcmp(keym, "MENU")) { 633 /* Check file exists & is readable */ 634 if (check_file(keym) == -1) 635 continue; 636 } 637 } 638 639 if (show) { 640 /* 641 * Take note of supported languages, which 642 * might be in a comma-delimited list 643 */ 644 char *tmp = strdup(lng); 645 char *delim = tmp; 646 647 for (delim = tmp; ; ) { 648 char ch = *delim++; 649 if (ch == ',' || ch == '\0') { 650 delim[-1] = '\0'; 651 if (!sl_find(lang_list, tmp)) 652 sl_add(lang_list, tmp); 653 if (ch == '\0') 654 break; 655 tmp = delim; 656 } 657 } 658 } 659 /* Set empty language to default language */ 660 if (lng[0] == '\0') 661 lg = lang_default; 662 else 663 lg = lng; 664 665 666 /* 4) Your choice if it exists 667 * 3) Long match eg. en_GB.ISO8859-1 is equal to 668 * en_..\.ISO8859-1 669 * 2) short match 'de' 670 * 1) default langlist 'en' 671 * 0) any language 672 * 673 * Language may be a comma separated list 674 * A higher match overwrites a lower 675 * A later entry overwrites a previous if it exists 676 * twice in the database 677 */ 678 679 /* Check for favoured language */ 680 km = get_keymap(keym); 681 mark = (km) ? km->mark : 0; 682 683 if (find_token(lg, lang)) 684 add_keymap(desc, 4, keym); 685 else if (mark <= 3 && find_token(lg, dialect)) 686 add_keymap(desc, 3, keym); 687 else if (mark <= 2 && find_token(lg, lang_abk)) 688 add_keymap(desc, 2, keym); 689 else if (mark <= 1 && find_token(lg, lang_default)) 690 add_keymap(desc, 1, keym); 691 else if (mark <= 0) 692 add_keymap(desc, 0, keym); 693 } 694 fclose(fp); 695 696 } else 697 fprintf(stderr, "Could not open %s for reading\n", filename); 698 699 if (show) { 700 qsort(lang_list->sl_str, lang_list->sl_cur, sizeof(char*), 701 compare_lang); 702 printf("Currently supported languages: "); 703 for (i=0; i< (int) lang_list->sl_cur; i++) 704 printf("%s ", lang_list->sl_str[i]); 705 puts(""); 706 exit(0); 707 } 708 709 km = get_keymap("MENU"); 710 if (km) 711 /* Take note of menu title */ 712 menu = strdup(km->desc); 713 km = get_keymap("FONT"); 714 if (km) 715 /* Take note of language font */ 716 font = strdup(km->desc); 717 718 /* Remove unwanted items from list */ 719 remove_keymap("MENU"); 720 remove_keymap("FONT"); 721 722 /* Look for keymaps not in database */ 723 dirp = opendir(dir); 724 if (dirp) { 725 while ((dp = readdir(dirp)) != NULL) { 726 const char *ext = get_extension(dp->d_name); 727 if (ext) { 728 if ((!strcmp(ext, ".fnt") || 729 !strcmp(ext, ".kbd")) && 730 !get_keymap(dp->d_name)) { 731 char *q; 732 733 /* Remove any .fnt or .kbd extension */ 734 q = strdup(dp->d_name); 735 *(get_extension(q)) = '\0'; 736 add_keymap(q, 0, dp->d_name); 737 free(q); 738 739 if (verbose) 740 fprintf(stderr, 741 "'%s' not in database\n", 742 dp->d_name); 743 } 744 } 745 } 746 closedir(dirp); 747 } else 748 fprintf(stderr, "Could not open directory '%s'\n", dir); 749 750 /* Sort items in keymap */ 751 num_keymaps = get_num_keymaps(); 752 753 km_sorted = (struct keymap **) 754 malloc(num_keymaps*sizeof(struct keymap *)); 755 756 /* Make array of pointers to items in hash */ 757 items = 0; 758 SLIST_FOREACH(km, &head, entries) 759 km_sorted[items++] = km; 760 761 /* Change '8x8' to '8x08' so sort works as we might expect... */ 762 kludge_desc(km_sorted, num_keymaps); 763 764 qsort(km_sorted, num_keymaps, sizeof(struct keymap *), compare_keymap); 765 766 /* ...change back again */ 767 unkludge_desc(km_sorted, num_keymaps); 768 769 if (print) { 770 for (i=0; i<num_keymaps; i++) 771 printf("%s\n", km_sorted[i]->desc); 772 exit(0); 773 } 774 775 show_dialog(km_sorted, num_keymaps); 776 777 free(km_sorted); 778 } 779 780 /* 781 * Display usage information and exit 782 */ 783 static void 784 usage(void) 785 { 786 787 fprintf(stderr, "usage: %s\t[-K] [-V] [-d|-default] [-h|-help] " 788 "[-l|-lang language]\n\t\t[-p|-print] [-r|-restore] [-s|-show] " 789 "[-v|-verbose]\n", program); 790 exit(1); 791 } 792 793 static void 794 parse_args(int argc, char **argv) 795 { 796 int i; 797 798 for (i=1; i<argc; i++) { 799 if (argv[i][0] != '-') 800 usage(); 801 else if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "-h")) 802 usage(); 803 else if (!strcmp(argv[i], "-verbose") || !strcmp(argv[i], "-v")) 804 verbose = 1; 805 else if (!strcmp(argv[i], "-lang") || !strcmp(argv[i], "-l")) 806 if (i + 1 == argc) 807 usage(); 808 else 809 lang = argv[++i]; 810 else if (!strcmp(argv[i], "-default") || !strcmp(argv[i], "-d")) 811 lang = lang_default; 812 else if (!strcmp(argv[i], "-show") || !strcmp(argv[i], "-s")) 813 show = 1; 814 else if (!strcmp(argv[i], "-print") || !strcmp(argv[i], "-p")) 815 print = 1; 816 else if (!strcmp(argv[i], "-restore") || 817 !strcmp(argv[i], "-r")) { 818 vidcontrol(font_current); 819 exit(0); 820 } else if (!strcmp(argv[i], "-K")) 821 dir = keymapdir; 822 else if (!strcmp(argv[i], "-V")) 823 dir = fontdir; 824 else 825 usage(); 826 } 827 } 828 829 /* 830 * A front-end for the 'vidfont' and 'kbdmap' programs. 831 */ 832 int 833 main(int argc, char **argv) 834 { 835 836 x11 = system("kbdcontrol -d >/dev/null"); 837 838 if (x11) { 839 fprintf(stderr, "You are not on a virtual console - " 840 "expect certain strange side-effects\n"); 841 sleep(2); 842 } 843 844 using_vt = check_vt(); 845 if (using_vt == 0) { 846 keymapdir = DEFAULT_SC_KEYMAP_DIR; 847 fontdir = DEFAULT_SC_FONT_DIR; 848 font_default = DEFAULT_SC_FONT; 849 } 850 851 SLIST_INIT(&head); 852 853 lang = get_locale(); 854 855 program = extract_name(argv[0]); 856 857 font_current = get_font(); 858 if (font_current == NULL) 859 font_current = font_default; 860 861 if (strcmp(program, "kbdmap")) 862 dir = fontdir; 863 else 864 dir = keymapdir; 865 866 /* Parse command line arguments */ 867 parse_args(argc, argv); 868 869 /* Read and display options */ 870 menu_read(); 871 872 return 0; 873 } 874