[net.micro.amiga] Terminal program with voice

ek@tilt.FUN (Eleftherios Koutsofios) (04/13/86)

I saw a couple  of  postings  this  last  week,  about  having  a
terminal emulator that can speak as well as print incomming text.
I had the same idea some time ago, so  I  modified  the  terminal
program that I use, to include that.

The following is a terminal emulation program for the amiga.

Its features are:
  ANSI protocol (25 lines x 80 columns)
  XMODEM file transfer
  graphics mode,
    where you can draw something on the amiga from a host machine.
  speech mode,
    where you can have the amiga speak as well as print incomming
    text.

Since I only got my ROM Kernel Manuals this week, I had  to  play
with  other  peoples'  programs, to do what I wanted. This is the
reason why the source looks a bit strange. It consists  of  parts
from other programs. So, please, no comments on style :-).

The program is far from finished. There  are  many  more  options
that can be added. Maybe you can help.

This program compiles and links under the Lattice 3.02 C. If  you
have any problems, send me mail.

------
	Lefteris Koutsofios   (princeton!tilt!ek)
------

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	makefile
#	term.c
#	gr.c
#	speech.c
#	termcap
#	say.c
# This archive created: Sun Apr 13 04:22:20 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(7880 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
term - a terminal emulator.

A few comments
--------------

The files term.c gr.c and speech.c  contain  the  sources  for  a
terminal emulator for the amiga.

This  terminal  emulator  has  several  features.  This  a   sort
description:

1)  ANSI  protocol.  This  terminal   uses   the   amiga's   ANSI
capabilities  (see  Developer's manual for details). It gives you
25 lines by 80 columns.  A unix termcap entry can be found in the
file  termcap (in this posting).  It assumes 1200 baud and it has
no problem of keeping up with this rate (it does buffered I/O, in
that  it  doesn't  print  anything,  as  long  as  the host keeps
sending).

2) XMODEM file transfer. You can send a file to a host or get one
from  the host using the XMODEM protocol. It works ok, and I have
seen it recovering from line noise. I have  only  tried  it  with
text files (not with binaries).

3) Graphics. You can get a picture from your host to your  amiga.
You  need of course a program on the host to send the appropriate
sequences. The program understands only 3  commands:  set  color,
draw  line,  and  terminate  :-). There are many more that can be
added (most notably mouse commands). In fact what I use  has  one
more  command:  draw polygon (possibly filled). The reason I have
removed it is  that  the  source  I  used  for  that  belongs  to
Princeton  University.  I guess you can add your own code (I have
left the part of the source that understands the polygon command,
so  all  you need to do is add your own. See function Graphics at
the end of file term.c). The  reason  I  didn't  do  it  yet,  is
because  my  source does some clipping and I don't know how to do
this yet (remember I just got my manuals and they are BIG!  :-)).
The  program  as  it is assumes high resolution - interlaced mode
(640 x 400) pixels.

4) Speech. Well, the speech option is simple: it 'reads out loud'
everything  between  a  control  A  and  the  first non-printable
character. So, to make it read a file, preceed every  line  by  a
control  A.  You  can switch the speech option on and off. What I
really like is to play hack with this!!  It's  fun!  To  do  this
instead  of  the the amiga entry, use the amiga-s entry. Then you
will get to hear things like: you hit the kobolt, or you die!! It
slows  down  the  game  but  its fun, and you can always turn the
speech option off. I have included a file called say.c  that  you
can install on your host and then use it to make your amiga talk.

How to use the program
----------------------

To create the executable do a cc term.c gr.c speech.c -o term, or
use  the  makefile supplied. Under Lattice 3.02 everything should
work ok, (but you will of course get the usual warnings!! :-) ).

To run the program type term (or whatever you want to call it).

The program should start by opening a window,  with  no  borders.
The  borders are there, but by printing the appropriate escapes I
get to use the whole screen for text.  The  prompt  term:  should
appear.  You are in the offline mode. press the help key to get a
listing of all the commands. Type on. You are now in  the  online
mode.  If  everything  is  ok,  you should now be able to talk to
whatever is at the other end of the serial port. To return to the
offline  mode, press the function key 7 (don't ask why 7, I don't
have a logical explanation  :-)).   You  should  get  an  offline
message,  but  note  that this is temporary. You can only execute
one command on the amiga, then  the  program  will  automatically
return  you  to  the  online  mode.  This is useful for executing
commands like sb or rb  that  transfer  files.  To  stay  to  the
offline  mode type off. To exit the program, first get to offline
mode (f7 then type off) and then type end. You should  note  that
you  can  give  any  command from offline. The program 'executes'
them (this of course does not work with cd). There is one bug, in
that  the  program  may crash when you try to go to offline mode,
but this happens very very rarely.

To use  the  XMODEM  commands,  get  to  online  mode,  give  the
appropriate  command  to  your  host,  then press f7 and give the
corresponding command to the amiga.  So, if say that you want  to
send something to the host, get to online, type rb filename, then
press f7 and type sb df1:filename or whatever. The program should
then  start transfering your file. At the same time it will print
a count of blocks  transfered.  You  do  need  of  course  XMODEM
commands on your host. There are a couple of bugs. When receiving
a file, the last line contains garbage. You need to edit the file
and remove it. When sending a file, the file contains some nulls.
If your host runs unix, just enter vi and do a w!.

