121ece67dSChris Pressey /*-
221ece67dSChris Pressey * Copyright (c) 2002 Jonathan Belson <jon@witchspace.com>
321ece67dSChris Pressey * All rights reserved.
421ece67dSChris Pressey *
521ece67dSChris Pressey * Redistribution and use in source and binary forms, with or without
621ece67dSChris Pressey * modification, are permitted provided that the following conditions
721ece67dSChris Pressey * are met:
821ece67dSChris Pressey * 1. Redistributions of source code must retain the above copyright
921ece67dSChris Pressey * notice, this list of conditions and the following disclaimer.
1021ece67dSChris Pressey * 2. Redistributions in binary form must reproduce the above copyright
1121ece67dSChris Pressey * notice, this list of conditions and the following disclaimer in the
1221ece67dSChris Pressey * documentation and/or other materials provided with the distribution.
1321ece67dSChris Pressey *
1421ece67dSChris Pressey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1521ece67dSChris Pressey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1621ece67dSChris Pressey * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1721ece67dSChris Pressey * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1821ece67dSChris Pressey * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1921ece67dSChris Pressey * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2021ece67dSChris Pressey * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2121ece67dSChris Pressey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2221ece67dSChris Pressey * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2321ece67dSChris Pressey * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2421ece67dSChris Pressey * SUCH DAMAGE.
2521ece67dSChris Pressey *
26*ebfa7d96SPeter Avalos * $FreeBSD: head/usr.sbin/kbdmap/kbdmap.c 237257 2012-06-19 06:10:31Z eadler $
2721ece67dSChris Pressey */
2821ece67dSChris Pressey
2921ece67dSChris Pressey #include <sys/types.h>
3021ece67dSChris Pressey #include <sys/queue.h>
3121ece67dSChris Pressey
3221ece67dSChris Pressey #include <assert.h>
3321ece67dSChris Pressey #include <ctype.h>
3421ece67dSChris Pressey #include <dirent.h>
3521ece67dSChris Pressey #include <limits.h>
3621ece67dSChris Pressey #include <stdio.h>
3721ece67dSChris Pressey #include <stdlib.h>
3821ece67dSChris Pressey #include <string.h>
3921ece67dSChris Pressey #include <stringlist.h>
4021ece67dSChris Pressey #include <unistd.h>
4121ece67dSChris Pressey
4221ece67dSChris Pressey #include "kbdmap.h"
4321ece67dSChris Pressey
4421ece67dSChris Pressey
4521ece67dSChris Pressey static const char *lang_default = DEFAULT_LANG;
4621ece67dSChris Pressey static const char *font;
4721ece67dSChris Pressey static const char *lang;
4821ece67dSChris Pressey static const char *program;
4921ece67dSChris Pressey static const char *keymapdir = DEFAULT_KEYMAP_DIR;
5021ece67dSChris Pressey static const char *fontdir = DEFAULT_FONT_DIR;
5121ece67dSChris Pressey static const char *sysconfig = DEFAULT_SYSCONFIG;
5221ece67dSChris Pressey static const char *font_default = DEFAULT_FONT;
5321ece67dSChris Pressey static const char *font_current;
5421ece67dSChris Pressey static const char *dir;
5521ece67dSChris Pressey static const char *menu = "";
5621ece67dSChris Pressey
5721ece67dSChris Pressey static int x11;
5821ece67dSChris Pressey static int show;
5921ece67dSChris Pressey static int verbose;
6021ece67dSChris Pressey static int print;
6121ece67dSChris Pressey
6221ece67dSChris Pressey
6321ece67dSChris Pressey struct keymap {
6421ece67dSChris Pressey char *desc;
6521ece67dSChris Pressey char *keym;
6621ece67dSChris Pressey int mark;
6721ece67dSChris Pressey SLIST_ENTRY(keymap) entries;
6821ece67dSChris Pressey };
6921ece67dSChris Pressey static SLIST_HEAD(slisthead, keymap) head = SLIST_HEAD_INITIALIZER(head);
7021ece67dSChris Pressey
7121ece67dSChris Pressey
7221ece67dSChris Pressey /*
7321ece67dSChris Pressey * Get keymap entry for 'key', or NULL of not found
7421ece67dSChris Pressey */
7521ece67dSChris Pressey static struct keymap *
get_keymap(const char * key)7621ece67dSChris Pressey get_keymap(const char *key)
7721ece67dSChris Pressey {
7821ece67dSChris Pressey struct keymap *km;
7921ece67dSChris Pressey
8021ece67dSChris Pressey SLIST_FOREACH(km, &head, entries)
8121ece67dSChris Pressey if (!strcmp(km->keym, key))
8221ece67dSChris Pressey return km;
8321ece67dSChris Pressey
8421ece67dSChris Pressey return NULL;
8521ece67dSChris Pressey }
8621ece67dSChris Pressey
8721ece67dSChris Pressey /*
8821ece67dSChris Pressey * Count the number of keymaps we found
8921ece67dSChris Pressey */
9021ece67dSChris Pressey static int
get_num_keymaps(void)9121ece67dSChris Pressey get_num_keymaps(void)
9221ece67dSChris Pressey {
9321ece67dSChris Pressey struct keymap *km;
9421ece67dSChris Pressey int count = 0;
9521ece67dSChris Pressey
9621ece67dSChris Pressey SLIST_FOREACH(km, &head, entries)
9721ece67dSChris Pressey count++;
9821ece67dSChris Pressey
9921ece67dSChris Pressey return count;
10021ece67dSChris Pressey }
10121ece67dSChris Pressey
10221ece67dSChris Pressey /*
10321ece67dSChris Pressey * Remove any keymap with given keym
10421ece67dSChris Pressey */
10521ece67dSChris Pressey static void
remove_keymap(const char * keym)10621ece67dSChris Pressey remove_keymap(const char *keym)
10721ece67dSChris Pressey {
10821ece67dSChris Pressey struct keymap *km;
10921ece67dSChris Pressey
11021ece67dSChris Pressey SLIST_FOREACH(km, &head, entries) {
11121ece67dSChris Pressey if (!strcmp(keym, km->keym)) {
11221ece67dSChris Pressey SLIST_REMOVE(&head, km, keymap, entries);
11321ece67dSChris Pressey free(km);
11421ece67dSChris Pressey break;
11521ece67dSChris Pressey }
11621ece67dSChris Pressey }
11721ece67dSChris Pressey }
11821ece67dSChris Pressey
11921ece67dSChris Pressey /*
12021ece67dSChris Pressey * Add to hash with 'key'
12121ece67dSChris Pressey */
12221ece67dSChris Pressey static void
add_keymap(const char * desc,int mark,const char * keym)12321ece67dSChris Pressey add_keymap(const char *desc, int mark, const char *keym)
12421ece67dSChris Pressey {
12521ece67dSChris Pressey struct keymap *km, *km_new;
12621ece67dSChris Pressey
12721ece67dSChris Pressey /* Is there already an entry with this key? */
12821ece67dSChris Pressey SLIST_FOREACH(km, &head, entries) {
12921ece67dSChris Pressey if (!strcmp(km->keym, keym)) {
13021ece67dSChris Pressey /* Reuse this entry */
13121ece67dSChris Pressey free(km->desc);
13221ece67dSChris Pressey km->desc = strdup(desc);
13321ece67dSChris Pressey km->mark = mark;
13421ece67dSChris Pressey return;
13521ece67dSChris Pressey }
13621ece67dSChris Pressey }
13721ece67dSChris Pressey
13821ece67dSChris Pressey km_new = (struct keymap *) malloc (sizeof(struct keymap));
13921ece67dSChris Pressey km_new->desc = strdup(desc);
14021ece67dSChris Pressey km_new->keym = strdup(keym);
14121ece67dSChris Pressey km_new->mark = mark;
14221ece67dSChris Pressey
14321ece67dSChris Pressey /* Add to keymap list */
14421ece67dSChris Pressey SLIST_INSERT_HEAD(&head, km_new, entries);
14521ece67dSChris Pressey }
14621ece67dSChris Pressey
14721ece67dSChris Pressey /*
14821ece67dSChris Pressey * Figure out the default language to use.
14921ece67dSChris Pressey */
15021ece67dSChris Pressey static const char *
get_locale(void)15121ece67dSChris Pressey get_locale(void)
15221ece67dSChris Pressey {
15321ece67dSChris Pressey const char *locale;
15421ece67dSChris Pressey
15521ece67dSChris Pressey if ((locale = getenv("LC_ALL")) == NULL &&
15621ece67dSChris Pressey (locale = getenv("LC_CTYPE")) == NULL &&
15721ece67dSChris Pressey (locale = getenv("LANG")) == NULL)
15821ece67dSChris Pressey locale = lang_default;
15921ece67dSChris Pressey
16021ece67dSChris Pressey /* Check for alias */
16121ece67dSChris Pressey if (!strcmp(locale, "C"))
16221ece67dSChris Pressey locale = DEFAULT_LANG;
16321ece67dSChris Pressey
16421ece67dSChris Pressey return locale;
16521ece67dSChris Pressey }
16621ece67dSChris Pressey
16721ece67dSChris Pressey /*
16821ece67dSChris Pressey * Extract filename part
16921ece67dSChris Pressey */
17021ece67dSChris Pressey static const char *
extract_name(const char * name)17121ece67dSChris Pressey extract_name(const char *name)
17221ece67dSChris Pressey {
17321ece67dSChris Pressey char *p;
17421ece67dSChris Pressey
17521ece67dSChris Pressey p = strrchr(name, '/');
17621ece67dSChris Pressey if (p != NULL && p[1] != '\0')
17721ece67dSChris Pressey return p + 1;
17821ece67dSChris Pressey
17921ece67dSChris Pressey return name;
18021ece67dSChris Pressey }
18121ece67dSChris Pressey
18221ece67dSChris Pressey /*
18321ece67dSChris Pressey * Return file extension or NULL
18421ece67dSChris Pressey */
18521ece67dSChris Pressey static char *
get_extension(const char * name)18621ece67dSChris Pressey get_extension(const char *name)
18721ece67dSChris Pressey {
18821ece67dSChris Pressey char *p;
18921ece67dSChris Pressey
19021ece67dSChris Pressey p = strrchr(name, '.');
19121ece67dSChris Pressey
19221ece67dSChris Pressey if (p != NULL && p[1] != '\0')
19321ece67dSChris Pressey return p;
19421ece67dSChris Pressey
19521ece67dSChris Pressey return NULL;
19621ece67dSChris Pressey }
19721ece67dSChris Pressey
19821ece67dSChris Pressey /*
19921ece67dSChris Pressey * Read font from /etc/rc.conf else return default.
20021ece67dSChris Pressey * Freeing the memory is the caller's responsibility.
20121ece67dSChris Pressey */
20221ece67dSChris Pressey static char *
get_font(void)20321ece67dSChris Pressey get_font(void)
20421ece67dSChris Pressey {
20521ece67dSChris Pressey char line[256], buf[20];
20621ece67dSChris Pressey char *fnt = NULL;
20721ece67dSChris Pressey
20821ece67dSChris Pressey FILE *fp = fopen(sysconfig, "r");
20921ece67dSChris Pressey if (fp) {
21021ece67dSChris Pressey while (fgets(line, sizeof(line), fp)) {
21121ece67dSChris Pressey int a, b, matches;
21221ece67dSChris Pressey
21321ece67dSChris Pressey if (line[0] == '#')
21421ece67dSChris Pressey continue;
21521ece67dSChris Pressey
21621ece67dSChris Pressey matches = sscanf(line,
21721ece67dSChris Pressey " font%dx%d = \"%20[-.0-9a-zA-Z_]",
21821ece67dSChris Pressey &a, &b, buf);
21921ece67dSChris Pressey if (matches==3) {
22021ece67dSChris Pressey if (strcmp(buf, "NO")) {
22121ece67dSChris Pressey if (fnt)
22221ece67dSChris Pressey free(fnt);
22321ece67dSChris Pressey fnt = (char *) malloc(strlen(buf) + 1);
22421ece67dSChris Pressey strcpy(fnt, buf);
22521ece67dSChris Pressey }
22621ece67dSChris Pressey }
22721ece67dSChris Pressey }
228*ebfa7d96SPeter Avalos fclose(fp);
22921ece67dSChris Pressey } else
23021ece67dSChris Pressey fprintf(stderr, "Could not open %s for reading\n", sysconfig);
23121ece67dSChris Pressey
23221ece67dSChris Pressey return fnt;
23321ece67dSChris Pressey }
23421ece67dSChris Pressey
23521ece67dSChris Pressey /*
23621ece67dSChris Pressey * Set a font using 'vidcontrol'
23721ece67dSChris Pressey */
23821ece67dSChris Pressey static void
vidcontrol(const char * fnt)23921ece67dSChris Pressey vidcontrol(const char *fnt)
24021ece67dSChris Pressey {
24121ece67dSChris Pressey char *tmp, *p, *q;
24221ece67dSChris Pressey char ch;
24321ece67dSChris Pressey int i;
24421ece67dSChris Pressey
24521ece67dSChris Pressey /* syscons test failed */
24621ece67dSChris Pressey if (x11)
24721ece67dSChris Pressey return;
24821ece67dSChris Pressey
24921ece67dSChris Pressey tmp = strdup(fnt);
25021ece67dSChris Pressey
25121ece67dSChris Pressey /* Extract font size */
25221ece67dSChris Pressey p = strrchr(tmp, '-');
25321ece67dSChris Pressey if (p && p[1] != '\0') {
25421ece67dSChris Pressey p++;
25521ece67dSChris Pressey /* Remove any '.fnt' extension */
25621ece67dSChris Pressey if ((q = strstr(p, ".fnt")))
25721ece67dSChris Pressey *q = '\0';
25821ece67dSChris Pressey
25921ece67dSChris Pressey /*
26021ece67dSChris Pressey * Check font size is valid, with no trailing characters
26121ece67dSChris Pressey * ('&ch' should not be matched)
26221ece67dSChris Pressey */
26321ece67dSChris Pressey if (sscanf(p, "%dx%d%c", &i, &i, &ch) != 2)
26421ece67dSChris Pressey fprintf(stderr, "Which font size? %s\n", fnt);
26521ece67dSChris Pressey else {
26621ece67dSChris Pressey char *cmd;
26721ece67dSChris Pressey asprintf(&cmd, "vidcontrol -f %s %s", p, fnt);
26821ece67dSChris Pressey if (verbose)
26921ece67dSChris Pressey fprintf(stderr, "%s\n", cmd);
27021ece67dSChris Pressey system(cmd);
27121ece67dSChris Pressey free(cmd);
27221ece67dSChris Pressey }
27321ece67dSChris Pressey } else
27421ece67dSChris Pressey fprintf(stderr, "Which font size? %s\n", fnt);
27521ece67dSChris Pressey
27621ece67dSChris Pressey free(tmp);
27721ece67dSChris Pressey }
27821ece67dSChris Pressey
27921ece67dSChris Pressey /*
28021ece67dSChris Pressey * Execute 'kbdcontrol' with the appropriate arguments
28121ece67dSChris Pressey */
28221ece67dSChris Pressey static void
do_kbdcontrol(struct keymap * km)28321ece67dSChris Pressey do_kbdcontrol(struct keymap *km)
28421ece67dSChris Pressey {
28521ece67dSChris Pressey char *kbd_cmd;
28621ece67dSChris Pressey asprintf(&kbd_cmd, "kbdcontrol -l %s/%s", dir, km->keym);
28721ece67dSChris Pressey
28821ece67dSChris Pressey if (!x11)
28921ece67dSChris Pressey system(kbd_cmd);
29021ece67dSChris Pressey
291*ebfa7d96SPeter Avalos fprintf(stderr, "keymap=\"%s\"\n", km->keym);
29221ece67dSChris Pressey free(kbd_cmd);
29321ece67dSChris Pressey }
29421ece67dSChris Pressey
29521ece67dSChris Pressey /*
29621ece67dSChris Pressey * Call 'vidcontrol' with the appropriate arguments
29721ece67dSChris Pressey */
29821ece67dSChris Pressey static void
do_vidfont(struct keymap * km)29921ece67dSChris Pressey do_vidfont(struct keymap *km)
30021ece67dSChris Pressey {
30121ece67dSChris Pressey char *vid_cmd, *tmp, *p, *q;
30221ece67dSChris Pressey
30321ece67dSChris Pressey asprintf(&vid_cmd, "%s/%s", dir, km->keym);
30421ece67dSChris Pressey vidcontrol(vid_cmd);
30521ece67dSChris Pressey free(vid_cmd);
30621ece67dSChris Pressey
30721ece67dSChris Pressey tmp = strdup(km->keym);
30821ece67dSChris Pressey p = strrchr(tmp, '-');
30921ece67dSChris Pressey if (p && p[1]!='\0') {
31021ece67dSChris Pressey p++;
31121ece67dSChris Pressey q = get_extension(p);
31221ece67dSChris Pressey if (q) {
31321ece67dSChris Pressey *q = '\0';
31421ece67dSChris Pressey printf("font%s=%s\n", p, km->keym);
31521ece67dSChris Pressey }
31621ece67dSChris Pressey }
31721ece67dSChris Pressey free(tmp);
31821ece67dSChris Pressey }
31921ece67dSChris Pressey
32021ece67dSChris Pressey /*
32121ece67dSChris Pressey * Display dialog from 'keymaps[]'
32221ece67dSChris Pressey */
32321ece67dSChris Pressey static void
show_dialog(struct keymap ** km_sorted,int num_keymaps)32421ece67dSChris Pressey show_dialog(struct keymap **km_sorted, int num_keymaps)
32521ece67dSChris Pressey {
32621ece67dSChris Pressey FILE *fp;
32721ece67dSChris Pressey char *cmd, *dialog;
32821ece67dSChris Pressey char tmp_name[] = "/tmp/_kbd_lang.XXXX";
32921ece67dSChris Pressey int fd, i, size;
33021ece67dSChris Pressey
33121ece67dSChris Pressey fd = mkstemp(tmp_name);
33221ece67dSChris Pressey if (fd == -1) {
33321ece67dSChris Pressey fprintf(stderr, "Could not open temporary file \"%s\"\n",
33421ece67dSChris Pressey tmp_name);
33521ece67dSChris Pressey exit(1);
33621ece67dSChris Pressey }
33721ece67dSChris Pressey asprintf(&dialog, "/usr/bin/dialog --clear --title \"Keyboard Menu\" "
338*ebfa7d96SPeter Avalos "--menu \"%s\" 0 0 0", menu);
33921ece67dSChris Pressey
34021ece67dSChris Pressey /* start right font, assume that current font is equal
34121ece67dSChris Pressey * to default font in /etc/rc.conf
34221ece67dSChris Pressey *
34321ece67dSChris Pressey * $font is the font which require the language $lang; e.g.
34421ece67dSChris Pressey * russian *need* a koi8 font
34521ece67dSChris Pressey * $font_current is the current font from /etc/rc.conf
34621ece67dSChris Pressey */
34721ece67dSChris Pressey if (font && strcmp(font, font_current))
34821ece67dSChris Pressey vidcontrol(font);
34921ece67dSChris Pressey
35021ece67dSChris Pressey /* Build up the command */
35121ece67dSChris Pressey size = 0;
35221ece67dSChris Pressey for (i=0; i<num_keymaps; i++) {
35321ece67dSChris Pressey /*
35421ece67dSChris Pressey * Each 'font' is passed as ' "font" ""', so allow the
35521ece67dSChris Pressey * extra space
35621ece67dSChris Pressey */
35721ece67dSChris Pressey size += strlen(km_sorted[i]->desc) + 6;
35821ece67dSChris Pressey }
35921ece67dSChris Pressey
36021ece67dSChris Pressey /* Allow the space for '2> tmpfilename' redirection */
36121ece67dSChris Pressey size += strlen(tmp_name) + 3;
36221ece67dSChris Pressey
36321ece67dSChris Pressey cmd = (char *) malloc(strlen(dialog) + size + 1);
36421ece67dSChris Pressey strcpy(cmd, dialog);
36521ece67dSChris Pressey
36621ece67dSChris Pressey for (i=0; i<num_keymaps; i++) {
36721ece67dSChris Pressey strcat(cmd, " \"");
36821ece67dSChris Pressey strcat(cmd, km_sorted[i]->desc);
36921ece67dSChris Pressey strcat(cmd, "\"");
37021ece67dSChris Pressey strcat(cmd, " \"\"");
37121ece67dSChris Pressey }
37221ece67dSChris Pressey
37321ece67dSChris Pressey strcat(cmd, " 2>");
37421ece67dSChris Pressey strcat(cmd, tmp_name);
37521ece67dSChris Pressey
37621ece67dSChris Pressey /* Show the dialog.. */
37721ece67dSChris Pressey system(cmd);
37821ece67dSChris Pressey
37921ece67dSChris Pressey fp = fopen(tmp_name, "r");
38021ece67dSChris Pressey if (fp) {
38121ece67dSChris Pressey char choice[64];
382*ebfa7d96SPeter Avalos if (fgets(choice, sizeof(choice), fp) != NULL) {
38321ece67dSChris Pressey /* Find key for desc */
38421ece67dSChris Pressey for (i=0; i<num_keymaps; i++) {
38521ece67dSChris Pressey if (!strcmp(choice, km_sorted[i]->desc)) {
38621ece67dSChris Pressey if (!strcmp(program, "kbdmap"))
38721ece67dSChris Pressey do_kbdcontrol(km_sorted[i]);
38821ece67dSChris Pressey else
38921ece67dSChris Pressey do_vidfont(km_sorted[i]);
39021ece67dSChris Pressey break;
39121ece67dSChris Pressey }
39221ece67dSChris Pressey }
39321ece67dSChris Pressey } else {
39421ece67dSChris Pressey if (font != NULL && strcmp(font, font_current))
39521ece67dSChris Pressey /* Cancelled, restore old font */
39621ece67dSChris Pressey vidcontrol(font_current);
39721ece67dSChris Pressey }
39821ece67dSChris Pressey fclose(fp);
39921ece67dSChris Pressey } else
40021ece67dSChris Pressey fprintf(stderr, "Failed to open temporary file");
40121ece67dSChris Pressey
40221ece67dSChris Pressey /* Tidy up */
40321ece67dSChris Pressey remove(tmp_name);
40421ece67dSChris Pressey free(cmd);
40521ece67dSChris Pressey free(dialog);
40621ece67dSChris Pressey close(fd);
40721ece67dSChris Pressey }
40821ece67dSChris Pressey
40921ece67dSChris Pressey /*
41021ece67dSChris Pressey * Search for 'token' in comma delimited array 'buffer'.
41121ece67dSChris Pressey * Return true for found, false for not found.
41221ece67dSChris Pressey */
41321ece67dSChris Pressey static int
find_token(const char * buffer,const char * token)41421ece67dSChris Pressey find_token(const char *buffer, const char *token)
41521ece67dSChris Pressey {
41621ece67dSChris Pressey char *buffer_tmp, *buffer_copy, *inputstring;
41721ece67dSChris Pressey char **ap;
41821ece67dSChris Pressey int found;
41921ece67dSChris Pressey
42021ece67dSChris Pressey buffer_copy = strdup(buffer);
42121ece67dSChris Pressey buffer_tmp = buffer_copy;
42221ece67dSChris Pressey inputstring = buffer_copy;
42321ece67dSChris Pressey ap = &buffer_tmp;
42421ece67dSChris Pressey
42521ece67dSChris Pressey found = 0;
42621ece67dSChris Pressey
42721ece67dSChris Pressey while ((*ap = strsep(&inputstring, ",")) != NULL) {
42821ece67dSChris Pressey if (strcmp(buffer_tmp, token) == 0) {
42921ece67dSChris Pressey found = 1;
43021ece67dSChris Pressey break;
43121ece67dSChris Pressey }
43221ece67dSChris Pressey }
43321ece67dSChris Pressey
43421ece67dSChris Pressey free(buffer_copy);
43521ece67dSChris Pressey
43621ece67dSChris Pressey return found;
43721ece67dSChris Pressey }
43821ece67dSChris Pressey
43921ece67dSChris Pressey /*
44021ece67dSChris Pressey * Compare function for qsort
44121ece67dSChris Pressey */
44221ece67dSChris Pressey static int
compare_keymap(const void * a,const void * b)44321ece67dSChris Pressey compare_keymap(const void *a, const void *b)
44421ece67dSChris Pressey {
44521ece67dSChris Pressey
44621ece67dSChris Pressey /* We've been passed pointers to pointers, so: */
44721ece67dSChris Pressey const struct keymap *km1 = *((const struct keymap * const *) a);
44821ece67dSChris Pressey const struct keymap *km2 = *((const struct keymap * const *) b);
44921ece67dSChris Pressey
45021ece67dSChris Pressey return strcmp(km1->desc, km2->desc);
45121ece67dSChris Pressey }
45221ece67dSChris Pressey
45321ece67dSChris Pressey /*
45421ece67dSChris Pressey * Compare function for qsort
45521ece67dSChris Pressey */
45621ece67dSChris Pressey static int
compare_lang(const void * a,const void * b)45721ece67dSChris Pressey compare_lang(const void *a, const void *b)
45821ece67dSChris Pressey {
45921ece67dSChris Pressey const char *l1 = *((const char * const *) a);
46021ece67dSChris Pressey const char *l2 = *((const char * const *) b);
46121ece67dSChris Pressey
46221ece67dSChris Pressey return strcmp(l1, l2);
46321ece67dSChris Pressey }
46421ece67dSChris Pressey
46521ece67dSChris Pressey /*
46621ece67dSChris Pressey * Change '8x8' to '8x08' so qsort will put it before eg. '8x14'
46721ece67dSChris Pressey */
46821ece67dSChris Pressey static void
kludge_desc(struct keymap ** km_sorted,int num_keymaps)46921ece67dSChris Pressey kludge_desc(struct keymap **km_sorted, int num_keymaps)
47021ece67dSChris Pressey {
47121ece67dSChris Pressey int i;
47221ece67dSChris Pressey
47321ece67dSChris Pressey for (i=0; i<num_keymaps; i++) {
47421ece67dSChris Pressey char *p;
47521ece67dSChris Pressey char *km = km_sorted[i]->desc;
47621ece67dSChris Pressey if ((p = strstr(km, "8x8")) != NULL) {
47721ece67dSChris Pressey int len;
47821ece67dSChris Pressey int j;
47921ece67dSChris Pressey int offset;
48021ece67dSChris Pressey
48121ece67dSChris Pressey offset = p - km;
48221ece67dSChris Pressey
48321ece67dSChris Pressey /* Make enough space for the extra '0' */
48421ece67dSChris Pressey len = strlen(km);
48521ece67dSChris Pressey km = realloc(km, len + 2);
48621ece67dSChris Pressey
48721ece67dSChris Pressey for (j=len; j!=offset+1; j--)
48821ece67dSChris Pressey km[j + 1] = km[j];
48921ece67dSChris Pressey
49021ece67dSChris Pressey km[offset+2] = '0';
49121ece67dSChris Pressey
49221ece67dSChris Pressey km_sorted[i]->desc = km;
49321ece67dSChris Pressey }
49421ece67dSChris Pressey }
49521ece67dSChris Pressey }
49621ece67dSChris Pressey
49721ece67dSChris Pressey /*
49821ece67dSChris Pressey * Reverse 'kludge_desc()' - change '8x08' back to '8x8'
49921ece67dSChris Pressey */
50021ece67dSChris Pressey static void
unkludge_desc(struct keymap ** km_sorted,int num_keymaps)50121ece67dSChris Pressey unkludge_desc(struct keymap **km_sorted, int num_keymaps)
50221ece67dSChris Pressey {
50321ece67dSChris Pressey int i;
50421ece67dSChris Pressey
50521ece67dSChris Pressey for (i=0; i<num_keymaps; i++) {
50621ece67dSChris Pressey char *p;
50721ece67dSChris Pressey char *km = km_sorted[i]->desc;
50821ece67dSChris Pressey if ((p = strstr(km, "8x08")) != NULL) {
50921ece67dSChris Pressey p += 2;
51021ece67dSChris Pressey while (*p++)
51121ece67dSChris Pressey p[-1] = p[0];
51221ece67dSChris Pressey
51321ece67dSChris Pressey km = realloc(km, p - km - 1);
51421ece67dSChris Pressey km_sorted[i]->desc = km;
51521ece67dSChris Pressey }
51621ece67dSChris Pressey }
51721ece67dSChris Pressey }
51821ece67dSChris Pressey
51921ece67dSChris Pressey /*
52021ece67dSChris Pressey * Return 0 if file exists and is readable, else -1
52121ece67dSChris Pressey */
52221ece67dSChris Pressey static int
check_file(const char * keym)52321ece67dSChris Pressey check_file(const char *keym)
52421ece67dSChris Pressey {
52521ece67dSChris Pressey int status = 0;
52621ece67dSChris Pressey
52721ece67dSChris Pressey if (access(keym, R_OK) == -1) {
52821ece67dSChris Pressey char *fn;
52921ece67dSChris Pressey asprintf(&fn, "%s/%s", dir, keym);
53021ece67dSChris Pressey if (access(fn, R_OK) == -1) {
53121ece67dSChris Pressey if (verbose)
53221ece67dSChris Pressey fprintf(stderr, "%s not found!\n", fn);
53321ece67dSChris Pressey status = -1;
53421ece67dSChris Pressey }
53521ece67dSChris Pressey free(fn);
53621ece67dSChris Pressey } else {
53721ece67dSChris Pressey if (verbose)
53821ece67dSChris Pressey fprintf(stderr, "No read permission for %s!\n", keym);
53921ece67dSChris Pressey status = -1;
54021ece67dSChris Pressey }
54121ece67dSChris Pressey
54221ece67dSChris Pressey return status;
54321ece67dSChris Pressey }
54421ece67dSChris Pressey
54521ece67dSChris Pressey /*
546*ebfa7d96SPeter Avalos * Read options from the relevant configuration file, then
54721ece67dSChris Pressey * present to user.
54821ece67dSChris Pressey */
54921ece67dSChris Pressey static void
menu_read(void)55021ece67dSChris Pressey menu_read(void)
55121ece67dSChris Pressey {
55221ece67dSChris Pressey const char *lg;
55321ece67dSChris Pressey char *p;
55421ece67dSChris Pressey int mark, num_keymaps, items, i;
55521ece67dSChris Pressey char buffer[256], filename[PATH_MAX];
55621ece67dSChris Pressey char keym[64], lng[64], desc[64];
55721ece67dSChris Pressey char dialect[64], lang_abk[64];
55821ece67dSChris Pressey struct keymap *km;
55921ece67dSChris Pressey struct keymap **km_sorted;
56021ece67dSChris Pressey struct dirent *dp;
56121ece67dSChris Pressey StringList *lang_list;
56221ece67dSChris Pressey FILE *fp;
56321ece67dSChris Pressey DIR *dirp;
56421ece67dSChris Pressey
56521ece67dSChris Pressey lang_list = sl_init();
56621ece67dSChris Pressey
56721ece67dSChris Pressey sprintf(filename, "%s/INDEX.%s", dir, extract_name(dir));
56821ece67dSChris Pressey
56921ece67dSChris Pressey /* en_US.ISO8859-1 -> en_..\.ISO8859-1 */
57021ece67dSChris Pressey strlcpy(dialect, lang, sizeof(dialect));
571*ebfa7d96SPeter Avalos if (strlen(dialect) >= 6 && dialect[2] == '_') {
57221ece67dSChris Pressey dialect[3] = '.';
57321ece67dSChris Pressey dialect[4] = '.';
57421ece67dSChris Pressey }
57521ece67dSChris Pressey
57621ece67dSChris Pressey
57721ece67dSChris Pressey /* en_US.ISO8859-1 -> en */
57821ece67dSChris Pressey strlcpy(lang_abk, lang, sizeof(lang_abk));
579*ebfa7d96SPeter Avalos if (strlen(lang_abk) >= 3 && lang_abk[2] == '_')
580*ebfa7d96SPeter Avalos lang_abk[2] = '\0';
58121ece67dSChris Pressey
58221ece67dSChris Pressey fprintf(stderr, "lang_default = %s\n", lang_default);
58321ece67dSChris Pressey fprintf(stderr, "dialect = %s\n", dialect);
58421ece67dSChris Pressey fprintf(stderr, "lang_abk = %s\n", lang_abk);
58521ece67dSChris Pressey
58621ece67dSChris Pressey fp = fopen(filename, "r");
58721ece67dSChris Pressey if (fp) {
58821ece67dSChris Pressey int matches;
58921ece67dSChris Pressey while (fgets(buffer, sizeof(buffer), fp)) {
59021ece67dSChris Pressey p = buffer;
59121ece67dSChris Pressey if (p[0] == '#')
59221ece67dSChris Pressey continue;
59321ece67dSChris Pressey
59421ece67dSChris Pressey while (isspace(*p))
59521ece67dSChris Pressey p++;
59621ece67dSChris Pressey
59721ece67dSChris Pressey if (*p == '\0')
59821ece67dSChris Pressey continue;
59921ece67dSChris Pressey
60021ece67dSChris Pressey /* Parse input, removing newline */
60121ece67dSChris Pressey matches = sscanf(p, "%64[^:]:%64[^:]:%64[^:\n]",
60221ece67dSChris Pressey keym, lng, desc);
60321ece67dSChris Pressey if (matches == 3) {
60421ece67dSChris Pressey if (strcmp(keym, "FONT")
60521ece67dSChris Pressey && strcmp(keym, "MENU")) {
60621ece67dSChris Pressey /* Check file exists & is readable */
60721ece67dSChris Pressey if (check_file(keym) == -1)
60821ece67dSChris Pressey continue;
60921ece67dSChris Pressey }
61021ece67dSChris Pressey }
61121ece67dSChris Pressey
61221ece67dSChris Pressey if (show) {
61321ece67dSChris Pressey /*
61421ece67dSChris Pressey * Take note of supported languages, which
61521ece67dSChris Pressey * might be in a comma-delimited list
61621ece67dSChris Pressey */
61721ece67dSChris Pressey char *tmp = strdup(lng);
61821ece67dSChris Pressey char *delim = tmp;
61921ece67dSChris Pressey
62021ece67dSChris Pressey for (delim = tmp; ; ) {
62121ece67dSChris Pressey char ch = *delim++;
62221ece67dSChris Pressey if (ch == ',' || ch == '\0') {
62321ece67dSChris Pressey delim[-1] = '\0';
62421ece67dSChris Pressey if (!sl_find(lang_list, tmp))
62521ece67dSChris Pressey sl_add(lang_list, tmp);
62621ece67dSChris Pressey if (ch == '\0')
62721ece67dSChris Pressey break;
62821ece67dSChris Pressey tmp = delim;
62921ece67dSChris Pressey }
63021ece67dSChris Pressey }
63121ece67dSChris Pressey }
63221ece67dSChris Pressey /* Set empty language to default language */
63321ece67dSChris Pressey if (lng[0] == '\0')
63421ece67dSChris Pressey lg = lang_default;
63521ece67dSChris Pressey else
63621ece67dSChris Pressey lg = lng;
63721ece67dSChris Pressey
63821ece67dSChris Pressey
63921ece67dSChris Pressey /* 4) Your choice if it exists
64021ece67dSChris Pressey * 3) Long match eg. en_GB.ISO8859-1 is equal to
64121ece67dSChris Pressey * en_..\.ISO8859-1
64221ece67dSChris Pressey * 2) short match 'de'
64321ece67dSChris Pressey * 1) default langlist 'en'
64421ece67dSChris Pressey * 0) any language
64521ece67dSChris Pressey *
64621ece67dSChris Pressey * Language may be a comma separated list
64721ece67dSChris Pressey * A higher match overwrites a lower
64821ece67dSChris Pressey * A later entry overwrites a previous if it exists
64921ece67dSChris Pressey * twice in the database
65021ece67dSChris Pressey */
65121ece67dSChris Pressey
65221ece67dSChris Pressey /* Check for favoured language */
65321ece67dSChris Pressey km = get_keymap(keym);
65421ece67dSChris Pressey mark = (km) ? km->mark : 0;
65521ece67dSChris Pressey
65621ece67dSChris Pressey if (find_token(lg, lang))
65721ece67dSChris Pressey add_keymap(desc, 4, keym);
65821ece67dSChris Pressey else if (mark <= 3 && find_token(lg, dialect))
65921ece67dSChris Pressey add_keymap(desc, 3, keym);
66021ece67dSChris Pressey else if (mark <= 2 && find_token(lg, lang_abk))
66121ece67dSChris Pressey add_keymap(desc, 2, keym);
66221ece67dSChris Pressey else if (mark <= 1 && find_token(lg, lang_default))
66321ece67dSChris Pressey add_keymap(desc, 1, keym);
66421ece67dSChris Pressey else if (mark <= 0)
66521ece67dSChris Pressey add_keymap(desc, 0, keym);
66621ece67dSChris Pressey }
66721ece67dSChris Pressey fclose(fp);
66821ece67dSChris Pressey
66921ece67dSChris Pressey } else
67021ece67dSChris Pressey printf("Could not open file\n");
67121ece67dSChris Pressey
67221ece67dSChris Pressey if (show) {
67321ece67dSChris Pressey qsort(lang_list->sl_str, lang_list->sl_cur, sizeof(char*),
67421ece67dSChris Pressey compare_lang);
67521ece67dSChris Pressey printf("Currently supported languages: ");
67621ece67dSChris Pressey for (i=0; i< (int) lang_list->sl_cur; i++)
67721ece67dSChris Pressey printf("%s ", lang_list->sl_str[i]);
67821ece67dSChris Pressey puts("");
67921ece67dSChris Pressey exit(0);
68021ece67dSChris Pressey }
68121ece67dSChris Pressey
68221ece67dSChris Pressey km = get_keymap("MENU");
68321ece67dSChris Pressey if (km)
68421ece67dSChris Pressey /* Take note of menu title */
68521ece67dSChris Pressey menu = strdup(km->desc);
68621ece67dSChris Pressey km = get_keymap("FONT");
68721ece67dSChris Pressey if (km)
68821ece67dSChris Pressey /* Take note of language font */
68921ece67dSChris Pressey font = strdup(km->desc);
69021ece67dSChris Pressey
69121ece67dSChris Pressey /* Remove unwanted items from list */
69221ece67dSChris Pressey remove_keymap("MENU");
69321ece67dSChris Pressey remove_keymap("FONT");
69421ece67dSChris Pressey
69521ece67dSChris Pressey /* Look for keymaps not in database */
69621ece67dSChris Pressey dirp = opendir(dir);
69721ece67dSChris Pressey if (dirp) {
69821ece67dSChris Pressey while ((dp = readdir(dirp)) != NULL) {
69921ece67dSChris Pressey const char *ext = get_extension(dp->d_name);
70021ece67dSChris Pressey if (ext) {
70121ece67dSChris Pressey if ((!strcmp(ext, ".fnt") ||
70221ece67dSChris Pressey !strcmp(ext, ".kbd")) &&
70321ece67dSChris Pressey !get_keymap(dp->d_name)) {
70421ece67dSChris Pressey char *q;
70521ece67dSChris Pressey
70621ece67dSChris Pressey /* Remove any .fnt or .kbd extension */
70721ece67dSChris Pressey q = strdup(dp->d_name);
70821ece67dSChris Pressey *(get_extension(q)) = '\0';
70921ece67dSChris Pressey add_keymap(q, 0, dp->d_name);
71021ece67dSChris Pressey free(q);
71121ece67dSChris Pressey
71221ece67dSChris Pressey if (verbose)
71321ece67dSChris Pressey fprintf(stderr,
71421ece67dSChris Pressey "'%s' not in database\n",
71521ece67dSChris Pressey dp->d_name);
71621ece67dSChris Pressey }
71721ece67dSChris Pressey }
71821ece67dSChris Pressey }
71921ece67dSChris Pressey closedir(dirp);
72021ece67dSChris Pressey } else
72121ece67dSChris Pressey fprintf(stderr, "Could not open directory '%s'\n", dir);
72221ece67dSChris Pressey
72321ece67dSChris Pressey /* Sort items in keymap */
72421ece67dSChris Pressey num_keymaps = get_num_keymaps();
72521ece67dSChris Pressey
72621ece67dSChris Pressey km_sorted = (struct keymap **)
72721ece67dSChris Pressey malloc(num_keymaps*sizeof(struct keymap *));
72821ece67dSChris Pressey
72921ece67dSChris Pressey /* Make array of pointers to items in hash */
73021ece67dSChris Pressey items = 0;
73121ece67dSChris Pressey SLIST_FOREACH(km, &head, entries)
73221ece67dSChris Pressey km_sorted[items++] = km;
73321ece67dSChris Pressey
73421ece67dSChris Pressey /* Change '8x8' to '8x08' so sort works as we might expect... */
73521ece67dSChris Pressey kludge_desc(km_sorted, num_keymaps);
73621ece67dSChris Pressey
73721ece67dSChris Pressey qsort(km_sorted, num_keymaps, sizeof(struct keymap *), compare_keymap);
73821ece67dSChris Pressey
73921ece67dSChris Pressey /* ...change back again */
74021ece67dSChris Pressey unkludge_desc(km_sorted, num_keymaps);
74121ece67dSChris Pressey
74221ece67dSChris Pressey if (print) {
74321ece67dSChris Pressey for (i=0; i<num_keymaps; i++)
74421ece67dSChris Pressey printf("%s\n", km_sorted[i]->desc);
74521ece67dSChris Pressey exit(0);
74621ece67dSChris Pressey }
74721ece67dSChris Pressey
74821ece67dSChris Pressey show_dialog(km_sorted, num_keymaps);
74921ece67dSChris Pressey
75021ece67dSChris Pressey free(km_sorted);
75121ece67dSChris Pressey }
75221ece67dSChris Pressey
75321ece67dSChris Pressey /*
75421ece67dSChris Pressey * Display usage information and exit
75521ece67dSChris Pressey */
75621ece67dSChris Pressey static void
usage(void)75721ece67dSChris Pressey usage(void)
75821ece67dSChris Pressey {
75921ece67dSChris Pressey
76021ece67dSChris Pressey fprintf(stderr, "usage: %s\t[-K] [-V] [-d|-default] [-h|-help] "
76121ece67dSChris Pressey "[-l|-lang language]\n\t\t[-p|-print] [-r|-restore] [-s|-show] "
76221ece67dSChris Pressey "[-v|-verbose]\n", program);
76321ece67dSChris Pressey exit(1);
76421ece67dSChris Pressey }
76521ece67dSChris Pressey
76621ece67dSChris Pressey static void
parse_args(int argc,char ** argv)76721ece67dSChris Pressey parse_args(int argc, char **argv)
76821ece67dSChris Pressey {
76921ece67dSChris Pressey int i;
77021ece67dSChris Pressey
77121ece67dSChris Pressey for (i=1; i<argc; i++) {
77221ece67dSChris Pressey if (argv[i][0] != '-')
77321ece67dSChris Pressey usage();
77421ece67dSChris Pressey else if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "-h"))
77521ece67dSChris Pressey usage();
77621ece67dSChris Pressey else if (!strcmp(argv[i], "-verbose") || !strcmp(argv[i], "-v"))
77721ece67dSChris Pressey verbose = 1;
77821ece67dSChris Pressey else if (!strcmp(argv[i], "-lang") || !strcmp(argv[i], "-l"))
77921ece67dSChris Pressey if (i + 1 == argc)
78021ece67dSChris Pressey usage();
78121ece67dSChris Pressey else
78221ece67dSChris Pressey lang = argv[++i];
78321ece67dSChris Pressey else if (!strcmp(argv[i], "-default") || !strcmp(argv[i], "-d"))
78421ece67dSChris Pressey lang = lang_default;
78521ece67dSChris Pressey else if (!strcmp(argv[i], "-show") || !strcmp(argv[i], "-s"))
78621ece67dSChris Pressey show = 1;
78721ece67dSChris Pressey else if (!strcmp(argv[i], "-print") || !strcmp(argv[i], "-p"))
78821ece67dSChris Pressey print = 1;
78921ece67dSChris Pressey else if (!strcmp(argv[i], "-restore") ||
79021ece67dSChris Pressey !strcmp(argv[i], "-r")) {
79121ece67dSChris Pressey vidcontrol(font_current);
79221ece67dSChris Pressey exit(0);
79321ece67dSChris Pressey } else if (!strcmp(argv[i], "-K"))
79421ece67dSChris Pressey dir = keymapdir;
79521ece67dSChris Pressey else if (!strcmp(argv[i], "-V"))
79621ece67dSChris Pressey dir = fontdir;
79721ece67dSChris Pressey else
79821ece67dSChris Pressey usage();
79921ece67dSChris Pressey }
80021ece67dSChris Pressey }
80121ece67dSChris Pressey
80221ece67dSChris Pressey /*
80321ece67dSChris Pressey * A front-end for the 'vidfont' and 'kbdmap' programs.
80421ece67dSChris Pressey */
80521ece67dSChris Pressey int
main(int argc,char ** argv)80621ece67dSChris Pressey main(int argc, char **argv)
80721ece67dSChris Pressey {
80821ece67dSChris Pressey
80921ece67dSChris Pressey x11 = system("kbdcontrol -d >/dev/null");
81021ece67dSChris Pressey
81121ece67dSChris Pressey if (x11) {
81221ece67dSChris Pressey fprintf(stderr, "You are not on a virtual console - "
81321ece67dSChris Pressey "expect certain strange side-effects\n");
81421ece67dSChris Pressey sleep(2);
81521ece67dSChris Pressey }
81621ece67dSChris Pressey
81721ece67dSChris Pressey SLIST_INIT(&head);
81821ece67dSChris Pressey
81921ece67dSChris Pressey lang = get_locale();
82021ece67dSChris Pressey
82121ece67dSChris Pressey program = extract_name(argv[0]);
82221ece67dSChris Pressey
82321ece67dSChris Pressey font_current = get_font();
82421ece67dSChris Pressey if (font_current == NULL)
82521ece67dSChris Pressey font_current = font_default;
82621ece67dSChris Pressey
82721ece67dSChris Pressey if (strcmp(program, "kbdmap"))
82821ece67dSChris Pressey dir = fontdir;
82921ece67dSChris Pressey else
83021ece67dSChris Pressey dir = keymapdir;
83121ece67dSChris Pressey
832914238a4SSascha Wildner /* Parse command line arguments */
833914238a4SSascha Wildner parse_args(argc, argv);
834914238a4SSascha Wildner
83521ece67dSChris Pressey /* Read and display options */
83621ece67dSChris Pressey menu_read();
83721ece67dSChris Pressey
83821ece67dSChris Pressey return 0;
83921ece67dSChris Pressey }
840