BSD 4_3_Net_1 release
[unix-history] / telnet / Source / sys_dos.c
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char sccsid[] = "@(#)sys_dos.c 1.4 (Berkeley) 6/29/88";
#endif /* not lint */
#if defined(MSDOS)
#include <time.h>
#include <signal.h>
#include <process.h>
#include <fcntl.h>
#include <io.h>
#include <dos.h>
#include <ctype.h>
#include "externs.h"
#include "defines.h"
#if !defined(SO_OOBINLINE)
#define SO_OOBINLINE
#endif /* !defined(SO_OOBINLINE) */
\f
/*
* MSDOS doesn't have anyway of deciding whether a full-edited line
* is ready to be read in, so we need to do character-by-character
* reads, and then do the editing in the program (in the case where
* we are supporting line-by-line mode).
*
* The following routines, which are internal to the MSDOS-specific
* code, accomplish this miracle.
*/
#define Hex(c) HEX[(c)&0xff]
static survivorSetup = 0; /* Do we have ^C hooks in? */
static int
lineend = 0, /* There is a line terminator */
ctrlCCount = 0;
static char linein[200], /* Where input line is assembled */
*nextin = linein, /* Next input character */
*nextout = linein; /* Next character to be consumed */
static char
savedInState, savedOutState;
#define consumechar() \
if ((++nextout) >= nextin) { \
nextout = nextin = linein; \
lineend = 0; \
}
#define characteratatime() (!MODE_LINE(globalmode)) /* one by one */
/*
* killone()
*
* Erase the last character on the line.
*/
static void
killone()
{
if (lineend) {
return; /* ??? XXX */
}
if (nextin == linein) {
return; /* Nothing to do */
}
nextin--;
if (!(isspace(*nextin) || isprint(*nextin))) {
putchar('\b');
putchar(' ');
putchar('\b');
}
putchar('\b');
putchar(' ');
putchar('\b');
}
/*
* setlineend()
*
* Decide if it's time to send the current line up to the user
* process.
*/
static void
setlineend()
{
if (nextin == nextout) {
return;
}
if (characteratatime()) {
lineend = 1;
} else if (nextin >= (linein+sizeof linein)) {
lineend = 1;
} else {
int c = *(nextin-1);
if ((c == termIntChar)
|| (c == termQuitChar)
|| (c == termEofChar)) {
lineend = 1;
} else if (c == termFlushChar) {
lineend = 1;
} else if ((c == '\n') || (c == '\r')) {
lineend = 1;
}
}
/* Otherwise, leave it alone (reset by 'consumechar') */
}
/*
* OK, what we do here is:
*
* o If we are echoing, then
* o Look for character erase, line kill characters
* o Echo the character (using '^' if a control character)
* o Put the character in the input buffer
* o Set 'lineend' as necessary
*/
static void
DoNextChar(c)
int c; /* Character to process */
{
static char literalnextcharacter = 0;
if (nextin >= (linein+sizeof linein)) {
putchar('\7'); /* Ring bell */
setlineend();
return;
}
if (MODE_LOCAL_CHARS(globalmode)) {
/* Look for some special character */
if (!literalnextcharacter) {
if (c == termEraseChar) {
killone();
setlineend();
return;
} else if (c == termKillChar) {
while (nextin != linein) {
killone();
}
setlineend();
return;
} else if (c == termLiteralNextChar) {
literalnextcharacter = 1;
return;
}
}
if (MODE_LOCAL_ECHO(globalmode)) {
if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) {
putchar('\r');
putchar('\n');
c = '\n';
} else if (!isprint(c) && !isspace(c)) {
putchar('^');
putchar(c^0x40);
} else {
putchar(c);
}
}
literalnextcharacter = 0;
}
*nextin++ = c;
setlineend();
}
static int
inputExists()
{
int input;
static state = 0;
while (ctrlCCount) {
DoNextChar(0x03);
ctrlCCount--;
}
if (lineend) {
return 1;
}
#if 1 /* For BIOS variety of calls */
if (kbhit() == 0) {
return lineend;
}
input = getch(); /* MSC - get console character */
if ((input&0xff) == 0) {
DoNextChar(0x01); /* ^A */
} else {
DoNextChar(input&0xff);
}
#else /* 0 */
if ((input = dirconio()) == -1) {
return lineend;
}
if ((input&0xff) == 0) {
if ((input&0xff00) == 0x0300) { /* Null */
DoNextChar(0);
} else {
DoNextChar(0x01);
if (input&0x8000) {
DoNextChar(0x01);
DoNextChar((input>>8)&0x7f);
} else {
DoNextChar((input>>8)&0xff);
}
}
} else {
DoNextChar(input&0xff);
}
#endif /* 0 */
return lineend;
}
void
CtrlCInterrupt()
{
if (!MODE_COMMAND_LINE(globalmode)) {
char far *Bios_Break = (char far *) (((long)0x40<<16)|0x71);
ctrlCCount++; /* XXX */
signal(SIGINT, CtrlCInterrupt);
} else {
closeallsockets();
exit(1);
}
}
int
dosbinary(fd, onoff)
int fd;
int onoff;
{
union REGS regs;
int oldstate;
/* Get old stuff */
regs.h.ah = 0x44;
regs.h.al = 0;
regs.x.bx = fd;
intdos(&regs, &regs);
oldstate = regs.h.dl&(1<<5); /* Save state */
/* Set correct bits in new mode */
regs.h.dh = 0;
if (onoff) {
regs.h.dl |= 1<<5;
} else {
regs.h.dl &= ~(1<<5);
}
/* Set in new mode */
regs.h.ah = 0x44;
regs.h.al = 1;
regs.x.bx = fd;
intdos(&regs, &regs);
return oldstate;
}
\f
/*
* The MSDOS routines, called from elsewhere.
*/
int
TerminalAutoFlush() /* MSDOS */
{
return 1;
}
int
TerminalCanRead()
{
return inputExists();
}
/*
* Flush output to the terminal
*/
void
TerminalFlushOutput() /* MSDOS */
{
}
void
TerminalNewMode(fd_in, fd_out, f) /* MSDOS */
int fd_in, fd_out; /* File descriptors */
register int f;
{
union REGS inregs;
struct SREGS segregs;
static old_1b_offset = 0, old_1b_segment = 0;
globalmode = f;
if (MODE_COMMAND_LINE(f)) {
signal(SIGINT, SIG_DFL);
if (old_1b_segment|old_1b_offset) {
inregs.h.ah = 0x25;
inregs.h.al = 0x1b;
inregs.x.dx = old_1b_offset;
segregs.ds = old_1b_segment;
intdosx(&inregs, &inregs, &segregs);
old_1b_segment = old_1b_offset = 0;
}
if (setmode(fd_out, O_TEXT) == -1) {
ExitPerror("setmode (text)", 1);
}
(void) dosbinary(fileno(stdout), 0);
if (setmode(fd_out, O_TEXT) == -1) {
ExitPerror("setmode (text)", 1);
}
(void) dosbinary(fileno(stdin), 0);
} else {
signal(SIGINT, CtrlCInterrupt);
if ((old_1b_segment|old_1b_offset) == 0) {
extern void iret_subr();
void (far *foo_subr)() = iret_subr;
inregs.h.ah = 0x35;
inregs.h.al = 0x1b;
intdosx(&inregs, &inregs, &segregs);
old_1b_segment = segregs.es;
old_1b_offset = inregs.x.bx;
inregs.h.ah = 0x25;
inregs.h.al = 0x1b;
inregs.x.dx = FP_OFF(foo_subr);
segregs.ds = FP_SEG(foo_subr);
intdosx(&inregs, &inregs, &segregs);
}
if (MODE_LOCAL_CHARS(f)) {
if (setmode(fd_out, O_TEXT) == -1) {
ExitPerror("setmode (text)", 1);
}
(void) dosbinary(fileno(stdout), 0);
if (setmode(fd_in, O_TEXT) == -1) {
ExitPerror("setmode (text)", 1);
}
(void) dosbinary(fileno(stdin), 0);
} else {
if (setmode(fd_out, O_BINARY) == -1) {
ExitPerror("setmode (binary)", 1);
}
(void) dosbinary(fileno(stdout), 1);
if (setmode(fd_in, O_BINARY) == -1) {
ExitPerror("setmode (binary)", 1);
}
(void) dosbinary(fileno(stdin), 1);
}
}
}
int
TerminalRead(fd, buffer, count)
int fd;
char *buffer;
int count;
{
int done = 0;
for (;;) {
while (inputExists() && (done < count)) {
*buffer++ = *nextout;
consumechar();
done++;
}
if (done) {
return(done);
} else {
return 0;
}
}
}
void
TerminalSaveState() /* MSDOS */
{
termEofChar = '\4';
termEraseChar = '\10';
termFlushChar = '\17';
termIntChar = '\3';
termKillChar = '\25';
termLiteralNextChar = '\26';
termQuitChar = '\0';;
savedInState = dosbinary(fileno(stdin), 0);
savedOutState = dosbinary(fileno(stdout), 0);
}
int
TerminalSpecialChars(c) /* MSDOS */
{
return 1;
}
void
TerminalRestoreState() /* MSDOS */
{
(void) dosbinary(fileno(stdin), savedInState);
(void) dosbinary(fileno(stdout), savedOutState);
}
int
TerminalWrite(fd, buffer, count) /* MSDOS */
int fd;
char *buffer;
int count;
{
return fwrite(buffer, sizeof (char), count, stdout); /* XXX */
}
int
NetClose(fd)
{
return closesocket(fd);
}
void
NetNonblockingIO(fd, onoff) /* MSDOS */
int
fd,
onoff;
{
if (SetSockOpt(fd, SOL_SOCKET, SO_NONBLOCKING, onoff)) {
perror("setsockop (SO_NONBLOCKING) ");
ExitString(stderr, "exiting\n", 1);
}
}
void
NetSigIO(fd) /* MSDOS */
int fd;
{
}
void
NetSetPgrp(fd) /* MSDOS */
int fd;
{
}
#endif /* defined(MSDOS) */