[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ttyvdev-0.7 update



new: loadable fonts, and a 3-finger-salute to run getty on a free tty...

 have fun
	Juergen :)

Index: ttyvdev/Makefile
@@ -12,11 +12,18 @@
 # MiNT 1.11 version
 M111 = -DWRITEB111
 
+# default font search path for ttyvfont
+DEFFONTPATH = -DDEFFONTPATH=\"/usr/share/lib/ttyvfonts:.\"
+
+# ctrl-alt-num-( execl args
+TGETTY = -DTGETTYUTMP '-DTGETTY="/bin/runtt", "runtt", "-t", tty, "/bin/nice", "-20", "/etc/getty", "vty"'
+#TGETTY = -DTGETTYUTMP '-DTGETTY="/bin/runtt", "runtt", "-t", tty, "/bin/nice", "-20", "/etc/mgetty", "-rb", "-p", prompt, tty'
+
 # files...
 SRC = Makefile README execgem.c runtt.c select0.c 1.12-filesys.h-diffs \
-	 filesys.h vcon.h vtdev.h daemon.c paint.c screen.c vtdev.c
+	 filesys.h vcon.h vtdev.h daemon.c paint.c screen.c vtdev.c ttyvfont.c
 # default executables
-DEFAULTX = execgem execmtos runtt select0.TOS vconsd
+DEFAULTX = execgem execmtos runtt select0.TOS ttyvfont vconsd
 # other executables (see README)
 MOREX = vcons1d vconx vcon
 
@@ -29,8 +36,8 @@
 clean:
 	rm -f *.o *.sym $(DEFAULTX) $(MOREX)
 
-ttyvdev.tar.gz:
-	tar cfvz ttyvdev.tar.gz $(SRC)
+ttyvdev.tar.gz: $(SRC) ttyvfonts
+	tar cfvz ttyvdev.tar.gz $(SRC) ttyvfonts
 
 tar: ttyvdev.tar.gz
 
@@ -46,6 +53,9 @@
 select0.TOS: select0.c
 	$(CC) $(CFLAGS) $< -o select0.TOS
 
+ttyvfont: ttyvfont.c
+	$(CC) $(CFLAGS) $(DEFFONTPATH) $< -o ttyvfont $(LIBS)
+
 vconsd: daemon.o vtdevxd.o paintx.o screen.o
 	$(CC) -G $(LFLAGS) daemon.o vtdevxd.o paintx.o screen.o -ovconsd
 	toglclr -super $@
@@ -65,6 +75,9 @@
 vcon.sym: daemon.o vtdev.o
 	$(CC) -B/usr/lib/sym- $(LFLAGS) daemon.o vtdev.o -ovcon.sym
 
+daemon.o: daemon.c
+	$(CC) $(CFLAGS) $(TGETTY) -c $< -o daemon.o
+
 paint.o: paint.c
 	$(CC) $(CFLAGS) -funroll-loops -c $< -o paint.o
 
Index: ttyvdev/README
@@ -1,5 +1,5 @@
 From nox  Sun Jan 15 19:53:14 1995
-Subject: virtual console (v0.6)
+Subject: virtual console(s) (v0.7)
 From: Juergen Lock <nox@jelal.hb.north.de>
 
 here is something you've all been waiting for... virtual terminals
@@ -8,7 +8,8 @@
  use up to 10 shells/whatever without magnifying glasses or 19" screens
  run GEM on the console, top on ttyv1 and gdb' a GEM program from ttyv2...
  send MiNTs debug output to another terminal than the debugged program
- run cu at 19200 bps (or 38400 on modem2) and actually use the speed...
+ run cu at 19200 bps (or 38400 on modem2) and actually use the speed,
+goodbye crawling GEM terminal emulations...
  when some stupid program hangs and MiNT is still alive just switch to
 another terminal and send the thing a signal. (ever heared of vp/ix?
 oops, wrong CPU...)
@@ -20,6 +21,8 @@
 fasttext device (including hardware scrolling for all terminals except
 console even on vanilla ST), so i guess output is faster than any GEM
 window writing could ever get.
+ and of course show people what gcc -O2 can do, the days of `if you
+want performance do everyhing in assembler' are over i would say...
 
  how to use:
 
@@ -61,8 +64,8 @@
 
 before `make' make sure filesys.h points to either a recent kernels
 file.h (this is a bit of a hack and may no longer work with future MiNTs)
