1096 lines
49 KiB
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 */
|