New vidcontrol utility replaces old syscons(1)
authorSoren Schmidt <sos@FreeBSD.org>
Fri, 20 May 1994 12:20:38 +0000 (12:20 +0000)
committerSoren Schmidt <sos@FreeBSD.org>
Fri, 20 May 1994 12:20:38 +0000 (12:20 +0000)
Font files are now uuencoded, and so are the scrnmaps.
Also allows changing colors and cursor type

usr.bin/vidcontrol/Makefile [new file with mode: 0644]
usr.bin/vidcontrol/decode.c [new file with mode: 0644]
usr.bin/vidcontrol/path.h [new file with mode: 0644]
usr.bin/vidcontrol/vidcontrol.c [new file with mode: 0644]
usr.sbin/vidcontrol/Makefile [new file with mode: 0644]
usr.sbin/vidcontrol/decode.c [new file with mode: 0644]
usr.sbin/vidcontrol/path.h [new file with mode: 0644]
usr.sbin/vidcontrol/vidcontrol.c [new file with mode: 0644]

diff --git a/usr.bin/vidcontrol/Makefile b/usr.bin/vidcontrol/Makefile
new file mode 100644 (file)
index 0000000..09d8eb1
--- /dev/null
@@ -0,0 +1,6 @@
+PROG=  vidcontrol
+SRCS=  vidcontrol.c decode.c
+
+NOMAN= coming soon
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/vidcontrol/decode.c b/usr.bin/vidcontrol/decode.c
new file mode 100644 (file)
index 0000000..3bea7ae
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ *     $Id$
+ */
+
+#include <stdio.h>
+
+int decode(FILE *fd, char *buffer)
+{
+       int n, pos = 0;
+       char *p;
+       char temp[128];
+
+#define        DEC(c)  (((c) - ' ') & 0x3f)
+
+       do {
+               if (!fgets(temp, sizeof(temp), fd)) 
+                       return(0);
+       } while (strncmp(temp, "begin ", 6));
+       sscanf(temp, "begin %o %s", &n, temp);
+       for (;;) {
+               if (!fgets(p = temp, sizeof(temp), fd))
+                       return(0);
+               if ((n = DEC(*p)) <= 0)
+                       break;
+               for (++p; n > 0; p += 4, n -= 3)
+                       if (n >= 3) {
+                               buffer[pos++] = DEC(p[0])<<2 | DEC(p[1])>>4;
+                               buffer[pos++] = DEC(p[1])<<4 | DEC(p[2])>>2;
+                               buffer[pos++] = DEC(p[2])<<6 | DEC(p[3]);
+                       }
+                       else {
+                               if (n >= 1) {
+                                       buffer[pos++] =
+                                               DEC(p[0])<<2 | DEC(p[1])>>4;
+                               }
+                               if (n >= 2) {
+                                       buffer[pos++] = 
+                                               DEC(p[1])<<4 | DEC(p[2])>>2;
+                               }
+                               if (n >= 3) {
+                                       buffer[pos++] =
+                                               DEC(p[2])<<6 | DEC(p[3]);
+                               }
+                       }
+       }
+       if (!fgets(temp, sizeof(temp), fd) || strcmp(temp, "end\n"))
+               return(0);
+       return(pos);
+}
diff --git a/usr.bin/vidcontrol/path.h b/usr.bin/vidcontrol/path.h
new file mode 100644 (file)
index 0000000..709acbc
--- /dev/null
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH    "/usr/share/syscons/keymaps/"
+#define FONT_PATH      "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH   "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.bin/vidcontrol/vidcontrol.c b/usr.bin/vidcontrol/vidcontrol.c
new file mode 100644 (file)
index 0000000..9a4c270
--- /dev/null
@@ -0,0 +1,448 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ *     $Id$
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include <sys/errno.h>
+#include "path.h"
+
+
+char   legal_colors[16][16] = {
+       "black", "blue", "green", "cyan",
+       "red", "magenta", "brown", "white",
+       "grey", "lightblue", "lightgreen", "lightcyan",
+       "lightred", "lightmagenta", "yellow", "lightwhite"
+       };
+int    hex = 0;
+int    number, verbose = 0;
+char   letter;
+struct         vid_info info;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+       if (*indp < ac)
+               return(av[(*indp)++]);
+       fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+       usage();
+       exit(1);
+       return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char    *buf = NULL;
+static int     bufl = 0;
+int            f;
+
+
+       f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+       if (f > bufl)
+               if (buf)
+                       buf = (char *)realloc(buf, f);
+               else
+                       buf = (char *)malloc(f);
+       if (!buf) {
+               bufl = 0;
+               return(NULL);
+       }
+
+       bufl = f;
+       strcpy(buf, s1);
+       strcat(buf, s2);
+       strcat(buf, s3);
+       return(buf);
+}
+
+
+void
+load_scrnmap(char *filename)
+{
+       FILE *fd;
+       int i;
+       char *name;
+       scrmap_t scrnmap;
+       char *prefix[]  = {"", "", SCRNMAP_PATH, NULL};
+       char *postfix[] = {"", ".scm", ".scm"};
+
+       for (i=0; prefix[i]; i++) {
+               name = mkfullname(prefix[i], filename, postfix[i]);
+               if (fd = fopen(name, "r"))
+                       break;
+       }
+       if (fd == NULL) {
+               perror("font file not found");
+               return;
+       }
+       if (decode(fd, scrnmap) != sizeof(scrnmap)) {
+               fprintf(stderr, "bad scrnmap file\n");
+               close(fd);
+               return;
+       }
+       if (ioctl(0, PIO_SCRNMAP, scrnmap) < 0)
+               perror("can't load screenmap");
+       close(fd);
+}
+
+
+void
+print_scrnmap()
+{
+       unsigned char map[256];
+       int i;
+
+       if (ioctl(0, GIO_SCRNMAP, &map) < 0) {
+               perror("getting scrnmap");
+               return;
+       }
+       for (i=0; i<sizeof(map); i++) {
+               if (i > 0 && i % 16 == 0)
+                       fprintf(stdout, "\n");
+               if (hex)
+                       fprintf(stdout, " %02x", map[i]); 
+               else
+                       fprintf(stdout, " %03d", map[i]);
+       }
+       fprintf(stdout, "\n");
+
+}
+
+
+void 
+load_font(char *type, char *filename)
+{
+       FILE    *fd;
+       int     i, io, size;
+       char    *name, *fontmap;
+       char    *prefix[]  = {"", "", FONT_PATH, NULL};
+       char    *postfix[] = {"", ".fnt", ".fnt"};
+
+       for (i=0; prefix[i]; i++) {
+               name = mkfullname(prefix[i], filename, postfix[i]);
+               if (fd = fopen(name, "r"))
+                       break;
+       }
+       if (fd == NULL) {
+               perror("font file not found");
+               return;
+       }
+       if (!strcmp(type, "8x8")) {
+               size = 8*256;
+               io = PIO_FONT8x8;
+       }
+       else if (!strcmp(type, "8x14")) {
+               size = 14*256;
+               io = PIO_FONT8x14;
+       }
+       else if (!strcmp(type, "8x16")) {
+               size = 16*256;
+               io = PIO_FONT8x16;
+       }
+       else {
+               perror("bad font size specification");
+               close(fd);
+               return;
+       }
+       fontmap = (char*) malloc(size);
+       if (decode(fd, fontmap) != size) {
+               fprintf(stderr, "bad font file\n");
+               close(fd);
+               free(fontmap);
+               return;
+       }
+       if (ioctl(0, io, fontmap) < 0)
+               perror("can't load font");
+       close(fd);
+       free(fontmap);
+}
+
+
+void
+set_screensaver_timeout(char *arg)
+{
+       int nsec;
+
+       if (!strcmp(arg, "off"))
+               nsec = 0;
+       else {
+               nsec = atoi(arg);
+               if ((*arg == '\0') || (nsec < 1)) {
+                       fprintf(stderr, "argument must be a positive number\n");
+                       return;
+               }
+       }
+       if (ioctl(0, CONS_BLANKTIME, &nsec) == -1)
+               perror("setting screensaver period");
+}
+
+
+void
+set_screensaver_type(char *type)
+{
+       ssaver_t saver;
+       int i, e;
+
+       if (!strcmp(type, "help")) {
+               i = 0;
+               printf("available screen saver types:\n");
+               do {
+                       saver.num = i;
+                       e = ioctl(0, CONS_GSAVER, &saver);
+                       i ++;
+                       if (e == 0)
+                               printf("\t%d\t%s\n", saver.num, saver.name);
+               } while (e == 0);
+               if (e == -1 && errno != EIO)
+                       perror("getting screensaver info");
+       } else {
+               i = 0;
+               do {
+                       saver.num = i;
+                       e = ioctl(0, CONS_GSAVER, &saver);
+                       i ++;
+                       if (e == 0 && !strcmp(type, saver.name)) {
+                               if (ioctl(0, CONS_SSAVER, &saver) == -1)
+                                       perror("setting screensaver type");
+                               return;
+                       }
+               } while (e == 0);
+               if (e == -1 && errno != EIO)
+                       perror("getting screensaver info");
+               else
+                       fprintf(stderr, "%s: No such screensaver\n", type);
+       }
+}
+
+void
+set_cursor_values(char *size)
+{
+       int start, end;
+       int n;
+       char *v1;
+
+       start = strtol(size, &v1, 0);
+       if ((start < 0) || (*v1 != '.'))
+               goto badopt;
+       size = ++v1;
+       end = strtol(size, &v1, 0);
+       if ((end < 0) || (*size == '\0') || (*v1 != '\0')) {
+badopt:
+               fprintf(stderr, 
+                       "argument to -c must be start.end\n");
+               return;
+       }
+       if (verbose)
+               fprintf(stderr, "setting cursor to %d.%d\n", start, end);
+       fprintf(stdout, "\e[=%d;%dC", start, end);
+}
+
+
+int
+video_mode(int argc, char **argv, int *index)
+{
+       int mode;
+
+       if (*index < argc) {
+               if (!strcmp(argv[*index], "80x25"))
+                       mode = CONS_80x25TEXT;
+               else if (!strcmp(argv[*index], "80x50"))
+                       mode = CONS_80x50TEXT;
+               else
+                       return;
+               if (ioctl(0, mode, NULL) < 0)
+                       perror("Cannot set videomode");
+               (*index)++;
+       }
+       return;
+}
+               
+
+int
+get_color_number(char *color)
+{
+       int i;
+
+       for (i=0; i<16; i++)
+               if (!strcmp(color, legal_colors[i]))
+                       return i;
+       return -1;
+}
+
+
+int
+set_normal_colors(int argc, char **argv, int *index)
+{
+       int color;
+
+       if (*index < argc && (color = get_color_number(argv[*index])) != -1) {
+               (*index)++;
+               fprintf(stderr, "\e[=%dF", color);
+               if (*index < argc 
+                   && (color = get_color_number(argv[*index])) != -1 
+                   && color < 8) {
+                       (*index)++;
+                       fprintf(stderr, "\e[=%dG", color);
+               }
+       }
+}
+
+
+set_reverse_colors(int argc, char **argv, int *index)
+{
+       int color;
+
+       if ((color = get_color_number(argv[*(index)-1])) != -1) {
+               fprintf(stderr, "\e[=%dH", color);
+               if (*index < argc 
+                   && (color = get_color_number(argv[*index])) != -1 
+                   && color < 8) {
+                       (*index)++;
+                       fprintf(stderr, "\e[=%dI", color);
+               }
+       }
+}
+
+
+set_border_color(char *arg)
+{
+       int color;
+
+       if ((color = get_color_number(arg)) != -1) {
+               fprintf(stderr, "\e[=%dA", color);
+       }
+       else
+               usage(); 
+}
+
+
+test_frame()
+{
+       int i;
+
+       fprintf(stdout, "\e[=0G\n\n");
+       for (i=0; i<8; i++) {
+               fprintf(stdout, "\e[=15F\e[=0G        %2d \e[=%dF%-16s"
+                               "\e[=15F\e[=0G        %2d \e[=%dF%-16s        "
+                               "\e[=15F %2d \e[=%dGBACKGROUND\e[=0G\n",
+                       i, i, legal_colors[i], i+8, i+8, 
+                       legal_colors[i+8], i, i); 
+       }
+       fprintf(stdout, "\e[=%dF\e[=%dG\e[=%dH\e[=%dI\n",
+               info.mv_norm.fore, info.mv_norm.back, 
+               info.mv_rev.fore, info.mv_rev.back);
+}
+
+
+usage()
+{
+       fprintf(stderr,
+"Usage: vidcontrol mode             (available modes: 80x25, 80x50)\n"
+"                  show             (show available colors)\n"
+"                  fgcol bgcol      (set fore- & background colors)\n"
+"                  -r fgcol bgcol   (set reverse fore- & background colors)\n"
+"                  -b color         (set border color)\n"
+"                  -c n.m           (set cursor start line n & end line m)\n"
+#if 0
+"                  -d               (dump scrnmap map to stdout)\n"
+#endif
+"                  -l filename      (load scrnmap map file)\n"
+"                  -f DxL filename  (load font, D dots wide & L lines high)\n"
+"                  -s saver | help  (set screensaver type or help for a list)\n"
+"                  -t N             (set screensaver timeout in seconds)\n"
+       );
+}
+
+
+void
+main(int argc, char **argv)
+{
+       extern char     *optarg;
+       extern int      optind;
+       int             opt;
+
+       
+       info.size = sizeof(info);
+       if (ioctl(0, CONS_GETINFO, &info) < 0) {
+               perror("Must be on a vty");
+               exit(1);
+       }
+       while((opt = getopt(argc, argv, "b:c:df:l:r:s:t:vx")) != -1)
+               switch(opt) {
+                       case 'c':
+                               set_cursor_values(optarg);
+                               break;
+                       case 'b':
+                               set_border_color(optarg);
+                               break;
+                       case 'd':
+                               print_scrnmap();
+                               break;
+                       case 'f':
+                               load_font(optarg,
+                                       nextarg(argc, argv, &optind, 'f'));
+                               break;
+                       case 'l':
+                               load_scrnmap(optarg);
+                               break;
+                       case 'r':
+                               set_reverse_colors(argc, argv, &optind);
+                               break;
+                       case 's':
+                               set_screensaver_type(optarg);
+                               break;
+                       case 't':
+                               set_screensaver_timeout(optarg);
+                               break;
+                       case 'v':
+                               verbose = 1;
+                               break;
+                       case 'x':
+                               hex = 1;
+                               break;
+                       default:
+                               usage();
+                               exit(1);
+               }
+       if (video_mode(argc, argv, &optind)) ;
+       if (set_normal_colors(argc, argv, &optind)) ;
+       if (optind < argc && !strcmp(argv[optind], "show")) {
+               test_frame();
+               optind++;
+       }
+       if ((optind != argc) || (argc == 1)) {
+               usage();
+               exit(1);
+       }
+       exit(0);
+}
+
diff --git a/usr.sbin/vidcontrol/Makefile b/usr.sbin/vidcontrol/Makefile
new file mode 100644 (file)
index 0000000..09d8eb1
--- /dev/null
@@ -0,0 +1,6 @@
+PROG=  vidcontrol
+SRCS=  vidcontrol.c decode.c
+
+NOMAN= coming soon
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/vidcontrol/decode.c b/usr.sbin/vidcontrol/decode.c
new file mode 100644 (file)
index 0000000..3bea7ae
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ *     $Id$
+ */
+
+#include <stdio.h>
+
+int decode(FILE *fd, char *buffer)
+{
+       int n, pos = 0;
+       char *p;
+       char temp[128];
+
+#define        DEC(c)  (((c) - ' ') & 0x3f)
+
+       do {
+               if (!fgets(temp, sizeof(temp), fd)) 
+                       return(0);
+       } while (strncmp(temp, "begin ", 6));
+       sscanf(temp, "begin %o %s", &n, temp);
+       for (;;) {
+               if (!fgets(p = temp, sizeof(temp), fd))
+                       return(0);
+               if ((n = DEC(*p)) <= 0)
+                       break;
+               for (++p; n > 0; p += 4, n -= 3)
+                       if (n >= 3) {
+                               buffer[pos++] = DEC(p[0])<<2 | DEC(p[1])>>4;
+                               buffer[pos++] = DEC(p[1])<<4 | DEC(p[2])>>2;
+                               buffer[pos++] = DEC(p[2])<<6 | DEC(p[3]);
+                       }
+                       else {
+                               if (n >= 1) {
+                                       buffer[pos++] =
+                                               DEC(p[0])<<2 | DEC(p[1])>>4;
+                               }
+                               if (n >= 2) {
+                                       buffer[pos++] = 
+                                               DEC(p[1])<<4 | DEC(p[2])>>2;
+                               }
+                               if (n >= 3) {
+                                       buffer[pos++] =
+                                               DEC(p[2])<<6 | DEC(p[3]);
+                               }
+                       }
+       }
+       if (!fgets(temp, sizeof(temp), fd) || strcmp(temp, "end\n"))
+               return(0);
+       return(pos);
+}
diff --git a/usr.sbin/vidcontrol/path.h b/usr.sbin/vidcontrol/path.h
new file mode 100644 (file)
index 0000000..709acbc
--- /dev/null
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH    "/usr/share/syscons/keymaps/"
+#define FONT_PATH      "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH   "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.sbin/vidcontrol/vidcontrol.c b/usr.sbin/vidcontrol/vidcontrol.c
new file mode 100644 (file)
index 0000000..9a4c270
--- /dev/null
@@ -0,0 +1,448 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ *
+ *     $Id$
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include <sys/errno.h>
+#include "path.h"
+
+
+char   legal_colors[16][16] = {
+       "black", "blue", "green", "cyan",
+       "red", "magenta", "brown", "white",
+       "grey", "lightblue", "lightgreen", "lightcyan",
+       "lightred", "lightmagenta", "yellow", "lightwhite"
+       };
+int    hex = 0;
+int    number, verbose = 0;
+char   letter;
+struct         vid_info info;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+       if (*indp < ac)
+               return(av[(*indp)++]);
+       fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+       usage();
+       exit(1);
+       return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char    *buf = NULL;
+static int     bufl = 0;
+int            f;
+
+
+       f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+       if (f > bufl)
+               if (buf)
+                       buf = (char *)realloc(buf, f);
+               else
+                       buf = (char *)malloc(f);
+       if (!buf) {
+               bufl = 0;
+               return(NULL);
+       }
+
+       bufl = f;
+       strcpy(buf, s1);
+       strcat(buf, s2);
+       strcat(buf, s3);
+       return(buf);
+}
+
+
+void
+load_scrnmap(char *filename)
+{
+       FILE *fd;
+       int i;
+       char *name;
+       scrmap_t scrnmap;
+       char *prefix[]  = {"", "", SCRNMAP_PATH, NULL};
+       char *postfix[] = {"", ".scm", ".scm"};
+
+       for (i=0; prefix[i]; i++) {
+               name = mkfullname(prefix[i], filename, postfix[i]);
+               if (fd = fopen(name, "r"))
+                       break;
+       }
+       if (fd == NULL) {
+               perror("font file not found");
+               return;
+       }
+       if (decode(fd, scrnmap) != sizeof(scrnmap)) {
+               fprintf(stderr, "bad scrnmap file\n");
+               close(fd);
+               return;
+       }
+       if (ioctl(0, PIO_SCRNMAP, scrnmap) < 0)
+               perror("can't load screenmap");
+       close(fd);
+}
+
+
+void
+print_scrnmap()
+{
+       unsigned char map[256];
+       int i;
+
+       if (ioctl(0, GIO_SCRNMAP, &map) < 0) {
+               perror("getting scrnmap");
+               return;
+       }
+       for (i=0; i<sizeof(map); i++) {
+               if (i > 0 && i % 16 == 0)
+                       fprintf(stdout, "\n");
+               if (hex)
+                       fprintf(stdout, " %02x", map[i]); 
+               else
+                       fprintf(stdout, " %03d", map[i]);
+       }
+       fprintf(stdout, "\n");
+
+}
+
+
+void 
+load_font(char *type, char *filename)
+{
+       FILE    *fd;
+       int     i, io, size;
+       char    *name, *fontmap;
+       char    *prefix[]  = {"", "", FONT_PATH, NULL};
+       char    *postfix[] = {"", ".fnt", ".fnt"};
+
+       for (i=0; prefix[i]; i++) {
+               name = mkfullname(prefix[i], filename, postfix[i]);
+               if (fd = fopen(name, "r"))
+                       break;
+       }
+       if (fd == NULL) {
+               perror("font file not found");
+               return;
+       }
+       if (!strcmp(type, "8x8")) {
+               size = 8*256;
+               io = PIO_FONT8x8;
+       }
+       else if (!strcmp(type, "8x14")) {
+               size = 14*256;
+               io = PIO_FONT8x14;
+       }
+       else if (!strcmp(type, "8x16")) {
+               size = 16*256;
+               io = PIO_FONT8x16;
+       }
+       else {
+               perror("bad font size specification");
+               close(fd);
+               return;
+       }
+       fontmap = (char*) malloc(size);
+       if (decode(fd, fontmap) != size) {
+               fprintf(stderr, "bad font file\n");
+               close(fd);
+               free(fontmap);
+               return;
+       }
+       if (ioctl(0, io, fontmap) < 0)
+               perror("can't load font");
+       close(fd);
+       free(fontmap);
+}
+
+
+void
+set_screensaver_timeout(char *arg)
+{
+       int nsec;
+
+       if (!strcmp(arg, "off"))
+               nsec = 0;
+       else {
+               nsec = atoi(arg);
+               if ((*arg == '\0') || (nsec < 1)) {
+                       fprintf(stderr, "argument must be a positive number\n");
+                       return;
+               }
+       }
+       if (ioctl(0, CONS_BLANKTIME, &nsec) == -1)
+               perror("setting screensaver period");
+}
+
+
+void
+set_screensaver_type(char *type)
+{
+       ssaver_t saver;
+       int i, e;
+
+       if (!strcmp(type, "help")) {
+               i = 0;
+               printf("available screen saver types:\n");
+               do {
+                       saver.num = i;
+                       e = ioctl(0, CONS_GSAVER, &saver);
+                       i ++;
+                       if (e == 0)
+                               printf("\t%d\t%s\n", saver.num, saver.name);
+               } while (e == 0);
+               if (e == -1 && errno != EIO)
+                       perror("getting screensaver info");
+       } else {
+               i = 0;
+               do {
+                       saver.num = i;
+                       e = ioctl(0, CONS_GSAVER, &saver);
+                       i ++;
+                       if (e == 0 && !strcmp(type, saver.name)) {
+                               if (ioctl(0, CONS_SSAVER, &saver) == -1)
+                                       perror("setting screensaver type");
+                               return;
+                       }
+               } while (e == 0);
+               if (e == -1 && errno != EIO)
+                       perror("getting screensaver info");
+               else
+                       fprintf(stderr, "%s: No such screensaver\n", type);
+       }
+}
+
+void
+set_cursor_values(char *size)
+{
+       int start, end;
+       int n;
+       char *v1;
+
+       start = strtol(size, &v1, 0);
+       if ((start < 0) || (*v1 != '.'))
+               goto badopt;
+       size = ++v1;
+       end = strtol(size, &v1, 0);
+       if ((end < 0) || (*size == '\0') || (*v1 != '\0')) {
+badopt:
+               fprintf(stderr, 
+                       "argument to -c must be start.end\n");
+               return;
+       }
+       if (verbose)
+               fprintf(stderr, "setting cursor to %d.%d\n", start, end);
+       fprintf(stdout, "\e[=%d;%dC", start, end);
+}
+
+
+int
+video_mode(int argc, char **argv, int *index)
+{
+       int mode;
+
+       if (*index < argc) {
+               if (!strcmp(argv[*index], "80x25"))
+                       mode = CONS_80x25TEXT;
+               else if (!strcmp(argv[*index], "80x50"))
+                       mode = CONS_80x50TEXT;
+               else
+                       return;
+               if (ioctl(0, mode, NULL) < 0)
+                       perror("Cannot set videomode");
+               (*index)++;
+       }
+       return;
+}
+               
+
+int
+get_color_number(char *color)
+{
+       int i;
+
+       for (i=0; i<16; i++)
+               if (!strcmp(color, legal_colors[i]))
+                       return i;
+       return -1;
+}
+
+
+int
+set_normal_colors(int argc, char **argv, int *index)
+{
+       int color;
+
+       if (*index < argc && (color = get_color_number(argv[*index])) != -1) {
+               (*index)++;
+               fprintf(stderr, "\e[=%dF", color);
+               if (*index < argc 
+                   && (color = get_color_number(argv[*index])) != -1 
+                   && color < 8) {
+                       (*index)++;
+                       fprintf(stderr, "\e[=%dG", color);
+               }
+       }
+}
+
+
+set_reverse_colors(int argc, char **argv, int *index)
+{
+       int color;
+
+       if ((color = get_color_number(argv[*(index)-1])) != -1) {
+               fprintf(stderr, "\e[=%dH", color);
+               if (*index < argc 
+                   && (color = get_color_number(argv[*index])) != -1 
+                   && color < 8) {
+                       (*index)++;
+                       fprintf(stderr, "\e[=%dI", color);
+               }
+       }
+}
+
+
+set_border_color(char *arg)
+{
+       int color;
+
+       if ((color = get_color_number(arg)) != -1) {
+               fprintf(stderr, "\e[=%dA", color);
+       }
+       else
+               usage(); 
+}
+
+
+test_frame()
+{
+       int i;
+
+       fprintf(stdout, "\e[=0G\n\n");
+       for (i=0; i<8; i++) {
+               fprintf(stdout, "\e[=15F\e[=0G        %2d \e[=%dF%-16s"
+                               "\e[=15F\e[=0G        %2d \e[=%dF%-16s        "
+                               "\e[=15F %2d \e[=%dGBACKGROUND\e[=0G\n",
+                       i, i, legal_colors[i], i+8, i+8, 
+                       legal_colors[i+8], i, i); 
+       }
+       fprintf(stdout, "\e[=%dF\e[=%dG\e[=%dH\e[=%dI\n",
+               info.mv_norm.fore, info.mv_norm.back, 
+               info.mv_rev.fore, info.mv_rev.back);
+}
+
+
+usage()
+{
+       fprintf(stderr,
+"Usage: vidcontrol mode             (available modes: 80x25, 80x50)\n"
+"                  show             (show available colors)\n"
+"                  fgcol bgcol      (set fore- & background colors)\n"
+"                  -r fgcol bgcol   (set reverse fore- & background colors)\n"
+"                  -b color         (set border color)\n"
+"                  -c n.m           (set cursor start line n & end line m)\n"
+#if 0
+"                  -d               (dump scrnmap map to stdout)\n"
+#endif
+"                  -l filename      (load scrnmap map file)\n"
+"                  -f DxL filename  (load font, D dots wide & L lines high)\n"
+"                  -s saver | help  (set screensaver type or help for a list)\n"
+"                  -t N             (set screensaver timeout in seconds)\n"
+       );
+}
+
+
+void
+main(int argc, char **argv)
+{
+       extern char     *optarg;
+       extern int      optind;
+       int             opt;
+
+       
+       info.size = sizeof(info);
+       if (ioctl(0, CONS_GETINFO, &info) < 0) {
+               perror("Must be on a vty");
+               exit(1);
+       }
+       while((opt = getopt(argc, argv, "b:c:df:l:r:s:t:vx")) != -1)
+               switch(opt) {
+                       case 'c':
+                               set_cursor_values(optarg);
+                               break;
+                       case 'b':
+                               set_border_color(optarg);
+                               break;
+                       case 'd':
+                               print_scrnmap();
+                               break;
+                       case 'f':
+                               load_font(optarg,
+                                       nextarg(argc, argv, &optind, 'f'));
+                               break;
+                       case 'l':
+                               load_scrnmap(optarg);
+                               break;
+                       case 'r':
+                               set_reverse_colors(argc, argv, &optind);
+                               break;
+                       case 's':
+                               set_screensaver_type(optarg);
+                               break;
+                       case 't':
+                               set_screensaver_timeout(optarg);
+                               break;
+                       case 'v':
+                               verbose = 1;
+                               break;
+                       case 'x':
+                               hex = 1;
+                               break;
+                       default:
+                               usage();
+                               exit(1);
+               }
+       if (video_mode(argc, argv, &optind)) ;
+       if (set_normal_colors(argc, argv, &optind)) ;
+       if (optind < argc && !strcmp(argv[optind], "show")) {
+               test_frame();
+               optind++;
+       }
+       if ((optind != argc) || (argc == 1)) {
+               usage();
+               exit(1);
+       }
+       exit(0);
+}
+