-or (if you don't have a newer one by then) patch MiNT 1.12 doc/appendix.d,
-see 1.12-filesys.h-diffs.
+or (if you don't have a newer one by then) use a patched MiNT 1.12
+doc/appendix.d, see 1.12-filesys.h-diffs.
 
 then with init simply put something like this into your rc.local:
 
@@ -151,7 +154,28 @@
 the terminals `keyboard queue' is full, to empty it hit alt-undo.  (if
 its empty alt-undo gets passed thru so programs can still use it.)
 
+ new features in 0.7:
+
+1. at special request of one user :) there is another way to `enable'
+free ttyvs now:  define a command (execl args) in Makfile to `runtt'
+something like a getty (TGETTY), then when you hit ctrl-alt-num(
+that is exec'd on the first free ttyv so that you can login there.
+note as init doesn't know about ttys used like this (for init they
+are still disabled) it still won't respawn anything when you log out
+there, this also means your utmp entry would still show you logged in
+(the place where programs like `finger' and `last' look), if you want
+the daemon update that as well define TGETTYUTMP also.  see Makefile...
+
+2. loadable fonts.  there are some new ioctls to load char bitmaps
+and keyboard translations for chars >= 0x80, and there is a small
+example program that uses these to load raw bitmap files or monospaced
+GDOS (bitmap) fonts of the `right' size.  run ttyvfont --h for a
+help screen... (and improve it if you like, send me the diffs.)
+
+3. and now for something completely different...
+
  coping with GEM
+(this should probably go in some general MiNT FAQ, at least parts of it)
 
 GEM still is not a nice citizen for a multitasking environment...  once
 started you can't shut it down, it does strange things to its tty that
@@ -163,10 +187,10 @@
 multitasking completely for seconds.
 
  to get around the last problem install nohog.acc from the minixfs
-distribution (also used for minixfs update daemon; btw everyone runnig
-MiNT should try out minixfs, its just so much better than this slow
-and stupid GEMDOS thing...)  to stop the SIGTT* signals (symptom is a
-`hanging' GEM) use execgem, it turns off job control (process group)
+distribution (also necessary for minixfs update daemon; btw everyone
+runnig MiNT should try out minixfs, its just so much better than this
+slow and stupid GEMDOS thing...)  to stop the SIGTT* signals (symptom
+is a `hanging' GEM) use execgem, it turns off job control (process group)
 checks on the console before it starts GEM, see execgem.c.  the only
 thing you can do about the wasted cycles is run GEM at lowest priority,
 i use this alias (ksh):
@@ -188,13 +212,13 @@
  and thats still not it.  said multitos beta no longer polls everything
 but instead it has a race condition that now makes short evnt_timer
 calls often `hang' for > 3 min, especially with MiNT >1.08...
-if this hits you the easiest cure is to get MH-MiNT 1.12, it has a
-kludge in select() that hacks around this GEM bug itself. (what your
-still waiting for a new multitos release from atari!? forget it!)
-and the built-in GEM in at least TOS 1.(0)4 sometimes apparently
-`forgets' to initialize pointers in (M)allocated memory i.e. often
-crashes while loading .accs unless, hack #x+1, the kernel is told to
-zero everything returned by Malloc for it.  (F_ALLOCZERO bit used by
+if this hits you the easiest cure is to get the latest MH-MiNT 1.12,
+it has a kludge in select() that hacks around this GEM bug itself.
+(what your still waiting for a new multitos release from atari!?
+forget it!)  and the built-in GEM in at least TOS 1.(0)4 sometimes
+apparently `forgets' to initialize pointers in (M)allocated memory i.e.
+often crashes while loading .accs unless, hack #x+1, the kernel is told
+to zero everything returned by Malloc for it.  (F_ALLOCZERO bit used by
 execgem, also added in MH-MiNT 1.12.)
 
  and finally another one nothing to do with virtual consoles:  things
Index: ttyvdev/daemon.c
@@ -1,5 +1,5 @@
 /*
- * virtual terminals for MiNT, v0.6 (beta)
+ * virtual terminals for MiNT, v0.7 (beta)
  *
  * ttyv1..9 are fast hardware-scrolling text-terminals, ttyv0 is the
  * original console and may still be used for graphic display and GEM.
@@ -34,6 +34,8 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <wait.h>
+#include <utmp.h>
 #include "vcon.h"
 #include "vtdev.h"
 
@@ -237,8 +239,8 @@
 	long bytes = (char *)bufp - (char *)cbuf;
 
 	if (bytes) {
-		/* pipe full? */
-		if (Foutstat (fd) < bytes)
+		/* closed/pipe full? */
+		if (!ttys[vcurrent].tt.use_cnt || Foutstat (fd) < bytes)
 			/* bing... */
 			Fputchar (0, 07l, 0);
 		else {
@@ -251,6 +253,88 @@
 	}
 }
 
+#ifdef TGETTY
+/* spawn getty (once) on ttyv(t), to use compile with something like
+ *	'-DTGETTY="/bin/runtt", "runtt", "-t", tty, "/etc/getty", "vty"'
+ * (see Makefile)
+ * the child should return ASAP, with return code 0 if successful
+ */
+int dogetty(t)
+int t;
+{
+	char tty[] = "/dev/ttyv0";
+	char prompt[] = "ttyv0 login: ";
+	int status;
+
+	prompt[sizeof "ttyv"-1] = tty[sizeof "/dev/ttyv"-1] = t+'0';
+	switch (vfork()) {		/* ok since runtt will fork itself */
+	case -1:
+		status = -1;		/* fork failed */
+		break;
+	case 0:
+		/* child */
+		for (status = 0; status < 3; ++status)
+		/* we don't want it mess with our /dev/console... */
+			Fclose(status);
+		execl (TGETTY, (char *) 0);  /* has to open the tty itself */
+		/* exec failed */
+		_exit(1);
+		/*NOTREACHED*/
+	default:
+		/* parent */
+		if (wait(&status) < 0)
+			status = -1;
+	}
+	return status;
+}
+
+#ifdef TGETTYUTMP
+#define UTMP_FILE	"/etc/utmp"
+#define WTMP_FILE	"/var/adm/wtmp"
+
+static enum gettystate {TNONE, TFORKING, TOPEN} tgstate[MAX_VT];
+
+int zaputmp(t)
+int t;
+{
+	char tty[] = "ttyv0";
+	static struct utmp wentry;
+	struct utmp rentry;
+	int i, r, fd;
+	int open();
+
+	tty[sizeof "ttyv"-1] = t+'0';
+	strncpy(wentry.ut_line, tty, 8);
+	wentry.ut_time = time(0L);
+
+	bzero(&rentry, sizeof(struct utmp));
+
+	if ((fd = open(UTMP_FILE, O_RDWR)) == -1)
+		return 1;
+	for (i = 0; ((r = read(fd, &rentry, sizeof(rentry))) != -1); ++i) {
+		if (!r)
+			return 1;
+		if (!strncmp(tty, rentry.ut_line, 8))
+			break;
+	}
+	if (lseek(fd, (i * sizeof(rentry)), 0) == -1 ||
+	    write(fd, &wentry, sizeof(wentry)) != sizeof(wentry)) {
+		close(fd);
+		return 1;
+	}
+	close(fd);
+	if ((fd = open(WTMP_FILE, (O_RDWR | O_APPEND))) == -1)
+		return 1;
+	if (write(fd, &wentry, sizeof(wentry)) != sizeof(wentry)) {
+		close(fd);
+		return 1;
+	}
+	close(fd);
+	return 0;
+}
+#endif
+#endif
+
 /*
  * main:  initialization stuff, and a daemon that handles input from
  * the physical console
@@ -317,8 +401,13 @@
 		Fcntl (pfd[i], 0, F_SETFD);
 	}
 	for (i = 0; i < MAX_VT; ++i) {
-		char name[] = "u:\\dev\\ttyv0";
+		char name[] = "u:\\dev\\ttyv0", *p = ttys[i].readxlat;
+		int j;
 
+		/* init input translation == none */
+		for (j = 0x80; j < 0x100; ++j) {
+			*p++ = j;
+		}
 		name[sizeof "u:\\dev\\ttyv"-1] = i+'0';
 		if (vcon_device.writeb)
 #ifndef follow_links	/* filesys.h */
@@ -420,6 +509,25 @@
 				}
 				/* select timed out, flash cursor & try again */
 				Fcntl(cfd, (char *) 0, VCTLFLASH);