The graphics option works like this: to draw  a  picture  on  the
amiga,  first  send  an escape G. This gets you in graphics mode.
Everything that comes after this must be a graphics sequence. The
implemented sequences are: T0 which exits the graphics mode, C %d
%d %d %d\n that sets the color (C pennum r g b, where  pennum the
pen  number,  and  r g b the rgb coefficients), and L %d %d %d %d
%d\n to draw a line (L x1 y1 x2 y2 pennum, where  pennum the  pen
number).   The  parser understands also the command P %d %d %d %d
%d %d %d\n that draws a polygon possibly filled  (P num_of_points
pennum  clip xmin ymin xmax ymax, where clip is a flag of whether
to clip or not and xmin .. are the clip boundaries).  After  this
command  you  must  supply  the  points on the polygon, each on a
separate line (%d %d\n. I didn't  include  the  source  for  this
routine, for the reasons I mentioned before.

When the escG is received the program opens a screen (640 x 400),
and  starts  drawing  on  it according to the incomming commands.
When it finishes, the menu strip that wasn't visible  up  to  now
comes  up. To return to the text window, drag this screen down or
send it back. What I chose to do is not to delete the screen when
it  finishes.  Instead  it  stays around until you try to end the
program. This way you can keep your picture for as  long  as  you
want, and maybe print it out using a screen dump program that was
posted some time ago. If you want draw a new picture however, and
since  I forgot to add a clear screen command :-), you must go to
offline mode and type gfxoff which will  delete  the  screen.  If
while  in  graphics mode you want to abort the drawing, press the
menu button on the mouse and then select the quit option from the
menu.  The  menu still works even when not visible. Then get back
to the text screen and do whatever necessary  to  stop  the  host
from  sending  the  graphics  sequences.   Since the program does
handshaking you'll probably need to press control Q first, to get
your  host  to continue. You should make sure that the host sends
the correct sequences, although a character out  of  place  (line
noise) will usually destroy just a small part of the picture. (My
problem is that the graphics packages I use initialize the screen
even  when  I give a command like: foo | amiga, where amiga is my
filter and foo is  a  non-existent  command.  In  this  case  the
program will hung.

The sound option is easy. Just preceed everything you want 'read'
by a control A.

Acknowledgments
---------------

As I mentioned before, this program uses  parts  (and  bugs  :-))
from a few other programs. The basic program comes from the myCLI
program of Mike Schwartz. I modified  that  to  get  a  25  x  80
screen.  I  then  added  the  XMODEM  transfer routines that were
posted by Michael Mounier, as part of his  terminal  program.   I
used  the  sparks  demo by Scott Ballantyne to get an idea of how
the graphics work. Finally I used Rob Peck's program  speech,  to
add  the  speech option.  Thanks for the help! (If only it hadn't
taken Commodore all these months to give me my manuals! :-( ).

SHAR_EOF
if test 7880 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 7880 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'makefile'" '(146 characters)'
if test -f 'makefile'
then
	echo shar: will not over-write existing file "'makefile'"
else
cat << \SHAR_EOF > 'makefile'
term : term.o gr.o speech.o
	cc term.o gr.o speech.o

term.o : term.c
	cc -c term.c

gr.o : gr.c
	cc -c gr.c

speech.o : speech.c
	cc -c speech.c
SHAR_EOF
if test 146 -ne "`wc -c < 'makefile'`"
then
	echo shar: error transmitting "'makefile'" '(should have been 146 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'term.c'" '(21608 characters)'
if test -f 'term.c'
then
	echo shar: will not over-write existing file "'term.c'"
else
cat << \SHAR_EOF > 'term.c'
#include <stdio.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <devices/serial.h>

#define MAX_CHARS 102
#define SECSIZ 0x80
#define TTIME 30
#define BufSize 0x1000
#define ERRORMAX 10
#define RETRYMAX 10
#define SOH 1
#define EOT 4
#define ACK 6
#define CTRLQ (char)17
#define CTRLS (char)19
#define NAK 21

static char bufr[BufSize];
static int fd, timeout = FALSE;
static long bytes_xferred;
static int oktosay = 1;

/*
 * External functions
 */
extern   unsigned char        *stpblk();
extern   unsigned char        *AllocMem();
extern   struct   MsgPort     *CreatePort();
extern   struct   FileHandle  *Open();

/*
 * forward references
 */
int   define_function_key(), end(), help(), offline(), online(), sb(), rb(),
      gfxoff(), speechon(), speechoff();
/*
 * Tables
 */
struct {
   unsigned char  *cmdname;
   int            (*cmdfunc)();
   } command_table[] = {
   (unsigned char *)"define", &define_function_key,
   (unsigned char *)"def", &define_function_key,
   (unsigned char *)"end", &end,
   (unsigned char *)"help", &help,
   (unsigned char *)"online", &online,
   (unsigned char *)"on", &online,
   (unsigned char *)"offline", &offline,
   (unsigned char *)"off", &offline,
   (unsigned char *)"gfxoff", &gfxoff,
   (unsigned char *)"sb", &sb,
   (unsigned char *)"rb", &rb,
   (unsigned char *)"speechon", &speechon,
   (unsigned char *)"speechoff", &speechoff,
   (unsigned char *)"\0", &help,
   };

unsigned char  *help_messages[] = {
   "sb         = send file using Xmodem",
   "rb         = receive file using Xmodem",
   "def        = define a function key",
   "define     = define a function key",
   "end        = exit the program",
   "help       = print this list",
   "online     = enter or re-enter terminal mode",
   "offline    = terminate communication",
   "gfxoff     = terminate graphics",
   "speechon   = permit speech",
   "speechoff  = forbid speech",
   0};

unsigned char  *function_key_definitions[20] = {
   0,0,0,0,0,0,0,0,0,0,
   0,0,0,0,0,0,0,0,0,0
   };

/*
 * Globals
 */
unsigned char     work[512];
unsigned char     buf[512];
unsigned char     iobuf[1024];
int num_of_chars, no_io;

/*
 * Terminal globals
 */
struct   FileHandle     *terminal_infp;
struct   FileHandle     *terminal_outfp;

/*
 * Terminal emulator stuff
 */
struct   Message        *mymessage;
struct   IOExtSer       *ModemReadRequest;
struct   IOExtSer       *ModemWriteRequest;

unsigned char  *WelcomeMessage = "Entering Terminal Mode\nUse ^C for command mode\n";
unsigned char  *GoodbyeMessage = "Disconnected\n";
unsigned char  *OfflineMessage = "--- Offline ---\n";
unsigned char  *OnlineMessage = "--- Online ---\n";

unsigned char     rs_in[2], rs_out[2];
int      bdoneflag = 0;
int      TermEcho = 0;
int      modem_online = 0;

static int gfx_flag;

main(argc, argv)
  int   argc;
  unsigned char  *argv[];
{
  gfx_flag = 0;
  num_of_chars = 0;
  no_io = 0;
  sprintf(work, "Raw:0/0/640/200/Terminal");
  terminal_infp = Open(work, MODE_NEWFILE);
  if (terminal_infp == 0) {
    printf("Can't open window\n");
    exit(1);
  }
  terminal_outfp = terminal_infp;
  sprintf(work, "\033[0x\033[0y\033[25t\033[80u\014");
  WriteWork();

  while (1) {
    Write(terminal_outfp, "\033[7mterm:\033[m ", 13);
    getcommand(buf);
    CommandInterpreter(buf);
  }
}

WriteWork() {
  Write(terminal_outfp, work, strlen(work));
}

CommandInterpreter(command)
  unsigned char  *command;
{
  int   i;

  command = stpblk(command);
  /*
   * Scan through the command table for the string and invoke the function
   *    to do the actual work of the command.  Each of these commands is
   *    defined below, and the functions each take a pointer to the
   *    string containing the arguments passed the command line.
   */
  for (i=0; command_table[i].cmdname[0] != '\0'; i++)
    if (strncmp(command, command_table[i].cmdname,
                strlen(command_table[i].cmdname)) == 0) {
      (*command_table[i].cmdfunc)
        (stpblk(&command[strlen(command_table[i].cmdname)]));
      goto FinishedCommand;
    }
  /*
   * Not found, so look for it on the disk.
   */
  executive(stpblk(&command[0]));
FinishedCommand:
}

executive(s)
  unsigned char  *s;
{
  if (!Execute(s, 0, terminal_outfp))
    printf("%d\n", IoErr());
}

define_function_key(s)
unsigned char  *s;
{
  int   i;

  if (s[0] == '\0')
    for (i=0; i<20; i++) {
      if (function_key_definitions[i]) {
        sprintf(work, "F%-2d = %s\n", i+1, function_key_definitions[i]);
        WriteWork();
      }
    }
  else if (s[0] == 'f' || s[0] == 'F') {
    s++;
    i = atoi(s);
    if (i < 1 || i > 20) {
      sprintf(work, "%c[36mInvalid function key%c[0m\n", 0x1b, 0x1b);
      WriteWork();
    } else {
      i--;
      if (function_key_definitions[i])
        FreeMem(function_key_definitions[i], strlen(function_key_definitions[i])+1);
      while (isdigit(*s))
        s++;
      s = stpblk(s);
      if (*s != '\0') {
        function_key_definitions[i] = AllocMem(strlen(s)+1, MEMF_PUBLIC|MEMF_CLEAR);
        if (function_key_definitions[i] == 0) {
          sprintf(work, "%c[36mDefine Error: not enough memory%c[0m\n",
                  0x1b, 0x1b);
          WriteWork();
        } else
          strcpy(function_key_definitions[i], s);
      }
    }
  } else {
    sprintf(work,
            "%c[36mDefine Error: invalid function key specified%c[0m\n",
            0x1b, 0x1b);
    WriteWork();
  }
}

end(s)
  unsigned char  *s;
{
  if (modem_online) {
    sprintf(work, "%c[36mTerminal Mode Error: Modem still online%c[0m\n",
            0x1b, 0x1b);
    WriteWork();
  } else {
    if (gfx_flag == 1)
      terminate();
    Close(terminal_outfp);
    exit(0);
  }
}

help(s)
  unsigned char  *s;
{
  int   i;

  sprintf(work,"%c[7m          MyCli Help          %c[0m\n", 0x1b, 0x1b);
  WriteWork();
  for (i=0; help_messages[i]; i++) {
    sprintf(work, "%s\n", help_messages[i]);
    WriteWork();
  }
  sprintf(work, "%c[7m          End of Help         %c[0m\n", 0x1b, 0x1b);
  WriteWork();
}

gfxoff()
{
  if (gfx_flag == 1)
    terminate();
  gfx_flag = 0;
}

speechon()
{
  oktosay = 1;
}

speechoff()
{
  oktosay = 0;
}

offline(s)
unsigned char  *s;
{
  modem_online = 0;
  say_string((char*)0, 1);
}

online(s)
  unsigned char  *s;
{
  modem_online = !0;      /* signal that modem is live !!! */
  if (initialize()) {     /* set baud rate, etc. */
    Write(terminal_outfp, WelcomeMessage, strlen(WelcomeMessage));
    while (modem_online) {
      bdoneflag = 0;    /* terminal mode on flag */
      Write(terminal_outfp, OnlineMessage, strlen(OnlineMessage));
      while (!bdoneflag) {
        check_keyboard();
        check_modem();
        if (bdoneflag || num_of_chars > MAX_CHARS || no_io > 0) {
          if (num_of_chars > 0) {
            Write(terminal_outfp, iobuf, num_of_chars);
            num_of_chars = 0;
          }
        }
      }
      Write(terminal_outfp, OfflineMessage, strlen(OfflineMessage));
      Write(terminal_outfp, "\033[7mterm:\033[m ", 13);
      getcommand(buf);
      CommandInterpreter(buf);
    }
    cleanup();
  }
  modem_online = 0;
}

getcommand(s)
  unsigned char  *s;
{
  unsigned char  c;
  unsigned col;

  col = 0;
  while (1) {
    Read(terminal_infp, &c, 1);
    switch(c) {
      case 8:
        if (col) {
          c = 8;
          Write(terminal_outfp, &c, 1);
          c = ' ';
          Write(terminal_outfp, &c, 1);
          c = 8;
          Write(terminal_outfp, &c, 1);
          col--;
        }
        continue;
      case 10:
      case 13:
        sprintf(work, "\n");
        WriteWork();
        s[col++] = '\0';
        break;
      case 0x1b:
      case 24:
        while (col) {
          c = 8;
          Write(terminal_outfp, &c, 1);
          c = ' ';
          Write(terminal_outfp, &c, 1);
          c = 8;
          Write(terminal_outfp, &c, 1);
          col--;
        }
        continue;
      case 0x9b:
        if (process_event(&s[col])) {
          strcat(s, "\n");
          Write(terminal_outfp, &s[col], strlen(&s[col]));
          break;
        }
        continue;
      default:
        s[col++] = c;
        Write(terminal_outfp, &c, 1);
        continue;
    }
    break;
  }
}

/*
 * this function converts an incoming ANSI escape sequence
 * and processes it.  A buffer is passed where any function
 * key expansion is to take place. If the buffer is modified
 * for any reason, this function returns true.
 */
process_event(cmd_line)
  unsigned char  *cmd_line;
{
  int   i;
  unsigned char  c;
  char  event_buffer[32];

  i = 0;
  while (1) {
    Read(terminal_infp, &c, 1);
    event_buffer[i] = c;
    if (c == '~' || c == '|' || c == 'A' || c == 'B' || c == 'C' || c == 'D')
      break;
    i++;
  }
  event_buffer[i+1] = '\0';
  if (event_buffer[i] == '~') {
    if (event_buffer[0] == '?') {
      strcpy(cmd_line, "help");
      return !0;
    } else if (isdigit(event_buffer[0])) {
      if (function_key(atoi(event_buffer), cmd_line))
        return !0;
      else if (atoi(event_buffer) == 6)
        bdoneflag = !0;
    }
  } else if (i == 0 && (event_buffer[0] >= 'A' && event_buffer[0] <= 'D')) {
    cmd_line[0] = '\033';
    cmd_line[1] = event_buffer[0];
    cmd_line[2] = '\000';
    return !0;
  }
  return 0;
}

/*
 * if a definition for the function key fkey exists (0-19), then
 * the translation for the function key is copied to the string
 * s, and this function returns !0.  Otherwise, now translation
 * exists, and this function returns 0.
 */
function_key(fkey, s)
  int fkey;
  unsigned char  *s;
{
  int   i;

  if (function_key_definitions[fkey] != 0) {
    for (i=0; function_key_definitions[fkey][i] != '\0'; i++)
      s[i] = function_key_definitions[fkey][i];
    s[i] = '\0';
    return !0;
  }
  return 0;
}

initialize() {
  ModemReadRequest = (struct IOExtSer *)AllocMem(sizeof(*ModemReadRequest),
                     MEMF_PUBLIC | MEMF_CLEAR);
  ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
  ModemReadRequest->IOSer.io_Message.mn_ReplyPort =
                                           CreatePort("Read_RS",0);
  if (OpenDevice(SERIALNAME, NULL, ModemReadRequest, NULL)) {
    sprintf(work, "%c[36mCan't open serial read device%c[0m\n",
            0x1b, 0x1b);
    WriteWork();
    DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort);
    FreeMem(ModemReadRequest, sizeof(*ModemReadRequest));
    return 0;
  }
  ModemReadRequest->IOSer.io_Command = CMD_READ;
  ModemReadRequest->IOSer.io_Length = 1;
  ModemReadRequest->IOSer.io_Data = (APTR) &rs_in[0];

  ModemWriteRequest = (struct IOExtSer *)AllocMem(sizeof(*ModemWriteRequest),
                      MEMF_PUBLIC | MEMF_CLEAR);
  ModemWriteRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
  ModemWriteRequest->IOSer.io_Message.mn_ReplyPort =
                                                 CreatePort("Write_RS",0);
  if (OpenDevice(SERIALNAME, NULL, ModemWriteRequest, NULL)) {
    sprintf(work, "%c[36mCan't open serial write device%c[0m\n",
            0x1b, 0x1b);
    WriteWork();
    DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort);
    FreeMem(ModemReadRequest, sizeof(*ModemReadRequest));
    DeletePort(ModemWriteRequest->IOSer.io_Message.mn_ReplyPort);
    FreeMem(ModemWriteRequest, sizeof(*ModemWriteRequest));
    return 0;
  }
  ModemWriteRequest->IOSer.io_Command = CMD_WRITE;
  ModemWriteRequest->IOSer.io_Length = 1;
  ModemWriteRequest->IOSer.io_Data = (APTR) &rs_out[0];

  ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
  ModemReadRequest->io_Baud = 1200;
  ModemReadRequest->io_ReadLen = 8;
  ModemReadRequest->io_WriteLen = 8;
  ModemReadRequest->io_CtlChar = 1L;
  ModemReadRequest->IOSer.io_Command = SDCMD_SETPARAMS;
  DoIO(ModemReadRequest);
  ModemReadRequest->IOSer.io_Command = CMD_READ;
  BeginIO(ModemReadRequest);
  return !0;
}

