blob: 1dc923a9c844ae6a061824ea11b2c51030cb22e8 [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <errno.h>
#include <error.h>
#include "kbd.h"
#include "getfd.h"
#include "nls.h"
#include "version.h"
static unsigned char *cmap;
/* Standard VGA terminal colors, matching those hardcoded in the Linux kernel's
* drivers/char/vt.c
*/
unsigned char vga_colors[] = {
0x00, 0x00, 0x00,
0xaa, 0x00, 0x00,
0x00, 0xaa, 0x00,
0xaa, 0x55, 0x00,
0x00, 0x00, 0xaa,
0xaa, 0x00, 0xaa,
0x00, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa,
0x55, 0x55, 0x55,
0xff, 0x55, 0x55,
0x55, 0xff, 0x55,
0xff, 0xff, 0x55,
0x55, 0x55, 0xff,
0xff, 0x55, 0xff,
0x55, 0xff, 0xff,
0xff, 0xff, 0xff,
};
static void attr_noreturn
usage(int code)
{
fprintf(stderr,
_("Usage: %s vga|FILE|-\n"
"\n"
"If you use the FILE parameter, FILE should be exactly 3 lines of\n"
"comma-separated decimal values for RED, GREEN, and BLUE.\n"
"\n"
"To seed a valid FILE:\n"
" cat /sys/module/vt/parameters/default_{red,grn,blu} > FILE\n"
"\n"
"and then edit the values in FILE.\n"
"\n"),
progname);
exit(code);
}
static void
set_colormap(unsigned char *colormap)
{
int fd = getfd(NULL);
/* Apply the color map to the tty via ioctl */
if (ioctl(fd, PIO_CMAP, colormap) == -1)
error(EXIT_FAILURE, errno, "ioctl");
close(fd);
}
static void
parse_file(FILE *fd, const char *filename)
{
int c;
unsigned int rows, cols, val;
if ((cmap = calloc(3 * 16, sizeof(unsigned char))) == NULL)
error(EXIT_FAILURE, errno, "calloc");
for (rows = 0; rows < 3; rows++) {
cols = 0;
while (cols < 16) {
if ((c = fscanf(fd, "%u", &val)) != 1) {
if (c == EOF)
error(EXIT_FAILURE, errno, "fscanf");
error(EXIT_FAILURE, 0, _("Error: %s: Invalid value in field %u in line %u."),
filename, rows + 1, cols + 1);
}
cmap[rows + cols * 3] = (unsigned char) val;
if (cols < 15 && fgetc(fd) != ',')
error(EXIT_FAILURE, 0, _("Error: %s: Insufficient number of fields in line %u."),
filename, rows + 1);
cols++;
}
if ((c = fgetc(fd)) == EOF)
error(EXIT_FAILURE, 0, _("Error: %s: Line %u has ended unexpectedly.\n"),
filename, rows + 1);
if (c != '\n')
error(EXIT_FAILURE, 0, _("Error: %s: Line %u is too long.\n"),
filename, rows + 1);
}
}
int
main(int argc, char **argv) {
int c;
const char *file;
FILE *fd;
set_progname(argv[0]);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE_NAME, LOCALEDIR);
textdomain(PACKAGE_NAME);
while ((c = getopt(argc, argv, "hV")) != EOF) {
switch (c) {
case 'V':
print_version_and_exit();
break;
case 'h':
usage(EXIT_SUCCESS);
break;
}
}
if (optind == argc)
usage(EXIT_FAILURE);
file = argv[optind];
if (!strcmp(file, "vga")) {
set_colormap(vga_colors);
return EXIT_SUCCESS;
} else if (!strcmp(file, "-")) {
parse_file(stdin, "stdin");
} else {
if ((fd = fopen(file, "r")) == NULL)
error(EXIT_FAILURE, errno, "fopen");
parse_file(fd, file);
fclose(fd);
}
set_colormap(cmap);
free(cmap);
return EXIT_SUCCESS;
}