1 /*****************************************************************************
2 
3 	TECO-C (version number is defined as TVERSION in file TECOC.H)
4 
5 	Copyright 1983, 1990 by Pete Siemsen. This software is provided to
6 you free of charge for your own use.  Use it as you see fit; if it doesn't
7 work, I disclaim all responsibility.  You may re-distribute this software
8 UNCHANGED only if you include this copy-right notice.  Alternatively, if
9 you change this software, you may re-distribute the result only if you
10 include BOTH this copyright notice, AND an additional notice identifying
11 you and indicating that you have changed the software.
12 
13 	This program is still under development.  See file PROBLEMS.TXT for
14 notes I've written to myself about things to do to the program. If you
15 modify this code to enhance it or fix a bug,  please communicate the changes
16 to me.  My address is
17 
18 			Pete Siemsen
19 			645 Ohio Avenue #302
20 			Long Beach, Ca. 90814
21 
22 			(213) 433-3059  (home)
23 			(213) 740-7391  (work)
24 			Internet: siemsen@usc.edu
25 
26 	The file PG.MEM (programmer's guide) contains documentation explaining
27 algorithms used in TECO-C.  File PROBLEMS.TXT is a notes file listing ideas
28 and known bugs.
29 
30 	Global variable declarations for system-independent variables are
31 in this file.
32 
33 *****************************************************************************/
34 
35 #include "zport.h"		/* define portability identifiers */
36 #include "tecoc.h"		/* define general identifiers */
37 #include "defext.h"		/* define external global variables */
38 #include "deferr.h"		/* define identifiers for error messages */
39 #include "dscren.h"		/* define UNTERM */
40 
41 /*****************************************************************************
42         Test for inconsistencies in the identifiers defined in the include
43 files.  The ANSI C way to complain is to use #error,  but some compilers
44 will complain even when the tests succeed,  because they don't recognize the
45 #error directive while they scan for #endif.  The goofy "include" statements
46 are used to generate a compile-time error.
47 *****************************************************************************/
48 
49 #if GAPMIN > EBFINIT
50 #include ">>> GAPMIN can't be greater than EBFINIT <<<"
51 #endif
52 #if IBFMIN > IBFINIT
53 #include ">>> IBFMIN can't be greater than IBFINIT <<<"
54 #endif
55 #if IBFEXP < IBFMIN
56 #include ">>> IBFEXP can't be less than IBFMIN <<<"
57 #endif
58 #if NIFDBS < 3
59 #include ">>> NIFDBS can't be less than 3 <<<"
60 #endif
61 #if ZBFEXP < ZBFMIN
62 #include ">>> ZBFEXP can't be less than ZBFMIN <<<"
63 #endif
64 
65 /*****************************************************************************
66 	These pointers point to the first and last characters in an "area",
67 which is specified when an m,n argument pair precedes a TECO command.  For
68 instance,  when the command 10,25T is executed,  the GetAra function is called
69 to set these pointers,  which are then used to display the text.
70 *****************************************************************************/
71 
72 GLOBAL	charptr	AraBeg;		/* start of m,n area */
73 GLOBAL	charptr	AraEnd;		/* end of m,n area */
74 
75 /*****************************************************************************
76 	ArgPtr points to the first character of the text argument associated
77 with a TECO-C command.  It is set by the FindES (find end-of-string) function.
78 When a command that has a text argument is executed,  FindES is called to
79 locate the end of the text argument.  FindES moves the command pointer CBfPtr
80 to the end of the text argument,  and remembers where the beginning was using
81 ArgPtr.
82 *****************************************************************************/
83 
84 GLOBAL	charptr	ArgPtr;		/* start of text argument of a cmd */
85 
86 /*****************************************************************************
87 	These variables point to the beginning and end of the command string
88 buffer.  Memory for the command string buffer is allocated in the MemIni
89 function.  CBfBeg always points to this buffer,  but CStBeg changes when an M
90 or EI command is executed.
91 *****************************************************************************/
92 
93 GLOBAL	charptr	CBfBeg;		/* command buffer beginning */
94 GLOBAL	charptr	CBfEnd;		/* command buffer end */
95 
96 /*****************************************************************************
97 	CBfPtr is the command string buffer pointer,  which moves across a
98 command string as it is executed.  CBfPtr usually points into the command
99 string buffer pointed to by CBfBeg,  but it points elsewhere when an M or EI
100 command is being executed.
101 *****************************************************************************/
102 
103 GLOBAL	charptr	CBfPtr;		/* command buffer pointer */
104 
105 /*****************************************************************************
106 	When TECO-C is executing a command string,  it looks at each command
107 (1 or 2 characters) and calls a function to implement the command.  Some
108 commands can be modified by preceding the command with a modifier character.
109 CmdMod contains bits which are set when a modifier character is "executed".
110 This variable is cleared by most commands before they successfully return.
111 The bits in CmdMod relate to the at-sign (@), colon (:), double-colon (::)
112 modifiers.  There is also a bit which indicates that a command has 2 numeric
113 arguments separated by a comma.
114 *****************************************************************************/
115 
116 GLOBAL	char	CmdMod;
117 
118 /*****************************************************************************
119 	These variables point to the beginning and end of the executing
120 command string,  whether that command string is in the command buffer, a
121 q-register or the EI buffer.
122 *****************************************************************************/
123 
124 GLOBAL	charptr	CStBeg;		/* start of command string */
125 GLOBAL	charptr	CStEnd;		/* end of command string */
126 
127 /*****************************************************************************
128 	CurInp and CurOut are indices into the IFiles and OFiles arrays,
129 respectively.  They indicate the entries for the current input stream and
130 current output stream.
131 *****************************************************************************/
132 
133 GLOBAL	DEFAULT	CurInp = PINPFL;
134 GLOBAL	DEFAULT	CurOut = POUTFL;
135 
136 /*****************************************************************************
137 	These variables point to the digit buffer.  When TECO-C needs to
138 convert a binary number into an ASCII string,  the string is generated in this
139 buffer.  The buffer is large enough to hold the largest integer represented
140 by 32 bits,  plus an optional sign and maybe a carriage-return/line-feed pair.
141 *****************************************************************************/
142 
143 GLOBAL	charptr	DBfBeg;		/* digit buffer */
144 GLOBAL	charptr	DBfPtr;		/* digit buffer pointer */
145 
146 /*****************************************************************************
147 	These variables point to the first and last characters in the edit
148 buffer.  See file PG.MEM for a description of memory management.
149 *****************************************************************************/
150 
151 GLOBAL	charptr	EBfBeg;		/* first character in edit buffer */
152 GLOBAL	charptr	EBfEnd;		/* last character in edit buffer */
153 
154 /*****************************************************************************
155 	EBPtr1 is used when a search is being performed.  It is adjusted when
156 the edit buffer is being scanned for the first character of the search string.
157 When a search command succeeds,  this pointer is left pointing to the first
158 character of the found string.
159 *****************************************************************************/
160 
161 GLOBAL	charptr	EBPtr1;
162 
163 /*****************************************************************************
164 	EBPtr2 is used when a search is being performed.  After a character
165 matching the first character of the search string is found,  this pointer is
166 adjusted as each remaining character of the search string is compared with
167 the edit buffer.  When a search command succeeds,  this pointer is left
168 pointing to the last character of the found string.
169 *****************************************************************************/
170 
171 GLOBAL	charptr	EBPtr2;
172 
173 /*****************************************************************************
174 	Bits within EdFlag have the following meanings:
175 
176         1    Allow caret (^) in search strings
177         2    Allow Y and _ commands to destroy edit buffer
178         4    Don't arbitrarily expand memory
179         16   preserve dot on failing searches
180         64   only move dot by one on multiple occurrence searches
181 *****************************************************************************/
182 
183 GLOBAL	WORD	EdFlag = 0;		/* ED mode control flag */
184 
185 /*****************************************************************************
186 	Bits within EhFlag have the following meanings:
187 
188         3    how much error message to display
189         4    display failing command string after errors
190 *****************************************************************************/
191 
192 GLOBAL	WORD	EhFlag = 0;		/* EH mode control flag */
193 
194 /*****************************************************************************
195 	EndSAr is used by search code to point to the end of the area to be
196 searched.
197 *****************************************************************************/
198 
199 GLOBAL	charptr	EndSAr;			/* end of search area */
200 
201 /*****************************************************************************
202 	Several TECO error messages take an argument.  For instance,  the
203 "illegal command"  error message shows the user the illegal command.  When
204 these kinds of messages are required,  ErrTxt is used to send the text
205 of the argument to the error display function (ErrMsg).
206 *****************************************************************************/
207 
208 GLOBAL	char	ErrTxt[6];		/* holds part of error message */
209 
210 /*****************************************************************************
211 	The EsFlag flag controls what is displayed on the terminal after every
212 successful search command completes.  EsFlag has the following meanings:
213 
214         0         don't display anything
215         -1        display the line containing the found string
216         1-31      display the line containing the found string,
217                   with a line feed at the character position
218         32-126    display the line containing the found string,
219                   with the character whose ASCII code is represented
220                   by ES at the character position
221         m*265+n   n has the meanings defined above.  m is the number
222                   of lines above and below the found string to be
223                   displayed.
224 *****************************************************************************/
225 
226 GLOBAL	WORD	EsFlag = 0;		/* ES mode control flag */
227 
228 /*****************************************************************************
229 	The expression stack contains the components of TECO's numeric
230 expressions.  Each entry on the expression stack is either an OPERAND or
231 an OPERATOR (like +, -, /, *).
232 *****************************************************************************/
233 
234 GLOBAL	struct	EStck EStack[EXS_SIZE]; /* expression stack */
235 GLOBAL	WORD	EStBot;			/* expression stack bottom */
236 GLOBAL	WORD	EStTop;			/* top of expression stack */
237 
238 /*****************************************************************************
239 	Bits in EtFlag control TECO's handling of the terminal.  Definitions
240 of masks for each bit and the meaning of each bit can be found in TECOC.H.
241 Bits in EtFlag are initialized when the terminal is set up in the ZTrmnl
242 function.
243 *****************************************************************************/
244 
245 GLOBAL	WORD	EtFlag = 0;		/* ET mode control flag */
246 
247 /*****************************************************************************
248 	The EuFlag is TECO's case mode control flag.  This flag allows TECO to
249 be used to input and output upper and lower case characters even if the
250 terminal being used is capable of displaying only uppercase characters.  If
251 the EU flag is -1, no case flagging is performed on type-out.  If the EU flag
252 is 0,  lowercase characters are converted to uppercase on type-out,  and are
253 preceded by a ' character.  If the EU flag is 1, then lowercase characters
254 are converted to uppercase on type-out,  but uppercase characters are
255 preceded by a ' character.
256 *****************************************************************************/
257 
258 GLOBAL	WORD	EuFlag = EU_NONE;	/* EU mode control flag */
259 
260 /*****************************************************************************
261 	The EV mode control flag controls what is displayed on the terminal
262 after every successful command string completes.  By default, nothing is
263 displayed (EV is 0).  EV has the following meanings:
264 
265         0         don't display anything
266         -1        display the line containing the character position
267         1-31      display the line containing the character position,
268                   with a line feed at the character position
269         32-126    display the line containing the character position,
270                   with the character whose ASCII code is represented
271                   by ES at the character position
272         m*265+n   n has the meanings defined above.  m is the number
273                   of lines above and below the character position to be
274                   displayed.
275 *****************************************************************************/
276 
277 GLOBAL	WORD	EvFlag = 0;		/* EV mode control flag */
278 
279 /*****************************************************************************
280 	These variables point to the filename buffer.
281 *****************************************************************************/
282 
283 GLOBAL	charptr	FBfBeg;			/* first char of filename buffer */
284 GLOBAL	charptr	FBfEnd;			/* last chr (+1) of filename buffer */
285 GLOBAL	charptr	FBfPtr;			/* pointer into file spec buffer */
286 
287 /*****************************************************************************
288 	Bits in the EzFlag are system-specific.  See the system-specific
289 file for each operating system (like ZVMS.C, ZUNIX.C, etc) for the meanings
290 of these bits.
291 *****************************************************************************/
292 
293 GLOBAL	WORD	EzFlag = 0;		/* EZ mode control flag */
294 
295 /*****************************************************************************
296 	FFPage is the value which is returned by the ^E command.  It is -1 if
297 the buffer currently contains a page of text that was terminated by a form
298 feed in the input file.  It is 0 if the buffer contains only part of a page
299 from the input file (because the input page filled the text buffer before it
300 was completely read in).  The FFPage flag is tested by the P command and
301 related operations to determine if a form feed should be appended to the
302 contents of the buffer when it is output.
303 *****************************************************************************/
304 
305 GLOBAL	LONG	FFPage = 0;		/* form feed flag (see ^E command) */
306 
307 /*****************************************************************************
308 	These variables point to the first and last characters in the edit
309 buffer gap.  See file PG.MEM for a description of memory management.
310 *****************************************************************************/
311 
312 GLOBAL	charptr	GapBeg;			/* first char in edit buffer gap */
313 GLOBAL	charptr	GapEnd;			/* last char in edit buffer gap */
314 
315 /*****************************************************************************
316 	GotCtC indicates that the user has interrupted the normal execution
317 of TECO-C by typing a control-C.  This variable is set by the special
318 interrupt-handling function executed when a control-C is struck,  and is
319 cleared before a command string is entered.  It is tested each time a command
320 terminates and when certain commands execute time-consuming loops.
321 *****************************************************************************/
322 
323 GLOBALV	BOOLEAN	GotCtC = FALSE;
324 
325 /*****************************************************************************
326 	IBfEnd is the end of the input buffer.  See file PG.MEM for a
327 description of memory management.
328 *****************************************************************************/
329 
330 GLOBAL	charptr	IBfEnd;
331 
332 /*****************************************************************************
333 	IniSrM is the initial search mode.  It is used when parsing search
334 strings and filenames.  The value of this variable is set by ^V and
335 ^W characters and is used to explicitly control the case (upper or lower) of
336 characters in a string.  It can take on the values LOWER, UPPER or NONE,
337 which are defined in TECOC.H.
338 *****************************************************************************/
339 
340 GLOBAL	int	IniSrM = NONE;
341 
342 /*****************************************************************************
343 	IsOpnI and IsOpnO contain indicators about the status of the file
344 data blocks in the IFiles and OFiles arrays,  respectively.  An element has
345 the value TRUE when the corresponding file data block reflects an opened file.
346 IsEofI indicates that the corresponding element of IFiles reflects a file
347 that has reached the end.
348 *****************************************************************************/
349 
350 GLOBAL	BOOLEAN	IsEofI[NIFDBS];
351 GLOBAL	BOOLEAN	IsOpnI[NIFDBS];
352 GLOBAL	BOOLEAN	IsOpnO[NOFDBS];
353 
354 /*****************************************************************************
355 	LstErr holds the code for the last error reported by TECO-C.  It is
356 set in the error display function (ErrMsg) and used when the user executes
357 the ? or / immediate mode commands,  to print out more information about the
358 last error that occurred.
359 *****************************************************************************/
360 
361 GLOBAL	WORD	LstErr = ERR_XXX;	/* number of last error message */
362 
363 /*****************************************************************************
364 	The loop stack maintains pointers to the first character of each loop
365 (the character following the "<").  LStTop is the element of LStack that
366 relates to the most recently executed "<" command.  LStBot is the index of
367 the bottom of the stack,  so that if (LStTop == LStBot),  we're not in a loop
368 in the current macro level.  When a macro is entered,  LStTop and LStBot are
369 saved on the macro stack,  and LStBot is set to LStTop,  so that LStBot
370 defines the bottom of the LStack frame for the new macro level.
371 *****************************************************************************/
372 
373 GLOBAL	WORD	LStBot;			/* bottom of loop stack */
374 GLOBAL	struct	LStck LStack[LPS_SIZE]; /* loop stack */
375 GLOBAL	WORD	LStTop;			/* top of loop stack */
376 
377 /*****************************************************************************
378 	MArgmt contains the m part of an m,n argument pair that precedes a
379 TECO command.  For instance,  MArgmt would contain 10 when the command
380 10,45T is being executed.
381 *****************************************************************************/
382 
383 GLOBAL	LONG	MArgmt;			/* m part of m,n numeric arguments */
384 
385 /*****************************************************************************
386 	MAtchd is used to indicate that a match has been found for a search
387 string.  It is only used when a search command is being executed.
388 *****************************************************************************/
389 
390 GLOBAL	BOOLEAN	Matchd;			/* indicates successful search */
391 
392 /*****************************************************************************
393 	These variables implement the macro stack.  When TECO executes a
394 macro,  it must first save the current state,  so that the state can be
395 restored when the macro has finished executing.  Each entry in the macro
396 stack preserves the critical variables for one macro call.
397 *****************************************************************************/
398 
399 GLOBAL	struct	MStck MStack[MCS_SIZE]; /* macro stack */
400 GLOBAL	WORD	MStTop = -1;		/* top of macro stack */
401 
402 /*****************************************************************************
403 	NArgmt holds the numeric argument that precedes a command.  It is set
404 by a call to the GetNmA function.  When the command is preceded by an m,n
405 argument pair,  NArgmt holds the value of the n argument.
406 *****************************************************************************/
407 
408 GLOBAL	LONG	NArgmt;			/* n argument (n part of m,n) */
409 
410 /*****************************************************************************
411 	QR is a pointer to a structure which defines a q-register.
412 It is set by calling the FindQR function.  Whenever a command that uses a
413 q-register is executed,  FindQR is called first to set QR.
414 *****************************************************************************/
415 
416 GLOBAL	QRptr	QR;
417 
418 /*****************************************************************************
419 	The structures in the QRgstr array represent the global and main-level
420 local q-registers.  The 0-9 elements are for global digit q-registers (0-9),
421 the 10-35 elements are for global alphabetic q-registers (a-z or A-Z),  the
422 36-45 elements are for main-level local digit q-registers (.0-.9) and the
423 46-71 elements are for main-level local alphabetic q-registers (.a-.z or
424 .A-.Z).  Local q-registers at macro levels other than the main level are
425 allocated dynamically.
426 *****************************************************************************/
427 
428 GLOBAL	struct	QReg QRgstr[72];
429 
430 /*****************************************************************************
431 	QStack is the q-register stack,  accessed via the [ and ] commands.
432 *****************************************************************************/
433 
434 GLOBAL	struct	QReg QStack[QRS_SIZE];	/* q-register stack */
435 GLOBAL	WORD	QStTop = -1;		/* top of q-register stack */
436 
437 /*****************************************************************************
438 	RefLen is the length of the last inserted string or found search
439 string.  It is accessed by the ^S command.
440 *****************************************************************************/
441 
442 GLOBAL	LONG	RefLen = 0;		/* returned by ^S */
443 
444 /*****************************************************************************
445 	Radix is TECO's radix,  usually 10.  It is set by the ^D, ^O and ^R
446 commands.
447 *****************************************************************************/
448 
449 GLOBAL	DEFAULT	Radix = 10;		/* TECO's current radix */
450 
451 /*****************************************************************************
452 	When searching,  this pointer points to the farthest-right character
453 in the area to be searched.  It is used after the first character of a string
454 has been found,  to indicate the limit of the area in the edit buffer that
455 should be checked against the remaining characters in the search string.
456 *****************************************************************************/
457 
458 GLOBAL	charptr	RhtSid;
459 
460 /*****************************************************************************
461 	These variables point to the search string buffer.  The search buffer
462 is allocated by function MemIni.
463 *****************************************************************************/
464 
465 GLOBAL	charptr	SBfBeg = NULL;		/* start of search buffer */
466 GLOBAL	charptr	SBfEnd;			/* end search buffer */
467 GLOBAL	charptr	SBfPtr;			/* end of search string buffer */
468 
469 /*****************************************************************************
470 	SIncrm is the value added to the search pointer when the edit buffer
471 is being searched.  If SIncrm is 1,  then the search proceeds in a forward
472 direction.  If SIncrm is -1,  then the search proceeds in a backward
473 direction.  By using this variable,  the rather complex code that implements
474 searching can easily be used to search in either direction.
475 *****************************************************************************/
476 
477 GLOBAL	LONG	SIncrm;			/* search increment */
478 
479 /*****************************************************************************
480 	SMFlag is TECOC's search mode flag,  and controls case sensitivity
481 during searches.  This variable holds the value of the ^X command.
482 *****************************************************************************/
483 
484 GLOBAL	WORD	SMFlag = 0;		/* search mode control flag (^X) */
485 
486 /*****************************************************************************
487 	SrcTyp is used to "remember" the kind of search command that we're
488 working on.  The same search code is used by all the search commands,  but
489 each search command is slightly different than the others.  The common
490 search code tests this variable to implement the differences.
491 *****************************************************************************/
492 
493 GLOBAL	WORD	SrcTyp;			/* type of search (E_SEARCH, etc) */
494 
495 /*****************************************************************************
496 	SStPtr points into the search buffer,  and is used only by the search
497 code.
498 *****************************************************************************/
499 
500 GLOBAL	charptr	SStPtr;		/* search string pointer */
501 
502 /*****************************************************************************
503 	This table serves two functions.  It is used by the character macros
504 defined in CHMACS.H.  It is also used by the command line input code in
505 function ReadCS.
506 	The top four bits of each mask are used by the functions in CHMACS.H.
507 The top four bits are masks used to represent "uppercase", "lowercase",
508 "digit" and "line terminator".
509 	The bottom four bits of each mask are used by function ReadCS.  They
510 are treated as a number and are used in a SWITCH statement.  In ReadCS,  the
511 top four bits of each mask are not used.
512 *****************************************************************************/
513 
514 unsigned char ChrMsk[256] =
515 		{
516 		RCS_DEF,		/* null */
517 		RCS_CCH,		/* ^A */
518 		RCS_CCH,		/* ^B */
519 		RCS_CTC,		/* ^C */
520 		RCS_CCH,		/* ^D */
521 		RCS_CCH,		/* ^E */
522 		RCS_CCH,		/* ^F */
523 		RCS_CTG,		/* ^G (bell) */
524 		RCS_BS,			/* ^H (bs) */
525 		RCS_DEF,		/* ^I (tab) */
526 		RCS_LF | CM_LINE_TERM,	/* ^J (lf) */
527 		RCS_VF | CM_LINE_TERM,	/* ^K (vt) */
528 		RCS_VF | CM_LINE_TERM,	/* ^L (ff) */
529 		RCS_CR,			/* ^M (cr) */
530 		RCS_CCH,		/* ^N */
531 		RCS_CCH,		/* ^O */
532 		RCS_CCH,		/* ^P */
533 		RCS_CCH,		/* ^Q */
534 		RCS_CCH,		/* ^R */
535 		RCS_CCH,		/* ^S */
536 		RCS_CCH,		/* ^T */
537 		RCS_CTU,		/* ^U */
538 		RCS_CCH,		/* ^V */
539 		RCS_CCH,		/* ^W */
540 		RCS_CCH,		/* ^X */
541 		RCS_CCH,		/* ^Y */
542 		RCS_CTZ,		/* ^Z */
543 		0,			/* escape */
544 		RCS_CCH,		/* FS */
545 		RCS_CCH,		/* GS */
546 		RCS_CCH,		/* RS */
547 		RCS_CCH,		/* US */
548 		RCS_SP,			/* space */
549 		RCS_DEF,		/* ! */
550 		RCS_DEF,		/* " */
551 		RCS_DEF,		/* # */
552 		RCS_DEF,		/* $ */
553 		RCS_DEF,		/* % */
554 		RCS_DEF,		/* | */
555 		RCS_DEF,		/* ' */
556 		RCS_DEF,		/* ( */
557 		RCS_DEF,		/* ) */
558 		RCS_AST,		/* * */
559 		RCS_DEF,		/* + */
560 		RCS_DEF,		/* , */
561 		RCS_DEF,		/* - */
562 		RCS_DEF,		/* . */
563 		RCS_DEF,		/* / */
564 		RCS_DEF | CM_DIGIT,	/* 0 */
565 		RCS_DEF | CM_DIGIT,	/* 1 */
566 		RCS_DEF | CM_DIGIT,	/* 2 */
567 		RCS_DEF | CM_DIGIT,	/* 3 */
568 		RCS_DEF | CM_DIGIT,	/* 4 */
569 		RCS_DEF | CM_DIGIT,	/* 5 */
570 		RCS_DEF | CM_DIGIT,	/* 6 */
571 		RCS_DEF | CM_DIGIT,	/* 7 */
572 		RCS_DEF | CM_DIGIT,	/* 8 */
573 		RCS_DEF | CM_DIGIT,	/* 9 */
574 		RCS_DEF,		/* : */
575 		RCS_DEF,		/* ; */
576 		RCS_DEF,		/* < */
577 		RCS_DEF,		/* = */
578 		RCS_DEF,		/* > */
579 		RCS_DEF,		/* ? */
580 		RCS_DEF,		/* @ */
581 		RCS_DEF | CM_UPPER,	/* A */
582 		RCS_DEF | CM_UPPER,	/* B */
583 		RCS_DEF | CM_UPPER,	/* C */
584 		RCS_DEF | CM_UPPER,	/* D */
585 		RCS_DEF | CM_UPPER,	/* E */
586 		RCS_DEF | CM_UPPER,	/* F */
587 		RCS_DEF | CM_UPPER,	/* G */
588 		RCS_DEF | CM_UPPER,	/* H */
589 		RCS_DEF | CM_UPPER,	/* I */
590 		RCS_DEF | CM_UPPER,	/* J */
591 		RCS_DEF | CM_UPPER,	/* K */
592 		RCS_DEF | CM_UPPER,	/* L */
593 		RCS_DEF | CM_UPPER,	/* M */
594 		RCS_DEF | CM_UPPER,	/* N */
595 		RCS_DEF | CM_UPPER,	/* O */
596 		RCS_DEF | CM_UPPER,	/* P */
597 		RCS_DEF | CM_UPPER,	/* Q */
598 		RCS_DEF | CM_UPPER,	/* R */
599 		RCS_DEF | CM_UPPER,	/* S */
600 		RCS_DEF | CM_UPPER,	/* T */
601 		RCS_DEF | CM_UPPER,	/* U */
602 		RCS_DEF | CM_UPPER,	/* V */
603 		RCS_DEF | CM_UPPER,	/* W */
604 		RCS_DEF | CM_UPPER,	/* X */
605 		RCS_DEF | CM_UPPER,	/* Y */
606 		RCS_DEF | CM_UPPER,	/* Z */
607 		RCS_DEF,		/* [ */
608 		RCS_DEF,		/* \ */
609 		RCS_DEF,		/* ] */
610 		RCS_DEF,		/* ^ */
611 		RCS_DEF,		/* _ */
612 		RCS_GRV,		/* ` */
613 		RCS_LWR | CM_LOWER,	/* a */
614 		RCS_LWR | CM_LOWER,	/* b */
615 		RCS_LWR | CM_LOWER,	/* c */
616 		RCS_LWR | CM_LOWER,	/* d */
617 		RCS_LWR | CM_LOWER,	/* e */
618 		RCS_LWR | CM_LOWER,	/* f */
619 		RCS_LWR | CM_LOWER,	/* g */
620 		RCS_LWR | CM_LOWER,	/* h */
621 		RCS_LWR | CM_LOWER,	/* i */
622 		RCS_LWR | CM_LOWER,	/* j */
623 		RCS_LWR | CM_LOWER,	/* k */
624 		RCS_LWR | CM_LOWER,	/* l */
625 		RCS_LWR | CM_LOWER,	/* m */
626 		RCS_LWR | CM_LOWER,	/* n */
627 		RCS_LWR | CM_LOWER,	/* o */
628 		RCS_LWR | CM_LOWER,	/* p */
629 		RCS_LWR | CM_LOWER,	/* q */
630 		RCS_LWR | CM_LOWER,	/* r */
631 		RCS_LWR | CM_LOWER,	/* s */
632 		RCS_LWR | CM_LOWER,	/* t */
633 		RCS_LWR | CM_LOWER,	/* u */
634 		RCS_LWR | CM_LOWER,	/* v */
635 		RCS_LWR | CM_LOWER,	/* w */
636 		RCS_LWR | CM_LOWER,	/* x */
637 		RCS_LWR | CM_LOWER,	/* y */
638 		RCS_LWR | CM_LOWER,	/* z */
639 		RCS_DEF,		/* { */
640 		RCS_DEF,		/* | */
641 		RCS_DEF,		/* } */
642 		RCS_DEF,		/* ~ */
643 		RCS_DEL,		/* delete */
644 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
645 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
646 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
647 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
648 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
649 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
650 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
651 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
652 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
653 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
654 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
655 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
656 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
657 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
658 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,
659 	RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF
660 	};
661 
662 /*****************************************************************************
663 	TraceM is the trace mode flag.  This variable is set to TRUE when
664 TECO's trace mode is on.  When it is set,  commands are echoed to the terminal
665 as they are executed.  This mode is used to aid in debugging TECO macros,  and
666 is toggled by the ? command.
667 	If you want to trace the command line parsing macro executed in
668 ZPrsCL(), set this to TRUE; otherwise, set it to FALSE.
669 *****************************************************************************/
670 
671 GLOBAL	BOOLEAN	TraceM = FALSE;		/* trace mode flag */
672 
673 /*****************************************************************************
674 	CrType is the terminal type.  It is used by the ZScrOp function to
675 drive the few screen capabilities of TECOC.  See ZScrOp for a list of the
676 values that CrType can take.
677 *****************************************************************************/
678 
679 GLOBAL	DEFAULT	CrType = UNTERM;	/* terminal type */
680 
681 #if VIDEO
682 GLOBAL DEFAULT	HldFlg;			/* value of 5:W (hold mode flag) */
683 GLOBAL DEFAULT	HtSize;			/* value of 1:W (screen width) */
684 GLOBAL DEFAULT	MrkFlg;			/* value of 4:W */
685 GLOBAL DEFAULT	ScroLn;			/* value of 7:W */
686 GLOBAL DEFAULT	SeeAll;			/* value of 3:W */
687 GLOBAL DEFAULT	TopDot;			/* value of 6:W */
688 GLOBAL DEFAULT	VtSize;			/* value of 2:W (screen height) */
689 #if CURSES
690 GLOBAL DEFAULT	SpcMrk = 0;		/* value of 8:W */
691 GLOBAL DEFAULT	KeyPad;			/* value of 9:W */
692 #endif
693 #endif
694 
695 /*****************************************************************************
696 	S t a r t   H e r e
697 *****************************************************************************/
698 
main(argc,argv)699 int _Cdecl main(argc, argv)		/* _Cdecl defined in ZPORT.H */
700 int argc;
701 char **argv;
702 {
703 
704 #if CHECKSUM_CODE			/* MS-DOS debugging code */
705 	init_code_checksums ();		/* calculate code checksums */
706 #endif
707 
708 	Init(argc, argv);		/* initialize TECO */
709 
710 /*
711  * read a command string and then execute it.  This loop is infinite.
712  * TECO-C is exited explicitly when a lower-level function calls TAbort.
713  */
714 
715 	CStBeg = CStEnd = CBfBeg;
716 	CStEnd--;
717 	FOREVER {			/* loop forever */
718 		ReadCS();		/* read command string */
719 		CBfPtr = CBfBeg;	/* initialize command string ptr */
720 		CmdMod = '\0';		/* clear modifiers flags */
721 		EStTop = EStBot =	/* clear expression stack */
722 		LStTop = LStBot =	/* clear loop stack */
723 		MStTop = -1;		/* clear macro stack */
724 		ExeCSt();		/* execute command string */
725 	}
726 }
727 
728 /*****************************************************************************
729 	The following code is support routines for the imbedded debugging code
730 in TECO-C.  If the "DEBUGGING" macro in ZPORT.H is set to "FALSE", then none
731 of this code is compiled.
732 *****************************************************************************/
733 
734 #if DEBUGGING
735 
736 #include <ctype.h>		/* isprint() macro */
737 #include "dchars.h"		/* define identifiers for characters */
738 
739 static	DEFAULT	DbgInd = 0;	/* debugging indent level */
740 static	DEFAULT	DbgLvl = 0;	/* debugging message level */
741 
742 #define DBGSBF	4000		/* huge buffer to avoid overruns */
743 
744 GLOBAL	char DbgSBf[DBGSBF+1];	/* sprintf() buffer for debugging messages */
745 
746 #if USE_PROTOTYPES
747 static VVOID DbgDMs(		/* debugging, display message */
748 	int DbgFLv,		/*   function display level */
749 	char *DbgFNm,		/*   function name */
750 	char *DbgWht,		/*   "called", "returning", or blank */
751 	char *DbgMsg);		/*   message to display */
752 static VVOID DbgDsA(void);	/* display address variables */
753 static VVOID DbgEBf(void);	/* display edit buffer details */
754 static VVOID DbgHlp(void);	/* display help message */
755 static VVOID DbgLSt(void);	/* display loop stack details */
756 static VVOID DbgMSt(void);	/* display macro stack details */
757 static VVOID DbgPrP(		/* display a pointer */
758 	char *s,
759 	voidptr ptr);
760 static VVOID DbgQRg(void);	/* display Q-register's */
761 static VVOID DbgQSt(void);	/* display Q-register stack */
762 static VVOID DbgSLv(void);	/* set debugging message level */
763 #endif
764 
765 /*****************************************************************************
766 
767 	DbgDsA()
768 
769 	This function displays details about address variables for 1^P.
770 
771 *****************************************************************************/
772 
773 
DbgPrP(s,ptr)774 static VVOID DbgPrP (s, ptr)	/* display a pointer */
775 char *s;
776 voidptr ptr;
777 {
778 	printf ("%s %lu", s, Zcp2ul(ptr));
779 }
780 
781 
DbgDsA()782 static VVOID DbgDsA()
783 {
784 	int	length;
785 
786 	DbgPrP ("\r\nAraBeg =", AraBeg);
787 	DbgPrP ("\tEBfBeg =",   EBfBeg);
788 	DbgPrP ("\tGapBeg =",   GapBeg);
789 
790 	DbgPrP ("\r\nAraEnd =", AraEnd);
791 	DbgPrP ("\tEBfEnd =",   EBfEnd);
792 	DbgPrP ("\tGapEnd =",   GapEnd);
793 
794 	DbgPrP ("\r\nCBfBeg =", CBfBeg);
795 	DbgPrP ("\tCStBeg =",   CStBeg);
796 	DbgPrP ("\tFBfBeg =",   FBfBeg);
797 
798 	DbgPrP ("\r\nCBfEnd =", CBfEnd);
799 	DbgPrP ("\tCStEnd =",   CStEnd);
800 	DbgPrP ("\tFBfEnd =",   FBfEnd);
801 
802 	DbgPrP ("\r\nSBfBeg =", SBfBeg);
803 	DbgPrP ("\tEBPtr1 =",   EBPtr1);
804 	DbgPrP ("\tEBPtr2 =",   EBPtr2);
805 
806 	DbgPrP ("\r\nSBfPtr =", SBfPtr);
807 	DbgPrP ("\tCBfPtr =",   CBfPtr);
808 
809 	DbgPrP ("\r\nSBfEnd =", SBfEnd);
810 	DbgPrP ("\tSStPtr =",   SStPtr);
811 
812 	printf ("\r\nsearch buffer = \"");
813 	if (SBfPtr != NULL) {
814 		length = (int) (SBfPtr-SBfBeg);
815 		if (length > 40) {
816 			length = 40;
817 		}
818 		printf ("%.*s", length, SBfBeg);
819 	} else {
820 		length = 0;
821 	}
822 	printf("\"\r\n");
823 }
824 
825 /*****************************************************************************
826 
827 	DbgEBf()
828 
829 	This function displays details about the edit buffer for 2^P.
830 
831 *****************************************************************************/
832 
DbgEBf()833 static VVOID DbgEBf()
834 {
835 	charptr	DbgPtr;
836 
837 	DbgPrP ("\r\nEBfBeg =", EBfBeg);
838 	DbgPrP ("\tGapBeg =",   GapBeg);
839 	printf (" (%ld bytes)", (LONG) (GapBeg - EBfBeg));
840 
841 	DbgPrP ("\r\nGapBeg =", GapBeg);
842 	DbgPrP ("\tGapEnd =",   GapEnd);
843 	printf (" (%ld bytes)", (LONG) (GapEnd - GapBeg));
844 
845 	DbgPrP ("\r\nGapEnd =", GapEnd);
846 	DbgPrP ("\tEBfEnd =",   EBfEnd);
847 	printf (" (%ld bytes)", (LONG) (EBfEnd - GapEnd));
848 
849 	DbgPrP ("\r\nEBfEnd =", EBfEnd);
850 	DbgPrP ("\tIBfEnd =",   IBfEnd);
851 	printf (" (%ld bytes)", (LONG) (IBfEnd - EBfEnd));
852 
853 	DbgPrP ("\r\nEBfBeg =", EBfBeg);
854 	DbgPrP ("\tIBfEnd =",   IBfEnd);
855 	printf (" (%ld bytes)", (LONG) (IBfEnd - EBfBeg));
856 
857 	for (DbgPtr = EBfBeg; DbgPtr < GapBeg; ++DbgPtr) {
858 		DbgPrP ("\r\nDbgEBf: first half, char at", DbgPtr);
859 		printf((isprint(*DbgPtr) ? " '%c'" : " <%d>"), *DbgPtr);
860 	}
861 
862 	for (DbgPtr = (GapEnd+1); DbgPtr <= EBfEnd; ++DbgPtr) {
863 		DbgPrP ("\r\nDbgEBf: second half, char at", DbgPtr);
864 		printf((isprint(*DbgPtr) ? " '%c'" : " <%d>"), *DbgPtr);
865 	}
866 	puts ("\r");
867 }
868 
869 /*****************************************************************************
870 
871 	DbgHlp()
872 
873 	This function displays help on ^P commands for ^P with no arguments.
874 
875 *****************************************************************************/
876 
DbgHlp()877 static VVOID DbgHlp()
878 {
879 	puts("\r\n\tArguments to ^P have the following meanings:\r\n");
880 	puts("\t\t^P\tno arguments - display help about ^P\r");
881 	puts("\t\tm,0\tset debugging message level to m (0-5)\r");
882 	puts("\t\t1\tdisplay global address variables\r");
883 	puts("\t\t2\tdisplay details about the edit buffer\r");
884 	puts("\t\t3\tdisplay the loop stack\r");
885 	puts("\t\t4\tdisplay the macro stack\r");
886 	puts("\t\t5\tdisplay details about the q-registers\r");
887 	puts("\t\t6\tdisplay the q-register stack\r\r\r");
888 }
889 
890 /*****************************************************************************
891 
892 	DbgLSt ()
893 
894 	This function displays details about the loop stack for 3^P.
895 
896 *****************************************************************************/
897 
DbgLSt()898 static VVOID DbgLSt()
899 {
900 	int	i;
901 
902 	printf ("\r\nLoop stack:  LStBot = %d, LstTop = %d\r\n\n", LStBot, LStTop);
903 	printf (" #     LIndex      LAddr\r\n");
904 	printf ("-- ---------- ----------\r\n");
905 
906 	for (i = 0; i <= LStTop; ++i) {
907 		printf("%2d %10ld %10lu\r\n",
908 			i, LStack[i].LIndex, Zcp2ul(LStack[i].LAddr));
909 	}
910 }
911 
912 /*****************************************************************************
913 
914 	DbgDMs()
915 
916 	This function displays a debugging message at the right indentation
917 level, in reverse video, if the debugging level is appropriate for the
918 message.  It also optionally calls the consistency_check() and the
919 check_code_checksums() routines while debugging.
920 	The debugging levels are:
921 
922 	1	command functions
923 	2	functions called by command functions
924 	3	everything but stuff that's too noisy
925 	4	everything
926 
927 *****************************************************************************/
928 
DbgDMs(DbgFLv,DbgFNm,DbgWht,DbgMsg)929 static VVOID DbgDMs(DbgFLv, DbgFNm, DbgWht, DbgMsg)
930 int DbgFLv;				/* function display level */
931 char *DbgFNm;				/* function name */
932 char *DbgWht;				/* "called", "returning", or blank */
933 char *DbgMsg;				/* message to display */
934 {
935 	if (DbgFLv <= DbgLvl) {			/* is message at right level */
936 		printf ("%*s", DbgInd, "");	/* indent message */
937 		ZScrOp(SCR_RON);		/* turn on reverse video */
938 		printf ("%s: %s %s\r\n",
939 			DbgFNm,
940 			DbgWht,
941 			(DbgMsg == NULL) ? "" : DbgMsg);
942 		ZScrOp(SCR_ROF);		/* turn off reverse video */
943 	}
944 	if (DbgMsg == DbgSBf) {			/* clear sprintf() buffer */
945 		DbgSBf[0] = '\0';
946 	}
947 	if (DbgSBf[DBGSBF] != '\0') {		/* check sprintf() overrun */
948 		puts("DbgSBf[] overrun");
949 		exit(EXIT_FAILURE);
950 	}
951 
952 /*
953  * If you enable consistency checking and code checksumming here, pointers
954  * and code will be checked on every function entry and exit in addition to
955  * being checked after every successful command execution in ExeCSt().
956  *
957  * Enabling code checksumming here r-e-a-l-l-y slows things down.
958  */
959 
960 #if CONSISTENCY_CHECKING
961 	check_consistency ();
962 #endif
963 
964 #if 0 && CHECKSUM_CODE				/* MS-DOS debugging code */
965 	check_code_checksums ();
966 #endif
967 }
968 
969 /*****************************************************************************
970 
971 	DbgFEn()
972 
973 	This function is called as the first thing upon entry to a function.
974 
975 *****************************************************************************/
976 
DbgFEn(DbgFLv,DbgFNm,DbgMsg)977 VVOID DbgFEn(DbgFLv, DbgFNm, DbgMsg)	/* debugging, function entry */
978 int DbgFLv;				/*   function display level */
979 char *DbgFNm;				/*   function name */
980 char *DbgMsg;				/*   a function entry message */
981 {
982 	DbgInd += 2;
983 	DbgDMs(DbgFLv, DbgFNm, "called", DbgMsg);
984 }
985 
986 /*****************************************************************************
987 
988 	DbgFEx()
989 
990 	This function is called as the last thing before a function returns.
991 
992 *****************************************************************************/
993 
DbgFEx(DbgFLv,DbgFNm,DbgMsg)994 VVOID DbgFEx(DbgFLv, DbgFNm, DbgMsg)
995 int DbgFLv;
996 char *DbgFNm;
997 char *DbgMsg;
998 {
999 	DbgDMs(DbgFLv, DbgFNm, "returning", DbgMsg);
1000 	DbgInd -= 2;
1001 }
1002 
1003 /*****************************************************************************
1004 
1005 	DbgFMs()
1006 
1007 	This function is called in the middle of a routine if the routine
1008 has something special to say.
1009 
1010 *****************************************************************************/
1011 
DbgFMs(DbgFLv,DbgFNm,DbgMsg)1012 VVOID DbgFMs(DbgFLv, DbgFNm, DbgMsg)	/* debugging, function message */
1013 int DbgFLv;				/*   function display level */
1014 char *DbgFNm;				/*   function name */
1015 char *DbgMsg;				/*   a debugging message */
1016 {
1017 	DbgDMs(DbgFLv, DbgFNm, "", DbgMsg);
1018 }
1019 
1020 /*****************************************************************************
1021 
1022 	DbgMSt()
1023 
1024 	This function displays details about the macro stack for 4^P.
1025 
1026 *****************************************************************************/
1027 
DbgMSt()1028 static VVOID DbgMSt()
1029 {
1030 	int	i;
1031 	MSptr	MSp;
1032 
1033 	printf("Macro Stack, MStTop = %d\r\n\n", MStTop);
1034 	printf(" #   CStBeg   CBfPtr   CStEnd EStBot EStTop LStBot LStTop   QRgstr\r\n");
1035 	printf("-- -------- -------- -------- ------ ------ ------ ------ --------\r\n");
1036 
1037 	for (MSp = MStack, i = 0; i <= MStTop; ++i, ++MSp) {
1038 		printf("%2d %8lu %8lu %8lu %6d %6d %6d %6d %8lu\r\n",
1039 			i,
1040 			Zcp2ul(MSp->CStBeg),
1041 			Zcp2ul(MSp->CBfPtr),
1042 			Zcp2ul(MSp->CStEnd),
1043 			MSp->EStBot,
1044 			MSp->EStTop,
1045 			MSp->LStBot,
1046 			MSp->LStTop,
1047 			Zcp2ul(MSp->QRgstr));
1048 	}
1049 }
1050 
1051 /*****************************************************************************
1052 
1053 	DbgQRg()
1054 
1055 	This function displays details about global Q-registers for 5^P.
1056 
1057 *****************************************************************************/
1058 
DbgQRg()1059 static VVOID DbgQRg()
1060 {
1061 	int	i;
1062 	int	length;
1063 	charptr	cp;
1064 	QRptr	QRp;
1065 
1066 	printf ("Non-empty Q-registers:\r\n\n");
1067 	printf (" #  Number   Start  End_P1 Text (possibly truncated)\r\n");
1068 	printf ("-- ------- ------- ------- --------------------------------------------------\r\n");
1069 
1070 	for (i = 0, QRp = QRgstr; i < 72; ++i, ++QRp) {
1071 		if (QRp->Number != 0 || QRp->Start != NULL) {
1072 			printf ("%c%c %7ld %7lu %7lu \"",
1073 				(i < 36) ? ' ' : '.',
1074 				i + ((i <= 9) ? '0' : 'A' - 10),
1075 				QRp->Number,
1076 				Zcp2ul(QRp->Start),
1077 				Zcp2ul(QRp->End_P1));
1078 
1079 			if (QRp->Start != NULL) {
1080 				length = (int) (QRp->End_P1 - QRp->Start);
1081 				if (length > 50) {
1082 					length = 50;
1083 				}
1084 				cp = QRp->Start;
1085 				while (length-- > 0) {
1086 					if (*cp < ' ') {
1087 						ZDspCh ('^');
1088 						ZDspCh (*cp + '@');
1089 						--length;
1090 					} else {
1091 						ZDspCh (*cp);
1092 					}
1093 					++cp;
1094 				}
1095 			}
1096 			printf ("\"\r\n");
1097 		}
1098 	}
1099 	printf ("\r\n");
1100 }
1101 
1102 /*****************************************************************************
1103 
1104 	DbgQSt()
1105 
1106 	This function displays details about the Q-register stack for 6^P.
1107 
1108 *****************************************************************************/
1109 
DbgQSt()1110 static VVOID DbgQSt()
1111 {
1112 	int	i;
1113 	int	length;
1114 	charptr	cp;
1115 	QRptr	QRp;
1116 
1117 	printf("Q-register Stack, QStTop = %d\r\n\n", QStTop);
1118 	printf ("#  Number   Start  End_P1 Text (possibly truncated)\r\n");
1119 	printf ("-- ------- ------- ------- --------------------------------------------------\r\n");
1120 
1121 	for (QRp = QStack, i = 0; i <= QStTop; ++i, ++QRp) {
1122 		printf ("%2d %7ld %7lu %7lu \"",
1123 			i,
1124 			QRp->Number,
1125 			Zcp2ul(QRp->Start),
1126 			Zcp2ul(QRp->End_P1));
1127 		if (QRp->Start != NULL) {
1128 			length = (int) (QRp->End_P1 - QRp->Start);
1129 			if (length > 50) {
1130 				length = 50;
1131 			}
1132 			cp = QRp->Start;
1133 			while (length-- > 0) {
1134 				if (*cp < ' ') {
1135 					ZDspCh ('^');
1136 					ZDspCh (*cp + '@');
1137 				} else {
1138 					ZDspCh (*cp);
1139 				}
1140 				++cp;
1141 			}
1142 		}
1143 		printf ("\"\r\n");
1144 	}
1145 	printf ("\r\n");
1146 }
1147 
1148 /*****************************************************************************
1149 
1150 	DbgSLv()
1151 
1152 	This function sets DbgLvl,  which controls how much debugging
1153 information is displayed as TECO executes.  If DbgLvl is 0,  no debugging
1154 messages are displayed.  If (DbgLvl>=1),  then messages are displayed by
1155 all "Exexxx" functions.  This means that a message is displayed for each
1156 entry and exit of execution of a single command.  If (DbgLvl>=1) then in
1157 addition to the messages displayed for entry and exit of Exexxx functions,
1158 a message is displayed for the "next level down" functions.  This scheme
1159 is continued for DbgLvl >= 3, DbgLvl >= 4, etc.
1160 	In most cases,  setting DbgLvl to 1 and then executing a TECO
1161 command string will reveal an error.  For more detail, DbgLvl can be set
1162 to successively higher values.  Using DbgLvl,  you can trade-off the amount
1163 of time you wait for the messages to go by on the screen with the amount
1164 of detail that's needed.
1165 	By using this system,  debug messages that are placed into new code
1166 in order to debug it can be left in the code so they're useful later.
1167 
1168 *****************************************************************************/
1169 
DbgSLv()1170 static VVOID DbgSLv()
1171 {
1172 	DbgLvl = (DEFAULT)MArgmt;
1173 }
1174 
1175 /*****************************************************************************
1176 
1177 	DbgDsp()
1178 
1179 	This function provides control of the imbedded debugging system in
1180 TECO-C.  An unused command character (currently control-P), when executed by
1181 the user, causes this function to be executed.
1182 
1183 	Arguments to ^P have the following meanings:
1184 
1185 		no argument - display help about ^P
1186 		m,0	set debugging message level to m
1187 		1	display global address variables
1188 		2	display details about the edit buffer
1189 		3	display the loop stack
1190 		4	display the macro stack
1191 		5	display details about the q-registers
1192 
1193 *****************************************************************************/
1194 
DbgDsp()1195 DEFAULT DbgDsp()
1196 {
1197 	if (EStTop == EStBot) {			/* if no numeric argument */
1198 		ZScrOp(SCR_RON);		/* turn on reverse video */
1199 		DbgHlp();			/* display debugging help */
1200 		ZScrOp(SCR_ROF);		/* turn off reverse video */
1201 		return SUCCESS;
1202 	}
1203 
1204 	if (GetNmA() == FAILURE) {		/* get numeric argument */
1205 		return FAILURE;
1206 	}
1207 
1208 	if (CmdMod & MARGIS) {			/* if it's m,n^P */
1209 		DbgSLv();			/* set DbgLvl */
1210 		return SUCCESS;
1211 	}
1212 
1213 	ZScrOp(SCR_RON);		/* turn on reverse video */
1214 	switch ((int)NArgmt) {
1215 	    case 1: DbgDsA(); break;	/* display address variable details */
1216 	    case 2: DbgEBf(); break;	/* display edit buffer details */
1217 	    case 3: DbgLSt(); break;	/* display loop stack */
1218 	    case 4: DbgMSt(); break;	/* display macro stack */
1219 	    case 5: DbgQRg(); break;	/* display q-registers */
1220 	    case 6: DbgQSt(); break;	/* display q-register stack */
1221 	    default:
1222 		printf("bad argument to ^P command\r\n");
1223 		ZScrOp(SCR_ROF);	/* turn off reverse video */
1224 		return FAILURE;
1225 	}
1226 	ZScrOp(SCR_ROF);		/* turn off reverse video */
1227 	return SUCCESS;
1228 }
1229 
1230 #endif	/* #if DEBUGGING */
1231 
1232 /*****************************************************************************
1233 
1234 	The following code was needed while debugging TECO-C on the IBM PC
1235 with it's brain-damaged memory addressing scheme.  This code checks the
1236 "consistency" of various pointers, making sure some don't change throughout
1237 the execution of TECO-C and making sure others are in the right order.
1238 
1239 	After init_consistency_check() is called in Init(), the
1240 check_consistency() code is called in ExeCSt() after the successful
1241 completion of each command.  For more frequent checking, it can also
1242 be called in the DbgDMs() routine above but then the "DEBUGGING" macro
1243 in ZPORT.H has to be set to "TRUE" as well.
1244 
1245 	If the "CONSISTENCY_CHECKING" macro in ZPORT.H is set to "FALSE",
1246  then none of this code is compiled.
1247 
1248 *****************************************************************************/
1249 
1250 #if CONSISTENCY_CHECKING
1251 
1252 #if USE_PROTOTYPES
1253 static int errprt(char *str, voidptr p1, voidptr p2);
1254 #endif
1255 
1256 static	charptr	ss_CBfBeg;
1257 static	charptr	ss_CBfEnd;
1258 static	charptr	ss_FBfBeg;
1259 static	charptr	ss_FBfEnd;
1260 static	charptr	ss_SBfBeg;
1261 static	charptr	ss_SBfEnd;
1262 
init_consistency_check()1263 VVOID init_consistency_check()
1264 {
1265 	ss_CBfBeg = CBfBeg;
1266 	ss_CBfEnd = CBfEnd;
1267 	ss_FBfBeg = FBfBeg;
1268 	ss_FBfEnd = FBfEnd;
1269 	ss_SBfBeg = SBfBeg;
1270 	ss_SBfEnd = SBfEnd;
1271 }
1272 
1273 
errprt(str,p1,p2)1274 static int errprt(str, p1, p2)
1275 char *str;
1276 voidptr p1;
1277 voidptr p2;
1278 {
1279 	printf ("%s (%lu,%lu)\r\n", str, Zcp2ul(p1), Zcp2ul(p2));
1280 	return EXIT_FAILURE;
1281 }
1282 
1283 
1284 #if defined(__TURBOC__) && (__TURBOC__ >= 0x0295)
1285 #include <alloc.h>		/* prototype for heapcheck() */
1286 #endif
1287 
check_consistency()1288 VVOID check_consistency()
1289 {
1290     int ex = EXIT_SUCCESS;
1291 
1292 /*
1293  * is the heap corrupted?
1294  */
1295 
1296 #if defined(__TURBOC__) && (__TURBOC__ >= 0x0295)
1297 	if (heapcheck () < 0) {
1298 		puts ("check_consistency: heapcheck failed");
1299 		ex = EXIT_FAILURE;
1300 	}
1301 #endif
1302 
1303 /*
1304  * the following point to the start and end of various buffers which are
1305  * initialized at program startup and should not have changed.
1306  */
1307 
1308     if (ss_CBfBeg != CBfBeg) ex=errprt("ss_CBfBeg != CBfBeg",ss_CBfBeg,CBfBeg);
1309     if (ss_CBfEnd != CBfEnd) ex=errprt("ss_CBfEnd != CBfEnd",ss_CBfEnd,CBfEnd);
1310     if (ss_FBfBeg != FBfBeg) ex=errprt("ss_FBfBeg != FBfBeg",ss_FBfBeg,FBfBeg);
1311     if (ss_FBfEnd != FBfEnd) ex=errprt("ss_FBfEnd != FBfEnd",ss_FBfEnd,FBfEnd);
1312     if (ss_SBfBeg != SBfBeg) ex=errprt("ss_SBfBeg != SBfBeg",ss_SBfBeg,SBfBeg);
1313     if (ss_SBfEnd != SBfEnd) ex=errprt("ss_SBfEnd != SBfEnd",ss_SBfEnd,SBfEnd);
1314 
1315 /*
1316  * make sure the pointers into the above buffers are between the start
1317  * and end of the buffers
1318  *
1319  * Note: while doing an EI or M command, CBfPtr can point outside of
1320  * [CBfBeg..CBfEnd] but it is always within [CStBeg..CStEnd].
1321  */
1322 
1323     if (CBfPtr < CStBeg) ex=errprt("CBfPtr < CStBeg",CBfPtr,CStBeg);
1324     if (CBfPtr > CStEnd) ex=errprt("CBfPtr > CStEnd",CBfPtr,CStEnd);
1325     if (FBfPtr < FBfBeg) ex=errprt("FBfPtr < FBfBeg",FBfPtr,FBfBeg);
1326     if (FBfPtr > FBfEnd) ex=errprt("FBfPtr > FBfEnd",FBfPtr,FBfEnd);
1327     if (SBfPtr < SBfBeg) ex=errprt("SBfPtr < SBfBeg",SBfPtr,SBfBeg);
1328     if (SBfPtr > SBfEnd) ex=errprt("SBfPtr > SBfEnd",SBfPtr,SBfEnd);
1329 
1330 /*
1331  * The order of pointers into the editing buffer should be:
1332  *
1333  *   EBfBeg <= GapBeg <= GapEnd <= EBfEnd <= IBfEnd
1334  */
1335 
1336     if (EBfBeg > GapBeg) ex=errprt("EBfBeg > GapBeg",EBfBeg,GapBeg);
1337     if (GapBeg > GapEnd) ex=errprt("GapBeg > GapEnd",GapBeg,GapEnd);
1338     if (GapEnd > EBfEnd) ex=errprt("GapEnd > EBfEnd",GapEnd,EBfEnd);
1339     if (EBfEnd > IBfEnd) ex=errprt("EBfEnd > IBfEnd",EBfEnd,IBfEnd);
1340 
1341     if (ex == EXIT_FAILURE) {
1342 	exit(EXIT_FAILURE);
1343     }
1344 }
1345 
1346 #endif	/* #if CONSISTENCY_CHECKING */
1347