cleanup() {
  CloseDevice(ModemReadRequest);
  DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort);
  FreeMem(ModemReadRequest, sizeof(*ModemReadRequest));

  CloseDevice(ModemWriteRequest);
  DeletePort(ModemWriteRequest->IOSer.io_Message.mn_ReplyPort);
  FreeMem(ModemWriteRequest, sizeof(*ModemWriteRequest));

  Write(terminal_outfp, GoodbyeMessage, strlen(GoodbyeMessage));
}

check_keyboard()
{
  unsigned char  *pc;

  if (WaitForChar(terminal_infp, 1)) {
    Read(terminal_infp, &rs_out[0], 1);
    switch ((unsigned char)rs_out[0]) {
      case 0x9b:                          /* ANSI keyboard stuff */
        if (process_event(&buf[0])) {    /* send the translation */
          pc = &buf[0];
          while (*pc != '\0') {
            rs_out[0] = *pc++;
            if (TermEcho)
              Write(terminal_outfp, &rs_out[0], 1);
            DoIO(ModemWriteRequest);
            check_modem();
          }
        }
        break;
      case 0x05:                    /* toggle keystroke echo */
        TermEcho = !TermEcho;
        sprintf(work, "%c[36mEcho %s%c[0m\n", 0x1b, TermEcho?"ON":"OFF",
                0x1b);
        WriteWork();
        break;
      default:
        if (TermEcho)
          Write(terminal_outfp, &rs_out[0], 1);
        DoIO(ModemWriteRequest);
    }
  }
}

