From 3001e6d4c96c8c99687945263696371abdb14116 Mon Sep 17 00:00:00 2001 From: markm Date: Wed, 3 Jul 2002 14:56:08 +0000 Subject: C rewrite of kbdmap/vidfont. Submitted by: Jonathan Belson OK'ed by: wosch (Perl code maintainer) --- usr.sbin/kbdmap/Makefile | 4 +- usr.sbin/kbdmap/kbdmap.1 | 9 +- usr.sbin/kbdmap/kbdmap.c | 842 ++++++++++++++++++++++++++++++++++++++++++++++ usr.sbin/kbdmap/kbdmap.h | 34 ++ usr.sbin/kbdmap/kbdmap.pl | 320 ------------------ 5 files changed, 884 insertions(+), 325 deletions(-) create mode 100644 usr.sbin/kbdmap/kbdmap.c create mode 100644 usr.sbin/kbdmap/kbdmap.h delete mode 100644 usr.sbin/kbdmap/kbdmap.pl (limited to 'usr.sbin') diff --git a/usr.sbin/kbdmap/Makefile b/usr.sbin/kbdmap/Makefile index 13e0c76..38d0212 100644 --- a/usr.sbin/kbdmap/Makefile +++ b/usr.sbin/kbdmap/Makefile @@ -1,8 +1,6 @@ # $FreeBSD$ -MAINTAINER= wosch - -SCRIPTS= ${.CURDIR}/kbdmap.pl +PROG= kbdmap LINKS= ${BINDIR}/kbdmap ${BINDIR}/vidfont MAN= kbdmap.1 MLINKS= kbdmap.1 vidfont.1 diff --git a/usr.sbin/kbdmap/kbdmap.1 b/usr.sbin/kbdmap/kbdmap.1 index a4fde69..d3cc094 100644 --- a/usr.sbin/kbdmap/kbdmap.1 +++ b/usr.sbin/kbdmap/kbdmap.1 @@ -143,5 +143,10 @@ commands appeared in .Fx 2.1 . .Sh AUTHORS .An Wolfram Schneider -.Aq wosch@FreeBSD.org , -Berlin. +.Aq wosch@FreeBSD.org +wrote the original Perl version. +The current version was rewritten in C by +.An Jonathan Belson +.Aq jon@witchspace.com +for +.Fx 5.0 . diff --git a/usr.sbin/kbdmap/kbdmap.c b/usr.sbin/kbdmap/kbdmap.c new file mode 100644 index 0000000..423a13c --- /dev/null +++ b/usr.sbin/kbdmap/kbdmap.c @@ -0,0 +1,842 @@ +/*- + * Copyright (c) 2002 Jonathan Belson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kbdmap.h" + + +static const char *lang_default = DEFAULT_LANG; +static const char *font; +static const char *lang; +static const char *program; +static const char *keymapdir = DEFAULT_KEYMAP_DIR; +static const char *fontdir = DEFAULT_FONT_DIR; +static const char *sysconfig = DEFAULT_SYSCONFIG; +static const char *font_default = DEFAULT_FONT; +static const char *font_current; +static const char *dir; +static const char *menu = ""; + +static int x11; +static int show; +static int verbose; +static int print; + + +struct keymap { + char *desc; + char *keym; + int mark; + SLIST_ENTRY(keymap) entries; +}; +static SLIST_HEAD(slisthead, keymap) head = SLIST_HEAD_INITIALIZER(head); + + +/* + * Get keymap entry for 'key', or NULL of not found + */ +static struct keymap * +get_keymap(const char *key) +{ + struct keymap *km; + + SLIST_FOREACH(km, &head, entries) + if (!strcmp(km->keym, key)) + return km; + + return NULL; +} + +/* + * Count the number of keymaps we found + */ +static int +get_num_keymaps(void) +{ + struct keymap *km; + int count = 0; + + SLIST_FOREACH(km, &head, entries) + count++; + + return count; +} + +/* + * Remove any keymap with given keym + */ +static void +remove_keymap(const char *keym) +{ + struct keymap *km; + + SLIST_FOREACH(km, &head, entries) { + if (!strcmp(keym, km->keym)) { + SLIST_REMOVE(&head, km, keymap, entries); + free(km); + break; + } + } +} + +/* + * Add to hash with 'key' + */ +static void +add_keymap(const char *desc, int mark, const char *keym) +{ + struct keymap *km, *km_new; + + /* Is there already an entry with this key? */ + SLIST_FOREACH(km, &head, entries) { + if (!strcmp(km->keym, keym)) { + /* Reuse this entry */ + free(km->desc); + km->desc = strdup(desc); + km->mark = mark; + return; + } + } + + km_new = (struct keymap *) malloc (sizeof(struct keymap)); + km_new->desc = strdup(desc); + km_new->keym = strdup(keym); + km_new->mark = mark; + + /* Add to keymap list */ + SLIST_INSERT_HEAD(&head, km_new, entries); +} + +/* + * Figure out the default language to use. + */ +static const char * +get_locale(void) +{ + const char *locale; + + if ((locale = getenv("LC_ALL")) == NULL && + (locale = getenv("LC_CTYPE")) == NULL && + (locale = getenv("LANG")) == NULL) + locale = lang_default; + + /* Check for alias */ + if (!strcmp(locale, "C")) + locale = DEFAULT_LANG; + + return locale; +} + +/* + * Extract filename part + */ +static const char * +extract_name(const char *name) +{ + char *p; + + p = strrchr(name, '/'); + if (p != NULL && p[1] != '\0') + return p + 1; + + return name; +} + +/* + * Return file extension or NULL + */ +static char * +get_extension(const char *name) +{ + char *p; + + p = strrchr(name, '.'); + + if (p != NULL && p[1] != '\0') + return p; + + return NULL; +} + +/* + * Read font from /etc/rc.conf else return default. + * Freeing the memory is the caller's responsibility. + */ +static char * +get_font(void) +{ + char line[256], buf[20]; + char *fnt = NULL; + + FILE *fp = fopen(sysconfig, "r"); + if (fp) { + while (fgets(line, sizeof(line), fp)) { + int a, b, matches; + + if (line[0] == '#') + continue; + + matches = sscanf(line, + " font%dx%d = \"%20[-.0-9a-zA-Z_]", + &a, &b, buf); + if (matches==3) { + if (strcmp(buf, "NO")) { + if (fnt) + free(fnt); + fnt = (char *) malloc(strlen(buf) + 1); + strcpy(fnt, buf); + } + } + } + } else + fprintf(stderr, "Could not open %s for reading\n", sysconfig); + + return fnt; +} + +/* + * Set a font using 'vidcontrol' + */ +static void +vidcontrol(const char *fnt) +{ + char *tmp, *p, *q; + char ch; + int i; + + /* syscons test failed */ + if (x11) + return; + + tmp = strdup(fnt); + + /* Extract font size */ + p = strrchr(tmp, '-'); + if (p && p[1] != '\0') { + p++; + /* Remove any '.fnt' extension */ + if ((q = strstr(p, ".fnt"))) + *q = '\0'; + + /* + * Check font size is valid, with no trailing characters + * ('&ch' should not be matched) + */ + if (sscanf(p, "%dx%d%c", &i, &i, &ch) != 2) + fprintf(stderr, "Which font size? %s\n", fnt); + else { + char *cmd; + asprintf(&cmd, "vidcontrol -f %s %s", p, fnt); + if (verbose) + fprintf(stderr, "%s\n", cmd); + system(cmd); + free(cmd); + } + } else + fprintf(stderr, "Which font size? %s\n", fnt); + + free(tmp); +} + +/* + * Execute 'kbdcontrol' with the appropriate arguments + */ +static void +do_kbdcontrol(struct keymap *km) +{ + char *kbd_cmd; + asprintf(&kbd_cmd, "kbdcontrol -l %s/%s", dir, km->keym); + + if (!x11) + system(kbd_cmd); + + printf("keymap=%s\n", km->keym); + free(kbd_cmd); +} + +/* + * Call 'vidcontrol' with the appropriate arguments + */ +static void +do_vidfont(struct keymap *km) +{ + char *vid_cmd, *tmp, *p, *q; + + asprintf(&vid_cmd, "%s/%s", dir, km->keym); + vidcontrol(vid_cmd); + free(vid_cmd); + + tmp = strdup(km->keym); + p = strrchr(tmp, '-'); + if (p && p[1]!='\0') { + p++; + q = get_extension(p); + if (q) { + *q = '\0'; + printf("font%s=%s\n", p, km->keym); + } + } + free(tmp); +} + +/* + * Display dialog from 'keymaps[]' + */ +static void +show_dialog(struct keymap **km_sorted, int num_keymaps) +{ + FILE *fp; + char *cmd, *dialog; + char tmp_name[] = "/tmp/_kbd_lang.XXXX"; + const char *ext; + int fd, i, size; + + fd = mkstemp(tmp_name); + if (fd == -1) { + fprintf(stderr, "Could not open temporary file \"%s\"\n", + tmp_name); + exit(1); + } + asprintf(&dialog, "/usr/bin/dialog --clear --title \"Keyboard Menu\" " + "--menu \"%s\" -1 -1 10", menu); + + ext = extract_name(dir); + + /* start right font, assume that current font is equal + * to default font in /etc/rc.conf + * + * $font is the font which require the language $lang; e.g. + * russian *need* a koi8 font + * $font_current is the current font from /etc/rc.conf + */ + if (font && strcmp(font, font_current)) + vidcontrol(font); + + /* Build up the command */ + size = 0; + for (i=0; idesc) + 6; + } + + /* Allow the space for '2> tmpfilename' redirection */ + size += strlen(tmp_name) + 3; + + cmd = (char *) malloc(strlen(dialog) + size + 1); + strcpy(cmd, dialog); + + for (i=0; idesc); + strcat(cmd, "\""); + strcat(cmd, " \"\""); + } + + strcat(cmd, " 2>"); + strcat(cmd, tmp_name); + + /* Show the dialog.. */ + system(cmd); + + fp = fopen(tmp_name, "r"); + if (fp) { + char choice[64]; + if (fgets(choice, 64, fp) != NULL) { + /* Find key for desc */ + for (i=0; idesc)) { + if (!strcmp(program, "kbdmap")) + do_kbdcontrol(km_sorted[i]); + else + do_vidfont(km_sorted[i]); + break; + } + } + } else { + if (font != NULL && strcmp(font, font_current)) + /* Cancelled, restore old font */ + vidcontrol(font_current); + } + fclose(fp); + } else + fprintf(stderr, "Failed to open temporary file"); + + /* Tidy up */ + remove(tmp_name); + free(cmd); + free(dialog); + close(fd); +} + +/* + * Search for 'token' in comma delimited array 'buffer'. + * Return true for found, false for not found. + */ +static int +find_token(const char *buffer, const char *token) +{ + char *buffer_tmp, *buffer_copy, *inputstring; + char **ap; + int found; + + buffer_copy = strdup(buffer); + buffer_tmp = buffer_copy; + inputstring = buffer_copy; + ap = &buffer_tmp; + + found = 0; + + while ((*ap = strsep(&inputstring, ",")) != NULL) { + if (strcmp(buffer_tmp, token) == 0) { + found = 1; + break; + } + } + + free(buffer_copy); + + return found; +} + +/* + * Compare function for qsort + */ +static int +compare_keymap(const void *a, const void *b) +{ + + /* We've been passed pointers to pointers, so: */ + const struct keymap *km1 = *((const struct keymap * const *) a); + const struct keymap *km2 = *((const struct keymap * const *) b); + + return strcmp(km1->desc, km2->desc); +} + +/* + * Compare function for qsort + */ +static int +compare_lang(const void *a, const void *b) +{ + const char *l1 = *((const char * const *) a); + const char *l2 = *((const char * const *) b); + + return strcmp(l1, l2); +} + +/* + * Change '8x8' to '8x08' so qsort will put it before eg. '8x14' + */ +static void +kludge_desc(struct keymap **km_sorted, int num_keymaps) +{ + int i; + + for (i=0; idesc; + if ((p = strstr(km, "8x8")) != NULL) { + int len; + int j; + int offset; + + offset = p - km; + + /* Make enough space for the extra '0' */ + len = strlen(km); + km = realloc(km, len + 2); + + for (j=len; j!=offset+1; j--) + km[j + 1] = km[j]; + + km[offset+2] = '0'; + + km_sorted[i]->desc = km; + } + } +} + +/* + * Reverse 'kludge_desc()' - change '8x08' back to '8x8' + */ +static void +unkludge_desc(struct keymap **km_sorted, int num_keymaps) +{ + int i; + + for (i=0; idesc; + if ((p = strstr(km, "8x08")) != NULL) { + p += 2; + while (*p++) + p[-1] = p[0]; + + km = realloc(km, p - km - 1); + km_sorted[i]->desc = km; + } + } +} + +/* + * Return 0 if file exists and is readable, else -1 + */ +static int +check_file(const char *keym) +{ + int status = 0; + + if (access(keym, R_OK) == -1) { + char *fn; + asprintf(&fn, "%s/%s", dir, keym); + if (access(fn, R_OK) == -1) { + if (verbose) + fprintf(stderr, "%s not found!\n", fn); + status = -1; + } + free(fn); + } else { + if (verbose) + fprintf(stderr, "No read permission for %s!\n", keym); + status = -1; + } + + return status; +} + +/* + * Read options from the relevent configuration file, then + * present to user. + */ +static void +menu_read(void) +{ + const char *lg; + char *p; + int mark, num_keymaps, items, i; + char buffer[256], filename[PATH_MAX]; + char keym[64], lng[64], desc[64]; + char dialect[64], lang_abk[64]; + struct keymap *km; + struct keymap **km_sorted; + struct dirent *dp; + StringList *lang_list; + FILE *fp; + DIR *dirp; + + lang_list = sl_init(); + + sprintf(filename, "%s/INDEX.%s", dir, extract_name(dir)); + + /* en_US.ISO8859-1 -> en_..\.ISO8859-1 */ + strlcpy(dialect, lang, sizeof(dialect)); + if (strlen(dialect) >= 6 && dialect[2] == '-') { + dialect[3] = '.'; + dialect[4] = '.'; + } + + + /* en_US.ISO8859-1 -> en */ + strlcpy(lang_abk, lang, sizeof(lang_abk)); + if (strlen(lang_abk) >= 3 && lang_abk[2] == '-') + lang_abk[2] = '.'; + + fprintf(stderr, "lang_default = %s\n", lang_default); + fprintf(stderr, "dialect = %s\n", dialect); + fprintf(stderr, "lang_abk = %s\n", lang_abk); + + fp = fopen(filename, "r"); + if (fp) { + int matches; + while (fgets(buffer, sizeof(buffer), fp)) { + p = buffer; + if (p[0] == '#') + continue; + + while (isspace(*p)) + p++; + + if (*p == '\0') + continue; + + /* Parse input, removing newline */ + matches = sscanf(p, "%64[^:]:%64[^:]:%64[^:\n]", + keym, lng, desc); + if (matches == 3) { + if (strcmp(keym, "FONT") + && strcmp(keym, "MENU")) { + /* Check file exists & is readable */ + if (check_file(keym) == -1) + continue; + } + } + + if (show) { + /* + * Take note of supported languages, which + * might be in a comma-delimited list + */ + char *tmp = strdup(lng); + char *delim = tmp; + + for (delim = tmp; ; ) { + char ch = *delim++; + if (ch == ',' || ch == '\0') { + delim[-1] = '\0'; + if (!sl_find(lang_list, tmp)) + sl_add(lang_list, tmp); + if (ch == '\0') + break; + tmp = delim; + } + } + } + /* Set empty language to default language */ + if (lng[0] == '\0') + lg = lang_default; + else + lg = lng; + + + /* 4) Your choice if it exists + * 3) Long match eg. en_GB.ISO8859-1 is equal to + * en_..\.ISO8859-1 + * 2) short match 'de' + * 1) default langlist 'en' + * 0) any language + * + * Language may be a comma separated list + * A higher match overwrites a lower + * A later entry overwrites a previous if it exists + * twice in the database + */ + + /* Check for favoured language */ + km = get_keymap(keym); + mark = (km) ? km->mark : 0; + + if (find_token(lg, lang)) + add_keymap(desc, 4, keym); + else if (mark <= 3 && find_token(lg, dialect)) + add_keymap(desc, 3, keym); + else if (mark <= 2 && find_token(lg, lang_abk)) + add_keymap(desc, 2, keym); + else if (mark <= 1 && find_token(lg, lang_default)) + add_keymap(desc, 1, keym); + else if (mark <= 0) + add_keymap(desc, 0, keym); + } + fclose(fp); + + } else + printf("Could not open file\n"); + + if (show) { + qsort(lang_list->sl_str, lang_list->sl_cur, sizeof(char*), + compare_lang); + printf("Currently supported languages: "); + for (i=0; i< (int) lang_list->sl_cur; i++) + printf("%s ", lang_list->sl_str[i]); + puts(""); + exit(0); + } + + km = get_keymap("MENU"); + if (km) + /* Take note of menu title */ + menu = strdup(km->desc); + km = get_keymap("FONT"); + if (km) + /* Take note of language font */ + font = strdup(km->desc); + + /* Remove unwanted items from list */ + remove_keymap("MENU"); + remove_keymap("FONT"); + + /* Look for keymaps not in database */ + dirp = opendir(dir); + if (dirp) { + while ((dp = readdir(dirp)) != NULL) { + const char *ext = get_extension(dp->d_name); + if (ext) { + if ((!strcmp(ext, ".fnt") || + !strcmp(ext, ".kbd")) && + !get_keymap(dp->d_name)) { + char *q; + + /* Remove any .fnt or .kbd extension */ + q = strdup(dp->d_name); + *(get_extension(q)) = '\0'; + add_keymap(q, 0, dp->d_name); + free(q); + + if (verbose) + fprintf(stderr, + "'%s' not in database\n", + dp->d_name); + } + } + } + closedir(dirp); + } else + fprintf(stderr, "Could not open directory '%s'\n", dir); + + /* Sort items in keymap */ + num_keymaps = get_num_keymaps(); + + km_sorted = (struct keymap **) + malloc(num_keymaps*sizeof(struct keymap *)); + + /* Make array of pointers to items in hash */ + items = 0; + SLIST_FOREACH(km, &head, entries) + km_sorted[items++] = km; + + /* Change '8x8' to '8x08' so sort works as we might expect... */ + kludge_desc(km_sorted, num_keymaps); + + qsort(km_sorted, num_keymaps, sizeof(struct keymap *), compare_keymap); + + /* ...change back again */ + unkludge_desc(km_sorted, num_keymaps); + + if (print) { + for (i=0; idesc); + exit(0); + } + + show_dialog(km_sorted, num_keymaps); + + free(km_sorted); +} + +/* + * Display usage information and exit + */ +static void +usage(void) +{ + + fprintf(stderr, "usage: %s\t[-K] [-V] [-d|-default] [-h|-help] " + "[-l|-lang language]\n\t\t[-p|-print] [-r|-restore] [-s|-show] " + "[-v|-verbose]\n", program); + exit(1); +} + +static void +parse_args(int argc, char **argv) +{ + int i; + + for (i=1; i/dev/null"); + + if (x11) { + fprintf(stderr, "You are not on a virtual console - " + "expect certain strange side-effects\n"); + sleep(2); + } + + SLIST_INIT(&head); + + lang = get_locale(); + + program = extract_name(argv[0]); + + /* Parse command line arguments */ + parse_args(argc, argv); + + font_current = get_font(); + if (font_current == NULL) + font_current = font_default; + + if (strcmp(program, "kbdmap")) + dir = fontdir; + else + dir = keymapdir; + + /* Read and display options */ + menu_read(); + + return 0; +} diff --git a/usr.sbin/kbdmap/kbdmap.h b/usr.sbin/kbdmap/kbdmap.h new file mode 100644 index 0000000..e57fa8c --- /dev/null +++ b/usr.sbin/kbdmap/kbdmap.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2002 Jonathan Belson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + +#define DEFAULT_LANG "en" +#define DEFAULT_KEYMAP_DIR "/usr/share/syscons/keymaps" +#define DEFAULT_FONT_DIR "/usr/share/syscons/fonts" +#define DEFAULT_SYSCONFIG "/etc/rc.conf" +#define DEFAULT_FONT "cp437-8x16.fnt" diff --git a/usr.sbin/kbdmap/kbdmap.pl b/usr.sbin/kbdmap/kbdmap.pl deleted file mode 100644 index 03536b2..0000000 --- a/usr.sbin/kbdmap/kbdmap.pl +++ /dev/null @@ -1,320 +0,0 @@ -#!/usr/bin/perl -# -# Copyright (c) March 1995 Wolfram Schneider . Berlin. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# kbdmap/vidfont - front end for syscons -# -# $FreeBSD$ - - -# simple test if syscons works -$x11 = system("kbdcontrol -d >/dev/null"); -if ($x11) { - warn "You are not on a virtual console - " . - "expect certain strange side-effects\n"; - sleep 2; -} - -sub variables_static { - $lang_default = "en"; # set default language - $lang = $ENV{'LC_ALL'} || $ENV{'LC_CTYPE'} || $ENV{'LANG'} || $lang_default; - $lang = &lang($lang); - $program = $0; $program =~ s|.*/||; $program =~ s/\.(pl|perl)$//; - $keymapdir = "/usr/share/syscons/keymaps"; - $fontdir = "/usr/share/syscons/fonts"; - $sysconfig = "/etc/rc.conf"; - - # for test only - #$keymapdir = "/tmp/kbdmap/syscons/keymaps"; - #$fontdir = "/tmp/kbdmap/syscons/fonts"; - - # read current font from rc.conf - $font_default = "cp437-8x16.fnt"; - $font_current = &font_current($font_default); - - if ($program eq "kbdmap") { - $dir = $keymapdir; - } else { - $dir = $fontdir; - } - - @langsupport = ('MENU', 'FONT'); # lang depended variables - $show = 0; # show which languages currently supported - $index = "INDEX"; # Keyboard language database - $verbose = 0; - %keymap = ''; -} - -sub lang { - local($lang) = @_; - - #$lang =~ s/_.*//; # strip country and font - $lang =~ s/^(C)$/en/; # aliases - #$lang =~ s/^(..).*/$1/; # use only first to characters - - return $lang; -} - -sub font_current { - local($font) = @_; - local($font_current); - - open(F, "$sysconfig") || warn "$sysconfig: $!\n"; - - while() { - /^#/ && next; - if (/^\s*font[0-9]+x[0-9]+\s*=\s*\"?([^\s\"]+)\"?/) { - $font_current = $1 if $1 ne "NO"; - } - } - close F; - - return $font_current if $font_current; - return $font; -} - -sub vidcontrol { - local($font) = @_; - - return $x11 if $x11; # syscons test failed - - if ($font =~ /.*([0-9]+x[0-9]+)(\.fnt)?$/) { - warn "vidcontrol -f $1 $font\n" if $verbose; - return system("vidcontrol -f $1 $font"); - } else { - warn "Which font size? ``$font''\n"; - return 1; - } -} - -sub menu_read { - local($e,@a,$mark,$ext); - local($keym, $lg, $dialect, $desc); - local(@langlist) = $lang_default; - - $ext = $dir; $ext =~ s|.*/||; - # en_US.ISO8859-1 -> en_..\.ISO8859-1 - ($dialect = $lang) =~ s/^(..)_..(.+)$/$1_..$2/; - # en_US.ISO8859-1 -> en - ($lang_abk = $lang) =~ s/^(..)_.*$/$1/; - - # read index database - open(I, "$dir/$index.$ext") || warn "$dir/$index.$ext: $!\n"; - while() { - # skip blank lines and comments - /^#/ && next; - s/^\s+//; - /^\w/ || next; - s/\s+$//; - - ($keym, $lg, $desc) = split(/:/); - if (! -r "$keym" && ! -r "$dir/$keym" && - !grep(/$keym/, @langsupport)) { - warn "$keym not found!\n" if $verbose; - next; - } - - # set empty language to default language - $lg = $lang_default if $lg eq ""; - - # save language - if ($show) { - foreach $e (split(/,/, $lg)) { - push(@langlist, $e) if !grep($_ eq $e, @langlist); - } - } - - # 4) your choise if exist - # 3) long match e.g. en_GB.ISO8859-1 is equal to en_..\.ISO8859-1 - # 2) short match 'de' - # 1) default langlist 'en' - # 0) any language - # - # language may be a kommalist - # higher match overwrite lower - # last entry overwrite previous if exist twice in database - - # found your favorite language :-) - if ($lg =~ /^(.+,)?$lang(,.+)?$/) { - $keymap{$keym} = $desc; - $mark{$keym} = 4; - } elsif ($mark{$keym} <= 3 && $lg =~ /^(.+,)?$dialect(,.+)?$/) { - # dialect - $keymap{$keym} = $desc; - $mark{$keym} = 3; - } elsif ($mark{$keym} <= 2 && $lg =~ /^(.+,)?$lang_abk(,.+)?$/) { - # abrevation - $keymap{$keym} = $desc; - $mark{$keym} = 2; - } elsif ($mark{$keym} <= 1 && $lg =~ /^(.+,)?$lang_default(,.+)?$/) { - # default - $keymap{$keym} = $desc; - $mark{$keym} = 1; - } elsif ($mark{$keym} <= 0) { - # any - $keymap{$keym} = $desc; - $mark{$keym} = 0; - } - } - close I; - - if ($show) { - @langlist = sort(@langlist); - print "Currently supported languages: @langlist\n"; - exit(0); - } - - # remove variables from list - local($ee); - foreach $e (@langsupport) { - ($ee = $e) =~ y/A-Z/a-z/; - eval "\$$ee = \"$keymap{$e}\""; - #warn "$e \$$ee = \"$keymap{$e}\""; - delete $keymap{$e}; - } - #warn "$font $font_default $font_current\n"; - - - # look for keymaps which are not in database - opendir(D, "$dir") || warn "$dir: $!\n"; - foreach $e (readdir(D)) { - if ($e =~ /^[a-z].*(kbd|fnt)$/ && !$keymap{$e}) { - warn "$e not in database\n" if $verbose; - $keymap{$e} = $e; - $keymap{$e} =~ s/\.(kbd|fnt)$//; - } - } - closedir D; - - # sort menu, font 8x8 is less than 8x14 and 8x16 - foreach $e (sort(keys %keymap)) { - if ($keymap{$e}) { - push(@a, "\"$keymap{$e}\" \"\""); - } - } - # side effects to @a - grep(s/8x8/8x08/, @a); - @a = sort @a; - grep(s/8x08/8x8/, @a); - - if ($print) { - foreach (@a) { - s/"//g; #" - print "$_\n"; - } - exit; - } - - return @a; -} - -sub dialog { - srand; - local(@argv) = @_; - local($tmp) = "/tmp/_kbd_lang" . rand(9999); - - $dialog = "/usr/bin/dialog \\ ---clear \\ ---title \"Keyboard Menu\" \\ ---menu \"$menu\" \\ --1 -1 10"; - - ## *always* start right font, don't believe that your current font - ## is equal with default font in /etc/rc.conf - ## see also at end of this function - ## if ($font) { - - # start right font, assume that current font is equal - # to default font in /etc/rc.conf - # - # $font is the font which require the language $lang; e.g. - # russian *need* a koi8 font - # $font_current is the current font from /etc/rc.conf - if ($font && $font ne $font_current) { - &vidcontrol($font); - } - - # start dialog - system("$dialog @argv 2> $tmp"); - - if (!$?) { - $choise = `cat $tmp`; - foreach $e (keys %keymap) { - if ($keymap{$e} eq $choise) { - if ($program eq "kbdmap") { - system("kbdcontrol -l $dir/$e\n") unless $x11; - print "keymap=$e", "\n"; - } else { - &vidcontrol("$dir/$e"); - $_ = $e; - if (/^.*\-(.*)\.fnt/) { - $font=$1 - } else { $font="unknown" } - print "font$font=$e", "\n"; - } - last; - } - } - # } else { - } elsif ($font && $font ne $font_current) { - # cancel, restore old font - &vidcontrol($font_current); - } - unlink $tmp; - exit($?); -} - -sub usage { - warn <