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