/*
 * Check to see if the Read Request IO has completed from the modem.
 */
check_modem()
{
  static int sayflag = 0;
  static char saystring[133];
  static int sayind = 0;
  static int escape_sequence = 0;

  if (CheckIO(ModemReadRequest)) {
    WaitIO(ModemReadRequest);
    rs_in[0] &= 0x7f;

    if (rs_in[0] == '\001' && oktosay == 1) {
      sayflag = 1;
      BeginIO(ModemReadRequest);
      return;
    }

    if (oktosay == 1 && sayflag) {
      if (rs_in[0] >= ' ' && rs_in[0] < (char)127) {
        saystring[sayind++] = rs_in[0];
      } else {
	Write(terminal_outfp, iobuf, num_of_chars);
	rs_out[0] = CTRLS;
	DoIO(ModemWriteRequest);
	num_of_chars = 0;
        saystring[sayind++] = (char)0;
        say_string(saystring,0);
        sayind = 0;
	sayflag = 0;
	rs_out[0] = CTRLQ;
	DoIO(ModemWriteRequest);
      }
    }
    if (rs_in[0] == '\033') {
      escape_sequence = 1;
    } else if (escape_sequence == 1) {
      if (rs_in[0] == 'G') {
        Graphics();
      } else {
        iobuf[num_of_chars++] = '\033';
        iobuf[num_of_chars++] = rs_in[0];
        no_io = 0;
      }
      escape_sequence = 0;
    } else {
      iobuf[num_of_chars++] = rs_in[0];
      no_io = 0;
    }
    BeginIO(ModemReadRequest);
  } else {
    no_io++;
  }
}

sendchar(ch)
  int ch;
{
  rs_out[0] = ch;
  DoIO(ModemWriteRequest);
}

readchar()
{
  unsigned char c;
  int rd,ch;
  rd = FALSE;
  while (rd == FALSE) {
    if(CheckIO(ModemReadRequest)) {
      WaitIO(ModemReadRequest);
      ch=rs_in[0];
      rd = TRUE;
      BeginIO(ModemReadRequest);
    }
  }
  if (rd == FALSE) {
    timeout = TRUE;
    emits("\nTimeout Waiting For Character\n");
  }
  c = ch;
  return(c);
}

