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