teacl/src/tecoc.c

1096 lines
49 KiB
C

/*****************************************************************************
TECO-C (version number is defined as TVERSION in file TECOC.H)
Copyright 1983, 1990 by Pete Siemsen. This software is provided to
you free of charge for your own use. Use it as you see fit; if it doesn't
work, I disclaim all responsibility. You may re-distribute this software
UNCHANGED only if you include this copy-right notice. Alternatively, if
you change this software, you may re-distribute the result only if you
include BOTH this copyright notice, AND an additional notice identifying
you and indicating that you have changed the software.
This program is still under development. See file PROBLEMS.TXT for
notes I've written to myself about things to do to the program. If you
modify this code to enhance it or fix a bug, please communicate the changes
to me. My address is
Pete Siemsen
645 Ohio Avenue #302
Long Beach, Ca. 90814
(213) 433-3059 (home)
(213) 740-7391 (work)
Internet: siemsen@usc.edu
The file PG.MEM (programmer's guide) contains documentation explaining
algorithms used in TECO-C. File PROBLEMS.TXT is a notes file listing ideas
and known bugs.
Global variable declarations for system-independent variables are
in this file.
*****************************************************************************/
#include "zport.h" /* define portability identifiers */
#include "tecoc.h" /* define general identifiers */
#include "defext.h" /* define external global variables */
#include "deferr.h" /* define identifiers for error messages */
#include "dscren.h" /* define UNTERM */
/*****************************************************************************
Test for inconsistencies in the identifiers defined in the include
files. The ANSI C way to complain is to use #error, but some compilers
will complain even when the tests succeed, because they don't recognize the
#error directive while they scan for #endif. The goofy "include" statements
are used to generate a compile-time error.
*****************************************************************************/
#if GAPMIN > EBFINIT
#include ">>> GAPMIN can't be greater than EBFINIT <<<"
#endif
#if IBFMIN > IBFINIT
#include ">>> IBFMIN can't be greater than IBFINIT <<<"
#endif
#if IBFEXP < IBFMIN
#include ">>> IBFEXP can't be less than IBFMIN <<<"
#endif
#if NIFDBS < 3
#include ">>> NIFDBS can't be less than 3 <<<"
#endif
#if ZBFEXP < ZBFMIN
#include ">>> ZBFEXP can't be less than ZBFMIN <<<"
#endif
/*****************************************************************************
These pointers point to the first and last characters in an "area",
which is specified when an m,n argument pair precedes a TECO command. For
instance, when the command 10,25T is executed, the GetAra function is called
to set these pointers, which are then used to display the text.
*****************************************************************************/
GLOBAL charptr AraBeg; /* start of m,n area */
GLOBAL charptr AraEnd; /* end of m,n area */
/*****************************************************************************
ArgPtr points to the first character of the text argument associated
with a TECO-C command. It is set by the FindES (find end-of-string) function.
When a command that has a text argument is executed, FindES is called to
locate the end of the text argument. FindES moves the command pointer CBfPtr
to the end of the text argument, and remembers where the beginning was using
ArgPtr.
*****************************************************************************/
GLOBAL charptr ArgPtr; /* start of text argument of a cmd */
/*****************************************************************************
These variables point to the beginning and end of the command string
buffer. Memory for the command string buffer is allocated in the MemIni
function. CBfBeg always points to this buffer, but CStBeg changes when an M
or EI command is executed.
*****************************************************************************/
GLOBAL charptr CBfBeg; /* command buffer beginning */
GLOBAL charptr CBfEnd; /* command buffer end */
/*****************************************************************************
CBfPtr is the command string buffer pointer, which moves across a
command string as it is executed. CBfPtr usually points into the command
string buffer pointed to by CBfBeg, but it points elsewhere when an M or EI
command is being executed.
*****************************************************************************/
GLOBAL charptr CBfPtr; /* command buffer pointer */
/*****************************************************************************
When TECO-C is executing a command string, it looks at each command
(1 or 2 characters) and calls a function to implement the command. Some
commands can be modified by preceding the command with a modifier character.
CmdMod contains bits which are set when a modifier character is "executed".
This variable is cleared by most commands before they successfully return.
The bits in CmdMod relate to the at-sign (@), colon (:), double-colon (::)
modifiers. There is also a bit which indicates that a command has 2 numeric
arguments separated by a comma.
*****************************************************************************/
GLOBAL char CmdMod;
/*****************************************************************************
These variables point to the beginning and end of the executing
command string, whether that command string is in the command buffer, a
q-register or the EI buffer.
*****************************************************************************/
GLOBAL charptr CStBeg; /* start of command string */
GLOBAL charptr CStEnd; /* end of command string */
/*****************************************************************************
CurInp and CurOut are indices into the IFiles and OFiles arrays,
respectively. They indicate the entries for the current input stream and
current output stream.
*****************************************************************************/
GLOBAL DEFAULT CurInp = PINPFL;
GLOBAL DEFAULT CurOut = POUTFL;
/*****************************************************************************
These variables point to the digit buffer. When TECO-C needs to
convert a binary number into an ASCII string, the string is generated in this
buffer. The buffer is large enough to hold the largest integer represented
by 32 bits, plus an optional sign and maybe a carriage-return/line-feed pair.
*****************************************************************************/
GLOBAL charptr DBfBeg; /* digit buffer */
GLOBAL charptr DBfPtr; /* digit buffer pointer */
/*****************************************************************************
These variables point to the first and last characters in the edit
buffer. See file PG.MEM for a description of memory management.
*****************************************************************************/
GLOBAL charptr EBfBeg; /* first character in edit buffer */
GLOBAL charptr EBfEnd; /* last character in edit buffer */
/*****************************************************************************
EBPtr1 is used when a search is being performed. It is adjusted when
the edit buffer is being scanned for the first character of the search string.
When a search command succeeds, this pointer is left pointing to the first
character of the found string.
*****************************************************************************/
GLOBAL charptr EBPtr1;
/*****************************************************************************
EBPtr2 is used when a search is being performed. After a character
matching the first character of the search string is found, this pointer is
adjusted as each remaining character of the search string is compared with
the edit buffer. When a search command succeeds, this pointer is left
pointing to the last character of the found string.
*****************************************************************************/
GLOBAL charptr EBPtr2;
/*****************************************************************************
Bits within EdFlag have the following meanings:
1 Allow caret (^) in search strings
2 Allow Y and _ commands to destroy edit buffer
4 Don't arbitrarily expand memory
16 preserve dot on failing searches
64 only move dot by one on multiple occurrence searches
*****************************************************************************/
GLOBAL WORD EdFlag = 0; /* ED mode control flag */
/*****************************************************************************
Bits within EhFlag have the following meanings:
3 how much error message to display
4 display failing command string after errors
*****************************************************************************/
GLOBAL WORD EhFlag = 0; /* EH mode control flag */
/*****************************************************************************
EndSAr is used by search code to point to the end of the area to be
searched.
*****************************************************************************/
GLOBAL charptr EndSAr; /* end of search area */
/*****************************************************************************
Several TECO error messages take an argument. For instance, the
"illegal command" error message shows the user the illegal command. When
these kinds of messages are required, ErrTxt is used to send the text
of the argument to the error display function (ErrMsg).
*****************************************************************************/
GLOBAL char ErrTxt[6]; /* holds part of error message */
/*****************************************************************************
The EsFlag flag controls what is displayed on the terminal after every
successful search command completes. EsFlag has the following meanings:
0 don't display anything
-1 display the line containing the found string
1-31 display the line containing the found string,
with a line feed at the character position
32-126 display the line containing the found string,
with the character whose ASCII code is represented
by ES at the character position
m*265+n n has the meanings defined above. m is the number
of lines above and below the found string to be
displayed.
*****************************************************************************/
GLOBAL WORD EsFlag = 0; /* ES mode control flag */
/*****************************************************************************
The expression stack contains the components of TECO's numeric
expressions. Each entry on the expression stack is either an OPERAND or
an OPERATOR (like +, -, /, *).
*****************************************************************************/
GLOBAL struct EStck EStack[EXS_SIZE]; /* expression stack */
GLOBAL WORD EStBot; /* expression stack bottom */
GLOBAL WORD EStTop; /* top of expression stack */
/*****************************************************************************
Bits in EtFlag control TECO's handling of the terminal. Definitions
of masks for each bit and the meaning of each bit can be found in TECOC.H.
Bits in EtFlag are initialized when the terminal is set up in the ZTrmnl
function.
*****************************************************************************/
GLOBAL WORD EtFlag = 0; /* ET mode control flag */
/*****************************************************************************
The EuFlag is TECO's case mode control flag. This flag allows TECO to
be used to input and output upper and lower case characters even if the
terminal being used is capable of displaying only uppercase characters. If
the EU flag is -1, no case flagging is performed on type-out. If the EU flag
is 0, lowercase characters are converted to uppercase on type-out, and are
preceded by a ' character. If the EU flag is 1, then lowercase characters
are converted to uppercase on type-out, but uppercase characters are
preceded by a ' character.
*****************************************************************************/
GLOBAL WORD EuFlag = EU_NONE; /* EU mode control flag */
/*****************************************************************************
The EV mode control flag controls what is displayed on the terminal
after every successful command string completes. By default, nothing is
displayed (EV is 0). EV has the following meanings:
0 don't display anything
-1 display the line containing the character position
1-31 display the line containing the character position,
with a line feed at the character position
32-126 display the line containing the character position,
with the character whose ASCII code is represented
by ES at the character position
m*265+n n has the meanings defined above. m is the number
of lines above and below the character position to be
displayed.
*****************************************************************************/
GLOBAL WORD EvFlag = 0; /* EV mode control flag */
/*****************************************************************************
These variables point to the filename buffer.
*****************************************************************************/
GLOBAL charptr FBfBeg; /* first char of filename buffer */
GLOBAL charptr FBfEnd; /* last chr (+1) of filename buffer */
GLOBAL charptr FBfPtr; /* pointer into file spec buffer */
/*****************************************************************************
Bits in the EzFlag are system-specific. See the system-specific
file for each operating system (like ZVMS.C, ZUNIX.C, etc) for the meanings
of these bits.
*****************************************************************************/
GLOBAL WORD EzFlag = 0; /* EZ mode control flag */
/*****************************************************************************
FFPage is the value which is returned by the ^E command. It is -1 if
the buffer currently contains a page of text that was terminated by a form
feed in the input file. It is 0 if the buffer contains only part of a page
from the input file (because the input page filled the text buffer before it
was completely read in). The FFPage flag is tested by the P command and
related operations to determine if a form feed should be appended to the
contents of the buffer when it is output.
*****************************************************************************/
GLOBAL LONG FFPage = 0; /* form feed flag (see ^E command) */
/*****************************************************************************
These variables point to the first and last characters in the edit
buffer gap. See file PG.MEM for a description of memory management.
*****************************************************************************/
GLOBAL charptr GapBeg; /* first char in edit buffer gap */
GLOBAL charptr GapEnd; /* last char in edit buffer gap */
/*****************************************************************************
GotCtC indicates that the user has interrupted the normal execution
of TECO-C by typing a control-C. This variable is set by the special
interrupt-handling function executed when a control-C is struck, and is
cleared before a command string is entered. It is tested each time a command
terminates and when certain commands execute time-consuming loops.
*****************************************************************************/
GLOBALV BOOLEAN GotCtC = FALSE;
/*****************************************************************************
IBfEnd is the end of the input buffer. See file PG.MEM for a
description of memory management.
*****************************************************************************/
GLOBAL charptr IBfEnd;
/*****************************************************************************
IniSrM is the initial search mode. It is used when parsing search
strings and filenames. The value of this variable is set by ^V and
^W characters and is used to explicitly control the case (upper or lower) of
characters in a string. It can take on the values LOWER, UPPER or NONE,
which are defined in TECOC.H.
*****************************************************************************/
GLOBAL int IniSrM = NONE;
/*****************************************************************************
IsOpnI and IsOpnO contain indicators about the status of the file
data blocks in the IFiles and OFiles arrays, respectively. An element has
the value TRUE when the corresponding file data block reflects an opened file.
IsEofI indicates that the corresponding element of IFiles reflects a file
that has reached the end.
*****************************************************************************/
GLOBAL BOOLEAN IsEofI[NIFDBS];
GLOBAL BOOLEAN IsOpnI[NIFDBS];
GLOBAL BOOLEAN IsOpnO[NOFDBS];
/*****************************************************************************
LstErr holds the code for the last error reported by TECO-C. It is
set in the error display function (ErrMsg) and used when the user executes
the ? or / immediate mode commands, to print out more information about the
last error that occurred.
*****************************************************************************/
GLOBAL WORD LstErr = ERR_XXX; /* number of last error message */
/*****************************************************************************
The loop stack maintains pointers to the first character of each loop
(the character following the "<"). LStTop is the element of LStack that
relates to the most recently executed "<" command. LStBot is the index of
the bottom of the stack, so that if (LStTop == LStBot), we're not in a loop
in the current macro level. When a macro is entered, LStTop and LStBot are
saved on the macro stack, and LStBot is set to LStTop, so that LStBot
defines the bottom of the LStack frame for the new macro level.
*****************************************************************************/
GLOBAL WORD LStBot; /* bottom of loop stack */
GLOBAL struct LStck LStack[LPS_SIZE]; /* loop stack */
GLOBAL WORD LStTop; /* top of loop stack */
/*****************************************************************************
MArgmt contains the m part of an m,n argument pair that precedes a
TECO command. For instance, MArgmt would contain 10 when the command
10,45T is being executed.
*****************************************************************************/
GLOBAL LONG MArgmt; /* m part of m,n numeric arguments */
/*****************************************************************************
MAtchd is used to indicate that a match has been found for a search
string. It is only used when a search command is being executed.
*****************************************************************************/
GLOBAL BOOLEAN Matchd; /* indicates successful search */
/*****************************************************************************
These variables implement the macro stack. When TECO executes a
macro, it must first save the current state, so that the state can be
restored when the macro has finished executing. Each entry in the macro
stack preserves the critical variables for one macro call.
*****************************************************************************/
GLOBAL struct MStck MStack[MCS_SIZE]; /* macro stack */
GLOBAL WORD MStTop = -1; /* top of macro stack */
/*****************************************************************************
NArgmt holds the numeric argument that precedes a command. It is set
by a call to the GetNmA function. When the command is preceded by an m,n
argument pair, NArgmt holds the value of the n argument.
*****************************************************************************/
GLOBAL LONG NArgmt; /* n argument (n part of m,n) */
/*****************************************************************************
QR is a pointer to a structure which defines a q-register.
It is set by calling the FindQR function. Whenever a command that uses a
q-register is executed, FindQR is called first to set QR.
*****************************************************************************/
GLOBAL QRptr QR;
/*****************************************************************************
The structures in the QRgstr array represent the global and main-level
local q-registers. The 0-9 elements are for global digit q-registers (0-9),
the 10-35 elements are for global alphabetic q-registers (a-z or A-Z), the
36-45 elements are for main-level local digit q-registers (.0-.9) and the
46-71 elements are for main-level local alphabetic q-registers (.a-.z or
.A-.Z). Local q-registers at macro levels other than the main level are
allocated dynamically.
*****************************************************************************/
GLOBAL struct QReg QRgstr[72];
/*****************************************************************************
QStack is the q-register stack, accessed via the [ and ] commands.
*****************************************************************************/
GLOBAL struct QReg QStack[QRS_SIZE]; /* q-register stack */
GLOBAL WORD QStTop = -1; /* top of q-register stack */
/*****************************************************************************
RefLen is the length of the last inserted string or found search
string. It is accessed by the ^S command.
*****************************************************************************/
GLOBAL LONG RefLen = 0; /* returned by ^S */
/*****************************************************************************
Radix is TECO's radix, usually 10. It is set by the ^D, ^O and ^R
commands.
*****************************************************************************/
GLOBAL DEFAULT Radix = 10; /* TECO's current radix */
/*****************************************************************************
When searching, this pointer points to the farthest-right character
in the area to be searched. It is used after the first character of a string
has been found, to indicate the limit of the area in the edit buffer that
should be checked against the remaining characters in the search string.
*****************************************************************************/
GLOBAL charptr RhtSid;
/*****************************************************************************
These variables point to the search string buffer. The search buffer
is allocated by function MemIni.
*****************************************************************************/
GLOBAL charptr SBfBeg = NULL; /* start of search buffer */
GLOBAL charptr SBfEnd; /* end search buffer */
GLOBAL charptr SBfPtr; /* end of search string buffer */
/*****************************************************************************
SIncrm is the value added to the search pointer when the edit buffer
is being searched. If SIncrm is 1, then the search proceeds in a forward
direction. If SIncrm is -1, then the search proceeds in a backward
direction. By using this variable, the rather complex code that implements
searching can easily be used to search in either direction.
*****************************************************************************/
GLOBAL LONG SIncrm; /* search increment */
/*****************************************************************************
SMFlag is TECOC's search mode flag, and controls case sensitivity
during searches. This variable holds the value of the ^X command.
*****************************************************************************/
GLOBAL WORD SMFlag = 0; /* search mode control flag (^X) */
/*****************************************************************************
SrcTyp is used to "remember" the kind of search command that we're
working on. The same search code is used by all the search commands, but
each search command is slightly different than the others. The common
search code tests this variable to implement the differences.
*****************************************************************************/
GLOBAL WORD SrcTyp; /* type of search (E_SEARCH, etc) */
/*****************************************************************************
SStPtr points into the search buffer, and is used only by the search
code.
*****************************************************************************/
GLOBAL charptr SStPtr; /* search string pointer */
/*****************************************************************************
This table serves two functions. It is used by the character macros
defined in CHMACS.H. It is also used by the command line input code in
function ReadCS.
The top four bits of each mask are used by the functions in CHMACS.H.
The top four bits are masks used to represent "uppercase", "lowercase",
"digit" and "line terminator".
The bottom four bits of each mask are used by function ReadCS. They
are treated as a number and are used in a SWITCH statement. In ReadCS, the
top four bits of each mask are not used.
*****************************************************************************/
unsigned char ChrMsk[256] =
{
RCS_DEF, /* null */
RCS_CCH, /* ^A */
RCS_CCH, /* ^B */
RCS_CTC, /* ^C */
RCS_CCH, /* ^D */
RCS_CCH, /* ^E */
RCS_CCH, /* ^F */
RCS_CTG, /* ^G (bell) */
RCS_BS, /* ^H (bs) */
RCS_DEF, /* ^I (tab) */
RCS_LF | CM_LINE_TERM, /* ^J (lf) */
RCS_VF | CM_LINE_TERM, /* ^K (vt) */
RCS_VF | CM_LINE_TERM, /* ^L (ff) */
RCS_CR, /* ^M (cr) */
RCS_CCH, /* ^N */
RCS_CCH, /* ^O */
RCS_CCH, /* ^P */
RCS_CCH, /* ^Q */
RCS_CCH, /* ^R */
RCS_CCH, /* ^S */
RCS_CCH, /* ^T */
RCS_CTU, /* ^U */
RCS_CCH, /* ^V */
RCS_CCH, /* ^W */
RCS_CCH, /* ^X */
RCS_CCH, /* ^Y */
RCS_CTZ, /* ^Z */
0, /* escape */
RCS_CCH, /* FS */
RCS_CCH, /* GS */
RCS_CCH, /* RS */
RCS_CCH, /* US */
RCS_SP, /* space */
RCS_DEF, /* ! */
RCS_DEF, /* " */
RCS_DEF, /* # */
RCS_DEF, /* $ */
RCS_DEF, /* % */
RCS_DEF, /* | */
RCS_DEF, /* ' */
RCS_DEF, /* ( */
RCS_DEF, /* ) */
RCS_AST, /* * */
RCS_DEF, /* + */
RCS_DEF, /* , */
RCS_DEF, /* - */
RCS_DEF, /* . */
RCS_DEF, /* / */
RCS_DEF | CM_DIGIT, /* 0 */
RCS_DEF | CM_DIGIT, /* 1 */
RCS_DEF | CM_DIGIT, /* 2 */
RCS_DEF | CM_DIGIT, /* 3 */
RCS_DEF | CM_DIGIT, /* 4 */
RCS_DEF | CM_DIGIT, /* 5 */
RCS_DEF | CM_DIGIT, /* 6 */
RCS_DEF | CM_DIGIT, /* 7 */
RCS_DEF | CM_DIGIT, /* 8 */
RCS_DEF | CM_DIGIT, /* 9 */
RCS_DEF, /* : */
RCS_DEF, /* ; */
RCS_DEF, /* < */
RCS_DEF, /* = */
RCS_DEF, /* > */
RCS_DEF, /* ? */
RCS_DEF, /* @ */
RCS_DEF | CM_UPPER, /* A */
RCS_DEF | CM_UPPER, /* B */
RCS_DEF | CM_UPPER, /* C */
RCS_DEF | CM_UPPER, /* D */
RCS_DEF | CM_UPPER, /* E */
RCS_DEF | CM_UPPER, /* F */
RCS_DEF | CM_UPPER, /* G */
RCS_DEF | CM_UPPER, /* H */
RCS_DEF | CM_UPPER, /* I */
RCS_DEF | CM_UPPER, /* J */
RCS_DEF | CM_UPPER, /* K */
RCS_DEF | CM_UPPER, /* L */
RCS_DEF | CM_UPPER, /* M */
RCS_DEF | CM_UPPER, /* N */
RCS_DEF | CM_UPPER, /* O */
RCS_DEF | CM_UPPER, /* P */
RCS_DEF | CM_UPPER, /* Q */
RCS_DEF | CM_UPPER, /* R */
RCS_DEF | CM_UPPER, /* S */
RCS_DEF | CM_UPPER, /* T */
RCS_DEF | CM_UPPER, /* U */
RCS_DEF | CM_UPPER, /* V */
RCS_DEF | CM_UPPER, /* W */
RCS_DEF | CM_UPPER, /* X */
RCS_DEF | CM_UPPER, /* Y */
RCS_DEF | CM_UPPER, /* Z */
RCS_DEF, /* [ */
RCS_DEF, /* \ */
RCS_DEF, /* ] */
RCS_DEF, /* ^ */
RCS_DEF, /* _ */
RCS_GRV, /* ` */
RCS_LWR | CM_LOWER, /* a */
RCS_LWR | CM_LOWER, /* b */
RCS_LWR | CM_LOWER, /* c */
RCS_LWR | CM_LOWER, /* d */
RCS_LWR | CM_LOWER, /* e */
RCS_LWR | CM_LOWER, /* f */
RCS_LWR | CM_LOWER, /* g */
RCS_LWR | CM_LOWER, /* h */
RCS_LWR | CM_LOWER, /* i */
RCS_LWR | CM_LOWER, /* j */
RCS_LWR | CM_LOWER, /* k */
RCS_LWR | CM_LOWER, /* l */
RCS_LWR | CM_LOWER, /* m */
RCS_LWR | CM_LOWER, /* n */
RCS_LWR | CM_LOWER, /* o */
RCS_LWR | CM_LOWER, /* p */
RCS_LWR | CM_LOWER, /* q */
RCS_LWR | CM_LOWER, /* r */
RCS_LWR | CM_LOWER, /* s */
RCS_LWR | CM_LOWER, /* t */
RCS_LWR | CM_LOWER, /* u */
RCS_LWR | CM_LOWER, /* v */
RCS_LWR | CM_LOWER, /* w */
RCS_LWR | CM_LOWER, /* x */
RCS_LWR | CM_LOWER, /* y */
RCS_LWR | CM_LOWER, /* z */
RCS_DEF, /* { */
RCS_DEF, /* | */
RCS_DEF, /* } */
RCS_DEF, /* ~ */
RCS_DEL, /* delete */
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF
};
/*****************************************************************************
TraceM is the trace mode flag. This variable is set to TRUE when
TECO's trace mode is on. When it is set, commands are echoed to the terminal
as they are executed. This mode is used to aid in debugging TECO macros, and
is toggled by the ? command.
If you want to trace the command line parsing macro executed in
ZPrsCL(), set this to TRUE; otherwise, set it to FALSE.
*****************************************************************************/
GLOBAL BOOLEAN TraceM = FALSE; /* trace mode flag */
/*****************************************************************************
CrType is the terminal type. It is used by the ZScrOp function to
drive the few screen capabilities of TECOC. See ZScrOp for a list of the
values that CrType can take.
*****************************************************************************/
GLOBAL DEFAULT CrType = UNTERM; /* terminal type */
#if VIDEO
GLOBAL DEFAULT HldFlg; /* value of 5:W (hold mode flag) */
GLOBAL DEFAULT HtSize; /* value of 1:W (screen width) */
GLOBAL DEFAULT MrkFlg; /* value of 4:W */
GLOBAL DEFAULT ScroLn; /* value of 7:W */
GLOBAL DEFAULT SeeAll; /* value of 3:W */
GLOBAL DEFAULT TopDot; /* value of 6:W */
GLOBAL DEFAULT VtSize; /* value of 2:W (screen height) */
#if CURSES
GLOBAL DEFAULT SpcMrk = 0; /* value of 8:W */
GLOBAL DEFAULT KeyPad; /* value of 9:W */
#endif
#endif
/*****************************************************************************
S t a r t H e r e
*****************************************************************************/
int _Cdecl main(argc, argv) /* _Cdecl defined in ZPORT.H */
int argc;
char **argv;
{
#if CHECKSUM_CODE /* MS-DOS debugging code */
init_code_checksums (); /* calculate code checksums */
#endif
Init(argc, argv); /* initialize TECO */
/*
* read a command string and then execute it. This loop is infinite.
* TECO-C is exited explicitly when a lower-level function calls TAbort.
*/
CStBeg = CStEnd = CBfBeg;
CStEnd--;
FOREVER { /* loop forever */
ReadCS(); /* read command string */
CBfPtr = CBfBeg; /* initialize command string ptr */
CmdMod = '\0'; /* clear modifiers flags */
EStTop = EStBot = /* clear expression stack */
LStTop = LStBot = /* clear loop stack */
MStTop = -1; /* clear macro stack */
ExeCSt(); /* execute command string */
}
}
/*****************************************************************************
The following code is support routines for the imbedded debugging code
in TECO-C. If the "DEBUGGING" macro in ZPORT.H is set to "FALSE", then none
of this code is compiled.
*****************************************************************************/
#if DEBUGGING
#include <ctype.h> /* isprint() macro */
#include "dchars.h" /* define identifiers for characters */
static DEFAULT DbgInd = 0; /* debugging indent level */
static DEFAULT DbgLvl = 0; /* debugging message level */
#define DBGSBF 4000 /* huge buffer to avoid overruns */
GLOBAL char DbgSBf[DBGSBF+1]; /* sprintf() buffer for debugging messages */
#if USE_PROTOTYPES
static VVOID DbgDMs( /* debugging, display message */
int DbgFLv, /* function display level */
char *DbgFNm, /* function name */
char *DbgWht, /* "called", "returning", or blank */
char *DbgMsg); /* message to display */
static VVOID DbgDsA(void); /* display address variables */
static VVOID DbgEBf(void); /* display edit buffer details */
static VVOID DbgHlp(void); /* display help message */
static VVOID DbgLSt(void); /* display loop stack details */
static VVOID DbgMSt(void); /* display macro stack details */
static VVOID DbgPrP( /* display a pointer */
char *s,
voidptr ptr);
static VVOID DbgQRg(void); /* display Q-register's */
static VVOID DbgQSt(void); /* display Q-register stack */
static VVOID DbgSLv(void); /* set debugging message level */
#endif
/*****************************************************************************
DbgDsA()
This function displays details about address variables for 1^P.
*****************************************************************************/
static VVOID DbgPrP (s, ptr) /* display a pointer */
char *s;
voidptr ptr;
{
printf ("%s %lu", s, Zcp2ul(ptr));
}
static VVOID DbgDsA()
{
int length;
DbgPrP ("\r\nAraBeg =", AraBeg);
DbgPrP ("\tEBfBeg =", EBfBeg);
DbgPrP ("\tGapBeg =", GapBeg);
DbgPrP ("\r\nAraEnd =", AraEnd);
DbgPrP ("\tEBfEnd =", EBfEnd);
DbgPrP ("\tGapEnd =", GapEnd);
DbgPrP ("\r\nCBfBeg =", CBfBeg);
DbgPrP ("\tCStBeg =", CStBeg);
DbgPrP ("\tFBfBeg =", FBfBeg);
DbgPrP ("\r\nCBfEnd =", CBfEnd);
DbgPrP ("\tCStEnd =", CStEnd);
DbgPrP ("\tFBfEnd =", FBfEnd);
DbgPrP ("\r\nSBfBeg =", SBfBeg);
DbgPrP ("\tEBPtr1 =", EBPtr1);
DbgPrP ("\tEBPtr2 =", EBPtr2);
DbgPrP ("\r\nSBfPtr =", SBfPtr);
DbgPrP ("\tCBfPtr =", CBfPtr);
DbgPrP ("\r\nSBfEnd =", SBfEnd);
DbgPrP ("\tSStPtr =", SStPtr);
printf ("\r\nsearch buffer = \"");
if (SBfPtr != NULL) {
length = (int) (SBfPtr-SBfBeg);
if (length > 40) {
length = 40;
}
printf ("%.*s", length, SBfBeg);
} else {
length = 0;
}
printf("\"\r\n");
}
/*****************************************************************************
DbgEBf()
This function displays details about the edit buffer for 2^P.
*****************************************************************************/
static VVOID DbgEBf()
{
charptr DbgPtr;
DbgPrP ("\r\nEBfBeg =", EBfBeg);
DbgPrP ("\tGapBeg =", GapBeg);
printf (" (%ld bytes)", (LONG) (GapBeg - EBfBeg));
DbgPrP ("\r\nGapBeg =", GapBeg);
DbgPrP ("\tGapEnd =", GapEnd);
printf (" (%ld bytes)", (LONG) (GapEnd - GapBeg));
DbgPrP ("\r\nGapEnd =", GapEnd);
DbgPrP ("\tEBfEnd =", EBfEnd);
printf (" (%ld bytes)", (LONG) (EBfEnd - GapEnd));
DbgPrP ("\r\nEBfEnd =", EBfEnd);
DbgPrP ("\tIBfEnd =", IBfEnd);
printf (" (%ld bytes)", (LONG) (IBfEnd - EBfEnd));
DbgPrP ("\r\nEBfBeg =", EBfBeg);
DbgPrP ("\tIBfEnd =", IBfEnd);
printf (" (%ld bytes)", (LONG) (IBfEnd - EBfBeg));
for (DbgPtr = EBfBeg; DbgPtr < GapBeg; ++DbgPtr) {
DbgPrP ("\r\nDbgEBf: first half, char at", DbgPtr);
printf((isprint(*DbgPtr) ? " '%c'" : " <%d>"), *DbgPtr);
}
for (DbgPtr = (GapEnd+1); DbgPtr <= EBfEnd; ++DbgPtr) {
DbgPrP ("\r\nDbgEBf: second half, char at", DbgPtr);
printf((isprint(*DbgPtr) ? " '%c'" : " <%d>"), *DbgPtr);
}
puts ("\r");
}
/*****************************************************************************
DbgHlp()
This function displays help on ^P commands for ^P with no arguments.
*****************************************************************************/
static VVOID DbgHlp()
{
puts("\r\n\tArguments to ^P have the following meanings:\r\n");
puts("\t\t^P\tno arguments - display help about ^P\r");
puts("\t\tm,0\tset debugging message level to m (0-5)\r");
puts("\t\t1\tdisplay global address variables\r");
puts("\t\t2\tdisplay details about the edit buffer\r");
puts("\t\t3\tdisplay the loop stack\r");
puts("\t\t4\tdisplay the macro stack\r");
puts("\t\t5\tdisplay details about the q-registers\r");
puts("\t\t6\tdisplay the q-register stack\r\r\r");
}
/*****************************************************************************
DbgLSt ()
This function displays details about the loop stack for 3^P.
*****************************************************************************/
static VVOID DbgLSt()
{
int i;
printf ("\r\nLoop stack: LStBot = %d, LstTop = %d\r\n\n", LStBot, LStTop);
printf (" # LIndex LAddr\r\n");
printf ("-- ---------- ----------\r\n");
for (i = 0; i <= LStTop; ++i) {
printf("%2d %10ld %10lu\r\n",
i, LStack[i].LIndex, Zcp2ul(LStack[i].LAddr));
}
}
/*****************************************************************************
DbgDMs()
This function displays a debugging message at the right indentation
level, in reverse video, if the debugging level is appropriate for the
message. It also optionally calls the consistency_check() and the
check_code_checksums() routines while debugging.
The debugging levels are:
1 command functions
2 functions called by command functions
3 everything but stuff that's too noisy
4 everything
*****************************************************************************/
static VVOID DbgDMs(DbgFLv, DbgFNm, DbgWht, DbgMsg)
int DbgFLv; /* function display level */
char *DbgFNm; /* function name */
char *DbgWht; /* "called", "returning", or blank */
char *DbgMsg; /* message to display */
{
if (DbgFLv <= DbgLvl) { /* is message at right level */
printf ("%*s", DbgInd, ""); /* indent message */
ZScrOp(SCR_RON); /* turn on reverse video */
printf ("%s: %s %s\r\n",
DbgFNm,
DbgWht,
(DbgMsg == NULL) ? "" : DbgMsg);
ZScrOp(SCR_ROF); /* turn off reverse video */
}
if (DbgMsg == DbgSBf) { /* clear sprintf() buffer */
DbgSBf[0] = '\0';
}
if (DbgSBf[DBGSBF] != '\0') { /* check sprintf() overrun */
puts("DbgSBf[] overrun");
exit(EXIT_FAILURE);
}
/*
* If you enable consistency checking and code checksumming here, pointers
* and code will be checked on every function entry and exit in addition to
* being checked after every successful command execution in ExeCSt().
*
* Enabling code checksumming here r-e-a-l-l-y slows things down.
*/
#if CONSISTENCY_CHECKING
check_consistency ();
#endif
#if 0 && CHECKSUM_CODE /* MS-DOS debugging code */
check_code_checksums ();
#endif
}
/*****************************************************************************
DbgFEn()
This function is called as the first thing upon entry to a function.
*****************************************************************************/
VVOID DbgFEn(DbgFLv, DbgFNm, DbgMsg) /* debugging, function entry */
int DbgFLv; /* function display level */
char *DbgFNm; /* function name */
char *DbgMsg; /* a function entry message */
{
DbgInd += 2;
DbgDMs(DbgFLv, DbgFNm, "called", DbgMsg);
}
/*****************************************************************************
DbgFEx()
This function is called as the last thing before a function returns.
*****************************************************************************/
VVOID DbgFEx(DbgFLv, DbgFNm, DbgMsg)
int DbgFLv;
char *DbgFNm;
char *DbgMsg;
{
DbgDMs(DbgFLv, DbgFNm, "returning", DbgMsg);
DbgInd -= 2;
}
/*****************************************************************************
DbgFMs()
This function is called in the middle of a routine if the routine
has something special to say.
*****************************************************************************/
VVOID DbgFMs(DbgFLv, DbgFNm, DbgMsg) /* debugging, function message */
int DbgFLv; /* function display level */
char *DbgFNm; /* function name */
char *DbgMsg; /* a debugging message */
{
DbgDMs(DbgFLv, DbgFNm, "", DbgMsg);
}
/*****************************************************************************
DbgMSt()
This function displays details about the macro stack for 4^P.
*****************************************************************************/
static VVOID DbgMSt()
{
int i;
MSptr MSp;
printf("Macro Stack, MStTop = %d\r\n\n", MStTop);
printf(" # CStBeg CBfPtr CStEnd EStBot EStTop LStBot LStTop QRgstr\r\n");
printf("-- -------- -------- -------- ------ ------ ------ ------ --------\r\n");
for (MSp = MStack, i = 0; i <= MStTop; ++i, ++MSp) {
printf("%2d %8lu %8lu %8lu %6d %6d %6d %6d %8lu\r\n",
i,
Zcp2ul(MSp->CStBeg),
Zcp2ul(MSp->CBfPtr),
Zcp2ul(MSp->CStEnd),
MSp->EStBot,
MSp->EStTop,
MSp->LStBot,
MSp->LStTop,
Zcp2ul(MSp->QRgstr));
}
}
/*****************************************************************************
DbgQRg()
This function displays details about global Q-registers for 5^P.
*****************************************************************************/
static VVOID DbgQRg()
{
int i;
int length;
charptr cp;
QRptr QRp;
printf ("Non-empty Q-registers:\r\n\n");
printf (" # Number Start End_P1 Text (possibly truncated)\r\n");
printf ("-- ------- ------- ------- --------------------------------------------------\r\n");
for (i = 0, QRp = QRgstr; i < 72; ++i, ++QRp) {
if (QRp->Number != 0 || QRp->Start != NULL) {
printf ("%c%c %7ld %7lu %7lu \"",
(i < 36) ? ' ' : '.',
i + ((i <= 9) ? '0' : 'A' - 10),
QRp->Number,
Zcp2ul(QRp->Start),
Zcp2ul(QRp->End_P1));
if (QRp->Start != NULL) {
length = (int) (QRp->End_P1 - QRp->Start);
if (length > 50) {
length = 50;
}
cp = QRp->Start;
while (length-- > 0) {
if (*cp < ' ') {
ZDspCh ('^');
ZDspCh (*cp + '@');
--length;
} else {
ZDspCh (*cp);
}
++cp;
}
}
printf ("\"\r\n");
}
}
printf ("\r\n");
}
/*****************************************************************************
DbgQSt()
This function displays details about the Q-register stack for 6^P.
*****************************************************************************/
static VVOID DbgQSt()
{
int i;
int length;
charptr cp;
QRptr QRp;
printf("Q-register Stack, QStTop = %d\r\n\n", QStTop);
printf ("# Number Start End_P1 Text (possibly truncated)\r\n");
printf ("-- ------- ------- ------- --------------------------------------------------\r\n");
for (QRp = QStack, i = 0; i <= QStTop; ++i, ++QRp) {
printf ("%2d %7ld %7lu %7lu \"",
i,
QRp->Number,
Zcp2ul(QRp->Start),
Zcp2ul(QRp->End_P1));
if (QRp->Start != NULL) {
length = (int) (QRp->End_P1 - QRp->Start);
if (length > 50) {
length = 50;
}
cp = QRp->Start;
while (length-- > 0) {
if (*cp < ' ') {
ZDspCh ('^');
ZDspCh (*cp + '@');
} else {
ZDspCh (*cp);
}
++cp;
}
}
printf ("\"\r\n");
}
printf ("\r\n");
}
/*****************************************************************************
DbgSLv()
This function sets DbgLvl, which controls how much debugging
information is displayed as TECO executes. If DbgLvl is 0, no debugging
messages are displayed. If (DbgLvl>=1), then messages are displayed by
all "Exexxx" functions. This means that a message is displayed for each
entry and exit of execution of a single command. If (DbgLvl>=1) then in
addition to the messages displayed for entry and exit of Exexxx functions,
a message is displayed for the "next level down" functions. This scheme
is continued for DbgLvl >= 3, DbgLvl >= 4, etc.
In most cases, setting DbgLvl to 1 and then executing a TECO
command string will reveal an error. For more detail, DbgLvl can be set
to successively higher values. Using DbgLvl, you can trade-off the amount
of time you wait for the messages to go by on the screen with the amount
of detail that's needed.
By using this system, debug messages that are placed into new code
in order to debug it can be left in the code so they're useful later.
*****************************************************************************/
static VVOID DbgSLv()
{
DbgLvl = (DEFAULT)MArgmt;
}
/*****************************************************************************
DbgDsp()
This function provides control of the imbedded debugging system in
TECO-C. An unused command character (currently control-P), when executed by
the user, causes this function to be executed.
Arguments to ^P have the following meanings:
no argument - display help about ^P
m,0 set debugging message level to m
1 display global address variables
2 display details about the edit buffer
3 display the loop stack
4 display the macro stack
5 display details about the q-registers
*****************************************************************************/
DEFAULT DbgDsp()
{
if (EStTop == EStBot) { /* if no numeric argument */
ZScrOp(SCR_RON); /* turn on reverse video */
DbgHlp(); /* display debugging help */
ZScrOp(SCR_ROF); /* turn off reverse video */
return SUCCESS;
}
if (GetNmA() == FAILURE) { /* get numeric argument */
return FAILURE;
}
if (CmdMod & MARGIS) { /* if it's m,n^P */
DbgSLv(); /* set DbgLvl */
return SUCCESS;
}
ZScrOp(SCR_RON); /* turn on reverse video */
switch ((int)NArgmt) {
case 1: DbgDsA(); break; /* display address variable details */
case 2: DbgEBf(); break; /* display edit buffer details */
case 3: DbgLSt(); break; /* display loop stack */
case 4: DbgMSt(); break; /* display macro stack */
case 5: DbgQRg(); break; /* display q-registers */
case 6: DbgQSt(); break; /* display q-register stack */
default:
printf("bad argument to ^P command\r\n");
ZScrOp(SCR_ROF); /* turn off reverse video */
return FAILURE;
}
ZScrOp(SCR_ROF); /* turn off reverse video */
return SUCCESS;
}
#endif /* #if DEBUGGING */
/*****************************************************************************
The following code was needed while debugging TECO-C on the IBM PC
with it's brain-damaged memory addressing scheme. This code checks the
"consistency" of various pointers, making sure some don't change throughout
the execution of TECO-C and making sure others are in the right order.
After init_consistency_check() is called in Init(), the
check_consistency() code is called in ExeCSt() after the successful
completion of each command. For more frequent checking, it can also
be called in the DbgDMs() routine above but then the "DEBUGGING" macro
in ZPORT.H has to be set to "TRUE" as well.
If the "CONSISTENCY_CHECKING" macro in ZPORT.H is set to "FALSE",
then none of this code is compiled.
*****************************************************************************/
#if CONSISTENCY_CHECKING
#if USE_PROTOTYPES
static int errprt(char *str, voidptr p1, voidptr p2);
#endif
static charptr ss_CBfBeg;
static charptr ss_CBfEnd;
static charptr ss_FBfBeg;
static charptr ss_FBfEnd;
static charptr ss_SBfBeg;
static charptr ss_SBfEnd;
VVOID init_consistency_check()
{
ss_CBfBeg = CBfBeg;
ss_CBfEnd = CBfEnd;
ss_FBfBeg = FBfBeg;
ss_FBfEnd = FBfEnd;
ss_SBfBeg = SBfBeg;
ss_SBfEnd = SBfEnd;
}
static int errprt(str, p1, p2)
char *str;
voidptr p1;
voidptr p2;
{
printf ("%s (%lu,%lu)\r\n", str, Zcp2ul(p1), Zcp2ul(p2));
return EXIT_FAILURE;
}
#if defined(__TURBOC__) && (__TURBOC__ >= 0x0295)
#include <alloc.h> /* prototype for heapcheck() */
#endif
VVOID check_consistency()
{
int ex = EXIT_SUCCESS;
/*
* is the heap corrupted?
*/
#if defined(__TURBOC__) && (__TURBOC__ >= 0x0295)
if (heapcheck () < 0) {
puts ("check_consistency: heapcheck failed");
ex = EXIT_FAILURE;
}
#endif
/*
* the following point to the start and end of various buffers which are
* initialized at program startup and should not have changed.
*/
if (ss_CBfBeg != CBfBeg) ex=errprt("ss_CBfBeg != CBfBeg",ss_CBfBeg,CBfBeg);
if (ss_CBfEnd != CBfEnd) ex=errprt("ss_CBfEnd != CBfEnd",ss_CBfEnd,CBfEnd);
if (ss_FBfBeg != FBfBeg) ex=errprt("ss_FBfBeg != FBfBeg",ss_FBfBeg,FBfBeg);
if (ss_FBfEnd != FBfEnd) ex=errprt("ss_FBfEnd != FBfEnd",ss_FBfEnd,FBfEnd);
if (ss_SBfBeg != SBfBeg) ex=errprt("ss_SBfBeg != SBfBeg",ss_SBfBeg,SBfBeg);
if (ss_SBfEnd != SBfEnd) ex=errprt("ss_SBfEnd != SBfEnd",ss_SBfEnd,SBfEnd);
/*
* make sure the pointers into the above buffers are between the start
* and end of the buffers
*
* Note: while doing an EI or M command, CBfPtr can point outside of
* [CBfBeg..CBfEnd] but it is always within [CStBeg..CStEnd].
*/
if (CBfPtr < CStBeg) ex=errprt("CBfPtr < CStBeg",CBfPtr,CStBeg);
if (CBfPtr > CStEnd) ex=errprt("CBfPtr > CStEnd",CBfPtr,CStEnd);
if (FBfPtr < FBfBeg) ex=errprt("FBfPtr < FBfBeg",FBfPtr,FBfBeg);
if (FBfPtr > FBfEnd) ex=errprt("FBfPtr > FBfEnd",FBfPtr,FBfEnd);
if (SBfPtr < SBfBeg) ex=errprt("SBfPtr < SBfBeg",SBfPtr,SBfBeg);
if (SBfPtr > SBfEnd) ex=errprt("SBfPtr > SBfEnd",SBfPtr,SBfEnd);
/*
* The order of pointers into the editing buffer should be:
*
* EBfBeg <= GapBeg <= GapEnd <= EBfEnd <= IBfEnd
*/
if (EBfBeg > GapBeg) ex=errprt("EBfBeg > GapBeg",EBfBeg,GapBeg);
if (GapBeg > GapEnd) ex=errprt("GapBeg > GapEnd",GapBeg,GapEnd);
if (GapEnd > EBfEnd) ex=errprt("GapEnd > EBfEnd",GapEnd,EBfEnd);
if (EBfEnd > IBfEnd) ex=errprt("EBfEnd > IBfEnd",EBfEnd,IBfEnd);
if (ex == EXIT_FAILURE) {
exit(EXIT_FAILURE);
}
}
#endif /* #if CONSISTENCY_CHECKING */