This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/deps/odoors/ODEmu.c
2017-03-19 07:49:46 +10:00

2213 lines
76 KiB
C

/* OpenDoors Online Software Programming Toolkit
* (C) Copyright 1991 - 1999 by Brian Pirie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* File: ODEmu.c
*
* Description: Code for the TTY/ANSI/AVATAR terminal emulation routines,
* including .ASC/.ANS/.AVT/.RIP file display functions.
*
* Revisions: Date Ver Who Change
* ---------------------------------------------------------------
* Oct 13, 1994 6.00 BP New file header format.
* Oct 21, 1994 6.00 BP Further isolated com routines.
* Dec 09, 1994 6.00 BP Standardized coding style.
* Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
* Jun 07, 1995 6.00 BP Added od_emu_simulate_modem.
* Jul 18, 1995 6.00 BP Fixed warning in call to _ulongdiv().
* Aug 19, 1995 6.00 BP 32-bit portability.
* Nov 11, 1995 6.00 BP Removed register keyword.
* Nov 14, 1995 6.00 BP Added include of odscrn.h.
* Nov 15, 1995 6.00 BP Terminal emulation speed optimization.
* Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
* Dec 12, 1995 6.00 BP Added entry, exit and kernel macros.
* Dec 24, 1995 6.00 BP Use od_connect_speed for modem sim.
* Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
* Jan 21, 1996 6.00 BP Use ODScrnShowMessage().
* Jan 09, 1996 6.00 BP ODComOutbound() returns actual size.
* Feb 19, 1996 6.00 BP Changed version number to 6.00.
* Mar 03, 1996 6.10 BP Begin version 6.10.
* Mar 06, 1996 6.10 BP Prevent TC generated N_LXMUL@ call.
* Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
* Oct 18, 2001 6.11 MD Added od_send_file_section()
* Aug 10, 2003 6.23 SH *nix support
*/
#define BUILDING_OPENDOORS
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include "OpenDoor.h"
#include "ODStr.h"
#include "ODCore.h"
#include "ODGen.h"
#include "ODCom.h"
#include "ODTypes.h"
#include "ODScrn.h"
#include "ODKrnl.h"
#include "ODUtil.h"
/* Manifest constants. */
#define MODEM_SIMULATOR_TICK 54L
#define LEVEL_NONE 0
#define LEVEL_ASCII 1
#define LEVEL_ANSI 2
#define LEVEL_AVATAR 3
#define LEVEL_RIP 4
/* Local helper function prototypes. */
static void ODEmulateFromBuffer(char *pszBuffer, BOOL bRemoteEcho);
static FILE *ODEmulateFindCompatFile(const char *pszBaseName, INT *pnLevel);
static void ODEmulateFillArea(BYTE btLeft, BYTE btTop, BYTE btRight,
BYTE btBottom, char chToFillWith);
/* Current terminal emulator state variables. */
static BYTE btANSISeqLevel = 0;
static INT anANSIParams[10];
static char szCurrentParam[4] = "";
static BYTE btCurrentParamLength;
static BYTE btSavedColumn=1;
static BYTE btSavedRow = 1;
static char szToRepeat[129];
static BYTE btRepeatCount;
static BYTE btAvatarSeqLevel = 0;
static char chPrevParam;
static BYTE btNumParams;
static BYTE btDefaultAttrib = 7;
static BOOL bAvatarInsertMode = FALSE;
static INT8 btScrollLines;
static BYTE btScrollLeft, btScrollTop, btScrollRight, btScrollBottom;
/* Variables for tracking hotkeys while displaying a menu file. */
static char *pszCurrentHotkeys=NULL;
static char chHotkeyPressed;
/* Lookup table to map colors from ANSI values to PC color values. */
static BYTE abtANSIToPCColorTable[8] = {0, 4, 2, 6, 1, 5, 3, 7};
/* ----------------------------------------------------------------------------
* od_hotkey_menu()
*
* Displays a .ASC/.ANS/.AVT/.RIP file, just as od_send_file() does. However,
* unlike od_send_file(), od_hotkey_menu() also allows checks for keypresses
* by the user. If any of the hotkeys listed in pszHotKeys are pressed while
* the file is being displayed, or after the file has finished being displayed,
* od_hotkey_menu() will return this value to the caller. This allows menu
* screens to be easily displayed from on-disk files, while permitting the user
* to choose a menu item at any time.
*
* Parameters: pszFileName - Pointer to the filename to display.
*
* pszHotKeys - Pointer to a string listing the valid keys.
* Keys are not case sensitive.
*
* bWait - If TRUE, od_hotkey_menu() will not return until
* the user presses one of the valid keys. If FALSE,
* then od_hotkey_menu() will return as soon as it
* has finished displaying the file, even if the
* user has not pressed any key;.
*
* Return: The key pressed by the user, or '\0' if no key was pressed.
*/
ODAPIDEF char ODCALL od_hotkey_menu(char *pszFileName, char *pszHotKeys,
BOOL bWait)
{
char chPressed;
/* Log function entry if running in trace mode. */
TRACE(TRACE_API, "od_hotkey_menu()");
/* Ensure that OpenDoors has been initialized. */
if(!bODInitialized) od_init();
OD_API_ENTRY();
if(!pszHotKeys)
{
od_control.od_error = ERR_PARAMETER;
OD_API_EXIT();
return('\0');
}
/* Store pointer to string of hotkeys in global hotkey array for access */
/* from od_send_file(). */
pszCurrentHotkeys = (char *)pszHotKeys;
/* Clear the hotkey status variable. */
chHotkeyPressed = '\0';
/* Display the menu file using od_send_file() primitive. */
if(!od_send_file(pszFileName))
{
OD_API_EXIT();
return('\0');
}
/* Clear the global hotkey array. */
pszCurrentHotkeys = NULL;
/* If the file display was interrupted by the pressing of one of the */
/* hotkeys, return the pressed hotkey immediately. */
if(chHotkeyPressed != '\0')
{
OD_API_EXIT();
return(chHotkeyPressed);
}
/* If no hotkey has been pressed key, and the wait flag has been set, */
/* wait for the user to press a valid hotkey. */
if(bWait)
{
/* Wait for a valid hotkey using the od_get_answer() primitive. */
chPressed = od_get_answer(pszHotKeys);
/* If a remote user is connected on this node. */
if(od_control.baud)
{
/* Clear the outbound buffer. */
ODComClearOutbound(hSerialPort);
}
/* Return the hotkey pressed by the user. */
OD_API_EXIT();
return(chPressed);
}
/* No hotkey has been pressed, so return 0. */
/* (Since 0 is used to terminate the string of valid hotkeys, it can */
/* never be a valid hotkey itself, and is therefore a safe value to */
/* indicate the "no key press" state.) */
OD_API_EXIT();
return(0);
}
/* ----------------------------------------------------------------------------
* od_send_file()
*
* Displays a .ASC/.ANS/.AVT/.RIP file to the local and remote screens. If
* OpenDoors is unable to display the required file format locally, an
* equivalent file that is locally displayable is selected. If no such
* equivalent file can be found, then a message box is displayed, indicating
* that the file is being transmitted to the remote system.
*
* Parameters: pszFileName - The name of the file to send. This parameter may
* explicitly specify the full filename and
* extension, or the extension may be omitted. In the
* case that the extension is omitted, this function
* automatically selects the appropriate file type
* for the current display mode (RIP, ANSI, etc.).
*
* Return: TRUE on success, or FALSE on failure.
*/
ODAPIDEF BOOL ODCALL od_send_file(const char *pszFileName)
{
FILE *pfRemoteFile;
FILE *pfLocalFile = NULL;
BOOL bAnythingLocal = TRUE;
void *pWindow;
INT nFileLevel;
BYTE btCount;
BOOL bPausing;
char chKey;
char *pchParsing;
char szMessage[74];
/* Log function entry if running in trace mode. */
TRACE(TRACE_API, "od_send_file()");
/* Initialize OpenDoors if it hasn't already been done. */
if(!bODInitialized) od_init();
OD_API_ENTRY();
if(!pszFileName)
{
od_control.od_error = ERR_PARAMETER;
OD_API_EXIT();
return(FALSE);
}
/* Initialize local variables. */
btCount = 2;
/* Turn on page pausing, if available. */
bPausing = od_control.od_page_pausing;
/* If operating in auto-filename mode (no extension specified). */
if(strchr(pszFileName, '.') == NULL)
{
/* Begin by searching for a .RIP file. */
nFileLevel = LEVEL_RIP;
/* If no .ASC/.ANS/.AVT/.RIP file. */
if((pfRemoteFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
== NULL)
{
/* Then return with an error. */
od_control.od_error = ERR_FILEOPEN;
OD_API_EXIT();
return(FALSE);
}
/* If the file found was a .RIP. */
if(nFileLevel == LEVEL_RIP)
{
/* Search for file to display locally. */
nFileLevel = LEVEL_AVATAR;
/* No page pausing with .RIP display. */
bPausing = FALSE;
if((pfLocalFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
== NULL)
{
/* If there is no further .ASC/.ANS/.AVT/.RIP files, then no */
/* local display. */
bAnythingLocal = FALSE;
}
}
else if(nFileLevel == LEVEL_NONE)
{
od_control.od_error = ERR_FILEOPEN;
OD_API_EXIT();
return(FALSE);
}
/* Get filename of remote file. */
strcpy(szODWorkString, pszFileName);
strcat(szODWorkString, ".rip");
strupr(szODWorkString);
}
else
{
/* If the full filename was specified, then attempt to open that file. */
if((pfRemoteFile = fopen(pszFileName,"rb")) == NULL)
{
/* If unable to open file, then return. */
od_control.od_error = ERR_FILEOPEN;
OD_API_EXIT();
return(FALSE);
}
strcpy(szODWorkString, pszFileName);
strupr(szODWorkString);
if(strstr(szODWorkString, ".rip"))
{
/* No page pausing during .RIP display. */
bPausing = FALSE;
/* Disable local display. */
bAnythingLocal = FALSE;
}
}
/* Set default colour to grey on black. */
btDefaultAttrib = 0x07;
/* Reset all terminal emulation. */
btAvatarSeqLevel = 0;
btANSISeqLevel = 0;
/* Turn off AVATAR insert mode. */
bAvatarInsertMode = FALSE;
/* Reset [S]top/[P]ause control key status. */
chLastControlKey = 0;
if(!bAnythingLocal)
{
strcpy(szODWorkString, od_control.od_sending_rip);
strcat(szODWorkString, pszFileName);
ODStringCopy(szMessage, szODWorkString, sizeof(szMessage));
pWindow = ODScrnShowMessage(szMessage, 0);
}
/* Loop to display each line in the file(s) with page pausing, etc. */
for(;;)
{
/* Call the OpenDoors kernel routine. */
CALL_KERNEL_IF_NEEDED();
/* If hotkeys are active. */
if(pszCurrentHotkeys != NULL)
{
/* If a key is waiting in buffer. */
while((chKey = (char)tolower(od_get_key(FALSE))) != 0)
{
/* Check for key in hotkey string. */
pchParsing = (char *)pszCurrentHotkeys;
while(*pchParsing)
{
/* If key is found. */
if(tolower(*pchParsing) == chKey)
{
/* Return, indicating that hotkey was pressed. */
chHotkeyPressed = *pchParsing;
goto abort_send;
}
++pchParsing;
}
}
}
/* If a control key has been pressed. */
if(chLastControlKey)
{
switch(chLastControlKey)
{
/* If it was a stop control key. */
case 's':
if(od_control.od_list_stop)
{
/* If enabled, clear keyboard buffer. */
abort_send:
/* If operating in remote mode. */
if(od_control.baud)
{
/* Clear the outbound FOSSIL buffer. */
ODComClearOutbound(hSerialPort);
}
/* Return from function. */
goto end_transmission;
}
break;
/* If control key was "pause". */
case 'p':
/* If pause is enabled. */
if(od_control.od_list_pause)
{
/* Clear keyboard buffer. */
od_clear_keybuffer();
/* Wait for any keypress. */
od_get_key(TRUE);
}
}
/* Clear control key status. */
chLastControlKey = 0;
}
/* Get next line, if any. */
if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile) == NULL)
{
/* If different local file. */
if(pfLocalFile)
{
/* Display rest of it. */
while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile))
{
/* Pass each line to terminal emulator. */
ODEmulateFromBuffer(szODWorkString, FALSE);
}
}
/* Return from od_send_file(). */
goto end_transmission;
}
/* Set parsepos = last char in globworkstr. */
pchParsing = (char *)&szODWorkString;
while(*++pchParsing) ;
--pchParsing;
/* Check for end of page state. */
if((*pchParsing == '\r' || *pchParsing == '\n') &&
++btCount >= od_control.user_screen_length && bPausing)
{
/* Display page pause prompt. */
if(ODPagePrompt(&bPausing))
{
/* If user chose to abort, then return from od_send_file(). */
goto end_transmission;
}
/* Reset line count. */
btCount = 2;
}
/* If the file is also to be displayed locally. */
if(bAnythingLocal)
{
/* If the local file is different from the remote file, then obtain */
/* the next line from the local file. */
if(pfLocalFile)
{
od_disp(szODWorkString, strlen(szODWorkString), FALSE);
if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile) == NULL)
{
while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile))
{
od_disp(szODWorkString, strlen(szODWorkString), FALSE);
}
/* Return from od_send_file(). */
goto end_transmission;
}
ODEmulateFromBuffer(szODWorkString, FALSE);
}
else
{
/* Pass the string through the local terminal emulation */
/* system, and send a copy to the remote system. */
if(od_control.od_no_ra_codes)
{
ODEmulateFromBuffer(szODWorkString, FALSE);
od_disp(szODWorkString, strlen(szODWorkString), FALSE);
}
else
{
ODEmulateFromBuffer(szODWorkString,TRUE);
}
}
}
else
{
/* If the file is not being displayed locally, then just send the */
/* entire line to the remote system (if any). */
od_disp(szODWorkString,strlen(szODWorkString),FALSE);
}
}
end_transmission:
/* Close remote file. */
fclose(pfRemoteFile);
/* If there is a different local file, then close it too. */
if(pfLocalFile)
{
fclose(pfLocalFile);
}
/* If we are not displaying anything on the local system. */
if(!bAnythingLocal)
{
/* Wait while file is being sent. */
if(od_control.baud != 0)
{
int nOutboundSize;
do
{
CALL_KERNEL_IF_NEEDED();
ODComOutbound(hSerialPort, &nOutboundSize);
} while(nOutboundSize != 0);
}
/* Get rid of the window. */
ODScrnRemoveMessage(pWindow);
}
OD_API_EXIT();
return(TRUE);
}
/* ----------------------------------------------------------------------------
* od_send_file_section()
*
* Displays a .ASC/.ANS/.AVT/.RIP multi-section file to the local and remote
* screens. If OpenDoors is unable to display the required file format locally,
* an equivalent file that is locally displayable is selected. If no such
* equivalent file can be found, then a message box is displayed, incdicating
* that the file is being transmitted to the remote system.
*
* Note: This function works virtually identical to od_send_file() except it
* checks for the section headers (if found).
*
* Parameters: pszFileName - The name of the file to send. This parameter may
* explicitly specify the full filename and
* extension, or the extension may be omitted. In the
* case that the extension is omitted, this function
* automatically selects the appropriate file type
* for the current display mode (RIP, ANSI, etc.).
* pszSectionname - Name of the section in which to send. This
* parameter must include only the section name
* and not the @# delimiter.
*
* Return: TRUE on success, or FALSE on failure.
*/
ODAPIDEF BOOL ODCALL od_send_file_section(char *pszFileName, char *pszSectionName)
{
FILE *pfRemoteFile;
FILE *pfLocalFile = NULL;
BOOL bAnythingLocal = TRUE;
void *pWindow;
INT nFileLevel;
BYTE btCount;
BOOL bPausing;
char chKey;
char *pchParsing;
char szMessage[74];
char szFullSectionName[256];
BOOL bSectionFound = FALSE;
UINT uSectionNameLength;
/* Log function entry if running in trace mode. */
TRACE(TRACE_API, "od_send_file_section()");
/* Initialize OpenDoors if it hasn't already been done. */
if(!bODInitialized) od_init();
OD_API_ENTRY();
if(!pszFileName || !pszSectionName)
{
od_control.od_error = ERR_PARAMETER;
OD_API_EXIT();
return(FALSE);
}
/* Initialize local variables. */
btCount = 2;
/* Turn on page pausing, if available. */
bPausing = od_control.od_page_pausing;
/* If operating in auto-filename mode (no extension specified). */
if(strchr(pszFileName, '.') == NULL)
{
/* Begin by searching for a .RIP file. */
nFileLevel = LEVEL_RIP;
/* If no .ASC/.ANS/.AVT/.RIP file. */
if((pfRemoteFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
== NULL)
{
/* Then return with an error. */
od_control.od_error = ERR_FILEOPEN;
OD_API_EXIT();
return(FALSE);
}
/* If the file found was a .RIP. */
if(nFileLevel == LEVEL_RIP)
{
/* Search for file to display locally. */
nFileLevel = LEVEL_AVATAR;
/* No page pausing with .RIP display. */
bPausing = FALSE;
if((pfLocalFile = ODEmulateFindCompatFile(pszFileName, &nFileLevel))
== NULL)
{
/* If there is no further .ASC/.ANS/.AVT/.RIP files, then no */
/* local display. */
bAnythingLocal = FALSE;
}
}
else if(nFileLevel == LEVEL_NONE)
{
od_control.od_error = ERR_FILEOPEN;
OD_API_EXIT();
return(FALSE);
}
/* Get filename of remote file. */
strcpy(szODWorkString, pszFileName);
strcat(szODWorkString, ".rip");
strupr(szODWorkString);
}
else
{
/* If the full filename was specified, then attempt to open that file. */
if((pfRemoteFile = fopen(pszFileName,"rb")) == NULL)
{
/* If unable to open file, then return. */
od_control.od_error = ERR_FILEOPEN;
OD_API_EXIT();
return(FALSE);
}
strcpy(szODWorkString, pszFileName);
strupr(szODWorkString);
if(strstr(szODWorkString, ".rip"))
{
/* No page pausing during .RIP display. */
bPausing = FALSE;
/* Disable local display. */
bAnythingLocal = FALSE;
}
}
/* Set default colour to grey on black. */
btDefaultAttrib = 0x07;
/* Reset all terminal emulation. */
btAvatarSeqLevel = 0;
btANSISeqLevel = 0;
/* Turn off AVATAR insert mode. */
bAvatarInsertMode = FALSE;
/* Reset [S]top/[P]ause control key status. */
chLastControlKey = 0;
if(!bAnythingLocal)
{
strcpy(szODWorkString, od_control.od_sending_rip);
strcat(szODWorkString, pszFileName);
ODStringCopy(szMessage, szODWorkString, sizeof(szMessage));
pWindow = ODScrnShowMessage(szMessage, 0);
}
/* Create section name information */
strcpy(szFullSectionName, "@#");
strncat(szFullSectionName, pszSectionName, 254);
/* Get the length of the section name in it's full form */
uSectionNameLength = strlen(szFullSectionName);
/* Loop to display each line in the file(s) with page pausing, etc. */
for(;;)
{
/* Call the OpenDoors kernel routine. */
CALL_KERNEL_IF_NEEDED();
/* If hotkeys are active. */
if(pszCurrentHotkeys != NULL)
{
/* If a key is waiting in buffer. */
while((chKey = (char)tolower(od_get_key(FALSE))) != 0)
{
/* Check for key in hotkey string. */
pchParsing = (char *)pszCurrentHotkeys;
while(*pchParsing)
{
/* If key is found. */
if(tolower(*pchParsing) == chKey)
{
/* Return, indicating that hotkey was pressed. */
chHotkeyPressed = *pchParsing;
goto abort_send;
}
++pchParsing;
}
}
}
/* If a control key has been pressed. */
if(chLastControlKey)
{
switch(chLastControlKey)
{
/* If it was a stop control key. */
case 's':
if(od_control.od_list_stop)
{
/* If enabled, clear keyboard buffer. */
abort_send:
/* If operating in remote mode. */
if(od_control.baud)
{
/* Clear the outbound FOSSIL buffer. */
ODComClearOutbound(hSerialPort);
}
/* Return from function. */
goto end_transmission;
}
break;
/* If control key was "pause". */
case 'p':
/* If pause is enabled. */
if(od_control.od_list_pause)
{
/* Clear keyboard buffer. */
od_clear_keybuffer();
/* Wait for any keypress. */
od_get_key(TRUE);
}
}
/* Clear control key status. */
chLastControlKey = 0;
}
/* Get next line, if any. */
if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile) == NULL)
{
/* If different local file. */
if(pfLocalFile)
{
/* Display rest of it. */
while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile))
{
if (!bSectionFound && strncmp(szFullSectionName, szODWorkString, uSectionNameLength) == 0)
{
/* Section Found, allow all lines up to EOF or new section to be displayed */
bSectionFound = TRUE;
/* Read next line, ignore the section line */
continue;
}
else if (!bSectionFound)
{
/* Section not found yet, continue loop */
continue;
}
else if (bSectionFound && strncmp(szODWorkString, "@#", 2) == 0)
{
/* New Section Intercepted */
goto end_transmission;
}
/* Pass each line to terminal emulator. */
ODEmulateFromBuffer(szODWorkString, FALSE);
}
}
/* Return from od_send_file(). */
goto end_transmission;
}
/* Check for section header @# + pszSectionName */
if (!bSectionFound && strncmp(szFullSectionName, szODWorkString, uSectionNameLength) == 0)
{
/* Flag the section as found */
bSectionFound = TRUE;
/* Read next line, ignore section line */
continue;
}
else if (!bSectionFound)
{
/* Section hasn't been found yet */
continue;
}
else if (bSectionFound && strncmp(szODWorkString, "@#", 2) == 0)
{
/* New section found, terminate send */
goto end_transmission;
}
/* Set parsepos = last char in globworkstr. */
pchParsing = (char *)&szODWorkString;
while(*++pchParsing) ;
--pchParsing;
/* Check for end of page state. */
if((*pchParsing == '\r' || *pchParsing == '\n') &&
++btCount >= od_control.user_screen_length && bPausing)
{
/* Display page pause prompt. */
if(ODPagePrompt(&bPausing))
{
/* If user chose to abort, then return from od_send_file(). */
goto end_transmission;
}
/* Reset line count. */
btCount = 2;
}
/* If the file is also to be displayed locally. */
if(bAnythingLocal)
{
/* If the local file is different from the remote file, then obtain */
/* the next line from the local file. */
if(pfLocalFile)
{
od_disp(szODWorkString, strlen(szODWorkString), FALSE);
if(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfLocalFile) == NULL)
{
while(fgets(szODWorkString, OD_GLOBAL_WORK_STRING_SIZE-1, pfRemoteFile))
{
od_disp(szODWorkString, strlen(szODWorkString), FALSE);
}
/* Return from od_send_file(). */
goto end_transmission;
}
ODEmulateFromBuffer(szODWorkString, FALSE);
}
else
{
/* Pass the string through the local terminal emulation */
/* system, and send a copy to the remote system. */
if(od_control.od_no_ra_codes)
{
ODEmulateFromBuffer(szODWorkString, FALSE);
od_disp(szODWorkString, strlen(szODWorkString), FALSE);
}
else
{
ODEmulateFromBuffer(szODWorkString,TRUE);
}
}
}
else
{
/* If the file is not being displayed locally, then just send the */
/* entire line to the remote system (if any). */
od_disp(szODWorkString,strlen(szODWorkString),FALSE);
}
}
end_transmission:
/* Close remote file. */
fclose(pfRemoteFile);
/* If there is a different local file, then close it too. */
if(pfLocalFile)
{
fclose(pfLocalFile);
}
/* If we are not displaying anything on the local system. */
if(!bAnythingLocal)
{
/* Wait while file is being sent. */
if(od_control.baud != 0)
{
int nOutboundSize;
do
{
CALL_KERNEL_IF_NEEDED();
ODComOutbound(hSerialPort, &nOutboundSize);
} while(nOutboundSize != 0);
}
/* Get rid of the window. */
ODScrnRemoveMessage(pWindow);
}
/* If the section was not found, return FALSE for error */
if (!bSectionFound)
{
OD_API_EXIT();
return (FALSE);
}
OD_API_EXIT();
return(TRUE);
}
/* ----------------------------------------------------------------------------
* ODEmulateFindCompatFile() *** PRIVATE FUNCTION ***
*
* Searches for an .ASC/.ANS/.AVT/.RIP file that is compatible with the
* specified display capabilities level.
*
* Parameters: pszBaseName - Base filename to use.
*
* pnLevel - Highest file level to search for. This value is
* updated to indicate the type of file found.
*
* Return: A pointer to a now-open file of the required type, or NULL if
* no match was found.
*/
static FILE *ODEmulateFindCompatFile(const char *pszBaseName, INT *pnLevel)
{
FILE *pfCompatibleFile;
ASSERT(pszBaseName != NULL);
ASSERT(pnLevel != NULL);
ASSERT(*pnLevel >= 0 && *pnLevel <= 4);
/* Loop though .RIP/.AVT/.ANS/.ASC extensions. */
for(;*pnLevel > LEVEL_NONE; --*pnLevel)
{
/* Get base-filename passed in. */
strcpy(szODWorkString, pszBaseName);
/* Try current extension. */
switch(*pnLevel)
{
case LEVEL_RIP:
if(!od_control.user_rip) continue;
strcat(szODWorkString, ".rip");
break;
case LEVEL_AVATAR:
if(!od_control.user_avatar) continue;
strcat(szODWorkString, ".avt");
break;
case LEVEL_ANSI:
if(!od_control.user_ansi) continue;
strcat(szODWorkString, ".ans");
break;
case LEVEL_ASCII:
strcat(szODWorkString, ".asc");
break;
}
/* If we are able to open this file, then return a pointer to */
/* the file. */
if((pfCompatibleFile = fopen(szODWorkString,"rb")) != NULL)
return(pfCompatibleFile);
}
/* Return NULL if no file was found. */
return(NULL);
}
/* ----------------------------------------------------------------------------
* od_disp_emu()
*
* Sends an entire string to both local and remote systems. The characters
* displayed locally are fed through the local terminal emulation sub-system,
* allowing aribtrary ANSI/AVATAR control sequences to be displayed both
* locally and remotely.
*
* Parameters: pszToDisplay - Pointer to string to display.
*
* bRemoteEcho - TRUE if characters should also be transmitted
* to the remote system.
*
* Return: void
*/
ODAPIDEF void ODCALL od_disp_emu(const char *pszToDisplay, BOOL bRemoteEcho)
{
BOOL bTranslateRemote;
/* Log function entry if running in trace mode. */
TRACE(TRACE_API, "od_disp_emu()");
/* Ensure that OpenDoors has been initialized. */
if(!bODInitialized) od_init();
OD_API_ENTRY();
/* Send pszToDisplay to remote system. */
if(bRemoteEcho)
{
if(od_control.od_no_ra_codes)
{
od_disp(pszToDisplay, strlen(pszToDisplay), FALSE);
bTranslateRemote = FALSE;
}
else
{
bTranslateRemote = TRUE;
}
}
else
{
bTranslateRemote = FALSE;
}
/* Pass string to be emulated to local terminal emulation function. */
ODEmulateFromBuffer(pszToDisplay, bTranslateRemote);
OD_API_EXIT();
}
/* ----------------------------------------------------------------------------
* od_emulate()
*
* Sends a single character to both local and remote systems. The characters
* displayed locally are fed through the local terminal emulation sub-system,
* allowing aribtrary ANSII/AVATAR control sequences to be displayed both
* locally and remotely.
*
* Parameters: chToEmulate - Character to feed through the terminal emulator.
*
* Return: void
*/
ODAPIDEF void ODCALL od_emulate(char chToEmulate)
{
static char szBuffer[2];
*szBuffer = chToEmulate;
/* Log function entry if running in trace mode. */
TRACE(TRACE_API, "od_emulate()");
/* Ensure that OpenDoors has been initialized. */
if(!bODInitialized) od_init();
OD_API_ENTRY();
/* Pass character to be emulated to local terminal emulation function. */
ODEmulateFromBuffer(szBuffer, TRUE);
OD_API_EXIT();
}
/* ----------------------------------------------------------------------------
* ODEmulateFromBuffer() *** PRIVATE FUNCTION ***
*
* Displays a string on the local screen, interpreting any terminal emulation
* control sequences. The string may also be sent to the remote system at the
* same time.
*
* Parameters: pszBuffer - Pointer to the string to transmit.
*
* bRemoteEcho - TRUE if string should also be sent to the remote
* system, FALSE if it should not be.
*
* Return: void
*/
static void ODEmulateFromBuffer(char *pszBuffer, BOOL bRemoteEcho)
{
char chCurrent;
static tODScrnTextInfo TextInfo;
INT nTemp;
BOOL bEchoThisChar;
INT nCharsPerTick;
INT nCharsThisTick;
tODTimer ModemSimTimer;
ASSERT(pszBuffer != NULL);
/* If we should simulate modem transmission speed. */
if(od_control.od_emu_simulate_modem)
{
DWORD lCharsPerSecond;
/* Determine character per second rate to simulate. */
if(od_control.baud == 0)
{
lCharsPerSecond = 960L;
}
else
{
ODDWordDivide(&lCharsPerSecond, (DWORD *)NULL,
od_control.od_connect_speed, 10L);
}
/* Determine number of characters to send per timer tick. */
lCharsPerSecond = ODDWordMultiply(lCharsPerSecond, MODEM_SIMULATOR_TICK);
ODDWordDivide(&lCharsPerSecond, (DWORD *)NULL, lCharsPerSecond, 1000L);
nCharsPerTick = (INT)lCharsPerSecond;
/* Start tick timer. */
ODTimerStart(&ModemSimTimer, MODEM_SIMULATOR_TICK);
/* Reset number of characters that we have sent during this tick. */
nCharsThisTick = 0;
}
while(*pszBuffer)
{
/* Read the next character from the buffer into local variable for */
/* access speed efficiency. */
chCurrent = *pszBuffer;
/* If we should simulate modem transmission speed. */
if(od_control.od_emu_simulate_modem)
{
/* If we have now sent all of the characters that should be sent */
/* during this tick. */
if(nCharsThisTick++ >= nCharsPerTick)
{
/* Wait for timer to elapse. */
ODTimerWaitForElapse(&ModemSimTimer);
/* Restart tick timer. */
ODTimerStart(&ModemSimTimer, MODEM_SIMULATOR_TICK);
/* Reset characters sent in this tick. */
nCharsThisTick = 0;
}
}
bEchoThisChar = bRemoteEcho;
/* Switch according to ANSI emulator state. */
switch(btANSISeqLevel)
{
/* If we are not in the middle of an ANSI command string. */
case 0:
/* Switch according to current character. */
switch(chCurrent)
{
/* If this is the escape character. */
case 27:
/* If we are not in the middle of an AVATAR sequence. */
if(btAvatarSeqLevel == 0)
{
/* Then treat this as the start an ANSI sequence. */
btANSISeqLevel = 1;
break;
}
/* Deliberate fallthrough to default case. */
/* If not start of an ANSI sequence. */
default:
/* Check our position in AVATAR sequence. */
switch(btAvatarSeqLevel)
{
/* If not in middle of an AVATAR command. */
case 0:
/* Check the character we've been sent. */
switch(chCurrent)
{
/* Check for QBBS/RA pause for keypress code. */
case 0x01:
if(od_control.od_no_ra_codes)
{
goto output_next_char;
}
/* Wait for user to press [ENTER] key. */
od_get_answer("\n\r");
bEchoThisChar = FALSE;
break;
/* QBBS/RA ^F user parameters. */
case 0x06:
if(od_control.od_no_ra_codes)
{
goto output_next_char;
}
btAvatarSeqLevel = 21;
bEchoThisChar = FALSE;
break;
/* QBBS/RA ^K user parameters. */
case 0x0b:
if(od_control.od_no_ra_codes)
{
goto output_next_char;
}
btAvatarSeqLevel = 22;
bEchoThisChar = FALSE;
break;
case 0x0c:
bAvatarInsertMode = FALSE;
ODScrnSetAttribute((BYTE)(
od_control.od_cur_attrib = btDefaultAttrib));
ODScrnClear();
break;
case 0x19:
bAvatarInsertMode = FALSE;
btAvatarSeqLevel = 1;
break;
case 0x16: /* ^V */
btAvatarSeqLevel = 3;
break;
default:
output_next_char:
/* Output next character. */
if(bAvatarInsertMode)
{
ODScrnGetTextInfo(&TextInfo);
if(TextInfo.curx < 80)
{
ODScrnCopyText(TextInfo.curx,
TextInfo.cury, 79, TextInfo.cury,
(BYTE)(TextInfo.curx + 1),
TextInfo.cury);
}
ODScrnDisplayChar(chCurrent);
}
else
{
ODScrnDisplayChar(chCurrent);
}
}
break;
case 1:
bAvatarInsertMode = FALSE;
chPrevParam = chCurrent;
btAvatarSeqLevel = 2;
break;
case 2:
for(nTemp = 0; nTemp < (INT)chCurrent;
++nTemp)
{
ODScrnDisplayChar(chPrevParam);
}
btAvatarSeqLevel = 0;
break;
case 3:
switch(chCurrent)
{
case 0x01:
bAvatarInsertMode = FALSE;
btAvatarSeqLevel = 4;
break;
case 0x02:
bAvatarInsertMode = FALSE;
ODScrnGetTextInfo(&TextInfo);
ODScrnSetAttribute((BYTE)
(od_control.od_cur_attrib =
TextInfo.attribute | 0x80));
btAvatarSeqLevel = 0;
break;
case 0x03:
bAvatarInsertMode = FALSE;
ODScrnGetTextInfo(&TextInfo);
if(TextInfo.cury > 1)
{
ODScrnSetCursorPos(TextInfo.curx,
(BYTE)(TextInfo.cury - 1));
}
btAvatarSeqLevel = 0;
break;
case 0x04:
bAvatarInsertMode = FALSE;
ODScrnGetTextInfo(&TextInfo);
if(TextInfo.cury < 25)
{
ODScrnSetCursorPos(TextInfo.curx,
(BYTE)(TextInfo.cury + 1));
}
btAvatarSeqLevel = 0;
break;
case 0x05:
bAvatarInsertMode = FALSE;
ODScrnGetTextInfo(&TextInfo);
if(TextInfo.curx > 1)
{
ODScrnSetCursorPos((BYTE)(TextInfo.curx - 1),
TextInfo.cury);
}
btAvatarSeqLevel = 0;
break;
case 0x06:
bAvatarInsertMode = FALSE;
ODScrnGetTextInfo(&TextInfo);
if(TextInfo.curx < 80)
{
ODScrnSetCursorPos((BYTE)(TextInfo.curx + 1),
TextInfo.cury);
}
btAvatarSeqLevel = 0;
break;
case 0x07:
bAvatarInsertMode = FALSE;
ODScrnClearToEndOfLine();
btAvatarSeqLevel = 0;
break;
case 0x08:
bAvatarInsertMode = FALSE;
btAvatarSeqLevel = 5;
break;
case 0x09: /* ^I */
bAvatarInsertMode = TRUE;
btAvatarSeqLevel = 0;
break;
case 0x0a: /* ^J */
btScrollLines = -1;
btAvatarSeqLevel = 7;
break;
case 0x0b: /* ^K */
btScrollLines = 1;
btAvatarSeqLevel = 7;
break;
case 0x0c: /* ^L */
btAvatarSeqLevel = 14;
break;
case 0x0d: /* ^M */
btAvatarSeqLevel = 15;
break;
case 0x0e: /* ^N */
ODScrnGetTextInfo(&TextInfo);
if(TextInfo.curx < 80)
{
ODScrnCopyText((BYTE)(TextInfo.curx + 1),
TextInfo.cury, 80, TextInfo.cury,
TextInfo.curx, TextInfo.cury);
}
ODScrnEnableScrolling(FALSE);
ODScrnSetCursorPos(80, TextInfo.cury);
ODScrnDisplayChar(' ');
ODScrnEnableScrolling(TRUE);
ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury);
btAvatarSeqLevel = 0;
break;
case 0x19: /* ^Y */
btAvatarSeqLevel = 19;
break;
default:
btAvatarSeqLevel = 0;
}
break;
case 4:
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= chCurrent));
btAvatarSeqLevel = 0;
break;
case 5:
chPrevParam = chCurrent;
btAvatarSeqLevel = 6;
break;
case 6:
ODScrnSetCursorPos(chCurrent, chPrevParam);
btAvatarSeqLevel = 0;
break;
case 7:
if(btScrollLines < 1)
{
btScrollLines = chCurrent;
}
else
{
btScrollLines = -chCurrent;
}
btAvatarSeqLevel = 8;
break;
case 8:
btScrollTop = chCurrent;
btAvatarSeqLevel = 9;
break;
case 9:
btScrollLeft = chCurrent;
btAvatarSeqLevel = 10;
break;
case 10:
btScrollBottom = chCurrent;
btAvatarSeqLevel = 11;
break;
case 11:
btScrollRight = chCurrent;
btAvatarSeqLevel = 12;
break;
case 12:
if(btScrollLines == 0
|| abs(btScrollLines) >
(btScrollBottom - btScrollTop))
{
ODEmulateFillArea(btScrollLeft, btScrollTop,
btScrollRight, btScrollBottom, ' ');
}
else if(btScrollLines < 0)
{
ODScrnCopyText(btScrollLeft, btScrollTop,
btScrollRight,
(BYTE)(btScrollBottom + btScrollLines),
btScrollLeft,
(BYTE)(btScrollTop - btScrollLines));
ODEmulateFillArea(btScrollLeft, btScrollTop,
btScrollRight,
(BYTE)(btScrollTop - (btScrollLines - 1)), ' ');
}
else
{
ODScrnCopyText(btScrollLeft,
(BYTE)(btScrollTop + btScrollLines),
btScrollRight, btScrollBottom,
btScrollLeft, btScrollTop);
ODEmulateFillArea(btScrollLeft,
(BYTE)(btScrollBottom - (btScrollLines - 1)),
btScrollRight, btScrollBottom, ' ');
}
btAvatarSeqLevel = 0;
break;
case 14:
btScrollLines = (chCurrent & 0x7f);
btScrollRight = ' ';
btAvatarSeqLevel = 17;
break;
case 15:
btScrollLines = (chCurrent & 0x7f);
btAvatarSeqLevel = 16;
break;
case 16:
btScrollRight = chCurrent;
btAvatarSeqLevel = 17;
break;
case 17:
btScrollTop = chCurrent;
btAvatarSeqLevel = 18;
break;
case 18:
ODScrnGetTextInfo(&TextInfo);
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= btScrollLines));
ODEmulateFillArea(TextInfo.curx, TextInfo.cury,
(BYTE)(TextInfo.curx + chCurrent),
(BYTE)(TextInfo.cury + btScrollTop), btScrollRight);
btAvatarSeqLevel = 0;
break;
case 19:
btScrollLines = (chCurrent & 0x7f);
szToRepeat[btRepeatCount = 0] = '\0';
btAvatarSeqLevel = 20;
break;
case 20:
if(btRepeatCount < btScrollLines)
{
szToRepeat[btRepeatCount] = chCurrent;
szToRepeat[++btRepeatCount] = '\0';
}
else
{
for(btRepeatCount = 0; btRepeatCount <
(BYTE)chCurrent;++btRepeatCount)
{
ODScrnDisplayString(szToRepeat);
}
btAvatarSeqLevel = 0;
}
break;
/* RA/QBBS ^F control codes. */
case 21:
bEchoThisChar = FALSE;
switch(chCurrent)
{
case 'A':
od_disp_str(od_control.user_name);
break;
case 'B':
od_disp_str(od_control.user_location);
break;
case 'C':
od_disp_str(od_control.user_password);
break;
case 'D':
od_disp_str(od_control.user_dataphone);
break;
case 'E':
od_disp_str(od_control.user_homephone);
break;
case 'F':
od_disp_str(od_control.user_lastdate);
break;
case 'G':
od_disp_str(od_control.user_lasttime);
break;
case 'H':
btScrollLines = 0;
goto show_flags;
case 'I':
btScrollLines = 1;
goto show_flags;
case 'J':
btScrollLines = 2;
goto show_flags;
case 'K':
btScrollLines = 3;
show_flags: for(btRepeatCount = 0; btRepeatCount < 8;
++btRepeatCount)
{
if((od_control.user_flags[btScrollLines] >>
btRepeatCount) & 0x01)
{
szToRepeat[btRepeatCount] = 'X';
}
else
{
szToRepeat[btRepeatCount] = '-';
}
}
szToRepeat[btRepeatCount] = '\0';
od_disp_str(szToRepeat);
break;
case 'L':
od_printf("%lu", od_control.user_net_credit);
break;
case 'M':
od_printf("%u", od_control.user_messages);
break;
case 'N':
od_printf("%u", od_control.user_lastread);
break;
case 'O':
od_printf("%u", od_control.user_security);
break;
case 'P':
od_printf("%u", od_control.user_numcalls);
break;
case 'Q':
od_printf("%ul", od_control.user_uploads);
break;
case 'R':
od_printf("%ul", od_control.user_upk);
break;
case 'S':
od_printf("%ul", od_control.user_downloads);
break;
case 'T':
od_printf("%ul", od_control.user_downk);
break;
case 'U':
od_printf("%d", od_control.user_time_used);
break;
case 'V':
od_printf("%d", od_control.user_screen_length);
break;
case 'W':
btRepeatCount = 0;
while(od_control.user_name[btRepeatCount])
{
if((szToRepeat[btRepeatCount]
= od_control.user_name[btRepeatCount])
== ' ')
{
szToRepeat[btRepeatCount] = '\0';
break;
}
++btRepeatCount;
}
od_disp_str(szToRepeat);
break;
case 'X':
if(od_control.user_ansi)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
break;
case 'Y':
if(od_control.user_attribute & 0x04)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
break;
case 'Z':
if(od_control.user_attribute & 0x02)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
break;
case '0':
if(od_control.user_attribute & 0x40)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
break;
case '1':
if(od_control.user_attribute & 0x80)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
break;
case '2':
if(od_control.user_attrib2 & 0x01)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
break;
case '3':
od_disp_str(od_control.user_handle);
break;
case '4':
od_disp_str(od_control.user_firstcall);
break;
case '5':
od_disp_str(od_control.user_birthday);
break;
case '6':
od_disp_str(od_control.user_subdate);
break;
case '7':
/* days until subscrption expiry */
break;
case '8':
if(od_control.user_attrib2 & 0x02)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
break;
case '9':
od_printf("%lu:%lu",
od_control.user_uploads,
od_control.user_downloads);
break;
case ':':
od_printf("%lu:%lu",
od_control.user_upk,
od_control.user_downk);
break;
case ';':
if(od_control.user_attrib2 & 0x04)
{
od_disp_str("ON");
}
else
{
od_disp_str("OFF");
}
}
btAvatarSeqLevel=0;
break;
/* QBBS/RA ^K control codes. */
case 22:
bEchoThisChar = FALSE;
switch(chCurrent)
{
case 'A':
od_printf("%lu", od_control.system_calls);
break;
case 'B':
od_disp_str(od_control.system_last_caller);
break;
case 'C':
/* number of active messages */
break;
case 'D':
/* system starting message number */
break;
case 'E':
/* system ending message number */
break;
case 'F':
/* number of times user has paged sysop */
break;
case 'G':
/* day of the week (Monday, Tuesday, etc.) */
break;
case 'H':
/* number of users in user file */
break;
case 'I':
/* Time in 24 hour format */
break;
case 'J':
/* today's date */
break;
case 'K':
/* minutes connected this call */
break;
case 'L':
/* Seconds connected (0) */
break;
case 'M':
od_printf("%d", od_control.user_time_used);
break;
case 'N':
od_disp_str("00");
break;
case 'O':
/* Minutes remaining today */
od_printf("%d", od_control.user_timelimit);
break;
case 'P':
/* seconds remaining today (0) */
break;
case 'Q':
od_printf("0", od_control.user_timelimit);
break;
case 'R': /* current baud rate */
od_printf("0", od_control.baud);
break;
case 'S':
/* day of the week (MON, TUE) */
break;
case 'T':
/* Daily download limit (in K) */
break;
case 'U':
/* Minutes until next system event */
break;
case 'V':
ODScrnDisplayString(od_control.event_starttime);
break;
case 'W':
/* line number (from command line) */
break;
case 'X':
od_exit(2, TRUE);
break;
case 'Y':
/* Name of current msg area */
break;
case 'Z':
/* name of current file area */
break;
case '0':
/* # of messages in area */
break;
case '1':
/* # of message area */
break;
case '2':
/* # of file area */
break;
}
btAvatarSeqLevel = 0;
}
}
break;
case 1:
switch(chCurrent)
{
case '[':
btANSISeqLevel = 2;
btCurrentParamLength = 0;
btNumParams = 0;
break;
default:
btANSISeqLevel = 0;
ODScrnDisplayChar(27);
ODScrnDisplayChar(chCurrent);
}
break;
default:
if((chCurrent >= '0' && chCurrent <= '9') || chCurrent == '?')
{
if(btCurrentParamLength < 3)
{
szCurrentParam[btCurrentParamLength] = chCurrent;
szCurrentParam[++btCurrentParamLength] = '\0';
}
else
{
btANSISeqLevel = 0;
}
}
else if(chCurrent == ';')
{
if(btNumParams < 10)
{
if(btCurrentParamLength != 0)
{
if(strcmp(szCurrentParam, "?9") == 0)
{
anANSIParams[btNumParams] = -2;
}
else
{
anANSIParams[btNumParams] = atoi(szCurrentParam);
}
szCurrentParam[0] = '\0';
btCurrentParamLength = 0;
++btNumParams;
}
else
{
anANSIParams[btNumParams++] = -1;
}
}
else
{
btANSISeqLevel = 0;
}
}
else
{
btANSISeqLevel = 0;
if(btCurrentParamLength != 0 && btNumParams < 10)
{
if(strcmp(szCurrentParam,"?9") == 0)
{
anANSIParams[btNumParams] = -2;
}
else
{
anANSIParams[btNumParams] = atoi(szCurrentParam);
}
szCurrentParam[0] = '\0';
btCurrentParamLength = 0;
++btNumParams;
}
ODScrnGetTextInfo(&TextInfo);
switch(chCurrent)
{
case 'A':
if(btNumParams == 0) anANSIParams[0] = 1;
if((nTemp = TextInfo.cury - anANSIParams[0]) < 1)
{
nTemp = 1;
}
if(nTemp > 25) nTemp=25;
ODScrnSetCursorPos(TextInfo.curx, (BYTE)nTemp);
break;
case 'B':
if(btNumParams == 0) anANSIParams[0] = 1;
if((nTemp = TextInfo.cury + anANSIParams[0]) > 25)
{
nTemp = 25;
}
if(nTemp < 1) nTemp = 1;
ODScrnSetCursorPos(TextInfo.curx, (BYTE)nTemp);
break;
case 'C':
if(btNumParams == 0) anANSIParams[0] = 1;
if((nTemp=TextInfo.curx + anANSIParams[0]) > 80)
{
nTemp = 80;
}
if(nTemp < 1) nTemp = 1;
ODScrnSetCursorPos((BYTE)nTemp, TextInfo.cury);
break;
case 'D':
if(btNumParams == 0) anANSIParams[0] = 1;
if((nTemp = TextInfo.curx - anANSIParams[0]) < 1)
{
nTemp = 1;
}
if(nTemp > 80) nTemp = 80;
ODScrnSetCursorPos((BYTE)nTemp, TextInfo.cury);
break;
case 'H':
case 'f':
if(btNumParams >= 2)
{
if(anANSIParams[0] == -1)
{
ODScrnSetCursorPos((BYTE)anANSIParams[1], 1);
}
else
{
ODScrnSetCursorPos((BYTE)anANSIParams[1],
(BYTE)anANSIParams[0]);
}
}
else if(btNumParams == 1)
{
if(anANSIParams[0] <= 0)
{
ODScrnSetCursorPos(1, TextInfo.cury);
}
else
{
ODScrnSetCursorPos(1, (BYTE)anANSIParams[0]);
}
}
else /* if(num_params==0) */
{
ODScrnSetCursorPos(1, 1);
}
break;
case 'J':
if(btNumParams >= 1 && anANSIParams[0] == 2)
{
/* Clear entire screen. */
ODScrnClear();
}
else if(btNumParams == 0 || anANSIParams[0] == 0)
{
/* Not supported - Clears from cursor to end of */
/* screen. */
}
else if(btNumParams>=1 && anANSIParams[0]==1)
{
/* Not supported - Clears from beginning of screen to */
/* cursor. */
}
break;
case 'K':
if(btNumParams == 0 || anANSIParams[0] == 0)
{
/* Clear to end of line. */
ODScrnClearToEndOfLine();
}
else if(btNumParams >= 1 && anANSIParams[0] == 1)
{
/* Not supported - should clear to beginning of line. */
}
else if(btNumParams >= 1 && anANSIParams[0] == 2)
{
/* Not supported - should clear entire line. */
}
break;
case 'm':
for(nTemp = 0; nTemp < btNumParams; ++nTemp)
{
if(anANSIParams[nTemp] == 0)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute = 0x07));
}
else if(anANSIParams[nTemp] == 1)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= TextInfo.attribute | 0x08));
}
else if(anANSIParams[nTemp] == 2)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= TextInfo.attribute & (~0x08)));
}
else if(anANSIParams[nTemp] == 4)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= (TextInfo.attribute & 0xf8) | (1)));
}
else if(anANSIParams[nTemp] == 5)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= TextInfo.attribute | 0x80));
}
else if(anANSIParams[nTemp] == 7)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= (TextInfo.attribute << 4)
| (TextInfo.attribute >> 4)));
}
else if(anANSIParams[nTemp] == 8)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= (TextInfo.attribute & 0xf0)
| ((TextInfo.attribute >> 4) & 0x07)));
}
else if(anANSIParams[nTemp] >= 30
&& anANSIParams[nTemp] <= 37)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= (TextInfo.attribute & 0xf8)
+ abtANSIToPCColorTable[
(anANSIParams[nTemp] - 30)]));
}
else if(anANSIParams[nTemp] >= 40
&& anANSIParams[nTemp]<=47)
{
ODScrnSetAttribute((BYTE)(od_control.od_cur_attrib
= TextInfo.attribute
= (TextInfo.attribute & 0x8f)
+ (abtANSIToPCColorTable[
anANSIParams[nTemp] - 40] << 4)));
}
}
break;
case 's':
btSavedColumn = TextInfo.curx;
btSavedRow = TextInfo.cury;
break;
case 'u':
ODScrnSetCursorPos(btSavedColumn, btSavedRow);
break;
case '@':
/* Not supported - inserts spaces at cursor. */
break;
case 'P':
/* Not supported - deletes characters at cursor. */
break;
case 'L':
/* Not supported - inserts lines at cursor. */
break;
case 'M':
/* Not supported - deletes lines at cursor. */
break;
case 'r':
/* Not supported - sets scrolling zone - 1st param is */
/* top row, 2nd param is bottom row. Cursor may go */
/* outside zone, but no scrolling occurs there. */
/* Also resets cursor to row 1, column 1. */
/* If only one param, bottom row is bottom of screen. */
break;
case 'h':
if(btNumParams >= 1 && anANSIParams[0] == 4)
{
/* Not suppored - turn insert mode on. */
}
else if(btNumParams >= 1 && anANSIParams[0] == -2)
{
/* Home cursor. */
ODScrnSetCursorPos(1, 1);
}
break;
case 'l':
if(btNumParams >= 1 && anANSIParams[0] == 4)
{
/* Not suppored - turn insert mode off. */
}
break;
case 'E':
/* Not supported - repeat CRLF specified # of times. */
break;
case 'F':
/* Not supported - repeat reverse CRLF specified # */
/* of times. Also not suppored ESC M - reverse */
/* linefeed, ESC D - LF, ESC E - CRLF */
break;
}
}
}
if(bEchoThisChar && od_control.baud != 0)
{
ODComSendByte(hSerialPort, chCurrent);
}
++pszBuffer;
}
}
/* ----------------------------------------------------------------------------
* ODEmulateFillArea() *** PRIVATE FUNCTION ***
*
* Fills an area of the local screen with the specified character, in the
* current display color.
*
* Parameters: btLeft - The left column of the area to fill.
*
* btTop - The top row of the area to fill.
*
* btRight - The right column of the area to fill.
*
* btBottom - The bottom row of the area to fill.
*
* chToFillWith - Character to fill in the specified area with.
*
* Return: void
*/
static void ODEmulateFillArea(BYTE btLeft, BYTE btTop, BYTE btRight,
BYTE btBottom, char chToFillWith)
{
BYTE btCount;
BYTE btLast;
static char szTemp[81];
static tODScrnTextInfo TextInfo;
ODScrnGetTextInfo(&TextInfo);
btLast = btRight - btLeft;
for(btCount=0; btCount <= btLast; ++btCount)
{
szTemp[btCount] = chToFillWith;
}
szTemp[btCount] = 0;
ODScrnEnableScrolling(FALSE);
for(btCount = btTop; btCount <= btBottom; ++btCount)
{
ODScrnSetCursorPos(btLeft, btCount);
ODScrnDisplayString(szTemp);
}
ODScrnSetCursorPos(TextInfo.curx, TextInfo.cury);
ODScrnEnableScrolling(TRUE);
}