+#ifdef TGETTYUTMP
+				for (i = 1; i < MAX_VT; ++i) {
+					switch (tgstate[i]) {
+					case TFORKING:
+						if (ttys[i].tt.use_cnt)
+/* getty is up... */
+							tgstate[i] = TOPEN;
+						break;
+					case TOPEN:
+						if (!ttys[i].tt.use_cnt) {
+/* we put the getty there, we have to clean up after it */
+							zaputmp(i);
+							tgstate[i] = TNONE;
+						}
+						break;
+					default:
+					}
+				}
+#endif
 			}
 			continue;
 		}
@@ -461,6 +569,33 @@
 					continue;
 				}
 			break;
+#ifdef TGETTY
+		} else	if ((cshift & ~0x10) == 0xc)  switch (scan=(char) (l>>16)) {
+			int i;
+			case 0x63:	/* ctrl-alt-num( */
+				csend (vcurrent, fd, cbuf, bufp);
+				bufp = cbuf;
+				for (i = 1; i < MAX_VT; ++i) {
+					if (!ttys[i].tt.use_cnt) {
+/* find a free tty and put up a getty...
+ * if just now something else decides to use this ttyv you'll lose.
+ */
+#ifdef TGETTYUTMP
+						if (tgstate[i]) continue;
+						tgstate[i] = TFORKING;
+#endif
+						if (!dogetty(i) &&
+						    !Fcntl(cfd, (char *) (long) i, VCTLSETV)) {
+							fshort = 1;
+							goto ok;
+						}
+						break;
+					}
+				}
+				Fputchar (0, 07l, 0);
+ok:
+				continue;
+#endif
 		} else	if ((ttys[vcurrent].tt.state & TS_COOKED) ||
 			    (cshift & 0xc) == 0xc) {
 			char ch = (char) l;
@@ -514,6 +649,8 @@
 				continue;
 			}
 		}
+		if ((unsigned char)l > 0x7f)
+			l = (l & ~0xff) | ttys[vcurrent].readxlat[l & 0x7f];
 		*bufp++ = l;
 	}
 }
Index: ttyvdev/paint.c
@@ -12,6 +12,8 @@
 #include "vtdev.h"
 #endif
 
+static char *lastfontdata;
+
 /* flash(v): invert the character currently under the cursor */
 
 #ifdef FORCE1PLANE
@@ -272,6 +274,10 @@
 	}
 	if (v->flags & FBOLD)
 		c += 0x100;
+	if (v->fontdata != lastfontdata) {
+		setup_chartab(v);
+		lastfontdata = v->fontdata;
+	}
 	data = chartab[c];
 	dounderline = (v->flags & FUNDERLINE) ? 0xff : 0;
 
@@ -405,6 +411,10 @@
 	}
 	if (v->flags & FBOLD)
 		c += 0x100;
+	if (v->fontdata != lastfontdata) {
+		setup_chartab(v);
+		lastfontdata = v->fontdata;
+	}
 	data = chartab[c];
 	dounderline = (v->flags & FUNDERLINE) ? 0xff : 0;
 
Index: ttyvdev/runtt.c
@@ -132,7 +132,7 @@
 	dup2(tty, 1);
 	dup2(tty, 2);
 
-	close(tty);
+	if (tty > 2) close(tty);
 
 	shell = getenv("SHELL");
 	if (!shell)
