home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
telecomm
/
t100.zoo
/
t100.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-22
|
20KB
|
957 lines
/*
* t100 - simple term emulator. vt52 and ANSI (much of vt100)
*
* by Bill Rosenkranz (rosenkra@convex.com).
*
* based on st52 program by Nick Castellano (entropy@ai.mit.edu) but
* greatly changed so it bears little resemblence. i added the vt100
* support, including font changes. also lifted rs232init from Howard
* Chu's tip and rs232cd (carrier detect) from Steve Yelvington.
*
* this was written with gcc 1.40 (and MiNT 10 libraries).
*
* currently it is hardwired to vt100 (vt100_mode==1 always). i am
* not sure why you'd want vt52 anyway. you can toggle this by adding
* code to set vt100_mode to 0 (the host better know you changed!).
* my reference for the ANSI/vt100 escape codes was an old Falco
* terminal manual. it may not be accurate/modern/complete but does
* seem accurate for all the escapes i find in standard vt100 termcap.
*
* it should be easy to hack in an escape to execute shell commands.
* i just have not done it. that way you could start up a kermit
* or xmodem or whatever. i have not tested this under MiNT or mgr.
*
* restrictions: to (re)set the fonts, i do a line A init ($A000)
* to get the fonthdr pointer and from there get the address of the
* font data. i poke in a new address to my own data, being careful
* to set it back on exit (i hope :-). this means if your big-screen
* monitor can't support this, you are SOL. it also won't run on a
* TT since line A went bye-bye. note that you can always recompile
* with -UUSE_FONTS and it should work fine on any system. you just
* won't have bold and underline.
*
* also, if you define SET_RS232_INIT at compile time, this relies
* on Rsconf returning a value. my understanding is that this does
* not work on TOS 1.0. the safe bet would be to check the TOS
* version. i have not tested this part of the code. currently,
* the rs232 paramaters are hardwired. i would set it from the
* control panel.
*
* major problem: i can't figure out how to tell the host we are an
* 80x25 term without changing /etc/termcap (difficult to do without
* the root passwd). setting TERMCAP did not help, at least with
* GNU emacs and less. maybe there is a termcap for 80x25 but i never
* checked. standard vt100 and vt100n has li set to 24. emacs manual
* sez stuff about this (maybe set TERM to vt100-25?). i have no idea
* about VMS and other non-unix systems with user library routines whose
* names contain "$". why bother? :-)
*/
#ifndef lint
static char *rcsid_t100_c = "$Id: t100.c,v 1.0 1991/09/12 20:32:56 rosenkra Exp $";
#endif
/*
* $Log: t100.c,v $
* Revision 1.0 1991/09/12 20:32:56 rosenkra
* Initial revision
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <osbind.h>
#include <mintbind.h>
#include <signal.h>
#include "t100.h"
#define MINTID "MiNT" /* MiNT's cookie string */
#define MAXWAIT 1000 /* see note in main loop */
#define PROMPT_STRING "\n\rt100> " /* MUST contain a newline */
#define NEWLINE 10 /* common chars */
#define ESC 27
#define RETURN 13
/*
* globals
*/
char iobuf[8192]; /* new iorec for rs232 (first half */
/* is in, second half out) */
_IOREC *recsav; /* ptr to iorec struct */
_IOREC oldirec; /* old input iorec */
_IOREC oldorec; /* old output iorec */
int par = 0; /* none, odd, even - 0, 1, 2 */
int baud = 4; /* see baud table 4=2400 */
int echo = 0; /* 0=off, 1=on */
int flow = 0; /* none, xon/xoff, rts/cts */
int ucr, rsr, tsr, scr; /* for resetting rs232 regs */
char *bauds[] = {"19200","9600","4800","3600","2400","2000",
"1800","1200","600","300","200","150","134",
"110","75","50"}; /* unused */
int vt100_mode = 1; /* 0 means revert to vt52 */
long mintcookie = 0L; /* if MiNT this will be non-NULL */
/*
* vt100 modes, etc...
*/
int bold = 0; /* OFF 1m */
int underline = 0; /* OFF 4m */
int blinking = 0; /* OFF 5m */
int reverse = 0; /* OFF 7m */
int wrap = 1; /* ON (set) */
int video = 0; /* 0=normal (reset) */
int repeat = 1; /* ON (set) */
int curskey = 0; /* OFF (reset) */
int keypad = 0; /* 0=normal (reset) */
int colwidth = 0; /* 0=80 (reset), 1=132 */
int smooth = 0; /* OFF (reset) */
int origmode = 0; /* 0=normal (reset) */
short kbinit, kbrpt; /* saved key repeat stuff */
int outtran[256]; /* char xlation table */
/*------------------------------*/
/* main */
/*------------------------------*/
int main (int argc, char *argv[], char *envp[])
{
short kbret;
int x;
register long key; /* raw Bconin value */
register int gnsrgh = MAXWAIT;
register int c;
#ifdef JUNK
/* this was in st52 code. i don't use it...(it was #ifdef'd already) */
char *terminal;
char *etmp;
char *newenv;
etmp = (char *) envp;
terminal = getenv ("TERM");
#ifdef DEBUG
Cconws ("Terminal type: ");
puts (terminal);
#endif
if (strcmp (terminal, "mgr") == 0)
{
#ifdef DEBUG
puts ("yep");
printf ("value: %d\n",
Pexec (200, "e:\\mint\\mgr\\bin\\vt52.prg",
"e:\\mint\\mgr\\bin\\vt52.prg t100", envp));
#else
Pexec (200, "e:\\mint\\mgr\\bin\\vt52.prg",
"e:\\mint\\mgr\\bin\\vt52.prg t100", envp);
#endif
}
#endif /*JUNK*/
/*
* some initializations: key repeat (save old) and wrap ON
*/
kbret = (short) Kbrate (15, 2);/* repeat ESC [ ? 8 h */
kbinit = (kbret >> 8) & 0x00ff;
kbrpt = kbret & 0x00ff;
Bconout (CON, (int) 27); /* wrap ESC [ ? 7 h */
Bconout (CON, (int) 'v');
/*
* set up output char translation array (normally output==input,
* but you can remap if you want here)
*/
for (x = 0; x < 256; x++)
outtran[x] = x;
#ifdef SWAP_DEL_AND_BS
/*
* this swaps DEL and BS
*/
outtran[127] = 8;
outtran[8] = 127;
#endif
/*
* check for MiNT cookie
*/
mintcookie = getcookie (MINTID);
#ifdef DEBUG
printf ("MiNT cookie %lx detected\n", mintcookie);
#endif
#ifdef USE_FONTS
/*
* set fonts
*/
#ifdef DEBUG
Cconws ("\n\rset fonts...\n\r\n\r");
#endif
if (vt100_mode)
fnt_roman ();
#if 0
/* test fonts */
Cconws ("Roman font (normal)\n\r");
fnt_bold (); Cconws ("BOLD font\n\r");
fnt_uline (); Cconws ("uline font\n\r");
fnt_reverse (); Cconws ("reverse font\n\r");
fnt_roman (); Cconws ("back to Roman\n\r\n\r\n\r");
Cconws ("roman ");
fnt_bold (); Cconws ("bold ");
fnt_uline (); Cconws ("uline ");
fnt_reverse (); Cconws ("reverse ");
fnt_roman (); Cconws ("roman\n\r\n\r");
#endif
#else /*! USE_FONTS*/
vt100_mode = 0;
#endif /*USE_FONTS*/
#if 0
/* test Setcolor */
Setcolor (0,0);
Setcolor (1,0x777);
Cconws ("any key\n\r");
Crawcin ();
Setcolor (0,0x777);
Setcolor (1,0);
#endif
/*
* introductions...
*/
blurb ();
/*
* initialize rs232 (buffers and baud)
*/
Cconws ("\n\rinitialize rs232...\n\r");
rs232init ();
Cconws ("baud set to 2400.\n\r");
/*
* prompt
*/
Cconws (PROMPT_STRING);
/*
* main loop...
*/
for (;;)
{
/*
* if there are characters at the AUX port, and we are
* not going to interrupt, print them. without the
* gnsrgh value, we can't interrupt and send a char.
* MAXWAIT controls how many chars we let in before
* checking the keyboard. 1000 seems reasonable.
*/
if (Bconstat (AUX) && gnsrgh--)
{
/*
* get char
*/
c = (int) Bconin (AUX);
/*
* check for newline. if we are connected do nothing
* special. otherwise print PROMPT_STRING (which
* must have the newline we ignore in it)
*/
if (c == NEWLINE)
{
/*
* if carrier detected...
*/
if (rs232cd ())
{
/*
* ...output the newline...
*/
Bconout (CON, (int) c);
}
else
{
/*
* ...otherwise do our prompt
*/
Cconws (PROMPT_STRING);
}
}
#ifdef EMUL_VT100
else if ((c == ESC) && vt100_mode)
{
/*
* assume if we get ESC that this will be
* an ANSI/vt100 escape seqence and handle
* it. vt100 also reads AUX for the rest
* of the sequence. maybe it should return
* an error code.
*/
vt100 ();
}
else
{
/*
* just echo the char
*/
Bconout (CON, (int) c);
}
#else
else
{
/*
* just echo the char. let the vt52 emulator
* handle the rest...
*/
Bconout (CON, (int) c);
}
#endif
}
else
{
/*
* reset gnsrgh. see note above.
*
* then check for keyboard input...
*/
gnsrgh = MAXWAIT;
if (Bconstat (CON))
{
/*
* get it...
*/
key = Bconin (CON);
#ifdef DEBUG
printf ("-%08lx-\n", key);
#endif
/*
* what was it? check for possible internal
* commands. here we can get fancy and look
* for something to do shell escapes, file
* xfers, etc. so far it is basic.
*
* also look for arrow and keypad keys and
* send the right thing depending on mode.
*/
handle_key (key);
}
else
{
/*
* nothing to do so give up a quantum to
* others if under MiNT...
*/
if (mintcookie)
(void) Syield ();
}
}
}
/*NOTREACHED*/
}
/*------------------------------*/
/* handle_key */
/*------------------------------*/
void handle_key (long key)
{
/*
* handle key from console...
*/
char buf[512];
int len;
switch (key)
{
/* cursor keys... */
case 0x00480000: /* up arrow */
if (curskey)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'A');
}
else
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'[');
Bconout (AUX, (int)'A');
}
break;
case 0x00500000: /* down arrow */
if (curskey)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'B');
}
else
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'[');
Bconout (AUX, (int)'B');
}
break;
case 0x004d0000: /* right arrow */
if (curskey)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'C');
}
else
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'[');
Bconout (AUX, (int)'C');
}
break;
case 0x004b0000: /* left arrow */
if (curskey)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'D');
}
else
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'[');
Bconout (AUX, (int)'D');
}
break;
/* keypad keys... */
case 0x00700030: /* 0 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'p');
}
else
{
Bconout (AUX, (int)'0');
}
break;
case 0x006d0031: /* 1 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'q');
}
else
{
Bconout (AUX, (int)'1');
}
break;
case 0x006e0032: /* 2 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'r');
}
else
{
Bconout (AUX, (int)'2');
}
break;
case 0x006f0033: /* 3 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'s');
}
else
{
Bconout (AUX, (int)'3');
}
break;
case 0x006a0034: /* 4 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'t');
}
else
{
Bconout (AUX, (int)'4');
}
break;
case 0x006b0035: /* 5 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'u');
}
else
{
Bconout (AUX, (int)'5');
}
break;
case 0x006c0036: /* 6 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'v');
}
else
{
Bconout (AUX, (int)'6');
}
break;
case 0x00670037: /* 7 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'w');
}
else
{
Bconout (AUX, (int)'7');
}
break;
case 0x00680038: /* 8 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'x');
}
else
{
Bconout (AUX, (int)'8');
}
break;
case 0x00690039: /* 9 */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'y');
}
else
{
Bconout (AUX, (int)'9');
}
break;
case 0x004a002d: /* - */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'m');
}
else
{
Bconout (AUX, (int)'-');
}
break;
case 0x0072000d: /* enter */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'M');
}
else
{
Bconout (AUX, (int)RETURN);
}
break;
case 0x0071002e: /* . */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'n');
}
else
{
Bconout (AUX, (int)'.');
}
break;
/*!!! not sure of this one */
case 0x004e002b: /* + */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'T');
}
else
{
Bconout (AUX, (int)'+');
}
break;
case 0x00630028: /* ( */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'P');
}
else
{
Bconout (AUX, (int)'(');
}
break;
case 0x00640029: /* ) */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'Q');
}
else
{
Bconout (AUX, (int)')');
}
break;
case 0x0065002f: /* / */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'R');
}
else
{
Bconout (AUX, (int)'/');
}
break;
case 0x0066002a: /* * */
if (keypad)
{
Bconout (AUX, (int)ESC);
Bconout (AUX, (int)'O');
Bconout (AUX, (int)'S');
}
else
{
Bconout (AUX, (int)'*');
}
break;
/* keys we track for control... */
case 0x00620000: /* HELP */
help ();
if (!rs232cd ())
Cconws (PROMPT_STRING);
break;
case 0x002E0000: /* alt-c (config) */
case 0x000000E3:
config ();
if (!rs232cd ())
Cconws (PROMPT_STRING);
break;
case 0x00260000: /* alt-l (long break) */
long_break ();
if (!rs232cd ())
Cconws (PROMPT_STRING);
break;
case 0x001f0000: /* alt-s (shell) */
buf[0] = 127;
Cconws ("\n\r\n\rEnter shell command (eg ls):\n\r");
Cconrs (buf);
Cconws ("\n\r");
len = buf[1];
buf[2+len+1] = '\0';
if (system (&buf[2]))
{
Cconws ("\n\r\n\rCommand failed!\n\r\n\r");
}
if (!rs232cd ())
Cconws (PROMPT_STRING);
break;
case 0x00250000: /* alt-k (kermit) */
buf[0] = 127;
Cconws ("\n\r\n\rEnter kermit command (eg kermit -c):\n\r");
Cconrs (buf);
len = buf[1];
buf[2+len+1] = '\0';
Cconws ("\n\r\n\rAttempting to start Kermit....\n\r\n\r");
if (system (&buf[2]))
{
Cconws ("\n\r\n\rKermit failed!\n\r\n\r");
}
if (!rs232cd ())
Cconws (PROMPT_STRING);
break;
case 0x00100000: /* alt-q (quit) */
case 0x000000F1:
Cconws ("\n\r");
bye (0);
break;
case 0x002C0000: /* alt-z */
case 0x000000FA:
/*
* if mint, put ourselves in the
* background
*/
if (mintcookie)
{
Cconws ("\n\r");
(void) Pkill (Pgetpid (), SIGTSTP);
}
break;
/* anything else... */
default:
/* note the character translation */
Bconout (AUX, outtran[(int) (key & KEYMASK)]);
}
}
/*------------------------------*/
/* blurb */
/*------------------------------*/
void blurb ()
{
/* remain humble and don't plaster yer name all over the screen,
asking for money :-) */
Cconws ("\n\r");
if (vt100_mode)
{
fnt_reverse ();
Cconws (" \n\r");
Cconws (" ");
fnt_bold ();
Cconws (" t100: ");
fnt_uline ();
Cconws ("Terminal Program ");
fnt_reverse ();
Cconws (" \n\r");
Cconws (" \n\r");
fnt_roman ();
}
else
{
Cconws ("==============================\n\r");
Cconws ("=== t100: Terminal Program ===\n\r");
Cconws ("==============================\n\r");
}
Cconws ("\n\r");
Cconws ("use HELP key for help...\n\r");
Cconws ("\n\r");
}
/*------------------------------*/
/* rs232init */
/*------------------------------*/
void rs232init ()
{
/*
* Set up a large I/O buffer for the RS232 port, and set initial
* speed, flow control, and parity.
*
* (lifted from howard chu's tip)
*/
#ifdef SET_RS232_INIT
register long m68901reg;
#endif
/*
* get current buffer ptr (0 is rs232)
*/
recsav = (_IOREC *) Iorec (0);
oldirec = *recsav; /* save input record (struct) */
/* this copies a structure, BTW */
recsav->ibuf = (char *) iobuf;
recsav->ibufsiz = (short) 4096;
recsav->ibufhd = (short) 0;
recsav->ibuftl = (short) 0;
recsav->ibuflow = (short) 100;
recsav->ibufhi = (short) 4000;
recsav++;
oldorec = *recsav; /* save output record (struct) */
recsav->ibuf = (char *) &iobuf[4096];
recsav->ibufsiz = (short) 4096;
recsav->ibufhd = (short) 0;
recsav->ibuftl = (short) 0;
recsav->ibuflow = (short) 100;
recsav->ibufhi = (short) 4000;
#ifdef SET_RS232_INIT
/* this ONLY works with TOS 1.2 or later!!! */
m68901reg = Rsconf (baud, 0, -1, -1, -1, -1);
scr = m68901reg & 0xff;
m68901reg >>= 8;
tsr = m68901reg & 0xff;
m68901reg >>= 8;
rsr = m68901reg & 0xff;
m68901reg >>= 8;
ucr = m68901reg & 0xf8;
Rsconf(-1, -1, ucr, -1, -1, -1); /* turn off parity */
#endif
}
/*------------------------------*/
/* bye */
/*------------------------------*/
void bye (int excode)
{
/*
* reset to old I/O rec stuff, then exit
*/
*recsav = oldorec;
recsav--;
*recsav = oldirec;
#ifdef USE_FONTS
fnt_normal ();
#endif
Cconws ("\n\rExit t100...\n\r\n\r");
/*
* reset kbrate!!!
*/
Kbrate (kbinit, kbrpt);
exit (excode);
/*NOTREACHED*/
}
/*------------------------------*/
/* rs232cd */
/*------------------------------*/
short rs232cd ()
{
/*
* function: rs232cd
* author: Steve Yelvington
* purpose: checks for RS-232 carrier detect signal
* return:
* values: 0 for no Carrier Detect
* 1 for Carried Detect
*/
register long ssp;
register short *mfp;
register short status;
mfp = ((short *) 0xfffffa00L); /* base address of MFP */
ssp = Super (0L); /* enter supervisor mode */
status = *mfp; /* get MFP status */
Super (ssp); /* return to user mode */
return (!(status & 0x0002)); /* check for carrier */
}
/*------------------------------*/
/* dobreak */
/*------------------------------*/
void dobreak ()
{
/*
* sends a break. currently unused...
*/
#define _MSLP 386 /* tune this for delay */
#define WAIT_MS(ms) \
{ \
register short _I,_MS=ms; \
for(;_MS>0;_MS--) \
for(_I=_MSLP;_I>0;_I--) \
; \
}
#ifdef SET_RS232_INIT
tsr |= 0x08;
Rsconf (-1, -1, -1, -1, tsr, -1);
if (mintcookie)
Fselect (300, 0L, 0L, 0L); /* sleep 300 milliseconds :-) */
else
WAIT_MS(300); /* wait 300 ms :-( */
tsr &= 0xf7;
Rsconf (-1, -1, -1, -1, tsr, -1);
#endif
}