rb(file)
  char *file;
{
  int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag;
  unsigned int checksum, j, bufptr,i;
  char numb[10];
  bytes_xferred = 0L;
  i = 10;
  if ((fd = creat(file, 0)) < 0) {
    emits("Cannot Open File\n");
    return FALSE;
  } else
    emits("Receiving File\n");
  timeout=FALSE;
  sectnum = errors = bufptr = 0;
  sendchar(NAK);
  firstchar = 0;
  while (firstchar != EOT && errors != ERRORMAX) {
    errorflag = FALSE;
    do {
      firstchar = readchar();
      if (timeout == TRUE)
        return FALSE;
    }
    while (firstchar != SOH && firstchar != EOT);
    if (firstchar == SOH) {
      emits("Getting Block ");
      stci_d(numb,sectnum,i);
      emits(numb);
      emits("...");
      sectcurr = readchar();
      if (timeout == TRUE)
        return FALSE;
      sectcomp = readchar();
      if (timeout == TRUE)
        return FALSE;
      if ((sectcurr + sectcomp) == 255) {
        if (sectcurr == (sectnum + 1 & 0xff)) {
          checksum = 0;
          for (j = bufptr; j < (bufptr + SECSIZ); j++) {
            bufr[j] = readchar();
            if (timeout == TRUE)
              return FALSE;
            checksum = (checksum + bufr[j]) & 0xff;
          }
          if (checksum == readchar()) {
            errors = 0;
            sectnum++;
            bufptr += SECSIZ;
            bytes_xferred += SECSIZ;
            emits("verified\n");
            if (bufptr == BufSize) {
              bufptr = 0;
              if (write(fd, bufr, BufSize) == EOF) {
                emits("\nError Writing File\n");
                return FALSE;
              };
            };
            sendchar(ACK);
          } else {
            errorflag = TRUE;
            if (timeout == TRUE)
              return FALSE;
          }
        } else {
          if (sectcurr == (sectnum & 0xff)) {
            emits("\nReceived Duplicate Sector\n");
            sendchar(ACK);
          } else
            errorflag = TRUE;
        }
      } else
         errorflag = TRUE;
    }
    if (errorflag == TRUE) {
      errors++;
      emits("\nError\n");
      sendchar(NAK);
    }
  };
  if ((firstchar == EOT) && (errors < ERRORMAX)) {
    sendchar(ACK);
    write(fd, bufr, bufptr);
    write(fd, "\n", 1);
    close(fd);
    return TRUE;
  }
  return FALSE;
}

sb(file)
  char *file;
{
  int sectnum, bytes_to_send, size, attempts, c, i;
  unsigned checksum, j, bufptr;
  char numb[10];
  timeout=FALSE;
  bytes_xferred = 0;
  i = 10;
  if ((fd = open(file, 1)) < 0) {
    emits("Cannot Open Send File\n");
    return FALSE;
  } else
    emits("Sending File\n");
  attempts = 0;
  sectnum = 1;
  j=1;
  while (((c = readchar()) != NAK) && (j++ < ERRORMAX));
  if (j >= (ERRORMAX)) {
    emits("\nReceiver not sending NAKs\n");
    return FALSE;
  };
  while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX)
  {
    if (bytes_to_send == EOF) {
      emits("\nError Reading File\n");
      return FALSE;
    };
    bufptr = 0;
    while (bytes_to_send > 0 && attempts != RETRYMAX) {
      attempts = 0;
      do {
        sendchar(SOH);
        sendchar(sectnum);
        sendchar(~sectnum);
        checksum = 0;
        size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send;
        bytes_to_send -= size;
        for (j = bufptr; j < (bufptr + SECSIZ); j++)
          if (j < (bufptr + size)) {
            sendchar(bufr[j]);
            checksum += bufr[j];
          } else {
            sendchar(0);
          }
        sendchar(checksum & 0xff);
        attempts++;
        c = readchar();
        if (timeout == TRUE)
          return FALSE;
      } while ((c != ACK) && (attempts != RETRYMAX));
      bufptr += size;
      bytes_xferred += size;
      emits("Block ");
      stci_d(numb,sectnum,i);
      emits(numb);
      emits(" sent\n");
      sectnum++;
    }
  }
  close(fd);
  if (attempts == RETRYMAX) {
    emits("\nNo Acknowledgment Of Sector, Aborting\n");
    return FALSE;
  } else {
    attempts = 0;
    do {
      sendchar(EOT);
      attempts++;
    } while ((readchar() != ACK) && (attempts != RETRYMAX) && (timeout == FALSE));
    if (attempts == RETRYMAX)
      emits("\nNo Acknowledgment Of End Of File\n");
  };
  return TRUE;
}

emits(embuf)
  char *embuf;
{
  Write(terminal_outfp, embuf, strlen(embuf));
}

Graphics()
{
  char buf[82], *gr_buf;
  int gr_len, r, g, b, color, x1, y1, x2, y2;
  int polx[256], poly[256], n, clip, xmin, ymin, xmax, ymax;
  int i;

  if (gfx_flag == 0) {
    gfx_flag = 1;
    initialise();
  } else
    get_screen();
  rs_out[0] = CTRLS;
  DoIO(ModemWriteRequest);
  BeginIO(ModemReadRequest);
  for(;;) {
    gr_len = 0;
    buf[0] = (char)0;
    gr_buf = &(buf[1]);
    while(gr_buf[gr_len-1] != '\015') {
      if (CheckIO(ModemReadRequest)) {
        WaitIO(ModemReadRequest);
        rs_in[0] &= 0x7f;
        if (rs_in[0] != '\012') {
          gr_buf[gr_len++] = rs_in[0];
        }
        BeginIO(ModemReadRequest);
      } else {
        rs_out[0] = CTRLQ;
        DoIO(ModemWriteRequest);
      }
    }
    rs_out[0] = CTRLS;
    DoIO(ModemWriteRequest);
    gr_buf[gr_len-1] = (char)0;
    switch (gr_buf[0]) {
      case 'T':
/*        terminate(); */
        put_screen();
	rs_out[0] = CTRLQ;
	DoIO(ModemWriteRequest);
        return;
      case 'C':
        sscanf(&(gr_buf[1]), "%d%d%d%d", &color, &r, &g, &b);
        define_color(color, r, g, b);
        if (check_user_action() == -1) {
          put_screen();
          return;
        }
        break;
      case 'L':
        sscanf(&(gr_buf[1]), "%d%d%d%d%d", &x1, &y1, &x2, &y2, &color);
        draw(x1, y1, x2, y2, color);
        if (check_user_action() == -1) {
          put_screen();
          return;
        }
        break;
      case 'P':
        sscanf(&(gr_buf[1]), "%d%d%d%d%d%d%d", &n, &color, &clip,
					       &xmin, &ymin, &xmax, &ymax);
        for (i=0; i<n; i++) {
          gr_len = 0;
          buf[0] = (char)0;
          gr_buf = &(buf[1]);
          while(gr_buf[gr_len-1] != '\015') {
            if (CheckIO(ModemReadRequest)) {
              WaitIO(ModemReadRequest);
              rs_in[0] &= 0x7f;
              if (rs_in[0] != '\012') {
                gr_buf[gr_len++] = rs_in[0];
              }
              BeginIO(ModemReadRequest);
            } else {
	      rs_out[0] = CTRLQ;
	      DoIO(ModemWriteRequest);
	    }
          }
          gr_buf[gr_len-1] = (char)0;
	  sscanf(gr_buf,"%d%d", &(polx[i]), &(poly[i]));
        }
	rs_out[0] = CTRLS;
	DoIO(ModemWriteRequest);
/* 	poly_draw(polx, poly, n, color, clip, xmin, ymin, xmax, ymax); */
        if (check_user_action() == -1) {
          put_screen();
          return;
        }
	break;
    }
  }
}
SHAR_EOF
if test 21608 -ne "`wc -c < 'term.c'`"
then
	echo shar: error transmitting "'term.c'" '(should have been 21608 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'gr.c'" '(5005 characters)'