Index: ttyvdev/ttyvfont.c
@@ -0,0 +1,378 @@
+/* a quick hack to load (old format) monospaced GDOS fonts, this can be
+ * improved...
+ *
+ * if the font filename contains the string `iso' assume ISO 8859 latin-1
+ * charset -> set input translation for non-ASCII keys (> 0x7f)
+ * (actually it looks at char 0xa0 now... if space assumes latin-1.)
+ *
+ * sets the tty on stdin i.e. can be redirected like stty, run without
+ * args to restore system font, run with --h for a small usage message
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <support.h>
+#include <linea.h>
+#include "vcon.h"
+
+int ioctl ();
+static unsigned char fontdata[256*16], rawbuf[256*16];
+
+unsigned char iso2a[97] = {
+#if 0
+/* ISO Latin 1 to IBM code page 437 (classic IBM PC character set) */
+
+   ' ', 173,155, 156, 'o', 157, '|',  21, '"', 'c',166,174,170,'-', 'R', '-',
+   248, 241,253, '3',  39, 230,  20, 249, ',', '1',167,175,172,171, '?', 168,
+   'A', 'A','A', 'A', 142, 143, 146, 128, 'E', 144,'E','E','I','I', 'I', 'I',
+   'D', 165,'O', 'O', 'O', 'O', 153, 'x', 237, 'U','U','U',154,'Y', 'T', 225,
+   133, 160,131, 'a', 132, 134, 145, 135, 138, 130,136,137,141,161, 140, 139,
+   'd', 164,149, 162, 147, 'o', 148, 246, 237, 151,163,150,129,'y', 't', 152
+#else
+/* ISO Latin 1 to ST... */
+
+   ' ', 173,155, 156, 'o', 157, '|',0xdd,0xb9,0xbd,166,174,170,'-',0xbe,0xff,
+   248, 241,253,0xfe,0xba, 230,0xbc, 249, ',', '1',167,175,172,171, '?', 168,
+   0xb6,'A','A',0xb7, 142, 143, 146, 128, 'E', 144,'E','E','I','I', 'I', 'I',
+   'D', 165,'O', 'O', 'O',0xb8, 153, 'x',0xb2, 'U','U','U',154,'Y', 'T',0x9e,
+   133, 160,131,0xb0, 132, 134, 145, 135, 138, 130,136,137,141,161, 140, 139,
+   'd', 164,149, 162, 147,0xb1, 148, 246,0xb3, 151,163,150,129,'y', 't', 152
+#endif
+};
+
+/* 0x80..0x9f (unused or same as 0..0x20 in ISO 8859):
+ *   0    1   2    3    4    5    6    7    8    9   a   b   c   d    e    f
+
+8*   ?    ?   ?    ?    ?    ?    ?    ?    ?    ?   ?   ?   ?   ?    ?    ?
+9*   ?    ?   ?    ?    ?    ?    ?    ?    ?    ?   ?   ?   ?   ?    ?    ?
+ */
+
+/* 0xa0..0xff:
+a*        ¡   ¢    £    ¤    ¥    ¦    §    ¨    ©   ª   «   ¬   ­    ®    ¯
+b*   °    ±   ²    ³    ´    µ    ¶    ·    ¸    ¹   º   »   ¼   ½    ¾    ¿
+c*   À    Á   Â    Ã    Ä    Å    Æ    Ç    È    É   Ê   Ë   Ì   Í    Î    Ï
+d*   Ð    Ñ   Ò    Ó    Ô    Õ    Ö    ×    Ø    Ù   Ú   Û   Ü   Ý    Þ    ß
+e*   à    á   â    ã    ä    å    æ    ç    è    é   ê   ë   ì   í    î    ï
+f*   ð    ñ   ò    ó    ô    õ    ö    ÷    ø    ù   ú   û   ü   ý    þ    ÿ
+ */
+
+void usage(myname)
+char *myname;
+{
+	if (myname) {
+		char *s;
+		if ((s = strrchr (myname, '/')))
+			myname = s+1;
+		if ((s = strrchr (myname, '\\')))
+			myname = s+1;
+	}
+	if (!myname || !*myname)
+		myname = "ttyvfont";
+	fprintf(stderr, "usage: %s -rizgnv -f firstchar -c chars -o off -w rawfile font\n\n"
+			"\t-r: file format raw bitmaps (otherwise GDOS unless file named .raw)\n"
+			"\t-i: force latin-1 input translation (depends on char 0xa0 otherwise)\n"
+			"\t-z: zap, empty char bitmaps (kept from previous font otherwise)\n"
+			"\t-g: always read GDOS header\n"
+			"\t-n: don't set font, read/convert only\n"
+			"\t-v: show font search path, GDOS header contents, and some more talk\n\n"
+			"\t-f 0-255 -c 1-256:\tfirst char, number of chars to get\n"
+			"\t-o off:\t\t\tinput file offset\n"
+			"\t-w rawfile:\t\toutput font file name (raw bitmap format)\n\n"
+			"examples:\n"
+			"\tttyvfont attp10cg\n"	
+			"  (load Atari Typewriter 10 point lo-res)\n"
+			"\tttyvfont; ttyvfont -f 0xb0 -c 48 -o 0xb00 ibm-16\n"
+			"  (a system font with IBM line graphic chars at 0xb0-0xdf, assuming raw format)\n"
+			"\tttyvfont -w aibm-16\n"
+			"  (save as aibm-16.raw)\n"
+			"\tttyvfont; ttyvfont -w system; ttyvfont iso-atari-16\n"
+			"  (save system font, load latin-1...)\n"
+			"\tttyvfont -r -f 0x81 -c 31 -o 16 -w funnyiso ./system.raw%s\n"
+			"  (latin1 with ataris face chars, etc. at 0x81-0x9f...)%s\n", myname, (!ioctl (0, TCGETFONTBITS, fontdata) && !fontdata[0x79f] && fontdata[0x69f] == 0xe0) ? "\t??" : "", (!ioctl (0, TCGETFONTBITS, fontdata) && !fontdata[0x79f] && fontdata[0x69f] == 0xe0) ? "\t\t\t??" : "");
+	exit (1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	static const char *const ext[] = { "fnt", "raw", (char *)0 };
+	static __FONT fhdr;
+
+	extern int optind,opterr;
+	extern char *optarg;
+
+	FILE *fp;
+	char *f, *path = getenv("TTYVFONTPATH");
+	const char *ttname = ttyname (0);
+	int isop = 0, rawp = 0, zero = 0, usehdr = 0, verbose = 0, doset = 1;
+	short tfontsiz[2] = {8, 16};
+	long off = -1, firstc = -1, nchars = -1;
+	char *outf = 0;
+	int c;
+
+	ioctl (0, TCGETFONTSIZE, &tfontsiz);
+
+	opterr = 0;
+	while( (c=getopt(argc,argv,"rizgnvo:f:c:w:"))!=EOF )
+	{
+		switch(c)
+		{
+			case 'r':
+			rawp = 1;
+			break;		
+
+			case 'i':
+			isop = 1;
+			break;		
+
+			case 'z':
+			zero = 1;
+			break;		
+
+			case 'g':
+			usehdr = 1;
+			break;		
+
+			case 'n':
+			doset = 0;
+			break;		
+
+			case 'v':
+			verbose = 1;
+			break;		
+
+			case 'o':
+			off = strtoul (optarg, (char **)0, 0);
+			break;		
+
+			case 'f':
+			firstc = strtoul (optarg, (char **)0, 0);
+			break;		
+
+			case 'c':
+			nchars = strtoul (optarg, (char **)0, 0);
+			break;		
+
+			case 'w':
+			outf = optarg;
+			break;		
+
+			case '?':
+			usage(argv[0]);
+			break;		
+		}
+	}
+
+	if ((argc-optind > 1) || opterr) usage(argv[0]);
+
+	if (!path)
+		path = DEFFONTPATH;
+	if (verbose) {
+		printf ("font path %s\n", path);
+		printf ("%s: chars %d bits wide, %d bits high\n",
+			ttname, tfontsiz[0], tfontsiz[1]);
+	}
+
+	if (argc-optind < 1) {
+		if (!outf) {			/* back to sysfont */
+			if (!doset)
+				return 0;
+			if (verbose)
+				printf ("%s: restoring system font\n", ttname);
+			if (!ioctl (0, TCSETFONTBITS, (char *)0))
+				ioctl (0, TCSETFONTXLAT, (char *)0);
+			return 0;
+		}
+		if (ioctl (0, TCGETFONTBITS, fontdata)) {
+			perror ("ioctl TCGETFONTSIZE");
+			return 1;
+		}
+	} else {
+		char *s;
+
+		f = findfile (argv[optind], path, ext);
+		for (s = f ? f : argv[optind]; *s; ++s) {
+			if (*s == '\\') *s = '/';
+		}
+
+		if (!f || !(fp = fopen(f, "rb"))) {
+			perror (f ? f : ((errno = ENOENT), argv[optind]));
+			return 1;
+		}
+#if 0
+		if (strstr (argv[optind], "iso"))
+			isop = 1;
+#endif
+		if ((s = strrchr (f, '.')) && !stricmp (s, ".raw")) {
+			rawp = 1;
+		}
+
+		if (!rawp && off < 0 && firstc < 0 && nchars < 0)
+			usehdr = 1;
+		if (usehdr) {
+			if (verbose)
+				printf ("\n%s: reading GDOS font header...\n", f);
+
+			fread(&fhdr, sizeof fhdr, 1, fp);
+			if (!(fhdr.flags & 4)) {	/* intel inside... */
+				union w {short x; unsigned char b[2];} *p;
+				union l {long x; unsigned char b[4];} *q
+					= (union l *) &fhdr.dat_table;
+
+				for (p = (union w *) &fhdr.font_id;
+				     p < (union w *) &fhdr.name; ++p) {
+					p->x = (p->b[1] << 8) | p->b[0];
+				}
+				for (p = (union w *) &fhdr.first_ade;
+				     p < (union w *) &fhdr.h_table; ++p) {
+					p->x = (p->b[1] << 8) | p->b[0];
+				}
+				q->x = (((((q->b[3] << 8) | q->b[2]) << 8) |
+					q->b[1]) << 8) | q->b[0];
+				for (p = (union w *) &fhdr.form_width;
+				     p < (union w *) &fhdr.next_font; ++p) {
+					p->x = (p->b[1] << 8) | p->b[0];
+				}
+			}
+			firstc = fhdr.first_ade;
+			nchars = fhdr.last_ade + 1 - firstc;
+			off = (long) fhdr.dat_table;
+
+			if (verbose) {
+				printf (" 0x%04x %d point\t%s\n",
+					fhdr.font_id, fhdr.size, fhdr.name);
+				printf (" first char %d last char %d top %d ascent %d half %d descent %d bottom %d\n",
+					fhdr.first_ade, fhdr.last_ade, fhdr.top, fhdr.ascent, fhdr.half, fhdr.descent, fhdr.bottom);
+				printf (" max char width %d max cell width %d left offset %d right offset %d\n",
+					fhdr.max_char_width, fhdr.max_cell_width, fhdr.left_offset, fhdr.right_offset);
+				printf (" thicken %d underline size %d lighten 0x%04x skew 0x%04x flags 0x%04x\n",
+					fhdr.thicken, fhdr.ul_size, fhdr.lighten, fhdr.skew, fhdr.flags);
+			}
+			if (!(fhdr.flags & 8)) {
+				fprintf(stderr, "%s: not monospaced, needs conversion\n", f);
+				return 1;
+			}
+			if (fhdr.form_width != nchars * ((tfontsiz[0]+7)>>3)) {
+				fprintf(stderr, "%s: bad form_width %d\n", f, fhdr.form_width);
+				return 1;
+			}
+		}
+
+		if (firstc < 0) firstc = 0;
+		if (nchars < 0 || firstc + nchars > 256) nchars = 256;
+		if (off < 0) off = rawp ? 0 : 90 + nchars * 2;
+		fseek(fp, off, SEEK_SET);         /* skip header */
+		if (nchars < 256 && !zero)
+			ioctl (0, TCGETFONTBITS, fontdata);
+		if (rawp) {
+			char *p = rawbuf, *q;
+			int i, j, fw = tfontsiz[0] * 256 / 8;
+
+			i = fread(rawbuf, 16, nchars, fp);
+			if (verbose)
+				printf ("\n%s: read %d raw char bitmaps\n", f, i);
+			for (i = 0; i < nchars; ++i) {
+				for (j = 0, q = fontdata+i+firstc; j < tfontsiz[1]; ++j) {
+					*q = *p++;
+					q += fw;
+				}
+			}
+		} else if (nchars < 256) {
+			char *p = rawbuf, *q;
+			int i, fw = tfontsiz[0] * 256 / 8, rfw = tfontsiz[0] * nchars / 8;
+
+			fread(rawbuf, 16, nchars, fp);
+			for (i = 0, q = fontdata+firstc; i < tfontsiz[1]; ++i) {
+				memcpy (q, p, rfw);
+				p += rfw;
+				q += fw;
+			}
+		} else {
+			fread(fontdata, 16, 256, fp);
+		}
+		fclose(fp);
+	}
+	if (outf) {
+		char *p = rawbuf, *q;
+		int i, j, fw = tfontsiz[0] * 256 / 8;
+
+		for (q = outf; *q; ++q) {
+			if (*q == '\\') *q = '/';
+		}
+		if (!(q = strrchr (outf, '.')) || strchr (q, '/')) {
+			
+			if (!(q = malloc (strlen (outf) + sizeof ".raw"))) {
+				perror (outf);
+				return 1;
+			}
+			strcpy (q, outf);
+			strcat (q, ".raw");
+			outf = q;
+		}
+		for (i = 0; i < 256; ++i) {
+			for (j = 0, q = fontdata+i; j < tfontsiz[1]; ++j) {
+				*p++ = *q;
+				q += fw;
+			}
+		}
+		if (!(fp = fopen(outf, "wb")) ||
+		    (i = fwrite(rawbuf, 16, 256, fp)) < 0 || fclose(fp)) {
+			perror (outf);
+			return 1;
+		}
+		if (verbose)
+			printf ("\n%s: wrote %d raw char bitmaps\n", outf, i);
+	}
+	if (!doset)  return 0;
+	if (ioctl (0, TCSETFONTBITS, fontdata)) {
+		perror ("ioctl TCSETFONTBITS");
+		return 1;
+	} else {
+		unsigned char buf[0x80];
+		unsigned char *xlat = 0, *xlatr = 0, *xlatroff = 0;
+		long xlatrsiz = 0;
+
+		if (!isop) {
+			char *q;
+			int i, fw = tfontsiz[0] * 256 / 8;
+
+			isop = 1;
+			for (i = 0, q = fontdata+0xa0; i < tfontsiz[1]; ++i) {
+				if (*q) {
+		/* 0xa0 not a space, not iso */
+					isop = 0;
+					break;
+				}
+				q += fw;
+			}
+		}
+
+		if (isop) {
+			xlatr = iso2a;
+			xlatroff = iso2a - ' ' - 0x80;
+			xlatrsiz = sizeof iso2a;
+		}
+		if (xlatr) {
+			unsigned char ch, *p, *q = buf;
+			int i;
+
+			for (i = 0x80; i < 0x100; ++i) {
+				ch = 0;
+				if ((p = memchr (xlatr, i, xlatrsiz)))
+					ch = p - xlatroff;
+				*q++ = ch;
+			}
+			xlat = buf;
+		}
+
+		if (ioctl (0, TCSETFONTXLAT, xlat)) {
+			perror ("ioctl TCSETFONTXLAT");
+			return 1;
+		}
+	}
+	return 0;
+}
+
Index: ttyvdev/vcon.h
@@ -82,3 +82,15 @@
 #define VCTLSETV	0x7fd0	/* show terminal (arg) */
 #define VCTLFLASH	0x7fd1	/* flash current term's cursor */
 #define VCTLWSEL	0x7fd2	/* wake select()ing readers on term (arg) */
+
+/* ioctls for font setting utilities...  */
+#ifndef TCGETFONTSIZE
+#define TCGETFONTSIZE	(('c'<< 8) | 128)	/* (one) chars bitmap size */
+#define TCSETFONTSIZE	(('c'<< 8) | 129)	/* (not yet) */
+#define TCGETFONTCHRS	(('c'<< 8) | 130)	/* char range in font */
+#define TCSETFONTCHRS	(('c'<< 8) | 131)	/* (not yet) */
+#define TCGETFONTBITS	(('c'<< 8) | 132)	/* bitmaps (old GDOS format) */
+#define TCSETFONTBITS	(('c'<< 8) | 133)
+#define TCGETFONTXLAT	(('c'<< 8) | 134)	/* ST -> font char mapping */
+#define TCSETFONTXLAT	(('c'<< 8) | 135)	/*  for chars 0x80..0xff */
+#endif
Index: ttyvdev/vtdev.c
@@ -33,8 +33,9 @@
 #define CONDEV	(2)
 
 #define VT_SCREEN(vt) (v0x+(vt)-1)
-#define TT_SCREEN(tty) (((struct ttyv *) \
-			((char *)(tty)-offsetof(struct ttyv, tt)))->v)
+#define TT_TTYV(tty) ((struct ttyv *) \
+			((char *)(tty)-offsetof(struct ttyv, tt)))
+#define TT_SCREEN(tty) (TT_TTYV(tty)->v)
 #define SCNSIZE(v) ( (((long)v->maxy + hardscroll + 2)) * v->linelen )
 
 SCREEN *v00, v0x[N_VT-1];
