diff --git a/doc/changes.txt b/doc/changes.txt new file mode 100644 index 0000000..4cfb412 --- /dev/null +++ b/doc/changes.txt @@ -0,0 +1,996 @@ + This file contains release notes for TECOC. The "base version" +is 100 (reported by the EO command). The version number starts at 100 to +avoid confusion with TECO-11 version numbers, which were close to 40 as of +01-Jan-1987. + + +10-Dec-1987 version 100 + +baseline version as of Fall Decus Symposium, Anaheim + + +04-Jan-1988 version 101 (mostly stuff for XENIX) + +1. created this file +2. changed EXEEO.C to make the version number 101. +3. changed FBFSIZ (file name size) to 20 in AMODEM.C +4. changed XAFTER.CSH to execute under CSH instead of SH +5. removed unused tags IFTag and OFTag from ZPORT.H +6. added comment about this file to AAAREADME.TXT +7. Created an updated XBUILD.CSH. +8. added a tab to INIT.C. +9. Added debugging code to PARSCL.C, MEMINI.C, ZINIFL.C, MUNG.C, ZREMBR.C, + and INIOPN.C. This code is activated only if the variable DbgLvl is + initialized to 1 in DBGDSP.C. +10. Added semi-colon to line 181 of ZOPINP.C so it'll compile. +11. Changed ZREMBR.C so it returns NO in XENIX section. +12. Added code to set TrmTyp in XENIX section of ZTRMNL.C. +13. Changed SCRNOP.C so it tests TrmTyp (not OpCode) against UNTERM. +14. Added XENIX sections to ZDSPCH.C, ZDSPBF.C and ZCHIN.C. + + +23-Jan-1988 version 102 + +1. changed EXEEO.C to make the version number 102. +2. changed the debugging code in ZABORT.C to avoid an infinite loop +3. removed "signal(SIGTERM, ZAbort)" from XENIX code in ZINIT.C +4. changed ZTRMNL.C to support control-Cs under XENIX +5. check for control-C in ZCHIN.C, needed to do it in all other Z routines +6. added XENIX section to ZRDLIN.C +7. define sys$close in ZOPINP.C and ZOPOUT.C +8. define sys$get, sys$putmsg in ZRDEI.C +9. renamed/modified all the .CSH and .COM files so they start with "Z" and + updated AAAREADME.TXT to reflect the changes. +10. added file FALL87.RNO, updated AAAREADME.TXT about it +11. fixed comment in RDLINE.C. +12. changed || to | in ZHELP.C so / immediate commands are okay under VMS. +13. fixed "invalid buffer size" bug for reading large files by changing + "65536" to "65535" in ZRDLIN.C. +14. fixed control-C handling, so that type-out of a large buffer works. + Changed EXECST.C, ZDSPBF.C, FRSTCH.C, READCS.C. +15. added a test to EXECST.C so that commands like "<test$$" will + now produce "unterminated command" errors, as they should +16. modified EXEEI.C to make EI$$ a null command to make CHANGE.TEC work + + +30-Jan-1988 version 103 ( to make CHANGE.TEC work ) + +1. changed EXEEO.C to make the version number 103. +2. changed definition of Mung from DEFAULT to VOID in MUNG.C. +3. changed TmpEI from DEFAULT to VOID in TMPEI.C, ZINIFL.C, MUNG.C +4. removed superfluous "else" from ZSWILD.C +5. moved WFab, WNam initialization from ZINIFL.C to ZINIT.C +6. set WFab.fab$l_fna in ZINIT.C to make EN command work +7. added XENIX section to ZCPYBL.C +8. fixed XENIX section of ZICLOS.C +9. fixed XENIX section of ZOPOUT.C +10. fixed XENIX section of ZRDLIN.C +11. fixed XENIX section of ZWRITE.C +12. changed constants for XENIX in ZPORT.H +13. changed calloc to malloc in ZALLOC.C, merged similar sections +14. added debugging code to RDLINE.C +15. added debugging line to WRBUFR.C +16. fixed unlink call in ZOCLOS.C, added debugging code +17. fixed unlink call in ZOCLDE.C +18. added -O switch to CC commands in XMKBLD.CSH (optimizes code) + + +31-Mar-1988 version 104 + +1. changed EXEEO.C to make the version number 104. +2. changed the way code is compiled under XENIX: deleted XMKBLD.CSH, + created ZXBLD.CSH and ZXDBLD.CSH, modified ZXLOGIN.CSH and ZXCCC.CSH +3. fixed XENIX file creation mode in ZOPOUT.C +4. fixed XENIX section of ZMKOFN.C +5. fixed setting of CmdMod and EStTop in EXEEB.C +6. removed unnecessary call to ExeEY in INIOPN.C +7. fixed XENIX file renaming in ZOCLOS.C +8. used auto-decrement instead of addition in MEMINI.C +9. Renamed CHRFUNCS.H to CHRMACS.H. All references to CHRFUNCS.H + had to be changed: many files modified. Also changed macros that + are in CHRMACS.H to use an array. Merged that array with the one that + was in ReadCS. +10. made ZTrmnl define TrmTyp as UNTERM when we're running in a batch job. +11. took out "dying" message in GETNMA.C +12. fixed CR/LF appending in EXEEQU.C +13. fixed file output code in ZDSPCH.C + + +13-Apr-1988 version 105 + +1. changed EXEEO.C to make the version number 105. +2. removed extra tab from ZINIT.C +3. renamed XAFTER.CSH to ZXAFTER.CSH +4. changed ZXAFTER.CSH so it renames CHRMACS.H, not CHRFUNCS.H +5. added improved error reporting in ZOPINP.C +6. added "cc -c tecoc.c" to ZXBLD.CSH +7. added "/STANDARD=PORTABLE" qualifiers to CC commands in ZVBLD.COM +8. Fixed ZWrite to append LFs correctly under XENIX +9. Fixed ZChIn to make CR/LFs under XENIX out of LFs. +10. changed ZOpOut to use fopen instead of creat/fdopen. +11. overhauled error reporting. Many modules changed, including all "Z" files. + Added OpnOut and ZErMsg. +12. Replaced GroEBf with InsStr to merge several copies of the same code + sequence. Affected ExeBSl, ExeCtI, ExeG, ExeI, Replac. +13. Removed post-copy of memory after ZRaloc calls. ZRaloc does it. +14. Took /STANDARD=PORTABLE off VMS compile commands to prevent warnings + about "globalref". + + +30-Jul-1988 version 106 + +1. changed EXEEO.C to make the version number 106. +2. fixed some error reporting bugs. +3. check for mung mode failure in ExeCSt, not ErrMsg +4. changed EI buffer size to 20000 to let TSTSRC.TEC be input + + +06-Aug-1988 version 107 + +1. changed EXEEO.C to make the version number 107. +2. fixed FR command. +3. fixed it so two control-C's terminate TECOC, as it should be. +4. overhauled command-line parsing to make it use a TECO macro to do it, + like TECO-11 does. Major changes to initialization code. I did this to + provide the extra power and to make invocation of TECOC the same as TECO-11 + under VAX/VMS. Created ExeEG, ZExeEJ, ZEgIni, ZEgLib, ZEgMem, ZEgSym + and ZEgVte. Deleted ZIniFl, Mung, ZExeEG. +5. fixed ::S command. +6. fixed ] command's memory deallocation. + + +22-Feb-1989 version 108 ( porting to Turbo C ) + +1. changed EXEEO.C to make the version number 108. +2. created function prototypes (without arguments) in DefTeco.h and removed + them from all other files. +3. changed /REPLACE to /INSERT in ZVBLD.COM +4. fixed definition of ErrTxt in BldStr. +5. moved "#include stsdef" into VAX section of ZErMsg. +6. moved expressions out of "if" statements to avoid compiler warnings in + FindQR, MakDBf, PshMac, StCopy, ZTrmnl. +7. Deleted reference to ZDefErr.h from ZOClDe. +8. deleted ZError.h +9. changed "ErrMag" to "ErrMsg" in ZOClos. +10. removed variables declared but never used in DoEI, ExeEG, WrBufr, ZOClos. +11. removed "return(xxx)" from XENIX section of ZHhelp, which is a VOID + function. +12. Express 32768 in octal in DefTeco.h for ET_TRAP_CTRL_C to avoid problems + putting it into an unsigned EtFlag. +13. Added type-cast to ZCpyBl call in RdLine. +14. changed XENIX section of ZExeEJ so it defines ZExeEJ, not ZExCtH. +15. Replaced the Execut function with syntax for calling a function whose + address you have in a variable. +16. Made mods to make it run under Turbo C under MS-DOS. Added __TURBOC__ + sections to Zxxxx.c files and created ZPBLD.BAT and ZPDBLD.BAT. +19. Fixed Turbo C section in ZDspBf, ZDspCh, ZChIn, ZWrite. +20. Changed "LONG" to "ptrdiff_t" in several files. +21. Added Turbo C section to ZPrsCL. + Just to get it working, commented out the Turbo C code in ZPrsCL. + This prevents the command-line macro from executing, which avoids the + execution of EJ and EG commands in the macro. EJ and EG are not yet + supported for non-VMS environments. It now limps under Turbo C/MS-DOS + + +28-Feb-1989 version 109 ( more porting to Turbo C ) + +1. changed EXEEO.C to make the version number 109. +2. made type conversions explicit via type casts in various functions. +3. replaced calls to ZChrIt with type-cast "(char)" and deleted ZChrIt +4. appended all the Dbgxxx functions to the end of TECOC.C and changed + compile/link so there is no separate debugging library. This simplifies + the link sequence. +5. fixed VDOW.C and VSETW.C so setting DEBUGGING to NO will not cause + compilation errors. +6. changed references to .h files to lowercase so you don't have to + explicitly rename them after copying them from one machine to another +7. various minor changes so it will build for an UNKNOWN environment +8. use FILENAME_MAX, an ANSI C identifier +9. changed the XENIX identifier to the more general __UNIX__ and restructured + the conditional compilation code to use "#elif". +10. replaced StCopy with strcpy +11. replaced ZCpyBl with MEMMOVE +12. created a file named MAKEFILE for use with Unix "make". +13. improved type definitions and casting to keep lint happy. +14. use EXIT_FAILURE and EXIT_SUCCESS in calls to exit() and ZAbort(). +15. Defined return codes for the EJ command in systems other than VMS + so the command-line parsing macro could function. +16. Removed references to StCopy and ZCpyBl from ZPBLD.BAT and deleted + ZPLNK.BAT. Fixed ZPLNK.BAT to not refer to DBGTECOC.LIB. + + +28-Feb-1989 version 110 + +1. changed EXEEO.C to make the version number 110. +2. made the 2048 bit of the ET flag cause the BACKSPACE character to be + treated just like the DEL character on input. This supports the + conventions used by IBM PCs and Unix. On those systems, you'll have + trouble getting a BACKSPACE into the command line, a minor problem. +3. to simplify an effort to port TECO-C to RT-11, renamed the following + files so the name portion of the filespec is 6 characters or less. + + renamed CHRMACS.H to CHMACS.H + renamed COMMANDS.TXT to WCHART.TXT + renamed DEFCHARS.H to DCHARS.H + renamed DEFSCREN.H to DSCREN.H + renamed DEFTECO.H to TECOC.H + renamed TEC0_V40.TEC to TECV40.TEC + renamed TECO_V40.TES to TECV40.TES + + The following files were not renamed, and are the only remaining files + with names longer than 6 characters. + + AAAREADME.TXT I just didn't want to rename this one + GETTECO. used only on Unix systems + MAKEFILE. used only on Unix systems + PROBLEMS.TXT I just didn't want to rename this one + RELEASE.TXT I just didn't want to rename this one + ZVLOGIN.COM used only on VAX/VMS systems + ZXAFTER.CSH used only on Xenix systems + ZXLOGIN.CSH used only on Xenix systems + +4. Fixed ZPBLD.BAT: removed superfluous -I option, added ECHO statements so + you can tell how far it's gotten, lowercased file names. +5. Removed definition of TraceM from ZExCtC, which doesn't use TraceM. +6. Don't return a value from ZDoCmd or ZHelp, they're VOID functions. +7. Fixed Sun and Turbo C sections of ZExeEJ and ZClnEG. +8. Changed second argument of PushEx from BYTE to DEFAULT. +9. Made ZClnEG a LONG function to match it's use in ExeEG. +10. Made MakDBf calls in PushEx and GetNMA use a type cast when passing + EstTop and EstBot so it works under Turbo C. +12. Fixed expression syntax in CLPARS.TES. +13. Fixed handling of :ER commands in Turbo C section of ZOpInp. +14. Added function prototypes to tecoc.h. They're conditionally compiled + based on the new USE_PROTOTYPES identifier defined in zport.h. +15. Replaced GENCLP.TEC with GENCLP.C. + + +11-Jun-1989 version 111 + +1. changed EXEEO.C to make the version number 111. +2. More type-casts added to allow Turbo C to compile the code when the + function prototypes are used (USE_PROTOTYPE == YES). +3. Moved setting of EtFlag out of ZInit.c and into ZTrmnl.c. + +28-Jun-1989 version 112 + +1. changed EXEEO.C to make the version number 112. +2. changed || to | in ZTrmnl.c to fix setting of EtFlag. +3. changed CrType to VT100 in ZTrmnl.c for IBM-PC so ANSI sequences are used. +4. rewrote logic to fix bugs and improve readability in InpDel.c. +5. renamed ScrnOp to ZScrOp so IBM-PC screen handling could be added. +6. replaced old usage of ET_BKSP_IS_DEL with new code in ZChIn. +7. added error message generation to ZChIn +8. fixed ZVBLD.COM so the link of GENCLP has LNK$LIBRARY defined +9. changed mktemp to tmpnam (ANSI) in ZOpOut.c. +10. merged VDoW, VGetW and VSetW into ExeW +11. Lots of little changes to reduce messages produced by lint and by + Turbo C when the -w switch (maximum warnings) is used. + +19-Jul-1989 version 113 + +1. changed EXEEO.C to make the version number 113. +2. Fixed ZPBLD.BAT and ZPTLIB.BAT +3. Added code for IBM PC to ZScrOp.c +4. Added FFLINS, used in InpDel and ReadCS. +5. Fixed comments in FindQR and tecoc +6. Changed ugly \015 to \r, \012 to \n, \011 to \t in all files +7. More type casting to reduce warnings from Turbo C. +8. Changed almost every file to insert new "charptr" and "QRptr" types. + These are needed to support the brain-damaged memory access on IBM-PCs, + where the pointers need to be "HUGE" to work. +9. fixed a bug in MakRom that caused :X commands (among others) to fail. +10. Converted QBfBeg, QBfPtr and QNumbr to the simpler QR +11. Rewrote GENCLP so it makes a file that Turbo C reads correctly. +12. Made a SIZE_T typedef to support Turbo C. +13. Used farmalloc in ZAlloc, farfree in ZFree and farrealloc in ZRaloc in + Turbo C sections. +14. made 0EJ return 0 for Turbo C. +15. Fixed ZWrite code for Turbo C. + +02-Aug-1989 version 114 + +1. changed EXEEO.C to make the version number 114. +2. Renamed RELEASE.TXT to CHANGES.TXT +3. merged all the Z files into ZVMS,C, ZMSDOS.C, ZUNIX.C, ZUNKN.C +4. merged all the SKP files into SKPCMD.C +5. merged CHKHLP.C, FRSTCH.C and INPDEL.C into READCS.C +6. merged REDUCE.C into PUSHEX.C +7. merged MEMINI.C into INIT.C +8. merged DOEI.C into EXEEI.C +9. merged DOFBFC.C into SRCLOP.C +10. merged EXEE*.C files into EXEE.C (EXEEB.C is an exception) +11. merged EXEF*.C files into EXEF.C (EXEFB.C is an exception) +12. Implemented colon modifier on EW command. This is an undocumented + feature required for the CLPARS macro to work on non-VAXen. +13. merged ZFILES.H into ZVMS.C, ZMSDOS.C, ZUNIX.C +14. fixed GENCLP.C yet again, for VMS +15. fixed memory shuffling bug in RDLINE.C + +21-Aug-1989 version 115 (Manfred Siemsen) + +1. Changed ExeEO() in EXEE.C to make the version number 115 +2. Created DEFEXT.H, replaced all EXTERN lines with #include "defext.h" +3. Modified all #if DEBUGGING...#endif lines to call 3 debugging + functions: DbgFEn() upon function entry, DbgFEx() upon function + exit, and DbgFMs() for messages in the body of a function. Also, + indented the debugging lines so they line up under the code they + "belong" with, instead of being munched over on the left margin. +4. Modified debugging routines to use sprintf/printf to display + values of variables instead of displaying things "manually" through + other Teco-C build/display routines. We still avoid the use of + sprint/printf in non-debugging code. +5. Modified the indentation scheme to more closely match K&R +6. Put squiggly braces '{}' around ALL statements, even if they + aren't required. +7. Modified the comment scheme to be consistent with Pete's + latest X-window'ish standard. +8. Created a Turbo C MAKEFILE (MAKEFILE.TC). +9. Began implementation of ZPWild() and ZSWild() in ZMSDOS.C. It + seems to work ok, but there should be more error checking put in + to guard against the user entering a bizarre filename. +10 Implememted ZDoCmd() in ZMSDOS.C. Required change to ExeEG() in + EXEE.C. If it wasn't :EG, TxtLen was never set, might have been + garbage, moved TxtLen assignment out of "if (COLON..." statement. + Also, ZAbort() was called if TxtLen was not zero, should have + been called if TxtLen *is* zero. + +30-Aug-1989 version 116 + +1. Changed ExeEO() in EXEE.C to make the version number 116 +2. rearranged includes in "Z" files so that my .h files come after the + system ones. This was needed so ZPORT.H can redefine FILENAME_MAX, + which on VMS is wrong (38 ain't right). Rearranged ZPORT.H for the + same reason. +3. Replaced ERRMSG.C with ERR.C and created the new error reporting + functions ErrChr and ErrStr. Doing this removes places where I was + writing into string literals, which worked but wasn't real kosher. + It also makes lint happy about ErrMsg (fixed number of arguments now) + and modularizes the error code. Merged DSPCHR.C and VRBERR.C into + ERR.C. +4. Created ZVrbos. +5. Fixed error message numbering. +6. Fixed prototype for ErrDsp and ErrPst in ERR.C. +7. Commented out illegal test case in TSTQR.TEC. +8. Made Charac a char instead of an int in ZChIn to fix bug. + +21-Oct-1989 version 117 + +1. Changed ExeEO() in EXEE.C to make the version number 117 +2. Moved #endif in TECOC.C from just after DbgSlv() to just after + DbgDsp() so DbgDsp() wasn't included when DEBUGGING is FALSE. +3. Updated MAKEFILE.TC. +4. Updated ZPTLIB.BAT. +6. Changed prototype of ZVrbos in ZMSDOS.C, ZVMS.C, ZUNIX.C, + ZUNKN.C, and TECOC.H. +7. Changed DoEI() comment in EXEE.C. +8. Made ZRdEI() call ZRdLin() instead of calling fgets() directly. +9. Changed ZWrite() to ZWrLin(), it's more descriptive. + +23-Oct-1989 version 118 + +1. Changed ExeEO() in EXEE.C to make the version number 118 +2. minor fixes to make lint happy +3. Changed ZChIn() in ZMSDOS.C to ignore any IBM PC scan code + other than DEL to eliminate the "Unrecognized character" bomb. +4. Changed CLPARS.TES so filespec memory works on PC's. +5. Changed EXEQ.C to fix numeric expression parsing +6. Change definition of FEArry[] from (*F[])() to (*F[])(VOID) + to eliminate Turboc C "function w/no prototype" warning. + +03-Nov-1989 version 119 (Manfred) + +1. Changed ExeEO() in EXEE.C to make the version number 119. + +2. Because of some bizzare behaviour, the CHECKSUM_CODE #define and routines + were added to check code at runtime to make sure it wasn't being + overwritten. These routines read the Turbo C .MAP file to get the order + and length of all the modules, calculates and stores an initial checksum + for each module; and then compares the initial checksum of each module + with the checksum calculated after every command is executed in ExeCSt(). + +3. Changed ZAlloc(), ZRaloc(), and ZFree() to return and expect a new + type "voidptr" instead of charptr's. I then removed the casts before + ZAlloc() and ZRaloc() returns in the code. Borland Turbo C says that + explictly casting returns from malloc/realloc hides things from the + compiler and is bad practice in ANSI C. + +4. Changed "struct QReg *LQTabl" to "QRptr LQTabl" in the definition of + MStck in TECOC.H per phone call w/Pete. + +5. Changed an incorrect call to DbgFEn() in ZOpOut()...should have displayed + DbgSBf instead of "". + +6. Changed the DbgFEn(), DbgFEx(), and DbgFMs() calls to send NULL instead + of "" if there is no special debugging message to display. This saves + space when Turbo C is not merging duplicate strings (tcc -d). Otherwise + there are billions of "" strings in the .EXE file ("" strings take 1 + byte of space because they contain a '\0'). I used CHANGE.TEC to do it! + +7. Changed ZRaloc() in ZMSDOS.C to manually reallocate blocks. There is a + problem with Turbo C's farrealloc() in that it uses movedata() to move + data from the old block to the new block. Movedata() expects a size_t + as the number of bytes to move. size_t under Turbo C v2 is *always* a + 16-bit unsigned int regardless of memory model. This means that if the + old block is >64K, movedata() won't move the data correctly from the old + block to the new block when the old block is >64K. + +8. Implemented the ^B system date (ZExCtB) and ^H system time (ZExCtH) + routines in ZMSDOS.C using DOS calls. EIDATE.TES$ will display the + current date and time. + +9. Initialized ff_status in ZMSDOS.C to -1 so EN$$ with no preceding + ENfilename$$ doesn't blow up by calling findnext() with no initial + findfirst(). Is a reasonable return? + +10.Changed ExeRBr() so that End_P1 is set to NULL when Start is set to + NULL after the ZFree(QR->Start). Otherwise, End_P1 might not be NULL + and will cause problems for those routines which blindly subtract + End_P1 from Start to get the length of text in the Q-register. + +11.Changed the line in ^EQq logic part of BldStr() where QR->End_P1 was + being subtracted from QR-Start, when it should be the other way around. + +12.Changed FArray[] in ExeCSt(). The ^Q entry was ExeNYI(), it should have + been ExeCtQ(). The ^_ entry was ExeOpr(), it should have been ExeUsc(). + Actually, both ExeOpr() and ExeUsc() would have pushed ^_ on the stack, + so it was a...uh...push. + +13.Changed ^G entry FCAray[] in ExeCrt() from ExeNul() to ExeIll() so it + jibes with FArray[] in ExeCSt() entry. + +14.The logic in ReadEI() in EXEE.C determining whether or not to add a + trailing CR-LF to the line read from the EI file was wrong. ReadEI() + now calls ZRdlin() to read lines from the EI file. ZRdLin() returns + the length of the read line *without* the trailing newline returned by + fgets(). The ReadEI() logic was checking if the line ended in VT or + in ESC-CR-LF. Since the line returned by ZRdLin() should never end in + CR-LF, the ESC check was bogus. I changed it to only add a CR-LF if + the line did NOT end in VT or ESC which I think was the original intent. + +15.While playing with ReadEI() in EXEE.C, I was having problems reading in + a huge macro (>ZBFINIT bytes long). The problem was that if the EI + buffer became full (ie: BufPtr == ZBfEnd), ReadEI() was calling + ZRdLin() with (ZBfEnd-BufPtr == 0). ZRdLin() was in turn essentially + calling "fgets(buf,0,fp)". When told to read into a 0 size buffer, + fgets() simply returns the buffer. ZRdLin() only fails if fgets() + returned NULL or if an error happened, otherwise it will happily + return 0 as the length of the line it read, therefore, back in + ReadEI(), the "BufPtr += line_len" never incremented BufPtr + anywhere and ReadEI() never broke out of it's FOREVER loop, it + looped infinitely, reading zero bytes into a zero length buffer. + + I added the ZBFMIN and ZBFEXP #defines in ZPORT.H and changed ReadEI() + so it dynamically reallocates the EI buffer when it is close to + becoming full. + +16.Changed ExeCtu(). The call to MakRom() used to make the Q-register + text area 1 character longer when doing a "n^Qq" was sending the wrong + argument. It was sending the new *total* size of the text area + (end-start+1) instead of the *additional* size of the text area (1 byte). + +17.Changed the way the CLPARS macro is handled: + + a) If USE_ANSI_CLPARS is FALSE. + + Changed CLPARS.TES to not clear itself out of memory when it was + finished. The CLPARS macro is loaded and executed in Q-register Y. + The last thing it did was a "0,0XY" to clear itself out. The problem + is that ExeX() would call ZFree() to clear Q-register Y, leaving + CBfPtr effectively pointing into a free'ed memory area. This wasn't + fatal because the "0,0XY" was the very last thing in the CLPARS macro + so no further TECO instructions were looked for in the free'ed area; + but, technically it was wrong. I removed the "0,0XY" from the CLPARS + macro and changed ZPrsCl() so it manually ZFree()'s Q-register Y after + it finishes executing it. + + Note: SQU also uses this technique: issuing a '0,0Xq' at the tail end of + a macro loaded in Q-register 'q' to clear the macro out after it + finishes executing. If this is a common TECO macro practice, maybe + we'll have to think this through a little more. + + b) If USE_ANSI_CLPARS is TRUE + + If USE_ANSI_CLPARS is true, the CLPARS macro is stored as one + gigantic string in clpars[]. If USE_ANSI_CLPARS is false, the + CLPARS macro is split into lines and stored as an array of strings + in *clpars[]. The advantage to USE_ANSI_CLPARS is that to execute + the CLPARS macro, ZPrsCL() simply made the text area pointers of + Q-register Y point at clpars[] to "load" Q-register Y before doing + the MY$$. Otherwise, if USE_ANSI_CLPARS is false, the CLPARS + macro is executed by (slowly) loading it from *clpars[], line-by-line, + into Q-register Y and then doing the "MY$$". + + The problem was that if USE_ANSI_CLPARS was true, Q-register Y held + statically allocated data which could cause problems when the CLPARS + macro did the "0,0XY" to clean up. "0,0XY" would make ExeX() try to + ZFree() the statically allocated clpars[] string. + + While looking at this problem I noticed that, other than for historical + reasons, there is no reason the CLPARS macro *has* to be executed from + Q-register Y. I changed ZPrsCL() so that if USE_ANSI_CLPRS is true, it + directly executes the CLPARS macro from the clpars[] string without + bothering to load it into Q-register Y first. + +18.Removed TRACE_IMBEDDED_MACRO. + +19.Removed static initialization of QRgstr[] in TECOC.C and moved it + into MemIni() in INIT.C along with the other initializations of + global static arrays (QStack[], etc). [See suggestion (1) below] + +20.Changed ExeEO to return ExeNYI() for "nEO". + +21.Changed DoEI(). DoEI() calls PshMac(), ExeCSt(), and PopMac(). If the + ExeCSt() failed, it would do a return(FAILURE) without doing the PopMac(), + leaving the macro stack off and CBfPtr pointing into the EI buffer. DoEI() + was changed so that it does a PopMac() even if ExeCSt() fails. This same + type of logic was changed in ExeM(). + + This problem didn't appear unless you tried executing a macro from a file + or from a Q-register which failed miserably. + +22.Changed ReadEI() . When ReadEI() finds a line containing double + 's, it returns to DoEI(), which then executes everything up to that + point. DoEI() then re-calls ReadEI() to finish reading the EI file. The + problem was that if there were any commands *after* the two 's on + the last line read, they would be lost in the shuffle because ReadEI() + would start reading into the beginning of ZBf. The SQU.TEC macro had + a line with commands after a double . + +23.Fixed ExeO(). ExeO() wasn't completely comparing the desired tag with + the tag in the command string. So, if the command string had two tag + names which start out the same way, for example: + + !aa! + !a! + + "Oa" would goto !aa!. + +24.Changed the way some of the colon-modified commands work. I ran into a + situation in SQU where "Y<:A;>" was used. If the yank read in the entire + buffer, ExeA() would fail immediately, without clearing the colon-modified + bit in CmdMod, thus "passing" CmdMod to ";" converting it to ":;". "n;" + breaks if n is zero or positive, "n:;" breaks if n is negative. "Passing" + CmdMod to ExeSCl() this way completely altered the sense of the ";" break. + +25.Fixed case flagging in TypBuf() and made it faster by not doing the + Is_Lower() and Is_Upper() checking if EuFlag() is set to EU_NONE. + +26.Rewrote ZCpyBl() in ZMSDOS.C to use memmove() and memcpy(). They + both use 80x86 string instructions and make things much faster. + +27.PopMac() was clearing the contents of the local Q-register table, + but wasn't de-allocating the table itself. + +28.Changed PshMac(), PopMac(), FindQR(), and Init() to use pointers into + the MStack[] and MStack[].QRgstr tables instead of doing redundant array + references. Changed Reduce() in PUSHEX.C to use pointers into EStack[] + for the same reason. Using pointers should be faster? + +29.The digit buffer (DBfBeg) was initialized in TECOC.C as: + + charptr *DBfBeg = " "; + + then digits were poked into this statically allocated string which really + isn't kosher. Changed it so DBfBeg is initialized in MemIni() in INIT.C. + + +06-Dec-1989 version 120 + +1. Changed ExeEO() in EXEE.C to make the version number 120. +2. Fixed bug in ZDspBf caused by "length" wrapping when unsigned. +3. various little fixups. + + +07-Dec-1989 version 121 + +1. Changed ExeEO() in EXEE.C to make the version number 121. +2. Made EC clear the edit buffer after writing files. Thanks, Phil. +3. Fixed ZFWrite in ZMSDOS.C to handle files > 64k better. + + +20-Dec-1989 version 122 + +1. Changed ExeEO() in EXEE.C to make the version number 122. +2. Added TVERSION (version number of TECOC-C) to TECOC.C +3. Fixed ZRdLin in ZVMS.C to make EI commands work. +4. Removed the ZInit function. It was being called late (after MemIni), + and turned out to be unused anyway. + + +04-Feb-1990 version 123 + +1. Changed ExeEO() in EXEE.C to make the version number 123. +2. Removed funny handling of lines terminated with do let + MS-DOS users edit macros without funnyness. +3. Regularized the "debugging level" numbers documented with DbgDMs in + TECOC.C. +4. Fixed looping logic in SrcLop to make "n_text$" commands work. +5. Fixed bug in ClTrEx in ZVMS.C so running from batch works. + + +20-Feb-1990 version 124 + +1. Changed TVERSION in TECOC.H to 124. +2. Rewrote MakDBf to make it more portable. + + +2-Mar-1990 version 125 + +1. Changed TVERSION in TECOC.H to 125. +2. Fixed so HP with an empty buffer doesn't cause an error message. +3. Moved the decision about whether to add/remove CR/LF pairs to/from the end + of lines when doing file I/O into the system-dependent functions. This + was needed to make MD-DOS happy, and is really where this stuff should + be anyway. +4. Defined GotCtC as "volatile". +5. Rewrote ZRdLin in ZVMS.C to do what TECO-11 really does with all the + special characters. +6. Put a check for an open output file into ExeEC, so the command HKEFEX + will work even if there's more pages in the input file. +7. Merged WrBufr and ZWrLin into a singl function called ZWrBfr. Deleted + WRBUFR.C and updated the build files. This was needed to provide system + dependent control over output so MS-DOS I/O could be cleaned up. + + +22-May-1990 version 126 + +1. Changed TVERSION in TECOC.H to 126. +2. Removed code that adds a CR/LF to each record read by ReadEI. +3. Fixed VMS output code in ZWrBfr broken in version 125. +4. Changed TypBuf so it is interruptable by ^C after displaying a line. +5. Defined ChkCtC() so that ^C's work better under MS-DOS. +6. Changed ZSWild & ZPWild to work better under CHANGE.TEC. +7. Folded wildcard filename buffer (WBf) into "normal" filename buffer (FBf) + so G* after ENfilespec$ returns "filespec". + + +1-June-1990 version 127 + +1. Changed TVERSION in TECOC.H to 127. +2. Modified ZDoCmd() in ZMSDOS.C so you can EGfilename.BAT$. +3. Added EBfFul to avoid "?MEM memory overflow" messages when reading large + files. Now TECO-C quietly stops reading. +4. Reduced number of times ChkCtC() is called to speed display up. +5. renamed AAAREADME.TXT to AAREADME.TXT, needed by MS-DOS + + +8-June-1990 version 128 + +1. Changed TVERSION in TECOC.H to 128. +2. Fixed loops that initialize IsOpnI, IsEofI and IsOpnO in Memini. Thanks + to Chuck Cranor. +3. Added ZExit, ZClnUp and ClenUp and replaced ZAbort with TAbort. This + modularizes exit handling. +4. Applied lots of fixes to zunix.c suggested by Chuck Cranor. These include + terminal initialization and use of termcap for terminal sequences. +5. Added a type cast to FindQR to prevent a compiler warning. + + +13-June-1990 version 129 + +1. Changed TVERSION in TECOC.H to 129. +2. Made n^T display n modulo 256 instead of generating an error when n + is out-of-range. Now it matches documentation. +3. Worked on file I/O in ZUNIX.C. + + +20-June-1990 version 130 + +1. Changed TVERSION in TECOC.H to 130. +2. Applied Tom Almy's MS-DOS fixes to prevent conversions of line feeds + written to the terminal to carriage-return/line-feed pairs. +3. Applied Tom Almy's fixes to the search code. Now backwards searches + work better. +4. Applied Tom Almy's fixes so eight-bit characters are better supported. +5. Minor fixes to ExeW. +6. Replaced ZRdLin in ZMSDOS.C with Tom Almy's superior version. +7. EBfFul was a global used only by RdLine, ExeA and RdPage. I made it + an argument. Seemed like the right thing to do. +8. Changed the type of the length argument to InsStr from LONG to ptrdiff_t. +9. Applied Tom Almy's fixes to DoEvEs and ReadCS. +10. Fixed up PG.RNO and created a new PG.MEM. +11. Removed BYTE identifier from ZPORT.H and did related fixups. +12. Started (by no means complete) supporting 8-bit characters throughout + the code. In most cases, this means changing things declared "char" + to be declared "unsigned char". +13. Deleted DSPCHR.C, which wasn't even compiled. + + +17-July-1990 version 131 (Manfred) + +0. Changed TVERSION in TECOC.H to 131 +1. In TECOC.C, ChrMsk[], changed 128 RCS_DEL entries Pete added to RCS_DEF. +2. In ZMSDOS.C, added #include to get O_BINARY #define. In + ZTrmnl(), added "setmode(fileno(stdout),O_BINARY)" per Tom Almy. +3. In MAKEFILE.TC, added -K (default to unsigned char) to TCC so string + literals which are signed char ptr's don't conflict with the unsigned + char ptr's now used all over to get eight-bit chars per Tom Almy. + Also added tabort.obj to TECOC_OBJS macro. Also added -DTCPP100 macro. +4. In ZPORT.H, changed EBFEXP, EBFINIT, IBFEXP, IBFINIT from 64000 + to 64000L to get rid of TC++'s "Constant is long" warnings. +5. In ERR.C, ToErr(), got rid of TC++'s "Conversion may lose significant + digits" in Sbuf[DBfPtr-DBfBeg] line by using SLen to hold DBf length; + changed bogus compare "> '\126'" to "> '\177'"; also, the final ']' + was overwriting last digit in SBuf. +6. In RDLINE.C, changed function return type of expand_ibf from an + "static" to "static void". Also added prototype. +7. In TECOC.H, added prototype for errprt(). +8. In RDLINE.C, expand_ibf(), added #if DEBUGGING lines so DbgFNm is declared. +9. In ZMSDOS.C, ZRdLin(), fixed typo in #if DEBUGGING "FAILURE" section. +10. In ZMSDOS.C, ZRaloc(), added test for TC++ v1.00 since the heap layout + has changed. In TC v2.0? mimic farrealloc(), in TC++ v1.00 call + farrealloc() directly. + + +18-July-1990 version 132 + +0. Changed TVERSION in TECOC.H to 132 +1. lots more work to resolve type mismatches, so lint and gcc don't + complain so much. +2. fixed the ? immediate-mode command. +3. used GAPMIN in RdLine to fix wasteful memory use. +4. removed superflous parentheses from return statements. +5. to test that identifiers defined in ZPORT.H are minimally consistent, + added some tests in TECOC.C +6. To finish up eightbit handling, added ZSetTT, a function to let TECO set + terminal characteristics. Since it's there, added code so the 1:W and + 2:W commands change screen size. Not video yet, but a little closer. +7. Changed ZMkOFN into a macro named ZMKOFN. +8. Fixed ZChIn to handle NoWait correctly. +9. Fixed handling of 0,32et bit. + + (8-August-1990 Manfred) + +10. In TECOC.C, changed "\n" to "\r\n" in debugging displays since stdout + is now in binary mode. +11. In INIT.C, in MemIni(), added Tom Almy's suggestion to temporarily + allocate a small chunk of memory to be used as a small-allocation + memory pool which may help keep memory fragmentation down. +12. In ZPORT.H, removed unused UWORD typedef. +13. In ZMSDOS.C, in ZVrBos(), changed old style function definition. +14. In ZMSDOS.C, propagated MPtrs[] dynamic allocation tracking to ZRaloc(), + added TC++'s new heapcheck() routines to check the heap on every alloc, + realloc, and free. We *are* DEBUGGING and don't care about speed + penalties, right? +15. In ERR.C, the one-line error messages for ERR_PES and ERR_PDO were + switched (Argh!). +16. In ZPORT.H, expanded EXS_SIZE, LPS_SIZE, MCS_SIZE, and QRS_SIZE so + SQU.TEC has some breathing room. Should these expand themselves? +17. Some of the .TEC and .TES files supplied with TECO-C were padded with + NUL's and some lines ending with ESC had an extra CR. +18. In ZMSDOS.C, ZDspCH() called write(). should call fwrite() or we're + mixing calls to write/fwrite on stdout which is bad. also, the code + which directly set stdout->flags'_F_BIN bit after setmode(stdout) in + ZTrmnl() somehow was lost between Pete's version and mine (?) +19. In ZMSDOS.C, in ZRdLin(), iBuf was cast as "char far *", should have + been cast simply as a "char *" otherwise compiling w/small data model + doesn't work. +20. In CHANGE.TES, changed some ^U constructs so it's now SQUishable. +21. In ZMSDOS.C, added ff_path[] to save ENfilespec$ wildcard lookup + filename since we can't be sure FBf will still contain the wildcard + lookup filename between ENfilespec$ and EN$. +22. Changed CLPARS.TES so when you MUNG there's no leftover trash in + q-register 0. (Pete) + + +19-August-1990 version 133 (Manfred) + +0. Changed TVERSION in TECOC.H to 133 +1. In EXEO.C, added support for computed gotos (nOtag0,tag1...$) +2. In INIT.C, in MemIni(), the digit buffer was being overrun on -1== since + the calculation to allocate the digit buffer either: a) didn't take into + account that 32-bits-per-long/3-bits-per-octal-digit doesn't divide evenly + (loses 2 bits), or b) didn't take into account that ExeEqu() might append + to the digit buffer for =, ==, or === display purposes. +3. In ZMSDOS.C, fixed MPtrs[] tracking in ZRaloc, didn't work correctly + when farrealloc() eventually returns NULL. +4. In TECOC.C, added Turbo C's heapcheck() routine to check_consistency(). +5. In RDLINE.C, in RdLine(), after expand_ibf(), was calling ZRdLin() even + if EBfFul was set TRUE. I don't think it should, even though we might be + able to read a line less than IBFMIN bytes long. + + +9-September-1990 version 134 (Pete) + +0. Changed TVERSION in TECOC.H to 134 +1. Changed the way I handle conditional inclusion of debugging code. + Borrowing from the way the ANSI assert macro works, all the debugging + functions are now macros, which don't produce any code if DEBUGGING + is FALSE. +2. Added TECOC.OPT so the VAX linker puts literal text strings into a + non-writeable PSECT. +3. Fixed ExeBSl so it will read a numeric string from the edit buffer even + if it's preceded by a minus-sign or plus-sign, and fixed TSTBSL.TEC + so it tests for these cases. + + +18-October-1990 version 135 (Pete) + +0. Changed TVERSION in TECOC.H to 135. +1. Updated PG.RNH/PG.MEM again. +2. Fixed define of DBGFEX in TECOC.H so DEBUGGING works again. +3. Fixed FindQR and ExeM to make TECO-C handle :M commands correctly. + + +21-November-1990 version 136 + +0. Changed TVERSION in TECOC.H to 136. +1. Fixed DBGFEX syntax bug on line 1118 of ZMSDOS.C +2. Removed extra close parenthesis in EXEW.C +3. Fixed BLDSTR.C to allow searching for nulls. Thanks to Tom Almy. +4. Fixed ExeFGt to work correctly. Bug found by Richard Graham. +5. Added missing enblosing braces in InsStr. Thanks to Mark Henderson. +6. Added Mark Henderson's additional code to BldStr to provide ^EQ* (file + spec buffer) and ^EQ_ (search string buffer) support. Then broke BldStr + into functions for readability. +7. Inserted Mark Henderson's time and date code into ZUNIX.C. Testing with + DATE.TEC revealed a slight bug, fixed. +8. Added ZAMIGA.C and some mods to ZPORT.H from Ben Mesander to support + TECO-C under Amiga-DOS. Thanks Ben! +9. Fixed ExeEQ so it preserves the state of FFPage when reading files. + Thanks to Mark Henderson. +10. Added ZBell function to make the bell sound better under MS-DOS. + Thanks to Steve Freyder. +11. Added Mark Henderson's code (he got glob.c from Berkeley stuff) + to do wild-carding of file names. Reorganized it some. Thanks, Mark. +12. Added Mark's code to name backup files sort of like VMS. Not sure I + like this yet, because I haven't tried it. ED bit 4 controls it, like + so (from Mark:) + ED&4 now specifies the mechanism for backup files + if ED&4 is set then we use the foo foo.bak mechanism (as originally) + if ED&4 is clear the first backup file will be named foo;1, the + second foo;2, ...&c. Sort of VMS like, but the most recent + version will be known by the name foo. +13. Mark added TECFILES environment variable. + If for ei commands and TECO.INI the file is not found in the + current directory the directory $(TECFILES) will be searched. + I've been keeping my teco startup files in ~/.teco + + +26-December-1990 version 137 + +0. Changed TVERSION in TECOC.H to 137. +1. Minor fixups to get ZUNIX.C to compile. +2. Moved the line that resets FFPage to zero. It was in RdPage, now it's + in RdLine so a 1:a command now correctly resets flag. Thanks to Richard + Graham for reporting this one. +3. Modified ExeCtE so you can now set the flag as well as get its value, + like in TECO-11 and TECO-32. +4. Fixed ExeBSl so it sets RefLen when it converts a digit string in the + edit buffer into a binary value. Thanks to Mark Henderson. +5. Merged in new Amiga support files from Ben Mesander. There's a new + ZAMIGA.C, which now has time and date support. Ben supplied files + MAKEFILE.AMI and TECOC.LNK for building on the Amiga. + + +29-December-1990 version 138 + +0. Changed TVERSION in TECOC.H to 138. +1. Rewrote the TSTO.TEC macro, which pointed out a bug in TECO-32! +2. Added "smallcode smalldata" to LFLAGS vlue in MAKEFILE.AMI to make TECO-C + smaller (for faster startup) under AmigaDOS. Thanks to Ben Mesander. +3. Moved OpnInp and OpnOut into ExeE because only ExeE functions call them. +4. Changed ZOpInp function in ZVMS to do the right thing with the default + macro library directory. ZAMIGA.C, ZUNIX.C and ZMSDOS.C need to be + changed. + + +10-January-1991 version 139 + +0. Changed TVERSION in TECOC.H to 139. +1. Fixed ZUNIX.C so it handles default EI file names correctly. Still needs + ZClnEG to be implemented. +2. Applied Mark Henderson's patch to ZChIn to fix Control-C handling. +3. Applied Mark Henderson's patch to ExeEQ to fix EBFEnd pointer screw-up + when reading a large file with EQ. Thanks again, Mark! +4. Applied Ben Masander's patch to ZAMIGA.C to correctly call isatty. +5. Implemented "SYM" part of :EG command for VAX/VMS, so TECO-C can set DCL + symbols like DEC's TECO. + + +20-January-1991 version 140 + +0. Changed TVERSION in TECOC.H to 140. +1. Reworked ExeEG and ZClnEG to make it work under Unix and to do the + system dependent stuff in the right places. +2. Modified GENCLP to make it create clpars as "unsigned char" instead of + "signed char" to remove a gcc warning. Made GENCLP compile/link/run under + SunOS and modified MAKEFILE.SUN to include processing of GENCLP. +3. Changed GENCLP.C to define clpars as "const" for ANSI compilers. +4. Received another ZAMIGA.C from Ben Mesander. He is now using RCS to + control revisions, so there'll be version numbers for ZAMIGA.C from now + on. This is version 1.4. +5. Implemented Mark Henderson's suggestion to make the size of error + message buffers a #define'd identifier. I named it ERBFSIZ. +6. Merged in Mark Henderson's video support. This involved a LOT of + changes, including: + a. Merged MOVE.C into ZUNIX.C + b. changed VOID to VVOID to avoid clashing with CURSES.H + c. lots of added code with "#if CURSES" control + d. created VIDEO.TXT + e. created an EZ mode control flag for Mark's bits. + f. added exetil.c + + +23-February-1991 version 141 + +0. Changed TVERSION in TECOC.H to 141. +1. Some slight changes to make lint happy. +2. From Manfred: added DBGFEN calls to DoCtVW and DoCtE in BldStr, fixed + DbgFNm in ExeF, removed extra "#include " from ZMSDOS.C, added + "fclose(fp)" to init_code_checksums in ZMSDOS.C, and some other minor + fixups in ZMSDOS.C. Changed MAKEFILE.TC to avoid "Abnormal Program + Termination". +3. Added check of terminal width & height to ExeW for 0,1:w error. +4. Added Mark Henderson's fix to let ZUNIX.C compile under SunOS 4.0. + + +15-March-1991 version 142 + +0. Changed TVERSION in TECOC.H to 142. +1. Added Ben's fixes to slight build problems on AmigaDOS. +2. Fixed makefile.sun to make it handle SunOS 4.1 as well as 4.0. Still + needs hand-editing to the makefile before running it. Defaults to 4.1. +3. Added some fixes to ZUNIX.C to reduce gcc warnings. +4. Repaired makefile.sun, which was broken. +5. Fixed EXEFTIL.C and EXEF.C so they compile when DEBUGGING is defined. + + +20-April-1991 version 143 + +0. Changed TVERSION in TECOC.H to 143. +1. Changed CLPARS.TEC to parse Unix command lines with "-" for options + instead of "/". +2. Under Unix, changed ZClnEg to implement last-file-edited memory using + files in /tmp instead of gawdawful TECF00.TMP files in the current + directory. +3. Slight include file #ifdef changes to let it compile under SunOS 4.1.1. +4. Changed makefile.sun to not use a library. It's much faster this way. +5. Added case for tilde command to SkpCmd.c. +6. Those C files that directly include curses.h needed to have the + #include moved above zport.h. +7. Fixed ExeW so if we're not compiled with video, it returns nothing + instead of FAILURE, like TECO32. Returning FAILURE causes the current + macro to fail, and the current macro might be CLPARS! +8. Fixed ZUNIX.C so ET_UNIXNL is correctly defined. +9. Added Jerry Leichter's fixes to port to Ultrix, including makefile.ulx. +10. Fixed bug in ZUNIX.C where ZDspCh was being called with a string instead + of a character. Thanks Jerry! + + +2-June-1991 version 144 + +0. Changed TVERSION in TECOC.H to 144. +1. For the ^P command (for debugging, must compile with DEBUGGING set) + to work, each function that starts with a call to DBGFEN needs to have + a call to DBGFEX before every exit point, or the pretty nesting gets + screwed up. Added some DBGFEX calls to BldStr and ZOClos (in ZUNIX.C) + to fix the display when 4,0 is used. +2. Fixed DoFlag, ExeCtR, ExeCtT, ExeW and ExeBSl so they check the expression + stack correctly. They can now be used in expressions without problems. + Thanks to Mark Henderson and Jerry Leichter for reporting this. +3. Moved the check for "negative argument to comma" from ExeCom to GetAra, + where it belongs. This allows -1,5:w commands to work. Thanks to Jerry + Leichter. +4. Instead of "unterminated command", GetNmA now returns "ill-formed + expression", an new error message, when the stack is bogus. + + +5-June-1991 version 145 + +0. Changed TVERSION in TECOC.H to 145. +1. Modified PshMac to test set NumArg correctly, so a command like + ^UA1$2+MA=$$ will work. +2. The "#else" on line 122 of ZUNIX.C should be a "#endif". + + +5-June-1991 to 18-June-1993 version 146 + +0. Changed TVERSION in TECOC.H to 146. +1. Removed the ~ and F~ commands (the EXETIL.C file and the ExeFTi function) + They were temporary commands used by Mark Henderson. +3. Added makefile.cct, fixed various minor nits suggested by CodeCenter. +4. Fixed error in the way the EI command reads files. If the file being + read was too large for the buffer, memory was getting stomped. Thanks + to Mark Henderson for reporting the bug in detail and suggesting a fix. diff --git a/doc/problems.txt b/doc/problems.txt new file mode 100644 index 0000000..6209824 --- /dev/null +++ b/doc/problems.txt @@ -0,0 +1,292 @@ + This file contains informal notes about TECO-C. It includes bugs +and ideas for improvements. + [Unfortunately, it isn't as up to date as possible, some problems +in here are fixed, some aren't strictly "problems"...Manfred] +. Mark made ~ and F~ commands which aren't documented. +. Mark aded Curses support, which works for split screen scrolling but + doesn't support vtedit. It also needs to completely enter or leave + split screen mode when the 7:W command is executed, because I/O is + lousy to the screen if curses is active, even when all it should do + is simple output to the screen. +. n,m:w commands should return a value, but don't +. Steve Freyder's bug: <-^N-1;a> on a large file loops infinitely under + MS-DOS and/or Unix? +. if you set eightbit (4096,0et) with TECOC and exit, it stays set. If you + do it with TECO32, it doesn't. Why? Changing the screen height/width + works as expected. (VMS) +. do a 0,1:w to TECO32, it just returns. Do it to TECOC, it dies with + bad parameter value. TECOC should be the same. +. I do a getdvi on the output channel and then do a sensemode in + open_output_terminal. They're redundant. The sensemode should be it. +. EW causes a backup file to be created. +Problems reported by Richard Graham: + . EI$ doesn't seem to work. EIfilename$ does. (unsure about this) + . :]p= returns -1 10 times, then 0 if executed when TECO first starts + up on a PC. + . Try ":stext$ .ue :s$" and get ISA error, and then (on PC) the ? + command doesn't work. Generalized problem: TECO-C doesn't + "overwrite" a numeric value that's on the stack with a new one. + . How to search for a control-E? ED flag # 1, ^Eq and ^Eu don't + seem to let Richard do it. He says TECO-11 will take FS^E$^E$. +Problems running under Unix: + . ^C doesn't work. + . look at "man 3 time" and "man localtime" to implement date/time + . Is there a way to sensibly set ET_EIGHTBIT under Unix? + . ZUNIX.C's ZChIn doesn't handle the NoWait argument +Problems running on PC: + 1. editing .EXE files doesn't work. should it? + 2. ZChIn doesn't handle PC-extended characters from the keyboard + 3. After the work to make ^C's work better, doing a ^C in the + middle of a macro like detab.tec now works; but, ".=" displays + 0. shouldn't . be in the middle of the file wherever the + ^C happened? +There's a test case in TSTQR.TEC that causes TECO-11 to give the +UTC error. TECOC does too, but from then on it's screwed up. Why? +To support eight-bit characters, there are several places where casts +to "unsigned char" are used. The better solution is to go through the +code and declare everything to be unsigned char, then delete the +casts. Some of the casts are in CHMACS.H. +If you search for a string using a match control construct and the +search fails, the "?SRH Search failure "xxx"" error message shows the +match control construct with a <> surrounding it. TECO-11/32 does +not. +BldStr is used by commands other than search commands, yet it reports +the "illegal search string" error sometimes. It looks like the error +messages from TECO-11/32 aren't really correct. Need an error message +like "illegal string build construct" or something. +The error message "illegal ^E command in search string" would be +better if it were "illegal ^E construct in search string" +In ERR.C, the routines ErrMsg, ErrStr and ErrPSt all share code. Fix +it. make verbose messages for system errors. flesh out error +handling in z files Make a test case that checks the cases: + 1. call to ErrMsg + 2. call to ErrChr + 3. call to ErrStr + 4. call to ErrPSt + 5. call to ZVrbos on VAX and non-VAX machines +re-indent the code (automatically) to use 4-space indenting. This +will solve the problem that some lines are now too long. use clean +indenting scheme +A command like n+^T$$ won't get parsed right. Is this a general +problem? +merge zfrsrc and baksrc +convert pushex to pshnbr and pshopr +terminal modes aren't right on Sun +use standard Isdigit, etc. macros/functions? +The non-VMS ZPrscl's concatenate argv's and spaces to re-construct the +command line. There are better ways that are operating-system +dependent. +The construct: <0a"ad>' is not well-formed in TECOC, but it is in +TECO-11/32 The loop exits when the "end loop" command is skipped. In +TECOC, this means the loop nesting control variable isn't decremented, +so we "think" we're still in a loop even though we're not. This isn't +a problem in TECO-11/32. A more common programming construct is: +<0a"ad|1;'> which works without problems in TECOC. +The @-modified form of the ! "command" is supported in TECO-11/32, not +in TECOC. +In BOTH tecos, output of a long string to SYS$OUTPUT doesn't work if +the string is long enough. TECOC gets a signal, TECO-11/32 gets a +"OPCODE reserved to Digital" error. To fix, must make the "terminal +output buffer" dynamic. +All system calls must correctly handle being interrupted by control-C. +Page 228 of "Unix Programmer's Manual, Volume 1" talks about this a +little. Each system call should check for errors, but should not +treat control-Cs as an error. +If type ^C while it's executing a macro, get "Operation completed +under control-C" and a dollar sign! +If you type a control-C while help is being displayed, you get two +prompts +Control-C works fine at command splits. Checks need to be inserted +everywhere commands do loops on command arguments. For instance, 23p +needs a check in the loop that calls SinglP. +Does ExeCtT do the right thing when it's read with no wait and the +user types control-C? +The following weird thing happens (I forget which TECO): + 1. compile a file/DEBUG/NOOPT in one terminal session + 2. open the file with TECO in another session + 3. debug the application in the first session. Can't find file. + 4. do ^Z^Z to leave TECO in the second session + 5. file is deleted!!! +The ^EUq string build construct behaves differently than the +TECO-11/32 algorithm for a special case: if the character in the +q-register is a ^E. The command "5uas^EUA$" will search for ^E in +TECO-11/32 and will fail in TECO-C. +ZFrSrc exists only because I was playing with SCANC on a VAX. Delete +the VAX-specific code and then merge what's left with BakSrc, using +SIncrm in the loops. This is much cleaner. +Local q-registers need to be tested further. +CBf, SBf, TBf, ZBf do not expand? +Finish creation of TSTPW.TEC, a test case that demonstrates that +ZWRITE mimics TECO-11/32 for all cases of the edit buffer/gap and all +cases of line termination: FF, VT, CR/LF, $/CR/LF, and GapBeg and +GapEnd. +Open SOFDEV.RNO for reading, do _glossary$v$$ and see junk. Also, do +rt -r notes.rno and then y$$y$$ and see an extra blank line at the +bottom of the buffer. +Use TRNLNM instead of TRNLOG in ZINIT and ZEXEEI. Make a +general-purpose logical name translation procedure to be used by both? +File COMMANDS.TXT has several "not implemented" lines that aren't +right +Add help text for E%q and EQq to hlp file. +In TECO-11/32, the EG command uses the BldStr-like routine to build +its string. Teco-c should call BldStr from ZExeEG. +The macro system needs to be carefully checked. +If do 8192ET, then a null command string with just two escapes won't +"work". Need to hit three, and then get an error. +Scan Appendix C of TECO-11/32 manual for goodies. +In ZExeEI: + 1. status != RMS$_NORMAL in ZRedEI does not error + gracefully. + 2. If find $$ in the middle of the read buffer, can't + continue after executing the string. + 3. EI buffer won't expand. + 4. File closure on error on ^C ? +ExeCSt was changed to do CBfPtr < CStEnd instead of CBfPtr <= CStEnd. +Track and check. +Why clear q-register stack in MemIni if it's been statically +initialized in TECOC? +Page 5 of TECO.LST shows ET and ED encodings. Compare/contrast +In ExeFGt, if we're not in a loop, should behave as if we're +. We're not doing that now. Put in + If (MstTop) + { + CBfPtr = CStEnd; + return(SUCCESS); + } +into the code before the first return(FAILURE). +On the VAX, deal with disk quota overflow. Larry Kilgallen described +the handling of this: when you get a disk quota exceeded, just issue +the identical $PUT call again to exploit overdraft. This doesn't work +for creating files. +Date and time (^B and ^H) commands work under VAX/VMS. They will work +differently under other systems. Make a standard? +Say jz10v instead of zj10v and the two TECO's behave differently +Normal TECO handles two numbers in a row differently than TECO-C does. +TECO-C dies with a debugging message!!! +use register variables +use declaration of variables within blocks +see if type casts are superfluous in places. C already does it? +The September 1984 issue of Scientific American has an article by +Niklaus Wirth that describes a fast searching algorithm. Use it? +The entire ", ', <, >, O system should be checked. +CmdMod should be checked. +Is MovGap right? +The W command is stubbed out now. For debugging, ExeW exists, SkpE +skips over EG, EM, EN and EZ as if they were valid commands. A +problem with this is that the command to turn on SEEALL mode +"-1,3:W^[" returns ERR_NCA error, "negative argument to comma". +The code for INCCBP and the other places where ++CBfPtr happens needs +the MStTop test to be changed. Now, if a UTC should be reported, it's +not. It returns SUCCESS! +ExeO needs it's handling of CBfPtr to be fixed. There aren't checks +against CStEnd, and the last "--CBfPtr" may be wrong. +Shouldn't CBfPtr be renamed CStPtr? It would relate better to CStBeg, +CStEnd, etc. +help subsystem works on VAX, won't on another machine +Get rid of ??? which marks unfinished or questionable stuff. Get rid +of calls to ExeNYI. +DoEvEs doesn't implement the ES flag exactly like the manual says +DoEvEs has a system-dependent structure (UDummy) +the free function is an int on the VAX, void on the SAGE +Standard input and standard output are not used to communicate with +the terminal. UNIX people may expect that they are. This rules out +using TECO-C in a pipe-oriented manner. +Use DbgDCh instead of ZDspCh in ErrMsg for passed string displaying +difference between TypChr, EchoIt, CharOut? +COLON sounds like a character identifier. So does ATSIGN. +ChrFuncs requires DefChars +memory overflow +skipping commands is NOT finished. +In help, for errors, trace down the possible ways the code can print +each error message. Some of them are unobvious. Give an explanation +of all the ways an error can be generated to help a user figure out +his error. +Page 92 of the manual lists two informational messages. The 16 bit of +the ET mode control flag suppresses informational messages. These +messages are neither generated nor suppressed by TECO-C. +Doing an "ERfilename$" puts the expanded filespec in the filespec +buffer. Under TECO-11/32, doing a subsequent "ER$" to change I/O +streams does not wipe out the filespec buffer. It does in TECO-C. +For all the xxxBeg, xxxEnd, xxxPtr things, change all the comments to + xxxBeg; /* first char of xxx buffer */ + xxxEnd; /* last char of xxx buffer */ + xxxPtr; /* last char of xxx, plus 1 */ +check the MOBY MUNGER. It mentions lots of bugs in other TECOs. Some +of the bugs are esoteric and quite possibly exist in TECO-C +nulls are not stripped from input. +VAX TPU is able to read a file that is currently locked by another +user, which is useful for looking at BATCH log files while a BATCH job +is running. TECO-C can't. I looked at the microfiche code to see how +TPU does it. It seems to try to open the file, and if it gets +RMS$_FLK, then it tries to open the file again after setting the UPI +bit in FAB$SHR. This means that it is supposed to do block I/O to the +file. I couldn't find the place where actual file reading is done +(it's in $fileio, which is in TPU$CAL_MODULE, which I couldn't find.) +Does TPU do block I/O (section mapping?) +The following commands are not yet implemented in TECO-C + W video scope control + ^Y equivalent to ".+^S,." + EL open log file + ^F return value in console switch register + nEC control memory management +The following commands are not implemented in TECO-C, and probably +never will be, as they require operating system features that cannot +be assumed by a portable TECO. + EZ zero output tape + EM position magnetic tape + In addition, most of the commands defined in Appendix C of + the manual (Incompatible, Obsolete and System-Specific Commands) + are not implemented. + The ^R command (set or return radix) supports the 8, 10 and 16 +radices. TECO-C parses command-line numeric arguments using the +current radix. This can make command execution confusing for radix +16. Consider the command string "14A=$$", which returns the ascii +value of the 14th character after the character pointer. If the radix +is 16, the "A" is parsed as part of the number, and the ascii value of +a completely different character will be returned. + This is a trade-off. TECO-11/32 always parses command-line arguments +using radix 10. This destroys TECO's utility as a calculator for +hexadecimal. I believe access to a base 16 calculator is more +important than possible user confusion. Thus, be careful if you want +to change TECO's radix. Remember to change it back. Also note that +if you use TECO-C as a hexadecimal calculator, you must precede +hexadecimal numbers which start with one of the letters A-F with a 0 +in order to make TECO-C parse the number correctly. +You won't get "%Superseding file" messages. +Differences between TECO-C and TECO-11 or TECO32 under VMS: + . video only under Unix, commands somewhat different, see VIDEO.TXT + . Command line syntax different under Unix. + . EO returns 100+ + . 2048 bit of ET flag reverses meaning of DELETE and BACKSPACE keys + . -1EJ command returns additional operating system types + . 0:W returns additional terminal types + . s^n$ gives "invalid search argument", TECO-11/32 does nothing + . on ^Z^Z^Z, third ^Z is echoed + . default directory is TECO$MACROS for EI command + . TECO-C won't allow HP or HPW when edit buffer is empty + . TECO-C supports q-register I/O commands E% and EQ, TECO-11 + doesn't + . TECO-C supports ^EQ* and ^EQ_ as string build contructs, TECO-11 + doesn't + . TECO-C does case sensitivity correctly, not with bit checking, + so TECO-C does not consider "`","{","|","}" and "~" to be + equivalent to "@","[","\","]" and "^", respectively. + . The -P, -Y, and -N commands, which are implemented in TECO-11 + version 39, are not yet implemented in TECO-C. + . TECO-11 supports switches on file name arguments to commands like + ER, EB, etc. TECO-C does not. + . TECO-11/32 supports files with nonstandard record formats (like + FORTRAN carriage control). TECO-C does not. + . TECO-11/32 does funny stuff with lines ending in . + TECO-C doesn't (it can't under MS-DOS, which uses as + line terminators in files.) + . Escape-sequence handling not in TECOC yet. + . can be anything in TECO-11/32, not in TECOC + . :EGcmd args' is in TECO-11/32 + . ^T on/off handling in TECO-11/32 is better than in TECOC + . values returned by initialization macro are used by TECO-11/32 + . ^E can be set by the user in TECO-11/32 + . :^T command exists in TECO-11/32 + . nOtag0,tag1,tag2$ with an "n" that's out-of-range is supposed to + . cause no branch at all. Under TECO-32, a negative "n" causes a + branch to tag0. TECO-C correctly does no branch. diff --git a/doc/readme.1st b/doc/readme.1st index ddabcc7..713c647 100644 --- a/doc/readme.1st +++ b/doc/readme.1st @@ -39,6 +39,6 @@ mung link to tecoc teco link to tecoc Inspect link to tecoc lib: -*.tes *.tec TECO macros -src: -Full source files for Linux version +*.tes TECO command files for various things +*.tec Compressed TECO command files +src: Full source files diff --git a/doc/video.txt b/doc/video.txt new file mode 100644 index 0000000..6218bd1 --- /dev/null +++ b/doc/video.txt @@ -0,0 +1,85 @@ + +Notes from Blake McBride (blake@mcbride.name) +Video support under Linux & Mac OS/X has been restored. Getting it to +work under Windows would probably be easy (given ncurses support). +See the makefile's for instructions on enabling or disabling video +support. +When a file is being edited, you can execute: 5,7:w$$ to enter video +mode (the $ is the escape key). The "5" means 5 scroll lines at the +bottom of the screen. The remaining screen space is for the video +display. +Video mode can be exited with: 0,7:w$$ +As shown below, you can also startup in video mode using: + teco -scroll:5 myfile.txt +---------------------------------------------------------------------- +Original notes +Command line +------- ---- +-NOPAGE + Don't separate input into pages. Instead, treat form feeds + as normal characters. ++nnn + where nnn is any number of digits. Go to line number nnn and + set NOPAGE. Note this uses the UNIX end of line convention + for use with cc output &c. The non-unix line termination will + still be used for nL and other intrinsic TECO commands, this just + controls the starting line AT INVOCATION. +-SCROLL:nnn + do nnn,7:w +-SCROLL:nnn:SEEALL + do nnn,7:W and 1,3:W +-INSPECT + Same as /INSPECT +-NOMEMORY + Same as /NOMEMORY +Video +----- +^W Immediate mode command - try to place line containing dot in + centre of scope window +-4W Complete redraw of screen +-1W Stop refreshing scope before each prompt +1W Start refreshing scope before each prompt +0W refresh scope +3:w Seeall Mode (set to 1 if SeeAll is on, 0 otherwise) + seeall is more unix style then you might expect +5:w Hold mode is not properly implemented. I don't like it anyway. +7:W Number of lines in command window. The size of the scope window + will be (Rows - 7:W (- 1 if ET&256)) +8:w Attribute for special characters. This is highly implementation + dependent (curses implementation dependent). Under SUN OS 4.1 + 0 - no marking + 1 - underline + 2 - reverse + 4 - blink + 8 - dim + 16 - bold + 128 - ALT_CHARSET + currently controls marking of ` + END OF PAGE (BTEE/+) +9:W Bit 0 - keypad support on + Bit 1 - do not do timeout escape sequence detection +ET&1 image mode - doesn't really do much with curses version +ET&2 use scope for delete and control-U +ET&4 accept lowercase input +ET&32 read with no wait on control-T (unimplemented - easy though) +ET&2048 reverse roles of BS and DEL (good if you use stty erase ^H, + in particular the key placement of BS is sometimes much easier + to get at then DEL). Should I have it detect the kill character + and automatically set this? +ET&8192 accept ` as escape (for VT220 terminals) +ET&16384 special VT200 mode +ET&32768 trap control-C +EZ&1 if false VMS style versioning for backup files (multiple backups) + if true only one backup level (foo, foo.bak) +EZ&8 if TRUE use LARROW (<) for CR, if false use ` +EZ&16 if set then prefer audio beep else visual flash +EZ&32 winline divider for scope +EZ&128 if set DO NOT stop read on FF otherwise make pages as usual +EZ&256 UNIX NL-convert LF to on input and invert on output +ED&512 controls scope display. If set will use VT100 line drawing + characters for CR and LF (in non-scope mode). May degrade + performance. +EZ&2048 if set use BTEE for end of buffer, else use DIAMOND + (desirable for pathological terminal types) +EZ&8192 don't show CR in scope - closer to TECO-11, but really + not as good in my opinion (Mark Henderson) diff --git a/src/genclp.c b/src/genclp.c index f6d5db7..c8cd202 100644 --- a/src/genclp.c +++ b/src/genclp.c @@ -36,7 +36,11 @@ open_clpars_tec(ifile) FILE **ifile; #endif { +#ifdef MSDOS + *ifile = fopen("clpars.tec","rb"); +#else *ifile = fopen("clpars.tec","r"); +#endif if (*ifile == NULL) { puts("genclp: Unable to open file CLPARS.TEC for reading"); @@ -52,7 +56,11 @@ open_clpars_h(ofile) FILE **ofile; #endif { +#ifdef MSDOS + *ofile = fopen("clpars.h","wt"); +#else *ofile = fopen("clpars.h","w"); +#endif if (*ofile == NULL) { puts("genclp: Unable to open file CLPARS.C for writing"); @@ -206,7 +214,7 @@ main() open_clpars_tec(&ifile); write_header(ofile); write_line("#if USE_ANSI_CLPARS\n", ofile); - write_line("unsigned const char clpars[] = {\n", ofile); + write_line("unsigned char clpars[] = {\n", ofile); cnvrt(ifile, ofile, TRUE); close_clpars_tec(ifile); /* diff --git a/src/makefile b/src/makefile.linux similarity index 96% rename from src/makefile rename to src/makefile.linux index ac48309..88e1754 100644 --- a/src/makefile +++ b/src/makefile.linux @@ -2,27 +2,41 @@ # This makefile builds TECOC on Linux # Before running it, inspect the lines between here and the line containing # all #'s to select the way you want TECO-C built. + # If you want to compile with built-in debugging support, uncomment the # following line. When debugging is compiled in, the control-P command # can be used to turn on function tracing or get views of internal data # structures (see the DbgDsp function in tecoc.c). Compiling in this support # makes TECO-C larger and a little slower, so you should only use this # when you're debugging TECO-C. + #DEBG = -DDEBUGGING + # If you're debugging TECO-C, use this option to compile in a consistency # checking function called after each command executes. The function checks # the sanity of TECO-C's internal variables. This obviously slows things # down a little. + #CCHEK = -DCONSISTENCY_CHECKING + # If you want to use gcc, uncomment the following lines, which override the # COMPILE.c macro so it doesn't stick in the -target option, which gcc # doesn't understand. + CC= gcc -#CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -DLINUX -CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -DLINUX -#TERMOBJS = -ltermcap + +# Uncomment the following line for non-video teco +#CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -DLINUX + +# Or, uncomment the following two lines for video teco +CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -DLINUX -DCURSES +TERMOBJS = -lncurses + + COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c -g + ############################################################################# + CFILES= baksrc.c bldstr.c clenup.c cmatch.c docjr.c doeves.c doflag.c \ echoit.c err.c exea.c exeats.c exeb.c exebar.c exebsl.c exec.c \ execcc.c execln.c execom.c execrt.c execst.c execta.c exectc.c \ @@ -39,34 +53,46 @@ CFILES= baksrc.c bldstr.c clenup.c cmatch.c docjr.c doeves.c doflag.c \ makdbf.c makrom.c popmac.c pshmac.c pushex.c rdline.c rdpage.c \ readcs.c replac.c search.c singlp.c skpcmd.c srclop.c sserch.c \ tabort.c typbuf.c typest.c uminus.c wrpage.c zfrsrc.c zlinux.c + OBJECTS= $(CFILES:.c=.o) + tecoc: tecoc.o ${OBJECTS} ${LINK.c} -s -o $@ tecoc.o ${OBJECTS} ${TERMOBJS} + tecoc.o: tecoc.c zport.h tecoc.h deferr.h dchars.h chmacs.h + clpars.h: genclp clpars.tec - genclp + ./genclp + genclp: genclp.o ${LINK.c} -o $@ genclp.o + genclp.o: genclp.c + clean: @for i in makedep? ${OBJECTS} ; do \ if [ -f $$i ] ; then rm $$i ; fi ; \ done - rm -f tecoc tecoc.o core + rm -f tecoc tecoc.o core genclp.o genclp clpars.h *.tmp *~ *.bak + tags: etags *.c *.h + lint: # b = report unreachable break statements # c = complain about casts with questionable portability # h = apply heuristic tests # x = report unused externs lint -bchx -DSUNOS4_0 tecoc.c ${CFILES} + + # # Invoking this target (with "make depend") causes a new version of this # file to be created. This current version will be saved in a file named # "makefile.bak". In the new file, the lines following the special "DO NOT # DELETE" line will be replaced with a new set of dependency rules. # + depend: makedep @echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >makedep0 @echo '$$r makedep5' >>makedep0 @@ -75,6 +101,7 @@ depend: makedep @ed - makefile < makedep0 @rm makedep? @echo "new version of makefile generated, old version in makefile.bak" + makedep: FRC @cat /dev/null >makedep5 @echo "generating include file dependency list..." @@ -100,6 +127,8 @@ makedep: FRC @cat makedepe @(if [ -s makedepe ]; then false; fi) FRC: + + # DO NOT DELETE THIS LINE -- make depend uses it baksrc.o: baksrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h bldstr.o: bldstr.c zport.h tecoc.h defext.h deferr.h dchars.h chmacs.h diff --git a/src/makefile.osx b/src/makefile.osx index 92d17eb..300ad59 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -1,28 +1,42 @@ # -# This makefile builds TECOC on Linux +# This makefile builds TECOC on Mac OS X # Before running it, inspect the lines between here and the line containing # all #'s to select the way you want TECO-C built. + # If you want to compile with built-in debugging support, uncomment the # following line. When debugging is compiled in, the control-P command # can be used to turn on function tracing or get views of internal data # structures (see the DbgDsp function in tecoc.c). Compiling in this support # makes TECO-C larger and a little slower, so you should only use this # when you're debugging TECO-C. + #DEBG = -DDEBUGGING + # If you're debugging TECO-C, use this option to compile in a consistency # checking function called after each command executes. The function checks # the sanity of TECO-C's internal variables. This obviously slows things # down a little. + #CCHEK = -DCONSISTENCY_CHECKING + # If you want to use gcc, uncomment the following lines, which override the # COMPILE.c macro so it doesn't stick in the -target option, which gcc # doesn't understand. + CC= gcc -#CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -Wall -Wshadow -Wpointer-arith -Wcast-qual -DLINUX -CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -DOSX -#TERMOBJS = -ltermcap + +# Uncomment the following line for non-video teco +#CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -DOSX + +# Or, uncomment the following two lines for video teco +CFLAGS= ${OSVERS} ${DEBG} ${CCHEK} -O -DOSX -DCURSES +TERMOBJS = -lncurses + + COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c -g + ############################################################################# + CFILES= baksrc.c bldstr.c clenup.c cmatch.c docjr.c doeves.c doflag.c \ echoit.c err.c exea.c exeats.c exeb.c exebar.c exebsl.c exec.c \ execcc.c execln.c execom.c execrt.c execst.c execta.c exectc.c \ @@ -39,34 +53,46 @@ CFILES= baksrc.c bldstr.c clenup.c cmatch.c docjr.c doeves.c doflag.c \ makdbf.c makrom.c popmac.c pshmac.c pushex.c rdline.c rdpage.c \ readcs.c replac.c search.c singlp.c skpcmd.c srclop.c sserch.c \ tabort.c typbuf.c typest.c uminus.c wrpage.c zfrsrc.c zosx.c + OBJECTS= $(CFILES:.c=.o) + tecoc: tecoc.o ${OBJECTS} - ${LINK.c} -s -o $@ tecoc.o ${OBJECTS} ${TERMOBJS} + ${LINK.c} -o $@ tecoc.o ${OBJECTS} ${TERMOBJS} + tecoc.o: tecoc.c zport.h tecoc.h deferr.h dchars.h chmacs.h + clpars.h: genclp clpars.tec ./genclp + genclp: genclp.o ${LINK.c} -o $@ genclp.o + genclp.o: genclp.c + clean: @for i in makedep? ${OBJECTS} ; do \ if [ -f $$i ] ; then rm $$i ; fi ; \ done - rm -f tecoc tecoc.o core + rm -f tecoc tecoc.o core genclp.o genclp clpars.h *.tmp *~ *.bak + tags: etags *.c *.h + lint: # b = report unreachable break statements # c = complain about casts with questionable portability # h = apply heuristic tests # x = report unused externs lint -bchx -DSUNOS4_0 tecoc.c ${CFILES} + + # # Invoking this target (with "make depend") causes a new version of this # file to be created. This current version will be saved in a file named # "makefile.bak". In the new file, the lines following the special "DO NOT # DELETE" line will be replaced with a new set of dependency rules. # + depend: makedep @echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >makedep0 @echo '$$r makedep5' >>makedep0 @@ -75,6 +101,7 @@ depend: makedep @ed - makefile < makedep0 @rm makedep? @echo "new version of makefile generated, old version in makefile.bak" + makedep: FRC @cat /dev/null >makedep5 @echo "generating include file dependency list..." @@ -100,6 +127,8 @@ makedep: FRC @cat makedepe @(if [ -s makedepe ]; then false; fi) FRC: + + # DO NOT DELETE THIS LINE -- make depend uses it baksrc.o: baksrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h bldstr.o: bldstr.c zport.h tecoc.h defext.h deferr.h dchars.h chmacs.h diff --git a/src/zlinux.c b/src/zlinux.c index 5d65a0f..c2c120c 100644 --- a/src/zlinux.c +++ b/src/zlinux.c @@ -25,6 +25,9 @@ #include #include #include /* Rewritten 05/04 by TAA to use glob function */ +#if CURSES +#include /* has to come before zport.h */ +#endif #include "zport.h" /* define portability identifiers */ #include "tecoc.h" /* define general identifiers */ #include "chmacs.h" /* define character processing macros */ @@ -33,8 +36,64 @@ #include "deferr.h" /* define identifiers for error messages */ #include "defext.h" /* define external global variables */ #include "dscren.h" /* define identifiers for screen i/o */ +#if CURSES +/* + * The ACS_xxx symbols are defined in the SunOS version of curses, but not + * in either the BSD or X/OPEN Ultrix versions. Who knows where else they + * are defined? Isn't portability wonderful? + * + * Note that this code implicitly assumes a VT100-compatible terminal. + * Tough. (Jerry Leichter, June 1991) + */ +#ifndef ACS_PLMINUS +#define ACS_PLMINUS (A_ALTCHARSET | 0x67) +#define ACS_LLCORNER (A_ALTCHARSET | 0x60) +#define ACS_LRCORNER (A_ALTCHARSET | 0x6A) +#define ACS_LARROW (A_ALTCHARSET | 0x7C) /* Really not-equal */ +#define ACS_HLINE (A_ALTCHARSET | 0x71) +#define ACS_BTEE (A_ALTCHARSET | 0x76) +#define ACS_DIAMOND (A_ALTCHARSET | 0x60) +#define ACS_RTEE (A_ALTCHARSET | 0x75) +#endif +WINDOW *curwin; +int ScopeFlg = 0; /* for ZDspCh and ZDspBuf */ +int olddot; +#define DOT (GapBeg - EBfBeg) +#define ISSCW (ScopeFlg) +unsigned char *p_scope_start; +int scope_start; +int winline; +int cursoratbottomline; +int cursorattopline; +static int colsave; +int dotx,doty; /* position of cursor in scope */ +int dotx1, doty1; /* pos. after printing character in scope */ +int skiprefresh = 0; +int cmdx,cmdy; /* position of cursor in command buffer */ +int scope_start, scope_end; +unsigned char *pscope_start; +#define CT ((EzFlag & EZ_VT100GRAPHICS) ? ACS_PLMINUS : '^') +#define LB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LLCORNER : '[') +#define RB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LRCORNER : ']') +#else /* else (not CURSES) ----------------------*/ +#ifdef LINUX static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */ static struct termios out, cur; /* terminal characteristics buffers */ +#else +#include /* define CBREAK, ECHO, TIOCGETP, etc. */ +static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */ +static struct sgttyb out, cur; /* terminal characteristics buffers */ +#endif +static char tbuf[1024]; /* store TERMCAP entry here */ +static char tarea[1024]; /* store decoded TERMCAP stuff here */ +static char *ce; /* TERMCAP sequence: clear to end-of-line */ +static char *up; /* TERMCAP sequence: cursor up */ +static char *so; /* TERMCAP sequence: reverse video on */ +static char *se; /* TERMCAP sequence: reverse video off */ +int tputs(); /* send termcap string to a given function */ +int tgetent(); /* load a terminal capability buffer */ +char *tgetstr(); /* get str value of a terminal capability */ +#endif static char tbuf[1024]; /* store TERMCAP entry here */ // static char tarea[1024]; /* store decoded TERMCAP stuff here */ // static char *ce; /* TERMCAP sequence: clear to end-of-line */ @@ -45,7 +104,6 @@ int tputs(); /* send termcap string to a given function */ int tgetent(); /* load a terminal capability buffer */ char *tgetstr(); /* get str value of a terminal capability */ static int vernum(); /* see bottom of this file */ -extern int sys_nerr; /* number of system error messages */ static int SupGotCtC = 0; static glob_t pglob; static int globindex = 0; @@ -82,8 +140,7 @@ system and imbedded in a TECO-style message with the SYS mnemonic. *****************************************************************************/ static VVOID ZErMsg() { - if (errno < sys_nerr) - ErrStr(ERR_SYS, sys_errlist[errno]); + ErrStr(ERR_SYS, strerror(errno)); } /***************************************************************************** ZAlloc() @@ -105,7 +162,14 @@ this function controls the signal generator directly. *****************************************************************************/ VVOID ZBell(VVOID) { +#if CURSES + if (EzFlag & EZ_AUDIO_BEEP) + beep(); /* audio beep */ + else + flash(); /* visible flash */ +#else ZDspCh('\7'); +#endif } /***************************************************************************** ZChIn() @@ -133,7 +197,11 @@ BOOLEAN NoWait; /* return immediately? */ LastLF = FALSE; return (DEFAULT)LINEFD; } +#if CURSES + if ((Charac = getch()) == ERR) { +#else if (read(fileno(stdin), &Charac, 1) != 1) { +#endif if (GotCtC || SupGotCtC) return (DEFAULT)CTRL_C; if (!GotCtC) { @@ -270,8 +338,14 @@ voidptr cp; VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */ { DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); +#if !CURSES if (tty_set == TRUE) +#ifdef LINUX tcsetattr(0, TCSANOW, &out); +#else + ioctl(0, TIOCSETP, &out); +#endif +#endif } /***************************************************************************** ZDoCmd() @@ -315,14 +389,267 @@ character. If such improvements do not apply to the system this program is running on, then this function can simply call ZDspCh for every character in the buffer. *****************************************************************************/ +#if CURSES +static void +zaddch(c,wecho) +char c; +int wecho; /* if set - also do refresh */ +{ + static int retflag = 0; + int needrefresh = 1; + int y,x; + if (c=='\n') { + if (!retflag) /* previous char was not \r */ + waddch(curwin,c); + else { /* this LF is part of a CRLF sequence */ + waddch(curwin,'\n'); /* this may force a scroll */ + waddch(curwin,'\r'); + } + } else if (c=='\b') { /* backspace */ + getyx(stdscr,y,x); + if (x==0 && y>0) + move(y-1,HtSize - 1); + else if (x>0) + move(y,x-1); + else /* x==0 and y==0 */ + ; + } else { /* c is neither a newline nor a backspace */ + if (retflag) + waddch(curwin,'\r'); + if (c!='\r') { + if (ISSCW) { + getyx(stdscr,y,x); + if (x < HtSize -1) + waddch(curwin,c); + } else + if (wecho) { +#ifdef ULTRIX + waddch(curwin,c); +#else + wechochar(curwin,c); + needrefresh = 0; +#endif + } else + waddch(curwin,c); + } + } + retflag = (c=='\r'); + if (wecho && needrefresh) + refresh(); +} +static void +specon() +{ + if (SpcMrk) + wattron(stdscr,0400000L * (long) SpcMrk); +} +static void +specoff() +{ + if (SpcMrk) + wattroff(stdscr,0400000L * (long) SpcMrk); +} +static void +gr_on() +{ + wattron(stdscr,A_ALTCHARSET); +} +static void +gr_off() +{ + wattroff(stdscr,A_ALTCHARSET); +} +static int +intabs(t) +int t; +{ + return (t<0) ? -t : t; +} +static void +zaddch2(c) +char c; +{ + static int retflag = 0; + if (SeeAll) { + if (c=='\n') { + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin, 'e'); + gr_off(); + } else { + waddch(curwin,CT); + waddch(curwin,'J'); + } + if (!retflag) { /* previous character was not \r */ + waddch(curwin,c); + } else { /* this LF is in a CRLF sequence */ + waddch(curwin,'\n'); + waddch(curwin,'\r'); + } + } else { /* c is not a newline */ + if (c=='\r') { + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin,'d'); gr_off(); + } else { + waddch(curwin,CT); + waddch(curwin,'M'); + } + } else if (c=='\t') { + if (EzFlag & EZ_VT100GRAPHICS) { + int y,x,y1,x1,cntr; + getyx(curwin,y,x); + waddch(curwin,'\t'); + getyx(curwin,y1,x1); + move(y,x); + gr_on(); + cntr = 0; + waddch(curwin,'b'); + getyx(curwin,y,x); + while ((cntr < 8) && (y!=y1 || x!=x1) && + (y 9) ? (i - 10 + 'A') : (i + '0'); + waddch(curwin,a); + waddch(curwin,b); + waddch(curwin,RB); + } else if (c < 32) { + waddch(curwin, CT); + waddch(curwin, c | 64); + } else + waddch(curwin,c); + } + retflag = (c==CRETRN); + } else { /* not in SEEALL mode */ + c = c & 0177; /* dump 8th bit */ + if (c=='\n') { + waddch(curwin,'\n'); + waddch(curwin,'\r'); + } else if (c=='\b') { + waddch(curwin,'^'); + waddch(curwin,'H'); + } else { /* c is neither a newline nor a backspace */ + switch (c) { + case CRETRN: + if (EzFlag & EZ_INVCR) { + waddch(curwin, ' '); + } else if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin, 'd'); + gr_off(); + } else if (EzFlag & EZ_ARROW) { + specon(); + waddch(curwin, ACS_LARROW); + specoff(); + } else { + specon(); + waddch(curwin,'`'); + specoff(); + } + break; + case ESCAPE: + specon(); + waddch(curwin,'$'); + specoff(); + break; + case VRTTAB: + case FORMFD: + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin,c); + gr_off(); + } else { + waddch(curwin, c); + } + waddch(curwin, '\n'); + waddch(curwin, '\r'); + default: + waddch(curwin,c); + } + } + retflag = (c=='\r'); + } +} +#endif VVOID ZDspBf(buffer, length) /* output a buffer to terminal */ charptr buffer; SIZE_T length; { +#if CURSES + int i; + int y,x; + for (i=0;i=(HtSize-1)) + break; + } + if (!GotCtC) + zaddch(*(buffer+i),0); + else + break; + } + wrefresh(curwin); +#else if (write(fileno(stdout), buffer, length) == -1) { puts("Unable to write to terminal in function ZDspBf"); TAbort(EXIT_FAILURE); } +#endif } /***************************************************************************** ZDspCh() @@ -331,10 +658,14 @@ SIZE_T length; VVOID ZDspCh(Charac) /* output a character to terminal */ char Charac; { +#if CURSES + zaddch(Charac,1); +#else if (write(fileno(stdout), &Charac, 1) == -1) { puts("Unable to write to terminal in function ZDspCh"); TAbort(EXIT_FAILURE); } +#endif } /***************************************************************************** ZExCtB() @@ -421,6 +752,11 @@ DEFAULT ZExeEJ() /* execute an EJ command */ VVOID ZExit(estat) /* terminate TECO-C */ DEFAULT estat; { +#if CURSES + nodelay(stdscr,FALSE); /* to avoid a bug in some System V.2 */ + /* releases of curses */ + endwin(); +#endif ZClnUp(); exit(estat); } @@ -671,7 +1007,8 @@ BOOLEAN RepFNF; /* report "file not found" error? */ charptr dummyp = NULL; char TmpBfr[FILENAME_MAX]; ptrdiff_t TmpLen = FBfPtr-FBfBeg; - if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + BOOLEAN noDot; + if (noDot = strchr(FBfBeg,'.') == NULL) { /* if no dot */ (void)strcat(FBfBeg,".tec"); /* append .tec */ FBfPtr += 4; if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { @@ -692,7 +1029,7 @@ BOOLEAN RepFNF; /* report "file not found" error? */ IFisCR[IfIndx] = 0; return SUCCESS; } - if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + if (noDot) { /* if no dot */ (void)strcat(FBfBeg,".tec"); /* append .tec */ FBfPtr += 4; if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { @@ -1045,19 +1382,35 @@ DEFAULT *retlen; /* returned length of string */ VVOID ZScrOp(OpCode) /* do a screen operation */ int OpCode; /* code for operation */ { -// if (CrType == UNTERM || tbuf[0] == 0) {/* if unknown terminal type */ -// return; /* can't do screen operations */ -// } -// -// switch (OpCode) { -// case SCR_CUP: tputs(up, 1, ZDspCh); -// break; -// case SCR_EEL: tputs(ce, 1, ZDspCh); -// break; -// case SCR_ROF: tputs(se, 1, ZDspCh); -// break; -// case SCR_RON: tputs(so, 1, ZDspCh); -// } +#if CURSES + int x,y; + switch (OpCode) { + case SCR_EEL: clrtoeol(); + break; + case SCR_CUP: getyx(stdscr,y,x); + if (y-1) + move(y-1,x); + break; + case SCR_ROF: standend(); break; + case SCR_RON: standout(); break; + } + refresh(); +#else +#ifndef LINUX // BAD for now, but do we really want this?? + if (CrType == UNTERM || tbuf[0] == 0) {/* if unknown terminal type */ + return; /* can't do screen operations */ + } + switch (OpCode) { + case SCR_CUP: tputs(up, 1, ZDspCh); + break; + case SCR_EEL: tputs(ce, 1, ZDspCh); + break; + case SCR_ROF: tputs(se, 1, ZDspCh); + break; + case SCR_RON: tputs(so, 1, ZDspCh); + } +#endif +#endif } /***************************************************************************** ZSetTT() @@ -1148,63 +1501,143 @@ static void sighup() { TAbort(EXIT_FAILURE); } +#if !CURSES /* * sigstop - what to do if we get a ^Z */ static void sigstop() { +#ifdef LINUX tcsetattr(0, TCSANOW, &out); puts("[Suspending...]\r\n"); kill(getpid(), SIGSTOP); puts("[Resuming...]\r\n"); tcsetattr(0, TCSANOW, &cur); +#else + ioctl(0, TIOCSETP, &out); + puts("[Suspending...]\r\n"); + kill(getpid(), SIGSTOP); + puts("[Resuming...]\r\n"); + ioctl(0, TIOCSETP, &cur); +#endif } +#ifndef LINUX +/* + * xtgetstr() - just like tgetstr() except it returns "" instead of + * NULL if the tgetstr() fails. As in tcsh 5.18. + */ +char *xtgetstr(c, a) +char *c; +char **a; +{ + char *r; + if ((r = tgetstr(c, a)) == NULL) + return ""; + return r; +} +#endif +#endif /* * ZTrmnl - set up terminal modes */ VVOID ZTrmnl() /* set up I/O to the terminal */ { +#if !CURSES + char *ta; +#endif EtFlag = ET_READ_LOWER | /* guess: term has lowercase and */ +#if CURSES + ET_WAT_SCOPE | /* "WATCH" support exists */ +#endif ET_EIGHTBIT | /* terminal uses 8-bit characters */ - ET_SCOPE; /* it's a scope, not hardcopy */ + ET_SCOPE; /* it's a scope, not hardcopy */ EzFlag = EZ_NO_VER | /* don't do VMS-style file versions */ +#if CURSES +/* EZ_UNIXNL | * don't add CRs to newlines */ +#endif EZ_INVCR; /* don't show little c/r characters */ /* * get terminal characteristics and set some signals */ +#if !CURSES +#ifdef LINUX if (tcgetattr(0, &out) != -1) tty_set = TRUE; /* tell ZClnUp to clean up */ tcgetattr(0, &cur); +#else + if (ioctl(0, TIOCGETP, &out) != -1) + tty_set = TRUE; /* tell ZClnUp to clean up */ + ioctl(0, TIOCGETP, &cur); +#endif #ifdef SIGTSTP signal(SIGTSTP, sigstop); /* call sigstop on stop (control-Z) */ #endif +#endif /* * set CBREAK/noECHO/noCRMOD */ +#if CURSES + initscr(); /* initialize screens */ +#ifdef ULTRIX + setupterm(0,1,0); /* Enable termcap compatibility */ +#endif + scrollok(stdscr,TRUE); /* scroll if cursor moves too hi/lo */ + idlok(stdscr,TRUE); /* use hardware insert/delete line */ + cbreak(); /* don't wait for CRs (CBREAK) */ + noecho(); /* don't echo characters (ECHO) */ + nonl(); /* don't add CRs to NEWLINEs (CRMOD) */ + curwin = stdscr; + ScopeFlg = 0; /* not writing in scope */ +#else /* NOT CURSES */ +#ifdef LINUX cur.c_lflag &= ~ICANON; cur.c_lflag &= ~ECHO; cur.c_oflag &= ~ONLCR; cur.c_iflag &= ~(ICRNL | INLCR); tcsetattr(0, TCSANOW, &cur); +#else + cur.sg_flags |= CBREAK; /* don't wait for CRs (CBREAK) */ + cur.sg_flags &= ~ECHO; /* don't echo characters (ECHO) */ + cur.sg_flags &= ~CRMOD; /* don't add CRs to NEWLINEs (CRMOD) */ + ioctl(0, TIOCSETP, &cur); /* set the new modes */ +#endif +#endif signal(SIGINT, CntrlC); /* call CntrlC on interrupt */ signal(SIGHUP, sighup); /* call sighup on hang up */ siginterrupt(SIGINT, 1); /* * set up termcap stuff */ +#if !CURSES tbuf[0] = 0; -// if ((ta = getenv("TERM")) == NULL) { /* get terminal type */ -// ta = "dumb"; -// } -// tgetent(tbuf, ta); /* tbuf gets terminal description */ -// ta = tarea; -// ce = xtgetstr("ce",&ta); /* clear to end of line */ -// se = xtgetstr("se",&ta); /* end standout mode (rev. video) */ -// so = xtgetstr("so",&ta); /* begin standout mode */ -// up = xtgetstr("up",&ta); /* cursor up */ +#ifdef LINUX // BAD for now but do we really want this?? +#else + if ((ta = getenv("TERM")) == NULL) { /* get terminal type */ + ta = "dumb"; + } + tgetent(tbuf, ta); /* tbuf gets terminal description */ + ta = tarea; + ce = xtgetstr("ce",&ta); /* clear to end of line */ + se = xtgetstr("se",&ta); /* end standout mode (rev. video) */ + so = xtgetstr("so",&ta); /* begin standout mode */ + up = xtgetstr("up",&ta); /* cursor up */ +#endif +#endif CrType = VT102; /* Let's pretend we are a VT102 even though we are really using termcap! */ +#if VIDEO +#if CURSES +#ifdef ULTRIX + VtSize = LINES; + HtSize = COLS; +#else + getmaxyx(stdscr, VtSize, HtSize); +#endif +#else + VtSize = HtSize = 0; +#endif +#endif } /***************************************************************************** ZVrbos() @@ -1263,7 +1696,7 @@ charptr BfrEnd; /* address of output buffer end */ BfrPtr--; } } - if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + if (putc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { ZErMsg(); ErrMsg(ERR_UWL); DBGFEX(2,DbgFNm,"FAILURE"); @@ -1354,3 +1787,384 @@ char *target; closedir(dirp); return (found) ? maxver : -2; } +#if CURSES +static void movedot(HowFar) +LONG HowFar; /* positive or negative displacement */ +{ + if (HowFar > 0) { + if ((GapEnd+HowFar) > EBfEnd) { + HowFar = EBfEnd - GapEnd; + } + MEMMOVE(GapBeg, GapEnd+1, HowFar); + GapBeg += HowFar; + GapEnd += HowFar; + } else { + if ((GapBeg+HowFar) < EBfBeg) { + HowFar = EBfBeg - GapBeg; + } + GapBeg += HowFar; + GapEnd += HowFar; + MEMMOVE(GapEnd+1, GapBeg, -(HowFar)); + } +} +static void +drawline() +{ + int i; + if (winline) { + move(VtSize - ScroLn - 1, 0); + for (i=0;i= VtSize - winline - ScroLn) + return; + clrtoeol(); + for (x=y+1;x HtSize * (VtSize - ScroLn)) + || HldFlg) { + /* admittedly a heuristic ! */ + int linedisp, disp; + int siz = VtSize - ScroLn - 1 - winline; + linedisp = siz/2-2; + if (linedisp > 0) { + disp = Ln2Chr(-linedisp); + p_scope_start = GapBeg + disp; + scope_start = DOT + disp; + goto l1; /* no need to do stuff to get to beginning + of line */ + } + } + if (p_scope_start > EBfBeg) { + /* set p_scope_start to beginning of line */ + if (scope_start > DOT) { /* move */ + p_scope_start = GapBeg; + scope_start = DOT; + } + flag = 0; + while ((p_scope_start > EBfBeg) && !flag) { + --p_scope_start; + if (IsEOL(*p_scope_start)) + flag++; + } + if (p_scope_start != EBfBeg || IsEOL(*p_scope_start)) + ++p_scope_start; + } +/* + * note here p_scope_start may still be at GapBeg after all this number of + * characters we "backed up" is GapBeg - p_scope_start + */ +l1: olddot = DOT; move(0,0); + charcounter = GapBeg - p_scope_start; + if (p_scope_start < GapBeg) { + for (curptr=p_scope_start; curptr < GapBeg; curptr++) { + int redrawflag; + zaddch2(*curptr); + getyx(stdscr,y,x); + if (y>VtSize - ScroLn - 1 - winline) { + int lines = 0; + unsigned char *charpointer; +/* + * we didn't get to print dot - try moving p_scope_start one line forward or + * if lots of lines in between DOT and p_scope_start then just redraw + */ + move(y-1,0); + clrtoeol(); + redrawflag = 0; + if (p_scope_start >= EBfEnd) { + finish(); + drawline(); + move(cccmdy,cccmdx); + return; /* blew it */ + } + /* about how many lines ? */ + for (charpointer = p_scope_start; + charpointer < GapBeg; charpointer++) { + if (IsEOL(*charpointer)) + lines++; + if (lines > 2*(VtSize - ScroLn)) + break; + } + if (lines > 2*(VtSize-ScroLn)) { + /* just redraw everything */ + p_scope_start = GapBeg; + scope_start = DOT; + move(0,0); + /* clear(); */ + p_scope_start = GapBeg; + scope_start = DOT; + goto draw_all; + } + /* move forward a line */ + while (p_scope_start < GapBeg && !IsEOL(*p_scope_start)) { + ++p_scope_start; + ++scope_start; + } + if (IsEOL(*p_scope_start)) { + p_scope_start++; scope_start++; + } + if (p_scope_start >= GapBeg) { + p_scope_start = GapBeg; + scope_start = DOT; + } + goto l1; + } + } + } + curptr = GapEnd+1; + standout(); + getyx(stdscr, doty, dotx); + if (curptr > EBfEnd) { + getyx(stdscr,y,x); + if (y <= VtSize - ScroLn - 1 - winline) { + specon(); + addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND); + specoff(); + standend(); + getyx(stdscr, doty1, dotx1); + } + finish(); + drawline(); + move(cccmdy,cccmdx); + clrtoeol(); + return; + } else { + if (*curptr=='\n') { + if (!(SeeAll) && (y <= VtSize - ScroLn - 1 - winline)) { + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); waddch(curwin,'e'); gr_off(); + } else + addch(ACS_RTEE); + } + } + zaddch2(*curptr); + } + standend(); + getyx(stdscr, doty1, dotx1); + curptr++; + getyx(stdscr,y,x); + if (y>VtSize - ScroLn - 1 - winline) { + drawline(); + move(cccmdy,cccmdx); + return; + } + while ((curptr <= EBfEnd)) { + zaddch2(*curptr); + getyx(stdscr,y,x); + if (y>=VtSize - ScroLn - winline) + break; + ++curptr; + } + if (y < VtSize - ScroLn - winline && curptr > EBfEnd) { + specon(); + addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND); + specoff(); + } + finish(); + drawline(); + move(cccmdy,cccmdx); +} +void +centre() +{ + int linedisp, disp; + int siz = VtSize - ScroLn - 1 - winline; + linedisp = siz/2-2; + if (linedisp > 0) { + disp = Ln2Chr(-linedisp); /* disp <= 0 */ + p_scope_start = GapBeg + disp; + scope_start = DOT + disp; + } else { + p_scope_start = GapBeg; + scope_start = DOT; + } + redraw(); +} +void +dolf() +{ + if (!skiprefresh) + redraw(); +} +void +dobs() +{ + if (!skiprefresh) + redraw(); +} +void +ccs() +{ + colsave = (-1); +} +void +do_right() +{ + colsave = (-1); + CmdMod &= ~COLON; + if (GapEnd < EBfEnd) { + DoCJR(1); + redraw(); + refresh(); + } +} +void +do_left() +{ + colsave = (-1); + CmdMod &= ~COLON; + if (EBfBeg < GapBeg) { + DoCJR(-1); + redraw(); + refresh(); + } +} +void +do_sf() +{ +} +void +do_sr() +{ +} +void +do_up() +{ + int disp = Ln2Chr(-1); int ll; int dist; + if (colsave < 0) { + colsave = -Ln2Chr(0); + } + CmdMod &= ~COLON; +/* + * find length of prev line in characters + */ + ll = Ln2Chr(0) - Ln2Chr(-1) - 1; + if (ll==(-1)) + return; + dist = disp + ((colsave >= ll) ? ll : colsave); + movedot(dist); + redraw(); + refresh(); +} +void +do_down() +{ + int disp = Ln2Chr(1); + int ll, dist; + if (colsave < 0) { + colsave = -Ln2Chr(0); + } + CmdMod &= ~COLON; + ll = Ln2Chr(2) - Ln2Chr(1) - 1; + if (ll==(-1)) { + movedot(EBfEnd - GapEnd); + } else { + dist = disp + ((colsave >= ll) ? ll : colsave); + movedot(dist); + } + redraw(); + refresh(); +} +void +do_seetog() /* toggle SeeAll mode */ +{ + SeeAll = (SeeAll > 0) ? 0 : 1; + redraw(); + refresh(); +} +void +keypad_on() +{ + keypad(stdscr, (KeyPad & 1)); + keypad(stdscr, (KeyPad & 2)); +} +void +keypad_off() +{ +#ifndef ULTRIX + notimeout(stdscr, FALSE); +#endif + keypad(stdscr, FALSE); +} +void +Scope(bot) /* first crack */ +int bot; +{ + if (bot <0) + return; + if (bot == 0) { + setscrreg(0, VtSize -1); + } else { + winline = (EzFlag & EZ_WIN_LINE) ? 1 : 0; + setscrreg(VtSize - bot, VtSize - 1); + move(VtSize - bot, 0); + curwin = stdscr; + initialize_scope(); + } +} +#endif diff --git a/src/zmsdos.c b/src/zmsdos.c index 1f87763..9aa3a04 100644 --- a/src/zmsdos.c +++ b/src/zmsdos.c @@ -17,6 +17,7 @@ #include /* prototypes for strlen(), strcat(), ... */ #include /* prototype for utime() */ #include /* prototype for stat() */ +#include #include "zport.h" /* define portability identifiers */ #include "tecoc.h" /* define general identifiers */ diff --git a/src/zosx.c b/src/zosx.c index 21cc7d9..268212e 100644 --- a/src/zosx.c +++ b/src/zosx.c @@ -1,6 +1,6 @@ /***************************************************************************** - ZLinux.c - System dependent code for Linux + zosx.c + System dependent code for Mac OS X This is based on zunix.c, with changes (see comments "TAA") for enhanced functionality. *****************************************************************************/ @@ -24,6 +24,9 @@ #include #include #include /* Rewritten 05/04 by TAA to use glob function */ +#if CURSES +#include /* has to come before zport.h */ +#endif #include "zport.h" /* define portability identifiers */ #include "tecoc.h" /* define general identifiers */ #include "chmacs.h" /* define character processing macros */ @@ -32,6 +35,62 @@ #include "deferr.h" /* define identifiers for error messages */ #include "defext.h" /* define external global variables */ #include "dscren.h" /* define identifiers for screen i/o */ +#if CURSES +/* + * The ACS_xxx symbols are defined in the SunOS version of curses, but not + * in either the BSD or X/OPEN Ultrix versions. Who knows where else they + * are defined? Isn't portability wonderful? + * + * Note that this code implicitly assumes a VT100-compatible terminal. + * Tough. (Jerry Leichter, June 1991) + */ +#ifndef ACS_PLMINUS +#define ACS_PLMINUS (A_ALTCHARSET | 0x67) +#define ACS_LLCORNER (A_ALTCHARSET | 0x60) +#define ACS_LRCORNER (A_ALTCHARSET | 0x6A) +#define ACS_LARROW (A_ALTCHARSET | 0x7C) /* Really not-equal */ +#define ACS_HLINE (A_ALTCHARSET | 0x71) +#define ACS_BTEE (A_ALTCHARSET | 0x76) +#define ACS_DIAMOND (A_ALTCHARSET | 0x60) +#define ACS_RTEE (A_ALTCHARSET | 0x75) +#endif +WINDOW *curwin; +int ScopeFlg = 0; /* for ZDspCh and ZDspBuf */ +int olddot; +#define DOT (GapBeg - EBfBeg) +#define ISSCW (ScopeFlg) +unsigned char *p_scope_start; +int scope_start; +int winline; +int cursoratbottomline; +int cursorattopline; +static int colsave; +int dotx,doty; /* position of cursor in scope */ +int dotx1, doty1; /* pos. after printing character in scope */ +int skiprefresh = 0; +int cmdx,cmdy; /* position of cursor in command buffer */ +int scope_start, scope_end; +unsigned char *pscope_start; +#define CT ((EzFlag & EZ_VT100GRAPHICS) ? ACS_PLMINUS : '^') +#define LB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LLCORNER : '[') +#define RB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LRCORNER : ']') +#else /* else (not CURSES) ----------------------*/ +#ifdef LINUX +static struct termios out, cur; /* terminal characteristics buffers */ +#else +#include /* define CBREAK, ECHO, TIOCGETP, etc. */ +static struct sgttyb out, cur; /* terminal characteristics buffers */ +#endif +static char tbuf[1024]; /* store TERMCAP entry here */ +static char tarea[1024]; /* store decoded TERMCAP stuff here */ +static char *ce; /* TERMCAP sequence: clear to end-of-line */ +static char *up; /* TERMCAP sequence: cursor up */ +static char *so; /* TERMCAP sequence: reverse video on */ +static char *se; /* TERMCAP sequence: reverse video off */ +int tputs(); /* send termcap string to a given function */ +int tgetent(); /* load a terminal capability buffer */ +char *tgetstr(); /* get str value of a terminal capability */ +#endif static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */ static struct termios out, cur; /* terminal characteristics buffers */ static char tbuf[1024]; /* store TERMCAP entry here */ @@ -104,7 +163,14 @@ this function controls the signal generator directly. *****************************************************************************/ VVOID ZBell(VVOID) { +#if CURSES + if (EzFlag & EZ_AUDIO_BEEP) + beep(); /* audio beep */ + else + flash(); /* visible flash */ +#else ZDspCh('\7'); +#endif } /***************************************************************************** ZChIn() @@ -132,7 +198,11 @@ BOOLEAN NoWait; /* return immediately? */ LastLF = FALSE; return (DEFAULT)LINEFD; } +#if CURSES + if ((Charac = getch()) == ERR) { +#else if (read(fileno(stdin), &Charac, 1) != 1) { +#endif if (GotCtC || SupGotCtC) return (DEFAULT)CTRL_C; if (!GotCtC) { @@ -269,8 +339,14 @@ voidptr cp; VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */ { DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); +#if !CURSES if (tty_set == TRUE) +#ifdef LINUX tcsetattr(0, TCSANOW, &out); +#else + ioctl(0, TIOCSETP, &out); +#endif +#endif } /***************************************************************************** ZDoCmd() @@ -303,6 +379,242 @@ VVOID ZDoCmd(charptr GBfBeg, charptr GBfPtr) /* die and pass command to OS */ (void)perror (""); ZExit (EXIT_SUCCESS); } +#if CURSES +static void +zaddch(c,wecho) +char c; +int wecho; /* if set - also do refresh */ +{ + static int retflag = 0; + int needrefresh = 1; + int y,x; + if (c=='\n') { + if (!retflag) /* previous char was not \r */ + waddch(curwin,c); + else { /* this LF is part of a CRLF sequence */ + waddch(curwin,'\n'); /* this may force a scroll */ + waddch(curwin,'\r'); + } + } else if (c=='\b') { /* backspace */ + getyx(stdscr,y,x); + if (x==0 && y>0) + move(y-1,HtSize - 1); + else if (x>0) + move(y,x-1); + else /* x==0 and y==0 */ + ; + } else { /* c is neither a newline nor a backspace */ + if (retflag) + waddch(curwin,'\r'); + if (c!='\r') { + if (ISSCW) { + getyx(stdscr,y,x); + if (x < HtSize -1) + waddch(curwin,c); + } else + if (wecho) { +#ifdef ULTRIX + waddch(curwin,c); +#else + wechochar(curwin,c); + needrefresh = 0; +#endif + } else + waddch(curwin,c); + } + } + retflag = (c=='\r'); + if (wecho && needrefresh) + refresh(); +} +static void +specon() +{ + if (SpcMrk) + wattron(stdscr,0400000L * (long) SpcMrk); +} +static void +specoff() +{ + if (SpcMrk) + wattroff(stdscr,0400000L * (long) SpcMrk); +} +static void +gr_on() +{ + wattron(stdscr,A_ALTCHARSET); +} +static void +gr_off() +{ + wattroff(stdscr,A_ALTCHARSET); +} +static int +intabs(t) +int t; +{ + return (t<0) ? -t : t; +} +static void +zaddch2(c) +char c; +{ + static int retflag = 0; + if (SeeAll) { + if (c=='\n') { + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin, 'e'); + gr_off(); + } else { + waddch(curwin,CT); + waddch(curwin,'J'); + } + if (!retflag) { /* previous character was not \r */ + waddch(curwin,c); + } else { /* this LF is in a CRLF sequence */ + waddch(curwin,'\n'); + waddch(curwin,'\r'); + } + } else { /* c is not a newline */ + if (c=='\r') { + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin,'d'); gr_off(); + } else { + waddch(curwin,CT); + waddch(curwin,'M'); + } + } else if (c=='\t') { + if (EzFlag & EZ_VT100GRAPHICS) { + int y,x,y1,x1,cntr; + getyx(curwin,y,x); + waddch(curwin,'\t'); + getyx(curwin,y1,x1); + move(y,x); + gr_on(); + cntr = 0; + waddch(curwin,'b'); + getyx(curwin,y,x); + while ((cntr < 8) && (y!=y1 || x!=x1) && + (y 9) ? (i - 10 + 'A') : (i + '0'); + waddch(curwin,a); + waddch(curwin,b); + waddch(curwin,RB); + } else if (c < 32) { + waddch(curwin, CT); + waddch(curwin, c | 64); + } else + waddch(curwin,c); + } + retflag = (c==CRETRN); + } else { /* not in SEEALL mode */ + c = c & 0177; /* dump 8th bit */ + if (c=='\n') { + waddch(curwin,'\n'); + waddch(curwin,'\r'); + } else if (c=='\b') { + waddch(curwin,'^'); + waddch(curwin,'H'); + } else { /* c is neither a newline nor a backspace */ + switch (c) { + case CRETRN: + if (EzFlag & EZ_INVCR) { + waddch(curwin, ' '); + } else if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin, 'd'); + gr_off(); + } else if (EzFlag & EZ_ARROW) { + specon(); + waddch(curwin, ACS_LARROW); + specoff(); + } else { + specon(); + waddch(curwin,'`'); + specoff(); + } + break; + case ESCAPE: + specon(); + waddch(curwin,'$'); + specoff(); + break; + case VRTTAB: + case FORMFD: + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); + waddch(curwin,c); + gr_off(); + } else { + waddch(curwin, c); + } + waddch(curwin, '\n'); + waddch(curwin, '\r'); + default: + waddch(curwin,c); + } + } + retflag = (c=='\r'); + } +} +#endif /***************************************************************************** ZDspBf() This function displays a buffer of a given length on the terminal @@ -318,10 +630,27 @@ VVOID ZDspBf(buffer, length) /* output a buffer to terminal */ charptr buffer; SIZE_T length; { +#if CURSES + int i; + int y,x; + for (i=0;i=(HtSize-1)) + break; + } + if (!GotCtC) + zaddch(*(buffer+i),0); + else + break; + } + wrefresh(curwin); +#else if (write(fileno(stdout), buffer, length) == -1) { puts("Unable to write to terminal in function ZDspBf"); TAbort(EXIT_FAILURE); } +#endif } /***************************************************************************** ZDspCh() @@ -330,10 +659,14 @@ SIZE_T length; VVOID ZDspCh(Charac) /* output a character to terminal */ char Charac; { +#if CURSES + zaddch(Charac,1); +#else if (write(fileno(stdout), &Charac, 1) == -1) { puts("Unable to write to terminal in function ZDspCh"); TAbort(EXIT_FAILURE); } +#endif } /***************************************************************************** ZExCtB() @@ -420,6 +753,11 @@ DEFAULT ZExeEJ() /* execute an EJ command */ VVOID ZExit(estat) /* terminate TECO-C */ DEFAULT estat; { +#if CURSES + nodelay(stdscr,FALSE); /* to avoid a bug in some System V.2 */ + /* releases of curses */ + endwin(); +#endif ZClnUp(); exit(estat); } @@ -670,7 +1008,8 @@ BOOLEAN RepFNF; /* report "file not found" error? */ charptr dummyp = NULL; char TmpBfr[FILENAME_MAX]; ptrdiff_t TmpLen = FBfPtr-FBfBeg; - if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + BOOLEAN noDot; + if (noDot = strchr(FBfBeg,'.') == NULL) { /* if no dot */ (void)strcat(FBfBeg,".tec"); /* append .tec */ FBfPtr += 4; if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { @@ -691,7 +1030,7 @@ BOOLEAN RepFNF; /* report "file not found" error? */ IFisCR[IfIndx] = 0; return SUCCESS; } - if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + if (noDot) { /* if no dot */ (void)strcat(FBfBeg,".tec"); /* append .tec */ FBfPtr += 4; if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { @@ -1044,6 +1383,21 @@ DEFAULT *retlen; /* returned length of string */ VVOID ZScrOp(OpCode) /* do a screen operation */ int OpCode; /* code for operation */ { +#if CURSES + int x,y; + switch (OpCode) { + case SCR_EEL: clrtoeol(); + break; + case SCR_CUP: getyx(stdscr,y,x); + if (y-1) + move(y-1,x); + break; + case SCR_ROF: standend(); break; + case SCR_RON: standout(); break; + } + refresh(); +#endif + // if (CrType == UNTERM || tbuf[0] == 0) {/* if unknown terminal type */ // return; /* can't do screen operations */ // } @@ -1164,46 +1518,85 @@ static void sigstop() VVOID ZTrmnl() /* set up I/O to the terminal */ { EtFlag = ET_READ_LOWER | /* guess: term has lowercase and */ +#if CURSES + ET_WAT_SCOPE | /* "WATCH" support exists */ +#endif ET_EIGHTBIT | /* terminal uses 8-bit characters */ ET_SCOPE; /* it's a scope, not hardcopy */ EzFlag = EZ_NO_VER | /* don't do VMS-style file versions */ +#if CURSES +/* EZ_UNIXNL | * don't add CRs to newlines */ +#endif EZ_INVCR; /* don't show little c/r characters */ /* * get terminal characteristics and set some signals */ +#if !CURSES if (tcgetattr(0, &out) != -1) tty_set = TRUE; /* tell ZClnUp to clean up */ tcgetattr(0, &cur); #ifdef SIGTSTP signal(SIGTSTP, sigstop); /* call sigstop on stop (control-Z) */ #endif +#endif /* * set CBREAK/noECHO/noCRMOD */ +#if CURSES + initscr(); /* initialize screens */ +#ifdef ULTRIX + setupterm(0,1,0); /* Enable termcap compatibility */ +#endif + scrollok(stdscr,TRUE); /* scroll if cursor moves too hi/lo */ + idlok(stdscr,TRUE); /* use hardware insert/delete line */ + cbreak(); /* don't wait for CRs (CBREAK) */ + noecho(); /* don't echo characters (ECHO) */ + nonl(); /* don't add CRs to NEWLINEs (CRMOD) */ + curwin = stdscr; + ScopeFlg = 0; /* not writing in scope */ +#else /* NOT CURSES */ cur.c_lflag &= ~ICANON; cur.c_lflag &= ~ECHO; cur.c_oflag &= ~ONLCR; cur.c_iflag &= ~(ICRNL | INLCR); tcsetattr(0, TCSANOW, &cur); +#endif signal(SIGINT, CntrlC); /* call CntrlC on interrupt */ signal(SIGHUP, sighup); /* call sighup on hang up */ siginterrupt(SIGINT, 1); /* * set up termcap stuff */ - tbuf[0] = 0; -// if ((ta = getenv("TERM")) == NULL) { /* get terminal type */ -// ta = "dumb"; -// } -// tgetent(tbuf, ta); /* tbuf gets terminal description */ -// ta = tarea; -// ce = xtgetstr("ce",&ta); /* clear to end of line */ -// se = xtgetstr("se",&ta); /* end standout mode (rev. video) */ -// so = xtgetstr("so",&ta); /* begin standout mode */ -// up = xtgetstr("up",&ta); /* cursor up */ CrType = VT102; /* Let's pretend we are a VT102 even though we are really using termcap! */ +#if !CURSES + tbuf[0] = 0; +#ifdef LINUX // BAD for now but do we really want this?? +#else + if ((ta = getenv("TERM")) == NULL) { /* get terminal type */ + ta = "dumb"; + } + tgetent(tbuf, ta); /* tbuf gets terminal description */ + ta = tarea; + ce = xtgetstr("ce",&ta); /* clear to end of line */ + se = xtgetstr("se",&ta); /* end standout mode (rev. video) */ + so = xtgetstr("so",&ta); /* begin standout mode */ + up = xtgetstr("up",&ta); /* cursor up */ +#endif +#endif +#if VIDEO +#if CURSES +#ifdef ULTRIX + VtSize = LINES; + HtSize = COLS; +#else + getmaxyx(stdscr, VtSize, HtSize); +#endif +#else + VtSize = HtSize = 0; +#endif +#endif } /***************************************************************************** ZVrbos() @@ -1262,7 +1655,7 @@ charptr BfrEnd; /* address of output buffer end */ BfrPtr--; } } - if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + if (putc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { ZErMsg(); ErrMsg(ERR_UWL); DBGFEX(2,DbgFNm,"FAILURE"); @@ -1353,3 +1746,384 @@ char *target; closedir(dirp); return (found) ? maxver : -2; } +#if CURSES +static void movedot(HowFar) +LONG HowFar; /* positive or negative displacement */ +{ + if (HowFar > 0) { + if ((GapEnd+HowFar) > EBfEnd) { + HowFar = EBfEnd - GapEnd; + } + MEMMOVE(GapBeg, GapEnd+1, HowFar); + GapBeg += HowFar; + GapEnd += HowFar; + } else { + if ((GapBeg+HowFar) < EBfBeg) { + HowFar = EBfBeg - GapBeg; + } + GapBeg += HowFar; + GapEnd += HowFar; + MEMMOVE(GapEnd+1, GapBeg, -(HowFar)); + } +} +static void +drawline() +{ + int i; + if (winline) { + move(VtSize - ScroLn - 1, 0); + for (i=0;i= VtSize - winline - ScroLn) + return; + clrtoeol(); + for (x=y+1;x HtSize * (VtSize - ScroLn)) + || HldFlg) { + /* admittedly a heuristic ! */ + int linedisp, disp; + int siz = VtSize - ScroLn - 1 - winline; + linedisp = siz/2-2; + if (linedisp > 0) { + disp = Ln2Chr(-linedisp); + p_scope_start = GapBeg + disp; + scope_start = DOT + disp; + goto l1; /* no need to do stuff to get to beginning + of line */ + } + } + if (p_scope_start > EBfBeg) { + /* set p_scope_start to beginning of line */ + if (scope_start > DOT) { /* move */ + p_scope_start = GapBeg; + scope_start = DOT; + } + flag = 0; + while ((p_scope_start > EBfBeg) && !flag) { + --p_scope_start; + if (IsEOL(*p_scope_start)) + flag++; + } + if (p_scope_start != EBfBeg || IsEOL(*p_scope_start)) + ++p_scope_start; + } +/* + * note here p_scope_start may still be at GapBeg after all this number of + * characters we "backed up" is GapBeg - p_scope_start + */ +l1: olddot = DOT; move(0,0); + charcounter = GapBeg - p_scope_start; + if (p_scope_start < GapBeg) { + for (curptr=p_scope_start; curptr < GapBeg; curptr++) { + int redrawflag; + zaddch2(*curptr); + getyx(stdscr,y,x); + if (y>VtSize - ScroLn - 1 - winline) { + int lines = 0; + unsigned char *charpointer; +/* + * we didn't get to print dot - try moving p_scope_start one line forward or + * if lots of lines in between DOT and p_scope_start then just redraw + */ + move(y-1,0); + clrtoeol(); + redrawflag = 0; + if (p_scope_start >= EBfEnd) { + finish(); + drawline(); + move(cccmdy,cccmdx); + return; /* blew it */ + } + /* about how many lines ? */ + for (charpointer = p_scope_start; + charpointer < GapBeg; charpointer++) { + if (IsEOL(*charpointer)) + lines++; + if (lines > 2*(VtSize - ScroLn)) + break; + } + if (lines > 2*(VtSize-ScroLn)) { + /* just redraw everything */ + p_scope_start = GapBeg; + scope_start = DOT; + move(0,0); + /* clear(); */ + p_scope_start = GapBeg; + scope_start = DOT; + goto draw_all; + } + /* move forward a line */ + while (p_scope_start < GapBeg && !IsEOL(*p_scope_start)) { + ++p_scope_start; + ++scope_start; + } + if (IsEOL(*p_scope_start)) { + p_scope_start++; scope_start++; + } + if (p_scope_start >= GapBeg) { + p_scope_start = GapBeg; + scope_start = DOT; + } + goto l1; + } + } + } + curptr = GapEnd+1; + standout(); + getyx(stdscr, doty, dotx); + if (curptr > EBfEnd) { + getyx(stdscr,y,x); + if (y <= VtSize - ScroLn - 1 - winline) { + specon(); + addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND); + specoff(); + standend(); + getyx(stdscr, doty1, dotx1); + } + finish(); + drawline(); + move(cccmdy,cccmdx); + clrtoeol(); + return; + } else { + if (*curptr=='\n') { + if (!(SeeAll) && (y <= VtSize - ScroLn - 1 - winline)) { + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); waddch(curwin,'e'); gr_off(); + } else + addch(ACS_RTEE); + } + } + zaddch2(*curptr); + } + standend(); + getyx(stdscr, doty1, dotx1); + curptr++; + getyx(stdscr,y,x); + if (y>VtSize - ScroLn - 1 - winline) { + drawline(); + move(cccmdy,cccmdx); + return; + } + while ((curptr <= EBfEnd)) { + zaddch2(*curptr); + getyx(stdscr,y,x); + if (y>=VtSize - ScroLn - winline) + break; + ++curptr; + } + if (y < VtSize - ScroLn - winline && curptr > EBfEnd) { + specon(); + addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND); + specoff(); + } + finish(); + drawline(); + move(cccmdy,cccmdx); +} +void +centre() +{ + int linedisp, disp; + int siz = VtSize - ScroLn - 1 - winline; + linedisp = siz/2-2; + if (linedisp > 0) { + disp = Ln2Chr(-linedisp); /* disp <= 0 */ + p_scope_start = GapBeg + disp; + scope_start = DOT + disp; + } else { + p_scope_start = GapBeg; + scope_start = DOT; + } + redraw(); +} +void +dolf() +{ + if (!skiprefresh) + redraw(); +} +void +dobs() +{ + if (!skiprefresh) + redraw(); +} +void +ccs() +{ + colsave = (-1); +} +void +do_right() +{ + colsave = (-1); + CmdMod &= ~COLON; + if (GapEnd < EBfEnd) { + DoCJR(1); + redraw(); + refresh(); + } +} +void +do_left() +{ + colsave = (-1); + CmdMod &= ~COLON; + if (EBfBeg < GapBeg) { + DoCJR(-1); + redraw(); + refresh(); + } +} +void +do_sf() +{ +} +void +do_sr() +{ +} +void +do_up() +{ + int disp = Ln2Chr(-1); int ll; int dist; + if (colsave < 0) { + colsave = -Ln2Chr(0); + } + CmdMod &= ~COLON; +/* + * find length of prev line in characters + */ + ll = Ln2Chr(0) - Ln2Chr(-1) - 1; + if (ll==(-1)) + return; + dist = disp + ((colsave >= ll) ? ll : colsave); + movedot(dist); + redraw(); + refresh(); +} +void +do_down() +{ + int disp = Ln2Chr(1); + int ll, dist; + if (colsave < 0) { + colsave = -Ln2Chr(0); + } + CmdMod &= ~COLON; + ll = Ln2Chr(2) - Ln2Chr(1) - 1; + if (ll==(-1)) { + movedot(EBfEnd - GapEnd); + } else { + dist = disp + ((colsave >= ll) ? ll : colsave); + movedot(dist); + } + redraw(); + refresh(); +} +void +do_seetog() /* toggle SeeAll mode */ +{ + SeeAll = (SeeAll > 0) ? 0 : 1; + redraw(); + refresh(); +} +void +keypad_on() +{ + keypad(stdscr, (KeyPad & 1)); + keypad(stdscr, (KeyPad & 2)); +} +void +keypad_off() +{ +#ifndef ULTRIX + notimeout(stdscr, FALSE); +#endif + keypad(stdscr, FALSE); +} +void +Scope(bot) /* first crack */ +int bot; +{ + if (bot <0) + return; + if (bot == 0) { + setscrreg(0, VtSize -1); + } else { + winline = (EzFlag & EZ_WIN_LINE) ? 1 : 0; + setscrreg(VtSize - bot, VtSize - 1); + move(VtSize - bot, 0); + curwin = stdscr; + initialize_scope(); + } +} +#endif diff --git a/src/zunix.c b/src/zunix.c index 906e13a..03872b9 100644 --- a/src/zunix.c +++ b/src/zunix.c @@ -34,6 +34,12 @@ #include #include #include +#ifdef LINUX +#include +#include +#include +#include +#endif #if CURSES #include /* has to come before zport.h */ #endif @@ -85,9 +91,14 @@ unsigned char *pscope_start; #define LB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LLCORNER : '[') #define RB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LRCORNER : ']') #else /* else (not CURSES) ----------------------*/ +#ifdef LINUX +static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */ +static struct termios out, cur; /* terminal characteristics buffers */ +#else #include /* define CBREAK, ECHO, TIOCGETP, etc. */ static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */ static struct sgttyb out, cur; /* terminal characteristics buffers */ +#endif static char tbuf[1024]; /* store TERMCAP entry here */ static char tarea[1024]; /* store decoded TERMCAP stuff here */ static char *ce; /* TERMCAP sequence: clear to end-of-line */ @@ -98,6 +109,8 @@ int tputs(); /* send termcap string to a given function */ int tgetent(); /* load a terminal capability buffer */ char *tgetstr(); /* get str value of a terminal capability */ #endif +#ifdef LINUX +#else int access(); /* determine accessibility of a file */ int atoi(); /* convert ASCII digits to inary integer */ int execlp(); /* terminate and execute a system command */ @@ -122,6 +135,7 @@ int stat(); /* get information about a file */ int time(); /* get current time */ int unlink(); /* remove link to file (delete the file) */ int write(); /* write to a file */ +#endif /* * The SunOS 4.0 system include files don't have declarations for some * functions, so add them here to keep gcc from complaining about implicit @@ -144,7 +158,9 @@ static char **glob(); /* see bottom of this file */ static int vernum(); /* see bottom of this file */ static int movefile(); /* see bottom of this file */ extern int sys_nerr; /* number of system error messages */ +#ifndef LINUX extern char *sys_errlist[]; /* error message text */ +#endif static int SupGotCtC = 0; static char **wild_list = (char **)0; /* wild-card file name list */ /***************************************************************************** @@ -298,6 +314,47 @@ So I partially implemented :EG for Unix. :EG can read the "INI", "LIB" and using a file (ugh) to save the name of the last-file-edited. The file is stored in /tmp so it gets deleted when the system boots. *****************************************************************************/ +#ifdef LINUX + LONG ZClnEG( /* execute special :EG command */ + DEFAULT EGWhat, /* what to get/set/clear: MEM, LIB, etc. */ + DEFAULT EGOper, /* operation: get, set or clear */ + charptr TxtPtr) /* if setting, value to set */ + { + char *cp=NULL; /* environment variable name */ + char buf[100]; /* enough for envname + 80 char filename */ + LONG retval; /* -1L on success, 0L on failure */ + DBGFEN(2,"ZClnEG",NULL); + DBGFEX(2,DbgFNm,"0"); + switch (EGWhat) { + case EG_INI: cp = "TEC_INIT"; break; + case EG_LIB: cp = "TEC_LIBRARY"; break; + case EG_MEM: cp = "TEC_MEMORY"; break; +#if VIDEO + case EG_VTE: cp = "TEC_VTEDIT"; break; +#endif + default: return 0L; + } + if (EGOper == GET_VAL) { + if ((cp = getenv(cp)) == NULL) { + retval = 0L; /* return failure */ + } else { + retval = -1L; /* success, copy to FBf */ + strcpy((char*)FBfBeg, cp); + FBfPtr = FBfBeg + strlen(cp); + } + } else { + strcpy(buf, cp); /* build NAME= */ + strcat(buf, "="); + if (EGOper == SET_VAL) { /* concatenate new value */ + strcat(buf, (char *)TxtPtr); + } + retval = (putenv(buf) != 0) /* if putenv() failed */ + ? 0L /* then return failure */ + : -1L; /* else return success */ + } + return retval; + } +#else /* Not LINUX */ static LONG do_egmem(EGOper,TxtPtr) DEFAULT EGOper; /* operation: get, set or clear */ charptr TxtPtr; /* if setting, value to set */ @@ -379,6 +436,7 @@ charptr TxtPtr; /* if setting, value to set */ DBGFEX(1,DbgFNm,"-1 (success)"); return -1; /* return "success" */ } +#endif /***************************************************************************** See the definition of MEMMOVE in ZPORT.H for a description of this function. @@ -418,8 +476,12 @@ VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */ DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); #if !CURSES if (tty_set == TRUE) +#ifdef LINUX + tcsetattr(0, TCSANOW, &out); +#else ioctl(0, TIOCSETP, &out); #endif +#endif } /***************************************************************************** ZDoCmd() @@ -749,12 +811,12 @@ current date encoded in the following way: *****************************************************************************/ DEFAULT ZExCtB() /* return current date */ { - time_t clock; + time_t clockt; struct tm *time_of_day; int tecodate; DBGFEN(1,"ZExCtB",""); - clock=time(NULL); - time_of_day=localtime(&clock); + clockt=time(NULL); + time_of_day=localtime(&clockt); tecodate = ((time_of_day->tm_year)*16+time_of_day->tm_mon+1)*32 + time_of_day->tm_mday ; DBGFEX(1,DbgFNm,"PushEx()"); @@ -768,12 +830,12 @@ current time encoded in the following way: *****************************************************************************/ DEFAULT ZExCtH() /* return current time */ { - time_t clock; + time_t clockt; struct tm *time_of_day; int tecotime; DBGFEN(1,"ZExCtH",""); - clock=time(NULL); - time_of_day=localtime(&clock); + clockt=time(NULL); + time_of_day=localtime(&clockt); tecotime = time_of_day->tm_hour * 60 /* hours * 60 */; tecotime += time_of_day->tm_min; /* minutes */ tecotime *= 30; @@ -1071,7 +1133,8 @@ BOOLEAN RepFNF; /* report "file not found" error? */ charptr dummyp = NULL; char TmpBfr[FILENAME_MAX]; ptrdiff_t TmpLen = FBfPtr-FBfBeg; - if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + BOOLEAN noDot; + if (noDot = strchr(FBfBeg,'.') == NULL) { /* if no dot */ (void)strcat(FBfBeg,".tec"); /* append .tec */ FBfPtr += 4; if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { @@ -1090,7 +1153,7 @@ BOOLEAN RepFNF; /* report "file not found" error? */ DBGFEX(1,DbgFNm,"SUCCESS"); return SUCCESS; } - if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + if (noDot) { /* if no dot */ (void)strcat(FBfBeg,".tec"); /* append .tec */ FBfPtr += 4; if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { @@ -1239,7 +1302,8 @@ char *argv[]; /* * execute imbedded command line-parsing macro directly from clpars[] */ - CStBeg = CBfPtr = clpars; /* command string start */ + CStBeg = clpars; /* command string start */ + CBfPtr = clpars; /* command string start */ CStEnd = clpars + CLPARS_LEN; /* command string end */ EStTop = EStBot; /* clear expression stack */ ExeCSt(); /* execute command string */ @@ -1421,6 +1485,7 @@ int OpCode; /* code for operation */ } refresh(); #else +#ifndef LINUX // BAD for now, but do we really want this?? if (CrType == UNTERM || tbuf[0] == 0) {/* if unknown terminal type */ return; /* can't do screen operations */ } @@ -1434,6 +1499,7 @@ int OpCode; /* code for operation */ case SCR_RON: tputs(so, 1, ZDspCh); } #endif +#endif } /***************************************************************************** ZSetTT() @@ -1527,12 +1593,21 @@ static void sighup() */ static void sigstop() { +#ifdef LINUX + tcsetattr(0, TCSANOW, &out); + puts("[Suspending...]\r\n"); + kill(getpid(), SIGSTOP); + puts("[Resuming...]\r\n"); + tcsetattr(0, TCSANOW, &cur); +#else ioctl(0, TIOCSETP, &out); puts("[Suspending...]\r\n"); kill(getpid(), SIGSTOP); puts("[Resuming...]\r\n"); ioctl(0, TIOCSETP, &cur); +#endif } +#ifndef LINUX /* * xtgetstr() - just like tgetstr() except it returns "" instead of * NULL if the tgetstr() fails. As in tcsh 5.18. @@ -1547,6 +1622,7 @@ char **a; return r; } #endif +#endif /* * ZTrmnl - set up terminal modes */ @@ -1569,9 +1645,15 @@ VVOID ZTrmnl() /* set up I/O to the terminal */ * get terminal characteristics and set some signals */ #if !CURSES +#ifdef LINUX + if (tcgetattr(0, &out) != -1) + tty_set = TRUE; /* tell ZClnUp to clean up */ + tcgetattr(0, &cur); +#else if (ioctl(0, TIOCGETP, &out) != -1) tty_set = TRUE; /* tell ZClnUp to clean up */ ioctl(0, TIOCGETP, &cur); +#endif #ifdef SIGTSTP signal(SIGTSTP, sigstop); /* call sigstop on stop (control-Z) */ #endif @@ -1591,11 +1673,19 @@ VVOID ZTrmnl() /* set up I/O to the terminal */ nonl(); /* don't add CRs to NEWLINEs (CRMOD) */ curwin = stdscr; ScopeFlg = 0; /* not writing in scope */ +#else /* NOT CURSES */ +#ifdef LINUX + cur.c_lflag &= ~ICANON; + cur.c_lflag &= ~ECHO; + cur.c_oflag &= ~ONLCR; + cur.c_iflag &= ~(ICRNL | INLCR); + tcsetattr(0, TCSANOW, &cur); #else cur.sg_flags |= CBREAK; /* don't wait for CRs (CBREAK) */ cur.sg_flags &= ~ECHO; /* don't echo characters (ECHO) */ cur.sg_flags &= ~CRMOD; /* don't add CRs to NEWLINEs (CRMOD) */ ioctl(0, TIOCSETP, &cur); /* set the new modes */ +#endif #endif signal(SIGINT, CntrlC); /* call CntrlC on interrupt */ signal(SIGHUP, sighup); /* call sighup on hang up */ @@ -1605,6 +1695,8 @@ VVOID ZTrmnl() /* set up I/O to the terminal */ */ #if !CURSES tbuf[0] = 0; +#ifdef LINUX // BAD for now but do we really want this?? +#else if ((ta = getenv("TERM")) == NULL) { /* get terminal type */ ta = "dumb"; } @@ -1614,6 +1706,7 @@ VVOID ZTrmnl() /* set up I/O to the terminal */ se = xtgetstr("se",&ta); /* end standout mode (rev. video) */ so = xtgetstr("so",&ta); /* begin standout mode */ up = xtgetstr("up",&ta); /* cursor up */ +#endif #endif CrType = VT102; /* Let's pretend we are a VT102 even though we are really using @@ -1688,7 +1781,7 @@ charptr BfrEnd; /* address of output buffer end */ BfrPtr--; } } - if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + if (putc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { ZErMsg(); ErrMsg(ERR_UWL); DBGFEX(2,DbgFNm,"FAILURE"); @@ -1986,7 +2079,7 @@ register char *s, *p; case '[': ok = 0; lc = 077777; - while (cc = *p++) { + while ((cc = *p++) != 0) { if (cc == ']') { if (ok) break; @@ -2076,12 +2169,21 @@ char *pattern; return; goto p_err2; } +#ifdef LINUX + if (fstat(dirfd(dirp), &stb) < 0) + goto p_err1; + if (!isdir(stb)) { + errno = ENOTDIR; + goto p_err1; + } +#else if (fstat(dirp->dd_fd, &stb) < 0) goto p_err1; if (!isdir(stb)) { errno = ENOTDIR; goto p_err1; } +#endif while ((dp = readdir(dirp)) != NULL) { if (dp->d_ino == 0) continue; diff --git a/src/zwin32.c b/src/zwin32.c new file mode 100644 index 0000000..61b2d62 --- /dev/null +++ b/src/zwin32.c @@ -0,0 +1,2153 @@ +/***************************************************************************** + Zwin32.c + System dependent code for Windows NT & Microsoft C 4.0 compiler. +*****************************************************************************/ +#ifdef _MSC_VER +#include /* prototype for farfree(), farmalloc() */ +#else +#include /* prototype for farfree(), farmalloc() */ +#endif +#include /* prototypes for sound(), nosound(), etc. */ +#include /* for tolower() */ +#include /* define errno */ +#include /* O_BINARY */ +#include /* prototype for access() */ +#include /* prototype for execlp() */ +#include +#include /* prototype for fread(), fwrite()... */ +#include /* prototype for exit(), system() */ +#include /* prototypes for strlen(), strcat(), ... */ +#include +#if VIDEO +#include +#undef INFINITE +#define BOOLEAN _BOOL +#undef DELETE +#endif +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "chmacs.h" /* define character processing macros */ +#include "clpars.h" /* command-line parsing macro */ +#include "deferr.h" /* define identifiers for error messages */ +#include "dchars.h" /* define identifiers for characters */ +#include "dscren.h" /* define identifiers for screen i/o */ +#if USE_PROTOTYPES +static void CntrlC(int sig); +#endif +#if VIDEO +static HANDLE PrevScreen, Screen; +static COORD Cursor; +static void move(int y, int x); +static void _getyx(int *y, int *x); +static void zaddchs(char *buf); +static void zaddch2(char buf); +static void zaddch(char buf, int echo); +static void clrtoeol(void); +#define getyx(scr, y, x) _getyx(&y, &x) +/* + * The ACS_xxx symbols are defined in the SunOS version of curses, but not + * in either the BSD or X/OPEN Ultrix versions. Who knows where else they + * are defined? Isn't portability wonderful? + * + * Note that this code implicitly assumes a VT100-compatible terminal. + * Tough. (Jerry Leichter, June 1991) + */ +#ifndef ACS_PLMINUS +#define A_ALTCHARSET 0 +#define ACS_PLMINUS (A_ALTCHARSET | 0x67) +#define ACS_LLCORNER (A_ALTCHARSET | 0x60) +#define ACS_LRCORNER (A_ALTCHARSET | 0x6A) +#define ACS_LARROW (A_ALTCHARSET | 0x7C) /* Really not-equal */ +#define ACS_HLINE (A_ALTCHARSET | 0x71) +#define ACS_BTEE (A_ALTCHARSET | 0x76) +#define ACS_DIAMOND (A_ALTCHARSET | 0x60) +#define ACS_RTEE (A_ALTCHARSET | 0x75) +#endif +static int curwin, stdscr; +int ScopeFlg = 0; /* for ZDspCh and ZDspBuf */ +int olddot; +#define DOT (GapBeg - EBfBeg) +#define ISSCW (ScopeFlg) +unsigned char *p_scope_start; +int scope_start; +int winline; +int cursoratbottomline; +int cursorattopline; +static int colsave; +int dotx,doty; /* position of cursor in scope */ +int dotx1, doty1; /* pos. after printing character in scope */ +int skiprefresh = 0; +int cmdx,cmdy; /* position of cursor in command buffer */ +int scope_start, scope_end; +unsigned char *pscope_start; +#define CT ((EzFlag & EZ_VT100GRAPHICS) ? ACS_PLMINUS : '^') +#define LB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LLCORNER : '[') +#define RB ((EzFlag & EZ_VT100GRAPHICS) ? ACS_LRCORNER : ']') +#endif +/***************************************************************************** + Keep track of Malloc'd data +*****************************************************************************/ +#if DEBUGGING +#define MMAX 256 /* max number of malloc'ed items */ +static voidptr MPtrs[MMAX]; /* save malloc'ed pointers */ +#endif +/***************************************************************************** + Define Power C's cursor positioning functions in terms of Turbo C's +functions. Be aware that Power C's upper left corner coordinates are (0,0) +while Turbo C's are (1,1). +*****************************************************************************/ +/***************************************************************************** + The following static data is used in ZPWild and ZSWild to +perform wildcard filename lookups under DOS. + Since Turbo C findfirst and findnext only return the filename +and extension of a file, we save the drive code and subdirectory path +in ff_drive[] and ff_dir[] when we call ZPWild so we can return a fully +expanded filename later on. + After a wildcard filename has been preset with ENfilename$, on the +first call to EN$, we find all the matching filenames in the directory and +save them in the dynamically allocated string ff_names. We use ff_names_p +to point into ff_names when returning filenames on subsequent EN$ calls. +We read the entire directory instead of simply findnext'ing for a new +filename to avoid the scenario where you get a filename from EN$, and +then modify and save it. The original filename will be renamed filename.BAK +and a new filename created. The new filename's directory entry may appear +after the filename.BAK entry in the DOS directory list, and therefore may +be returned on a subsequent EN$. Since we don't want this to happen, we +read the entire directory at once. + The ff_preset flag is: -1 if the wildcard lookup hasn't been preset +yet; 0 if we haven't done any findfirst/findnext'ing yet; or, 1 if ff_names +should hold names returned by findfirst/findnext. + ??? Making ff_drive[] & ff_dir[] global will cause problems later on +if we want to recurse down subdirectories. Also, we'll be doing a lot of +ZRaloc'ing if we try to read a humongous directory. +*****************************************************************************/ +static char ff_dir[_MAX_DIR]; /* filename path name */ +static char ff_drive[_MAX_DRIVE]; /* filename drive code */ +static char ff_path[_MAX_PATH]; /* complete EN filespec */ +static charptr ff_names = NULL; /* filenames found */ +static charptr ff_names_p = NULL; /* pointer into ff_names */ +static int ff_preset = -1; /* say ZPWild not called */ +/***************************************************************************** + IFiles holds the file data blocks for input files. There are three +static input streams: the primary input stream, the secondary input stream, +and the input stream used by the EQq command. To access these three files, +identifiers defined in file tecoc.h are used to index into this array. +Other elements of this array are used to access input files for the EI +command. +*****************************************************************************/ +FILE *IFiles[NIFDBS]; +/***************************************************************************** + OFiles holds the file data blocks for the output files. There are +three output streams: the primary output stream, the secondary output +stream and the output stream used by the E%q command. The array is indexed +using identifiers defined in file tecoc.h. +*****************************************************************************/ +static struct { + char OFNam[FILENAME_MAX]; /* output file name */ + char OTNam[FILENAME_MAX]; /* temporary output file name */ + FILE *OStrem; /* stream */ +} OFiles[NOFDBS]; +/***************************************************************************** + ZErMsg() + This function displays an error message from the operating system on +the terminal screen. The error message text is retrieved from the operating +system and imbedded in a TECO-style message with the SYS mnemonic. +*****************************************************************************/ +static VVOID ZErMsg(void) +{ + char *ErrMsg; + char *cp; + if ((ErrMsg = strerror(errno)) != NULL) { + cp = ErrMsg + strlen(ErrMsg) - 1; + if (*cp == '\n') { + *cp = '\0'; + } + } else { + ErrMsg = "???"; + } + ErrStr(ERR_SYS, ErrMsg); +} +/***************************************************************************** + ZAlloc() + This function allocates memory. The single argument is the number +of bytes to allocate. TECO-C uses the ZFree() and ZRaloc() functions to +de-allocate and re-allocate, respectively, the memory allocated by this +function. +*****************************************************************************/ +voidptr ZAlloc(SIZE_T MemSiz) /* allocate memory */ +{ + voidptr NewBlk; +#if DEBUGGING + static char *DbgFNm = "ZAlloc"; + sprintf(DbgSBf,"MemSiz = %ld", MemSiz); + DbgFEn(4,DbgFNm,DbgSBf); +#endif + NewBlk = malloc(MemSiz); + +#if DEBUGGING +/* + * save malloc'ed block in first NULL entry in MPtrs[] + */ + if (NewBlk != NULL) { + int i; + for (i = 0; i < MMAX && MPtrs[i] != NULL; ++i) { + ; + } + if (i == MMAX) { + puts ("ZAlloc: MPtrs[] stack exceeded"); + exit (1); + } + MPtrs[i] = NewBlk; + } +#endif + DBGFEX(4,DbgFNm,(NewBlk == NULL) ? "NULL" : NULL); + return NewBlk; +} +/***************************************************************************** + ZBell() + Thus function rings the terminal bell. For most platforms, this +means just writing a bell character (control-G) to the terminal. Under +MS-DOS, ringing the bell this way produces a yucky sound, so for MS-DOS +this function controls the signal generator directly. +*****************************************************************************/ +VVOID ZBell(void) +{ +#if 0 + sound(0); /* turns PC speaker on at 0 hertz */ + sound(800); /* turns PC speaker on at 800 hertz */ + delay(10); /* suspend execution for 10 milliseconds */ + nosound(); /* turn PC speaker off */ +#else + putchar('\07'); +#endif +} +/***************************************************************************** + ZChIn() + This function inputs a single character from the terminal. + 1. the character is not echoed on the terminal + 2. ^C calls an interrupt routine. Note that this must be + implemented so that a ^C will cancel a current output via + ZDspBf. The ^C must be a true interrupt. + 3. type-ahead is always nice + 4. The character must be returned immediately: no fooling + around waiting for a carriage-return before returning. + 5. If the NoWait argument is TRUE, don't wait + 6. When the user hits the RETURN key, TECO is supposed to see + a carriage return and then a line feed. The function must + deal with this by returning a carriage return to the caller + and then "remembering" to send a line feed on the next call. + 7. handle ET_BKSP_IS_DEL flag +*****************************************************************************/ +DEFAULT ZChIn(BOOLEAN NoWait) /* input a character from terminal */ +{ + int Charac; + static BOOLEAN NeedLF = FALSE; + if (NeedLF) { + NeedLF = FALSE; + return (DEFAULT)LINEFD; + } + if (NoWait && (kbhit() == 0)) { /* if no char available */ + return -1; /* return immediately */ + } + for (;;) { + Charac = getch(); + if (Charac == 0x03) { /* ^C? */ + CntrlC (SIGINT); + break; + } + if (Charac != 0) { /* not an IBM PC scan code? */ + break; /* ??? what happens on ^@? */ + } + Charac = getch(); /* get 2nd scan code byte */ + if (Charac == 0x53) { /* DEL key? */ + Charac = DELETE; + break; + } + } + if (Charac == CRETRN) { + NeedLF = TRUE; + } else { + if (EtFlag & ET_BKSP_IS_DEL) { + if (Charac == DELETE) { + Charac = BAKSPC; + } else if (Charac == BAKSPC) { + Charac = DELETE; + } + } + } + return (DEFAULT)Charac; +} +/***************************************************************************** + ZClnEG() + This function executes a :EG command. The :EG commands are used to +get access to operating system functions. The minimum set of functions is + :EGINI$ gets, sets or clears the initialization file name + :EGMEM$ gets, sets or clears the file name memory + :EGLIB$ gets, sets or clears the macro library directory + :EGVTE$ gets, sets or clears the video macro file name +although more functions may be defined. +The :EG command was designed to access logical names, which are supported +by DEC's VAX/VMS and RSX operating systems. Logical names are a useful way +to specify, for example, a directory that a program is to find a set of files +in. A user can define logical names to set up a program's environment. +Programs can read, create or delete logical names. +Logical names are stored separately from program memory, so if a program sets +a logical name and then exits, the logical name still exists. TECO on a VAX +uses a logical name to store the name of the file being edited. If the user +starts TECO without specifying a file name, TECO looks for the logical name +and, if it exists, uses the value of the logical name as a filename. This +allows users to edit a file several times in a session without having to +type the file name each time they start TECO (except the first time). +Unix doesn't have logical names. The closest thing is environment variables, +which are passed to a program when it is started. A user can define +environment variables, and a program can get the values with a getenv call. +A program can even add to it's private list of environment variables, but +the list disappears when the program exits. So environment variables don't +fill the needs of the :EG command. +Environment variables are, however, natural for some of what :EG is really +used for. Users rarely need the :EG command, even in macros. The main use +of :EG is in the command-line-parsing macro (in CLPARS.TES, CLPARS.TEC and +CLPARS.H). That macro can handle a partially-implemented :EG command (it +tests the success/failure flag returned by :EG). +So I partially implemented :EG for Unix. :EG can read the "INI", "LIB" and +"VTE" values, but can't set or clear them. The "MEM" value is supported +using a file (ugh) to save the name of the last-file-edited. The file is +stored in /tmp so it gets deleted when the system boots. +*****************************************************************************/ +static LONG do_egmem(EGOper,TxtPtr) +DEFAULT EGOper; /* operation: get, set or clear */ +charptr TxtPtr; /* if setting, value to set */ +{ + FILE *memfile; + static char memname[] = "tecoc.m~"; /* I use this file name so that it + gets deleted when I clean up my + emacs backup files (which end with + ~ */ + switch (EGOper) { + case GET_VAL: + if ((memfile = fopen(memname, "r")) == NULL) { + if (errno == ENOENT) { /* file not found? */ + FBfPtr = FBfBeg; + return -1; /* return "success" */ + } else { + return errno; + } + } + if (fgets(FBfBeg, FBfEnd-FBfBeg, memfile) == NULL) { + fclose(memfile); + return errno; + } + FBfPtr = FBfBeg + strlen(FBfBeg); + if (fclose(memfile) == EOF) { + return errno; + } + break; + case SET_VAL: + if ((memfile = fopen(memname, "w")) == NULL) { + return errno; + } + if (fputs(TxtPtr, memfile) == -1) { + fclose(memfile); + return errno; + } + if (fclose(memfile) == EOF) { + return errno; + } + break; + case CLEAR_VAL: + remove(memname); + break; + } + return -1; /* return "success" */ +} +LONG ZClnEG(EGWhat,EGOper,TxtPtr) +DEFAULT EGWhat; /* what to get/set/clear: MEM, LIB, etc. */ +DEFAULT EGOper; /* operation: get, set or clear */ +charptr TxtPtr; /* if setting, value to set */ +{ + char *envvar_name; + char *envval; + DBGFEN(1,"ZClnEG",NULL); + switch (EGWhat) { + case EG_INI: envvar_name = "TEC_INIT"; break; + case EG_LIB: envvar_name = "TEC_LIBRARY"; break; + case EG_VTE: envvar_name = "TEC_VTEDIT"; break; + case EG_MEM: DBGFEX(1,DbgFNm,"do_egmem()"); + return do_egmem(EGOper, TxtPtr); + default: DBGFEX(1,DbgFNm,"0 (unsupported)"); + return 0; /* return "unsupported" */ + } + if (EGOper != GET_VAL) { + DBGFEX(1,DbgFNm,"0 (unsupported)"); + return 0; /* return "unsupported" */ + } + if ((envval = getenv(envvar_name)) == NULL) { + DBGFEX(1,DbgFNm,"1 (supported, but failed)"); + return 1; /* supported, but failed */ + } + strcpy(FBfBeg, envval); + FBfPtr = FBfBeg + strlen(envval); + DBGFEX(1,DbgFNm,"-1 (success)"); + return -1; /* return "success" */ +} +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */ +{ + DBGFEN(3,"ZClnUp",NULL); +#if CHECKSUM_CODE /* MS-DOS debugging code */ + check_code_checksums (); /* check one final time */ +#endif + ZDspBf("\r\n", 2); /* final carriage return/line feed */ +} +/***************************************************************************** + Zcp2ul() + Converts a huge pointer to a long for debugging messages. +*****************************************************************************/ +#if DEBUGGING || CONSISTENCY_CHECKING +ULONG Zcp2ul(voidptr cp) /* convert voidptr to ULONG */ +{ +#if TC_SMALL_DATA || defined(MSC32) + return (unsigned long) cp; +#else + return (((ULONG) FP_SEG(cp)) << 4) + ((ULONG) FP_OFF(cp)); +#endif +} +#endif +/***************************************************************************** + ZDoCmd() + This function terminates TECO and feeds a command line to the +command line interpreter. The command to be executed is passed to this +function in the file name buffer (FBf). +*****************************************************************************/ +VVOID ZDoCmd(void) /* die and pass command to OS */ +{ + char buf[128+1]; + char *space_p; + char *comspec; + DBGFEN(1,"ZDoCmd",NULL); +/* + * 1. Terminate buf[] and command line in FBf + * 2. make local copy since FBf will be free'd in ZClnUp() + * 3. separate program name from arguments, if any + * 4. Call ZClnUp to free up everything + * 5. Execute the command line, with optional arguments. If we know where + * the command processor is, use it so we can execute .BAT batch files + * 6. we shouldn't be here, exit + */ + buf[128] = *FBfPtr = '\0'; + strncpy(buf, (char *) FBfBeg, 128); + if ((space_p = strchr (buf,' ')) != NULL) { + *space_p++ = '\0'; + } + ZClnUp (); + if ((comspec = getenv("COMSPEC")) != NULL) { + execlp (comspec, + comspec, + " /c ", + buf, + (space_p) ? space_p : NULL, NULL); + } else { + execlp (buf, + buf, + (space_p) ? space_p : NULL, NULL); + } + perror (NULL); + ZExit (EXIT_SUCCESS); +} +/***************************************************************************** + ZDspBf() + This function displays a buffer of a given length on the terminal +screen. On the VAX (and maybe other systems) doing any kind of output +involves a fair amount of overhead, regardless of the size of the buffer +being output. It is therefore better to make a single call to the operating +system's output function than to call the function for each and every +character. If such improvements do not apply to the system this program +is running on, then this function can simply manually output every character +in the buffer. +*****************************************************************************/ +VVOID ZDspBf(charptr buffer, SIZE_T length) +{ +#if DEBUGGING + static char *DbgFNm = "ZDspBf"; + sprintf(DbgSBf,"buffer = %ld, length = %ld", Zcp2ul(buffer), length); + DbgFEn(5,DbgFNm,DbgSBf); +#endif +#if VIDEO + zaddchs(buffer); +#else + if (fwrite (buffer, sizeof(char), length, stdout) != length) { + puts("\nZDspBf: fwrite() failed, unable to write to terminal"); +#if DEBUGGING + printf("*buffer = %X(h) %o(o) %d(d)\n", *buffer, *buffer, *buffer); + perror("perror"); +#endif + TAbort(EXIT_FAILURE); + } +#endif + + DBGFEX(5,DbgFNm,NULL); +} +/***************************************************************************** + ZDspCh() + This function outputs a single character to the terminal. +*****************************************************************************/ +VVOID ZDspCh(char Charac) /* output a character to terminal */ +{ +#if VIDEO + zaddch(Charac,1); +#else + if (fwrite(&Charac, sizeof(char), 1, stdout) != 1) + TAbort(EXIT_FAILURE); +#endif +} +/***************************************************************************** + ZExCtB() + This function implements the TECO ^B command, which returns the +current date encoded in the following way: + ((year-1900)*16+month)*32+day +*****************************************************************************/ +DEFAULT ZExCtB(void) /* return current date */ +{ + time_t clock; + struct tm *time_of_day; + int tecodate; + DBGFEN(1,"ZExCtB",""); + clock=time(NULL); + time_of_day=localtime(&clock); + tecodate = ((time_of_day->tm_year)*16+time_of_day->tm_mon+1)*32 + + time_of_day->tm_mday ; + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(tecodate, OPERAND); +} +/***************************************************************************** + ZExCtH() + This function implements the TECO ^H command, which returns the +current time encoded in the following way: + (seconds since midnight) / 2 + Note: to execute this function, enter H, as ^H is interpreted +as a backspace. +*****************************************************************************/ +DEFAULT ZExCtH(void) /* return current time */ +{ + time_t clock; + struct tm *time_of_day; + int tecotime; + DBGFEN(1,"ZExCtH",""); + clock=time(NULL); + time_of_day=localtime(&clock); + tecotime = time_of_day->tm_hour * 60 /* hours * 60 */; + tecotime += time_of_day->tm_min; /* minutes */ + tecotime *= 30; + tecotime += time_of_day->tm_sec >> 1; /* seconds / 2 */ + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(tecotime, OPERAND); +} +/***************************************************************************** + ZExeEJ() + This function executes an EJ command, which returns environment +characteristics. It returns: + -1EJ 1024 under VAX/VMS (4*256 = VAX, 0 = VMS in native mode) + 1025 under Ultrix (4*256 = VAX, 1 = Ultrix) + 25600 under Sun/SunOS (100*256 = Sun, 0 = SunOS) + 25856 under MS-DOS (101*256 = IBM-PC, 0 = MS-DOS) + 0EJ process id on VAXen, 0 on anything else + 1EJ 0 on all systems + 2EJ UIC, in longword format (unlike TECO-11) on VAX/VMS, + 0 on all other systems. +*****************************************************************************/ +DEFAULT ZExeEJ(void) /* execute an EJ command */ +{ + DBGFEN(1,"ZExeEJ",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 0; /* default is 0EJ */ + } else { + UMinus(); /* if -EJ, make it -1EJ */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + } + if (NArgmt == -1) { + DBGFEX(1,DbgFNm,"PushEx(25856)"); + return PushEx((LONG)25856, OPERAND); /* means "MS-DOS" */ + } + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L, OPERAND); /* process id */ + } + DBGFEX(1,DbgFNm,"ExeNYI"); + return ExeNYI(); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +VVOID ZExit(DEFAULT estat) /* terminate TECO-C */ +{ +#if VIDEO + SetConsoleActiveScreenBuffer(PrevScreen); + CloseHandle(Screen); +#endif + exit(estat); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(voidptr OldBlk) /* free memory allocated by ZAlloc */ +{ +#if DEBUGGING + static char *DbgFNm = "ZFree"; + sprintf(DbgSBf,"OldBlk = %ld", Zcp2ul(OldBlk)); + DbgFEn(4,DbgFNm,DbgSBf); +/* + * don't allow them to free a NULL pointer + */ + if (OldBlk == NULL) { + puts ("ZFree: trying to free NULL pointer"); + exit (1); + } else { +/* + * find malloc'ed block in MPtrs[] and free it + */ + int i; + for (i = 0; i < MMAX && MPtrs[i] != OldBlk; ++i) { + ; + } + if (i == MMAX) { + puts ("Zfree: trying to free non-malloc'ed pointer"); + exit (1); + } + MPtrs[i] = NULL; + } +#endif + free ((void *)OldBlk); + DBGFEX(4,DbgFNm,NULL); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +VVOID ZHelp( /* display a help message */ + charptr HlpBeg, /* first char of help request */ + charptr HlpEnd, /* last character of help request */ + BOOLEAN SysLib, /* use default HELP library? */ + BOOLEAN Prompt) /* enter interactive help mode? */ +{ + HlpBeg = HlpBeg; /* avoid "parameter not used" Turbo C warning */ + HlpEnd = HlpEnd; /* avoid "parameter not used" Turbo C warning */ + SysLib = SysLib; /* avoid "parameter not used" Turbo C warning */ + Prompt = Prompt; /* avoid "parameter not used" Turbo C warning */ + (void)ExeNYI(); +} +/***************************************************************************** + ZIClos() + This function closes the current input file. It must + 1. if current input stream is not open, simply return + 2. close the input file + 3. set open indicator to FALSE +*****************************************************************************/ +VVOID ZIClos(DEFAULT IfIndx) /* close input file */ +{ +#if DEBUGGING + static char *DbgFNm = "ZIClos"; + sprintf(DbgSBf,"IfIndx = %d", IfIndx); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + if (IsOpnI[IfIndx]) { /* if it's open */ + if (fclose(IFiles[IfIndx]) == EOF) { + ZErMsg(); + ErrMsg(ERR_UCI); + DBGFEX(2,DbgFNm,"fclose() failed"); + exit(EXIT_FAILURE); + } + IsOpnI[IfIndx] = FALSE; + } + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + ZOClDe() + This function closes and deletes the current output stream. It must + 1. if no current output stream is defined, simply return + 2. close the output stream + 3. delete the file just closed +*****************************************************************************/ +VVOID ZOClDe(DEFAULT OfIndx) /* close and delete output file */ +{ + DBGFEN(2,"ZOClDe",NULL); + if (IsOpnO[OfIndx]) { /* if output stream is open */ + if (fclose(OFiles[OfIndx].OStrem) == EOF) { + ZErMsg(); + ErrStr(ERR_UCO, OFiles[OfIndx].OFNam); + DBGFEX(2,DbgFNm,"fclose() failed, calling exit()"); + exit(EXIT_FAILURE); + } + if (remove(OFiles[OfIndx].OFNam) != 0) { + ZErMsg(); + ErrStr(ERR_UCD, OFiles[OfIndx].OFNam); + DBGFEX(2,DbgFNm,", remove() failed, calling exit()"); + exit(EXIT_FAILURE); + } + IsOpnO[OfIndx] = FALSE; + } + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + ZOClos() + This function closes the current output stream. It is only called +when an output stream is defined. It must + 1. flush output to the stream, if neccessary + 2. close the stream + 3. set OFile to -1 +*****************************************************************************/ +VVOID ZOClos(DEFAULT OfIndx) /* close output file */ +{ + char *DotPtr; + char TmpFsp[FILENAME_MAX]; + DBGFEN(2,"ZOClos",NULL); + if (!IsOpnO[OfIndx]) { /* if it's not open */ + DBGFEX(2,DbgFNm,NULL); + return; /* we're done */ + } + if (fclose(OFiles[OfIndx].OStrem) == EOF) { /* close it */ + ZErMsg(); + ErrMsg(ERR_UCO); /* unable to close */ + DBGFEX(2,DbgFNm,"fclose() failed"); + exit(EXIT_FAILURE); + } + if (OFiles[OfIndx].OTNam[0] != '\0') { /* if temporary output file */ +/* + * build "filename.bak" filespec in TmpFsp[] + */ + strcpy(TmpFsp, OFiles[OfIndx].OTNam); /* copy to TmpFsp */ + DotPtr = strchr(TmpFsp, '.'); /* find the "." */ + if (DotPtr != NULL) { /* if "." exists */ + *DotPtr = '\0'; /* make it null */ + } + strcat(TmpFsp, ".bak"); /* append ".bak" */ +/* + * (maybe) delete an old "filename.bak" file + */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf,"removing old version of %s", TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"remove() failed"); + exit(EXIT_FAILURE); + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s", + OFiles[OfIndx].OTNam, TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif +/* + * rename "filename" to "filename.bak" + */ + if (rename(OFiles[OfIndx].OTNam,TmpFsp)) { + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"rename() failed, calling exit()"); + exit(EXIT_FAILURE); + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s", + OFiles[OfIndx].OFNam, OFiles[OfIndx].OTNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif +/* + * rename "tmpnam" to "filename" + */ + if (rename(OFiles[OfIndx].OFNam,OFiles[OfIndx].OTNam)) { + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"rename() failed, calling exit()"); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; /* mark it as closed */ + DBGFEX(2,DbgFNm,NULL); +} +#ifdef OLD_CODE +/***************************************************************************** + ZOpInp() + This function opens an input file. The name of the file is pointed +to by FBfBeg. FBfPtr points to the character following the last character of +the file name. +*****************************************************************************/ +DEFAULT ZOpInp( /* open input file */ + DEFAULT IfIndx, /* index into file data block array IFiles */ + BOOLEAN EIFile, /* is it a macro file (hunt for it) */ + BOOLEAN RepFNF) /* report "file not found" error? */ +{ +#if DEBUGGING + static char *DbgFNm = "ZOpInp"; + sprintf(DbgSBf,"FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + *FBfPtr = '\0'; /* terminate the file name */ +/* + * If we're executing an EI command, then the default file type (the part of + * the filename following the ".") is "tec". If we're supposed to use the + * default type, and if the filename doesn't already have a type, then + * append ".tec" to the filename. + */ + if (EIFile) { + if (strchr((char *)FBfBeg,'.') == NULL) { + strcat((char *)FBfBeg,".tec"); + FBfPtr += 4; + } + } + if ((IFiles[IfIndx] = fopen((char *)FBfBeg, "rb")) == NULL) { + if (!RepFNF && ((errno == ENODEV) || (errno == ENOENT))) { + DBGFEX(2,DbgFNm,"FILENF"); + return FILENF; + } + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE, fopen() failed"); + return FAILURE; + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +#endif +/***************************************************************************** + ZOpInp() + This function opens an input file. The name of the file is pointed +to by FBfBeg. FBfPtr points to the character following the last character of +the file name. + This function is used to open all files, including macro files +needed by the "EI" command. The "EIFlag" argument tells this function if +it's an "EI" file. If it is, some extra file searching is done to make +things convenient for the user. The extra processing is modelled after what +happens under VMS (or really, what SHOULD happen under VMS). The basic idea +is to find the macro file whether the user has specificed the ".tec" or not, +and whether it's in the current directory or the macro library directory. +The basic Unix logic is like this: + if (the file exists) + open it and return SUCCESS + if (EIfile) { + if (there's no dot and appending ".tec" works) + open it and return SUCCESS + if (prepending default library directory works) + open it and return SUCCESS + if (prepending library and appending ".tec" works) + open it and return SUCCESS + } + file not found, so return with error +Under VAX/VMS, it's a little different. VMS tries to open the file only +twice, each time with the RMS "default type" field set to ".TEC", so VMS +will insert ".TEC" if the user doesn't. There's no straightforward way to +avoid putting ".TEC" on the end of your TECO macro file namess under VMS, +which some would argue is a good thing, as long as you don't have to type +the ".TEC" when you use them. +Under MS-DOS, the above PDL works, except that when the logic talks about +appending ".tec", it doesn't happen if there's alreay a dot in the file +name, as you can only have one dot in MS-DOS file names. +*****************************************************************************/ +DEFAULT ZOpInp(IfIndx, EIFile, RepFNF) +DEFAULT IfIndx; /* index into file data block array IFiles */ +BOOLEAN EIFile; /* is it a macro file (hunt for it) */ +BOOLEAN RepFNF; /* report "file not found" error? */ +{ +#if DEBUGGING + static char *DbgFNm = "ZOpInp"; + sprintf(DbgSBf,", FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + *FBfPtr = '\0'; /* terminate the file name */ + if ((IFiles[IfIndx] = fopen(FBfBeg, "rb")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + if (EIFile) { + charptr dummyp = NULL; + char TmpBfr[FILENAME_MAX]; + ptrdiff_t TmpLen = FBfPtr-FBfBeg; + if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + (void)strcat(FBfBeg,".tec"); /* append .tec */ + FBfPtr += 4; + if ((IFiles[IfIndx] = fopen(FBfBeg, "rb")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + MEMMOVE(TmpBfr, FBfBeg, TmpLen); /* save file name */ + if (ZClnEG(EG_LIB, GET_VAL, dummyp) != -1) { /* get dir spec */ + goto open_failed; + } + MEMMOVE(FBfPtr, TmpBfr, TmpLen); /* append name to dir spec */ + FBfPtr += TmpLen; + *FBfPtr = '\0'; /* terminate file name */ + if ((IFiles[IfIndx] = fopen(FBfBeg, "rb")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + (void)strcat(FBfBeg,".tec"); /* append .tec */ + FBfPtr += 4; + if ((IFiles[IfIndx] = fopen(FBfBeg, "rb")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + } +/* + * The fopen failed, so return with error. + */ +open_failed: + if (!RepFNF && ((errno == ENODEV) || (errno == ENOENT))) { + DBGFEX(2,DbgFNm,"FILENF"); + return FILENF; + } + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; +} +/***************************************************************************** + ZOpOut() + This function creates (and opens) an output file. The name of the +file to be created is pointed to by FBfBeg. FBfPtr points to the character +following the last character of the file name. + MS-DOS does not have file version numbers like VAX/VMS, so we have +to deal with creating ".bak" versions of files. For output files, this means +that when the output file is opened, we check if a file with the same name +already exists. If a file already exists, then we open a temporary output +file and, when the file is closed, the ZOClos function will deal with +renaming things to make them come out right. If no file with the same name +already exists, then the output file can simply be opened. The ZOClos +function will only rename files if a temporary file was created by this +funtion. +*****************************************************************************/ +DEFAULT ZOpOut(DEFAULT OfIndx, BOOLEAN RepErr) +{ +#if DEBUGGING + static char *DbgFNm = "ZOpOut"; + sprintf(DbgSBf,"FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg); + DbgFEn(2,DbgFNm,DbgSBf); +#endif +/* + * If the output file already exists, make a temporary file. + */ + *FBfPtr = '\0'; + if (access((char *)FBfBeg, 0) == 0) { /* if file already exists */ + tmpnam(OFiles[OfIndx].OFNam); + strcpy(OFiles[OfIndx].OTNam, (char *)FBfBeg); +#if DEBUGGING + sprintf(DbgSBf,"\"%s\" file exists, using tmpnam()", FBfBeg); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + } else { + strcpy(OFiles[OfIndx].OFNam, (char *)FBfBeg); + OFiles[OfIndx].OTNam[0] = '\0'; + } +#if DEBUGGING + sprintf(DbgSBf,"creating file \"%s\"", OFiles[OfIndx].OFNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + OFiles[OfIndx].OStrem = fopen(OFiles[OfIndx].OFNam, "wb"); + if (OFiles[OfIndx].OStrem == NULL) { + if (RepErr) { + ZErMsg(); + } +#if DEBUGGING + sprintf(DbgSBf,"FAILURE, fopen(\"%s\",\"w\") failed", + OFiles[OfIndx].OFNam); + DbgFEx(2,DbgFNm,DbgSBf); +#endif + return FAILURE; + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ZPrsCL() + Parse the command line using a TECO macro. + load q-register Z with the command line + if USE_ANSI_CLPARS + directly execute command-line parsing macro in clpars[] + else + load q-register Y with a command-line parsing macro + do an MY$$ +*****************************************************************************/ +VVOID ZPrsCL(int argc, char **argv) +{ + int i; + char TmpBuf[256]; + SIZE_T line_len; + DBGFEN(2,"ZPrsCL",NULL); +/* + * If the command line contains arguments, construct a replica of the + * command line in Q-register Z. It's a "replica" because spacing might + * be wrong. + */ + if (argc > 1) { + TmpBuf[0] = '\0'; + for (i = 1; i < argc; i++) { + strcat(TmpBuf, *++argv); + strcat(TmpBuf, " "); + } + line_len = strlen(TmpBuf)-1; /* ignore trailing space */ + QR = &QRgstr[35]; /* 35 = q-register Z */ + if (MakRom(line_len) == FAILURE) { + DBGFEX(2,DbgFNm, + "couldn't make room, exiting EXIT_FAILURE"); + exit(EXIT_FAILURE); + } + MEMMOVE(QR->Start, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +#if USE_ANSI_CLPARS +/* + * execute embedded command line-parsing macro directly from clpars[] + */ + CStBeg = CBfPtr = clpars; /* command string start */ + CStEnd = clpars + CLPARS_LEN; /* command string end */ + EStTop = EStBot; /* clear expression stack */ + ExeCSt(); /* execute command string */ +#else +#if 0 + { + char *p, *p2; + int i, len, tlen=0; + p2 = p = malloc(CLPARS_LEN); + if (!p) { + fprintf(stderr, "Out of memory\n"); + exit(-1); + } + for (i=0 ; i != CLPARS_LINES ; ++i) { + len = strlen(clpars[i]); + MEMMOVE(p2, clpars[i], len); + tlen += len; + p2 += len; + } + if (tlen != CLPARS_LEN) { + fprintf(stderr, "CLPARS_LEN error %d %d\n", tlen, CLPARS_LEN); + exit(-1); + } + CStBeg = CBfPtr = p; /* command string start */ + CStEnd = p + CLPARS_LEN; /* command string end */ + EStTop = EStBot; /* clear expression stack */ + ExeCSt(); /* execute command string */ + free(p); + } +#endif + +#if 1 +/* + * Load imbedded command-line parsing macro into Q-register Y + */ + QR = &QRgstr[34]; /* 34 = q-register Y */ + if (MakRom((SIZE_T)CLPARS_LEN) == FAILURE) { + DBGFEX(2,DbgFNm,"MakRom(CLPARS_LEN) failed, calling exit()"); + exit(EXIT_FAILURE); + } + for (i = 0; i < CLPARS_LINES; i++) { + line_len = strlen(clpars[i]); + MEMMOVE(QR->End_P1, clpars[i], line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +/* + * Execute an MY$$ command. + */ + CBfPtr = "my\33\33"; /* command string start */ + CStEnd = CBfPtr + 3; /* command string end */ + EStTop = EStBot; /* clear expression stack */ + ExeCSt(); /* execute command string */ + +/* + * Clear the command-line parsing macro from Q-register Y + */ + QR = &QRgstr[34]; /* 34 = q-register Y */ + ZFree (QR->Start); + QR->Start = QR->End_P1 = NULL; +#endif +#endif + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + ZPWild() + This function presets the wildcard lookup filename. It is +called when the user executes an ENfilename$ command. Later executions of +the EN$ command will cause the ZSWild function to be called to return +successive wildcard matches. + Under Turbo C, we save the drive code and subdirectory path so +later on we can return full filenames. +*****************************************************************************/ +DEFAULT ZPWild(void) /* preset the wildcard lookup filename */ +{ + DBGFEN(2,"ZPWild",NULL); +/* + * say wildcard lookup has been preset, but we haven't done any + * findfirst or findnext'ing yet. + */ + ff_preset = 0; +/* + * if they didn't process all of the filenames from a + * previous EN' call, discard them + */ + if (ff_names != NULL) { + ZFree (ff_names); + ff_names = NULL; + } + ff_names_p = NULL; +/* + * "clean out" ff_drive, ff_dir, and ff_path. + */ + memset (ff_drive, 0, _MAX_DRIVE); + memset (ff_dir, 0, _MAX_DIR); + memset (ff_path, 0, _MAX_PATH); +/* + * NULL-terminate wildcard filename in FBf so fnsplit knows + * where it ends, copy it into ff_path[], and save drive code + * and directory path in ffdrive[] and ff_path[]. + */ + *FBfPtr = '\0'; + strncpy (ff_path, (char *)FBfBeg, _MAX_PATH-1); + strlwr (ff_path); + _splitpath (ff_path, ff_drive, ff_dir, NULL, NULL); + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(voidptr OldBlk, SIZE_T NewSiz) +{ + voidptr NewBlk; +#if DEBUGGING + static char *DbgFNm = "ZRaloc"; + sprintf(DbgSBf,"OldBlk = %ld, NewSiz = %ld", + Zcp2ul(OldBlk),(LONG)NewSiz); + DbgFEn(4,DbgFNm,DbgSBf); +#endif + NewBlk = realloc ((void *)OldBlk, NewSiz); +#if DEBUGGING +/* + * update OldBlk's entry in MPtrs[] + */ + if (NewBlk != NULL && OldBlk != NewBlk) { + int i; + for (i = 0; i < MMAX && MPtrs[i] != OldBlk; ++i) { + ; + } + if (i == MMAX) { + puts ("ZRaloc: trying to realloc non-malloc'ed pointer"); + exit (1); + } + MPtrs[i] = NewBlk; + } +#endif +#if DEBUGGING + sprintf(DbgSBf,"NewBlk = %ld", Zcp2ul(NewBlk)); + DbgFEx(4,DbgFNm,DbgSBf); +#endif + return NewBlk; +} +/***************************************************************************** + ZRdLin() + This function reads a line from a file. It is passed a buffer, the +size of the buffer, a file pointer and a pointer to a place to leave the +length of the line. +*****************************************************************************/ +DEFAULT ZRdLin( /* read a line from a file */ + charptr ibuf, /* where to put string */ + ptrdiff_t ibuflen, /* max length of ibuf */ + int IfIndx, /* index into IFiles[] */ + DEFAULT *retlen) /* returned length of string */ +{ + int character; /* the last character read */ + DEFAULT shortBuf; /* max size to read, 32767 or ibuflen */ + DEFAULT charsLeft; /* number of characters left */ + FILE *fp; /* input stream pointer to read from */ + char *iBuf; /* non-huge pointer into IBf for speed */ +#if DEBUGGING + static char *DbgFNm = "ZRdLin"; + sprintf(DbgSBf,"ibuf = %ld, ibuflen = %ld, IfIndx = %d", + Zcp2ul(ibuf),(LONG)ibuflen,IfIndx); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + shortBuf = (ibuflen > 32767) ? 32767 : (DEFAULT) ibuflen; + charsLeft = shortBuf; + fp = IFiles[IfIndx]; + iBuf = (char *) ibuf; + while ((character = getc(fp)) >= 0) { /* we got one */ + *iBuf++ = character; + if (character == LINEFD || character == VRTTAB) { + /* finished with this line */ + *retlen = shortBuf - charsLeft + 1; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + if (character == FORMFD) { + /* toss form feed, then finished */ + *retlen = shortBuf - charsLeft; + FFPage = -1; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + if (--charsLeft == 0) { + /* no more room, so return */ + *retlen = shortBuf; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + } +/* + * If we made it to here, the read has failed --- EOF or Error. + */ + if (ferror(fp)) { /* if we got an error */ + *retlen = 0; /* say didn't read anything */ + ZErMsg(); +#if DEBUGGING + sprintf(DbgSBf,"ferror() FAILURE"); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return FAILURE; + } +/* + * If we made it to here, the read has failed because of EOF. + */ + if ((*retlen = shortBuf-charsLeft) == 0) { + IsEofI[IfIndx] = TRUE; /* say we reached EOF */ + } +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} +/***************************************************************************** + ZScrOp() + This function is called to perform special screen functions. +*****************************************************************************/ +VVOID ZScrOp(DEFAULT OpCode) /* do a screen operation */ +{ + int index; + static int map[] = { + 1, /* 0 - VT52 is a VT52 */ + 2, /* 1 - VT61 is a VT61 */ + 1, /* 2 - VT100 in VT52 mode is a VT52 */ + 0, /* 3 - unused */ + 3, /* 4 - VT100 in ANSI mode is a VT100 */ + 0, /* 5 - unused */ + 0, /* 6 - VT05 is a VT05 */ + 0, /* 7 - unused */ + 3, /* 8 - VT102 is a VT100 */ + 0, /* 9 - unused */ + 3, /* 10 - VK100 is a VT100 */ + 3, /* 11 - VT200 in VT200 mode is a VT100 */ + 3, /* 12 - VT200 in VT100 mode is a VT100 */ + 1, /* 13 - VT200 in VT52 mode is a VT52 */ + }; + struct strng + { + charptr strt; + DEFAULT len; + }; + static struct strng CUP[] = { /* cursor up one line */ + {"\232\0\0\0\0", 5}, /* VT05 - ? */ + {"\033A", 2}, /* VT52 - ESC A */ + {"", 0}, /* VT61 */ + {"\033[A", 3} /* VT100 - ESC [ A */ + }; + static struct strng EEL[] = { /* erase to end of line */ + {"\36", 1}, /* VT05 - RS */ + {"\033K\r", 3}, /* VT52 - ESC K CR */ + {"", 0}, /* VT61 */ + {"\033[K", 3} /* VT100 - ESC [ K */ + }; + static struct strng ROF[] = { /* reverse video on */ + {"", 0}, /* VT05 */ + {"", 0}, /* VT52 */ + {"", 0}, /* VT61 */ + {"\033[m", 3} /* VT100 - ESC [ m */ + }; + static struct strng RON[] = { /* reverse video off */ + {"", 0}, /* VT05 */ + {"", 0}, /* VT52 */ + {"", 0}, /* VT61 */ + {"\033[7m", 4} /* VT100 - ESC [ 7 m */ + }; + if (CrType == UNTERM) { /* if unknown terminal type */ + return; /* can't do screen operations */ + } + if (CrType == IBMPC) { + int x, y; + + switch (OpCode) { +#if VIDEO + case SCR_CUP: /* cursor up one line */ + getyx(stdscr, y, x); + move(y-1, x); + break; + case SCR_EEL: /* erase to end-of-line */ + clrtoeol(); + break; +#endif + case SCR_ROF: /* turn on reverse video */ + case SCR_RON: /* turn off reverse video */ + break; + } + return; + } +/* + * The numbering used for CrType comes from TECO-11. Convert it to get an + * index into the string arrays. + */ + index = map[CrType]; + switch (OpCode) { + case SCR_CUP: ZDspBf(CUP[index].strt, CUP[index].len); break; + case SCR_EEL: ZDspBf(EEL[index].strt, EEL[index].len); break; + case SCR_ROF: ZDspBf(ROF[index].strt, ROF[index].len); break; + case SCR_RON: ZDspBf(RON[index].strt, RON[index].len); break; + } +} +/***************************************************************************** + ZSetTT() + This function sets or clears terminal parameters. The only terminal +parameters that TECO can set are + 1. whether the terminal can display 8-bit characters + 2. the number of rows + 3. the number of columns +*****************************************************************************/ +DEFAULT ZSetTT( /* tell operating system that we set the terminal */ +DEFAULT TTWhat, /* what terminal parameter to set */ +DEFAULT TTVal) /* what to set it to */ +{ + TTWhat = TTWhat; /* avoid "parameter not used" Turbo C warning */ + TTVal = TTVal; /* avoid "parameter not used" Turbo C warning */ + return ExeNYI(); +} +/***************************************************************************** + ZSWild() + This function searches for the next wildcard filename. It +is called when the user executes an "EN$" or ":EN$" command. If the user +executes an "ENfilename$" command, the ZPWild function is called, not this +function. + This function returns + 1. SUCCESS if the filename buffer has a new file name + 2. FAILURE if the search failed somehow other than FILENF + 3. FILENF if no more occurrences of the wildcard exist +*****************************************************************************/ +DEFAULT ZSWild(void) /* search for next wildcard filename */ +{ + charptr cp; + struct _finddata_t ff_blk; /* wildcard control block */ + const size_t ff_exp = (_MAX_PATH*20); /* expansion increment */ + size_t ff_max; /* max_size of ff_names */ + size_t ff_size; /* current size of ff_names */ + int ff_status; + charptr ffp; + size_t filename_length; + long hnd; /* handle to find */ + DBGFEN(2,"ZSWild",NULL); + switch (ff_preset) { + case -1: +/* + * if ZPWild hasn't been called, return FILENF (or FAILURE ???) + */ + DBGFEX(2,DbgFNm,"FILENF, ENfilename$ not called"); + return FILENF; + case 0: +/* + * if ZPWild has been called, but we haven't done any directory searching + * yet, search the directory and build a list of filenames in ff_names + * like "filespec\0filespec\0...filespec\0\0" + */ + ff_preset = 1; + ffp = ff_names = NULL; + ff_size = ff_max = 0; /* force initial ZRaloc */ + hnd = _findfirst (ff_path, &ff_blk); + ff_status = hnd == -1L; + while (ff_status == 0) { +/* + * allocate if ff_names is not big enough to hold a full filename + */ + if (ff_max - ff_size < _MAX_PATH) { + ff_max += ff_exp; + ffp = (charptr) ZRaloc (ff_names, ff_max); + if (ffp == NULL) { + if (ff_names != NULL) { + ZFree (ff_names); + ff_names = NULL; + } + ff_names_p = NULL; + ff_preset = -1; + DBGFEX(2,DbgFNm,"FAILURE, ZRaloc failed"); + return FAILURE; + } + ff_names = ffp; + ffp = &ff_names[ff_size]; + } +/* + * copy drive, subdirectory path, and filename + * to ff_names, then NULL-terminate filename + */ + for (cp = ff_drive; *cp; ++ff_size) { + *ffp++ = *cp++; + } + for (cp = ff_dir; *cp; ++ff_size) { + *ffp++ = *cp++; + } + for (cp = ff_blk.name; *cp; ++ff_size, ++cp) { + *ffp++ = tolower (*cp); + } + *ffp++ = '\0'; + ++ff_size; +/* + * find next match + */ + ff_status = _findnext (hnd, &ff_blk); + } + if (hnd != -1L) + _findclose(hnd); +/* + * NULL-terminate filename list + */ + if (ffp) { + *ffp = '\0'; + } + ff_names_p = ff_names; +/* + * fall through to return first name in ff_names list + */ + default: +/* + * if no more names in ff_names, free what we found + */ + if (ff_names_p != NULL && *ff_names_p == '\0') { + ZFree (ff_names); + ff_names = ff_names_p = NULL; + } + if (ff_names_p == NULL) { + DBGFEX(2,DbgFNm,"FILENF, no more names in ff_names"); + return FILENF; + } +/* + * copy next name in ff_names to FBf and make + * ff_names_p point to next name in ff_names + */ + filename_length = strlen ((char *)ff_names_p); + MEMMOVE (FBfBeg, ff_names_p, filename_length); + FBfPtr = FBfBeg + filename_length; + ff_names_p += (filename_length + 1); + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ZTrmnl() + This function sets up the input/output of commands. Usually, that +means the input/output channels to the terminal, but TECOC might be run +from a BATCH file and that possibility must be handled. In addition, the +handling of interrupts is found here. + In general, this function must: + 1. Set TIChan so it can be used to read commands + 2. Set TOChan so it can be used for output + 3. handle interrupts + 4. initialize CrType (what kind of terminal it is) + 5. initialize EtFlag (terminal capability bits) + 6. initialize HtSize (number columns terminal has) + 7. initialize VtSize (number rows terminal has) +*****************************************************************************/ +static void CntrlC(int sig) /* see ZPORT.H for _Cdecl */ +{ + if (EtFlag & ET_TRAP_CTRL_C) { /* if user wants it */ + EtFlag &= ~ET_TRAP_CTRL_C; /* turn off bit */ + } else { + if (EtFlag & ET_MUNG_MODE) { /* if in MUNG mode */ + TAbort(EXIT_SUCCESS); + } + GotCtC = TRUE; /* set "stop soon" flag */ + } +} +VVOID ZTrmnl(void) /* set up I/O to the terminal */ +{ + DBGFEN(2,"ZTrmnl",NULL); +/* + * To prevent line feeds written to the terminal from being converted to + * carriage-return/line-feeds, reset stdout to binary mode. This is enough + * to fix the problem in Microsoft C, but Turbo-C requires that the FILE + * struct member "flags" also be twiddled with. + */ + setmode(fileno(stdout), O_BINARY); + EtFlag = ET_READ_LOWER | /* don't convert lower to upper */ +#if VIDEO + ET_WAT_SCOPE | /* "WATCH" support exists */ +#endif + ET_BKSP_IS_DEL | /* backspace key is delete key */ + ET_SCOPE | /* ok to use video for del and ^U */ + ET_EIGHTBIT; /* terminal uses 8-bit characters */ + signal(SIGINT, CntrlC); + CrType = IBMPC; /* use ROM BIOS routines */ +#if VIDEO + PrevScreen = GetStdHandle(STD_OUTPUT_HANDLE); + Screen = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + 0, NULL, + CONSOLE_TEXTMODE_BUFFER, + NULL); + SetConsoleActiveScreenBuffer(Screen); + VtSize = 25; + HtSize = 80; +#endif + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + ZVrbos() + This function displays the verbose form of an error message. +*****************************************************************************/ +VVOID ZVrbos(WORD ErrNum, char *ErMnem) +{ + char **TmpPtr; +#include "vrbmsg.h" + ErrNum = ErrNum; /* avoid "parameter not used" Turbo C warning */ + ErMnem = ErMnem; /* avoid "parameter not used" Turbo C warning */ + ZDspBf("\r\n",2); + for (TmpPtr = &ParaTx[StartP[LstErr]]; *TmpPtr; ++TmpPtr) { + ZDspBf((charptr)*TmpPtr, strlen (*TmpPtr)); + ZDspBf("\r\n",2); + } +} +/***************************************************************************** + ZWrBfr() + This function writes a buffer to a file. It is passed an output +file index and pointers to the beginning and end (plus 1) of the buffer +to be output. +*****************************************************************************/ +DEFAULT ZWrBfr( + DEFAULT OfIndx, /* index into OFiles array */ + charptr BfrBeg, /* address of output buffer beginning */ + charptr BfrEnd) /* address of output buffer end */ +{ + ptrdiff_t bufsiz = BfrEnd - BfrBeg + 1; +#if DEBUGGING + static char *DbgFNm = "ZWrBfr"; + sprintf(DbgSBf,"OfIndx = %d, BfrBeg = %ld, BfrEnd = %ld", + OfIndx, Zcp2ul(BfrBeg), Zcp2ul(BfrEnd)); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + if (fwrite(BfrBeg,sizeof(char),bufsiz,OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"fwrite() failed"); + return FAILURE; + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +#if CHECKSUM_CODE /* MS-DOS only debugging aid */ +/***************************************************************************** + While debugging on the PC, we ran into some bizzare behavior which led +us to think code was being overwritten somewhere. The following routines +calculate checksums for each module in TECO-C. These checksums can be checked +during runtime to see if the code has been changed. If a checksum has +changed, the offending module is displayed and TECOC-C is exited. + This code only works under Turbo-C. This code doesn't work under +Turbo Debugger since TD modifies code while it runs. + After init_code_checksums() is called in main() above, +check_code_checksums() is called in ExeCSt() after the successful completion +of each command. For more frequent checking, it can also be called in the +DbgDMs() routine above but then the "DEBUGGING" macro in ZPORT.H has to be +set to "TRUE" as well. + If the "CHECKSUM_CODE" macro in ZPORT.H is set to "FALSE", then none +of this code is compiled. +*****************************************************************************/ +#pragma inline /* use Turbo Asm version of calc_checksum() */ +/* + * As of 1-Jun-1990, TECO-C contains about 230 modules so I've hardwired + * module_checksums[] to contain 300 entries, plus a final empty entry which + * signifies the end of the module list. some space is wasted, but + * hardwiring it is simpler. Manfred Siemsen. + */ +#define MAX_MODULES 200 +/* + * The large model module names in the map file are in the form "NAME_TEXT" + * and it turns out that "NAME" is never more than 8 characters. Since I + * strip off the "_TEXT", I've made the maximum length of the module name 8 + * characters and left space for the trailing '\0'. This might be a bad + * assumption. Some space is wasted but again hardwiring it is simpler. + */ +#define MAX_MODULE_NAME_LEN 8 /* is 8 enough? */ +/* + * The chksum struct contains the name, length, and checksum of each module + * in TECO-C. + */ + struct chksum { + char name[MAX_MODULE_NAME_LEN+1]; + unsigned length; + unsigned checksum; +} module_checksums[MAX_MODULES+1]; +/* + * ZFirst() is an empty function who's object file is the first object file + * named on the TLINK command line (even before the C0? startup code). The + * reason for this is so we know where the first function in the executable + * is. I tried using "main()" as the first function in the TECOC module, + * but that meant I couldn't checksum a few functions which are included + * along with the startup code in the "_TEXT" module, and I thought it was + * better to check everything. + */ +extern void ZFirst (void); +/* + * calc_checksum (cp, length) + * + * this routine calculates and returns a simple checksum for a block of + * memory starting at "cp" that is "length" bytes long. + * + * the assembler version is much quicker and seems to produce the same + * result as the C version. we'll assume a module is <64K. + */ +unsigned calc_checksum (charptr cp, unsigned length) +{ +#if 1 /* ASM version */ + unsigned off; + unsigned seg; +#if TC_SMALL_CODE + off = (unsigned) cp; + seg = _CS; +#else + off = FP_OFF (cp); + seg = FP_SEG (cp); +#endif + off = (unsigned) cp; /* dos.h: FP_OFF() */ + seg = (unsigned) (((unsigned long) cp) >> 16); /* dos.h: FP_SEG() */ + asm push ds /* save DS */ + asm push si /* save SI */ + asm xor ax,ax /* AX = checksum = 0 */ + asm mov ds,seg /* DS = module segment */ + asm mov si,off /* SI = module offset */ + asm mov cx,length /* CX = module length */ + asm xor bh,bh /* BH is always zero for add */ + asm inc cx /* prepare for 1st decrement */ + asm jmp short loop_test /* jump directly to loop test */ +cks_loop: /* calculate checksum loop */ + asm mov bl,[si] /* BL = character at DS:SI */ + asm add ax,bx /* checksum += character */ + asm inc si /* ++(module offset) */ +loop_test: + asm loop cks_loop /* dec CX and loop if not zero */ + asm pop si /* restore SI */ + asm pop ds /* restore DS */ + return _AX; /* is this redundant? */ +#else /* C version */ + unsigned checksum; + for (checksum = 0; length != 0; ++cp, --length) { + checksum += *cp; + } + return checksum; +#endif +} +/* + * init_code_checksums () + * + * this routine reads a Turbo C TLINK version 2.0 generated map file for + * the names and lengths of the various TECO-C modules. once the map + * file has been read, checksums are calculated for each module. + * + * this routine assumes the map file is in perfect shape. the format + * of the map file is: + * + * "" + * " Start Stop Length Name Class" + * "" + * " 00000H 0000BH 0000CH FRSTFUNC_TEXT CODE" + * " 0000CH 00A51H 00A46H _TEXT CODE" + * " 00A52H 01AFDH 010ACH TECOC_TEXT CODE" + * " 01AFEH 026F8H 00BFBH BAKSRC_TEXT CODE" + * " 026F9H 02E0CH 00714H BLDSTR_TEXT CODE" + * + * etc, etc (one line for each code module) ... + * + * " 16D83H 16E23H 000A1H VRAM_TEXT CODE" + * " 16E24H 16E59H 00036H WHEREXY_TEXT CODE" + * " 16E5AH 1E699H 07840H _DATA DATA" + * " 1E69AH 1E69DH 00004H _EMUSEG DATA" + * + * etc, etc (the rest is ignored) ... + */ +#define MAX_MAP_LINE_LEN 128 /* 128 should be enough (???) */ +#define NAME_COL 22 /* "Name" column */ +#define CLASS_COL 41 /* "Class" column */ +void init_code_checksums (void) +{ + char buf[MAX_MAP_LINE_LEN]; + charptr cp; + FILE *fp; + int i; + struct chksum *mcp; + long start; + long stop; + char temp_name[CLASS_COL-NAME_COL+1]; + memset (buf, 0, MAX_MAP_LINE_LEN); + memset (temp_name, 0, CLASS_COL-NAME_COL+1); +/* + * open map file + */ + if ((fp = fopen ("tecoc.map","r")) == NULL) { + printf ("init_code_checksums: can't open tecoc.map file\n"); + exit (EXIT_FAILURE); + } +/* + * skip the first three header lines + */ + for (i = 0; i < 3; ++i) { + if (fgets (buf, MAX_MAP_LINE_LEN, fp) == NULL) { + printf ("init_code_checksums: premature eof on map file\n"); + exit (EXIT_FAILURE); + } + } +/* + * read the map file until we reach a line with "DATA" in the "Class" column + * instead of "CODE". + */ + mcp = module_checksums; + while (fgets (buf, MAX_MAP_LINE_LEN, fp) && buf[CLASS_COL] == 'C') { + if (sscanf (buf, " %5lxH %5lxH %5xH %s", + &start, + &stop, + &mcp->length, + temp_name) != 4) { + printf ("init_code_checksums: sscanf() failed\n"); + exit (EXIT_FAILURE); + } +/* + * zap "_TEXT" from the end of the "NAME_TEXT" module name and copy it to + * mcp->name. + * + * we start strstr() at &temp_name[1] because we don't want to zap "_TEXT" + * off the module named "_TEXT". + */ + if ((cp = strstr (&temp_name[1], "_TEXT")) != NULL) { + *cp = '\0'; + } + if (strlen (temp_name) > MAX_MODULE_NAME_LEN) { + printf("init_code_checksums: module name"); + printf(" \"%s\" > MAX_MODULE_NAME_LEN\n", temp_name); + exit (EXIT_FAILURE); + } + strcpy (mcp->name, temp_name); +/* + * go to next entry in module_checksums[] + */ + if (++mcp == &module_checksums[MAX_MODULES-1]) { + printf ("init_code_checksums: more code modules "); + printf("than MAX_MODULES (%d)\n", MAX_MODULES); + exit (EXIT_FAILURE); + } +/* + * make sure the while() test fails if the next line we read is less than + * CLASS_COL characters long. + */ + buf[CLASS_COL] = '\0'; + } + fclose(fp); +/* + * now, calculate checksums for all the modules that have been read in from + * the map file + */ + cp = (charptr) ZFirst; + mcp = &module_checksums[1]; + while (mcp->name[0] != '\0') { + mcp->checksum = calc_checksum (cp, mcp->length); + cp += mcp->length; + ++mcp; + } +} +/* + * check_code_checksums () + * + * this routine calculates a current checksum for each module and + * compares it with the module's initial checksum. if they are + * different then something has probably modified the code in that + * module. + */ +void check_code_checksums (void) +{ + struct chksum *mcp; + charptr cp; + BOOLEAN chksum_failed; +/* + * '\373' is the IBM PC square-root "check" character + * + * fputc ('\373', stdout); + */ + chksum_failed = FALSE; + cp = (charptr) ZFirst; + mcp = module_checksums; + while (mcp->name[0] != '\0') { + if (mcp->checksum != calc_checksum (cp, mcp->length)) { + printf ("\n%s checksum has changed!\n", mcp->name); + chksum_failed = TRUE; + } + cp += mcp->length; + ++mcp; + } + if (chksum_failed) { + exit (EXIT_FAILURE); + } +} +#endif /* #if CHECKSUM_CODE */ +#if VIDEO +static void move(int y, int x) +{ + Cursor.X = x; + Cursor.Y = y; + SetConsoleCursorPosition(Screen, Cursor); +} +static void _getyx(int *y, int *x) +{ + CONSOLE_SCREEN_BUFFER_INFO Info; + GetConsoleScreenBufferInfo(Screen, &Info); + if (y) + *y = Info.dwCursorPosition.Y; + if (x) + *x = Info.dwCursorPosition.X; +} +static void zaddchs(char *buf) +{ + long n; + if (buf && *buf && Screen) + WriteConsole(Screen, buf, strlen(buf), &n, NULL); +} +static void zaddch2(char c) +{ + long n; + if (c == 13) + clrtoeol(); + WriteConsole(Screen, &c, 1, &n, NULL); +} +static void zaddch(char c, int echo) +{ + long n; + if (Screen) + WriteConsole(Screen, &c, 1, &n, NULL); +} +static void clrtoeol() +{ + static char buf[] = " "; + int x, y, len; + long n; + getyx(scr, y, x); + len = HtSize - x; + if (len > 0 && Screen) + WriteConsole(Screen, buf, len, &n, NULL); + move(y, x); +} +static void standout() +{ +} +static void standend() +{ +} +static void specon() +{ +} +static void specoff() +{ +} +static void addch(int v) +{ +} +static void drawline() +{ +} +static int intabs(int t) +{ + return t < 0 ? -t : t; +} +static void gr_on() +{ +} +static void gr_off() +{ +} +static void waddch(int win, char c) +{ +} +void refresh() +{ +} +void wrefresh(int s) +{ +} +static void clear() +{ +} +static void setscrreg(int h, int v) +{ +} +/**********************************************************************/ +static void +initialize_scope() +{ +/* + * not dotx, doty will be character and line offsets from 0,0 + * wrap will not effect these + */ + dotx = doty = 0; + olddot = 0; + getyx(stdscr,cmdy,cmdx); + move(0,0); + clear(); + p_scope_start=GapBeg; + scope_start = DOT; + if (winline) + drawline(); + move(cmdy,cmdx); + refresh(); +} +static void finish() +{ + int x; + int y; + getyx(stdscr,y,x); + if (y >= VtSize - winline - ScroLn) + return; + clrtoeol(); + for (x=y+1;x= EBfEnd || (p) == GapBeg-1 && GapEnd == EBfEnd) +/* Is this a valid pointer into the buffer? */ +#define VALID(p) ((p) < GapBeg && (p) >= EBfBeg || (p) > GapEnd && (p) <= EBfEnd) +/* Return the next character pointer or an invalid pointer. */ +#define NEXT(p) ((p)+1 == GapBeg ? GapEnd+1 : (p)+1) +/* Return the previous character pointer or an invalid pointer. */ +#define PREV(p) ((p)-1 == GapEnd ? GapBeg-1 : (p)-1) +/* Are there any characters in the buffer? */ +#define ANY (GapBeg != EBfBeg || GapEnd != IBfEnd) +/* Return a pointer to the first character or an invalid pointer. */ +#define FIRST (EBfBeg == GapBeg ? GapEnd+1 : EBfBeg) +/* Return a pointer to the last character or an invalid pointer. */ +#define LAST (EBfEnd == GapEnd ? GapBeg-1 : EBfEnd) +/* Return a pointer to the current character or invalid pointer if at EOB */ +#define DOT (GapEnd + 1) +#endif +void +redraw() +{ + int cccmdx; + int cccmdy; + int flag = 0; + int x; + int y; + int charcounter; + unsigned char *curptr; + if (ScroLn == 0) + return; + getyx(stdscr,cccmdy,cccmdx); +draw_all: + if (EBfBeg == GapBeg && EBfEnd==GapEnd) { + int i; + move(0,0); + scope_start = 0; + p_scope_start = EBfBeg; + standout(); + specon(); + getyx(stdscr, doty, dotx); + addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND); + specoff(); + standend(); + getyx(stdscr, doty1, dotx1); + clrtoeol(); + for (i=1; i<=VtSize - ScroLn - 1 - winline;i++) { + move(i,0); + clrtoeol(); + } + drawline(); + move(cccmdy,cccmdx); + olddot = 0; + return; + } + if ((intabs(olddot - DOT) > HtSize * (VtSize - ScroLn)) + || HldFlg) { + /* admittedly a heuristic ! */ + int linedisp, disp; + int siz = VtSize - ScroLn - 1 - winline; + linedisp = siz/2-2; + if (linedisp > 0) { + disp = Ln2Chr(-linedisp); + p_scope_start = GapBeg + disp; + scope_start = DOT + disp; + goto l1; /* no need to do stuff to get to beginning + of line */ + } + } + if (p_scope_start > EBfBeg) { + /* set p_scope_start to beginning of line */ + if (scope_start > DOT) { /* move */ + p_scope_start = GapBeg; + scope_start = DOT; + } + flag = 0; + while ((p_scope_start > EBfBeg) && !flag) { + --p_scope_start; + if (IsEOL(*p_scope_start)) + flag++; + } + if (p_scope_start != EBfBeg || IsEOL(*p_scope_start)) + ++p_scope_start; + } +/* + * note here p_scope_start may still be at GapBeg after all this number of + * characters we "backed up" is GapBeg - p_scope_start + */ +l1: olddot = DOT; move(0,0); + charcounter = GapBeg - p_scope_start; + if (p_scope_start < GapBeg) { + for (curptr=p_scope_start; curptr < GapBeg; curptr++) { + int redrawflag; + zaddch2(*curptr); + getyx(stdscr,y,x); + if (y>VtSize - ScroLn - 1 - winline) { + int lines = 0; + unsigned char *charpointer; +/* + * we didn't get to print dot - try moving p_scope_start one line forward or + * if lots of lines in between DOT and p_scope_start then just redraw + */ + move(y-1,0); + clrtoeol(); + redrawflag = 0; + if (p_scope_start >= EBfEnd) { + finish(); + drawline(); + move(cccmdy,cccmdx); + return; /* blew it */ + } + /* about how many lines ? */ + for (charpointer = p_scope_start; + charpointer < GapBeg; charpointer++) { + if (IsEOL(*charpointer)) + lines++; + if (lines > 2*(VtSize - ScroLn)) + break; + } + if (lines > 2*(VtSize-ScroLn)) { + /* just redraw everything */ + p_scope_start = GapBeg; + scope_start = DOT; + move(0,0); + /* clear(); */ + p_scope_start = GapBeg; + scope_start = DOT; + goto draw_all; + } + /* move forward a line */ + while (p_scope_start < GapBeg && !IsEOL(*p_scope_start)) { + ++p_scope_start; + ++scope_start; + } + if (IsEOL(*p_scope_start)) { + p_scope_start++; scope_start++; + } + if (p_scope_start >= GapBeg) { + p_scope_start = GapBeg; + scope_start = DOT; + } + goto l1; + } + } + } + curptr = GapEnd+1; + standout(); + getyx(stdscr, doty, dotx); + if (curptr > EBfEnd) { + getyx(stdscr,y,x); + if (y <= VtSize - ScroLn - 1 - winline) { + specon(); + addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND); + specoff(); + standend(); + getyx(stdscr, doty1, dotx1); + } + finish(); + drawline(); + move(cccmdy,cccmdx); + clrtoeol(); + return; + } else { + if (*curptr=='\n') { + if (!(SeeAll) && (y <= VtSize - ScroLn - 1 - winline)) { + if (EzFlag & EZ_VT100GRAPHICS) { + gr_on(); waddch(curwin,'e'); gr_off(); + } else + addch(ACS_RTEE); + } + } + zaddch2(*curptr); + } + standend(); + getyx(stdscr, doty1, dotx1); + curptr++; + getyx(stdscr,y,x); + if (y>VtSize - ScroLn - 1 - winline) { + drawline(); + move(cccmdy,cccmdx); + return; + } + while ((curptr <= EBfEnd)) { + zaddch2(*curptr); + getyx(stdscr,y,x); + if (y>=VtSize - ScroLn - winline) + break; + ++curptr; + } + if (y < VtSize - ScroLn - winline && curptr > EBfEnd) { + specon(); + addch((EzFlag & EZ_BTEE) ? ACS_BTEE : ACS_DIAMOND); + specoff(); + } + finish(); + drawline(); + move(cccmdy,cccmdx); +} +void +Scope(bot) /* first crack */ +int bot; +{ + if (bot <0) + return; + if (bot == 0) { + setscrreg(0, VtSize -1); + } else { + winline = (EzFlag & EZ_WIN_LINE) ? 1 : 0; + setscrreg(VtSize - bot, VtSize - 1); + move(VtSize - bot, 0); + curwin = stdscr; + initialize_scope(); + } +} +#endif