if test -f 'gr.c'
then
	echo shar: will not over-write existing file "'gr.c'"
else
cat << \SHAR_EOF > 'gr.c'
#include <exec/types.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <hardware/blit.h>
#include <graphics/copper.h>
#include <graphics/regions.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/gels.h>
#include <graphics/display.h>
#include <intuition/intuition.h>

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;

#define MAXX   640

struct NewScreen MyScreen =
{ 0,0,MAXX,400,4,0,1,HIRES | INTERLACE, CUSTOMSCREEN, NULL, "Graphics", 0,0,};

struct NewWindow DrawWindow = {
  0,0,MAXX,400,
  0,1,
  MENUPICK,
  BORDERLESS | BACKDROP | ACTIVATE,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  0,0,0,0,
  CUSTOMSCREEN,
};

struct Screen *Screen = NULL;
struct Window *Backdrop = NULL;
struct RastPort *DrawRP;
struct ViewPort *DrawVP;
struct IntuiMessage  *message;

struct MenuItem OnlyMenuItems[3];
struct IntuiText OnlyMenuText[3];
struct Menu OnlyMenu[1];

#define MAXLINES  125
#define ERASE     0

initialise()
{
  if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
    exit(1);

  if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) {
    cleanitup();
    exit(2);
  }

  if(!(Screen = (struct Screen *)OpenScreen(&MyScreen))) {
    cleanitup();
    exit(3);
  }

  DrawWindow.Screen = Screen;

  if(!(Backdrop = (struct Window *)OpenWindow(&DrawWindow))) {
    cleanitup();
    exit(4);
  }

  DrawRP = Backdrop->RPort;     /* Draw into backdrop window */
  DrawVP = &Screen->ViewPort;   /* Set colors in Screens VP  */

  initmenuitems();
  initmenu();
  SetMenuStrip(Backdrop, &OnlyMenu[0]);

  ShowTitle(Screen,FALSE);

  define_color( 0,  0,  0,  0);
  define_color( 1, 15, 15, 15);
  define_color( 2, 15,  0,  0);
  define_color( 3,  7,  0,  0);
  define_color( 4,  0, 15,  0);
  define_color( 5,  0,  7,  0);
  define_color( 6,  0,  0, 15);
  define_color( 7,  0,  0,  7);
  define_color( 8, 15, 15,  0);
  define_color( 9,  7,  7,  0);
  define_color(10, 15,  0, 15);
  define_color(11,  7,  0,  7);
  define_color(12,  0, 15, 15);
  define_color(13,  0,  7,  7);
  define_color(14,  7,  7,  7);
  define_color(15,  3,  3,  3);
}

terminate()
{
  ShowTitle(Screen,TRUE);
/*  while(check_user_action() != -1); */
  cleanitup();
}

cleanitup()    /* release allocated resources */
{
  if (Backdrop)
    CloseWindow(Backdrop);
  if (Screen)
    CloseScreen(Screen);
  if (GfxBase)
    CloseLibrary(GfxBase);
  if (IntuitionBase)
    CloseLibrary(IntuitionBase);
}

draw(x1, y1, x2, y2, color)
  int x1, x2;
  int y1, y2;
  BYTE color;
{
  SetAPen(DrawRP, color);
  SetDrMd(DrawRP, JAM1);
  Move(DrawRP, x1, y1);
  Draw(DrawRP, x2, y2);
}

define_color(color, r, g, b)
  int color, r, g, b;
{
  SetRGB4(DrawVP, color, r, g, b);
}