@@ -42,6 +43,9 @@
 short hardscroll;
 long scrnsize;
 char *rowoff;
+char *sysfontdata;	/* saved ttyv[1..9] v->fontdata if using loaded font */
+long sfontbytes;	/* size of ... */
+char *sysfontdata0;	/* saved console v->fontdata if using loaded font */
 #ifndef FORCE1PLANE
 void (*vpaint) P_((SCREEN *, int, char *));
 #endif
@@ -202,66 +206,13 @@
 	clear(v);
 }
 
-INLINE static int
-init()
-{
+void
+setup_chartab(v)
 	SCREEN *v;
+{
 	int i, j;
 	char *data, *foo;
 	static char chardata[256*16*2];
-	register int linelen;
-
-	foo = lineA0();
-	v = getvtmode (ttys[0].v = v00 = (SCREEN *)(foo - 346));
-#ifdef FORCE1PLANE
-	if ((v->cheight != 16 && v->cheight != 8) ||
-		((v != v00 && v->v.t.usedplanes) ?
-			v->v.t.usedplanes : v->planes) != 1) {
-		ALERT("Colour and cheight != 8 or 16 not supported, recompile without -DFORCE1PLANE");
-		return -1;
-	}
-#endif
-	
-	/* Ehem... The screen might be bigger than 32767 bytes.
-	   Let's do some casting... 
-	   Erling
-	*/
-	linelen = v->linelen;
-	scrnsize = (v->maxy+1)*(long)linelen;
-	rowoff = (char *)kmalloc((long)((v->maxy+1) * sizeof(long) * (N_VT-1)));
-	if (rowoff == 0) {
-		ALERT("Insufficient memory for screen offset table!");
-		return -ENOMEM;
-	} else {
-		long off, *lptr = (long *)rowoff;
-		SCREEN *vp = v0x;
-
-		for (i=0, off=0; i<=v->maxy; i++) {
-			*lptr++ = off;
-			off += linelen;
-		}
-		for (i=1; i<N_VT-1; i++) {
-			ttys[i].v = vp++;
-			vp->v.t.rowlist = (char *)lptr;
-			lptr += v->maxy+1;
-		}
-		ttys[N_VT-1].v = vp;
-	}
-	if (hardscroll == -1) {
-	/* request for auto-setting */
-		hardscroll = v->maxy+1;
-	}
-	if (!hardbase && (v == v00 || !(hardbase = v->v.t.vbase))) {
-		hardbase = (char *)(((long)kcore(SCNSIZE(v)+256L)+255L)
-					   & 0xffffff00L);
-		if (hardbase == 0) {
-			ALERT("Insufficient memory for second screen buffer!");
-			kfree (rowoff);
-			return -ENOMEM;
-		}
-	}
-	init_screen(v0x, v, hardbase, rowoff, V_FREE);
-	hardline = 0;
 
 #ifndef FORCE1PLANE
 	if (v->cheight == 8 && V_USEDPLANES(v) == 2) {
@@ -315,6 +266,79 @@
 	else
 		vpaint = paint;
 #endif
+}
+
+INLINE static int
+init()
+{
+	SCREEN *v;
+	int i;
+	char *foo;
+	register int linelen;
+	long sfontbytes0;
+
+	foo = lineA0();
+	v = getvtmode (ttys[0].v = v00 = (SCREEN *)(foo - 346));
+#ifdef FORCE1PLANE
+	if ((v->cheight != 16 && v->cheight != 8) ||
+		((v != v00 && v->v.t.usedplanes) ?
+			v->v.t.usedplanes : v->planes) != 1) {
+		ALERT("Colour and cheight != 8 or 16 not supported, recompile without -DFORCE1PLANE");
+		return -1;
+	}
+#endif
+	
+	/* Ehem... The screen might be bigger than 32767 bytes.
+	   Let's do some casting... 
+	   Erling
+	*/
+	linelen = v->linelen;
+	scrnsize = (v->maxy+1)*(long)linelen;
+	sfontbytes = V_NFONTBYTES(v);
+	sfontbytes0 = V_NFONTBYTES(v00) * 2;
+	sysfontdata0 = v00->fontdata;
+	rowoff = (char *)kmalloc((long)((v->maxy+1) * sizeof(long) * (N_VT-1)) + sfontbytes0);
+	if (rowoff == 0) {
+		ALERT("Insufficient memory for screen offset table!");
+		return -ENOMEM;
+	} else {
+		long off, *lptr = (long *)rowoff;
+		SCREEN *vp = v0x;
+
+		for (i=0, off=0; i<=v->maxy; i++) {
+			*lptr++ = off;
+			off += linelen;
+		}
+		for (i=1; i<N_VT-1; i++) {
+			ttys[i].v = vp++;
+			vp->v.t.rowlist = (char *)lptr;
+			lptr += v->maxy+1;
+		}
+		ttys[N_VT-1].v = vp;
+		ttys[0].loadfontdata = (char *)lptr;
+		ttys[0].loadfontbytes = sfontbytes0;
+	}
+	if (hardscroll == -1) {
+	/* request for auto-setting */
+		hardscroll = v->maxy+1;
+	}
+	if (!hardbase && (v == v00 || !(hardbase = v->v.t.vbase))) {
+		long scnsize = SCNSIZE(v);
+
+		hardbase = (char *)(((long)kcore(scnsize+256L+sfontbytes)+255L)
+					   & 0xffffff00L);
+		if (hardbase == 0) {
+			ALERT("Insufficient memory for second screen buffer!");
+			kfree (rowoff);
+			return -ENOMEM;
+		}
+		ttys[1].loadfontdata = hardbase + scnsize;
+		ttys[1].loadfontbytes = sfontbytes;
+	}
+	init_screen(v0x, v, hardbase, rowoff, V_FREE);
+	hardline = 0;
+	setup_chartab(v);
+	sysfontdata = v->fontdata;
 
 #ifndef VT00XCON
 	vpaint0x = vpaint;
@@ -399,13 +423,22 @@
 			exchangeb (vline, V_LINE(v, i), v->linelen);
 			vline += v->linelen;
 		}
-		/* and pointers... */
+		/* pointers... */
 		foo = oldv->v.t.vbase;
 		oldv->v.t.vbase = v->v.t.vbase;
 		v->v.t.vbase = foo;
 		foo = oldv->v.t.rowlist;
 		oldv->v.t.rowlist = v->v.t.rowlist;
 		v->v.t.rowlist = foo;
+		/* and fonts... */
+		exchangeb (ttys[v0xcurrent].loadfontdata,
+				ttys[vt].loadfontdata, sfontbytes);
+		foo = ttys[v0xcurrent].loadfontdata;
+		ttys[v0xcurrent].loadfontdata = ttys[vt].loadfontdata;
+		ttys[vt].loadfontdata = foo;
+		if (v->fontdata != sysfontdata)
+			v->fontdata = ttys[vt].loadfontdata;
+		setup_chartab(v);
 
 		/* free screen memory if told so */
 		if (oldv->v.t.on == V_FREE) {
@@ -415,6 +448,8 @@
 		} else {
 			oldv->v.t.on = 0;
 			oldv->cursaddr = PLACE(oldv, oldv->cx, oldv->cy);
+			if (oldv->fontdata != sysfontdata)
+				oldv->fontdata = ttys[v0xcurrent].loadfontdata;
 		}
 		v->v.t.on = V_USED;
 		v->cursaddr = PLACE(v, v->cx, v->cy);
@@ -1170,12 +1205,16 @@
 	if (!((struct tty *)f->devinfo)->use_cnt) {
 		/* init and alloc screen memory if necessary */
 		if (vt) {
-			SCREEN *v = TT_SCREEN((struct tty *)f->devinfo);
+			struct ttyv *tt = TT_TTYV((struct tty *)f->devinfo);
+			SCREEN *v = tt->v;
 
 			if (!v->v.t.vbase) {
-				char *vbase = (char *)kmalloc(scrnsize);
+				char *vbase = (char *)kmalloc(scrnsize+sfontbytes);
+
 				if (!vbase)
 					return -ENOMEM;
+				tt->loadfontdata = vbase + scrnsize;
+				tt->loadfontbytes = sfontbytes;
 				init_screen (v, (void *)0, vbase, v->v.t.rowlist, 0);
 			} else if (v->v.t.on == V_FREE)
 				v->v.t.on = V_USED;
@@ -1206,17 +1245,29 @@
 		FCLOSE (qfd[vt]);
 
 		/* last close on ttyv0 means uninstall... */
-		if (!vt)
+		if (!vt) {
+			ttys[0].v->fontdata = sysfontdata0;
 			deinit();
 		/* otherwise it means free screen memory */
-		else {
-			SCREEN *v = TT_SCREEN((struct tty *)f->devinfo);
-
+		} else {
+			struct ttyv *tt = TT_TTYV((struct tty *)f->devinfo);
+			SCREEN *v = tt->v;
+			char *p = tt->readxlat;
+			int j;
+
+			/* reset font... */
+			v->fontdata = sysfontdata;
+			/* ..and read translation */
+			for (j = 0x80; j < 0x100; ++j) {
+				*p++ = j;
+			}
 			if (v->v.t.on)
 				v->v.t.on = V_FREE;
 			else {
 				kfree (v->v.t.vbase);
 				v->v.t.vbase = 0;
+				tt->loadfontbytes = 0;
+				tt->loadfontdata = 0;
 			}
 		}
 	}
@@ -1487,6 +1538,66 @@
 #endif
 			}
 		}
+/* font setting stuff...  */
+	} else if (mode >= TCGETFONTSIZE && mode <= TCSETFONTXLAT) {
+		struct ttyv *tt = TT_TTYV((struct tty *)f->devinfo);
+		SCREEN *v = tt->v;
+		long bytes;
+
+		if ((f->flags & O_RWMODE) == O_WRONLY)
+			return -EPERM;		/* want read permission */
+		switch(mode) {
+		case TCGETFONTSIZE:		/* (one) chars bitmap size */
+			*(short *)buf = v->form_width >> (8-3);
+			((short *)buf)[1] = v->cheight;
+			break;
+		/* case TCSETFONTSIZE: */	/* (not yet) */
+		case TCGETFONTCHRS:		/* char range in font */
+			*(short *)buf = 0;
+			((short *)buf)[1] = 0xff;
+			break;
+		/* case TCSETFONTCHRS: */	/* (not yet) */
+		case TCGETFONTBITS:		/* bitmaps (old GDOS format) */
+			if (!buf)
+				return -EINVAL;
+			/*FALLTHRU*/
+		case TCSETFONTBITS:
+			bytes = V_NFONTBYTES(v);
+
+			if (mode == TCGETFONTBITS) {
+				memmove (buf, v->fontdata, bytes);
+			} else if (!buf) {
+				/* default == sysfont */
+				v->fontdata = vt ? sysfontdata : sysfontdata0;
+			} else if (tt->loadfontbytes < bytes) {
+				return -ENOMEM;
+			} else {
+				memmove (tt->loadfontdata, buf, bytes);
+				v->fontdata = tt->loadfontdata;
+				setup_chartab(v);
+			}
+			break;
+		case TCGETFONTXLAT:		/* ST -> font char mapping */
+			if (!buf) {		/*  for chars 0x80..0xff */
+				return -EINVAL;
+			} else {
+				memmove (buf, tt->readxlat, 0x80);
+			}
+			break;
+		case TCSETFONTXLAT:
+			if (!buf) {
+				/* default == none */
+				char *p = tt->readxlat;
+				int j;
+
+				for (j = 0x80; j < 0x100; ++j) {
+					*p++ = j;
+				}
+			} else {
+				memmove (tt->readxlat, buf, 0x80);
+			}
+			break;
+		}
 	} else
 		return -EINVAL;
 
Index: ttyvdev/vtdev.h
@@ -173,9 +173,14 @@
 #define V_SCRNSIZE(x) ((x) == v00 ? ((x)->maxy+1)*(long)(x)->linelen : scrnsize)
 #endif
 
+#define V_NFONTBYTES(x) ((long) (x)->form_width * (x)->cheight)
+
 extern struct ttyv {
 	SCREEN	*v;
 	struct tty tt;
+	char	*loadfontdata;	/* (allocated) storage for loaded fonts */
+	long	loadfontbytes;	/* size of ... */
+	unsigned char readxlat[0x80];	/* keys > 0x7f translation */
 } ttys[];
 extern DEVDRV vcon_device;
 extern struct dev_descr devinfo[];
@@ -201,6 +206,7 @@
 #define showscreen(vt, v, vbase, save) Setscreen (-1l, vbase, -1l)
 #endif
 
+void setup_chartab P_((SCREEN *));
 #ifndef FORCE1PLANE
 void flash P_((SCREEN *));
 void paint P_((SCREEN *, int, char *)),
-- 
J"urgen Lock / nox@jelal.hb.north.de / UUCP: ..!uunet!unido!uniol!jelal!nox
								...ohne Gewehr
PGP public key fingerprint =  8A 18 58 54 03 7B FC 12  1F 8B 63 C7 19 27 CF DA