blob: dc336c18beaae6e08416e4bd41222e630fa78d4b [file] [log] [blame]
/*
* setfont.c - Eugene Crosser & Andries Brouwer
*/
#include "config.h"
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sysexits.h>
#include <kfont.h>
#include "libcommon.h"
static void KBD_ATTR_NORETURN
usage(int retcode, const struct kbd_help *options)
{
fprintf(stderr, _("Usage: %s [option...] [newfont...]\n"), program_invocation_short_name);
fprintf(stderr, "\n");
fprintf(stderr, _("Loads the console font, and possibly the corresponding screen map(s).\n"));
print_options(options);
fprintf(stderr, "\n");
fprintf(stderr,
_("The options -[o|O|om|ou] are processed before the new font is uploaded.\n"
"\n"
"If no <newfont> and no -[o|O|om|ou|m|u] option is given, a default\n"
"font is loaded.\n"
"\n"
"There are two kinds of screen maps, one [-m] giving the correspondence\n"
"between some arbitrary 8-bit character set currently in use and the\n"
"font positions, and the second [-u] giving the correspondence between\n"
"font positions and Unicode values.\n"
"\n"
"Explicitly (with -m or -u) or implicitly (in the fontfile) given\n"
"mappings will be loaded and, in the case of consolemaps, activated.\n"
"\n"
"Files are loaded from the %s/*/.\n"),
DATADIR);
print_report_bugs();
exit(retcode);
}
enum kbd_getopt_arg {
kbd_no_argument,
kbd_required_argument
};
struct kbd_option {
const char *short_name;
const char *long_name;
enum kbd_getopt_arg has_arg;
int val;
};
static int
kbd_getopt(int argc, char **argv, const struct kbd_option *opts)
{
const struct kbd_option *opt;
char *p, *o, *option;
const char *name;
optarg = NULL;
if (!optind)
optind = 1;
if (optind >= argc || !argv[optind])
return -1;
if (argv[optind][0] != '-')
return '?';
option = argv[optind];
if (option[1] && option[1] != '-') {
// A short option that starts with "-" (not "--"). Unlike the
// standard getopt for historical reasons we have two character
// short options.
option += 1;
for (opt = opts; opt->val; opt++) {
name = opt->short_name + 1;
for (p = (char *) name, o = option; *p && *p == *o; p++, o++);
switch (opt->short_name[0]) {
// Case: full match option.
case '=':
if (*p == *o) {
optind++;
if (opt->has_arg) {
if (optind == argc)
goto required_argument;
optarg = argv[optind++];
}
return opt->val;
}
break;
// Case: prefix option.
case '+':
if (*p == '\0' && *o != '\0') {
optind++;
if (opt->has_arg)
optarg = o;
return opt->val;
}
break;
}
}
} else if (option[1] && option[1] == '-') {
// The special argument "--" forces an end of option-scanning
// regardless of the scanning mode.
if (!option[2]) {
optind++;
return -1;
}
option += 2;
for (opt = opts; opt->val; opt++) {
name = opt->long_name;
for (p = (char *) name, o = option; *p && *p == *o; p++, o++);
// Case: --arg param
if (*p == *o) {
optind++;
if (opt->has_arg) {
if (optind == argc)
goto required_argument;
optarg = argv[optind++];
}
return opt->val;
}
if (!opt->has_arg)
continue;
// Case: --arg=param
if (*p == '\0' && *o == '=') {
optind++;
optarg = ++o;
if (!optarg[0])
goto required_argument;
return opt->val;
}
}
}
return '?';
required_argument:
optind--;
return '!';
}
int main(int argc, char *argv[])
{
const char *ifiles[MAXIFILES];
char *mfil, *ufil, *Ofil, *ofil, *omfil, *oufil, *console;
int ifilct = 0, fd, no_m, no_u;
unsigned int iunit, hwunit;
int restore = 0;
int ret, c;
struct kfont_context *kfont;
const struct kbd_help opthelp[] = {
{ "-<N>, --default8x <N>", _("load font \"default8x<N>\".") },
{ "-h<N>, --font-height <N>", _("override font height (there shouldn't be a space in the short option).") },
{ "-o, --output-font <FILE>", _("write current font to <FILE>.") },
{ "-om, --output-consolemap <FILE>", _("write current consolemap to <FILE>.") },
{ "-ou, --output-unicodemap <FILE>", _("write current unicodemap to <FILE>.") },
{ "-O, --output-fullfont <FILE>", _("write current font and unicode map to <FILE>.") },
{ "-m, --consolemap <FILE>", _("load console screen map ('none' means don't load it).") },
{ "-u, --unicodemap <FILE>", _("load font unicode map ('none' means don't load it).") },
{ "-C, --console <DEV>", _("the console device to be used.") },
{ "-d, --double", _("double size of font horizontally and vertically.") },
{ "-f, --force", _("force load unicode map.") },
{ "-R, --reset", _("reset the screen font, size, and unicode map to the bootup defaults.") },
{ "-v, --verbose", _("be more verbose.") },
{ "-V, --version", _("print version number.") },
{ "-h, --help", _("print this usage message.") },
{ NULL, NULL }
};
const struct kbd_option opts[] = {
{ "=d", "double", kbd_no_argument, 'd' },
{ "=f", "force", kbd_no_argument, 'f' },
{ "=R", "reset", kbd_no_argument, 'R' },
{ "=v", "verbose", kbd_no_argument, 'v' },
{ "=V", "version", kbd_no_argument, 'V' },
{ "=h", "help", kbd_no_argument, 'H' },
{ "+h", "font-height", kbd_required_argument, 'h' },
{ "=om", "output-consolemap", kbd_required_argument, 'M' },
{ "=ou", "output-unicodemap", kbd_required_argument, 'U' },
{ "=o", "output-font", kbd_required_argument, 'o' },
{ "=O", "output-fullfont", kbd_required_argument, 'O' },
{ "=m", "consolemap", kbd_required_argument, 'm' },
{ "=u", "unicodemap", kbd_required_argument, 'u' },
{ "=C", "console", kbd_required_argument, 'C' },
{ "+", "default8x", kbd_required_argument, 'N' },
{ NULL, NULL, 0, 0 },
};
setuplocale();
if ((ret = kfont_init(program_invocation_short_name, &kfont)) < 0)
return -ret;
ifiles[0] = mfil = ufil = Ofil = ofil = omfil = oufil = NULL;
iunit = hwunit = 0;
no_m = no_u = 0;
console = NULL;
while ((c = kbd_getopt(argc, argv, opts)) != -1) {
switch (c) {
case 'h': {
int num = atoi(optarg);
if (num <= 0 || num > 32) {
kbd_warning(0, "bad option '%s': not a number '%s'",
argv[optind - 1], optarg);
usage(EX_USAGE, opthelp);
}
hwunit = (unsigned int) num;
}
break;
case 'N': {
int num = atoi(optarg);
if (num <= 0 || num > 32) {
kbd_warning(0, "unrecognized option '%s'",
argv[optind - 1]);
usage(EX_USAGE, opthelp);
}
iunit = (unsigned int) num;
}
break;
case 'o':
ofil = optarg;
break;
case 'M':
omfil = optarg;
break;
case 'U':
oufil = optarg;
break;
case 'm':
no_m = !strcmp(optarg, "none");
if (!no_m)
mfil = optarg;
break;
case 'u':
no_u = !strcmp(optarg, "none");
if (!no_u)
ufil = optarg;
break;
case 'O':
Ofil = optarg;
break;
case 'C':
console = optarg;
break;
case 'R':
restore = 1;
break;
case 'd':
kfont_set_option(kfont, kfont_double_size);
break;
case 'f':
kfont_set_option(kfont, kfont_force);
break;
case 'v':
kfont_inc_verbosity(kfont);
break;
case 'V':
print_version_and_exit();
break;
case 'H':
usage(EXIT_SUCCESS, opthelp);
break;
case '?':
if (argv[optind][0] == '-') {
kbd_warning(0, "invalid option '%s'", argv[optind]);
usage(EX_USAGE, opthelp);
}
if (ifilct == MAXIFILES)
kbd_error(EX_USAGE, 0, _("Too many input files."));
ifiles[ifilct++] = argv[optind++];
break;
case '!':
kbd_warning(0, "option '%s' requires an argument", argv[optind]);
usage(EX_USAGE, opthelp);
break;
}
}
for (; optind < argc; optind++) {
if (ifilct == MAXIFILES)
kbd_error(EX_USAGE, 0, _("Too many input files."));
ifiles[ifilct++] = argv[optind];
}
if (ifilct && restore)
kbd_error(EX_USAGE, 0, _("Cannot both restore from character ROM"
" and from file. Font unchanged."));
if ((fd = getfd(console)) < 0)
kbd_error(EX_OSERR, 0, _("Couldn't get a file descriptor referring to the console."));
int kd_mode = -1;
if (!ioctl(fd, KDGETMODE, &kd_mode) && (kd_mode == KD_GRAPHICS)) {
/*
* PIO_FONT will fail on a console which is in foreground and in KD_GRAPHICS mode.
* 2005-03-03, jw@suse.de.
*/
if (kfont_get_verbosity(kfont))
kbd_warning(0, "graphics console %s skipped", console ? console : "");
close(fd);
return EX_OK;
}
if (!ifilct && !mfil && !ufil &&
!Ofil && !ofil && !omfil && !oufil && !restore)
/* reset to some default */
ifiles[ifilct++] = "";
if (Ofil && (ret = kfont_save_font(kfont, fd, Ofil, 1)) < 0)
return -ret;
if (ofil && (ret = kfont_save_font(kfont, fd, ofil, 0)) < 0)
return -ret;
if (omfil && (ret = kfont_save_consolemap(kfont, fd, omfil)) < 0)
return -ret;
if (oufil && (ret = kfont_save_unicodemap(kfont, fd, oufil)) < 0)
return -ret;
if (mfil) {
if ((ret = kfont_load_consolemap(kfont, fd, mfil)) < 0)
return -ret;
kfont_activatemap(fd);
no_m = 1;
}
if (ufil)
no_u = 1;
if (restore)
kfont_restore_font(kfont, fd);
if (ifilct && (ret = kfont_load_fonts(kfont, fd, ifiles, ifilct, iunit, hwunit, no_m, no_u)) < 0)
return -ret;
if (ufil && (ret = kfont_load_unicodemap(kfont, fd, ufil)) < 0)
return -ret;
return EX_OK;
}