199357Smarkm/*- 299357Smarkm * Copyright (c) 2002 Jonathan Belson <jon@witchspace.com> 399357Smarkm * All rights reserved. 499357Smarkm * 599357Smarkm * Redistribution and use in source and binary forms, with or without 699357Smarkm * modification, are permitted provided that the following conditions 799357Smarkm * are met: 899357Smarkm * 1. Redistributions of source code must retain the above copyright 999357Smarkm * notice, this list of conditions and the following disclaimer. 1099357Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1199357Smarkm * notice, this list of conditions and the following disclaimer in the 1299357Smarkm * documentation and/or other materials provided with the distribution. 1399357Smarkm * 1499357Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1599357Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1699357Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1799357Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1899357Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1999357Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2099357Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2199357Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2299357Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2399357Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2499357Smarkm * SUCH DAMAGE. 2599357Smarkm */ 2699357Smarkm 2799357Smarkm#include <sys/cdefs.h> 2899357Smarkm__FBSDID("$FreeBSD$"); 2999357Smarkm 3099357Smarkm#include <sys/types.h> 3199357Smarkm#include <sys/queue.h> 32270309Sse#include <sys/sysctl.h> 3399357Smarkm 3499357Smarkm#include <assert.h> 3599357Smarkm#include <ctype.h> 3699357Smarkm#include <dirent.h> 37106053Swollman#include <limits.h> 3899357Smarkm#include <stdio.h> 3999357Smarkm#include <stdlib.h> 4099357Smarkm#include <string.h> 4199357Smarkm#include <stringlist.h> 4299357Smarkm#include <unistd.h> 4399357Smarkm 4499357Smarkm#include "kbdmap.h" 4599357Smarkm 4699357Smarkm 4799357Smarkmstatic const char *lang_default = DEFAULT_LANG; 4899357Smarkmstatic const char *font; 4999357Smarkmstatic const char *lang; 5099357Smarkmstatic const char *program; 51270309Ssestatic const char *keymapdir = DEFAULT_VT_KEYMAP_DIR; 52270309Ssestatic const char *fontdir = DEFAULT_VT_FONT_DIR; 53270309Ssestatic const char *font_default = DEFAULT_VT_FONT; 5499357Smarkmstatic const char *sysconfig = DEFAULT_SYSCONFIG; 5599357Smarkmstatic const char *font_current; 5699357Smarkmstatic const char *dir; 5799357Smarkmstatic const char *menu = ""; 5899357Smarkm 5999357Smarkmstatic int x11; 6099357Smarkmstatic int show; 6199357Smarkmstatic int verbose; 6299357Smarkmstatic int print; 6399357Smarkm 6499357Smarkm 6599357Smarkmstruct keymap { 6699357Smarkm char *desc; 6799357Smarkm char *keym; 6899357Smarkm int mark; 6999357Smarkm SLIST_ENTRY(keymap) entries; 7099357Smarkm}; 7199357Smarkmstatic SLIST_HEAD(slisthead, keymap) head = SLIST_HEAD_INITIALIZER(head); 7299357Smarkm 7399357Smarkm 7499357Smarkm/* 7599357Smarkm * Get keymap entry for 'key', or NULL of not found 7699357Smarkm */ 7799357Smarkmstatic struct keymap * 7899357Smarkmget_keymap(const char *key) 7999357Smarkm{ 8099357Smarkm struct keymap *km; 8199357Smarkm 8299357Smarkm SLIST_FOREACH(km, &head, entries) 8399357Smarkm if (!strcmp(km->keym, key)) 8499357Smarkm return km; 8599357Smarkm 8699357Smarkm return NULL; 8799357Smarkm} 8899357Smarkm 8999357Smarkm/* 9099357Smarkm * Count the number of keymaps we found 9199357Smarkm */ 9299357Smarkmstatic int 9399357Smarkmget_num_keymaps(void) 9499357Smarkm{ 9599357Smarkm struct keymap *km; 9699357Smarkm int count = 0; 9799357Smarkm 9899357Smarkm SLIST_FOREACH(km, &head, entries) 9999357Smarkm count++; 10099357Smarkm 10199357Smarkm return count; 10299357Smarkm} 10399357Smarkm 10499357Smarkm/* 10599357Smarkm * Remove any keymap with given keym 10699357Smarkm */ 10799357Smarkmstatic void 10899357Smarkmremove_keymap(const char *keym) 10999357Smarkm{ 11099357Smarkm struct keymap *km; 11199357Smarkm 11299357Smarkm SLIST_FOREACH(km, &head, entries) { 11399357Smarkm if (!strcmp(keym, km->keym)) { 11499357Smarkm SLIST_REMOVE(&head, km, keymap, entries); 11599357Smarkm free(km); 11699357Smarkm break; 11799357Smarkm } 11899357Smarkm } 11999357Smarkm} 12099357Smarkm 12199357Smarkm/* 12299357Smarkm * Add to hash with 'key' 12399357Smarkm */ 12499357Smarkmstatic void 12599357Smarkmadd_keymap(const char *desc, int mark, const char *keym) 12699357Smarkm{ 12799357Smarkm struct keymap *km, *km_new; 12899357Smarkm 12999357Smarkm /* Is there already an entry with this key? */ 13099357Smarkm SLIST_FOREACH(km, &head, entries) { 13199357Smarkm if (!strcmp(km->keym, keym)) { 13299357Smarkm /* Reuse this entry */ 13399357Smarkm free(km->desc); 13499357Smarkm km->desc = strdup(desc); 13599357Smarkm km->mark = mark; 13699357Smarkm return; 13799357Smarkm } 13899357Smarkm } 13999357Smarkm 14099357Smarkm km_new = (struct keymap *) malloc (sizeof(struct keymap)); 14199357Smarkm km_new->desc = strdup(desc); 14299357Smarkm km_new->keym = strdup(keym); 14399357Smarkm km_new->mark = mark; 14499357Smarkm 14599357Smarkm /* Add to keymap list */ 14699357Smarkm SLIST_INSERT_HEAD(&head, km_new, entries); 14799357Smarkm} 14899357Smarkm 14999357Smarkm/* 150270309Sse * Return 0 if syscons is in use (to select legacy defaults). 151270309Sse */ 152270309Ssestatic int 153270309Ssecheck_newcons(void) 154270309Sse{ 155270309Sse size_t len; 156270309Sse char term[3]; 157270309Sse 158270309Sse len = 3; 159270309Sse if (sysctlbyname("kern.vty", &term, &len, NULL, 0) != 0 || 160270309Sse strcmp(term, "vt") != 0) 161270309Sse return 0; 162270309Sse return -1; 163270309Sse} 164270309Sse 165270309Sse/* 16699357Smarkm * Figure out the default language to use. 16799357Smarkm */ 16899357Smarkmstatic const char * 16999357Smarkmget_locale(void) 17099357Smarkm{ 17199357Smarkm const char *locale; 17299357Smarkm 17399357Smarkm if ((locale = getenv("LC_ALL")) == NULL && 17499357Smarkm (locale = getenv("LC_CTYPE")) == NULL && 17599357Smarkm (locale = getenv("LANG")) == NULL) 17699357Smarkm locale = lang_default; 17799357Smarkm 17899357Smarkm /* Check for alias */ 17999357Smarkm if (!strcmp(locale, "C")) 18099357Smarkm locale = DEFAULT_LANG; 18199357Smarkm 18299357Smarkm return locale; 18399357Smarkm} 18499357Smarkm 18599357Smarkm/* 18699357Smarkm * Extract filename part 18799357Smarkm */ 18899357Smarkmstatic const char * 18999357Smarkmextract_name(const char *name) 19099357Smarkm{ 19199357Smarkm char *p; 19299357Smarkm 19399357Smarkm p = strrchr(name, '/'); 19499357Smarkm if (p != NULL && p[1] != '\0') 19599357Smarkm return p + 1; 19699357Smarkm 19799357Smarkm return name; 19899357Smarkm} 19999357Smarkm 20099357Smarkm/* 20199357Smarkm * Return file extension or NULL 20299357Smarkm */ 20399357Smarkmstatic char * 20499357Smarkmget_extension(const char *name) 20599357Smarkm{ 20699357Smarkm char *p; 20799357Smarkm 20899357Smarkm p = strrchr(name, '.'); 20999357Smarkm 21099357Smarkm if (p != NULL && p[1] != '\0') 21199357Smarkm return p; 21299357Smarkm 21399357Smarkm return NULL; 21499357Smarkm} 21599357Smarkm 21699357Smarkm/* 21799357Smarkm * Read font from /etc/rc.conf else return default. 21899357Smarkm * Freeing the memory is the caller's responsibility. 21999357Smarkm */ 22099357Smarkmstatic char * 22199357Smarkmget_font(void) 22299357Smarkm{ 22399357Smarkm char line[256], buf[20]; 22499357Smarkm char *fnt = NULL; 22599357Smarkm 22699357Smarkm FILE *fp = fopen(sysconfig, "r"); 22799357Smarkm if (fp) { 22899357Smarkm while (fgets(line, sizeof(line), fp)) { 22999357Smarkm int a, b, matches; 23099357Smarkm 23199357Smarkm if (line[0] == '#') 23299357Smarkm continue; 23399357Smarkm 23499357Smarkm matches = sscanf(line, 23599357Smarkm " font%dx%d = \"%20[-.0-9a-zA-Z_]", 23699357Smarkm &a, &b, buf); 23799357Smarkm if (matches==3) { 23899357Smarkm if (strcmp(buf, "NO")) { 23999357Smarkm if (fnt) 24099357Smarkm free(fnt); 24199357Smarkm fnt = (char *) malloc(strlen(buf) + 1); 24299357Smarkm strcpy(fnt, buf); 24399357Smarkm } 24499357Smarkm } 24599357Smarkm } 246222568Sjh fclose(fp); 24799357Smarkm } else 24899357Smarkm fprintf(stderr, "Could not open %s for reading\n", sysconfig); 24999357Smarkm 25099357Smarkm return fnt; 25199357Smarkm} 25299357Smarkm 25399357Smarkm/* 25499357Smarkm * Set a font using 'vidcontrol' 25599357Smarkm */ 25699357Smarkmstatic void 25799357Smarkmvidcontrol(const char *fnt) 25899357Smarkm{ 25999357Smarkm char *tmp, *p, *q; 26099357Smarkm char ch; 26199357Smarkm int i; 26299357Smarkm 26399357Smarkm /* syscons test failed */ 26499357Smarkm if (x11) 26599357Smarkm return; 26699357Smarkm 26799357Smarkm tmp = strdup(fnt); 26899357Smarkm 26999357Smarkm /* Extract font size */ 27099357Smarkm p = strrchr(tmp, '-'); 27199357Smarkm if (p && p[1] != '\0') { 27299357Smarkm p++; 27399357Smarkm /* Remove any '.fnt' extension */ 27499357Smarkm if ((q = strstr(p, ".fnt"))) 27599357Smarkm *q = '\0'; 27699357Smarkm 27799357Smarkm /* 27899357Smarkm * Check font size is valid, with no trailing characters 27999357Smarkm * ('&ch' should not be matched) 28099357Smarkm */ 28199357Smarkm if (sscanf(p, "%dx%d%c", &i, &i, &ch) != 2) 28299357Smarkm fprintf(stderr, "Which font size? %s\n", fnt); 28399357Smarkm else { 28499357Smarkm char *cmd; 28599357Smarkm asprintf(&cmd, "vidcontrol -f %s %s", p, fnt); 28699357Smarkm if (verbose) 28799357Smarkm fprintf(stderr, "%s\n", cmd); 28899357Smarkm system(cmd); 28999357Smarkm free(cmd); 29099357Smarkm } 29199357Smarkm } else 29299357Smarkm fprintf(stderr, "Which font size? %s\n", fnt); 29399357Smarkm 29499357Smarkm free(tmp); 29599357Smarkm} 29699357Smarkm 29799357Smarkm/* 29899357Smarkm * Execute 'kbdcontrol' with the appropriate arguments 29999357Smarkm */ 30099357Smarkmstatic void 30199357Smarkmdo_kbdcontrol(struct keymap *km) 30299357Smarkm{ 30399357Smarkm char *kbd_cmd; 30499357Smarkm asprintf(&kbd_cmd, "kbdcontrol -l %s/%s", dir, km->keym); 30599357Smarkm 30699357Smarkm if (!x11) 30799357Smarkm system(kbd_cmd); 30899357Smarkm 309226439Snwhitehorn fprintf(stderr, "keymap=\"%s\"\n", km->keym); 31099357Smarkm free(kbd_cmd); 31199357Smarkm} 31299357Smarkm 31399357Smarkm/* 31499357Smarkm * Call 'vidcontrol' with the appropriate arguments 31599357Smarkm */ 31699357Smarkmstatic void 31799357Smarkmdo_vidfont(struct keymap *km) 31899357Smarkm{ 31999357Smarkm char *vid_cmd, *tmp, *p, *q; 32099357Smarkm 32199357Smarkm asprintf(&vid_cmd, "%s/%s", dir, km->keym); 32299357Smarkm vidcontrol(vid_cmd); 32399357Smarkm free(vid_cmd); 32499357Smarkm 32599357Smarkm tmp = strdup(km->keym); 32699357Smarkm p = strrchr(tmp, '-'); 32799357Smarkm if (p && p[1]!='\0') { 32899357Smarkm p++; 32999357Smarkm q = get_extension(p); 33099357Smarkm if (q) { 33199357Smarkm *q = '\0'; 33299357Smarkm printf("font%s=%s\n", p, km->keym); 33399357Smarkm } 33499357Smarkm } 33599357Smarkm free(tmp); 33699357Smarkm} 33799357Smarkm 33899357Smarkm/* 33999357Smarkm * Display dialog from 'keymaps[]' 34099357Smarkm */ 34199357Smarkmstatic void 34299357Smarkmshow_dialog(struct keymap **km_sorted, int num_keymaps) 34399357Smarkm{ 34499357Smarkm FILE *fp; 34599357Smarkm char *cmd, *dialog; 34699357Smarkm char tmp_name[] = "/tmp/_kbd_lang.XXXX"; 34799357Smarkm int fd, i, size; 34899357Smarkm 34999357Smarkm fd = mkstemp(tmp_name); 35099357Smarkm if (fd == -1) { 35199357Smarkm fprintf(stderr, "Could not open temporary file \"%s\"\n", 35299357Smarkm tmp_name); 35399357Smarkm exit(1); 35499357Smarkm } 35599357Smarkm asprintf(&dialog, "/usr/bin/dialog --clear --title \"Keyboard Menu\" " 356217359Snwhitehorn "--menu \"%s\" 0 0 0", menu); 35799357Smarkm 35899357Smarkm /* start right font, assume that current font is equal 35999357Smarkm * to default font in /etc/rc.conf 36099357Smarkm * 36199357Smarkm * $font is the font which require the language $lang; e.g. 36299357Smarkm * russian *need* a koi8 font 36399357Smarkm * $font_current is the current font from /etc/rc.conf 36499357Smarkm */ 36599357Smarkm if (font && strcmp(font, font_current)) 36699357Smarkm vidcontrol(font); 36799357Smarkm 36899357Smarkm /* Build up the command */ 36999357Smarkm size = 0; 37099357Smarkm for (i=0; i<num_keymaps; i++) { 37199357Smarkm /* 37299357Smarkm * Each 'font' is passed as ' "font" ""', so allow the 37399357Smarkm * extra space 37499357Smarkm */ 37599357Smarkm size += strlen(km_sorted[i]->desc) + 6; 37699357Smarkm } 37799357Smarkm 37899357Smarkm /* Allow the space for '2> tmpfilename' redirection */ 37999357Smarkm size += strlen(tmp_name) + 3; 38099357Smarkm 38199357Smarkm cmd = (char *) malloc(strlen(dialog) + size + 1); 38299357Smarkm strcpy(cmd, dialog); 38399357Smarkm 38499357Smarkm for (i=0; i<num_keymaps; i++) { 38599357Smarkm strcat(cmd, " \""); 38699357Smarkm strcat(cmd, km_sorted[i]->desc); 38799357Smarkm strcat(cmd, "\""); 38899357Smarkm strcat(cmd, " \"\""); 38999357Smarkm } 39099357Smarkm 39199357Smarkm strcat(cmd, " 2>"); 39299357Smarkm strcat(cmd, tmp_name); 39399357Smarkm 39499357Smarkm /* Show the dialog.. */ 39599357Smarkm system(cmd); 39699357Smarkm 39799357Smarkm fp = fopen(tmp_name, "r"); 39899357Smarkm if (fp) { 39999357Smarkm char choice[64]; 400167260Skevlo if (fgets(choice, sizeof(choice), fp) != NULL) { 40199357Smarkm /* Find key for desc */ 40299357Smarkm for (i=0; i<num_keymaps; i++) { 40399357Smarkm if (!strcmp(choice, km_sorted[i]->desc)) { 40499357Smarkm if (!strcmp(program, "kbdmap")) 40599357Smarkm do_kbdcontrol(km_sorted[i]); 40699357Smarkm else 40799357Smarkm do_vidfont(km_sorted[i]); 40899357Smarkm break; 40999357Smarkm } 41099357Smarkm } 41199357Smarkm } else { 41299357Smarkm if (font != NULL && strcmp(font, font_current)) 41399357Smarkm /* Cancelled, restore old font */ 41499357Smarkm vidcontrol(font_current); 41599357Smarkm } 41699357Smarkm fclose(fp); 41799357Smarkm } else 41899357Smarkm fprintf(stderr, "Failed to open temporary file"); 41999357Smarkm 42099357Smarkm /* Tidy up */ 42199357Smarkm remove(tmp_name); 42299357Smarkm free(cmd); 42399357Smarkm free(dialog); 42499357Smarkm close(fd); 42599357Smarkm} 42699357Smarkm 42799357Smarkm/* 42899357Smarkm * Search for 'token' in comma delimited array 'buffer'. 42999357Smarkm * Return true for found, false for not found. 43099357Smarkm */ 43199357Smarkmstatic int 43299357Smarkmfind_token(const char *buffer, const char *token) 43399357Smarkm{ 43499357Smarkm char *buffer_tmp, *buffer_copy, *inputstring; 43599357Smarkm char **ap; 43699357Smarkm int found; 43799357Smarkm 43899357Smarkm buffer_copy = strdup(buffer); 43999357Smarkm buffer_tmp = buffer_copy; 44099357Smarkm inputstring = buffer_copy; 44199357Smarkm ap = &buffer_tmp; 44299357Smarkm 44399357Smarkm found = 0; 44499357Smarkm 44599357Smarkm while ((*ap = strsep(&inputstring, ",")) != NULL) { 44699357Smarkm if (strcmp(buffer_tmp, token) == 0) { 44799357Smarkm found = 1; 44899357Smarkm break; 44999357Smarkm } 45099357Smarkm } 45199357Smarkm 45299357Smarkm free(buffer_copy); 45399357Smarkm 45499357Smarkm return found; 45599357Smarkm} 45699357Smarkm 45799357Smarkm/* 45899357Smarkm * Compare function for qsort 45999357Smarkm */ 46099357Smarkmstatic int 46199357Smarkmcompare_keymap(const void *a, const void *b) 46299357Smarkm{ 46399357Smarkm 46499357Smarkm /* We've been passed pointers to pointers, so: */ 46599357Smarkm const struct keymap *km1 = *((const struct keymap * const *) a); 46699357Smarkm const struct keymap *km2 = *((const struct keymap * const *) b); 46799357Smarkm 46899357Smarkm return strcmp(km1->desc, km2->desc); 46999357Smarkm} 47099357Smarkm 47199357Smarkm/* 47299357Smarkm * Compare function for qsort 47399357Smarkm */ 47499357Smarkmstatic int 47599357Smarkmcompare_lang(const void *a, const void *b) 47699357Smarkm{ 47799357Smarkm const char *l1 = *((const char * const *) a); 47899357Smarkm const char *l2 = *((const char * const *) b); 47999357Smarkm 48099357Smarkm return strcmp(l1, l2); 48199357Smarkm} 48299357Smarkm 48399357Smarkm/* 48499357Smarkm * Change '8x8' to '8x08' so qsort will put it before eg. '8x14' 48599357Smarkm */ 48699357Smarkmstatic void 48799357Smarkmkludge_desc(struct keymap **km_sorted, int num_keymaps) 48899357Smarkm{ 48999357Smarkm int i; 49099357Smarkm 49199357Smarkm for (i=0; i<num_keymaps; i++) { 49299357Smarkm char *p; 49399357Smarkm char *km = km_sorted[i]->desc; 49499357Smarkm if ((p = strstr(km, "8x8")) != NULL) { 49599357Smarkm int len; 49699357Smarkm int j; 49799357Smarkm int offset; 49899357Smarkm 49999357Smarkm offset = p - km; 50099357Smarkm 50199357Smarkm /* Make enough space for the extra '0' */ 50299357Smarkm len = strlen(km); 50399357Smarkm km = realloc(km, len + 2); 50499357Smarkm 50599357Smarkm for (j=len; j!=offset+1; j--) 50699357Smarkm km[j + 1] = km[j]; 50799357Smarkm 50899357Smarkm km[offset+2] = '0'; 50999357Smarkm 51099357Smarkm km_sorted[i]->desc = km; 51199357Smarkm } 51299357Smarkm } 51399357Smarkm} 51499357Smarkm 51599357Smarkm/* 51699357Smarkm * Reverse 'kludge_desc()' - change '8x08' back to '8x8' 51799357Smarkm */ 51899357Smarkmstatic void 51999357Smarkmunkludge_desc(struct keymap **km_sorted, int num_keymaps) 52099357Smarkm{ 52199357Smarkm int i; 52299357Smarkm 52399357Smarkm for (i=0; i<num_keymaps; i++) { 52499357Smarkm char *p; 52599357Smarkm char *km = km_sorted[i]->desc; 52699357Smarkm if ((p = strstr(km, "8x08")) != NULL) { 52799357Smarkm p += 2; 52899357Smarkm while (*p++) 52999357Smarkm p[-1] = p[0]; 53099357Smarkm 53199357Smarkm km = realloc(km, p - km - 1); 53299357Smarkm km_sorted[i]->desc = km; 53399357Smarkm } 53499357Smarkm } 53599357Smarkm} 53699357Smarkm 53799357Smarkm/* 53899357Smarkm * Return 0 if file exists and is readable, else -1 53999357Smarkm */ 54099357Smarkmstatic int 54199357Smarkmcheck_file(const char *keym) 54299357Smarkm{ 54399357Smarkm int status = 0; 54499357Smarkm 54599357Smarkm if (access(keym, R_OK) == -1) { 54699357Smarkm char *fn; 54799357Smarkm asprintf(&fn, "%s/%s", dir, keym); 54899357Smarkm if (access(fn, R_OK) == -1) { 54999357Smarkm if (verbose) 55099357Smarkm fprintf(stderr, "%s not found!\n", fn); 55199357Smarkm status = -1; 55299357Smarkm } 55399357Smarkm free(fn); 55499357Smarkm } else { 55599357Smarkm if (verbose) 55699357Smarkm fprintf(stderr, "No read permission for %s!\n", keym); 55799357Smarkm status = -1; 55899357Smarkm } 55999357Smarkm 56099357Smarkm return status; 56199357Smarkm} 56299357Smarkm 56399357Smarkm/* 564228990Suqs * Read options from the relevant configuration file, then 56599357Smarkm * present to user. 56699357Smarkm */ 56799357Smarkmstatic void 56899357Smarkmmenu_read(void) 56999357Smarkm{ 57099357Smarkm const char *lg; 57199357Smarkm char *p; 57299357Smarkm int mark, num_keymaps, items, i; 57399357Smarkm char buffer[256], filename[PATH_MAX]; 57499357Smarkm char keym[64], lng[64], desc[64]; 57599357Smarkm char dialect[64], lang_abk[64]; 57699357Smarkm struct keymap *km; 57799357Smarkm struct keymap **km_sorted; 57899357Smarkm struct dirent *dp; 57999357Smarkm StringList *lang_list; 58099357Smarkm FILE *fp; 58199357Smarkm DIR *dirp; 58299357Smarkm 58399357Smarkm lang_list = sl_init(); 58499357Smarkm 58599357Smarkm sprintf(filename, "%s/INDEX.%s", dir, extract_name(dir)); 58699357Smarkm 58799357Smarkm /* en_US.ISO8859-1 -> en_..\.ISO8859-1 */ 58899357Smarkm strlcpy(dialect, lang, sizeof(dialect)); 589147685Sru if (strlen(dialect) >= 6 && dialect[2] == '_') { 59099357Smarkm dialect[3] = '.'; 59199357Smarkm dialect[4] = '.'; 59299357Smarkm } 59399357Smarkm 59499357Smarkm 59599357Smarkm /* en_US.ISO8859-1 -> en */ 59699357Smarkm strlcpy(lang_abk, lang, sizeof(lang_abk)); 597147685Sru if (strlen(lang_abk) >= 3 && lang_abk[2] == '_') 598147685Sru lang_abk[2] = '\0'; 59999357Smarkm 60099357Smarkm fprintf(stderr, "lang_default = %s\n", lang_default); 60199357Smarkm fprintf(stderr, "dialect = %s\n", dialect); 60299357Smarkm fprintf(stderr, "lang_abk = %s\n", lang_abk); 60399357Smarkm 60499357Smarkm fp = fopen(filename, "r"); 60599357Smarkm if (fp) { 60699357Smarkm int matches; 60799357Smarkm while (fgets(buffer, sizeof(buffer), fp)) { 60899357Smarkm p = buffer; 60999357Smarkm if (p[0] == '#') 61099357Smarkm continue; 61199357Smarkm 61299357Smarkm while (isspace(*p)) 61399357Smarkm p++; 61499357Smarkm 61599357Smarkm if (*p == '\0') 61699357Smarkm continue; 61799357Smarkm 61899357Smarkm /* Parse input, removing newline */ 61999357Smarkm matches = sscanf(p, "%64[^:]:%64[^:]:%64[^:\n]", 62099357Smarkm keym, lng, desc); 62199357Smarkm if (matches == 3) { 62299357Smarkm if (strcmp(keym, "FONT") 62399357Smarkm && strcmp(keym, "MENU")) { 62499357Smarkm /* Check file exists & is readable */ 62599357Smarkm if (check_file(keym) == -1) 62699357Smarkm continue; 62799357Smarkm } 62899357Smarkm } 62999357Smarkm 63099357Smarkm if (show) { 63199357Smarkm /* 63299357Smarkm * Take note of supported languages, which 63399357Smarkm * might be in a comma-delimited list 63499357Smarkm */ 63599357Smarkm char *tmp = strdup(lng); 63699357Smarkm char *delim = tmp; 63799357Smarkm 63899357Smarkm for (delim = tmp; ; ) { 63999357Smarkm char ch = *delim++; 64099357Smarkm if (ch == ',' || ch == '\0') { 64199357Smarkm delim[-1] = '\0'; 64299357Smarkm if (!sl_find(lang_list, tmp)) 64399357Smarkm sl_add(lang_list, tmp); 64499357Smarkm if (ch == '\0') 64599357Smarkm break; 64699357Smarkm tmp = delim; 64799357Smarkm } 64899357Smarkm } 64999357Smarkm } 65099357Smarkm /* Set empty language to default language */ 65199357Smarkm if (lng[0] == '\0') 65299357Smarkm lg = lang_default; 65399357Smarkm else 65499357Smarkm lg = lng; 65599357Smarkm 65699357Smarkm 65799357Smarkm /* 4) Your choice if it exists 65899357Smarkm * 3) Long match eg. en_GB.ISO8859-1 is equal to 65999357Smarkm * en_..\.ISO8859-1 66099357Smarkm * 2) short match 'de' 66199357Smarkm * 1) default langlist 'en' 66299357Smarkm * 0) any language 66399357Smarkm * 66499357Smarkm * Language may be a comma separated list 66599357Smarkm * A higher match overwrites a lower 66699357Smarkm * A later entry overwrites a previous if it exists 66799357Smarkm * twice in the database 66899357Smarkm */ 66999357Smarkm 67099357Smarkm /* Check for favoured language */ 67199357Smarkm km = get_keymap(keym); 67299357Smarkm mark = (km) ? km->mark : 0; 67399357Smarkm 67499357Smarkm if (find_token(lg, lang)) 67599357Smarkm add_keymap(desc, 4, keym); 67699357Smarkm else if (mark <= 3 && find_token(lg, dialect)) 67799357Smarkm add_keymap(desc, 3, keym); 67899357Smarkm else if (mark <= 2 && find_token(lg, lang_abk)) 67999357Smarkm add_keymap(desc, 2, keym); 68099357Smarkm else if (mark <= 1 && find_token(lg, lang_default)) 68199357Smarkm add_keymap(desc, 1, keym); 68299357Smarkm else if (mark <= 0) 68399357Smarkm add_keymap(desc, 0, keym); 68499357Smarkm } 68599357Smarkm fclose(fp); 68699357Smarkm 68799357Smarkm } else 68899357Smarkm printf("Could not open file\n"); 68999357Smarkm 69099357Smarkm if (show) { 69199357Smarkm qsort(lang_list->sl_str, lang_list->sl_cur, sizeof(char*), 69299357Smarkm compare_lang); 69399357Smarkm printf("Currently supported languages: "); 69499357Smarkm for (i=0; i< (int) lang_list->sl_cur; i++) 69599357Smarkm printf("%s ", lang_list->sl_str[i]); 69699357Smarkm puts(""); 69799357Smarkm exit(0); 69899357Smarkm } 69999357Smarkm 70099357Smarkm km = get_keymap("MENU"); 70199357Smarkm if (km) 70299357Smarkm /* Take note of menu title */ 70399357Smarkm menu = strdup(km->desc); 70499357Smarkm km = get_keymap("FONT"); 70599357Smarkm if (km) 70699357Smarkm /* Take note of language font */ 70799357Smarkm font = strdup(km->desc); 70899357Smarkm 70999357Smarkm /* Remove unwanted items from list */ 71099357Smarkm remove_keymap("MENU"); 71199357Smarkm remove_keymap("FONT"); 71299357Smarkm 71399357Smarkm /* Look for keymaps not in database */ 71499357Smarkm dirp = opendir(dir); 71599357Smarkm if (dirp) { 71699357Smarkm while ((dp = readdir(dirp)) != NULL) { 71799357Smarkm const char *ext = get_extension(dp->d_name); 71899357Smarkm if (ext) { 71999357Smarkm if ((!strcmp(ext, ".fnt") || 72099357Smarkm !strcmp(ext, ".kbd")) && 72199357Smarkm !get_keymap(dp->d_name)) { 72299357Smarkm char *q; 72399357Smarkm 72499357Smarkm /* Remove any .fnt or .kbd extension */ 72599357Smarkm q = strdup(dp->d_name); 72699357Smarkm *(get_extension(q)) = '\0'; 72799357Smarkm add_keymap(q, 0, dp->d_name); 72899357Smarkm free(q); 72999357Smarkm 73099357Smarkm if (verbose) 73199357Smarkm fprintf(stderr, 73299357Smarkm "'%s' not in database\n", 73399357Smarkm dp->d_name); 73499357Smarkm } 73599357Smarkm } 73699357Smarkm } 73799357Smarkm closedir(dirp); 73899357Smarkm } else 73999357Smarkm fprintf(stderr, "Could not open directory '%s'\n", dir); 74099357Smarkm 74199357Smarkm /* Sort items in keymap */ 74299357Smarkm num_keymaps = get_num_keymaps(); 74399357Smarkm 74499357Smarkm km_sorted = (struct keymap **) 74599357Smarkm malloc(num_keymaps*sizeof(struct keymap *)); 74699357Smarkm 74799357Smarkm /* Make array of pointers to items in hash */ 74899357Smarkm items = 0; 74999357Smarkm SLIST_FOREACH(km, &head, entries) 75099357Smarkm km_sorted[items++] = km; 75199357Smarkm 75299357Smarkm /* Change '8x8' to '8x08' so sort works as we might expect... */ 75399357Smarkm kludge_desc(km_sorted, num_keymaps); 75499357Smarkm 75599357Smarkm qsort(km_sorted, num_keymaps, sizeof(struct keymap *), compare_keymap); 75699357Smarkm 75799357Smarkm /* ...change back again */ 75899357Smarkm unkludge_desc(km_sorted, num_keymaps); 75999357Smarkm 76099357Smarkm if (print) { 76199357Smarkm for (i=0; i<num_keymaps; i++) 76299357Smarkm printf("%s\n", km_sorted[i]->desc); 76399357Smarkm exit(0); 76499357Smarkm } 76599357Smarkm 76699357Smarkm show_dialog(km_sorted, num_keymaps); 76799357Smarkm 76899357Smarkm free(km_sorted); 76999357Smarkm} 77099357Smarkm 77199357Smarkm/* 77299357Smarkm * Display usage information and exit 77399357Smarkm */ 77499357Smarkmstatic void 77599357Smarkmusage(void) 77699357Smarkm{ 77799357Smarkm 77899357Smarkm fprintf(stderr, "usage: %s\t[-K] [-V] [-d|-default] [-h|-help] " 77999357Smarkm "[-l|-lang language]\n\t\t[-p|-print] [-r|-restore] [-s|-show] " 78099357Smarkm "[-v|-verbose]\n", program); 78199357Smarkm exit(1); 78299357Smarkm} 78399357Smarkm 78499357Smarkmstatic void 78599357Smarkmparse_args(int argc, char **argv) 78699357Smarkm{ 78799357Smarkm int i; 78899357Smarkm 78999357Smarkm for (i=1; i<argc; i++) { 79099357Smarkm if (argv[i][0] != '-') 79199357Smarkm usage(); 79299357Smarkm else if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "-h")) 79399357Smarkm usage(); 79499357Smarkm else if (!strcmp(argv[i], "-verbose") || !strcmp(argv[i], "-v")) 79599357Smarkm verbose = 1; 79699357Smarkm else if (!strcmp(argv[i], "-lang") || !strcmp(argv[i], "-l")) 79799357Smarkm if (i + 1 == argc) 79899357Smarkm usage(); 79999357Smarkm else 80099357Smarkm lang = argv[++i]; 80199357Smarkm else if (!strcmp(argv[i], "-default") || !strcmp(argv[i], "-d")) 80299357Smarkm lang = lang_default; 80399357Smarkm else if (!strcmp(argv[i], "-show") || !strcmp(argv[i], "-s")) 80499357Smarkm show = 1; 80599357Smarkm else if (!strcmp(argv[i], "-print") || !strcmp(argv[i], "-p")) 80699357Smarkm print = 1; 80799357Smarkm else if (!strcmp(argv[i], "-restore") || 80899357Smarkm !strcmp(argv[i], "-r")) { 80999357Smarkm vidcontrol(font_current); 81099357Smarkm exit(0); 81199357Smarkm } else if (!strcmp(argv[i], "-K")) 81299357Smarkm dir = keymapdir; 81399357Smarkm else if (!strcmp(argv[i], "-V")) 81499357Smarkm dir = fontdir; 81599357Smarkm else 81699357Smarkm usage(); 81799357Smarkm } 81899357Smarkm} 81999357Smarkm 82099357Smarkm/* 82199357Smarkm * A front-end for the 'vidfont' and 'kbdmap' programs. 82299357Smarkm */ 82399357Smarkmint 82499357Smarkmmain(int argc, char **argv) 82599357Smarkm{ 82699357Smarkm 82799357Smarkm x11 = system("kbdcontrol -d >/dev/null"); 82899357Smarkm 82999357Smarkm if (x11) { 83099357Smarkm fprintf(stderr, "You are not on a virtual console - " 83199357Smarkm "expect certain strange side-effects\n"); 83299357Smarkm sleep(2); 83399357Smarkm } 83499357Smarkm 835270309Sse if (check_newcons() == 0) { 836270309Sse keymapdir = DEFAULT_SC_KEYMAP_DIR; 837270309Sse fontdir = DEFAULT_SC_FONT_DIR; 838270309Sse font_default = DEFAULT_SC_FONT; 839270309Sse } 840270309Sse 84199357Smarkm SLIST_INIT(&head); 84299357Smarkm 84399357Smarkm lang = get_locale(); 84499357Smarkm 84599357Smarkm program = extract_name(argv[0]); 84699357Smarkm 84799357Smarkm font_current = get_font(); 84899357Smarkm if (font_current == NULL) 84999357Smarkm font_current = font_default; 85099357Smarkm 85199357Smarkm if (strcmp(program, "kbdmap")) 85299357Smarkm dir = fontdir; 85399357Smarkm else 85499357Smarkm dir = keymapdir; 85599357Smarkm 856154151Sflz /* Parse command line arguments */ 857154151Sflz parse_args(argc, argv); 858154151Sflz 85999357Smarkm /* Read and display options */ 86099357Smarkm menu_read(); 86199357Smarkm 86299357Smarkm return 0; 86399357Smarkm} 864