initmenuitems()
{
  short n;

  for(n = 0; n < 3; n++) {  /* One struct for each item */
    OnlyMenuItems[n].NextItem = &OnlyMenuItems[n + 1]; /* next item */
    OnlyMenuItems[n].LeftEdge = 0;
    OnlyMenuItems[n].TopEdge = 10 * n;
    OnlyMenuItems[n].Width = 112;
    OnlyMenuItems[n].Height = 10;
    OnlyMenuItems[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP;
    OnlyMenuItems[n].MutualExclude = 0;
    OnlyMenuItems[n].ItemFill = (APTR)&OnlyMenuText[n];
    OnlyMenuItems[n].SelectFill = NULL;
    OnlyMenuItems[n].Command = 0;
    OnlyMenuItems[n].SubItem = NULL;
    OnlyMenuItems[n].NextSelect = 0;

    OnlyMenuText[n].FrontPen = 0;
    OnlyMenuText[n].BackPen = 1;
    OnlyMenuText[n].DrawMode = JAM2;
    OnlyMenuText[n].LeftEdge = 0;
    OnlyMenuText[n].TopEdge = 1;
    OnlyMenuText[n].ITextFont = NULL;
    OnlyMenuText[n].NextText = NULL;
  }
  OnlyMenuItems[2].NextItem = NULL; /* Last item */

  OnlyMenuText[0].IText = (UBYTE *)"Hide Title Bar";
  OnlyMenuText[1].IText = (UBYTE *)"Show Title Bar";
  OnlyMenuText[2].IText = (UBYTE *)"QUIT!";
}

initmenu()
{
  OnlyMenu[0].NextMenu = NULL;                 /* No more menus */
  OnlyMenu[0].LeftEdge = 0;
  OnlyMenu[0].TopEdge = 0;
  OnlyMenu[0].Width = 85;
  OnlyMenu[0].Height = 10;
  OnlyMenu[0].Flags = MENUENABLED;             /* All items selectable */
  OnlyMenu[0].MenuName = "Actions";
  OnlyMenu[0].FirstItem = &OnlyMenuItems[0];   /* Pointer to first item */
}

check_user_action()
{
  ULONG class;
  USHORT code, ItemNum;
  int action;

  action = 0;

  while(message = (struct IntuiMessage *)GetMsg(Backdrop->UserPort)) {
    class = message->Class;
    code = message->Code;
    ReplyMsg(message);

    if (class == MENUPICK && code != MENUNULL) {
      ItemNum = ITEMNUM( code );
      switch (ItemNum) {
        case 0:
          ShowTitle(Screen, FALSE);
          break;
        case 1:
          ShowTitle(Screen, TRUE);
          break;
        case 2:
/*          ClearMenuStrip(Backdrop); */
          action = -1;
          return(action);
      }
    }
  }
  return (action);
}

put_screen()
{
/*  ScreenToBack(Screen); */
  ShowTitle(Screen,TRUE);
}

get_screen()
{
  ScreenToFront(Screen);
  ShowTitle(Screen,TRUE);
}
SHAR_EOF
if test 5005 -ne "`wc -c < 'gr.c'`"
then
	echo shar: error transmitting "'gr.c'" '(should have been 5005 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'speech.c'" '(8123 characters)'
if test -f 'speech.c'
then
	echo shar: will not over-write existing file "'speech.c'"
else
cat << \SHAR_EOF > 'speech.c'
/* Here is a sample speech demo program that compiles on
 * Amiga (Lattice) C.  It can be thought of as a stripped
 * down version of the speechtoy (lucas).  I haven't 
 * provided the graphics for the drawing of the mouth,
 * but the access to the mouth variables is shown here.
 * 
 * It is the sample program from the rev 1.1 ROM KERNEL
 * manual, now at the printers.
 * 
 * Rob Peck.   
 *
 * This code may be freely utilized to create programs for the Amiga.
 */
 


#include "exec/types.h"
#include "exec/exec.h"

#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"

#include "devices/narrator.h"
#include "libraries/translator.h"

struct MsgPort *readport=0;
struct MsgPort *writeport=0;

extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();	

struct narrator_rb *writeNarrator=0;
struct mouth_rb *readNarrator=0;
struct Library *TranslatorBase=0;
UBYTE outputstring[500];	/* place to put the translation */
SHORT rtnCode;			/* return code from function */
SHORT readError;
SHORT writeError;
SHORT error;
BYTE  audChanMasks[4] = { 3,5,10,12 }; /* which channels to use */

#define CANT_OPEN_TRANSLATOR -100
#define CANT_OPEN_NARRATOR -200
#define CREATE_PORT_PROBLEMS -300
#define CREATE_IO_PROBLEMS -400
#define CANT_PERFORM_WRITE -500
#define REVISION 1

extern struct Library *OpenLibrary();

say_string(Txt,done)
  UBYTE *Txt;
  int done;
{
  static FirstTime = 1;

  if (FirstTime) {
    FirstTime = 0;
	TranslatorBase = OpenLibrary("translator.library",REVISION);
	if(TranslatorBase == NULL) exit (CANT_OPEN_TRANSLATOR);
	rtnCode = Translate(Txt,strlen(Txt)+1,outputstring,500);
	error = rtnCode + 100;
	if(rtnCode != 0) goto cleanup0;
	
	writeport = CreatePort(0,0);
	if(writeport == NULL) { error=CREATE_PORT_PROBLEMS; goto cleanup1; }
	readport = CreatePort(0,0);
	if(readport == NULL) { error=CREATE_PORT_PROBLEMS; goto cleanup2; }
	writeNarrator = (struct narrator_rb *)CreateExtIO(writeport,
					sizeof(struct narrator_rb));
	if(writeNarrator == NULL) { error=CREATE_IO_PROBLEMS; goto cleanup3; }
	readNarrator = (struct mouth_rb *)CreateExtIO(readport,
					sizeof(struct mouth_rb));

	if(readNarrator == NULL) { error=CREATE_IO_PROBLEMS; goto cleanup4; }
/* SET UP THE PARAMETERS FOR THE WRITE-MESSAGE TO THE NARRATOR DEVICE */

	/* show where to find the channel masks */
	writeNarrator->ch_masks = (audChanMasks);

	/* and tell it how many of them there are */
	writeNarrator->nm_masks = sizeof(audChanMasks);	

	/* tell it where to find the string to speak */	
	writeNarrator->message.io_Data = (APTR)outputstring;

	/* tell it how many characters the translate function returned */
	writeNarrator->message.io_Length = strlen(outputstring);

	/* if nonzero, asks that mouths be calculated during speech */
	writeNarrator->mouths = 1;

	/* tell it this is a write-command */
	writeNarrator->message.io_Command = CMD_WRITE;

	/* select rate of 165 words/min. */

	writeNarrator->rate = (UWORD)165;

/* Open the device  */

	error = OpenDevice("narrator.device", 0, writeNarrator, 0);
	if(error != 0) goto cleanup4;

/* SET UP THE PARAMETERS FOR THE READ-MESSAGE TO THE NARRATOR DEVICE */

	/* tell narrator for whose speech a mouth is to be generated */
	readNarrator->voice.message.io_Device = 
		writeNarrator->message.io_Device;
	readNarrator->voice.message.io_Unit = 
		writeNarrator->message.io_Unit;

	readNarrator->width = 0;
	readNarrator->height = 0;	/* initial mouth parameters */

	readNarrator->voice.message.io_Command = CMD_READ;
		/* initial error value */
	readNarrator->voice.message.io_Error = 0;	

/* Send an asynchronous write request to the device */

	writeError = SendIO(writeNarrator);
	if(writeError != NULL) { error=CANT_PERFORM_WRITE; goto cleanup5; }
	/* return immediately, run tasks concurrently */

/* keep sending reads until it comes back saying "no write in progress" */

	while((readError = readNarrator->voice.message.io_Error) != 
		ND_NoWrite)
	{
		DoIO(readNarrator);
		/* put task to sleep waiting for a different
		 * mouth shape or return of the message block
		 * with the error field showing no write in
		 * process
		 */
	}

	Delay(30);
     return;
   }
   if ( !done ) {
	rtnCode = Translate(Txt,strlen(Txt)+1,outputstring,500);
/*	writeNarrator->sex = FEMALE;
	writeNarrator->pitch = MAXPITCH;  /* raise pitch from default value */
	writeNarrator->message.io_Data = (APTR)outputstring;
	writeNarrator->message.io_Length = strlen(outputstring);
	DoIO(writeNarrator);
	
	Delay(30);
    return;
  }

    cleanup5:
	if(writeNarrator != 0)
		CloseDevice(writeNarrator);
				/* terminate access to the device */

	/* now return system memory to the memory allocator */ 

    cleanup4:
	if(readNarrator != 0)
		DeleteExtIO(readNarrator,sizeof(struct mouth_rb));
    cleanup3:
	if(writeNarrator != 0)
		DeleteExtIO(writeNarrator,sizeof(struct narrator_rb));
    cleanup2:
	if(readport != 0)
		DeletePort(readport);
    cleanup1:
	if(writeport != 0)
		DeletePort(writeport);
    cleanup0:
	if(TranslatorBase != 0)
   		CloseLibrary(TranslatorBase);
				/* terminate access to the library */
	
	if(error != 0) exit(error);
} /* end of test */	

/***********************************************************************
*
*	Exec Support Function -- Extended IO Request
*
***********************************************************************/

extern APTR AllocMem();

/****** exec_support/CreateExtIO **************************************
*
*   NAME	
*	CreateExtIO() -- create an Extended IO request
*
*   SYNOPSIS
*	ioReq = CreateExtIO(ioReplyPort,size);   
*
*   FUNCTION
*	Allocates memory for and initializes a new IO request block
*	of a user-specified number of bytes.
*
*   INPUTS
*	ioReplyPort - a pointer to an already initialized
*		message port to be used for this IO request's reply port.
*
*   RESULT
*	Returns a pointer to the new block.  Pointer is of the type
*	struct IORequest.
*
*	0 indicates inability to allocate enough memory for the request block
*	or not enough signals available.
*
*   EXAMPLE
*	struct IORequest *myBlock;
*	if( (myBlock = CreateExtIO(myPort,sizeof(struct IOExtTD)) == NULL)
*		exit(NO_MEM_OR_SIGNALS);
*
*	example used to allocate space for IOExtTD (trackdisk driver
*	IO Request block for extended IO operations).
*
*   SEE ALSO
*	DeleteExtIO
*
***********************************************************************/

struct IORequest *CreateExtIO(ioReplyPort,size)
    struct MsgPort *ioReplyPort;
    LONG size;
{
    struct IORequest *ioReq;

    if (ioReplyPort == 0)
	return ((struct IORequest   *) 0);

    ioReq = (struct IORequest *)AllocMem (size, MEMF_CLEAR | MEMF_PUBLIC);

    if (ioReq == 0)
	return ((struct IORequest   *) 0);

    ioReq -> io_Message.mn_Node.ln_Type = NT_MESSAGE;
    ioReq -> io_Message.mn_Node.ln_Pri = 0;

    ioReq -> io_Message.mn_ReplyPort = ioReplyPort;
    ioReq -> io_Message.mn_Length = (size - sizeof(struct Message));
						/* new (rap) */
    return (ioReq);
}

/****** exec_support/DeleteExtIO **************************************
*
*   NAME
*	DeleteExtIO() - return memory allocated for extended IO request
*
*   SYNOPSIS
*	DeleteExtIO(ioReq,size);
*
*   FUNCTION
*	See summary line at NAME.  Also frees the signal bit which
*	had been allocated by the call to CreateExtIO.
*
*   INPUTS
*	A pointer to the IORequest block whose resources are to be freed.
*
*   RESULT
*	Frees the memory.  Returns (no error conditions shown)
*
*   EXAMPLE
*	struct IORequest *myBlock;
*	DeleteExtIO(myBlock,(sizeof(struct IOExtTD)));
*		
*	example shows that CreateExtIO had been used to create a trackdisk
*	(extended) IO Request block.
*
*   SEE ALSO
*	CreateExtIO
*
**************************************************************************/

DeleteExtIO(ioExt,size)
    struct IORequest *ioExt;
    LONG size;
{
    ioExt -> io_Message.mn_Node.ln_Type = 0xff;
    ioExt -> io_Device = (struct Device *) -1;
    ioExt -> io_Unit = (struct Unit *) -1;

    FreeMem (ioExt, size);
}
SHAR_EOF
if test 8123 -ne "`wc -c < 'speech.c'`"
then
	echo shar: error transmitting "'speech.c'" '(should have been 8123 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'termcap'" '(532 characters)'
if test -f 'termcap'
then
	echo shar: will not over-write existing file "'termcap'"
else
cat << \SHAR_EOF > 'termcap'
#normal amiga entry

am|amiga:\
	:al=\E[L:bs:cd=\E[J:ce=\E[K:cl=^L:cm=\E[%i%d;%dH:co#80:cr=^M:\
	:dc=\E[P:do=\E[B:kd=\EB:kl=\ED:kr=\EC:ku=\EA:li#25:nd=\E[C:\
	:sf=\E[S:sr=\E[T:up=\E[A:bw:nl=\E[B:am:so=\E[7m:se=\E[m:bl=^G:\
	:dl=\E[M:us=\E[4m:ue=\E[0m:ic=\E[@:

#hack amiga entry

sm|amiga-s:\
	:al=\E[L:bs:cd=\E[J:ce=\E[K:cl=^L^A:cm=\E[%i%d;%dH:co#80:cr=^M:\
	:dc=\E[P:do=\E[B:kd=\EB:kl=\ED:kr=\EC:ku=\EA:li#25:nd=\E[C:\
	:sf=\E[S:sr=\E[T:up=\E[A:bw:nl=\E[B:am:so=\E[7m:se=\E[m:bl=^G:\
	dl=\E[M:us=\E[4m:ue=\E[0m:ic=\E[@:ho=\E[H^A:
SHAR_EOF
if test 532 -ne "`wc -c < 'termcap'`"
then
	echo shar: error transmitting "'termcap'" '(should have been 532 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'say.c'" '(527 characters)'
if test -f 'say.c'
then
	echo shar: will not over-write existing file "'say.c'"
else
cat << \SHAR_EOF > 'say.c'
# include <stdio.h>

main(argc,argv)
  int	 argc;
  char	*argv[];
{
  char	 x[133];
  int	 i;
  FILE	*in;

  if (argc == 1) {
    while (gets(x) != NULL) {
      printf("%c%s\n",'\001',x);
    }
  } else {
      
    for (i=1; i<argc; i++) {
      if (strcmp(argv[i],"-")==0) {
	in = stdin;
      } else {
	if ((in = fopen(argv[i],"r"))==NULL) {
	  fprintf(stderr,"Can't open %s\n", argv[i]);
	  continue;
	}
      }
      while (fgets(x,sizeof(x),in) != NULL) {
	printf("%c%s",'\001',x);
      }
      fclose(in);
    }
  }
}
SHAR_EOF
if test 527 -ne "`wc -c < 'say.c'`"
then
	echo shar: error transmitting "'say.c'" '(should have been 527 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 

------
	Lefteris   (princeton!tilt!kyrimis)
------

kyrimis@tilt.FUN (Kriton Kyrimis) (04/13/86)

In article <408@tilt.FUN> tilt!ek (Eleftherios Koutsofios) writes:
>------
>	Lefteris   (princeton!tilt!kyrimis)
>------

-----------------------------------^

He obviously means princeton!tilt!ek

Although I did help by typing parts of the program  and  by  con-
stantly  nagging until it was perfect, this is Lefteris' work, so
I don't think this is the correct place for  an  acknowledgement.
:-)
-- 

	Kriton	(princeton!tilt!kyrimis)
------
"Is it you, timelord?"
"As far as I know, there is no one except you and me here, so it *must* be me!"
------