From 0e17d45276dfaf461a8f53c728f1f51579d175d0 Mon Sep 17 00:00:00 2001 From: Blake McBride Date: Sat, 30 May 2015 10:04:47 -0500 Subject: [PATCH] Initial commit of merged but untouched source from Tom Almy on 2015-05-29 --- .gitignore | 7 + bin/Make | 1 + bin/inspect | 1 + bin/inspect.bat | 1 + bin/inspect.cmd | 1 + bin/mung | 1 + bin/mung.bat | 1 + bin/mung.cmd | 1 + bin/teco | 1 + bin/teco.bat | 1 + bin/teco.cmd | 1 + bin/tecocmd.btm | 4 + bin/tmake.bat | 1 + bin/tmake.cmd | 1 + doc/aareadme.txt | 469 ++ doc/fixes.txt | 118 + doc/prog-guide.txt | 856 ++++ doc/readme.1st | 44 + doc/readme.osx | 171 + doc/readme.txt | 134 + doc/readme.win | 121 + doc/readme2.1st | 61 + doc/readme2.osx | 142 + doc/readme2.txt | 80 + doc/teco.doc | 11104 +++++++++++++++++++++++++++++++++++++++++ doc/wchart.txt | 212 + lib/change.tec | 1 + lib/change.tes | 237 + lib/checkqr.tec | 36 + lib/date.tec | 8 + lib/date.tes | 96 + lib/detab.tec | 8 + lib/detab.tes | 44 + lib/dir.tec | 3 + lib/dir.tes | 32 + lib/lowcase.tec | 3 + lib/makprnt.tec | 6 + lib/makprnt.tes | 16 + lib/squ.tec | 80 + lib/squ.tes | 1773 +++++++ lib/sub.tec | 9 + lib/tst.tec | 6 + lib/tstbsl.tec | 92 + lib/tstcss.tec | 73 + lib/tstequ.tec | 102 + lib/tsto.tec | 129 + lib/tstqr.tec | 120 + lib/tstsrc.tec | 544 ++ lib/unsqu.tec | 6 + lib/unsqu.tes | 187 + lib/upcase.tec | 3 + src/aaout.txt | 469 ++ src/amodem.c | 333 ++ src/baksrc.c | 338 ++ src/bldstr.c | 243 + src/changes.txt | 816 +++ src/chmacs.h | 22 + src/clenup.c | 50 + src/clpars.tec | 72 + src/clpars.tes | 808 +++ src/cmatch.c | 279 ++ src/dchars.h | 37 + src/deferr.h | 93 + src/defext.h | 89 + src/docjr.c | 54 + src/doeves.c | 88 + src/doflag.c | 38 + src/dscren.h | 24 + src/echoit.c | 51 + src/err.c | 273 + src/exea.c | 113 + src/exeats.c | 17 + src/exeb.c | 15 + src/exebar.c | 21 + src/exebsl.c | 86 + src/exec.c | 23 + src/execcc.c | 19 + src/execln.c | 22 + src/execom.c | 25 + src/execrt.c | 38 + src/execst.c | 113 + src/execta.c | 25 + src/exectc.c | 19 + src/exectd.c | 16 + src/execte.c | 30 + src/execti.c | 25 + src/exectl.c | 13 + src/exectn.c | 17 + src/execto.c | 16 + src/exectp.c | 23 + src/exectq.c | 24 + src/exectr.c | 33 + src/exects.c | 15 + src/exectt.c | 40 + src/exectu.c | 136 + src/exectv.c | 29 + src/exectw.c | 29 + src/exectx.c | 13 + src/execty.c | 23 + src/exectz.c | 25 + src/exed.c | 55 + src/exedgt.c | 49 + src/exedot.c | 20 + src/exedqu.c | 127 + src/exee.c | 1443 ++++++ src/exeequ.c | 54 + src/exeesc.c | 33 + src/exeexc.c | 20 + src/exeey.c | 37 + src/exef.c | 333 ++ src/exefb.c | 25 + src/exeg.c | 54 + src/exegtr.c | 31 + src/exeh.c | 18 + src/exei.c | 70 + src/exeill.c | 13 + src/exej.c | 22 + src/exek.c | 64 + src/exel.c | 35 + src/exelbr.c | 52 + src/exelst.c | 40 + src/exem.c | 91 + src/exen.c | 34 + src/exenul.c | 11 + src/exenyi.c | 14 + src/exeo.c | 167 + src/exeopr.c | 25 + src/exep.c | 57 + src/exeprc.c | 36 + src/exepw.c | 41 + src/exeq.c | 87 + src/exeqes.c | 17 + src/exer.c | 23 + src/exerbr.c | 69 + src/exertp.c | 22 + src/exes.c | 68 + src/exescl.c | 52 + src/exet.c | 51 + src/exeu.c | 38 + src/exeund.c | 33 + src/exeusc.c | 14 + src/exev.c | 38 + src/exew.c | 280 ++ src/exex.c | 94 + src/exey.c | 28 + src/exez.c | 19 + src/ff | 134 + src/findes.c | 47 + src/findqr.c | 86 + src/flowec.c | 35 + src/flowee.c | 38 + src/flowel.c | 42 + src/genclp.c | 223 + src/getara.c | 58 + src/getnma.c | 46 + src/inccbp.c | 25 + src/init.c | 159 + src/insstr.c | 111 + src/isradx.c | 26 + src/ln2chr.c | 45 + src/makdbf.c | 85 + src/makefile | 223 + src/makefile.ami | 170 + src/makefile.b32 | 258 + src/makefile.cct | 131 + src/makefile.dg | 248 + src/makefile.osx | 223 + src/makefile.prj | 149 + src/makefile.sun | 245 + src/makefile.tc | 359 ++ src/makefile.ulx | 245 + src/makrom.c | 46 + src/popmac.c | 49 + src/problems.txt | 292 ++ src/pshmac.c | 61 + src/purge.c | 154 + src/pushex.c | 162 + src/rdline.c | 115 + src/rdpage.c | 27 + src/readcs.c | 640 +++ src/readme.1st | 63 + src/readme.lnx | 181 + src/replac.c | 26 + src/search.c | 128 + src/singlp.c | 27 + src/skpcmd.c | 398 ++ src/srclop.c | 315 ++ src/sserch.c | 102 + src/tabort.c | 13 + src/tecoc.c | 1095 ++++ src/tecoc.h | 702 +++ src/test.c | 13 + src/tstsrc.tec | 544 ++ src/typbuf.c | 132 + src/typest.c | 13 + src/uminus.c | 22 + src/video.txt | 70 + src/vrbmsg.h | 288 ++ src/win/clpars.ori | 801 +++ src/win/clpars.tec | 71 + src/win/clpars.tes | 808 +++ src/win/makecl.bat | 2 + src/win/maketeco.bat | 2 + src/win/mung.bat | 1 + src/win/squ.bat | 26 + src/win/tctlib.rsp | 20 + src/win/teco.bat | 1 + src/win/teco.cmd | 1 + src/win/tecoc.lnk | 122 + src/win/tecocmd.btm | 4 + src/win/tst.bat | 11 + src/wrpage.c | 103 + src/zamiga.c | 1065 ++++ src/zfirst.c | 15 + src/zfrsrc.c | 783 +++ src/zlinux.c | 1356 +++++ src/zmsdos.c | 2282 +++++++++ src/zos2.c | 1355 +++++ src/zosx.c | 1355 +++++ src/zport.h | 649 +++ src/zunix.c | 2851 +++++++++++ src/zunix.c.save | 2952 +++++++++++ src/zunkn.c | 585 +++ src/zvms.c | 1935 +++++++ 224 files changed, 54618 insertions(+) create mode 100644 .gitignore create mode 120000 bin/Make create mode 120000 bin/inspect create mode 100644 bin/inspect.bat create mode 100644 bin/inspect.cmd create mode 120000 bin/mung create mode 100644 bin/mung.bat create mode 100644 bin/mung.cmd create mode 120000 bin/teco create mode 100644 bin/teco.bat create mode 100644 bin/teco.cmd create mode 100644 bin/tecocmd.btm create mode 100644 bin/tmake.bat create mode 100644 bin/tmake.cmd create mode 100644 doc/aareadme.txt create mode 100644 doc/fixes.txt create mode 100644 doc/prog-guide.txt create mode 100644 doc/readme.1st create mode 100644 doc/readme.osx create mode 100644 doc/readme.txt create mode 100644 doc/readme.win create mode 100644 doc/readme2.1st create mode 100644 doc/readme2.osx create mode 100644 doc/readme2.txt create mode 100644 doc/teco.doc create mode 100644 doc/wchart.txt create mode 100644 lib/change.tec create mode 100644 lib/change.tes create mode 100644 lib/checkqr.tec create mode 100644 lib/date.tec create mode 100644 lib/date.tes create mode 100644 lib/detab.tec create mode 100644 lib/detab.tes create mode 100644 lib/dir.tec create mode 100644 lib/dir.tes create mode 100644 lib/lowcase.tec create mode 100644 lib/makprnt.tec create mode 100644 lib/makprnt.tes create mode 100644 lib/squ.tec create mode 100644 lib/squ.tes create mode 100644 lib/sub.tec create mode 100644 lib/tst.tec create mode 100644 lib/tstbsl.tec create mode 100644 lib/tstcss.tec create mode 100644 lib/tstequ.tec create mode 100644 lib/tsto.tec create mode 100644 lib/tstqr.tec create mode 100644 lib/tstsrc.tec create mode 100644 lib/unsqu.tec create mode 100644 lib/unsqu.tes create mode 100644 lib/upcase.tec create mode 100644 src/aaout.txt create mode 100644 src/amodem.c create mode 100644 src/baksrc.c create mode 100644 src/bldstr.c create mode 100644 src/changes.txt create mode 100644 src/chmacs.h create mode 100644 src/clenup.c create mode 100644 src/clpars.tec create mode 100644 src/clpars.tes create mode 100644 src/cmatch.c create mode 100644 src/dchars.h create mode 100644 src/deferr.h create mode 100644 src/defext.h create mode 100644 src/docjr.c create mode 100644 src/doeves.c create mode 100644 src/doflag.c create mode 100644 src/dscren.h create mode 100644 src/echoit.c create mode 100644 src/err.c create mode 100644 src/exea.c create mode 100644 src/exeats.c create mode 100644 src/exeb.c create mode 100644 src/exebar.c create mode 100644 src/exebsl.c create mode 100644 src/exec.c create mode 100644 src/execcc.c create mode 100644 src/execln.c create mode 100644 src/execom.c create mode 100644 src/execrt.c create mode 100644 src/execst.c create mode 100644 src/execta.c create mode 100644 src/exectc.c create mode 100644 src/exectd.c create mode 100644 src/execte.c create mode 100644 src/execti.c create mode 100644 src/exectl.c create mode 100644 src/exectn.c create mode 100644 src/execto.c create mode 100644 src/exectp.c create mode 100644 src/exectq.c create mode 100644 src/exectr.c create mode 100644 src/exects.c create mode 100644 src/exectt.c create mode 100644 src/exectu.c create mode 100644 src/exectv.c create mode 100644 src/exectw.c create mode 100644 src/exectx.c create mode 100644 src/execty.c create mode 100644 src/exectz.c create mode 100644 src/exed.c create mode 100644 src/exedgt.c create mode 100644 src/exedot.c create mode 100644 src/exedqu.c create mode 100644 src/exee.c create mode 100644 src/exeequ.c create mode 100644 src/exeesc.c create mode 100644 src/exeexc.c create mode 100644 src/exeey.c create mode 100644 src/exef.c create mode 100644 src/exefb.c create mode 100644 src/exeg.c create mode 100644 src/exegtr.c create mode 100644 src/exeh.c create mode 100644 src/exei.c create mode 100644 src/exeill.c create mode 100644 src/exej.c create mode 100644 src/exek.c create mode 100644 src/exel.c create mode 100644 src/exelbr.c create mode 100644 src/exelst.c create mode 100644 src/exem.c create mode 100644 src/exen.c create mode 100644 src/exenul.c create mode 100644 src/exenyi.c create mode 100644 src/exeo.c create mode 100644 src/exeopr.c create mode 100644 src/exep.c create mode 100644 src/exeprc.c create mode 100644 src/exepw.c create mode 100644 src/exeq.c create mode 100644 src/exeqes.c create mode 100644 src/exer.c create mode 100644 src/exerbr.c create mode 100644 src/exertp.c create mode 100644 src/exes.c create mode 100644 src/exescl.c create mode 100644 src/exet.c create mode 100644 src/exeu.c create mode 100644 src/exeund.c create mode 100644 src/exeusc.c create mode 100644 src/exev.c create mode 100644 src/exew.c create mode 100644 src/exex.c create mode 100644 src/exey.c create mode 100644 src/exez.c create mode 100644 src/ff create mode 100644 src/findes.c create mode 100644 src/findqr.c create mode 100644 src/flowec.c create mode 100644 src/flowee.c create mode 100644 src/flowel.c create mode 100644 src/genclp.c create mode 100644 src/getara.c create mode 100644 src/getnma.c create mode 100644 src/inccbp.c create mode 100644 src/init.c create mode 100644 src/insstr.c create mode 100644 src/isradx.c create mode 100644 src/ln2chr.c create mode 100644 src/makdbf.c create mode 100644 src/makefile create mode 100644 src/makefile.ami create mode 100644 src/makefile.b32 create mode 100644 src/makefile.cct create mode 100644 src/makefile.dg create mode 100644 src/makefile.osx create mode 100644 src/makefile.prj create mode 100644 src/makefile.sun create mode 100644 src/makefile.tc create mode 100644 src/makefile.ulx create mode 100644 src/makrom.c create mode 100644 src/popmac.c create mode 100644 src/problems.txt create mode 100644 src/pshmac.c create mode 100644 src/purge.c create mode 100644 src/pushex.c create mode 100644 src/rdline.c create mode 100644 src/rdpage.c create mode 100644 src/readcs.c create mode 100644 src/readme.1st create mode 100644 src/readme.lnx create mode 100644 src/replac.c create mode 100644 src/search.c create mode 100644 src/singlp.c create mode 100644 src/skpcmd.c create mode 100644 src/srclop.c create mode 100644 src/sserch.c create mode 100644 src/tabort.c create mode 100644 src/tecoc.c create mode 100644 src/tecoc.h create mode 100644 src/test.c create mode 100644 src/tstsrc.tec create mode 100644 src/typbuf.c create mode 100644 src/typest.c create mode 100644 src/uminus.c create mode 100644 src/video.txt create mode 100644 src/vrbmsg.h create mode 100644 src/win/clpars.ori create mode 100644 src/win/clpars.tec create mode 100644 src/win/clpars.tes create mode 100644 src/win/makecl.bat create mode 100644 src/win/maketeco.bat create mode 100644 src/win/mung.bat create mode 100644 src/win/squ.bat create mode 100644 src/win/tctlib.rsp create mode 100644 src/win/teco.bat create mode 100644 src/win/teco.cmd create mode 100644 src/win/tecoc.lnk create mode 100644 src/win/tecocmd.btm create mode 100644 src/win/tst.bat create mode 100644 src/wrpage.c create mode 100644 src/zamiga.c create mode 100644 src/zfirst.c create mode 100644 src/zfrsrc.c create mode 100644 src/zlinux.c create mode 100644 src/zmsdos.c create mode 100644 src/zos2.c create mode 100644 src/zosx.c create mode 100644 src/zport.h create mode 100644 src/zunix.c create mode 100644 src/zunix.c.save create mode 100644 src/zunkn.c create mode 100644 src/zvms.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f82a6c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ + +*.o +*.obj +*~ +*.bak +*.exe + diff --git a/bin/Make b/bin/Make new file mode 120000 index 0000000..9e6cec2 --- /dev/null +++ b/bin/Make @@ -0,0 +1 @@ +tecoc \ No newline at end of file diff --git a/bin/inspect b/bin/inspect new file mode 120000 index 0000000..9e6cec2 --- /dev/null +++ b/bin/inspect @@ -0,0 +1 @@ +tecoc \ No newline at end of file diff --git a/bin/inspect.bat b/bin/inspect.bat new file mode 100644 index 0000000..efed97d --- /dev/null +++ b/bin/inspect.bat @@ -0,0 +1 @@ +tecoc teco/inspect %$ diff --git a/bin/inspect.cmd b/bin/inspect.cmd new file mode 100644 index 0000000..efed97d --- /dev/null +++ b/bin/inspect.cmd @@ -0,0 +1 @@ +tecoc teco/inspect %$ diff --git a/bin/mung b/bin/mung new file mode 120000 index 0000000..9e6cec2 --- /dev/null +++ b/bin/mung @@ -0,0 +1 @@ +tecoc \ No newline at end of file diff --git a/bin/mung.bat b/bin/mung.bat new file mode 100644 index 0000000..5c598a8 --- /dev/null +++ b/bin/mung.bat @@ -0,0 +1 @@ +tecoc mung %$ diff --git a/bin/mung.cmd b/bin/mung.cmd new file mode 100644 index 0000000..5c598a8 --- /dev/null +++ b/bin/mung.cmd @@ -0,0 +1 @@ +tecoc mung %$ diff --git a/bin/teco b/bin/teco new file mode 120000 index 0000000..9e6cec2 --- /dev/null +++ b/bin/teco @@ -0,0 +1 @@ +tecoc \ No newline at end of file diff --git a/bin/teco.bat b/bin/teco.bat new file mode 100644 index 0000000..a354ed8 --- /dev/null +++ b/bin/teco.bat @@ -0,0 +1 @@ +tecoc teco %$ diff --git a/bin/teco.cmd b/bin/teco.cmd new file mode 100644 index 0000000..a354ed8 --- /dev/null +++ b/bin/teco.cmd @@ -0,0 +1 @@ +tecoc teco %$ diff --git a/bin/tecocmd.btm b/bin/tecocmd.btm new file mode 100644 index 0000000..b0a8da0 --- /dev/null +++ b/bin/tecocmd.btm @@ -0,0 +1,4 @@ +alias teco tecoc teco/norename +alias inspect tecoc/inspect +alias mung tecoc mung +alias tmake tecoc make diff --git a/bin/tmake.bat b/bin/tmake.bat new file mode 100644 index 0000000..22ef6e0 --- /dev/null +++ b/bin/tmake.bat @@ -0,0 +1 @@ +tecoc make %$ diff --git a/bin/tmake.cmd b/bin/tmake.cmd new file mode 100644 index 0000000..22ef6e0 --- /dev/null +++ b/bin/tmake.cmd @@ -0,0 +1 @@ +tecoc make %$ diff --git a/doc/aareadme.txt b/doc/aareadme.txt new file mode 100644 index 0000000..84cefce --- /dev/null +++ b/doc/aareadme.txt @@ -0,0 +1,469 @@ + AAREADME.TXT + + This directory contains TECO-C, a version of TECO written in C. +It was written in C so the author could move comfortably from VAX/VMS +to various other machines, including MicroVaxes, which couldn't execute +TECO-11 prior to VMS 5.0 because they don't support PDP-11 compatibility +mode. TECO32, distributed with v5.0, solved this problem. + + TECO-C is meant to be a complete implementation of TECO as defined +by the Standard TECO User's Guide, which is in file TECO.DOC. There is no +manual for TECO-C itself, but the Standard TECO manual was the specification +for TECO-C, so it serves as an excellent manual. TECO-C departs from the +Standard manual in only a few places (like no video mode), listed in file +PROBLEMS.TXT. There is quick-and-dirty "wall chart" of all TECO commands +in file WCHART.TXT. + + This version of TECO-C runs under VMX/VMS, MS-DOS, AmigaDOS and Unix +(SunOS, Ultrix and System V on a Data General Aviion). If you find bugs or +have any comments about TECO-C, please contact + + Pete Siemsen Pete Siemsen + 645 Ohio Avenue #302 University of Southern California + Long Beach, Ca. 90814 1020 West Jefferson Blvd. + Los Angeles, CA 90089-0251 + + (213) 433-3059 (home) (213) 740-7391 (work) + + Internet: siemsen@usc.edu + + The following sections describe how to use or build TECO-C for +different environments. The command line syntax is the same as the syntax +for TECO-11 command lines. + + +########################################################################### + U N D E R V A X / V M S + + TECO-C was mostly developed under VAX/VMS. It compiles and links +using VAX C 3.1 under VMS version 5.3. + +To set up: inspect and modify ZVLOGIN.COM and then add it to your + LOGIN.COM + +To compile: inspect/edit ZVBLD.COM, then SUBMIT it + +To link: use the "LT" command (defined in ZVLOGIN.COM) + +To run: inspect/edit the symbol definitions in ZVLOGIN.COM + Note: TECO-C uses the same command line syntax as TECO32 + + +########################################################################### + U N D E R M S - D O S + + TECO-C compiles/links under Turbo C v2.00 under MS-DOS 4.01 and +Concurrent DOS 386 v3.0. + +To build: run MAKE on MAKEFILE.TC. to build TECO from scratch say: + "make -fmakefile.tc -DALL". see MAKEFILE.TC for other make + -D options. also see MAKETECO.BAT. + +To run: use TECO.BAT to edit a file or MUNG.BAT to run a macro, + for example: TECO filename. + + +########################################################################### + U N D E R U N I X + +To compile and link: use the make utility on "makefile.sun" (for SunOS) or + "makefile.ulx" (for Ultrix) or "makefile.dg" (for System V Unix + on a Data General Aviion). + +To run: define aliases and environment variables in your .cshrc file. + Here's an example, assuming my initialization file is named + .tecorc and it's in my home directory, and my macros are in a + directory named tecoc under my main directory. You'll have to + change the directory names, of course. + + setenv TEC_INIT \$/home/sol/siemsen/.tecorc + setenv TEC_LIBRARY /home/sol/siemsen/tecoc/ + alias te '/home/sol/siemsen/tecoc/tecoc teco -nocreate' + alias mung '/home/sol/siemsen/tecoc/tecoc mung' + alias tma '/home/sol/siemsen/tecoc/tecoc make' + +After doing this, "te" runs tecoc. + + +Unix Command line +---- ------- ---- + +To make Unix users more comfortable, TECO-C uses Unix-like options syntax +instead of the familiar "/" style used under VAX/VMS. The options can be +abbreviated. They are (optional characters in square brackets): + +-in[spect] +-noc[reate] +-noi[ni] +-nom[emory] +-sc[roll] +-scroll:nnn:SEEALL + do nnn,7:W and 1,3:W + + +-nop[age] + 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. + + +EZ Mode Control Flag +-- ---- ------- ---- + +To add functionality, TECO-C is sensitive to bits in an extra mode control +flag in addition to the standard ones. Bits in the EZ mode control flag are +used in different ways by different operating systems. Under Unix, bits in +the flag have the following meanings: + + 1 Mark Henderson, who did much of the Unix port, likes the way + VAX/VMS keeps versions of files. VMS appends a semicolon followed + by a version number to files, and has the PURGE command to clean + out old versions of files. If this bit is off, TECO-C will handle + file version numbers, appending the appropriate version number to + file names. Mark supplied a "purge" program (distributed with TECO-C) + for users of this feature. Setting this flag turns off the feature, + to make TECO-C function as expected by the average Unix user. This + flag is set by default. + + 8 I don't know what this flag does. It only makes sense when TECO-C + is compiled with CURSES support. + + 16 If set, when it's time to beep, use an audio beep, and if it fails, + then try a video flash. If clear, try a video flash, and if it + fails, use an audio beep. This bit works only if TECO-C was compiled + with CURSES support. This bit is off by default. + + 32 If set, and split screen scrolling mode is on (see the 7:W command), + TECO-C puts a line between the upper and lower scrolling regions. + If off, don't display a line. This bit works only if TECO-C was + compiled with CURSES support. This bit is off by default. + + 128 If set, don't stop on form feeds when reading. If clear, a form + fed in the input stream stops the read (the standard TECO style). + This bit is off by default. + + 256 If set, use Unix-style newline terminators. This means when files + are read in, carriage-returns are not added to the end of lines, + and when the user types the RETURN key, only a newline is entered + into the command line (usually a carriage-return/line-feed pair is + entered). Old macros (and old TECO users) may get confused if this + bit is set, but it's required if CURSES support is compiled into + TECO-C. + + 2048 If set, use a bottom-tee symbol instead of a diamond to indicate + the end-of-buffer. This bit works only if TECO-C was compiled with + CURSES support. This bit is off by default. + + 8192 If set, don't show CR in SCROLL mode (like standard TECO). If clear, + show CR (a graphics character indicating a carriage return) when in + SCROLL mode. This bit works only if TECO-C was compiled with CURSES + support. This bit is on by default. + + +Filename Memory +-------- ------ + +TECO tries to remember the last file edited by TECO, so that after you've +edited a file once, you can re-edit without having to type the file name +on the command line. TECO-C implements this under Unix by writing and reading +files named /tmp/tecoxxx.tmp, where "xxx" is the process id of the parent +process. + + +NOTE: There is another TECO in C, written by Matt Fichtenbaum, which +runs under Unix. It is part of the DECUS TECO Collection. Contact Pete +Siemsen at the above address for a copy. + +########################################################################### + U N D E R A M I G A D O S + +To compile and link: see makefile.ami, (note: it needs tecoc.lnk) + +Comments from the author of the Amiga code: + + I've completed my TECOC port to the Amiga. It has been tested on an + Amiga 1000 under AmigaDOS 1.3.2. My system configuration is: + + 68000 microprocessor + 2.5 megs memory + 80 meg hard drive + Old Amiga chip set + SAS Institute C for the Amiga version 5.10 + + TECO-C runs in the CLI window it was started from, and it should run + over a terminal hooked to an Amiga serial port as well. + + Adding 'W' command stuff would probably best be done by one of the + termcap ports to the Amiga, however, TECO would have to handle + SIGWINCH-like events, unless it is modified to open it's own window of + a particular size without a resizing gadget. It wouldn't be to hard to + write a terminal driver for Amiga windows using hard-coded escape + sequences either, but then that would lose over a serial port. + +EzFlag +------ + +The EZ flag is system-dependent. Under AmigaDOS, bits in the flag have the +following meanings: + + 128 If set, don't stop on form feeds when reading. If clear, a form + fed in the input stream stops the read (the standard TECO style). + This bit os off by default. + + 256 If set, use Unix-style newline terminators. This means when files + are read in, carriage-returns are not added to the end of lines, + and when the user types the RETURN key, only a newline is entered + into the command line (usually a carriage-return/line-feed pair is + entered). Old macros (and old TECO users) may get confused if this + bit is set, but it's required if CURSES support is compiled into + TECO-C. + + + + +########################################################################### + F I L E S + + + aareadme.txt this readme file + baksrc.c backwards search + bldstr.c build a string with string build constructs + change.tec change macro squished + change.tes change macro source. this macro allows you to + replace one string with another in a group of + files using match constructs. + changes.txt contains teco-c release notes starting from + version 1.00 (TVERSION = 100) + chmacs.h ctype.h for teco-c + clenup.c clean up before exiting teco-c + clpars.h command line parsing macro, created by genclp.c + clpars.tec command line parsing macro squished + clpars.tes command line parsing macro source + cmatch.c match character with match construct + date.tec date macro squished + date.tes date macro source. this macro displays the + date and time. + dchars.h define identifiers for control characters + deferr.h define identifiers for error messages + defext.h EXTERN decarations for global variables + detab.tec de-tabify macro squished + detab.tes de-tabify macro source. this macro converts + tabs to spaces + dir.tec "display directory" macro, in squished form + dir.tes "display directory" macro source. This macro simply + displays the directory. a wildcarded filename + in the edit buffer can control what is displayed. + docjr.c code common to ExeC, ExeJ, and ExeR + doeves.c work code for EV and ES + doflag.c changes a mode control flag (ED,EH,ES,ET,EU,EV,^X) + dscren.h terminal types for 0:W command + echoit.c display character in its printable form + err.c display teco-c's error messages + exea.c execute A + exeats.c execute at-sign @ + exeb.c execute B + exebar.c execute | + exebsl.c execute backslash \ + exec.c execute C + execcc.c execute control-caret ^^ + execln.c execute colon modifiers : and :: + execom.c execute comma , + execrt.c execute caret ^ + execst.c execute a TECO command string + execta.c execute ^A + exectc.c execute ^C + exectd.c execute ^D + execte.c execute ^E + execti.c execute ^I + exectl.c execute ^L + exectn.c execute ^N + execto.c execute ^O + exectp.c execute ^P + exectq.c execute ^Q + exectr.c execute ^R + exects.c execute ^S + exectt.c execute ^T + exectu.c execute ^U + exectv.c execute ^V + exectw.c execute ^W + exectx.c execute ^X + execty.c execute ^Y + exectz.c execute ^Z + exed.c execute D + exedgt.c execute digit (0-9) + exedot.c execute dot . + exedqu.c execute double quote " + exee.c execute E + exeequ.c execute equals =, ==, and === + exeesc.c execute escape + exeexc.c execute exclamation point ! + exeey.c execute EY + exef.c execute F + exefb.c execute FB + exeg.c execute G + exegtr.c execute greater than sign > + exeh.c execute H + exei.c execute I + exeill.c "execute" illegal command + exej.c execute J + exek.c execute K + exel.c execute L + exelbr.c execute left-bracket [ + exelst.c execute less than sign < + exem.c execute M + exen.c execute N + exenul.c execute null ^@ + exenyi.c "execute" not-yet-implemented command + exeo.c execute O + exeopr.c execute operator (+,-,(,#,/,&,^_,*) + exep.c execute P (see singlp.c) + exeprc.c execute percent sign % + exepw.c execute PW + exeq.c execute Q + exeqes.c execute question mark ? + exer.c execute R + exerbr.c execute right bracket ] + exertp.c execute right paren ) + exes.c execute S + exescl.c execute semicolon ; + exet.c execute T + exeu.c execute U + exeund.c execute underscore _ + exeusc.c execute unit separator character ^_ + exev.c execute V + exew.c execute W + exex.c execute X + exey.c execute Y + exez.c execute Z + findes.c find end of string + findqr.c find q-register name + flowec.c flow to end of conditional + flowee.c flow to else part of conditional + flowel.c flow to end of loop + fmtmac.tec PDP-11 .MAC formatter squished + fmtmac.tes PDP-11 .MAC formatter source. this macro does + case formatting for PDP-11 macro (.MAC) source files + format.tec FORTRAN formatter squished + format.tes FORTRAN formatter source. formats the first part of + a FORTRAN source line. + genclp.c generates the command line parsing macro in clpars.h + getara.c get area in edit buffer an "m,n" argument defines + getnma.c get numeric argument off expression stack + inccbp.c increments command buffer pointer + init.c teco-c initializatin routines + insstr.c insert string into edit buffer + isradx.c is digit within current radix? + ln2chr.c convert line-number to character-number (^Q) + lowcase.tec convert edit buffer to lowercase macro, see upcase.tec + makdbf.c make digit buffer, binary to ascii in current radix + makefile.ami AmigaDOS make file + makefile.cct CodeCenter under SunOS + makefile.dg System V Unix make file (works on Data General Aviion) + makefile.sun SunOS make file + makefile.tc Turbo C make file (MS-DOS) + makefile.ulx Ultrix make file + maketeco.bat MS-DOS batch file to make teco. this is probably how + the temdos.exe executable file was made. + makprnt.tec make printable macro squished + makprnt.tes make printable macro squished. this macro makes a + string with embedded control characters printable + makrom.c make room in Q-register for new text + mung.bat MS-DOS batch to execute a teco macro from command line + pg.mem a programmer's guide. it may be useful to anyone + fixing bugs, adding features, or porting teco-c to + a new environment. + pkzip.rsp a PKZIP response file used to build TECOC.ZIP archive + popmac.c pop macro environment off macro stack + problems.txt contains notes about bugs and ideas + pshmac.c push current macro environment on macro stack + pushex.c push expression onto stack, try to reduce it + rdline.c read a line + rdpage.c read a page + readcs.c read command string + replac.c code for search and replace commands + search.c code for most of the search comamnds + search.tec search macro squished + search.tes search macro source. this macro finds a string in + a group of files using teco match constructs + singlp.c does a single P command + skpcmd.c skip over current command in command bufer + squ.bat MS-DOS batch file to run squ.tec w/standard options + squ.tec squish macro squished + squ.tes squish macro source. this macro takes a teco macro + source file and makes it as small and as fast (and + as unreadable) as possible + srclop.c search loop, handles loop arguments for search + sserch.c do a simple search + sub.tec ? + tabort.c terminate teco-c + tctlib.rsp a Turbo C TLIB response file used by makefile.tc + teco.bat MS-DOS batch file to run teco-c + teco.doc Standard TECO documentation from DECUS + teco.tes teco initialization file + tecoc.c the main source module, contains all the definitions + of system-independent global variables, as well as + comments explaining what they are. + tecoc.exe the teco-c executable for VMS + tecoc.h defines structures, general identifiers, and + the in-line debugging scheme. + tecoc.lnk link file needed under AmigaDOS (see makefile.ami) + tecoin.tes teco initialization file + temsdos.exe the teco-c executable for MS-DOS + tst.bat MS-DOS batch file to run the test macros + tst.com VMS command procedure to run the test macros + tstbsl.tec -- + tstcss.tec | + tstequ.tec | these macros contain code which tests some + tsto.tec | aspects of teco-c + tstpw.tec | + tstqr.tec | + tstsrc.tec -- + typbuf.c types a buffer on the screen, converting unprintable + characters to printable as nescessary. + type.tec type a file macro squished + type.tes type a file macro source. this macro apparently + types a file on the console with all kinds of + wonderful options. + typest.c types the erroneous command string for errors + uminus.c unary minus (converts -C to -1C) + unsqu.tec unsquish macro squished + unsqu.tes unsquish macro source. this macro does some simple + formatting of a squished teco macro to make it more + readable (like indenting) + upcase.tec convert edit buffer to uppercase macro, see lowcase.tec + vrbmsg.h verbose forms of teco error messages + vtedit.tec vtedit macro squished + vtedit.tes vtedit macro source. humongous screen editor macro. + note: this macro does NOT run under teco-c. + wchart.txt contains a wall chart of TECO commands + wrpage.c write a page + zamiga.c AmigaDOS system dependent code. + zfirst.c dummy module used if CHECKSUM_CODE is TRUE in zport.h + zfrsrc.c do a forward search using VAX SCANC instruction + zmsdos.c MS-DOS system dependant code + zport.h portability header file. + zunix.c SunOS (Unix) system dependant code + zunkn.c UNKNOWN system dependant code (function stubs) + zvms.c VAX/VMS system dependant code + + + The W command does not work, but the EXEW.C file contains code +to tell you what the command would have done if it had been executed. I used +this to play with executing VTEDIT.TEC under TECOC in order to find bugs. + + I maintain the DECUS TECO Collection, a bunch of stuff relating to +TECO. It includes sources for DEC's TECO-11 v39, three TECOs written in C, +including ones for VAX/VMS, MS-DOS, SunOS (Unix) and Ultrix, the current +Standard TECO manual, two EMACs-like macro packages and LOTS of macros. + + I you have something that you feel should be included in this +collection, or if you would like to improve the software, please contact +me at the above address. + + +Pete Siemsen diff --git a/doc/fixes.txt b/doc/fixes.txt new file mode 100644 index 0000000..dd7b758 --- /dev/null +++ b/doc/fixes.txt @@ -0,0 +1,118 @@ +FINDQR.C: + +Cast is needed to get it to compile under Borland C. + +CLPARS.TES: + +If no EGMEM or if EGMEM and filename starts with a $, then CLPARS +gets totally hosed. Major hacking was needed to fix. + +ZMSDOS.C, EXEE.C TECOC.H: + +Backup file is created for EW and other occasions. It should only be +created with the EB command (or TECOC TECO on the command line). + +Added BOOLEAN Backup argument to ZMSDOS:ZOpOut. Only make backup if +Backup==TRUE. Argument is passed through in EXEE:OpnOut. In +EXEE:ExeEB, value passed is TRUE. In EXEE:ExeEW and EXEE:ExeEPr the +value passed is False. When file is closed in ZMSDOS:ZOClos then if +no backup was wanted we won't create one. + +EXEM.C: + +Colon modified macros pass the colon into the internal command. This +prevented the tstqr.tec test file from working. + +The fix is to clear the colon flag if it is set within ExeM(). + +EXEM.C: + +Execution of local macros caused new set of local q registers to be +generated. + +The fix is to not generate new macro set if macro is local. + +SRCLOP.C: + +n,mFB command did not work unless at gap. Fixed. + +SEARCH.C: + +ES now ignored if in macro or loop + +WCHART.TXT: + +Changed FB and FC as "implemented" Also G* and G_ as implemented. + +ZMSDOS.C: CLPARS.TES: + +Added test for ED_FF flag (in EZ??) to ignore form feeds. Then change +clpars.tes so /NOPAGE will set it *before* yanking. + +ZMSDOS.C TECOC.H EXEE.C: + +ZDoCmd used the file name buffer for the command, while ExeEG keeps the +command in a local buffer. This prevents EG from working in any version! + +I added arguments to ZDoCmd to pass the command string. + +ZMSDOS.C + +The TEC$LIBRARY environment variable was not being examined for the EI +command, unlike at least the UNIX version. This basically made TEC$LIBARY +worthless since its only other use was during initializaton for video +support, which doesn't exist in MSDOS. So I fixed it. + + +ZMSDOS.C + +Tecoc has the ugly habit of allowing you to edit a readonly file, +only to die on you when you finish. It's easy enough to check that +the output file is writable first. The problem is in ZOpOut(). + +Because MSDOS TECOC creates the temp file in the current directory, +any attempt to EW or EB a file in another drive will cause failure +when the rename is attempted. In these cases the file must be copied. +ZOClos() is the culprit. + +I added a "fastcopy" function, much like what was done in zunix.c, +but quite a bit simpler. The OS/2 version will need this since OS/2 +prefers copying over renaming to preserve file extended attributes +and PM references. The handling in the OS/2 code is slightly +different in that the only file that ever gets deleted is the +temporary file. When this code is included in the MSDOS version, it +takes too much space for compact model, so I don't update the time stamp +(that allows it to squeek by). + +Along the same lines, Tecoc will create a backup file in the wrong +directory if the file name has an explicit path and has a "." in one +of the directory names. ZOClos() is the culprit, again. + +I added the "% Superseding existing file" warning message. Why wasn't +it there?? + +CLPARS.TES + +After the attempt to do an EB fails, clpars assumed the failure was +caused by the input file not being found. Added new code to attempt +to open the file via ER - if that succeeds, prints message that file +is being opened read-only. + +Added handling for a /NORENAME switch, needed by OS/2. I also added +code to remove quotes in a quoted file name string if OS/2. Reason: +file names can have embedded spaces, yet quotes are not allowed. + +I couldn't see any reason to strip spaces from the filename saved +in "memory" since the name had already been processed. This was causing +a problem with the OS/2 version since I stripped the quotes. + +I removed the restriction of the +nnn commandline argument so it +would work with MS/DOS and OS/2. Why limit it to UNIX? + +Clpars leaves the macro .T around after completion (remember -- it's +not called as a macro if USE_ANSI_CLPARS, which makes it a top level +local macro), and also leaves non-zero values in qy, q8, q.l, q4, and +possibly q.1. Fixed. However I don't understand the reasoning for +*saving* q registers during execution of clpars since there is +nothing in them at the start of the macro execution. + diff --git a/doc/prog-guide.txt b/doc/prog-guide.txt new file mode 100644 index 0000000..f462c9c --- /dev/null +++ b/doc/prog-guide.txt @@ -0,0 +1,856 @@ + + + + TECO-C + + Programmer's Guide + (last updated February 18, 1991 to reflect TECO-C version 140) + + + +1 INTRODUCTION + + These notes apply to TECOC version 135, which runs under VAX/VMS, +MS-DOS, and Unix (SunOS, which is BSD). See file AAREADME.TXT for the +specifics of operating system and compilers which have been used. + + TECO-C is meant to be a complete implementation of TECO as defined by +the Standard TECO User's Guide and Language Reference Manual, (in file +TECO.DOC). It was written so that the author could move to many machines +without knowing many editors. + + + +2 COMPILING AND LINKING + + Conditional compilation directives are used to build TECO-C correctly +for different environments. Identifiers automatically defined by +the different compilers are used. Some identifiers defined in file ZPORT.H +control whether video support or extra debugging code is included. See +"VIDEO" and "DEBUGGING". Files are provided which "build" TECO-C in various +environments. See file AAREADME.TXT for details. + + + +3 RUNNING TECO-C + + When you run TECO, the command line used to invoke TECO is parsed for +an input/output file name and several optional switches. TECO-11 parses the +command line using a TECO macro imbedded in the program. TECO-C does the +same thing. Actually, the imbedded macro used to parse the command line +was stolen from TECO-11. I commented it and then modified it to repair +minor inconsistencies. Use of TECO-11's macro makes TECO-C invocation +identical to TECO-11's, even responding to "make love" with "Not war?". + + The macro is in file CLPARS.TES. The compressed version (no comments +or whitespace) is in file CLPARS.TEC. The GENCLP program converts +CLPARS.TEC into CLPARS.H, an include file suitable for compiling into +TECO-C. + + + +4 CODE CONVENTIONS + + The code is not modular. Communication between almost all functions +is through global variables, not argument lists. There is a reason: the +nature of the basic parsing algorithm is to use the characters in the +command string as indices into a table of functions. This makes for very +fast command parsing, but it means that all the functions have to modify + + Page 2 + + +global values, because no arguments are passed in. In other words, there +were going to be 130 or so un-modular functions anyway, so I gave up on +modularity. This explanation does not explain some of the complications in +the search code, like the global variable SrcTyp. Oh, well. + + Here's a brief list of some of the conventions followed by the code: + + 1. TECO-C is portable, so some convention was needed to separate + portable code from system-dependent code. There is one file + containing the system-dependent code for each platform TECO-C + supports. These files have names that start with a "Z": ZVMS.C, + ZMSDOS.C and ZUNIX.C. + + All the system-dependent functions in those files start with a + "Z". For example, the function that allocates memory is called + ZAlloc. A VMS version of ZAlloc can be found in ZVMS.C, and an + MS-DOS version can be found in ZMSDOS.C. + + An extra file called ZUNKN.C exists to help efforts to port TECO-C + to a new environment. This file contains stubs for all the + system-dependent functions. + + 2. All system-independent global variables are declared + alphabetically in file TECOC.C. They are defined in DEFEXT.H, + which is included by all modules. + + 3. File TECOC.H contains the "global" definitions, including those + for most structures. + + 4. Variables and functions are defined using the portability + identifiers defined in the ZPORT.H file. Functions which do not + return a value are defined as VOID. TECO-C should compile and + link on different machines by changing only the environment + definitions in the ZPORT.H file. + + 5. At one time, every function was in a file with the same name + as the function. This made it easy to find the code for a + function. The problem was that some groups of functions use data + not needed by the other functions. This was especially true of + the system-dependent functions. Also, some functions were called + only by one other function, so it made sense for them to be in the + same module as the caller and be made "static". So now, most + functions are in a file named the same as the function, with the + following exceptions: + + 1. All the "Z" functions are in are in the "Z" file for the given + system. + + 2. The conditionally-compiled functions (ZCpyBl in ZINIT.C, the + "Dbg" functions at the bottom of TECOC.C, the "v" functions in + EXEW.C) aren't in their own files. If they were, then the + command procedures/makefiles that compile the files would need + to contain logic to conditionally compile the files. + + Page 3 + + + 3. The functions for the "E" and "F" commands are in EXEE.C and + EXEF.C, respectively. So if you want to find function ExeEX, + don't look for a file named EXEEX.C. + + + 6. Symbols are 6 characters long or less. The way I remember it, + this was caused by the first system I wrote TECOC for: CP/M-68k, + which had a limit of 8 characters for file names. The last two + characters had to be ".C", so 6 characters were left for the file + name. Since the file name was the same as the function it + contained, functions were limited to 6 characters in length. When + I saw how nicely the function declarations looked (they fit in one + tab slot), I used 6 characters for other symbols too. + + I've since been told that CP/M-68k has 8-character file names + followed by 3-character file types, so CP/M-68k can't be blamed. + So shoot me. + + This standard has prevented problems from occurring with compilers + that don't support very many characters of uniqueness. + + In order to make up for the resultant cryptic names, upper and + lower case are mixed. An uppercase letter indicates a new word. + For example, "EBfEnd" stands for "Edit Buffer End". If you need + to know what a variable name means, look at the definition of the + variable in DEFEXT.H. The expanded version of the abbreviated + name appears in the comment on the same line as the variable + definition. A detailed description can be found with the + declaration of the variable in TECOC.C. + + The limit of 6 letters in variable names is relaxed in + system-dependent code. + + 7. Variable and function names follow patterns where possible. For + instance, "EBfBeg" and "EBfEnd" are the beginning and end of the + edit buffer. If you see a variable named "BBfBeg", you can assume + that it is the beginning of some other buffer, and that a "BBfEnd" + exists which is the end of that buffer. + + 8. Character strings are usually represented in C by a pointer to a + sequences of bytes terminated with a null character. I didn't do + that in TECO-C because I thought it was too inefficient. To get + the length of a string, you have to count characters. Most + strings in TECO-C are therefore represented by two pointers, on to + the first character and one to the character following the last + character. With this representation, it's easy to add characters + to a string and trivial to get the length. + + 9. Each file has a consistent format, which is: + + 1. a comment describing the function + 2. include directives + 3. the function declaration + + Page 4 + + + 4. local variable definitions, in alphabetical order + 5. code + + + + +5 TOP LEVEL EXECUTION AND COMMAND PARSING + + The top level code for TECO-C is contained in file TECOC.C. It is +very simple: after initializing, a loop is entered which reads a command +string from the user, executes it, and loops back to read another command +string. If the user executes a command which causes TECO-C to exit, the +program is exited directly via a call to the TAbort function. TECO-C never +exits by "falling out the bottom" of the main function. + + After a command string is read, the ExeCSt function is called to +execute the command string. ExeCSt contains the top-level parsing code. +The parse is trivial: each command character is used as an index into a +table of functions. The table contains one entry for each of the 128 +possible characters. Each function is responsible for "consuming" its +command so that when it returns, the command string pointer points to the +next command. + + + +5.1 Error Handling + + When an error is detected, an error message is displayed at the point +that the error is detected, and the function in which the error was +detected returns a FAILURE status to its caller. Almost always, the caller +returns a FAILURE status to it's caller, which returns a FAILURE status to +it's caller, etc. When a FAILURE status is returned to the main command +string parser, parsing of the command string stops and the user is prompted +for a new command string. + + This style tends to cause all function calls to follow the same form, +which is + + if (function() == FAILURE) + return(FAILURE); + + Things get more complicated in the system-dependent code (in the files +with names that start with a "Z"). I extended TECO's error reporting +slightly to allow the user to see the operating system's reason for an +error, as this is often useful. For example, under VAX/VMS there are many +reasons why an attempt to create an output file might fail. They include: +errors in file name syntax, destination directory non-existence, file +protection violations or disk quota violation. In order to supply enough +information to the user, TECO-C outputs multiple-line error messages when a +system error occurs. + + Multiple-line error messages contain one line that describes the +operating system's perception of the error and one line that describe's +TECO's perception of the error. For instance, if a user of VAX/VMS does a +"EW[abc]test.txt$$" command when the directory [abc] does not exist, the + + Page 5 + + +error message generated by TECO-C is: + + ?SYS %RMS-F-DNF, directory not found + ?UFO unable to open file "[abc]test.txt" for output + + System errors are therefore reported in a system-dependent fashion, +using whatever messages the operating system can supply. Under VAX/VMS, +the system service $GETMSG provides human-readable messages that TECO-C can +use in the "SYS" part of the error message. Under UNIX, syserrlist[error] +is a pointer to these messages. + + There is another way in which error reporting in the system-dependent +code is tricky. Under VAX/VMS, some system calls may return a code that is +"successful" but contains extra information. For instance, when a user has +set his directories so that only a limited number of versions of a file can +exist, RMS will automatically purge the oldest version of the file when the +user creates a file. This only happens if the newly created file would +cause too many versions of the file to exist. When this happens, the VMS +service returns a FILEPURGED status, which is successful. TECO-C informs +the user about these things by displaying the message in brackets. + + + +5.2 Command Modifiers (CmdMod) + + Command parsing is complicated by command modifiers and numeric +arguments, which may precede some commands. These are implemented in a way +that maintains the basic "jump table" idea. For instance, when an at-sign +(@) modifier is encountered in a command string, the at-sign command +function (ExeAtS) is called. The only thing ExeAtS does is set a flag +indicating that an at-sign has been encountered. Commands which are +affected by an at-sign modifier check this flag and behave accordingly. + + The flags which indicate command modifiers are contained in global +variable CmdMod. A bit in CmdMod is reserved for each command modifier. +The modifiers are "@", ":" and "::". Of course, once the flag has been +set, it must be cleared. With this parsing algorithm, the only way to do +that is to make every command function explicitly reset CmdMod before a +successful return. This is not too bad: clearing all the flags in CmdMod +is done with one statement: "CmdMod = '\0';". + + For numeric arguments to commands, an expression stack is used (see +Stacks). The EstTop variable is the pointer to the top of the expression +stack. Commands which handle numeric arguments check EStTop to see if the +expression stack contains a value. + + A special case of numeric arguments is "m,n". The "m" part is +encountered and causes the value to be pushed onto the expression stack. +The comma causes the ExeCom function to move the value into a special +"m-argument" global variable (MArgmt), clear the expression stack and set +another flag in CmdMod indicating that the "m" part of an "m,n" pair is +defined. Then the "n" is encountered and pushed onto the stack. Commands +which can take "m,n" pairs check the flag in CmdMod. + + Page 6 + + + To summarize, CmdMod and EStTop are variables which describe the +context of a command. Each command function tests these variables to see +if it was preceded by modifiers or numbers. For this to work, it is +important that the expression stack and the flags in CmdMod are cleared at +the right times. It is the responsibility of each command function to +leave CmdMod and EStTop with the proper values before successfully +returning. The rules are: + + 1. If the command function is returning FAILURE, don't worry about + clearing CmdMod or EStTop. They will be cleared before the next + command string is executed. + + 2. If the command function leaves a value on the expression stack, do + not clear EStTop before returning SUCCESS. If the command calls + GetNmA, do not clear EStTop, as GetNmA does it for you. + Otherwise, clear EStTop before returning SUCCESS. + + 3. Clear CmdMod unless the command function sets flags or needs to + leave them alone. ExeDgt, for example, handles digit strings and + doesn't clear CmdMod because the MARGIS bit may be set. + + + + +6 SEARCHING + + The search algorithm in TECO-C is complex. The war between the desire +for a fast search and the need to handle all the features of TECO'ssearch +commands has produced code which can be a real pain to follow. This +section attempts to explain how things got the way they are. The code is +explained in a bottom-up fashion, to follow the way it evolved in the +author's twisted mind. + + The basic search idea is to scan a contiguous edit buffer for a search +string. The steps are: + + 1. Search the edit buffer for the first character in the search + string. If you reach the end of the edit buffer without matching, + the search fails. + + 2. When the first character of the search string matches a character + in the edit buffer, try to match successive characters in the + search string with the characters which follow the found character + in the edit buffer. If they all match, the search succeeds. If + one doesn't, go back to step 1. + + + This is basically what TECO-C does. The features of TECO's search +commands has buried these steps deep within some confusing code. + + The first complication is introduced by pattern matching characters. +TECO has 17 "match constructs", whiceh are indicated in the search string +by the special characters ^X, ^S, ^N and ^Ex where "x" can be several other +characters. For instance, a ^X in the search string means that any +character is to be accepted as a match in place of the ^X. Characters + + Page 7 + + +other than the match constructs represent themselves. An example: the +search string "a^Xb" contains 3 match constructs: a, ^X and b. + + TECO also supports forward or backward searching. When searching +backwards, only the search for the first match construct in the search +string is done in a backwards direction. When the character is found, the +characters following it are compared in a forward direction to the edit +buffer characters. This means that once the first match construct has been +found, a single piece of code can be used to compare successive characters +in the search string with successive characters in the edit buffer, +regardless of whether the search is forwards or backwards. + + Adding these new features, the new description of searching is: + + 1. Search the edit buffer forwards or backwards for a character which + matches the first match construct in the search string. If you + reach the end of the edit buffer without matching, the search + fails. + + 2. When the first match construct of the search string matches a + character in the edit buffer, try to match successive match + constructs in the search string with the characters which follow + the found character in the edit buffer. If they all match, the + search succeeds. If one doesn't, go back to step 1. + + + To begin a description of which routines implement the above steps, +and in order to have a reference for later discussion, the following +hierarchy chart of "who calls who" is presented. + + + + Page 8 + + + ExeEUn ExeFB ExeFC ExeFD ExeFK ExeFN ExeFS ExeFUn ExeN ExeS ExeUnd + | | | | | | | | | | | + | | | | | | | | | | | + ------------------------------------------------------------ + | + V + Search + | + V + SrcLop + | + V + SSerch + | | | + +------+ | +------+ + +---+ | | | +---+ + | V V | V V | + | ZFrSrc | BakSrc | + | | | | | | | + +---+ | | | +---+ + +------+ | +------+ + V V V + CMatch <--+ + | | + +--------+ + + + At the top are the functions that implement search commands (E_, FB, +FC, FD, FK, FN, FS, F_, N, S and _). All of these functions call the main +search function: Search. + + At the lower level are the functions which implement steps 1 and 2 +described above. ZFrSrc searches forwards in the edit buffer for +characters which match the first character in the search string. BakSrc +does the same thing, but searches backwards. SSerch calls one of these two +functions and then executes a loop which calls CMatch to compare successive +match constructs in the search string to characters following the found +character in the edit buffer. The reason that ZFrSrc, BakSrc and CMatch +call themselves is to handle some of the more esoteric match constructs. + + Case dependence in TECO is controlled by the search mode flag (see the +^X command). The variable SMFlag holds the value of the search mode flag, +and is used by ZFrSrc, BakSrc and CMatch. + + One final point to help confuse things: ZFrSrc is system-dependent. +It contains a VAX/VMS-specific version which uses the LIB$SCANC run-time +library routine to access the SCANC instruction. The SCANC instruction +looks like it was designed to handle TECO's match constructs. I couldn't +resist using it, but it was a mistake, as it needlessly complicates an +already messy algorithm. I have decided to remove the VMS-specific code +some time in the future. + + Further complications of the search algorithm arise because of the +following capabilities of TECO searches: + + Page 9 + + + 1. If there is no text argument, use the previous search argument. + + 2. If colon modified, return success/failure and no error message + + 3. If the search fails and we're in a loop and a semicolon follows + the search command, exit the loop without displaying an error + message. + + 4. Handle optional repeat counts + + 5. If the ES flag is non-zero, verify the search based on the value + of the flag. + + 6. If bit 64 of the ED flag is set, move dot by one on multiple + searches. + + 7. If bit 16 of the ED flag is set, don't move after a failing + search. + + 8. Be fast. + + + + +7 MEMORY MANAGEMENT + + 7.1 The Edit Buffer And Input Buffer + + TECO-C is based on TECO-11, but it uses a different form of edit +buffer memory management. Here's why. + + The edit buffer in TECO-11 is implemented as a continuous block of +memory. This allows rapid movement through the edit buffer (by just +maintaining a pointer to the current spot) and makes searches very +straightforward. Insertion and deletion of text is expensive, because each +insertion or deletion requires moving the text following the spot where the +insertion or deletion occurs in order to maintain a continuous block of +memory. This gets to be a real pain when a video editing capability is +added to TECO, because in video mode text is added/deleted one character at +a time very rapidly. + + TECO-C uses a edit buffer gap scheme. The edit buffer occupies a +continuous piece of memory, but there is a gap at the "current spot" in the +edit buffer. When the user moves around the edit buffer, the gap is moved +by shuffling text from one side of the gap to the other. This means that +moving around the text buffer is slower than for TECO-11's scheme, but text +insertion and deletion is very fast. Searches are still fast because most +searches start at the current spot and go forwards or backwards, so a +continuous piece of memory is searched. In the future, when some kind of +video mode is added, insertion and deletion one-character-at-a-time will be +fast using the gap scheme. + + The variables that maintain pointers to the edit buffer and the gap +within the buffer can be confusing, so here's some examples. Suppose that +10000 bytes are allocated for the edit buffer when TECO-C is initialized. + + Page 10 + + +Suppose the allocated memory starts at address 3000. + + Empty edit buffer (the gap spans the whole edit buffer): + + EBfBeg = 3000 (edit buffer beginning) + GapBeg = 3000 (gap beginning) + GapEnd = 13000 (gap end) + EBfEnd = 13000 (edit buffer end) + + Buffer contains "test", character pointer is before the first 't': + + EBfBeg = 3000 (edit buffer beginning) + GapBeg = 3000 (gap beginning) + GapEnd = 12996 (gap end) + 12997 't' + 12998 'e' + 12999 's' + EBfEnd = 13000 't' (edit buffer end) + + + Buffer contains "test", character pointer is after the last 't': + + EBfBeg = 3000 't' (edit buffer beginning) + 3001 'e' + 3002 's' + 3003 't' + GapBeg = 3004 (gap beginning) + GapEnd = 13000 (gap end) + EBfEnd = 13000 (edit buffer end) + + + Buffer contains "test", character pointer is after the 'e': + + EBfBeg = 3000 't' (edit buffer beginning) + 3001 'e' + GapBeg = 3002 (gap beginning) + GapEnd = 12998 (gap end) + 12999 's' + EBfEnd = 13000 't' (edit buffer end) + + When an insertion command is executed, the text is inserted starting +at GapBeg. When a deletion command is executed, GapEnd is incremented for +a forward delete or GapBeg is decremented for a backwards delete. When the +character pointer is moved forwards, the gap is moved forwards by copying +text from the end of the gap to the beginning. When the character pointer +is moved backwards, the gap is moved backwards by copying text from the the +area just before the gap to the area at the end of the gap. + + There are a few messy cases, such as when a bounded search is executed +and the bounded text area includes the edit buffer gap. In this case, the +gap is temporarily moved so that the search can proceed over a continuous +memory area. + + Page 11 + + + In order to confuse things a little, TECO-C has one addition to the +basic edit buffer gap management. Following the end of the edit buffer +(EBfEnd) is the current input stream buffer. Since file input commands +always cause text to be appended to the end of the edit buffer, this is +natural. Thus, no input buffer is needed: text is input directly into the +edit buffer. This makes the code a little confusing, but it avoids the +problem of having an input buffer. When you have an input buffer, you have +to deal with the question of how large the buffer should be and what to do +with it when it's too small. this scheme is fast and and saves some +memory. (see File Input) + + + +7.2 Q-registers + + Q-registers have two parts: a numeric part and a text part. Each +q-register is represented by a structure containing three fields: one to +hold the numeric part and two to point to the beginning and end of the +memory holding the text part. If the text part of the q-register is empty, +then the pointer to the beginning of the text is NULL. + + There are 36 global q-registers, one for each letter of the alphabet +and 1 for each digit from 0 to 9. These q-registers are accessible from +any macro level. There are 36 local q-registers for each macro level. The +names for local q-registers are preceded by a period. Thus the command +"1xa" inserts a line into global q-register "a", while the command "1x.a" +inserts a line into local q-register ".a". Storage for the data structure +defining local q-registers is not allocated until a local q-register is +first used. This saves space and time, because local q-registers are +rarely used, and doing things this way avoids allocating and freeing memory +every time a macro is executed. + + + +8 STACKS + + 8.1 Expression Stack + + An expression stack is used to parse TECO's expressions. Consider the +command string QA+50=$$. When the command string is executed, the value of +QA is pushed on the expression stack, then the operator "+" is pushed on +the expression stack, and then the value "50" is pushed on the expression +stack. Whenever a full expression that can be reduced is on the expression +stack, it is reduced. For the above example, the stack is reduced when the +value "50" is pushed. + + The expression stack is implemented in the following variables: + + EStack the stack itself, containing saved operators and operands + EStTop index of the top element in EStack + EStBot index of the current "bottom" of the stack in EStack + + The "bottom" of the expression stack can change because an expression +can include a macro invocation. For example, the command QA+M3=$$ causes +the value of "QA" to be pushed on the expression stack, then the "+" is + + Page 12 + + +pushed, and then the macro contained in q-register 3 is executed. The +macro in q-register 3 returns a value to be used in the expression. When +the macro is entered, a new expression stack "bottom" is established. This +allows the macro to have a "local" expression stack bottom while +maintaining the stack outside the macro. + + + +8.2 Loop Stack + + The loop stack contains the loop count and the address of the first +command in the loop. For example, in the command 5$$, the loop +stack contains the loop count (5) and the address of the first command in +the loop (F). Whenever the end-of-loop character (>) is encountered, the +loop count is decremented. If the loop count is still greater than zero +after it has been decremented, then the command string pointer is reset to +point to the first character in the loop (F). + + The loop stack is implemented in the following variables: + + LStack the stack itself, containing saved counts and addresses + LStTop index of the top element in LStack + LStBot index of the current "bottom" of the stack in LStack + + The loop stack needs a "floating" bottom for the same reason that the +expression stack needs one: macros. Consider the command string +4$$. When the "<" in is encountered, the loop count (4) and the +address of the first character in the loop (S) are placed on the loop +stack. Command execution continues, and the "M7" command is encountered. +Suppose that q-register 7 contains the erroneous command string 10>DL>$$. +When the ">" command is encountered in the macro, TECO expects the loop +stack to contain a loop count and an address for the first character in the +loop. In this example, there is no matching "<" command in the macro which +would have set up the loop stack. It would be very bad if TECO were to +think that the loop count was 4 and the first command in the loop was "S". +In this situation, what TECO should do is generate the error message "BNI > +not in iteration". In order to implement this, the variable LStBot is +adjusted each time a macro is entered or exited. LStBot represents the +bottom of the loop stack for the current macro level. + + + +8.3 Macro Stack + + The macro stack is used to preserve context each time a macro is +entered. All important values are pushed onto the stack before a macro is +entered and popped off the stack when the macro is exited. The macro stack +is also used by the EI command, which means it's used when executing +initialization files and mung files. + + + +9 HELP + + This section discusses on-line HELP, which is available only under + + Page 13 + + +VAX/VMS. + + The HELP command is not documented in the TECO manual distributed by +DEC., even though it is supported in TECO-11 and TECO-32. To get help, +simply type "HELP" followed by a carriage return. HELP is the only TECO +command that is not terminated by double escapes. + + Help in TECOC is different than help in TECO-11. In TECO-C, +interactive help mode is entered, so that a user can browse through a help +tree, as he can from DCL. In TECO-C, access is provided to only two +libraries: the library specific to TECO-C (pointed to by logical name +TEC$INIT) and the system help library. To get help on TECO-C, just say +"HELP", with or without arguments. To get help from the system library, +say "HELP/S". I find this easier to use than TECO-11's syntax. + + The help library for TECO-C is contained in file TECOC.HLB, which is +generated from TECOC.HLP, which is generated from TECOC.RNH. See file +TECOC.RNH for a description of how to do it. This help library is far +broader than the library for TECO-11, but much of it has yet to be filled +in. + + The help library is also the repository for verbose error messages, +which are displayed when the help flag (EH) is set to 3. For systems other +than VMS, the ZHelp function displays verbose text contained in static +memory (see file ZHELP.C). + + + +10 FILE INPUT + + TECO has an elegant design that allows high speed input. There are no +linked list data structures to keep track of, and most file input goes +directly to the end of the edit buffer. + + TECO-C takes advantage of this by reading normal file input directly +to the end of the edit buffer. After each input call, nothing needs to be +moved; the pointer to the end of the edit buffer is simply adjusted to +point to the end of the new record. The pointer to the end of the edit +buffer (EBfEnd) serves two purposes: it points to the end of the edit +buffer and to the beginning of the input buffer. + + A side effect of this scheme is the sharing of memory between the edit +buffer and the input buffer. When the edit buffer is empty, it can be made +smaller by shrinking the edit buffer gap in order to make the input buffer +larger. Obviously, if the edit buffer needs to be expanded, the input +buffer can suffer before more memory is actually requested from the +operating system. This is easily achieved by moving the pointer to the +"end-of-the-edit-buffer"/ "beginning-of-the-input-buffer". + + This scheme works, but provides no support for the other forms of file +input. The EP and ER$ commands provide a complete secondary input stream +which can be open at the same time as the primary stream (two input files +at once). The EI command reads and executes files containing TECO +commands, and is used to execute the initialization file, if one exists. +The EQq command, if implemented, reads the entire contents of a file + + Page 14 + + +directly into a Q-register. + + A second problem arises: on each of the open files, the quantum unit +of input is not standard. For A, Y and P commands, a form feed or +end-of-file "terminate" the read. For n:A commands, form feed, end-of-line +or end-of-file "terminate" each read. For EI commands, two escapes or +end-of-file "terminate" the read. The input code must "save" the portion +of an input record following a special character and yield the saved text +when the next command for the file is executed. + + The scheme used in TECO-C is to read text from the current input +stream directly to the end of the edit buffer. When the input stream is +switched via a EP or ER$ command, the obvious switching of file descriptors +happens, and any text that's "leftover" from the last read is explicitly +saved elsewhere. Note that this happens VERY rarely, so a malloc/free is +acceptable. + + For EI and EQq commands, the input memory following the edit buffer is +used as a temporary input buffer. After the file is read, the text is +copied to a Q-register in the case of EQq and to a separate buffer in the +case of EI. + + + +11 VIDEO + + As of 18-Feb-1991, TECO-C supports video only under Unix. The code +was written by Mark Henderson, using the CURSES package. See file +VIDEO.TXT for a discussion of how it works. + + + +12 PORTABILITY + + TECO-C was written with portability in mind. The first development +machine was "minimal": a SAGE IV (68000) running CP/M-68k. In that +environment, there was no "make" utility. + + Initially, the system-independent code (files that don't start with a +"Z") had absolutely no calls to standard C runtime functions. This was +because I had several problems with the "standard" functions not being +"standard" on different machines. With the onset of ANSI C I've grown less +timid, but the main code still references almost no standard functions. +This is less of a limitation than you might think: TECO-C doesn't use +null-terminated strings. It also doesn't use unions, floating point or bit +fields. + + + +13 PORTING TO A NEW ENVIRONMENT + + + 1. Move the source code to the target machine. + + Page 15 + + + 2. Inspect file ZPORT.H. You need to select the compiler you want + the code compiled for. For instance, if you are porting to a Unix + system, then fix ZPORT.H so that the unix identifier is defined + (it is usually defined by default by the compiler). If your + compiler is nothing like anything supported by ZPORT.H, then set + the UNKNOWN identifier. + + 3. Compile and link. See file AAREADME.TXT for descriptions of how + TECO-C is built in supported environments, and steal like mad. + The problem here is that you need a "Z" file for your environment, + containing all the "Z" functions needed by TECO-C. The easiest + thing to do is copy ZUNKN.C to your own "Z" file and link against + that. For instance, if I ever port TECO-C to a Macintosh, I'll + copy ZUNKN.C to ZMAC.C. + + 4. Fix things so the compile/link is successful. If you have + compiled with UNKNOWN set, you should get an executable file that + displays a message and dies when the first system-dependent + function is called. The strategy is to fix that function (often + by stealing from the code for other operating systems), relink and + deal with the next message until you have something that works. + Functions should be implemented in roughly the following order: + ZInit, ZTrmnl, ZExit, ZDspCh, ZAlloc, ZRaloc, ZFree, ZChin. This + will give you a TECO with everything but file I/O. You can run + it, add text to the edit buffer, delete text, search, use + expressions and the = sign command (a calculator). Then do file + input: ZOpInp, ZRdLin, ZIClos. Then do file output: ZOpout, + ZWrBfr, ZOClos, ZOClDe. Use the test macros (*tst*.tec) to test + how everything works (see Testing). + + + + +14 TESTING + + Testing of TECO-C is performed by executing macros. The macros are +contained in files named TSTxxx.TEC, where XXX is some kind of indication +as to what is tested. For instance, TSTQR.TEC tests q-registers. The test +macros do not test all the functions provided by TECO. They were +originally used to verify that TECO-C performs exactly the same as TECO-11 +under the VMS operating system. When I needed to test a chunk of code, I +sometimes did it the right way and wrote a macro. + + + +15 DEBUGGING + + A debugging system (very ugly, very useful) is imbedded within the +code. It is conditionally complied into the code by turning on or off an +identifier (DEBUGGING) defined in the TECOC.H file. When debugging code is +compiled in, you can access it using the ^P command, which is not used by +regular TECO. The ^P command with no argument will display help about how +to use ^P. + + Page 16 + + + If you are working under VMS, it sometimes helps to compare the +execution of TECO-C with TECO-11. Put a test command string into a file. +Use DEFINE/USER_MODE to redirect the output of TECO-C to a file and execute +the macro with TECO-C. Then do the same thing with TECO-11. Use the +DIFFERENCES command to compare the two output files. They should be 100 +percent identical. diff --git a/doc/readme.1st b/doc/readme.1st new file mode 100644 index 0000000..ddabcc7 --- /dev/null +++ b/doc/readme.1st @@ -0,0 +1,44 @@ + TECO-C (version number 146) + Copyright 1983, 1990 by Pete Siemsen. This software is provided to +you free of charge for your own use. Use it as you see fit; if it doesn't +work, I disclaim all responsibility. You may re-distribute this software +UNCHANGED only if you include this copy-right notice. Alternatively, if +you change this software, you may re-distribute the result only if you +include BOTH this copyright notice, AND an additional notice identifying +you and indicating that you have changed the software. + This program is still under development. See file PROBLEMS.TXT for +notes I've written to myself about things to do to the program. If you +modify this code to enhance it or fix a bug, please communicate the changes +to me. My address is + Pete Siemsen + 645 Ohio Avenue #302 + Long Beach, Ca. 90814 + (213) 433-3059 (home) + (213) 740-7391 (work) + Internet: siemsen@usc.edu +[NOTE -- This is old information. Better to contact me, Tom Almy, below.] +******************************************************* +This archive contains TECO-C modified and compiled for DOS, Win32, +OS/2, and Linux (on Intel 32bit architecture). The modifications have been made by: + Tom Almy + tomalmy@aracnet.com +who is a "old time" TECO user. Not only did I port TECO-C but I also +corrected some bugs. For OS/2 modified the file backup algorithm to do +copying rather than renaming as an option. This makes it Workplace +Shell friendly. The Win32, Linux and OS/2 versions allow long file names. +Included files in this archive: +doc: +readme.1st This file +readme.txt Operating and install instructions for Linux users +wchart.txt List of all the implemented commands. +teco.doc The official teco reference. TECOC IS CLOSE TO TECO-11 IN FUNCTIONALITY +bin: +tecoc Executable +Make link to tecoc +mung link to tecoc +teco link to tecoc +Inspect link to tecoc +lib: +*.tes *.tec TECO macros +src: +Full source files for Linux version diff --git a/doc/readme.osx b/doc/readme.osx new file mode 100644 index 0000000..61b25d5 --- /dev/null +++ b/doc/readme.osx @@ -0,0 +1,171 @@ +Running TECOC on OS X + +Tecoc takes a first argument of mung, teco, or make to control its +operating mode. In this Linux version, the name of the executable is +tested to provide this first argument. Typically soft links are used +to the tecoc executable, however aliases could be used instead. The +mapping is: + +Make is tecoc make (note uppercase first letter) +teco is tecoc teco +mung is tecoc mung +inspect is tecoc teco -inspect + +The provided TAR file has these four soft links defined. Extract the +TAR file into a directory in your execution path +after making sure none of the command names already exist for other +applications. Necessary environment variables and files are described below. + +Several option switches are allowed on the TECO command line: + + -in[spect] -- Read file only, don't create an output file. + -noc[reate] -- If file doesn't exist, don't create it. + -noi[ni] -- Don't execute INI file. (valid for MAKE or MUNG as well) + -nom[emory] -- don't save filename as "last edited file" (valid for + MAKE also) + -nop[age] -- Formfeeds don't stop file reads (valid for MAKE also) + +nnn -- sets NOPAGE and positions dot to line nnn. + +The part of the switch name in the square brackets is optional. For +instance "-in" is the same as "-inspect". + +MAKE filespec + + starts tecoc to create file filespec. Does equivalent of EWfilespec$$ + +TECO filespec + + starts tecoc to edit file filespec. Does equivalent of + EBfilespec$Y$ + +TECO filespec2=filespec1 + + starts tecoc to edit filespec1, writing to filespec2. Does + equivalent of ERfilespec1$EWfilespec2$Y$$ + +TECO + + starts tecoc to edit last edited file. Filename is saved in file + named teco*.tmp in the current directory, unless overriden + (described below). + +MUNG filespec + + starts tecoc to execute filespec. Equivalent to + I$JEIfilespec$$ + + You can use "TECO @filespec " instead of MUNG. + +************** +Key Bindings + +The keys mentioned in the teco.doc file are somewhat confusing. +This should help: + + The "Esc" key, "Esc" echoes as "$", however the + teco.doc file shows it as '`'. + Type as Control-h, this isn't the "Backspace" key. + The "Backspace" key. This isn't the "Delete" key. + The "Enter" key. + Type as Control-j. + +Note that the assignments for and shown here are +swapped. can be "Backspace" and can be control-h by +clearing ET&2048, e.g. 2048,0ET + + +************** + +The Initialization File. + +Tecoc mungs (executes as teco commands) the file TECO.INI in the +current directory before processing the command line. Initialization +can be done instead by defining a TEC_INIT environment variable. The +value is either the list of teco commands to execute or a "$" followed +by the pathname of the file containing the initialization file. This +allows a single, centrally located initialization file. REMEMBER that +the "$" must be escaped, i.e. "\$" + +The initialization file can be used to make initial settings. It can +return a value, but the value setting is somewhat obscure. + +Example: +export TEC_INIT=1es + +will cause successful searches to auto-display in all teco sessions. + +************** + +Changing the location of the memory file. + +Define the environment variable TEC_MEMORY to be "$" followed by the +pathname of the file designated the memory file. + +Examples (csh): +export TEC_MEMORY=~/teco.mem +export TEC_MEMORY=\$$TEC_MEMORY + +will cause the name of the last edit file to be stored in the file +teco.mem in the home directory. By default the file name is tecoN.tmp in +the current directory, where "N" is the process ID of the parent process to +teco. + + +************** + +The Libary directory + +Defining the environment variable TEC_LIBRARY to be a directory path +(including the final "/") will allow the EI command to fetch +teco commands from this directory if the file is not found in the +current directory. + +Example: +export TEC_LIBRARY=\$/usr/local/lib/ + +will cause the directory /usr/local/lib to be searched for teco command files. + + +************** + +Implemented flags: + +ED&1 Allow carat "^" character in string searches +ED&2 Allow yank and _ unconditionally +ED&16 Failed searches preserve dot +ED&64 Move dot by one after each match in multiple occurance searches + +ET&1 Type out in image mode +ET&2 Use scope for delete and control-U (default=1) +ET&4 Accept lowercase input (default=1) +ET&8 ^T reads without echo +ET&32 ^T reads with no wait +ET&128 MUNG mode (abort on error) cleared by "*" prompt +ET&2048 Swap backspace and delete +ET&4096 We are using 8 bit characters (default=1) +ET&32768 Trap control-C + +EZ&1 Mark Henderson, who did much of the Unix port, likes the way + VAX/VMS keeps versions of files. VMS appends a semicolon followed + by a version number to files, and has the PURGE command to clean + out old versions of files. If this bit is off, TECO-C will handle + file version numbers, appending the appropriate version number to + file names. Mark supplied a "purge" program (distributed with TECO-C) + for users of this feature. Setting this flag turns off the feature, + to make TECO-C function as expected by the average Unix user. This + flag is set by default. +EZ&128 Don't stop read on formfeeds +EZ&256 If set, don't do newline translation on file read/write -- binary mode. + TECO is based on separate carriage return (CR) and line feed (LF) + line termination. Normally on file input newline (line feed) + characters are converted to CRLF pairs unless preceded + by a CR -- this allows reading DOS format files. On output CRLF pairs + are converted back to new line characters. Set this bit before starting + to edit a binary file, or when editing a DOS file for which no format + conversion is desired (ie file is saved back in DOS format). +EZ&8192 This bit is set by default, but has no significance in this release. +EZ&16384 Normally the backup file name is created by replacing the file extension + with "bak" -- foo.c becomes foo.bak, however if this bit is set then + the backup file name is created by simply adding ".bak" to the name -- foo.c + becomes foo.c.bak. This choice is overridden by EZ&1 = 0. + diff --git a/doc/readme.txt b/doc/readme.txt new file mode 100644 index 0000000..b056b54 --- /dev/null +++ b/doc/readme.txt @@ -0,0 +1,134 @@ +Running TECOC on Linux +Tecoc takes a first argument of mung, teco, or make to control its +operating mode. In this Linux version, the name of the executable is +tested to provide this first argument. Typically soft links are used +to the tecoc executable, however aliases could be used instead. The +mapping is: +Make is tecoc make (note uppercase first letter) +teco is tecoc teco +mung is tecoc mung +inspect is tecoc teco -inspect +The provided TAR file has these four soft links defined. Extract the +TAR file into a directory in your path, typically /usr/local/bin, +after making sure none of the command names already exist for other +applications. Necessary environment variables and files are described below. +Several option switches are allowed on the TECO command line: + -in[spect] -- Read file only, don't create an output file. + -noc[reate] -- If file doesn't exist, don't create it. + -noi[ni] -- Don't execute INI file. (valid for MAKE or MUNG as well) + -nom[emory] -- don't save filename as "last edited file" (valid for + MAKE also) + -nop[age] -- Formfeeds don't stop file reads (valid for MAKE also) + -nor[ename] -- Don't rename files, but copy them to keep references correct + (OS/2 only) + +nnn -- sets NOPAGE and positions dot to line nnn. +The part of the switch name in the square brackets is optional. For +instance "-in" is the same as "-inspect". +MAKE filespec + starts tecoc to create file filespec. Does equivalent of EWfilespec$$ +TECO filespec + starts tecoc to edit file filespec. Does equivalent of + EBfilespec$Y$ +TECO filespec2=filespec1 + starts tecoc to edit filespec1, writing to filespec2. Does + equivalent of ERfilespec1$EWfilespec2$Y$$ +TECO + starts tecoc to edit last edited file. Filename is saved in file + named teco*.tmp in the current directory, unless overriden + (described below). +MUNG filespec + starts tecoc to execute filespec. Equivalent to + I$JEIfilespec$$ + You can use "TECO @filespec " instead of MUNG. +************** +Key Bindings +The keys mentioned in the teco.doc file are somewhat confusing. +This should help: + The "Esc" key, "Esc" echoes as "$", however the + teco.doc file shows it as '`'. + Type as Control-h, this isn't the "Backspace" key. + The "Backspace" key. This isn't the "Delete" key. + The "Enter" key. + Type as Control-j. +Note that the assignments for and shown here are +swapped. can be "Backspace" and can be control-h by +clearing ET&2048, e.g. 2048,0ET +************** +The Initialization File. +Tecoc mungs (executes as teco commands) the file TECO.INI in the +current directory before processing the command line. Initialization +can be done instead by defining a TEC_INIT environment variable. The +value is either the list of teco commands to execute or a "$" followed +by the pathname of the file containing the initialization file. This +allows a single, centrally located initialization file. REMEMBER that +the "$" must be escaped, i.e. "\$" +The initialization file can be used to make initial settings. It can +return a value, but the value setting is somewhat obscure. +Example (csh): +setenv TEC_INIT 1es +Example (bash): +TEC_INIT=1es +export TEC_INIT +will cause successful searches to auto-display in all teco sessions. +************** +Changing the location of the memory file. +Define the environment variable TEC_MEMORY to be "$" followed by the +pathname of the file designated the memory file. +Example (csh): +setenv TEC_MEMORY ~/teco.mem +setenv TEC_MEMORY \$$TEC_MEMORY +Example (bash): +TEC_MEMORY = ~/teco.mem +TEC_MEMORY = \$$TEC_MEMORY +export TEC_MEMORY +will cause the name of the last edit file to be stored in the file +teco.mem in the home directory. By default the file name is tecoN.tmp in +the current directory, where "N" is the process ID of the parent process to +teco. +************** +The Libary directory +Defining the environment variable TEC_LIBRARY to be a directory path +(including the final "/") will allow the EI command to fetch +teco commands from this directory if the file is not found in the +current directory. +Example (csh): +setenv TEC_LIBRARY=\$/usr/local/lib/ +will cause the directory /usr/local/lib to be searched for teco command files. +************** +Implemented flags: +ED&1 Allow carat "^" character in string searches +ED&2 Allow yank and _ unconditionally +ED&16 Failed searches preserve dot +ED&64 Move dot by one after each match in multiple occurance searches +ET&1 Type out in image mode +ET&2 Use scope for delete and control-U (default=1) +ET&4 Accept lowercase input (default=1) +ET&8 ^T reads without echo +ET&32 ^T reads with no wait +ET&128 MUNG mode (abort on error) cleared by "*" prompt +ET&2048 Swap backspace and delete +ET&4096 We are using 8 bit characters (default=1) +ET&32768 Trap control-C +EZ&1 Mark Henderson, who did much of the Unix port, likes the way + VAX/VMS keeps versions of files. VMS appends a semicolon followed + by a version number to files, and has the PURGE command to clean + out old versions of files. If this bit is off, TECO-C will handle + file version numbers, appending the appropriate version number to + file names. Mark supplied a "purge" program (distributed with TECO-C) + for users of this feature. Setting this flag turns off the feature, + to make TECO-C function as expected by the average Unix user. This + flag is set by default. +EZ&128 Don't stop read on formfeeds +EZ&256 If set, don't do newline translation on file read/write -- binary mode. + TECO is based on separate carriage return (CR) and line feed (LF) + line termination. Normally on file input newline (line feed) + characters are converted to CRLF pairs unless preceded + by a CR -- this allows reading DOS format files. On output CRLF pairs + are converted back to new line characters. Set this bit before starting + to edit a binary file, or when editing a DOS file for which no format + conversion is desired (ie file is saved back in DOS format). +EZ&8192 This bit is set by default, but has no significance in this release. +EZ&16384 Normally the backup file name is created by replacing the file extension + with "bak" -- foo.c becomes foo.bak, however if this bit is set then + the backup file name is created by simply adding ".bak" to the name -- foo.c + becomes foo.c.bak. This choice is overridden by EZ&1 = 0. diff --git a/doc/readme.win b/doc/readme.win new file mode 100644 index 0000000..7a9cad9 --- /dev/null +++ b/doc/readme.win @@ -0,0 +1,121 @@ +Running TECOC + +Tecoc is typically started via batch commands to set the first +argument to MUNG, TECO, or MAKE. The batch files are typically called +mung, teco, make, and inspect. (Inspect does a TECO/INSPECT.) + +Several option switches are allowed on the TECO command line: + + /IN[SPECT] -- Read file only, don't create an output file. + /NOC[REATE] -- If file doesn't exist, don't create it. + /NOI[NI] -- Don't execute INI file. (valid for MAKE or MUNG as well) + /NOM[EMORY] -- don't save filename as "last edited file" (valid for + MAKE also) + /NOP[AGE] -- Formfeeds don't stop file reads (valid for MAKE also) + /NOR[ENAME] -- Don't rename files, but copy them to keep references correct + (OS/2 only) + +nnn -- sets NOPAGE and positions dot to line nnn. + +The part of the switch name in the square brackets is optional. For +instance "/IN" is the same as "/INSPECT". + +MAKE filespec + + starts tecoc to create file filespec. Does equivalent of EWfilespec$$ + +TECO filespec + + starts tecoc to edit file filespec. Does equivalent of + EBfilespec$Y$ + +TECO filespec2=filespec1 + + starts tecoc to edit filespec1, writing to filespec2. Does + equivalent of ERfilespec1$EWfilespec2$Y$$ + +TECO + + starts tecoc to edit last edited file. Filename is saved in file + named teco*.tmp in the current directory, unless overriden + (described below). + +MUNG filespec + + starts tecoc to execute filespec. Equivalent to + I$JEIfilespec$$ + + You can use "TECO @filespec " instead of MUNG. + +************** + +The Initialization File. + +Tecoc mungs (executes as teco commands) the file TECO.INI in the +current directory before processing the command line. Initialization +can be done instead by defining a TEC$INIT environment variable (the +DOS "SET" command does this). The value is either the list of teco +commands to execute or a "$" followed by the pathname of the file +containing the initialization file. This allows a single, centrally +located initialization file. + +The initialization file can be used to make initial settings. It can +return a value, but the value setting is somewhat obscure. + +Example: + +set TEC$INIT=1es + +will cause successful searches to auto-display in all teco sessions. + +************** + +Changing the location of the memory file. + +Define the environment variable TEC$MEMORY to be "$" followed by the +pathname of the file designated the memory file. + +Example: + +set TEC$MEMORY=$c:\teco.mem + +will cause the name of the last edit file to be stored in the file +teco.mem in the root directory of drive C. + + +************** + +The Libary directory + +Defining the environment variable TEC$LIBRARY to be a directory path +(including the final "\" or "/") will allow the EI command to fetch +teco commands from this directory if the file is not found in the +current directory. + +Example: + +set TEC$LIBRARY=c:\lib\teco\ + +will cause the directory c:\lib\teco to be searched for teco command files. + + +************** + +Implemented flags: + +ED&1 Allow carat "^" character in string searches +ED&2 Allow yank and _ unconditionally +ED&16 Failed searches preserve dot +ED&64 Move dot by one after each match in multiple occurance searches + +ET&1 Type out in image mode +ET&2 Use scope for delete and control-U (default=1) +ET&4 Accept lowercase input (default=1) +ET&8 ^T reads without echo +ET&32 ^T reads with no wait +ET&128 MUNG mode (abort on error) cleared by "*" prompt +ET&2048 Swap backspace and delete (default=1) +ET&4096 We are using 8 bit characters (default=1) +ET&32768 Trap control-C + +EZ&2 Don't rename files, copy them (OS/2 Version) +EZ&128 Don't stop read on formfeeds diff --git a/doc/readme2.1st b/doc/readme2.1st new file mode 100644 index 0000000..260fc3b --- /dev/null +++ b/doc/readme2.1st @@ -0,0 +1,61 @@ + TECO-C (version number 146) + + Copyright 1983, 1990 by Pete Siemsen. This software is provided to +you free of charge for your own use. Use it as you see fit; if it doesn't +work, I disclaim all responsibility. You may re-distribute this software +UNCHANGED only if you include this copy-right notice. Alternatively, if +you change this software, you may re-distribute the result only if you +include BOTH this copyright notice, AND an additional notice identifying +you and indicating that you have changed the software. + + This program is still under development. See file PROBLEMS.TXT for +notes I've written to myself about things to do to the program. If you +modify this code to enhance it or fix a bug, please communicate the changes +to me. My address is + + Pete Siemsen + 645 Ohio Avenue #302 + Long Beach, Ca. 90814 + + (213) 433-3059 (home) + (213) 740-7391 (work) + Internet: siemsen@usc.edu + +[NOTE -- This is old information. Better to contact me, Tom Almy, below.] + +******************************************************* + +This archive contains TECO-C modified and compiled for DOS, Win32, +and OS/2. The modifications have been made by: + + Tom Almy + tomalmy@aracnet.com -or- + tom_almy@ieee.org + +who is a "old time" TECO user. Not only did I port TECO-C but I also +corrected some bugs and modified the file backup algorithm to do +copying rather than renaming as an option. This makes it Workplace +Shell friendly. Both the Win32 and OS/2 version allow long file names. + +Included files in this archive: + +readme.1st This file +readme.txt Quick operating instructions for the TECO literate +wchart.txt List of all the implemented commands. +teco.doc The official teco reference. +inspect.cmd Command files to invoke tecoc +inspect.bat (cmd for OS/2, bat for DOS/Win32) +mung.cmd +mung.bat +teco.cmd +teco.bat +tmake.cmd this would be "make" but most people use the program + "make". +tmake.bat +tecocmd.btm Equivalent aliases for JPSoft products (4DOS, et cetera) + +*.tes TECO command files for various things +*.tec Compressed TECO command files + + +The executable program is downloaded as a separate file. diff --git a/doc/readme2.osx b/doc/readme2.osx new file mode 100644 index 0000000..e2abf5d --- /dev/null +++ b/doc/readme2.osx @@ -0,0 +1,142 @@ +Running TECOC + +NOTE -- IF YOU ARE USING LINUX, READ THE FILE README.LNX INSTEAD! + + +Tecoc is typically started via batch commands to set the first +argument to MUNG, TECO, or MAKE. The batch files are typically called +mung, teco, make, and inspect. (Inspect does a TECO/INSPECT.) + +Several option switches are allowed on the TECO command line: + + /IN[SPECT] -- Read file only, don't create an output file. + /NOC[REATE] -- If file doesn't exist, don't create it. + /NOI[NI] -- Don't execute INI file. (valid for MAKE or MUNG as well) + /NOM[EMORY] -- don't save filename as "last edited file" (valid for + MAKE also) + /NOP[AGE] -- Formfeeds don't stop file reads (valid for MAKE also) + /NOR[ENAME] -- Don't rename files, but copy them to keep references correct + (OS/2 only) + +nnn -- sets NOPAGE and positions dot to line nnn. + +The part of the switch name in the square brackets is optional. For +instance "/IN" is the same as "/INSPECT". + +MAKE filespec + + starts tecoc to create file filespec. Does equivalent of EWfilespec$$ + +TECO filespec + + starts tecoc to edit file filespec. Does equivalent of + EBfilespec$Y$ + +TECO filespec2=filespec1 + + starts tecoc to edit filespec1, writing to filespec2. Does + equivalent of ERfilespec1$EWfilespec2$Y$$ + +TECO + + starts tecoc to edit last edited file. Filename is saved in file + named teco*.tmp in the current directory, unless overriden + (described below). + +MUNG filespec + + starts tecoc to execute filespec. Equivalent to + I$JEIfilespec$$ + + You can use "TECO @filespec " instead of MUNG. + +************** +Key Bindings + +The keys mentioned in the teco.doc file are somewhat confusing. +This should help: + + The "Esc" key, "Esc" echoes as "$", however the + teco.doc file shows it as '`'. + Type as Control-h, this isn't the "Backspace" key. + The "Backspace" key. This isn't the "Delete" key. + The "Enter" key. + Type as Control-j. + +Note that the assignments for and shown here are +swapped. can be "Backspace" and can be control-h by +clearing ET&2048, e.g. 2048,0ET + + +************** + +The Initialization File. + +Tecoc mungs (executes as teco commands) the file TECO.INI in the +current directory before processing the command line. Initialization +can be done instead by defining a TEC$INIT environment variable (the +DOS "SET" command does this). The value is either the list of teco +commands to execute or a "$" followed by the pathname of the file +containing the initialization file. This allows a single, centrally +located initialization file. + +The initialization file can be used to make initial settings. It can +return a value, but the value setting is somewhat obscure. + +Example: + +set TEC$INIT=1es + +will cause successful searches to auto-display in all teco sessions. + +************** + +Changing the location of the memory file. + +Define the environment variable TEC$MEMORY to be "$" followed by the +pathname of the file designated the memory file. + +Example: + +set TEC$MEMORY=$c:\teco.mem + +will cause the name of the last edit file to be stored in the file +teco.mem in the root directory of drive C. + + +************** + +The Libary directory + +Defining the environment variable TEC$LIBRARY to be a directory path +(including the final "\" or "/") will allow the EI command to fetch +teco commands from this directory if the file is not found in the +current directory. + +Example: + +set TEC$LIBRARY=c:\lib\teco\ + +will cause the directory c:\lib\teco to be searched for teco command files. + + +************** + +Implemented flags: + +ED&1 Allow carat "^" character in string searches +ED&2 Allow yank and _ unconditionally +ED&16 Failed searches preserve dot +ED&64 Move dot by one after each match in multiple occurance searches + +ET&1 Type out in image mode +ET&2 Use scope for delete and control-U (default=1) +ET&4 Accept lowercase input (default=1) +ET&8 ^T reads without echo +ET&32 ^T reads with no wait +ET&128 MUNG mode (abort on error) cleared by "*" prompt +ET&2048 Swap backspace and delete (default=1) +ET&4096 We are using 8 bit characters (default=1) +ET&32768 Trap control-C + +EZ&2 Don't rename files, copy them (OS/2 Version) +EZ&128 Don't stop read on formfeeds diff --git a/doc/readme2.txt b/doc/readme2.txt new file mode 100644 index 0000000..0c8d66f --- /dev/null +++ b/doc/readme2.txt @@ -0,0 +1,80 @@ +Running TECOC +Tecoc is typically started via batch commands to set the first +argument to MUNG, TECO, or MAKE. The batch files are typically called +mung, teco, make, and inspect. (Inspect does a TECO/INSPECT.) +Several option switches are allowed on the TECO command line: + /IN[SPECT] -- Read file only, don't create an output file. + /NOC[REATE] -- If file doesn't exist, don't create it. + /NOI[NI] -- Don't execute INI file. (valid for MAKE or MUNG as well) + /NOM[EMORY] -- don't save filename as "last edited file" (valid for + MAKE also) + /NOP[AGE] -- Formfeeds don't stop file reads (valid for MAKE also) + /NOR[ENAME] -- Don't rename files, but copy them to keep references correct + (OS/2 only) + +nnn -- sets NOPAGE and positions dot to line nnn. +The part of the switch name in the square brackets is optional. For +instance "/IN" is the same as "/INSPECT". +MAKE filespec + starts tecoc to create file filespec. Does equivalent of EWfilespec$$ +TECO filespec + starts tecoc to edit file filespec. Does equivalent of + EBfilespec$Y$ +TECO filespec2=filespec1 + starts tecoc to edit filespec1, writing to filespec2. Does + equivalent of ERfilespec1$EWfilespec2$Y$$ +TECO + starts tecoc to edit last edited file. Filename is saved in file + named teco*.tmp in the current directory, unless overriden + (described below). +MUNG filespec + starts tecoc to execute filespec. Equivalent to + I$JEIfilespec$$ + You can use "TECO @filespec " instead of MUNG. +************** +The Initialization File. +Tecoc mungs (executes as teco commands) the file TECO.INI in the +current directory before processing the command line. Initialization +can be done instead by defining a TEC$INIT environment variable (the +DOS "SET" command does this). The value is either the list of teco +commands to execute or a "$" followed by the pathname of the file +containing the initialization file. This allows a single, centrally +located initialization file. +The initialization file can be used to make initial settings. It can +return a value, but the value setting is somewhat obscure. +Example: +set TEC$INIT=1es +will cause successful searches to auto-display in all teco sessions. +************** +Changing the location of the memory file. +Define the environment variable TEC$MEMORY to be "$" followed by the +pathname of the file designated the memory file. +Example: +set TEC$MEMORY=$c:\teco.mem +will cause the name of the last edit file to be stored in the file +teco.mem in the root directory of drive C. +************** +The Libary directory +Defining the environment variable TEC$LIBRARY to be a directory path +(including the final "\" or "/") will allow the EI command to fetch +teco commands from this directory if the file is not found in the +current directory. +Example: +set TEC$LIBRARY=c:\lib\teco\ +will cause the directory c:\lib\teco to be searched for teco command files. +************** +Implemented flags: +ED&1 Allow carat "^" character in string searches +ED&2 Allow yank and _ unconditionally +ED&16 Failed searches preserve dot +ED&64 Move dot by one after each match in multiple occurance searches +ET&1 Type out in image mode +ET&2 Use scope for delete and control-U (default=1) +ET&4 Accept lowercase input (default=1) +ET&8 ^T reads without echo +ET&32 ^T reads with no wait +ET&128 MUNG mode (abort on error) cleared by "*" prompt +ET&2048 Swap backspace and delete (default=1) +ET&4096 We are using 8 bit characters (default=1) +ET&32768 Trap control-C +EZ&2 Don't rename files, copy them (OS/2 Version) +EZ&128 Don't stop read on formfeeds diff --git a/doc/teco.doc b/doc/teco.doc new file mode 100644 index 0000000..2ead288 --- /dev/null +++ b/doc/teco.doc @@ -0,0 +1,11104 @@ + + + + + + + + + + + + + + + + Standard TECO + + + TEXT EDITOR AND CORRECTOR FOR THE + VAX-11, PDP-11, PDP-10, and PDP-8 + + + USER'S GUIDE AND LANGUAGE REFERENCE MANUAL + + + May 1985 Edition + + + TECO-11 VERSION 40 + TECO-10 VERSION 3 + TECO-8 VERSION 7 + + + + + + + + + + + + + + + + + + + + + May, 1985 + + Standard TECO + + + + The information in this document is subject to change without + notice and should not be construed as a commitment by Digital + Equipment Corporation or by DECUS. + + Neither Digital Equipment Corporation, DECUS, nor the authors + assume any responsibility for the use or reliability of this + document or the described software. + + + + Copyright (C) 1979, 1985 TECO SIG + + General permission to copy or modify, but not + for profit, is hereby granted, provided that + the above copyright notice is included and + reference made to the fact that reproduction + privileges were granted by the TECO SIG. + + Standard TECO PAGE i + + + + CONTENTS + + + + + INTRODUCTION 1 + + PREFACE TO THE MAY 1985 EDITION 4 + + CHAPTER 1 BASICS OF TECO 7 + + 1.1 USING TECO 7 + 1.2 DATA STRUCTURE FUNDAMENTALS 9 + 1.3 FILE SELECTION COMMANDS 10 + 1.3.1 Simplified File Selection 10 + 1.3.2 Input File Specification (ER command) 11 + 1.3.3 Output File Specification (EW command) 12 + 1.3.4 Closing Files (EX command) 13 + 1.4 INPUT AND OUTPUT COMMANDS 14 + 1.5 POINTER POSITIONING COMMANDS 15 + 1.6 TYPE OUT COMMANDS 16 + 1.6.1 Immediate Inspection Commands 17 + 1.7 TEXT MODIFICATION COMMANDS 18 + 1.8 SEARCH COMMANDS 19 + 1.9 SAMPLE EDITING JOB 20 + + INTERLUDE 23 + + CHAPTER 2 INVOKING TECO 24 + + 2.1 RUNNING TECO 24 + 2.2 CREATING A NEW FILE 24 + 2.3 EDITING AN EXISTING FILE 24 + 2.4 SWITCHES ON TECO AND MAKE COMMANDS 25 + 2.5 INVOKING A TECO PROGRAM 26 + 2.6 USER INITIALIZATION 27 + + CHAPTER 3 CONVENTIONS AND STRUCTURES 29 + + 3.1 TECO CHARACTER SET 29 + 3.2 TECO COMMAND FORMAT 30 + 3.2.1 Numeric Arguments 31 + 3.2.2 Text Arguments 32 + 3.2.3 Colon Modifiers 33 + 3.3 DATA STRUCTURES 34 + 3.3.1 Text Buffer 35 + 3.3.2 Q-registers 36 + 3.3.3 Q-register Push-down List 37 + 3.3.4 Numeric Values and Flags 37 + + Standard TECO PAGE ii + + + + CHAPTER 4 COMMAND STRING EDITING 38 + + 4.1 Immediate Action Editing Characters 38 + 4.2 Immediate Action Commands 41 + 4.3 Introduction to Macros 43 + 4.4 Immediate ESCAPE-Sequence Commands 44 + 4.5 Operating System Character Filters 46 + + CHAPTER 5 COMMAND DESCRIPTIONS 48 + + 5.1 FILE SPECIFICATION COMMANDS 49 + 5.1.1 File Opening Commands 49 + 5.1.2 File Specification Switches 51 + 5.1.3 File Close and Exit Commands 51 + 5.1.4 Secondary Stream Commands 54 + 5.1.5 Wildcard Commands 56 + 5.1.6 Direct I/O to Q-Registers 56 + 5.2 PAGE MANIPULATION COMMANDS 58 + 5.3 BUFFER POINTER MANIPULATION COMMANDS 61 + 5.4 TEXT TYPE OUT COMMANDS 63 + 5.5 DELETION COMMANDS 66 + 5.6 INSERTION COMMANDS 68 + 5.7 SEARCH COMMANDS 70 + 5.8 SEARCH ARGUMENTS 76 + 5.9 Q-REGISTER MANIPULATION 80 + 5.10 ARITHMETIC AND EXPRESSIONS 86 + 5.11 SPECIAL NUMERIC VALUES 89 + 5.12 COMMAND LOOPS 94 + 5.13 BRANCHING COMMANDS 95 + 5.14 CONDITIONAL EXECUTION COMMANDS 101 + 5.15 RETRIEVING ENVIRONMENT CHARACTERISTICS 103 + 5.16 MODE CONTROL FLAGS 105 + 5.17 SCOPE COMMANDS 113 + 5.17.1 Video Terminal Scope Commands 113 + 5.17.2 Refresh Scope Commands 116 + 5.18 PROGRAMMING AIDS 117 + 5.18.1 Text Formatting 117 + 5.18.2 Comments 117 + 5.18.3 Messages 118 + 5.18.4 Tracing 119 + 5.18.5 Convenience Characters 119 + 5.18.6 Memory Expansion 120 + 5.18.7 Case Control 121 + 5.19 MANIPULATING LARGE PAGES 122 + 5.20 TECHNIQUES AND EXAMPLES 123 + + Standard TECO PAGE iii + + + + APPENDIX A ASCII CHARACTER SET 128 + + APPENDIX B ERROR MESSAGES 137 + + APPENDIX C INCOMPATIBLE, OBSOLETE, AND SYSTEM-SPECIFIC + COMMANDS 145 + + C.1 SPECIFIC FEATURES OF TECO-11 145 + C.1.1 TECO Commands 145 + C.1.2 String Build Constructs 147 + C.2 SPECIFIC FEATURES OF RT-11 148 + C.3 SPECIFIC FEATURES OF RSTS/E 148 + C.4 SPECIFIC FEATURES OF RSX-11/M, RSX-11/D, + and IAS 149 + C.5 SPECIFIC FEATURES OF VAX/VMS 149 + C.6 SPECIFIC FEATURES OF OS/8 149 + C.7 SPECIFIC FEATURES OF TOPS-10 150 + + APPENDIX D RT-11 OPERATING CHARACTERISTICS 153 + + APPENDIX E RSTS/E OPERATING CHARACTERISTICS 157 + + APPENDIX F RSX-11 OPERATING CHARACTERISTICS 160 + + APPENDIX G VAX/VMS OPERATING CHARACTERISTICS 167 + + APPENDIX H OS/8 OPERATING CHARACTERISTICS 175 + + APPENDIX I TOPS-10 OPERATING CHARACTERISTICS 187 + + APPENDIX J BASIC-PLUS/BASIC-PLUS-2 HANDLING 194 + + GLOSSARY 197 + + INDEX 214 + + Standard TECO PAGE 1 + Introduction + + + INTRODUCTION + + TECO is a powerful text editing language available under most + DIGITAL operating systems. TECO may be used to edit any form of + ASCII text: program sources, command procedures, or manuscripts, + for example. TECO is a character-oriented editor, and also + offers a number of facilities for dealing with lines of text. + + You can use TECO interactively, issuing commands which are to be + executed as soon as they are typed in. (TECO is an interpreter.) + In this mode, TECO can be used for tasks ranging from very simple + to quite complex. + + You can write sequences of commands called macros, which can be + stored and then invoked by short commands or even single + keystrokes. You can write sequences of commands to be run as + TECO programs, and store them on disk for execution at + convenience. + + TECO can be used as an implementation language, as it provides + powerful primitive functions for text processing, screen + handling, and keyboard management. (The VTEDIT program included + with some TECO distributions is an example of a full keypad + editor developed in the TECO language.) + + TECO correctly handles most sequential ASCII formats supported by + the operating systems upon which it runs. It provides flexible + pattern-matching constructs for text searching, file wildcarding, + and special support for editing BASIC-PLUS/BASIC-PLUS-2 source + programs. A split screen scrolling feature allows command + dialogue to share the screen with an automatically-updated window + into the editing buffer. + + TECO's syntax is terse; commands are designed to minimize + keystrokes. Also, the versatility of TECO "in all its glory" + makes it complex. However, just a few commands suffice to get + real work done, and a novice TECO user can begin creating and + editing text files after only a few hours of instruction. More + powerful features can be learned one at a time, and at leisure. + + This manual presents TECO in two stages. The first part (Chapter + 1) contains basic information and introduces that set of "just a + few" commands. + + Subsequent chapters describe the full TECO command set, including + a review of the those commands presented in Chapter 1. These + chapters also introduce the concept of TECO as a programming + language and explain how basic editing commands may be combined + into "programs" sophisticated enough to handle the most + complicated editing tasks. + + The early sections of this manual include few specific examples + of commands, since all TECO commands have a consistent, logical + + Standard TECO PAGE 2 + Introduction + + + format which will quickly become apparent to the beginning user. + There is, however, an extensive example at the end of Chapter 1 + which employs most of the commands introduced up to that point. + Students of TECO should experiment with each command as it is + introduced, and then duplicate the examples on their computer. + + (If a video terminal which supports split-screen scrolling such + as a member of the VT100 or VT200 families is available and the + TECO being used supports it, seeing both your commands and their + effects in the text buffer simultaneously can make learning + easier. A command such as "5,7:W" allows 5 lines for command + dialogue, while "watching" the text buffer on the remainder of + the screen. The 7:W command is described in Table 5-17B.) + + This manual is intended to be a reference manual, and except for + Chapter 1 is not a tutorial. After Chapter 1, it is assumed that + the reader has a general familiarity with TECO and is referring + to this manual to find detailed information. + + + Notation + + The following notation is used in this manual to represent + special characters: + + Notation ASCII code (octal) Name + + 0 Null + 10 Backspace + 11 Tab + 12 Line Feed + 13 Vertical Tab + 14 Form Feed + 15 Carriage Return + or $ 33 ESCape or Altmode + - Control-x + 40 Space + 177 Delete or Rubout + + or ` - See below + + is a character used to signify the end of text strings + and TECO commands typed at the console. (TECO presumes that you + may need to deal with carriage return and line feed as ordinary + characters in ASCII text, so another character must be used as + TECO's text-string and command-string delimiter.) + + When a command string is being executed, TECO looks for the + ESCape character (octal 033) as its delimiter. Some newer + terminals, however, no longer possess an ESCape key. Late-model + TECO's are capable of recognizing a surrogate (some other, + user-specified) character as signifying an ESCape when typed at + the console. Such a character echos as accent grave -- you see + + Standard TECO PAGE 3 + Introduction + + + an ` character, and TECO receives an ESCape character. (Note + that TECO programs, command files, and macros cannot use the + surrogate, since it is translated to ESCape only when you type it + at the console.) For details on choosing a surrogate for ESCape, + see the EE flag or the 8192 ET bit (section 5.16). + + Throughout this manual, the term is used to mean whatever + character you type as a text-string or command-string delimiter. + The ` character is used throughout to mean whichever character is + echoed for a keystroke which passes an ESCape to TECO; if no + ESCape surrogate is active, you will see a $ instead. + + Control characters, , are produced by striking the + CONTROL key and a character key simultaneously. + + Throughout this manual, upper case characters will be used to + represent TECO commands. + + Standard TECO PAGE 4 + Preface to the May 1985 edition + + + PREFACE TO THE MAY 1985 EDITION + + + Trading in the ESCape key + + In the beginning, terminals had ESCape keys. (Go back far + enough and the device TT: stands for might actually have + existed on the system, too.) Programs wanting to treat + & Co. as data needed another character to serve as command + delimiter, and ESCape looked available. + + Times change. Welcome to ESCape sequences, to + cursor-control and function keys. Farewell to $$. + + See the Introduction for the notation used in this manual. + Hello ``. + + + Changes to the manual + + This edition of the manual incorporates new material + pertinent to the enhancements to TECO-11 between Version 36 + and Version 40 (see below). + + Although this manual is still not intended to be a tutorial, + some "how to learn" suggestions (such as use of split-screen + scrolling) were added, as were indications of how TECO can + be used to build custom-designed editors. + + Numerous smaller changes were also made: clarifications, + new index and glossary entries, additional explanatory + material and cross referrals, correction of old typographic + errors, and (no doubt) addition of new ones. + + Standard TECO PAGE 5 + Preface to the May 1985 edition + + + From Version 36 to Version 40 - affected section numbers + + Manual organization/additions -- + + Introduction to Macros (new section), 4.3 + + Split-screen scrolling, 5.17 + + "Immediate action commands" renamed + to "immediate inspection commands", 1,6.1 + + "Immediate action editing characters" (new name), 4.1 + + VAX/VMS filespec qualifiers, format/attribute table, G.11 + + Eight-bit ASCII character set table, Appendix A + + Handling for BASIC-PLUS-x source files, Appendix J + + "Significant" software changes -- + + ESCape surrogate - EE flag, 8192 ET bit, 5.16 + + Reverse paging (-P, et al, VAX/VMS only), 5.2 + + Reverse searching (-N, et al, VAX/VMS only), 5.7 + + Local Q-registers, 3.3.2 + + Local Q-register manipulation, 5.9 + + Immediate ESCape-sequence commands, 4.4 + + :^T, read/decode a keystroke, 5.11 + + 32 ED bit controls immediate ESC-seq commands, 5.16 + + Acceptance and handling of 8-bit characters, [throughout] + + Typeout of 8-bit data, and the 4096 ET bit, 5.16 + + n:^T, one-shot binary-mode character typeout, 5.4 + + TECO HELP facilities on VAX/VMS, G.13 + + "Minor" software changes -- + + ^W as immediate mode command (screen re-paint), 4.2 + + character as immediate inspection command, 1.6.1, + 4.2 + + Null tag allowed in computed GOTO, 5.13 + + Standard TECO PAGE 6 + Preface to the May 1985 edition + + + + nFRtext` command (replace n characters), 5.6 + + m,nFRtext` command (replace from m to n), 5.6 + + ^E (form feed flag) can now be user-set, 5.11 + + Setting 1:W changes width and O/S characteristic, 5.17 + + WRAP/NOWRAP set by 256 ET bit on VAX/VMS, 5.16 + + 128 ED bit inhibits auto-refresh in split scrolling, 5.16 + + Search matching with diacritical marks, 5.16 + + New 0:W codes for VT102 and GIGI scope types, 5.17 + + VAX/VMS handling of ^T (disabled when), 4.5 + + Standard TECO PAGE 7 + Basics of TECO + + + CHAPTER 1 + + BASICS OF TECO + + + 1.1 USING TECO + + TECO may be called from command level by typing the appropriate + command, followed by a carriage return: + + For RT-11, OS/8, TOPS-10, and TOPS-20 R TECO + + For RSTS/E RUN TECO$:TECO -or- + EDIT/TECO + + For RSX-11 RUN $TEC + + For VAX/VMS RUN SYS$SYSTEM:TECO + + TECO will respond by printing an asterisk at the left margin to + indicate that it is ready to accept user commands. At this + point, you may type one or more commands. + + A TECO command consists of one or two characters which cause a + specific operation to be performed. Some TECO commands may be + preceded or followed by arguments. Arguments may be either + numeric or textual. A numeric argument is simply an integer + value which can be used to indicate, for example, the number of + times a command should be executed. A text argument is a string + of ASCII characters which might be, for example, words of text or + a file specification. + + If a command requires a numeric argument, the numeric argument + always precedes the command. If a command requires a text + argument, the text argument always follows the command. Each + text argument is terminated by a special character (usually a + character, which TECO hears as an ESCape - see + Introduction). This indicates to TECO that the next character + typed will be the first character of a new command. + + TECO accumulates commands as they are typed in a command string, + and executes commands upon receipt of two consecutive + characters. may be any character you select (if your + TECO and operating system support user-selectable ESCape + surrogates - see sections on ET and EE flags). When you type the + character you have designated as , TECO receives an ESCape + character, and an ` (accent grave) is echoed. (If you are not + using an ESCape surrogate -- that is, you are actually pressing + an ESCape key -- a dollar sign is echoed.) The accent grave + character is used in examples throughout this manual to represent + typed s. Note that the carriage return character has no + special significance to TECO; only the forces + execution of the command string. + + Standard TECO PAGE 8 + Using TECO + + + TECO executes command strings from left to right until either all + commands have been executed or a command error is recognized. It + then prints an asterisk to signal that additional commands may be + entered. + + If TECO encounters an erroneous command, it prints an error + message and ignores the erroneous command as well as all commands + which follow it. All error messages are of the form: + + ?XXX Message + + where XXX is an error code and the message is a description of + the error. Some error messages mention the specific character or + string of characters in error. In these error messages, TECO + represents the non-printing special characters as follows: + + Character Form Displayed + + + + + + + + <^x> + + + Every error message is followed by an asterisk at the left + margin, indicating that TECO is ready to accept additional + commands. If you type a single question mark character after a + TECO-generated error message, TECO will print the erroneous + command string up to and including the character which caused the + error message. This helps you to find errors in long command + strings and to determine how much of a command string was + executed before the error was encountered. + + You can correct typing errors by hitting the DELETE key, which + may be labeled DEL or RUBOUT on your keyboard. Each depression + of the DELETE key deletes one character and echoes it on your + terminal, beginning with the last character typed. If your + terminal is a CRT, TECO will actually erase the deleted character + from the screen. You can delete an entire command string this + way, if necessary. To delete an entire line of commands, enter + the character , typed by holding down the CONTROL key + while depressing the "U" key. + + When you are done editing, use the EX command to exit TECO, as + described below in section 1.3.4. + + Standard TECO PAGE 9 + Data Structure Fundamentals + + + 1.2 DATA STRUCTURE FUNDAMENTALS + + TECO considers any string of ASCII codes to be text. Text is + broken down into units of characters, lines, and pages. A + character is one ASCII code. A line of text is a string of ASCII + codes including one line terminator (usually a line feed) as the + last character on the line. A page of text is a string of ASCII + codes including one form feed character as the last character on + the page. + + TECO maintains a text buffer in which text is stored. The buffer + usually contains one page of text, but the terminating form feed + character never appears in the buffer. TECO also maintains a + text buffer pointer. The pointer is a movable position indicator + which is never located directly on a character, but is always + between characters: between two characters in the buffer, before + the first character in the buffer, or after the last character in + the buffer. + + Line feed and form feed characters are inserted automatically by + TECO. A line feed is automatically appended to every carriage + return typed to TECO and a form feed is appended to the contents + of the buffer by certain output commands. Additional line feed + and form feed characters may be entered into the buffer as text. + If a form feed character is entered into the buffer, it will + cause a page break upon output; text following the form feed + will begin a new page. + + Finally, TECO maintains an input file and an output file, both of + which are selected by the user through file specification + commands. The input file may be on any device from which text + may be accepted. The output file may be on any device on which + edited text may be written. + + TECO functions as a "pipeline" editor. Text is read from the + input file into the text buffer, and is written from the buffer + onto the output file. In the VAX/VMS implementation, it is + possible to "back up" as well as page forward in the file being + edited. In other implementations, once text has been written to + the output file, it cannot be accessed again without closing the + output file and reopening it as an input file. + + Standard TECO PAGE 10 + File Selection Commands + + + 1.3 FILE SELECTION COMMANDS + + Input and output files may be specified to TECO in several ways. + The following sections present first a simple method for + specifying files, and then more sophisticated commands that + permit flexible file selection. + + + NOTE + + All of the following file selection commands are shown + with a general argument of "filespec". The actual + contents of this filespec argument are operating system + dependent. See the operating characteristics appendices. + Examples include a mixture of file specifications from + various operating systems. + + + 1.3.1 Simplified File Selection + + For most simple applications, you can use special operating + system commands to specify the name of the file you wish to edit + at the same time that you start up TECO. + + To create a new file: + + MAKE filespec + + This command starts up TECO and creates the specified file for + output. + + To edit an existing file: + + TECO filespec + + This command starts up TECO and opens the specified file for + editing while preserving the original file (as a backup file). + It also automatically brings the first page of the file into the + text buffer. These functions simulate the EB command described + in Chapter 5. + + If any of the above commands do not seem to work on your + operating system, consult the appropriate appendix for + information about how to install TECO and its associated + operating system commands. + + Standard TECO PAGE 11 + File Selection Commands + + + 1.3.2 Input File Specification (ER command) + + TECO will accept input text from any input device in the + operating system. The input device may be specified by the text + string supplied in the ER command (and which, like any text + argument, is terminated by a character). The ER command + causes TECO to open the specified file or print an error message + if the file is not found. This command does not cause any + portion of the file to be read into the text buffer, however. + The following examples illustrate use of the ER command. + + + COMMAND FUNCTION + + ERfilespec` General form of the ER command where + "filespec" is the designation of the input + file. The command is terminated by a + character. + + ERPR:` Prepare to read an input file from the paper + tape reader. + + ERPROG.MAC` Prepare to read input file PROG.MAC from the + system's default device. + + ERDX1:PROG.FOR` Prepare to read input file PROG.FOR from + DX1:. + + + TECO will only keep one input and one output file open and + selected at a time. The current input file may be changed by + simply using the ER command to specify a new file. + + It is not always necessary to specify an input file. If you want + to create a file without using any previously edited text as + input, you may type commands to insert the necessary text + directly into the text buffer from the keyboard and, at the end + of each page, write the contents of the buffer onto an output + file. Since all input is supplied from the keyboard, no input + file is necessary. + + Standard TECO PAGE 12 + File Selection Commands + + + 1.3.3 Output File Specification (EW command) + + TECO will write output text onto any output device in the + operating system. The output file may be specified by means of + the text string supplied in an EW command. If the output device + is a file-structured device (for example, a disk), the file name + and any extension must be supplied. If a file name is specified + but no device is explicitly specified, the system's default + device is assumed. The following examples illustrate use of the + EW command. + + + COMMAND FUNCTION + + EWfilespec` General form of the EW command where + "filespec" is the designation of the output + file. The command is terminated by a + character. + + EWSYS:TEXT.LST` Prepare to write output file TEXT.LST on + SYS:. + + EWPROG` Prepare to write output file PROG on the + system's default device. + + ERDX1:INPUT.MAC`EWOUTPUT.MAC`` + Open an input file INPUT.MAC to be found on + DX1: and open an output file named + OUTPUT.MAC. The double (echoed as + ``) terminates the command string and causes + the string to be executed. Note that the + which terminates the EW command may + be one of the two s which terminates + the command string. + + + You do not need to specify an output file if you only want to + examine an input file, without making permanent changes or + corrections. In this case, the contents of the input file may be + read into the text buffer page by page and examined at the + terminal. Since all output is printed on the user terminal, no + output file is needed. + + Standard TECO PAGE 13 + File Selection Commands + + + 1.3.4 Closing Files (EX command) + + When you are finished editing a file, use the EX command to close + out the file and exit from TECO. The current contents of the + text buffer and any portion of the input file that has not been + read yet are copied to the output file before TECO exits. The EX + command takes no arguments. + + + COMMAND FUNCTION + + EX Write the text buffer to the current output + file, move the remainder of the current input + file to the current output file, close the + output file, then return to the operating + system. + + ERFILE.MAC`EWCOPY.MAC`EX`` + Open an input file FILE.MAC and open an + output file named COPY.MAC, then copy all the + text in the input file to the output file, + close the output file, and exit from TECO. + + Standard TECO PAGE 14 + Input and Output Commands + + + 1.4 INPUT AND OUTPUT COMMANDS + + The following commands permit pages of text to be read into the + TECO text buffer from an input file or written from the buffer + onto an output file. Once a page of text has been written onto + the output file, it cannot be recalled into the text buffer + unless the output file is closed and reopened as an input file. + + + COMMAND FUNCTION + + Y Clear the text buffer, then read the next page of the + input file into the buffer. Since the Y command causes + the contents of the text buffer to be lost, it is not + permitted if an output file is open and there is text in + the buffer. + + P Write the contents of the text buffer onto the next page + of the output file, then clear the buffer and read the + next page of the input file into the buffer. + + nP Execute the P command n times. If n is not specified, a + value of 1 is assumed. + + After each Y, P, or nP command, TECO positions the pointer before + the first character in the buffer. + + Standard TECO PAGE 15 + Pointer Positioning Commands + + + 1.5 POINTER POSITIONING COMMANDS + + The buffer pointer provides the means of specifying the location + within a block of text at which insertions, deletions or + corrections are to be made. The following commands permit the + buffer pointer to be moved to a position between any two adjacent + characters in the buffer. + + + COMMAND FUNCTION + + J Move the pointer to the beginning of the buffer. + + L Move the pointer forward to a position between the next + line feed and the first character of the next line. That + is, advance the pointer to the beginning of the next + line. + + nL Execute the L command n times, where n is a signed + integer. A positive value of n moves the pointer to the + beginning of the nth line following the current pointer + position. A negative value moves the pointer backward n + lines and positions it at the beginnning of the nth line + preceding the current position. If n is zero, the + pointer is moved to the beginning of the line on which it + is currently positioned. + + C Advance the pointer forward across one character. + + nC Execute the C command n times, where n is a signed + integer. A positive value of n moves the pointer forward + across n characters. A negative value of n moves the + pointer backward across n characters. If n is zero, the + pointer position is not changed. Remember that there are + two characters, and , at the end of each line in + the buffer. + + These commands may be used to move the buffer pointer across any + number of lines or characters in either direction; however, they + will not move the pointer across a page boundary. If a C command + attempts to move the pointer backward beyond the beginning of the + buffer or forward past the end of the buffer, an error message is + printed and the command is ignored. + + If an L command attempts to exceed the page boundaries in this + manner, the pointer is positioned at the boundary which would + have been exceeded. Thus, in a page of 2000 lines, the command + "-4000L" would position the pointer before the first character in + the buffer. The command "4000L" would position the pointer after + the last character in the buffer. No error message is printed in + either case. + + Standard TECO PAGE 16 + Type Out Commands + + + 1.6 TYPE OUT COMMANDS + + The following commands permit sections of the text in the buffer + to be printed out on your terminal for examination. These + commands do not move the buffer pointer. + + + COMMAND FUNCTION + + T Type the contents of the text buffer from the current + position of the pointer through and including the next + line feed character. + + nT Type n lines, where n is a signed integer. A positive + value of n causes the n lines following the pointer to be + typed. A negative value of n causes the n lines + preceding the pointer to be typed. If n is zero, the + contents of the buffer from the beginning of the line on + which the pointer is located up to the pointer is typed. + This is useful for verifying the location of the buffer + pointer. + + HT Type the entire contents of the text buffer. + + V Type the current line. Equivalent to the sequence "0TT". + + Standard TECO PAGE 17 + Type Out Commands + + + 1.6.1 Immediate Inspection Commands [not in TECO-10] + + In addition, there are available as a convenience abbreviations + of two frequently used type out commands. Each one consists of a + single character, and must be the very first character typed + after TECO prints its prompting asterisk. Each of these commands + takes effect immediately; there is no need to follow any of + these commands by any character. For this reason, these + commands are known as "immediate" commands (see Chapter 4 for + more information on immediate commands). + + + COMMAND FUNCTION + + Immediately execute an LT command. This command is + issued by typing the line feed key as the first keystroke + after TECO's prompt. It causes TECO to move the pointer + ahead one line and then type out the new line. On + terminals without a line feed key, typing has + the same effect. (See also the next command.) + + Immediately execute an LT command. (Action identical to + that of the command above.) This command is available + when an ESCape surrogate is active, and causes TECO to + move the pointer ahead one line and then type out the new + line when a is the first thing typed after TECO's + prompting asterisk. + [RSTS/E only] + + Immediately execute a -LT command. This command is + issued by typing the backspace key as the first keystroke + after TECO's prompt. It causes TECO to move the pointer + back one line and then type the line just moved over on + the terminal. On terminals without a backspace key, + typing has the same effect. + + + + These commands are useful for "walking through" a file, examining + and/or modifying lines one at a time. + + Standard TECO PAGE 18 + Text Modification Commands + + + 1.7 TEXT MODIFICATION COMMANDS + + You can insert or delete text from the buffer using the following + commands: + + + COMMAND FUNCTION + + Itext` Where "text" is a string of ASCII characters terminated + by a character. The specified text is inserted + into the buffer at the current position of the pointer. + The pointer is positioned immediately after the last + character of the insertion. + + K Delete the contents of the text buffer from the current + position of the pointer up to and including the next line + feed character. + + nK Execute the K command n times, where n is a signed + integer. A positive value of n causes the n lines + following the pointer to be deleted. A negative value of + n causes the n lines preceding the pointer to be deleted. + If n is zero, the contents of the buffer from the + beginning of the line on which the pointer is located up + to the pointer is deleted. + + HK Delete the entire contents of the text buffer. + + D Delete the character following the buffer pointer. + + nD Execute the D command n times, where n is a signed + integer. A positive value of n causes the n characters + following the pointer to be deleted. A negative value of + n causes the n characters preceding the pointer to be + deleted. If n is zero, the command is ignored. + + Like the L and C commands, the K and D commands may not execute + across page boundaries. If a K command attempts to delete text + up to and across the beginning or end of the buffer, text will be + deleted only up to the buffer boundary and the pointer will be + positioned at the boundary. No error message is printed. A D + command attempting to delete text past the end or beginning of + the text buffer will produce an error message and the command + will be ignored. + + Standard TECO PAGE 19 + Search Commands + + + 1.8 SEARCH COMMANDS + + The following commands may be used to search the input file for a + specified string of characters. + + + COMMAND FUNCTION + + Stext` Where "text" is a string of ASCII characters terminated + by a character. This command searches the text + buffer for the next occurrence of the specified character + string following the current pointer position. If the + string is found, the pointer is positioned after the last + character on the string. If it is not found, the pointer + is positioned immediately before the first character in + the buffer and an error message is printed. + + Ntext` Performs the same function as the S command except that + the search is continued across page boundaries, if + necessary, until the character string is found or the end + of the input file is reached. If the end of the input + file is reached, an error message is printed. On + VAX/VMS, you can "back up" into the file and continue + editing, although doing so uses TECO features beyond + those introduced in this chapter. Using only basic + features (or a TECO implementation other than VAX/VMS), + you must close the output file and reopen it as an input + file before you can edit the file further. + + Both the S command and the N command begin searching for the + specified character string at the current position of the + pointer. Therefore, neither command will locate any occurrence + of the character string which precedes the current pointer + position, nor will it locate any character string which is split + across a page boundary. + + Both commands execute the search by attempting to match the + command argument, character for character, with some portion of + the buffer contents. If an N command reaches the end of the + buffer without finding a match for its argument, it writes the + contents of the buffer onto the output file, clears the buffer, + reads the next page of the input file into the buffer, and + continues the search. + + Standard TECO PAGE 20 + Sample Editing Job + + + 1.9 SAMPLE EDITING JOB + + The following sample editing job is included to help the new user + to achieve a greater understanding of the basic TECO commands. + The entire terminal output from the editing run is reproduced + intact, with numbers added in the left margin referring to the + explanatory paragraphs which follow. + + + + + 1< *EWDT1:FILE1.TXT`` + 2< *HKIMR. JOHN P. JONES + ! COMPUTER ELECTRONICS CORPORATION + ! BOSTON, MASAASACHUSETTS + ! + ! DEAR MR. JONES: + ! + ! I WAS PLEASED TO RECEIVE YOUR REQUEST FOR INFORMATION + ! PERTAINING TO THE NEW TECO TEXT EDITING AND CORRECTING + ! PROGRAM. + ! + ! ENCLOSED IS A COPY OF THE TECO USERS'S GUIDE, WHICH + ! SHOULD ANSWER ALL OF YOUR QUESTIONS. + ! + ! SINCERELY, + ! + ! + ! + ! + ! `` + 3< *-20LSETTS`I 02150`` + ! *STION`2C13DIREGARDING`` + 4< *SGUIDE`-5DIMANUAL`` + ! *SELY`0T`` + ! SINCERELY*0KIVERY TRULY YOURS`` + ! *HT`` + ! MR. JOHN P. JONES + ! COMPUTER ELECTRONICS CORPORATION + ! BOSTON, MASSACHUSETTS 02150 + ! + ! DEAR MR. JONES: + ! + ! I WAS PLEASED TO RECEIVE YOUR REQUEST FOR INFORMATION + ! REGARDING THE NEW TECO TEXT EDITING AND CORRECTING + ! PROGRAM. + ! + ! ENCLOSED IS A COPY OF THE TECO USER'S MANUAL, WHICH + ! SHOULD ANSWER ALL OF YOUR QUESTIONS. + ! + ! VERY TRULY YOURS, + ! + ! + + Standard TECO PAGE 21 + Sample Editing Job + + + ! + ! + ! + 5< *EX`` + ! (TECO is rerun, operating system dependent) + ! *ERDT1:FILE1.TXT`EWLP:`` + 6< *Y5KIMR. JAMES B. SMITH + ! DATEK ASSOCIATES, INC. + ! 122 MAIN STREET WEST + ! AUSTIN, TEXAS + ! + ! DEAR MR. SMITH: + ! `` + ! *HT`` + ! MR. JAMES B. SMITH + ! DATEK ASSOCIATES, INC. + ! 122 MAIN STREET WEST + ! AUSTIN, TEXAS + ! + ! DEAR MR. SMITH: + ! + ! I WAS PLEASED TO RECEIVE YOUR REQUEST FOR INFORMATION + ! REGARDING THE NEW TECO TEXT EDITING AND CORRECTING + ! PROGRAM. + ! + ! ENCLOSED IS A COPY OF THE TECO USER'S MANUAL, WHICH + ! SHOULD ANSWER ALL OF YOUR QUESTIONS. + ! + ! VERY TRULY YOURS, + ! + ! + ! + ! + ! + ! *EX`` + + + 1) At this point, the user called TECO into memory. TECO + responded by printing an asterisk at the left margin. The user + then entered an EW command, opening an output file called + "FILE1.TXT" on DT1. There is no input file. Upon receipt of the + double (echoed as ``), TECO created the designated output + file, then printed another asterisk at the left margin. + + 2) The user entered a command string consisting of two commands. + The HK command cleared the text buffer (not really necessary, + since it was already empty), and the I command inserted 18 lines + of text into the buffer, including 8 blank lines. TECO executed + these commands upon receipt of the second double . At + this point, the buffer pointer was positioned at the end of the + buffer, following the last line feed character in the text. Note + that the user made an error while typing the word + "MASSACHUSETTS". He typed "MASA", then realized his mistake and + + Standard TECO PAGE 22 + Sample Editing Job + + + struck the DELETE key once to delete the second "A". TECO echoed + the deleted character. The user then typed the correct character + and continued the insertion. + + 3) The user typed -20L to move the pointer to the beginning of + the buffer and SETTS` to position the pointer immediately after + the character string "ETTS" (which terminates the word + "MASSACHUSETTS"). He then used an I command to insert one space + and a five-digit zip code. A second S command positioned the + pointer after the word "INFORMATION". The 2C command moved the + pointer to the beginning of the next line (carriage return and + line feed count two characters), and the user deleted the words + "PERTAINING TO" and replaced them with the word "REGARDING". + + 4) The user continued editing by positioning the pointer after + the word "GUIDE". He then deleted this word, and replaced it + with the word "MANUAL". Finally, he searched for the word + "SINCERELY", typed 0T to determine that the pointer was correctly + positioned between the Y and the comma which follows it, and + typed 0K to delete everything on the line except the comma. He + then inserted "VERY TRULY YOURS" in place of the word + "SINCERELY". An HT command caused the edited text to be printed + at the terminal. + + 5) The command string EX`` caused the contents of the buffer to + be written onto the output file and the output file to be closed. + The user then reentered TECO and reopened the file "FILE1.TXT" as + an input file and specified the line printer as an output file. + + 6) This command string reads the first (and only) page of + "FILE1.TXT" into the buffer, deleted the first 5 lines, replaced + them with a different address and salutation, then printed the + contents of the buffer on the terminal for verification and + finally printed the new version of the letter onto the line + printer. Note that the previous version of the letter still + resides in file "FILE1.TXT" on DT1. + + Standard TECO PAGE 23 + Interlude + + + INTERLUDE + + The rest of this manual is a description of TECO in all its + glory. TECO is a complex editor and has many features because it + has been under development for a long time. (TECO is older than + some of the readers of this manual!) Do not try to understand + everything the first time through. If you find that what you are + reading seems hopelessly obscure, or makes no sense whatsoever, + skip to the next section and come back to it some time later. It + will be a while before you need all of TECO's features. + + This manual is meant to be a reference manual and not a tutorial. + Readers who are first learning TECO may wish to consult the + following document (available from Digital Equipment Corporation) + for more basic material: DEC-10-UTECA-A-D INTRODUCTION TO TECO. + + The commands described in this manual are those implemented in + TECO-11 Version 40, TECO-8 Version 7, and TECO-10 Version 3. + Some of the more obscure commands may not be present under some + operating systems, in which case this is indicated by a note in + the form [Not in TECO-x]. + + This manual also describes some (but not necessarily all) of the + obscure commands that belong to one implementation of TECO but + not to the other implementations. Such commands are flagged by a + note of the form [TECO-x only]. These commands are not to be + considered part of the so-called "Standard TECO" and should not + be used in applications that may be run on multiple operating + systems. Consult also the appendices for commands that are very + operating system dependent. + + Standard TECO PAGE 24 + Invoking TECO + + + CHAPTER 2 + + + INVOKING TECO + + + 2.1 RUNNING TECO + + To run TECO with no special options or defaults, use the same + command on your operating system that you would use to run any + other program. The command is system dependent but is usually + something like + + RUN TECO + + Consult the appendix that describes your operating system's + characteristics for details. + + + 2.2 CREATING A NEW FILE + + As described in Chapter 1, most operating systems use the same + command to invoke TECO for the purpose of creating a new file: + + MAKE filespec + + The "MAKE filespec" command takes as its single argument the file + specification for the file to be created. This file + specification must conform to the conventions used by your + operating system. If a file by that name already exists, TECO + will give you a warning message telling you that you are + superseding an existing file. + + The MAKE command invokes TECO and performs an effective + EWfilespec`` command, as described in Chapter 1. + + + 2.3 EDITING AN EXISTING FILE + + As Chapter 1 states, most operating systems use the same command + to invoke TECO for the purpose of editing an existing file: + + TECO filespec + + The "TECO filespec" command takes as its argument the file + specification for the file to be edited. The file will be opened + for input and output, with back-up protection. That means that + the system will save the original version of the source file (in + case you 'blow' the edit). If your operating system supports + file version numbers, a new version will be created. If your + operating system does not support file version numbers, the + original file will be preserved in a file with the same name but + with a backup extension (.BAK). + + Standard TECO PAGE 25 + Editing an Existing File + + + The TECO command invokes TECO and performs an effective + EBfilespec`Y`` command. Note that the first page of the file is + brought into memory and that the text buffer pointer is + positioned at the start of the file. + + If, at any time during the edit, you discover that the edit is + invalid, slowly (so TECO can respond to them) type enough + s to get you back to the operating system. You will find + that your original file has been preserved. + + TECO remembers the filespec given in a MAKE or TECO command. If + TECO is invoked with the command "TECO", with no filespec, it + will open the file edited last (i.e., the remembered filespec). + + + 2.4 SWITCHES ON TECO and MAKE COMMANDS + + The TECO and MAKE commands can take switches (qualifiers) of the + form /SWITCH. These switches are described below. + + + SWITCHES ON COMMAND LINES + + System Switch Meaning + + RSTS/E /SIZE:n start with nK word editing area + /SIZE:+n start with nK additional words of + editing area + + RSTS/E + RSX-11 + VAX/VMS /INSPECT Do not create an output file + /FIND Initially position to the position + marker left in the file by the VTEDIT + macro and delete the marker. + /NOCREATE Do not automatically create a new file + if the file specified by the TECO + command does not exist. + /NOINI Do not use TECO.INI to perform + initialization + /NOMEMORY Do not remember the argument to the + invocation command. + /SCROLL Automatically enter split screen + scrolling mode, using 1/4 of the + screen's lines as the scrolling area + (available on VT100 terminals only). + /VTEDIT Load VTEDIT video terminal editor + + The /SCROLL switch may take a value of the following form: + + /SCROLL:n Enter split screen scrolling mode, using + n lines for the scrolling area. + + Standard TECO PAGE 26 + Switches on TECO and MAKE Commands + + + The /VTEDIT switch may also take values (of the form :value). + + /VTEDIT:HOLD Start up in hold screen mode + /VTEDIT:SEEALL Start up in SEEALL mode + + These values can be combined, viz.: /VTEDIT:HOLD:SEEALL. + + + 2.5 INVOKING A TECO PROGRAM + + All operating systems except TOPS-10 and TOPS-20 use the same + command to let you start up execution of a TECO program (macro). + This is the MUNG command. + + The MUNG command has the form + + MUNG filespec + + where filespec is the name of the TECO program that is to be run. + If no file extension (file type) is specified, .TEC is assumed. + This command executes the TECO code that appears within the + specified file. It invokes TECO and performs an effective + EIfilespec`` command (consult the appendices for operating-system + dependent differences). The contents of the specified file + should generally end with a double ESCAPE so that execution will + start immediately. + + Another form of this command is + + MUNG filespec,data + + where "data" is any string of ASCII characters to be passed to + the TECO program. This version of the MUNG command invokes TECO + and issues an effective + + Idata`EIfilespec`` + + command. Under TECO-11, a space, tab, or a slash (/) may be used + instead of the comma. + + Standard TECO PAGE 27 + Invoking a TECO Program + + + 2.6 USER INITIALIZATION + + You can specify initialization commands to TECO by creating a + file called TECO.INI. If, upon start-up, TECO finds a file + called TECO.INI in your area, TECO executes the commands in that + file. You can use TECO.INI commands to set initial values of + flags and to tailor TECO to your needs. You must, however, be + very careful in constructing code for your TECO.INI file: an + error in this code may keep TECO from running at all! + + If you include unusual commands in your initialization file, you + would be prudent to surround such commands with the ? command. + This causes TECO to type the commands out when they are executed + (see section 5.18.4). You should also print an informative + message on the terminal reminding other users that this version + of TECO has been customized. + + Example 1: + + ?1ED? + + The user initialization file sets the ED flag to 1 so that ^ + characters in search strings have their traditional meaning (do + not convert the next character to a control character). The file + also causes the command to be typed out when it is executed. + + Example 2: + + 0,16ED ^A[Dot preserved on failing searches]^A 13^T 10^T + + The user initialization file causes future search string failures + to preserve the pointer position. It also prints a message + informing all users of this feature. + + Standard TECO PAGE 28 + User Initialization + + + In TECO-11, the TECO.INI commands may return a value to the + command processor. Such a value, if present, is interpreted as a + set of bit encoded flags that control the startup processing. + The following bits may be set: + + Value&1 Automatically load the VTEDIT macro (as if + the user had typed TECO/VTEDIT). + + Value&4 Inhibit use of the memory file (as if the + user had typed TECO/NOMEMORY). + + Value&16 Automatically load VTEDIT and start it in + SEEALL mode (as if the user had typed + TECO/VTEDIT:SEEALL). + + Value&32 Automatically load VTEDIT and start it in + HOLDSCREEN mode (as if the user had typed + TECO/VTEDIT:HOLD). + + Value&128 Automatically enter split screen scrolling + mode (as if the user had typed TECO/SCROLL). + + Value&256 Inhibit automatic creation of the output file + if the input file does not exist (as if the + user had typed TECO/NOCREATE). + + For additional information on initialization, consult the + operating system specific appendices. + + Standard TECO PAGE 29 + Conventions and Structures + + + CHAPTER 3 + + CONVENTIONS AND STRUCTURES + + + 3.1 TECO CHARACTER SET + + TECO accepts the full 8-bit ASCII character set. (In other than + TECO-11, characters typed at the console have their 8th bit + trimmed off. If your terminal does not transmit or receive all + of the ASCII codes, you can still insert the full character set + into your TECO buffer, using special commands (see section 5.6). + + For more information on TECO's handling of 8-bit characters + (including on terminals capable of displaying only 7-bit data), + see the description of the 4096 ET bit, in section 5.16. + + When TECO is maintaining a window into the text buffer, a special + facility (called "SEEALL" or "View All" mode) is available to + explicitly show certain characters which normally do not print, + such as , , and . This mode is controlled by the + 3:W flag, which is described in section 5.17. + + TECO command strings may be entered using upper case characters + (as shown throughout this manual) or lower case characters. For + example, the commands MQ, mQ, Mq, and mq are executed + identically. A file containing upper and lower case text can be + edited in the same way as a file containing upper case only, + although this may be clumsy to do from an upper case only + terminal. TECO can be set to convert lower case alphabetics to + upper case as they are typed in; commands to enable or disable + lower case type-in will be presented in section 5.16. + + Control characters are generally echoed by TECO as a caret or + up-arrow followed by the character. Some control characters, + such as (form feed) and (bell) echo as the + function they perform. In many cases, you can type a control + character as a caret (up-arrow) followed by a character, and it + will be treated as if it had been entered using the control key. + + There are exceptions to the interchangeable use of the CONTROL + key and the caret. When a control character is used as the + delimiter of a text string (as explained in Section 3.2.2 below), + it must be entered in its form. This form must also be + used if the control character is the second character of a + two-character command, or is being entered as an immmediate + action command. Since certain control characters have special + meaning in text arguments, some of them (such as and + ), must be entered into a text string using the CONTROL + key and preceded by , ^Q, , or ^R. + + Standard TECO PAGE 30 + Conventions and Structures + + + 3.2 TECO COMMAND FORMAT + + Each TECO commands consists of one or two characters. + + TECO commands may be strung together (concatenated) into a + command string. If a command in the string returns numeric + value(s), it or they will be passed to the following command. + + + NOTE + + Most commands which return a value are expressly designed + for that purpose. A few commands (such as n%q and m,n:W, + q.v.) can be used to cause an action, and also return a + value. Good programming practice suggests following such + a command with or caret-[ if the returned value + is not intended to affect the following command. + + + A TECO command may be preceded by one or two numeric arguments. + Some TECO commands may be followed by a text argument. Many TECO + commands can be modified by "@" (see section 3.2.2) and/or by ":" + (see section 3.2.3). + + When TECO commands are concatenated into a command string, no + delimiter is necessary between commands except for one necessary + to delimit a text argument or one as suggested in the note above. + + TECO commands are accumulated into a command string as they are + typed. The command string is executed when it is terminated by + typing two consecutive characters. TECO then executes + the commands in the order in which they appear in the command + string, until the string is exhausted or an error occurrs. (Some + TECO commands cause branching or looping, so altering the order + of execution.) + + TECO's character is (internally) the ESCape (octal 33). + Because newer terminals use the ESCape character as part of + control sequences (and some terminals no longer even possess an + ESCape key), provision is made for you to designate a key on your + terminal to cause an ESCape to be sent to TECO -- that is, to act + as an ESCape surrogate. (See the EE flag and the 8192 ET bit, + section 5.16.) Because the key you press to delimit text strings + and TECO commands may be the ESCape key or may be the surrogate, + this manual uses the indirect term to mean whichever one + you are using. When an ESCape surrogate is active, the character + you see is `. (When no surrogate is active, you see $.) This + manual uses the ` character. + + Standard TECO PAGE 31 + Conventions and Structures + + + 3.2.1 Numeric Arguments + + Most TECO commands may be preceded by a numeric argument. Some + numeric arguments must be positive; others can be negative or + zero. The maximum size of any numeric argument is restricted, as + summarized in the following table: + + Signed Unsigned + System Min Max Max + TECO-8 -2**12+1 +2**12-1 2**13-1 + TECO-10 -2**34 +2**34-1 2**35-1 + TECO-11 -2**15 +2**15-1 2**16-1 + + TABLE 3-1 Restrictions on numeric arguments + + Exceeding these ranges of values can cause unpredictable results. + So can using a negative argument with a command that takes only + an unsigned argument. + + Numeric arguments can be used in the following ways: + + - Character commands such as J, C, R, and D take a single + numeric argument which represents the number of + characters that the command is to act on. + + - Such commands as P, PW, and < perform an action that + can be repeated. The numeric argument is the + repetition count. + + - Some commands, such as ED, ET, ^E, ^X, ES, EU, and EV, + control the setting of variables called flags. When a + numeric argument is specified, the value of that + argument becomes the new value of the associated flag. + When no numeric argument is specified, these command + return the value of the associated flag. + + - Line commands such as T, K, X, FB, and FC operate on + lines. They take zero, one, or two numeric arguments. + If one argument (n) is specified, it represents the + number of lines over which the command is to have + effect, beginning at the current buffer pointer + position. A positive (non-zero) n affects a text + running from the current pointer position to the nth + following line delimiter. A negative n affects a text + running from the pointer back to the beginning of the + line containing the nth previous line delimiter. When + n is zero, the affected text runs from the beginning of + the current line to the current pointer position. When + n is omitted, n = 1 is assumed. + + When a line command contains two numeric arguments + (m,n), these represent the pointer positions between + which text is affected. Unless the description of the + + Standard TECO PAGE 32 + Conventions and Structures + + + command says the order of these two arguments is + important, they may be entered in either order. + + When a command that normally takes an argument is specified with + no argument, TECO executes the command in the most common or most + useful way, as shown in the following table: + + Command Default Argument Default Action + + C 1 Advance 1 character + R 1 Back over 1 character + L 1 Advance 1 line + J 0 Jump to start of buffer + V 1 View 1 line + D 1 Delete 1 character + K 1 Kill 1 line + S, N, etc. 1 Search for first occurrence + % 1 Increment Q-register by 1 + X 1 Extract one line + + Table 3-2 Default Arguments + + These default arguments reduce the number of keystrokes needed + for common TECO actions. + + + 3.2.2 Text Arguments + + Many TECO commands take a text (character string) argument. The + string is placed immediately after the command and consists of a + sequence of ASCII characters terminated by a character + (or in the case of ! and ^A commands, by the command character). + The string of ASCII characters may not include a , since + this would terminate the string prematurely, but may include any + other character. (Some characters may be difficult to enter from + a terminal because they are TECO immediate action commands or + because they have been filtered out by the operating system). + + Examples of text arguments: + + Sabc` Search for the string "abc" + + ^UAHELLO` Insert the text "HELLO" into + Q-register A + + OBEGIN` Branch to the tag specified by + the string "BEGIN" + + Some TECO commands require two text arguments. Each argument + must be followed by a character, as follows: + + FSabc`def` Replace string "abc" by "def" + + Standard TECO PAGE 33 + Conventions and Structures + + + You can include a character in a text string by using + another format of text argument. In this alternate form, the + string is delimited on both sides by any ASCII code that does not + otherwise appear in the string. You signal that this format is + being used by inserting an @ character before the command, as + follows: + + @ER5TEST.FOR5 Open the file "TEST.FOR" for + input. The delimiter used is + "5" + + @^A+Hello out there!+ Type the message "Hello out + there!" on the terminal. The + delimiter is "+" + + Unpredictable results will occur if another TECO command + intervenes between an @ sign and the command that it is supposed + to affect. Note that a control character used as a delimiter + must be entered as (that is, in its single-keystroke + form). + + + + 3.2.3 Colon Modifiers + + The colon (:) command modifies the action of the next command. + In some cases, it will cause the next command to return a value + indicating whether it has failed or succeeded. A zero (0) + indicates that the command has failed, while a -1 indicates that + it has succeeded. The colon modifier is used this way with such + commands as :ER, :EB, :EN, :S, :N, :FS, :FN, :FB, and :FC. If + the next sequential command requires a positive argument, the -1 + is interpreted as the largest possible positive number. In other + cases, such as :Gq and :=, the colon modifier changes the meaning + of the command. Unpredictable results may occur if you place a + colon directly before a TECO command that does not normally + accept a colon modifier. + + If both the : and the @ (string delimiter) are used with the + same command, they may be placed in either order. + + Standard TECO PAGE 34 + Conventions and Structures + + + 3.3 DATA STRUCTURES + + A good way to begin the study of a programming language is to + forget the commands, for the moment, and concentrate instead on + the data structures. This section follows that approach, + describing both the values on which TECO operates and the buffers + and registers in which these values are stored. + + TECO manipulates two types of data, namely, + + o The character string: a sequence of zero or more ASCII + characters, and + + o The integer: a numeric value that may be signed or + unsigned. + + + The text that TECO edits is, of course, a character string. Less + obviously, the command string by which the user controls TECO is + also a character string. The counters and indices for character + string manipulation, and the repetition counts for loops are + integers. + + Character strings and integers have distinct internal + representation and this is reflected in the design of the TECO + commands. Commands designed for character strings do not work on + integers and vice versa. + + The data structures described in this section are frequently + applied to character strings. Structure is never "built into" + the data, but rather is attributed to the data by particular + commands and conventions. Thus "lines" of characters are + recognized by line manipulation commands, but not by character + manipulation commands, which view an end-of-line character as + just another ASCII code. + + The following are definitions for the line and the page in TECO: + + o Any character string can be divided into TECO lines by + considering the line to be ended by either + + a line feed (octal 12) + a form feed (octal 14) + a vertical tab (octal 13) or + the end of the given character string + + o Any character string can be divided into TECO pages by + considering the page to be ended by either + + a form feed (octal 14) or + the end of the given character string + + Standard TECO PAGE 35 + Conventions and Structures + + + These data structures are used to achieve two quite separate + results: the formatting of type out and the logical division of + data. + + + 3.3.1 Text Buffer + + The main storage of TECO is the text buffer. The text buffer + stores a single character string that TECO edits. A text buffer + pointer is used to address text in the buffer; it is moved about + by many TECO commands. The text buffer pointer never points to + characters in the buffer; it is always pointing at pointer + positions (between characters). The available pointer positions + in the text buffer are sequentially numbered beginning with 0. + Pointer position 0 is the position at the start of the buffer, + just to the left of the first character. Pointer position 1 is + the next position, just to the right of the first character, etc. + As an example, suppose the text buffer contains the string + FOOBAR. Then seven text buffer pointer positions are determined + as shown by the arrows in the following figure: + + F O O B A R + | | | | | | | + 0 1 2 3 4 5 6 + + + Note that there are 6 characters in the buffer and that the + highest numbered pointer position is 6. The pointer position + number is equal to the number of characters preceding that + position. + + Useful definitions of "current" objects are made with respect to + the text buffer pointer as follows: + + 1. The current character of the text buffer is the + character just to the right of the pointer. If the + pointer is at the end of the text buffer, there is no + character to the right of the buffer pointer, and the + current character does not exist. + + 2. The current line of the text buffer is the TECO line + that contains the current character. In the special + case that the pointer is at the end of the buffer, the + current line is everything back to (but not including) + the last end-of-line character. + + 3. The current page of the text buffer is the TECO page + that contains the current character. In the special + case that the pointer is at the end of the buffer, the + current page is everything back to (but not including) + the last form feed character (or the beginning of the + buffer). + + Standard TECO PAGE 36 + Conventions and Structures + + + When the text buffer pointer is at the end of the text buffer and + the last character of the buffer is an end-of-line character, + then the current line is an empty string according to the + definition just given. In this case, TECO performs the required + operation on this empty string. For example, if the pointer is + at the end of the buffer and TECO is commanded to kill (delete) + the next 3 lines, then the empty string is killed 3 times. + Similarly, if the pointer is at the end of the buffer and TECO is + commanded to advance the pointer 5 lines, the pointer will remain + at the end of the buffer. No error message will be given. In a + like fashion, if the pointer is at the end of the first line of + the buffer, and TECO is instructed to extract the previous 4 + lines (into a Q-register), then only the first line is extracted + since it is presumed to be preceded by 3 empty lines. + + + + 3.3.2 Q-registers + + TECO provides data storage registers, called Q-registers, which + may be used to store single integers and/or ASCII character + strings. Each Q-register is divided into two storage areas. In + its numeric storage area, each Q-register can store one signed + integer. In its text storage area, each Q-register can store an + ASCII character string (which can be any text, including the + important case of a TECO command string). + + There are global Q-registers and (in TECO-11) local Q-registers. + + In every TECO, there are 36 global Q-registers, each of which has + a one-character name: A through Z and 0 through 9. The global + Q-registers are available to all macro levels, including + "outside" macros altogether (that is, at prompt level). + + In TECO-11, there are additionally 36 local Q-registers, each of + which has a two-character name: .A through .Z and .0 through .9. + Effectively, there is a complete and unique set of local + Q-registers available to each and every macro level, including + prompt level. TECO automatically saves and restores a given + macro level's local Q-registers around execution of a nested + (lower level) macro. When a macro is invoked via an Mq command + (where the command is not colon-modified, and q is a global + Q-register), the current set of local Q-registers is saved and a + new set of local Q-registers created. When the macro exits, its + local Q-registers are destroyed and those of the calling macro + level are restored. (If a fatal error occurs and TECO goes back + to prompt level, local Q-registers from all macro levels are + destroyed and prompt level's set is restored.) + + (A new set of local Q-registers is not created when the command + is colon-modified, as in :MA, or when the invoked macro itself + resides in a local Q-register, as in M.A -- see Table 5-9C.) + + Standard TECO PAGE 37 + Conventions and Structures + + + A local Q-register name can be used in any command that takes a + Q-register name. + + Various TECO commands allow the storing and retrieving of numeric + values from the numeric storage areas of the Q-registers. Other + TECO commands allow the storage and retrieval of strings from the + text storage areas of the Q-registers. + + + + 3.3.3 Q-register Push-down List [not in TECO-8] + + The Q-register pushdown list is a stack that permits the numeric + and text storage areas of Q-registers to be saved (the [ command) + and restored (the ] command). The command sequence [A ]B + replicates the text string and numeric value from Q-register A + into Q-register B. (Note that in TECO-11, macros can be written + to use local Q-registers, avoiding the need to save and restore + Q-registers via the pushdown list.) + + + + 3.3.4 Numeric Values and Flags + + TECO has many special numeric values and flags which are + accessible through TECO commands. Some of these values, such as + the text buffer pointer, reflect the state of TECO. Others + control TECO's behavior in various ways. + + Standard TECO PAGE 38 + Command String Editing + + + CHAPTER 4 + + COMMAND STRING EDITING + + + 4.1 Immediate Action Editing Characters + + While you are typing command strings at a terminal, TECO + considers certain ASCII characters to have special meaning. Most + of the special characters cause TECO to perform a specified + function immediately, without waiting for the double + which normally be required to terminate a command string. + Immediate action editing characters may be entered at any point + in a command string - even in the middle of a command or text + argument. + + Many immediate action editing characters, such as (which + deletes the immediately preceding character), cannot be used as + regular TECO commands. For instance, if you enter a + into a command string which is to be later executed as a macro, + the will not delete a character as part the execution of + the macro. + + Some characters, like , are both regular TECO commands + and immediate action commands. The command string ^Uqtext` + enters the specified text into Q-register q. However, + typed while entering a command string is an immediate action + editing character which deletes the current line. Thus you + cannot type a (or any similar sequence) directly into + TECO as part of a command string. Nevertheless, is + still a valid TECO command; should TECO encounter it in a macro + or indirect file, it will have its regular TECO effect + (^Uqtext`). + + Control characters used as immediate action editing characters + must be entered using the CONTROL key; they will not be + recognized if entered in their caret or up-arrow form. + + Table 4-1 lists the immediate action editing characters and + explains their functions. + + Standard TECO PAGE 39 + Command String Editing + + + TABLE 4-1: IMMEDIATE ACTION EDITING CHARACTERS + + These characters take immediate effect and are used to edit a + command string as it is being entered: + + CHARACTER EXPLANATION + + + The double character sequence tells TECO + to begin execution of the command string just + typed in. It inserts two s into the + command string. ( may be generated by + pressing a key designated by the user as an + "ESCape surrogate" or by pressing an actual ESCape + key. In the former case, `` is echoed; if no + ESCape surrogate has been designated, $$ is + echoed. See the EE flag and the 8192 ET bit, + section 5.16, for more information.) + + The two s must be typed successively. If + any other character is typed in between the two + s (even if subsequently DELETEd), then the + two s might be treated simply as two + s to be entered into the command string + rather than as an immediate action command. + + If you need to enter two s into a command + line, as in the case where you want to use the + FSstring`` command to delete a string, you can + keep TECO from recognizing `` as an immediate + action command. Type + and then continue + entering the remainder of your command string. + + A single character can also be an + immediate action command (when typed immediately + after TECO's prompting asterisk, see section 4.2). + Elsewhere, a single performs no immediate + action. + + Typing a DELETE character (DEL or RUBOUT on some + terminals) deletes the last character typed. + DELETE can be typed repeatedly to erase multiple + characters. TECO echoes the deleted character + whenever a DELETE is typed, indicating to you that + the character has been rubbed out. If you are + doing your editing on a scope terminal, then the + action of this key is different: the character + that has been rubbed out will disappear from the + screen of your editing terminal and the cursor + will be moved back one position. + + If you delete a line feed, form feed, or vertical + + Standard TECO PAGE 40 + Command String Editing + + + tab, the cursor will move up the screen and + position itself at the end of the text that + immediately preceded the line feed, form feed, or + vertical tab. + + echoes as ^C (Caret-C) and aborts the + entering of the command string. The exact action + of the key depends on the operating + system being used (See appendices). + + causes the current line of the current + command line to be deleted. TECO echoes the + character as ^U followed by and an + asterisk prompt. If you are using a scope + terminal, the visible action of typing this key is + different. The current line physically disappears + from the screen and the cursor is positioned back + at the beginning of the line. + + + Typing two consecutive characters causes + all commands which have been entered but not + executed to be erased. (If the terminal has a + bell, it will ring.) This command is used to erase + an entire command string. A single + character is not a special character. + + + followed by a space causes the line + currently being entered into the command string to + be retyped. + + * followed by an asterisk causes all the + lines typed by the user from the last TECO prompt + (the asterisk) to be retyped. + + Typing a carriage return enters a carriage return + followed by a line feed into the command string. + To enter a carriage return without a line feed, + type . + + + RSX-11 TECO uses the triple command as an + immediate action command. See the appropriate + appendix for more details. + + The character is used as an end-of-file terminator in + some contexts on some operating systems. While its presence is + usually harmless in disk files, it may cause premature end of + file if the file is copied to other media (e.g., paper tape). + + Standard TECO PAGE 41 + Command String Editing + + + 4.2 Immediate Action Commands + + TABLE 4-2: IMMEDIATE ACTION COMMANDS + + The following commands take effect if (and only if) they are + typed as the very first keystroke(s) after TECO issues its + asterisk prompt. + + The , , and commands are also described in + Chapter 1, where they are introduced as "immediate inspection + commands". + + CHARACTER EXPLANATION + + ? If the previous command aborted because of an + error, this immediate action command causes TECO + to print the erroneous command string from the + beginning of the current macro level up to and + including the character that caused the error. + + / If TECO has just printed an error message, type + this immediate action command to receive a more + detailed explanation of the error. (On VAX/VMS, a + HELP command is also available. See section + G.13.) + [In TECO-11, implemented only on VAX/VMS] + + Typing this immediate action command, line feed, + as the first keystroke after TECO's prompt causes + TECO to immediately execute an LT command. This + aid lets you "walk through" a file on a non-scope + terminal. (If the EV flag is non-zero, then the T + portion of this command is redundant and therefore + is not performed.) If you are already positioned + at the end of the text buffer, TECO-11 will not + type out anything. + [Not in TECO-10] + + Typing this immediate action command, , is + synonymous with typing the immediate action + command (described above). This command is + available on TECOs offering the ESCAPE surrogate. + [TECO-11 only] + + Typing this immediate action command, backspace, + (as the first keystroke after TECO's prompt) + causes TECO to immediately execute a -LT command. + (If the EV flag is non-zero, then the T portion of + this command is redundant and therefore is not + performed.) + [Not in TECO-10] + + ^W Typing this immediate action command, , as + + Standard TECO PAGE 42 + Command String Editing + + + the first keystroke after TECO's prompt when + split-screen scrolling is active causes TECO to + re-paint the buffer display portion of the screen. + (Split-screen scrolling is active when 7:W is + non-zero.) This command is useful if the display + has been "confused" by characters from a broadcast + message or type-ahead. It is also useful in + conjunction with ED's 128 bit (which inhibits all + automatic scroll display updating). + [TECO-11 only] + + *q When an asterisk followed immediately by a + Q-register name (any alphanumeric character, here + represented by q) is the first keystroke after + TECO's prompt, TECO places the previous command + string into Q-register q. [In TECO-8, only the *Z + command is permitted, and TECO will automatically + type the Z.] Note that since *q is itself an + immediate action command, it may not be edited + with other immediate action commands. In other + words, you can't use DELETE to delete an + incorrectly typed *. + + [In TECO-10, *q must be followed by + .] + + Standard TECO PAGE 43 + Command String Editing + + + 4.3 Introduction to Macros + + One of TECO's powerful features is the ability to execute ASCII + text stored in a Q-register as a command string. This is called + the "macro" facility, and a command string so stored and executed + is called a "macro". + + A Q-register may be loaded with a macro by any of several means: + directly from the console (via the ^Uq command), by extraction + from the text buffer (via the X command), or by these or other + Q-register loading commands contained in an indirect file or even + in another macro. + + Particularly handy is the "*" immediate action command, discussed + in a preceding section. When you type this command as the first + character following TECO's asterisk prompt, whatever immediately + preceding command you just typed at the console is saved in a + Q-register. You can then use that command again (and repeatedly) + by using the Mq command. + + You invoke a macro by using the Mq command, where "q" is the name + of the Q-register in which the macro text has been stored. + + A related facility is that of immediate ESCAPE-sequence commands, + which is discussed in the following section. + + Standard TECO PAGE 44 + Command String Editing + + + 4.4 Immediate ESCAPE-Sequence Commands [TECO-11 only] + + Certain keys on many newer terminals generate ESCape sequences. + TECO provides a facility by which you can cause the pressing of + one of these keys at the prompting asterisk to be interpreted as + an immediate command. When this facility is enabled, a key such + as one of the cursor control keys can cause TECO to immediately + execute commands (previously stored as a macro). The single + keystroke suffices; no is needed. + + The 32 bit in the ED flag enables immedate ESCape-sequence + commands. When ED's 32 bit is non-zero, and the first character + TECO receives after its * prompt is ESCape, TECO will + automatically read further characters and attempt to decode an + ESCape sequence. The decoded ESCape sequence is resolved into a + pair of numeric values, which are then passed to the macro + residing in global Q-register A. + + The two numeric values are a type code and a value code. They + are passed to the macro in QA by an effective ,MA``. + The macro in QA can retrieve them by code such as: + UA ! Save the code in QA ! + @O!T0,T1,T2,T3! ! Dispatch on code ! + !T0! ! Type 0 codes come here ! + QA@O!V0,V1,V2... + + The and codes are as follows. + + Type 0 - ESCape followed by a control character + The code is the control character's code (0 - 31.) + + Type 1 - ESCape followed by a letter (e.g., ESC A), -or- + ESCape followed by [ then a letter (e.g., ESC [ A), -or- + CSI followed by a letter (e.g., CSI A), -or- + ESCape, O, then an uppercase letter (e.g., ESC O A) + The code is the letter's ASCII value, + trimmed to 5 bits (that is, a value of 0 through 31) + Common keys of 1 are: + Up arrow 1 1 + Down arrow 1 2 + Left arrow 1 4 + Right arrow 1 3 + PF1 1 16 + PF2 1 17 + PF3 1 18 + PF4 1 19 + ENTER 1 13 + + Standard TECO PAGE 45 + Command String Editing + + + Type 2 - ESCape followed by ? then a letter (e.g., ESC ? p), -or- + ESCape, O, then an lowercase letter (e.g., ESC O p) + The code is the letter's ASCII value, + trimmed to 5 bits (that is, a value of 0 through 31) + Common keys of 2 are: + Keypad , 2 12 + Keypad - 2 13 + Keypad . 2 14 + Keypad 0 2 16 + Keypad 1 2 17 + Keypad 2 2 18 + Keypad 3 2 19 + Keypad 4 2 20 + Keypad 5 2 21 + Keypad 6 2 22 + Keypad 7 2 23 + Keypad 8 2 24 + Keypad 9 2 25 + + Type 3 - ESCape followed by [ then a digit string then ~ -or- + CSI followed by a digit string then ~ + The code is the value of the digit string. + All of the LK201 keyboard's editing and function + keys generate sequences of this format. + + Standard TECO PAGE 46 + Command String Editing + + + 4.5 Operating System Character Filters + + In general, TECO accepts any ASCII character, whether encountered + in a macro, read from an indirect file, or entered directly via a + command string from the terminal. (Note that TECOs other than + TECO-11 strip the eighth bit on command input.) In addition, some + operating systems filter out certain characters typed at a + terminal and do not pass them to TECO. So that you can be aware + of the possible difficulty of entering these characters directly + into a TECO command string, we list them below in Table 4-5. + Note that these characters are still valid characters to TECO, + but may have to be entered indirectly, such as by using the nI` + command. + + ^T Note: + On some operating systems, the ^T character is an + immediate action command (to the operating system), and + invokes a one-line status report. + + Where reference is made below in Table 4-5 to this + note, TECO causes the operating system's recognition of + ^T to be turned off if TECO ever asks the user for + input. The original state of ^T handling is restored + upon exit. MUNGed TECO macros that never ask the user + for input do not affect the operating system's handling + of ^T. + + Standard TECO PAGE 47 + Command String Editing + + + TABLE 4-5: OPERATING SYSTEM CHARACTER FILTERS + + SYSTEM CHARACTER SYSTEM's USE + + RT-11 ^A VT11 support [only if GT ON] + ^B Background control [F/B systems only] + ^E VT11 support [only if GT ON] + ^F Foreground control [F/B systems only] + ^O Output control + ^Q Terminal Synchronization + ^S Terminal Synchronization + + RSTS/E ^O Output control + ^Q Terminal Synchronization + ^S Terminal Synchronization + + VAX/VMS ^O Output control + ^Q Terminal Synchronization + ^S Terminal Synchronization + ^T System status (see ^T Note above) + ^X Cancel Type-ahead + ^Y Process Interruption + + RSX-11 ^O Output control + ^Q Terminal synchronization + ^S Terminal synchronization + ^X Task control [RSX-11D only] + + TOPS-10 ^C^C Job interruption + ^O Output control + ^Q Terminal synchronization + ^S Terminal synchronization + ^T System status + + TOPS-20 ^C^C Job interruption + ^O Output control + ^Q Terminal synchronization + ^S Terminal synchronization + ^T System status + + OS/8 ^B Background control [F/B systems only] + ^F Foreground control [F/B systems only] + ^Y Reboot indicator [F/B systems only] + + Standard TECO PAGE 48 + Command Descriptions + + + CHAPTER 5 + + + COMMAND DESCRIPTIONS + + + This chapter presents a detailed description of the full TECO + command set, functionally organized. It assumes that the reader + is familiar with the elementary TECO commands presented earlier. + + In the sections following, the letters "m" and "n" are used in + command formats to represent numerical arguments. These may be + either simple integers or complex expressions. The letter "q" + represents any Q-register. + + Standard TECO PAGE 49 + File Selection Commands + + + 5.1 FILE SPECIFICATION COMMANDS + + You must specify an input file whenever you want TECO to accept + text from any source other than the terminal. You must specify + an output file whenever you want to make a permanent change to + the input file. Input and output files are selected by means of + file specification commands. + + File specification formats are operating system dependent and are + fully described in the operating characteristics appendices at + the end of this manual. + + Almost every editing job begins with at least one file + specification command. Additional file specification commands + may be executed during an editing job whenever required; + however, TECO will keep only one input file and one output file + selected at a time. + + TECO-11 recognizes two input and two output "streams" called the + primary and secondary streams. The primary input and output + streams are initially selected when TECO is invoked. Most file + selection commands, and all of the other TECO commands (page + manipulation, etc.), operate on the currently selected input + and/or output stream. + + The following sections list all of the file specification + commands. Unless otherwise noted, all of these commands leave + the text buffer unchanged. Examples of some of these commands + appear in Chapter 1. + + + 5.1.1 File Opening Commands + + The following commands are used to open files for input and + output: + + + TABLE 5-1A: FILE SPECIFICATION COMMANDS + + COMMAND FUNCTION + + EBfilespec` Edit Backup. This command is recommended for most + editing jobs. It is used for files on + file-structured devices only. It opens the + specified file for input on the currently selected + input stream and for output on the currently + selected output stream. The EB command also keeps + the unmodified file (the latest copy of the input + file) available to the user; details of this + process are system dependent (See appendices). + + ERfilespec` Edit Read. Opens a file for input on the + currently selected input stream. + + Standard TECO PAGE 50 + File Opening Commands + + + EWfilespec` Edit Write. Opens a file for output on the + currently selected output stream. + + :EBfilespec` Executes the EB command, and returns a numeric + value. -1 returned indicates success: the file + is open for input. A 0 indicates the specified + file could not be found, and no error message is + generated. Other errors (e.g., hardware errors, + protection violations, etc.) generate messages and + terminate command execution as usual. + + :ERfilespec` Executes the ER command, and returns a numeric + value. See the :EB command, above. + + Standard TECO PAGE 51 + File Specification Switches + + + 5.1.2 File Specification Switches + + Various system-dependent switches (qualifiers) of the form + /SWITCH can be used with the file specification in ER, EW, and EB + commands. These switches are listed below. Consult the + operating system specific appendices for further details. + + In addition, on some systems switches are provided for convenient + handling of BASIC-PLUS or BASIC-PLUS-2 source files which use + or & characters for program line continuation. See Appendix + J for more information. + + + TABLE 5-1B: SWITCHES ON FILE SPECIFICATIONS + + System Switch Meaning + + OS/8 /S Ignore end-of-file (s) on input. + (SUPER TECO mode) + + RSTS/E /B Read and write with unfiltered 8-bit + /n Handle BASIC-PLUS-x line continuation + /B+ Handle BASIC-PLUS line continuation + / Same as /B+ + /B2 Handle BASIC-PLUS-x line continuation + /CLUSTERSIZE:n Specifies output file cluster size + /MODE:n Use non-standard open mode + + VAX/VMS, /B2 Handle BASIC-PLUS-x line continuation + RSX-11 /CR Implied carriage control + /-CR No (internal) carriage control + /FT FORTRAN carriage control + /FTN Same as /FT + /RW Rewind magtape before opening file + /SH Open the file in shared mode + /SHR Same as /SH + /STM Stream format + /VAR Variable format + + TOPS-10 /APPEND Append to existing output file (EW only) + /ASCII File is ASCII + /GENLSN Generate line sequence numbers + /NOIN Don't put user type-in into log file + /NONSTD Open DECtape in non-standard mode + /NOOUT Don't put TECO's type out into log file + (EL only) + /OCTAL Read file in octal + /PROTECT:n Specify protection code + /SIXBIT Read file in pure SIXBIT + /SUPLSN Suppress line sequence numbers + + + 5.1.3 File Close and Exit Commands + + Standard TECO PAGE 52 + File Close and Exit Commands + + + The following commands are used to close files and exit from + TECO: + + + TABLE 5-1C: FILE CLOSE AND EXIT + + EC Moves the contents of the text buffer, plus the + remainder of the current input file on the + currently selected input stream, to the current + output file on the currently selected output + stream; then closes those input and output files. + Control remains in TECO. EC leaves the text + buffer empty. + + EF Closes the current output file on the currently + selected output stream. The EF command does not + write the current contents of the buffer to the + file before closing it. + + EG` Performs the same function as the EC command, but + then exits from TECO and re-executes the last + COMPIL class command (.COMPILE, .LINK, .EXECUTE, + etc.) + [Same as EX in TECO-11] + + EGtext` Performs the same function as the EC command, but + then exits from TECO and passes "text" to the + operating system as a command string to be + executed (see appendices). + + :EGcmd args` Performs operating system function "cmd" passing + that function "args" as arguments. This command + always returns a value as follows: + + -1 Function "cmd" successfully performed. + 0 Function "cmd" is unsupported. + Other Function "cmd" attempted, but failed. The + returned value is the failure status. + + There are four functions that are commonly + defined: + + INI Locates the user's private initialization + TECO macro. + LIB Defines the user's private library of TECO + macros. + MEM Read/write TECO's last edited file memory. + VTE Locates the user's private scope editing + TECO macro. + + These four functions work as follows: + + :EGcmd` Loads Q-register * with the + + Standard TECO PAGE 53 + File Close and Exit Commands + + + requested information. If there is + no information (e.g., no user + private scope editing TECO macro) + then Q-register * is set to the null + string. + + :EGcmd ` Clears the information holder. + Subsequent :EGcmd` commands will set + Q-register * to the null string. + + :EGcmd text` Sets the information holder to + "text". Subsequent :EGcmd` commands + will set Q-register * to "text". + + Consult the appendices for details. + + EK Kill the current output file on the currently + selected output stream. This command, which + purges the output file without closing it, is + useful to abort an undesired edit. Executing the + EK command after an EW which is superseding an + existing file leaves the old file intact. The EK + command also "undoes" an EB command. (See + appendices for details.) + + ELfilespec` Open the specified file for output as a log file. + Any currently open log file will be closed. If + the /APPEND switch is given, future logs will + append to the file (if it already exists). The + default is to supersede. All type-in to TECO and + all type out from TECO goes into the log file. + The log file is automatically closed by the EX and + TECO commands. + [TECO-10 only] + + EX Performs the same function as the EC command, but + then exits from TECO. For safety reasons, this + command is aborted if there is text in the text + buffer but no output file is open. To exit TECO + after just looking at a file, use the command + string HKEX. + + EZfilespec` This command is useful for outputting to magtapes + and DECtapes, on which it initializes (zeros) the + specified output device before switching the ouput + to the primary output stream. In the case of a + magtape, this command rewinds the magtape to load + point. If the output device is a disk, this + command works exactly like the EW command. + [TECO-10 only] + + The (caret/C) command terminates + execution of the current command string and + + Standard TECO PAGE 54 + File Close and Exit Commands + + + returns control to TECO's prompt. (Under TECO-8, + the command currently acts as + .) + + + The ^C command causes an immediate abort + and exit from TECO. Currently open files are not + necessarily closed. See the appendices for more + details. Note that the second may not be + entered in up-arrow mode. + + + 5.1.4 Secondary Stream Commands + + TECO-11 provides secondary input and output streams. These + permit the user to have two input and two output files open at + the same time, and to switch processing back and forth between + them. Each stream maintains its file position independently, so + that one can read from one stream (for example), switch to the + other, and then switch back to the first and resume from where + one left off. In addition, a separate command stream allows one + to execute TECO commands from a file without disturbing either + input stream. + + The following commands manipulate the secondary input and output + streams: + + + TABLE 5-1D: SECONDARY STREAM COMMANDS + [Not in TECO-8 or TECO-10] + + Input commands (do not open or close any file; do not change the + text buffer): + + EP Switches the input to the secondary input stream. + + ER` Switches the input to the primary input stream. + + Output commands (do not open or close any file; do not change + the text buffer): + + EA Switches the output to the secondary output + stream. + + EW` Switches the output to the primary output stream. + + Indirect file commands: + + EIfilespec` Opens a file as an indirect command file, so that + any further TECO requests for terminal input will + come from this file. At end-of-file, or upon + TECO's receipt of any error message, the indirect + command file will be closed and terminal input + + Standard TECO PAGE 55 + Secondary Stream Commands + + + will be switched back to the terminal. Note that + this command only presets where input will come + from; it does not "splice" the file's data into + the current command string. + + While end-of-file closes the indirect command + file, it does not automatically start execution of + commands. Execution will begin only upon TECO's + receipt of two adjacent s. For instance, + assume that FOO.TEC contains valid TECO commands, + that it presets a return to your terminal with the + customary EI`, but that it does not contain an + pair. If you type EIFOO``, TECO will + read in the contents of FOO.TEC (building a + command string) and attempt to continue building + the command string by reading from your terminal + when end of file on FOO.TEC is encountered. + Things will appear "very quiet" until it occurs to + you to type and so begin execution + of the (composite) command string. + + All commands encountered in the indirect file will + have their normal TECO meaning (as opposed to any + immediate action meaning). For example, a + encountered in an indirect file will not + erase the command line in which it occurs. + Instead, it will be treated as the TECO ^Uqtext` + command. The only exception to this rule is the + command, which directs TECO to execute + the preceding command string and then return to + the indirect file at the point following the + . (We can say explicitly here, + because can be other than ESCape only in + commands typed at the console.) + + EI` If an indirect command file is active, this + command will close it and resume terminal input + from the terminal. Any portion of the file after + a double which has not yet been read is + discarded. This command has no effect if no + indirect file is already open. + + Standard TECO PAGE 56 + Wildcard Commands + + + 5.1.5 Wildcard Commands + + TECO-11 supports wild card file processing with a set of special + commands, to allow TECO programs to operate on a set of files. + + + TABLE 5-1E: WILDCARD COMMANDS + [Not in TECO-8 or TECO-10] + + ENfilespec` This command presets the "wild card" lookup + filespec. It is only a preset; it does not open, + close, or try to find any file. The "wild card" + lookup is the only filespec that can contain any + wild card notations. See the appendices for the + allowed wild fields in each operating system. + + EN` Once the wild card lookup filespec has been + preset, executing this command will find the next + file that matches the preset wild card lookup + filespec and will load the filespec buffer with + that file's name. The G* command (see Appendix C, + section C.1.1) can be used to retrieve the fully + expanded filespec. When no more occurences of the + wild card filespec exist, the ?FNF error is + returned. + + :EN` Executes the EN` command, and returns a numeric + value. A -1 indicates that another match of the + wild card filespec exists and has been loaded into + the filespec buffer. A 0 indicates no more + occurences exist. No error message is generated. + + The filespec argument to the file selection commands in TECO-11 + can use the string building characters described in Table 5-8A + (see section 5.8). The Q* construct, described in + Appendix C, is especially useful in TECO-11. + + + 5.1.6 Direct I/O to Q-Registers + + TECO-10 provides commands to do I/O directly to and from the + Q-registers, allowing I/O to bypass the text buffer. + + + TABLE 5-1F: DIRECT I/O TO Q-REGISTERS + [Not in TECO-8 or TECO-11] + + EQqfilespec` Read specified file into Q-register q. No s + or s are removed from the file, except that + trailing s are discarded. The only switch + permitted on the filespec in this command is the + /DELETE switch, which causes TECO to delete the + file after reading it, providing that the file is + + Standard TECO PAGE 57 + Direct I/O to Q-Registers + + + less than 500 characters long. This command + supports the pseudo-device TMP:, for TMPCOR. + Consult the appropriate appendix for details. + [TECO-10 only] + + E%qfilespec` Create the specified file. The contents of the + file will be the contents of Q-register q with no + s deleted. No switches are permitted on the + filespec of this command. This command supports + the pseudo-device TMP:, for TMPCOR. Consult the + appropriate appendix for details. + [TECO-10 only] + + Standard TECO PAGE 58 + Page Manipulation Commands + + + 5.2 PAGE MANIPULATION COMMANDS + + The following commands permit text to be read into the text + buffer from an input file or written from the buffer onto an + output file. + + All of the input commands listed in this table assume that the + input file is organized into pages small enough to fit into + available memory. If any page of the input file contains more + characters than will fit into available memory, the input command + will continue reading characters into the buffer until a line + feed is encountered when the buffer is about 3/4 full. See the + appendices for more details. Special techniques for handling + pages larger than the buffer capacity will be presented later in + this chapter. + + + TABLE 5-2: PAGE MANIPULATION COMMANDS + + COMMAND FUNCTION + + APPEND commands: + + A Appends the next page of the input file to the contents + of the text buffer, thus combining the two pages of + text on a single page with no intervening form feed + character. This command takes no argument. To perform + n Appends, use the n construct. Note that nA is a + completely different command. + + :A Equivalent to the A command except that a value is + returned. -1 is returned if the append succeeded, and + 0 is returned if the append failed because the + end-of-the-input-file had previously been reached (^N + flag is -1 at start of this command). + [Not in TECO-8] + + n:A Appends n lines of text from the input file to the + contents of the text buffer. The value of n must not + be negative. A value is returned indicating whether or + not there were in fact n lines remaining in the input + file. -1 is returned if the command succeeded. 0 is + returned if end-of-file on the input file was + encountered before all n lines were read in. Note that + the command can succeed and yet read in fewer than n + lines in the case that the text buffer fills up. + [Not in TECO-8] + + PAGE Commands: + + P Writes the contents of the buffer onto the output file, + then clears the buffer and reads the next page of the + input file into the buffer. A form feed is appended to + + Standard TECO PAGE 59 + Page Manipulation Commands + + + the output file if the last page read in (with a P, Y, + or A command) was terminated with a form feed. + + :P Same as the P command except that a value is returned. + -1 is returned if the command succeeded. 0 is returned + if the command failed because the end-of-file on the + input file had been reached prior to the initiation of + this command. The command string <:P;> takes you to + end of file. + [Not in TECO-8] + + nP Executes the P command n times, where n must be a + non-zero positive integer. + + In TECO-11 on VAX/VMS, n can be a negative integer (and + -P means -1P). A -nP command will back up n pages. + + n:P Executes the :P command n times, where n must be a + non-zero positive integer. In TECO-11 on VAX/VMS, n + can be a negative integer (and -:P means -1:P). This + command returns 0 when another page could not be backed + up because beginning of file had been reached. + [Not in TECO-8] + + PW Write the contents of the buffer onto the output file + and append a form feed character. The buffer is not + cleared and the pointer position remains unchanged. + + nPW Executes the PW command n times, where n must be a + non-zero positive integer. + + m,nPW Writes the contents of the buffer between pointer + positions m and n onto the output file. m and n must + be positive integers. A form feed is not appended to + this output, nor is the buffer cleared. The pointer + position remains unchanged. + + m,nP Equivalent to m,nPW. + + HPW Equivalent to the PW command except that a form feed + character is not appended to the output. + + HP Equivalent to HPW. + + YANK commands: + + Y Clears the text buffer and then reads the next page of + the input file into the buffer. Because the Y command + DESTROYS the current text buffer, its use can result in + the loss of data, and is subject to "Yank protection" + (see ED flag in section 5.14). + + -Y Clears the text buffer and then reads the previous page + + Standard TECO PAGE 60 + Page Manipulation Commands + + + of the file being edited back into the buffer. Because + the Y command DESTROYS the current text buffer, its use + can result in the loss of data, and is subject to "Yank + protection" (see ED flag in section 5.14). + [TECO-11 on VAX/VMS only] + + :Y Same as the Y command but a value is returned. -1 is + returned if the Yank succeeded. 0 is returned if the + Yank failed because the end-of-file had been reached on + the input file prior to the initiation of this command. + [Not in TECO-8] + + -:Y Same as the -Y command but a value is returned. -1 is + returned if the Yank succeeded. 0 is returned if the + Yank failed because the beginning of file had been + reached on the file being edited prior to the + initiation of this command. + [TECO-11 on VAX/VMS only] + + EY Same as the Y command, but its action is always + permitted regardless of the value of the Yank + Protection bit in the ED flag. Remember that Yank + DESTROYS the current buffer; there's no way to get it + back! + + :EY Same as the :Y command, but its action is always + permitted regardless of the value of the Yank + protection bit in the ED flag. Remember that Yank + DESTROYS the current buffer; there's no way to get it + back! + [Not in TECO-8] + + Standard TECO PAGE 61 + Buffer Pointer Manipulation Commands + + + 5.3 BUFFER POINTER MANIPULATION COMMANDS + + Table 5-3 describes all of the buffer pointer manipulation + commands These commands may be used to move the pointer to a + position between any two characters in the buffer, but they will + not move the pointer across a buffer boundary. If any R or C + command attempts to move the pointer backward beyond the + beginning of the buffer or forward past the end of the buffer, + the command is ignored and an error message is printed. If any L + command attempts to exceed the buffer boundaries, the pointer is + positioned at the boundary which would have been exceeded and no + error message is printed. + + + TABLE 5-3: BUFFER POINTER MANIPULATION COMMANDS + + COMMAND FUNCTION + + CHARACTER commands: + + C Advances the pointer forward across one character. + + nC Executes the C command n times. If n is positive, the + pointer is moved forward across n characters. If n is + negative, the pointer is moved backward across n + characters. If n is zero, the pointer position is not + changed. + + n:C Same as nC except that a value is returned. If the + command succeeded, -1 is returned. If the command + failed, the pointer does not move and a value of 0 is + returned. + [TECO-10 only] + + :C Equivalent to 1:C. + + -C Equivalent to -1C. + + JUMP commands: + + J Moves the pointer to a position immediately preceding + the first character in the buffer. Equivalent to 0J. + + nJ Moves the pointer to a position immediately following + the nth character in the buffer. + + ZJ Moves the pointer to a position immediately following + the last character in the buffer. + + n:J Same as the nJ command except that if pointer position + n is outside of the buffer, the pointer does not move + and a value of 0 is returned. If the command + succeeded, a value of -1 is returned. + + Standard TECO PAGE 62 + Buffer Pointer Manipulation Commands + + + [TECO-10 only] + + LINE commands: + + L Advances the pointer forward across the next line + terminator (line feed, vertical tab, or form feed) and + positions it at the beginning of the next line. + + nL Executes the L command n times. A positive value of n + advances the pointer to the beginning of the nth line + following its current position. A negative value of n + moves the pointer backwards to the beginning of the nth + complete line preceding its current position. If n is + zero, the pointer is moved to the beginning of the line + on which it is currently positioned. + + -L Equivalent to -1L. + + REVERSE commands: + + R Moves the pointer backward across one character. + + nR Executes the R command n times. If n is positive, the + pointer is moved backward across n characters. If n is + negative, the pointer is moved forward across n + characters. If n is zero, the position of the pointer + is not changed. + + -R Equivalent to -1R. + + n:R Same as the nR command except that a value is returned. + If the command succeeded, then a value of -1 is + returned. If the command failed, then the buffer + pointer is not moved and a value of 0 is returned. + [TECO-10 only] + + :R Equivalent to 1:R. + + Standard TECO PAGE 63 + Text Type Out Commands + + + 5.4 TEXT TYPE OUT COMMANDS + + Table 5-4 describes the commands used to type out part or all of + the contents of the buffer for examination. These commands do + not move the buffer pointer. + + + TABLE 5-4: TEXT TYPE OUT COMMANDS + + COMMAND FUNCTION + + T Types out the contents of the buffer from the current + position of the buffer pointer through and including + the next line terminator character. + + nT Types n lines. If n is positive, types the n lines + following the current position of the pointer. If n is + negative, types the n lines preceding the pointer. If + n is zero, types the contents of the buffer from the + beginning of the line on which the pointer is located + up to the pointer. + + -T Equivalent to -1T. + + m,nT Types out the contents of the buffer between pointer + positions m and n. + + .,.+nT Types out the n characters immediately following the + buffer pointer. n should be greater than zero. + + .-n,.T Types the n characters immediately preceding the buffer + pointer. n should be greater than zero. + + n^T Types out to the console the character whose ASCII + value is n. Whatever normal type-out conversions may + currently be in effect and applicable (such as + translation of control characters to up-arrow format) + are done. The value of n is used modulo 256. + + n:^T Outputs to the console the character whose ASCII value + is n. Output is done in "one-shot" binary mode; no + type-out translations are done. The value of n is used + modulo 256. + [TECO-11 only] + + HT Types out the entire contents of the buffer. + + V Types out the current line. Equivalent to 0TT. + + nV Types out n-1 lines on each side of the current line. + Equivalent to 1-nTnT. + [Not in TECO-8] + + Standard TECO PAGE 64 + Text Type Out Commands + + + m,nV Types out m-1 lines before and n-1 lines after the + current line. + [Not in TECO-8] + + ^Atext + Types "text" on the terminal. While the command may + begin with or Caret/A, the closing character + must be a . A numeric argument must not be + specified with this command. + + @^A/text/ Equivalent to the ^A command except that the text to be + printed may be bracketed with any character. This + avoids the need for the closing . + + Standard TECO PAGE 65 + Text Type Out Commands + + + You may stop or delay the output of any type out command by + typing certain special characters at the keyboard while TECO is + typing out at the terminal (via a T, V, ^A, or :G command). + These characters are described in the table below: + + + TABLE 5-4B: TYPE OUT TIME COMMANDS + + CHARACTER FUNCTION + + Stops the terminal output of the current command + string. TECO continues to run and to send + characters to the terminal, however, these + characters are suppressed from actually printing on + the terminal. You can resume printing characters by + typing another while type out is being + suppressed. TECO cancels this suppression the next + time that it prompts for command string input. A + TECO macro can cancel the effect of any by + setting the 16's bit in the ET flag (see section + 5.16). + + Freezes the terminal output of the current command + string. TECO stops running the next time it tries + to output a character to your terminal, and waits + for you to type a to indicate that output + should resume. + + Causes TECO to resume any type out that was frozen + via use of the command described above. + This character has this effect only while typout is + frozen. Striking any key other than or + while type out is frozen will have + unpredictable results; consult the appropriate + operating system manual. + + + Note that , , and are legal TECO + commands as well. When TECO is not typing on the terminal (when + you are entering a command string, for example), these characters + do not have the effect described above. They may be entered into + your command string just like any other control character (except + under operating systems that filter out these characters). + + Standard TECO PAGE 66 + Deletion Commands + + + 5.5 DELETION COMMANDS + + Table 5-5 summarizes the text deletion commands, which permit + deletion of single characters, groups of adjacent characters, + single lines, or groups of adjacent lines. + + + TABLE 5-5: TEXT DELETION COMMANDS + + COMMAND FUNCTION + + DELETE commands: + + D Delete the first character following the current + position of the buffer pointer. + + nD Execute the D command n times. If n is positive, the n + characters following the current pointer position are + deleted. If n is negative, the n characters preceding + the current pointer position are deleted. If n is + zero, the command is ignored. + + -D Equivalent to -1D. + + m,nD Equivalent to m,nK. + [TECO-11 only] + + n:D Same as nD but returns a value (-1 if command succeeds, + 0 if command failed because the range of characters to + be deleted fell outside the text buffer). + [TECO-10 only] + + FDtext` Search for the specified text string and delete it. + (See search commands in section 5.7.) + [TECO-10 only] + + @FD/text/ Equivalent to FDtext` except that the character + is not necessary. + + FR` Equivalent to -nD where n is the length of the last + insert, get or search command. See the description of + the FRtext` command in section 5.6 for more details. + + @FR// Form of the FR` command that does not require use of + the character. + + KILL commands: + + K Deletes the contents of the buffer from the current + position of the buffer pointer through and including + the next line terminator character. + + nK Executes the K command n times. If n is positive, the + + Standard TECO PAGE 67 + Deletion Commands + + + n lines following the current pointer position are + deleted. If n is negative, the n lines preceding the + current pointer position are deleted. If n is zero, + the contents of the buffer from the beginning of the + line on which the pointer is located up to the pointer + is deleted. It is not an error if more lines are + specified than occur when a boundary of the text buffer + is encountered. + + -K Equivalent to -1K. + + m,nK Deletes the contents of the buffer between pointer + positions m and n. The pointer moves to the point of + the deletion. The ?POP error message (or its + equivalent) is issued if either m or n is out of range. + + FKtext` Executes a Stext` command then deletes all the text + from the initial pointer position to the new pointer + position. + [TECO-10 only] + + @FK/text/ Equivalent to FKtext` except that "text" may contain + any character, including , other than the + delimiter (shown here as /). + [TECO-10 only] + + HK Deletes the entire contents of the buffer. + + Standard TECO PAGE 68 + Insertion Commands + + + 5.6 INSERTION COMMANDS + + Table 5-6 lists all of the text insertion commands. These + commands cause the string of characters specified in the command + to be inserted into the text buffer at the current position of + the buffer pointer. Following execution of an insertion command, + the pointer will be positioned immediately after the last + character of the insertion. + + The length of an insertion command is limited primarily by the + amount of memory available for command string storage. During + normal editing jobs, it is most convenient to limit insertions to + about 10 or 15 lines each. When command string space is about to + run out, TECO will ring the terminal's bell after each character + that is typed. From the time you hear the first warning bell, + you have 10 characters to type in order to clean up your command + line. Attempting to enter too many characters into the current + command string causes unpredictible results to occur and should + be avoided. Use the DELETE key to shorten the command to permit + its termination. + + As explained above in Chapter 4, certain characters are filtered + out by the operating system and/or may perform special functions, + and some characters are immediate action commands and have + special effect. If you want to insert such characters into the + text buffer, use the nI` command described in the following + table. It will insert any ASCII character into the buffer, + including the special characters that could not ordinarily be + typed at a terminal. + + + TABLE 5-6: TEXT INSERTION COMMANDS + + COMMAND FUNCTION + + INSERT commands: + + Itext` Where "text" is a string of ASCII characters terminated + by a . The specified text string is entered + into the buffer at the current position of the pointer, + with the pointer positioned immediately after the last + character of the insertion. + + nI` This form of the I command inserts the single character + whose ASCII code is n into the buffer at the current + position of the buffer pointer. (n is taken modulo 256 + in TECO-11, modulo 128 in other TECOs.) nI` is used to + insert characters that are not available on the user's + terminal or special characters such as DELETE which may + not be inserted from a terminal with the standard I + command. + + @I/text/ Equivalent to the I command except that the text to be + + Standard TECO PAGE 69 + Insertion Commands + + + inserted may contain ESCAPE characters. A delimiting + character (shown as a slash here) must precede and + follow the text to be inserted, as described in Section + 3.1.2 above. + + n@I// Equivalent to the nI` command, but does not require the + character. + + text` This command is equivalent to the I command except + that the is part of the text which is inserted + into the buffer. + + FRtext` Equivalent to "-nDItext`", where "n" is obtained from + the most recent occurrence of the following: (a) the + length of the most recent string found by a successful + search command, (b) the length of the most recent text + string inserted (including insertions from the FS, FN, + or FR commands), or (c) the length of the string + retrieved by the most recent "G" command. In effect, + the last string inserted or found is replaced with + "text", provided that the pointer has not been moved. + After execution of this command, the buffer pointer is + positioned immediately after "text". + [Not in TECO-8] + + @FR/text/ Equivalent to "FRtext`", except that "text" may contain + ESCAPE characters. + [Not in TECO-8] + + nFRtext` Equivalent to "nDItext`". If n is less than 0, + characters preceding the buffer pointer are deleted and + replaced with "text". If n is greater than 0, + characters following the buffer pointer are deleted and + replaced with "text". In either case, the buffer + pointer is left positioned immediately after "text" + upon completion of this command. + [TECO-11 only] + + n@FR/text/ Equivalent to "nFRtext`", except that "text" may + contain ESCAPE characters. + [TECO-11 only] + + m,nFRtext` Equivalent to "m,nDItext`". The characters between + buffer positions m and n are deleted and replaced with + "text". The buffer pointer is left positioned + immediately after "text" upon completion of this + command. + [TECO-11 only] + + m,n@FR/text/ Equivalent to "m,nFRtext`", except that "text" may + contain ESCAPE characters. + [TECO-11 only] + + Standard TECO PAGE 70 + Search Commands + + + 5.7 SEARCH COMMANDS + + In many cases, the easiest way to position the buffer pointer is + by means of a character string search. Search commands cause + TECO to scan through text until a specified string of characters + is found, and then position the buffer pointer at the end of the + string. A character string search begins at the current position + of the pointer. It proceeds within the current buffer in a + forward or a reverse direction or through the file in a forward + direction. Specifying a negative numeric argument to the search + command causes the search to proceed backwards from the pointer. + + Your last explicitly specified search string is always remembered + by TECO. If a search command is specified with a null search + string argument, the last explicitly defined search string will + be used. This saves having to retype a complex or lengthy search + string on successive search commands. + + Normally searches are "unbounded" - they search from the current + position to the end of the text buffer (or in the case of + backwards searches, until the beginning of the buffer). A + bounded search, however, will only search from the current + position to the specified bound limit. If the search string is + found within the bound limits, the pointer is positioned + immediately after the last character in the string. If the + string cannot be found, the pointer is left unchanged. + + A special case of the bounded search occurs when the upper and + lower bound limits are the same. In such a case, the search + command is called an anchored search, and is used to compare the + search argument against the character string immediately + following the text buffer pointer. + + TECO-8 does not permit backward, bounded, or anchored searches. + This is a general property and will not be specifically mentioned + again in the following tables. + + Standard TECO PAGE 71 + Search Commands + + + TABLE 5-7A: SEARCH COMMANDS + + Stext` Where "text" is a string of characters terminated by a + . This command searches the text buffer for the + next occurrence of the specified character string + following the current position of the buffer pointer. + If the string is found, the pointer is positioned after + the last character in the string. If it is not found, + the pointer is positioned immediately before the first + character in the buffer (i.e., a 0J is executed) and an + error message is printed. + + nStext` This command searches for the nth occurrence of the + specified character string, where n is greater than + zero. It is identical to the S command in other + respects. + + -nStext` Identical to "nStext`" except that the search proceeds + in the reverse direction. If the string is not found, + the pointer is positioned immediately before the first + character in the buffer and an error message is + printed. If the pointer is positioned at the beginning + of or within an occurrence of the desired string, that + occurrence is considered to be the first one found. + Upon successful completion, the pointer is positioned + after the last character in the string found. + + -Stext` Equivalent to -1Stext`. + + Ntext` Performs the same function as the S command except that + the search is continued across page boundaries, if + necessary, until the character string is found or the + end of the input file is reached. This is accomplished + by executing an effective P command after each page is + searched. If the end of the input file is reached, an + error message is printed and it is necessary to close + the output file and re-open it as an input file before + any further editing may be done on that file. The N + command will not locate a character string which spans + a page boundary. + + -Ntext` Performs the same function as the -S command except + that the search is continued (backwards) across page + boundaries, if necessary, until the character string is + found or the beginning of the file being edited is + reached. + [TECO-11 on VAX/VMS only] + + -nNtext` This command searches (backwards) for the nth + occurrence of the specified character string. It is + identical to the -N command in other respects. + [TECO-11 on VAX/VMS only] + + Standard TECO PAGE 72 + Search Commands + + + nNtext` This command searches for the nth occurrance of the + specified character string, where n must be greater + than zero. It is identical to the N command in other + respects. + + _text` The underscore command is identical to the N command + except that the search is continued across page + boundaries by executing effective Y commands instead of + P commands, so that no output is generated. Since an + underscore search can result in the loss of data, it is + aborted under the same circumstances as the Y command + (see the ED flag in section 5.16). Note that + underscore is backarrow on some terminals. + + n_text` This command searches for the nth occurrence of the + specified character string, where n must be greater + than zero. It is identical to the _ command in other + respects. + + In TECO-11 on VAX/VMS, n can be negative, in which case + the search proceeds backwards through each text buffer + and through the file being edited. It terminates upon + the correct search string match and/or beginning of + file. A -n:_ command returns 0 at beginning of file. + + E_text` Same as _text` command except that effective EY (rather + than Y) commands are used. Thus, this command is never + aborted and is not controlled by the Yank protection + bit in the ED flag. Remember that Yank DESTROYS the + current buffer; there's no way to get it back! + + nE_text` Same as n_text` command except that effective EY + (rather than Y) commands are used. + + Standard TECO PAGE 73 + Search Commands + + + TABLE 5-7B: BOUNDED SEARCH COMMANDS + + m,nStext` System specific command. Consult Appendix C. + + m,nFBtext` Performs the same function as the nStext` command, but + m and n (inclusive) serve as bounds for the search. In + order for a search to be successful, the first + character to match must occur between buffer pointer + positions m and n. The string that is matched is + permitted to extend beyond the search limits specified, + provided that it begins within bounds. If mn, + then the search proceeds in the reverse direction. + + nFBtext` Performs a bounded search over the next n lines. If n + is positive, the search proceeds forward over the next + n lines; if n is negative the search proceeds + backwards over the n preceding lines; if n is zero, + the search proceeds backwards over the portion of the + line preceding the pointer. + + FBtext` Equivalent to 1FBtext`. + + -FBtext` Equivalent to -1FBtext`. + + ::Stext` Compare command. The ::S command is not a true search. + If the characters in the buffer immediately following + the current pointer position match the search string, + the pointer is moved to the end of the string and the + command returns a value of -1; i.e., the next command + is executed with an argument of -1. If the characters + in the buffer do not match the string, the pointer is + not moved and the command returns a value of 0. + Identical to ".,.:FBtext`". + + + + The search and replace commands listed below perform equivalent + functions to the search commands listed next to them, but then + delete "text1" and replace it with "text2". + + + TABLE 5-7C: SEARCH AND REPLACE COMMANDS + + Search & Replace Search Command + + FStext1`text2` Stext1` + + nFStext1`text2` nStext1` + + FNtext1`text2` Ntext1` + + nFNtext1`text2` nNtext1` + + Standard TECO PAGE 74 + Search Commands + + + F_text1`text2` _text1` + [not in TECO-10] + + nF_text1`text2` n_text1` + [Not in TECO-10] + + FCtext1`text2` FBtext1` + + nFCtext1`text2` nFBtext1` + + m,nFCtext1`text2` m,nFBtext1` + + + In addition, the four following commands can be used on TECO-10: + + FDtext` Identical to the "FStext``" command. + [TECO-10 only] + + nFDtext` Identical to the "nFStext``" command. + [TECO-10 only] + + nFKtext` Searches for the nth following occurrence of "text" and + then deletes all characters in the text buffer between + the pointer positions before and after the search. + [TECO-10 only] + + FKtext` Equivalent to 1FKtext` + [TECO-10 only] + + The FS, F_, and FN commands above can also be reverse searches + (n<0) or bounded searches (m,n argument). A reverse F_ or FN + acts like a reverse S; that is the search terminates when the + beginning of the text buffer is encountered. + + (In TECO-11 on VAX/VMS, -nFN searches backwards through each text + buffer and through the file being edited. It terminates upon the + correct search string match and/or beginning of file. A colon + modified reverse search returns 0 at beginning of file.) + + If a search command is entered without a text argument, TECO will + execute the search command as though it had been entered with the + same character string argument as the last search command + entered. For example, suppose the command "STHE END`" results in + an error message, indicating that character string "THE END" was + not found on the current page. Entering the command "N`" causes + TECO to execute an N search for the same character string. + Although the text argument may be omitted, the command terminator + must always be entered. + + Search commands can make use of the colon modifier described in + Chapter 3. The following examples illustrate use of the colon + modifier: + + Standard TECO PAGE 75 + Search Commands + + + COMMANDS: n:Stext` + m,n:Stext` + n:Ntext` + n:_text` + n:FStext1`text2` + m,n:FStext1`text2` + n:FNtext1`text2` + etc. + + FUNCTION: In each case, execute the search command. If the + search is successful, execute the next sequential + command with an argument of -1. If the search + fails, execute the next command with an argument + of zero. If the next command does not require a + numeric argument, execute it as it stands. + + + + All search commands may also use the @ modifier to use alternate + delimiters, to allow characters in search strings or to + avoid the use of characters in command strings. Such + search commands take the following forms: + + COMMANDS: @S/text/ + m,n@FB/text/ + n@FS/text1/text2/ + @:N/text/ + etc. + + Standard TECO PAGE 76 + Search Arguments + + + 5.8 SEARCH ARGUMENTS + + TECO builds the search string by loading its search string buffer + from the supplied search command argument. To help you enter + special characters or frequently used character sequences, the + argument may contain special string building characters. Table + 5-8A lists the string building characters and their functions. + + TECO-8 does not support the extended String Build functions or + Match Control Constructs that begin with . This is a + general property and will not be repeated in the following + tables. + + Note that, as explained in Chapter 3, a caret (up-arrow) may be + used to indicate that the character following it is to be treated + as a control character. Any of the commands below may be entered + using the caret. This function of the caret can be disabled by + using the ED flag (see 5.16 and appendices). + + + TABLE 5-8A: STRING BUILDING CHARACTERS + + CHARACTER FUNCTION + + A character in a search command argument + indicates that the character following the + is to be used literally rather than as a + match control character. + + Same as . + + A character in a search command argument + indicates that the character following the + is to be used as the equivalent character + in the lower case ASCII range (i.e., octal 100 to + 137 is treated as octal 140 to 177). + + + Two successive characters in a string + argument indicate to TECO that all following + alphabetic characters in this string are to be + converted to lower case unless an explicit ^W is + given to override this state. This state + continues until the end of the string or until a + ^W^W construct is encountered. + [TECO-10 only] + + A character in a search command argument + indicates that the character following the + is to be used as the equivalent character + in the upper case ASCII range (i.e., octal 140 to + 177 is treated as octal 100 to 137). + + Standard TECO PAGE 77 + Search Arguments + + + + Two successive characters indicates to + TECO that all following alphabetic characters in + this string are to be converted to upper case + unless an explicit ^V is encountered to override + this state. This state continues until the end of + the string or until a ^V^V construct is + encountered. + [TECO-10 only] + + Qq Qq indicates that the string stored in + Q-register q is to be used in the position + occupied by the ^EQq in the search string. Q + registers are discussed in sections 3.3.2 and 5.9. + [Not in TECO-10] + + Uq Uq indicates that the character whose + ASCII code is specified by the numeric storage + area of Q-register q is to be used in the position + occupied by the ^EUq in the search string. + [TECO-11 only] + + + String build characters are also permitted inside the string + arguments of the O, EB, ER, EW, and EG commands. + + TECO executes a search command by attempting to match the search + command argument character-by-character with some portion of the + input file. There are several special control characters that + may be used in search command arguments to alter the usual + matching process. Table 5-8B lists these match control + characters and their functions. + + + TABLE 5-8B: MATCH CONTROL CHARACTERS + + CHARACTER FUNCTION + + A character indicates that this position + in the character string may be any character. + TECO accepts any character as a match for + . + + A character indicates that any separator + character is acceptable in this position. TECO + accepts any character that is not a letter (upper + or lower case A to Z) or a digit (0 to 9) as a + match for . + + x TECO accepts any character as a match for the + x combination EXCEPT the character which + follows the . can be combined + with other special characters. For example, the + + Standard TECO PAGE 78 + Search Arguments + + + combination D means match anything + except a digit in this position. + + A A indicates that any alphabetic character + (upper or lower case A to Z) is acceptable in this + position. + + B Same as . + + C C indicates that any character that is + legal as part of a symbol constituent is + acceptable in this position. TECO accepts any + letter (upper or lower case A to Z), any digit (0 + to 9), a dot (.), or a dollar sign ($) as a match + for C. Additional characters may be + matched depending upon the operating system; + consult the appropriate appendix. + + D D indicates that any digit (0 to 9) is + acceptable in this position. + + Gq Gq indicates that any character contained + in Q-register q is acceptable in this position. + For example, if Q-register A contains "A*:" then + TECO accepts either A, *, or : as a match for + GA. + [Not in TECO-10] + + L L indicates that any line terminator (line + feed, vertical tab, or form feed) is acceptable in + the position occupied by L in the search + string. + + M M indicates that any non-zero number of + occurrences of the immediately following character + or match control construct is acceptable at this + position. + [TECO-10 only] + + R R indicates that any alphanumeric + character (letter or digit as defined above) is + acceptable in this position. + + S S indicates that any non-null string of + spaces and/or tabs is acceptable in the position + occupied by S. + + V V indicates that any lower case alphabetic + character is acceptable in this position. + + W W indicates that any upper case alphabetic + character is acceptable in this position. + + Standard TECO PAGE 79 + Search Arguments + + + X Equivalent to . + + indicates that the character whose + ASCII octal code is nnn is acceptable in this + position. + [TECO-10 only] + + [a,b,c,...] + [a,b,c,...] indicates that any one of the + specified characters is acceptable in this + position. One or more characters or other match + control constructs are permitted. + [TECO-10 only] + + TECO-8 uses special symbols to represent certain match control + characters when they are displayed by an error message. These + display symbols are: + + Character Display + + ^N + ^S + ^X + + Standard TECO PAGE 80 + Q-registers + + + 5.9 Q-REGISTER MANIPULATION + + TECO provides data storage registers, called Q-registers, each of + which may be used to store an integral numeric value and, + simultaneously, an ASCII character string. Q-registers are + described in section 3.3.2; this section describes the commands + used to load values into and retrieve values from Q-registers. + + An important kind of character string which may be stored in the + text portion of a Q-register is a TECO command string. Such a + command is known as a macro, and is available for execution via + the Mq command, described in Table 5-9C below. (See also section + 4.4, Immediate ESCape-sequence commands, for a keypad method of + macro invocation, and section 4.2, for the *q command, which + saves the last-typed command for possible editing or + re-execution.) + + TECO-10 allows additional Q-registers other than those described + in section 3.3.2. Consult Appendix I for further details. + + Table 5-9A lists the commands which permit characters to be + loaded into the Q-registers. + + + TABLE 5-9A: Q-REGISTER LOADING COMMANDS + + COMMAND FUNCTION + + nUq Put n in the numeric storage area of Q-register q. + + m,nUq Equivalent to the nUqm command. That is, this command + puts the number n into the numeric storage area of + Q-register q and then returns the number m as a value. + The command UAUB is useful at the beginning of a macro + to save the two arguments specified on the macro call. + (See the m,nMq command below.) + + n%q Add n to the contents of the number storage area of + Q-register q. The updated contents of Q-register q are + also returned as a value to be passed to the next + command. + + If your intent is only to update the Q-register, good + programming practice suggests following the n%q command + with a or ^[ to prevent the returned value from + unintentionally affecting the following command. + + n%q` Same as n%q but discards the value returned. + + %q Equivalent to 1%q. + + ^Uqstring` + This command inserts character string "string" into the + + Standard TECO PAGE 81 + Q-registers + + + text storage area of Q-register q. When entering a + command string from the terminal, you must specify ^U + using the caret/U format, since the character + is the line erase immediate action command. + + :^Uqstring` + This command appends character string "string" to the + text storage area of Q-register "q". + [not in TECO-8] + + n^Uq` This form of the ^Uq` command inserts the single + character whose ASCII code is n into the text storage + area of Q-register "q". (n is taken modulo 256 in + TECO-11, modulo 128 in other TECOs.) + [not in TECO-8] + + n:^Uq` This form of the :^Uq` command appends the single + character whose ASCII code is n to the text storage + area of Q-register "q". (n is taken modulo 256 in + TECO-11, modulo 128 in other TECOs.) + [not in TECO-8] + + @^Uq/string/ + @:^Uq/string/ + n@^Uq// + n@:^Uq// Equivalent, respectively, to the ^Uqstring`, + :^Uqstring`, n^Uq`, and n:^Uq` commands, except that + alternate delimiters are used and no characters + are necessary. + + nXq Clear Q-register q and move n lines into it, where n is + a signed integer. If n is positive, the n lines + following the current pointer position are copied into + the text storage area of Q-register q. If n is + negative, the n lines preceding the pointer are copied. + If n is zero, the contents of the buffer from the + beginning of the line on which the pointer is located + up to the pointer is copied. The pointer is not moved. + The text is not deleted. + + Xq Equivalent to 1Xq. + + -Xq Equivalent to -1Xq. + + m,nXq Copy the contents of the buffer from the m+1th + character through and including the nth character into + the text storage area of Q-register q. M and n must be + positive, and m should be less than n. + + .,.+nXq Copy the n characters immediately following the buffer + pointer into the text storage area of Q-register q. N + should be greater than zero. + + Standard TECO PAGE 82 + Q-registers + + + .-n,.Xq Copy the n characters immediately preceeding the buffer + pointer into the text storage area of Q-register q. N + should be greater than zero. + + n:Xq Append n lines to Q-register q, where n is a signed + integer with the same functions as n in the nXq command + above. The pointer is not moved. + [not in TECO-8] + + The colon construct for appending to a Q-register can + be used with all forms of the X command. + + ]q Pop from the Q-register push-down list into Q-register + q. Any previous contents of Q-register q are + destroyed. Both the numeric and text parts of the + Q-register are loaded by this command. The Q-register + push-down list is a last-in first-out (LIFO) storage + area. (See section 3.3.3 for a description of the + push-down list.) This command does not use or affect + numeric values. Numeric values are passed through this + command transparently. This allows macros to restore + Q-registers and still return numeric values. + [Not in TECO-8] + + :]q Execute the ]q command and return a numeric value. A + -1 indicates that there was another item on the + Q-register push-down list to be popped. A 0 indicates + that the Q-register push-down list was empty, so + Q-register q was not modified. + [Not in TECO-8] + + *q Save last-typed command string. See section 4.2. + + Standard TECO PAGE 83 + Q-registers + + + Table 5-9B lists the commands which permit data to be retrieved + from the Q-registers. + + + TABLE 5-9B: Q-REGISTER RETRIEVAL COMMANDS + + COMMAND FUNCTION + + Qq Use the integer stored in the number storage area of + Q-register q as the argument of the next command. + + nQq Return the ASCII value of the (n+1)th character in + Q-register q. The argument n must be between 0 and the + Q-register's size minus 1. If n is out of range, a + value of -1 is returned. Characters within a + Q-register are numbered the same way that characters in + the text buffer are numbered. The initial character is + at character position 0, the next character is at + character position 1, etc. Therefore, if Q-register A + contains "xyz", then 0QA will return the ASCII code for + "x" and 1QA will return the ASCII code for "y". + + :Qq Use the number of characters stored in the text storage + area of Q-register q as the argument of the next + command. + + Gq Copy the contents of the text storage area of + Q-register q into the buffer at the current position of + the buffer pointer, leaving the pointer positioned + after the last character copied. + + :Gq Print the contents of the text storage area of + Q-register q on the terminal. Neither the text buffer + nor the buffer pointer is changed by this command. + + [q Copy the contents of the numeric and text storage areas + of Q-register q into the Q-register push-down list. + This command does not alter either the numeric or text + storage areas of Q-register q. It does not use or + affect numeric values. Numeric values are passed + through this command transparently, allowing macros to + save temporary Q-registers and still accept numeric + values. (Note, however, macros written to use local + Q-registers, available in TECO-11, may be able to avoid + saving and restoring Q-registers via the the pushdown + list.) The command sequence [A ]B replicates the text + string and numeric value from Q-register A into + Q-register B. + [Not in TECO-8] + + Standard TECO PAGE 84 + Q-registers + + + Table 5-9C lists the commands which cause macros (strings stored + in Q-registers) to be executed. + + Macro invocations can be nested recursively; the limit is set by + the amount of pushdown storage TECO has available. + + In this table only, a distinction is made between a global + Q-register name (indicated below by "q") and a local Q-register + name (indicated below by ".q"). Elsewhere in this manual, "q" + indicates either a global or local Q-register name. + + + TABLE 5-9C: MACRO INVOCATION COMMANDS + + COMMAND FUNCTION + + Mq Execute the contents of the text storage area of global + Q-register q as a command string. In TECO-11, a new + set of local Q-registers is created before the macro is + invoked. + + nMq Execute the Mq command as above, using n as a numeric + argument for the first command contained in global + Q-register q. In TECO-11, a new set of local + Q-registers is created. + + m,nMq Execute the Mq command as above, using m,n as numeric + arguments for the first command contained in global + Q-register q. In TECO-11, a new set of local + Q-registers is created. + + :Mq Execute the contents of the text storage area of global + Q-register q as a command string. In TECO-11, the + current set of local Q-registers remains available to + the invoked macro; no new set is created. + + n:Mq Execute the :Mq command as above, using n as a numeric + argument for the first command contained in global + Q-register q. In TECO-11, no new set of local + Q-registers is created. + + m,n:Mq Execute the :Mq command as above, using m,n as numeric + arguments for the first command contained in global + Q-register q. In TECO-11, no new set of local + Q-registers is created. + + M.q Execute the contents of the text storage area of local + Q-register .q as a command string. In TECO-11, no new + set of local Q-registers is created. + + nM.q Execute the M.q command as above, using n as a numeric + argument for the first command contained in local + Q-register .q. In TECO-11, no new set of local + + Standard TECO PAGE 85 + Q-registers + + + Q-registers is created. + + m,nM.q Execute the M.q command as above, using m,n as numeric + arguments for the first command contained in local + Q-register .q. In TECO-11, no new set of local + Q-registers is created. + + :M.q Execute the contents of the text storage area of local + Q-register .q as a command string. In TECO-11, no new + set of local Q-registers is created. + + n:M.q Execute the :M.q command as above, using n as a numeric + argument for the first command contained in local + Q-register .q. In TECO-11, no new set of local + Q-registers is created. + + m,n:M.q Execute the :M.q command as above, using m,n as numeric + arguments for the first command contained in local + Q-register .q. In TECO-11, no new set of local + Q-registers is created. + + Standard TECO PAGE 86 + Arithmetic and Expressions + + + 5.10 ARITHMETIC AND EXPRESSIONS + + The numeric argument of a TECO command may consist of a single + integer, any of the characters listed in Table 5-11, the numeric + contents of any Q-register, or an arithmetic combination of these + elements. If an arithmetic expression is supplied as a numeric + argument, TECO will evaluate the expression. All arithmetic + expressions are evaluated from left to right without any operator + precedence. Parentheses may be used to override the normal order + of evaluation of an expression. If parentheses are used, all + operations within the parentheses are performed, left to right, + before operations outside the parentheses. Parentheses may be + nested, in which case the innermost expression contained by + parentheses will be evaluated first. Table 5-10A lists all of + the arithmetic operators that may be used in arithmetic + expressions. + + + TABLE 5-10A: ARITHMETIC OPERATORS + + OPERATOR EXAMPLE FUNCTION + + + +2=2 Ignored if used before the first term in an + expression. + + + 5+6=11 Addition, if used between terms. + + - -2=-2 Negation, if used before the first term in an + expression. + + - 8-2=6 Subtraction, if used between terms + + * 8*2=16 Multiplication. Used between terms. + + / 8/3=2 Integer division with loss of the remainder. + Used between terms. + + & 12&10=8 Bitwise logical AND of the binary + representation of the two terms. Used + between the terms. + + # 12#10=14 Bitwise logical OR of the binary of the two + terms. Used between the terms. + + ^_ 5^_=-6 Unary one's complement. Used after an + expression. This is a TECO command that + complements its argument. Strictly speaking, + it is not a unary operator. + + Standard TECO PAGE 87 + Arithmetic and Expressions + + + TABLE 5-10B: CONVERSION AND RADIX CONTROL COMMANDS + + COMMAND FUNCTION + + n= This command causes the value of n to be output at the + terminal in decimal followed by a carriage return and + line feed. Decimal numeric conversion is signed. For + example, the unsigned number 65535 will output as -1 on + TECO-11. TECO's radix is unaltered. + + n== This command causes the value of n to be output at the + terminal in octal (base 8) followed by a carriage + return and line feed. Octal numeric conversion is + unsigned. For example, the unsigned number 8191 + (decimal) will output as 17777 on TECO-8. TECO's radix + is unaltered. + + n=== This command causes the value of n to be output at the + terminal in hexadecimal (base 16) followed by a + carriage return and line feed. Hexadecimal output is + unsigned. TECO's radix is unaltered. + [TECO-11 only] + + n:= + n:== + n:=== These commands are equivalent to n=, n==, and n===, + except that they leave the carriage positioned at the + end of the output. + + ^O (caret/O) causes all subsequent numeric input + to be accepted as octal numbers. Numeric conversions + using the \ or n\ commands will also be octal. The + digits 8 and 9 become illegal as numeric characters. + The octal radix will continue to be used until the next + ^D command is executed or until TECO's radix is changed + by an n^R command. + NOTE: On TECO-10, this command only affects the + immediately following digit string. + + ^D (caret/D) causes all subsequent numeric input + to be accepted as decimal numbers. This is the initial + setting. + [Not in TECO-10] + + ^R This command returns the binary value of TECO's current + radix. + [TECO-11 only] + + n^R This command sets TECO's radix to the value of n. It + is currently implemented only in TECO-11, where n may + only be one of the values 8, 10, or 16 (representing + octal mode, decimal mode, or hexadecimal mode). If n + is not one of these values, TECO's radix remains + + Standard TECO PAGE 88 + Arithmetic and Expressions + + + unchanged and the ?IRA error message is produced. + + \ A backslash character which is not preceded by a + numeric argument causes TECO to evaluate the digit + string (if any) beginning with the character + immediately following the buffer pointer and ending at + the next character that is not valid for the current + radix. The value becomes the numeric argument of the + next command. The first character may be a digit or + + or -. As the backslash command is evaluated, TECO + moves the buffer pointer to a position immediately + following the digit string. If there is no digit + string following the pointer, the result is zero and + the pointer position remains unchanged. Except on + TECO-8, the digits 8 and 9 will stop the evaluation if + TECO's current radix is octal. + + n\ The backslash command preceded by an argument inserts + the value of n into the text buffer at the current + position of the pointer, leaving the pointer positioned + after the last digit of the insertion. The insertion + is either signed decimal (decimal radix), unsigned + octal (octal radix), or unsigned hexadecimal + (hexadecimal radix). Note that \ is a "bidirectional" + command. n\ inserts a string into text while \ (no + argument) returns a numeric result. + + Standard TECO PAGE 89 + Special Numeric Values + + + 5.11 SPECIAL NUMERIC VALUES + + TECO maintains several internal variables which record conditions + within TECO. The variable name is equivalent to the current + contents of the variable and may be entered as a numeric argument + to TECO commands. When the command is executed, the current + value of the designated variable becomes the numeric argument of + the command. + + Some of the characters which stand for specific values associated + with the text buffer have been introduced earlier in this manual. + For example, the dot character (.), which represents the current + pointer position, may be used in the argument of a T command. + The command ".,.+5T" causes the 5 characters following the buffer + pointer to be typed out. When this command is executed, the + number of characters preceding the buffer pointer is substituted + in each case for the "dot". The addition is then carried out, + and the command is executed as though it were of the form "m,nT". + + Table 5-11 lists all of the characters which have special numeric + values. Any of these characters may be used as numeric argument + in place of the value it represents. + + + TABLE 5-11: CHARACTERS ASSOCIATED WITH NUMERIC QUANTITIES + + CHARACTER FUNCTION + + B Always equivalent to zero. Thus, B represents the + position preceding the first character in the buffer. + + Z Equivalent to the number of characters currently + contained in the buffer. Thus, Z represents the + position following the last character in the buffer. + + . Equivalent to the number of characters between the + beginning of the buffer and the current position of the + pointer. Thus "." represents the current position of + the pointer. + + H Equivalent to the numeric pair "B,Z", or "from the + beginning of the buffer up to the end of the buffer." + Thus, H represents the whole buffer. + + nA Equivalent to the ASCII code for the .+n+1th character + in the buffer (that is, the character to the right of + buffer pointer position .+n). The expression -1A is + equivalent to the ASCII code of the character + immediately preceding the pointer and 0A is equivalent + to the ASCII code of the character immediately + following the pointer (the current character). If the + character position referenced lies outside the bounds + of the text buffer, this command returns a -1. + + Standard TECO PAGE 90 + Special Numeric Values + + + Mq The Mq command (execute the contents of the text + storage area of Q-register "q" as a command string) may + return a numeric value if the last command in the + string returns a numeric value and is not followed by a + . + + Qq Equivalent to the value stored in the number storage + area of Q-register q. + + :Qq Equivalent to the number of characters in the text + storage area of Q-register q. + [Not in TECO-8] + + \ Backslash is equivalent to the numeric value of the + digit string in the text buffer at the current pointer + position, interpreted in the current radix. The + pointer is moved to the end of the digit string. + + ^B (caret/B) is equivalent to the current date + via the following equations: + + OS/8: ^B = (((month*32)+day)*8)+((year-1970)&7)+k + where k = 4096 if year>1977 + and k=0 otherwise + RT-11: ^B = (((month*32)+day)*32)+year-1972 + RSTS/E: ^B = ((year-1970)*1000)+day within year + RSX-11: ^B = ((year-1900)*16+month)*32+day + VAX/VMS: ^B = ((year-1900)*16+month)*32+day + TOPS-10: ^B = (((year-1964)*12+month-1)*31+day-1) + + ^E (caret/E) determines whether or not the P + command (and related operations) append a form feed to + the contents of the buffer on output. If ^E is -1, a + form feed is appended; if ^E is 0, no form feed is + appended. + + Each time text is read into the text buffer TECO sets + the ^E flag. If the text read terminated due to a form + feed (i.e., if the text buffer was loaded with a + "complete page"), ^E is set to -1. If the text read + terminated because the buffer was filled to capacity + before a form feed was encountered or because there was + no form feed (i.e., the text buffer was not loaded with + a "complete page"), ^E is set to 0. + + In TECO-11, you can set the ^E flag's value directly, + overriding the value set by the most recent buffer + read. Be sure to use only values of 0 or -1; other + values may cause unpredictable results. + + ^F (caret/F) is equivalent to the current value + of the console switch register. + + Standard TECO PAGE 91 + Special Numeric Values + + + n^F n is the terminal number plus 200000 (octal) + for job n's terminal. -1^F is the terminal number plus + 200000 (octal) for your job's terminal. The result is + 0 if the specified job is detached or if there is no + such job. + [TECO-10 only] + + ^H (caret/H) is equivalent to the current time of + day via the following equations: + + OS/8: ^H = 0 + RT-11: ^H = (seconds since midnight)/2 + RSTS/E: ^H = minutes until midnight + RSX-11: ^H = (seconds since midnight)/2 + VAX/VMS: ^H = (seconds since midnight)/2 + TOPS-10: ^H = 60ths of a second since midnight + (or 50ths of a second where 50 Hz power is used) + + ^N (caret/N) is the end of file flag. It is + equivalent to -1 if the file open on the currently + selected input stream is at end of file, and zero + otherwise. + + ^S (caret/S) is equivalent to the negative of the + length of the last insert, string found, or string + inserted with a "G" command, whichever occurred last. + To back up the pointer to the start of the last insert, + string found, etc., type "^SC". + [Not in TECO-8] + + ^T (caret/T) is equivalent to the ASCII code for + the next character typed at the terminal. Every ^T + command executed causes TECO to pause and accept one + character typed at the terminal. See the ET flag + description (section 5.16) for variations. + + :^T Reads and decodes the next keystroke typed at the + terminal. The decoded keystroke is returned in a + manner similar to that used for immediate ESCape + sequence commands (see section 4.4), i.e., via + and codes, as follows: + 0 Normal character, + is ASCII value + + 1 Control character + (except ESCape or CSI); + is ASCII value of + control char. + A typed yields + 1 13, + and subsequent ^T or :^T + does not return a . + + Standard TECO PAGE 92 + Special Numeric Values + + + 2 Same as immed ESC seq 0 + 3 Same as immed ESC seq 1 + 4 Same as immed ESC seq 2 + 5 Same as immed ESC seq 3 + [TECO-11 only] + + ^Y (caret/Y) is equivalent to ".+^S,.", the n,m + numeric argument spanning the text just searched for or + inserted. This value may be used to recover from + inserting a string in the wrong place. Type "^YXSFR`" + to store the string in Q-register S and remove it from + the buffer. You can then position the pointer to the + right place and type "GS" to insert the string. + [TECO-11 only] + + ^Z (caret/Z) is equivalent to the total space + occupied by text in the Q-registers (including the + command line currently being executed). + [TECO-11 only] + + ^^x The combination of the Control-caret (double caret or + double up-arrow) followed by any character is + equivalent to the value of the ASCII code for that + character. The "x" in this example may be any + character that can be typed in to TECO. + + Standard TECO PAGE 93 + Special Numeric Values + + + MODE CONTROL FLAGS + + The following mode control flags return numeric values. The use + of these flags is described below in section 5.16. + + ED Equivalent to the current value of the edit level flag. + + EH Equivalent to the current value of the help level flag. + + EO Equivalent to the version number of the version of TECO + which is currently being run. This manual describes + TECO-11 Version 40, TECO-8 Version 7, and TECO-10 + Version 3. + + ES Equivalent to the current value of the search + verification flag. + [Not in TECO-8] + + ET Equivalent to the current value of the type out control + flag. + + EU Equivalent to the current value of the upper/lower case + flag. + + EV Equivalent to the current value of the edit verify + flag. + [TECO-11 only] + + ^X (caret/X) is equivalent to the current value + of the search mode flag. + [Not in TECO-8] + + Standard TECO PAGE 94 + Command Loops + + + 5.12 COMMAND LOOPS + + You can cause a command string to be executed any number of times + by placing the command string within angle brackets and preceding + the brackets with a numeric argument designating the number of + iterations. Iterated command strings are called command loops. + Loops may be nested so that one command loop contains another + command loop, which, in turn, contains other command loops, and + so on. The maximum depth to which command loops may be nested is + determined by the size of TECO's push-down list (system + dependent), but is always greater than 10. + + The general form of the command loop is: + + n + + where "command string" is the sequence of commands to be iterated + and n is the number of iterations. If n is not supplied then no + limit is placed on the number of iterations. If n is 0 or less + than 0 then the iteration is not executed at all; command + control skips to the closing angle bracket. If n is greater than + 0, then the iteration is performed n times. + + Search commands inside command loops are treated specially. If a + search command which is not preceded by a colon modifier is + executed within a command loop and the search fails, a warning + message is printed [on TECO-11], the command loop is exited + immediately and the command following the right angle bracket of + the loop is the next command to be executed. If an unmodified + search command in a command loop is immediately followed by a + semicolon, it is treated as if it were a colon-modified search + (see section 5.13). + + Standard TECO PAGE 95 + Branching Commands + + + 5.13 BRANCHING COMMANDS + + TECO provides an unconditional branch command and a set of + conditional execution commands. To branch within a command + string, you must be able to name locations inside the string. + TECO permits location tags of the form: + + !tag! + + to be placed between any two commands in a command string. The + name "tag" will be associated with this location when the command + string is executed. Tags may contain any number of ASCII + characters and any character except an exclamation mark. (When + using the @ form of this command, any character except the + delimiter is legal.) Since tags are ignored by TECO except when a + branch command references the tagged location, they may also be + used as comments within complicated command strings. + + The unconditional branch command is the O command which has the + form: + + Otag` + + where "tag" is a location named elsewhere in the command string + and "`" signifies a . When an O command is executed, the + next command to be executed will be the one that follows the tag + referenced by the O command. Command execution continues + normally from this point. + + Use of the O command is subject to two restrictions. First, if + an O command is stored in a Q-register as part of a command + string which is to be executed by an M command, the tag + referenced by the O command must reside in the same Q-register. + + Second, an O command which is inside a command loop may not + branch to a tagged location preceding the command loop. However, + it is always possible to branch out of a command loop to a + location which follows the command loop and then branch to the + desired tag. + + The string argument in the O command has the same format as the + string arguments in the search and E commands. String build + characters such as ^EQq can be embedded within the string in + TECO-11. Also, in TECO-11 and TECO-10, the O command may be + @-sign modified. In that case, the syntax of the command would + be @O/tag/ where / represents any delimiting character that does + not appear within the tag. + + Branching into a conditional poses no problems, but branching + into a command loop will causes unpredictable results. + + Although tags may contain any sequence of ASCII characters, good + programming practice dictates that tags should not contain + + Standard TECO PAGE 96 + Branching Commands + + + unusual characters (such as space, comma, ESCAPE, etc.) and that + they should be mnemonic for the piece of code to which they + refer. + + There are many other branching commands. Most of these are + considerably faster than the O command and should be used + wherever convenient. They are all described in the table below. + + TABLE 5-13: BRANCHING COMMANDS + + COMMAND FUNCTION + + Otag` This command causes TECO to branch to the first + occurrence of the specified label (tag) in the current + macro level. In TECO-8 and TECO-11, branching to the + left of the start of the current iteration is not + permitted, and this command will only look for an + occurrence of the specified tag following the < of the + current iteration, if you are in an iteration. In any + case, branching out of an iteration is poor programming + practice. Command execution resumes at the first + character after the delimiter terminating the specified + tag. Using this syntax, any character except is + permitted in the tag specification. The usual string + build characters are permitted when specifying the tag. + + @O/tag/ Equivalent to Otag` except that a delimiter (shown here + as /) is used before and after the specified tag. Any + character other than that delimiter is permitted inside + the tag. The usual string build characters are + permitted when specifying the tag. + [Not in TECO-8] + + nOtag0,tag1,tag2,...` + This command causes TECO to branch to the tag specified + by the nth tag in the accompanying list. The string + argument to this command consists of a sequence of tags + separated by commas. The tags may contain any + characters other than comma or ; however, good + programming practice suggests that the tags should + consist only of letters and digits. There must be no + intervening spaces since these would be considered part + of the tag. If n is out of range, or if n selects a + null tag, then command execution continues with the + first command following the that delimits this + command. (A null tag would be signified in the list by + two adjacent commas.) + [TECO-11 only] + + n@O/tag0,tag1,tag2,.../ + Same as the preceding command except that the list of + tags is bracketed by a delimiter shown here as "/". + The delimiter can be any character that does not appear + + Standard TECO PAGE 97 + Branching Commands + + + within the list of tags. In particular, using comma + for the delimiter would not be very useful. + [TECO-11 only] + + ; This command causes TECO to branch out of the current + iteration, if the immediately preceding search (or + search and replace) command failed. In that case, + control resumes at the character following the matching + > at the end of the current iteration. On the other + hand, if the preceding search succeeded, command + execution continues with the character following the ;. + If this command is encountered from outside of an + iteration (in the current macro level), then the ?SNI + error message is issued. + + n; This command causes TECO to branch out of the current + iteration if the value of n is greater than or equal to + 0. In that case, command execution resumes at the + character following the matching > at the end of the + current iteration. On the other hand, if n is less + than 0, command execution continues with the character + following the ;. If this command is encountered from + outside of an iteration (in the current macro level), + then the ?SNI error message is issued. + + :; This command causes TECO to branch out of the current + iteration if the immediately preceding search (or + search and replace) command succeeded. In that case, + control resumes at the character following the matching + > at the end of the current iteration. On the other + hand, if the preceding search failed, command execution + continues with the character following the ;. If this + command is encountered from outside of an iteration (in + the current macro level), then the ?SNI error message + is issued. + [TECO-11 only] + + n:; This command causes TECO to branch out of the current + iteration if the value of n is less than 0. In that + case, command execution resumes at the character + following the matching > at the end of the current + iteration. On the other hand, if n is greater than or + equal to 0, command execution continues with the + character following the ;. If this command is + encountered from outside of an iteration (in the + current macro level), then the ?SNI error message is + issued. + [TECO-11 only] + + ' This "command" is actually part of the syntax of TECO + conditionals. It has no affect if "executed" other + than to signify termination of the current conditional + level. If an argument is specified to this command, + + Standard TECO PAGE 98 + Branching Commands + + + the result is not defined. (Arguments pass through + this command on TECO-11.) Conditionals are described in + section 5.14. + + | This "command" is actually part of the syntax of TECO + conditionals. If executed, it causes control to branch + to the end of the conditional. Command execution + resumes with the character following the ' that ends + the current conditional with the ELSE clause being + skipped. + + > This "command" is actually part of the syntax of TECO + iterations. If executed, it causes TECO to bump the + current iteration count by 1 and test to see if the + resulting count is equal to the maximum count permitted + for the iteration (specified as an argument before the + matching <). If the iteration count has not expired, + then control returns to the command following the < at + the beginning of the current iteration. If the + iteration has expired, then command execution continues + with the character following this >. If this command + is encountered outside of an iteration (within the + current macro level), then the ?BNI error message (or + its equivalent) is issued. + + F> This command causes TECO to branch (flow) to the end of + the current iteration. TECO effectively resumes + execution at the matching >. The iteration count is + tested as usual. If it has not expired, control + returns back to the start of the iteration with the + count having been incremented by 1. If the count was + up, the iteration is exited and control continues with + the first command after the >. If this command is + encountered outside of an iteration, it has the same + effect as the command. + [TECO-11 only] + + F< This command causes TECO to branch (flow) to the start + of the current iteration. TECO effectively resumes + execution at the first command following the < at the + beginning of the current iteration. The iteration + count is not affected. If this command is issued + outside of an iteration, it causes TECO to branch back + to the start of the current command string (in the + current macro level). + [TECO-11 only] + + F' This command causes TECO to branch (flow) to the end of + the current conditional. TECO effectively resumes + execution at the first command following the ' at the + end of the current conditional. Numeric arguments are + eaten up by this command. If this command is issued + while not in a conditional, the ?MAP error (or its + + Standard TECO PAGE 99 + Branching Commands + + + equivalent) is issued. + [TECO-11 only] + + F| This command causes TECO to branch (flow) to the else + clause of the current conditional. TECO effectively + resumes execution at the first command following the | + at the end of the current THEN clause. If the current + conditional has no ELSE clause, or if an unmatched ' is + encountered before an unmatched |, then control resumes + at the command following the ' . Numeric arguments are + eaten up by this command. If this command is issued + while not in a conditional, the ?MAP error (or its + equivalent) is issued. Well-structured programs should + not need to use this command. + [TECO-11 only] + + $$ The command causes TECO to exit from the + current macro level. If this command is issued from + top level (not from within a macro), then the command + string execution is terminated and TECO returns to + prompt level. Note that the second must be a + true ESCape and may not be a ^[. Also, note that both + ESCapes must be true TECO commands and not part of the + syntax of some previous command. That is, the first + does not count if it is the delimiting ESCape of + a string. Finally, note that these must be real ESCape + characters, and not the user-designated + character (which TECO understands as an ESCape only + when typed at the console). + + n$$ This command causes TECO to exit from the current macro + level, returning the number n as a value. This value + will be used as the numeric argument to the first + command following the macro call. + + m,n$$ This command causes TECO to exit from the current macro + level, returning the pair of values m and n as + arguments to the first command following the macro + call. Good programming practice dictates that all ways + of exiting a macro return the same number of arguments. + + ^C The (Caret-C) command when executed as a TECO + command, causes command execution to stop and control + return to TECO's prompt. No clean-up of push-down + lists, flag settings, etc. is done. This command lets + a macro abort TECO's command execution. + [On TECO-8 and TECO-10, this command causes control to + return to the operating system.] + [On TECO-11, this command returns to the operating + system if executed from the top level.] + Consult the appendices for specific details concerning + your operating system. + + Standard TECO PAGE 100 + Branching Commands + + + ^C + This command causes TECO to unconditionally abort and + control exits from TECO. Control returns to the + operating system. The second must be a true + and may not be a Caret-C. + + Standard TECO PAGE 101 + Conditional Execution Commands + + + 5.14 CONDITIONAL EXECUTION COMMANDS + + All conditonal execution commands are of the form: + + n"X command-string ' + or + n"X then-command-string | else-command-string ' + + In the first form of the command, "n" is a numeric argument on + which the decision is based, "X" is any of the conditional + execution commands listed in table 5-14, and "command string" is + the command string which will be executed if the condition is + satisfied. The numeric argument is separated from the + conditional execution command by a double quote (") and the + command string is terminated with an apostrophe ('). If the + condition is not satisfied, the command string will not be + executed; execution will continue with the first command after + the apostrophe. + + In the second form of the command, two command strings are + specified. The first one is executed if the condition is + satisfied and the second is executed if the condition is not + satisfied. Only one of the command strings will be executed. + After execution of the appropriate command string, control will + continue with the first command after the apostrophe (unless the + command string caused a branch out of the conditional to occur), + since execution of the vertical bar command (|) causes TECO to + scan to the next matching apostrophe. + + Conditional commands are similar to the IF-THEN-ELSE constructs + that you find in other structured programming languages, although + none can match the brevity and elegance of TECO's implementation. + Nonetheless, you must use these facilities wisely. Good + programming practice dictates that a branch into the range of a + conditional (from outside that range) should not occur. + + Conditional execution commands may be nested in the same manner + as iteration commands. That is, the command string which is to + be executed if the condition on n is met may contain conditional + execution commands, which may, in turn, contain further + conditional execution commands. + + + TABLE 5-14: CONDITIONAL EXECUTION COMMANDS + + COMMAND FUNCTION + + n"A Execute the following command string if n equals the + ASCII code for an alphabetic character (upper or lower + case A to Z). + + n"C Execute the following command string if n is the ASCII + code of any character that is a symbol constituent. + + Standard TECO PAGE 102 + Conditional Execution Commands + + + This is usually one of the upper or lower case letters + A to Z, one of the digits 0 to 9, or period, or dollar + sign, but may include additional characters on some + operating systems. Consult the appropriate appendix. + + n"D Execute the following command string if n equals the + ASCII code for a digit (0 to 9). + + n"E Execute the following command string if n is equal to + zero. + + n"F Execute the following command string if n is FALSE. + Equivalent to n"E. + + n"G Execute the following command string if n is greater + than zero. + + n"L Execute the following command string if n is less than + zero. + + n"N Execute the following command string if n is not equal + to zero. + + n"R Execute the following command string if n equals the + ASCII code for an alphanumeric (upper or lower case A + to Z or 0 to 9). + + n"S Execute the following command string if n is + SUCCESSFUL. Equivalent to n"L. + + n"T Execute the following command string if n is TRUE. + Equivalent to n"L. + + n"U Execute the following command string if n is + UNSUCCESSFUL. Equivalent to n"E. + + n"V Execute the following command string if n equals the + ASCII code for a lower case alphabetic character (lower + case A to Z). + [Not in TECO-8] + + n"W Execute the following command string if n equals the + ASCII code for an upper case alphabetic character + (upper case A to Z). + [Not in TECO-8] + + n"< Identical to n"L + + n"> Identical to n"G + + n"= Identical to n"E + + Standard TECO PAGE 103 + Retrieving Environment Characteristics + + + 5.15 RETRIEVING ENVIRONMENT CHARACTERISTICS + + The following TECO commands return values of interest to users + who want information about their current job, the operating + system, their terminal, etc. + + All negative EJ commands return an operating system dependent + value. Consult the appendices for operating system unique + commands. + + + TABLE 5-15A: RETREIVING ENVIRONMENT CHARACTERISTICS + + COMMAND FUNCTION + + -1EJ Return a number representing the computer and operating + system upon which TECO is currently running. This + value has the form 256m+n where m is a number + representing the computer in use and n is a number + representing the operating system that is running. + Current values of m and n are: + + Computer (m) Operating System (n) + + 0 PDP-11 0 RSX-11D + 1 RSX-11M + 2 RSX-11S + 3 IAS + 4 RSTS/E + 5 VAX/VMS + (compatibility mode) + 6 RSX-11M+ + 7 RT-11 + 1 PDP-8 0 OS/8 + 2 DEC-10 0 TOPS-10 + 3 DEC-20 0 TOPS-20 + 4 VAX-11 0 VAX/VMS + (native mode) + + 0EJ Returns a value equal to your job number. On + single-user systems, this is always a 0. + + 1EJ Returns a value equal to your console keyboard number + (the keyboard you detached from if you are running + detached). On single-terminal systems, this is always + a 0. + + 2EJ Returns a value equal to your operating system's user + identification number. This may be called your UIC, + PPN, Group, etc. under various operating systems. + Consult the appendices for more information. + + Standard TECO PAGE 104 + Retrieving Environment Characteristics + + + TABLE 5-15B: SETTING ENVIRONMENT INFORMATION + + n,1EJ Set the terminal number to receive output. This will + not affect terminal input. Your job will remain + attached to, or detached from, your terminal, whichever + it was before. Output will only occur if the specified + terminal is ASSIGNed with a monitor ASSIGN command (you + may ^C, issue that command and continue) and if your + job has POKE privileges. This command also sets the + terminal to be reattached if the set detach flag + (64&ET) is cleared. The reattaching operation requires + [1,2] or JACCT privileges. + [TECO-10 only] + + n,2EJ Sets your [p,pn] to n where n has the same format as + the number returned by the 2EJ command. Issuance of + this command requires the appropriate privileges. + [TECO-10 only] + + Standard TECO PAGE 105 + Mode Control Flags + + + 5.16 MODE CONTROL FLAGS + + TECO has flags which control various aspects of its operation. + You can find a flag's current setting by executing its command + name without an argument; the current setting of the flag is + returned as a value. A flag may be set to a specific value by + executing its command name preceded by a numerical argument; the + flag is set to the value of the argument. + + The following table describes the commands that set and clear + flags; represents any of the flags listed below. + + + TABLE 5-16A: FLAG MANIPULATION COMMANDS + + Return value of flag. + + n Set value of flag to n. + + m,n In the flag, turn off those bits specified by m + and turn on those bits specified by n. + + 0,n Turn on the bits in the flag specified by n. + + m,0 Turn off the bits in the flag specified by m. + + + The flags have the following functions: + + + TABLE 5-16B: MODE CONTROL FLAGS + + COMMAND FUNCTION + + ED The edit level flag, a bit-encoded word that controls + TECO's behavior in various respects. Any combination + of the individual bits may be set as the user sees fit. + The bits have the following functions: + + ED&1 Allow caret (^) in search strings. If this + bit is clear, a caret (^) in a search string + modifies the immediately following character + to become a control character. When this bit + is set, a caret in a search string is simply + the literal character caret. If you are + editing a file that contains many caret + characters (e.g., a RUNOFF file with case + control), you will want to set this bit. + (For control of upper/lower case matching in + search strings, see the ^X flag.) + + ED&2 Allow all Y and _ commands. If this bit is + set, the Y (Yank) command and _ (underscore + + Standard TECO PAGE 106 + Mode Control Flags + + + or backarrow) command work unconditionally as + described earlier in the manual. If clear, + the behavior of the Y and _ commands are + modified as follows: If an output file is + open and text exists in the text buffer, the + Y or _ command will produce an error message + and the command will be aborted leaving the + text buffer unchanged. Note that if no + output file is open the Y and _ commands act + normally. Furthermore, if the text buffer is + empty the Y command can be used to bring in a + page of text whether or not an output file is + open (HKY will always work). The _ command + will succeed in bringing one page of text + into an empty text buffer but will fail to + bring in successive pages if an output file + is open. + + ED&4 When this bit is clear, TECO will try to + expand memory as much as it can in order to + try to fit entire pages into memory when + requested to do so. If this bit is set, + arbitrary memory expansion will not occur. + In that case, TECO will expand memory only on + the A command and not on the Y, P, or N + commands. This bit is always set in TECO-10 + and has no significance in TECO-8 or in + TECO-11 on RT-11. + + ED&8 Reserved for future use by TECO-8. + + ED&16 Allow failing searches to preserve dot. If + this bit is set, then whenever a search + fails, the original location of the text + buffer pointer will be preserved. If this + bit is clear, then failing searches (other + than bounded searches) leave the text buffer + pointer at pointer position 0 after they + fail. + [not in TECO-8] + + ED&32 Enable immediate ESCape-sequence commands. + If this bit is set, TECO will recognize an + ESCape-sequence key pressed immediately after + the prompting asterisk as an immediate + command. See section 4.4 for a description + of immediate ESCape-sequence commands. + + If this bit is clear (the default case), TECO + will treat an ESCape coming in immediately + after the asterisk prompt as a That + is, TECO will hear a discrete + character: an ESCape sequence will therefore + + Standard TECO PAGE 107 + Mode Control Flags + + + be treated not as a unified command, but as a + sequence of characters. + [TECO-11 only] + + ED&64 Only move dot by one on multiple occurrence + searches. If this bit is clear, TECO treats + nStext` exactly as n<1Stext`>. That is, skip + over the whole matched search string when + proceeding to the nth search match. For + example, if the text buffer contains only + A's, the command 5SAA` will complete with dot + equal to ten (10). If this bit is set, TECO + increments dot by one each search match. In + the above example, dot would become five (5). + [TECO-11 only] + + ED&128 Automatic refresh inhibit. If scroll mode is + enabled (that is, if 7:W is non-zero), TECO + normally refreshes the text buffer display + just before printing its * prompt. Setting + the 128 bit in ED inhibits this automatic + refresh. (Inhibiting the automatic refresh + may be useful when running over a slow + terminal line; see also the ^W immediate + command.) + [TECO-11 only] + + The initial value of ED&1 is system dependent (See + appendices). The initial value of the other bits in + the ED flag is 0. + + EE This flag is initially zero, and (unless the 8192 ET + bit is set) TECO recognizes only the ESCape as its + character from the console. If it is desired + to use another character as an ESCape surrogate (as + when working from a terminal lacking an ESCape key), + the ASCII value of that other character may be set in + the EE flag. Note that when an ESCape surrogate is + set, the designated character (when typed at the + console) is received by TECO as an ESCape -- that + character is no longer directly available at the + keyboard. When an ESCape surrogate is active, an + ESCape received by TECO echos as accent grave; when + none is active, an ESCape received by TECO echos as + dollar sign. This feature is provided for the benefit + of newer terminals which lack an ESCape key. (8192ET + and 96EE both set ` as ESCape surrogate. EE, however, + can be used to designate a character other than accent + grave.) + [RSTS/E only] + + EH The help level flag, which controls the printing of + error messages and failed commands. (See also the / + + Standard TECO PAGE 108 + Mode Control Flags + + + command.) + + EH&3 The low two bits of EH (value range 0 through + 3) control the printing of TECO error + messages as follows (assuming the low two + bits have value m): + + If m is equal to 1, error messages are output + in abbreviated form ("?XXX"). If m is equal + to 2, error messages are output in normal + form ("?XXX Message"). If m is equal to 3, + error messages are output in long or "War and + Peace" form, that is, a paragraph of + informative material is typed following the + normal form of the error message. In + TECO-11, m=3 is implemented only on VAX/VMS. + (See section G.13 for a description of HELP + facilities available on VAX/VMS.) In other + TECO-11's, case m=3 is equivalent to m=2. + + EH&4 If this bit of EH is set, the failing command + is also output up to and including the + failing character in the command followed by + a question mark. (Just like TECO's response + to the typing of a question mark immediately + after an error.) This bit is not supported by + TECO-10. + + The initial value of the EH flag is 0 which is + equivalent to a value of 2. + + EO Setting the value of the EO flag to n allows features + that were peculiar to that version of TECO to work. + [TECO-10 only] + + ES The search verification flag, which controls the text + typed out after searches. + + If n is equal to 0, nothing is typed out after + searches. If n is -1, the current line is typed out + when a successful search at top level is completed + (i.e., a V command is done automatically). If n is + between 1 and 31, the current line is typed out with a + line feed immediately following the position of the + pointer to identify its position. If n is between 32 + and 126, the current line is typed out with the ASCII + character corresponding to the value of n immediately + following the position of the pointer to identify its + position. If you want to see more than one line of + type out, use the form m*256+n. The n is the same as + above. The m is the number of lines of view. For + example, 3*256+^^! would give two lines on either side + of the found line, and the found line with the + + Standard TECO PAGE 109 + Mode Control Flags + + + character "!" at the pointer's position. The ES flag + does not apply to searches executed inside iterations + or macros; lines found inside iterations or macros are + never typed out. + [Not in TECO-8] + + The initial value of ES is 0. + + ET The ET flag is a bit-encoded word controlling TECO's + treatment of the console terminal. Any combination of + the individual bits may be set. The bits provide the + following functions, when set: + + ET&1 Type out in image mode. Setting this bit + inhibits all of TECO's type out conversions. + All characters are output to the terminal + exactly as they appear in the buffer or ^A + command. For example, the changing of + control characters into the "caret/character" + form, and the conversion of to ` + (accent grave) or to $ (dollar sign) are + suppressed. This mode is useful for driving + displays. It should be used with caution, + especially if you are talking to TECO over a + dial-up line. + + ET&2 Process DELETEs and s in "scope" + mode. Scope mode processing uses the cursor + control features of CRT type terminals to + handle character deletion by actually erasing + characters from the screen. + + ET&4 Read lower case. TECO normally converts all + lower case alphabetics to upper case on + input. Setting this bit causes lower case + alphabetics to be input as lower case. TECO + commands and file specifiers may be typed in + either upper or lower case. For the purpose + of searches, however, upper and lower case + may be treated as different characters. (See + ^X flag). + + ET&8 Read without echo for ^T commands. This + allows data to be read by the ^T command + without having the characters echo at the + terminal. Normal command input to TECO will + echo. + + ET&16 Cancel on type out. Setting this + bit will cancel any outstanding when + the next type out occurs. After TECO has + canceled the , it will automatically + clear the bit. + + Standard TECO PAGE 110 + Mode Control Flags + + + ET&32 Read with no wait. This enables the ^T + command to test if a character is available + at the user terminal. If a character has + been typed, ^T returns the value of the + character as always. If no character has + been typed, ^T immediately returns a value of + -1 and execution continues without waiting + for a character. + + ET&64 Detach flag (See appendices). + + ET&128 "Abort-on-error" bit. Initially set, when + TECO starts up; cleared each time TECO + issues its asterisk prompt. When this bit is + set: 1) all informational messages are + supressed, 2) any causes the + immediate termination of TECO, and 3) any + error causes the termination of TECO after + the error message is printed. + + ET&256 If this bit is set, all lines output to the + terminal are truncated to the terminal's + width if needed. (RSTS/E, RSX-11, and + VAX/VMS only. On VAX/VMS, this bit reflects + and can change the state of the terminal + characteristic WRAP/NOWRAP; TECO restores + the terminal characteristic to its original + state upon exit.) + + ET&512 If this bit is set, the scope "WATCH" feature + of TECO is present and your terminal is a + scope type terminal. This bit is a read-only + bit; its state cannot be altered. (See + Section 5.17.) + + ET&1024 If this bit is set, the refresh scope "WATCH" + feature of TECO is present and a refresh + scope is available. This bit is a read-only + bit; its state cannot be altered. (See + Section 5.17.) + + ET&4096 This bit reflects and can change the state of + the terminal characteristic (maintained by + the operating system) recording whether the + terminal is capable of handling eight-bit + character codes. Upon entry to TECO, this + bit reflects the characteristic as recorded + with the operating system at that time. If + you change this bit, the operating system is + directed to change its recording of the + characteristic to match. + + Because the data manipulated (edited) by TECO + + Standard TECO PAGE 111 + Mode Control Flags + + + can consist of all 256 possible byte codes, + the way data characters are displayed (typed + out) at the console varies depending upon the + setting of the 4096 ET bit. + + If the bit is clear (meaning that TECO + understands your terminal to be 7-bit), valid + DEC multi-national codes are typed out as + (where xy is the corresponding LK201 + keyboard compose sequence). + + If the bit is set (meaning that TECO + understands your terminal to be 8-bit), valid + DEC multi-national codes are typed out as + themselves. + + In either case, unprintable or illegal codes + in the 128 to 255 range are typed out as [ab] + (where ab is the corresponding hexadecimal + code). The scope watch feature (screen + buffer display, controlled by the W commands) + always uses the and [ab] notations. + + ET&8192 Accent grave as ESCape surrogate. + [TECO-11 only] + + If this bit is set, TECO recognizes the ` + (accent grave) character as an ESCAPE + surrogate. That is, an ` character typed at + the console will be recognized as a command + character, and passed to TECO as an + ESCape. (This interpretation applies only to + s typed at the console; ESCape + characters must still be used in macros and + indirect files.) When an ESCape surrogate is + set, an ESCape received by TECO echos as + accent grave; when none is set, an ESCape + received by TECO echos as dollar sign. This + feature is provided for the benefit of + certain newer terminals which lack an ESCape + key. (See also the Introduction, and the EE + flag.) + + ET&32768 If this bit is set and a is typed, + the bit is turned off, but execution of the + current command string is allowed to + continue. This allows a TECO macro to detect + typed s. + In TECO-8, this bit is the 2048's bit rather + than the 32768's bit. + + The initial setting of ET is operating system dependent + (See appendices). In addition, some of the ET bits are + + Standard TECO PAGE 112 + Mode Control Flags + + + automatically turned off by certain error conditions. + + EU The upper/lower case flag. + + If n is -1, no case flagging of any type is performed + on type out, lower case characters are output as lower + case characters. If n is 0, lower case characters are + flagged by outputting a ' (quote) before the lower case + character and the lower case character is output in + upper case; upper case characters are unchanged. If n + is +1, upper case characters are flagged by outputting + a ' (quote) before each one and then the upper case + character is output; lower case characters are output + as their upper case equivalents. + + The initial value of the EU flag is -1 if TECO can tell + from the operating system that the user's terminal + supports display of lower case characters; otherwise + te initial value is 0. Consult the appendices for more + details. + + EV The edit verify flag is decoded just like the ES flag. + Just before TECO prints its prompting *, the EV flag is + checked. If it is non-zero the lines to be viewed are + printed on the terminal. + + The initial value of the EV flag is 0. + [TECO-11 only] + + ^X The search mode flag. + [Not in TECO-8] + + If ^X is 0, the text argument in a search command will + match text in the text buffer independent of case in + either the search argument or the text buffer. The + lower case alphabetics match the upper case + alphabetics, and "`", "{", "|", "}", "~" match "@", + "[", "\", "]", "^" respectively. In addition, DEC + multinational characters having diacritical marks are + regarded as matching the corresponding characters + without diacritical marks. + + If ^X is -1, the search will succeed only if the text + argument is identical to text in the text buffer. + (This means that lower case does NOT match upper case, + nor does a character having a diacritical mark match + one without). + + The initial value of the ^X flag is 0. (For control of + caret or uparrow treatment in search strings, see the + ED&1 bit above.) + + Standard TECO PAGE 113 + Scope Commands + + + 5.17 SCOPE COMMANDS + + The W command (scope "WATCH") is present in most implementations + of TECO. There are two different variations of the W command. + Neither, one, or both may be present. ET flag Bits 9 and 10 + indicate which variation(s) are configured and can be used. + + + 5.17.1 Video Terminal Scope Commands + + If the VT support is present and your terminal is a video + terminal (such as a VT05, VT52, or VT100), ET flag Bit 9 (value + 512) will be on. + + + TABLE 5-17A: VIDEO TERMINAL WATCH COMMANDS + + COMMAND FUNCTION + + -1W Refresh the terminal's screen to show the contents of + the text buffer. + + -nW Tell the video terminal screen refresher that the top + n-1 lines of the screen have been altered. The screen + refresher will completely redraw the top n-1 lines of + the screen upon the next -1W command. + + nW Place the default cursor line at line n of the screen. + The initial default cursor line is line 16. This + command makes the window support forget the screen + image and any special associated modes (SEEALL, MARK, + HOLD). + + 0W Equivalent to "16W". + + W Forget screen image and special scope modes. + + -1000W Forget that output was done. Normally, if the user + outputs to the terminal with a command such as T, n^T, + or ^A, TECO will believe that the window needs + updating, and upon the next -1W command, TECO will + refresh the entire window display. Issuing the -1000W + command informs TECO that the output command did not + destroy the window. + [TECO-11 only] + + Standard TECO PAGE 114 + Video Terminal Scope Commands + + + The :W commands are used to interrogate and set (see m,n:W below) + video terminal status information, as well as implement some of + the more advanced features of the video terminal "WATCH" + functions. + + + TABLE 5-17B: VIDEO TERMINAL STATUS COMMANDS + + COMMAND FUNCTION + + 0:W Return a number representing the type of scope in use + as the editing terminal. Current values are: + + 0 VT52 + 1 VT61 [TECO-10 only] + 2 VT100 in VT52 mode + 4 VT100 in ANSI mode + 6 VT05 + 8 VT102 in ANSI mode + 10 VK100 (GIGI) + + :W Equivalent to 0:W + + 1:W Return or set the horizontal size of the user's editing + scope. This number represents the number of character + positions available horizontally along the face of the + scope. + + If this value is changed (see m,n:W below), the + operating system is automatically informed of the + terminal's new width setting, and the appropriate + control sequence is issued to physically change the + terminal's screen mode (80 versus 132 column mode) if + needed. + + 2:W Return or set the vertical size of the user's editing + scope. This number represents the number of lines of + text that can appear on the screen of the terminal. + This number is affected by use of the m,7:W command + (set scrolling region). + + 3:W Return or set SEEALL mode. 0 represents off and -1 + represents on. In SEEALL mode, a visible indication is + shown in the window for every character, including + characters that normally don't print. + + 4:W Return or set "mark" status of window support. 0 means + that no mark has been set. A value of n means that a + mark has been set at buffer ("dot") position n-1. This + status is used by software that uses the window support + and by the support itself in the case of scopes that + support reverse video. + + Standard TECO PAGE 115 + Video Terminal Scope Commands + + + 5:W Return or set the hold mode indicator. 0 means off, -1 + means hold whole screen, and a positive value, n, means + hold all but top and bottom n lines. If hold mode is + on, then scrolling is inhibited until the cursor is + about to run off either end of the screen. This makes + the window display more palatable on terminals on a + slow line. If hold mode is on, the window support will + scroll the window as necessary in an attempt to keep + the cursor centered. + + 6:W Returns buffer pointer position of character that was + in the upper left hand corner of the window as of the + last -1W command. + + 7:W Return or set the number of lines in the scrolling + (command dialogue) portion of the screen. If n is + zero, then split screen scrolling is disabled. When + split screen scrolling is enabled, n lines (as + specified) are reserved at the bottom of the screen to + scroll the terminal interaction. The remainder of the + screen is used as a display window into the text + buffer, and is automatically updated by TECO + immediately before each command prompt. This feature + functions only on terminals capable of split screen + scrolling, such as members of the VT100 and VT200 + families. + + The value of n must be greater than 1, and scope height + minus n must be greater than 9. + + Whenever the scrolling region's size is modified (that + is, whenever an m,7:W command is executed), TECO alters + the scope's height (2:W) accordingly. For example, if + 2:W is currently returning a value of 24, then after a + 5,7:W command 2:W will return a value of 19. Executing + a 0,7:W will restore 2:W to 24. + + m,n:W Sets the entity represented by n:W to m and returns a + value. If the new setting has been accepted, the + returned value is m. Elsewise, the returned value is + either the old value associated with n:W or whatever + new setting was actually set. In all cases, the + returned value reflects the new current setting. + Specific operating systems may put restrictions on the + valid values for m. + + Note that each m,n:W command returns a value, even if + your only intent is to set something. Good programming + practice suggests following any command which returns a + value with or ^[ if you don't intend that value + to be passed to the following command. + + Standard TECO PAGE 116 + Video Terminal Scope Commands + + + 5.17.2 Refresh Scope Commands + + If refresh scope support is present and a refresh scope is + available (such as a VS60 or a VR12), bit value 1024 of the ET + flag will be on. + + + TABLE 5-17C: REFRESH SCOPE WATCH COMMANDS + + COMMAND FUNCTION + + W Update the refresh scope screen to reflect the contents + of the text buffer surrounding the text pointer + ("dot"). + + 0W Turn off the refresh scope display. + + nW Set the number of lines to be displayed around the text + pointer to n. + + Standard TECO PAGE 117 + Programming Aids + + + 5.18 PROGRAMMING AIDS + + In addition to the command string editing capabilities described + in Chapter 4, TECO includes various features to facilitate + programming. These are described in the following sections. + + + 5.18.1 Text Formatting + + The characters carriage return, line feed, and space are ignored + in command strings, except when they appear as part of a text + argument. Numeric values are not affected. (Inserting a space + between digits within a digit string may cause unpredictable + results). These characters may be inserted between any two TECO + commands to lend clarity to a long command string. The carriage + return/line feed combination is particularly useful for typing + command strings which are too long to fit on a single line. + + If the character form feed is encountered in a command string and + it is not part of a text argument, a form feed is output to the + terminal. This can be used to format terminal output. On + TECO-10, execution of the form feed command will clear the screen + if TECO is in scope command string editing mode (2&ET on). + + + 5.18.2 Comments + + One of the most powerful features of TECO is its ability to store + very long command strings so that a given sequence of commands + may be executed whenever needed. Long command strings may be + thought of as editing programs and, like any other type of + program, they should be documented by means of comments. + + Comments may be inserted between any two commands by using a tag + construction of the form: + + !THIS IS A COMMENT! + + Comments may contain any number of characters and any characters + except the special characters. Thus a long TECO macro might look + like: + + TECO commands !This comment describes line 1! + TECO commands !This comment describes line 2! + more commands + more commands !end of comment string! + + Do not use characters to format long command strings! Only + , , and can be used to format command strings + since is an insertion command. + + Good TECO code is well structured and adequately commented. + Unfortunately, massive comments in a TECO macro tend to slow + + Standard TECO PAGE 118 + Programming Aids + + + execution, especially if they appear within text scanned by GOTOs + or unsatisfied conditionals. Unless speed is not a goal, it is + common practice in larger TECO programs to strip out comments + before loading up TECO macros. Thus the TECO program can be + adequately commented, yet still run efficiently. + + A large TECO program can start by placing a comment stripper in a + Q-register, say Q-register C. Then it can successively put + subroutines (macro text) into the text buffer, do an MC, and load + the appropriate Q-register with the resulting text buffer, until + all the subroutines have been loaded. Finally, Q-register C can + be zeroed and the program started. + + In order for you to strip the comments without losing essential + tags, you must make a convention for the format of your comments + so that your comment stripper can distinguish them from tags. + There are two common conventions. In one, the first character in + every comment after the initial ! is some distinctive character, + such as *. In the other, all tags start in the left margin and + all comments are embedded within the text. Any large comment + that wants to be on a line by itself starts with a before + the !. Both methods allow for readable code and easy comment + stripping. + + + 5.18.3 Messages + + The command may be used to print out a statement at any + point during the execution of a command string. The + command has the general form: + + ^Atext + + or + + @^A/text/ + + The first ^A is the actual command, which may be entered by + striking the control key and the A key simultaneously or by + typing a caret (uparrow) followed by an A character. The second + character of the first form shown is the command + terminator, which must be entered by typing the control key and + the A key simultaneously. In the second form, the second + occurrence of the delimiting character (shown as slash in the + example) terminates the message. Upon execution, this command + causes TECO to print the specified message at the terminal. + + The ^Amessage command is particularly useful when it + precedes a command whose numeric argument contains ^T or ^F + characters. The message may contain instructions notifying the + user as to what sort of input is required. + + Standard TECO PAGE 119 + Programming Aids + + + 5.18.4 Tracing + + A question mark entered betweeen any two commands in a command + string causes TECO to print all subsequent commands at the + terminal as they are executed. Commands will be printed as they + are executed until another question mark character is encountered + or the command string terminates. + + + 5.18.5 Convenience Characters + + In addition to the characters mentioned in Section 5.18.1, there + are several characters which have no special meaning to TECO but + which may be used to help format your TECO programs and command + strings. Judicious use of these commands will make your program + easier to read and maintain. These characters are described in + the table below: + + + TABLE 5-18A: CONVENIENCE CHARACTERS + + CHARACTER MEANING + + A null (ASCII 0) encountered as a TECO + command will be ignored. Numeric values are + not affected. A null read in from an input + file will be discarded (except under RSX-11 + and VAX/VMS). A null typed in from a + terminal will be ignored. + + An ESCape that is executed as a TECO command + (as distinct from an immediate action command + or an ESCape that is part of the syntax of + some other TECO command) is ignored by TECO. + However, any pending numeric values are + discarded. This command is useful for + discarding the value returned from a command + (such as n%q or m,n:W) when you don't want + that value to affect execution of the + following command. + + ^[ Same as . Like any other TECO + command that is a control character, ESCape + may be entered in up-arrow mode. Sometimes + easier to type, ^[ is also useful on systems + whose line-printer spoolers do not visibly + print the ESCape character. + + Any pending numeric values are discarded. + This command is useful for discarding the + value returned from a command (such as n%q or + m,n:W) when you don't want that value to + affect execution of the following command. + + Standard TECO PAGE 120 + Programming Aids + + + Some older terminals may have no ESCape key, + but instead a key labelled ALTMODE or PREFIX + which sends TECO a character whose ASCII + value is 175 or 176. In such a case, TECO + will treat these characters as if they were + typed in as an ESCape (octal 33), provided + lower to upper case conversion is enabled. + + $ (dollar sign) Same as , but as a command only, not + as a string terminator. + [TECO-10 only] + + Note that and
are valid TECO commands and must + not be used as aids to formatting TECO programs. + + + 5.18.6 Memory Expansion + + The nEC command can be used to make TECO reclaim lost space after + it had expanded memory usage. nEC tells TECO to expand or + contract until it uses nK words of memory. If this is not + possible, then TECO's memory usage does not change. The 0EC + command tells TECO to shrink back to its original size (use the + least amount of memory possible). + [TECO-10 only] + + Standard TECO PAGE 121 + Programming Aids + + + 5.18.7 Case Control + + The and TECO commands are used to specify + automatic case control for alphabetic characters typed into + strings. + + + TABLE 5-18B: CASE CONTROL CHARACTERS + + CHARACTER MEANING + + ^V puts TECO into lower case conversion mode. In + this mode, all alphabetic characters in string + arguments are automatically changed to lower case. + This mode can be overridden by explicit case control + within the search string. This command makes all + strings behave as if they began with a ^V^V. + [TECO-10 only] + + ^W puts TECO into upper case conversion mode. In + this mode, all alphabetic characters in string + arguments are automatically changed to upper case. + This mode can be overriden by explicit case control + within the search string. This command makes all + strings behave as if they began with ^W^W. + [TECO-10 only] + + 0^V Returns TECO to its original mode. No special case + conversion occurs within strings except those case + conversions that are explicitly specified by ^V and ^W + string build constructs located within the string. + [TECO-10 only] + + 0^W Same as ^V. + [TECO-10 only] + + Standard TECO PAGE 122 + Manipulating Large Pages + + + 5.19 MANIPULATING LARGE PAGES + + TECO is designed to operate most efficiently when editing files + that contain no more than several thousand characters per page. + (TECO storage includes Q-register storage and buffer space. The + size of the text storage area is dynamic and depends on the + amount of available memory.) If any page of an input file is too + large to fit in the text area, the TECO input commands will + terminate reading that page into memory when the first line feed + is encountered after a point that the buffer is 3/4 full. (See + appendices for details.) You can make room by positioning the + pointer past a section of text at the beginning of the buffer and + moving that section out of the buffer with the commands: + + 0,.PW0,.K + + It is sometimes advantageous to restrict the amount of the file + that is present in the buffer. For example, each insert and + delete command must move the entire text that is beyond the point + of insertion or deletion. An operation that does many small + inserts or deletes may therefore run extremely slowly if the text + buffer is large. Such an operation can be sped up substantially + by reading the input file with n:A commands and explicitly + writing the processed text. + + Standard TECO PAGE 123 + Techniques + + + 5.20 TECHNIQUES AND EXAMPLES + + The most elementary TECO application, described in Chapter 1 of + this manual, is creating and editing ASCII files on-line. The + user enters short command strings, often consisting of a single + command, and proceeds from task to task until the file is + completely edited. + + Since every editing job is simply a long sequence of TECO + commands, you may accomplish an entire job with one long command + string made up of all the short command strings placed end to end + with the intervening double characters removed. A long + command string that performs a certain editing task can be + considered a TECO "editing program". Editing programs may be + written (using TECO) and stored in the same manner as any other + ASCII file. Whenever the program is needed, it may be read into + the buffer as text, stored in a Q-register, and executed by an Mq + command. + + For more complex editing jobs, you may want to write and maintain + a collection of specialized "editing subroutines." TECO + subroutines can perform such elementary functions as replacing + every occurrence of two or more consecutive spaces with a + tabulation character, for example, or ensuring that words are not + hyphenated across a page boundary. When an editing problem + arises, you can load the right combination of subroutines into + various Q-registers, augment them with additional commands if + necessary, and call them by a "mainline" command string. + + Editing subroutines are essentially macros; that is, sequences + of commands which perform commonly required editing functions. + The most powerful application of TECO is the creation and use of + a macro library. As you perform an editing job, look for + sequences of operations which might be required in future editing + assignments. Load all of the TECO commands required to perform + such an operation into a Q-register. When the job is finished, + write the contents of the Q-register onto an output file (via the + buffer) and save it in the macro library. The nMq and m,nMq + commands, which were designed to facilitate use of macros, permit + run-time numeric arguments to be passed to a macro. + + TECO macros can preserve the user's radix, flag values, etc. By + using the Q-register push-down list, the macro can save and then + restore values and/or text. For example: + + [0 [1 [2 ! Save contents of Q-registers 0, 1 and 2 ! + +0U0 ! Put any calling argument into Q-register 0 ! + 10U1 ! Put a 10 (if radix is decimal) or 8 (if radix is + octal) into Q-register 1 ! + ^D ! Ensure that the current radix is now decimal ! + EUU2 ! Save the case flagging flag ! + -1EU ! Ensure no case flagging ! + Q0"E 3U0 ' ! Default calling argument to 3 ! + + Standard TECO PAGE 124 + Techniques + + + ... + Q2EU ! Restore the case flagging flag ! + 10-Q1"N ^O ' ! Restore radix as octal if needed ! + ]2 ]1 ]0 ! Restore contents of Q-registers 2, 1, and 0 ! + + The EI command is particularly useful for executing macros from a + library, since with it they may be read without disturbing the + current input file. This makes it unnecessary to plan in advance + which macros might be needed; it also saves Q-register storage + space. You can retrieve two kinds of TECO command files with an + EI command: a file containing a TECO command that loads the + macro into a Q-register for later use, or a file containing just + the macro (which must be retrieved with EI each time it is used). + + The following examples are intended to illustrate some of the + techniques discussed above. It would not be practical to include + examples of the use of every TECO command, since most of the + commands apply to many diverse situations. Instead, you are + encouraged to experiment with the individual commands on scratch + files. + + + EXAMPLE 1: SPLITTING, MERGING, AND REARRANGING FILES + + Assume that there is a file named PROG.DAT on the system disk and + that this file contains data in the following form: + + AB CD EF GH IJ KL MN OP + + where each of the letters A, B, C etc., represents 20 lines of + text and represents a form feed character. The user intends + to rearrange the file so that it appears in the following format: + + AOB D MN EF ICJ KL P GH + + The following sequence of commands will achieve this + rearrangement. (Search command arguments are not listed + explicitly.) + + + Start TECO. + *2ED`` Allow all Y commands. + *EBPROG.DAT`Y`` Specify input file and get first page. + *NC`` Search for a character string in C, writing A + and B on the output file. + *J20X1`` Save all of C in Q-register 1. + *20K`` Delete C from the buffer. + *NG`` Search for a character string in G, writing + D, E, and F on the output file. + *HX2`` Save G and H in Q-register 2. + *Y`` Delete GH from the buffer and read IJ. + *20L`` Move the pointer to the beginning of J. + *G1`` Insert C, which was stored in Q-register 1. + + Standard TECO PAGE 125 + Techniques + + + *NM`` Search for a character string in M, writing + ICJ and KL on the output file. + *HX1`` Save MN in Q-register 1 (the previous + contents is overwritten). + *Y`` Delete MN and read OP + *J20X3`` Save all of O in Q-register 3. + *20K`` Delete O from the buffer. + *PWHK`` Write P onto the output file, appending a + form feed, and clear the text buffer. + *G2`` Bring GH into the buffer from Q-register 2. + *HPEF`` Write GH on the output file and close it. + *EBPROG.DAT`Y`` Open the partially revised file. + *20L`` Move the pointer to the beginning of B. + *G3`` Insert all of O from Q-register 3. + *ND`` Search for a character string in D writing + AOB on the output file. + *PWHK`` Write D on the output file and clear buffer. + *G1`` Bring all of MN from Q-register 1 into the + buffer. + *EX`` Write MN onto the output file, then close the + file and exit. + + At this point the file has been rearranged in the desired format. + Of course, this rearrangement could have been accomplished in + fewer steps if the commands listed above had been combined into + longer command strings. Note that the asterisks shown at the + left margin in this example are generated by TECO, and not typed + by the user. + + Assume, now, that the same input file, containing data in the + form: + + AB CD EF ... OP + + is to be split into two separate files, with the first file + containing AB CD and the second file containing KL M, + while the rest of the data is to be discarded. The following + commands could be used to achieve this rearrangement: + + + Start TECO. + *2ED`` Allow all Y commands. + *ERFILE`EWFILE1`` Open the input file and the first output + file. + *Y`` Read AB into the buffer. + *P`` Write AB onto the output file and read + CD into the buffer. + *HPEF`` Write CD onto the output file (without + appending a form feed), and close the first + output file. + *_K`` Search for a character string in K. After + this command has been executed, the buffer + will contain KL. No output is generated. + + Standard TECO PAGE 126 + Techniques + + + *EWFILE2`P`` Open the second output file and write KL onto + it. Read MN into the buffer. + *20L0,.P`` Move the pointer to the end of M, then write + M onto the output file. + *EF`` Close the output file. + *HKEX`` Clear the buffer and exit. + + As a final example of file manipulation techniques, assume that + there are two files. One file is MATH.ONE, which contains + information in the form: + + AB CD EF GH IJ KL + + and the other is MATH.TWO, which contains: + + MN OP QR + + If both of these files are stored on DK1, the following sequence + of commands may be used to merge the two files into a single + file, MATH.NEW, which contains all of MATH.TWO followed by the + latter half of file MATH.ONE in the following format: + + MN OP QR GH IJ KL + + + Start TECO. + *2ED`` Allow all Y commands. + *ERDK1:MATH.TWO`` Open the first input file. + *EWMATH.NEW`` Open the output file on the default device. + *Y`` Read MN into the text buffer. + *NR`` Search for a character string in R, writing + MN and OP onto the output file. + *PW`` Write QR onto the output file, appending a + form feed. + *ERDK1:MATH.ONE`` Open the second input file. + *HKY`` Read AB into the buffer. QR is over-written. + *_G`` Search for a character string in G, deleting + AB, CD, and EF, leaving GH in the buffer. + *NK`` Search for a character string in K, writing + GH and IJ on the output file, leaving KL in + the buffer. + *HPEFHKEX`` Write KL onto the output file (without + appending a form feed) and close the file, + then exit. + + Standard TECO PAGE 127 + Techniques + + + EXAMPLE 2: ALPHABETIZING BY INTERCHANGE SORT + + Assume that TECO is running and that the buffer contains many + short lines of text beginning with an alphabetic character at the + left margin (i.e., immediately following a line feed). The lines + might consist of names in a roster, for example, or entries in an + index. The following command string will rearrange the lines + into rough alphabetical order, grouping all lines which begin + with the character "A" at the beginning of the page, followed by + all lines with "B", and so on. Note that the algorithm could be + extended to place the entries in strict alphabetical order by + having it loop back to perform the same sorting operation on + successive characters in each line. + + + !START! J 0AUA !Load first character of first line + into Q-register A ! + !CONT! L 0AUB !Load first character of next line + into Q-register B ! + QA-QB"G XA K -L GA 1UZ ' !If A>B, switch the lines and set a + flag (Q-register Z) ! + QBUA !Load B into A ! + L Z-."G -L @O/CONT/ ' !Loop back if there is another line + in the buffer ! + QZ"G 0UZ @O/START/ ' !Repeat if a switch was made on the + last pass ! + + + The same algorithm can be coded in a more structured way as + follows: + + + 0UZ !clear repeat flag! + B, switch the lines and set a + flag ! + QBUA !Load B into A ! + L .-Z;> !Loop back if there is another line + in the buffer ! + QZ;> !Repeat if a switch was made on the + last pass ! + + This example is a bit shorter and does not use any GOTOs. It + will also run somewhat faster. + + Standard TECO PAGE 128 + Appendix A + + + APPENDIX A + + + Octal & Decimal ASCII Character Set + + (GL characters, on one page) + + + + + Char Oct Dec Char Oct Dec Char Oct Dec Char Oct Dec + + + NUL 000 000 SP 040 032 @ 100 064 ` 140 096 + ^A 001 001 ! 041 033 A 101 065 a 141 097 + ^B 002 002 " 042 034 B 102 066 b 142 098 + ^C 003 003 # 043 035 C 103 067 c 144 099 + ^D 004 004 $ 044 036 D 104 068 d 144 100 + ^E 005 005 % 045 037 E 105 069 e 145 101 + ^F 006 006 & 046 038 F 106 070 f 146 102 + ^G 007 007 ' 047 039 G 107 071 g 147 103 + + BS 010 008 ( 050 040 H 110 072 h 150 104 + TAB 011 009 ) 051 041 I 111 073 i 151 105 + LF 012 010 * 052 042 J 112 074 j 152 106 + VT 013 011 + 053 043 K 113 075 k 153 107 + FF 014 012 , 054 044 L 114 076 l 154 108 + CR 015 013 - 055 045 M 115 077 m 155 109 + ^N 016 014 . 056 046 N 116 078 n 156 110 + ^O 017 015 / 057 047 O 117 079 o 157 111 + + ^P 020 016 0 060 048 P 120 080 p 160 112 + ^Q 021 017 1 061 049 Q 121 081 q 161 113 + ^R 022 018 2 062 050 R 122 082 r 162 114 + ^S 023 019 3 063 051 S 123 083 s 163 115 + ^T 024 020 4 064 052 T 124 084 t 164 116 + ^U 025 021 5 065 053 U 125 085 u 165 117 + ^V 026 022 6 066 054 V 126 086 v 166 118 + ^W 027 023 7 067 055 W 127 087 w 167 119 + + ^X 030 024 8 070 056 X 130 088 x 170 120 + ^Y 031 025 9 071 057 Y 131 089 y 171 121 + ^Z 032 026 : 072 058 Z 132 090 z 172 122 + ESC 033 027 ; 073 059 [ 133 091 { 173 123 + FS 034 028 < 074 060 \ 134 092 | 174 124 + GS 035 029 = 075 061 ] 135 093 } 175 125 + RS 036 030 > 076 062 ^ 136 094 ~ 176 126 + US 037 031 ? 077 063 _ 137 095 DEL 177 127 + + + + + Continued... + + Standard TECO PAGE 129 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec Char Description + + [00] 000 0. + [01] 001 1. ^A Control-A + [02] 002 2. ^B Control-B + [03] 003 3. ^C Control-C + [04] 004 4. ^D Control-D + [05] 005 5. ^E Control-E + [06] 006 6. ^F Control-F + [07] 007 7. ^G Bell + + [08] 010 8. Backspace + [09] 011 9. Horizontal tab + [0A] 012 10. Line feed + [0B] 013 11. Vertical tab + [0C] 014 12. Form feed + [0D] 015 13. Carriage return + [0E] 016 14. Control-N + [0F] 017 15. Control-O + + [10] 020 16. ^P Control-P + [11] 021 17. Control-Q + [12] 022 18. ^R Control-R + [13] 023 19. Control-S + [14] 024 20. ^T Control-T + [15] 025 21. ^U Control-U + [16] 026 22. ^V Control-V + [17] 027 23. ^W Control-W + + [18] 030 24. ^X Control-X + [19] 031 25. ^Y Control-Y + [1A] 032 26. ^Z Control-Z + [1B] 033 27. ESCape, control-[ + [1C] 034 28. Control-\ + [1D] 035 29. Control-] + [1E] 036 30. Control-^ + [1F] 037 31. Control-_ + + + + + Continued... + + Standard TECO PAGE 130 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec Char Description + + [20] 040 32. Space + [21] 041 33. ! Explanation point + [22] 042 34. " Double quotation mark + [23] 043 35. # Number sign + [24] 044 36. $ Dollar sign + [25] 045 37. % Percent sign + [26] 046 38. & Ampersand + [27] 047 39. ' Single quote, apostrophe + + [28] 050 40. ( Left parenthesis + [29] 051 41. ) Right parenthesis + [2A] 052 42. * Asterisk + [2B] 053 43. + Plus + [2C] 054 44. , Comma + [2D] 055 45. - Hyphen, minus + [2E] 056 46. . Period, decimal point + [2F] 057 47. / Slash, slant, solidus + + [30] 060 48. 0 Digit 0 + [31] 061 49. 1 Digit 1 + [32] 062 50. 2 Digit 2 + [33] 063 51. 3 Digit 3 + [34] 064 52. 4 Digit 4 + [35] 065 53. 5 Digit 5 + [36] 066 54. 6 Digit 6 + [37] 067 55. 7 Digit 7 + + [38] 070 56. 8 Digit 8 + [39] 071 57. 9 Digit 9 + [3A] 072 58. : Colon + [3B] 073 59. ; Semicolon + [3C] 074 60. _< Left angle, less than + [3D] 075 61. = Equals + [3E] 076 62. _> Right angle, greater than + [3F] 077 63. ? Question mark + + + + + Continued... + + Standard TECO PAGE 131 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec Char Description + + [40] 100 64. @ Commercial at + [41] 101 65. A Upper case A + [42] 102 66. B Upper case B + [43] 103 67. C Upper case C + [44] 104 68. D Upper case D + [45] 105 69. E Upper case E + [46] 106 70. F Upper case F + [47] 107 71. G Upper case G + + [48] 110 72. H Upper case H + [49] 111 73. I Upper case I + [4A] 112 74. J Upper case J + [4B] 113 75. K Upper case K + [4C] 114 76. L Upper case L + [4D] 115 77. M Upper case M + [4E] 116 78. N Upper case N + [4F] 117 79. O Upper case O + + [50] 120 80. P Upper case P + [51] 121 81. Q Upper case Q + [52] 122 82. R Upper case R + [53] 123 83. S Upper case S + [54] 124 84. T Upper case T + [55] 125 85. U Upper case U + [56] 126 86. V Upper case V + [57] 127 87. W Upper case W + + [58] 130 88. X Upper case X + [59] 131 89. Y Upper case Y + [5A] 132 90. Z Upper case Z + [5B] 133 91. [ Opening bracket + [5C] 134 92. \ Backslash, reverse slant + [5D] 135 93. ] Closing bracket + [5E] 136 94. ^ Circumflex, caret, uparrow + [5F] 137 95. _ Underline, underscore + + + + + Continued... + + Standard TECO PAGE 132 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec Char Description + + [60] 140 96. ` Accent grave + [61] 141 97. a Lower case a + [62] 142 98. b Lower case b + [63] 143 99. c Lower case c + [64] 144 100. d Lower case d + [65] 145 101. e Lower case e + [66] 146 102. f Lower case f + [67] 147 103. g Lower case g + + [68] 150 104. h Lower case h + [69] 151 105. i Lower case i + [6A] 152 106. j Lower case j + [6B] 153 107. k Lower case k + [6C] 154 108. l Lower case l + [6D] 155 109. m Lower case m + [6E] 156 110. n Lower case n + [6F] 157 111. o Lower case o + + [70] 160 112. p Lower case p + [71] 161 113. q Lower case q + [72] 162 114. r Lower case r + [73] 163 115. s Lower case s + [74] 164 116. t Lower case t + [75] 165 117. u Lower case u + [76] 166 118. v Lower case v + [77] 167 119. w Lower case w + + [78] 170 120. x Lower case x + [79] 171 121. y Lower case y + [7A] 172 122. z Lower case z + [7B] 173 123. { Opening brace + [7C] 174 124. | Vertical line + [7D] 175 125. } Closing brace + [7E] 176 126. ~ Tilde, overline, high line + [7F] 177 127. Delete, rubout + + + + + Continued... + + Standard TECO PAGE 133 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec Char Description + + [80] 200 128. + [81] 201 129. + [82] 202 130. + [83] 203 131. + [84] 204 132. + [85] 205 133. + [86] 206 134. + [87] 207 135. + + [88] 210 136. + [89] 211 137. + [8A] 212 138. + [8B] 213 139. + [8C] 214 140. + [8D] 215 141. + [8E] 216 142. + [8F] 217 143. + + [90] 220 144. + [91] 221 145. + [92] 222 146. + [93] 223 147. + [94] 224 148. + [95] 225 149. + [96] 226 150. + [97] 227 151. + + [98] 230 152. + [99] 231 153. + [9A] 232 154. + [9B] 233 155. + [9C] 234 156. + [9D] 235 157. + [9E] 236 158. + [9F] 237 159. + + + + + Continued... + + Standard TECO PAGE 134 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec -- Description + + [A0] 240 160. - + [A1] 241 161. Inverted exclamation mark + [A2] 242 162. Cent sign + [A3] 243 163. Pound sterling sign + [A4] 244 164. reserved for future + [A5] 245 165. Yen + [A6] 246 166. reserved for future + [A7] 247 167. Section sign + + [A8] 250 168. General currency sign + [A9] 251 169. Copyright sign + [AA] 252 170. Feminine ordinal indicator + [AB] 253 171. Angle quotation mark left + [AC] 254 172. reserved for future + [AD] 255 173. reserved for future + [AE] 256 174. reserved for future + [AF] 257 175. reserved for future + + [B0] 260 176. Degree sign + [B1] 261 177. Plus/minus sign + [B2] 262 178. Superscript 2 + [B3] 263 179. Superscript 3 + [B4] 264 180. reserved for future + [B5] 265 181. Micro sign, Greek mu + [B6] 266 182. Paragraph sign, pilcrow + [B7] 267 183. Middle dot + + [B8] 270 184. reserved for future + [B9] 271 185. Superscript 1 + [BA] 272 186. Masculine ordinal indicator + [BB] 273 187. Angle quotation mark right + [BC] 274 188. Fraction one quarter + [BD] 275 189. Fraction one half + [BE] 276 190. reserved for future + [BF] 277 191. Inverted question mark + + + + + Continued... + + Standard TECO PAGE 135 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec -- Description + + [C0] 300 192. A with accent grave + [C1] 301 193. A with accent aigu (acute) + [C2] 302 194. A with circumflex + [C3] 303 195. A with tilde + [C4] 304 196. A with umlaut (diaeresis) + [C5] 305 197. A with ring + [C6] 306 198. AE ligature + [C7] 307 199. C with cedilla + + [C8] 310 200. E with accent grave + [C9] 311 201. E with accent aigu (acute) + [CA] 312 202. E with circumflex + [CB] 313 203. E with umlaut (diaeresis) + [CC] 314 204. I with accent grave + [CD] 315 205. I with accent aigu (acute) + [CE] 316 206. I with circumflex + [CF] 317 207. I with umlaut (diaeresis) + + [D0] 320 208. reserved for future + [D1] 321 209. N with tilde + [D2] 322 210. O with accent grave + [D3] 323 211. O with accent aigu (acute) + [D4] 324 212. O with circumflex + [D5] 325 213. O with tilde + [D6] 326 214. O with umlaut (diaeresis) + [D7] 327 215. OE ligature + + [D8] 330 216. O (letter) with slash + [D9] 331 217. U with accent grave + [DA] 332 218. U with accent aigu (acute) + [DB] 333 219. U with circumflex + [DC] 334 220. U with umlaut (diaeresis) + [DD] 335 221. Y with umlaut (diaeresis) + [DE] 336 222. reserved for future + [DD] 337 223. German sharp s + + + + + Continued... + + Standard TECO PAGE 136 + Appendix A + + + APPENDIX A, Continued + + + Octal, Hexadecimal, & Decimal ASCII Character Set (Complete) + + + + + Hex Oct Dec -- Description + + [E0] 340 224. a with accent grave + [E1] 341 225. a with accent aigu (acute) + [E2] 342 226. a with circumflex + [E3] 343 227. a with tilde + [E4] 344 228. a with umlaut (diaeresis) + [E5] 345 229. a with ring + [E6] 346 230. ae ligature + [E7] 347 231. c with cedilla + + [E8] 350 232. e with accent grave + [E9] 351 233. e with accent aigu (acute) + [EA] 352 234. e with circumflex + [EB] 353 235. e with umlaut (diaeresis) + [EC] 354 236. e with umlaut (diaeresis) + [ED] 355 237. i with accent aigu (acute) + [EE] 356 238. i with circumflex + [EF] 357 239. i with umlaut (diaeresis) + + [F0] 360 240. reserved for future + [F1] 361 241. n with tilde + [F2] 362 242. o with accent grave + [F3] 363 243. o with accent aigu (acute) + [F4] 364 244. o with circumflex + [F5] 365 245. o with tilde + [F6] 366 246. o with umlaut (diaeresis) + [F7] 367 247. oe ligature + + [F8] 370 248. o (letter) with slash + [F9] 371 249. u with accent grave + [FA] 372 250. u with accent aigu (acute) + [FB] 373 251. u with circumflex + [FC] 374 252. u with umlaut (diaeresis) + [FD] 375 253. y with umlaut (diaeresis) + [FE] 376 254. reserved for future + [FF] 377 255. - + + Standard TECO PAGE 137 + Appendix B + + + APPENDIX B + + + ERROR MESSAGES + + TECO error messages consist of a three letter message preceded by + a question mark (?) or preceeded by ?TEC. A short description of + the error optionally follows (dependent on the current value of + the EH flag). Typing ? (question mark) immediately after an + error message printout causes the command string to be printed up + to and including the character which causes the error message. + Typing *q (asterisk, Q-register name) immediately after an error + message printout saves the entire command string in the specified + Q-register. This is especially useful for recovering mistyped + insert commands. Both the ? and *q facilities may be used when + an error occurs. + + TECO-11 also produces two warning messages. These messages do + not abort the command and execution continues. + + + %Superseding existing file + Indicates that the file to be created as the result + of an EW command already exists. If the output + file is closed the old copy of the file will be + deleted. The EK command may be used to "take back" + the EW command. + + %Search fail in iter + Indicates that a search command has failed inside + iteration brackets. A ; (semi-colon) command + immediately following the search command can + typically be used to suppress this message. After + printing the message, the iteration is terminated, + i.e., TECO simulates a 0; command. + + + + + + These error messages are listed alphabetically by their + three-letter code. In general, these three-letter codes have the + same meaning on all implementations, although not all error + messages are produced by each implementation. The one-line error + message given here is a paraphrasing of the message given, which + may differ slightly from system to system. + + Standard TECO PAGE 138 + Appendix B + + + ?ARG Improper Arguments + Three arguments are given (a,b,c or H,c). + + ?BNI > not in iteration + There is a close angle bracket not matched by an + open angle bracket somewhere to its left. (Note: + an iteration in a macro stored in a Q-register must + be complete within the Q-register.) + + ?CCL CCL.SV not found or EG argument too long + The EGcommand` command on OS/8 was unable to locate + SYS:CCL.SV or the specified command has more than + 46 characters. + + ?CON Confused use of conditionals + Conditionals, parenthesized arguments, and + iterations must be properly nested. The user + probably used some construct like: N"E...(...' + where an iteration or parenthesized argument is + begun in a conditional but not terminated in the + same conditional. + + ?CPQ Can't pop into Q-register + A ] command has been executed and there is nothing + saved on the Q-register push down list. + + ?DEV Invalid device + A file specification string in an E command + contains an unknown device name. + + ?DTB Delete too big + An nD command has been attempted which is not + contained within the current page. + + ?ERR RSTS/E error message (RSTS/E only) + Some RSTS/E monitor call failed. The error message + text explains the error. + + ?FER File Error + The file specified in an ER, EW or EB command was + not found. + + ?FNF File not found "filespec" + The requested input file could not be located. If + this occurred within a macro the colon modified ER + or EB command may be necessary. + + ?FUL Output Command would have overflowed output device + The page of text currently in the text buffer will + not fit in the open output file. Until enough free + space can be obtained on the output device the file + may have to be split. An EF command to close the + current output file, followed by a new EW command + + Standard TECO PAGE 139 + Appendix B + + + to a temporary file may be used. The files should + be concatenated when the space problem is + alleviated. + + ?ICE Illegal ^E Command in Search Argument + A search argument contains a ^E command that is + either not defined or incomplete. The only valid + ^E commands in search arguments are: ^EA, ^ED, + ^EV, ^EW, ^EL, ^ES, ^E, and ^E[A,B,C,...]. + + ?IEC Illegal character "x" after E + An invalid E command has been executed. The E + character must be followed by an alphabetic to form + a legal E command (i.e., ER or EX). + + ?IFC Illegal character "x" after F + An invalid F command has been executed. + + ?IFN Illegal character "x" in filename + The filespec as an argument to one of the E + commands is unacceptable to the system. The file + specification must be appropriate to the system in + use. + + ?IIA Illegal insert arg + A command of the form "nItext`" was attempted. + Combining character (nI`) and text (Itext`) + insertions is illegal. + + ?ILL Illegal command "x" + An attempt has been made to execute an invalid TECO + command. + + ?ILN Illegal number + An 8 or 9 has been entered when the radix of TECO + is set to octal. + + ?INP Input error + The system has reported an error attempting to read + the current input file. The text buffer may be + corrupt. This operation may be retried, but if the + error persists, you may have to return to a backup + file. + + ?IPA Negative or 0 argument to P + The argument preceding a P or PW command is + negative or 0. + + ?IQC Illegal " character + One of the valid " commands did not follow the ". + Refer to Section 5.14 (conditional execution + commands) for the legal set of commands. + + Standard TECO PAGE 140 + Appendix B + + + ?IQN Illegal Q-register name "x" + An illegal Q-register name was specified in one of + the Q-register commands. + + ?IRA Illegal radix argument to ^R + The argument to a ^R radix command must be 8, 10, + or 16. + + ?ISA Illegal search arg + The argument preceding a search command is 0. This + argument must not be 0. + + ?ISS Illegal search string + One of the search string special characters (^Q, + ^V, ^W, etc.) would have modified the search string + delimiter (usually ESCAPE). + + ?IUC Illegal character "x" following ^ + The character following an ^ must have ASCII value + between 100 and 137 inclusive or between 141 and + 172 inclusive. + + ?MAP Missing ' + Every conditional (opened with the " command) must + be closed with the ' command. + + ?MEM Memory overflow + Insufficient memory available to complete the + current command. Make sure the Q-register area + does not contain much unnecessary text. Breaking + up the text area into multiple pages might be + useful. (See section 5.19.) + + ?MLA Missing Left Angle Bracket + There is a right angle bracket that has no matching + left angle bracket. An iteration must be complete + within the macro or command. + + ?MLP Missing ( + There is a right parenthesis that is not matched by + a corresponding left parenthesis. + + ?MRA Missing Right Angle Bracket + There is a left angle bracket that has no matching + right angle bracket. An iteration must be complete + within the macro or command. + + ?MRP Missing ) + There is a right parenthesis that is not matched by + a corresponding left parenthesis. + + Standard TECO PAGE 141 + Appendix B + + + ?MSC Missing Start of Conditional + A ' command (end of conditional) was encountered. + Every ' command must be matched by a preceding " + (start of conditional) command. + + ?NAB No arg before ^_ + The ^_ command must be preceded by either a + specific numeric argument or a command that returns + a numeric value. + + ?NAC No arg before , + A command has been executed in which a , is not + preceded by a numeric argument. + + ?NAE No arg before = + The =, ==, or === command must be preceded by + either a specific numeric argument or a command + that returns a numeric value. + + ?NAP No arg before ) + A ) parenthesis has been encountered and is not + properly preceded by a specific numeric argument or + a command that returns a numeric value. + + ?NAQ No arg before " + The " commands must be preceded by a single numeric + argument on which the decision to execute the + following commands or skip to the matching ' is + based. + + ?NAS No arg before ; + The ; command must be preceded by a single numeric + argument on which the decision to execute the + following commands or skip to the matching > is + based. + + ?NAU No arg before U + The U command must be preceded by either a specific + numeric argument or a command that returns a + numeric value. + + ?NCA Negative argument to , + A comma was preceded by a negative number. + + ?NYA Numeric argument with Y + The Y command must not be preceded by either a + numeric argument or a command that returns a + numeric value. + + ?NYI Not yet implemented + A command was issued which tries to invoke a + feature not available on this implementation of + TECO. + + Standard TECO PAGE 142 + Appendix B + + + ?NFI No file for input + Before issuing an input command, such as Y, it is + necessary to open an input file by use of a command + such as ER or EB. + + ?NFO No file for output + Before issuing an output command such as N search + or P it is necessary to open an output file by use + of a command such as EW or EB. + + ?NPA Negative or 0 argument to P + A P command was preceded by a negative or 0 + argument. + + ?NRO No room for output + The output device is too full to accept the + requested output file. + + ?NYI Not Yet Implemented + A command was issued that is not yet implemented in + this version of TECO. + + ?OFO Output file already open + A command has been executed which tried to create + an output file, but an output file currently is + open. It is typically appropriate to use the EC or + EK command as the situation calls for to close the + output file. + + ?OUT Output error + The system has reported an error attempting to do + output to the output file. Make sure that output + device did not become write locked. Use of the EF + command (or EK if necessary) and another EW can be + considered until the condition is fixed. + + ?PES Attempt to Pop Empty Stack + A ] command (pop off q-register stack into a + q-register) was encountered when there was nothing + on the q-register stack. + + ?PDO Push-down list overflow + The command string has become too complex. + Simplify it. + + ?POP Attempt to move Pointer Off Page with "x" + A J, C or R command has been executed which + attempted to move the pointer off the page. The + result of executing one of these commands must + leave the pointer between 0 and Z, inclusive. The + characters referenced by a D or m,nX command must + also be within the buffer boundary. + + Standard TECO PAGE 143 + Appendix B + + + ?SNI ; not in iteration + A ; command has been executed outside of an open + iteration bracket. This command may only be + executed within iteration brackets. + + ?SRH Search failure "text" + A search command not preceded by a colon modifier + and not within an iteration has failed to find the + specified "text". After an S search fails the + pointer is left at the beginning of the buffer. + After an N or _ search fails the last page of the + input file has been input and, in the case of N, + output, and the buffer is cleared. In the case of + an N search it is usually necessary to close the + output file and reopen it for continued editing. + + ?STL String too long + A search or file name string is too long. This is + most likely the result of a missing after + the string. + + ?TAG Missing Tag !tag! + The tag !tag! specified by an O command cannot be + found. This tag must be in the same macro level as + the O command referencing it. + + ?UTC Unterminated command "x" + This is a general error which is usually caused by + an unterminated insert, search, or filespec + argument, an unterminated ^A message, an + unterminated tag or comment (i.e., unterminated ! + construct), or a missing ' character which closes a + conditional execution command. + + ?UTM Unterminated macro + This error is the same as the ?UTC error except + that the unterminated command was executing from a + Q-register (i.e., it was a macro). (Note: An + entire command sequence stored in a Q-register must + be complete within the Q-register.) + + ?XAB Execution aborted + Execution of TECO was aborted. This is usually due + to the typing of . + + ?WLO System Device Write-Locked + TECO-8 needs to write on the system device when it + is running in less than 16K (less than 20K if VT52 + is present) so that it can later swap in overlays. + + ?YCA Y command aborted + An attempt has been made to execute an Y or _ + search command with an output file open, that would + + Standard TECO PAGE 144 + Appendix B + + + cause text in the text buffer to be erased without + outputting it to the output file. The ED command + (section 5.16) controls this check. + + ?nnn I/O Error or Directive Error (RSX-11 only) + All errors from the executive and file system are + reported in this format, where nnn is the decimal + I/O or directive error status. The accompanying + message is the corresponding message from the + QIOSYM message file. A complete list of I/O and + directive errors appears in appendices to the + various Executive reference manuals and in the + IAS/RSX-11 I/O Operations Reference Manual. + + Standard TECO PAGE 145 + Appendix C + + + APPENDIX C + + + Incompatible, Obsolete, and System-Specific Commands + + This appendix describes commands that are peculiar to specific + operating systems. These commands fall into many categories. + Some are obsolete, and are kept around only as a convenience to + the user. Others are so system specific or so obscure that it + was felt best not to include them in the main body of the manual. + Some are incompatible across operating systems. Some are new + commands that have not become firmly established and may change + in the future. In general, use these commands at your own risk + and with the understanding that in future releases of TECO, these + commands may change or go away completely. Implementors of TECO + on other operating systems should contact the TECO SIG before + implementing any of these features. + + + C.1 SPECIFIC FEATURES OF TECO-11 + + + C.1.1 TECO Commands + + Command Description + + m,nStext` Performs the same function as the nS command, but + m serves a bound limit for the search. If the + search string can be found without moving the + pointer more than ABS(m)-1 places, the search + succeeds and the pointer is repositioned to + immediately after the last character of the + string. Otherwise, the pointer is left unchanged. + The ^Q operator, described below, is useful in + conjunction with this command. + + Note that m,Stext` is identical to m,1Stext` and + m,-Stext` is identical to m,-1Stext`. + + m,-nStext` Performs the same function as the m,nS command, + but searches in the reverse direction. + + 0,nStext` Performs the same function as the nS command, + except that the pointer position will remain + unchanged on search string failure. (Essentially + an unbounded search with no pointer movement on + failure.) + + G* Get most recent filespec string. The asterisk + represents TECO's filespec string area, which + contains the fully expanded filespec of the last E + command (see appendices). Copy the contents of + the filespec string area into the buffer at the + + Standard TECO PAGE 146 + Appendix C + + + current position of the buffer pointer, leaving + the pointer positioned after the last character + copied. + + :G* Print the contents of the filespec buffer on the + terminal. + + G_ Get most recent search string. The underscore + (backarrow) represents TECO's search string area. + Copy the contents of the search string area into + the buffer at the current position of the buffer + pointer, leaving the pointer positioned after the + last character copied. + + :G_ Print the contents of the search string buffer on + the terminal. + + n^Q n^QC is identical to nL. The n^Q command returns + the number of characters between the buffer + pointer and the nth line separator (both positive + and negative). This command converts line + oriented command argument values into character + oriented argument values. Used after an + expression. + + m,-256+n:W Inserts characters at "dot" until... Characters + are read (echo off) from the terminal and inserted + at "dot" until and according to the microcoded + bits in n. The terminating character is not + inserted. + + 128 => Return immediately if no typed characters + 64 => Terminate on any character + 32 => Don't keep screen updated (i.e., no -1W) + 8 => Treat m as terminating character(s) + 4 => Convert any alphabetic inserts to upper + case + 2 => Terminate on + 1 => Screen is initially O.K. + + Control characters (octal 0 through 37 and 177 + except ) are always terminating characters. + The returned value has the terminating character + code in low byte (octal 0 through 177 or 377 for + returned immediately). The sign bit is set if one + or more inserts were done. The return value may + be a character code that normally would have been + inserted, but could not be for some reason (e.g., + convert alphabetic inserts to upper case + requested, but not supported in this + implementation). + + The m of m,-256+n:W is always optional. If bit + + Standard TECO PAGE 147 + Appendix C + + + value 8 of n is set, m contains up to two + additional termination character codes, one in the + low 8 bits (low byte) and another in the high 8 + bits (high byte). If only one extra termination + character is desired, it is placed simply placed + in m thus setting the high 8 bits to zero (which + is already a termination character). If bit value + 8 of n is not set, passing the m argument is + undefined... + + + C.1.2 String Build Constructs + + Construct Description + + Q* Q* indicates that the string stored in the + filespec buffer is to be used in the position + occupied by the ^EQ* in the search string. + + Q_ Q_ indicates that the string stored in the + search string buffer is to be used in the position + occupied by the ^EQ_ in the search string. + + Standard TECO PAGE 148 + Appendix C + + + C.2 SPECIFIC FEATURES OF RT-11 + + [For "RT-11 Operating Characteristics", refer to Appendix D.] + + + C.3 SPECIFIC FEATURES OF RSTS/E + + [For "RSTS/E Operating Characteristics", refer to Appendix E.] + + TECO COMMANDS + + Command Description + + :EGRTS` Switch to private default run-time-system. + + :EGRTS foo` Switch to RTS "foo". + + :EGFSS string` File string scan "string". + + :EGCCL cmd` Try "cmd" as a CCL command. + + :EGRUN file` Try to run "file". + + :EGRUN file=xx` + Try to run "file" with "xx" placed in core common. + + :EGEMT` Issue a monitor directive. The FIRQB is loaded + from Q-registers A through P and the XRB is loaded + from Q-registers Q through W. The low byte of the + value in Q-register A is the monitor EMT code to + issue. If the high byte of the value in + Q-register A is >0 then the text part of + Q-register A is put into the XRB for a 'write' + (XRLEN= size of A, XRBC=size of A, XRLOC->A); if + Q-register A high byte is <0 then the text part of + Q-register A is put into the XRB for a 'read' + (XRLEN=size of A, XRBC=0, XRLOC->A). + Returned value is -1 for success, 0 for + unrecognized command, or >0 for the RSTS/E error + code. The FIRQB is placed in the numeric part of + Q-regs A, B, C, D, E, F, G, H, I, J, K, L, M, N, + O, P. The XRB is placed in the numeric part of + Q-regs Q, R, S, T, U, V, W. + + See also section 5.1.2, File Specification Switches. + + Standard TECO PAGE 149 + Appendix C + + + C.4 SPECIFIC FEATURES OF RSX-11/M, RSX-11/D, and IAS + + [For "RSX-11 Operating Characteristics", refer to Appendix F.] + + Command Description + + + Returns control to the operating system + immediately. Equivalent to typing + . + + See also section 5.1.2, File Specification Switches. + + + C.5 SPECIFIC FEATURES OF VAX/VMS + + [For "VAX/VMS Operating Characteristics", refer to Appendix G.] + + Command Description + + + Returns control to VAX/VMS immediately. + Equivalent to typing . + + EG` Exit with special status + TECO's normal exit status code (as reflected by + the DCL symbols $STATUS and $SEVERITY) is 1 + (success). If the exit was due to an EG` command, + the exit status code is 9 (also success). + + :EGSYM symbol_name symbol_value` + Defines the DCL local symbol "symbol_name" with a + value string of "symbol_value". Useful for + creating symbols that will be used by a command + procedure upon TECO's exit. + + See also section 5.1.2, File Specification Switches. + + + C.6 SPECIFIC FEATURES OF OS/8 + + [For "OS/8 Operating Characteristics", refer to Appendix H.] + + Command Description + + If used as the first keystroke after TECO's + prompt, this command is the same as *Z, that is, + it saves the last command string in Q-register Z. + This command echoes as *Z and does not have to be + followed by a . + + See also section 5.1.2, File Specification Switches. + + Standard TECO PAGE 150 + Appendix C + + + C.7 SPECIFIC FEATURES OF TOPS-10 + + [For "TOPS-10 Operating Characteristics", refer to Appendix I.] + + Command Description + + nEM Positions a magtape. You must open the magtape + for input with an appropriate ER command before it + can be positioned. Exact positioning depends on + the value of n, as described below. You must + reopen the magtape for output before you can + output to it. + [TECO-10 only] + + Value Action + + 1EM Rewind the currently-selected input + magtape to load point. EM is identical + to 1EM. + + 3EM Write an end-of-file record. + + 6EM Skip ahead one record. + + 7EM Back up one record. + + 8EM Skip ahead to logical end of tape + (defined by two successive end-of-file + marks). Leave the magtape positioned + between the two end-of-file marks so + that successive output correctly + overwrites the second EOF. + + 9EM Rewind and unload. + + 11EM Write 3 inches of blank tape. + + 14EM Advance tape one file. This leaves the + tape positioned so that the next item + read will be the first record of the + next file (or the second end-of-file + mark at the logical end-of-tape). + + 15EM Backspace tape one file. This leaves + the tape positioned so that the next + item read will be the end-of-file mark + preceding the file backspaced over + (unless the file is the first file on + the tape). + + n^Q n^QC is identical to nL. This command returns the + number of characters between the buffer pointer + and the nth line separator (both positive and + + Standard TECO PAGE 151 + Appendix C + + + negative). This command converts line oriented + command argument values into character oriented + argument values. Used after an expression. + + F0 Pointer position of start of window. Same as 6:W. + + FZ Pointer position of end of window. + + FH Same as F0,FZ. + + FX Software maintained horizontal coordinate of + location of cursor on screen (0-origin). Updated + by TECO on terminal output. If TECO cannot + determine the updated location of the cursor, this + value is set to -1. + + nFX Set value of FX register to n. + + FY Software maintained vertical coordinate of + location of cursor on screen (0-origin). Updated + by TECO on terminal output. If TECO cannot + determine the updated location of the cursor, this + value is set to -1. + + nFY Set value of FY register to n. + + FP Equivalent to FY,FX. + + m,nFP Equivalent to mFYnFX. + + m,nFF Updates FY and FX registers as if the m,nT command + were executed. + + nFF Assumes that the scope cursor is pointing at the + character that is just to the right of the text + buffer pointer (the current character). Then this + command advances n screen lines and goes to the + end of that line and returns that pointer + position. + + nFQq Compares characters beginning at dot with + characters beginning at the nth character in + Q-register q (0-origin). When a match fails or + the match ends, this command moves the pointer to + after the last character that matched and returns + the index into the Q-register. + + E=filespec` Renames the input file. + + E&filespec` Run the specified program when TECO exits. Can + take a numeric argument which is the run-offset. + 0 is the default. + + Standard TECO PAGE 152 + Appendix C + + + m,nE* Does an arbitrary TRMOP to your terminal. + [Not available on TOPS-20.] + + ::Gq Same as :Gq but types literally. + + ::ER Same as ER but no defaults are used. + + ^Z Closes output file and exits from TECO. + + ^P Returns current page number. + + n^P Executes P commands until page n has been reached. + + n^Y Executes Y commands until page n has been reached. + + n,m= Same as m=n^T. + + m,n:^T Does an arbitrary TTCALL. + + +See also section 5.1.2, File Specification Switches. + + Standard TECO PAGE 153 + Appendix D + + + APPENDIX D + + + RT-11 OPERATING CHARACERISTICS + + + D.1 STARTUP + + TECO is started with the + + .R TECO + + command. TECO is now immediately ready to accept commands. The + text buffer and Q-register areas are empty. + + The EDIT command + + .EDIT/TECO filespec + + is used to edit an already existing file. It is equivalent to + + .R TECO + *EBfilespec`Y`` + + For those RT-11 users that will use TECO as the primary editor, a + monitor SET command is provided: + + .SET EDITOR TECO + + Once this command is issued, the /TECO option on the EDIT command + is no longer necessary since the default editor is now TECO. + Since this SET command only has affect between system bootstraps, + it is recommended that the command be placed in the appropriate + startup file (e.g., STARTS.COM). + + Now, assuming the SET command has been issued, the command + + .EDIT filespec + + can be used to edit an already existing file. + + The standard RT-11 EDIT command options are all available with + TECO. + + .EDIT/CREATE filespec + .EDIT/INSPECT filespec + .EDIT/OUTPUT:filespec filespec + + Another option, /EXECUTE, is also available: + + .EDIT/EXECUTE[:string] filespec + + The /EXECUTE option causes TECO to process the filespec (assumed + + Standard TECO PAGE 154 + Appendix D + + + .TEC filetype) as a set of TECO commands. If "string" is used, + the string is placed into TECO's text buffer. If "string" + contains only alphanumeric characters, it does not have to be + enclosed in quotes. If it is to contain blanks, it must be + quoted with single quotes. The equivalent TECO commands would be + + .R TECO + *ERfilespec`YHXZHKIstring`MZ`` + + Note the input file remains open and can provide more input to + the macro. + + + D.2 FILE SPECIFICATION + + The file access commands ER, EB, EI, and EW accept a file + specification in the standard RT-11 format: + + dev:filename.type + + in which dev: is a physical device name or a user assigned + logical name; if dev: is not specified, the default DK: is + assumed. The filename field must be specified in the commands + ER, EB, EI, and EW and be a legal RT-11 filename. The type field + is a file extension and must be explicitly given if used (there + is no default). The EB and EW commands also accept the extended + notation for an output file size + + dev:filename.type[n] + + The optional [n] specifies the output file size where n is the + number of blocks to be allocated. + + + D.3 BACKUP FILES + + The EB command maintains one level of file backup on RT-11. The + pre-edited input file name is changed to + + filename.BAK + + before the new output file is closed with the original name. + Only normal file closing commands (EC, EF, EG, and EX) cause this + renaming to happen. If TECO is aborted or the output file is + purged by the EK command, the input filename remains unchanged. + Note only one .BAK file for a given name is kept; earlier .BAK + backup files are deleted each time a new backup file is created. + + A good policy to follow when editing is to close the edited file + frequently enough so that an unexpected incident would not cause + a substantial loss of work. Files should be backed up regularly. + TECO has the power to let an unsuspecting user alter a good file + into a completely useless state. The SRCCOM program can be used + + Standard TECO PAGE 155 + Appendix D + + + to verify an editing session. + + + D.4 EXIT AND GO + + If TECO is exited via the EGstring` command, the string is passed + to the system as the next command to execute. This string may be + any valid command or an indirect command file specification. + + + D.5 REENTER AND CLOSE + + The RT-11 REENTER command may always be used to continue TECO. + Its primary differences from running TECO is that when REENTER is + used, the text buffer and Q-register areas are unmodified, as + opposed to when TECO is run the text buffer and Q-register areas + are cleared. The input and output file are always lost upon + reentering TECO. If an output file was open before reentering + TECO, the file will have to be recreated with the appropriate + E-command. (Note that the monitor commands GT ON, GT OFF, LOAD, + and UNLOAD disallow a REENTER.) + + The output file is not closed if TECO is aborted. The RT-11 + CLOSE command can be used to make the output file permanent, but + be aware that the output file will not be complete because of + internal buffers that TECO keeps. TECO may be reentered after a + CLOSE command. + + + D.6 FILE RECOVERY + + TECO can be a useful tool in recovering ASCII files lost on a + block replaceable device. TECO allows block replaceable devices + to be opened in a non-file structured mode. This gives the user + the capability to open a disk and access ASCII data anywhere on + it, independent of file boundaries. The command + + ERdev:` + + is used to open the device at which point _ (underscore or + backarrow) searches may be used to locate specific ASCII data and + transfer it to new output files. Note that files tend to get + reproduced, in whole or part, many places on a block replaceable + device; be sure to verify that any given text is indeed complete + and the correct version. + + + D.7 SYSTEM CRASH RECOVERY + + TECO and RT-11 are highly reliable, but if during an important + edit session a random system failure should occur, the following + procedure may help save some or all of the editing. + + Standard TECO PAGE 156 + Appendix D + + + 1. Bootstrap the system + + 2. Immediately perform a SAVE command to save as much of + memory as possible into a file on SY:. The address + range form of the SAVE command must be used. The SAVE + command will not allow any part of the monitor to be + saved, e.g., if you have a 28K system and are running SJ + you cannot save 28K but only 26.3K. + + 3. Perform standard startup procedures, e.g., DATE. + + 4. Use TECO on the SAVEd file to try and recover useful + parts of the edit. + + + D.8 VT11 GRAPHICS SUPPORT + + If the monitor supports the VT11 graphics processor (GT ON and + GT OFF work) TECO will automatically start up in display mode, + adjusting to both the size of the display screen and to the + presence or absence of the scroller. + + If the display fails to start with a working VT11, TECO has + decided that there is not enough free memory and will not + allocate the display file buffer or start the display. + + See Section 5.17 for a description of the available commands to + interact with the display. + + Various aspects of the display screen become immediately obvious + upon seeing them; the text pointer, its position and shape and + its position between lines; wrap around of more than 72 + characters per line; the scroller interaction and so on. + Experiment with a scratch file for more familiarity. + + Standard TECO PAGE 157 + Appendix E + + + APPENDIX E + + + RSTS/E OPERATING CHARACERISTICS + + + E.1 STARTUP + + RSTS supports all of the standard TECO invocation commands, + namely + + TECO + TECO filespec + TECO filespec=filespec + MAKE filespec + MUNG filespec + MUNG filespec,text + + The CCL command switches /DETACH and /SIZE:n (or /SIZE:+n) can be + used with TECO. If /DETACH is used and the user's detached-job + quota has not yet been reached, TECO will detach the job before + any further processing. If /SIZE:n is used, TECO will pre-expand + the text and Q-register storage area to nK. If /SIZE:+n is used, + TECO will set the text storage and Q-register storage area to + n+4K initially (TECO's default startup size is 4K). + + + E.2 FILE SPECIFICATION + + The file access commands ER, EB, EW, and EI accept a file + specification in the standard RSTS/E format: + + dev:[p,pn]filename.ext + + in which dev: is a physical device name or a logical device + name; if dev: is not specified, the public structure is + assumed. If [p,pn] is not specified, the user's current logged + in account is assumed. The filename field must be specified + whenever the device name references a file structured device. + The .ext field is a file extension and must be explicitly given + if used. There is no default extension except for EI commands + which default the .ext field to .TEC. + + The file specification switches /n, /B+, /, and /B2 may be + applied to the ER, EW, and EB commands. These switches invoke + special handling of program lines containing or & + continuation characters. See Appendix J for more information. + + The file specification switch /B causes TECO to handle the file + as a stream of 8-bit binary characters; normal ASCII format + processing (such as removal of null characters) is not done. + + The file specification switches /RONLY, /MODE:n, and + + Standard TECO PAGE 158 + Appendix E + + + /CLUSTERSIZE:n can be included in a file specification. TECO + automatically opens any disk input file in /RONLY mode. The file + size switches /FILESIZE:n and /SIZE:n might leave an output file + larger than the amount of data output by TECO. These file size + switches are therefore illegal and produce an error if included + in a file specification. + + The EB and EW commands also accept the extended notation for an + output file protection code + + dev:[p,pn]filename.ext + + The optional specifies the output file protection code. + + + E.3 BACKUP FILES + + The EB command maintains one level of file backup on RSTS/E. The + pre-edited input file name is changed to + + filename.BAK + + before the new output file is closed with the original name. + Only normal file closing commands (EC, EF, EG, and EX) cause this + renaming to happen. If TECO is aborted or the output file is + purged by the EK command, the input filename remains unchanged. + Note only one .BAK file for a given name is kept; earlier .BAK + backup files are deleted each time a new backup file is created. + + A good policy to follow when editing is to close the edited file + frequently enough so that an unexpected incident would not cause + a substantial loss of work. Files should be backed up regularly. + TECO has the power to let an unsuspecting user alter a good file + into a completely useless state. The FILCOM program can be used + to verify an editing session. + + + E.4 EXIT AND GO + + If TECO is exited via the EGstring` command, the "string" is + executed as a RSTS/E CCL command after the input and output + file(s) are closed. + + + E.5 ET FLAG HANDLING + + Bit 6 (detach) is handled specially by TECO. Every time the ET + flag is read (used as a numeric value), TECO ensures that Bit 6 + is on if the job is attached or off if the job is detached. This + allows a TECO macro to check for "detachedness". If an attempt + is made to set Bit 6 and the user's detached-job quota has been + reached, the request is ignored and Bit 6 will read back as a 0 + (assuming the job is attached). If Bit 6 is set and the user's + + Standard TECO PAGE 159 + Appendix E + + + detached-job quota has not yet been reached, the job will become + detached. Further reading of Bit 6 will return a 1, indicating + the detached condition. + + Standard TECO PAGE 160 + Appendix F + + + APPENDIX F + + + RSX-11 OPERATING CHARACERISTICS + + + F.1 STARTUP + + RSX-11 systems support all of the standard TECO invocation + commands, namely + + TECO + TECO filespec + TECO filespec=filespec + MAKE filespec + MUNG filespec + MUNG filespec,text + + If any of these commands are not recognized by the system, check + with your system manager to see that TECO is properly installed. + + TECO macros may also be invoked with the command + + TECO @filespec + + It is exactly equivalent to + + MUNG filespec + + In systems supporting dynamic task expansion, TECO will expand + its buffer space as necessary. Also, TECO'S buffer space may be + explicitly allocated in the startup command + + RUN $TEC/INC=n + + + F.2 INITIALIZATION + + TECO searches for the TECO.INI startup file in the current + default device and directory. TECO's memory, in which a plain + TECO command edits the file last edited with a TECO filespec or a + MAKE filespec command, is implemented with a file named + TECF00.TMP, also stored in the current default device and + directory. + + The initial value of the ED flag is always 1. + + When TECO is initially invoked it will automatically set the ET + and EU flags according to the user's terminal characteristics. + If the terminal supports CRT style rubouts, then bit 1 of the ET + flag is set to do the same in TECO. If the terminal supports + lower case type in, then bit 2 of the ET flag is set and the EU + flag is set to -1 to turn off case flagging. If the terminal is + + Standard TECO PAGE 161 + Appendix F + + + a CRT type terminal and the version of TECO includes the screen + support package, then bit 9 of the ET flag is set. While the + command line is being processed, bit 7 of the ET flag is also set + to cause TECO to exit should any errors occurr. ET bit 7 is + cleared every time TECO reaches prompt (*) level. + + + F.3 FILE SPECIFICATION + + The file access commands ER, EB, EW, and EI accept a file + specification in the standard RSX-11 format: + + dev:[p,pn]filename.typ;version + + in which dev: is a physical device name or a logical device + name; if dev: is not specified, SY: is assumed. If [p,pn] is + not specified, the user's current default directory is assumed. + The filename field must be specified whenever the device name + references a file structured device. The typ field is a file + type and must be explicitly given if used. There is no default + type except for EI commands which default the .typ field to .TEC. + + The /B2 file specification switch may be applied to the ER, EW, + and EB commands and invokes special handling of program lines + containing & continuation characters. See Appendix J for more + information. + + The switch /RW may be applied to any file specification in an ER, + EW, and EI command. If the file specification references a + magtape, the tape is rewound before the file is opened. Note + that for output files, this has the effect of zeroing the tape. + The /RW switch is ignored for all other device types. + + The presence of version numbers in Files-11 causes file + processing to behave slightly differently under RSX-11 than under + other operating systems. For example, no .BAK files are used; + each execution of an EB command simply produces a new version of + the file. Thus a user may retain any level of backup he feels to + be comfortable. It also means that one must occasionally delete + obsolete files to avoid cluttering the disk. Thus the command + + EBname.typ;version` + + is equivalent to the commands + + ERname.typ;version`EWname.typ;0` + + The EW command also creates a new version (one higher than the + current highest) if no version number is given. If an explicit + version number is given, then that number is used, and if another + file of the same name, type, and version previously existed, it + is superseded without warning. (See use of the EP and EK + commands below.) + + Standard TECO PAGE 162 + Appendix F + + + In reading files, version numbers behave the same as in other + RSX-11 utilities: the default is the highest version. This + leads to a problem in re-opening the input file while a file is + being edited with EB. Since the output file is already created + and in the directory, the input file is no longer the highest + version. One may deduce the version number of the input file by + doing a :G* (typing the file string of the output file) and + subtracting one from that version number. + + In symmetry with the EB command, the EK command functions by + simply deleting the current output file. Note, however, that a + supersede (EW of same name, type, and version) is not undone - + the file is already deleted! + + The EP and EA commands, while simulating two channels each with + an open file for each of input and output, in fact only keep one + file open for each to conserve buffer space. This means that + they are only useful for disk files. Also, it means that if you + open a file and then supersede it, you should not switch the + input channel away from it with an EP or ER` command, since it + will not be possible to open the file again. + + + F.4 WILD CARD LOOKUP + + The EN command will process wild card lookups on RSX-11. To + preset the wild card lookup file specification, use the standard + RSX-11 format + + dev:[p,pn]filename.typ;version + + The device name must reference a file structured disk device or + magtape. All other fields of the file specification may be fully + wild (*), including either or both halves of the directory. The + version number may be explicit, wild, or default. As with the + other file specification commands, there is no default file type. + + + F.5 EXITING FROM TECO + + The normal method of exiting from TECO is with the EX command. + This copies the remaining input file to the output file, closes + all files and exits. + + The (or Caret-C) command is the "give up and get out" + command. Executed from main command level, it will cause TECO to + exit regardless of the state of the buffer. If there is an open + output file, it is deleted. The command is roughly + equivalent to EKHKEX. + + Standard TECO PAGE 163 + Appendix F + + + F.6 + + The action taken when the user types depends on what + TECO is doing. + + If TECO is executing commands, or is awaiting type-in for the ^T + command, the ?XAB error occurs. + + If TECO is at command level, typing cancels the command + string currently being typed and returns TECO to its prompt. Two + consecutive characters will cause an instant HKEKEX + exit. + + Sometimes it is desireable for a TECO macro to detect when a + was typed. By detecting the , the macro can + exit cleanly back to command level (pop saved Q-registers, + restore any flag values, etc.). To do this, the macro sets Bit + 15 (Octal 100000, Decimal -32768) of the ET flag. When a + is typed, TECO will automatically turn off Bit 15, but + will continue execution of the macro. The macro periodically + checks Bit 15 and exits cleanly if it ever goes off. For + example: + + [0 [1 -32768#ETET < ... ET; > 32767&ETET ]1 ]0 + + Setting the intercept bit in the ET flag must be done + with some care; if the bit is set inside a command loop which + does not check it, it will be impossible for the user to abort + the loop. The only remedy for this situation is to abort TECO + from another terminal. + + + F.7 EXIT AND GO + + If TECO is exited via the EGstring` command, TECO closes its + files and exits. It then causes "string" to be executed as an + MCR command using the spawn system directive. This feature works + only on RSX-11M V3.2 and RSX-11M+ V1 or later. + + + F.8 ET FLAG HANDLING + + TECO will automatically turn off the following bits in the ET + flag on every error: Bit 0 (image output), Bit 3 (no echo on + ^T), Bit 4 (cancel ^O), Bit 5 (no stall on ^T), and Bit 15 (^C + trap). + + In addition, TECO always turns off Bit 7 (exit on error, etc.) + every time is reaches prompt (*) level. + + Bit 6 (the detach flag) controls TECO'S treatment of the + terminal. Normally, TECO keeps the terminal attached to gain + control of interrupts. Setting bit 6 of the ET flag + + Standard TECO PAGE 164 + Appendix F + + + causes TECO to run with the terminal detached. All commands + function normally, except that typing causes the MCR to + be activated, allowing other tasks to be run from the same + terminal concurrently with TECO. It is, of course, the user's + problem to sort out the confusion that will arise if both TECO + and another task request input from the terminal at the same + time. + + + F.9 FILE RECORD FORMAT + + Files-11 files are record structured, while TECO'S text buffer is + ASCII stream. Thus TECO must make format conversions when + reading and writing files. The conversion depends on the record + attributes of the file. While reading a file, the records are + packed into the buffer. If the file is implied carriage control + (the standard RSX-11 source format) or Fortran carriage control, + TECO inserts a carriage return and line feed after each record to + make each record appear as a line of text in the buffer, unless + the record ends with ESCAPE, carriage return, line feed, vertical + tab, or form feed. A record ending in form feed is interpreted + as an end of page mark; it stops the read operation and the form + feed is not entered in the buffer. If the file has print file + carriage control, TECO interprets the carriage control bytes and + inserts the resulting carriage return and line feed characters + about the record. If the input file has no carriage control + (also called internal carriage control), TECO simply packs the + records together in the text buffer. + + On output, TECO scans the text buffer for carriage return, line + feed, vertical tab, and form feed characters. Each such + character delimits the end of an output record. If the output + file is implied or Fortran carriage control, and the record ends + with exactly carriage return / line feed, the carriage return and + line feed are not output with the record; Otherwise, the record + is output in its entirety. The carriage return and line feed are + also output with the record if the record ends with ESCAPE / + carriage return / line feed. + + Switches may be applied to the input and output files to control + their carriage control attributes. The switch /CR forces implied + carriage control; /-CR forces no (internal) carriage control; + /FT forces Fortran carriage control. When a carriage control + switch is applied to an input file, the file is read as if it had + that attribute; when the switch is applied to an output file, + the file is written with that attribute. Applying a switch to an + EB file specification causes the switch to apply to both input + and output files. When an output file is created, its carriage + control attributes are defaulted to those of the currently open + input file as follows: + + Standard TECO PAGE 165 + Appendix F + + + Input Output + + implied implied + none implied + FORTRAN FORTRAN + print file implied + + Files read with the EI command have their record attributes + interpreted in the same manner. This leads to an unexpected side + effect with EI files containing an entire command. The last + record of the file presumably contains as its last characters the + two alt modes which initiate execution of the macro. If the file + is implied carriage control, however, there are also the final + carriage return / line feed belonging to the last record, which + remain in the type in buffer while the macro executes. If the + macro attempts to receive input with the command, the + carriage return / line feed will be the first two characters + read. Alternatively, if the macro does no type in, the carriage + return / line feed will be read by TECO as the first two + characters of the next command. Then no asterisk (*) will appear + as the prompt for the next command. The remedy for both cases is + for the macro to execute an EI` command early on. This causes + the remainder of the indirect file to be discarded and further + input to be read from the terminal. + + + F.10 COMMAND LINE PROCESSING + + The mechanism used to process the command line in RSX-11 TECO is + designed to allow sophisticated TECO users the greatest + flexibility in customizing TECO for their own use. It functions + as follows: + + The initialization routine places the original MCR command line + (if any) into the filename buffer. It copies into the text + buffer the text of a TECO macro that will be used to interpret + the command line. Then it starts up TECO with the command + + HXY HKG* HXZ HK :EITECO`` + + in the type in buffer. This loads the command line into + Q-register Z and the macro into Q-register Y. It then executes + the file named TECO.TEC located in the user's default directory, + if it exists. After the user's TECO.TEC, and any files it might + link to with EI, have been executed, TECO executes the command + MY``, thus executing the macro to interpret the command line and + open the files requested. + + The TECO.TEC mechanism should not be used for simple + initialization; the standard TECO.INI facility should suffice + for that. The alternate TECO.TEC facility is provided for the + sophisticated user who wants his own command processing and thus + wishes to usurp control from the normal initialization. + + Standard TECO PAGE 166 + Appendix F + + + If an EI` command (to close the indirect command file) is + executed during the processing of a user's TECO.TEC startup file, + the final MY`` which causes processing of the command line is not + executed. This results from the fact that the MY`` normally + appears in TECO's type in after all command files have been + processed. Executing the EI` command causes all "type ahead" to + be discarded to allow a TECO command file to prompt and read + input from the terminal (and not read extraneous type ahead). It + is assumed that a TECO startup file that executes EI` and reads + input from the terminal will want to manage the rest of TECO's + startup. If it still wants to process the command line, it must + issue the MY itself. + + Standard TECO PAGE 167 + Appendix G + + + APPENDIX G + + + VAX/VMS OPERATING CHARACERISTICS + + + + TECO is implemented in VAX/VMS as a half-native, + half-compatibility mode program. The command processor and + editor proper is the same as TECO-11 and runs in compatibility + mode. Operating system interface and file service logic run in + native mode. + + + G.1 STARTUP + + VAX/VMS supports all of the standard TECO invocation commands, + namely + + TECO + TECO filespec + TECO filespec=filespec + MAKE filespec + MUNG filespec + MUNG filespec,text + + If any of these commands are not recognized by the system, see + the installation instructions (section G.13) in this appendix. + + TECO macros may also be invoked with the command + + TECO @filespec + + It is exactly equivalent to + + MUNG filespec + + + G.2 INITIALIZATION + + TECO performs initialization by attempting to translate the + logical name TEC$INIT. If this name does not translate, no + special initialization is done. If it translates to a string of + the form $filespec (where "$" is a dollar sign), TECO executes + the TECO commands in the specified filespec during + initialization. If TEC$INIT translates to any other string, TECO + executes that string as TECO commands during initialization. The + original command line is available in the text buffer when the + user initialization commands execute. Generally, you would set + user private modes and/or flags at this time. This is also the + normal place to detect, strip off, and do something appropriate + with user private qualifiers. + + Standard TECO PAGE 168 + Appendix G + + + TECO's memory is controlled by the logical name TEC$MEMORY. If + this name translates to a string of the form $filespec, TECO uses + the specified file for its memory. Otherwise, TECO uses the + logical name itself as the memory. + + If TECO is requested to load VTEDIT at startup (e.g., via a + TECO /VTEDIT command), it attempts to translate the logical name + TEC$VTEDIT. If the name is defined, the resulting filespec is + used as the file from which to load the scope editor. If + TEC$VTEDIT is not defined, TECO attempts to translate the logical + name TEC$LIBRARY. If that logical is defined, it is used as the + (device and) directory name of where to find VTEDIT.TEC. + Elsewise, TECO defaults to SYS$LIBRARY:VTEDIT.TEC. + + These four logical names (TEC$INIT, TEC$MEMORY, TEC$VTEDIT, and + TEC$LIBRARY) are the information holders corresponding to the + four standard :EG commands INI, MEM, VTE, and LIB respectively + (see section 5.1.3). + + + G.3 FILE SPECIFICATION + + All file specifiers are subject to the VAX/VMS file specifier + rules; logical names and multi-level directories are properly + handled, including transparent network file access. The filename + field must be specified whenever the device name references a + file structured device. The type field must be explicitly given + if used. There is no default type except for EI commands which + default the type field to .TEC. + + Qualifiers may be applied to file specifications to control + format and attributes; see G.11. + + The qualifier /RW may be applied to any file specification in an + ER, EW, and EI command. If the file specification references a + magtape, the tape is rewound before the file is opened. Note + that for output files, this has the effect of zeroing the tape. + The /RW qualifier is ignored for all other device types. + + The presence of version numbers in Files-11 causes file + processing to behave slightly differently under VAX/VMS than + under other operating systems. For example, no .BAK files are + used; each execution of an EB command simply produces a new + version of the file. Thus a user may retain any level of backup + he feels to be comfortable. It also means that one must + occasionally delete obsolete files to avoid cluttering the disk. + Thus the command + + EBname.typ;version` + + is equivalent to the commands + + ERname.typ;version`EWname.typ;0` + + Standard TECO PAGE 169 + Appendix G + + + The EW command also creates a new version (one higher than the + current highest) if no version number is given. If an explicit + version number is given, then that number is used, and if another + file of the same name, type, and version previously existed, it + is superseded without warning. (See use of the EK command + below.) + + In reading files, version numbers behave the same as in other + VAX/VMS utilities: the default is the highest version. This + leads to a problem in re-opening the input file while a file is + being edited with EB. Since the output file is already created + and in the directory, the input file is no longer the highest + version. One may deduce the version number of the input file by + doing a ER`:G*`` which types the file string of the current + (primary) input file. + + In symmetry with the EB command, the EK command functions by + simply deleting the current output file. Note, however, that a + supersede (EW of same name, type, and version) is not undone - + the file is already deleted! + + When files are processed concurrently on the primary and + secondary channels, all files are kept open. Thus the problems + that occur under RSX-11 do not exist under VAX/VMS. + + + G.4 WILD CARD LOOKUP + + Wild card file name processing supports all of the wild carding + facilities of RMS. For VAX/VMS V2 and later systems this + includes embedded * and % and multi-level directory wildcarding. + + + G.5 SYMBOL CONSTITUENTS + + The match control character ^EC and the conditional n"C accept + the VAX/VMS symbol constituent character set, which consists of + upper and lower case alphabetics, numerics, ., $, and _. + + + G.6 EXITING FROM TECO + + The normal method of exiting from TECO is with the EX command. + This copies the remaining input file to the output file, closes + all files and exits. + + The (or Caret-C) command is the "give up and get out" + command. Executed from main command level, it will cause TECO to + exit regardless of the state of the buffer. If there is an open + output file, it is deleted. The command is roughly + equivalent to EKHKEX. + + TECO's normal exit status code (as reflected by the DCL symbols + + Standard TECO PAGE 170 + Appendix G + + + $STATUS and `SEVERITY) is 1 (success). An exit caused by an EG` + command sets the exit status code to 9 (also success). An error + exit caused by an error or with the 128 bit set in ET + sets the exit status code to hexidecimal 1000002C which is + SS$_ABORT with the inhibit message bit set. All other exits are + from fatal internal errors and the exit status code is the fatal + error status code. + + + G.7 + + The action taken when the user types depends on what + TECO is doing. + + If TECO is executing commands, or is awaiting type-in for the ^T + command, the ?XAB error occurs. + + If TECO is at command level, typing cancels the command + string currently being typed and returns TECO to its prompt. Two + consecutive characters will cause an instant HKEKEX + exit. + + Sometimes it is desireable for a TECO macro to detect when a + was typed. By detecting the , the macro can + exit cleanly back to command level (pop saved Q-registers, + restore any flag values, etc.). To do this, the macro sets Bit + 15 (Octal 100000, Decimal -32768) of the ET flag. When a + is typed, TECO will automatically turn off Bit 15, but + will continue execution of the macro. The macro periodically + checks Bit 15 and exits cleanly if it ever goes off. For + example: + + [0 [1 -32768#ETET < ... ET; > 32767&ETET ]1 ]0 + + Setting the intercept bit in the ET flag must be done + with some care; if the bit is set inside a command loop which + does not check it, it will be impossible for the user to abort + the loop. The only remedy for this situation is to abort TECO + with , resulting in the loss of the edit. + + + G.8 + + is not handled at all by TECO and will result in + trapping to the command interpreter. Should you accidentally + type , immediately type CONTINUE in response to the DCL + prompt to resume editing. + + + G.9 EXIT AND GO + + If TECO is exited with the EGstring` command, the string is + passed to the command interpreter as the next command to execute + + Standard TECO PAGE 171 + Appendix G + + + after TECO has closed its files and exited. This feature works + only on VAX/VMS V2 and later systems. + + + G.10 ET FLAG HANDLING + + TECO will automatically turn off the following bits in the ET + flag on every error: Bit 0 (image output), Bit 3 (no echo on + ^T), Bit 4 (cancel ^O), Bit 5 (no stall on ^T), and Bit 15 (^C + trap). + + In addition, TECO always turns off Bit 7 (exit on error, etc.) + every time is reaches prompt (*) level. + + Bit 6 (the detach flag) has no meaning in VAX/VMS. + + + G.11 FILE RECORD FORMAT + + Files-11 files are record structured, while TECO'S text buffer is + ASCII stream. Thus TECO must make format conversions when + reading and writing files. The conversion depends on the record + attributes of the file. While reading a file, the records are + packed into the buffer. If the file is implied carriage control + (the standard VAX/VMS source format) or FORTRAN carriage control, + TECO inserts a carriage return and line feed after each record to + make each record appear as a line of text in the buffer, unless + the record ends with ESCAPE, carriage return, line feed, vertical + tab, or form feed. A record containing a form feed is + interpreted as an end of page mark; it stops the read operation + and the form feed is not entered in the buffer. The portion of + the record after the form feed, if any, is saved for the next + input command. If the file has print file carriage control, TECO + interprets the carriage control bytes and inserts the resulting + carriage return and line feed characters about the record. If + the input file has no carriage control (also called internal + carriage control), TECO simply packs the records together in the + text buffer. + + On output, TECO scans the text buffer for carriage return, line + feed, vertical tab, and form feed characters. Each such + character delimits the end of an output record. If the output + file is implied or FORTRAN carriage control, and the record ends + with exactly carriage return / line feed, the carriage return and + line feed are not output with the record; Otherwise, the record + is output in its entirety. The carriage return and line feed are + also output with the record if the record ends with ESCAPE / + carriage return / line feed. + + Qualifiers may be applied to the input and output file + specifications. When a carriage control qualifier is applied to + an input file, the file is read as if it had that attribute; + when the qualifier is applied to an output file, the file is + + Standard TECO PAGE 172 + Appendix G + + + written with that attribute. Applying a qualifier to an EB file + specification causes the qualifier to apply to both input and + output files. + + The following qualifiers may be used to control input processing: + + /-CR Force "none" file record attributes + /CR Force "Implied" file record attributes + /FT Force "FORTRAN" file record attributes + /FTN Same as /FT + /B2 BASIC-PLUS-x handling (see Appendix J) + + The following qualifiers may be used to control output + processing: + + /VAR Create file record format "Var" + /STM Create file record format "Stm" + /-CR Create file record format "None" + /CR Create file record format "Implied" + /FT Create file record format "FORTRAN" + /FTN Same as /FT + /B2 BASIC-PLUS-x handling (see Appendix J) + + The following qualifiers may be used to control + open/create/access options: + + /RW Rewind before open/create + /SH Enable file sharing + /SHR Same as /SH + + Below is a complete list of valid TECO input file record + format/attribute combinations and the resulting file + format/attribute combinations for EB commands: + + Input Output + Format Attribute Format Attribute + + Fix none Var Implied + Fix Implied Var Implied + Fix FORTRAN Var FORTRAN + Var none Var Implied + Var Implied Var Implied + Var FORTRAN Var FORTRAN + VFC Print Var Implied + Stm none Stm Implied + Stm Implied Stm Implied + + Files read with the EI command have their record attributes + interpreted in the same manner. This leads to an unexpected side + effect with EI files containing an entire command. The last + record of the file presumably contains as its last characters the + two alt modes which initiate execution of the macro. If the file + is implied carriage control, however, there are also the final + + Standard TECO PAGE 173 + Appendix G + + + carriage return / line feed belonging to the last record, which + remain in the type in buffer while the macro executes. If the + macro attempts to receive input with the command, the + carriage return / line feed will be the first two characters + read. Alternatively, if the macro does no type in, the carriage + return / line feed will be read by TECO as the first two + characters of the next command. Then no asterisk (*) will appear + as the prompt for the next command. The remedy for both cases is + for the macro to execute an EI` command early on. This causes + the remainder of the indirect file to be discarded and further + input to be read from the terminal as soon as the double alt mode + is encountered. + + + G.12 COMMAND LINE PROCESSING + + The mechanism used to process the command line in VAX/VMS TECO is + designed to allow sophisticated TECO users the greatest + flexibility in customizing TECO for their own use. It functions + as follows: + + The initialization routine places a built-in command decoding + TECO macro into Q-register Y and the original command line + (including the keyword TECO, MAKE, or MUNG) into Q-register Z. + + It then looks for a user private command decoding TECO macro by + attempting + + 1. an EITECO`` if the logical name "TECO" exists, elsewise + + 2. an EISYS$LOGIN:TECO`` if the logical name "SYS$LOGIN" + exists, elsewise + + 3. an EITECO`` + + If the EI succeeds, the found file is executed. The file may, or + course, do anything it pleases. Generally, you would use a + private command decoder to automate some sort of system specific + editing package. For example, to implement an editing package + called FOOBAR, you would define the logical TECO with + $ DEFINE/SYSTEM TECO dev:[dir]FOOBAR + define a DCL foreign command symbol with + $ FOOBAR :== $SYS$SYSTEM:TECO FOOBAR + and place the TECO macro the implements the FOOBAR editor in + dev:[dir]FOOBAR.TEC. Now, whenever a TECO, MAKE, MUNG, or FOOBAR + command is issued, the your macro will gain control. It should + fetch Q-register Z (the original command line), check the command + type, if it's FOOBAR then go do its thing, else it should + terminate and execute TECO's built-in command decoder. + + GZ ! Put command into text buffer ! + J ::@S/FOOBAR/"U ! Is the command for us? ! + @EI// ! Not for us, turn us off ! + + Standard TECO PAGE 174 + Appendix G + + + HK ! Clear out text buffer ! + MY ! Let the real TECO takeover ! + ' ! It's for us, just flow on... ! + $$ ! Double ESCAPE; 1st command's end ! + ... ! Do your own thing here... ! + + This mechanism should not be used for simple initialization; the + standard TEC$INIT facility should suffice for that. This + facility is provided for the sophisticated user who wants his own + command processing and thus wishes to usurp control. + + + G.13 HELP + + On VAX/VMS, TECO can provide HELP in any of three ways. + + You can issue a HELP command at TECO's asterisk prompt. This + HELP command obeys the standard VAX/VMS HELP command syntax + rules. The HELP command may be terminated by either RETURN or + ``. + + You can type the / command immediately after an error. (See + section 4.2.) TECO will respond with a one-paragraph description + of the error. + + You can set EH to 3. (See section 5.16.) This will cause TECO to + automatically respond with a one-paragraph description of any + error which occurs. + + + G.14 INSTALLING TECO + + TECO is distributed with VAX/VMS; the files are already in + place. If TECO will receive heavy use, it should be installed + /OPEN and /HEADER_RESIDENT. + + The following commands, if used in a LOGIN.COM file, would define + the three normal TECO invocation commands: + + $ TE*CO :== $SYS$SYSTEM:TECO TECO + $ MAK*E :== $SYS$SYSTEM:TECO MAKE + $ MU*NG :== $SYS$SYSTEM:TECO MUNG + + The asterisk allows for abbreviation of these commands. For + example, the TE*CO definition permits TE, TEC, or TECO. + + One may include command qualifiers in the command definitions. + For example, one can define a command to invoke TECO with VTEDIT + as follows: + + $ VTECO :== $SYS$SYSTEM:TECO TECO /VTEDIT + + Standard TECO PAGE 175 + Appendix H + + + APPENDIX H + + + OS/8 OPERATING CHARACTERISTICS + + + H.1 STARTUP + + TECO is started with the + + .R TECO + + command. TECO is now immediately ready to accept commands. The + text buffer and Q-register areas are empty. + + The TECO command + + .TECO filespec + + is used to edit an already existing file. It is equivalent to + + .R TECO + *EBfilespec`Y`` + + OS/8 "remembers" the filespec as the name of the last file that + has been edited. + + The MAKE command + + .MAKE filespec + + is used to create a new file. It is equivalent to + + .R TECO + *EWfilespec`` + + OS/8 "remembers" the filespec as the name of the last file that + was edited. + + The command + + .TECO filespec1=filespec2 + + is used to edit filespec2 into filespec1. That is, filespec2 is + opened as the input file, and filespec1 is created as the output + file. It is equivalent to + + .R TECO + *ERfilespec2`EWfilespec1`Y`` + + OS/8 "remembers" the filespec1 as the name of the last file that + was edited. + + Standard TECO PAGE 176 + Appendix H + + + The command + + .TECO + + with no arguments, causes CCL to execute the command + + .TECO filespec + + where filespec was the file that was previously remembered as the + last file to be edited. The system purposely does not remember + filenames from one day to the next, but it will remember names + across bootstraps. + + The command + + .MUNG filespec + + executes the specified TECO program. The default extension is + .TEC . This is equivalent to the sequence: + + .R TECO + *ERfilespec`YHXYHKMY`` + + Another format of this command is + + .MUNG filespec,argument + + which is used to pass an argument to the TECO program to control + its action. This is equivalent to the sequence: + + .R TECO + *ERfilespec`YHXYHKIargument`MY`` + + + The argument may be the name of a file that the TECO program is + to mung, or it may be a command to the program to specify what + action to take, or whatever. It is up to the TECO program to + decode this argument (which is left in the text buffer) and take + appropriate action. A TECO program executed via the MUNG command + must never destroy the text storage area of Q-register Y and + expect to ever see the light of day again. + + Note the input file remains open and can provide more input to + the macro. + + + H.2 STARTUP CONDITIONS + + The initial value of the EU flag is 0 if the CCL command SET TTY + NO SCOPE had been previously issued, and is -1 if the CCL command + SET TTY SCOPE had previously been issued. + + The initial value of the ET flag is as follows: + + Standard TECO PAGE 177 + Appendix H + + + Bit value Initial value + + 1 0 + 2 0 (1 if terminal is a scope) + 4 0 + 8 0 + 16 0 + 32 0 + 64 0 + 128 1 (TECO's prompt sets this to 0) + 256 0 + 512 0 (1 if VT support is present) + 1024 0 (1 if VR12 support is present) + 2048 0 + + The initial value of the ED flag is 1. + + + H.3 FILE SPECIFICATION + + The file access commands ER, EB, and EW accept a file + specification in the standard OS/8 format: + + dev:filename.type + + in which dev: is a physical device name or a user assigned + logical name; if dev: is not specified, the default DSK: is + assumed. The filename field must be specified in the commands + ER, EB, and EW and be a legal OS/8 filename. The type field is a + file extension and must be explicitly given if used (there is no + default). Any characters after the second will be ignored, thus + the filespecs FOO.TEC and FOO.TE are equivalent. The EB and EW + commands do not accept the extended notation for an output file + size + + dev:filename.type[n] + + specifying an output size allocation. + + + H.5 BACKUP FILES + + The EB command maintains one level of file backup on OS/8. The + pre-edited input file name is changed to + + filename.BK + + before the new output file is closed with the original name. + Only normal file closing commands (EC, EF, EG, and EX) cause this + renaming to happen. If TECO is aborted or the output file is + purged by the EK command, the input filename remains unchanged. + Note only one .BK file for a given name is kept; earlier .BK + backup files are deleted each time a new backup file is created. + + Standard TECO PAGE 178 + Appendix H + + + A good policy to follow when editing is to close the edited file + frequently enough so that an unexpected incident would not cause + a substantial loss of work. Files should be backed up regularly. + TECO has the power to let an unsuspecting user alter a good file + into a completely useless state. The SRCCOM program can be used + to verify an editing session. + + + H.6 EXIT AND GO + + If TECO is exited via the EGstring` command, the string is passed + to the system as the next command to execute. This string may be + any valid command or an indirect command file specification. The + command may be either a KBM or a CCL command. This command is + especially useful while running under BATCH. + + If TECO is exited via the EG` command, then OS/8 will re-execute + the last explicit compile-class command that was executed that + day. The commands that are considered to be compile-class + commands are: + + COMPILE file + LOAD file + EXECUTE file + LINK file + MACRO file. + + This feature, combined with OS/8's other remembering features, + minimizes the number of keystrokes necessary to do normal program + development. The programmer does not have to constantly type in + the name of the file he is working with. A typical debugging + session would look like this: + + .MAKE FOO.MAC + *!type in assembly language file to be executed! + *EX`` + .EXECUTE FOO + (get error messages) + .TECO + *!fix bugs! + *EG`` !re-compile and execute program! + (watch program work or repeat process) + + + H.7 + + The action taken when the user types depends on what + TECO is doing. At command level is an immediate action + command. If typed as the very first character in a command + string (not necessarily the first keystroke) it aborts TECO and + returns to the keyboard monitor. If this was done accidentally, + TECO may be restarted (at your own risk) by using ODT to branch + to location 207 in your program's image. If is typed in + + Standard TECO PAGE 179 + Appendix H + + + the middle of entering a command string, then the ?XAB error + message is given and TECO reprompts with its asterisk. Note that + if TECO executes as a command from command level, TECO + is aborted. If TECO executes a command from within a + macro, TECO is also aborted. If a is typed while TECO + is running, or while TECO is typing on the terminal, or while an + error message is printing, then the ?XAB error message is given + and TECO reprompts with its asterisk. TECO will abort similarly, + if is typed while TECO is waiting for input because of a + ^T command. Note that if TECO is performing I/O using non-system + handlers, the non-system handler may intercept the and + abort back to the keyboard monitor. In such a case, you may + attempt to re-enter TECO. However, part of your file has been + lost; good luck in attempting to issue an EF command. Manually + resetting the value of Z might recover your data. + + If TECO is executing commands or doing I/O, a will stop + the operation and generate the ?XAB error message. + + Sometimes it is desireable for a TECO macro to detect when a + was typed. By detecting the , the macro can + exit cleanly back to command level (restore any flag values, + etc.). To do this, the macro sets Bit 0 (Octal 4000, Decimal + 2048) of the ET flag. When a is typed, TECO will + automatically turn off Bit 0, but will continue execution of the + macro. The macro periodically checks Bit 0 and exits cleanly if + it ever goes off. If the trap bit is on, then the ^T + can read a typed at the terminal. It has an ASCII value + of 3. + + + H.8 FILE RECOVERY + + TECO can be a useful tool in recovering ASCII files lost on a + block replaceable device. TECO allows non-file-structured + devices to be opened in a non-file structured mode. This gives + the user the capability to open a disk and access ASCII data + anywhere on it, independent of file boundaries. To do this, you + must issue a command of the form + + .SET dev: NOFILES + + to the monitor to make it think that your disk is + non-file-structured. The command + + ERdev:` + + is used to open the device at which point _ (underscore or + backarrow) searches may be used to locate specific ASCII data and + transfer it to new output files. Note that files tend to get + reproduced, in whole or part, many places on a block replaceable + device; be sure to verify that any given text is indeed complete + and the correct version. + + Standard TECO PAGE 180 + Appendix H + + + If the disk's directory has not been clobbered (or if you are + willing to create a new one), then it is not necessary to turn + the disk into a non-file-structured device. Merely open up a + file early on the disk for input and read through end-of-files + until you locate the lost file. To read through end-of-files, + you must use the /S switch on an ER, EB, or EW command. For + example, the command + + ERFOO.MAC/S` + + will open the file FOO.MA for input and put TECO into "SUPERTECO" + mode. In this mode, TECO will not treat a found in a + file as an end-of-file character. Instead, will be + treated like any other character. It is not a line terminator or + a page terminator. This mode continues until an ER, EW, or EB + command is issued without a /S switch. + + + H.9 VR12 GRAPHICS SUPPORT + + If TECO is run on a PDP-12, TECO will automatically start up in + display mode, adjusting to both the size of the display screen + and to the presence or absence of the scroller. + + On a PDP-12, TECO only permits one-page input and output + handlers. + + See Section 5.17 for a description of the available commands to + interact with the display. + + Various aspects of the display screen become immediately obvious + upon seeing them; the text pointer, its position and shape and + its position between lines; wrap around of more than 72 + characters per line, and so on. Experiment with a scratch file + for more familiarity. + + + H.10 EXCEPTIONS + + TECO-8 does not support the following commands which are + described in this manual: + + 1. Secondary streams (EP, EA, ER`, EW`) + + 2. Auxiliary command streams (EI) + + 3. Wildcards (EN) + + 4. Zeroing of directories (EZ) + + 5. Magtape commands (EM) + + 6. View command (nV) + + Standard TECO PAGE 181 + Appendix H + + + 7. Bounded searches + + 8. Anchored searches + + 9. Search verification (ES) + + 10. Command verification (EV) + + 11. Backward searches + + 12. Extended string build or match constructs (^Ex) + + The following incompatibilities exist between TECO-8 and Standard + TECO: + + 1. In octal mode, the digits 8 and 9 are not treated as + errors when occurring in a numeric string. + + 2. The *q immediate action command is not implemented. + Instead, the immediate action command * has the same + effect as *Z of the standard. (The immediate mode + command ^S is still accepted for compatibility with OS/8 + TECO V5.) + + + + H.11 CHAINING TO TECO + + A user program may chain to TECO passing it a command to be + executed. There are two formats that such a command may take. + + Format 1 (the TECO command format) passes TECO a valid TECO + command to be executed. This TECO command is placed in a buffer + starting at location 17600, one 7-bit ASCII character per word. + A negative word represents a pointer to a continuation buffer in + field 1. There may be any number of continuation buffers, but + they must all begin above location 4000 in field 1. Since TECO + clobbers most of field 1, these buffers must in fact start above + location 7400. TECO will never load into page 7400 of field 1. + The buffer ends with a fullword 0. + + Format 2 (the CCL command format) passes TECO a CCL command to be + parsed and executed. Such a command usually begins with the + words TECO, MAKE, or MUNG, but is not limited to these words. + Such a CCL command is placed in a buffer starting at location + 17601, one 7-bit ASCII character per word. Location 17600 must + be a fullword 0 to specify that this format is being used. A + negative word in the buffer represents a pointer to a + continuation buffer in field 1 as described above. The buffer + ends with a fullword 0. If this format is used, the passed CCL + command will be parsed and executed by TECO.TEC as described + below. A user may write his own TECO.TEC, thus implementing his + own CCL commands. There is no limit to the possiblities, other + + Standard TECO PAGE 182 + Appendix H + + + than the user's imagination. + + + H.12 USER INITIALIZATION + + If a user has a file called TECO.INI on SYS:, then when TECO + starts up (via a CCL command, it will execute the contents of + this file (as a TECO macro). This file must contain a valid TECO + program (which will execute out of Q-register W). God help you + if you have any errors in this program. This start-up file must + not modify itself (Q-register W) and must not modify the contents + of Q-register V. It should not indiscriminately modify the + contents of Q-register Z or the text buffer. TECO.INI will be + executed before TECO opens any files. That is, if TECO was + invoked via a MAKE command, TECO.INI will be executed before the + EW command (for the MAKE) is executed. At this point, the text + buffer will contain a copy of the CCL command that invoked TECO + (assuming your monitor has TECO.TEC support). However, TECO has + not as yet parsed this line. The user may examine this line for + himself, and modify it, but you had better know what you are + doing (and do it right!). TECO.TEC will parse the contents of + the text buffer at the conclusion of execution of TECO.INI. + + If your monitor does not have TECO.TEC support, or if a user + program chained to TECO passing it a TECO command (rather than a + CCL command), then the initial TECO command will be in Q-register + Z when TECO.INI gets control. That command has not as yet been + executed. The initialization file may examine the contents of + Q-register Z to determine what TECO command will be executed and + proceed accordingly. It may also modify the contents of + Q-register Z (but you better know what you are doing). + + In this case, TECO.INI is started up via the sequence + + @:ER/SYS:TECO.INI/"SYHXWHK + @^UZ^@teco command^@ + MW+0ES.,.XWMZES"N0ESMX'`` + + which loads TECO.INI into Q-register W, loads the chain argument + consisting of an appropriate teco command into Q-register Z, and + temporarily stores the value returned by TECO.INI in the search + verification flag (this feature may change in a subsequent + release). Q-register W and ES are cleared before the + post-processing command in Q-register X is executed. Note that + the chain argument may not contain any embedded nulls. + + + H.13 RETURNED VALUES FROM TECO.INI + + TECO.INI may also return a value. If your monitor does not + support TECO.TEC, then only two values are permitted. Returning + a 0 (or not returning anything) is the normal sequence of events. + Returning a 1 means that TECO should execute the contents of + + Standard TECO PAGE 183 + Appendix H + + + Q-register X (via an MX command) after it executes the initial + TECO command (in Q-register Z). TECO.INI may set up Q-register X + with the appropriate post-processing commands. A typical use of + this feature would be to have TECO.INI load up Q-register I with + an editing macro and then put an "MI" command in Q-register X for + subsequent execution. If your monitor does have TECO.TEC + support, then TECO.TEC can support additional returned values. + It is recommended that TECO.TEC support the returned values of 0 + and 1 as above, but in addition, it may support additional values + determined by the user. + + Note that TECO.INI is not invoked if TECO is started with a RUN + or R command. + + + H.14 TECO.TEC SUPPORT + + If the version of CCL you are using to invoke TECO supports + TECO.TEC, then it will chain to TECO with a 0 at location 17600 + and will pass TECO the invokig CCL command (beginning at location + 17601). If TECO is invoked in this manner, it will parse this + CCL command by executing the TECO command line parser macro + stored in SYS:TECO.TEC. This macro can be modified by the user + to parse switches or do any special processing that is desired. + TECO.TEC is started up via the command + + @I^@ccl command^@:ER/SYS:TECO.TEC/"F^ACan't find SYS:TECO.TEC + ^A^C^CA.,ZXV.,ZKMV.,.XV`` + + which puts your CCL command in the text buffer and then loads + (the first page of) TECO.TEC into Q-register V. TECO.TEC is then + executed with the MV command and then Q-register V is cleared. + It is the responsibility of TECO.TEC to parse the command line in + the text buffer and do the appropriate processing and clean-up. + It is also the responsibility of TECO.TEC to execute a user's + start-up file (TECO.INI) if one is present. Note that TECO.TEC + is not invoked if TECO is started via a RUN or R command. Also + note, that the CCL command may not contain any embedded nulls. + + + H.15 OVERLAYS + + The key to writing fast TECO programs lies in understanding + TECO-8's overlay structure. If TECO-8 is run in 16K or more (20K + or more if VT support is present), then the overlays will be + memory-resident rather than disk-resident. Although this is much + faster than swapping from the disk, swapping from memory still + involves some overhead, so it would be wise to structure your + TECO program to minimize the number of swaps necessary. + + The overlay structure is designed so that the minimal number of + swaps will be required unless obscure TECO features are used. + There are five overlays to TECO: + + Standard TECO PAGE 184 + Appendix H + + + 1. The I/O-overlay. This overlay handles file opening and + is initially resident. Thus no swapping is necessary to + do an initial ER, EW, or EB. + + 2. The Q-overlay. This overlay contains most of the + frequently used conditional commands and branching + commands. It is intended that this overlay swap in once + and remain in memory until TECO is exited. + + 3. The X-overlay. This is the exit overlay and handles + commands needed only when TECO is exiting, such as EX, + EF, EC, and EG. It is intended that this overlay will + swap in only once when you are ready to leave TECO. + + 4. The F-overlay. This overlay contains the flag commands + and other little-used commands. It is intended that + this overlay be not used at all, or if it is used, it + will be used so infrequently that it will not slow down + system performance. + + 5. The E-overlay. This is the error overlay. It is + swapped in only when an error occurs. It is intended + that this overlay never be swapped in. + + + To write efficient TECO code, the user must know exactly which + commands are handled by which overlay. This information is + summarized below. + + Overlay Commands + + I-overlay ERfile`, EWfile`, EBfile`, :ERfile`, :EBfile` + + Q-overlay Otag`, n"Xthen|else', n;, search;, n<...>, <...> + + X-overlay EC, EG`, EGcmd`, EF, EK, EX, + *q, ?, nEJ, n^_, V, ^B, ^E, ^F, ^L, ^N, ^Uqtext` + + F-overlay ED, EH, EO, ES, ET, EU, ^D, ^O, + \, n\, n=, n==, n:=, n:==, | + + Several things are immediately obvious. The command 0TT should + always be preferred to the V command. ELSE clauses should be + avoided. (In future releases, we will try to move the processing + of the | command into overlay Q.) The commands \ and = should be + used as infrequently as possible from within long-running macros. + Xq is preferred to ^Uq to load up a Q-register. -n-1 is + preferred to n^_ to take a one's complement. Radix changes + should be avoided. Flags, such as ET and ED, should be set once + at the beginning of a macro, and then not fiddled with if at all + possible. + + Standard TECO PAGE 185 + Appendix H + + + H.16 INSTALLATION INSTRUCTIONS + + The source of TECO consists of the following modules: + + TECO.MAC Main module + TECINI.MAC Initialization module + TECTBL.MAC Tables + TECDEF.MAC Global definitions + TECO12.MAC VR12 support + TECOVT.MAC VT support + TECOVI.MAC I/O-overlay + TECOVQ.MAC Q-overlay + TECOVX.MAC X-overlay + TECOVF.MAC F-overlay + TECERR.MAC E-overlay and error processor + TECSRH.MAC Search processor + TECNUM.MAC Arithmetic processor + + Each of these modules should be assembled (using MACREL V2 or + later). This can be accomplished via the command + + .MAC TEC???.MAC + + if your monitor supports wildcards in compile-class commands. + + The resulting relocatable modules are then linked together (using + LINK V2 or later) to produce the executable TECO.SV image which + should be put on SYS: (but it may reside on any device). If + your monitor supports TECO.TEC, then TECO.TEC must be placed on + SYS:. + + + H.17 ARITHMETIC PRECISION + + TECO-8 performs 13-bit arithmetic except that multiplication and + division by negative numbers gives unpredictable results. All + numbers stored in Q-registers are 13 bits long. Numbers stored + in flags (such as ET, EU, etc.) are only 12-bits long. When + storing a number into a flag, the high order (sign bit) is lost. + When using the value of a flag in an arithmetic expression, the + 12-bit value is sign extended first. + + + H.18 ALTERNATE STARTING ADDRESS + + The normal starting address of TECO is location 00200. In this + (normal) mode, TECO will simulate tabs by spaces on type out and + will simulate vertical tabs and form feeds by line feeds. If + your terminal has hardware tabs and vertical tabs (such as a + KSR-35), then TECO can take advantage of these features. To + enable this ability, you should change TECO's starting address to + be 05200. This can be done by the monitor commands: + + Standard TECO PAGE 186 + Appendix H + + + .GET SYS:TECO + .SAVE SYS:TECO;5200 + + H.19 VT05 SUPPORT + + TECO will automatically handle command string scope editing + correctly on a VT05. The VT support (obtained via use of the -1W + command) will handle VT05's correctly. The VTEDIT macro does not + currently support the VT05 keypad. + + Standard TECO PAGE 187 + Appendix I + + + APPENDIX I + + + TOPS-10 OPERATING CHARACTERISTICS + + + I.1 STARTUP + + TECO is started with the + + .R TECO + + command. TECO is now immediately ready to accept commands. The + text buffer and Q-register areas are empty. Initial commands may + also be specifified by following the monitor command with a + dollar sign ($) and then some TECO commands. For example, + + .R TECO $3EH + + starts TECO with the help level flag set to 3. + + The TECO command + + .TECO filespec + + is used to edit an already existing file. It is equivalent to + + .R TECO + *EBfilespec`Y`` + + TOPS-10 "remembers" the filespec as the name of the last file + that has been edited. + + The MAKE command + + .MAKE filespec + + is used to create a new file. It is equivalent to + + .R TECO + *EWfilespec`` + + TOPS-10 "remembers" the filespec as the name of the last file + that was edited. + + The command + + .MAKE filespec1=filespec2 + + is used to edit filespec2 into filespec1. That is, filespec2 is + opened as the input file, and filespec1 is created as the output + file. It is equivalent to + + Standard TECO PAGE 188 + Appendix I + + + .R TECO + *ERfilespec2`EWfilespec1`Y`` + + TOPS-10 "remembers" the filespec1 as the name of the last file + that was edited. + + The command + + .TECO + + with no arguments, causes CCL to execute the command + + .TECO filespec + + where filespec was the file that was previously remembered as the + last file to be edited. The system purposely does not remember + filenames from one editing session to the next, that is, when you + log out, the system "forgets" the name of the file you were + editing. + + TECO-10 does not require the use of the MUNG command to execute + TECO macros because runnable TECO programs can be created via use + of the EE command and these can then be run with the standard R + or RUN command. This TECO command has the format + + EEfilespec` + + which saves away the current image of TECO in the filename + specified. The default extension is .EXE. When the file is + subsequently run (using the R or RUN monitor command), TECO + resumes execution with the TECO command immediately following the + EE command. + + + I.2 STARTUP CONDITIONS + + The initial value of the EU flag is 0 if you are running on a + terminal that does not support lower case, and is -1 if you are + running on a terminal that does support lower case. + + The initial value of the ET flag is as follows: + + Bit value Initial value + + 1 0 + 2 0 (1 if terminal is a scope) + 4 1 + 8 0 + 16 0 + 32 0 + 64 0 + 128 1 (TECO's prompt sets this to 0) + 256 0 + + Standard TECO PAGE 189 + Appendix I + + + 512 0 (1 if VT support is present) + 1024 0 + 2048 0 + + The initial value of the ED flag is 1. + + + I.3 FILE SPECIFICATION + + The file access commands ER, EB, and EW accept a file + specification in the standard TOPS-10 format: + + dev:filename.type[p,pn] + + in which dev: is a physical device name or a user assigned + logical name; if dev: is not specified, the default DSK: is + assumed. The filename field must be specified in the commands + ER, EB, and EW and be a legal TOPS-10 filename. The type field + is a file extension and must be explicitly given the first time. + Thereafter, if a corresponding command is given with no extension + specified, the system uses the previously specified extension as + the default. The same defaulting rules hold for the dev: field. + The construct is permitted on any output filespecification + to allow setting the protection of the file being created. + + + I.4 BACKUP FILES + + The EB command maintains one level of file backup on TOPS-10. + The pre-edited input file name is changed to + + filename.BAK + + before the new output file is closed with the original name. + Only normal file closing commands (EC, EF, EG, and EX) cause this + renaming to happen. If TECO is aborted or the output file is + purged by the EK command, the input filename remains unchanged. + Note only one .BAK file for a given name is kept; earlier .BAK + backup files are deleted each time a new backup file is created. + + A good policy to follow when editing is to close the edited file + frequently enough so that an unexpected incident would not cause + a substantial loss of work. Files should be backed up regularly. + TECO has the power to let an unsuspecting user alter a good file + into a completely useless state. The FILCOM program can be used + to verify an editing session. + + + I.5 EXIT AND GO + + If TECO is exited via the EG` command, then TOPS-10 will + re-execute the last explicit compile-class command that was + executed during that session. + + Standard TECO PAGE 190 + Appendix I + + + I.6 + + The action taken when the user types depends on what + TECO is doing. At command level is an immediate action + command. If typed as the very first character in a command + string (not necessarily the first keystroke) it aborts TECO and + returns to the monitor. No Control-C trapping is available under + TOPS-10. The ?XAB error message is not supported. If + is typed in the middle of entering a command string, then TECO + returns control to the monitor. Note that if TECO executes + as a command from command level, TECO is aborted. If + TECO executes a command from within a macro, TECO is + also aborted. If two consecutive s are typed while TECO + is running, or while TECO is typing on the terminal, or while an + error message is printing, then control returns to the operating + system. If one is typed to TECO while it is waiting for + input, then control returns to the operating system. + + + I.7 EXCEPTIONS + + TECO-10 does not support the following commands which are + described in this manual: + + 1. Secondary streams (EP, EA, ER`, EW`) + + 2. Wildcards (EN) + + 3. Immediate aids LF and BS. + + The following incompatibilities exist between TECO-10 and DEC's + TOPS-10 TECO V24: + + 1. The nA command under TOPS-10 TECO V24 always returned + the value of the current character, regardless of the + value of n. In TECO-10, 0A gives the value of the + current character. + + + + I.8 USER INITIALIZATION + + If a user has a file called TECO.INI in his area, then when TECO + starts up (via a CCL command), it will execute the contents of + this file (as a TECO macro). This file must contain a valid TECO + program. TECO.INI will be executed before TECO opens any files. + That is, if TECO was invoked via a MAKE command, TECO.INI will be + executed before the EW command (for the MAKE) is executed. + + Standard TECO PAGE 191 + Appendix I + + + I.9 INSTALLATION INSTRUCTIONS + + To create TECO for TOPS-10 from the sources, issue the following + commands: + + .LOAD/MAC/COMPILE TECO10.T10+TECO10.MAC + .SAVE TECO10 + .LOAD/MAC/COMPILE TECERR.T10+TECO10.MAC + .SAVE TECERR + + To create TECO for TOPS-20 from the sources, issue the following + commands: + + @LOAD/MAC/COMPILE TECO10 + @SAVE TECO20 + + This builds a raw TECO. This version of TECO does not contain + any window support since the W and :W commands are implemented as + macros. To load window support, issue the following commands: + + .RUN TECO10 (or TECO20) + *EITECO10.TEC`` + *EETECO`` + + You now have a runnable TECO image with window support. + + I.10 TMPCOR SUPPORT + + The EQ and E% commands support the pseudo-device TMP: for + TMPCOR. Only the first three letters of the file name will be + used, to try and access a TMPCOR file. If that fails, it will + try nnnNAM.TMP where nnn is your job number and NAM is the + three-character name. For example: for job 23, EQqTMP:FOOBAR` + will read TMPCOR file FOO or 023FOO.TMP. + + I.11 Q-REGISTER NAMES + + Any printable character (except open parenthesis) is valid as a + Q-register name. A Q-register whose name is a lower case + alphabetic character is the same as the Q-register whose name + consists of the corresponding upper case letter. Thus Qa and QA + are equivalent commands. Q-register names may also be up to 6 + characters long, by enclosing the name in parentheses, for + example, Q(FOOBAR). Q-register names may contain any printable + characters, however all characters other than letters, digits, + dollar-sign, space, and underline are reserved for special use by + TECO. A Q-register name consisting entirely of zero or more + spaces is the same as Q-register (), which is special and + discussed below. Trailing spaces in Q-register names are + discarded, and lower case is converted to upper case. + + Standard TECO PAGE 192 + Appendix I + + + I.12 REFERENCING THE TEXT BUFFER AS A Q-REGISTER + + The Q-register with the null name: () is the text buffer. The + numeric part of this Q-register is the value of dot. The + sequence [A ]() causes Q-register A to share with the text + buffer. The old main text buffer is lost (unless it is also + sharing with some Q-register or if it has been saved on the + Q-register push-down list). The text in Q-register A becomes the + text buffer and the numeric part of Q-register A is used for "." + if it is in range, otherwise dot is set to 0. + + I.13 SHARING OF Q-REGISTER POINTERS + + Q-registers may share their text with each other and with the + text buffer as a result of [ and ] commands. When a Q-register + is pushed onto the Q-register pushdown list, all that is pushed + is the numeric part of the Q-register and a pointer to the text + part of the Q-register. Thus a command such as [A ]B would cause + Q-registers A and B to share the same text. The commands X, ^U, + and EQ could be applied to either Q-register without modifying + the other, since the Q-register is unbound from its previous text + first. However, the colon-modified forms of X and ^U append to + the existing text, so a :X or :^U command for either of them + would affect the other. + + I.14 EDITING LINE SEQUENCE NUMBERED FILES + + Some ASCII files have a special type of line number at the + beginning of each line. These "line-sequence numbers" conform to + certain rules so that they may be ignored or treated specially by + compilers and other programs. The standards for line-sequence + numbers are given in the LINED Program Reference Manual. + + TECO does not need line-sequence numbers for operation, but TECO + can be used to edit files containing them. If such a file is + edited with TECO-10, the line-sequence numbers are, in the normal + case, simply preserved as additional text at the beginning of + each line. The line-sequence numbers may be deleted, edited, and + inserted exactly like any other text. On output, the + line-sequence numbers are output according to the standard, + except that the tab after the number is output only if it is + already there. Leading zeros are added as necessary. If a line + without a line-sequence number is encountered, a line-sequence + number word of five spaces is placed at the beginning of the + line. + + The following switches are available for use with line-sequence + numebred files. These switches are merely added to the + appropriate file selection command. + + ERfilespec/SUPLSN` + EBfilespec/SUPLSN` + + Standard TECO PAGE 193 + Appendix I + + + causes line sequence numbers to be suppressed at input time. The + numbers will not be read into the editing buffer. Also, the tabs + following the line-sequence numbers, if they exist, will be + suppressed. + + EWfilespec/SUPLSN` + + causes the line-sequence numbers to be suppressed at output time. + Tabs following the line-sequence numbers will also be suppressed + if they exist. + + EWfilespec/GENLSN` + EBfilespec/GENLSN` + + causes line sequence numbers to be generated for the output file + if they did not already exist in the input file. Generated + line-sequence numbers begin at 00010 and continue with increments + of 10 for each line. + + Note that these switches are needed only if a change is to be + made in the format of the file being edited. If no switches are + specified, a file is output in the same form as it was input. + + I.15 COMPILER RESTRICTIONS + + TECO-10 is a compiler rather than an interpreter. This means, + that before your command string is executed, TECO-10 compiles it + into assembly language code. This makes it must faster than most + other TECOs. Before executing a macro (with the Mq command) TECO + compiles the program in the macro. The next time the macro is + executed, TECO notes that the macro has already been compiled and + merely branches to the compiled code. If the contents of the + Q-register are changed (via an X or U command), then TECO notes + that it must re-compile the commands should the Q-register be + invoked as a macro. + + One consequence of this is that if a syntax error is detected in + a command, no portion of that command will have been executed. + For example, typing the command HK= will yield the ?NAE error + message and the text buffer will NOT be cleared. Another + consequence of this is that you must not invoke a macro two + different times using two different numbers of arguments. If a + macro gets initially invoked with two arguments, then all + subsequent invocations must supply two arguments. Also, TECO + cannot tell while compiling an Mq command whether or not the + macro returns a value. Therefore it assumes that a value is + always returned. This value can be explicitly removed by + followed the Mq command with an . The MqA command will + compile the A command as if it were an nA command rather than an + APPEND. + + Standard TECO PAGE 194 + Appendix J + + + APPENDIX J + + + BASIC-PLUS/BASIC-PLUS-2 HANDLING + + + J.1 PURPOSE + + In BASIC-PLUS and BASIC-PLUS-2 a program statement may be + continued over more than one text line. A text line which is not + the last text line of a given statement may need to be flagged as + a "continued" line. (See the appropriate language reference + manual for requirements of each version of each language + processor.) + + The standard continuation flag is the & character. A line which + must be marked as "continued" is written with an & as the last + non-whitespace character before the . + + (An older form of continuation was, in BASIC-PLUS only, to end + the text line by typing a key instead of .) + + The switches described in this appendix cause TECO to manipulate + the text files in such a way that each text line appears in the + editing buffer to be completely "conventional": that is, each + text line ends with a standard , and no text line has a + trailing & character. You can correctly edit well-formed + BASIC-PLUS or BASIC-PLUS-2 source files without having to be + concerned about continuation conventions. + + + J.2 METHOD + + TECO allows you to work with "unemcumbered" lines in the editing + buffer by removing continuation conventions as each text line is + read in. You indicate that you want this processing by + specifying a switch on the file specification supplied to the ER + (or the EB) command. + + TECO (again) adds appropriate continuation conventions to each + text line as it is written out from the editing buffer. You + indicate that you want this processing by specifying a switch on + the file specification supplied to the EW (or the EB) command. + + + J.3 INPUT PROCESSING + + As TECO reads each new text line into the editing buffer, it is + examined for a trailing & character. If one is found, TECO + removes it, and then additionally removes any trailing spaces + and/or tabs. + + (In the case of continuation, TECO converts that kind of + + Standard TECO PAGE 195 + Appendix J + + + line terminator character sequence to .) + + The available switches follow. (Consult the appropriate appendix + to see which switches are supported on your operating system.) + + /B2 TECO strips trailing & sequences + + /n Same as /B2 for input processing + + /B+ TECO changes + sequences to . + + + J.4 OUTPUT PROCESSING + + As TECO writes each text line from the editing buffer, it takes a + look at the text line which will follow. If the following line + begins with a digit, the current line is written without change. + If the following line does not begin with a digit, TECO assumes + that the current line must be continued. + + The convention applied to an output text line which TECO marks as + "continued" depends on the form of the switch you specify. + (Consult the appropriate appendix to see which switches are + supported on your operating system.) + + /B2 TECO appends a space and an & + + /n TECO appends an &, after padding out + the line with tabs and/or spaces to make + the & appear in column n + + /B+ TECO ends the line with a + sequence + (instead of .) + + + J.5 FORM FEED INTERACTION + + When TECO reads a page of text into the editing buffer, it stops + when a character is encountered, or when the buffer + has been filled to capacity. In the latter case, the last line + will be complete, and will include its line delimiter. However, + no look-ahead is done to examine the next line in the file. + + If TECO is being used with one of the switches described in this + appendix, a very long BASIC-PLUS-x source program which is not + segmented with characters can cause the last line in the + buffer to not be the last text line of a multi-line source + statement. + + When the buffer is written to the output file, TECO has no way of + determining whether the next text line (the first line of the + + Standard TECO PAGE 196 + Appendix J + + + next buffer load) will begin with a line number. TECO makes the + assumption that the buffer's last text line is not to be + "continued", and terminates it with . If this assumption + is incorrect (frequently the case), remaining text lines of that + multi-line statement will be lost when the program is + subsequently OLDed. + + To avoid this problem, lengthy BASIC-PLUS or BASIC-PLUS-2 + programs should be segmented with characters before + editing them using these TECO switches. Segments of + approximately 150 to 200 lines are convenient. Starting a new + page even more frequently to make listings readable isn't a bad + idea, either. + + Standard TECO PAGE 197 + Glossary + + + GLOSSARY OF OBSCURE TECO TERMS + + + Accent grave + The ` character. Echoed for TECO's text and + command string delimiter when an ESCape surrogate + is in effect. Actually set as the ESCape + surrogate by the 8192 ET bit. + + Abort-on-error bit + The 128's bit of the ET flag. If this bit is set, + then TECO will abort execution on encountering an + error (after printing the error message) and + control returns to the operating system. This bit + is initially set when TECO starts up, but is reset + whenever TECO issues its prompt. + + One of several characters that TECO treats + specially for use as a delimiter. Known as ESCAPE + in more recent times, but traditional TECO users + will still go on ending their command strings with + "ALT" "ALT". + + Anchored search + A search (S) or search and replace (FS) command + that is preceded by a ::. This indicates that the + search must match the characters immediately + following the current pointer position. If these + characters do not match, no further searching is + performed and the text buffer pointer does not + move. + + Argument pair A command of the form m,n where m and n are + numbers (or TECO commands that return numbers). + When used before a command that normally acts on + lines, the argument pair causes the command to + work on characters. The characters specified by + this argument pair is the set of characters + between pointer positions m and n. The number m + should normally be less than or equal to n. + + ASCII code The American Standard Code for Information + Interchange. The code used by TECO to represent + characters internally. Consult Appendix A for + details. + + @-sign modified command + A command that is preceded by an @-sign modifier. + + @-sign modifier + An at-sign (@) that proceeds a command. It + indicates to TECO that the string argument to the + command is to delimited on both sides by a + + Standard TECO PAGE 198 + Glossary + + + user-supplied delimiter rather than to be + delimited only at the end by a TECO-designated + delimiter (normally ). + + Automatic refresh + A refresh of the buffer display done when + scrolling is active (when 7:W is non-zero) just + before TECO issues its asterisk prompt. Automatic + refresh can be disabled by the 128 ED bit. + + Automatic type out + The feature of TECO that causes lines of text to + be automatically typed out. The ES flag may be + used to control the automatic type out of lines + after search commands, and the EV flag may be used + to cause automatic type out of lines after command + execution. + + Auto-trace mode + A mode that TECO goes into when the 4's bit of the + EH (Help-level) flag is set. In this mode, TECO + will automatically print out the erroneous command + string after an error occurs. + + Backup protection + The process of preserving the user's original file + (as a backup) when editing that file with the EB + (Edit with Backup) command. + + Backwards searches + A search that proceeds in the backwards direction. + If the string being looked for does not occur at + the current pointer position, the pointer position + is moved back one character and the search is + tried again. This continues until the string is + found or until the boundary of the search has been + reached or until the beginning of the current text + buffer has been reached. Backward searches are + initiated by using a negative argument to a search + command or by using an argument pair m,n with m + greater than n to an FB or FC command. + + Bounded searches + A search command that requires searching only a + portion of the text buffer. Of particular + importance is the case where you only want to + search the current line for a given string. + Bounded searches are accomplished using the FB + command. + + Case flagging A mode of TECO wherein, on type out, it will flag + alphabetic characters (in either upper or lower + case) by preceding them with a single quote. + + Standard TECO PAGE 199 + Glossary + + + Lower case flagging is particularly useful on + terminals that do not display lower case. Case + flagging is controlled by EU, the case flag. + Setting EU to 0 sets lower case flagging mode; + setting EU to 1 sets upper case flagging mode, and + setting EU to -1 removes all case flagging. + + Character-oriented editor + An editor that allows modification of single + characters, so that if just one character of a + line is wrong, the entire line does not have to be + retyped. TECO is a character-oriented editor + (although it has a number of facilities for + dealing with text lines, too). + + Colon-modified command + A command that is preceded by a colon (:) + modifier. + + Colon-modifier + A colon preceding a TECO command, used to indicate + that the action of the command is to change. + Frequently indicates that the command is to return + a value (-1 if the command succeeded, 0 if the + command failed). + + Command line The current line of the command string that is + being typed into TECO. + + Command string scope editing + The feature of TECO that is enabled when editing + is performed on a CRT terminal. In this mode, + typing the immediate action command + causes the character deleted from the command + string to physically disappear from the screen. + Other commands, such as also behave + differently, taking best advantage of the + properties of a video terminal. + + Command string + The string of TECO commands that is currently + being typed into TECO, or is currently being + executed by TECO. + + Comment An informative message used within a TECO program, + to make the code more readable. The comment + explains the meaning and purpose of the associated + TECO commands. The comment is enclosed in + exclamation marks. + + Compile-class command + A set of operating systems commands (such as + COMPILE) that causes compilation (translation) of + + Standard TECO PAGE 200 + Glossary + + + a source file written in a computer language into + machine instructions. The EG` command is useful + to finish an editing session and re-execute the + last compile-class command (normally a command + that compiles the file that was just edited). + + Conditional A TECO language construct used to specify code to + be conditionally executed depending upon the + results of some test. The most general form of + the TECO conditional is + n"X | ' + which tests the number n using condition X (See + section 5.13 for details). The commands specified + by the are executed if the condition + succeeds, otherwise the commands specified by the + are executed. + + Control-character + An ASCII character whose octal code is in the + range 0-37. Usually denoted in this manual by + where X is the character whose ASCII code + is 100 (octal) greater than the ASCII code for the + control character being represented. TECO + displays such a character as ^X (Caret-X) except + for , , , , AND which have + their normal display, and which is displayed + as $ (dollar sign) or, if a user-designated ESCAPE + surrogate is in effect, as ` (accent grave). + Anytime a single control-character, is a + valid TECO command, the two-character sequence, + ^X, may be used instead. + + trapping + A mode of operation wherein a TECO macro will + regain control (rather than TECO) when or + is typed on the user's terminal + to abort execution of the current command string. + trapping is enabled by setting the + high-order bit of the ET flag. + + Current character + The character immediately following the current + text buffer pointer position. + + Cursor A visible pattern on a CRT terminal (usually + blinking) that would specify to a true scope + editor (like VTEDIT) the current location of the + text buffer pointer, or which would specify the + location where subsequently typed characters would + be displayed. + + Standard TECO PAGE 201 + Glossary + + + Terminology in this manual for an ESCape typed at + the console and passed to TECO. On newer + terminals, there may be no ESCape key. Some + versions of TECO provide for an "ESCape + surrogate", a user-designated key which is to + cause transmission of an ESCape to TECO. The term + is used to indicate an ESCape transmitted + to TECO whether it was generated by the designated + "surrogate" key or by a "real" ESCape key. An + ESCape types out as ` when a surrogate is active, + but as $ when no surrogate is active. + + Destructive search + A form of global search in which pages of text + that are passed over (because they did not contain + the string being searched for) are discarded + rather than written to the output file. + Destructive searches are initiated in TECO via use + of the _ command. + + Display editor + A true display editor is on which makes efficent + use of a CRT terminal or display scope. Such an + editor maintains a "window" into the text being + edited. As characters are typed on the terminal, + these characters immediately are entered into the + text buffer and the window is immediately updated + to reflect this change. With the help of some + macro support, TECO can be made to be a true + display editor. A more modest use of a CRT + terminal (and which requires no macro support) is + scrolling, q.v. + + Dot A mnemonic for "the current text buffer pointer + position". Stems from the fact that the . (dot, + or period) TECO command returns this number as its + value. + + E command One of several two-character TECO commands that + start with the letter 'E'. + + Echo mode A normal mode of operation in which TECO will + automatically echo (display) each character that + is typed in response to a ^T command. Opposite of + no-echo mode. This mode is controlled by the 8's + bit of the ET flag. (0 means no-echo mode.) + + ED flag The edit level flag. + + Edit-class command + A type of operating system command (such as MAKE + and TECO) that specifies that file editing is to + occur. Many operating systems remember the + + Standard TECO PAGE 202 + Glossary + + + argument specified with the last Edit-class + command, so that the next time an edit-class + command is used without an argument, the previous + argument can be recalled. + + Edit level flag + A bit-encoded flag, referenced by the ED command, + that describes how TECO should behave with + reference to certain features. See section 5.16 + for more details. + + Edit verify flag + A flag that describes how TECO should act after + processing of a command string. This flag can be + set so that TECO will display the line just edited + on the terminal after each command. See section + 5.16 for more details. + + EH flag The help level flag. + + Either-case search mode + A standard mode of operation in which alphabetic + characters specified within a search string are + permitted to match a corresponding character of + either upper or lower case. + + Else-clause The part of a conditional command that is executed + if the condition is not satisfied. In TECO, these + are the commands that occur between the | and the + ' characters within the conditional construct. + + End-of-file flag + A read-only flag, referenced by the ^N command + that specifies whether or not end-of-file has been + seen on the currently selected input stream. A + value of 0 means that end-of-file has not been + seen; a value of -1 means that end-of-file has + been reached. This flag is initially 0 and is + reset to 0 each time a new file is selected for + input. + + EO level The current version level of TECO-10. + + ES flag The search verification flag. + + The character whose ASCII code is 33 (octal). It + is a general-purpose delimiter used by TECO. + Traditionally known as an . When no + ESCape surrogate is active, an ESCape types out as + $ (dollar sign). See also . + + Standard TECO PAGE 203 + Glossary + + + ESCape surrogate + A character (designated via the 8192 ET bit, or + via the EE flag) which causes an ESCape to be + transmitted to TECO. When an ESCape surrogate is + active, an ESCape types out as ` (accent grave). + See also . + + ET flag The terminal characteristics flag + + EU flag The upper/lower case flag. + + EV flag The edit verify flag. + + Exact-case search mode + A mode of operation in which alphabetic characters + within a search string must match the exact case + (upper case or lower case) of characters + specified. + + Exit Protection + A protective feature of TECO that prevents a user + from exiting TECO if a potential los of data is + imminent. The EX and EG commands are aborted + (with the ?NFO error message) if there is text in + the text buffer, but no output file is open. + + F command One of several two-character TECO commands that + start with the letter 'F'. + + Flag A data register used by TECO to control various + modes of operation. The contents of the flag are + set by specifying the new value before the flag + name; and the contents are returned by using the + flag name without a numeric argument. The TECO + flags are: ^X, ^E, ^N, ED, EE, EH, EO, ES, ET, + EU, and EV. + + Flow command A TECO-11 command that is used to flow (branch) to + a particular flow control character. The flow + commands are F<, F>, F', and F|. + + Form feed flag + A read-only flag, referenced by the ^E command + that specifies whether the previous append from + the input file terminated because of encountering + a form feed character in the input file, or + because the text buffer became nearly full. The + value of this flag is automatically set to -1 by + TECO if input is terminated by the presence of a + form feed character in the input file. + + Standard TECO PAGE 204 + Glossary + + + Garbage collection + A process used by TECO-10 to collect unused memory + when more memory is required. + + Global Q-register + A Q-register available throughout all macro levels + (including "outside", or at prompt level). Global + Q-registers are named A-Z and 0-9. See also Local + Q-Registers, and section 3.3.2. + + Global search A type of search that continues through the entire + input file until the specified characters are + found. Successive pages of the file are read into + the text buffer and then written out into the + output file (if the string is not located). + Global searches in TECO are initiated via the N + command. + + Hard-copy editing mode + A mode of operation that TECO uses when the user's + terminal is not a CRT. In this mode, when a + character is rubbed out using the key, + the rubbed-out character is re-typed on the + terminal as a visible indication that this + character was rubbed out. Opposite of scope + editing mode. This mode can be entered, even on a + scope terminal, by turning off the 2's bit of the + ET flag. + + Help level flag + A bit-encoded flag, referenced by the EH command, + that controls properties of TECO having to do with + error messages and user assistance. + + Immediate command + A special command to TECO that takes immediate + effect, requiring no s to begin its + execution. + + "Immediate action editing characters" are commands + such as and , which perform + editing of the TECO command string currently being + typed in. See section 4.1. + + An "immediate inspection command" is a + single-character command which can be typed as the + very first character after TECO's prompting + asterisk, and which causes the current location + counter to be moved by one line and the new + current line to be typed out. Examples are + and . See section 1.6.1. + + "Immediate action commands" are other commands + + Standard TECO PAGE 205 + Glossary + + + which may be typed right after TECO's prompting + asterisk, such as the *q to save the + previously-typed command in a Q-register or the ^W + to re-display a scrolling buffer window. See + section 4.2. + + "Immediate ESCape sequence" commands are invoked + by keys which generate escape sequences, such as + "arrow" or "auxiliary keypad" keys. See section + 4.4. Such commands are usually used to perform + editing of the TECO command string currently being + entered into TECO. For example, the commands + and are immediate action + commands. + + Iteration A language construct that permits a sequence of + operations to be re-executed indefinitely or a + given number of times. In TECO, this is + accomplished by enclosing the commands in angle + brackets. + + Kernel The TECO-11 kernel refers to the TECO-11 module + that implements all those features of TECO-11 that + are common to all PDP-11 operating systems. + Operating system specific features and the + interface to the operating system is accomplished + by linking an I/O module tailored for the desired + operating system with the kernel. + + Keypad editor A true scope editor that uses special keys on the + terminal (such as a VT52 or VT100) to control + editing functions. VTEDIT is an example of a + keypad editor. + + Line A portion of text delimited by , , , + or the beginning or end of the text buffer. The + final delimiter is considered to be part of the + line. + + Line-numbered file + In TOPS-10, an ASCII file that contains line + numbers embedded in the start of each line. TECO + does not require these line numbers, but can + handle them if they are present. They can also be + generated or suppressed via the /GENLSN and + /SUPLSN switches respectively. + + Line-oriented editor + An editor that primarily uses line numbers to + direct editing, and most of whose commands are + line-oriented. TECO is a character-oriented + editor, but also has many facilities that work + with lines. + + Standard TECO PAGE 206 + Glossary + + + Line-wrap mode + A standard mode of TECO's window support wherein + lines that are too long to fit on a single + physical line of the user's terminal are + automatically continued on the next line. + Opposite of truncate mode. + + Literal type out mode + A mode that TECO can be put into by setting the + 1's bit in the ET flag, or (for a single character + on a one-shot basis) by using the :^T command. In + this mode, any characters typed by a TECO program + via use of one of the commands T, V, ^A, or :G, + will be displayed on the user's terminal without + any modification. When not in this mode, TECO + will convert characters that normally do not print + to a form that can be displayed on the user's + terminal (e.g. displays as ^X and + displays as $ or, if a user-designated + ESCAPE surrogate is in effect, as `). Literal + type out mode is useful when trying to do + real-time displays on a CRT terminal. Normal + (up-arrow) mode is particularly useful to let you + see what characters are really in your file. + + Local Q-register + A Q-register available to only a single macro + level (including "outside", or at prompt level). + The local Q-registers for a particular macro level + are automatically saved and restored by TECO + around execution of a lower-level macro. Local + Q-registers are named .A-.Z and .0-.9. See also + Global Q-Registers, and section 3.3.2. + + Log file An audit trail that TECO-10 can keep showing all + the commands that were typed to TECO and/or all + the type out made by TECO. This is useful for + reviewing what went wrong with a 'bad' edit. The + log file is initiated with the EL command (see + Appendix C). + + Macro A sequence of TECO commands intended to be loaded + into a Q-register and executed as a TECO program. + + Macro level Two commands within the same TECO macro are said + to be at the same macro level. When one TECO + macro calls another, the calling macro is said to + be at the higher macro level, and the called macro + at the lower macro level. + + Match control construct + A command, consisting of certain special + characters, used within a search string to + + Standard TECO PAGE 207 + Glossary + + + indicate to TECO that special groups of characters + are permitted to match at this point. + + Memory expansion + TECO's act of acquiring additional storage from + the operating system when the currently allocated + storage is insufficient to handle the current TECO + command. Typically, TECO will attempt to acquire + this additional memory before it completely runs + out of memory, so as to allow a 'buffer zone' for + the user. This allows him to complete a few more + commands even in the case where TECO is unable to + get more memory. The informative message "[nK + Bytes]" or its equivalent is printed on the + terminal informing the user that memory usage has + expanded. + + Mung A recursive acronym for "Mung Until No Good"; an + act applied by novice TECO users to their source + files. + + MUNG command An operating system command used to invoke a + pre-written TECO program. The most general form + of this command is "MUNG file,data" where "file" + is the name of a TECO source program, and "data" + is data to be passed to that program. + + No-echo mode A mode of operation in which TECO will not + automatically echo (display) the character typed + by the user in response to the ^T command. This + mode is entered by setting the 8's bit of the ET + flag. Opposite of echo mode. + + Page A portion of text delimited by form feeds. The + form feeds are not considered to be part of the + page. Sometimes the term 'page' is used to refer + to all the text currently in the text buffer. + + Panic Mode A condition that occurs (on small, single-user + operating systems), when, in the middle of + outputting during an edit, the output device fills + up so that the I/O transfer cannot continue. TECO + recovers gracefully from this condition by + printing the ?FUL error message and returning + control to TECO without any loss of data. At this + point, the user closes the current output file and + opens another one on another device (with more + room) and resumes editing. At a subsequent time, + the two parts of his file can be concatenated back + together. + + Standard TECO PAGE 208 + Glossary + + + Pipeline editor + An editor which only makes sequential edits to a + file. The file to be edited is read into the text + buffer one piece at a time. Each piece is edited + and then written out. Once a piece has been + written out, further editing to that piece is not + possible unless the output file is re-opened in a + later edit as a new file to be edited. TECOs are + pipeline editors, with the exception of TECO-11 on + VAX/VMS (which offers the capability to page + backwards as well as forward). + + Pointer preservation mode + A mode of operation in which the text buffer + pointer will not change after a failing search. + This mode is controlled by the 16's bit of the ED + flag. + + Primary input stream + A term used by TECO-11 to refer to the main input + file that TECO is using. + + Primary output stream + A term used by TECO-11 to refer to the main output + file that TECO is using. + + Prompt level A TECO command is said to be executed from prompt + level if it was typed in directly in response to + TECO's prompt, as opposed to being executed from a + macro. + + Q-register One of 36 global or 36 local user-accessible + registers provided by TECO. Each Q-register can + hold both a number and a string of text. Of + particular importance is the ability to store TECO + command strings in Q-registers to be used as + "macros". + + Q-register push down list + A last-in first-out stack available to users for + saving and restoring the contents of Q-registers. + + Read-with-no-wait mode + A mode of operation in which the ^T command will + not hang until a key is typed on the user's + terminal. In this mode, if no key has been + struck, TECO returns a -1 as the value of the ^T + command. This mode is entered by setting the 32's + bit of the ET flag. + + Scrolling A form of TECO operation available on CRT + terminals capable of supporting split-screen + operation. The bottom n lines are used for TECO's + + Standard TECO PAGE 209 + Glossary + + + asterisk prompt and the usual typed command lines; + the remaining lines above are used for an + automatically-updated window into the text buffer. + A valuable training aid: one can experiment with + TECO commands and immediately observe their + effects. Not a bad idea for advanced users, + either. Controlled by the n,7:W command. + + SEALL mode A mode of window operation in which all characters + have a distinctive visible display, including + characters such as , , and , which + normally do not print. Controlled by the 3:W flag + (see section 5.17). Also known as "View all" + mode. + + Search verification flag + A flag, referenced by the ES command, that + controls the action of TECO subsequent to the + execution of a command string containg a search + command. Proper setting of this flag will enable + the user to verify that the search located the + correct string, by having the line containing the + string found displayed on the terminal. See + section 5.16 for more details. + + Search mode flag + A flag, referenced by the ^X command, that + controls how TECO treats alphabetical characters + within search strings. This flag is used to put + TECO into either exact-case mode, or either-case + mode. If the ^X flag is set to 0, then either + case matches in searches. If the ^X flag is set + to 1, then exact case matches are required. + + Secondary input stream + A term used by TECO-11 to refer to an auxiliary + input "channel" that was formed by use of the EP + command. + + Secondary output stream + A term used by TECO-11 to refer to an auxiliary + output "channel" that was formed by use of the EA + command. See section 5.1.4 for details. + + Scope editing mode + A mode of TECO in which command line scope editing + (q.v.) algorithms are used. This mode is enabled + by setting the 2's bit of the ET flag. It is + usually automatically enabled by TECO if the + operating system can detect that the user has + invoked TECO from a scope terminal. Opposite of + hard-copy editing mode. + + Standard TECO PAGE 210 + Glossary + + + Split Q-registers + The feature of TECO that permits storing of both a + number and a string within a Q-register. Each + Q-register can be considered to consist of two + compartments. + + String build construct + A command, consisting of special characters, used + within a text argument to build up the contents of + the text argument from other components. + + SUPER TECO mode + A mode of TECO-8 wherein TECO will read past the + end-of-file mark (CTRL/Z) of a sequential ASCII + file. This mode is enabled by using the /S switch + on an ER or EB command and is terminated when an + ER or EB command is issued with no /S switch. + This mode is useful for scanning through mass + storage devices in an attempt to recover data from + files that had previously been deleted. + + Switch A construct of the form /SWITCH used within a + command that takes a filespecification, to modify + the action of the command or attributes of the + file specified. Also known as a qualifier. + + Tag A label specified within exclamation marks to mark + a point within a TECO program. Control can be + transferred to this point by the use of a GOTO + (Otag`) command. + + TECO Text Editor and COrrector program. + + TECO.INI A file containing TECO commands that is used as a + user's private initialization file. When TECO + starts up, it looks for such a file in the user's + area, and if it finds one, the TECO commands in + this file are executed before editing commences. + + TECO.TEC A TECO macro used by many operating systems to + parse the user's edit-class commands. + + TECO I/O mode A mode of I/O operation under the RSTS/E and + RSX-11 operating systems, in which the system + buffers most characters and returns control to the + caller (usually TECO) only when interesting + characters (such as , , etc.) are + typed. + + TECO's prompt refers to the asterisk (*) that TECO prints to + indicate that it is ready to accept commands. + + Standard TECO PAGE 211 + Glossary + + + TECO SIG A DECUS Special Interest Group, consisting of + users who are dedicated to the spread of, + improvement of, and standardization of TECO. + + Terminal characteristics flag + A bit-encoded flag, referenced via the ET command, + that contains information about the user's console + terminal and specifies in what manner TECO should + support it. + + Text buffer + The main buffer used by TECO to hold the text to + be edited. + + Text buffer pointer + A pointer that marks the position within the text + buffer where TECO is currently 'at'. This pointer + always points to positions between characters; it + never points at a character. The current + character is considred to be the character + immediately to the right of the current position + of the text buffer pointer. + + Then-clause The set of commands within a conditional that are + executed if the condition is satisfied. In TECO, + these commands immediately follow the "X at the + start of the conditional. They are terminated by + a | or ' character. + + Tracing The act of watching the command-by-command + execution of a TECO program. This is accomplished + by putting TECO into trace mode, via use of the ? + command. + + Trace mode A mode of TECO wherein each command that is + executed by TECO is also displayed on the user's + terminal as it is being executed. This mode is + useful for debugging complicated TECO programs. + TECO is toggled in and out of this mode via use of + the ? command. See section 5.18.4 for more + details. + + Truncate mode A mode of TECO's window support wherein lines that + are too long to fit on a single physical line of + the user's terminal are truncated when the right + margin of the scope is encountered. This mode is + entered by setting the 256's bit in the ET flag. + Opposite of line-wrap mode. + + Type-out-time command + A special command that makes sense only while TECO + is typing out text on the terminal. These + commands are , , and and + + Standard TECO PAGE 212 + Glossary + + + affect the type out. + + Up-arrow mode A standard mode of operation wherein upon type + out, TECO will display control characters by + typing the visible two-character sequence ^X to + represent the control character . On many + older terminals, the caret character (^), whose + octal ASCII code is 136, prints as an up-arrow. + Some control characters are not printed in + up-arrow mode, notably , , , , + and . + + Upper/lower case flag + A flag, referenced by the EU command, that + specifies whether or not case flagging is to + occur. If set to -1, no case flagging occurs. If + set to 0, lower case characters are flagged on + type out. If set to +1, upper case characters are + flagged on type out. + + View all mode A mode of window operation in which all characters + have a distinctive visible display, including + characters such as , , and , which + normally do not print. Controlled by the 3:W flag + (see section 5.17). Also known as SEALL mode. + + War and Peace mode + A mode of operation in which TECO outputs a large + informative paragraph of information automatically + upon encountering an error in a user's program. + This paragraph of information describes the error + in painstaking detail and tells the user how to + recover. This mode is entered by setting the help + level to 3. This mode is particularly useful to + Novices and particularly obnoxious to experts. + + Window The portion of the text buffer that is currently + being displayed on the user's terminal or + auxiliary display device. + + Window support + Assembly language code, built into TECO, that + maintains a window into the text buffer on the + user's terminal or auxiliary display device. + + Yank protection + A feature of TECO wherein any Y, _, or F_ command + that will potentially destroy valid data is + aborted. This mode is normally enabled and will + cause any of the aforementioned commands to abort + with the ?YCA error message if there is text in + the text buffer and an output file is open. This + feature can be disabled by turning off the 2's bit + + Standard TECO PAGE 213 + Glossary + + + in the ED flag. + + Standard TECO PAGE 214 + Index + + + INDEX TO TECO COMMANDS + AND SPECIAL CHARACTERS + + + NULL Discarded on input; Ignored in comman . . 119 + ^A Output message to terminal . . . . . . . . 64 + ^B Current date . . . . . . . . . . . . . . . 90 + ^C Stop execution . . . . . . . . . . . . . . 40, 53, 99 + ^D Set radix to decimal . . . . . . . . . . . 87 + ^E Form Feed flag . . . . . . . . . . . . . . 90 + ^E (Match char) Match ASCII code n . . . . . 79 + ^EA (Match char) Match alphabetics . . . . . . 78 + ^EB (Match char) Match separator char . . . . 78 + ^EC (Match char) Match Symbol Constituent . . 78 + ^ED (Match char) Match numerics . . . . . . . 78 + ^EGq (Match char) Match contents of Q-reg . . 78 + ^EL (Match char) Match line terminators . . . 78 + ^EMx (Match char) Match any number of x . . . . 78 + ^EQq (String char) Use contents of Q-reg q . . 77 + ^ER (Match char) Match alphanumerics . . . . . 78 + ^ES (Match char) Match non-null space/tab . . 78 + ^EUq (String char) Use ASCII code in Q-reg . . 77 + ^EV (Match char) Match lower case alphabe . . 78 + ^EW (Match char) Match upper case alphabe . . 78 + ^EX (Match char) Match any character . . . . . 79 + ^E[] (Match char) Match one of list . . . . . . 79 + ^F Contents of console switch register . . . 90 + n^F Return terminal number of job n . . . . . 91 + ^G^G Kill command string . . . . . . . . . . . 40 + ^G Retype current command line . . . . . . . 40 + ^G* Retype current command input . . . . . . . 40 + ^H Current time of day . . . . . . . . . . . 91 + BS Back up and type one line . . . . . . . . 17, 41 + TAB Insert tab and text . . . . . . . . . . . 69 + LF Line terminator; Ignored in commands . . . 9, 34, 117 + LF Advance and type one line . . . . . . . . 17, 41 + VT Line terminator; Not a TECO command . . . 34 + FF Page terminator; Output Form Feed . . . . 9, 34 + CR End input line; Ignored in commands . . . 9, 40, 117 + ^N End of file flag . . . . . . . . . . . . . 91 + ^Nx (Match char) Match all but x . . . . . . . 77 + ^O Set radix to octal . . . . . . . . . . . . 87 + ^O Kill terminal output . . . . . . . . . . . 65 + ^P Not a TECO command . . . . . . . . . . . . 214 + ^Q Resume terminal output . . . . . . . . . . 65 + ^Q Convert line arg into character arg . . . 146, 150 + ^Qx (String char) Use x literally . . . . . . 76 + ^R Value of current radix . . . . . . . . . . 87 + n^R Set radix to n . . . . . . . . . . . . . . 87 + ^Rx (String char) Use x literally . . . . . . 76 + ^S -(length) of last referenced string . . . 91 + ^S Suspend terminal output . . . . . . . . . 65 + ^S Save last command string . . . . . . . . . 149 + + Standard TECO PAGE 215 + Index + + + ^S (Match char) Match separator char . . . . 77 + ^T ASCII value of next character typed . . . 91 + ^T Read and decode next keystroke typed . . . 91 + n^T Type ASCII character of value n . . . . . 63 + n:^T Output binary byte of value n . . . . . . . 63 + ^U Kill command line . . . . . . . . . . . . 40 + ^Uq Put string into Q-register q . . . . . . . 80 + :^Uq Append string to Q-register q . . . . . . 81 + n^Uq Put ASCII char "n" into Q-register q . . . 81 + n:^Uq Append ASCII char "n" to Q-register q . . 81 + ^V Enable lower case conversion . . . . . . . 121 + ^Vx (String char) Force x to lower case . . . 76 + ^W Enable upper case conversion . . . . . . . 121 + ^W Refresh scrolled display . . . . . . . . . 41 + ^Wx (String char) Force x to upper case . . . 76 + ^X Search mode flag . . . . . . . . . . . . . 112 + ^X (Match char) Match any character . . . . . 77 + ^Y Equivalent to ".+^S,." . . . . . . . . . . 92 + ^Z Size of text in all Q-registers . . . . . 92 + ^Z^Z^Z Immediate exit from TECO . . . . . . . . . 40 + ESC String and command terminator . . . . . . 7, 39, 99 + ESC String and command terminator . . . . . . 119 + ^[ String and command terminator . . . . . . 119 + ^\ Not a TECO command . . . . . . . . . . . . 214 + ^] Not a TECO command . . . . . . . . . . . . 214 + ^^x ASCII value of x . . . . . . . . . . . . . 92 + ^_ Ones complement (logical NOT) . . . . . . 86 + SP Ignored in commands . . . . . . . . . . . 117 + ! Define label . . . . . . . . . . . . . . . 95 + " Start conditional . . . . . . . . . . . . 101 + n"< Test for less than zero . . . . . . . . . 102 + n"= Test for equal to zero . . . . . . . . . . 102 + n"> Test for greater than zero . . . . . . . . 102 + n"A Test for alphabetic . . . . . . . . . . . 101 + n"C Test for symbol constituent . . . . . . . 101 + n"D Test for numeric . . . . . . . . . . . . . 102 + n"E Test for equal to zero . . . . . . . . . . 102 + n"F Test for false . . . . . . . . . . . . . . 102 + n"G Test for greater than zero . . . . . . . . 102 + n"L Test for less than zero . . . . . . . . . 102 + n"N Test for not equal to zero . . . . . . . . 102 + n"R Test for alphanumeric . . . . . . . . . . 102 + n"S Test for successful . . . . . . . . . . . 102 + n"T Test for true . . . . . . . . . . . . . . 102 + n"U Test for unsuccessful . . . . . . . . . . 102 + n"V Test for lower case . . . . . . . . . . . 102 + n"W Test for upper case . . . . . . . . . . . 102 + # Logical OR . . . . . . . . . . . . . . . . 86 + $ Separate TECO commands . . . . . . . . . . 120 + $ ESCape (no surrogate) typeout . . . . . . 3 + n%q Add n to Q-register q and return resu . . 80 + & Logical AND . . . . . . . . . . . . . . . 86 + ' End conditional . . . . . . . . . . . . . 101 + + Standard TECO PAGE 216 + Index + + + ( Expression grouping . . . . . . . . . . . 86 + ) Expression grouping . . . . . . . . . . . 86 + * Multiplication . . . . . . . . . . . . . . 86 + *q Save last command in Q-register q . . . . 42 + + Addition . . . . . . . . . . . . . . . . . 86 + , Argument separator . . . . . . . . . . . . 86 + - Subtraction or negation . . . . . . . . . 86 + . Current pointer position . . . . . . . . . 89 + / Division . . . . . . . . . . . . . . . . . 86 + / Type detailed explanation of error . . . . 41 + 0-9 Digit . . . . . . . . . . . . . . . . . . 214 + : Modify next command . . . . . . . . . . . 33 + ; Exit iteration on search failure . . . . . 97 + n; Exit iteration if n is positive . . . . . 97 + :; Exit iteration on search success . . . . . 97 + n:; Exit iteration if n is negative . . . . . 97 + n< Iterate n times . . . . . . . . . . . . . 94 + = Type in decimal . . . . . . . . . . . . . 87 + == Type in octal . . . . . . . . . . . . . . 87 + === Type in hexadecimal . . . . . . . . . . . 87 + := Type in decimal, no carriage return . . . 87 + :== Type in octal, no carriage return . . . . 87 + :=== Type in hexadecimal, no carriage retu . . 87 + > End iteration . . . . . . . . . . . . . . 94 + ? Toggle trace mode . . . . . . . . . . . . 119 + ? Type out command string in error . . . . . 41 + @ Modify next text argument . . . . . . . . 33 + A Append to buffer . . . . . . . . . . . . . 58 + nA ASCII value of char in buffer . . . . . . 89 + n:A Append n lines to buffer . . . . . . . . . 58 + B 0 - beginning of buffer . . . . . . . . . 89 + nC Advance n characters . . . . . . . . . . . 61 + nD Delete n characters . . . . . . . . . . . 66 + m,nD Delete between m and n . . . . . . . . . . 66 + DELIM Character typed as surrogate for ESCa . . 2, 7, 30, 39, 107, 111 + DELIM Advance and type one line . . . . . . . . 17, 41 + E%q Write Q-register q into a file . . . . . . 57 + EA Select secondary output stream . . . . . . 54 + EB Open input and output . . . . . . . . . . 49 + EC Close out (copy in to out and close) . . . 52 + ED Edit mode flag . . . . . . . . . . . . . . 105 + EE ESCape surrogate character . . . . . . . . 107 + EF Close output file . . . . . . . . . . . . 52 + EG Close out and exit with command . . . . . 52 + :EG Execute operating system function . . . . 52, 148, 149 + EH Help level flag . . . . . . . . . . . . . 107 + EI Open indirect command file . . . . . . . . 54 + m,nEJ Set environment characteristics . . . . . 104 + nEJ Return environment characteristics . . . . 103 + EK Kill output file . . . . . . . . . . . . . 53 + EL Open log file . . . . . . . . . . . . . . 53 + nEM Position magtape . . . . . . . . . . . . . 150 + EN Wildcard lookup . . . . . . . . . . . . . 56 + + Standard TECO PAGE 217 + Index + + + EO Version of TECO . . . . . . . . . . . . . 93 + nEO Set TECO to function as version n . . . . 108 + EP Select secondary input stream . . . . . . 54 + EQq Read file into Q-register q . . . . . . . 56 + ER Open input file . . . . . . . . . . . . . 49, 54 + ES Search verification flag . . . . . . . . . 108 + ET Type out control flag . . . . . . . . . . 109 + EU Case flagging flag . . . . . . . . . . . . 112 + EV Edit verify flag . . . . . . . . . . . . . 112 + EW Open output file . . . . . . . . . . . . . 50, 54 + EX Close out and exit . . . . . . . . . . . . 53 + EY Read without yank protection . . . . . . . 60 + EZ Zero output tape . . . . . . . . . . . . . 53 + nE_ Search without yank protection . . . . . . 72 + F' Flow to end of conditional . . . . . . . . 98 + F< Flow to start of iteration . . . . . . . . 98 + F> Flow to end of iteration . . . . . . . . . 98 + F| Flow to ELSE part of conditional . . . . . 99 + m,nFB Search between locations m and n . . . . . 73 + nFB Search, bounded by n lines . . . . . . . . 73 + m,nFC Search and replace between m and n . . . . 74 + nFC Search and replace over n lines . . . . . 74 + nFD Search and delete string . . . . . . . . . 66, 74 + nFK Search and delete intervening text . . . . 67, 74 + nFN Global string replace . . . . . . . . . . 73 + FR Replace last string . . . . . . . . . . . 69 + nFS Local string replace . . . . . . . . . . . 73 + nF_ Destructive search and replace . . . . . . 74 + Gq Get string from Q-register q into buf . . 83 + G* Get last filespec string into buffer . . . 145 + :Gq Type Q-register q on terminal . . . . . . 83 + G_ Get last search string into buffer . . . . 146 + H Equivalent to "B,Z" . . . . . . . . . . . 89 + I Insert text . . . . . . . . . . . . . . . 68 + nI Insert ASCII character "n" . . . . . . . . 68 + nJ Move pointer to "n" . . . . . . . . . . . 61 + nK Kill n lines . . . . . . . . . . . . . . . 66 + m,nK Delete between m and n . . . . . . . . . . 67 + nL Advance n lines . . . . . . . . . . . . . 62 + Mq Execute string in Q-register q . . . . . . 84, 90 + nN Global search . . . . . . . . . . . . . . 72 + O Go to label . . . . . . . . . . . . . . . 95 + nO Computed goto . . . . . . . . . . . . . . 96 + nP Advance or back up n pages . . . . . . . . 59 + m,nP Write out chars m to n . . . . . . . . . . 59 + nPW Write buffer n times . . . . . . . . . . . 59 + m,nPW Write out chars m to n . . . . . . . . . . 59 + Qq Number in Q-register q . . . . . . . . . . 83, 90 + :Qq Size of text in Q-register q . . . . . . . 83, 90 + nR Back up n characters . . . . . . . . . . . 62 + nS Local search . . . . . . . . . . . . . . . 71 + m,nS Search for nth occurrence within m ch . . 145 + ::S Compare string . . . . . . . . . . . . . . 73 + + Standard TECO PAGE 218 + Index + + + SEEALL "View All" characters display mode . . . . 29 + nT Type n lines . . . . . . . . . . . . . . . 63 + m,nT Type from m to n . . . . . . . . . . . . . 63 + nUq Put number n into Q-register q . . . . . . 80 + nV Type n current lines . . . . . . . . . . . 63 + m,nV Type m before & n after current line . . . 64 + W Scope "WATCH" . . . . . . . . . . . . . . 113 + n:W Return scope characteristics . . . . . . . 114, 146 + m,n:W Set scope characteristics . . . . . . . . 115 + nXq Put n lines into Q-register q . . . . . . 81 + m,nXq Put characters m to n into Q-register . . 81 + n:Xq Append n lines to Q-register q . . . . . . 82 + m,n:Xq Append characters m to n into Q-regis . . 82 + Y Read into buffer . . . . . . . . . . . . . 59 + Z End of buffer value . . . . . . . . . . . 89 + [q Q-register push . . . . . . . . . . . . . 83 + \ Value of digit string in buffer . . . . . 88, 90 + n\ Convert n to digits in buffer . . . . . . 88 + ]q Q-register pop . . . . . . . . . . . . . . 82 + n_ Global search without output . . . . . . . 72 + ` ESCape surrogate typeout . . . . . . . . . 3, 30, 39, 107, 111 + a-z Treated the same as upper case A-Z . . . . 214 + { Not a TECO command . . . . . . . . . . . . 214 + | Start ELSE part of conditional . . . . . . 101 + } Not a TECO command . . . . . . . . . . . . 214 + ~ Not a TECO command . . . . . . . . . . . . 214 + DEL Delete last character typed in . . . . . . 39 + diff --git a/doc/wchart.txt b/doc/wchart.txt new file mode 100644 index 0000000..23631f3 --- /dev/null +++ b/doc/wchart.txt @@ -0,0 +1,212 @@ +NULL ignored +^A output message to terminal +^B current date +^C interrupt +^D set radix to decimal +^E form feed flag +^E (match char) match ASCII code n +^E[] (match char) match one of list +^EA (match char) match alphabetics +^EB (match char) match separator character +^EC (match char) match symbol constituent +^ED (match char) match digit +^EGq (match char) match contents of q-register +^EL (match char) match line terminators +^EMx (match char) match any number of x +^EQq (string build char) use contents of q-register q +^ER (match char) match alphanumerics +^ES (match char) match spaces and/or tabs +^EUq (string build char) use ASCII code in q-register +^EV (match char) match lowercase +^EW (match char) match uppercase +^EX (match char) match anything +^F not implemented +^G^G kill command string +^G retype current command line +^G* retype entire current command line +^H current time +BS immediate mode: back up one line and type one line +TAB insert tab and text +LF ignored in commands +LF immediate mode: advance one line and type one line +VT not a TECO command +FF output a form feed to terminal +CR ignored +^N end of file flag +^Nx (match char) match any character but x +^O set radix to octal +^P not a TECO command +n^Q convert line offset to character offset +^Qx (string char) use x literally +^R value of current radix +n^R set radix to n +^Rx (string char) use x literally +^S -(length of last inserted string or found search string) +^S immediate mode: not yet implemented +^S (match char) match any separator character +^T ASCII value of next character typed in +n^T output character whose ASCII value is n to the terminal screen +^U (command line) erase current command line +^Uq put string into q-register +:^Uq append string to q-register +n^Uq put ASCII character "n" into q-register +n:^Uq append ASCII "n" to q-register +^V convert search strings to lowercase +^Vx (string char) convert x to lowercase +^W convert search strings to uppercase +^Wx (string char) convert x to uppercase +^X search mode flag +^X (match char) match any character +^Y equivalent to ".+^S,." +^Z size of text in all q-registers, plus command line +^Z^Z^Z quit TECO, leave everything as it was before TECO was entered +ESC command and string terminator +^[ like ESC +^\ not a TECO command +^] not a TECO command +^^x ASCII value of x +n^_ ones complement of n +SP ignored +! define tag +n"< test for less than zero +n"= test for equal to zero +n"> test for greater than zero +n"A test for alphabetic +n"C test for symbol constituent +n"D test for digit +n"E test for equal to zero +n"F test for false +n"G test for greater than zero +n"L test for less than zero +n"N test for not equal to zero +n"R test for alphanumeric +n"S test for successful +n"T test for true +n"U test for unsuccessful +n"V test for lowercase +n"W test for uppercase +# logical OR +$ separate TECO commands +n%q add n to q-register q, return the result +& logical AND +' end of conditional +( numeric expression grouping +) numeric expression grouping +* multiplication +*q immediate mode: save last command string in q-register q ++ addition +, numeric argument separator +- subtraction or negation +. current pointer position +/ division +/ immediate mode: type detailed explanation of error +0-9 numeric argument constructors +: modify next command +n; exit iteration of n is greater than or equal to zero +n:; exit iteration if n is less than or equal to zero +n< iterate n times +n= type n in decimal +n== type n in octal +n=== type n in hexadecimal +n:= type n in decimal, no carriage return +n:== type n in octal, no carriage return +n:=== type n in hexadecimal, no carriage return +> end iteration +? toggle trace mode +? immediate mode: type out erroneous command string +@ modify next text argument +A append next input page to edit buffer +nA ASCII value of character at .+n +n:A append n lines to input buffer +B always zero. represents beginning of edit buffer +nC advance n characters +nD delete n characters +m,nD delete between m and n (same as m,nK) +E%q write q-register to file +nE_ destructive search without page protection +EA select secondary output stream +EB open input and output files +EC copy input file to output file and close files +nEC not yet implemented +ED edit mode flag +EF close output file +EH help level flag +EI open indirect command file +EK kill output file +EL open log file +EN wildcard lookup +EO return version number of TECO +EP select secondary input stream +EQq read from file into q-register +ER open input file +ES search verification flag +ET type out control flag +EU case flagging flag +EV edit verify flag +EW open output file +EX close files and exit +EY read without yank protection +nF_ destructive search and replace +F' flow to end of conditional +F< flow to start of iteration +F> flow to end of iteration +F| flow to ELSE part of conditional +m,nFB search between locations m and n +nFB search, bounded by n lines +m,nFC search and replace between m and n +nFC search and replace over n lines +nFD search for and delete string +nFK search for string and delete intervening text +nFN paged search and replace +FR replace last string +nFS search and replace +Gq get string from q-register into edit buffer +G* get string from filespec buffer into edit buffer +G_ get string from search buffer into edit buffer +:Gq type text in q-register q +:G* type filespec +:G_ type search string +H equivalent to B,Z +I insert text +nI insert character whose ASCII value is n +nJ move pointer to J +nK kill n lines +m,nK delete between m and n (same as m,nD) +nL advance n lines +Mq execute commands in q-register +nN paged search +O go to label +nO goto selected label in list +nP advance n pages +m,nP write out characters m to n +nPW write edit buffer n times +m,nPW write out characters m to n +Qq number in q-register q +:Qq size of text in q-register q +nR back up n characters +nS search for nth occurrence of a string +::S compare string +nT type n lines +m,nT type characters between m and n +nUq put n into q-register q +nV view n lines +m,nV view m lines before, n lines after pointer +W not yet implemented +nXq put n lines into q-register q +m,nXq put character m through n into q-register q +n:Xq append n lines to q-register q +m,n:Xq append characters m through n to q-register q +Y yank a page into the edit buffer +Z end of buffer (number of characters in the edit buffer) +[q push q-register q onto q-register stack +\ value of string in edit buffer +n\ convert n to digits in edit buffer +]q pop q-register stack into q-register q +n_ destructive paged search +` not a TECO command +a-z treated as uppercase equivalents +{ not a TECO command +| start of ELSE part of conditional +} not a TECO command +~ not a TECO command +DEL not a TECO command diff --git a/lib/change.tec b/lib/change.tec new file mode 100644 index 0000000..d4f839b --- /dev/null +++ b/lib/change.tec @@ -0,0 +1 @@ +ED#2EDFilename(s): ^UBenEI<UAQA-127"E8328HKGBB,Z-1XBHK|QA-27"E13101;|QA-13"E0,32ET32,0ET1;|QA:^UB'''>27:^UB27:^UBMB@^UB\0UX27:^UBNew string to replace search string: UAQA-27"E1UE|0UEON2'<UA!N2!QA-127"E8328HKGBB,Z-1XBHK|QA-27"E13101;|QA-13"EQE"E0,32ET32,0ET1;|QA:^UB:^UB'|QA:^UB'''>@:^UB\"SQW"E1UX1310:G*1310101UW'V1UZ|1;'>QZ"NEC|EK'|1;'>QX"ENo matches.'ex\27:^UBMB diff --git a/lib/change.tes b/lib/change.tes new file mode 100644 index 0000000..8fa5c63 --- /dev/null +++ b/lib/change.tes @@ -0,0 +1,237 @@ +! This TECO macro written by Pete Siemsen of Midcom (Orange, Ca.) to ! +! run under VAX/VMS V2.3 running TECO V36, 9-Mar-1982 ! +! ! +! This TECO macro changes one string to another in a set of files. It prompts! +! the user for a file specification (wildcards ok) and two strings: the old ! +! one and the new one. It then goes through the file(s), making the change. ! +! It is designed to be a convenient tool for users who are familiar with ! +! the SEARCH program on most VAXes. CHANGE prompts for input and displays its! +! output very like the SEARCH program. Note that the strings prompted for by ! +! this macro can be delimited: if the first character of the string is an ! +! , then only an will terminate the string, else both and ! +! will terminate the string. ! +! ! +! The general way this macro works is to build a hideous TECO command string ! +! in q-register B, then execute the command string. We need to build the ! +! string because we have to create an FN command, at least, to make the ! +! changes. ! +! ! +! The following Q-registers are used: ! +! ! +! QA number ascii value of text character from the terminal ! +! ! +! QW number 0 if we haven't output the file specification of ! +! the file in which the string was found, 1 if we ! +! already have. This guy lets us output file specs ! +! only for those files which contain the string ! +! ! +! QX number 0 if no changes have been made, else > 0 ! +! This is only used to tell us if we should output ! +! the "No matches." string when we're done. ! +! ! +! QZ number 0 if we haven't changed a string in the file, 1 if ! +! we have. This guy tells us whether to close and kill ! +! the output file (when no changes were made in the ! +! file) or to close the output file normally (when ! +! changes have been made). ! +! ! +! QB text This is the biggee. It holds the TECO command string ! +! we are building. It is used twice, once to build and ! +! execute the EN command that presets the TECO ! +! wildcard lookup buffer, and once to build and ! +! execute the command string that does all the work. ! +! We could build just one string and execute it, but ! +! then the user wouldn't know that he's misspelled his ! +! file specification until after he's typed in the ! +! old and new strings. ! +! ! +! QE text holds an EB command so we can execute it ! + +ED#2ED ! make Y command work like it should ! + +Filename(s):  ! prompt for a file specification ! + +! read the wildcard file specification from the terminal and use it ! +! in a TECO EN command to preset the wildcard lookup file specification ! + +@^UB%en% ! put EN in q-register B ! + +! Do an EI$ to throw away extraneous input in the type-ahead buffer. See ! +! page 117-118 of the PDP-11 TECO User's Guide for an explanation of why ! +! this is necessary. ! + +EI +< + UA ! get a character from the terminal ! + QA-127"E ! if it's a delete ! + 8 ! send a backspace to the terminal ! + 32 ! send a space to the terminal ! + 8 ! send a backspace to the terminal ! + HK ! clear the edit buffer ! + GB ! get contents of q-register B ! + B,Z-1XB ! copy back all but last character ! + HK ! clear the edit buffer ! + | ! else (it's not a delete) ! + QA-27"E ! if it's an escape ! + 1310 ! output ! + 1; ! get out of the loop ! + | ! else (it's not a delete or escape) ! + QA-13"E ! if it's a ! + 0,32ET ! set "read with no wait" ! +  ! get the line feed that follows ! + 0,32ET ! set "read with wait" ! + 1; ! and get out of the loop ! + | ! else (not , , or ) ! + QA:^UB ! append it to q-register B ! + ' ! endif ! + ' ! endif ! + ' ! endif ! +> +27:^UB ! append an escape to q-register B ! +27:^UB ! append an escape to q-register B ! +MB ! execute the command in q-register B ! + +! The unsquished code inserted in Q-register B does the following: ! +! 0UX zero the 'strings changed' flag ! +! < loop through all files ! +! HK clear the edit buffer ! +! :EN^["S try to get a file specification ! +! IEB^[ start building an EB command ! +! G* fill in the file specification ! +! 27I^[ put in the first terminating ! +! 27I^[ put in the second terminating ! +! HXE load the EB command into q-reg E ! +! ME the EB command opens the file ! +! Y get the first page of input ! +! 0UW zero the 'display filespec?' flag ! +! 0UZ zero the 'save output file?' flag ! +! < loop for all changes in this file ! +! :FN make the actual change ! + +@^UB%0UX < HK :EN"S IEB G* 27I 27I HXE ME Y 0UW 0UZ < :FN% + +Search string:  ! prompt for the search string ! + +UA +QA-27"E ! if it's an ! + 1UE ! set 'escape terminator only' flag ! + | ! else (first character not ) ! + 0UE ! clear 'escape terminator only' flag ! + ON1 ! jump into the loop ! + ' ! endif ! + +< + UA ! get a character from the terminal ! + !N1! + QA-127"E ! if it's a delete ! + 8 ! send a backspace to the terminal ! + 32 ! send a space to the terminal ! + 8 ! send a backspace to the terminal ! + HK ! clear the edit buffer ! + GB ! get contents of q-register B ! + B,Z-1XB ! copy back all but last character ! + HK ! clear the edit buffer ! + | ! else (it's not a delete) ! + QA-27"E ! if it's an escape ! + 1310 ! output ! + 1; ! get out of the loop ! + | ! else (it's not a delete or escape) ! + QA-13"E ! if it's a ! + QE"E ! if carriage returns terminate ! + 0,32ET ! set "read with no wait" ! +  ! get the line feed that follows ! + 0,32ET ! set "read with wait" ! + 1; ! and get out of the loop ! +| +QA:^UB +:^UB +' + | ! else (not , , or ) ! + QA:^UB ! append it to q-register B ! + ' ! endif ! + ' ! endif ! + ' ! endif ! +> +27:^UB +New string to replace search string:  +UA +QA-27"E ! if it's an ! + 1UE ! set 'escape terminator only' flag ! + | ! else (first character not ) ! + 0UE ! clear 'escape terminator only' flag ! + ON2 ! jump into the loop ! + ' ! endif ! + +< + UA ! get a character from the terminal ! + !N2! + QA-127"E ! if it's a delete ! + 8 ! send a backspace to the terminal ! + 32 ! send a space to the terminal ! + 8 ! send a backspace to the terminal ! + HK ! clear the edit buffer ! + GB ! get contents of q-register B ! + B,Z-1XB ! copy back all but last character ! + HK ! clear the edit buffer ! + | ! else (it's not a delete) ! + QA-27"E ! if it's an escape ! + 1310 ! output ! + 1; ! get out of the loop ! + | ! else (it's not a delete or escape) ! + QA-13"E ! if it's a ! + QE"E ! if carriage returns terminate ! + 0,32ET ! set "read with no wait" ! +  ! get the line feed that follows ! + 0,32ET ! set "read with wait" ! + 1; ! and get out of the loop ! +| +QA:^UB +:^UB +' + | ! else (not , , or ) ! + QA:^UB ! append it to q-register B ! + ' ! endif ! + ' ! endif ! + ' ! endif ! +> + +! The unsquished code appended to Q-register B does the following ! +! ^[ terminate the :FN command ! +! "S if a string was found ! +! QW"E if haven't displayed file spec yet ! +! 1UX^[ make the 'any found?' flag true ! +! 13^T display a ! +! 10^T display a ! +! :G* display the file specification ! +! 13^T display a ! +! 10^T display a ! +! 10^T display a ! +! 1UW make 'display filespec?' flag false ! +! ' endif ! +! V view the changed line ! +! 1UZ make the 'any found?' flag true ! +! | else (search string not in file) ! +! 1; terminate this loop ! +! ' endif ! +! > end of loop over the file ! +! QZ"N if a string was found in this file ! +! EC close and save the output file ! +! | else (search string not in file) ! +! EK close and delete the output file ! +! ' endif ! +! | else (no more files) ! +! 1; terminate this loop ! +! ' endif ! +! > end of loop over all files ! +! QX"E if didn't match the search string ! +! ^ANo matches.^A tell the user ! +! ' endif ! +! ex^[ and we are finally done ! + +@:^UB%  "S QW"E 1UX 13 10 :G* 13 10 10 1UW ' V 1UZ | 1; ' > + QZ"N EC | EK ' | 1; ' > QX"E No matches. ' ex % + +27:^UB + +MB + diff --git a/lib/checkqr.tec b/lib/checkqr.tec new file mode 100644 index 0000000..407117b --- /dev/null +++ b/lib/checkqr.tec @@ -0,0 +1,36 @@ +Q Register A qA:= :qA=Q Register .A q.A:= :q.A=^T +Q Register B qB:= :qB=Q Register .B q.B:= :q.B=^T +Q Register C qC:= :qC=Q Register .C q.C:= :q.C=^T +Q Register D qD:= :qD=Q Register .D q.D:= :q.D=^T +Q Register E qE:= :qE=Q Register .E q.E:= :q.E=^T +Q Register F qF:= :qF=Q Register .F q.F:= :q.F=^T +Q Register G qG:= :qG=Q Register .G q.G:= :q.G=^T +Q Register H qH:= :qH=Q Register .H q.H:= :q.H=^T +Q Register I qI:= :qI=Q Register .I q.I:= :q.I=^T +Q Register J qJ:= :qJ=Q Register .J q.J:= :q.J=^T +Q Register K qK:= :qK=Q Register .K q.K:= :q.K=^T +Q Register L qL:= :qL=Q Register .L q.L:= :q.L=^T +Q Register M qM:= :qM=Q Register .M q.M:= :q.M=^T +Q Register N qN:= :qN=Q Register .N q.N:= :q.N=^T +Q Register O qO:= :qO=Q Register .O q.O:= :q.O=^T +Q Register P qP:= :qP=Q Register .P q.P:= :q.P=^T +Q Register Q qQ:= :qQ=Q Register .Q q.Q:= :q.Q=^T +Q Register R qR:= :qR=Q Register .R q.R:= :q.R=^T +Q Register S qS:= :qS=Q Register .S q.S:= :q.S=^T +Q Register T qT:= :qT=Q Register .T q.T:= :q.T=^T +Q Register U qU:= :qU=Q Register .U q.U:= :q.U=^T +Q Register V qV:= :qV=Q Register .V q.V:= :q.V=^T +Q Register W qW:= :qW=Q Register .W q.W:= :q.W=^T +Q Register X qX:= :qX=Q Register .X q.X:= :q.X=^T +Q Register Y qY:= :qY=Q Register .Y q.Y:= :q.Y=^T +Q Register Z qZ:= :qZ=Q Register .Z q.Z:= :q.Z=^T +Q Register 0 q0:= :q0=Q Register .0 q.0:= :q.0=^T +Q Register 1 q1:= :q1=Q Register .1 q.1:= :q.1=^T +Q Register 2 q2:= :q2=Q Register .2 q.2:= :q.2=^T +Q Register 3 q3:= :q3=Q Register .3 q.3:= :q.3=^T +Q Register 4 q4:= :q4=Q Register .4 q.4:= :q.4=^T +Q Register 5 q5:= :q5=Q Register .5 q.5:= :q.5=^T +Q Register 6 q6:= :q6=Q Register .6 q.6:= :q.6=^T +Q Register 7 q7:= :q7=Q Register .7 q.7:= :q.7=^T +Q Register 8 q8:= :q8=Q Register .8 q.8:= :q.8=^T +Q Register 9 q9:= :q9=Q Register .9 q.9:= :q.9=^T diff --git a/lib/date.tec b/lib/date.tec new file mode 100644 index 0000000..d04227b --- /dev/null +++ b/lib/date.tec @@ -0,0 +1,8 @@ +!DATE.TES!EI[D[Y[W[H[M[S[0[1U0(Q0/32)&15UM(Q0)&31UD(Q0/512)UYQDUW +QM-2"=31%W'QM-3"=59%W'QM-4"=90%W'QM-5"=120%W'QM-6"=151%W'QM-7"=181%W' +QM-8"=212%W'QM-9"=243%W'QM-10"=273%W'QM-11"=304%W'QM-12"=334%W'QY&3"= +QW-59">1%W''QY+QW+(QY-1/4)U1Q1-(Q1/7*7)U1Q1"=WSUN'Q1-1"=WMON' +Q1-2"=WTUE'Q1-3"=WWED'Q1-4"=WTHU'Q1-5"=WFRI'Q1-6"=WSAT'*2U0 +Q0/3600UHQH*3600U1(Q0-Q1)/60UN(Q0-Q1)-(QN*60)US:GW32QM-10"<48'QM:= +47QD-10"<48'QD:=471900+QY:=32QH-10"<48'QH:=58QN-10"<48'QN:=58 +QS-10"<48'QS=]1]0]S]M]H]W]Y]D]M diff --git a/lib/date.tes b/lib/date.tes new file mode 100644 index 0000000..f840dee --- /dev/null +++ b/lib/date.tes @@ -0,0 +1,96 @@ +!DATE.TEC! +! display the current date and time: ! +! ^B == ((year-1900)*16+month)*32+day ! +! ^H == (seconds since midnight)/2 ! + +ei + +[M[D[Y[W[H[M[S[0[1 ! save used Q-reg's ! + + ! Get MM/DD/YYYY in Q-reg's M,D,Y ! +^B U0 ! 0.num = encoded date ! +(Q0/32) & 15 UM ! M.num = month ! +(Q0) & 31 UD ! D.num = day ! +(Q0/512) UY ! Y.num = year ! + + ! Get day of week in Q-reg W ! +QD UW ! W.num = days this month ! +QM-2 "= 31%W | ! add days before this month ! +QM-3 "= 59%W | +QM-4 "= 90%W | +QM-5 "= 120%W | +QM-6 "= 151%W | +QM-7 "= 181%W | +QM-8 "= 212%W | +QM-9 "= 243%W | +QM-10 "= 273%W | +QM-11 "= 304%W | +QM-12 "= 334%W ''''''''''' +QY & 3 "= ! correct for leap years ! + QW-59 "> + 1%W + ' +' +QY+QW+(QY-1/4) U1 +Q1-(Q1/7*7) U1 +Q1-0"= @^UW%Sunday% | +Q1-1"= @^UW%Monday% | +Q1-2"= @^UW%Tuesday% | +Q1-3"= @^UW%Wednesday% | +Q1-4"= @^UW%Thursday% | +Q1-5"= @^UW%Friday% | +Q1-6"= @^UW%Saturday% ''''''' + + +QM-1"= @^UM%January% | ! get name of month in Q-reg M ! +QM-2"= @^UM%February% | +QM-3"= @^UM%March% | +QM-4"= @^UM%April% | +QM-5"= @^UM%May% | +QM-6"= @^UM%June% | +QM-7"= @^UM%July% | +QM-8"= @^UM%August% | +QM-9"= @^UM%September% | +QM-10"= @^UM%October% | +QM-11"= @^UM%November% | +QM-12"= @^UM%December% '''''''''''' + + ! Get HH:MM:SS in Q-reg's H,N,S ! +^H*2 U0 ! 0.num = second's since midnight ! +Q0/3600 UH ! H.num = hours ! +QH*3600 U1 ! 1.num = hours (in seconds) ! +(Q0-Q1)/60 UN ! N.num = minutes ! +(Q0-Q1)-(QN*60) US ! S.num = seconds ! + + ! Display DAY MM/DD/YYYY ! +:GW ! display DAY ! +32 ! display ! + +:GM ! display MONTH ! +32 ! display ! + +! QM-10"< 48^T ' display leading zero? ! +! QM:= display MM ! +! 47^T display / ! + +QD-10"< 48^T ' ! display leading zero? ! +QD:= ! display DD ! +! 47^T display / ! +44 ! display , ! +32 ! display ! + +1900+QY := ! display YYYY ! +32 ! display ! + + ! Display HH:MM:DD ! +QH-10"< 48^T ' ! display leading zero? ! +QH:= ! display HH ! +58^T ! display : ! +QN-10"< 48^T ' ! display leading zero? ! +QN:= ! display MM ! +58^T ! display : ! +QS-10"< 48^T ' ! display leading zero? ! +QS= ! display SS ! + +]1]0]S]M]H]W]Y]D]M ! restore used Q-reg's ! + diff --git a/lib/detab.tec b/lib/detab.tec new file mode 100644 index 0000000..af607e4 --- /dev/null +++ b/lib/detab.tec @@ -0,0 +1,8 @@ + +******************************************************** + This macro will read the file and transform all +characters into the appropriate number of chars. +Note that tab stops are assumed to be at every 8 spaces. +******************************************************** +FEBH:XF27:FHKMFY<:N "U1;'.UB0L.UAQB-QAUC9-QCUD +S -DQD>EX diff --git a/lib/detab.tes b/lib/detab.tes new file mode 100644 index 0000000..2631a55 --- /dev/null +++ b/lib/detab.tes @@ -0,0 +1,44 @@ +! Author: John Guidi, sped up by Pete Siemsen + Date: 20-July-79 + + Useage: MUNG DETAB filespec + + Abstract: All tabs in the file specified will be replaced with + spaces. Tab stops are assumed to be at every 8 spaces. +! + + +******************************************************** + This macro will read the file and transform all +characters into the appropriate number of chars. +Note that tab stops are assumed to be at every 8 spaces. +******************************************************** + + +@^UF%EB% ! set F up with EB command ! +H:XF ! append filespec to F ! +27@:^UF%% ! append to F ! + +HK ! clear text buffer ! +MF ! execute F to open input and output files ! +Y ! pull first page into text buffer ! + +< + :@N/ /"U1;' ! search for a tab, leave loop when unsuccessful ! + .UB ! put current pointer in B ! + 0L .UA ! put pointer to begining of line in A ! + QB-QAUC ! put how many characters up to TAB in C ! + < ! subtract 8 until QC is less than 9 ! + QC-9"L + 1; + ' + -8%C + > + 9-QCUD ! put number of spaces into D ! + @S/ /-D ! find the tab again and delete it ! + QD< ! insert the spaces ! + @I/ / + > +> +EX ! close files ! + diff --git a/lib/dir.tec b/lib/dir.tec new file mode 100644 index 0000000..c6a242e --- /dev/null +++ b/lib/dir.tec @@ -0,0 +1,3 @@ +!dir.tes-display directory![0[1[2.U0ZJ.U10U21*.*Q1"N80-Q1"G0,Q1X1'' +EN^eq1Q1J<:EN;G*(1%2)-5"E13I10I0U2|15+<32I>'>Q1,ZTQ1,ZKQ0J]2]1]0 + diff --git a/lib/dir.tes b/lib/dir.tes new file mode 100644 index 0000000..777528c --- /dev/null +++ b/lib/dir.tes @@ -0,0 +1,32 @@ +!dir.tes-display directory! +[0 [1 [2 ! save Q-regs 0-2 ! +.u0 ! remember where we are ! +zj ! jump to end of buffer ! +.u1 ! remember old end of buffer ! +0u2 ! zero column count ! +@^u1%*.*% ! default is get dir of everything ! +q1"n ! is buffer not empty? ! + 80-q1"g ! is buffer length < maxpath? ! + 0,q1x1 ! assume edit buf = filespec ! + ' ! endif ! +' ! endif ! +en^eq1 ! preset wildcard lookup ! +q1j ! jump to end of buffer ! +< ! ! + 10@i%% ! insert ! + 0u2 ! reset column count ! + | ! else ! + 15+^S< ! ! + > ! > ! + ' ! endif ! +> ! > ! +q1,zt ! display what we built ! +q1,zk ! kill what we built ! +q0j ! jump to where we were ! +]2 ]1 ]0 ! restore Q-regs 0-2 ! + diff --git a/lib/lowcase.tec b/lib/lowcase.tec new file mode 100644 index 0000000..1b9dd0e --- /dev/null +++ b/lib/lowcase.tec @@ -0,0 +1,3 @@ +@^ul/<0a-13"e1;'0a"w0a+32id|c'>v/ + q - register L loaded + diff --git a/lib/makprnt.tec b/lib/makprnt.tec new file mode 100644 index 0000000..5f31f81 --- /dev/null +++ b/lib/makprnt.tec @@ -0,0 +1,6 @@ +This TECO macro makes a TECO command string printable by converting +escape characters to dollar signs and all control characters to the +tilde-character string which is usually printed on the terminal, except +for ^I (tab), ^M (cr), ^L (ff), and ^J (lf). + diff --git a/lib/makprnt.tes b/lib/makprnt.tes new file mode 100644 index 0000000..da1b94e --- /dev/null +++ b/lib/makprnt.tes @@ -0,0 +1,16 @@ +This TECO macro makes a TECO command string printable by converting +escape characters to dollar signs and all control characters to the +tilde-character string which is usually printed on the terminal, except +for ^I (tab), ^M (cr), ^L (ff), and ^J (lf). + +< +z-."e1;' ! if at end of buffer, exit the loop ! +0a-31"gcf<' ! it it's already printable, skip it ! +0a-27"ei$df<' ! if it's ESCAPE, make it into a dollar-sign ! +0a-13"ecf<' ! if it's carriage return, skip it ! +0a-10"ecf<' ! if it's line feed, skip it ! +0a-9"ecf<' ! if it's TAB, skip it ! +0a-12"ecf<' ! if it's form feed, skip it ! +i^0a+64id +> + diff --git a/lib/squ.tec b/lib/squ.tec new file mode 100644 index 0000000..7a0e0ad --- /dev/null +++ b/lib/squ.tec @@ -0,0 +1,80 @@ +!SQU.TEC V40.00!@F0ED0ET&128"N0,0XP'0,128ETJ<@FS%^ES%%;>J:S/UB +QB"TET&64"E +''@R\[0[1[2[3+0U3X0K.U1ZJ.U2Q3&127"R| +?Invalid Q-register in INPLIN +OEXIT'IQ2,.XQ3&127IQ2,.X1Q2,.K!PROMPT!13ET&512"N0,1ET271,0ET +0:W-4"E['J|10'.-Q2+(0)"G0T|:G0Q2,ZT'!GETCH!U0Q0-127"EZ-Q2"N-D' +OPROMPT'Q0-21"EQ2,ZKOPROMPT'Q0-18"E1310:G0Q2,ZTOGETCH'Q0-26"E +Q2,ZK%0'Q0-27"E1310ODONE'Q3&128"EQ0-10"E13ODONE'Q0-13"EODONE' +'Q0IOGETCH!DONE!M1Q2,.K!EXIT!Q1J]3]2]1]0\0,0X9J:@FS%/D%%"S +::@FS%:%%"S0AQD|QY'|QB"TQ|IDelete CR/LF (Y/N) ? QMR''0QQ"A +0QQ&95-Y"E9DA.......TD..D.......U....Z...V.D''!BADNUM!0UO:Q9"NJ +:@FS%/L%%"S%/L specified with /D, /L ignored +::@FS%:%%"S0A"D'|D'''|J:@FS%/L%%"S::@FS%:%%"S0AQ0A"D'|D'|QY'|QB"TQ| +ISet line lengths (Y for 70, N, or length) ? QMR''0QQ"A +0QQ&95-Y"E9DA.......TO..O.......U....Z...V.O70UO''0QQ"D.UQZJGQC\UO +D.-Z"NZKQQJOBADNUM'QQJQO"EOBADNUM' +9DA.......TO..O.......U....Z...V.O'':Q9"NJ:@FS%/B%%"S::@FS%:%%"S +0A-N"E%/B:N specified with /D or /L, /B:N ignored +'D''|J:@FS%/B%%"S::@FS%:%%"S0AQD|QY'|QB"TQ| +IDelete blank lines (Y/N) ? QMR''0QQ"A0QQ&95-Y"E +9DA.......TB..........U....Z...V.D''':Q9"E +9DA.......T...........U....Z...V.D'J:@FS%/T%%"S::@FS%:%%"S0AQD| +QY'|QB"TQ|IDelete lexical TABs and FORM FEEDs (Y/N) ? QMR'' +0QQ"A0QQ&95Q'0QQ-Y"EJG99JDIO12JDIOJ0,33X90,33K'CJ:@FS%/C%%"S +::@FS%:%%"S0AQD|QY'|QB"TQ| +IDelete comments (Y for SP/TAB, N, or set) ? QMR'':QQ"EQN'0QQUQ +QQ"VQQ-32UQ'QQ-N"E:9A|:9CQQ-Y"E32C9:C|GQXCK'' +:91..1..........................:9@....EF1.$...1$$.1.$.1..1..1.1^$ +:9.LLLLLLLLLLLLLLLLLLLLLLLLLL....D8/#*&\?()$!@1U8126W +ET&512"EJ:@FS%/W%%"S::@FS%:%%"SD''|J:@FS%/W%%"S::@FS%:%%"S0AQD|QY' +|QB"TQ|IWatch progress (Y/N) ? QMR''0QQ"A0QQ&95-Y"E0:W-2"E +4,0:W'W-1W'''KJ:@FS%/A%%"S::@FS%:%%"S0AQD|QY'|QB"TQY| +IAutomatic mode (Y for %, N, or set) ? QMR'':QQ"N0QQUQQQ"VQQ-32UQ +'QQ-N"NQQ-Y"E%K|GQXKK'''0UHJ:@FS%/E%%"S::@FS%:%%"S0AQD|QY'| +QB"TQ|IAllow adjacent ESCapes (Y/N) ? QMR''0QQ"A0QQ&95-Y"E-1UH +''@Z*[10U1:QW"N-1,3:W0,4:W0,5:W'QSJQT-27"EI '''Q0IODISP!B!-1+2"E-2D'O.. +!O!-D."N-1A&128"N-D'.-1"G-1A-10"E-2A-128-13"EQ0-13"E-2D|O..'''' +Q0#128IQ0-13"E.-Z"E10IR'0A&127-10"ED'10I''O..!U!271.UC0AU0C +Q0-."E0AU0C'Q0"VQ0-32U0-DQ0I'Q1"T0A-(1A)"EO$$'|0A-27"EO$$''.USQ1"T +0A1D':QW"N:S^EQ1"UOSTRINGFAIL'.,4:WQSJMW':QK"E:QW"E0T10T'7ETUQ +ET#8#4-4ETU0QQET|G1R::S^EGK"S-DNU0|DYU0'':QW"N0,4:W32768W'Q0-Y"E +[E[C[SE-1UE0A-^^0Q1:E:E"E0UE'QEMZ]S]C]E"NOPRIORFAIL'CO$$$$' +O$$$!T!0U1!$!271.UC!$$!.USQ1"T0A1D'!$$$!:S^EQ1"UOSTRINGFAIL' +!$$$$!-D.UT27U0!AA!Q00QT-QS"GQSJ.,.+QT-QS:FB^EQ0"SG8:X1K0U0< +Q0Q10QSJ.,.+QT-QSFB^EQ0;%0-:Q8"EONOQUOTE'>Q0Q1U0QSJQ0IQC-1JI@ +2%T''QTJQ0I0U1O..!1!0A-."EC'0A"V0A-32U0DQ0IO.'!V!CO.!@!-1U1!D! +-DO.!F!271.UC0AU0CQ0"VQ0-32U0-DQ0I'Q0-B"EO$$'Q0-C"EOF$$' +Q0-R"EO$$'Q0-S"EOF$$'Q0-N"EOF$$'Q0-_"EOF$$'O.!F$$!.US271 +Q1"T0A1D':S^EQ1"UOSTRINGFAIL'-D.UT:S^EQ1"UOSTRINGFAIL'-D.UUQH"T +27U0Q00QU-QS"GQSJ.,.+QU-QS:FB^EQ0"UOF0'|OF0'|QU-QT"G27U0Q00QSJ +.,.+QU-QS:FB^EQ0"UOF0'''G8:X1K0U0Q0Q1U0QSJQ0IQC-1JI@2%T2%U!F0!QTJQ0IQU-QTCQ0I +0U1O..!A!Q01.UC.USQ1"T0A1D':S^EQ1"UOSTRINGFAIL'-D.UTOAA!C! +::S^EGC"UOA'R.UCQ01Q1"T0A1D':S^EQ1"UOSTRINGFAIL'QC-1,.K0U1O.. +!E!271.UC0AU0CQ0"VQ0-32U0-DQ0I'Q0-B"EO$$'Q0-G"EO$$'Q0-I"EO$$' +Q0-N"EO$$'Q0-R"EO$$'Q0-W"EO$$'Q0-_"EO$$'O.!Z!-DI^ZO..>Q1"T +1Trailing, pending @OERROR'0U10"N!OFFEND! +1End of buffer while sub-squishingOERROR!NOQUOTE! +1Can't find a quote characterOSETPOS!PRIORFAIL! +1Prior recursion level failedOSETPOS!STRINGFAIL! +1Unterminated string!SETPOS!:1 from squished .=QC\:X1K13:1 +10:1QCJ0+.,.:X1|:110:1|:1.,+.:X1!ERROR!ZJMW0,0XW7?:G17 +1310-1U1'Q1]1*@A*-1E.-ZQO"NZJI 'JMZ"EQO"N:QW"N-1,3:W0,4:W +0,5:W'J0A&127-13"ED'D.-Z;.U0<0A&128"N0;'C><.U10L +.-Q0-1"L0;'R>Q1J-(0)-QO"GQ0J-1A-27"EI 'I +'>MW'QH"FZJ."E10I'-1A-10"N10I +'R."E13I'-1A-13"N13I''ZJ:QW"N0:W-4"E2,0:W'-1,3:W0,4:WMW'| +?Squish run failed; aborting any output +0,0XF'0*Z"EIFile <.TES or .TEC>? QMRGQ'0,0XR0,0XQEIMF0,0XFZ"E +Enter your macro then type MA$$ +|J:@FS%=%%"SFEW0,.:XF.UF-:S."U:F.TEC'QFJ27:FQB"TET&64"E:F +Creating ":G*" +''0,.K'J:S."UZJI.TESHXQ:ER^EQQ"U-FS.TES.TEC''HXQHKER^EQQQB"T +ET&64"ESquishing ":G*" +'':QF"EY128,0ET<"TZJ12I':A;>MAMP|YQB"F128,0ET'"T"TZJ12I'MAMFHPW +HK|MF<"TZJ12I'MAHPWHK:Y;>'EFEX'' diff --git a/lib/squ.tes b/lib/squ.tes new file mode 100644 index 0000000..05df340 --- /dev/null +++ b/lib/squ.tes @@ -0,0 +1,1773 @@ +!SQU.TEC V40.00! +! --------------------------------------------------------------------- ! +! ! +! TECO macro to squish other TECO macros. This macro will take a nice, ! +! readable TECO macro and squish it so that it is as small and as fast ! +! as possible (and is completely unreadable). ! +! ! +! Command line: ! +! ! +! MUNG SQU OUTFILE[.TEC]=INFILE[.TES]/SWITCHES ! +! ! +! For example: ! +! ! +! MUNG SQU SQU.TEC=SQU.TES/D:N/L:Y/B:Y/T:Y/C:Y/W:N/A:Y/E:N ! +! ! +! Switches: ! +! ! +! /D Delete lexical CR/LFs ! +! /L Set line lengths ! +! /B Delete blank lines ! +! /T Delete lexical TAB/FFs ! +! /C Delete comments ! +! /W Watch progress ! +! /A Automatic mode (ie: squish macros loaded w/^U) ! +! /E Allow adjacent ESCapes ! +! ! +! Use of Q-registers: ! +! ! +! A.str = macro to run the squish macro in Z; then, if /L is set, ! +! post-process the squished macro so each line is no longer the ! +! length set by /L:nn. ! +! ! +! B.num = TRUE if any command line switches were present. ! +! ! +! C.num = the buffer pointer while squishing things for error ! +! reporting purposes. ! +! ! +! C.str = the set of comment delimiter characters (/C:set, or ! +! for /C:Y). ! +! ! +! E.str = macro telling when to break out of squish loop. either ! +! on end of file or end of sub-squish loop ! +! ! +! F.str = SQU initialization and termination macro. ! +! ! +! H.num = TRUE (-1) if we are allowing adjacent escapes (/E:Y) ! +! ! +! K.str = the "non-squishable ^U command" character set (/A:set) ! +! If we run into a @^Qtext, and is *not* ! +! in the "non-squishable ^U command" character set, we'll assume ! +! that "text" is a macro that we have to recursively squish. ! +! ! +! O.num = the maximum line width (/L:nn, or 70 for /L) ! +! ! +! P.str = ???P is cleared if abort-on-error bit is set, and it is ! +! executed as a macro during cleanup, but I don't see where it is ! +! loaded anywhere. ! +! ! +! Q.str = used to contain responses from the user. ! +! ! +! R.str = "get-response-from-user" macro. ! +! ! +! S.num, T.num, U.num = used to store the start and end of text ! +! arguments to TECO commands like FStext1$text2$. ! +! ! +! W.str = "-1W" scope refresh command if watching progress (/W:Y) ! +! ! +! Z.str = SQU macro proper ! +! ! +! 1.num = TRUE (-1) if the following command is @-sign modified ! +! ! +! 8.str = a string containing potential delimiting characters ! +! in case we can't use ESC as a delimiter. this string will be ! +! searched for a delimiting character which is not in the string ! +! we are trying to delimit. ! +! ! +! 9.str = a mask containing labels we'll use in a goto. Each ! +! character in the mask corresponds with a TECO command character ! +! and controls some action the squisher takes when it runs into ! +! that TECO command. For example, if the squisher runs into ! +! , the squisher uses the first character in the 9.str mask ! +! as a label to goto which handles 's. The mask characters ! +! are: ! +! ! +! 1 command takes character argument ! +! A ^A command ! +! B delete if line is blank ! +! D delete character from output ! +! E E command ! +! F F command ! +! L lowercase char (convert to uppercase) ! +! O optionally delete character from output ! +! T TAB char ! +! U ^U command ! +! V ^^ command, leave next char as is ! +! Z ^Z command, convert to -Z ! +! ^ (caret) next char is really CTRL-char ! +! $ command takes string argument(s) ! +! . (dot) pass character through w/o squishing ! +! @ the next command is '@' modified ! +! ! +! Changes: ! +! ! +! Nov-89 ! +! added comments ! +! changed system specific "n,Stext$" to generic "m,nFBtext$" ! +! --------------------------------------------------------------------- ! + +! --------------------------------------------------------------------- ! +! Load Q-register F with SQU initialization macro. This macro loads ! +! other macros into various Q-registers and handles the command line ! +! switches: either taking them from the command line in the edit ! +! buffer or prompting the user for them. When this macro is done, ! +! SQU will be poised to run and the only thing left in the edit buffer ! +! will be the input and output filenames. ! +! --------------------------------------------------------------------- ! + +^UF ! F.str = initialization macro ! +^D ! set radix to decimal ! +0ED ! zero edit mode flag ! +0^X ! zero search mode flag ! +ET&128"N ! if abort-on-error bit is not zero ! + 0,0XP ! clear P.str ! +' ! endif ! +0,128ET ! turn on abort-on-error bit ! +J ! jump to beginning of edit buffer ! +< @FS%^ES%%; > ! zap multiple spaces and tabs in edit buffer ! +J ! jump to beginning of edit buffer ! +:@S%/% ! search for '/' command line switch delimiter ! +UB ! put search success into B.num ! +QB"T ! if there are switches ! + ET&64"E ! if not detached ! + @^A% +% ! display ! + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Load Q-register R with a "get-response-from-user" macro. ! +! ! +! Entry: ! +! The last inserted string is the display prompt. ! +! ! +! The top of the stack is the Q-register name we will return ! +! the response in. If the high bit of the Q-register name ! +! is set, insist on ESC to terminate the response, otherwise ! +! allow the response to be terminated with CR-LF . ! +! ! +! Returns: ! +! Input string in the Q-register you specified on entry. ! +! --------------------------------------------------------------------- ! + +@^UR\ ! R.str = response macro ! +[0 [1 [2 [3 ! save Q-reg's 0 through 3 ! ++0U3 ! 3.num = Q-reg name on top of stack ! +^YX0 ! 0.str = display prompt (last inserted string) ! +^YK ! kill display prompt from edit buffer ! +.U1 ! 1.num = current buf ptr ! +ZJ ! jump to buf end ! +.U2 ! 2.num = current end of buffer ! +Q3&127"R ! if Q-reg name in 3.num is alphanumeric ! + ! it's a valid Q-reg name ! +| ! else (Q-reg name not alphanumeric) ! + ! it's not a valid Q-reg name ! + @^A%?Invalid Q-register in INPLIN +% ! display error message ! + @O!EXIT! ! go down to EXIT ! +' + +! --------------------------------------------------------------------- ! +! build a mini-macro in Q-reg 1 which will put the user's response ! +! into the Q-reg we are using to return the user's response in. ! +! --------------------------------------------------------------------- ! + +@I%Q2,.X% ! insert "Q2,.X" into edit buffer ! +Q3&127@I%% ! insert Q-reg name we're loading response in ! +Q2,.X1 ! put this mini-macro into 1.str ! +Q2,.K ! and kill it ! + +! --------------------------------------------------------------------- ! +! display the prompt on a new, clean, line ! +! --------------------------------------------------------------------- ! + +!PROMPT! + +13^T ! display ! +ET&512"N ! if scope, clear to end of screen ! + 0,1ET ! inhibit type-out conversions ! + 27^T ! display ESCAPE ! + 1,0ET ! enable type-out conversions ! + 0:W-4"E ! if VT100 in ANSI mode ! + ^^[^T ! display [ ! + ' ! endif ! + ^^J^T ! display J ! +| ! else (not scope) ! + 10^T ! display ! +' ! endif ! +.-Q2+(0^Q)"G ! if anything on current line ! + 0T ! display it ! +| ! else ! + :G0 ! display prompt in 0.str ! + Q2,ZT ! plus what we've entered so far ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Read characters from the console & insert them into the edit buffer. ! +! ! +! DEL delete last char entered ! +! ^U delete everything entered ! +! ^R redisplay prompt & what's been entered ! +! ^Z delete everything entered and return ! +! , , terminate input ! +! --------------------------------------------------------------------- ! + +!GETCH! + +^TU0 ! get char from console & put in 0.num ! +Q0-127"E ! if char is DEL ! + Z-Q2"N ! if anything has been added to buffer ! + -D ! delete last char ! + ' ! endif ! + @O!PROMPT! ! go up to PROMPT ! +' ! endif ! +Q0-21"E ! if char is ^U ! + Q2,ZK ! kill everything we've entered up to now ! + @O!PROMPT! ! go up to PROMPT ! +' ! endif ! +Q0-18"E ! if char is ^R ! + 13^T ! display ! + 10^T ! display ! + :G0 ! display prompt in 0.str ! + Q2,ZT ! display everything we've entered up to now ! + @O!GETCH! ! go up to GETCH ! +' ! endif ! +Q0-26"E ! if char is ^Z ! + Q2,ZK ! kill everything we've entered up to now ! + %0^[ ! convert ^Z (1Ah) to (1Bh) ! +' ! endif ! +Q0-27"E ! if char is ! + 13^T ! display ! + 10^T ! display ! + @O!DONE! ! go down to DONE ! +' ! endif ! +Q3&128"E ! if hi-bit of return Q-reg name is zero ! + Q0-10"E ! if char is ! + 13^T ! display ! + @O!DONE! ! go down to DONE ! + ' ! endif ! + Q0-13"E ! if char is ! + ^T^[ ! suck up of - pair? ! + @O!DONE! ! go down to DONE ! + ' ! endif ! +' ! endif ! +Q0@I%% ! insert input char into edit buffer ! +@O!GETCH! ! go up to GETCH to get next character ! + +!DONE! + +M1 ! execute mini-macro to load Q-reg w/response ! +Q2,.K ! kill everything we added to the input buffer ! + +!EXIT! + +Q1J ! jump back to where we were before we started ! +]3 ]2 ]1 ]0 ! restore Q-reg's 0 through 3 ! +\ ! end of ^UR ! + +! --------------------------------------------------------------------- ! +! Done loading response macro into Q-register R ! +! --------------------------------------------------------------------- ! + +! --------------------------------------------------------------------- ! +! Check for command line switches. Basically, each switch is searched ! +! for in the edit buffer: ! +! ! +! If the switch is not found ! +! If there were other switches on the command line ! +! Set the switch to its default value ! +! else ! +! Prompt the user for the value of the switch ! +! else ! +! If switch followed by ":argument" ! +! Set switch to "argument" ! +! else ! +! Set switch to the opposite of its default ! +! ! +! While we are checking for switches, we will be building the mask in ! +! Q-register 9 ! +! --------------------------------------------------------------------- ! + +! --------------------------------------------------------------------- ! +! Check for /D "Delete CR/LF" switch. /D will delete all lexical CR's ! +! and LF's. /D:N is the default. The format for the /D switch is: ! +! /D:Y or /D:N. /D just by itself is the same as /D:Y. ! +! ! +! A problem with /D:Y is that the output will probably be all on one ! +! line. If you want to delete all CR's and LF's, yet keep the output ! +! width manageable, use /L:nn. ! +! --------------------------------------------------------------------- ! + +0,0X9 ! clear mask in 9.str ! +J ! jump to beginning of buffer ! +:@FS%/D%%"S ! if "/D" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A@^UQ%% ! Q.str = arg ! + D ! delete arg ! + | ! else (":" not found) ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! +| ! else ("/D" not found) ! + QB"T ! if any other switches ! + @^UQ%% ! Q.str = "" ! + | ! else ! + @I%Delete CR/LF (Y/N) ? % + ^^QMR ! ask for /D value ! + ' ! endif ! +' ! endif ! +0QQ"A ! if /D val is alphabetic ! + 0QQ&95-^^Y"E ! if it's 'y' or 'Y' ! + + ! load 9.str with labels for control chars, with , ! + ! , and marked as D. ! + ! ! + ! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ % ! + @^U9%DA.......TD..D.......U....Z...V.D% + + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Check for /L "Set line lengths" switch. If you're not explicitly ! +! deleting all CR/LF's (ie: /D:N), you can still delete CR/LF's which ! +! are unecessary yet still keep the width of the output line manageable.! +! The format of the /L switch is: /L, /L:Y, /L:N, or /L:nn where nn is ! +! the line length. /L just by itself is the same as /L:Y, and /L:Y is ! +! the same as /L:70. If /D is Y then any /L is ignored. ! +! ! +! Note: the /L switch does delete all lexical CR/LF's; but, after ! +! everything is squished, goes back and inserts CR/LF wherever needed ! +! so the maximum width of the output line doesn't exceed nn chars. ! +! --------------------------------------------------------------------- ! + +!BADNUM! ! label to re-ask if :nn bad ! +0UO ! clear O.num ! +:Q9"N ! if we had /D:Y above ! + J ! jump to beginning of buf ! + :@FS%/L%%"S ! if "/L" found, delete it ! + @^A"%/L specified with /D, /L ignored +" ! and warn the user ! + ::@FS%:%%"S ! if ":arg" found, kill ":" ! + 0A"D ! if arg is numeric ! + < D .-Z; 0A"D > ' ! delete nn ! + | ! else ! + D ! delete arg ! + ' ! endif ! + ' ! endif ! + ' ! endif ! +| ! else (no /D:Y above) ! + J ! jump to beginning of buf ! + :@FS%/L%%"S ! if "/L" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A@^UQ%% ! Q.str = arg ! + 0A"D ! if arg is numeric ! + < D .-Z; 0A"D 0A:@^UQ%% > ' ! get nn ! + | ! else ! + D ! delete arg ! + ' ! endif ! + | ! else, just /L ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! + | ! else ! + QB"T ! if any other switches ! + @^UQ%% ! Q.str = "" ! + | ! else ! + @I%Set line lengths (Y for 70, N, or length) ? % + ^^QMR ! ask for /L value ! + ' ! endif ! + ' ! endif ! + 0QQ"A ! if /L val is alphabetic ! + 0QQ&95-^^Y"E ! if it's 'y' or 'Y' ! + + ! load 9.str with labels for control chars, ! + ! with , , and marked as O. ! + ! ! + ! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ % ! + @^U9%DA.......TO..O.......U....Z...V.O% + + 70UO ! set line length to 70 ! + ' ! endif ! + ' ! endif ! + 0QQ"D ! if /L val is numeric ! + .UQ ! save current buf ptr ! + ZJ ! jump to buf end ! + GQ ! put /L str in buffer ! + ^SC ! go back to /L str begin ! + \UO ! put str value in O.num ! + ^SD ! and delete str ! + .-Z"N ! if anything left over ! + ZK ! kill chars \ skipped ! + QQJ ! jump back to old cp ! + @O!BADNUM! ! bad number ! + ' ! endif ! + QQJ ! jump back to old cp ! + QO"E ! if /L arg is 0 ! + @O!BADNUM! ! bad number ! + ' ! endif ! + + ! load 9.str with labels for control chars, with , ! + ! , and marked as O. ! + ! ! + ! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ % ! + @^U9%DA.......TO..O.......U....Z...V.O% + + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Check for /B "Delete blank lines" switch ! +! --------------------------------------------------------------------- ! + +:Q9"N ! if we had /D:Y above ! + J ! jump to beginning of buf ! + :@FS%/B%%"S ! if "/B" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A-^^N"E ! if "/B:N", ignore it ! + @^A"%/B:N specified with /D or /L, /B:N ignored +" ! warn user ! + ' ! endif ! + D ! delete arg ! + ' ! endif ! + ' ! endif ! +| ! else (no /D:Y above) ! + J ! jump to beginning of buf ! + :@FS%/B%%"S ! if "/B" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A@^UQ%% ! Q.str = arg ! + D ! delete arg ! + | ! else ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! + | ! else ! + QB"T ! if any other switches ! + @^UQ%% ! Q.str = "" ! + | ! else ! + @I%Delete blank lines (Y/N) ? % + ^^QMR ! ask for /B value ! + ' ! endif ! + ' ! endif ! + 0QQ"A ! if /B val is alphabetic ! + 0QQ&95-^^Y"E ! if it's 'y' or 'Y' ! + + ! load 9.str with labels for control chars, ! + ! with marked as B and marked as D. ! + ! ! + ! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ % ! + @^U9%DA.......TB..........U....Z...V.D% + + ' ! endif ! + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! at this point, if we've specified /D, /L, or /B above, 9.str should ! +! hold the labels for the control characters, if it doesn't, we'll ! +! supply the default labels which only deletes and . ! +! ! +! Note: we only have entries for to here. The entry for ! +! exclamation point will be put in by the /C checking code below. All ! +! other entries are appended to 9.str after switch parsing is finished. ! +! --------------------------------------------------------------------- ! + +:Q9"E ! if 9.str is empty ! + ! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ % ! + @^U9%DA.......T...........U....Z...V.D% ! load default mask ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Check for /T "Delete lexical TABs and FFs" switch. The format of ! +! the /T switch is: /T, /T:Y, /T:N. /T by itself is the same as /T:Y. ! +! If TABs are used to format the macro to be squished, instead of being ! +! used to start an insert, you'll have to delete them using /T:Y ! +! --------------------------------------------------------------------- ! + +J ! jump to beginning of buffer ! +:@FS%/T%%"S ! if "/T" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A@^UQ%% ! Q.str = arg ! + D ! delete arg ! + | ! else ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! +| ! else ! + QB"T ! if any other switches ! + @^UQ%% ! Q.str = "" ! + | ! else ! + @I%Delete lexical TABs and FORM FEEDs (Y/N) ? % + ^^QMR ! ask for /T value ! + ' ! endif ! +' ! endif ! +0QQ"A ! if /T val is alphabetic ! + 0QQ&95@^UQ%% ! force it to uppercase ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! if /T is "Y", the following code takes the existing control char ! +! mask in Q-reg 9 and replaces the TAB and FF entries with "O". The ! +! new control char mask is then put back in Q-reg 9. ! +! --------------------------------------------------------------------- ! + +0QQ-^^Y"E ! if /T is 'Y' ! + J ! jump to beginning of buffer ! + G9 ! load mask into edit buffer ! + 9J ! jump to TAB entry ! + D ! delete existing entry ! + @I%O% ! insert "O" ! + 12J ! jump to FF entry ! + D ! delete existing entry ! + @I%O% ! insert "O" ! + J ! jump to beginning of buffer ! + 0,33X9 ! put mask back in 9.str ! + 0,33K ! and clean up edit buffer ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Check for /C "Delete comments" switch. This switch deletes comments ! +! as opposed to labels. It is easier if comments are distinguishable ! +! from labels by having a special delimiting character immediately ! +! following the initial exclamation point. The format of the /C ! +! switch is: /C, /C:Y, /C:N, or /C:? where ? is the special comment ! +! delimiting character. /C is the same as /C:Y, and /C:Y implies that ! +! SPACE and TAB are the special comment delimiters. When done, Q-reg ! +! C will contain the special comment delimiting characters. ! +! --------------------------------------------------------------------- ! + +@^UC%% ! C.str = "" ! +J ! jump to beginning of buffer ! +:@FS%/C%%"S ! if "/C" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A@^UQ%% ! Q.str = arg ! + D ! delete arg ! + | ! else ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! +| ! else ! + QB"T ! if any other switches ! + @^UQ%% ! Q.str = "" ! + | ! else ! + @I%Delete comments (Y for SP/TAB, N, or set) ? % + ^^QMR ! ask for /C value ! + ' ! endif ! +' ! endif ! +:QQ"E ! if Q.str empty ! + @^UQ%N% ! Q.str = "N" ! +' ! endif ! +0QQUQ ! Q.num = ASCII 1st Q.str char ! +QQ"V ! if Q.num lowercase ! + QQ-32UQ ! force it to uppercase ! +' ! endif ! +QQ-^^N"E ! if /C == "N" ! + :@^U9%A% ! append "A" to 9.str mask ! +| ! else ! + :@^U9%C% ! append "C" to 9.str mask ! + QQ-^^Y"E ! if /C == "Y" ! + 32@^UC%% ! C.str = ! + 9:@^UC%% ! append TAB to C.str ! + | ! else (it's a set?) ! + GQ ! put /C set in edit buf ! + ^YXC ! load it into Q-reg C ! + ^YK ! clean up edit buffer ! + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! append entries for all other TECO commands to the mask in Q-reg 9. ! +! --------------------------------------------------------------------- ! + +! %"#$%&'()*+,-./0123456789:;<=>?% ! +:@^U9%1..1..........................% + +! %@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_% ! +:@^U9%@....EF1.$...1$$.1.$.1..1..1.1^$% + +! %`abcdefghijklmnopqrstuvwxyz{|}% ! +:@^U9%.LLLLLLLLLLLLLLLLLLLLLLLLLL....D% + +! --------------------------------------------------------------------- ! +! Load Q-register 8 with potential characters in case ESC can't ! +! be used. We initially load 8.str with the preferred delimiters: ! +! ! +! / # * & \ ? ( ) $ @ ! +! ! +! in case these can't be used either, we'll also append every ASCII ! +! character to 8.str in the hope that something can be used. ! +! --------------------------------------------------------------------- ! + +@^U8%/#*&\?()$!@% ! pre-load 8.str ! +1U8 ! put 1 in 8.num ! +126< ! this loop appends ASCII chars ! + Q8:@^U8%% %8^[ ! CTRL-A to TILDE to 8.str ! + > + +! --------------------------------------------------------------------- ! +! Check for /W "Watch progress" switch ! +! --------------------------------------------------------------------- ! + +@^UW%% ! clear W.str ! +ET&512"E ! if not scope, ignore /W ! + J ! jump to beginning of buf ! + :@FS%/W%%"S ! if "/W" found, delete it ! + ::@FS%:%%"S ! if ":" found ! + D ! delete arg ! + ' ! endif ! + ' ! endif ! +| ! else (it's a scope) ! + J ! jump to beginning of buf ! + :@FS%/W%%"S ! if "/W" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A@^UQ%% ! Q.str = arg ! + D ! delete arg ! + | ! else ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! + | ! else ! + QB"T ! if any other switches ! + @^UQ%% ! Q.str = "" ! + | ! else ! + @I%Watch progress (Y/N) ? % + ^^QMR ! ask for /W value ! + ' ! endif ! + ' ! endif ! + 0QQ"A ! if /W val is alphabetic ! + 0QQ&95-^^Y"E ! if it's 'y' or 'Y' ! + 0:W-2"E ! if VT100 in VT52 mode ! + 4,0:W^[ ! set VT100 in ANSI ! + ' ! endif ! + @^UW/-1W/ ! Q.str = "-1W" (refresh) ! + ' ! endif ! + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Check for /A "Automatic mode". If /A:Y, then if @^U%text% is found, ! +! "text" is assumed to something which should *not* be sub-squished; ! +! any other character used as a special *will* be sub-squished. ! +! If /A:N, then go into "manual mode" where each time SQU runs into ! +! ^Utext, it will ask if you want to sub-squish it. If /A: is ! +! a command line switch then use as the "non-squishable" ! +! char. If you're asked for the /A value, then you can enter a set of ! +! "non-squishable" chars. ! +! --------------------------------------------------------------------- ! + +@^UK%% ! clear K.str ! +J ! jump to beginning of buffer ! +:@FS%/A%%"S ! if "/A" found ! + ::@FS%:%%"S ! if ":arg" found ! + 0A@^UQ%% ! Q.str = arg ! + D ! delete arg ! + | ! else ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! +| ! else ! + QB"T ! if any other switches ! + @^UQ%Y% ! Q.str = "Y" ! + | ! else ! + @I/Automatic mode (Y for %, N, or set) ? / + ^^QMR ! ask for /A value ! + ' ! endif ! +' ! endif ! +:QQ"N ! if any /A val ! + 0QQUQ ! convert /A val to ASCII ! + QQ"V ! if /A val lowercase ! + QQ-32UQ ! force to uppercase ! + ' ! endif ! + QQ-^^N"N ! if /A not "N" ! + QQ-^^Y"E ! if /A == "Y" ! + ^^%@^UK%% ! K.str = "%" ! + | ! else (it's a set?) ! + GQ ! put /A set in edit buf ! + ^YXK ! load it into K.str ! + ^YK ! clean up edit buffer ! + ' ! endif ! + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Check for /E "Allow adjacent ESCapes" switch. Sometimes squishing ! +! will put two escapes together where there weren't two escapes before. ! +! For example, @FS/abc// will be squished to @FSabc$$, the two adjacent ! +! escapes could be a problem this is in a macro which is EI'd. The ! +! format of the /E switch is: /E, /E:N, or /E:Y. /E is the same as ! +! /E:Y. /E:N will direct SQU to never generate adjacent escapes where ! +! there were none before. ! +! --------------------------------------------------------------------- ! + +0UH ! H.num = 0 (FALSE) ! +J ! jump to beginning of buffer ! +:@FS%/E%%"S ! if "/E" found ! + ::@FS%:%%"S ! if ":" found ! + 0A@^UQ%% ! Q.str = arg ! + D ! delete arg ! + | ! else ! + @^UQ%Y% ! Q.str = "Y" ! + ' ! endif ! +| ! else ! + QB"T ! if any other switches ! + @^UQ%% ! Q.str = "" ! + | ! else ! + @I%Allow adjacent ESCapes (Y/N) ? % + ^^QMR ! ask for /E value ! + ' ! endif ! +' ! endif ! +0QQ"A ! if /E val is alphabetic ! + 0QQ&95-^^Y"E ! if it's 'y' or 'Y' ! + -1UH ! H.num = -1 (TRUE) ! + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Load Q-register Z with the squisher macro ! +! ! +! Uses Q-register 1 for @-modified flag while processing and for ! +! an error return when through. ! +! --------------------------------------------------------------------- ! + +@^UZ* ! Z.str = squish macro ! +[1 ! save Q-reg 1 ! +0U1 ! clear @-modifed flag ! +:QW"N ! if /W was TRUE ! + -1,3:W^[ ! turn on SEEALL mode ! + 0,4:W^[ ! set no "mark" status ! + 0,5:W^[ ! turn hold mode off ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! main loop start ! +! --------------------------------------------------------------------- ! + +< +!..! + +MW ! refresh scope ! + +!.! + +ME; ! break if E macro returns 0 ! + +0AU0 ! 0.num = char in buffer ! +Q0"L ! if char is less than zero ! + @O!OFFEND! ! end of file err ! +' ! endif ! +C ! advance one character ! +Q0&128"N ! if char's hi bit is set ! + Q0&127U0 ! zero hi bit ! + -D ! delete hi bit char ! + Q0@I%% ! insert zero hi bit char ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! Use the ASCII value of the current char in 0.num as an index into the ! +! labels in 9.str, and goto that label. ! +! --------------------------------------------------------------------- ! + +!DISP! ! dispatch ! +Q0Q9@^U0%% ! 0.str = Q0th char of 9.str ! +@O!^EQ0! ! and jump to it ! + +! --------------------------------------------------------------------- ! +! handle a lowercase character. convert it to uppercase and process ! +! it again. ! +! --------------------------------------------------------------------- ! + +!L! + +Q0-32U0 ! convert to uppercase ! +-D ! delete lowercase char ! +Q0@I%% ! insert uppercase char ! +@O!DISP! ! try label for uppercase char ! + +! --------------------------------------------------------------------- ! +! handle '^'. the next character is really CTRL-char. we'll delete ! +! the "^char" construct, insert the "real" control char, and go back ! +! and process it again. we'll watch out for inserting ^[ (), we ! +! have to be careful about creating adjacent 's. ! +! --------------------------------------------------------------------- ! + +!^! + +0A&31U0 ! 0.num = ^char ! +C ! skip past char ! +-2D ! delete both ^ and char ! +QH"F ! if no adjacent ESC's ! + Q0-27"E ! if ^char is ESC ! + 0A-27"E ! if next char is ESC ! + @I%^[% ! insert a single ESC ! + C ! skip past next ESC ! + @O!..! ! jump to main loop ! + ' ! endif ! + ! ----------------------------------------------------- ! + ! at this point we are trying to insert an ESC; but we ! + ! don't know if by doing so we will inadvertently form ! + ! two adjacent escapes. the following code searches ! + ! backwards for the last important character (skipping ! + ! CF/LF's) to see if that last important character was ! + ! also an ESC. if it was, we'll insert a to keep ! + ! the two ESC's lexically apart. ! + ! ----------------------------------------------------- ! + .US ! S.num = cur buf ptr ! + 0UT ! T.num = 0 ! + < ! ----loop begin--------------- ! + -.; ! break if .==0 ! + R ! back up one char ! + 0AUT ! T.num = previous char ! + QT&128"E ! if hi bit of char zero ! + QT-10"N ! if char is not ! + 0; ! break out of loop ! + | ! else (it is ) ! + -.; ! break if .==0 ! + -1A-128-13"N ! if not ! + 0; ! break out of loop ! + ' ! endif ! + ' ! endif ! + ' ! endif ! + > ! ----loop end----------------- ! + QSJ ! jump to where we startd ! + QT-27"E ! if last char == ESC ! + @I% % ! insert ! + ' ! endif ! + ' ! endif ! +' ! endif ! +Q0@I%% ! insert ^char ! +@O!DISP! ! try again ! + +! --------------------------------------------------------------------- ! +! handle 'B'. we've run into the portion of CR/LF with the /B ! +! switch (delete blank lines) set. if there are only two chars on the ! +! current line, assume they are CR/LF and delete them. ! +! --------------------------------------------------------------------- ! + +!B! + +-1^Q+2"E ! if only 2 chars on this line ! + -2D ! delete ! +' ! endif ! +@O!..! ! jump to main loop ! + +! --------------------------------------------------------------------- ! +! handle 'O'. we've run into , , or with the /L switch ! +! set. ! +! --------------------------------------------------------------------- ! + +!O! + +-D ! delete last char ! +."N ! if not at beginning of buffer ! + -1A&128"N ! if last char hi bit set ! + -D ! delete it ! + ' ! endif ! + .-1"G ! if 2 chars past buf begin ! + -1A-10"E ! if hi bi of last char set ! + -2A-128-13"E ! if 2nd last char = ! + Q0-13"E ! if curr char is ! + -2D ! delete ! + | ! else ! + @O!..! ! jump to main loop ! + ' ! endif ! + ' ! endif ! + ' ! endif ! + ' ! endif ! + Q0#128@I%% ! insert char w/hi bit ! + Q0-13"E ! if char is ! + .-Z"E ! if at end of buffer ! + 10@I%% ! insert ! + R ! back up one char ! + ' ! endif ! + 0A&127-10"E ! if curr char is ! + D ! delete it ! + ' ! endif ! + 10@I%% ! insert ! + ' ! endif ! +' ! endif ! +@O!..! ! jump to main loop ! + +! --------------------------------------------------------------------- ! +! handle 'U'. we've run into ^Uq. usually, the string ^Uq is loading ! +! into Q-register q is *not* squished. the problem with ^Uq is that it ! +! is sometimes used to load a macro into a Q-register. This macro code ! +! should be squished too. What we do is if the ^U is @-modified, and ! +! the is *not* in the "non-squishible ^U command" character set ! +! in Q-register K, we assume it is a macro and should be sub-squished. ! +! Otherwise, the ^U argument is assumed to be a simple string and is ! +! not sub-squished. ! +! --------------------------------------------------------------------- ! + +!U! + +27@^U1%% ! 1.str = ESC (default delim) ! +.UC ! C.num = current buf ptr ! +0AU0 ! 0.num = ^U Q-reg name ! +C ! advance past Q-reg name ! +Q0-^^."E ! if it's .q (local Q-reg name) ! + 0AU0 ! 0.num = "real" Q-reg name ! + C ! advance past "." ! +' ! endif ! +Q0"V ! if Q-reg name is lowercase ! + Q0-32U0 ! convert it to uppercase ! + -D ! delete lowercase char ! + Q0@I%% ! insert uppercase char ! +' ! endif ! +Q1"T ! if @-modified ! + 0A-(1A)"E ! if @^Uqtext ! + @O!$$! ! goto $$ ! + ' ! endif ! +| ! else ! + 0A-27"E ! if ^Uq ! + @O!$$! ! goto $$ ! + ' ! endif ! +' ! endif ! +.US ! S.num = current buf ptr ! +Q1"T ! if @-modifed ! + 0A@^U1%% ! 1.str = ! + D ! delete ! +' ! endif ! +:QW"N ! if /W was TRUE ! + :@S%^EQ1%"U ! if search for fails ! + @O!STRINGFAIL! ! unterminated string ! + ' ! endif ! + .,4:W^[ ! set mark status ! + QSJ ! jump back to where we were ! + MW ! refresh scope ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! if there are no "non-squishable ^U command" characters, you used the ! +! /A:N switch. If this is the case, we'll have to drop into "manual" ! +! mode: everytime we run into a ^U we'll ask if you want to squish it ! +! or not, Y or N. ! +! --------------------------------------------------------------------- ! + +:QK"E ! if no non-squishable ^U delim ! + :QW"E ! if /W was FALSE ! + 0T ! display line up to now ! + 10^T ! display ! + T ! display rest of line ! + ' ! endif ! + 7^T ! display ! + ETUQ ! save ET flags in Q.num ! + ET#8#4-4ET ! turn on read w/o echo ! + ^TU0 ! read char into 0.num ! + QQET ! restore ET flags ! +| ! else (non-squishable delims) ! + G1 ! put in buf ! + R ! back up one char ! + ::@S%^EGK%"S ! if is non-squish ! + -D ! delete ! + ^^NU0 ! 0.num = N ! + | ! else ! + D ! delete ! + ^^YU0 ! 0.num = Y ! + ' ! endif ! +' ! endif ! +:QW"N ! if /W was TRUE ! + 0,4:W^[ ! clear "mark" status ! + 32768W ! set huge # of display lines ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! at this point, 0.num will be "Y" if we are to sub-squish the ^U text ! +! --------------------------------------------------------------------- ! + +Q0-^^Y"E ! if 0.num is Y ! + ! ------------------------------------------------------------- ! + ! Q-register E originally holds ".-Z" (-number of chars until ! + ! end of the buffer, when zero we're at end of buf). The E ! + ! macro is executed at the top of the squish loop so we break ! + ! out of the squish loop when we reach the end of the buf. When ! + ! we recursively sub-squish a ^U string, we want the squish ! + ! loop to break out when it reaches the end of the ^U string. ! + ! Therefore, we'll now load Q-register E with a macro to do so. ! + ! ! + ! -1UE E.num == -1 (continue flag) ! + ! 0A-^^"E if we've run into ! + ! 0UE E.num == 0 (break flag) ! + ! ' endif ! + ! QE push -1 or 0 on stack ! + ! ------------------------------------------------------------- ! + [E [C [S ! save Q-reg's E, C, & S ! + @^UE%-1UE0A-^^% ! load Q-reg E w/macro start ! + 0Q1:@^UE%% ! append to Q-reg E ! + :@^UE%"E0UE'QE% ! append macro end to Q-reg E ! + MZ ! squish recursively ! + ]S ]C ]E ! restore Q-reg's C, S & E ! + "N ! if recursive MZ failed ! + @O!PRIORFAIL! ! announce it ! + ' ! endif ! + C ! advance past end ^U delim ! + @O!$$$$! ! goto $$$$ ! +' ! endif ! +@O!$$$! ! goto $$$ ! + +! --------------------------------------------------------------------- ! +! handle 'T'. we've run into a TAB character, start an insert. ! +! --------------------------------------------------------------------- ! + +!T! + +0U1 ! clear @-modified flag ! + +! --------------------------------------------------------------------- ! +! handle '$'. we've run into I, N, O, or S: commands which take a ! +! single string argument (ie: commands which contain one ). ! +! --------------------------------------------------------------------- ! + +!$! + +27@^U1%% ! 1.str = ESC (default delim) ! +.UC ! C.num = current buf ptr ! + +! --------------------------------------------------------------------- ! +! $$, entry point for commands which take two string arguments (ie: ! +! commands which contain two 's). ! +! --------------------------------------------------------------------- ! + +!$$! + +.US ! S.num = start of text ! +Q1"T ! if @-modified ! + 0A@^U1%% ! 1.str = ! + D ! delete ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! $$$, entry point for the ^U routine when we are not sub-squishing the ! +! ^U argument, but we've already handled being @-modified. ! +! --------------------------------------------------------------------- ! + +!$$$! + +:@S%^EQ1%"U ! if search for fails ! + @O!STRINGFAIL! ! unterminated string ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! $$$$, entry point for the ^U routine after we've sub-squished a ^U ! +! macro. ! +! --------------------------------------------------------------------- ! + +!$$$$! + +-D ! delete trailing ! +.UT ! T.num = end of text ! +27U0 ! 0.num = ESC (default ! + +! --------------------------------------------------------------------- ! +! At this point, we have to output a delimited string. ! +! ! +! 0.num = ! +! C.num = start of command ! +! S.num = start of text ! +! T.num = end of text ! +! ! +! --------------------------------------------------------------------- ! + +!AA! + +Q0@^U0%% ! 0.str = char ! +QT-QS"G ! if string is not-empty ! + QSJ ! jump to start of string ! + .,.+QT-QS:@FB%^EQ0%"S ! if is in string ! + ! ----------------------------------------------------- ! + ! find a we can use, one which is *not* already ! + ! in the string. ! + ! ----------------------------------------------------- ! + G8 ! put 8.str into buf ! + ^Y:X1 ! put 8.str into 1.str ! + ^YK ! kill 8.str from buf ! + 0U0 ! clear 0.num ! + < ! ----loop begin--------------- ! + Q0Q1@^U0%% ! 0.str = Q0th char of Q1 ! + QSJ ! jump to start of text ! + .,.+QT-QS@FB%^EQ0%; ! break if search fails ! + %0-:Q8"E ! if next char last char ! + @O!NOQUOTE! ! can't find " char ! + ' ! endif ! + > ! ----loop end----------------- ! + Q0Q1U0 ! 0.num = to use ! + QSJ ! jump to start of string ! + Q0@I%% ! insert ! + QC-1J ! jump before command ! + @I%@% ! insert @ ! + 2%T^[ ! T.num (end of text) += 2 ! + ! ----------------------------------------------------- ! + ' ! endif ! +' ! endif ! +QTJ ! jump to end of string ! +Q0@I%% ! insert ! +0U1 ! clear @-modified flag ! +@O!..! ! jump to main loop ! + +! --------------------------------------------------------------------- ! +! handle '1'. we've run into ", %, G, M, Q, U, X, [, or ]. For ", the ! +! next character is a conditional execution command. For everything ! +! else, the next character is a Q-register name. In either case, if ! +! the next char is lowercase, we uppercase it; otherwise, we fall ! +! through to the 'V' code below which simply advances past the char. ! +! --------------------------------------------------------------------- ! + +!1! + +0A-^^."E ! if it's .q (local Q-reg name) ! + C ! advance past "." ! +' ! endif ! +0A"V ! if lowercase ! + 0A-32U0 ! convert to uppercase ! + D ! delete lowercase char ! + Q0@I%% ! insert uppercase char ! + @O!.! ! goto . ! +' ! endif ! +! ... fall through ...! + +! --------------------------------------------------------------------- ! +! handle 'V'. we've run into -^, simply skip it ! +! --------------------------------------------------------------------- ! + +!V! + +C ! simply advance past it ! +@O!.! ! goto . ! + +! --------------------------------------------------------------------- ! +! handle '@'. the following command is @ modified, set a flag in 1.num ! +! so we know to look for the alternate delimiter characters. ! +! ! +! even though characters will be specified along with the '@' ! +! command, we'll try to use ESC whenever possible and convert the @ ! +! modified command back into a "normally" delimited command. ! +! --------------------------------------------------------------------- ! + +!@! + +-1U1 ! set @-modified flag ! +! ...fall through ... ! + +! --------------------------------------------------------------------- ! +! handle 'D'. delete the character from the output file ! +! --------------------------------------------------------------------- ! + +!D! + +-D ! delete last character ! +@O!.! + +! --------------------------------------------------------------------- ! +! handle 'F'. we've run into a F', F<. F>, F|, FB, FC, FD, FK, FN, FR, ! +! FS, or F_ command. ! +! --------------------------------------------------------------------- ! + +!F! + +27@^U1%% ! 1.str = ESC (default delim) ! +.UC ! C.num = current buf ptr ! +0AU0 ! 0.num = 2nd command char ! +C ! advance past 2nd cmd char ! +Q0"V ! if 2nd cmd char is lowercase ! + Q0-32U0 ! convert it to uppercase ! + -D ! delete lowercase char ! + Q0@I%% ! insert uppercase char ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! the FB and FR commands take a single string argument, goto $$ ! +! the FC, FS, FN, and F_ commands take two string arguments, goto F$$ ! +! ! +! ???What about FD and FK taking 1 string argument ! +! --------------------------------------------------------------------- ! + +Q0-^^B"E ! if it's FB ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^C"E ! if it's FC ! + @O!F$$! ! goto F$$ ! +' ! endif ! +Q0-^^R"E ! if it's FR ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^S"E ! if it's FS ! + @O!F$$! ! goto F$$ ! +' ! endif ! +Q0-^^N"E ! if it's FN ! + @O!F$$! ! goto F$$ ! +' ! endif ! +Q0-^^_"E ! if it's F_ ! + @O!F$$! ! goto F$$ ! +' ! endif ! +@O!.! + +! --------------------------------------------------------------------- ! +! handle FC, FS, FN, and F_ commands which take two string arguments, ! +! there are three possible formats for these commands: ! +! ! +! Fx ! +! Fx text ! +! Fx text1 text2 ! +! ! +! we first have to find the starting and ending points of the text ! +! arguments. we set S.num to be the start of text1, we look for the ! +! 1st , delete it, and set T.num to be the start of text2. we ! +! then look for the 2nd , delete it, and set U.num to be the ! +! end of text2. ! +! ! +! if S.num == T.num & T.num == U.num, then we have: FS$$ ! +! if S.num <> T.num & T.num == U.num, then we have: FStext$$ ! +! if S.num <> T.num & T.num <> U.num, then we have: FStext1$text2 ! +! --------------------------------------------------------------------- ! + +!F$$! + +.US ! S.num = start of text1 ! +27@^U1%% ! 1.str = ESC (default delim) ! +Q1"T ! if @-modified ! + 0A@^U1%% ! 1.str = ! + D ! delete ! +' ! endif ! +:@S%^EQ1%"U ! if search for 1st delim fails ! + @O!STRINGFAIL! ! unterminated string ! +' ! endif ! +-D ! delete 1st ! +.UT ! T.num = start of text2 ! +:@S%^EQ1%"U ! if search for 2nd delim fails ! + @O!STRINGFAIL! ! unterminated string ! +' ! endif ! +-D ! delete 2nd ! +.UU ! U.num = end of text2 ! +QH"T ! if allow adjacent escapes ! + 27U0 ! 0.num = ESC ! + Q0@^U0%% ! 0.str = ESC ! + QU-QS"G ! if we have text1 & text2 ! + QSJ ! jump to start of text1 ! + .,.+QU-QS:@FB%^EQ0%"U ! if search for ESC fails ! + @O!F0! ! use ESC as ! + ' ! endif ! + | ! else (no text arguments) ! + @O!F0! ! use ESC as DELIM ! + ' ! endif ! +| ! else (don't allow adjacent $) ! + QU-QT"G ! if we have text2 ! + 27U0 ! 0.num = ESC ! + Q0@^U0%% ! 0.str = ESC ! + QSJ ! jump to start of text1 ! + .,.+QU-QS:@FB%^EQ0%"U ! if search for ESC fails ! + @O!F0! ! done w/F ! + ' ! endif ! + ' ! endif ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! if we reach this point, there is a danger of putting adjacent ESC's ! +! in the output. we will try to find a character that's not in the ! +! string we're delimiting and use that as a character instead ! +! of ESC. basically, we search "text1text2" looking for each character ! +! in G8, trying to find a delimiter char that's not already in the ! +! string. ! +! --------------------------------------------------------------------- ! + +G8 ! put 8.str into buf ! +^Y:X1 ! put 8.str into 1.str ! +^YK ! kill 8.str from buf ! +0U0 ! 0.num = 0 ! +< ! loop begin------------------- ! + Q0Q1@^U0%% ! 0.str = 0.num'th char of Q1 ! + QSJ ! jump to start of text1 ! + .,.+QU-QS@FB%^EQ0%; ! break if 0.str search fails ! + %0-:Q8"E ! inc 0.num, if end of 8.str ! + @O!NOQUOTE! ! can't find " char ! + ' ! endif ! +> ! loop end--------------------- ! + +! --------------------------------------------------------------------- ! +! at this point, we've found our char, it's index is in 0.num ! +! --------------------------------------------------------------------- ! + +Q0Q1U0 ! 0.num = Q0th char of Q1 ! +QSJ ! jump to start of text1 ! +Q0@I%% ! insert ! +QC-1J ! jump 1 char before F command ! +@I%@% ! insert @ ! +2%T^[ ! T.num (end of text1) += 2 ! +2%U^[ ! U.num (end of text2) += 2 ! + +!F0! + +QTJ ! jump to end of text1 ! +Q0@I%% ! insert ! +QU-QTC ! advance to end of text2 ! +Q0@I%% ! insert ! +0U1 ! clear @-modified flag ! +@O!..! ! jump to main loop ! + +! --------------------------------------------------------------------- ! +! handle 'A'. we've run into ^Atext^A or @^A/text/. This is also the ! +! entry point for the 'C' routine: if we're not deleting the comment ! +! we handle comment just like ! +! ^Atest^A. ! +! --------------------------------------------------------------------- ! + +!A! + +Q0@^U1%% ! 1.str = ^A or exclamation pt. ! +.UC ! C.num = start of text ! +.US ! S.num = start of text ! +Q1"T ! if @-modified ! + 0A@^U1%% ! 1.str = ! + D ! delete ! +' ! endif ! +:@S%^EQ1%"U ! if search for fails ! + @O!STRINGFAIL! ! unterminated string ! +' ! endif ! +-D ! delete second ! +.UT ! T.num = end of text ! +@O!AA! ! goto AA ! + +! --------------------------------------------------------------------- ! +! handle 'C'. we've run into an exclamation point with the /C switch ! +! set. Q-register C contains the special comment delimiter characters. ! +! --------------------------------------------------------------------- ! + +!C! + +::@S%^EGC%"U ! if not special comment delim ! + @O!A! ! handle like ^Astring^A ! +' ! endif ! +R ! back up past special ! +.UC ! C.num = current buf ptr ! +Q0@^U1%% ! 1.str = exclamation point ! +Q1"T ! if @-modified ! + 0A@^U1%% ! 1.str = ! + D ! delete ! +' ! endif ! +:@S%^EQ1%"U ! if search for failed ! + @O!STRINGFAIL! ! unterminated string ! +' ! endif ! +QC-1,.K ! kill entire comment ! +0U1 ! clear @-modified flag ! +@O!..! ! jump to main loop ! + +! --------------------------------------------------------------------- ! +! handle 'E'. we've run into an E command. ! +! --------------------------------------------------------------------- ! + +!E! + +27@^U1%% ! 1.str = ESC (default delim) ! +.UC ! C.num = current buf ptr ! +0AU0 ! 0.num = 2nd command char ! +C ! advance past 2nd cmd char ! +Q0"V ! if 2nd cmd char is lowercase ! + Q0-32U0 ! convert to uppercase ! + -D ! delete lowercase char ! + Q0@I%% ! insert uppercase char ! +' ! endif ! + +! --------------------------------------------------------------------- ! +! the EB, EG, EI, EN, ER, EW, E_ commands take a string argument, they ! +! have to be passed to the $$ routine. ! +! ???What about EL, EQq, EZ, and E%q taking a string argument ! +! --------------------------------------------------------------------- ! + +Q0-^^B"E ! if it's EB ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^G"E ! if it's EG ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^I"E ! if it's EI ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^N"E ! if it's EN ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^R"E ! if it's ER ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^W"E ! if it's EW ! + @O!$$! ! goto $$ ! +' ! endif ! +Q0-^^_"E ! if it's E_ ! + @O!$$! ! goto $$ ! +' ! endif ! +@O!.! + +! --------------------------------------------------------------------- ! +! handle 'Z'. we've run into a ^Z, replace it with -Z ! +! --------------------------------------------------------------------- ! + +!Z! + +-D ! delete -Z ! +@I%^Z% ! insert -Z ! +@O!..! ! jump to main loop ! + +> ! main loop end---------------- ! + +! --------------------------------------------------------------------- ! +! At this point, everything should be squished and Q1 will be -1 if ! +! an error occurred, or 0 if everything is OK. ! +! --------------------------------------------------------------------- ! + +Q1"T ! if error flag ! + @^U1%Trailing, pending @% ! ! + @O!ERROR! ! goto error display ! +' ! endif ! +0U1 ! clear Z-macro return value ! + +! --------------------------------------------------------------------- ! +! the only way the following error reporting code is executed is if we ! +! jump to a label inside of it. if we arrive here by any other means ! +! then things are OK, skip down to the "endif". ! +! --------------------------------------------------------------------- ! + +0"N ! skip the following code ! +!OFFEND! + @^U1%End of buffer while sub-squishing% + @O!ERROR! + +!NOQUOTE! + @^U1%Can't find a quote character% + @O!SETPOS! + +!PRIORFAIL! + @^U1%Prior recursion level failed% + @O!SETPOS! + +!STRINGFAIL! + @^U1%Unterminated string% + +! --------------------------------------------------------------------- ! +! the following code finishes building an error string in Q-register 1. ! +! 1.str already contains the type of error, this code appends the ! +! position where the error occurred and the line before and after the ! +! error, like so: ! +! ! +! from squished .= ! +! | ! +! | ! +! ! +! --------------------------------------------------------------------- ! + +!SETPOS! + :@^U1% from squished .=% ! append msg to 1.str ! + QC\ ! position in C.num to buf ! + ^Y:X1 ! append position in buf ! + ^YK ! delete position from buf ! + 13:@^U1%% ! append ! + 10:@^U1%% ! append ! + QCJ ! jump to where error starts ! + 0^Q+.,.:X1 ! append line up to error ! + ^^|:@^U1%% ! append | ! + 10:@^U1%% ! append ! + ^^|:@^U1%% ! append | ! + .,^Q+.:X1 ! append rest of line ! + +!ERROR! + ZJ ! jump to buf end ! + MW ! refresh scope ! + 0,0XW ! clear W.str (/W switch) ! + 7^T ! sound bell ! + ^^?^T ! display "?" ! + :G1 ! display 1.str ! + 7^T ! sound bell ! + 13^T ! display ! + 10^T ! display ! + -1U1 ! set Z-macro return to -1 ! +' ! endif ! +Q1 ! push Z-macro return val ! +]1 ! restore Q-reg 1 ! +* ! end of ^UZ ! + +! --------------------------------------------------------------------- ! +! Done loading squisher macro into Q-register Z ! +! --------------------------------------------------------------------- ! + +! --------------------------------------------------------------------- ! +! Load squish driver macro into Q-register A ! +! --------------------------------------------------------------------- ! + +@^UA* ! A.str = squish driver macro ! +-1^X ! search flag = exact matches ! +@^UE%.-Z% ! E.str = -# chars to buf end ! +QO"N ! if max line length not 0 ! + ZJ ! jump buf end ! + @I% % ! insert , insure we halt ! +' ! endif ! +J ! jump to beginning of buffer ! +MZ"E ! if squish macro returns OK ! + ! ------------------------------------------------------------- ! + ! at this point, everything is squished; but, if the /L switch ! + ! was set, we've deleted all lexical CR/LF's and have to go ! + ! back and insert CR/LF wherever needed so the line is no ! + ! longer than the width specified with /L:nn. ! + ! ------------------------------------------------------------- ! + QO"N ! if max line length not 0 ! + :QW"N ! if /W was TRUE ! + -1,3:W^[ ! turn on SEEALL mode ! + 0,4:W^[ ! clear "mark" status ! + 0,5:W^[ ! turn off hold mode ! + ' ! endif ! + J ! jump to beginning of buf ! + < ! ----loop begin--------------- ! + MW ! refresh scope ! + ! --------------------------------------------- ! + ! the following loop advances through the edit ! + ! buffer, looking for a character with the high ! + ! bit set. ! + ! --------------------------------------------- ! + < ! ------loop begin------------- ! + 0A&128"N ! if high bit is set ! + 0; ! break out of loop ! + ' ! endif ! + C ! advance 1 char ! + > ! ------loop end--------------- ! + 0A&127-13"E ! if char is ! + D ! delete it ! + ' ! endif ! + D ! delete ! + .-Z; ! break if at end of buf ! + .U0 ! 0.num = current buf ptr ! + ! --------------------------------------------- ! + ! --------------------------------------------- ! + < ! ------loop begin------------- ! + 0A&128"N ! if hi bit clear ! + 0; ! break out of loop ! + ' ! endif ! + C ! advance 1 char ! + > ! ------loop end--------------- ! + ! --------------------------------------------- ! + ! --------------------------------------------- ! + < ! ------loop begin------------- ! + .U1 ! 1.num = cur buf ptr ! + 0L ! go to begin of line ! + .-Q0-1"L ! if ! + 0; ! break out of loop ! + ' ! endif ! + R ! back up one char ! + > ! ------loop end--------------- ! + Q1J + -(0^Q)-QO"G ! if ! + Q0J ! ! + -1A-27"E ! if last char was ESC ! + @I% % ! insert ! + ' ! endif ! + @I% +% ! insert ! + ' ! endif ! + > ! ----loop end----------------- ! + ! ----------------------------------------------------- ! + ! the following loop deletes trailing CR's, LF's, and ! + ! 's from the end of the buffer ! + ! ----------------------------------------------------- ! + < ! ----loop begin--------------- ! + ZJ ! jump to buf end ! + -Z; ! break if buf empty ! + -1A-10"N ! is it LF? ! + -1A-13"N ! is it CR? ! + -1A-32"N ! is it ? ! + 0; ! break ! + ' ! endif ! + ' ! endif ! + ' ! endif ! + -D ! delete it ! + > ! ----loop end----------------- ! + MW ! refresh scope ! + ' ! endif ! + ! ------------------------------------------------------------- ! + ! make sure the edit buffer ends in a CR/LF. ! + ! ------------------------------------------------------------- ! + QH"F ! if no adjacent escapes ! + ZJ ! jump to buf end ! + ."E ! if at beginning of buf ! + 10@I%% ! insert ! + ' ! endif ! + -1A-10"N ! if prev char is not ! + 10@I%% ! insert ! + ' ! endif ! + R ! back up one char ! + ."E ! if at beginning of buf ! + 13@I%% ! insert ! + ' ! endif ! + -1A-13"N ! if prev char is not ! + 13@I%% ! insert ! + ' ! endif ! + ' ! endif ! + ZJ ! jump to buf end ! + ! ------------------------------------------------------------- ! + ! clean up the scope ! + ! ------------------------------------------------------------- ! + :QW"N ! if /W was TRUE ! + 0:W-4"E ! if VT100 in ANSI mode ! + 2,0:W^[ ! set VT100 in VT52 mode ! + ' ! endif ! + -1,3:W^[ ! turn on SEEALL mode ! + 0,4:W^[ ! clear "mark" status ! + MW ! refresh scope ! + ' ! endif ! +| ! else (Z macro returned err) ! + @^A/?Squish run failed; aborting any output +/ ! warn user ! + 0,0XF ! clear F.str ! +' ! endif ! +0^X ! reset search mode flag ! +* ! end of ^UA ! + +! --------------------------------------------------------------------- ! +! Done loading squish driver macro into Q-register A ! +! --------------------------------------------------------------------- ! + +! --------------------------------------------------------------------- ! +! If nothing is in the edit buffer, as them to input the name of the ! +! input file and insert it into the buffer. ! +! --------------------------------------------------------------------- ! + +Z"E ! if edit buffer is empty ! + @I%File <.TES or .TEC>? % ! ask for input file ! + ^^QMR ! get response in Q.str ! + GQ ! and put it into the buffer ! +' ! endif ! +0,0XR ! clear R.str (response macro) ! +0,0XQ ! clear Q.str (user responses) ! + ! end of ^UF ! + +! --------------------------------------------------------------------- ! +! Done loading initialization macro into Q-register F ! +! --------------------------------------------------------------------- ! + + ! execute everything up until this point ! + +! --------------------------------------------------------------------- ! +! S t a r t H e r e ! +! --------------------------------------------------------------------- ! + +@EI%% ! close current EI command ! +MF ! execute initialization macro in F.str ! +0,0XF ! clear F.str ! + +Z"E ! if no command line in buffer ! + @^A%Enter your macro then type MA$$ +% ! ask them to input a macro to squeeze ! +| ! else (the buffer isn't empty) ! + + ! ------------------------------------------------------------- ! + ! If the edit buffer isn't empty, it must contain the input ! + ! filename, and it might contain the output filename like so: ! + ! ! + ! [OUTFILE[.TEC]=]INFILE[.TES] ! + ! ! + ! Executing the F macro above has stripped all the switches ! + ! from the command line in the edit buffer. ! + ! ! + ! First, deal with an output filename. If an output filename ! + ! exists on the command line, we might append a .TEC filetype ! + ! to it if a filetype wasn't specified. Then we'll load Q-reg ! + ! F with "EWfilename$" to open it for output and remove the ! + ! output filename from the buffer. ! + ! ------------------------------------------------------------- ! + + J ! jump to start of buffer ! + :@FS%=%%"S ! if "=" found, have output fn ! + @^UF%EW% ! put "EW" in F.str ! + 0,.:XF ! append fn to F.str ! + .UF ! put cp in F.num ! + -:@S%.%"U ! if no ".", no file type ! + :@^UF%.TEC% ! append ".TEC" ! + ' ! endif ! + QFJ ! jump to end of filename ! + 27:@^UF%% ! append ESC to F.str ! + QB"T ! if any switches ! + ET&64"E ! if not detached ! + :@^UF/ ! append create msg to F ! + @^A%Creating "% + :G* ! append last filespec ! + @^A%" +% ! append " ! + / ! done loading F.str ! + ' ! endif ! + ' ! endif ! + 0,.K ! kill output fn in buffer ! + ' ! endif ! + + ! ------------------------------------------------------------- ! + ! Now, deal with an input filename. If the filename doesn't ! + ! have a filetype, first we'll try .TES; and, if there is no ! + ! .TES file, we'll try .TEC. Once we have an input filename, ! + ! we'll ER it. ! + ! ------------------------------------------------------------- ! + + J ! jump to start of buf ! + :@S%.%"U ! if no ".", no filetype ! + ZJ ! jump to buf end ! + @I%.TES% ! insert ".TES" ! + HXQ ! put input fn in Q.str ! + :@ER%^EQQ%"U ! if ".TES" doesn't exist ! + -@FS%.TES%.TEC% ! try ".TEC" ! + ' ! endif ! + ' ! endif ! + HXQ ! Q.str = input filename ! + HK ! kill buffer ! + @ER%^EQQ% ! open input file ! + QB"T ! if any switches ! + ET&64"E ! if not detached ! + @^A%Squishing "%! display squish message" ! + :G* ! display filespec buffer ! + @^A%" +% ! display " ! + ' ! endif ! + ' ! endif ! + + ! ------------------------------------------------------------- ! + ! If there's no output filename, we'll stay in TECO after ! + ! squishing the input file. If there is an output file, we'll ! + ! exit TECO after squishing. ! + ! ------------------------------------------------------------- ! + + :QF"E ! if no output filename ! + Y ! yank 1st page ! + 128,0ET ! turn off abort-on-error ! + < ! ----loop begin--------------- ! + ^E"T ! if formfeed flag ! + ZJ ! jump to buf end ! + 12@I%% ! insert ! + ' ! endif ! + :A; ! break if append fails ! + > ! ----loop end----------------- ! + MA ! squeeze page ! + MP ! ??? what's in Q-reg P ??? ! + | ! else (we have an output fn) ! + Y ! yank 1st page ! + QB"F ! if no switches ! + 128,0ET ! turn off abort-on-error ! + ' ! endif ! + + ! ----------------------------------------------------- ! + ! if we're at end-of-file after yanking in the first ! + ! page, then squeeze what we've read in and write it ! + ! out. If we're not at end-of-file, then we'll have ! + ! to go into a loop: squeezing the page we have, and ! + ! then reading in the next page. ! + ! ----------------------------------------------------- ! + + ^N"T ! if at end-of-file ! + ^E"T ! if formfeed flag ! + ZJ ! jump to buf end ! + 12@I%% ! insert ! + ' ! endif ! + MA ! squeeze page ! + MF ! open output file ! + HPW ! write page ! + HK ! kill page ! + | ! else ! + MF ! open output file ! + < ! ------loop begin------------- ! + ^E"T ! if formfeed flag ! + ZJ ! jump to buf end ! + 12@I%% ! insert ! + ' ! endif ! + MA ! squeeze current page ! + HPW ! write current page ! + HK ! kill current page ! + :Y; ! break if yank fails ! + > ! ------loop end--------------- ! + ' ! endif ! + EF ! close output file ! + EX ! exit ! + ' ! endif ! +' ! endif ! + diff --git a/lib/sub.tec b/lib/sub.tec new file mode 100644 index 0000000..0fd6454 --- /dev/null +++ b/lib/sub.tec @@ -0,0 +1,9 @@ +:EN*.DIR"FNo subdirectories1310^C' + +<:EN"FOL1'G*I +>!L1!J:S]"FNo subdirectories +^C' +Subdirectories of 0T + +-C0,.XAJJ< :S:"F^C'T-6C.U1I:ENL-2CI*.DIR27II"FOL327II'<:EN27II"FOL227II'I27IIG*27II0LFS]27II.27IIFS.27II]27II0L S:27II.U1S]27IIQ1,.T +SR;127II0,.K>!L3!^C27II!L2!0,.XN0,.KMNL> diff --git a/lib/tst.tec b/lib/tst.tec new file mode 100644 index 0000000..b353d0e --- /dev/null +++ b/lib/tst.tec @@ -0,0 +1,6 @@ +10u.n ! put 10 in main-level q-register .n ! +@^U1/20u.n:m2/27:^U1 ! put 20u.n$:m2$$ in q-register 1 ! +@^U2/:m3/27:^U2 ! put :m3$$ in q-register 2 ! +@^U3/q.n=/27:^U3 ! put q.n=$$ into q-register 3 ! + + diff --git a/lib/tstbsl.tec b/lib/tstbsl.tec new file mode 100644 index 0000000..2349cf5 --- /dev/null +++ b/lib/tstbsl.tec @@ -0,0 +1,92 @@ + + Test the backslash command + + +! test 1: \ to get a number that's terminated by end-of-edit-buffer + test 2: \ to get a number that's terminated by characters + test 3: \ to get a number that's preceded by a unary plus + test 4: \ to get a number that's preceded by a unary minus + test 5: \ to write a digit string into the edit buffer +! + +i1234 + +js1j ! set ^S to 1, to be sure the backslash sets it ! +\-1234"e + .-4"e + ^s+4"e + test 1 passed13^T10^T + | + test 1 failed, ^s is wrong13^T10^T + ' + | + test 1 failed, dot is wrong13^T10^T + ' +| + test 1 failed, should be 123413^T10^T +' + +hki1234xyz + +js1j ! set ^S to 1, to be sure the backslash sets it ! +\-1234"e + .-4"e + ^s+4"e + test 2 passed13^T10^T + | + test 2 failed, ^s is wrong13^T10^T + ' + | + test 2 failed, dot is wrong13^T10^T + ' +| + test 2 failed, should be 123413^T10^T +' + +hki+1234xyz + +js1j ! set ^S to 1, to be sure the backslash sets it ! +\-1234"e + .-5"e + ^s+5"e + test 3 passed13^T10^T + | + test 3 failed, ^s is wrong13^T10^T + ' + | + test 3 failed, dot is wrong13^T10^T + ' +| + test 3 failed, should be 123413^T10^T +' + +hki-1234xyz + +js1j ! set ^S to 1, to be sure the backslash sets it ! +\+1234"e + .-5"e + ^s+5"e + test 4 passed13^T10^T + | + test 4 failed, ^s is wrong13^T10^T + ' + | + test 4 failed, dot is wrong13^T10^T + ' +| + test 4 failed, should be 123413^T10^T +' + +hk +i1js1jhk ! set ^S to 1, to be sure the backslash sets it ! +1234\j::s1234"s + ^s+4"e + test 5 passed13^T10^T + | + test 5 failed, ^s is wrong13^T10^T + ' +| + test 5 failed.13^T10^T +' + +hkex diff --git a/lib/tstcss.tec b/lib/tstcss.tec new file mode 100644 index 0000000..9caed35 --- /dev/null +++ b/lib/tstcss.tec @@ -0,0 +1,73 @@ + + Test the ::S command + + +! test 1: 1-character argument + test 2: 2-character argument + test 3: 3-character argument last char on end-of-buffer + test 4: no argument: use same one as test 3 + test 5: 3-character argument that can't be found +! +iabcdef +3j::sd"s + .-4"e + ^s+1"e + test 1 passed1310 + | + test 1 failed, ^S is wrong13^T10^T + ' + | + test 1 failed, dot is wrong13^T10^T + ' + | + test 1 failed, search failed13^t10^T + ' +3j::sde"s + .-5"e + ^s+2"e + test 2 passed1310 + | + test 2 failed, ^S is wrong13^T10^T + ' + | + test 2 failed, dot is wrong13^T10^T + ' + | + test 2 failed, search failed13^t10^T + ' +3j::sdef"s + .-6"e + ^s+3"e + test 3 passed1310 + | + test 3 failed, ^S is wrong13^T10^T + ' + | + test 3 failed, dot is wrong13^T10^T + ' + | + test 3 failed, search failed13^t10^T + ' +3j::s"s + .-6"e + ^s+3"e + test 4 passed1310 + | + test 4 failed, ^S is wrong13^T10^T + ' + | + test 4 failed, dot is wrong13^T10^T + ' + | + test 4 failed, search failed13^t10^T + ' +3j::sabc"f + .-3"e + test 5 passed1310 + | + test 5 failed, dot is wrong13^T10^T + ' + | + test 5 succeeded, search failed13^t10^T + ' +hkex diff --git a/lib/tstequ.tec b/lib/tstequ.tec new file mode 100644 index 0000000..ac396ba --- /dev/null +++ b/lib/tstequ.tec @@ -0,0 +1,102 @@ + + This file tests the =, ==, ===, :=, :== and :=== commands. + It is dependent on the size in bytes of the variables used to + hold TECO numbers. This test gives the results to be expected + for a 16-bit implementation like TECO-11 and a 32-bit implementation + like TECO-C on a VAX. + + Please strike any key to continue, or ^A to exit + +-1"eex' + + + Test of = command. You should see + + (16-bit implementation) (32-bit implementation) + + -31072 100000 + 2 2 + 1 1 + 0 0 + -1 -1 + -2 -2 + 31072 -100000 + + +100000=2=1=0=-1=-2=-100000= + + Please strike any key to continue, or ^A to exit + +-1"eex' + + Test of == command. You should see + + (16-bit implementation) (32-bit implementation) + + 72460 72460 + 2 2 + 1 1 + 0 0 + 177777 37777777777 + 177776 37777777776 + 105320 37777705320 + + +30000==2==1==0==-1==-2==-30000== + + Please strike any key to continue, or ^A to exit + +-1"eex' + + Test of === command. You should see + + (16-bit implementation) (32-bit implementation) + + 7530 7530 + 2 2 + 1 1 + 0 0 + FFFF FFFFFFFF + FFFE FFFFFFFE + 8AD0 FFFF8AD0 + + +30000===2===1===0===-1===-2===-30000=== + + Please strike any key to continue, or ^A to exit + +-1"eex' + + Test of := command. You should see + +30000,2,1,0,-1,-2,-30000 (16 or 32 bit implementation) + + +30000:=,2:=,1:=,0:=,-1:=,-2:=,-30000:= + + + Please strike any key to continue, or ^A to exit + +-1"eex' + + Test of :== command. You should see + +72460,2,1,0,177777,177776,105320 (16 bit implementation) +72460,2,1,0,37777777777,37777777776,37777705320 (32 bit implementation) + + +30000:==,2:==,1:==,0:==,-1:==,-2:==,-30000:== + + + Please strike any key to continue, or ^A to exit + +-1"eex' + + Test of :=== command. You should see + +7530,2,1,0,FFFF,FFFE,8AD0 (16 bit implementation) +7350,2,1,0,FFFFFFFF,FFFFFFFE,FFFF8AD0 (32 bit implementation) + + +30000:===,2:===,1:===,0:===,-1:===,-2:===,-30000:=== +ex diff --git a/lib/tsto.tec b/lib/tsto.tec new file mode 100644 index 0000000..fa5486b --- /dev/null +++ b/lib/tsto.tec @@ -0,0 +1,129 @@ + + Test the O command. + + +! + Testing jump commands is a little hairy. I do it by setting a +state variable. At every label, I test that we're in the proper state. +! +1us@O!test1! + +!tag2! +qs-4"e + test 4 passed (jumping to 3rd (last) tag in a list works)13^T10^T +| + reached tag2 by mistake, terminating.13^T10^Todone + +' +5usOtest5 + + +!tag1! +qs-3"e + test 3 passed (jumping to 2nd (middle) tag in a list works)13^T10^T +| + reached tag1 by mistake, terminating.13^T10^Todone + +' +4us2@O!tag0,tag1,tag2! + +!tag0! +qs-2"e + test 2 passed (jumping to 0th (first) tag in a list works)13^T10^T +| + reached tag0 by mistake, terminating.13^T10^Todone + +' +3us1@O!tag0,tag1,tag2! + + +!test1! +qs-1"e + test 1 passed (a simple jump works)13^T10^T +| + reached test1 by mistake, terminating.13^T10^Todone + +' +2us0@O!tag0,tag1,tag2! + + + + +!test5! +qs-5"e + test 5 passed (another simple jump, escape-terminated)13^T10^T +| + reached test5 by mistake, terminating.13^T10^Todone + +' + +6us3@O!tag0,tag1,tag2! +qs-6"e + test 6 passed (too large tag index causes fall through)13^T10^T +| + test 6 failed, 13^T10^T +' + +7us-1@O!tag0,tag1,tag2! +qs-7"e + test 7 passed (too small tag index causes fall through)13^T10^T +| + test 7 failed, 13^T10^T +' + +8us2@O!tag0,tag1,,tag2! +qs-8"e + test 8 passed (an index to a null tag causes fall through)13^T10^T +| + test 8 failed, 13^T10^T +' +9us3@O!tag0,tag1,,test9! +test 9 failed, 13^T10^T +10usotest10 + + +!test9! +qs-9"e + test 9 passed (index to tag past null tag works)13^T10^T +| + test 9 failed, 13^T10^T +' +10us2@O!,,test10! + +test 9 failed, 13^T10^T +10usotest10 + +!test10! +qs-10"e + test 10 passed (index to tag past 2 null tags works)13^T10^T +| + test 10 failed, 13^T10^T +' + +11us + +< + < + < + < + @O!endloop2! + > + > + > + !endloop2! + qs-11"e + test 11 passed (jumping from inner to outer loop works)13^T10^T + 12us@O!done! + | + reached endloop2 by mistake, terminating.13^T10^Todone + + ' +> + +!done! +qs-12"e + test 12 passed (jumping completely out of nested loops works)13^T10^T +| + test 12 failed, 13^T10^T +' +ex diff --git a/lib/tstqr.tec b/lib/tstqr.tec new file mode 100644 index 0000000..da3ee64 --- /dev/null +++ b/lib/tstqr.tec @@ -0,0 +1,120 @@ +ei + Test q-register commands + + + +1uaqa-1"nobadtest1' +2ubqb-2"nobadtest1' +3ucqc-3"nobadtest1' +4udqd-4"nobadtest1' +5ueqe-5"nobadtest1' +6ufqf-6"nobadtest1' +7ugqg-7"nobadtest1' +8uhqh-8"nobadtest1' +9uiqi-9"nobadtest1' +10ujqj-10"nobadtest1' +11ukqk-11"nobadtest1' +12ulql-12"nobadtest1' +13umqm-13"nobadtest1' +14unqn-14"nobadtest1' +15uoqo-15"nobadtest1' +16upqp-16"nobadtest1' +17uqqq-17"nobadtest1' +18urqr-18"nobadtest1' +19usqs-19"nobadtest1' +20utqt-20"nobadtest1' +21uuqu-21"nobadtest1' +22uvqv-22"nobadtest1' +23uwqw-23"nobadtest1' +24uxqx-24"nobadtest1' +25uyqy-25"nobadtest1' +26uzqz-26"nobadtest1' +1uAqA-1"nobadtest1' +2uBqB-2"nobadtest1' +3uCqC-3"nobadtest1' +4uDqD-4"nobadtest1' +5uEqE-5"nobadtest1' +6uFqF-6"nobadtest1' +7uGqG-7"nobadtest1' +8uHqH-8"nobadtest1' +9uIqI-9"nobadtest1' +10uJqJ-10"nobadtest1' +11uKqK-11"nobadtest1' +12uLqL-12"nobadtest1' +13uMqM-13"nobadtest1' +14uNqN-14"nobadtest1' +15uOqO-15"nobadtest1' +16uPqP-16"nobadtest1' +17uQqQ-17"nobadtest1' +18uRqR-18"nobadtest1' +19uSqS-19"nobadtest1' +20uTqT-20"nobadtest1' +21uUqU-21"nobadtest1' +22uVqV-22"nobadtest1' +23uWqW-23"nobadtest1' +24uXqX-24"nobadtest1' +25uYqY-25"nobadtest1' +26uZqZ-26"nobadtest1' +-9u0q0+9"nobadtest1' +-8u1q1+8"nobadtest1' +-7u2q2+7"nobadtest1' +-6u3q3+6"nobadtest1' +-5u4q4+5"nobadtest1' +-4u5q5+4"nobadtest1' +-3u6q6+3"nobadtest1' +-2u7q7+2"nobadtest1' +-1u8q8+1"nobadtest1' +0u9q9"nobadtest1' +101,102ua-101"nobadtest1'qa-102"nobadtest1' + test 1 passed (basic U and Q commands work)13^T10^T +otest1done + +!badtest1! + test 1 failed.13^T10^T +!test1done! + +10ua5ub2uc(qa+qb+qc)-17"e +  test 2 passed (q-registers seem to work in expressions)13^T10^T +| +  test 2 failed13^T10^T +' + +! This test helps to see what's really supposed to happen in TECO when + you do a :M command and then refer to local q-registers in the macro. + The correct behavior is to use the local q-registers from the previous + macro level, if there are any. If not, use the ones from the previous + level, etc. The test verifies that three levels deep, values from + level 1 can be accessed if no intervening levels have local q-registers. +! +10u.n ! put 10 in main-level q-register .n ! +@^U1/20u.n:m2/ ! put 20u.n$:m2$$ in q-register 1 ! +27:^U1 +@^U2/:m3/ ! put :m3$$ in q-register 2 ! +27:^U2 +@^U3/q.n/ ! put q.n$$ into q-register 3 ! +27:^U3 +m1+q.n-30"e +  test 3 passed (:M commands use old local q-registers)13^T10^T +| +  test 3 failed13^T10^T +' +:m1+q.n-40"e +  test 4 passed (:M commands use old local q-registers)13^T10^T +| +  test 4 failed13^T10^T +' +! If local macros are called, the : modifier is assumed (no local regs) ! + +10u.n ! put 10 in main-level q-register .n ! +@^U1/20u.nm.2/ ! put 20u.n$m.2$$ in q-register .1 ! +27:^U1 +@^U.2/m.3/ ! put m.3$$ in q-register .2 ! +27:^U.2 +@^U.3/q.n/ ! put q.n$$ into q-register .3 ! +27:^U.3 +:m1+q.n-40"e +  test 5 passed (M. commands use old local q-registers)13^T10^T +| +  test 5 failed13^T10^T +' +ex diff --git a/lib/tstsrc.tec b/lib/tstsrc.tec new file mode 100644 index 0000000..e6d8365 --- /dev/null +++ b/lib/tstsrc.tec @@ -0,0 +1,544 @@ + + + This file tests search commands. + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test some simple searches + + +hk iabcdefghi j +forward search for 1st char  sa .-1"e passed + | failed!!! + ' +forward search for 4th char  sd .-4"e passed + | failed!!! +' +forward search for last char  si .-9"e passed + | failed!!! +' +backwards search for 4th char  -sd .-4"e passed + | failed!!! +' +backwards search for 1st char  -sa .-1"e passed + | failed!!! +' + + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Ea match construct + + +test 1  jsa .-1"e passed + | failed!!! +' +test 2  jsba .-3"e passed + | failed!!! +' +test 3  jsha .-9"e passed + | failed!!! +' +test 4  jsbad .-4"e passed + | failed!!! +' +test 5  jsbaaa .-5"e passed + | failed!!! +' +test 6  jsaaaaaaaaa .-9"e passed + | failed!!! +' +hk +0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./0123456789:;<=>?@[\]^_`{|}~127iiA +test 7  jsa .-77"e passed + | failed!!! +' + + Test the ^Eb match construct + + +hki!@#$%&*() +jsb.-1"etest 1 passed +|test 1 failed!!! +' +js!b.-2"etest 2 passed +|test 2 failed!!! +' +js(b.-9"etest 3 passed +|test 3 failed!!! +' +js!b#.-3"etest 4 passed +|test 4 failed!!! +' +js!bbb.-4"etest 5 passed +|test 5 failed!!! +' +jsbbbbbbbbb.-9"etest 6 passed +|test 6 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! +jsb.-63"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Ec match construct + + +hkiabcdefghi +jsc.-1"etest 1 passed +|test 1 failed!!! +' +jsbc.-3"etest 2 passed +|test 2 failed!!! +' +jshc.-9"etest 3 passed +|test 3 failed!!! +' +jsbcd.-4"etest 4 passed +|test 4 failed!!! +' +jsbccc.-5"etest 5 passed +|test 5 failed!!! +' +jsccccccccc.-9"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#%&'()*+,-/:;<=>?@[\]^`{|}~127iiA +jsc.-64"etest 7 passed +|test 7 failed!!! +' +hki0123456789$. +jscccccccccccc.-12"etest 8 passed +|test 8 failed!!! +' + + Test the ^Ed match construct + + +hki0123456789 +jsd.-1"etest 1 passed +|test 1 failed!!! +' +js1d.-3"etest 2 passed +|test 2 failed!!! +' +js8d.-10"etest 3 passed +|test 3 failed!!! +' +js2d4.-5"etest 4 passed +|test 4 failed!!! +' +js2ddd.-6"etest 5 passed +|test 5 failed!!! +' +jsdddddddddd.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTU +iVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127ii0 +jsd.-119"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Eg match construct + + +^Uadef +hkiabcdefghi +jsGa.-4"etest 1 passed +|test 1 failed!!! +' +0^Ua1:^Ua2:^Ua3:^Ua4:^Ua5:^Ua6:^Ua7:^Ua8:^Ua9:^Ua10:^Ua11:^Ua +12:^Ua13:^Ua14:^Ua15:^Ua16:^Ua17:^Ua18:^Ua19:^Ua20:^Ua21:^Ua +22:^Ua23:^Ua24:^Ua25:^Ua26:^Ua27:^Ua28:^Ua29:^Ua30:^Ua31:^Ua +:^Ua !"#$%&'()*+,-./0123456789:;<=>?@JKLMNOPQRSTU +:^UaVWXYZ[\]^_`jklmnopqrstuvwxyz{|}127i +j:sga"ftest 2 passed +|test 2 failed!!! +' +hkiabcdefghi@ +jsga.-10"etest 3 passed +|test 3 failed!!! +' +hki@ +jsga.-1"etest 4 passed +|test 4 failed!!! +' + + Test the ^El match construct + + + +!10 is line feed, 11 is vertical tab, 12 is form feed! + +hk10i10i10i10i10i10i10i10i11i12i +jsl.-1"etest 1 passed +|test 1 failed!!! +' +hkixx10i10i10i10i10i10i10i11i12i +jsxxl.-3"etest 2 passed +|test 2 failed!!! +' +hkixxxxxxxx11i12i +js l.-10"etest 3 passed +|test 3 failed!!! +' +hk10i10i10i10i10i10i10i10i11i12i +jsllllllllll.-10"etest 4 passed +|test 4 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i13i14i15i16i17i18i19i20i21i22i +23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU +iVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127i12i +jsl.-126"etest 5 passed +|test 5 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Er match construct + + +hki0123456789 +jsr.-1"etest 1 passed +|test 1 failed!!! +' +js1r.-3"etest 2 passed +|test 2 failed!!! +' +js8r.-10"etest 3 passed +|test 3 failed!!! +' +js2r4.-5"etest 4 passed +|test 4 failed!!! +' +js2rrr.-6"etest 5 passed +|test 5 failed!!! +' +jsrrrrrrrrrr.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~127iia +jsr.-67"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Es match construct + + +hki  +jss.-1"etest 1 passed +|test 1 failed!!! +' +hkiab cde +jsbs.-3"etest 2 passed +|test 2 failed!!! +' +hkiab de +jss.-7"etest 3 passed +|test 3 failed!!! +' +hkiab de +jsbsd.-4"etest 4 passed +|test 4 failed!!! +' +hkiab de +jsbsd.-11"etest 5 passed +|test 5 failed!!! +' +hk0i1i2i3i4i5i6i7i8i10i11i12i13i14i15i16i17i18i +19i20i21i22i23i24i25i26i27i28i29i30i31i +i!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ +i[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127ii  +jss.-127"etest 6 passed +|test 6 failed!!! +' + + Test the ^Ev match construct + + +hkiabcdefghij +jsv.-1"etest 1 passed +|test 1 failed!!! +' +jsabv.-3"etest 2 passed +|test 2 failed!!! +' +jsiv.-10"etest 3 passed +|test 3 failed!!! +' +jsbvd.-4"etest 4 passed +|test 4 failed!!! +' +jsbvvv.-5"etest 5 passed +|test 5 failed!!! +' +jsvvvvvvvvvv.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`{|}~127iia +jsv.-93"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Ew match construct + + +hkiABCDEFGHIJ +jsw.-1"etest 1 passed +|test 1 failed!!! +' +jsabw.-3"etest 2 passed +|test 2 failed!!! +' +jsiw.-10"etest 3 passed +|test 3 failed!!! +' +jsbwd.-4"etest 4 passed +|test 4 failed!!! +' +jsbwww.-5"etest 5 passed +|test 5 failed!!! +' +jswwwwwwwwww.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127iiA +jsw.-93"etest 7 passed +|test 7 failed!!! +' + + Test the ^Ex match construct + + +hki0123456789 +jsx.-1"etest 1 passed +|test 1 failed!!! +' +js1x.-3"etest 2 passed +|test 2 failed!!! +' +js8x.-10"etest 3 passed +|test 3 failed!!! +' +js2x4.-5"etest 4 passed +|test 4 failed!!! +' +js2xxx.-6"etest 5 passed +|test 5 failed!!! +' +jsxxxxxxxxxx.-10"etest 6 passed +|test 6 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^N match construct + + +hkiaaaaaaaaab +jsa.-10"etest 1 passed +|test 1 failed!!! +' +jsa^Na.-10"etest 2 passed +|test 2 failed!!! +' +hkiAAAbAAA +jsaaa.-5"etest 3 passed +|test 3 failed!!! +' +hki0123456789x9876543210 +jsd.-11"etest 4 passed +|test 4 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZaZZZZZ +js^N^EW.-27"etest 5 passed +|test 5 failed!!! +' +hkiabcdefghijklmnopqrstuvwxyz#oooo +jsv.-27"etest 6 passed +|test 6 failed!!! +' + + Test the ^S match construct + + +hki!@#$%&*() +js^S.-1"etest 1 passed +|test 1 failed!!! +' +js!^S.-2"etest 2 passed +|test 2 failed!!! +' +js(^S.-9"etest 3 passed +|test 3 failed!!! +' +js!^S#.-3"etest 4 passed +|test 4 failed!!! +' +js!^S^S^S.-4"etest 5 passed +|test 5 failed!!! +' +js^S^S^S^S^S^S^S^S^S.-9"etest 6 passed +|test 6 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! +js^S.-63"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^X match construct + + +hki0123456789 +js^X.-1"etest 1 passed +|test 1 failed!!! +' +js1^X.-3"etest 2 passed +|test 2 failed!!! +' +js8^X.-10"etest 3 passed +|test 3 failed!!! +' +js2^X4.-5"etest 4 passed +|test 4 failed!!! +' +js2^x^x^x.-6"etest 5 passed +|test 5 failed!!! +' +js^X^x^x^X^X^X^X^X^X^X.-10"etest 6 passed +|test 6 failed!!! +' + + The remaining tests test features not found in TECO-11. + +eo-99"lexiting. +oexit' + + Test the ^Em match construct + + +hkiabcdefghi +jsma.-1"etest 1 passed +|test 1 failed!!! +' +jsmd.-4"etest 2 passed +|test 2 failed!!! +' +jsmi.-9"etest 3 passed +|test 3 failed!!! +' +hkiabbbbbc +jsmb.-6"etest 4 passed +|test 4 failed!!! +' +jsa^Embc.-7"etest 5 passed +|test 5 failed!!! +' +jsabbbbb^Emc.-7"etest 6 passed +|test 6 failed!!! +' + + Test the ^E match construct + + +hkiabcdefghi +js<141>.-1"etest 1 passed +|test 1 failed!!! +' +jsb<143>.-3"etest 2 passed +|test 2 failed!!! +' +jsh<151>.-9"etest 3 passed +|test 3 failed!!! +' +jsb<143>d.-4"etest 4 passed +|test 4 failed!!! +' +jsb<143><144><145>.-5"etest 5 passed +|test 5 failed!!! +' +js<141><142><143><144><145><146><147><150><151>.-9"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU +iVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127ii% +js<45>.-128"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^E[a,b,c...] match construct ??? + + +hki!@#$%&*() +js[a,b,%,d].-5"etest 1 passed +|test 1 failed!!! +' +js![a,b,c,@].-2"etest 2 passed +|test 2 failed!!! +' +js([)].-9"etest 3 passed +|test 3 failed!!! +' +js![a,b,c,d,e,f,g,h,i,j,k,l,m,@]#.-3"etest 4 passed +|test 4 failed!!! +' +js!^S^S^S.-4"etest 5 passed +|test 5 failed!!! +' +js^S^S^S^S^S^S^S^S^S.-9"etest 6 passed +|test 6 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! +js^S.-63"etest 7 passed +|test 7 failed!!! +' +!exit! +ex diff --git a/lib/unsqu.tec b/lib/unsqu.tec new file mode 100644 index 0000000..6e290d3 --- /dev/null +++ b/lib/unsqu.tec @@ -0,0 +1,6 @@ +[i@^U.c/i +/27:^U.c@^U.i/qi/27:^U.i27u.e0ui"ec-1%im.cm.if<'0a-^^["e2cm.cm.if<'0a-^^]"e2cm.cm.if<'0a-47"g0a-58"lc-1u.doc' +0a-^^a"ecm.cm.if<'0a-^^A"ecm.cm.if<'0a-^^b"ec-1u.doc'0a-^^B"ec-1u.doc'0a-^^c"ecm.cm.if<'0a-^^C"ecm.cm.if<'0a-^^d"ecm.cm.if<'0a-^^D"ecm.cm.if<'0a-^^e"eoe'0a-^^E"eoe'0a-^^f"eof'0a-^^F"eof'0a-^^g"e2cm.cm.if<'0a-^^G"e2cm.cm.if<'0a-^^h"ecf<'0a-^^H"ecf<'0a-^^i"esu.em.cm.if<'0a-^^I"esu.em.cm.if<'0a-^^j"ecm.cm.if<'0a-^^J"ecm.cm.if<'0a-^^k"ecm.cm.if<'0a-^^K"ecm.cm.if<'0a-^^l"ecm.cm.if<'0a-^^L"ecm.cm.if<'0a-^^m"e2cm.cm.if<'0a-^^M"e2cm.cm.if<'0a-^^n"esu.em.cm.if<'0a-^^N"esu.em.cm.if<'0a-^^o"esu.em.cm.if<'0a-^^O"esu.em.cm.if<'0a-^^q"e2c-1u.doc'0a-^^Q"e2c-1u.doc'0a-^^r"ecm.cm.if<'0a-^^R"ecm.cm.if<'0a-^^s"esu.em.cm.if<'0a-^^S"esu.em.cm.if<'0a-^^t"ecm.cm.if<'0a-^^T"ecm.cm.if<'0a-^^u"e2cm.cm.if<'0a-^^U"e2cm.cm.if<'0a-^^v"ecm.cm.if<' +0a-^^V"ecm.cm.if<'0a-^^w"ecm.cm.if<'0a-^^W"ecm.cm.if<'0a-^^x"e2cm.cm.if<'0a-^^X"e2cm.cm.if<'0a-^^y"ecm.cm.if<'0a-^^Y"ecm.cm.if<'0a-^^z"ec-1u.doc'0a-^^Z"ec-1u.doc'cf"ecm.cm.if<'0a-^^|"ecm.cm.if<'0a-^^b"esu.em.cm.if<'0a-^^B"esu.em.cm.if<'0a-^^c"esu.esu.em.cm.if<'0a-^^C"esu.esu.em.cm.if<'0a-^^d"esu.em.cm.if<'0a-^^D"esu.em.cm.if<'0a-^^n"esu.esu.em.cm.if<'0a-^^N"esu.esu.em.cm.if<'0a-^^r"esu.em.cm.if<'0a-^^R"esu.em.cm.if<' +0a-^^s"esu.esu.em.cm.if<'0a-^^S"esu.esu.em.cm.if<'0a-^^_"esu.esu.em.cm.if<'c>[i diff --git a/lib/unsqu.tes b/lib/unsqu.tes new file mode 100644 index 0000000..9cf255f --- /dev/null +++ b/lib/unsqu.tes @@ -0,0 +1,187 @@ +! This TECO macro indents TECO code to help make it readable + +It does NOT handle @-modified commands correctly or caret-preceeded commands. + +Q-REGISTERS USED: + + q-register usage + + .a true if @-sign modified + .c (text) insert carriage return/line feed + .d true if numeric argument + .i (text) insert indenting spaces + i indenting level +! + +[i + +@^U.c/i +/27:^U.c + +@^U.i/qi/27:^U.i + +27u.e +0ui +< + z-."e1;' + 0u.a + 0u.d + 0u.s +!c! + 0a"ecf<' + 0a-^^^A"ecs^Am.cm.if<' + 0a-^^^B"ec-1u.doc' + 0a-^^^C"ecm.cm.if<' + 0a-^^^D"ecm.cm.if<' + 0a-^^^E"ec-1u.doc' + 0a-^^^G"e2cm.cm.if<' + 0a-8"ec-1u.doc' + 0a-9"es^Eu.em.cm.if<' + 0a-^^^N"ec-1u.doc' + 0a-^^^O"ecm.cm.if<' + 0a-^^^Q"ec-1u.doc' + 0a-^^^R"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^^S"ec-1u.doc' + 0a-^^^T"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^^U"es^Eu.em.cm.if<' + 0a-^^^V"ecm.cm.if<' + 0a-^^^W"ecm.cm.if<' + 0a-^^^X"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^^Z"ec-1u.doc' + 0a-27"ecm.cm.if<' + 0a-^^!"ecs!m.cm.if<' + 0a-^^""e2cm.c%im.if<' + 0a-^^%"e2c-1u.doc' + 0a-^^'"e-4dc-1%im.cm.if<' + 0a-^^@"ec-1q.aoc' + 0a-^^|"e-4dcm.cm.if<' + 0a-^^."ec-1u.doc' + 0a-^^;"ecm.cm.if<' + 0a-^^<"e2cm.c%im.if<' + 0a-^^>"ec-1%im.cm.if<' + 0a-^^["e2cm.cm.if<' + 0a-^^]"e2cm.cm.if<' + 0a-47"g0a-58"lc-1u.doc' + 0a-^^a"ecm.cm.if<' + 0a-^^A"ecm.cm.if<' + 0a-^^b"ec-1u.doc' + 0a-^^B"ec-1u.doc' + 0a-^^c"ecm.cm.if<' + 0a-^^C"ecm.cm.if<' + 0a-^^d"ecm.cm.if<' + 0a-^^D"ecm.cm.if<' + 0a-^^e"eoe' + 0a-^^E"eoe' + 0a-^^f"eof' + 0a-^^F"eof' + 0a-^^g"e2cm.cm.if<' + 0a-^^G"e2cm.cm.if<' + 0a-^^h"ecf<' + 0a-^^H"ecf<' + 0a-^^i"es^Eu.em.cm.if<' + 0a-^^I"es^Eu.em.cm.if<' + 0a-^^j"ecm.cm.if<' + 0a-^^J"ecm.cm.if<' + 0a-^^k"ecm.cm.if<' + 0a-^^K"ecm.cm.if<' + 0a-^^l"ecm.cm.if<' + 0a-^^L"ecm.cm.if<' + 0a-^^m"e2cm.cm.if<' + 0a-^^M"e2cm.cm.if<' + 0a-^^n"es^Eu.em.cm.if<' + 0a-^^N"es^Eu.em.cm.if<' + 0a-^^o"es^Eu.em.cm.if<' + 0a-^^O"es^Eu.em.cm.if<' + 0a-^^q"e2c-1u.doc' + 0a-^^Q"e2c-1u.doc' + 0a-^^r"ecm.cm.if<' + 0a-^^R"ecm.cm.if<' + 0a-^^s"es^Eu.em.cm.if<' + 0a-^^S"es^Eu.em.cm.if<' + 0a-^^t"ecm.cm.if<' + 0a-^^T"ecm.cm.if<' + 0a-^^u"e2cm.cm.if<' + 0a-^^U"e2cm.cm.if<' + 0a-^^v"ecm.cm.if<' + 0a-^^V"ecm.cm.if<' + 0a-^^w"ecm.cm.if<' + 0a-^^W"ecm.cm.if<' + 0a-^^x"e2cm.cm.if<' + 0a-^^X"e2cm.cm.if<' + 0a-^^y"ecm.cm.if<' + 0a-^^Y"ecm.cm.if<' + 0a-^^z"ec-1u.doc' + 0a-^^Z"ec-1u.doc' + c + f< +!e! + c + 0a-^^a"ecm.cm.if<' + 0A-^^a"ecm.cm.if<' + 0a-^^b"es^Eu.em.cm.if<' + 0a-^^B"es^Eu.em.cm.if<' + 0a-^^c"ecm.cm.if<' + 0a-^^C"ecm.cm.if<' + 0a-^^d"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^D"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^f"ecm.cm.if<' + 0a-^^F"ecm.cm.if<' + 0a-^^g"es^Eu.em.cm.if<' + 0a-^^G"es^Eu.em.cm.if<' + 0a-^^h"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^H"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^i"es^Eu.em.cm.if<' + 0a-^^I"es^Eu.em.cm.if<' + 0a-^^j"ec-1u.doc'' + 0a-^^J"ec-1u.doc'' + 0a-^^k"ecm.cm.if<' + 0a-^^K"ecm.cm.if<' + 0a-^^n"es^Eu.em.cm.if<' + 0a-^^N"es^Eu.em.cm.if<' + 0a-^^o"ec-1u.doc'' + 0a-^^O"ec-1u.doc'' + 0a-^^p"ecm.cm.if<' + 0a-^^P"ecm.cm.if<' + 0a-^^q"ecm.cm.if<' + 0a-^^Q"ecm.cm.if<' + 0a-^^r"es^Eu.em.cm.if<' + 0a-^^R"es^Eu.em.cm.if<' + 0a-^^s"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^S"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^t"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^T"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^u"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^U"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^v"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^V"ecq.d"tm.cm.if<|-1u.doc'' + 0a-^^w"es^Eu.em.cm.if<' + 0a-^^W"es^Eu.em.cm.if<' + 0a-^^x"ecm.cm.if<' + 0a-^^X"ecm.cm.if<' + c + f< +!f! + c + 0a-^^'"ecm.cm.if<' + 0a-^^<"ecm.cm.if<' + 0a-^^>"ecm.cm.if<' + 0a-^^|"ecm.cm.if<' + 0a-^^b"es^Eu.em.cm.if<' + 0a-^^B"es^Eu.em.cm.if<' + 0a-^^c"es^Eu.es^Eu.em.cm.if<' + 0a-^^C"es^Eu.es^Eu.em.cm.if<' + 0a-^^d"es^Eu.em.cm.if<' + 0a-^^D"es^Eu.em.cm.if<' + 0a-^^n"es^Eu.es^Eu.em.cm.if<' + 0a-^^N"es^Eu.es^Eu.em.cm.if<' + 0a-^^r"es^Eu.em.cm.if<' + 0a-^^R"es^Eu.em.cm.if<' + 0a-^^s"es^Eu.es^Eu.em.cm.if<' + 0a-^^S"es^Eu.es^Eu.em.cm.if<' + 0a-^^_"es^Eu.es^Eu.em.cm.if<' + c +> + +[i + + diff --git a/lib/upcase.tec b/lib/upcase.tec new file mode 100644 index 0000000..84386eb --- /dev/null +++ b/lib/upcase.tec @@ -0,0 +1,3 @@ +@^uu/<0a-13"e1;'0a"v0a-32id|c'>v/ + q - register U loaded + diff --git a/src/aaout.txt b/src/aaout.txt new file mode 100644 index 0000000..84cefce --- /dev/null +++ b/src/aaout.txt @@ -0,0 +1,469 @@ + AAREADME.TXT + + This directory contains TECO-C, a version of TECO written in C. +It was written in C so the author could move comfortably from VAX/VMS +to various other machines, including MicroVaxes, which couldn't execute +TECO-11 prior to VMS 5.0 because they don't support PDP-11 compatibility +mode. TECO32, distributed with v5.0, solved this problem. + + TECO-C is meant to be a complete implementation of TECO as defined +by the Standard TECO User's Guide, which is in file TECO.DOC. There is no +manual for TECO-C itself, but the Standard TECO manual was the specification +for TECO-C, so it serves as an excellent manual. TECO-C departs from the +Standard manual in only a few places (like no video mode), listed in file +PROBLEMS.TXT. There is quick-and-dirty "wall chart" of all TECO commands +in file WCHART.TXT. + + This version of TECO-C runs under VMX/VMS, MS-DOS, AmigaDOS and Unix +(SunOS, Ultrix and System V on a Data General Aviion). If you find bugs or +have any comments about TECO-C, please contact + + Pete Siemsen Pete Siemsen + 645 Ohio Avenue #302 University of Southern California + Long Beach, Ca. 90814 1020 West Jefferson Blvd. + Los Angeles, CA 90089-0251 + + (213) 433-3059 (home) (213) 740-7391 (work) + + Internet: siemsen@usc.edu + + The following sections describe how to use or build TECO-C for +different environments. The command line syntax is the same as the syntax +for TECO-11 command lines. + + +########################################################################### + U N D E R V A X / V M S + + TECO-C was mostly developed under VAX/VMS. It compiles and links +using VAX C 3.1 under VMS version 5.3. + +To set up: inspect and modify ZVLOGIN.COM and then add it to your + LOGIN.COM + +To compile: inspect/edit ZVBLD.COM, then SUBMIT it + +To link: use the "LT" command (defined in ZVLOGIN.COM) + +To run: inspect/edit the symbol definitions in ZVLOGIN.COM + Note: TECO-C uses the same command line syntax as TECO32 + + +########################################################################### + U N D E R M S - D O S + + TECO-C compiles/links under Turbo C v2.00 under MS-DOS 4.01 and +Concurrent DOS 386 v3.0. + +To build: run MAKE on MAKEFILE.TC. to build TECO from scratch say: + "make -fmakefile.tc -DALL". see MAKEFILE.TC for other make + -D options. also see MAKETECO.BAT. + +To run: use TECO.BAT to edit a file or MUNG.BAT to run a macro, + for example: TECO filename. + + +########################################################################### + U N D E R U N I X + +To compile and link: use the make utility on "makefile.sun" (for SunOS) or + "makefile.ulx" (for Ultrix) or "makefile.dg" (for System V Unix + on a Data General Aviion). + +To run: define aliases and environment variables in your .cshrc file. + Here's an example, assuming my initialization file is named + .tecorc and it's in my home directory, and my macros are in a + directory named tecoc under my main directory. You'll have to + change the directory names, of course. + + setenv TEC_INIT \$/home/sol/siemsen/.tecorc + setenv TEC_LIBRARY /home/sol/siemsen/tecoc/ + alias te '/home/sol/siemsen/tecoc/tecoc teco -nocreate' + alias mung '/home/sol/siemsen/tecoc/tecoc mung' + alias tma '/home/sol/siemsen/tecoc/tecoc make' + +After doing this, "te" runs tecoc. + + +Unix Command line +---- ------- ---- + +To make Unix users more comfortable, TECO-C uses Unix-like options syntax +instead of the familiar "/" style used under VAX/VMS. The options can be +abbreviated. They are (optional characters in square brackets): + +-in[spect] +-noc[reate] +-noi[ni] +-nom[emory] +-sc[roll] +-scroll:nnn:SEEALL + do nnn,7:W and 1,3:W + + +-nop[age] + 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. + + +EZ Mode Control Flag +-- ---- ------- ---- + +To add functionality, TECO-C is sensitive to bits in an extra mode control +flag in addition to the standard ones. Bits in the EZ mode control flag are +used in different ways by different operating systems. Under Unix, bits in +the flag have the following meanings: + + 1 Mark Henderson, who did much of the Unix port, likes the way + VAX/VMS keeps versions of files. VMS appends a semicolon followed + by a version number to files, and has the PURGE command to clean + out old versions of files. If this bit is off, TECO-C will handle + file version numbers, appending the appropriate version number to + file names. Mark supplied a "purge" program (distributed with TECO-C) + for users of this feature. Setting this flag turns off the feature, + to make TECO-C function as expected by the average Unix user. This + flag is set by default. + + 8 I don't know what this flag does. It only makes sense when TECO-C + is compiled with CURSES support. + + 16 If set, when it's time to beep, use an audio beep, and if it fails, + then try a video flash. If clear, try a video flash, and if it + fails, use an audio beep. This bit works only if TECO-C was compiled + with CURSES support. This bit is off by default. + + 32 If set, and split screen scrolling mode is on (see the 7:W command), + TECO-C puts a line between the upper and lower scrolling regions. + If off, don't display a line. This bit works only if TECO-C was + compiled with CURSES support. This bit is off by default. + + 128 If set, don't stop on form feeds when reading. If clear, a form + fed in the input stream stops the read (the standard TECO style). + This bit is off by default. + + 256 If set, use Unix-style newline terminators. This means when files + are read in, carriage-returns are not added to the end of lines, + and when the user types the RETURN key, only a newline is entered + into the command line (usually a carriage-return/line-feed pair is + entered). Old macros (and old TECO users) may get confused if this + bit is set, but it's required if CURSES support is compiled into + TECO-C. + + 2048 If set, use a bottom-tee symbol instead of a diamond to indicate + the end-of-buffer. This bit works only if TECO-C was compiled with + CURSES support. This bit is off by default. + + 8192 If set, don't show CR in SCROLL mode (like standard TECO). If clear, + show CR (a graphics character indicating a carriage return) when in + SCROLL mode. This bit works only if TECO-C was compiled with CURSES + support. This bit is on by default. + + +Filename Memory +-------- ------ + +TECO tries to remember the last file edited by TECO, so that after you've +edited a file once, you can re-edit without having to type the file name +on the command line. TECO-C implements this under Unix by writing and reading +files named /tmp/tecoxxx.tmp, where "xxx" is the process id of the parent +process. + + +NOTE: There is another TECO in C, written by Matt Fichtenbaum, which +runs under Unix. It is part of the DECUS TECO Collection. Contact Pete +Siemsen at the above address for a copy. + +########################################################################### + U N D E R A M I G A D O S + +To compile and link: see makefile.ami, (note: it needs tecoc.lnk) + +Comments from the author of the Amiga code: + + I've completed my TECOC port to the Amiga. It has been tested on an + Amiga 1000 under AmigaDOS 1.3.2. My system configuration is: + + 68000 microprocessor + 2.5 megs memory + 80 meg hard drive + Old Amiga chip set + SAS Institute C for the Amiga version 5.10 + + TECO-C runs in the CLI window it was started from, and it should run + over a terminal hooked to an Amiga serial port as well. + + Adding 'W' command stuff would probably best be done by one of the + termcap ports to the Amiga, however, TECO would have to handle + SIGWINCH-like events, unless it is modified to open it's own window of + a particular size without a resizing gadget. It wouldn't be to hard to + write a terminal driver for Amiga windows using hard-coded escape + sequences either, but then that would lose over a serial port. + +EzFlag +------ + +The EZ flag is system-dependent. Under AmigaDOS, bits in the flag have the +following meanings: + + 128 If set, don't stop on form feeds when reading. If clear, a form + fed in the input stream stops the read (the standard TECO style). + This bit os off by default. + + 256 If set, use Unix-style newline terminators. This means when files + are read in, carriage-returns are not added to the end of lines, + and when the user types the RETURN key, only a newline is entered + into the command line (usually a carriage-return/line-feed pair is + entered). Old macros (and old TECO users) may get confused if this + bit is set, but it's required if CURSES support is compiled into + TECO-C. + + + + +########################################################################### + F I L E S + + + aareadme.txt this readme file + baksrc.c backwards search + bldstr.c build a string with string build constructs + change.tec change macro squished + change.tes change macro source. this macro allows you to + replace one string with another in a group of + files using match constructs. + changes.txt contains teco-c release notes starting from + version 1.00 (TVERSION = 100) + chmacs.h ctype.h for teco-c + clenup.c clean up before exiting teco-c + clpars.h command line parsing macro, created by genclp.c + clpars.tec command line parsing macro squished + clpars.tes command line parsing macro source + cmatch.c match character with match construct + date.tec date macro squished + date.tes date macro source. this macro displays the + date and time. + dchars.h define identifiers for control characters + deferr.h define identifiers for error messages + defext.h EXTERN decarations for global variables + detab.tec de-tabify macro squished + detab.tes de-tabify macro source. this macro converts + tabs to spaces + dir.tec "display directory" macro, in squished form + dir.tes "display directory" macro source. This macro simply + displays the directory. a wildcarded filename + in the edit buffer can control what is displayed. + docjr.c code common to ExeC, ExeJ, and ExeR + doeves.c work code for EV and ES + doflag.c changes a mode control flag (ED,EH,ES,ET,EU,EV,^X) + dscren.h terminal types for 0:W command + echoit.c display character in its printable form + err.c display teco-c's error messages + exea.c execute A + exeats.c execute at-sign @ + exeb.c execute B + exebar.c execute | + exebsl.c execute backslash \ + exec.c execute C + execcc.c execute control-caret ^^ + execln.c execute colon modifiers : and :: + execom.c execute comma , + execrt.c execute caret ^ + execst.c execute a TECO command string + execta.c execute ^A + exectc.c execute ^C + exectd.c execute ^D + execte.c execute ^E + execti.c execute ^I + exectl.c execute ^L + exectn.c execute ^N + execto.c execute ^O + exectp.c execute ^P + exectq.c execute ^Q + exectr.c execute ^R + exects.c execute ^S + exectt.c execute ^T + exectu.c execute ^U + exectv.c execute ^V + exectw.c execute ^W + exectx.c execute ^X + execty.c execute ^Y + exectz.c execute ^Z + exed.c execute D + exedgt.c execute digit (0-9) + exedot.c execute dot . + exedqu.c execute double quote " + exee.c execute E + exeequ.c execute equals =, ==, and === + exeesc.c execute escape + exeexc.c execute exclamation point ! + exeey.c execute EY + exef.c execute F + exefb.c execute FB + exeg.c execute G + exegtr.c execute greater than sign > + exeh.c execute H + exei.c execute I + exeill.c "execute" illegal command + exej.c execute J + exek.c execute K + exel.c execute L + exelbr.c execute left-bracket [ + exelst.c execute less than sign < + exem.c execute M + exen.c execute N + exenul.c execute null ^@ + exenyi.c "execute" not-yet-implemented command + exeo.c execute O + exeopr.c execute operator (+,-,(,#,/,&,^_,*) + exep.c execute P (see singlp.c) + exeprc.c execute percent sign % + exepw.c execute PW + exeq.c execute Q + exeqes.c execute question mark ? + exer.c execute R + exerbr.c execute right bracket ] + exertp.c execute right paren ) + exes.c execute S + exescl.c execute semicolon ; + exet.c execute T + exeu.c execute U + exeund.c execute underscore _ + exeusc.c execute unit separator character ^_ + exev.c execute V + exew.c execute W + exex.c execute X + exey.c execute Y + exez.c execute Z + findes.c find end of string + findqr.c find q-register name + flowec.c flow to end of conditional + flowee.c flow to else part of conditional + flowel.c flow to end of loop + fmtmac.tec PDP-11 .MAC formatter squished + fmtmac.tes PDP-11 .MAC formatter source. this macro does + case formatting for PDP-11 macro (.MAC) source files + format.tec FORTRAN formatter squished + format.tes FORTRAN formatter source. formats the first part of + a FORTRAN source line. + genclp.c generates the command line parsing macro in clpars.h + getara.c get area in edit buffer an "m,n" argument defines + getnma.c get numeric argument off expression stack + inccbp.c increments command buffer pointer + init.c teco-c initializatin routines + insstr.c insert string into edit buffer + isradx.c is digit within current radix? + ln2chr.c convert line-number to character-number (^Q) + lowcase.tec convert edit buffer to lowercase macro, see upcase.tec + makdbf.c make digit buffer, binary to ascii in current radix + makefile.ami AmigaDOS make file + makefile.cct CodeCenter under SunOS + makefile.dg System V Unix make file (works on Data General Aviion) + makefile.sun SunOS make file + makefile.tc Turbo C make file (MS-DOS) + makefile.ulx Ultrix make file + maketeco.bat MS-DOS batch file to make teco. this is probably how + the temdos.exe executable file was made. + makprnt.tec make printable macro squished + makprnt.tes make printable macro squished. this macro makes a + string with embedded control characters printable + makrom.c make room in Q-register for new text + mung.bat MS-DOS batch to execute a teco macro from command line + pg.mem a programmer's guide. it may be useful to anyone + fixing bugs, adding features, or porting teco-c to + a new environment. + pkzip.rsp a PKZIP response file used to build TECOC.ZIP archive + popmac.c pop macro environment off macro stack + problems.txt contains notes about bugs and ideas + pshmac.c push current macro environment on macro stack + pushex.c push expression onto stack, try to reduce it + rdline.c read a line + rdpage.c read a page + readcs.c read command string + replac.c code for search and replace commands + search.c code for most of the search comamnds + search.tec search macro squished + search.tes search macro source. this macro finds a string in + a group of files using teco match constructs + singlp.c does a single P command + skpcmd.c skip over current command in command bufer + squ.bat MS-DOS batch file to run squ.tec w/standard options + squ.tec squish macro squished + squ.tes squish macro source. this macro takes a teco macro + source file and makes it as small and as fast (and + as unreadable) as possible + srclop.c search loop, handles loop arguments for search + sserch.c do a simple search + sub.tec ? + tabort.c terminate teco-c + tctlib.rsp a Turbo C TLIB response file used by makefile.tc + teco.bat MS-DOS batch file to run teco-c + teco.doc Standard TECO documentation from DECUS + teco.tes teco initialization file + tecoc.c the main source module, contains all the definitions + of system-independent global variables, as well as + comments explaining what they are. + tecoc.exe the teco-c executable for VMS + tecoc.h defines structures, general identifiers, and + the in-line debugging scheme. + tecoc.lnk link file needed under AmigaDOS (see makefile.ami) + tecoin.tes teco initialization file + temsdos.exe the teco-c executable for MS-DOS + tst.bat MS-DOS batch file to run the test macros + tst.com VMS command procedure to run the test macros + tstbsl.tec -- + tstcss.tec | + tstequ.tec | these macros contain code which tests some + tsto.tec | aspects of teco-c + tstpw.tec | + tstqr.tec | + tstsrc.tec -- + typbuf.c types a buffer on the screen, converting unprintable + characters to printable as nescessary. + type.tec type a file macro squished + type.tes type a file macro source. this macro apparently + types a file on the console with all kinds of + wonderful options. + typest.c types the erroneous command string for errors + uminus.c unary minus (converts -C to -1C) + unsqu.tec unsquish macro squished + unsqu.tes unsquish macro source. this macro does some simple + formatting of a squished teco macro to make it more + readable (like indenting) + upcase.tec convert edit buffer to uppercase macro, see lowcase.tec + vrbmsg.h verbose forms of teco error messages + vtedit.tec vtedit macro squished + vtedit.tes vtedit macro source. humongous screen editor macro. + note: this macro does NOT run under teco-c. + wchart.txt contains a wall chart of TECO commands + wrpage.c write a page + zamiga.c AmigaDOS system dependent code. + zfirst.c dummy module used if CHECKSUM_CODE is TRUE in zport.h + zfrsrc.c do a forward search using VAX SCANC instruction + zmsdos.c MS-DOS system dependant code + zport.h portability header file. + zunix.c SunOS (Unix) system dependant code + zunkn.c UNKNOWN system dependant code (function stubs) + zvms.c VAX/VMS system dependant code + + + The W command does not work, but the EXEW.C file contains code +to tell you what the command would have done if it had been executed. I used +this to play with executing VTEDIT.TEC under TECOC in order to find bugs. + + I maintain the DECUS TECO Collection, a bunch of stuff relating to +TECO. It includes sources for DEC's TECO-11 v39, three TECOs written in C, +including ones for VAX/VMS, MS-DOS, SunOS (Unix) and Ultrix, the current +Standard TECO manual, two EMACs-like macro packages and LOTS of macros. + + I you have something that you feel should be included in this +collection, or if you would like to improve the software, please contact +me at the above address. + + +Pete Siemsen diff --git a/src/amodem.c b/src/amodem.c new file mode 100644 index 0000000..3f8e65c --- /dev/null +++ b/src/amodem.c @@ -0,0 +1,333 @@ +/***************************************************************************** + This program provides basic communication with a remote computer. +The remote machine is connected to /dev/tty01. It is assumed to be a VAX +running VMS. This program sends whatever is typed at the keyboard to the +remote machine and puts whatever the remote machine sends on the terminal +screen. + When this program is invoked, connections to the serial port and +the keyboard are made and the user is left in the communication state. To +terminate the program, use control-N, then period. + A special feature is the "trapping" of what the modem sends to one +or more files. Basically, the program was written to provide a way to +get a large number of files from the VAX to this machine (XENIX). The idea +is to log in to the VAX and execute a command like "TYPE *.C". When VAX/VMS +types out files which match the wildcard filename "*.C", it +precedes the text of each file with a header line containing the file name. +This program is sensitive to these headers, and uses them to name output +files. Thus, running this program and typing "TYPE *.C" to VMS on the +remote machine should produce one file in the current directory for each +file typed on the remote machine. + This program seems to be similar to the CU program provided by UNIX. +When I wrote the first version of this program, I didn't know about CU. +When I learned of CU, I had trouble getting it working, so I just decided +to use this program. + A feature of setting port characteristics with stty is that the port's +characteristics remain set after the program exits. This is inconvenient in +the case of the console, so this program tries to re-set the characteristics +before exiting. +*****************************************************************************/ +#include +#include +#include +#include +#define BOOLEAN char +#define CMPECHO 0777767 /* complement of ECHO in sgtty.h */ +#define KEY "SD0:[PETE.TECO.TECOC]" +#define KEY_LEN 21 +#define FALSE 0 +#define TRUE 1 +char buffer[100]; /* character buffer */ +char chr; /* one character */ +struct sgttyb cons_cb; /* console charactertistics block */ +int cons_fd; /* console file descriptor */ +int cons_flags_saved; /* saved value of cons_cb.sg_flags */ +BOOLEAN cons_opened; /* console need to be closed? */ +BOOLEAN cons_set; /* console characteristics changed? */ +struct sgttyb modm_cb; /* modem characteristics block */ +int modm_fd; /* modem file descriptor */ +int modm_flags_saved; /* saved value of modm_cb.sg_flags */ +char modm_ispeed_saved; /* saved value of modm_cb.sg_ispeed */ +char modm_ospeed_saved; /* saved value of modm_cb.sg_ospeed */ +BOOLEAN modm_opened; /* does the modem need to be closed? */ +BOOLEAN modm_set; /* modem characteristics changed? */ +int proc_id; /* process identification */ +BOOLEAN trapping; /* trapping modem input to a file? */ +FILE *splice_fp; /* splice file descriptor */ +FILE *trap_fp; /* capture file descriptor */ +reset_modm_port() +{ + modm_cb.sg_ispeed = modm_ispeed_saved; + modm_cb.sg_ospeed = modm_ospeed_saved; + modm_cb.sg_flags = modm_flags_saved; + printf("Amodem: re-sttying the modem port\n"); + if (stty(modm_fd, &modm_cb) != 0) + { + printf("Amodem: couldn't re-stty the modem port\n"); + exit(1); + } +} +close_modm_port() +{ + printf("Amodem: closing the modem port\n"); + if (close(modm_fd) == -1) + { + printf("Amodem: couldn't close the modem port\n"); + exit(1); + } +} +reset_cons_port() +{ + cons_cb.sg_flags = cons_flags_saved; + printf("Amodem: re-sttying the console port\r\n"); + if (stty(cons_fd, &cons_cb) != 0) + { + printf("Amodem: couldn't re-stty the console port\n"); + exit(1); + } +} +close_cons_port() +{ + printf("Amodem: closing the console port\r\n"); + if (close(cons_fd) == -1) + { + printf("Amodem: couldn't close the console port\n"); + exit(1); + } +} +cleanup_and_exit() +{ + if (proc_id == 0) + { + if (trapping) + { + printf("Amodem: closing trap file\r\n"); + if (fclose(trap_fp) == EOF) + printf("cleanup: unable to close trap file\n"); + } + } + else + { + if (cons_set) + reset_cons_port(); + if (cons_opened) + close_cons_port(); + if (modm_set) + reset_modm_port(); + if (modm_opened) + close_modm_port(); + } + exit(1); +} +open_console() /* open console port */ +{ + cons_fd = open("/dev/tty",2); + if (cons_fd == -1) + { + printf ("Amodem: couldn't open the console port\n"); + cleanup_and_exit(); + } + cons_opened = TRUE; + if (gtty(cons_fd, &cons_cb) != 0) + { + printf("Amodem: couldn't gtty the console port\n"); + cleanup_and_exit(); + } + cons_flags_saved = cons_cb.sg_flags; + cons_cb.sg_flags = RAW; + if (stty(cons_fd, &cons_cb) != 0) + { + printf("Amodem: couldn't stty the console port\n"); + cleanup_and_exit(); + } + cons_set = TRUE; +} +open_modem() /* open modem port (serial port A, or /dev/tty01)*/ +{ + modm_fd = open("/dev/tty01",2); + if (modm_fd == -1) + { + printf ("Amodem: couldn't open the modem port\n"); + cleanup_and_exit(); + } + modm_opened = TRUE; + if (gtty(modm_fd, &modm_cb) != 0) + { + printf("Amodem: couldn't gtty the modem port\n"); + cleanup_and_exit(); + } + modm_ispeed_saved = modm_cb.sg_ispeed; + modm_ospeed_saved = modm_cb.sg_ospeed; + modm_cb.sg_ispeed = modm_cb.sg_ospeed = B1200; + modm_flags_saved = modm_cb.sg_flags; + modm_cb.sg_flags = RAW; + if (stty(modm_fd, &modm_cb) != 0) + { + printf("Amodem: couldn't stty the modem port\n"); + cleanup_and_exit(); + } + modm_set = TRUE; +} +cmd_char() +{ +#define FBFSIZ 20 +#define MAXLINE 132 + int idx; + char FNamBuf[FBFSIZ]; + char fline[MAXLINE]; + char *line; + read(cons_fd, &chr, 1); + switch (chr){ + case '.': + if (kill(proc_id, SIGTERM) != 0) + printf("cmd_char: kill failed\n"); + cleanup_and_exit(); + break; + case '\016': + break; + case 's': + case 'S': + printf("\r\nname of file to splice into output: "); + idx = 0; + while (chr != '\15') + { + read(cons_fd, &chr, 1); + write(cons_fd, &chr, 1); + if (chr == '\15') + { + FNamBuf[idx] = '\0'; + write(cons_fd, "\n", 1); + break; + } + else + { + FNamBuf[idx] = chr; + if (idx++ > FBFSIZ) + { + printf("file name too long\r\n"); + chr = '\15'; + return; + } + } + } + if (access(FNamBuf, 4) != 0) + { + printf("that file does not exist\r\n"); + return; + } + if ((splice_fp = fopen(FNamBuf, "r")) == NULL) + { + printf("\tUnable to open %s\r\n", FNamBuf); + return; + } + line = &fline[0]; + for (;;) + { + line = fgets(line, MAXLINE, splice_fp); + if (line == NULL) + break; + write(modm_fd, line, strlen(line) - 1); + write(modm_fd, "\r", 1); + } + if (fclose(splice_fp) == EOF) + { + printf("Unable to close %s\r\n", FNamBuf); + cleanup_and_exit(); + } + break; + default: + printf("\r\n"); + printf("\r\n"); + printf("Control-N options are:"); + printf("\r\n"); + printf("\r\n"); + printf("1.\t. to terminate this program"); + printf("\r\n"); + printf("2.\t^n to send a control-N"); + printf("\r\n"); + printf("3.\ts to splice a file into the output"); + printf("\r\n"); + printf("\r\n"); + break; + } +} +tst_line() /* if line contains the key, trap to file */ +{ + char *index(); + char *semi; + char *tmpptr; + if (strncmp(buffer, KEY, KEY_LEN) == 0) + { + if (trapping) + if (fclose(trap_fp) == EOF) + { + printf("Amodem: unable to close trap file\n"); + cleanup_and_exit(); + } + semi = index(buffer, ';'); + *semi = '\0'; + tmpptr = buffer; + while (*tmpptr != '\0') + { + if (isupper(*tmpptr)) + *tmpptr = tolower(*tmpptr); + tmpptr++; + } + if ((trap_fp = fopen(&buffer[KEY_LEN], "w")) == NULL) + { + printf("Unable to create file AMODEM.OUT\r\n"); + cleanup_and_exit(); + } + trapping = TRUE; + } +} +parent_send() /* reads keyboard, sends to tty01 */ +{ + for (;;) + { + read(cons_fd, &chr, 1); + if (chr == '\016') + cmd_char(); + write(modm_fd, &chr, 1); + } +} +child_receive() /* reads tty01, sends to terminal screen */ +{ + char *ptr; + ptr = &buffer[0]; + for (;;) + { + read(modm_fd, &chr, 1); + write(cons_fd, &chr, 1); + if ((trapping) && (chr != '\r')) + putc(chr, trap_fp); + *ptr++ = chr; + if (chr == '\n') + { + tst_line(); + ptr = &buffer[0]; + } + } +} +main() +{ + cons_opened = cons_set = modm_opened = modm_set = trapping = FALSE; + signal(SIGINT, cleanup_and_exit); + signal(SIGTERM, cleanup_and_exit); + open_console(), + open_modem(); + printf("\r\n"); + printf("\r\n"); + printf("Communication established."); + printf("\r\n"); + printf("\r\n"); + proc_id = fork(); + if (proc_id == -1) + { + printf("Amodem: fork failed\n"); + cleanup_and_exit(); + } + if (proc_id == 0) + child_receive(); + else + parent_send(); +} diff --git a/src/baksrc.c b/src/baksrc.c new file mode 100644 index 0000000..a87c361 --- /dev/null +++ b/src/baksrc.c @@ -0,0 +1,338 @@ +/***************************************************************************** + BakSrc() + This recursive function does a backward search in the edit buffer, +looking for a string which will match the first match construct in the search +buffer. Basically, it is the high-speed part of the search algorithm: it +scans the edit buffer looking for the first character in the search string. + On entry, SStPtr points to the first match construct in the search +buffer. On exit, SStPtr points to the last character of the first match +construct in the search buffer. + SBfPtr points to the character following the last character in +the search string. This function does not modify SBfPtr. + On entry, EBPtr1 points to the place in the edit buffer where +the search starts. On exit, if the search was successful, EBPtr1 will +point to the found character. If the search was unsuccessful, EBPtr1 will +be less than EndSAr. + On entry, EBPtr2 is undefined. On exit, if the search was +successful, EBPtr2 points to the last character of the found string. If +the search was unsuccessful, EBPtr2 is undefined. + EndSAr points to the end of the search area (where the search ends). +Note that for backwards searches, EndSAr is less than EBPtr1. This function +does not modify EndSAr. + Match constructs are: + ^X match any character + ^S match a separator character (not letter or digit) + ^N match anything but following match construct + ^EA match any alphabetic + ^EB match a separator character (not letter or digit) + ^EC match symbol constituent + ^ED match any digit + ^EGq match any character in q-register q + ^EL match any line terminator (LF, VT, FF) + ^EM match non-null string of following match construct + ^ER match any alphanumeric + ^ES match non-null string of spaces and/or tabs + ^EV match lowercase alphabetic + ^EW match uppercase alphabetic + ^EX match any character + ^E match character with ASCII code nnn (octal) + ^E[x1,x2,...xn] match any of the match constructs x1, x2, etc. + else match the character itself +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "chmacs.h" /* define character processing macros */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT BakSrc() /* forward search for 1st search char */ +{ + unsigned char Charac; /* holds a character */ + charptr LstBeg; /* beginning of ^E[x1,x2,...] list */ + char OtCase; /* "other" case character */ + charptr QRPtr; /* pointer into q-register text */ + BOOLEAN SamChr; /* same character indicator */ + charptr SavEP2; /* temporary holder of EBPtr2 */ + charptr SavSSP; /* temporary holder of SStPtr */ + DEFAULT Status; /* FindQR() status for ^EGq */ + charptr TCBfPt; /* temporary holder of CBfPtr */ + charptr TCStEn; /* temporary holder of CStEnd */ + LONG TmpLng; /* holds octal number for ^E */ +#if DEBUGGING + static char *DbgFNm = "BakSrc"; + sprintf(DbgSBf,"*SStPtr = '%c', *EBPtr1 = '%c'", *SStPtr, *EBPtr1); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + switch (*SStPtr) { + case CTRL_X: /* ^X match any char */ + break; + case CTRL_S: /* ^S match separator char */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (!Is_Alnum(*EBPtr1)) { + break; + } + } + break; + case CTRL_N: /* ^Nx match any BUT next match construct */ + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ISS); /* illegal search string */ + DBGFEX(3,DbgFNm,"FAILURE, no ^N arg"); + return FAILURE; + } + SavSSP = SStPtr; + for (;EBPtr1>=EndSAr;--EBPtr1) { + EBPtr2 = EBPtr1; + SStPtr = SavSSP; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, CMatch failed"); + return FAILURE; + } + if (!SamChr) { + break; + } + } + break; + case CTRL_E: /* ^E match construct */ + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); /* ICE = illegal ^E */ + DBGFEX(3,DbgFNm,"FAILURE, no ^E arg"); + return FAILURE; + } + switch (To_Upper(*SStPtr)) { + case 'A': /* ^EA match any alphabetic */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (Is_Alpha(*EBPtr1)) { + break; + } + } + break; + case 'B': /* ^EB match any separator (==^S) */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (!Is_Alnum(*EBPtr1)) { + break; + } + } + break; + case 'C': /* ^EC match symbol constitient */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (Is_SyCon(*EBPtr1)) { + break; + } + } + break; + case 'D': /* ^ED match any digit */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (Is_Digit(*EBPtr1)) { + break; + } + } + break; + case 'G': /* ^EGq match any char in Q-reg q */ + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE, no ^EG arg"); + return FAILURE; + } + TCBfPt = CBfPtr; /* save CBfPtr */ + TCStEn = CStEnd; /* save CStEnd */ + CBfPtr = SStPtr; + CStEnd = SBfPtr; + Status = FindQR(); + SStPtr = CBfPtr; + SBfPtr = CStEnd; + CBfPtr = TCBfPt; /* restore CBfPtr */ + CStEnd = TCStEn; /* restore CStEnd */ + if (Status == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, ^EG FindQR failed"); + return FAILURE; + } + for (; EBPtr1 >= EndSAr; --EBPtr1) { + QRPtr = QR->Start; + while (QRPtr < QR->End_P1) { + if (*QRPtr++ == *EBPtr1) { + goto kludge; + } + } + } +kludge: break; + case 'L': /* ^EL match line terminator */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (IsEOL(*EBPtr1)) { + break; + } + } + break; + case 'M': /* ^EM match multiple next constructs */ + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE, no ^EM arg"); + return FAILURE; + } + SavSSP = SStPtr; + if (BakSrc() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (EBPtr1 < EndSAr) { /* if not found */ + break; + } + SavEP2 = EBPtr2; + while (EBPtr1 > EndSAr) { + EBPtr1--; + EBPtr2 = EBPtr1; + SStPtr = SavSSP; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (!SamChr) { + EBPtr1++; + EBPtr2 = SavEP2; + break; + } + } + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + case 'R': /* ^ER match any alphanumeric */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (Is_Alnum(*EBPtr1)) { + break; + } + } + break; + case 'S': /* ^ES match any spaces/tabs */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if ((*EBPtr1 == SPACE) || (*EBPtr1 == TABCHR)) { + EBPtr2 = EBPtr1; + while (EBPtr1 > EndSAr) { + EBPtr1--; + if ((*EBPtr1 != SPACE) && + (*EBPtr1 != TABCHR)) { + EBPtr1++; + break; + } + } + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + break; + case 'V': /* ^EV match any lowercase char */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (Is_Lower(*EBPtr1)) { + break; + } + } + break; + case 'W': /* ^EW match any uppercase character */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (Is_Upper(*EBPtr1)) { + break; + } + } + break; + case 'X': /* ^EX match any char (==^X) */ + break; + case '<': /* ^E match char w/ASCII octal code n */ + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE, no ^E<> arg"); + return FAILURE; + } + TmpLng = 0; + while (Is_Digit(*SStPtr)) { + TmpLng = (TmpLng * 8) + (*SStPtr - '0'); + if (TmpLng > 127) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + if (*SStPtr != '>') { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + Charac = (unsigned char)TmpLng; + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (*EBPtr1 == Charac) { + break; + } + } + break; + case '[': /* ^E[x1,x2,...] match any one of x1,x2,... */ + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE, no ^E[] arg"); + return FAILURE; + } + LstBeg = SStPtr; + for (; EBPtr1 >= EndSAr; --EBPtr1) { + while (*SStPtr != ']') { + if (*SStPtr == ',') { + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } else { + EBPtr2 = EBPtr1; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (SamChr) { + while (*SStPtr != ']') { + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + EBPtr2 = EBPtr1; + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + } + SStPtr = LstBeg; + } + break; + default: + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE, bad ^E arg"); + return FAILURE; + } /* end of ^E switch */ + break; + default: /* edit buffer char must match search string char */ + if (SMFlag) { /* if case dependence */ + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if (*EBPtr1 == *SStPtr) { + break; + } + } + } else { /* else case independence */ + OtCase = Is_Upper(*SStPtr) + ? To_Lower(*SStPtr) + : To_Upper(*SStPtr); + for (; EBPtr1 >= EndSAr; --EBPtr1) { + if ((*EBPtr1 == *SStPtr) || (*EBPtr1 == OtCase)) { + break; + } + } + } + } /* end of switch */ + EBPtr2 = EBPtr1; + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/bldstr.c b/src/bldstr.c new file mode 100644 index 0000000..9116010 --- /dev/null +++ b/src/bldstr.c @@ -0,0 +1,243 @@ +/***************************************************************************** + BldStr() + This function "builds" a string. This means converting string +build constructs in the input string into their intended equivalents +in the output string. The string build constructs are as follows: + ^Q use next character literally, not as a string build char + ^R use next character literally, not as a string build char + ^V lowercase the next character + ^V^V lowercase all following characters + ^W uppercase the next character + ^W^W uppercase all following characters + ^EQq use string in q-register q here + ^EUq use ASCII char for number in q-register q here + When this function is called, CBfPtr points to the first character +of the input string. It is assumed that the string is terminated by an ESCAPE +character (or something else if the calling command was @-modified). If the +string is not properly terminated this function will die with "unterminated +command" when it encounters CStEnd while looking for the terminator character. + When this function returns, CBfPtr points to the ESCAPE which +terminates the string, the built string is in the buffer pointed to by +XBfBeg, and XBfPtr points to the character after the last character in +the built string. + The commands which contain a filename (EB, EI, EN, ER and +EW) use this function. The EG command, which exits with an operating system +command line, uses this function. The O command, which jumps to a tag, uses +this function. The search commands (E_, FK, FN, FS, F_, N, S and _) use this +function. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "dchars.h" /* define identifiers for characters */ +#include "chmacs.h" /* define character processing macros */ +#if USE_PROTOTYPES +static DEFAULT DoCtVW(charptr EndArg, unsigned char TmpChr); +static DEFAULT DoCtE(charptr EndArg, charptr XBfEnd); +#endif +static charptr BBfPtr; /* pointer into XBf */ +static int CaseCv; /* case conversion */ +static unsigned char WVFlag; /* ^W or ^V flag */ +static DEFAULT DoCtVW(EndArg, TmpChr) /* do a control-V or control-W */ +charptr EndArg; /* ptr to end of string argument */ +unsigned char TmpChr; /* temporary character */ +{ + DBGFEN(3,"DoCtVW",NULL); + WVFlag = TmpChr; + if (++CBfPtr == EndArg) { /* move past ^W or ^V, too far? */ + ErrMsg(ERR_ISS); /* yes, illegal search string */ + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if ((*CBfPtr == '^') && ((EdFlag & ED_CARET_OK) == 0)) { + if (++CBfPtr == EndArg) { + ErrMsg(ERR_ISS); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + TmpChr = To_Upper(*CBfPtr); + if ((TmpChr < '@') || (TmpChr > '_')) { + ErrChr(ERR_IUC, *CBfPtr); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + TmpChr &= '\077'; + } else { + TmpChr = *CBfPtr; + } + if (WVFlag == CTRL_V) { + if (TmpChr == CTRL_V) { + CaseCv = LOWER; + } else { + *BBfPtr++ = To_Lower(TmpChr); + } + } else { + if (TmpChr == CTRL_W) { + CaseCv = UPPER; + } else { + *BBfPtr++ = To_Upper(TmpChr); + } + } + WVFlag = '\0'; + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +static DEFAULT DoCtE(EndArg, XBfEnd) /* do a control-E */ +charptr EndArg; /* ptr to end of string argument */ +charptr XBfEnd; /* end of build-string buffer */ +{ + DEFAULT Status; /* returned from FindQR */ + charptr TCStEn; /* temporary holder of CStEnd */ + DBGFEN(3,"DoCtE",NULL); + if (++CBfPtr == EndArg) { /* move past ^E, too far? */ + ErrMsg(ERR_ICE); /* yes, illegal ^E command */ + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if ((*CBfPtr == 'Q') || (*CBfPtr == 'q')) { + if (++CBfPtr == EndArg) { + ErrMsg(ERR_ISS); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } +/* + * handle filespec buffer and search string buffer + */ + if (*CBfPtr=='*' || *CBfPtr=='_') { + charptr BufPtr, BufBeg; + if (*CBfPtr=='*') { + BufPtr=FBfPtr; + BufBeg=FBfBeg; + } else { + BufPtr=SBfPtr; + BufBeg=SBfBeg; + } + if ((BufPtr-BufBeg) > (XBfEnd-BBfPtr)) { + ErrMsg(ERR_STL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + MEMMOVE(BBfPtr, BufBeg, (SIZE_T)(BufPtr - BufBeg)); + BBfPtr += BufPtr-BufBeg; + } else { +/* + * it really must be a Q reg reference after all + */ + TCStEn = CStEnd; /* save CStEnd */ + CStEnd = EndArg; + Status = FindQR(); + CStEnd = TCStEn; /* restore CStEnd */ + if (Status == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if ((QR->End_P1-QR->Start) > (XBfEnd-BBfPtr)) { + ErrMsg(ERR_STL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + MEMMOVE(BBfPtr, QR->Start, (SIZE_T)(QR->End_P1 - QR->Start)); + BBfPtr += QR->End_P1 - QR->Start; + } + } else if ((*CBfPtr == 'U') || (*CBfPtr == 'u')) { + if (++CBfPtr == EndArg) { + ErrMsg(ERR_ISS); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + TCStEn = CStEnd; /* save CStEnd */ + CStEnd = EndArg; + Status = FindQR(); + CStEnd = TCStEn; /* restore CStEnd */ + if (Status == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + *BBfPtr++ = (char)QR->Number; + } else { + *BBfPtr++ = CTRL_E; + *BBfPtr++ = *CBfPtr; + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +DEFAULT BldStr(XBfBeg, XBfEnd, XBfPtr) /* build a string */ +charptr XBfBeg; /* beginning of build-string buffer */ +charptr XBfEnd; /* end of build-string buffer */ +charptr (*XBfPtr); /* pointer into build-string buffer */ +{ + charptr EndArg; /* end of input string, plus 1 */ + unsigned char TmpChr; /* temporary character */ + DBGFEN(2,"BldStr",NULL); + if (FindES(ESCAPE) == FAILURE) { /* move CBfPtr to end of argument */ + DBGFEX(2,DbgFNm,"FAILURE, FindES(ESCAPE) failed"); + return FAILURE; + } + WVFlag = '\0'; /* initialize ^W and ^V flag */ + CaseCv = IniSrM; /* initialize internal search mode */ + BBfPtr = XBfBeg; /* initialize ptr into build-string buffer */ + EndArg = CBfPtr; /* save pointer to end of argument */ + CBfPtr = ArgPtr; /* reset to beginning of argument */ + while (CBfPtr < EndArg) { + if ((*CBfPtr == '^') && ((EdFlag & ED_CARET_OK) == 0)) { + if (++CBfPtr == EndArg) { + ErrMsg(ERR_ISS); + DBGFEX(2,DbgFNm,"FAILURE, no char after ^"); + return FAILURE; + } + TmpChr = To_Upper(*CBfPtr); + if ((TmpChr < '@') || (TmpChr > '_')) { + ErrChr(ERR_IUC, *CBfPtr); + DBGFEX(2,DbgFNm,"FAILURE, bad char after ^"); + return FAILURE; + } + TmpChr &= '\077'; + } else { + TmpChr = *CBfPtr; + } + switch (TmpChr) { + case CTRL_R: + case CTRL_Q: + if (++CBfPtr == EndArg) { + ErrMsg(ERR_ISS); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + *BBfPtr++ = *CBfPtr; + break; + case CTRL_V: + case CTRL_W: + if (DoCtVW(EndArg, TmpChr) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, DoCtVW failed"); + return FAILURE; + } + break; + case CTRL_E: + if (DoCtE(EndArg, XBfEnd) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, DoCtE failed"); + return FAILURE; + } + break; + default: + if (CaseCv == LOWER) { + TmpChr = To_Lower(TmpChr); + } else if (CaseCv == UPPER) { + TmpChr = To_Upper(TmpChr); + } + *BBfPtr++ = TmpChr; + } + if (BBfPtr > XBfEnd) { + ErrMsg(ERR_STL); /* string too long */ + DBGFEX(2,DbgFNm,"FAILURE, string too long"); + return FAILURE; + } + ++CBfPtr; + } + *XBfPtr = BBfPtr; +#if DEBUGGING + sprintf(DbgSBf,"string = \"%.*s\"", (int)(BBfPtr-XBfBeg), XBfBeg); + DbgFEx(2,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} diff --git a/src/changes.txt b/src/changes.txt new file mode 100644 index 0000000..31249c2 --- /dev/null +++ b/src/changes.txt @@ -0,0 +1,816 @@ + 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/src/chmacs.h b/src/chmacs.h new file mode 100644 index 0000000..ccfe5e8 --- /dev/null +++ b/src/chmacs.h @@ -0,0 +1,22 @@ +/***************************************************************************** + Chmacs.h + These are tested relational expressions. The ones defined for some +C's, like isalnum, tolower, etc do not always work, because they rely on bit +patterns within ASCII. These work. + Note: if this file is included, the tecoc.h file must precede it. +*****************************************************************************/ +extern unsigned char ChrMsk[]; +#define Is_Upper(ch) (ChrMsk[(ch)] & CM_UPPER) +#define Is_Lower(ch) (ChrMsk[(ch)] & CM_LOWER) +#define Is_Digit(ch) (ChrMsk[(ch)] & CM_DIGIT) +#define Is_Alpha(ch) (ChrMsk[(ch)] & (CM_UPPER | CM_LOWER)) +#define Is_Alnum(ch) (ChrMsk[(ch)] & (CM_UPPER | CM_LOWER | CM_DIGIT)) +#define To_Lower(ch) (Is_Upper(ch) ? (ch)+' ' : (ch) ) +#define To_Upper(ch) (Is_Lower(ch) ? (ch)-' ' : (ch) ) +/***************************************************************************** + these are TECO-specific. The above are not. +*****************************************************************************/ +/* is line terminator */ +#define IsEOL(ch) (ChrMsk[(ch)] & CM_LINE_TERM) +/* is symbol constituent */ +#define Is_SyCon(ch) (Is_Alnum(ch) || ch == '.' || ch == '_' || ch == '$') diff --git a/src/clenup.c b/src/clenup.c new file mode 100644 index 0000000..f343842 --- /dev/null +++ b/src/clenup.c @@ -0,0 +1,50 @@ +/***************************************************************************** + ClenUp() + This function "cleans up" in preparation for terminating TECO-C. All +open files are closed and memory is freed. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +VVOID ClenUp (VVOID) /* cleanup for TECO-C abort */ +{ + QRptr QRp; + int i; + ZIClos(PINPFL); /* Close the primary and secondary... */ + ZIClos(SINPFL); /* ...input streams, if they're open */ + ZOClDe(POUTFL); /* Close the primary and secondary... */ + ZOClDe(SOUTFL); /* ...output streams, if they're open */ +/* + * free dynamically allocated buffers + */ + if (CBfBeg) ZFree((voidptr)CBfBeg); /* the command buffer */ + if (DBfBeg) ZFree((voidptr)DBfBeg); /* the digit buffer */ + if (EBfBeg) ZFree((voidptr)EBfBeg); /* the edit buffer */ + if (FBfBeg) ZFree((voidptr)FBfBeg); /* the filename buffer */ + if (SBfBeg) ZFree((voidptr)SBfBeg); /* the search string buffer */ +/* + * free the global [0-35] and main-level local [36-71] Q-registers, + * and then the Q-register stack. + */ + for (QRp = QRgstr, i = 0; i < 72; ++i, ++QRp) { + if (QRp->Start != NULL) { + ZFree((voidptr)QRp->Start); + } + } + for (QRp = QStack, i = 0; i < QRS_SIZE; ++i, ++QRp) { + if (QRp->Start != NULL) { + ZFree((voidptr)QRp->Start); + } + } + ZClnUp(); /* do system-dependent cleanup */ +#if DEBUGGING +{ +/* + * at this point, there shouldn't be any block malloc'ed by TECO-C. + * except if we're here because we EX'ed out of a macro, and we can't + * get to the ZBf buffer allocated in ExeEI, so the ZBf buffer is + * left hanging. + */ +} +#endif +} diff --git a/src/clpars.tec b/src/clpars.tec new file mode 100644 index 0000000..f5cac01 --- /dev/null +++ b/src/clpars.tec @@ -0,0 +1,72 @@ +!CLPARS.TEC V2.3 14-May-2004 Tom Almy, Pete Siemsen, and Mark Henderson! +[F0,0XF[90,0X9[00,0X0[20,0X210U0[0U0[00EDU0[0ED&4EDEUU0[0-1EU +ESU0[00ESETU0[032768#32#8#1,0ETQ1U00U1[10,0X10U4 +(-1EJ-25600)*(-1EJ-25858)"E-UY|/UY'@.T/:QF"E.U.1Iteco0EJ\.-Q1U.L +Q.L-8"GQ.1+4JQ.L-8D4C'I.tmpQ.1,.XFQ.1,.D'/27:.TQ0+1"E32768U0' +32768"E:EITECO"S]1Q0#32768U1[1JODONE''Z"EGZ0,0XZ'J::S^ES"SD' +::STECO32"S-2D'ZJ-:S^ES"S.-Z"EFR''Z"EODONE'Q0&32767U10,0X10,0X9 +J:S^ES^EUYNOI"SONOINI'J:S^EUYNOI"FONONOINI'!NOINI! +D::SN"S-D::SI"S-D''::S^ES"SD0A"AI ''Q1#4096U1!NONOINI!Q1&4096"E +HX0HKEPEAEF:EGINI"SG*J0A-36"EDHX1HK:ER^EQ1"SYHX1HKECG1| +%Can't find initialization file ":G1"1310''0,0X1|0,0X1 +(-1EJ-5)*(-1EJ-1024)"EEN[]*.*:EN"SG*JS[R0KFS.]JS]0,.X1HK'' +:ER^EQ1TECO.INI"SYHX9HKECG90,0X9''EREWZ"NZJ.U0G1I=G0Q0JZX9ZK]1 +]0Q0ET]0Q0ES]0Q0EU]0Q0ED]0Q0]0Q0]2HX0HKG9JS=0,.-1X90,.KM0+0U90,0X0 +[20,0X210U0[0U0[00EDU0[0ED&4EDEUU0[0-1EUESU0[00ES +ETU0[032768#32#8#1,0ET[1G9X1K0,0X9Q9U1J::S^ES"SD' +ZJ-:S^ES"S.-Z"EFR''Z"EOSCOPES'|G0''J:S^ES^EUYNOM"SONOMEMORY' +J:S^EUYNOM"FONONOMEMORY'!NOMEMORY! +D::SE"S-D::SM"S-D::SO"S-D::SR"S-D::SY"S-D''''' +::S^ES"SD0A"AI ''Q1#4U1!NONOMEMORY!J:S^ES^EUYNOC"SONOCREATE' +J:S^EUYNOC"FONONOCREATE'!NOCREATE! +D::SR"S-D::SE"S-D::SA"S-D::ST"S-D::SE"S-D''''' +::S^ES"SD0A"AI ''Q1#256U1!NONOCREATE!J:S^ES^EUYNOP"SONOPAGE' +J:S^EUYNOP"FONONOPAGE'!NOPAGE!D::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"SD0A"AI ''Q1#64U1!NONOPAGE!J:S^ES^EUYNOR"SONORENAME' +J:S^EUYNOR"FONONORENAME'!NORENAME!D::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"SD0A"AI ''Q1#512U1!NONORENAME! +J::STE"S<0A"AC|1;'>::S^ES@"S0KIMUNG ''J::SMU"S-2D<0A"AD|1;'> +::S^ES"SD'(-1EJ-5)*(-1EJ-1024)"EJ::S""S-D::S^ES"SD'''ZU0 +(-1EJ-25600)*(-1EJ-25858)"EJ:S-"SR.-Q0"L.U0''|J:S/"SR.-Q0"L.U0''' +J:S^ES"S.-Q0"L.U0''J"S.-Q1"GF<'''Q1-1J-:S("S:S)"S.-Q1"GF<''' +Q1-1J.-1-Q0"LD.U0'0;>Q0J<-.;-1A-32"N-1A-9"N0;''-D>0,.X.0 +:Q.0"E?How can I MUNG nothing?1310'::S^ES 0,.K0U0EI^EQ.0 +JODONE'J:S^ES^EUYVT"SOVTEDIT'J:S^EUYVT"FONOVTEDIT'!VTEDIT! +The VTEDIT command line option is not supported by TECOC1310 +!NOVTEDIT!J:S^ES+"SD\U40,128EZD::Ss"SD0A"AI '''Q1&64"N0,128EZ' +J:S^ES^EUYSC"SOSCROLL'J:S^EUYSC"FONOSCROLL'!SCROLL! +D::SR"S-D::SO"S-D::SL"S-D::SL"S-D''''::S:^ED"SR-D\U2FR|0U2' +::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D'''''Q1#16U1' +::S^ES"SD0A"AI ''Q1#128U1!NOSCROLL!J::STE"S-2D<0A"AD|1;'> +::S^ES"SD'J:S^ES^EUYIN"SOINSPECT'J:S^EUYIN"FONOINSPECT'!INSPECT! +D::SS"S-D::SP"S-D::SE"S-D::SC"S-D::ST"S-D''''' +::S^ES"SD0A"AI ''Q1#2U1!NOINSPECT!J:S^ES^EUYFI"SOFIND' +J:S^EUYFI"FONOFIND'!FIND! +The /FIND command line option is not supported by TECOC1310 +!NOFIND!J<.-Z;0A-9"EDF<'0A-32"EDF<'C-1A-""E:S""S +(-1EJ-25857)*(-1EJ-25858)"E0J2<@FS/"//>ZJ'|ZJ''>Q1&4#Z"E:EGMEM"SG*J +::S$"SD|OGOTIT'|M.TGF'HX0HKEPEAEF:ER^EQ0"SYL."N-1A-10"E-D'' +."N-1A-13"E-D''ZKHX0HKECG0'EREW0,0X0!GOTIT!ZJZ"NQ1#32768#16384U1'' +Q1&16384"NQ1&2"EEdi|Inspec'ting file "HT"1310'Z"E +Q1&2"EOSCOPES'?How can I inspect nothing?1310'Q1&2"EJ:S="S +0,.-1X00,.KZU0HX2HK:Q2"N:ER^EQ2"UG2HX0HKONOTFND'':Q0"NEW^EQ0'Q0"N +Q1#2048U1'OREMEM''HX0HKQ1&2"E:EB^EQ0"SQ1#2048U1OREMEM':ERQ0"S +Q1#2048U1%Can't write to file -- opening for input only1310OREMEM +'Q1&256"NQ1&32768"EONOTFND''%Can't find file ":G0"1310 +Q1&32768"E%Creating new file1310OCREATE| +%Ignoring TECO's memory1310Q1#8192U10,0X0OREMEM'':ER^EQ0"S +Q1#2048U1OSCOPES'!NOTFND!?Can't find file ":G0"?1310' +J::SMA"S-2D<0A"AD|1;'>::S^ES"SD'J<.-Z;0A-9"EDF<'0A-32"EDF<'C +-1A-""E:S""S(-1EJ-25857)*(-1EJ-25858)"E0J2<@FS/"//>ZJ'|ZJ''> +Z"E?How can I MAKE nothing?1310' +Z-4"EJ::SLOVE"SNot war?1310''HX0HK!CREATE!EW^EQ0OREMEM' +%Unrecognized command "HTHK"1310OSCOPES!REMEM!Q1&8192"E +Q1&(32768#4)"NOSCOPES':Q0"EOSCOPES'':EGMEM"SZJG*C::S$"U +ZK:EGMEM ^EQ0OSCOPES|-1DZXFZK'|M.T'EA:EW^EQF"SG0HPWHKEF'EW!SCOPES! +!YANK!Q1&2048"NY'JQ1&128"NET&512"E +%Your terminal is not an interactive scope1310|Q2"E2:W-4U2'0,3:W +Q1&16"N1,3:W'0,5:WQ1&32"N1,5:W'Q2,7:W-Q2"N +%Your terminal doesn't support scrolling1310'''!DONE!Q4-1"G +Q4-1:S^J"U0J''Q1&64"N0,128EZ'Q1&512"N0,2EZ']1]0Q0ET]0Q0ES]0Q0EU]0Q0ED +]0Q0]0Q0]2]0]9]F0U.10U.L0U40UY0,0X.T diff --git a/src/clpars.tes b/src/clpars.tes new file mode 100644 index 0000000..6b83574 --- /dev/null +++ b/src/clpars.tes @@ -0,0 +1,808 @@ +!CLPARS.TEC V2.3 14-May-2004 Tom Almy, Pete Siemsen, and Mark Henderson! + +!+*************************************************************************** + This macro is the imbedded command-line parsing macro for TECOC. It + was created by extracting the imbedded command-line parsing macro from the + TECO-11 executable file and then modifying it. + + This macro is compiled into TECO-C. This is the human-readable + source code. To compress it (remove comments, extra whitespace, etc.) + into an unreadable version in file CLPARS.TEC, do the following command + with a working TECO: + + mung squ clpars.tec=clpars.tes/d:n/l:y/b:y/t:n/c:+/w:n/a:y/e:n + + Then run genclp to convert CLPARS.TEC into CLPARS.H, a C include file. + + Notes: + + 1. On entry, Q1 contains a value + + 2. Bits in Q-register 1 have the following meanings: + + 1 /VTEDIT + 2 /INSPECT + 4 /NOMEMORY + 8 /FIND + 16 /SEEALL + 32 /HOLD + 64 /NOPAGE + 128 /SCROLL + 256 /NOCREATE + 512 /NORENAME + 1024 unused + 2048 input file is open + 4096 /NOINI + 8192 force setting of filespec memory + 16384 input filename is in edit buffer + 32768 ??? + + 3. Q-register 2 holds numeric argument of /SCROLL:n switch + + 4. Q-register Y holds the command-line option character, which + is a slash on most systems, and a dash under Unix. + + 5. Q-register .T holds a macro which is needed only when the :EGMEM + command isn't supported. It generates (in q-register F) the + name of a file that holds filename memory. + + 6. Q-register F holds the name of the file used to save file names. + + 7. Q-register 4 holds the line number to go to. + +****************************************************************************! + +!+ save the q-registers that we'll be changing ! +[F0,0XF +[90,0X9 +[00,0X0 +[20,0X2 +10U0[0 !+ radix 10 ! +U0[00 !+ case independent searching ! +EDU0[0ED&4ED !+ turn on automatic memory expansion ! +EUU0[0-1EU !+ no case flagging on typeout ! +ESU0[00ES !+ no typeout after searches ! +ETU0[032768#32#8#1,0ET !+ ^C trap, read nowait and noecho, image typeout ! +Q1U0 !+ Q0 = Q1 ! +0U1[1 +0,0X1 +0U4 +(-1EJ-25600)*(-1EJ-25858)"E !+ if Unix or Linux ! + ^^-UY !+ Unix command lines delimit options with '-' ! +| + ^^/UY !+ VMS command lines delimit options with '/' ! +' + +!+*************************************************************************** + Put a subroutine into Q-register .T which, when called, fills Q-register + F with a filename to be used to store filespec memory. This subroutine + will only be needed if the :EGMEM isn't supported. +****************************************************************************! +@^U.T/ + :QF"E !+ if we haven't already set q-register F ! + .U.1 !+ remember where we are in edit buffer ! + Iteco !+ start building "tecoxxxx.tmp" ! + 0EJ\ !+ insert process id into edit buffer ! + .-Q1U.L !+ length of "tecoxxxx" part of filename ! + Q.L-8"G !+ if it's longer than 8 characters ! + Q.1+4J !+ go to front of the digits ! + Q.L-8D !+ prune most significant digits from front ! + 4C !+ and move to the end again ! + ' + I.tmp !+ finish it off ! +!+ RSTS/E and RT-11 aren't supported by TECO-C + -1EJ-4"E ~* if RSTS/E ~ + I<60>-MODE:#3000 + | + -1EJ-7"N ~* if not RT-11 ~ + I;1--CR + ' + ' +! + Q.1,.XFQ.1,.D !+ save it in q-register F and clean up ! + '/ +27:^U.T +!+*************************************************************************** + If we're on RSTS/E, do something special +****************************************************************************! +!+-1EJ-4"E:QZ#Z"E-1G_J::FSdcl tecoTECO"UHK':S ^[J0''! + +Q0+1"E !+ if Q1 was equal to -1 on entry ! + 32768U0 !+ Q0 = 32768 ! +' +32768"E !+ if we're on a 16-bit machine (?) ! + :EITECO"S !+ try to execute macro in file TECO ! + ]1 + Q0#32768U1 + [1 + J + ODONE + ' +' + +!+*************************************************************************** + Get the command line string from q-register Z into the edit buffer +****************************************************************************! + +Z"EGZ0,0XZ' !+ get command line string from Z and clear Z ! +J +::S^ES"S^SD' !+ remove leading whitespace ! +::STECO32"S-2D' !+ change TECO32 to TECO, if needed ! +ZJ-:S^ES"S.-Z"EFR'' !+ remove trailing whitespace ! +Z"EODONE' !+ if there's no command line, don't initialize ! + +Q0&32767U1 +0,0X1 +0,0X9 + +!+*************************************************************************** + If there's a -NOINI switch, (-NOINI if under Unix) delete it, compact + any trailing whitespace, and set the 4096 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOI"SONOINI' +J:S^EUYNOI"FONONOINI' +!NOINI! +^SD::SN"S-D::SI"S-D'' +::S^ES"S^SD0A"AI '' +Q1#4096U1 +!NONOINI! + +!+*************************************************************************** + Execute the initialization file. +****************************************************************************! + +Q1&4096"E !+ if there's no NOINI switch ! + HX0HK !+ save the command line in Q0 ! + EPEA !+ switch to secondary I-O streams ! + EF + +!+ Get the INI macro into the edit buffer ! + + :EGINI"S !+ get the INI file specification ! + G* + J0A-36"ED !+ if the first character is a dollar-sign ! + HX1 + HK + :ER^EQ1"S !+ open the file for reading ! + YHX1HKECG1 !+ and put it's contents into the edit buffer ! + | + %Can't find initialization file ":G1"1310 + ' + ' + 0,0X1 + | !+ else (no defined INI filename) ! + 0,0X1 + (-1EJ-5)*(-1EJ-1024)"E !+ if VAX/VMS ! + EN[]*.*:EN"S !+ get current dir spec into Q1 ! + G*JS[R0KFS.]JS]0,.X1HK + ' + ' + :ER^EQ1TECO.INI"S !+ if TECO.INI exists in current directory ! + YHX9HKECG90,0X9 !+ get it's contents into the edit buffer ! + ' + ' + EREW !+ switch back to primary streams ! + + Z"N !+ if there's an INI macro to execute ! + ZJ + .U0 + G1 + I= + G0 + Q0J + ZX9 + ZK + ]1 + ]0Q0ET + ]0Q0ES + ]0Q0EU + ]0Q0ED + ]0Q0 + ]0Q0 + ]2 + HX0 + HK + G9 + J + S= + 0,.-1X9 + 0,.K + M0+0U9 !+ execute INI macro, save result in Q9 ! + 0,0X0 + [2 + 0,0X2 + 10U0[0 !+ radix 10 ! + U0[00 !+ case independent searching ! + EDU0[0ED&4ED !+ turn on no-memory-expansion bit ! + EUU0[0-1EU !+ no case flagging on typeout ! + ESU0[00ES !+ no typeout after searches ! + ETU0[032768#32#8#1,0ET !+ image mode, ^T noecho and nowait, ^C trap ! + [1 + G9 + X1 + K + 0,0X9 + Q9U1 + J::S^ES"S^SD' !+ delete leading whitespace ! + ZJ-:S^ES"S.-Z"EFR'' !+ delete trailing whitespace ! + Z"E + OSCOPES + ' + | + G0 + ' +' + + +!+*************************************************************************** + If there's a -NOMEMORY switch (-NOMEMORY under Unix), delete it, compact + any trailing whitespace, and set the 4 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOM"SONOMEMORY' +J:S^EUYNOM"FONONOMEMORY' +!NOMEMORY! +^SD::SE"S-D::SM"S-D::SO"S-D::SR"S-D::SY"S-D''''' +::S^ES"S^SD0A"AI '' +Q1#4U1 +!NONOMEMORY! + + +!+*************************************************************************** + If there's a /NOCREATE switch, (-NOCREATE under Unix), delete it, compact + any trailing whitespace, and set the 256 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOC"SONOCREATE' +J:S^EUYNOC"FONONOCREATE' +!NOCREATE! +^SD::SR"S-D::SE"S-D::SA"S-D::ST"S-D::SE"S-D''''' +::S^ES"S^SD0A"AI '' +Q1#256U1 +!NONOCREATE! + + +!+*************************************************************************** + If there's a /NOPAGE switch, (-NOPAGE under Unix), delete it, compact + any trailing whitespace, and set the 64 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOP"SONOPAGE' +J:S^EUYNOP"FONONOPAGE' +!NOPAGE! +^SD::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"S^SD0A"AI '' +Q1#64U1 +!NONOPAGE! + + +!+*************************************************************************** + If there's a /NORENAME switch, (-NORENAME under Unix), delete it, compact + any trailing whitespace, and set the 512 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOR"SONORENAME' +J:S^EUYNOR"FONONORENAME' +!NORENAME! +^SD::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"S^SD0A"AI '' +Q1#512U1 +!NONORENAME! + + +!+*************************************************************************** + If we're not under RSTS/E, and the command is "TECO @file", then change + it to "MUNG file". +****************************************************************************! + +!+ -1EJ-4"N! !+ if not RSTS/E ! +J::STE"S<0A"AC|1;'>::S^ES@"S0KIMUNG '' +!+ '! + + +!+*************************************************************************** + If it's a MUNG command, find the file specification, delete it from + the edit buffer, and do an EI on the file. +****************************************************************************! + +J::SMU"S-2D !+ if it's a MUNG command ! + <0A"AD|1;'> !+ delete alphabetics following MU ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + (-1EJ-5)*(-1EJ-1024)"E !+ if VAX/VMS ! + J::S""S-D !+ and it starts with double quote ! + ::S^ES"S^SD' !+ remove whitespace following the " ! + ' + ' + +!+ The MUNG file specification might be followed by data to be put into + the edit buffer. The file specification and the data are separated by + a comma, a slash, or whitespace. Set Q0 to point to the end of the + file specification, regardless of how its terminated.! + + ZU0 !+ put edit buffer length in Q0 ! + (-1EJ-25600)*(-1EJ-25858)"E !+ if Unix or Linux ! + J:S-"SR.-Q0"L.U0'' !+ if - precedes Q0, change Q0 ! + | + J:S/"SR.-Q0"L.U0'' !+ if / precedes Q0, change Q0 ! + ' + J:S^ES"S.-Q0"L.U0'' !+ if whitespace precedes Q0, change Q0 ! + + J"S.-Q1"GF<''' + Q1-1J-:S("S:S)"S.-Q1"GF<''' + Q1-1J.-1-Q0"LD.U0' + 0; + > + + Q0J<-.;-1A-32"N-1A-9"N0;''-D> !+ delete whitespace preceding Q0 ! + +!+ copy the file specification into q-register .0. If there's no file + specification, complain and die. ! + + 0,.X.0 + :Q.0"E?How can I MUNG nothing?1310' + +!+ delete the file specification and trailing whitespace (if any) from the + edit buffer, execute the MUNG file and we're done. ! + + ::S^ES^[ !+ locate end of whitespace, if any ! + 0,.K !+ delete spec + trailing whitespace ! + 0U0 !+ don't leave trash in Q0 ! + EI^EQ.0 !+ execute the MUNG file ! + JODONE !+ and we're done ! +' + +!+*************************************************************************** + If there's a /VTEDIT (-VTEDIT under Unix), switch... +****************************************************************************! + +J:S^ES^EUYVT"SOVTEDIT' +J:S^EUYVT"FONOVTEDIT' +!VTEDIT! +The VTEDIT command line option is not supported by TECOC1310 + +!+ + ::SE"S^SD::SD"S^SD::SI"S^SD::ST"S^SD'''' + ::S:H"S-2D::SO"S-D::SL"S-D::SD"S-D'''Q1#32U1' + ::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D'''''Q1#16U1' + ::S:H"S-2D::SO"S-D::SL"S-D::SD"S-D'''Q1#32U1' + ::S^ES"S^SD0A"AI '' + Q1#1U1 +! +!NOVTEDIT! + +!+*************************************************************************** + If we're running Unix, check for a +nnn option. If there is one, set + the 128 bit of the EZ flag (to read in the whole file, regardless of form + feeds) and put the number in Q-register 4. +****************************************************************************! + +!+ -1EJ-25600"E if Unix ! + J:S^ES+"S + ^SD\U40,128EZ^sd::ss"S^sD0A"AI '' + ' +!+ ' ! +!+Set EZ flag if nopage! +Q1&64"N0,128ez' + +!+*************************************************************************** + If there's a /SCROLL switch (-SCROLL under Unix), delete it, get the + numeric argument (or default to 0) into q-register 2. + If :SEEALL follows -SCROLL, then set bit 16 of q-register 1. + Delete any trailing whitespace and set bit 128 of q-register 1. +****************************************************************************! + +J:S^ES^EUYSC"SOSCROLL' +J:S^EUYSC"FONOSCROLL' +!SCROLL! +^SD::SR"S-D::SO"S-D::SL"S-D::SL"S-D'''' +::S:^ED"SR-D\U2FR|0U2' !+ get numeric arg into Q2! +::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D''''' + Q1#16U1 +' +::S^ES"S^SD0A"AI '' !+ delete trailing whitespace! +Q1#128U1 +!NOSCROLL! + + +!+*************************************************************************** + If it's a TECO command... +****************************************************************************! + +J::STE"S-2D !+ if it's a TE command ! + <0A"AD|1;'> !+ delete alphabetics following TE ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + +!+*************************************************************************** + If there's a /INSPECT switch, (-INSPECT if under Unix) delete it, compact + any trailing whitespace, and set the 2 bit of q-register 1. +****************************************************************************! + + J:S^ES^EUYIN"SOINSPECT' + J:S^EUYIN"FONOINSPECT' + !INSPECT! + ^SD::SS"S-D::SP"S-D::SE"S-D::SC"S-D::ST"S-D''''' + ::S^ES"S^SD0A"AI '' + Q1#2U1 + !NOINSPECT! + +!+*************************************************************************** + If there's a /FIND switch, (-FIND if under Unix) delete it, compact + any trailing whitespace, and set the 8 bit of q-register 1. +****************************************************************************! + + J:S^ES^EUYFI"SOFIND' + J:S^EUYFI"FONOFIND' + !FIND! + The /FIND command line option is not supported by TECOC1310 +  +!+ + ^SD::SN"S-D::SD"S-D'' + ::S^ES"S^SD0A"AI '' + Q1#8U1 +! + !NOFIND! + +!+ If there's more to the command, then delete preceding whitespace and + if the remainder of the command line contains a quoted string, do a ZJ. ! + + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""S + (-1EJ-25857)*(-1EJ-25858)"E !+ If OS/2 or Linux then delete quotes ! + 0J2<@FS/"//>ZJ'| + ZJ'' !+ if no second quote, go to end ! + > + +!+ Get the remembered file specification into the edit buffer. ! + + Q1&4#Z"E !+ if there's no file name and no -NOMEMORY ! + :EGMEM"S !+ if :EGMEM is supported ! + G*J !+ get it into the edit buffer ! + ::S$"S^SD !+ if leading dollar sign, delete and... ! + |OGOTIT' !+ otherwise got it and get outa here ! + | !+ else :EGMEM isn't supported ! + M.T !+ generate file name in F ! + GF !+ and get it ! + ' + HX0HK !+ save filename in Q0 and clear buffer ! + EPEA !+ select secondary I-O streams ! + EF !+ close current output file ! + :ER^EQ0"S !+ open file (name is in Q0) ! + Y + L + ."N-1A-10"E-D'' !+ remove trailing lf, if any ! + ."N-1A-13"E-D'' !+ remove trailing cr, if any ! + ZK + HX0HK + EC !+ copy input to output and close streams ! + G0 + ' + EREW !+ select primary I-O streams ! + 0,0X0 + !GOTIT! + +!+ If there's a file specification, then delete preceding whitespace and + if the remainder of the filespec contains a quoted string, do a ZJ. ! +!+ However there shouldn't be any whitespace -- don't do this step + because it messes up names with embedded spaces + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""UZJ'' + > +! ZJ !+ but move to end just in case ! + Z"N + Q1#32768#16384U1 + ' + ' !+ endif (no filename and no -NOMEMORY) ! + + Q1&16384"N !+ if input filename in edit buffer ! + Q1&2"E !+ if not -INSPECT ! + Edi + | + Inspec + ' + ting file "HT"1310 + ' + + Z"E !+ if there's no file name ! + Q1&2"EOSCOPES' !+ if not -INSPECT, goto SCOPES ! + ?How can I inspect nothing?1310 +  + ' + + Q1&2"E !+ if not -INSPECT ! + J:S="S !+ if it's ofile=ifile ! + 0,.-1X00,.K !+ save ofile name in Q0 ! + ZU0 !+ save length of ifile name in Q0 ! + HX2HK !+ save ifile name in Q2 ! + :Q2"N !+ if there's an ifile name ! + :ER^EQ2"U !+ try to open the ifile ! + G2HX0HKONOTFND !+ and goto NOTFND if it fails ! + ' + ' + :Q0"N !+ if there's an ofile name ! + EW^EQ0 !+ open the ofile ! + ' + Q0"N !+ if the ifile name length not = 0 ! + Q1#2048U1 !+ remember: input file is open ! + ' + OREMEM + ' + ' + + HX0HK + Q1&2"E !+ if not -INSPECT ! + :EB^EQ0"S !+ open it for reading-writing ! + Q1#2048U1 !+ remember: input file is open ! + OREMEM + ' + :ERQ0"S !+ TAA Added -- try to open for read ! + Q1#2048U1 + %Can't write to file -- opening for input only1310 + OREMEM + ' + Q1&256"N !+ EB failed, so if -NOCREATE ! + Q1&32768"E + ONOTFND + ' + ' + %Can't find file ":G0"1310 + Q1&32768"E + %Creating new file1310 + OCREATE + | + %Ignoring TECO's memory1310 + Q1#8192U1 + 0,0X0 + OREMEM + ' + ' + + :ER^EQ0"S !+ it's -INSPECT, open input file ! + Q1#2048U1 !+ remember: input file is open ! + OSCOPES + ' + + !NOTFND! + ?Can't find file ":G0"?1310 +  +' + + +!+*************************************************************************** + If it's a MAKE command... +****************************************************************************! + +J::SMA"S-2D + <0A"AD|1;'> !+ delete letters following MA ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""S + (-1EJ-25857)*(-1EJ-25858)"E !+ If OS/2 or Linux then delete quotes ! + 0J2<@FS/"//>ZJ'| + ZJ'' !+ if no second quote, go to end ! + > + + Z"E?How can I MAKE nothing?1310' + + Z-4"EJ::SLOVE"SNot war?1310'' + + HX0HK !+ save the filespec in Q0 for REMEM ! + !CREATE! + EW^EQ0 !+ Open file for writing ! + OREMEM !+ and go remember ! +' +%Unrecognized command "HTHK"1310 +OSCOPES +!+*************************************************************************** + Remember the filename in filespec memory. The filespec is in Q0. +****************************************************************************! + +!REMEM! +Q1&8192"E !+ if 8192 bit is off in Q1 ! + Q1&(32768#4)"NOSCOPES' !+ if ??? or -NOMEMORY, goto SCOPES ! + :Q0"EOSCOPES' !+ if Q0 is empty, goto SCOPES ! +' + +!+ The file specification is now in Q0. If :EGMEM is unsupported, a file + is used to implement filespec memory. +! + +:EGMEM"S !+ if :EGMEM is supported ! + ZJG*C !+ append remembered spec to buffer ! + ::S$"U !+ no leading $ ! + ZK:EGMEM ^EQ0 !+ set remembered filespec to Q0 ! + OSCOPES !+ Goto SCOPES ! + | + -1D !+ delete dollar ! + ZXFZK !+ Save in q reg F ! + ' +| + M.T !+ Generate file name ! +' +EA !+ switch to secondary output stream ! +:EW^EQF"S !+ open the file ! + G0 HPW HK EF !+ and write the filespec into it ! + ' + EW !+ switch to primary output stream ! + + +!+*************************************************************************** +****************************************************************************! + +!SCOPES! +!+ -VTEDIT is not supported +Q1&1"N ~* if /VTEDIT ~ + ET&512"E + %Your terminal is not an interactive scope1310 + Q1#1-1U1 + | + 0,3:W ~* clear SEEALL mode ~ + Q1&16"N-1,3:W' ~* if /SEEALL, set SEEALL mode ~ + 0,5:W ~* clear hold mode ~ + Q1&32"N/1,5:W' ~* if /HOLD, set hold mode ~ + ' +' + +Q1&1"E + OYANK +' + +~* load the VTEDIT macro file name into q-register 9 ~ + +:EGVTE"S ~* if :EGVTE is supported ~ + 1G*X9K +| + :@9%DIT% + :Q1"E + (-1EJ-5)*(-1EJ-1024)"E + EN[]*.*:EN"S + ZJ + .U0 + G* + Q0J + S[ R + Q0,.K + FS.] Q0J + S] Q0,.X1 + Q0,ZK + ' + ' + ' +' + +:Q9"N ~* if Q9 isn't empty ~ + :EI^EQ1^EQ9"S + Q1#2048-2048U1 + OYANK + ' +' + +~**************************************************************************** + Get the library directory specification into q-register 1. + If there's no defined library directory, define the default one. +****************************************************************************~ + +:EGLIB"S ~* if there's a defined lib dir ~ + G*X1K ~* use it ~ +| ~* else ~ + -1EJ-0"E @1%LB:[1,2]% | ~* if RSX-11D: LB:[1,2] else~ + -1EJ-1"E @1%LB:[1,2]% | ~* if RSX-11M: LB:[1,2] else~ + -1EJ-2"E @1%LB:[1,2]% | ~* if RSX-11S: LB:[1,2] else~ + -1EJ-3"E @1%LB:[1,2]% | ~* if IAS: LB:[1,2] else~ + (-1EJ-5)*(-1EJ-1024)"E ~* if VAX/VMS ~ + @1%SYS$LIBRARY:% | ~* SYS$LIBRARY: else~ + -1EJ-6"E @1%LB:[1,2]% | ~* if RSX-11S: LB:[1,2] else~ + -1EJ-7"E @1%SY:% | ~* if RT-11: SY: else~ + @1%% ~* default: nothing ~ + ''''''' +' + +:Q1"N ~* if there's a library directory ~ + :EI^EQ1VTEDIT"S ~* execute the macro in there ~ + Q1#2048-2048U1 + OYANK + ' +' +%The :G9 macro is not available1310 +! + + +!+**************************************************************************! + +!YANK! +Q1&2048"N !+ if input file is open ! + Y !+ read in the first page ! +' + +J +!+ +Q1&8"N ~* if /FIND ~ + Finding position marker...1310 + EW G* + X0 + K + -1 + :Q0"N + :N~~/\~~ +"S^SD' + U0 + | + :_~~/\~~ +"S^SD' + U0 + ' + 0 + Q0"U + ?Position marker not found?1310 +  + ' +' +! + + +!+*************************************************************************** + On entry, Q2 contains the numeric argument given in the -SCROLL:n + switch, or 0 if no -SCROLL switch was specified. +****************************************************************************! + +Q1&128"N !+ if -SCROLL ! + ET&512"E + %Your terminal is not an interactive scope1310 + | + Q2"E + 2:W-4U2 + ' + 0,3:W Q1&16"N !+ if -SEEALL ! + 1,3:W ' + 0,5:W Q1&32"N !+ if -HOLD! + 1,5:W ' + Q2,7:W-Q2"N + %Your terminal doesn't support scrolling1310 + ' + ' +' + +!+*************************************************************************** +****************************************************************************! + +!DONE! +q4-1"G !+ if q4 greater than 1 ! + q4-1:s^J"U0J' !+ search for q4th line feed ! +' +q1&64"N !+ NOPAGE switch? ! + 0,128EZ +' +q1&512"N !+ NORENAME switch? ! + 0,2EZ +' +]1 +]0Q0ET +]0Q0ES +]0Q0EU +]0Q0ED +]0Q0 +]0Q0 +]2 +]0 +]9 +]F +0U.10U.L0U40UY0,0X.T !+ reset q registers ! + diff --git a/src/cmatch.c b/src/cmatch.c new file mode 100644 index 0000000..26a22d7 --- /dev/null +++ b/src/cmatch.c @@ -0,0 +1,279 @@ +/***************************************************************************** + CMatch() + This recursive function trys to match one match construct with the +character pointed to by EBPtr2. It sets SamChr, which indicates whether the +match was successful or not. SStPtr is left pointing to the last character +of the match construct. + If the match construct is ^Em or ^S, then EBPtr2 will be updated to +point to the last matched character. In this case, RhtSid is needed to +indicate the limit past which EBPtr2 should not be incremented. + Match constructs are: + ^X match any character + ^S match a separator character (not letter or digit) + ^N match anything but following match construct + ^EA match any alphabetic + ^EB match a separator character (not letter or digit) + ^EC match symbol constituent + ^ED match any digit + ^EGq match any character in q-register q + ^EL match any line terminator (LF, VT, FF) + ^EM match non-null string of following match construct + ^ER match any alphanumeric + ^ES match non-null string of spaces and/or tabs + ^EV match lowercase alphabetic + ^EW match uppercase alphabetic + ^EX match any character + ^E match character with ASCII code nnn (octal) + ^E[x1,x2,...xn] match any of the match constructs x1, x2, etc. + else match the character itself +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "chmacs.h" /* define character processing macros */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT CMatch(SamChr) /* match a character */ +BOOLEAN *SamChr; /* returned match indicator */ +{ + BOOLEAN ChrMat; /* character match indicator */ + char OtCase; /* "other" case character */ + charptr QRPtr; /* pointer into q-register text */ + charptr SavEP2; /* temporary holder of EBPtr2 */ + charptr SavSSP; /* temporary holder of SStPtr */ + DEFAULT Status; /* FindQR() status for ^EGq */ + charptr TCBfPt; /* temporary holder of CBfPtr */ + charptr TCStEn; /* temporary holder of CStEnd */ + unsigned int TmpChr; /* accumulator for ^E */ +#if DEBUGGING + static char *DbgFNm = "CMatch"; + sprintf(DbgSBf,"*SStPtr = '%c', *EBPtr2 = '%c'", *SStPtr, *EBPtr2); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + switch (*SStPtr) { + case CTRL_X: + *SamChr = TRUE; + break; + case CTRL_S: + *SamChr = !Is_Alnum(*EBPtr2); + break; + case CTRL_N: + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ISS); /* ill. search str. */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (CMatch(&ChrMat) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + *SamChr = !ChrMat; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, *SamChr = %s", + (*SamChr == TRUE) ? "TRUE" : "FALSE"); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + case CTRL_E: + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); /* ICE = illegal ^E */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + switch (To_Upper(*SStPtr)) { + case 'A': + *SamChr = Is_Alpha(*EBPtr2); + break; + case 'B': + *SamChr = !Is_Alnum(*EBPtr2); + break; + case 'C': + *SamChr = Is_SyCon(*EBPtr2); + break; + case 'D': + *SamChr = Is_Digit(*EBPtr2); + break; + case 'G': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); /* ill. ^E command */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + TCBfPt = CBfPtr; /* save CBfPtr */ + TCStEn = CStEnd; /* save CStEnd */ + CBfPtr = SStPtr; + CStEnd = SBfPtr; + Status = FindQR(); + SStPtr = CBfPtr; + SBfPtr = CStEnd; + CBfPtr = TCBfPt; /* restore CBfPtr */ + CStEnd = TCStEn; /* restore CStEnd */ + if (Status == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + QRPtr = QR->Start; + while (QRPtr < QR->End_P1) { + if (*QRPtr++ == *EBPtr2) { + *SamChr = TRUE; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, *SamChr = %s", (*SamChr)?"TRUE":"FALSE"); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + } + *SamChr = FALSE; + break; + case 'L': + *SamChr = IsEOL(*EBPtr2); + break; + case 'M': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + SavSSP = SStPtr; + if (CMatch(&ChrMat) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + *SamChr = ChrMat; + if (ChrMat) { + while (EBPtr2 <= RhtSid) { + SavEP2 = EBPtr2; + ++EBPtr2; + SStPtr = SavSSP; + if (CMatch(&ChrMat) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (!ChrMat) { + EBPtr2 = SavEP2; + break; + } + } + } +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, *SamChr = %s",(*SamChr)?"TRUE":"FALSE"); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + case 'R': + *SamChr = Is_Alnum(*EBPtr2); + break; + case 'S': + if ((*EBPtr2 != SPACE) && (*EBPtr2 != TABCHR)) { + *SamChr = FALSE; + } else { + *SamChr = TRUE; + while (EBPtr2 <= RhtSid) { + ++EBPtr2; + if ((*EBPtr2 != SPACE) && (*EBPtr2 != TABCHR)) { + EBPtr2--; + break; + } + } + } + break; + case 'V': + *SamChr = Is_Lower(*EBPtr2); + break; + case 'W': + *SamChr = Is_Upper(*EBPtr2); + break; + case 'X': + *SamChr = TRUE; + break; + case '<': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3, DbgFNm,"FAILURE"); + return FAILURE; + } + TmpChr = 0; + while (Is_Digit(*SStPtr)) { + TmpChr *= 8; + TmpChr += *SStPtr - '0'; + if (TmpChr > 255) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + if (*SStPtr != '>') { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + *SamChr = (*EBPtr2 == (unsigned char)TmpChr); + break; + case '[': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + while (*SStPtr != ']') { + if (*SStPtr == ',') { + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } else { + if (CMatch(&ChrMat) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (ChrMat) { + while (*SStPtr != ']') { + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + *SamChr = TRUE; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, *SamChr = %s", + (*SamChr) ? "TRUE" : "FALSE"); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + } + break; + default: + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } /* end of ^E switch */ + break; + default: + if (SMFlag == 0) { /* if case independence */ + OtCase = Is_Upper(*SStPtr) ? To_Lower(*SStPtr) + : To_Upper(*SStPtr); + *SamChr = ((*EBPtr2 == *SStPtr) || (*EBPtr2 == OtCase)); + } else { + *SamChr = (*EBPtr2 == *SStPtr); + } + } /* end of switch */ +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, *SamChr = %s", (*SamChr) ? "TRUE" : "FALSE"); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} diff --git a/src/dchars.h b/src/dchars.h new file mode 100644 index 0000000..48bab5d --- /dev/null +++ b/src/dchars.h @@ -0,0 +1,37 @@ +/***************************************************************************** + DChars.h + This header file defines identifiers for control characters. +*****************************************************************************/ +#define CTRL_A '\001' /* SOH - start of heading */ +#define CTRL_B '\002' /* STX - start of text */ +#define CTRL_C '\003' /* ETX - end of text */ +#define CTRL_D '\004' /* EOT - end of transmission */ +#define CTRL_E '\005' /* ENQ - enquiry */ +#define CTRL_F '\006' /* ACK - acknowledge */ +#define CTRL_G '\007' /* BEL - bell */ +#define BAKSPC '\010' /* BS - backspace control H */ +#define TABCHR '\011' /* HT - horizontal tab control I */ +#define LINEFD '\012' /* LF - line feed control J */ +#define VRTTAB '\013' /* VT - vertical tab control K */ +#define FORMFD '\014' /* FF - form feed control L */ +#define CRETRN '\015' /* CR - carriage return control M */ +#define CTRL_N '\016' /* SO - shift out */ +#define CTRL_O '\017' /* SI - shift in */ +#define CTRL_P '\020' /* DLE - data link escape */ +#define CTRL_Q '\021' /* DC1 - device control 1 */ +#define CTRL_R '\022' /* DC2 - device control 2 */ +#define CTRL_S '\023' /* DC3 - device control 3 */ +#define CTRL_T '\024' /* DC4 - device control 4 */ +#define CTRL_U '\025' /* NAK - negative acknowledge */ +#define CTRL_V '\026' /* SYN - synchronous idle */ +#define CTRL_W '\027' /* ETB - end of transmission block */ +#define CTRL_X '\030' /* CAN - cancel */ +#define CTRL_Y '\031' /* EM - end of medium */ +#define CTRL_Z '\032' /* SUB - substitute */ +#define ESCAPE '\033' /* ESC - escape control [ */ +#define FSCHAR '\034' /* FS - file separator control \ */ +#define GSCHAR '\035' /* GS - group separator control ] */ +#define RSCHAR '\036' /* RS - record separator control ^ */ +#define USCHAR '\037' /* US - unit separator control _ */ +#define SPACE '\040' /* SP - space */ +#define DELETE '\177' /* DEL - delete */ diff --git a/src/deferr.h b/src/deferr.h new file mode 100644 index 0000000..ac8b7ec --- /dev/null +++ b/src/deferr.h @@ -0,0 +1,93 @@ +/***************************************************************************** + DefErr.h + This file defines identifiers for error messages generated by TECOC-C. +The codes that are commented out are those that were defined in TECO-11, but +are not used by TECOC-C. + IMPORTANT: if you change this file, you will need to change +TECOC.RNH, DEFERR.H, VRBMSG.H and ERR.C. +*****************************************************************************/ +#define ERR_XXX -1 /* no error */ +#define ERR_ARG 0 /* improper arguments */ +#define ERR_BNI 1 /* > not in iteration */ +#define ERR_DTB 2 /* delete too big */ +#define ERR_FNF 3 /* file not found "filename" */ +#define ERR_ICE 4 /* illegal ^E command in search argument */ +#define ERR_IEC 5 /* illegal character "x" after E */ +#define ERR_IFC 6 /* illegal character "x" after F */ +#define ERR_IIA 7 /* illegal insert argument */ +#define ERR_ILL 8 /* illegal command "x" */ +#define ERR_ILN 9 /* illegal number */ +#define ERR_IPA 10 /* negative or 0 argument to P */ +#define ERR_IQC 11 /* illegal character "x" following " */ +#define ERR_IQN 12 /* illegal q-register name "x" */ +#define ERR_IRA 13 /* illegal radix argument to ^R */ +#define ERR_ISA 14 /* illegal search argument */ +#define ERR_ISS 15 /* illegal search string */ +#define ERR_IUC 16 /* illegal character "x" following ^ */ +#define ERR_MAP 17 /* missing ' */ +#define ERR_MEM 18 /* memory overflow */ +#define ERR_NAB 19 /* no argument before ^_ */ +#define ERR_NAC 20 /* no argument before , */ +#define ERR_NAE 21 /* no argument before = */ +#define ERR_NAP 22 /* no argument before ) */ +#define ERR_NAQ 23 /* no argument before " */ +#define ERR_NAS 24 /* no argument before ; */ +#define ERR_NAU 25 /* no argument before U */ +#define ERR_NCA 26 /* negative argument to , */ +#define ERR_NFI 27 /* no file for input */ +#define ERR_NFO 28 /* no file for output */ +#define ERR_NYA 29 /* numeric argument with Y */ +#define ERR_NYI 30 /* not yet implemented */ +#define ERR_OFO 31 /* output file already open */ +#define ERR_PDO 32 /* push-down list overflow */ +#define ERR_PES 33 /* attempt to pop empty stack */ +#define ERR_POP 34 /* attempt to move pointer off page with "x" */ +#define ERR_SNI 35 /* ; not in iteration */ +#define ERR_SRH 36 /* search failure "text" */ +#define ERR_STL 37 /* string too long */ +#define ERR_TAG 38 /* missing tag !tag! */ +#define ERR_UTC 39 /* unterminated command "x" */ +#define ERR_UTM 40 /* unterminated macro */ +#define ERR_XAB 41 /* execution aborted */ +#define ERR_YCA 42 /* Y command aborted */ +/* + * The following errors aren't listed in the Standard TECO Manual, but + * were added for use by TECO-C. + */ +#define ERR_IFE 43 /* ill-formed numeric expression */ +#define ERR_SYS 44 /* %s */ +#define ERR_UCD 45 /* unable to close and delete output file */ +#define ERR_UCI 46 /* unable to close input file */ +#define ERR_UCO 47 /* unable to close output file */ +#define ERR_UFI 48 /* unable to open file "x" for input */ +#define ERR_UFO 49 /* unable to open file "x" for output */ +#define ERR_URC 50 /* unable to read character from terminal */ +#define ERR_URE 51 /* unable to read TECO command file */ +#define ERR_URL 52 /* unable to read line from input file */ +#define ERR_UWL 53 /* unable to write line to output file */ +/* + Standard TECO errors that possibly should be generated by TECOC-C: +?CON Confused use of conditionals +?FER File error +?INP Input error +?OUT Output error + Standard TECO errors not used by TECO-C are: +?CCL CCL.SV not found or EG argument too long +?CPQ Can't pop into Q-register (TECO-C uses PES) +?DEV Invalid device +?ERR RSTS/E error message (RSTS/E only) +?FUL Output Command would have overflowed output device +?IFN Illegal character "x" in filename +?MLA Missing Left Angle Bracket +?MLP Missing ( +?MRA Missing Right Angle Bracket +?MRP Missing ) +?MSC Missing Start of Conditional +?NPA Negative or 0 argument to P (TECO-C uses IPA) +?NRO No room for output +?UTM Unterminated macro +?WLO System Device Write-Locked +?nnn I/O Error or Directive Error (RSX-11 only) +%Superseding existing filed (TECO-11 only) +%Search fail in iter (TECO-11 only) +*/ diff --git a/src/defext.h b/src/defext.h new file mode 100644 index 0000000..c198836 --- /dev/null +++ b/src/defext.h @@ -0,0 +1,89 @@ +/***************************************************************************** + DefExt.h + This header file declares as EXTERN all the variables declared as +GLOBAL in Tecoc.c for use by everyone else. +*****************************************************************************/ +EXTERN charptr AraBeg; /* beginning of text m,n area */ +EXTERN charptr AraEnd; /* end of text m,n area */ +EXTERN charptr ArgPtr; /* beginning of text argument */ +EXTERN charptr CBfBeg; /* command buffer beginning */ +EXTERN charptr CBfEnd; /* command buffer end */ +EXTERN charptr CBfPtr; /* pointer into command string */ +EXTERN char CmdMod; /* command modifiers flags for @, ;, etc. */ +EXTERN DEFAULT CrType; /* value of 0:W (terminal type) */ +EXTERN charptr CStBeg; /* command string beginning */ +EXTERN charptr CStEnd; /* pointer to last char of command string */ +EXTERN DEFAULT CurInp; /* index of current input stream in IFiles */ +EXTERN DEFAULT CurOut; /* index of current output stream in OFiles */ +EXTERN charptr DBfBeg; /* digit buffer beginning */ +EXTERN charptr DBfPtr; /* digit buffer pointer */ +#if DEBUGGING +EXTERN char DbgSBf[]; /* debug message sprintf() buffer */ +#endif +EXTERN charptr EBfBeg; /* edit buffer beginning */ +EXTERN charptr EBfEnd; /* edit buffer end */ +EXTERN charptr EBPtr1; /* pointer to start of found string */ +EXTERN charptr EBPtr2; /* pointer to end of found string */ +EXTERN WORD EdFlag; /* ED mode control flag */ +EXTERN WORD EhFlag; /* EH mode control flag */ +EXTERN charptr EndSAr; /* end of search area */ +EXTERN char ErrTxt[]; /* holds part of error message */ +EXTERN WORD EsFlag; /* ES mode control flag */ +EXTERN WORD EStBot; /* expression stack bottom */ +EXTERN struct EStck EStack[]; /* expression stack */ +EXTERN WORD EStTop; /* expression stack top */ +EXTERN WORD EtFlag; /* ET mode control flag */ +EXTERN WORD EuFlag; /* EU mode control flag */ +EXTERN WORD EvFlag; /* EV mode control flag */ +EXTERN WORD EzFlag; /* EZ mode control flag */ +EXTERN charptr FBfBeg; /* beginning of filename buffer */ +EXTERN charptr FBfEnd; /* end of filename buffer */ +EXTERN charptr FBfPtr; /* pointer into filename buffer */ +EXTERN LONG FFPage; /* form feed flag (returned by ^E command) */ +EXTERN charptr GapBeg; /* edit buffer gap beginning */ +EXTERN charptr GapEnd; /* end of edit buffer gap */ +EXTERNV BOOLEAN GotCtC; /* TRUE if the user just hit a control-C */ +EXTERN charptr IBfEnd; /* end of input buffer */ +EXTERN charptr IBfEnd; /* input buffer end */ +EXTERN int IniSrM; /* initial search mode */ +EXTERN BOOLEAN IsEofI[]; /* input file has reached end of file */ +EXTERN BOOLEAN IsOpnI[]; /* input file is opened indicators */ +EXTERN BOOLEAN IsOpnO[]; /* output file is opened indicators */ +EXTERN WORD LStBot; /* loop stack bottom */ +EXTERN struct LStck LStack[]; /* loop stack */ +EXTERN struct LStck LStack[]; /* loop stack */ +EXTERN WORD LstErr; /* number of last error message */ +EXTERN WORD LStTop; /* loop stack top */ +EXTERN LONG MArgmt; /* m part of m,n numeric argument pair */ +EXTERN BOOLEAN Matchd; /* indicates successful search */ +EXTERN struct MStck MStack[]; /* macro stack */ +EXTERN WORD MStTop; /* macro stack top */ +EXTERN LONG NArgmt; /* numeric argument */ +EXTERN QRptr QR; /* pointer to q-register structure */ +EXTERN struct QReg QRgstr[]; /* global q-registers */ +EXTERN struct QReg QStack[]; /* q-register stack */ +EXTERN WORD QStTop; /* top of q-register stack */ +EXTERN DEFAULT Radix; /* TECO-C's current radix, 2-36 */ +EXTERN LONG RefLen; /* value returned by ^S command */ +EXTERN charptr RhtSid; /* right-hand side of area to be searched */ +EXTERN charptr SBfBeg; /* search string buffer beginning */ +EXTERN charptr SBfEnd; /* search string buffer end */ +EXTERN charptr SBfPtr; /* end of search string, plus one */ +EXTERN LONG SIncrm; /* search increment, 1 (forward), -1 (back) */ +EXTERN WORD SMFlag; /* search mode flag */ +EXTERN WORD SrcTyp; /* type of search (E_SEARCH, N_SEARCH, etc) */ +EXTERN charptr SStPtr; /* pointer into search string */ +EXTERN BOOLEAN TraceM; /* trace mode flag */ +#if VIDEO +EXTERN DEFAULT HldFlg; /* value of 5:W (hold mode flag) */ +EXTERN DEFAULT HtSize; /* value of 1:W (screen width) */ +EXTERN DEFAULT MrkFlg; /* value of 4:W */ +EXTERN DEFAULT ScroLn; /* value of 7:W */ +EXTERN DEFAULT SeeAll; /* value of 3:W */ +EXTERN DEFAULT TopDot; /* value of 6:W */ +EXTERN DEFAULT VtSize; /* value of 2:W (screen height) */ +#if CURSES +EXTERN DEFAULT SpcMrk; /* value of 8:W */ +EXTERN DEFAULT KeyPad; /* value of 9:W */ +#endif +#endif diff --git a/src/docjr.c b/src/docjr.c new file mode 100644 index 0000000..91e552a --- /dev/null +++ b/src/docjr.c @@ -0,0 +1,54 @@ +/***************************************************************************** + DoCJR() + This function contains the code that's common to the C, J and R +commands. It is called by ExeC, ExeJ and ExeR only. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT DoCJR(HowFar) /* do C, J or R stuff */ +LONG HowFar; /* positive or negative displacement */ +{ + LONG InRange; + BOOLEAN ColonMod; +#if DEBUGGING + static char *DbgFNm = "DoCJR"; + sprintf(DbgSBf,"HowFar = %ld", HowFar); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + ColonMod = (CmdMod & COLON); /* is it :C, :J, or :R? */ + CmdMod &= ~COLON; /* clear : flag */ + InRange = -1; /* -1 means SUCCESS in TECO */ + if (HowFar > 0) { + if ((GapEnd+HowFar) > EBfEnd) { + InRange = 0; /* 0 means FAILURE in TECO */ + } else { + MEMMOVE(GapBeg, GapEnd+1, HowFar); + GapBeg += HowFar; + GapEnd += HowFar; + } + } else { + if ((GapBeg+HowFar) < EBfBeg) { + InRange = 0; /* 0 means FAILURE in TECO */ + } else { + GapBeg += HowFar; + GapEnd += HowFar; + MEMMOVE(GapEnd+1, GapBeg, -(HowFar)); + } + } + if (ColonMod) { /* if colon modifier */ + DBGFEX(2,DbgFNm,"PushEx"); + return PushEx(InRange, OPERAND); + } else { + if (InRange == 0) { /* if out-of-bounds */ + ErrChr(ERR_POP, *CBfPtr); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/doeves.c b/src/doeves.c new file mode 100644 index 0000000..6b3975c --- /dev/null +++ b/src/doeves.c @@ -0,0 +1,88 @@ +/***************************************************************************** + DoEvEs() + This function "does" what's specified by the EV (edit verify) or +ES (search verify) flag. The ES and EV flags are mode control flags that +allow the user to cause TECO to display a part of the edit buffer after +executing a command string (edit verify) or after a search (search verify). +Both the ES and EV flags are 0 by default, which means don't do anything. +This function is only called when the ES or EV flag is non-zero. + The flag is passed to this function for decoding. This function +examines the flag and acts accordingly. Both the ES and EV flags have the +following meaning: + -1 do a 1V command to display the current line + 0 do nothing (this function is not even called) + 1-31 type out current line with line-feed at CP + 32-255 type out current line with ASCII character (32-255) at CP + else bottom byte as above, top byte is argument to V command +*****************************************************************************/ +#if CURSES /* need to define standout and standend? */ +#if ULTRIX +#include /* note: this has to come before zport.h */ +#else +#include /* note: this has to come before zport.h */ +#endif +#endif +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +VVOID DoEvEs(Flag) /* EV or ES flag code */ +WORD Flag; +{ + unsigned char PtChar; /* special "CP" character */ + unsigned char VLines; /* argument to V command */ + if (Flag == 0) { + return; + } + if (Flag == -1) { /* -1 means do a 1V command */ + VLines = 1; /* view 1 line */ + PtChar = '\0'; + } else { + PtChar = (unsigned char)Flag; + VLines = (unsigned char)(Flag >> 8); + if (VLines == 0) { /* be sure it's at least 1 */ + VLines = 1; + } + } + TypBuf(GapBeg+Ln2Chr((LONG)1 - (LONG)VLines), GapBeg); +#if CURSES + if (GapEnd+1 < EBfEnd) { + unsigned char c = *(GapEnd + 1); + standout(); + if (c=='\b') { + ZDspBf("^H", 2); + } else if (c=='\r') { + ZDspBf("^M", 2); + } else if (c=='\n') { + ZDspBf("^J", 2); + } else if (c & 0200) { + int i; + char a,b; + c = c & 0177; + i = c/16; + if (i==0) + a='8'; + else if (i==1) + a=9; + else + a = i - 2 + 'A'; + i = (c % 16); + b = (i > 9) ? i - 10 + 'A' : i + '0'; + ZDspCh('['); + ZDspCh(a); + ZDspCh(b); + ZDspCh(']'); + } else + ZDspCh(c); + standend(); + TypBuf(GapEnd+2, GapEnd + Ln2Chr((LONG)VLines)+1); + } +#else + if ((PtChar >= '\001') && (PtChar <= '\037')) { + ZDspCh(LINEFD); + } else if (PtChar != 0) { + ZDspCh(PtChar); + } + TypBuf(GapEnd+1, GapEnd+Ln2Chr((LONG)VLines)+1); +#endif +} diff --git a/src/doflag.c b/src/doflag.c new file mode 100644 index 0000000..471ce9b --- /dev/null +++ b/src/doflag.c @@ -0,0 +1,38 @@ +/***************************************************************************** + DoFlag() + This function gets or sets the value of a TECO mode control flag. + The TECO mode control flags are ED, EH, ES, ET, EU, EV, EZ and ^X. +The EO flag can only be examined, not set, so ExeEO does not call this +function. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT DoFlag(Flag) /* handle a mode control flag */ +WORD *Flag; +{ + DBGFEN(2,"DoFlag",NULL); + if ((EStTop == EStBot) || /* if no numeric arg or */ + (EStack[EStTop].ElType != OPERAND)) { /* partial expression */ + DBGFEX(2,DbgFNm,"PushEx"); + return PushEx((LONG)*Flag, OPERAND); /* return the flag */ + } + if (GetNmA() == FAILURE) { /* get the numeric argument */ + DBGFEX(2,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if ((CmdMod & MARGIS) == '\0') { /* if it's n */ + *Flag = (WORD)NArgmt; /* set the flag to n */ + } else if (MArgmt && NArgmt) { /* else if it's m,n */ + *Flag &= (WORD)~MArgmt; /* turn off m bits */ + *Flag |= (WORD)NArgmt; /* turn on n bits */ + } else if ((MArgmt == 0) && NArgmt) { /* else if it's 0,n */ + *Flag |= (WORD)NArgmt; /* turn on n bits */ + } else if ((MArgmt) && (NArgmt == 0)) { /* else if it's m,0 */ + *Flag &= (WORD)~MArgmt; /* turn off m bits */ + } + EStTop = EStBot; /* clear expression stack */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/dscren.h b/src/dscren.h new file mode 100644 index 0000000..fab065e --- /dev/null +++ b/src/dscren.h @@ -0,0 +1,24 @@ +/***************************************************************************** + DScren.h + Terminal types (0:W command, CrType variable). The strange +numbering is what is used in TECO-11. +*****************************************************************************/ +#define UNTERM -1 /* unknown */ +#define VT52 0 /* VT52 */ +#define VT61 1 /* VT61 */ +#define VT100V 2 /* VT100 in VT52 mode */ +#define VT100 4 /* VT100 in ANSI mode */ +#define VT05 6 /* VT05 */ +#define VT102 8 /* VT102 */ +#define VK100 10 /* VK100 */ +#define VT200 11 /* VT200 in VT200 mode */ +#define VT200A 12 /* VT200 in ANSI (VT100) mode */ +#define VT200V 13 /* VT200 in VT52 mode */ +#define IBMPC 14 /* IBM PC console */ +/***************************************************************************** + Screen function codes. These are used in calls to ZScrOp. +*****************************************************************************/ +#define SCR_CUP 1 /* move cursor up 1 row */ +#define SCR_EEL 2 /* erase to end of line */ +#define SCR_RON 3 /* reverse-video on */ +#define SCR_ROF 4 /* reverse-video off */ diff --git a/src/echoit.c b/src/echoit.c new file mode 100644 index 0000000..a82db1e --- /dev/null +++ b/src/echoit.c @@ -0,0 +1,51 @@ +/***************************************************************************** + EchoIt() + This function displays a character in it's printable form, either +as CH, ^CH, or [CH]. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global identifiers */ +#include "dchars.h" /* define identifiers for characters */ +VVOID EchoIt(Charac) +unsigned char Charac; +{ + if (Charac > USCHAR && Charac < DELETE) { /* displayable? */ + ZDspCh(Charac); + } else if (Charac & '\200') { /* eighth bit set? */ + if (EtFlag & ET_EIGHTBIT) { /* term can display */ + ZDspCh(Charac); + } else { + ZDspCh('['); /* display as [ch] */ + MakDBf((LONG)Charac,16); + *DBfPtr++ = ']'; + ZDspBf(DBfBeg, DBfPtr-DBfBeg); + } + } else { + switch (Charac) { + case BAKSPC: + case TABCHR: + case LINEFD: + case CRETRN: + ZDspCh(Charac); + break; + case ESCAPE: + ZDspCh('$'); + break; + case FORMFD: + ZDspCh('\r'); + /* fall through to VRTTAB */ + case VRTTAB: + ZDspBf("\n\n\n\n", 4); + break; + case DELETE: + break; + case CTRL_G: + ZDspCh(CTRL_G); + /* fall through to default case */ + default: /* display as ^ch */ + ZDspCh('^'); + ZDspCh(Charac | '\100'); + } + } +} diff --git a/src/err.c b/src/err.c new file mode 100644 index 0000000..7a900df --- /dev/null +++ b/src/err.c @@ -0,0 +1,273 @@ +/***************************************************************************** + ErrChr(), ErrMsg(), ErrStr(), ErrUTC(), ErrVrb() + These functions display TECO's error messages. + ErrChr display a message that contains a special character + ErrMsg display a message given the message number + ErrStr display a message that contains a special string + ErrUTC display UTC or UTM based on macro stack depth + ErrVrb display the verbose form of an error message +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define error message codes */ +#include "dchars.h" /* define identifiers for characters */ +#include /* prototype for strlen() */ +#if USE_PROTOTYPES +static VVOID ErrDsp(WORD ErrNum, unsigned char *ELine); +static VVOID ToErr(unsigned char Charac, charptr *PtrPtr); +#endif +/**** + IMPORTANT: if you change this list, you must also change DEFERR.H, + TECOC.RNH and VRBMSG.H !!! +****/ +static char *Errors[] = { +/* 0*/ "ARG Improper arguments", +/* 1*/ "BNI > not in iteration", +/* 2*/ "DTB Delete too big", +/* 3*/ "FNF File not found \"%s\"", +/* 4*/ "ICE Illegal ^E command in search argument", +/* 5*/ "IEC Illegal character \"%s\" after E", +/* 6*/ "IFC Illegal character \"%s\" after F", +/* 7*/ "IIA Illegal insert argument", +/* 8*/ "ILL Illegal command \"%s\"", +/* 9*/ "ILN Illegal number", +/* 10*/ "IPA Negative or 0 argument to P", +/* 11*/ "IQC Illegal \" character", +/* 12*/ "IQN Illegal Q-register name \"%s\"", +/* 13*/ "IRA Illegal radix argument to ^R", +/* 14*/ "ISA Illegal search argument", +/* 15*/ "ISS Illegal search string", +/* 16*/ "IUC Illegal character \"%s\" following ^", +/* 17*/ "MAP Missing '", +/* 18*/ "MEM Memory overflow", +/* 19*/ "NAB No argument before ^_ ", +/* 20*/ "NAC No argument before ,", +/* 21*/ "NAE No argument before =", +/* 22*/ "NAP No argument before )", +/* 23*/ "NAQ No argument before \"", +/* 24*/ "NAS No argument before ;", +/* 25*/ "NAU No argument before U", +/* 26*/ "NCA Negative argument to ,", +/* 27*/ "NFI No file for input", +/* 28*/ "NFO No file for output", +/* 29*/ "NYA Numeric argument with Y", +/* 30*/ "NYI Not yet implemented", +/* 31*/ "OFO Output file already open", +/* 32*/ "PDO Push-down list overflow", +/* 33*/ "PES Attempt to pop an empty stack", +/* 34*/ "POP Attempt to move pointer off page with \"%s\"", +/* 35*/ "SNI ; not in iteration", +/* 36*/ "SRH Search failure \"%s\"", +/* 37*/ "STL String too long", +/* 38*/ "TAG Missing tag !%s!", +/* 39*/ "UTC Unterminated command", +/* 40*/ "UTM Unterminated macro", +/* 41*/ "XAB Execution aborted", +/* 42*/ "YCA Y command aborted", +/* 43*/ "IFE ill-formed numeric expression", +/* 44*/ "SYS %s", +/* 45*/ "UCD unable to close and delete output file %s", +/* 46*/ "UCI unable to close input file", +/* 47*/ "UCO unable to close output file", +/* 48*/ "UFI unable to open file %s for input", +/* 49*/ "UFO unable to open file %s for output", +/* 50*/ "URC unable to read character from terminal", +/* 51*/ "URE unable to read TECO command file", +/* 52*/ "URL unable to read line from input file", +/* 53*/ "UWL unable to write line to output file" +}; +/***************************************************************************** + ErrUTC() + Simply call ErrMsg with either ERR_UTC (unterminated command) or +ERR_UTM (unterminated macro) depending on whether we're in a macro or not. +*****************************************************************************/ +VVOID ErrUTC() +{ + ErrMsg((MStTop < 0) ? ERR_UTC : ERR_UTM); +} +/***************************************************************************** + ErrVrb() + This function displays the verbose form of an error message. +The verbose form is a short paragraph explaining the error condition in +some detail. This function is called from ErrDsp when the least significant +two bits of the EH flag are set to 3, or from FrstCh when the user types +a / immediately after receiving a short error message. + Verbose explanations of error messages are stored in the HELP system +so that they can be accessed using the HELP command. Therefore this function +calls ZHelp to display the verbose messages. +*****************************************************************************/ +VVOID ErrVrb(ErrNum) /* display verbose error message */ +WORD ErrNum; /* error message number */ +{ + DBGFEN(3,"ErrVrb",NULL); + ZVrbos(ErrNum, Errors[ErrNum]); + DBGFEX(3,DbgFNm,NULL); +} +/***************************************************************************** + ErrDsp() + This function displays a TECO error message on the terminal screen. +This function is passed the number of the error message and the text of the +error message. + The EH flag controls how verbose the error message will be. The two +least significant bits of the EH flag control how verbose the error message +is. The third bit (mask is EH_COMMAND) causes the erroneous command string up +to and including the erroneous command to be displayed. + The low two bits of EH have the following meanings: + 0 same as 2 + 1 only the three letter code is output + 2 three letter code and one-line error message + 3 three letter code, one-lien message and paragraph +*****************************************************************************/ +static VVOID ErrDsp(ErrNum, ELine) +WORD ErrNum; /* the error number */ +unsigned char *ELine; /* error message text */ +{ + WORD HlpLvl; + ptrdiff_t lenn; + HlpLvl = (EhFlag & 3) ? (EhFlag & 3) : 2; + lenn = (HlpLvl < 2) ? 4 : strlen(ELine); + ZDspBf(ELine, lenn); + if (HlpLvl == 3) { /* if paragraph */ + ErrVrb(ErrNum); /* display paragraph */ + } + ZDspBf("\r\n", 2); + if (EhFlag & EH_COMMAND) { /* if error string display is on */ + TypESt(); + } + LstErr = ErrNum; +} +/***************************************************************************** + ToErr() + Given a character and a buffer pointer, this function puts the +displayable representation for the character into the buffer and updates +the buffer position. For most characters, the displayable representation +is the character itself. +*****************************************************************************/ +static VVOID ToErr(Charac, PtrPtr) +unsigned char Charac; +charptr *PtrPtr; +{ + char SBuf[5]; + char *SPtr; + size_t SLen; + switch (Charac) { + case TABCHR: SPtr = ""; SLen = 5; break; + case LINEFD: SPtr = ""; SLen = 4; break; + case VRTTAB: SPtr = ""; SLen = 4; break; + case FORMFD: SPtr = ""; SLen = 4; break; + case CRETRN: SPtr = ""; SLen = 4; break; + case ESCAPE: SPtr = ""; SLen = 5; break; + case '\0': SPtr = ""; SLen = 5; break; + default: if (Charac >= DELETE) { + SPtr = SBuf; + MakDBf((LONG)Charac, 16); + SLen = (size_t) (DBfPtr - DBfBeg); + SBuf[0] = '['; + MEMMOVE(&SBuf[1], DBfBeg, SLen); + SBuf[++SLen] = ']'; + ++SLen; + } else if (Charac < SPACE) { + SPtr = SBuf; + MEMMOVE(SBuf, "<^x>", 4); + SBuf[2] = Charac + '@'; + SLen = 4; + } else { + SPtr = (char *)&Charac; + SLen = 1; + } + break; + } + MEMMOVE(*PtrPtr, SPtr, SLen); + *PtrPtr += SLen; +} +/***************************************************************************** +*****************************************************************************/ +VVOID ErrChr(ErrNum, EChr) /* display error message with character arg */ +WORD ErrNum; /* the error number */ +unsigned char EChr; /* character to imbed in message */ +{ + char *TmpPtr; + unsigned char ErrBuf[ERBFSIZ]; + charptr EPtr = ErrBuf; + *EPtr++ = '?'; + TmpPtr = Errors[ErrNum]; + while (*TmpPtr != '%') { /* copy up to "%" */ + *EPtr++ = *TmpPtr++; + } + ToErr(EChr, &EPtr); /* copy the %c character */ + TmpPtr++; /* skip % */ + TmpPtr++; /* skip c */ + while (*TmpPtr) { /* copy rest of string */ + *EPtr++ = *TmpPtr++; + } + *EPtr = '\0'; + ErrDsp(ErrNum, ErrBuf); +} +/***************************************************************************** +*****************************************************************************/ +VVOID ErrMsg(ErrNum) /* display error message */ +WORD ErrNum; /* the error number */ +{ + char *TmpPtr; + unsigned char ErrBuf[ERBFSIZ]; + charptr EPtr = ErrBuf; + *EPtr++ = '?'; + TmpPtr = Errors[ErrNum]; + while (*TmpPtr) { /* copy rest of string */ + *EPtr++ = *TmpPtr++; + } + *EPtr = '\0'; + ErrDsp(ErrNum, ErrBuf); +} +/***************************************************************************** +*****************************************************************************/ +VVOID ErrStr(ErrNum, EStr) /* display error message with string arg */ +WORD ErrNum; /* the error number */ +char *EStr; /* string to imbed in message */ +{ + char *TmpPtr; + unsigned char ErrBuf[ERBFSIZ]; + charptr EPtr = ErrBuf; + *EPtr++ = '?'; + TmpPtr = Errors[ErrNum]; + while (*TmpPtr != '%') { /* copy up to "%" */ + *EPtr++ = *TmpPtr++; + } + while (*EStr) { /* copy %s string */ + ToErr((unsigned char)*EStr++, &EPtr); + } + TmpPtr++; /* skip % */ + TmpPtr++; /* skip s */ + while (*TmpPtr) { /* copy rest of string */ + *EPtr++ = *TmpPtr++; + } + *EPtr = '\0'; + ErrDsp(ErrNum, ErrBuf); +} +/***************************************************************************** +*****************************************************************************/ +VVOID ErrPSt(ErrNum, EBeg, EEnd) /* display error message with string arg */ +WORD ErrNum; /* the error number */ +charptr EBeg; /* string to imbed in message */ +charptr EEnd; /* ptr to char after last char */ +{ + char *TmpPtr; + unsigned char ErrBuf[ERBFSIZ]; + charptr EPtr = ErrBuf; + *EPtr++ = '?'; + TmpPtr = Errors[ErrNum]; + while (*TmpPtr != '%') { /* copy up to "%" */ + *EPtr++ = *TmpPtr++; + } + while (EBeg < EEnd) { /* copy %s string */ + ToErr(*EBeg++, &EPtr); + } + TmpPtr++; /* skip % */ + TmpPtr++; /* skip s */ + while (*TmpPtr) { /* copy rest of string */ + *EPtr++ = *TmpPtr++; + } + *EPtr = '\0'; + ErrDsp(ErrNum, ErrBuf); +} diff --git a/src/exea.c b/src/exea.c new file mode 100644 index 0000000..7f071d9 --- /dev/null +++ b/src/exea.c @@ -0,0 +1,113 @@ +/***************************************************************************** + ExeA() + This function executes an A command. + A Appends the next page of the input file to the contents + of the text buffer, thus combining the two pages of + text on a single page with no intervening form feed + character. This command takes no argument. To perform + n Appends, use the n construct. Note that nA is a + completely different command. + :A Equivalent to the A command except that a value is + returned. -1 is returned if the append succeeded, and + 0 is returned if the append failed because the + end-of-the-input-file had previously been reached (^N + flag is -1 at start of this command). + n:A Appends n lines of text from the input file to the + contents of the text buffer. The value of n must not + be negative. A value is returned indicating whether or + not there were in fact n lines remaining in the input + file. -1 is returned if the command succeeded. 0 is + returned if end-of-file on the input file was + encountered before all n lines were read in. Note that + the command can succeed and yet read in fewer than n + lines in the case that the text buffer fills up. + nA Equivalent to the ASCII code for the .+n+1th character + in the buffer (that is, the character to the right of + buffer pointer position .+n). The expression -1A is + equivalent to the ASCII code of the character + immediately preceding the pointer and 0A is equivalent + to the ASCII code of the character immediately + following the pointer (the current character). If the + character position referenced lies outside the bounds + of the text buffer, this command returns a -1. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeA() /* execute an A command */ +{ + BOOLEAN EBfFul; + unsigned char TmpChr; + BOOLEAN ColonMod; + DBGFEN(1,"ExeA",NULL); + ColonMod = (CmdMod & COLON); /* is it :A or n:A */ + CmdMod &= ~COLON; /* clear : flag */ +/* + * if we have a numeric argument, it's nA or n:A + */ + if (EStTop > EStBot) { /* if numeric argument */ + UMinus(); /* if it's -A, make it -1A */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if (ColonMod) { /* if it's n:A */ + if (NArgmt < 1) { + ErrMsg(ERR_IPA); + DBGFEX(1,DbgFNm,"FAILURE, n:A, n < 1"); + return FAILURE; + } + while (NArgmt-- > 0) { + EBfFul = FALSE; + if (RdLine(&EBfFul) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, RdLine() failed"); + return FAILURE; + } + if (EBfFul) { + break; + } + if (IsEofI[CurInp]) { /* if end-of-file */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L, OPERAND); + } + } + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L, OPERAND); + } +/* + * it's nA + */ + if (NArgmt < 0) { + if ((GapBeg+NArgmt) < EBfBeg) { + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L, OPERAND); + } + TmpChr = *(GapBeg+NArgmt); + } else { + if ((GapEnd+NArgmt+1) > EBfEnd) { + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L, OPERAND); + } + TmpChr = *(GapEnd+NArgmt+1); + } +#if DEBUGGING + sprintf(DbgSBf,"PushEx(%d)", TmpChr); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx((LONG)TmpChr, OPERAND); + } +/* + * if there is no numeric argument, must be A or :A + */ + if (IsEofI[CurInp]) { /* if already at end-of-file */ + DBGFEX(1,DbgFNm,(ColonMod) ? "PushEx(0)" : "SUCCESS"); + return ((ColonMod) ? PushEx(0L,OPERAND) : SUCCESS); + } + if (RdPage() == FAILURE) { /* read a page */ + DBGFEX(1,DbgFNm,"FAILURE, RdPage() failed"); + return FAILURE; + } + DBGFEX(1,DbgFNm,(ColonMod) ? "PushEx(-1)" : "SUCCESS"); + return (ColonMod) ? PushEx(-1L, OPERAND) : SUCCESS; +} diff --git a/src/exeats.c b/src/exeats.c new file mode 100644 index 0000000..2839029 --- /dev/null +++ b/src/exeats.c @@ -0,0 +1,17 @@ +/***************************************************************************** + ExeAtS() + This function executes an @ (at-sign) command. + This function implements the at-sign modifier by setting a bit in +the CmdMod variable. Commands which are sensitive to at-sign modification +check CmdMod explicitly. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeAtS() /* execute an @ (at sign) command */ +{ + DBGFEN(1,"ExeAtS",NULL); + CmdMod |= ATSIGN; /* set at sign */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeb.c b/src/exeb.c new file mode 100644 index 0000000..ba80814 --- /dev/null +++ b/src/exeb.c @@ -0,0 +1,15 @@ +/***************************************************************************** + ExeB() + This function executes a B command. + B Always equivalent to zero. Thus, B represents the + position preceding the first character in the buffer. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeB() /* execute a B command */ +{ + DBGFEN(1,"ExeB",NULL); + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L, OPERAND); +} diff --git a/src/exebar.c b/src/exebar.c new file mode 100644 index 0000000..7989bcd --- /dev/null +++ b/src/exebar.c @@ -0,0 +1,21 @@ +/***************************************************************************** + ExeBar() + This function executes a | (vertical bar) command. + | Start ELSE part of conditional +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeBar() /* execute | (vertical bar) command */ +{ + DBGFEN(1,"ExeBar",NULL); + if (FlowEC() == FAILURE) { /* flow to ' */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exebsl.c b/src/exebsl.c new file mode 100644 index 0000000..79e803f --- /dev/null +++ b/src/exebsl.c @@ -0,0 +1,86 @@ +/***************************************************************************** + ExeBSl() + This function executes a \ (backslash) command. + \ Value of digit string in buffer + n\ Convert n to digits in buffer + The backslash command allows the user to convert binary numbers +to/from their ASCII representations. If a numeric argument precedes the +backslash command, then the ASCII representation for the number is inserted +into the edit buffer at the current point. If there is no preceding numeric +argument, then the number in it's ASCII representation in the edit buffer is +converted to binary, and is returned by the backslash command. In either +case, TECO's current radix controls how the numbers are represented. If +the current radix is decimal, then a plus or minus sign can precede an +ASCII number being read, and a minus sign will be generated if necessary +for a number being generated. When converting a string that's in the edit +buffer, the character pointer is left at the end of the string in the buffer. +*****************************************************************************/ +#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 */ +DEFAULT ExeBSl() /* execute a \ (backslash) command */ +{ + DBGFEN(1,"ExeBSl",NULL); +/* + * Handle the case where there's no numeric argument: convert the digit + * string in the edit buffer into a binary value and push it onto the + * expression stack. + */ + if ((EStTop == EStBot) || /* if no numeric arg or */ + (EStack[EStTop].ElType != OPERAND)) { /* partial expression */ + LONG StrVal = 0; + RefLen=0; + if (GapEnd != EBfEnd) { /* if not at end of buffer */ + BOOLEAN negative = FALSE; + char NxtChr; + if (*(GapEnd+1) == '-') { /* minus sign? */ + RefLen--; + GapEnd++; /* move forward... */ + *GapBeg++ = *GapEnd; /* ... one character */ + negative = TRUE; + } else if (*(GapEnd+1) == '+') { /* plus sign? */ + RefLen--; + GapEnd++; /* move forward... */ + *GapBeg++ = *GapEnd; /* ... one character */ + } + while ((GapEnd != EBfEnd) && (IsRadx(*(GapEnd+1)))) { + RefLen--; + GapEnd++; /* move forward... */ + *GapBeg++ = *GapEnd; /* ... one character */ + NxtChr = *GapEnd; + if (Is_Digit(NxtChr)) + NxtChr -= '0'; + else if (Is_Upper(NxtChr)) + NxtChr -= '\67'; + else + NxtChr -= '\127'; + StrVal = (StrVal * Radix) + NxtChr; + } + if (negative) + StrVal = -StrVal; + } + CmdMod = '\0'; /* clear modifiers flags */ +#if DEBUGGING + sprintf(DbgSBf,"PushEx(%ld)", StrVal); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx(StrVal,OPERAND); + } +/* + * If we made it to here, then there is a numeric argument + */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + MakDBf(NArgmt, Radix); /* convert it to ASCII */ + if (InsStr(DBfBeg, DBfPtr-DBfBeg) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exec.c b/src/exec.c new file mode 100644 index 0000000..042305f --- /dev/null +++ b/src/exec.c @@ -0,0 +1,23 @@ +/***************************************************************************** + ExeC() + This function executes a C command. + nC Advance n characters +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeC() /* execute a C command */ +{ + DBGFEN(1,"ExeC",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1C */ + } else { + UMinus(); /* if it's -C, make it -1C */ + if (GetNmA() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(1,DbgFNm,"DoCJR"); + return DoCJR(NArgmt); +} diff --git a/src/execcc.c b/src/execcc.c new file mode 100644 index 0000000..c861df3 --- /dev/null +++ b/src/execcc.c @@ -0,0 +1,19 @@ +/***************************************************************************** + ExeCCC() + This function executes a ^^ (control-caret or caret-caret) command. + ^^x Equivilent to the ASCII value of x +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCCC() /* execute a control-^ command */ +{ + DBGFEN(1,"ExeCCC",NULL); + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx((LONG)*CBfPtr, OPERAND); +} diff --git a/src/execln.c b/src/execln.c new file mode 100644 index 0000000..6d25614 --- /dev/null +++ b/src/execln.c @@ -0,0 +1,22 @@ +/***************************************************************************** + ExeCln() + This function handles the colon and double-colon modifiers. + This function implements the modifiers by setting bits in the +CmdMod variable. Commands which are sensitive to colon or double colon +modification check CmdMod explicitly. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCln() /* execute : or :: modifiers */ +{ + DBGFEN(1,"ExeCln",NULL); + if (CmdMod & COLON) { /* if colon bit is set */ + CmdMod &= ~COLON; /* clear colon bit */ + CmdMod |= DCOLON; /* set double-colon bit */ + } else { + CmdMod |= COLON; /* set colon bit */ + } + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/execom.c b/src/execom.c new file mode 100644 index 0000000..a2aad07 --- /dev/null +++ b/src/execom.c @@ -0,0 +1,25 @@ +/***************************************************************************** + ExeCom() + This function executes a , (comma argument separator) command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCom() /* execute a , (comma) command */ +{ + DBGFEN(1,"ExeCom",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + ErrMsg(ERR_NAC); /* no arg before , */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (GetNmA() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + MArgmt = NArgmt; + CmdMod |= MARGIS; + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/execrt.c b/src/execrt.c new file mode 100644 index 0000000..4401ad8 --- /dev/null +++ b/src/execrt.c @@ -0,0 +1,38 @@ +/***************************************************************************** + ExeCrt() + This function "executes" a ^ (caret) command. Most TECO commands +which are control characters (^A, ^B, etc) can also be entered as a caret +and letter combination. For example, control-A can also be entered as +caret-A. +*****************************************************************************/ +#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 "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCrt() /* execute a ^ (caret) command */ +{ + unsigned char TmpChr; + static DEFAULT (*FCAray[])(VVOID) = { + /* ^A*/ ExeCtA, /* ^B*/ ZExCtB, /* ^C*/ ExeCtC, + /* ^D*/ ExeCtD, /* ^E*/ ExeCtE, /* ^F*/ ExeNYI, + /* ^G*/ ExeIll, /* ^H*/ ZExCtH, /*TAB*/ ExeCtI, + /* LF*/ ExeNul, /* VT*/ ExeIll, /* FF*/ ExeCtL, + /* CR*/ ExeNul, /* ^N*/ ExeCtN, /* ^O*/ ExeCtO, + /* ^P*/ ExeCtP, /* ^Q*/ ExeCtQ, /* ^R*/ ExeCtR, + /* ^S*/ ExeCtS, /* ^T*/ ExeCtT, /* ^U*/ ExeCtU, + /* ^V*/ ExeCtV, /* ^W*/ ExeCtW, /* ^X*/ ExeCtX, + /* ^Y*/ ExeCtY, /* ^Z*/ ExeCtZ, /* ^[*/ ExeEsc, + /* ^\*/ ExeIll, /* ^]*/ ExeIll, /* ^^*/ ExeCCC, + /* ^_*/ ExeUsc + }; + if (IncCBP() == FAILURE) { + return FAILURE; + } + TmpChr = To_Upper(*CBfPtr); + if ((TmpChr < 'A') || (TmpChr > '_')) { + ErrChr(ERR_IUC, *CBfPtr); + return FAILURE; + } + return (*FCAray[TmpChr-'A'])(); +} diff --git a/src/execst.c b/src/execst.c new file mode 100644 index 0000000..b646045 --- /dev/null +++ b/src/execst.c @@ -0,0 +1,113 @@ +/***************************************************************************** + ExeCSt() + This function executes a TECO command string. The string is pointed +to by CBfPtr. The last character in the string is pointed to by CStEnd. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCSt() /* execute command string */ +{ + DEFAULT status; + static DEFAULT (*FArray[])(VVOID) = { +/*NUL*/ ExeNul, /* ^A*/ ExeCtA, /* ^B*/ ZExCtB, /* ^C*/ ExeCtC, +/* ^D*/ ExeCtD, /* ^E*/ ExeCtE, /* ^F*/ ExeNYI, /* ^G*/ ExeIll, +/* ^H*/ ZExCtH, /* ^I*/ ExeCtI, /* LF*/ ExeNul, /* VT*/ ExeIll, +/* ^L*/ ExeCtL, /* CR*/ ExeNul, /* ^N*/ ExeCtN, /* ^O*/ ExeCtO, +/* ^P*/ ExeCtP, /* ^Q*/ ExeCtQ, /* ^R*/ ExeCtR, /* ^S*/ ExeCtS, +/* ^T*/ ExeCtT, /* ^U*/ ExeCtU, /* ^V*/ ExeCtV, /* ^W*/ ExeCtW, +/* ^X*/ ExeCtX, /* ^Y*/ ExeCtY, /* ^Z*/ ExeCtZ, /*ESC*/ ExeEsc, +/* ^\*/ ExeIll, /* ^]*/ ExeIll, /* ^^*/ ExeCCC, /* ^_*/ ExeUsc, +/* SP*/ ExeNul, /* ! */ ExeExc, /* " */ ExeDQu, /* # */ ExeOpr, +/* $ */ ExeEsc, /* % */ ExePrc, /* & */ ExeOpr, /* ' */ ExeNul, +/* ( */ ExeOpr, /* ) */ ExeRtP, /* * */ ExeOpr, /* + */ ExeOpr, +/* , */ ExeCom, /* - */ ExeOpr, /* . */ ExeDot, /* / */ ExeOpr, +/* 0 */ ExeDgt, /* 1 */ ExeDgt, /* 2 */ ExeDgt, /* 3 */ ExeDgt, +/* 4 */ ExeDgt, /* 5 */ ExeDgt, /* 6 */ ExeDgt, /* 7 */ ExeDgt, +/* 8 */ ExeDgt, /* 9 */ ExeDgt, /* : */ ExeCln, /* ; */ ExeSCl, +/* < */ ExeLst, /* = */ ExeEqu, /* > */ ExeGtr, /* ? */ ExeQes, +/* @ */ ExeAtS, /* A */ ExeA, /* B */ ExeB, /* C */ ExeC, +/* D */ ExeD, /* E */ ExeE, /* F */ ExeF, /* G */ ExeG, +/* H */ ExeH, /* I */ ExeI, /* J */ ExeJ, /* K */ ExeK, +/* L */ ExeL, /* M */ ExeM, /* N */ ExeN, /* O */ ExeO, +/* P */ ExeP, /* Q */ ExeQ, /* R */ ExeR, /* S */ ExeS, +/* T */ ExeT, /* U */ ExeU, /* V */ ExeV, /* W */ ExeW, +/* X */ ExeX, /* Y */ ExeY, /* Z */ ExeZ, /* [ */ ExeLBr, +/* \ */ ExeBSl, /* ] */ ExeRBr, /* ^ */ ExeCrt, /* _ */ ExeUnd, +/* ` */ ExeIll, /* a */ ExeA, /* b */ ExeB, /* c */ ExeC, +/* d */ ExeD, /* e */ ExeE, /* f */ ExeF, /* g */ ExeG, +/* h */ ExeH, /* i */ ExeI, /* j */ ExeJ, /* k */ ExeK, +/* l */ ExeL, /* m */ ExeM, /* n */ ExeN, /* o */ ExeO, +/* p */ ExeP, /* q */ ExeQ, /* r */ ExeR, /* s */ ExeS, +/* t */ ExeT, /* u */ ExeU, /* v */ ExeV, /* w */ ExeW, +/* x */ ExeX, /* y */ ExeY, /* z */ ExeZ, /* { */ ExeIll, +/* | */ ExeBar, /* } */ ExeIll, /* ~ */ ExeIll, /*DEL*/ ExeIll, +/*129*/ ExeIll, /*130*/ ExeIll, /*131*/ ExeIll, /*132*/ ExeIll, +/*133*/ ExeIll, /*134*/ ExeIll, /*135*/ ExeIll, /*136*/ ExeIll, +/*137*/ ExeIll, /*138*/ ExeIll, /*139*/ ExeIll, /*140*/ ExeIll, +/*141*/ ExeIll, /*142*/ ExeIll, /*143*/ ExeIll, /*144*/ ExeIll, +/*145*/ ExeIll, /*146*/ ExeIll, /*147*/ ExeIll, /*148*/ ExeIll, +/*149*/ ExeIll, /*150*/ ExeIll, /*151*/ ExeIll, /*152*/ ExeIll, +/*153*/ ExeIll, /*154*/ ExeIll, /*155*/ ExeIll, /*156*/ ExeIll, +/*157*/ ExeIll, /*158*/ ExeIll, /*159*/ ExeIll, /*160*/ ExeIll, +/*161*/ ExeIll, /*162*/ ExeIll, /*163*/ ExeIll, /*164*/ ExeIll, +/*165*/ ExeIll, /*166*/ ExeIll, /*167*/ ExeIll, /*168*/ ExeIll, +/*169*/ ExeIll, /*170*/ ExeIll, /*171*/ ExeIll, /*172*/ ExeIll, +/*173*/ ExeIll, /*174*/ ExeIll, /*175*/ ExeIll, /*176*/ ExeIll, +/*177*/ ExeIll, /*178*/ ExeIll, /*179*/ ExeIll, /*180*/ ExeIll, +/*181*/ ExeIll, /*182*/ ExeIll, /*183*/ ExeIll, /*184*/ ExeIll, +/*185*/ ExeIll, /*186*/ ExeIll, /*187*/ ExeIll, /*188*/ ExeIll, +/*189*/ ExeIll, /*190*/ ExeIll, /*191*/ ExeIll, /*192*/ ExeIll, +/*193*/ ExeIll, /*194*/ ExeIll, /*195*/ ExeIll, /*196*/ ExeIll, +/*197*/ ExeIll, /*198*/ ExeIll, /*199*/ ExeIll, /*200*/ ExeIll, +/*201*/ ExeIll, /*202*/ ExeIll, /*203*/ ExeIll, /*204*/ ExeIll, +/*205*/ ExeIll, /*206*/ ExeIll, /*207*/ ExeIll, /*208*/ ExeIll, +/*209*/ ExeIll, /*210*/ ExeIll, /*211*/ ExeIll, /*212*/ ExeIll, +/*213*/ ExeIll, /*214*/ ExeIll, /*215*/ ExeIll, /*216*/ ExeIll, +/*217*/ ExeIll, /*218*/ ExeIll, /*219*/ ExeIll, /*220*/ ExeIll, +/*221*/ ExeIll, /*222*/ ExeIll, /*223*/ ExeIll, /*224*/ ExeIll, +/*225*/ ExeIll, /*226*/ ExeIll, /*227*/ ExeIll, /*228*/ ExeIll, +/*229*/ ExeIll, /*230*/ ExeIll, /*231*/ ExeIll, /*232*/ ExeIll, +/*233*/ ExeIll, /*234*/ ExeIll, /*235*/ ExeIll, /*236*/ ExeIll, +/*237*/ ExeIll, /*238*/ ExeIll, /*239*/ ExeIll, /*240*/ ExeIll, +/*241*/ ExeIll, /*242*/ ExeIll, /*243*/ ExeIll, /*244*/ ExeIll, +/*245*/ ExeIll, /*246*/ ExeIll, /*247*/ ExeIll, /*248*/ ExeIll, +/*249*/ ExeIll, /*250*/ ExeIll, /*251*/ ExeIll, /*252*/ ExeIll, +/*253*/ ExeIll, /*254*/ ExeIll, /*255*/ ExeIll, /*256*/ ExeIll + }; + DBGFEN(4,"ExeCSt",NULL); + while (CBfPtr <= CStEnd) { /* while more commands */ + if (TraceM) { /* if trace mode is on */ + EchoIt(*CBfPtr); /* display the command */ + } + status = (*FArray[*CBfPtr])(); /* execute command */ +#if CONSISTENCY_CHECKING + check_consistency(); +#endif +#if CHECKSUM_CODE + check_code_checksums (); +#endif + ZCHKKB(); /* kludge for MS-DOS only */ + if (GotCtC) { /* if got a control-C */ + GotCtC = FALSE; + ErrMsg(ERR_XAB); /* XAB = execution aborted */ + DBGFEX(4,DbgFNm,"SUCCESS"); + return SUCCESS; + } + if (status == FAILURE) { /* did command fail? */ + if (EtFlag & ET_MUNG_MODE) { /* if in mung mode */ + TAbort(EXIT_FAILURE); /* ... terminate */ + } else { + DBGFEX(4,DbgFNm,"FAILURE"); + return FAILURE; + } + } + CBfPtr++; /* move to next command */ + } + if (LStTop != LStBot) { /* if unclosed loop */ + ErrUTC(); /* unterminated command */ + } + DBGFEX(4,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/execta.c b/src/execta.c new file mode 100644 index 0000000..f4d68c4 --- /dev/null +++ b/src/execta.c @@ -0,0 +1,25 @@ +/***************************************************************************** + ExeCtA() + This function executes a ^A (control-A or caret-A) command. + ^Atext^A Types "text" on the terminal. The closing + character must be a control-A. + @^A/text/ Equivilent to ^A except text can be bracketed + with any character, avoids need for second ^A. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeCtA() /* execute a ^A (control-A) command */ +{ + DBGFEN(1,"ExeCtA",NULL); + if (FindES(CTRL_A) == FAILURE) { /* find end of string */ + DBGFEX(1,DbgFNm,"FAILURE, FindES() failed"); + return FAILURE; + } + TypBuf(ArgPtr, CBfPtr); + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exectc.c b/src/exectc.c new file mode 100644 index 0000000..ff83d84 --- /dev/null +++ b/src/exectc.c @@ -0,0 +1,19 @@ +/***************************************************************************** + ExeCtC() + This function executes a control-C command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeCtC() /* execute an control-C command */ +{ + DBGFEN(1,"ExeCtC",NULL); + if ((CBfPtr < CStEnd) && (*(CBfPtr+1) == CTRL_C)) { /* if it's ^C^C */ + TAbort(EXIT_SUCCESS); + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; +} diff --git a/src/exectd.c b/src/exectd.c new file mode 100644 index 0000000..d9380e5 --- /dev/null +++ b/src/exectd.c @@ -0,0 +1,16 @@ +/***************************************************************************** + ExeCtD() + This function executes a ^D (control-D or caret-D) command. This +command sets the radix to decimal. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtD() /* execute a ^D (control-D) command */ +{ + DBGFEN(1,"ExeCtD",NULL); + Radix = 10; + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/execte.c b/src/execte.c new file mode 100644 index 0000000..8a9f704 --- /dev/null +++ b/src/execte.c @@ -0,0 +1,30 @@ +/***************************************************************************** + ExeCtE() + This function executes a ^E (control-E or caret-E) command, which +returns the value of the form feed flag. The form feed flag is -1 if the +last read operation was terminated because a form feed was encountered. It +is 0 otherwise. If the ^E command is preceded by a numeric argument, then +the command sets the value of the form feed flag. The form feed flag is +used by the output code to indicate whether a form feed should be appended +when the edit buffer is written to the output file. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtE() /* execute a ^E (control-E) command */ +{ + DBGFEN(1,"ExeCtE",NULL); + if (EStTop > EStBot) { /* if numeric argument */ + if (GetNmA() == FAILURE) { /* get numeric arg */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + FFPage = (NArgmt == -1) ? -1 : 0; + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"PushEx(FFPage)"); + return PushEx(FFPage, OPERAND); +} diff --git a/src/execti.c b/src/execti.c new file mode 100644 index 0000000..8f097d2 --- /dev/null +++ b/src/execti.c @@ -0,0 +1,25 @@ +/***************************************************************************** + ExeCtI() + This function executes a ^I (control-I or caret-I) command. This +is equivilent to the I command, except the is inserted as well. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeCtI() /* execute control-I (tab) command */ +{ + DBGFEN(1,"ExeCtI",NULL); + if (FindES(ESCAPE) == FAILURE) { /* find end of text arg */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (InsStr(ArgPtr-1, (CBfPtr-ArgPtr)+1) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exectl.c b/src/exectl.c new file mode 100644 index 0000000..630d0f3 --- /dev/null +++ b/src/exectl.c @@ -0,0 +1,13 @@ +/***************************************************************************** + ExeCtL() + This function executes a ^L (control-L or caret-L) command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeCtL() /* execute an ^L (control-L) command */ +{ + ZDspCh(FORMFD); + return SUCCESS; +} diff --git a/src/exectn.c b/src/exectn.c new file mode 100644 index 0000000..0b4fd07 --- /dev/null +++ b/src/exectn.c @@ -0,0 +1,17 @@ +/***************************************************************************** + ExeCtN() + This function executes a ^N (control-N or caret-N) command. + ^N (caret/N) is the end of file flag. It is + equivalent to -1 if the file open on the currently + selected input stream is at end of file, and zero + otherwise. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtN() /* execute a ^N (control-N) command */ +{ + DBGFEN(1,"ExeCtN",NULL); + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx((IsEofI[CurInp] ? -1L : 0L), OPERAND); +} diff --git a/src/execto.c b/src/execto.c new file mode 100644 index 0000000..6a4cdbb --- /dev/null +++ b/src/execto.c @@ -0,0 +1,16 @@ +/***************************************************************************** + ExeCtO() + This function executes a ^O (control-O or caret-O) command. This +command sets the radix to octal. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtO() /* execute a ^O (control-O) command */ +{ + DBGFEN(1,"ExeCtO",NULL); + Radix = 8; /* set radix to octal */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exectp.c b/src/exectp.c new file mode 100644 index 0000000..3b9de41 --- /dev/null +++ b/src/exectp.c @@ -0,0 +1,23 @@ +/***************************************************************************** + ExeCtP() + This function executes a ^P (control-P or caret-P) command. ^P +is not a TECO command and is used to set TECO-C debugging parameters. For +more information on the debugging routines, see the DEBUGGING lines in +Tecoc.c. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtP() /* execute a ^P (control-P) command */ +{ +#if DEBUGGING + if (DbgDsp() == FAILURE) { + return FAILURE; + } + EStTop = EStBot; /* clear expression stack */ + CmdMod = '\0'; /* clear modifiers flags */ + return SUCCESS; +#else + return (ExeIll ()); /* Illegal command */ +#endif +} diff --git a/src/exectq.c b/src/exectq.c new file mode 100644 index 0000000..b6477ce --- /dev/null +++ b/src/exectq.c @@ -0,0 +1,24 @@ +/***************************************************************************** + ExeCtQ() + This function executes a ^Q (control-Q or caret-Q) command. + n^Q returns number of characters between the buffer pointer + and the nth line separator (n^QC == nL). +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtQ() /* execute a ^Q (control-Q) command */ +{ + DBGFEN(1,"ExeCtQ",NULL); + CmdMod = '\0'; /* clear modifiers flags */ + if (EStTop == EStBot) { /* if no numeric argument */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L, OPERAND); + } + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(Ln2Chr(NArgmt), OPERAND); +} diff --git a/src/exectr.c b/src/exectr.c new file mode 100644 index 0000000..d2fd209 --- /dev/null +++ b/src/exectr.c @@ -0,0 +1,33 @@ +/***************************************************************************** + ExeCtR() + This function executes a ^R (control-R or caret-R) command. The +control-R command sets TECO's radix, which controls how ASCII strings are +converted to/from their binary representations. The current radix is used +by the backslash command and whenever TECO encounters a string of digits in +a command string. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCtR() /* execute a ^R (control-R) command */ +{ + DBGFEN(1,"ExeCtR",NULL); + if ((EStTop == EStBot) || /* if no numeric arg or */ + (EStack[EStTop].ElType != OPERAND)) { /* partial expression */ + DBGFEX(1,DbgFNm,"PushEx"); + return PushEx((LONG)Radix, OPERAND); + } + if (GetNmA() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if ((NArgmt != 8) && (NArgmt != 10) && (NArgmt != 16)) { + ErrMsg(ERR_IRA); /* illegal radix with ^R */ + DBGFEX(1,DbgFNm,"FAILURE, illegal radix"); + return FAILURE; + } + Radix = (DEFAULT)NArgmt; + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exects.c b/src/exects.c new file mode 100644 index 0000000..28990eb --- /dev/null +++ b/src/exects.c @@ -0,0 +1,15 @@ +/***************************************************************************** + ExeCtS() + This function executes a ^S (control-S or caret-S) command. This +is equivilent to the negative of the last referenced string (last insert, +string found, or string inserted with "G" command). +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtS() /* execute a ^S (control-S) command */ +{ + DBGFEN(1,"ExeCtS",NULL); + DBGFEX(1,DbgFNm,"PushEx(RefLen)"); + return PushEx(RefLen, OPERAND); +} diff --git a/src/exectt.c b/src/exectt.c new file mode 100644 index 0000000..3ac267a --- /dev/null +++ b/src/exectt.c @@ -0,0 +1,40 @@ +/***************************************************************************** + ExeCtT() + This function executes a ^T (control-T or caret-T) command. + ^T ASCII value of next char typed + n^T Types out character for ASCII code n. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCtT() /* execute a ^T (control-T) command */ +{ + DEFAULT lchar; + DBGFEN(1,"ExeCtT",NULL); + if ((EStTop == EStBot) || /* if no numeric arg or */ + (EStack[EStTop].ElType != OPERAND)) { /* partial expression */ + lchar = ZChIn(EtFlag & ET_NO_WAIT); /* read a character */ + if (GotCtC) { /* if got a control-C */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (((EtFlag & ET_NO_ECHO) == 0) && (lchar != -1)) { + EchoIt((unsigned char)lchar); + } + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx((LONG)lchar, OPERAND); + } + if (GetNmA() == FAILURE) { /* get numeric arg */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if ((CmdMod & COLON) || (EtFlag & ET_IMAGE_MODE)) { + ZDspCh((char)NArgmt); + } else { + EchoIt((unsigned char)NArgmt); + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exectu.c b/src/exectu.c new file mode 100644 index 0000000..575e83a --- /dev/null +++ b/src/exectu.c @@ -0,0 +1,136 @@ +/***************************************************************************** + ExeCtU() + This function executes a ^U (control-U or caret-U) command. + ^Uqstring` + This command inserts character string "string" into the text + storage area of Q-register q. When entering a command string + from the terminal, you must specify ^U using the caret/U + format, since the character is the line erase + immediate action command. + :^Uqstring` + This command appends character string "string" to the text + storage area of Q-register "q". + n^Uq' This form of the ^Uq` command inserts the single character + whose ASCII code is n into the text storage area of + Q-register "q". (n is taken modulo 256 in TECO-11, modulo + 128 in other TECOs.) + n:^Uq` This form of the :^Uq` command appends the single character + whose ASCII code is n to the text storage area of Q-register + "q". (n is taken modulo 256 in TECO-11, modulo 128 in other + TECOs.) [not in TECO-8] + @^Uq/string/ + @:^Uq/string/ + n@^Uq// + n@:^Uq// + Equivalent, respectively, to the ^Uqstring`, :^Uqstring`, + n^Uq`, and n:^Uq` commands, except that alternate delimiters + are used and no characters are necessary. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeCtU() /* execute a ^U (control-U) command */ +{ + ptrdiff_t TmpSiz; + DBGFEN(1,"ExeCtU",NULL); +/* + * increment CBfPtr past ^U + */ + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } +/* + * try to find Q-register name after ^U + */ + if (FindQR() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } +/* + * If there is a colon modifier, we are appending to the Q-register text. + * If there isn't a colon modifier, we are replacing the text currently + * in the Q-register. If there is any text currently in the Q-register, + * we have to zap it first. + */ + if (!(CmdMod & COLON)) { /* if no colon modifier */ + if (QR->Start != NULL) { /* if not empty */ + ZFree((voidptr)QR->Start); /* free the memory */ + QR->Start = QR->End_P1 = NULL; + } + } +/* + * If there is a numeric argument n, we are dealing with a character to + * place into or append to the Q-register. + */ + if (EStTop > EStBot) { /* if numeric argument */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if (CmdMod & ATSIGN) { /* it's @^U// */ +/* + * increment CBfPtr to 1st delimiter + */ + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } +/* + * increment CBfPtr to 2nd delimiter + */ + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } +/* + * the two delimiters should be the same + */ + if (*CBfPtr != *(CBfPtr-1)) { + ErrMsg(ERR_IIA); + DBGFEX(1,DbgFNm,"FAILURE, ERR_IIA"); + return FAILURE; + } + } +/* + * Increase the size of the text area by 1 character + */ + if (MakRom((SIZE_T) 1) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, MakRom() failed"); + return FAILURE; + } +/* + * Append the character to the Q-register + */ + *(QR->End_P1) = (char) NArgmt; + QR->End_P1++; + } else { /* else no numeric argument */ +/* + * We must be dealing with a string, find the end of the string. + */ + if (FindES(ESCAPE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, FindES() failed"); + return FAILURE; + } + TmpSiz = CBfPtr - ArgPtr; + if (TmpSiz > 0) { +/* + * make room for the string + */ + if (MakRom((SIZE_T)TmpSiz) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, MakRom() failed"); + return FAILURE; + } +/* + * Append the string to the Q-register text + */ + MEMMOVE(QR->End_P1, ArgPtr, (SIZE_T)TmpSiz); + QR->End_P1 += TmpSiz; + } + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exectv.c b/src/exectv.c new file mode 100644 index 0000000..9e6d357 --- /dev/null +++ b/src/exectv.c @@ -0,0 +1,29 @@ +/***************************************************************************** + ExeCtV() + This function executes a ^V (control-V or caret-V) command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCtV() /* execute a ^V (control-V) command */ +{ + DBGFEN(1,"ExeCtV",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + IniSrM = LOWER; + } else { + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (NArgmt) { /* if it wasn't 0^V */ + ErrMsg(ERR_ARG); /* improper arguments */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + IniSrM = NONE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exectw.c b/src/exectw.c new file mode 100644 index 0000000..6153e11 --- /dev/null +++ b/src/exectw.c @@ -0,0 +1,29 @@ +/***************************************************************************** + ExeCtW() + This function executes a control-W command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeCtW() /* execute a ^W (control-W) command */ +{ + DBGFEN(1,"ExeCtW",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + IniSrM = UPPER; + } else { + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (NArgmt) { /* if it wasn't 0^W */ + ErrMsg(ERR_ARG); /* improper arguments */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + IniSrM = NONE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exectx.c b/src/exectx.c new file mode 100644 index 0000000..4fc76cf --- /dev/null +++ b/src/exectx.c @@ -0,0 +1,13 @@ +/***************************************************************************** + ExeCtX() + This function executes a control-X command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtX() /* execute a ^X (control-X) command */ +{ + DBGFEN(1,"ExeCtX",NULL); + DBGFEX(1,DbgFNm,"DoFlag()"); + return DoFlag(&SMFlag); +} diff --git a/src/execty.c b/src/execty.c new file mode 100644 index 0000000..1857bb0 --- /dev/null +++ b/src/execty.c @@ -0,0 +1,23 @@ +/***************************************************************************** + ExeCtY() + This function executes a control-Y command. + ^Y (caret/Y) is equivalent to ".+^S,.", the n,m + numeric argument spanning the text just searched for or + inserted. This value may be used to recover from + inserting a string in the wrong place. Type "^YXSFR`" + to store the string in Q-register S and remove it from + the buffer. You can then position the pointer to the + right place and type "GS" to insert the string. + [TECO-11 only] +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtY() /* execute ^Y command */ +{ + DBGFEN(1,"ExeCtY",NULL); + MArgmt = (GapBeg-EBfBeg) + RefLen; /* set m part of m,n pair */ + CmdMod |= MARGIS; /* say that m part exists */ + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx((LONG)(GapBeg-EBfBeg), OPERAND); /* push n part */ +} diff --git a/src/exectz.c b/src/exectz.c new file mode 100644 index 0000000..466c13f --- /dev/null +++ b/src/exectz.c @@ -0,0 +1,25 @@ +/***************************************************************************** + ExeCtZ() + This function executes a control-Z command. + ^Z (caret/Z) is equivalent to the total space + occupied by text in the Q-registers (including the + command line currently being executed). +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeCtZ() /* execute a ^Z (control-Z) command */ +{ + LONG TmpLng; + WORD TmpWrd; + DBGFEN(1,"ExeCtZ",NULL); + TmpLng = (CStEnd - CStBeg) + 1; + for (TmpWrd = 0; TmpWrd < 36; ++TmpWrd) { + TmpLng += QRgstr[TmpWrd].End_P1 - QRgstr[TmpWrd].Start; + } +#if DEBUGGING + sprintf(DbgSBf,"PushEx(%ld)", TmpLng); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx(TmpLng,OPERAND); +} diff --git a/src/exed.c b/src/exed.c new file mode 100644 index 0000000..48f302c --- /dev/null +++ b/src/exed.c @@ -0,0 +1,55 @@ +/***************************************************************************** + ExeD() + This function executes a D command. + nD Delete n characters. + m,nD Delete between m and n +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeD() /* execute a D command */ +{ + LONG Status; + DBGFEN(1,"ExeD",NULL); + if (CmdMod & MARGIS) { /* if it's m,nD */ + DBGFEX(1,DbgFNm,"ExeK()"); + return ExeK(); + } + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1D */ + } else { + UMinus(); /* if it's -D, make it -1D */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + Status = -1; /* -1 means success */ + if (NArgmt > 0) { + if ((GapEnd+NArgmt) > EBfEnd) { /* if out of range */ + Status = 0; /* 0 means failure */ + } else { + GapEnd += NArgmt; /* delete */ + } + } else { + if ((GapBeg+NArgmt) < EBfBeg) { /* if out of range */ + Status = 0; /* 0 means failure */ + } else { + GapBeg += NArgmt; /* delete */ + } + } + if (CmdMod & COLON) { /* if it's :D */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(Status, OPERAND); + } + if (Status == 0) { + ErrMsg(ERR_DTB); /* DTB = "delete too big" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exedgt.c b/src/exedgt.c new file mode 100644 index 0000000..3199a62 --- /dev/null +++ b/src/exedgt.c @@ -0,0 +1,49 @@ +/***************************************************************************** + ExeDgt() + This function handles a digit encountered in a command string. +It converts the digit and any following digits into a binary value using +the current radix, and pushes the value onto the expression stack. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "chmacs.h" /* define character processing macros */ +DEFAULT ExeDgt() /* execute a digit command */ +{ + LONG TmpLng; + DBGFEN(1,"ExeDgt",NULL); + if ((Radix == 8) && (*CBfPtr > '7')) { /* if bad octal digit */ + ErrMsg(ERR_ILN); /* ILN = "illegal number" */ + DBGFEX(1,DbgFNm,"FAILURE, bad octal digit"); + return FAILURE; + } + TmpLng = 0; + do { + TmpLng *= Radix; + if (Is_Digit(*CBfPtr)) { + TmpLng += *CBfPtr - '0'; + } else if (Is_Upper(*CBfPtr)) { + TmpLng += *CBfPtr - '\67'; + } else { + TmpLng += *CBfPtr - '\127'; + } + if (CBfPtr == CStEnd) { +#if DEBUGGING + sprintf(DbgSBf,"PushEx(%ld,OPERAND)", TmpLng); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx(TmpLng, OPERAND); + } + ++CBfPtr; + if (IsRadx(*CBfPtr) && TraceM) { + EchoIt(*CBfPtr); + } + } while (IsRadx(*CBfPtr)); + --CBfPtr; /* cancel ExeCSt's ++CBfPtr */ +#if DEBUGGING + sprintf(DbgSBf,"PushEx(%ld,OPERAND)", TmpLng); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx(TmpLng, OPERAND); +} diff --git a/src/exedot.c b/src/exedot.c new file mode 100644 index 0000000..f002143 --- /dev/null +++ b/src/exedot.c @@ -0,0 +1,20 @@ +/***************************************************************************** + ExeDot() + This function executes a . (dot) command. + . Equivalent to the number of characters between the + beginning of the buffer and the current position of the + pointer. Thus "." represents the current position of + the pointer. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeDot() /* execute a . (dot) command */ +{ +#if DEBUGGING + DBGFEN(1,"ExeDot",NULL); + sprintf(DbgSBf,"PushEx(%ld)", (LONG)(GapBeg-EBfBeg)); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx((LONG)(GapBeg-EBfBeg), OPERAND); +} diff --git a/src/exedqu.c b/src/exedqu.c new file mode 100644 index 0000000..be38887 --- /dev/null +++ b/src/exedqu.c @@ -0,0 +1,127 @@ +/***************************************************************************** + ExeDQu() + This function executes a " (double-quote) command. + " Start conditional + n"< Text for less than zero + n"= Test for equal to zero + n"> Test for greater than zero + n"A Test for alphabetic + n"C Test for symbol constituent + n"D Test for numeric + n"E Test for equal to zero + n"F Test for false + n"G Test for greater than zero + n"L Test for less than zero + n"N Test for not equal to zero + n"R Test for alphanumeric + n"S Test for successful + n"T Test for true + n"U Test for unsuccessful + n"V Test for lower case + n"W Test for upper case +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "chmacs.h" /* define character processing macros */ +DEFAULT ExeDQu() /* execute a " (double quote) command */ +{ + unsigned char RelExp; /* relational expression */ + DBGFEN(1,"ExeDQu",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + ErrMsg(ERR_NAQ); /* no argument before " */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (GetNmA() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + CmdMod = '\0'; + RelExp = (unsigned char)NArgmt; + switch (To_Upper(*CBfPtr)) { + case 'A': /* test for alphabetic */ + if (Is_Alpha(RelExp)) { + DBGFEX(1,DbgFNm,"SUCCESS, Is_Alpha"); + return SUCCESS; + } + break; + case 'C': /* test for symbol constituent */ + if (Is_SyCon(RelExp)) { + DBGFEX(1,DbgFNm,"SUCCESS, Is_SyCon"); + return SUCCESS; + } + break; + case 'D': /* test for numeric */ + if (Is_Digit(RelExp)) { + DBGFEX(1,DbgFNm,"SUCCESS, Is_Digit"); + return SUCCESS; + } + break; + case 'E': /* test for equal to zero */ + case 'F': /* test for false */ + case 'U': /* test for unsuccessful */ + case '=': /* test for equal to zero */ + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"SUCCESS, equal to zero"); + return SUCCESS; + } + break; + case 'G': /* test for greater than zero */ + case '>': /* test for greater than zero */ + if (NArgmt > 0) { + DBGFEX(1,DbgFNm,"SUCCESS, greater than zero"); + return SUCCESS; + } + break; + case 'L': /* test for less than zero */ + case 'S': /* test for successful */ + case 'T': /* test for TRUE */ + case '<': /* test for less than zero */ + if (NArgmt < 0) { + DBGFEX(1,DbgFNm,"SUCCESS, less than zero"); + return SUCCESS; + } + break; + case 'N': /* test for not equal to zero */ + if (NArgmt != 0) { + DBGFEX(1,DbgFNm,"SUCCESS, not equal to zero"); + return SUCCESS; + } + break; + case 'R': /* test for alphanumeric */ + if (Is_Alnum(RelExp)) { + DBGFEX(1,DbgFNm,"SUCCESS, Is_Alnum"); + return SUCCESS; + } + break; + case 'V': /* test for lowercase */ + if (Is_Lower(RelExp)) { + DBGFEX(1,DbgFNm,"SUCCESS, Is_Lower"); + return SUCCESS; + } + break; + case 'W': /* test for uppercase */ + if (Is_Upper(RelExp)) { + DBGFEX(1,DbgFNm,"SUCCESS, Is_Upper"); + return SUCCESS; + } + break; + default: + ErrMsg(ERR_IQC); /* ill. char. after " */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (FlowEE() == FAILURE) { /* flow to | or ' */ + DBGFEX(1,DbgFNm,"FAILURE, FlowEE() failed"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS, test failed"); + return SUCCESS; +} diff --git a/src/exee.c b/src/exee.c new file mode 100644 index 0000000..f40f696 --- /dev/null +++ b/src/exee.c @@ -0,0 +1,1443 @@ +/***************************************************************************** + + ExeE() + + This function executes a E command. + + EA Select secondary output stream + EBfilespec$ Open file for input and output + :EBfilespec$ EB, return status + EC Close out (copy in to out and close) + ED Edit mode flag + EE Escape surrogate character + EF Close output file + EG Close out and exit, run last COMPIL class command + :EGcmd args$ Performs operating system function + :EGtext$ Close out and exit, run "text" + EH Help level flag + EI Close current indirect command file + EIfilespec$ Open indirect command file + m,nEJ Set environment characteristics + nEJ Return environment characteristics + EK Kill output file + ELfilespec$ Open log file + mEM Position mag tape + EN Wildcard lookup + :EN EN, return status + ENfilespec$ Preset wildcard lookup + EO Version of TECO + nEO Set TECO to function as version n + EP Select secondary input stream + EQqfilespec$ Read file into Q-register q + ER Select primary input stream + ERfilespec$ Open input file + :ERfilespec$ ER, return status + ES Search verification flag + ET Type out control flag + EU Case flagging flag + EV Edit verify flag + EWfilespec$ Open output file + EW Select primary output stream + EX Close out and exit + EY Read without yank protection + EZ System-dependent mode control flags + E%qfilespec$ Write Q-register q into a file + nE_ Search without yank protection + +*****************************************************************************/ + +#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 "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ + +#if USE_PROTOTYPES +static DEFAULT DoEI(DEFAULT IfIndx); +static DEFAULT ExeEA(void); +static DEFAULT ExeEB(void); +static DEFAULT ExeEC(void); +static DEFAULT ExeED(void); +static DEFAULT ExeEF(void); +static DEFAULT ExeEG(void); +static DEFAULT ExeEH(void); +static DEFAULT ExeEI(void); +static DEFAULT ExeEK(void); +static DEFAULT ExeEN(void); +static DEFAULT ExeEO(void); +static DEFAULT ExeEP(void); +static DEFAULT ExeEPr(void); +static DEFAULT ExeEQ(void); +static DEFAULT ExeER(void); +static DEFAULT ExeES(void); +static DEFAULT ExeET(void); +static DEFAULT ExeEU(void); +static DEFAULT ExeEUn(void); +static DEFAULT ExeEV(void); +static DEFAULT ExeEW(void); +static DEFAULT ExeEX(void); +static DEFAULT ExeEZ(void); +static DEFAULT GetWha(charptr TxtPtr, ptrdiff_t TxtLen); +static DEFAULT OpnEI(DEFAULT EInd); +static DEFAULT OpnInp(DEFAULT IfIndx, BOOLEAN EIFile, BOOLEAN RepFNF); +static DEFAULT OpnOut(DEFAULT OfIndx, BOOLEAN RepErr, BOOLEAN Backup); +static DEFAULT ReadEI(DEFAULT IfIndx, charptr *ZBfPtr, charptr *EscPtr); +#endif + +charptr ZBfBeg; +charptr ZBfEnd; +charptr ZBfRdP; /* pointer where to start reading into ZBf */ + +/***************************************************************************** + + OpnInp() + + 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. + +*****************************************************************************/ + +static DEFAULT OpnInp(IfIndx, EIFile, RepFNF) +DEFAULT IfIndx; /* output file indicator */ +BOOLEAN EIFile; /* is it a macro file? */ +BOOLEAN RepFNF; /* report "file not found" error? */ +{ + DEFAULT status; + + DBGFEN(2,"OpnInp",NULL); + + ZIClos(IfIndx); /* close input file, if any */ + + status = ZOpInp(IfIndx, EIFile, RepFNF); + if (status != SUCCESS) { + if (!RepFNF && (status == FILENF)) { + DBGFEX(2,DbgFNm,"FILENF"); + return FILENF; + } + ErrPSt(ERR_UFI, FBfBeg, FBfPtr); + DBGFEX(2,DbgFNm,"status"); + return status; + } + + IsOpnI[IfIndx] = TRUE; /* mark the file as open */ + IsEofI[IfIndx] = FALSE; /* end-of-file indicator */ + + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + OpnOut() + + 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. + +*****************************************************************************/ + + +static DEFAULT OpnOut(OfIndx, RepErr, Backup) +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +BOOLEAN Backup; /* create backup? TAA Added */ +{ + DBGFEN(2,"OpnOut",NULL); + + if (IsOpnO[OfIndx]) { /* if output file is open */ + ErrMsg(ERR_OFO); /* OFO = output file already open */ + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + + if (ZOpOut(OfIndx, RepErr, Backup) == FAILURE) { + if (RepErr) { + ErrPSt(ERR_UFO, FBfBeg, FBfPtr); + } + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + + IsOpnO[OfIndx] = TRUE; + + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEA() + + This function executes an EA command. + + EA Select secondary output stream + +*****************************************************************************/ + +static DEFAULT ExeEA() /* execute an EA command */ +{ + DBGFEN(1,"ExeEA",NULL); + + CurOut = SOUTFL; + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEB() + + This function executes an EB command. + + EBfilespec$ Open file for input and output + :EBfilespec$ EB, return status + +*****************************************************************************/ + +static DEFAULT ExeEB() /* execute an EB command */ +{ + BOOLEAN RepFNF; /* report "file not found" ? */ + DEFAULT status; /* OpnInp() status */ + + DBGFEN(1,"ExeEB",NULL); + + if (BldStr(FBfBeg, FBfEnd, &FBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + RepFNF = !(CmdMod & COLON); /* report file not found? */ + CmdMod = '\0'; /* clear modifiers flags */ + status = OpnInp(CurInp, FALSE, RepFNF); /* open input file */ + if (status != SUCCESS) { + if (status == FILENF) { + if (!RepFNF) { /* if it's :EB */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L,OPERAND); + } + } + DBGFEX(1,DbgFNm,"FAILURE, OpnInp() failed"); + return FAILURE; + } + + ZMKOFN(); /* kludge for VMS filenames */ + + if (OpnOut(CurOut, RepFNF, TRUE) == FAILURE) {/* open output file */ +#if DEBUGGING + sprintf(DbgSBf,"%s, OpnOut() failed", + (RepFNF) ? "FAILURE" : "PushEx(0)"); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return (RepFNF) ? FAILURE : PushEx(0L,OPERAND); + } + + if (!RepFNF) { /* if it's :EB */ + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L,OPERAND); + } + + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEC() + + This function executes an EC command. + + EC Close out (copy in to out and close) + +*****************************************************************************/ + +static DEFAULT ExeEC() /* execute an EC command */ +{ + DBGFEN(1,"ExeEC",NULL); + + if (EStTop > EStBot) { /* if numeric argument */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + +/* ??? */ ZDspBf("memory expand as per page 84\r\n", 29); + CmdMod = '\0'; /* clear modifiers flags */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + + if (IsOpnO[CurOut]) { + +/* + * if there's text in the edit buffer, or if the form feed flag indicates + * that the current page needs to be output, call WrPage to write the page, + * then clear the edit buffer. + */ + + if ((GapBeg > EBfBeg) || (GapEnd < EBfEnd) || FFPage) { + if (WrPage(CurOut, EBfBeg, EBfEnd, FFPage) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, WrPage() failed"); + return FAILURE; + } + GapBeg = EBfBeg; /* clear the... */ + GapEnd = EBfEnd; /* ...edit buffer */ + } + +/* + * Move the remainder of the current input file, if any, to the currenti + * output file. + */ + + if (IsOpnI[CurInp]) { /* if input file is open */ + while (!IsEofI[CurInp]) { /* while not end-of-file */ + if (RdPage() == FAILURE) { /* read a page */ + DBGFEX(1,DbgFNm,"FAILURE, RdPage() failed"); + return FAILURE; + } + if (WrPage(CurOut, EBfBeg, EBfEnd, FFPage) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, WrPage() failed"); + return FAILURE; + } + GapBeg = EBfBeg; /* clear the... */ + GapEnd = EBfEnd; /* ...edit buffer */ + } + } + } + + ZIClos(PINPFL); /* close primary input file */ + ZIClos(SINPFL); /* close secondary input file */ + ZOClos(POUTFL); /* close primary output file */ + ZOClos(SOUTFL); /* close secondary output file */ + + CmdMod = '\0'; /* clear modifiers flag */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeED() + + This function executes an ED command. + + ED Edit mode flag + +*****************************************************************************/ + +static DEFAULT ExeED() /* execute an ED command */ +{ + DBGFEN(1,"ExeED",NULL); + DBGFEX(1,DbgFNm,"DoFlag(&EdFlag)"); + return DoFlag(&EdFlag); +} + +/***************************************************************************** + + ExeEF() + + This function executes an EF command. + + EF Close output file + +*****************************************************************************/ + +static DEFAULT ExeEF() /* execute an EF command */ +{ + DBGFEN(1,"ExeEF",NULL); + + ZOClos(CurOut); /* close output file */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEG() + + This function implements the EG command. If the EG command is not +colon modified, it terminates TECO and passes a command line to the command +line interpreter. + + EG Close out and exit + EGtext$ Close out and exit, execute "text" command + +If the EG command is colon modified, then it implements one of the "special +functions" as follows: + + :EGINI$ gets, sets or clears the initialization file name + :EGLIB$ gets, sets or clears the macro library directory + :EGMEM$ gets, sets or clears the file name memory + :EGVTE$ gets, sets or clears the video macro file name + +other, system-dependent functions may be defined. See the ZClnEG function. + +*****************************************************************************/ + +static DEFAULT GetWha(TxtPtr, TxtLen) /* get "what to operate on" */ +charptr TxtPtr; /* string to parse */ +ptrdiff_t TxtLen; /* length of string */ +{ + if (TxtLen >= 3) { /* it's long enough */ + switch(To_Upper(*TxtPtr)) { + case 'I': /* INI (init macro) */ + TxtPtr++; + if (To_Upper(*TxtPtr) == 'N') { + ++TxtPtr; + if (To_Upper(*TxtPtr) == 'I') { + return EG_INI; + } + } + break; + + case 'L': /* LIB (macro directory) */ + TxtPtr++; + if (To_Upper(*TxtPtr) == 'I') { + TxtPtr++; + if (To_Upper(*TxtPtr) == 'B') { + return EG_LIB; + } + } + break; + + case 'M': /* MEM (filename memory) */ + TxtPtr++; + if (To_Upper(*TxtPtr) == 'E') { + TxtPtr++; + if (To_Upper(*TxtPtr) == 'M') { + return EG_MEM; + } + } + break; + + case 'V': /* VTE (vtedit macro) */ + TxtPtr++; + if (To_Upper(*TxtPtr) == 'T') { + TxtPtr++; + if (To_Upper(*TxtPtr) == 'E') { + return EG_VTE; + } + } + break; + + default: + break; + } + } + + return EG_OTHER; +} + +#define GBFSIZE 256 + +static DEFAULT ExeEG() /* perform operating system function */ +{ + DEFAULT EGWhat; /* what to operate on: INI, VTE, etc. */ + unsigned char GBfBeg[GBFSIZE]; + charptr GBfPtr; + ptrdiff_t GBfLen; + + DBGFEN(1,"ExeEG",NULL); + + if (BldStr(GBfBeg, GBfBeg+GBFSIZE-2, &GBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + GBfLen = GBfPtr - GBfBeg; + if (CmdMod & COLON) { /* if it's :EG */ + DEFAULT EGOper = GET_VAL; /* get, set or clear */ + charptr TmpPtr; + CmdMod &= ~COLON; /* clear colon flag */ + EGWhat = GetWha(GBfBeg,GBfLen); + TmpPtr = (charptr)GBfBeg; + if (EGWhat != EG_OTHER) { + if (GBfLen == 4) { /* if it's "clear" */ + if (*(TmpPtr+3) != ' ') { + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L,OPERAND); + } + EGOper = CLEAR_VAL; + } else if (GBfLen != 3) { /* it it's not "get" */ + EGOper = SET_VAL; + TmpPtr += 4; + } + } + *GBfPtr = '\0'; + DBGFEX(1,DbgFNm,"PushEx(ZClnEG())"); + return PushEx(ZClnEG(EGWhat,EGOper,TmpPtr),OPERAND); + } + + if (ExeEC() == FAILURE) { /* do an EC command */ + DBGFEX(1,DbgFNm,"FAILURE, ExeEC() failed"); + return FAILURE; + } + + if (GBfLen == 0) { /* if it was EC$ */ + TAbort(EXIT_SUCCESS); /* just exit TECO-C */ + } + + ZDoCmd(GBfBeg, GBfPtr); /* exit with a command */ + DBGFEX(1,DbgFNm,"SUCCESS"); /* we should never reach this */ + return SUCCESS; +} + +/***************************************************************************** + + ExeEH() + + This function executes an EH command. + + EH Help level flag + +*****************************************************************************/ + +static DEFAULT ExeEH() /* execute an EH command */ +{ + DBGFEN(1,"ExeEH",NULL); + DBGFEX(1,DbgFNm,"DoFlag()"); + return DoFlag(&EhFlag); +} + +/***************************************************************************** + + ReadEI() + + This function reads an EI file. It is passed an index for the file +data block of the open EI file, and a buffer. It reads the contents of the +file into the buffer, stopping when a double ESCAPE or end-of-file is +encountered. + +*****************************************************************************/ + +static DEFAULT ReadEI(IfIndx, ZBfPtr, EscPtr) +DEFAULT IfIndx; /* index into IFiles array */ +charptr *ZBfPtr; /* returned ptr to end of EI string (+1) */ +charptr *EscPtr; /* returned ptr to $$ in EI string (+1) */ +{ + DEFAULT line_len; + charptr NewBuf; + SIZE_T NewSiz; + BOOLEAN previous_char_was_escape; + charptr TmpPtr; + +#if DEBUGGING + static char *DbgFNm = "ReadEI"; + sprintf(DbgSBf,"ZBfBeg = %ld, ZBfEnd = %ld", + Zcp2ul(ZBfBeg), Zcp2ul(ZBfEnd)); + DbgFEn(1,DbgFNm,DbgSBf); +#endif + + FOREVER { + +/* + * potentially reallocate ZBf + */ + + if ((ZBfEnd - ZBfRdP) < ZBFMIN) { + NewSiz = (ZBfEnd - ZBfBeg) + ZBFEXP; + NewBuf = (charptr)ZRaloc(ZBfBeg, NewSiz); + if (NewBuf == NULL) { + ErrMsg(ERR_MEM); /* MEM = memory overflow */ + DBGFEX(1,DbgFNm,"FAILURE, ZRaloc() failed"); + return (FAILURE); + } + ZBfRdP = NewBuf + (ZBfRdP - ZBfBeg); + ZBfEnd = NewBuf + NewSiz; + ZBfBeg = NewBuf; + } +/* + * append a line from the EI file to ZBf + */ + + if (ZRdLin(ZBfRdP,ZBfEnd-ZBfRdP,IfIndx,&line_len) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, ZRdLin() failed"); + return (FAILURE); + } + +/* + * break out of FOREVER loop if we tried reading past end of file. + */ + + if (IsEofI[IfIndx]) { + DBGFMS(1,DbgFNm,"ran into EOF"); + break; + } + +#if DEBUGGING + sprintf(DbgSBf,"read %d bytes: \"%.*s\"", + (int)line_len, (int)line_len, ZBfRdP); + DbgFMs(1,DbgFNm,DbgSBf); +#endif + +/* + * go through the line we've read, looking for $$. + */ + + TmpPtr = ZBfRdP; + ZBfRdP += line_len; + previous_char_was_escape = FALSE; + for (; TmpPtr < ZBfRdP; ++TmpPtr) { + if (*TmpPtr == ESCAPE) { + if (previous_char_was_escape) { + *ZBfPtr = ZBfRdP; + *EscPtr = ++TmpPtr; + DBGFEX(1,DbgFNm, + "SUCCESS, ran into $$"); + return (SUCCESS); + } + previous_char_was_escape = TRUE; + } else { + previous_char_was_escape = FALSE; + } + } + } + + *ZBfPtr = ZBfRdP; + *EscPtr = NULL; + + DBGFEX(1,DbgFNm,"SUCCESS"); + + return SUCCESS; +} + +/***************************************************************************** + + OpnEI() + + This function opens an EI file. The file name given by the user may +find the file one of the following ways: + + 1. as given (current directory) + 2. as given, but with a ".TEC" type (current directory) + 3. as given, in the default directory, with a ".TEC" type + 3. as given, in the default directory + +As soon as one of these forms is found and opened, this function returns. + +*****************************************************************************/ + +static DEFAULT OpnEI(EInd) /* open an EI file */ +DEFAULT EInd; +{ +#ifdef OPNEI_FINISHED + if (OpnInp(EInd, FALSE, TRUE) == SUCCESS) + return(SUCCESS); + if (OpnInp(EInd, TRUE, TRUE) == SUCCESS) + return(SUCCESS); + save contents of FBf + use :EGDEF command to fill FBf with default directory (how?) + append saved FBf to actual FBf + if (OpnInp(EInd, FALSE, TRUE) == SUCCESS) + return(SUCCESS); + if (OpnInp(EInd, TRUE, TRUE) == SUCCESS) + return(SUCCESS); +#else + return OpnInp(EInd, TRUE, TRUE); +#endif +} + +/***************************************************************************** + + DoEI() + + This function performs the execution part of an EI command. It is +called by the ExeEI function. It is passed an index to a file data block in +the IFiles array that has been opened. It is also passed a memory buffer. +This function reads text from the file into the buffer and calls ExeCSt to +execute the text. + +*****************************************************************************/ + +static DEFAULT DoEI(IfIndx) /* do an EI command */ +DEFAULT IfIndx; /* index into IFiles array */ +{ + charptr ZBfPtr; /* pointer to end of command string in ZBf */ + charptr EscPtr; /* ptr into ZBf past second $ of $$ pair */ + DEFAULT status; /* return status of ExeCSt() */ + + DBGFEN(1,"DoEI",NULL); + + status = SUCCESS; /* in case we try doing an empty EI file */ + ZBfRdP = ZBfBeg; /* start reading into beginning of ZBf */ + do { +/* + * Read EI file into ZBf until $$ or EOF, whichever comes first + */ + if (ReadEI(IfIndx, &ZBfPtr, &EscPtr) == FAILURE) { + ErrMsg(ERR_URE); /* Unable to Read EI file */ + DBGFEX(1,DbgFNm,"FAILURE, ReadEI() failed"); + return FAILURE; + } +/* + * save the current execution state and make ZBf the current command string + * to execute + */ + if (PshMac(ZBfBeg, (EscPtr) ? EscPtr : ZBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, PshMac() failed"); + return FAILURE; + } +/* + * execute macro in ZBf + */ + status = ExeCSt(); + +#if DEBUGGING + if (status == FAILURE) { + DbgFMs(1,DbgFNm,"ExeCSt() failed"); + } +#endif +/* + * restore old execution state + */ + if (PopMac() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, PopMac() failed"); + return FAILURE; + } +/* + * if we ran into an $$ that was in the middle of a line, then we want to + * move it to the beginning of ZBf and append the rest of the EI file to + * it; otherwise, we'll just start reading into the beginning of ZBf. + */ + if (EscPtr) { + ptrdiff_t LeftOver; + + LeftOver = ZBfPtr - EscPtr; + MEMMOVE(ZBfBeg, EscPtr, LeftOver); + ZBfRdP = ZBfBeg + LeftOver; + } else { + ZBfRdP = ZBfBeg; + } + + } while (!IsEofI[IfIndx] && !GotCtC && status != FAILURE); + + DBGFEX(1,DbgFNm,(status == FAILURE) ? "FAILURE" : "SUCCESS"); + + return status; /* return ExeCSt() status */ +} + +/***************************************************************************** + + ExeEI() + + This function executes an EI command. This function does only part of +the work; the DoEI function does the rest. This function opens/closes the +file and allocates/deallocates an input buffer. The code executes such that +no matter what happens, an open file will always be closed and allocated +memory will always be freed. + + EI Close current indirect command file + EIfilespec$ Open indirect command file + +*****************************************************************************/ + +/* + * EIIndx is an index into the IFiles array. It is incremented each time an + * EI command is executed and decremented each time an EI command completes. + * It is the index of the file data block of the currently open EI input file. + * When EIIndx equals EIFL-1, no EI files are open. + */ + +static DEFAULT EIIndx = EIFL-1; + +static DEFAULT ExeEI() /* execute an EI command */ +{ + int status; + + DBGFEN(1,"ExeEI",NULL); + + if (BldStr(FBfBeg, FBfEnd, &FBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + if (FBfPtr == FBfBeg) { /* if it's EI$ */ + if (EIIndx >= EIFL) { /* if EI file is open */ + CmdMod = '\0'; /* clear modifiers flags */ + } + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + + if (++EIIndx > NIFDBS) { /* If EI nesting too deep */ + EIIndx--; + ErrMsg(ERR_MEM); /* ERR_MEM=memory overflow */ + DBGFEX(1,DbgFNm,"FAILURE, EI nested too deep"); + return FAILURE; + } + + if (OpnEI(EIIndx) != SUCCESS) { /* open EI file */ + status = FAILURE; + } else { + ZBfBeg = (charptr)ZAlloc(ZBFINIT); /* allocate input buffer */ + if (ZBfBeg == NULL) { /* if allocation failed */ + ErrMsg(ERR_MEM); /* MEM = memory overflow */ + status = FAILURE; + } else { /* else allocation ok */ + ZBfEnd = ZBfBeg + ZBFINIT; + status = DoEI(EIIndx); + ZFree((voidptr)ZBfBeg); /* free allocated memory */ + } + ZIClos(EIIndx); + } + EIIndx--; /* decrement nesting count */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + + return status; +} + +/***************************************************************************** + + ExeEK() + + This function executes an EK command. + + EK Kill output file + +*****************************************************************************/ + +static DEFAULT ExeEK() /* execute an EK command */ +{ + DBGFEN(1,"ExeEK",NULL); + + ZOClDe(CurOut); /* close and delete output file */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + + return SUCCESS; +} + +/***************************************************************************** + + ExeEN() + + This function executes an EN command. + + EN Wildcard lookup + :EN EN, return status + ENfilespec$ Preset wildcard lookup + +*****************************************************************************/ + +static DEFAULT ExeEN() /* execute an EN command */ +{ + DBGFEN(1,"ExeEN",NULL); + + if (BldStr(FBfBeg, FBfEnd, &FBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + if (FBfPtr == FBfBeg) { /* if it's EN$ or :EN$ */ + switch (ZSWild()) { + case FAILURE: + DBGFEX(1,DbgFNm,"FAILURE, ZSWild() failed"); + return FAILURE; + + case FILENF: + if (CmdMod & COLON) { /* if it's :EN */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot;/* clear expression stack */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L,OPERAND); + } + ErrStr(ERR_FNF, ""); /* file not found */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + + case SUCCESS: + if (CmdMod & COLON) { /* if it's :EN */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L,OPERAND); + } + EStTop = EStBot;/* clear expression stack */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + + if (ZPWild() == FAILURE) { /* preset wildcard filepsec */ + DBGFEX(1,DbgFNm,"FAILURE, ZPWild() failed"); + return FAILURE; + } + + EStTop = EStBot; /* clear expression stack */ + CmdMod = '\0'; /* clear modifiers flags */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEO() + + This function executes an EO command. TECO-C's version numbers +started at 100 and went up. Other implementations of TECO have version +numbers less than 100. + + EO Version of TECO + nEO Set TECO to function as version n + +*****************************************************************************/ + +static DEFAULT ExeEO() /* execute an EO command */ +{ + return ((EStTop > EStBot) /* is it nEO ? */ + ? ExeNYI() /* ...yes, not supported */ + : PushEx((LONG)TVERSION,OPERAND)); /* ...no, return version */ +} + +/***************************************************************************** + + ExeEP() + + This function executes an EP command. + + EP Select secondary input stream + +*****************************************************************************/ + +static DEFAULT ExeEP() /* execute an EP command */ +{ + DBGFEN(1,"ExeEP",NULL); + + CurInp = SINPFL; /* select secondary input stream */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEPr() + + This function executes an E% command. + + E%qfilespec$ Write Q-register q into a file + +*****************************************************************************/ + +static DEFAULT ExeEPr() /* execute an E% command */ +{ + BOOLEAN RepErr; /* report errors? */ + + DBGFEN(1,"ExeEPr",NULL); + + if (IncCBP() == FAILURE) { /* move to char after % */ + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + + if (FindQR() == FAILURE) { /* find q-register */ + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } + + if (BldStr(FBfBeg, FBfEnd, &FBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + if (FBfPtr == FBfBeg) { /* if it's E%q$ */ + ErrUTC(); /* unterminated command */ + DBGFEX(1,DbgFNm,"FAILURE, unterminated command"); + return FAILURE; + } + + RepErr = !(CmdMod & COLON); + CmdMod = '\0'; + if (OpnOut(EPRCFL, RepErr, FALSE) == FAILURE) { +#if DEBUGGING + sprintf(DbgSBf,"%s, OpnOut() failed", + (RepErr) ? "FAILURE" : "PushEx(0)"); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return ((RepErr) ? FAILURE : PushEx(0L,OPERAND)); + } + + if (QR->Start != NULL) { /* if it's not empty */ + if (ZWrBfr(EPRCFL, QR->Start, QR->End_P1-1) == FAILURE) { +#if DEBUGGING + sprintf(DbgSBf,"%s, ZWrBfr() failed", + (RepErr) ? "FAILURE" : "PushEx(0)"); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return ((RepErr) ? FAILURE : PushEx(0L,OPERAND)); + } + } + + ZOClos(EPRCFL); /* close the file */ + + if (!RepErr) { + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L,OPERAND); + } + + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEQ() + + This function executes an EQ command. The EQ command reads a file +directly into a q-register. This command uses the RdPage function to +temporarily append the contents of the file to the end of the edit buffer. +It then copies the text to a q-register. + + EQqfilespec$ Read file into Q-register q + +*****************************************************************************/ + +static DEFAULT ExeEQ() /* execute an EQ command */ +{ + ptrdiff_t FSize; /* file size */ + LONG SvFFPg; /* saved FFPage value */ + DEFAULT SvCrIn; /* saved CurInp value */ + ptrdiff_t SvEbSz; /* saved edit buffer size */ + DEFAULT Status; + + DBGFEN(1,"ExeEQ",NULL); + + if (IncCBP() == FAILURE) { /* move to char after Q */ + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + + if (FindQR() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } + + if (BldStr(FBfBeg, FBfEnd, &FBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + if (FBfPtr == FBfBeg) { /* if it's EQq$ */ + ErrUTC(); /* unterminated command */ + DBGFEX(1,DbgFNm,"FAILURE, unterminated command"); + return FAILURE; + } + + if (OpnInp(EQFL, FALSE, TRUE) != SUCCESS) { /* open the file */ + DBGFEX(1,DbgFNm,"FAILURE, OpnInp() failed"); + return FAILURE; + } + +/* + * We borrow RdPage's ability to read files correctly. RdPage reads file + * CurInp, so we need to temporarily set CurInp to the EQ file data block. + * The data is appended to the edit buffer, so we need to save the pointer + * to the current end of the edit buffer. + */ + SvCrIn = CurInp; /* save CurInp */ + SvEbSz = (EBfEnd - EBfBeg) - (GapEnd - GapBeg); /* save EBfEnd */ + SvFFPg = FFPage; /* save FFPage */ + CurInp = EQFL; + do { + if (RdPage() == FAILURE) { + Status = FAILURE; + goto exeeqdone; + } + } while (!IsEofI[EQFL]); + +/* + * Make room in the q-register. + */ + FSize = EBfEnd - (EBfBeg + SvEbSz + (GapEnd - GapBeg)); + if (MakRom((SIZE_T)FSize) == FAILURE) { + Status = FAILURE; + goto exeeqdone; + } + +/* + * Copy the text that we just read from the file into the q-register. + */ + MEMMOVE(QR->Start, + EBfBeg + SvEbSz + 1 + (GapEnd - GapBeg), + (SIZE_T)FSize); + QR->End_P1 = QR->Start + FSize; + + Status = SUCCESS; +exeeqdone: + FFPage = SvFFPg; /* restore FFpage */ + EBfEnd = EBfBeg + SvEbSz + + (GapEnd - GapBeg); /* restore EBfEnd */ + CurInp = SvCrIn; /* restore CurInp */ + + ZIClos(EQFL); /* close the file */ + + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,(Status == SUCCESS) ? "SUCCESS" : "FAILURE"); + return Status; +} + +/***************************************************************************** + + ExeER() + + This function executes an ER command. + + ER Select primary input stream + ERfilespec$ Open input file + :ERfilespec$ ER, return status +*****************************************************************************/ + +static DEFAULT ExeER() /* execute an ER command */ +{ + BOOLEAN RepFNF; /* report "file not found" errors? */ + DEFAULT status; + + DBGFEN(1,"ExeER",NULL); + + if (BldStr(FBfBeg, FBfEnd, &FBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + if (FBfPtr == FBfBeg) { /* if it's ER$ */ + CurInp = PINPFL; /* primary input stream */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + + RepFNF = !(CmdMod & COLON); /* report file not found? */ + CmdMod = '\0'; /* clear modifiers flags */ + status = OpnInp(CurInp, FALSE, RepFNF); /* open input file */ + if (status != SUCCESS) { + if (status == FILENF) { + if (!RepFNF) { /* if it's :ER */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L,OPERAND); + } + } + DBGFEX(1,DbgFNm,"FAILURE, OpnInp() failed"); + return FAILURE; + } + + if (!RepFNF) { /* if it's :ER */ + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L,OPERAND); + } + + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeES() + + This function executes an ES command. + + ES Search verification flag + +*****************************************************************************/ + +static DEFAULT ExeES() /* execute an ES command */ +{ + DBGFEN(1,"ExeES",NULL); + DBGFEX(1,DbgFNm,"DoFlag(&EsFlag)"); + return DoFlag(&EsFlag); +} + +/***************************************************************************** + + ExeET() + + This function executes an ET command. + + ET Type out control flag + +*****************************************************************************/ + +static DEFAULT ExeET() /* execute an ET command */ +{ + DEFAULT status; + WORD TmpET; + + DBGFEN(1,"ExeET",NULL); + + TmpET = EtFlag; + status = DoFlag(&EtFlag); + +/* + * If DoFlag set or cleared the 8-bit flag, we have to tell the operating + * system. + */ + if (status != FAILURE) { + if ((TmpET & ET_EIGHTBIT) && /* eightbit flag cleared? */ + !(EtFlag & ET_EIGHTBIT)) { + status = ZSetTT(TT8BIT, 0); + } else if (!(TmpET & ET_EIGHTBIT) && /* eightbit flag set? */ + (EtFlag & ET_EIGHTBIT)) { + status = ZSetTT(TT8BIT, 1); + } + } + +/* + * If one of the read-only flags was changed, set it back. + */ + if ((TmpET & ET_WAT_SCOPE) != (EtFlag & ET_WAT_SCOPE)) { + if (TmpET & ET_WAT_SCOPE) /* if it was cleared */ + EtFlag |= ET_WAT_SCOPE; /* set it */ + else + EtFlag &= ~ET_WAT_SCOPE; /* clear it */ + } + if ((TmpET & ET_WAT_REFRESH) != (EtFlag & ET_WAT_REFRESH)) { + if (TmpET & ET_WAT_REFRESH) /* if it was cleared */ + EtFlag |= ET_WAT_REFRESH; /* set it */ + else + EtFlag &= ~ET_WAT_REFRESH; /* clear it */ + } + + DBGFEX(1,DbgFNm,(status==FAILURE) ? "FAILURE" : "SUCCESS"); + return status; +} + +/***************************************************************************** + + ExeEU() + + This function executes an EU command. + + EU Case flagging flag + +*****************************************************************************/ + +static DEFAULT ExeEU() /* execute an EU command */ +{ + DBGFEN(1,"ExeEU",NULL); + DBGFEX(1,DbgFNm,"DoFlag(&EuFlag)"); + return DoFlag(&EuFlag); +} + +/***************************************************************************** + + ExeEUn() + + This function executes an E_ command. + + nE_ Search without yank protection + +*****************************************************************************/ + +static DEFAULT ExeEUn() /* execute an E_ command */ +{ + DBGFEN(1,"ExeEUn",NULL); + +/* + * The command m,nE_ is illegal: the user should use m,nFB + */ + + if (CmdMod & MARGIS) { /* if it's m,nE_ */ + ErrStr(ERR_ILL, "m,nE_"); /* illegal command "m,nE_" */ + DBGFEX(1,DbgFNm,"FAILURE, m,nE is illegal"); + return FAILURE; + } + + if (CmdMod & DCOLON) { /* if it's ::E_ */ + ErrStr(ERR_ILL, "::E_"); /* illegal command "::E_" */ + DBGFEX(1,DbgFNm,"FAILURE, ::E_ is illegal"); + return FAILURE; + } + + SrcTyp = E_SEARCH; + if (Search(FALSE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, Search() failed"); + return FAILURE; + } + + CmdMod = '\0'; /* clear modifiers flags */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEV() + + This function executes an EV command. + + EV Edit verify flag + +*****************************************************************************/ + +static DEFAULT ExeEV() /* execute an EV command */ +{ + DBGFEN(1,"ExeEV",NULL); + DBGFEX(1,DbgFNm,"DoFlag()"); + return DoFlag(&EvFlag); +} + +/***************************************************************************** + + ExeEW() + + This function executes an EW command. + + EWfilespec$ Open output file + EW Select primary output stream + +*****************************************************************************/ + +static DEFAULT ExeEW() /* execute an EW command */ +{ + BOOLEAN RepErr; /* report errors? */ + + DBGFEN(1,"ExeEW",NULL); + + if (BldStr(FBfBeg, FBfEnd, &FBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + + if (FBfPtr == FBfBeg) { /* if it's EW$ */ + CmdMod = '\0'; /* clear modifiers flags */ + CurOut = POUTFL; /* primary output stream */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + + RepErr = !(CmdMod & COLON); + CmdMod = '\0'; /* clear modifiers flags */ + if (OpnOut(CurOut, RepErr, FALSE) == FAILURE) { +#if DEBUGGING + sprintf(DbgSBf,"%s, OpnOut() failed", + (RepErr) ? "FAILURE" : "PushEx(0)"); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return ((RepErr) ? FAILURE : PushEx(0L,OPERAND)); + } + + if (!RepErr) { + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L,OPERAND); + } + + EStTop = EStBot; /* clear expression stack */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} + +/***************************************************************************** + + ExeEX() + + This function executes an EX command. + + EX Close out and exit + +*****************************************************************************/ + +static DEFAULT ExeEX() /* execute an EX command */ +{ + DBGFEN(1,"ExeEX",NULL); + + if (ExeEC() != FAILURE) { /* execute an EC command */ + DBGFEX(1,DbgFNm,"exiting successfully!"); + TAbort(EXIT_SUCCESS); /* exit TECO-C */ + } + + DBGFEX(1,DbgFNm,"FAILURE, ExeEX() failed"); + return FAILURE; +} + +/***************************************************************************** + + ExeEZ() + + This function executes an EZ command. EZ is a mode control flag +that contains bits specific to the operating system we're using. + +*****************************************************************************/ + +static DEFAULT ExeEZ() /* execute an EZ command */ +{ + DBGFEN(1,"ExeEZ",NULL); + DBGFEX(1,DbgFNm,"DoFlag(&EZFlag)"); + return DoFlag(&EzFlag); +} + +/***************************************************************************** + + ExeE() + + This function executes two-letter commands that start with "E". +It uses the character following the "E" to index into a table of functions. + +*****************************************************************************/ + +DEFAULT ExeE() /* execute an E command */ +{ + unsigned char TmpChr; + static DEFAULT (*FEAray[])(VVOID) = { + /* A */ ExeEA, /* B */ ExeEB, + /* C */ ExeEC, /* D */ ExeED, + /* E */ ExeIll, /* F */ ExeEF, + /* G */ ExeEG, /* H */ ExeEH, + /* I */ ExeEI, /* J */ ZExeEJ, + /* K */ ExeEK, /* L */ ExeNYI, + /* M */ ExeNYI, /* N */ ExeEN, + /* O */ ExeEO, /* P */ ExeEP, + /* Q */ ExeEQ, /* R */ ExeER, + /* S */ ExeES, /* T */ ExeET, + /* U */ ExeEU, /* V */ ExeEV, + /* W */ ExeEW, /* X */ ExeEX, + /* Y */ ExeEY, /* Z */ ExeEZ + }; + + if (IncCBP() == FAILURE) { + return FAILURE; + } + + TmpChr = To_Upper (*CBfPtr); + + if (TmpChr == '%') { /* we have E%q */ + return ExeEPr(); + } + + if (TmpChr == '_') { /* we have nE_ */ + return ExeEUn(); + } + + if (!Is_Upper(TmpChr) || (TmpChr == 'E')) { + ErrChr(ERR_IEC, TmpChr); + return FAILURE; + } + + return (*FEAray[TmpChr-'A'])(); +} diff --git a/src/exeequ.c b/src/exeequ.c new file mode 100644 index 0000000..538c769 --- /dev/null +++ b/src/exeequ.c @@ -0,0 +1,54 @@ +/***************************************************************************** + ExeEqu() + This function executes the = (equals sign) command: + n= display n in decimal, with carriage return + n== display n in octal, with carriage return + n=== display n in hexadecimal, with carriage return + n:= display n in decimal, without carriage return + n:== display n in octal, without carriage return + n:=== display n in hexadecimal, without carriage return +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeEqu() /* execute an = (equals sign) comand */ +{ + DBGFEN(1,"ExeEqu",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + ErrMsg(ERR_NAE); /* NAE = "No arg before =" */ + DBGFEX(1,DbgFNm,"FAILURE, no arg before ="); + return FAILURE; + } + if (GetNmA() == FAILURE) { /* get the numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if (*(CBfPtr+1) != '=') { /* if next char not = */ + MakDBf(NArgmt, 10); /* make string in decimal */ + } else { + if (IncCBP() == FAILURE) { /* move to next char */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (*(CBfPtr+1) != '=') { /* if next char not = */ + MakDBf(NArgmt, 8); /* make string in octal */ + } else { + if (IncCBP() == FAILURE) { /* move to next char */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + MakDBf(NArgmt, 16); /* make string in hex */ + } + } + if (CmdMod & COLON) { /* if colon modified */ + CmdMod &= ~COLON; /* clear colon flag */ + } else { + *DBfPtr++ = CRETRN; /* append a carriage return */ + *DBfPtr++ = LINEFD; /* append a line feed */ + } + ZDspBf(DBfBeg, DBfPtr-DBfBeg); /* display the string */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeesc.c b/src/exeesc.c new file mode 100644 index 0000000..674a86f --- /dev/null +++ b/src/exeesc.c @@ -0,0 +1,33 @@ +/***************************************************************************** + ExeEsc() + This function executes an ESCAPE command. +An ESCAPE that is executed as a TECO command (as distinct from an ESCAPE +that is part of the syntax of some other TECO command) is ignored by TECO, +except that pending numeric values are discarded. This command is useful +for discarding the value returned from a command (such as n%q) when that +value is not needed. +Two escapes cause TECO to exit from the current macro level. If two escapes +are encountered from top level (not from within a macro), then the command +string execution is terminated. Both escapes must be true TECO commands +and not part of the syntax of some previous command. That is, the first +ESCAPE cannot be part of the syntax of the preceding TECO command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeEsc() /* execute an ESCAPE command */ +{ + DBGFEN(1,"ExeEsc",NULL); + if (*(CBfPtr+1) == ESCAPE) { /* if it's */ + if (TraceM) { /* if tracing is on */ + ZDspCh('$'); /* echo the escape */ + } + CBfPtr = CStEnd; /* exit this macro level */ + } else { + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + } + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeexc.c b/src/exeexc.c new file mode 100644 index 0000000..3734d45 --- /dev/null +++ b/src/exeexc.c @@ -0,0 +1,20 @@ +/***************************************************************************** + ExeExc() + This function executes the ! (exclamation point) command. + ! Define label +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeExc() /* execute a ! (exclamation mark) command */ +{ + DBGFEN(1,"ExeExc",NULL); + if (FindES('!') == FAILURE) { /* simply skip to next '!' */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeey.c b/src/exeey.c new file mode 100644 index 0000000..53d9e6e --- /dev/null +++ b/src/exeey.c @@ -0,0 +1,37 @@ +/***************************************************************************** + ExeEY() + This function executes an EY command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeEY() /* execute an EY command */ +{ + BOOLEAN ColonMod; + DBGFEN(1,"ExeEY",NULL); + ColonMod = (CmdMod & COLON); /* is it :EY ? */ + CmdMod &= ~COLON; /* clear modifiers flags */ + GapBeg = EBfBeg; /* clear the... */ + GapEnd = EBfEnd; /* ...edit buffer */ + if (IsEofI[CurInp]) { /* if at end-of-file */ + if (ColonMod) { /* if it's :EY */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L, OPERAND); + } else { + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + if (RdPage() == FAILURE) { /* read a page */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (ColonMod) { /* if it's :EY */ + DBGFEX(1,DbgFNm,"PushEx(-1)"); + return PushEx(-1L, OPERAND); + } + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exef.c b/src/exef.c new file mode 100644 index 0000000..f33cb3b --- /dev/null +++ b/src/exef.c @@ -0,0 +1,333 @@ +/***************************************************************************** + ExeF() + This function executes a F command. + nF_ Destructive search and replace + F' Flow to end of conditional + F< Flow to start of iteration + F> Flow to end of iteration + F| Flow to ELSE part of conditional + m,nFB Search between locations m and n + nFB Search, bounded by n lines + m,nFC Search and replace between locations m and n + nFC Search and replace over n lines + nFD Search and delete string + nFK Search and delete intervening text + nFN Global string replace + FR Replace last string + nFS Local string replace +*****************************************************************************/ +#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 "deferr.h" /* define identifiers for error messages */ +#if USE_PROTOTYPES +static DEFAULT ExeFBr(void); +static DEFAULT ExeFC(void); +static DEFAULT ExeFD(void); +static DEFAULT ExeFGt(void); +static DEFAULT ExeFK(void); +static DEFAULT ExeFLs(void); +static DEFAULT ExeFN(void); +static DEFAULT ExeFR(void); +static DEFAULT ExeFS(void); +static DEFAULT ExeFSQ(void); +static DEFAULT ExeFUn(void); +#endif +/***************************************************************************** + ExeFBr() + This function executes a F| (F-bar) command. +*****************************************************************************/ +static DEFAULT ExeFBr() /* execute an F| command */ +{ + DBGFEN(1,"ExeFBr",NULL); + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"FlowEE()"); + return FlowEE(); +} +/***************************************************************************** + ExeFC() + This function executes a FC command. +*****************************************************************************/ +static DEFAULT ExeFC() /* execute an FC command */ +{ + DBGFEN(1,"ExeFC",NULL); + if (CmdMod & DCOLON) { /* if it's ::FC */ + ErrStr(ERR_ILL, "::FC"); /* illegal command "::FC" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = FB_SEARCH; + if (Replac() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeFD() + This function executes a FD command. +*****************************************************************************/ +static DEFAULT ExeFD() /* execute an FD command */ +{ + DBGFEN(1,"ExeFD",NULL); +/* + * The command m,nFD is illegal: the user should use m,nFB + */ + if (CmdMod & MARGIS) { /* if it's m,nFD */ + ErrStr(ERR_ILL, "m,nFD"); /* illegal command "m,nFD" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (CmdMod & DCOLON) { /* if it's ::FD */ + ErrStr(ERR_ILL, "::FD"); /* illegal command "::FD" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = S_SEARCH; + if (Search(FALSE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (Matchd) { /* if successful search */ + GapBeg += RefLen; /* delete found string */ + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeFGt() + This function executes a F> command. +*****************************************************************************/ +static DEFAULT ExeFGt() /* execute an F> command */ +{ + DBGFEN(1,"ExeFGt",NULL); + if (LStTop == LStBot) { /* if not in a loop */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (FlowEL() == FAILURE) { /* flow to end-of-loop */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CBfPtr--; /* backup before the ">" */ + LStTop++; /* cancel what FlowEL did */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeFK() + This function executes a FK command. +*****************************************************************************/ +static DEFAULT ExeFK() /* execute an FK command */ +{ + DBGFEN(1,"ExeFK",NULL); + if (CmdMod & MARGIS) { /* if it's m,nFK */ + ErrStr(ERR_ILL, "m,nFK"); /* illegal command "m,nFK" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (CmdMod & DCOLON) { /* if it's ::FK */ + ErrStr(ERR_ILL, "::FK"); /* illegal command "::FK" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = FK_SEARCH; + if (Search(FALSE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeFLs() + This function executes a F< command. +*****************************************************************************/ +static DEFAULT ExeFLs() /* execute an F< command */ +{ + DBGFEN(1,"ExeFLs",NULL); + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + CBfPtr = (LStTop == LStBot) ? CStBeg-1 : LStack[LStTop].LAddr; + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeFN() + This function executes a FN command. +*****************************************************************************/ +static DEFAULT ExeFN() /* execute an FN command */ +{ + DBGFEN(1,"ExeFN",NULL); +/* + * The command m,nFN is illegal: the user should use m,nFC + */ + if (CmdMod & MARGIS) { /* if it's m,nFN */ + ErrStr(ERR_ILL, "m,nFN"); /* illegal command "m,nFN" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (CmdMod & DCOLON) { /* if it's ::FN */ + ErrStr(ERR_ILL, "::FN"); /* illegal command "::FN" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = N_SEARCH; + if (Replac() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeFR() + This function executes a FR command. +*****************************************************************************/ +static DEFAULT ExeFR() /* execute an FR command */ +{ + DBGFEN(1,"ExeFR",NULL); + if ((GapBeg-RefLen) < EBfBeg) { /* if out of range */ + ErrMsg(ERR_DTB); /* DTB = "delete too big" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + GapBeg += RefLen; /* delete */ + CmdMod = (CmdMod & COLON); /* retain only colon bit */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"ExeI()"); + return ExeI(); +} +/***************************************************************************** + ExeFS() + This function executes a FS command. +*****************************************************************************/ +static DEFAULT ExeFS() /* execute an FS command */ +{ + DBGFEN(1,"ExeFS",NULL); +/* + * The command m,nFS is illegal: the user should use m,nFC + */ + if (CmdMod & MARGIS) { /* if it's m,nFS */ + ErrStr(ERR_ILL, "m,nFS"); /* illegal command "m,nFS" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } +/* + * If it's ::FStext$, it's a compare, not a search. The text argument is + * compared to the characters immediately following the character pointer. + * It returns -1 if the strings match, else 0. A ::FStext$ command is + * equivalent to a .,.+1:FCtext$ command, so that's the way it's implemented. + */ + if (CmdMod & DCOLON) { /* if it's ::FS */ + if (CmdMod & MARGIS) { /* if it's m,n::FS */ + ErrStr(ERR_ILL, "m,n::FS"); + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (EStTop > EStBot) { /* if it's n::FS */ + ErrStr(ERR_ILL, "n::FS"); + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (GapEnd == EBfEnd) { /* if nothing to search */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L,OPERAND); + } + CmdMod &= ~DCOLON; /* clear double-colon bit */ + CmdMod |= COLON; /* set colon bit */ + CmdMod |= MARGIS; /* set m defined bit */ + MArgmt = GapBeg - EBfBeg; /* set m */ + if (PushEx((LONG)((GapBeg-EBfBeg)+1),OPERAND) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, PushEx() failed"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"ExeFC()"); + return ExeFC(); /* execute FC command */ + } + SrcTyp = S_SEARCH; + if (Replac() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, Replac() failed"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeFSQ() + This function executes a F' command. +*****************************************************************************/ +static DEFAULT ExeFSQ() /* execute an F' command */ +{ + DBGFEN(1,"ExeFSQ",NULL); + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"FlowEC()"); + return FlowEC(); +} +/***************************************************************************** + ExeFUn() + This function executes a F_ command. +*****************************************************************************/ +static DEFAULT ExeFUn() /* execute an F_ command */ +{ + DBGFEN(1,"ExeFUn",NULL); +/* + * The command m,nF_ is illegal: the user should use m,nFC + */ + if (CmdMod & MARGIS) { /* if it's m,nF_ */ + ErrStr(ERR_ILL, "m,nF_"); /* illegal command "m,nF_" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (CmdMod & DCOLON) { /* if it's ::F_ */ + ErrStr(ERR_ILL, "::F_"); /* illegal command "::F_" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = U_SEARCH; + if (Replac() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ExeF() + This function executes an F command. +*****************************************************************************/ +DEFAULT ExeF() /* execute one of the F commands */ +{ + if (IncCBP() == FAILURE) { + return FAILURE; + } + switch (To_Upper(*CBfPtr)) { + case 'S': return ExeFS(); + case 'N': return ExeFN(); + case 'D': return ExeFD(); + case 'R': return ExeFR(); + case 'B': return ExeFB(); + case 'C': return ExeFC(); + case 'K': return ExeFK(); + case '_': return ExeFUn(); + case '>': return ExeFGt(); + case '<': return ExeFLs(); + case '\'': return ExeFSQ(); + case '|': return ExeFBr(); + default: ErrChr(ERR_IFC, *CBfPtr); + return FAILURE; + } +} diff --git a/src/exefb.c b/src/exefb.c new file mode 100644 index 0000000..571362b --- /dev/null +++ b/src/exefb.c @@ -0,0 +1,25 @@ +/***************************************************************************** + ExeFB() + This function executes an FB command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeFB() /* execute an FB command */ +{ + DBGFEN(1,"ExeFB",NULL); + if (CmdMod & DCOLON) { /* if it's ::FB */ + ErrStr(ERR_ILL, "::FB"); /* illegal command "::FB" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = FB_SEARCH; + if (Search(FALSE) == FAILURE) { /* FALSE: not two text args */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeg.c b/src/exeg.c new file mode 100644 index 0000000..f113933 --- /dev/null +++ b/src/exeg.c @@ -0,0 +1,54 @@ +/***************************************************************************** + ExeG() + This function executes a G command. + Gq Get string from Q-register q into buffer + G* Get last filespec string into buffer + G_ Get last search string into buffer + :Gq Type Q-register q on terminal +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeG() /* execute a G command */ +{ + charptr TxtBeg; /* beginning of a text area */ + charptr TxtEnd; /* end of a text area */ + DBGFEN(1,"ExeG",NULL); + if (IncCBP() == FAILURE) { /* move to char after G */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (*CBfPtr == '*') { /* if it's G* */ + TxtBeg = FBfBeg; + TxtEnd = FBfPtr; + } else if (*CBfPtr == '_') { /* else if it's G_ */ + TxtBeg = SBfBeg; + TxtEnd = SBfPtr; + } else { /* else it's Gq */ + if (FindQR() == FAILURE) { + return FAILURE; + } + if (QR->Start == NULL) { /* if empty */ + RefLen = 0; + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS, Q-register empty"); + return SUCCESS; + } + TxtBeg = QR->Start; + TxtEnd = QR->End_P1; + } + if (CmdMod & COLON) { /* if it's :G */ + TypBuf(TxtBeg, TxtEnd); + } else { /* else (no : modifier) */ + if (InsStr(TxtBeg, TxtEnd-TxtBeg) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exegtr.c b/src/exegtr.c new file mode 100644 index 0000000..f726dee --- /dev/null +++ b/src/exegtr.c @@ -0,0 +1,31 @@ +/***************************************************************************** + ExeGtr() + This function executes a greater-than-sign (>) command. + > End iteration +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeGtr() /* execute a > command */ +{ + DBGFEN(1,"ExeGtr",NULL); + if (LStTop == LStBot) { /* if not in loop */ + ErrMsg(ERR_BNI); /* BNI = > not in iteration */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (LStack[LStTop].LIndex != INFINITE) {/* if not infinite loop */ + --LStack[LStTop].LIndex; /* decrement loop counter */ + } + if ((LStack[LStTop].LIndex == INFINITE) || /* if infinite loop */ + (LStack[LStTop].LIndex > 0)) { /* or more iterations to do */ + CBfPtr = LStack[LStTop].LAddr; /* jump to front of loop */ + } else { + --LStTop; /* leave the loop */ + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeh.c b/src/exeh.c new file mode 100644 index 0000000..f7a3de4 --- /dev/null +++ b/src/exeh.c @@ -0,0 +1,18 @@ +/***************************************************************************** + ExeH() + This function executes an H command. + H Equivalent to the numeric pair "B,Z", or "from the + beginning of the buffer up to the end of the buffer." + Thus, H represents the whole buffer. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeH() /* execute an H command */ +{ + DBGFEN(1,"ExeH",NULL); + MArgmt = 0; /* load m with B */ + CmdMod |= MARGIS; /* say there's an m,n pair */ + DBGFEX(1,DbgFNm,"ExeZ()"); + return ExeZ(); /* load n with Z */ +} diff --git a/src/exei.c b/src/exei.c new file mode 100644 index 0000000..3a0e896 --- /dev/null +++ b/src/exei.c @@ -0,0 +1,70 @@ +/***************************************************************************** + ExeI() + This function executes an I command. + Itext$ Insert text + nI Insert ASCII character "n" +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeI() /* execute an I command */ +{ + unsigned char InChar; + DBGFEN(1,"ExeI",NULL); + if (EStTop > EStBot) { /* if numeric argument */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if (CmdMod & ATSIGN) { /* if it's n@I// */ + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, 1st IncCBP() failed"); + return FAILURE; + } + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, 2nd IncCBP() failed"); + return FAILURE; + } + if (*CBfPtr != *(CBfPtr-1)) { + ErrMsg(ERR_IIA); /* illegal insert arg */ + DBGFEX(1,DbgFNm,"FAILURE, illegal insert arg"); + return FAILURE; + } + } else { /* else must be nI$ */ + if ((CBfPtr+1) == CStEnd) { + if (MStTop < 0) { + ErrUTC(); + DBGFEX(1,DbgFNm,"FAILURE, unterminated command"); + return FAILURE; + } else { + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + if (*(CBfPtr+1) != ESCAPE) { + ErrMsg(ERR_IIA); /* illegal insert arg */ + DBGFEX(1,DbgFNm,"FAILURE, illegal insert arg"); + return FAILURE; + } + } + InChar = (char)NArgmt; + if (InsStr(&InChar, (ptrdiff_t)1) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, InsStr() failed"); + return FAILURE; + } + } else { /* else no numeric argument */ + if (FindES(ESCAPE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, FindES() failed"); + return FAILURE; + } + if (InsStr(ArgPtr, CBfPtr-ArgPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, InsStr() failed"); + return FAILURE; + } + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeill.c b/src/exeill.c new file mode 100644 index 0000000..91e817e --- /dev/null +++ b/src/exeill.c @@ -0,0 +1,13 @@ +/***************************************************************************** + ExeIll() + This function "executes" an illegal command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeIll() /* illegal TECO command */ +{ + ErrChr(ERR_ILL, *CBfPtr); /* ILL = illegal command */ + return FAILURE; +} diff --git a/src/exej.c b/src/exej.c new file mode 100644 index 0000000..f702ff9 --- /dev/null +++ b/src/exej.c @@ -0,0 +1,22 @@ +/***************************************************************************** + ExeJ() + This function executes a J command. + nJ Move pointer to "n" +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeJ() /* execute J command */ +{ + DBGFEN(1,"ExeJ",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 0; /* default is 0J */ + } else { + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(1,DbgFNm,"DoCJR()"); + return DoCJR(EBfBeg-GapBeg+NArgmt); +} diff --git a/src/exek.c b/src/exek.c new file mode 100644 index 0000000..935b9ab --- /dev/null +++ b/src/exek.c @@ -0,0 +1,64 @@ +/***************************************************************************** + ExeK() + This function executes a K command. + nK Kill n lines + m,nK Delete between m and n +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeK() /* execute a K command */ +{ + ptrdiff_t HowFar; + DBGFEN(1,"ExeK",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1K */ + } else { + UMinus(); /* if it's -K, make it -1K */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FALURE"); + return FAILURE; + } + } + if (CmdMod & MARGIS) { /* if it's m,nK */ + if (NArgmt == MArgmt) { /* if n equals m */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + MEMMOVE(ErrTxt, + (*CBfPtr == 'D' || *CBfPtr=='d') ? "m,nD" : "m,nK", + 5); + if (GetAra() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if ((AraBeg < GapBeg) && (AraEnd > GapEnd)) { + GapBeg = AraBeg; + GapEnd = AraEnd; + } else { + if (AraEnd < GapEnd) { + HowFar = (GapBeg-1) - AraEnd; + GapBeg -= HowFar; + GapEnd -= HowFar; + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)HowFar); + GapBeg = AraBeg; + } else { + HowFar = AraBeg - (GapEnd+1); + MEMMOVE(GapBeg, GapEnd+1, (SIZE_T)HowFar); + GapBeg += HowFar; + GapEnd = AraEnd; + } + } + } else { /* else it's nK */ + NArgmt = Ln2Chr(NArgmt); /* cvt line to char offset */ + if (NArgmt > 0) { + GapEnd += NArgmt; + } else { + GapBeg += NArgmt; + } + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exel.c b/src/exel.c new file mode 100644 index 0000000..6babe8d --- /dev/null +++ b/src/exel.c @@ -0,0 +1,35 @@ +/***************************************************************************** + ExeL() + This function executes an L command. + nL Advance n lines +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeL() /* execute L command */ +{ + LONG HowFar; + DBGFEN(1,"ExeL",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1 */ + } else { + UMinus(); /* if it's -L, make it -1L */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + HowFar = Ln2Chr(NArgmt); + if (HowFar > 0) { + MEMMOVE(GapBeg, GapEnd+1, (SIZE_T)HowFar); + GapBeg += HowFar; + GapEnd += HowFar; + } else if (HowFar < 0) { + GapBeg += HowFar; + GapEnd += HowFar; + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)-HowFar); + } + CmdMod = '\0'; + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exelbr.c b/src/exelbr.c new file mode 100644 index 0000000..27394d3 --- /dev/null +++ b/src/exelbr.c @@ -0,0 +1,52 @@ +/***************************************************************************** + ExeLBr() + This function executes a left-bracket ([) command. + [q Q-register push +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeLBr() /* execute [ command */ +{ + QRptr TmpQRp; + ptrdiff_t TmpSiz; +#if DEBUGGING + static char *DbgFNm = "ExeLBr"; + sprintf(DbgSBf, "QStTop = %d", QStTop); + DbgFEn(1,DbgFNm,DbgSBf); +#endif + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"IncCBP() FAILURE"); + return FAILURE; + } + if (FindQR() == FAILURE) { + DBGFEX(1,DbgFNm,"FindQR() FAILURE"); + return FAILURE; + } + if (++QStTop >= QRS_SIZE) { + ErrMsg(ERR_PDO); /* push-down list overflow */ + DBGFEX(1,DbgFNm,"ERR_PDO FAILURE"); + return FAILURE; + } +/* + * Copy QR to top of QStack + */ + TmpQRp = QR; + QR = &QStack[QStTop]; + TmpSiz = TmpQRp->End_P1 - TmpQRp->Start; + if (TmpSiz > 0) { + if (MakRom((SIZE_T)TmpSiz) == FAILURE) { + QR = TmpQRp; + --QStTop; + DBGFEX(1,DbgFNm,"MakRom() FAILURE"); + return FAILURE; + } + MEMMOVE(QR->Start, TmpQRp->Start, (SIZE_T) TmpSiz); + QR->End_P1 = QR->Start + TmpSiz; + } + QR->Number = TmpQRp->Number; + QR = TmpQRp; + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exelst.c b/src/exelst.c new file mode 100644 index 0000000..481b096 --- /dev/null +++ b/src/exelst.c @@ -0,0 +1,40 @@ +/***************************************************************************** + ExeLst() + This function executes a less-than-sign (<) command. + n< Iterate n times +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeLst() /* execute a < command */ +{ + DBGFEN(1,"ExeLst",NULL); + if (++LStTop >= LPS_SIZE) { /* if loop stack is full */ + ErrMsg(ERR_PDO); /* push-down list overflow */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = INFINITE; /* make it an infinite loop */ + } else { + if (GetNmA() == FAILURE) { /* get numeric argmument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (NArgmt <= 0) { /* if null loop */ + if (FlowEL()== FAILURE) { /* flow to end of loop */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + LStack[LStTop].LIndex = NArgmt; /* store loop index */ + LStack[LStTop].LAddr = CBfPtr; /* store loop start */ + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exem.c b/src/exem.c new file mode 100644 index 0000000..0f5665b --- /dev/null +++ b/src/exem.c @@ -0,0 +1,91 @@ +/***************************************************************************** + + ExeM() + + This function executes an M command. + Mq Execute string in Q-register q + +*****************************************************************************/ + +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ + +DEFAULT ExeM() /* execute an M command */ +{ + DEFAULT status; + BOOLEAN islocal; + + DBGFEN(1,"ExeM",NULL); + + if (IncCBP() == FAILURE) { /* if no character after M */ + DBGFEX(1,DbgFNm,"FAILURE, no Q-register specified"); + return FAILURE; + } + + islocal = (*CBfPtr=='.'); /* TAA Addition */ + + if (FindQR() == FAILURE) { /* find q-register */ + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } + + if (QR->Start == NULL) { /* if q-register is empty */ + DBGFEX(1,DbgFNm,"SUCCESS, Q-register is empty"); + return SUCCESS; + } + +/* + * Save the current execution state and make the text in the Q-register be + * the command string to execute. + */ + + if (PshMac(QR->Start, QR->End_P1) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, PshMac() failed"); + return FAILURE; + } + +/* + * If the M command is not colon-modified, create a new set of local + * q-registers and zero them out. + */ + if ((CmdMod & COLON) == 0&&!islocal) { /* if not colon-modified */ + QRptr QRp; + WORD i; + QRp = (QRptr)ZAlloc(36 * sizeof(struct QReg)); + if (QRp == NULL) { + ErrMsg(ERR_MEM); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + MStack[MStTop].QRgstr = QRp; + for (i = 0; i < 36; ++i, ++QRp) { + QRp->Start = QRp->End_P1 = NULL; + QRp->Number = 0; + } + } + else CmdMod &= ~COLON; /* clear colon flag TAA Mod */ + +/* + * execute command string in Q-register + */ + status = ExeCSt(); +#if DEBUGGING + if (status == FAILURE) { + DbgFMs(1,DbgFNm,"ExeCSt() failed"); + } +#endif + +/* + * restore old execution state + */ + + if (PopMac() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, PopMac() failed"); + return FAILURE; + } + + DBGFEX(1,DbgFNm,(status == FAILURE) ? "FAILURE" : "SUCCESS"); + return status; +} diff --git a/src/exen.c b/src/exen.c new file mode 100644 index 0000000..314a2b7 --- /dev/null +++ b/src/exen.c @@ -0,0 +1,34 @@ +/***************************************************************************** + ExeN() + This function executes an N command. + nNtext$ Global search +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeN() /* execute an N command */ +{ + DBGFEN(1,"ExeN",NULL); +/* + * The command m,nN is illegal: the user should use m,nFB + */ + if (CmdMod & MARGIS) { /* if it's m,nN */ + ErrStr(ERR_ILL, "m,nN"); /* illegal command "m,nN" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (CmdMod & DCOLON) { /* if it's ::N */ + ErrStr(ERR_ILL, "::N"); /* illegal command "::N" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = N_SEARCH; + if (Search(FALSE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exenul.c b/src/exenul.c new file mode 100644 index 0000000..0888c26 --- /dev/null +++ b/src/exenul.c @@ -0,0 +1,11 @@ +/***************************************************************************** + ExeNul() + This function executes a null command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeNul() /* execute a null command */ +{ + return SUCCESS; +} diff --git a/src/exenyi.c b/src/exenyi.c new file mode 100644 index 0000000..d1b3d9e --- /dev/null +++ b/src/exenyi.c @@ -0,0 +1,14 @@ +/***************************************************************************** + ExeNYI() + This function handles a TECO command that is "not yet implemented" by +displaying the message "not yet implemented" and failing. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeNYI() /* command not yet implemented */ +{ + ErrMsg(ERR_NYI); /* NYI = not yet implemented */ + return FAILURE; +} diff --git a/src/exeo.c b/src/exeo.c new file mode 100644 index 0000000..691c56b --- /dev/null +++ b/src/exeo.c @@ -0,0 +1,167 @@ +/***************************************************************************** + ExeO() + This function executes an O command. + Otag Goto label + nOtag0,tag1 Computed goto +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeO() /* execute an O command */ +{ + BOOLEAN Found; /* has the tag been found? */ + unsigned char TBfBeg[TBFINIT]; /* tag buffer */ + charptr TBfEnd; /* end of tag buffer */ + charptr TBfPtr; /* end of tag in tag buffer */ + charptr TagPtr; /* pointer into tag buffer */ + charptr TmpPtr; /* temp pointer for shuffling in Tbf */ + DBGFEN(1,"ExeO",NULL); + /* + * ??? Pete, + * given "O^EQq$" we simply use BldStr to build the string + * before looking for the tag in q-reg q. What do we do if + * given "nOtag0,^EQq,tag2$", especially if q-reg q contains a + * comma? if we BldStr first, the comma in the q-reg will + * change the number of tags, maybe changing the nth tag. + * If we BldStr after finding the tag we want, we don't take + * into account the list of tags which may be in q-reg q. + * + * After implementing it the second way (search/Bldstr), I find + * it is much easier to do it the first way (BldStr/search). One + * disadvantage to doing it this way is BldStr is probably building + * much more than it needs to, potentially overrunning TBf? + */ + TBfEnd = TBfBeg + TBFINIT; + if (BldStr(TBfBeg, TBfEnd, &TBfPtr) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } +/* + * If there's something on the expression stack, then we have a computed + * goto, so figure out which tag in TBf they want. + * + * TBf: "TAG0,TAG1,TAG2........" + * ^ ^ ^ + * TBfBeg TBfPtr TBfEnd + */ + if (EStTop > EStBot) { + if (GetNmA () == FAILURE) { /* get NArgmt */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if (NArgmt < 0) { /* n is out of range */ + TagPtr = TBfPtr; /* say we ran into end of tag list */ + } else { /* find the nth tag */ + TagPtr = TBfBeg; + if (NArgmt > 0) { /* n==0 is already done */ + while (TagPtr < TBfPtr) { + if (*TagPtr++ == ',') { + if (--NArgmt == 0) { + break; + } + } + } + } + } +/* + * If we ran into the end of the tag list, or the tag we found is null + * (",,"), then flow past nO command. + */ + if (TagPtr == TBfPtr || *TagPtr == ',') { + DBGFEX(1,DbgFNm,"SUCCESS"); + CmdMod = '\0'; /* clear modifiers flags */ + return SUCCESS; + } +/* + * shuffle tag we found to beginning of TBf for searching. + */ + TmpPtr = TBfBeg; + while (TagPtr < TBfPtr && *TagPtr != ',') { + *TmpPtr++ = *TagPtr++; + } + TBfPtr = TmpPtr; + } +#if DEBUGGING + *TBfPtr = '\0'; + sprintf(DbgSBf,"searching for tag \"%s\"", TBfBeg); + DbgFMs(1,DbgFNm,DbgSBf); +#endif +/* + * reset CBfPtr to point to the front of the command string, or the front + * of the loop if we're in a loop, then search for the tag in TBf, keeping + * track of nested <> loops. + */ + CBfPtr = (LStTop == LStBot) ? CStBeg : LStack[LStTop].LAddr + 1; + Found = FALSE; + CmdMod = '\0'; /* clear modifiers flags */ + while (!Found) { + while (*CBfPtr != '!') { + if (CBfPtr == CStEnd) { + ErrPSt(ERR_TAG, TBfBeg, TBfPtr); + DBGFEX(1,DbgFNm,"FAILURE, missing tag"); + return FAILURE; + } + switch (*CBfPtr) { + case '<': + if (++LStTop >= LPS_SIZE) { + ErrMsg(ERR_PDO); + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + LStack[LStTop].LIndex = INFINITE; + LStack[LStTop].LAddr = CBfPtr; + CmdMod = '\0'; + break; + case '>': + if (LStTop == LStBot) { + ErrMsg(ERR_BNI); + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + --LStTop; + CmdMod = '\0'; + break; + default: + if (SkpCmd() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, SkpCmd() failed"); + return FAILURE; + } + } /* end of switch */ + ++CBfPtr; + } /* end of while (!='!')*/ +/* + * At this point, we've found an '!'. if tracing is on, display exclamation + * point + */ + if (TraceM) { /* if trace mode is on */ + if (CmdMod & ATSIGN) { /* if it was @O */ + ZDspCh('@'); + } + ZDspCh('!'); + } + if (FindES('!') == FAILURE) { /* find end of tag */ + DBGFEX(1,DbgFNm,"FAILURE, FindES() failed"); + return FAILURE; + } +#if DEBUGGING + sprintf(DbgSBf,"found tag \"%.*s\"\n",(int)(CBfPtr-ArgPtr), ArgPtr); + DbgFMs(1,DbgFNm,DbgSBf); +#endif +/* + * compare found tag (in ArgPtr) to O command tag (in TBf). + */ + TagPtr = TBfBeg; + while ((TagPtr < TBfPtr) && (*ArgPtr == *TagPtr)) { + ++ArgPtr; + ++TagPtr; + } + Found = ((TagPtr == TBfPtr) && (*ArgPtr == '!')); + ++CBfPtr; + } /* end of while (!Found) */ + --CBfPtr; + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeopr.c b/src/exeopr.c new file mode 100644 index 0000000..ae91858 --- /dev/null +++ b/src/exeopr.c @@ -0,0 +1,25 @@ +/***************************************************************************** + ExeOpr() + This function executes an operator command. + + Addition + - Subtraction or negation + ( Expression grouping (ExeRtP() executes ')') + # Logical OR + / Division + & Logical AND + ^_ Ones complement (logical NOT) + * Multiplication +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeOpr() /* operators: + - * / # & ^_ */ +{ + DBGFEN(1,"ExeOpr",NULL); + if (PushEx((LONG)*CBfPtr, OPERATOR) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exep.c b/src/exep.c new file mode 100644 index 0000000..53ade88 --- /dev/null +++ b/src/exep.c @@ -0,0 +1,57 @@ +/***************************************************************************** + ExeP() + This function executes a P or PW command. + nP Advance n pages + m,nP Write out chars m to n + nPW Write buffer n times + m,nPW Write out chars m to n +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeP() /* execute a P or PW command */ +{ + BOOLEAN SavEof; + DBGFEN(1,"ExeP",NULL); + SavEof = IsEofI[CurInp]; /* save end-of-file flag */ + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1P */ + } else { + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if ((NArgmt <= 0) && ((CmdMod & MARGIS) == 0)) { + ErrMsg(ERR_IPA); /* negative or 0 arg to P */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } +/* + * If it's a "PW" or "m,nP" command, let ExePW handle it. + */ + if ((CBfPtr != CStEnd) && + ((*(CBfPtr+1) == 'W') || (*(CBfPtr+1) == 'w'))) { + ++CBfPtr; /* skip the "W" */ + DBGFEX(1,DbgFNm,"ExePW"); + return ExePW(); /* execute a PW command */ + } + if (CmdMod & MARGIS) { /* if it's m,nP */ + DBGFEX(1,DbgFNm,"ExePW"); + return ExePW(); /* execute a PW command */ + } + do { + if (SinglP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } while ((--NArgmt > 0) && !IsEofI[CurInp]); + if (CmdMod & COLON) { /* if it's :P */ + DBGFEX(1,DbgFNm,SavEof ? "PushEx(0)" : "PushEx(-1)"); + return PushEx(SavEof ? 0L : -1L, OPERAND); + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeprc.c b/src/exeprc.c new file mode 100644 index 0000000..f82f7d9 --- /dev/null +++ b/src/exeprc.c @@ -0,0 +1,36 @@ +/***************************************************************************** + ExePrc() + This function executes a % command. + n%q Add n to Q-register q and return result +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExePrc() /* execute % (percent) command */ +{ + DBGFEN(1,"ExePrc",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1%q */ + } else { + UMinus(); /* if it's -%, make it -1% */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + } + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + if (FindQR() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } + QR->Number += NArgmt; +#if DEBUGGING + sprintf(DbgSBf,"PushEx(%ld,OPERAND)",QR->Number); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx(QR->Number, OPERAND); +} diff --git a/src/exepw.c b/src/exepw.c new file mode 100644 index 0000000..d67fd6d --- /dev/null +++ b/src/exepw.c @@ -0,0 +1,41 @@ +/***************************************************************************** + ExePW() + This function executes a PW command. Note that this function is +called only by ExeP. + nPW Write buffer n times + m,nPW Write out chars m to n +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExePW() /* execute a PW command */ +{ + DBGFEN(1,"ExePW",NULL); + if (CmdMod & MARGIS) { /* if it's m,nPW */ + if (MArgmt != NArgmt) { /* if m != n */ + if ((*CBfPtr == 'W') || (*CBfPtr == 'w')) { + MEMMOVE(ErrTxt, "m,nPW", 6); + } else { + MEMMOVE(ErrTxt, "m,nP", 5); + } + if (GetAra() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (WrPage(CurOut,AraBeg,AraEnd,0L) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + } else { /* else it's nPW */ + while (NArgmt-- > 0) + if (WrPage(CurOut,EBfBeg,EBfEnd,-1L) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeq.c b/src/exeq.c new file mode 100644 index 0000000..897cb49 --- /dev/null +++ b/src/exeq.c @@ -0,0 +1,87 @@ +/***************************************************************************** + + ExeQ() + + This function executes a Q command. + + Qq Use the integer stored in the number storage area of + Q-register q as the argument of the next command. + + nQq Return the ASCII value of the (n+1)th character in + Q-register q. The argument n must be between 0 and the + Q-register's size minus 1. If n is out of range, a + value of -1 is returned. Characters within a + Q-register are numbered the same way that characters in + the text buffer are numbered. The initial character is + at character position 0, the next character is at + character position 1, etc. Therefore, if Q-register A + contains "xyz", then 0QA will return the ASCII code for + "x" and 1QA will return the ASCII code for "y". + + :Qq Return the number of characters stored in the text storage + area of Q-register q as the argument of the next command. + +*****************************************************************************/ + +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ + +DEFAULT ExeQ() /* execute a Q command */ +{ + LONG TmpVal; + + DBGFEN(1,"ExeQ",NULL); + +/* + * increment command buffer pointer to point to Q-register name + */ + + if (IncCBP() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, no Q-register specified"); + return FAILURE; + } + +/* + * verify Q-register name and point QR global at it + */ + + if (FindQR() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } + +/* + * if something is on the stack and it's a number then we have nQq + */ + + if ((EStTop > EStBot) && (EStack[EStTop].ElType == OPERAND)) { + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + +/* + * if NArgmt is between 0 and length of text area, return the ASCII value + * of the (NArgmt+1)th character, otherwise return -1 + */ + + TmpVal = (NArgmt >= 0 && NArgmt < (QR->End_P1 - QR->Start)) + ? *(QR->Start + NArgmt) + : -1; + EStTop = EStBot; /* clear expression stack */ + } else { /* else we have Qq or :Qa */ + if (CmdMod & COLON) { /* if it's :Qa */ + TmpVal = QR->End_P1 - QR->Start; + CmdMod &= ~COLON; /* clear colon flag */ + } else { + TmpVal = QR->Number; + } + } +#if DEBUGGING + sprintf(DbgSBf,"PushEx(%ld,OPERAND)",TmpVal); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx(TmpVal,OPERAND); +} diff --git a/src/exeqes.c b/src/exeqes.c new file mode 100644 index 0000000..65a15f9 --- /dev/null +++ b/src/exeqes.c @@ -0,0 +1,17 @@ +/***************************************************************************** + ExeQes() + This function executes a ? command. + ? Toggle trace mode +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeQes() /* question mark command */ +{ + DBGFEN(1,"ExeQes",NULL); + TraceM = !TraceM; + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exer.c b/src/exer.c new file mode 100644 index 0000000..53855fa --- /dev/null +++ b/src/exer.c @@ -0,0 +1,23 @@ +/***************************************************************************** + ExeR() + This function executes a R command. + nR Back up n characters +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeR() /* execute a R command */ +{ + DBGFEN(1,"ExeR",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1R */ + } else { + UMinus(); /* if it's -R, make it -1R */ + if (GetNmA() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(1,DbgFNm,"DoCJR()"); + return DoCJR(-NArgmt); +} diff --git a/src/exerbr.c b/src/exerbr.c new file mode 100644 index 0000000..afc702c --- /dev/null +++ b/src/exerbr.c @@ -0,0 +1,69 @@ +/***************************************************************************** + ExeRBr() + This function executes a ] command. + ]q Q-register pop +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeRBr() /* execute ] command */ +{ + QRptr TmpQRp; + ptrdiff_t TmpSiz; + BOOLEAN ColonMod; +#if DEBUGGING + static char *DbgFNm = "ExeRBr"; + sprintf(DbgSBf, "QStTop = %d", QStTop); + DbgFEn(1,DbgFNm,DbgSBf); +#endif + ColonMod = (CmdMod & COLON); /* is it :] ? */ + CmdMod &= ~COLON; /* clear colon flag */ + if (IncCBP() == FAILURE) { + return FAILURE; + } + if (FindQR() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (QStTop < 0) { /* if q-reg stack is empty */ + if (ColonMod) { /* if it's :] */ + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L, OPERAND); + } else { + ErrMsg(ERR_PES); /* can't pop empty stack */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } +/* + * Copy QStack Q-register to QR + */ + TmpQRp = &QStack[QStTop]; + TmpSiz = TmpQRp->End_P1 - TmpQRp->Start; + if (TmpSiz == 0) { /* if it should be empty */ + if (QR->Start != NULL) { /* but it isn't empty */ + ZFree((voidptr)QR->Start); /* then empty it */ + QR->Start = QR->End_P1 = NULL; + } + } else { + if (MakRom((SIZE_T)TmpSiz) == FAILURE) { /* adjust QR space */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + MEMMOVE(QR->Start, TmpQRp->Start, (SIZE_T)TmpSiz); + QR->End_P1 = QR->Start + TmpSiz; + } + QR->Number = TmpQRp->Number; +/* + * clear QStack Q-register + */ + if (TmpQRp->Start != NULL) { + ZFree((voidptr)TmpQRp->Start); + TmpQRp->Start = TmpQRp->End_P1 = NULL; + } + TmpQRp->Number = 0; + --QStTop; + DBGFEX(1,DbgFNm,(ColonMod) ? "PushEx(-1)" : "SUCCESS"); + return (ColonMod) ? PushEx(-1L, OPERAND) : SUCCESS; +} diff --git a/src/exertp.c b/src/exertp.c new file mode 100644 index 0000000..f3c37ea --- /dev/null +++ b/src/exertp.c @@ -0,0 +1,22 @@ +/***************************************************************************** + ExeRtP() + This function executes a ) command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeRtP() /* execute right parenthesis command */ +{ + DBGFEN(1,"ExeRtP",NULL); +/* + * if no numeric arg. or not a number + */ + if ((EStTop == EStBot) || (EStack[EStTop].ElType != OPERAND)) { + ErrMsg(ERR_NAP); /* no argument before ) */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"PushEx(')')"); + return PushEx((LONG)')', OPERATOR); +} diff --git a/src/exes.c b/src/exes.c new file mode 100644 index 0000000..27a3410 --- /dev/null +++ b/src/exes.c @@ -0,0 +1,68 @@ +/***************************************************************************** + ExeS() + This function executes an S command. + nStext$ Local search + m,nStext$ Search for nth occurrance within m chars + ::Stext$ Compare string +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeS() /* execute an S command */ +{ + DBGFEN(1, "ExeS", NULL); +/* + * The command m,nS is illegal: the user should use m,nFB + */ + if (CmdMod & MARGIS) { /* if it's m,nS */ + ErrStr(ERR_ILL, "m,nS"); /* illegal command "m,nS" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } +/* + * If it's ::Stext$, it's a compare, not a search. The text argument is + * compared to the characters immediately following the character pointer. + * It returns -1 if the strings match, else 0. A ::Stext$ command is + * equivalent to a .,.+1:FBtext$ command, so that's the way it's implemented. + */ + if (CmdMod & DCOLON) { /* if it's ::S */ + if (CmdMod & MARGIS) { /* if it's m,n::S */ + ErrStr(ERR_ILL, "m,n::S"); + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (EStTop > EStBot) { /* if it's n::S */ + ErrStr(ERR_ILL, "n::S"); + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (GapEnd == EBfEnd) { /* if nothing to search */ + if (FindES(ESCAPE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx(0L,OPERAND); + } + CmdMod &= ~DCOLON; /* clear double-colon bit */ + CmdMod |= COLON; /* set colon bit */ + CmdMod |= MARGIS; /* set m defined bit */ + MArgmt = GapBeg - EBfBeg; /* set m */ + if (PushEx((LONG)((GapBeg-EBfBeg)+1),OPERAND) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"ExeFB()"); + return ExeFB(); /* execute FB command */ + } + SrcTyp = S_SEARCH; + if (Search(FALSE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exescl.c b/src/exescl.c new file mode 100644 index 0000000..53a2267 --- /dev/null +++ b/src/exescl.c @@ -0,0 +1,52 @@ +/***************************************************************************** + ExeSCl() + This function executes a semi-colon (;) command. + ; Exit iteration on search failure + n; Exit iteration if n is positive + :; Exit iteration on search success + n:; Exit iteration if n is negative +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeSCl() /* execute semi-colon command */ +{ +#if DEBUGGING + static char *DbgFNm = "ExeSCl"; + DbgFEn(1,DbgFNm, + (CmdMod & COLON) + ? (EStTop == EStBot) ? "have :;" : "have n:;" + : (EStTop == EStBot) ? "have ;" : "have n;" ); +#endif + if (LStTop == LStBot) { /* if not in a loop */ + ErrMsg(ERR_SNI); /* ; not in iteration */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (EStTop == EStBot) { /* if no numeric argument */ + ErrMsg(ERR_NAS); /* no argument before ; */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE. GetNmA failed()"); + return FAILURE; + } +/* + * If not colon-modified and numeric arg is positive OR + * if colon-modified and numeric arg is negative + * flow to the end of the loop and exit it + */ + if ( (!(CmdMod & COLON) && (NArgmt >= 0) ) || + ( (CmdMod & COLON) && (NArgmt < 0) ) ) { + if (FlowEL() == FAILURE) { /* flow to end of loop */ + DBGFEX(1,DbgFNm,"FAILURE, FlowEL() failed"); + return FAILURE; + } + } + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot; /* clear expression stack */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exet.c b/src/exet.c new file mode 100644 index 0000000..cfd1025 --- /dev/null +++ b/src/exet.c @@ -0,0 +1,51 @@ +/***************************************************************************** + ExeT() + This function executes a T command. + nT Type n lines + m,nT Type from m to n +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeT() /* execute T command */ +{ + DBGFEN(1,"ExeT",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1T */ + } else { + UMinus(); /* if it's -T, make it -1T */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + if (CmdMod & MARGIS) { /* if it's m,nT */ + if (NArgmt != MArgmt) { + MEMMOVE(ErrTxt, "m,nT", 5); + if (GetAra() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } +/* + * if the area to type out is split by the buffer gap, we have to display + * each half separately. + */ + if ((AraBeg < GapBeg) && (AraEnd > GapEnd)) { + TypBuf(AraBeg, GapBeg); + TypBuf(GapEnd+1, AraEnd+1); + } else { + TypBuf(AraBeg, AraEnd+1); + } + } + } else { /* else it's nT */ + if (NArgmt <= 0) { + TypBuf(GapBeg+Ln2Chr(NArgmt), GapBeg); + } else { + TypBuf(GapEnd+1, GapEnd+Ln2Chr(NArgmt)+1); + } + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeu.c b/src/exeu.c new file mode 100644 index 0000000..a72285b --- /dev/null +++ b/src/exeu.c @@ -0,0 +1,38 @@ +/***************************************************************************** + ExeU() + This function performs a U command. + nUq Put number n into Q-register q +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeU() /* execute U command */ +{ + DBGFEN(1,"ExeU",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + ErrMsg(ERR_NAU); + DBGFEX(1,DbgFNm,"FAILURE, no arg before U"); + return FAILURE; + } + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + if (IncCBP() == FAILURE) { /* increment to Q-reg name */ + DBGFEX(1,DbgFNm,"FAILURE, IncCBp() failed."); + return FAILURE; + } + if (FindQR() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } + QR->Number = NArgmt; + if (CmdMod & MARGIS) { /* if m,nUq */ + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(MArgmt, OPERAND); + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeund.c b/src/exeund.c new file mode 100644 index 0000000..f9a21ad --- /dev/null +++ b/src/exeund.c @@ -0,0 +1,33 @@ +/***************************************************************************** + ExeUnd() + This function executes an underscore (_) command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeUnd() /* execute a _ (underscore) command */ +{ + DBGFEN(1,"ExeUnd",NULL); +/* + * The command m,n_ is illegal: the user should use m,nFB + */ + if (CmdMod & MARGIS) { /* if it's m,n_ */ + ErrStr(ERR_ILL, "m,n_"); /* illegal command "m,n_" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if (CmdMod & DCOLON) { /* if it's ::_ */ + ErrStr(ERR_ILL, "::_"); /* illegal command "::_" */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + SrcTyp = U_SEARCH; + if (Search(FALSE) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exeusc.c b/src/exeusc.c new file mode 100644 index 0000000..9318121 --- /dev/null +++ b/src/exeusc.c @@ -0,0 +1,14 @@ +/***************************************************************************** + ExeUsc() + This function executes a control-underscore (^_) command. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT ExeUsc() /* execute control-_ command */ +{ + DBGFEN(1,"ExeUsc",NULL); + DBGFEX(1,DbgFNm,"PushEx(USCHAR)"); + return PushEx((LONG)USCHAR, OPERATOR); +} diff --git a/src/exev.c b/src/exev.c new file mode 100644 index 0000000..0a03418 --- /dev/null +++ b/src/exev.c @@ -0,0 +1,38 @@ +/***************************************************************************** + ExeV() + This function executes a V command. The V command is for "viewing" +some lines around the cursor. + nV do 1-nTnT + m,nV do 1-mTnT +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeV() /* execute an V command */ +{ + LONG firstarg; + DBGFEN(1,"ExeV",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1V */ + } else { + UMinus(); /* if it's -V, make it -1V */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + firstarg = 1 - ((CmdMod & MARGIS) ? MArgmt : NArgmt); + if (firstarg <= 0) { + TypBuf(GapBeg+Ln2Chr(firstarg), GapBeg); + } else { + TypBuf(GapEnd+1, GapEnd+Ln2Chr(firstarg)+1); + } + if (NArgmt <= 0) { + TypBuf(GapBeg+Ln2Chr(NArgmt), GapBeg); + } else { + TypBuf(GapEnd+1, GapEnd+Ln2Chr(NArgmt)+1); + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exew.c b/src/exew.c new file mode 100644 index 0000000..41efbd8 --- /dev/null +++ b/src/exew.c @@ -0,0 +1,280 @@ +/***************************************************************************** + + ExeW() + + This function executes a W command. + + W Scope "WATCH" + n:W Return scope characteristics + m,n:W Set scope characteristics + + TECO-C implements only the part of the W command relating to the +terminal type. + +*****************************************************************************/ + +#if CURSES +#if ULTRIX +#include /* has to come before zport.h */ +#else +#include /* has to come before zport.h */ +#endif +#endif + +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "deferr.h" /* identifiers for error messages */ +#include "defext.h" /* define external global variables */ + +#if VIDEO + +#if CURSES +extern int scope_start; +extern unsigned char *p_scope_start; +extern int skiprefresh; +#endif + +#if USE_PROTOTYPES +static DEFAULT VGetW(void); +static DEFAULT VSetW(void); +static DEFAULT VDoW(void); +#endif + +#include "dscren.h" /* define screen identifiers */ +#include /* prototype for strlen() */ + +static DEFAULT VGetW() /* execute an n:W command */ +{ + DBGFEN(1,"VGetW",NULL); + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx( NArgmt==0 ? CrType : + NArgmt==1 ? HtSize : + NArgmt==2 ? VtSize : + NArgmt==3 ? SeeAll : + NArgmt==4 ? MrkFlg : + NArgmt==5 ? HldFlg : + NArgmt==6 ? TopDot : + NArgmt==7 ? ScroLn : +#if CURSES + NArgmt==8 ? SpcMrk : + NArgmt==9 ? KeyPad : +#endif + 0 , OPERAND); +} + + + +static DEFAULT VSetW() /* execute an m,n:W command */ +{ + DBGFEN(1,"VSetW",NULL); + +/* + * Use an if here instead of a "default" case because doing a switch will + * cast the variable to an "int", causing Turbo-C to warn about types. + */ + + if ((NArgmt < 0) || (NArgmt > 9)) { + return ExeNYI(); + } + + switch ((int)NArgmt) { + case 0: + if ((MArgmt < 0) || (MArgmt > 13) || (MArgmt == 3) || + (MArgmt == 5) || + (MArgmt == 7) || + (MArgmt == 9)) { + ZDspBf("Illegal terminal type.", 22); + ZDspBf(" Terminal types are:\r\n", 23); + ZDspBf("\t0\t= VT52\r\n", 11); + ZDspBf("\t1\t= VT61\r\n", 11); + ZDspBf("\t2\t= VT100 in VT52 mode\r\n", 25); + ZDspBf("\t4\t= VT100 in VT100 mode\r\n", 26); + ZDspBf("\t6\t= VT05\r\n", 11); + ZDspBf("\t8\t= VT102\r\n", 12); + ZDspBf("\t10\t= VK100\r\n", 13); + ZDspBf("\t11\t= VT200 in VT200 mode\r\n", 27); + ZDspBf("\t12\t= VT200 in ANSI (VT100) mode\r\n", 34); + ZDspBf("\t13\t= VT200 in VT52 mode\r\n", 26); + CrType = (DEFAULT)MArgmt; + return FAILURE; + } + CrType = (DEFAULT)MArgmt; + break; + case 1: + if (MArgmt < 1) { + ErrMsg(ERR_ARG); + return FAILURE; + } + if (ZSetTT(TTWIDTH, (DEFAULT)MArgmt) == FAILURE) + return FAILURE; + HtSize = (DEFAULT)MArgmt; + break; + case 2: + if (MArgmt < 1) { + ErrMsg(ERR_ARG); + return FAILURE; + } + if (ZSetTT(TTHEIGHT, (DEFAULT)MArgmt) == FAILURE) + return FAILURE; + VtSize = (DEFAULT)MArgmt; + break; + case 3: + SeeAll = (DEFAULT)MArgmt; + break; + case 4: + MrkFlg = (DEFAULT)MArgmt; + break; + case 5: + HldFlg = (DEFAULT)MArgmt; + break; + case 6: +#if CURSES + scope_start = (int)MArgmt; + p_scope_start = (scope_start > GapBeg - EBfBeg) + ? (scope_start - (GapBeg - EBfBeg)) + GapEnd + : EBfBeg + scope_start; +#else + TopDot = (DEFAULT)MArgmt; +#endif + break; + case 7: + ScroLn = (DEFAULT)MArgmt; +#if CURSES + Scope(ScroLn); +#endif + break; +#if CURSES + case 8: + SpcMrk = (DEFAULT)MArgmt; + break; + case 9: + KeyPad = (DEFAULT)MArgmt; + break; +#endif + } /* end of switch */ + + DBGFEX(1,DbgFNm,"SUCCESS"); + return (PushEx(MArgmt, OPERAND)); +} + + +static DEFAULT VDoW() /* execute an nW command */ +{ + DBGFEN(1,"VDoW",NULL); + +#if CURSES + if (NArgmt== (-4)) { + redraw(); + wrefresh(curscr); + return SUCCESS; + } else if (NArgmt==0 || NArgmt == 16) { + redraw(); + refresh(); + return SUCCESS; + } else if (NArgmt == -1) { + skiprefresh = 1; + return SUCCESS; + } else if (NArgmt == 1) { + skiprefresh = 0; + return SUCCESS; + } else if (NArgmt == 2) { /* put line containing dot at top */ + p_scope_start=GapBeg; + scope_start=GapBeg - EBfBeg; + redraw(); + refresh(); + return SUCCESS; + } else + return SUCCESS; +#else /* if CURSES */ +#if DEBUGGING + if (NArgmt == -1) { + printf("VDoW: -1W refreshing the screen\r\n"); + } else if (NArgmt == 0) { + printf("VDoW: 0W Placing default cursor line at 16. Forgetting.\r\n"); + } else if (NArgmt == -1000) { + printf("VDoW: -1000W Forgetting output was done.\r\n"); + } else if (NArgmt < 0) { + printf("VDoW: %ldW telling refresher top %ld lines are altered.\r\n", + NArgmt, -NArgmt-1); + } else { + printf("VDoW: %ldW Placing def. cursor at line %ld. Forgetting.\r\n", + NArgmt, NArgmt); + } + + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +#else + return ExeNYI(); +#endif /* DEBUGGING */ +#endif /* CURSES */ +} +#endif /* VIDEO */ + + + +DEFAULT ExeW() /* execute an W command */ +{ + DBGFEN(1,"ExeW",NULL); + +/* + * If the terminal is not a scope, don't do anything. Don't return + * FAILURE, because that'll terminate the current macro. + */ + if (!(EtFlag & ET_WAT_SCOPE)) { /* if scope not available */ + CmdMod = '\0'; + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; + } + +#if VIDEO + + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = (CmdMod & COLON) ? 0 : 16; + } else { + if (GetNmA() == FAILURE) { /* get the numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + + if (CmdMod & COLON) { /* if it's :W */ + if (NArgmt < 0) { /* insert processing? */ + CmdMod = '\0'; + return ExeNYI(); + } else { + if (CmdMod & MARGIS) { /* if it's m,n:W */ + CmdMod = '\0'; + if (VSetW() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } else { /* else (must be n:W) */ + CmdMod = '\0'; + if (VGetW() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + } + } else { /* else there's no colon */ + CmdMod = '\0'; + if (VDoW() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + EStTop = EStBot; /* clear expression stack */ + CmdMod &= ~COLON; /* clear colon modifier */ + } + + DBGFEX(1,DbgFNm,"SUCCESS"); + CmdMod = '\0'; + return SUCCESS; + +#else /* not VIDEO */ + + CmdMod = '\0'; + DBGFEX(1,DbgFNm,"ExeNYI()"); + return ExeNYI(); + +#endif /* VIDEO */ +} diff --git a/src/exex.c b/src/exex.c new file mode 100644 index 0000000..321bcb9 --- /dev/null +++ b/src/exex.c @@ -0,0 +1,94 @@ +/***************************************************************************** + ExeX() + This function executes an X command. + nXq Put n lines into Q-register q + m,nXq Put characters m to n into Q-register q + n:Xq Append n lines to Q-register q + m,n:Xq Append characters m to n into Q-register q +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeX() /* execute an X command */ +{ + ptrdiff_t TmpSiz; + DBGFEN(1,"ExeX",NULL); + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1X */ + } else { + UMinus(); /* if it's -X, make it -1X */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + } + if (IncCBP() == FAILURE) { /* move to char after X */ + DBGFEX(1,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + if (FindQR() == FAILURE) { /* find q-register values */ + DBGFEX(1,DbgFNm,"FAILURE, FindQR() failed"); + return FAILURE; + } + if (!(CmdMod & COLON)) { /* if no colon modifier */ + if (QR->Start != NULL) { /* if text area not empty */ + ZFree((voidptr)QR->Start);/* free allocated memory */ + QR->Start = QR->End_P1 = NULL; + } + } + if ((CmdMod & MARGIS) == '\0') { /* if it's nXq (not m,nXq) */ + NArgmt = Ln2Chr(NArgmt); + if (NArgmt > 0) { + if (MakRom((SIZE_T)NArgmt) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, MakRom() failed"); + return FAILURE; + } + MEMMOVE(QR->End_P1, GapEnd+1, (SIZE_T)NArgmt); + QR->End_P1 += NArgmt; + } else if (NArgmt < 0) { + if (MakRom((SIZE_T)-NArgmt) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, MakRom() failed"); + return FAILURE; + } + MEMMOVE(QR->End_P1, GapBeg+NArgmt, (SIZE_T)-NArgmt); + QR->End_P1 -= NArgmt; + } + } else if (NArgmt != MArgmt) { /* else (it's m,nXq) */ + MEMMOVE(ErrTxt, "m,nX", 5); + if (GetAra() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, GetAra() failed"); + return FAILURE; + } + if ((AraBeg < GapBeg) && (AraEnd > GapEnd)) { + TmpSiz = (GapBeg-AraBeg) + (AraEnd-GapEnd); + if (TmpSiz > 0) { + if (MakRom((SIZE_T)TmpSiz) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, MakRom() failed"); + return FAILURE; + } + MEMMOVE(QR->End_P1, + AraBeg, + (SIZE_T)(GapBeg - AraBeg)); + QR->End_P1 += GapBeg-AraBeg; + MEMMOVE(QR->End_P1, + GapEnd+1, + (SIZE_T)(AraEnd - GapEnd)); + QR->End_P1 += AraEnd-GapEnd; + } + } else { /* else area is contiguous */ + TmpSiz = (AraEnd - AraBeg) + 1; + if (TmpSiz > 0) { + if (MakRom((SIZE_T)TmpSiz) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, MakRom() failed"); + return FAILURE; + } + MEMMOVE(QR->End_P1, AraBeg, (SIZE_T)TmpSiz); + QR->End_P1 += TmpSiz; + } + } + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/exey.c b/src/exey.c new file mode 100644 index 0000000..5f071d0 --- /dev/null +++ b/src/exey.c @@ -0,0 +1,28 @@ +/***************************************************************************** + ExeY() + This function executes a Y command. + Y Read into buffer +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT ExeY() /* Y command */ +{ + DBGFEN(1,"ExeY",NULL); + if (EStTop > EStBot) { /* if numeric argument */ + ErrMsg(ERR_NYA); /* numeric argument with Y */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + if ((EdFlag & ED_YANK_OK) == 0) { /* if no yank when full EBf */ + if (IsOpnO[CurOut] && /* if output file is open */ + ((GapBeg != EBfBeg) || (GapEnd != EBfEnd))) { + ErrMsg(ERR_YCA); /* Y command aborted */ + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(1,DbgFNm,"ExeEY()"); + return ExeEY(); +} diff --git a/src/exez.c b/src/exez.c new file mode 100644 index 0000000..dbf38b5 --- /dev/null +++ b/src/exez.c @@ -0,0 +1,19 @@ +/***************************************************************************** + ExeZ() + This function executes a Z command. + Z Equivalent to the number of characters currently + contained in the buffer. Thus, Z represents the + position following the last character in the buffer. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT ExeZ() /* execute Z command */ +{ +#if DEBUGGING + DBGFEN(1,"ExeZ",NULL); + sprintf(DbgSBf,"PushEx(%ld)", ((GapBeg-EBfBeg)+(EBfEnd-GapEnd))); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return PushEx((LONG)((GapBeg-EBfBeg)+(EBfEnd-GapEnd)), OPERAND); +} diff --git a/src/ff b/src/ff new file mode 100644 index 0000000..07cb6c9 --- /dev/null +++ b/src/ff @@ -0,0 +1,134 @@ +./docjr.c: OK +./err.c: OK +./defext.h: OK +./zfirst.c: OK +./exedot.c: OK +./genclp.c: OK +./exel.c: OK +./exex.c: OK +./exep.c: OK +./exeu.c: OK +./execti.c: OK +./zfrsrc.c: OK +./exes.c: OK +./execom.c: OK +./exei.c: OK +./deferr.h: OK +./exeequ.c: OK +./exej.c: OK +./test.c: OK +./exeopr.c: OK +./makdbf.c: OK +./sserch.c: OK +./pushex.c: OK +./getnma.c: OK +./baksrc.c: OK +./exebar.c: OK +./exeqes.c: OK +./findes.c: OK +./exegtr.c: OK +./tecoc.c: OK +./exedgt.c: OK +./dchars.h: OK +./execcc.c: OK +./srclop.c: OK +./tstsrc.tec: OK +./makrom.c: OK +./flowec.c: OK +./exectp.c: OK +./exeusc.c: OK +./exeund.c: OK +./insstr.c: OK +./readcs.c: OK +./exeq.c: OK +./exectc.c: OK +./findqr.c: OK +./exeats.c: OK +./exectd.c: OK +./execst.c: OK +./replac.c: OK +./exeb.c: OK +./exef.c: OK +./exebsl.c: OK +./exerbr.c: OK +./execln.c: OK +./doflag.c: OK +./execto.c: OK +./exenyi.c: OK +./popmac.c: OK +./echoit.c: OK +./singlp.c: OK +./flowel.c: OK +./exectn.c: OK +./chmacs.h: OK +./exectr.c: OK +./vrbmsg.h: OK +./problems.txt: OK +./exectt.c: OK +./exedqu.c: OK +./exectu.c: OK +./exeo.c: OK +./exectl.c: OK +./flowee.c: OK +./init.c: OK +./exey.c: OK +./exec.c: OK +./exepw.c: OK +./exeexc.c: OK +./exenul.c: OK +./exelst.c: OK +./pshmac.c: OK +./rdpage.c: OK +./exectq.c: OK +./exez.c: OK +./execte.c: OK +./exet.c: OK +./execty.c: OK +./exeey.c: OK +./exeg.c: OK +./execrt.c: OK +./aaout.txt: OK +./exee.c: OK +./clenup.c: OK +./bldstr.c: OK +./cmatch.c: OK +./inccbp.c: OK +./exeill.c: OK +./exek.c: OK +./uminus.c: OK +./exefb.c: OK +./exelbr.c: OK +./exectv.c: OK +./exeh.c: OK +./exertp.c: OK +./ln2chr.c: OK +./exeesc.c: OK +./video.txt: OK +./execta.c: OK +./typbuf.c: OK +./skpcmd.c: OK +./dscren.h: OK +./exects.c: OK +./exev.c: OK +./exectw.c: OK +./tabort.c: OK +./getara.c: OK +./exescl.c: OK +./exem.c: OK +./exew.c: OK +./purge.c: OK +./exed.c: OK +./isradx.c: OK +./rdline.c: OK +./search.c: OK +./exectz.c: OK +./typest.c: OK +./exea.c: OK +./exeprc.c: OK +./exer.c: OK +./doeves.c: OK +./changes.txt: OK +./tecoc.h: OK +./exen.c: OK +./exectx.c: OK +./wrpage.c: OK diff --git a/src/findes.c b/src/findes.c new file mode 100644 index 0000000..4f44d06 --- /dev/null +++ b/src/findes.c @@ -0,0 +1,47 @@ +/***************************************************************************** + FindES() + This function finds the end of the text argument to a command. +If the command is at-sign (@) modified, the text argument may be delimited +by a special character. + On entry, CBfPtr points at the beginning of the text argument. +TrmChr contains the "usual" termination character for the command. If the +ATSIGN bit of CmdMod is set, it means the command is at-sign modified. +In that case the first character of the text argument (pointed to by CBfPtr) +is the delimiter character. + On return, ArgPtr points to the beginning of the true text argument +and CBfPtr points to the termination character. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT FindES(TrmChr) /* find end of text argument */ +unsigned char TrmChr; /* termination char if no @ modifier */ +{ +#if DEBUGGING + static char *DbgFNm = "FindES"; + sprintf(DbgSBf,", string is %sat-sign modified", + (CmdMod & ATSIGN) ? "" : "not "); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + if (IncCBP() == FAILURE) { /* point to 1st char of text */ + DBGFEX(3,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + if (CmdMod & ATSIGN) { /* if it's @-modified */ + TrmChr = *CBfPtr; + if (IncCBP() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + } + ArgPtr = CBfPtr; + while (*CBfPtr != TrmChr) { + if (IncCBP() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/findqr.c b/src/findqr.c new file mode 100644 index 0000000..3e5c0c6 --- /dev/null +++ b/src/findqr.c @@ -0,0 +1,86 @@ +/***************************************************************************** + + FindQR() + + This function "finds" a q-register. CBfPtr points to the first +character of the q-register name. If it is a period (q-register is local to +this macro level), then CBfPtr is incremented to point to the next +character and, if this is the first use of a local q-register in this macro +level, then memory for a local q-register table is allocated. + + This function sets up the QR global variable. + +*****************************************************************************/ + +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "chmacs.h" /* define character processing macros */ + +DEFAULT FindQR() /* find q-register index */ +{ + WORD i; + BOOLEAN LocalQ; + WORD QIndex; + unsigned char QName; + +/* + * If it's a local q-register name (starts with a dot), remember and move on. + */ + DBGFEN(3,"FindQR",NULL); + LocalQ = (*CBfPtr == '.'); /* if local q-register */ + if (LocalQ) { /* if local q-register name */ + if (IncCBP() == FAILURE) { /* move to next character */ + DBGFEX(3,DbgFNm,"FAILURE, IncCBP() failed"); + return FAILURE; + } + } + +/* + * Get the index into the QRgstr array into i. + */ + QName = *CBfPtr; + if (Is_Upper(QName)) { + i = 'A' - 10; /* QRgStr[10..35] */ + } else if (Is_Lower(QName)) { + i = 'a' - 10; /* QRgstr[10..35] */ + } else if (Is_Digit(QName)) { + i = '0'; /* QRgstr[0..9] */ + } else { + ErrChr(ERR_IQN, QName); + DBGFEX(3,DbgFNm,"FAILURE, illegal Q-register name"); + return FAILURE; + } + +/* + * Get a pointer to the structure into QR. + */ + QIndex = QName - i; /* index into QRgstr[] */ + if (LocalQ) { /* if local q-register */ + if (MStTop < 0) { /* if not in a macro */ + QR = &QRgstr[QIndex+36]; /* use QRgstr[36..71] */ + } else { /* else (we're in a macro) */ + WORD TMIndx; + QRptr QRp; + for (TMIndx=MStTop; TMIndx>0; TMIndx--) { + if (MStack[TMIndx].QRgstr != NULL) { + QRp = MStack[TMIndx].QRgstr; + break; + } + } + QR = (TMIndx != 0) ? /* if we found one */ + &QRp[QIndex]: /* use the one we found */ + (QRptr) &QRgstr[QIndex+36]; /* else use main level ones */ + } + } else { + QR = &QRgstr[QIndex]; + } + +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, %sQIndex = %d (QName = '%c')", + (LocalQ) ? "local " : "", QIndex, QName); + DBGFEX(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} diff --git a/src/flowec.c b/src/flowec.c new file mode 100644 index 0000000..6fc2e37 --- /dev/null +++ b/src/flowec.c @@ -0,0 +1,35 @@ +/***************************************************************************** + FlowEC() + This function moves the command string pointer to the next matching +' character in the command string. It is called when a F' command is +encountered or when a | character is encountered while a conditional command +string is executing. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT FlowEC() /* flow to end of conditional */ +{ + WORD TmpNst; + TmpNst = 1; + do { + if (CBfPtr == CStEnd) { + ErrMsg(ERR_MAP); /* missing ' */ + return FAILURE; + } + ++CBfPtr; + if (*CBfPtr == '"') { + ++TmpNst; + } else if (*CBfPtr == '\'') { + --TmpNst; + } + if (SkpCmd() == FAILURE) { + return FAILURE; + } + } while (TmpNst > 0); + if (TraceM) { + EchoIt(*CBfPtr); + } + return SUCCESS; +} diff --git a/src/flowee.c b/src/flowee.c new file mode 100644 index 0000000..7e323a0 --- /dev/null +++ b/src/flowee.c @@ -0,0 +1,38 @@ +/***************************************************************************** + FlowEE() + This function moves the command string pointer to the next matching +' or | character in the command string. It is called when a conditional +command (e.g. "E) is encountered and the condition fails, or when an F| +command is encountered. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT FlowEE() /* flow to else or end (| or ') */ +{ + WORD TmpNst; + TmpNst = 1; + do { + if (CBfPtr == CStEnd) { + ErrUTC(); /* unterminated command */ + return FAILURE; + } + ++CBfPtr; + if ((*CBfPtr == '|') && (TmpNst == 1)) { + break; + } + if (*CBfPtr == '"') { + ++TmpNst; + } else if (*CBfPtr == '\'') { + --TmpNst; + } + if (SkpCmd() == FAILURE) { + return FAILURE; + } + } while (TmpNst > 0); + if (TraceM) { + EchoIt(*CBfPtr); + } + return SUCCESS; +} diff --git a/src/flowel.c b/src/flowel.c new file mode 100644 index 0000000..a566c33 --- /dev/null +++ b/src/flowel.c @@ -0,0 +1,42 @@ +/***************************************************************************** + FlowEL() + This function exits the current loop. It is called when a loop +command (<) is executed with a numeric argument less than or equal to zero, +when a semi-colon command is executed with a numeric argument greater than +zero, when a search command within a loop fails, or when an F> command is +executed. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT FlowEL() /* flow to end of loop */ +{ + WORD TmpNst; /* temporary loop nest count */ + DBGFEN(3,"FlowEL",NULL); + TmpNst = 1; + do { + if (CBfPtr == CStEnd) { /* if end of command string */ + ErrUTC(); /* unterminated command */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + ++CBfPtr; /* move to next command */ + if (*CBfPtr == '<') { /* if loop start character */ + ++TmpNst; /* increment nesting count */ + } else if (*CBfPtr == '>') { /* else if loop end char */ + --TmpNst; /* decrement nesting count */ + } else { + if (SkpCmd() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + } while (TmpNst > 0); + if (TraceM) { /* if tracing is on */ + EchoIt(*CBfPtr); /* echo the character */ + } + --LStTop; /* pop loop stack */ + DBGFEX(3,DbgFNm,"FlowEL"); + return SUCCESS; +} diff --git a/src/genclp.c b/src/genclp.c new file mode 100644 index 0000000..f6d5db7 --- /dev/null +++ b/src/genclp.c @@ -0,0 +1,223 @@ +/*************************************************************************** + * This program reads a TECO macro contained in file CLPARS.TEC. It writes + * CLPARS.H, a C include file that is included by the ZPrsCL function. +***************************************************************************/ +#ifdef sun +void exit(); /* exit the program */ +int puts(); /* write string to stdout, with newline */ +void perror(); /* write a message on stdout */ +int fputs(); /* put string to a given stream */ +int fclose(); /* close a stream */ +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 +#else +#include /* define prototype for exit() */ +#ifdef vax11c +#define EXIT_SUCCESS 1 +#define EXIT_FAILURE 2 +#endif +#endif +#include /* define prototypes for fopen(), etc. */ +#include /* define prototype for strcpy */ +#ifndef FALSE +#define FALSE (1==0) +#endif +#ifndef TRUE +#define TRUE (1==1) +#endif +typedef char BOOLEAN; +#define ILINE_SIZE 132 /* maximum input file (CLPARS.TEC) line length */ +#define OLINE_SIZE 75 /* maximum output file (CLPARS.H) line length */ +static void +#if USE_PROTOTYPES +open_clpars_tec(FILE **ifile) +#else +open_clpars_tec(ifile) +FILE **ifile; +#endif +{ + *ifile = fopen("clpars.tec","r"); + if (*ifile == NULL) + { + puts("genclp: Unable to open file CLPARS.TEC for reading"); + perror("genclp"); + exit(EXIT_FAILURE); + } +} +static void +#if USE_PROTOTYPES +open_clpars_h(FILE **ofile) +#else +open_clpars_h(ofile) +FILE **ofile; +#endif +{ + *ofile = fopen("clpars.h","w"); + if (*ofile == NULL) + { + puts("genclp: Unable to open file CLPARS.C for writing"); + perror("genclp"); + exit(EXIT_FAILURE); + } +} +static void +#if USE_PROTOTYPES +write_line(char *obuf, FILE *ofile) +#else +write_line(obuf, ofile) +char *obuf; +FILE *ofile; +#endif +{ + if (fputs(obuf, ofile) == EOF) + { + puts("genclp: Unable to write to file CLPARS.C"); + perror("genclp"); + exit(EXIT_FAILURE); + } +} +static void +#if USE_PROTOTYPES +write_header(FILE *ofile) +#else +write_header(ofile) +FILE *ofile; +#endif +{ + write_line("/*\n", ofile); + write_line(" * This file was created by the GENCLP program.\n",ofile); + write_line(" * It should not be edited. To make changes,\n", ofile); + write_line(" * change the CLPARS.TES file, then squeeze\n", ofile); + write_line(" * CLPARS.TES to produce the CLPARS.TEC file,\n", ofile); + write_line(" * then run GENCLP to produce this file.\n", ofile); + write_line(" */\n", ofile); +} +static void +#if USE_PROTOTYPES +close_clpars_tec(FILE *ifile) +#else +close_clpars_tec(ifile) +FILE *ifile; +#endif +{ + if (fclose(ifile) != 0) + { + puts("genclp: Unable to close input file CLPARS.C"); + perror("genclp"); + exit(EXIT_FAILURE); + } +} +static void +#if USE_PROTOTYPES +close_clpars_h(FILE *ofile) +#else +close_clpars_h(ofile) +FILE *ofile; +#endif +{ + if (fclose(ofile) != 0) + { + puts("genclp: Unable to close output file CLPARS.C"); + perror("genclp"); + exit(EXIT_FAILURE); + } +} +static void +#if USE_PROTOTYPES +cnvrt( FILE *ifile, + FILE *ofile, + BOOLEAN ANSI_style) +#else +cnvrt(ifile, ofile, ANSI_style) +FILE *ifile; +FILE *ofile; +BOOLEAN ANSI_style; +#endif +{ + char *iptr; + char *optr; + int total_chars = 0; + int total_lines = 0; + char iline[ILINE_SIZE]; + char oline[OLINE_SIZE]; + oline[0] = '\"'; + optr = &oline[1]; + while (fgets(iline, ILINE_SIZE, ifile) != NULL) + { + iptr = iline; + while (*iptr != '\n') + { + switch (*iptr) { + case '"': *optr++ = '\\'; *optr++ = '"'; break; + case '\\': *optr++ = '\\'; *optr++ = '\\'; break; + case '\n': *optr++ = '\\'; *optr++ = 'n'; break; + case '\r': *optr++ = '\\'; *optr++ = 'r'; break; + default: + if (*iptr >= ' ') + *optr++ = *iptr; + else { + sprintf(optr, + (ANSI_style) ? "\\%o\"\"" : "\\%03o", + *iptr); + optr += strlen(optr); + } + } + iptr++; + total_chars += 1; + if (optr > &oline[OLINE_SIZE-10]) + { + *optr++ = '"'; + if (!ANSI_style) + *optr++ = ','; + *optr++ = '\n'; + *optr++ = '\0'; + write_line(oline, ofile); + total_lines += 1; + optr = &oline[1]; + } + } + } + *optr++ = '"'; + *optr++ = '\n'; + *optr = '\0'; + write_line(oline, ofile); + total_lines += 1; + write_line("};\n", ofile); + sprintf(oline, "#define CLPARS_LEN %d\n", total_chars); + write_line(oline, ofile); + if (!ANSI_style) + { + sprintf(oline, "#define CLPARS_LINES %-3d\n", total_lines); + write_line(oline, ofile); + } +} +int +#if USE_PROTOTYPES +main(void) +#else +main() +#endif +{ + FILE *ifile, *ofile; + open_clpars_h(&ofile); +/* + * write "#if USE_ANSI_CLPARS" part + */ + open_clpars_tec(&ifile); + write_header(ofile); + write_line("#if USE_ANSI_CLPARS\n", ofile); + write_line("unsigned const char clpars[] = {\n", ofile); + cnvrt(ifile, ofile, TRUE); + close_clpars_tec(ifile); +/* + * write "#else" part + */ + open_clpars_tec(&ifile); + write_line("#else\n", ofile); + write_line("char *clpars[] = {\n", ofile); + cnvrt(ifile, ofile, FALSE); + close_clpars_tec(ifile); + write_line("#endif\n", ofile); + close_clpars_h(ofile); + return EXIT_SUCCESS; +} diff --git a/src/getara.c b/src/getara.c new file mode 100644 index 0000000..018e42b --- /dev/null +++ b/src/getara.c @@ -0,0 +1,58 @@ +/***************************************************************************** + GetAra() + This function is used by commands which can be preceded by two +arguments which specify an "area" of the edit buffer. For instance, the "T" +command can have the form "m,nT", which will cause the characters between the +mth and nth character of the edit buffer to be typed on the terminal screen. +All commands which support m,n arguments call this function to compute the +addresses of the m and nth characters. The resulting addresses are left +in the global variables AraBeg and AraEnd. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT GetAra() /* get m,n addresses */ +{ + LONG TmpLng; +#if DEBUGGING + static char *DbgFNm = "GetAra"; + sprintf(DbgSBf,"MArgmt = %ld, NArgmt = %ld", MArgmt, NArgmt); + DbgFEn(4,DbgFNm,DbgSBf); +#endif + if (MArgmt < 0) { /* if negative m */ + ErrMsg(ERR_NCA); /* negative argument to , */ + DBGFEX(4,DbgFNm,"FAILURE, negative m"); + return FAILURE; + } + if (NArgmt < 0) { /* if negative n */ + ErrStr(ERR_POP, ErrTxt); /* POP = pointer off page */ + DBGFEX(4,DbgFNm,"FAILURE, negative n"); + return FAILURE; + } + if (MArgmt > NArgmt) { /* if wrong order */ + TmpLng = NArgmt; + NArgmt = MArgmt; + MArgmt = TmpLng; + } + AraBeg = EBfBeg + MArgmt; /* compute area beginning */ + if (AraBeg > GapBeg-1) { /* if past start of gap */ + AraBeg += (GapEnd-GapBeg) + 1; /* correct for gap */ + } + AraEnd = (EBfBeg + NArgmt) - 1; /* compute area end */ + if (AraEnd > GapBeg-1) { /* if before end of gap */ + AraEnd += (GapEnd-GapBeg) + 1; /* correct for gap */ + } + if ((AraBeg > EBfEnd) || /* if m or n too large */ + (AraEnd > EBfEnd)) { + ErrStr(ERR_POP, ErrTxt); /* POP = pointer off page */ + DBGFEX(4,DbgFNm,"FAILURE"); + return FAILURE; + } +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, AraBeg = %ld, AraEnd = %ld", + Zcp2ul(AraBeg), Zcp2ul(AraEnd)); + DbgFEx(4,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} diff --git a/src/getnma.c b/src/getnma.c new file mode 100644 index 0000000..212973c --- /dev/null +++ b/src/getnma.c @@ -0,0 +1,46 @@ +/***************************************************************************** + GetNmA() + This function "gets the numeric argument". When a command which takes +a numeric argument is executed, it checks whether the expression stack is +empty. If the expression stack is not empty, this function is called to get +the numeric argument on the expression stack into global variable Number. + It is assumed that the calling function checked that the expression +stack is non-empty (i.e. that EStTop > EStBot). This function checks that +the expression stack contains an operand (not an operator). If it does, the +operand is removed from the stack and placed in NArgmt. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT GetNmA() /* get numeric argument */ +{ + DBGFEN(2,"GetNmA",NULL); + if (EStack[EStTop].ElType == OPERAND) { /* it's an operand */ + NArgmt = EStack[EStTop].Elemnt; + --EStTop; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, NArgmt = %ld",NArgmt); + DbgFEx(2,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } +#if DEBUGGING + sprintf(DbgSBf,"dying with IFE, EstBot = %ld, stack =",(LONG)EStBot); + DbgFMs(2,DbgFNm,DbgSBf); + while (EStTop > 0) { + printf("EStack[%ld].ElType = ", (LONG)EStTop); + if (EStack[EStTop].ElType == OPERATOR) { + printf("OPERATOR, EStack[%ld].Elemnt = '%c'\r\n", + (LONG)EStTop, (char)EStack[EStTop].Elemnt); + } else { + printf("OPERAND, EStack[%ld].Elemnt = %ld\r\n", + (LONG)EStTop, (LONG)EStack[EStTop].Elemnt); + } + EStTop--; + } +#endif + ErrMsg(ERR_IFE); /* ill-formed numeric expression */ + DBGFEX(2,DbgFNm,"FAILURE, unterminated command"); + return FAILURE; +} diff --git a/src/inccbp.c b/src/inccbp.c new file mode 100644 index 0000000..164d60e --- /dev/null +++ b/src/inccbp.c @@ -0,0 +1,25 @@ +/***************************************************************************** + IncCBp() + This function increments the command buffer pointer CBfPtr. It +checks whether incrementing the command buffer pointer will move the command +buffer pointer past the end of the command buffer. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT IncCBP() +{ + if (CBfPtr == CStEnd) { /* if end of command string */ + if (MStTop < 0) { /* if not in a macro */ + ErrUTC(); /* unterminated command */ + return FAILURE; + } + return SUCCESS; + } + ++CBfPtr; + if (TraceM) { /* if trace mode is on */ + EchoIt(*CBfPtr); /* display the character */ + } + return SUCCESS; +} diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000..d8131e2 --- /dev/null +++ b/src/init.c @@ -0,0 +1,159 @@ +/***************************************************************************** + Init.c + Initialization routines for Tecoc. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include +#if USE_PROTOTYPES +static VVOID MemIni(void); +#endif +/***************************************************************************** + MemIni() + This function allocates memory for the edit buffer, command buffer, +filename buffer and search string buffer. System-independent global +variables are also initialized by this function. +*****************************************************************************/ +static VVOID MemIni() +{ + WORD i; + QRptr QRp; + charptr TmpMem; + DBGFEN(2,"MemIni",NULL); +/* + * allocate a chunk of memory to start with which is free'd as soon as + * MemIni exits. subsequent small memory allocations might be taken from + * this free'd chunk without fragmenting the end of the heap where the + * edit buffer resides. + */ + TmpMem = (charptr)ZAlloc((SIZE_T)(4*1024)); +/* + * allocate memory for the digit buffer. It needs to be big enough to hold + * the decimal (signed), octal or hexadecimal representation of the largest + * number that can be stored in a LONG. Here, it's assumed that octal takes + * the most characters. The calculation is as follows: + * + * sizeof(LONG) * 8 to get bits per long + * +2 to round up so /3 doesn't truncate + * /3 since there is 3 bits per octal digit + * +2 in case ExeEqu() appends a for display purposes + */ + DBfBeg = DBfPtr = (charptr)ZAlloc((((sizeof(LONG)*8)+2)/3)+2); + if (DBfBeg == NULL) { + ErrMsg(ERR_MEM); /* MEM = memory overflow */ +#if DEBUGGING + sprintf(DbgSBf,"DBfBeg = ZAlloc(15) failed, calling TAbort()"); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + TAbort(EXIT_FAILURE); + } +/* + * allocate memory for the filename buffer + */ + FBfBeg = FBfPtr = (charptr)ZAlloc((SIZE_T)FILENAME_MAX); + if (FBfBeg == NULL) { + ErrMsg(ERR_MEM); /* MEM = memory overflow */ +#if DEBUGGING + sprintf(DbgSBf,"FBfBeg = ZAlloc(%ld) failed, calling TAbort()", + (LONG)FILENAME_MAX); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + TAbort(EXIT_FAILURE); + } + FBfEnd = FBfBeg + FILENAME_MAX - 1; +/* + * allocate memory for the command buffer + */ + CBfBeg = (charptr)ZAlloc((SIZE_T)CBFINIT); + if (CBfBeg == NULL) { + ErrMsg(ERR_MEM); /* MEM = memory overflow */ +#if DEBUGGING + sprintf(DbgSBf,"CbfBeg =ZAlloc(%ld) failed, calling TAbort()", + (LONG)CBFINIT); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + TAbort(EXIT_FAILURE); + } + CBfEnd = CBfBeg + CBFINIT - 1; +/* + * allocate memory for the search string buffer + */ + SBfBeg = SBfPtr = (charptr)ZAlloc((SIZE_T)SBFINIT); + if (SBfBeg == NULL) { + ErrMsg(ERR_MEM); /* MEM = memory overflow */ +#if DEBUGGING + sprintf(DbgSBf,"SbfBeg = ZAlloc(%ld) failed, calling TAbort()", + (LONG)SBFINIT); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + TAbort(EXIT_FAILURE); + } + SBfEnd = SBfBeg + SBFINIT - 1; +/* + * allocate memory for the edit buffer and input buffer + */ + EBfBeg = GapBeg = (charptr)ZAlloc((SIZE_T)EBFINIT + (SIZE_T)IBFINIT); + if (EBfBeg == NULL) { + ErrMsg(ERR_MEM); /* MEM = memory overflow */ +#if DEBUGGING + sprintf(DbgSBf,"EbfBeg = ZAlloc(%ld) failed, calling TAbort()", + (LONG)(EBFINIT + IBFINIT)); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + TAbort(EXIT_FAILURE); + } + EBfEnd = GapEnd = EBfBeg + EBFINIT - 1; + IBfEnd = EBfEnd + IBFINIT; +/* + * clear the global [0-35] and main-level local [36-71] Q-registers + */ + for (QRp = QRgstr, i = 0; i < 72; ++i, ++QRp) { + QRp->Start = QRp->End_P1 = NULL; + QRp->Number = 0; + } +/* + * Clear the Q-register stack + */ + for (QRp = QStack, i = 0; i < QRS_SIZE; ++i, ++QRp) { + QRp->Start = QRp->End_P1 = NULL; + QRp->Number = 0; + } +/* + * Initialize the file-open and end-of-file indicators. + */ + for (i = 0; i < NIFDBS; i++) { + IsOpnI[i] = IsEofI[i] = FALSE; + } + for (i = 0; i < NOFDBS; i++) { + IsOpnO[i] = FALSE; + } +/* + * Free our small allocation memory pool. + */ + if (TmpMem) { + ZFree (TmpMem); + } + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + Init() + This function initializes TECO-C. + If an error is detected in any of the functions called by this +function, a message is displayed and the program terminates. +*****************************************************************************/ +VVOID Init(argc, argv) /* initialize TECO-C */ +int argc; +char **argv; +{ + DBGFEN(2,"Init",NULL); + ZTrmnl(); /* open terminal for input and output */ + MemIni(); /* allocate memory and initialize variables */ +#if CONSISTENCY_CHECKING + init_consistency_check(); + check_consistency(); +#endif + ZPrsCL(argc, argv); /* parse the command line */ + DBGFEX(2,DbgFNm,NULL); +} diff --git a/src/insstr.c b/src/insstr.c new file mode 100644 index 0000000..64ed07c --- /dev/null +++ b/src/insstr.c @@ -0,0 +1,111 @@ +/***************************************************************************** + InsStr() + This function is called to insert text into the edit buffer. The +edit buffer is expanded to make room for the text if necessary. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +/* + * The edit buffer gap needs to be expanded. If there's room in the input + * buffer, then we can shuffle memory to steal some room from the input + * buffer. If there's not room to steal from the input buffer, we have to + * re-allocate the whole edit/input buffer and then adjust the pointers to + * reflect the movement. + */ +#if USE_PROTOTYPES +static DEFAULT expand_gap(ptrdiff_t length) +#else +static DEFAULT expand_gap(length) +ptrdiff_t length; /* amount of gap room needed */ +#endif +{ + SIZE_T TmpSiz; + SIZE_T NewSiz; + charptr NewBeg; + DBGFEN(3,"expand_gap",NULL); +/* + * If the size of the input buffer exceeds IBFMIN, make it IBFMIN and + * add the leftover space to the edit buffer gap. + * + * from: EbfBeg...GapBeg...GapEnd...EBfEndIBfEnd + * to: EbfBeg...GapBeg...GapEnd...EBfEndIBfEnd + */ + TmpSiz = IBfEnd-EBfEnd; + if (TmpSiz > IBFMIN) { + TmpSiz -= IBFMIN; + MEMMOVE(GapEnd+1+TmpSiz, GapEnd+1, (SIZE_T)(EBfEnd-GapEnd)); + GapEnd += TmpSiz; + EBfEnd += TmpSiz; + } +/* + * If there's still not enough room in the edit buffer gap, expand the gap + * by reallocating the edit buffer. Since reallocating is expensive, take + * this opportunity to expand it by EBFEXP bytes more than what we need. + * + * from: EbfBeg...GapBegGapEnd...EBfEnd...IBfEnd + * to: EbfBeg...GapBegGapEnd...EBfEnd...IBfEnd + */ + TmpSiz = GapEnd-GapBeg+1; + if (TmpSiz < length) { /* str length > GapSiz */ + TmpSiz = (length - TmpSiz) + EBFEXP; /* amt to expand EBf */ + NewSiz = (IBfEnd-EBfBeg+1) + TmpSiz; /* new size of EBf */ + NewBeg = (charptr)ZRaloc(EBfBeg, NewSiz); /* reallocate EBf */ + if (NewBeg == NULL) { /* if failure */ + ErrMsg(ERR_MEM); /* memory overflow */ + DBGFEX(3,DbgFNm,"FAILURE, couldn't ZRaloc more gap room"); + return FAILURE; + } +/* + * Make sure all the pointers reference the new memory area. + */ + if (NewBeg != EBfBeg) { + GapBeg = NewBeg + (GapBeg - EBfBeg); + GapEnd = NewBeg + (GapEnd - EBfBeg); + EBfEnd = NewBeg + (EBfEnd - EBfBeg); + IBfEnd = NewBeg + (IBfEnd - EBfBeg); + EBfBeg = NewBeg; + } +/* + * Now open up the gap by moving the second half of the edit buffer + * down the amount we expanded the edit buffer (TmpSiz), then update the + * pointers again. + */ + MEMMOVE(GapEnd+1+TmpSiz, GapEnd+1, (SIZE_T)(EBfEnd - GapEnd)); + GapEnd += TmpSiz; + EBfEnd += TmpSiz; + IBfEnd += TmpSiz; + } + DBGFEX(3,DbgFNm,NULL); + return SUCCESS; +} +DEFAULT InsStr(string, length) /* insert string into edit buffer */ +charptr string; +ptrdiff_t length; +{ +#if DEBUGGING + static char *DbgFNm = "InsStr"; + sprintf(DbgSBf,"length = %d", length); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + RefLen = -length; /* ^S = -length of last string */ +/* + * Before trying to insert the text, we have to be sure there's enough room + * in the edit buffer gap for the text. + */ + if ((GapEnd-GapBeg+1) < length) { + if (expand_gap(length) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, expand_gap() failed"); + return FAILURE; + } + } +/* + * Copy the new text into the edit buffer gap, and adjust GapBeg to make the + * text part of the edit buffer. + */ + MEMMOVE(GapBeg, string, (SIZE_T)length); + GapBeg += length; + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/isradx.c b/src/isradx.c new file mode 100644 index 0000000..f59eb87 --- /dev/null +++ b/src/isradx.c @@ -0,0 +1,26 @@ +/***************************************************************************** + IsRadx() + This function returns TRUE if the argument is a valid digit in the +current radix. +*****************************************************************************/ +#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 */ +BOOLEAN IsRadx(Charac) /* is Charac in the radix set? */ +unsigned char Charac; +{ + if (Charac < '0') { + return FALSE; + } + if (Charac <= '9') { + Charac -= '0'; + } else if (Is_Lower(Charac)) { + Charac -= ('a' - 10); + } else if (Is_Upper(Charac)) { + Charac -= ('A' - 10); + } else { + return FALSE; + } + return Charac < Radix; +} diff --git a/src/ln2chr.c b/src/ln2chr.c new file mode 100644 index 0000000..5faca00 --- /dev/null +++ b/src/ln2chr.c @@ -0,0 +1,45 @@ +/***************************************************************************** + Ln2Chr() + This function converts an edit buffer offset represented by a line +number into the corresponding character number. It basically performs the +function of the control-Q command. + The returned character offset is minimized with the edge of the +buffer. This means that if there are 10 lines in the edit buffer and this +function is called to compute the character offset of the 100th line, the +character offset of the 10th line is returned. Of course, this happens +whether the argument is positive or negative. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "chmacs.h" /* define character processing macros */ +LONG Ln2Chr(Value) +LONG Value; +{ + charptr TmpPtr; + if (Value > 0) { + TmpPtr = GapEnd; + while ((TmpPtr < EBfEnd) && (Value > 0)) { + ++TmpPtr; + if (IsEOL(*TmpPtr)) { + --Value; + } + } + return TmpPtr-GapEnd; + } + TmpPtr = GapBeg; + while ((TmpPtr > EBfBeg) && (Value <= 0)) { + --TmpPtr; + if (IsEOL(*TmpPtr)) { + ++Value; + } + } +/* + * at this point (Value > 0 OR TmpPtr == EBfBeg) + */ + if ((TmpPtr != EBfBeg) || (IsEOL(*TmpPtr))) { + ++TmpPtr; + } + return TmpPtr-GapBeg; +} diff --git a/src/makdbf.c b/src/makdbf.c new file mode 100644 index 0000000..caf9ed8 --- /dev/null +++ b/src/makdbf.c @@ -0,0 +1,85 @@ +/***************************************************************************** + MakDBf() + This function converts a binary number to it's ASCII equivalent. +The resultant ASCII string is left in the digit buffer DBfBeg. The second +argument to this function specifies the radix to be used. If the radix is +decimal, then a minus sign will be prepended to the number if it is negative. +If the radix is not decimal, then minus sign are never prepended. + The recursive algorithm for base 10 conversion comes from "C Traps and +Pitfalls" by Andrew Koenig. In the "portability problems" section, the book +discusses common problems converting binary numbers to characters. One such +problem arises when the maximum negative number is presented to a conversion +algorithm. Many algorithms don't handle this well, including the one that +I used to use here. So I stole his, which avoids the problem and is also +impervious to the character collating sequence. I liked using recursion to +order the string so much that I made the base 8 and 16 code use it too. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#if USE_PROTOTYPES +static VVOID DoHex(ULONG n); +static VVOID DoOct(ULONG n); +static VVOID DoNeg(LONG n); +#endif +static char digits[] = "0123456789ABCDEF"; +static VVOID DoHex(n) +ULONG n; +{ + if (n != 0) { + DoHex(n >> 4); + *DBfPtr++ = digits[(int) n & 0x000f]; + } +} +static VVOID DoOct(n) +ULONG n; +{ + if (n != 0) { + DoOct(n >> 3); + *DBfPtr++ = digits[(int) n & 0x0007]; + } +} +/* + * Put the character representation for the negative number n into DBf + */ +static VVOID DoNeg(n) +LONG n; +{ + LONG quotient; + DEFAULT remainder; + quotient = n / 10; + remainder = (int) (n % 10); /* trailing digit */ + if (remainder > 0) { /* on some machines, remainder might be positive */ + remainder -= 10; + quotient++; + } + if (n <= -10) + DoNeg(quotient); + *DBfPtr++ = digits[-remainder]; +} +VVOID MakDBf(Binary, NRadix) /* make digit buffer (DBfBeg) */ +LONG Binary; /* binary number to be converted */ +DEFAULT NRadix; /* radix to be used: 8, 10 or 16 */ +{ + ULONG TmpBin; + DBfPtr = DBfBeg; /* initialize digit buffer ptr */ + if (Binary == 0) { /* simple case? */ + *DBfPtr++ = '0'; + return; + } + if (NRadix == 10) { + if (Binary < 0) { + *DBfPtr++ = '-'; + DoNeg(Binary); + } else { + DoNeg(-Binary); + } + return; + } + TmpBin = Binary; + if (NRadix == 8) { + DoOct(TmpBin); + } else { + DoHex(TmpBin); + } +} diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..ac48309 --- /dev/null +++ b/src/makefile @@ -0,0 +1,223 @@ +# +# 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 +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 \ + exectd.c execte.c execti.c exectl.c exectn.c execto.c exectp.c \ + exectq.c exectr.c exects.c exectt.c exectu.c exectv.c exectw.c \ + exectx.c execty.c exectz.c exed.c exedgt.c exedot.c exedqu.c \ + exee.c exeequ.c exeesc.c exeexc.c exeey.c exef.c exefb.c exeg.c \ + exegtr.c exeh.c exei.c exeill.c exej.c exek.c exel.c exelbr.c \ + exelst.c exem.c exen.c exenul.c exenyi.c exeo.c exeopr.c exep.c \ + exeprc.c exepw.c exeq.c exeqes.c exer.c exerbr.c exertp.c exes.c \ + exescl.c exet.c exeu.c exeund.c exeusc.c exev.c exew.c exex.c \ + exey.c exez.c findes.c findqr.c flowec.c flowee.c flowel.c \ + getara.c getnma.c inccbp.c init.c insstr.c isradx.c ln2chr.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.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 +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 + @echo 'w' >>makedep0 + @cp makefile makefile.bak + @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..." + @-(for i in ${CFILES} ; do \ + ${CPP} -M $$i >> makedep1; done) 2>makedepe + @echo "generating new version of makefile..." + @sed -e 's|: ./|: |' makedep1 > makedep2 + @awk ' { if ($$1 != prev) \ + { print rec; rec = $$0; prev = $$1; } \ + else \ + { if (length(rec $$2) > 70) \ + { print rec; rec = $$0; } \ + else \ + rec = rec " " $$2 \ + } \ + } \ + END { print rec } \ + ' \ + makedep2 >makedep3 + @awk '/:/ {printf "%s\n", $$0}' \ + makedep3 >makedep4 + @sed -e 's|:|:|' makedep4 > makedep5 + @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 +clenup.o: clenup.c zport.h tecoc.h defext.h +cmatch.o: cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.o: docjr.c zport.h tecoc.h defext.h deferr.h +doeves.o: doeves.c zport.h tecoc.h defext.h dchars.h +doflag.o: doflag.c zport.h tecoc.h defext.h +echoit.o: echoit.c zport.h tecoc.h defext.h dchars.h +err.o: err.c zport.h tecoc.h defext.h deferr.h dchars.h +exea.o: exea.c zport.h tecoc.h defext.h deferr.h +exeats.o: exeats.c zport.h tecoc.h defext.h +exeb.o: exeb.c zport.h tecoc.h defext.h +exebar.o: exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.o: exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.o: exec.c zport.h tecoc.h defext.h +execcc.o: execcc.c zport.h tecoc.h defext.h deferr.h +execln.o: execln.c zport.h tecoc.h defext.h +execom.o: execom.c zport.h tecoc.h defext.h deferr.h +execrt.o: execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.o: execst.c zport.h tecoc.h defext.h deferr.h +execta.o: execta.c zport.h tecoc.h defext.h dchars.h +exectc.o: exectc.c zport.h tecoc.h defext.h dchars.h +exectd.o: exectd.c zport.h tecoc.h defext.h +execte.o: execte.c zport.h tecoc.h defext.h +execti.o: execti.c zport.h tecoc.h defext.h dchars.h +exectl.o: exectl.c zport.h tecoc.h defext.h dchars.h +exectn.o: exectn.c zport.h tecoc.h defext.h +execto.o: execto.c zport.h tecoc.h defext.h +exectp.o: exectp.c zport.h tecoc.h defext.h +exectq.o: exectq.c zport.h tecoc.h defext.h +exectr.o: exectr.c zport.h tecoc.h defext.h deferr.h +exects.o: exects.c zport.h tecoc.h defext.h +exectt.o: exectt.c zport.h tecoc.h defext.h deferr.h +exectu.o: exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.o: exectv.c zport.h tecoc.h defext.h deferr.h +exectw.o: exectw.c zport.h tecoc.h defext.h deferr.h +exectx.o: exectx.c zport.h tecoc.h defext.h +execty.o: execty.c zport.h tecoc.h defext.h +exectz.o: exectz.c zport.h tecoc.h defext.h +exed.o: exed.c zport.h tecoc.h defext.h deferr.h +exedgt.o: exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.o: exedot.c zport.h tecoc.h defext.h +exedqu.o: exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.o: exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.o: exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.o: exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.o: exeexc.c zport.h tecoc.h defext.h +exeey.o: exeey.c zport.h tecoc.h defext.h +exef.o: exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.o: exefb.c zport.h tecoc.h defext.h deferr.h +exeg.o: exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.o: exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.o: exeh.c zport.h tecoc.h defext.h +exei.o: exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.o: exeill.c zport.h tecoc.h defext.h deferr.h +exej.o: exej.c zport.h tecoc.h defext.h +exek.o: exek.c zport.h tecoc.h defext.h +exel.o: exel.c zport.h tecoc.h defext.h +exelbr.o: exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.o: exelst.c zport.h tecoc.h defext.h deferr.h +exem.o: exem.c zport.h tecoc.h defext.h deferr.h +exen.o: exen.c zport.h tecoc.h defext.h deferr.h +exenul.o: exenul.c zport.h tecoc.h defext.h +exenyi.o: exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.o: exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.o: exeopr.c zport.h tecoc.h defext.h +exep.o: exep.c zport.h tecoc.h defext.h deferr.h +exeprc.o: exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.o: exepw.c zport.h tecoc.h defext.h +exeq.o: exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.o: exeqes.c zport.h tecoc.h defext.h +exer.o: exer.c zport.h tecoc.h defext.h +exerbr.o: exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.o: exertp.c zport.h tecoc.h defext.h deferr.h +exes.o: exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.o: exescl.c zport.h tecoc.h defext.h deferr.h +exet.o: exet.c zport.h tecoc.h defext.h dchars.h +exeu.o: exeu.c zport.h tecoc.h defext.h deferr.h +exeund.o: exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.o: exeusc.c zport.h tecoc.h defext.h dchars.h +exev.o: exev.c zport.h tecoc.h defext.h +exew.o: exew.c zport.h tecoc.h defext.h deferr.h +exex.o: exex.c zport.h tecoc.h defext.h deferr.h +exey.o: exey.c zport.h tecoc.h defext.h deferr.h +exez.o: exez.c zport.h tecoc.h defext.h +findes.o: findes.c zport.h tecoc.h defext.h deferr.h +findqr.o: findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.o: flowec.c zport.h tecoc.h defext.h deferr.h +flowee.o: flowee.c zport.h tecoc.h defext.h deferr.h +flowel.o: flowel.c zport.h tecoc.h defext.h deferr.h +getara.o: getara.c zport.h tecoc.h defext.h deferr.h +getnma.o: getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.o: inccbp.c zport.h tecoc.h defext.h deferr.h +init.o: init.c zport.h tecoc.h defext.h deferr.h +insstr.o: insstr.c zport.h tecoc.h defext.h deferr.h +isradx.o: isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.o: ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.o: makdbf.c zport.h tecoc.h defext.h +makrom.o: makrom.c zport.h tecoc.h defext.h deferr.h +popmac.o: popmac.c zport.h tecoc.h defext.h +pshmac.o: pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.o: pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.o: rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.o: rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.o: readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +readcs.o: dscren.h +replac.o: replac.c zport.h tecoc.h defext.h dchars.h +search.o: search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.o: singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.o: skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.o: srclop.c zport.h tecoc.h defext.h deferr.h +sserch.o: sserch.c zport.h tecoc.h defext.h +tabort.o: tabort.c zport.h tecoc.h +typbuf.o: typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.o: typest.c zport.h tecoc.h defext.h dchars.h +uminus.o: uminus.c zport.h tecoc.h defext.h +wrpage.o: wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.o: zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zlinux.o: zlinux.c tecoc.h clpars.h dchars.h deferr.h +zlinux.o: defext.h dscren.h vrbmsg.h diff --git a/src/makefile.ami b/src/makefile.ami new file mode 100644 index 0000000..4ad14ad --- /dev/null +++ b/src/makefile.ami @@ -0,0 +1,170 @@ +# +# This makefile correctly builds TECOC on a Commodore Amiga with AmigaDOS +# version 1.3, and SAS Institute C version 5.10. To use this file, type +# +# lmk -f makefile.ami +# +# Note: file tecoc.lnk is needed for this file to work. +# +CC=lc +# +# use for production runs: +# +#CFLAGS= -O -cu +#LFLAGS= nodebug smallcode smalldata +# +# use for debugging runs: +# +CFLAGS= -d3 -cu +LFLAGS= verbose +# +# Objects to link to build tecoc +# +OFILES= baksrc.o bldstr.o clenup.o cmatch.o docjr.o doeves.o doflag.o \ + echoit.o err.o exea.o exeats.o exeb.o exebar.o exebsl.o exec.o \ + execcc.o execln.o execom.o execrt.o execst.o execta.o exectc.o \ + exectd.o execte.o execti.o exectl.o exectn.o execto.o exectp.o \ + exectq.o exectr.o exects.o exectt.o exectu.o exectv.o exectw.o \ + exectx.o execty.o exectz.o exed.o exedgt.o exedot.o exedqu.o \ + exee.o exeequ.o exeesc.o exeexc.o exeey.o exef.o exefb.o exeg.o \ + exegtr.o exeh.o exei.o exeill.o exej.o exek.o exel.o exelbr.o \ + exelst.o exem.o exen.o exenul.o exenyi.o exeo.o exeopr.o exep.o \ + exeprc.o exepw.o exeq.o exeqes.o exer.o exerbr.o exertp.o exes.o \ + exescl.o exet.o exeu.o exeund.o exeusc.o exev.o exew.o exex.o \ + exey.o exez.o findes.o findqr.o flowec.o flowee.o flowel.o \ + getara.o getnma.o inccbp.o init.o insstr.o isradx.o ln2chr.o \ + makdbf.o makrom.o popmac.o pshmac.o pushex.o rdline.o rdpage.o \ + readcs.o replac.o search.o singlp.o skpcmd.o srclop.o sserch.o \ + tabort.o typbuf.o typest.o uminus.o wrpage.o zfrsrc.o zamiga.o \ + tecoc.o +tecoc: $(OFILES) + blink with tecoc.lnk $(LFLAGS) +# +# delete objects and executable +# +clean: + delete \#?.o tecoc +# +# object <- source dependencies +# +tecoc.o: tecoc.c zport.h tecoc.h deferr.h dchars.h chmacs.h +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 +clenup.o: clenup.c zport.h tecoc.h defext.h +cmatch.o: cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.o: docjr.c zport.h tecoc.h defext.h deferr.h +doeves.o: doeves.c zport.h tecoc.h defext.h dchars.h +doflag.o: doflag.c zport.h tecoc.h defext.h +echoit.o: echoit.c zport.h tecoc.h defext.h dchars.h +err.o: err.c zport.h tecoc.h defext.h deferr.h dchars.h +exea.o: exea.c zport.h tecoc.h defext.h deferr.h +exeats.o: exeats.c zport.h tecoc.h defext.h +exeb.o: exeb.c zport.h tecoc.h defext.h +exebar.o: exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.o: exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.o: exec.c zport.h tecoc.h defext.h +execcc.o: execcc.c zport.h tecoc.h defext.h deferr.h +execln.o: execln.c zport.h tecoc.h defext.h +execom.o: execom.c zport.h tecoc.h defext.h deferr.h +execrt.o: execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.o: execst.c zport.h tecoc.h defext.h deferr.h +execta.o: execta.c zport.h tecoc.h defext.h dchars.h +exectc.o: exectc.c zport.h tecoc.h defext.h dchars.h +exectd.o: exectd.c zport.h tecoc.h defext.h +execte.o: execte.c zport.h tecoc.h defext.h +execti.o: execti.c zport.h tecoc.h defext.h dchars.h +exectl.o: exectl.c zport.h tecoc.h defext.h dchars.h +exectn.o: exectn.c zport.h tecoc.h defext.h +execto.o: execto.c zport.h tecoc.h defext.h +exectp.o: exectp.c zport.h tecoc.h defext.h +exectq.o: exectq.c zport.h tecoc.h defext.h +exectr.o: exectr.c zport.h tecoc.h defext.h deferr.h +exects.o: exects.c zport.h tecoc.h defext.h +exectt.o: exectt.c zport.h tecoc.h defext.h deferr.h +exectu.o: exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.o: exectv.c zport.h tecoc.h defext.h deferr.h +exectw.o: exectw.c zport.h tecoc.h defext.h deferr.h +exectx.o: exectx.c zport.h tecoc.h defext.h +execty.o: execty.c zport.h tecoc.h defext.h +exectz.o: exectz.c zport.h tecoc.h defext.h +exed.o: exed.c zport.h tecoc.h defext.h deferr.h +exedgt.o: exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.o: exedot.c zport.h tecoc.h defext.h +exedqu.o: exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.o: exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.o: exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.o: exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.o: exeexc.c zport.h tecoc.h defext.h +exeey.o: exeey.c zport.h tecoc.h defext.h +exef.o: exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.o: exefb.c zport.h tecoc.h defext.h deferr.h +exeg.o: exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.o: exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.o: exeh.c zport.h tecoc.h defext.h +exei.o: exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.o: exeill.c zport.h tecoc.h defext.h deferr.h +exej.o: exej.c zport.h tecoc.h defext.h +exek.o: exek.c zport.h tecoc.h defext.h +exel.o: exel.c zport.h tecoc.h defext.h +exelbr.o: exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.o: exelst.c zport.h tecoc.h defext.h deferr.h +exem.o: exem.c zport.h tecoc.h defext.h deferr.h +exen.o: exen.c zport.h tecoc.h defext.h deferr.h +exenul.o: exenul.c zport.h tecoc.h defext.h +exenyi.o: exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.o: exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.o: exeopr.c zport.h tecoc.h defext.h +exep.o: exep.c zport.h tecoc.h defext.h deferr.h +exeprc.o: exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.o: exepw.c zport.h tecoc.h defext.h +exeq.o: exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.o: exeqes.c zport.h tecoc.h defext.h +exer.o: exer.c zport.h tecoc.h defext.h +exerbr.o: exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.o: exertp.c zport.h tecoc.h defext.h deferr.h +exes.o: exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.o: exescl.c zport.h tecoc.h defext.h deferr.h +exet.o: exet.c zport.h tecoc.h defext.h dchars.h +exeu.o: exeu.c zport.h tecoc.h defext.h deferr.h +exeund.o: exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.o: exeusc.c zport.h tecoc.h defext.h dchars.h +exev.o: exev.c zport.h tecoc.h defext.h +exew.o: exew.c zport.h tecoc.h defext.h dscren.h +exex.o: exex.c zport.h tecoc.h defext.h deferr.h +exey.o: exey.c zport.h tecoc.h defext.h deferr.h +exez.o: exez.c zport.h tecoc.h defext.h +findes.o: findes.c zport.h tecoc.h defext.h deferr.h +findqr.o: findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.o: flowec.c zport.h tecoc.h defext.h deferr.h +flowee.o: flowee.c zport.h tecoc.h defext.h deferr.h +flowel.o: flowel.c zport.h tecoc.h defext.h deferr.h +getara.o: getara.c zport.h tecoc.h defext.h deferr.h +getnma.o: getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.o: inccbp.c zport.h tecoc.h defext.h deferr.h +init.o: init.c zport.h tecoc.h defext.h deferr.h +insstr.o: insstr.c zport.h tecoc.h defext.h deferr.h +isradx.o: isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.o: ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.o: makdbf.c zport.h tecoc.h defext.h +makrom.o: makrom.c zport.h tecoc.h defext.h deferr.h +popmac.o: popmac.c zport.h tecoc.h defext.h +pshmac.o: pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.o: pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.o: rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.o: rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.o: readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h \ + dscren.h +replac.o: replac.c zport.h tecoc.h defext.h dchars.h +search.o: search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.o: singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.o: skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.o: srclop.c zport.h tecoc.h defext.h deferr.h +sserch.o: sserch.c zport.h tecoc.h defext.h +tabort.o: tabort.c zport.h tecoc.h +typbuf.o: typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.o: typest.c zport.h tecoc.h defext.h dchars.h +uminus.o: uminus.c zport.h tecoc.h defext.h +wrpage.o: wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.o: zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zamiga.o: zamiga.c zport.h tecoc.h clpars.h dchars.h deferr.h defext.h \ + dscren.h vrbmsg.h diff --git a/src/makefile.b32 b/src/makefile.b32 new file mode 100644 index 0000000..f02a49b --- /dev/null +++ b/src/makefile.b32 @@ -0,0 +1,258 @@ +# +# MAKEFILE.B32: Borland Make file for TECO-C, 32 bit windows +# Last updated: 9/9/98 +# +# Command line: +# +# make -fmakefile.b32 [-DALL] +# [-DMAP] +# [-DNODEBUG] [-DTCPP100] +# +# -DALL +# +# The default is to compile a TECO-C module and add it to the TECOC.LIB +# library. If you're compiling all the modules from scratch, -DALL will +# compile every module first, then build the TECOC.LIB library which is +# much faster. +# +# -DMAP +# +# The default is to not generate a TLINK .MAP file. The CHECKSUM_CODE +# #define in ZPORT.H enables runtime code checksumming to insure that +# code isn't being overwritten by stray pointers. The checksumming +# routines in TECOC.C require a current TLINK C .MAP file in order to +# work, so if you enable the CHECKSUM_CODE option, be sure to compile +# with -DMAP; and be sure you have an up-to-date .MAP file when running +# with code checksumming. Note: CHECKSUM_CODE doesn't work with Turbo +# Debugger since TD modifies code as it runs. +# +# -DNODEBUG +# +# The default is to include stack checking (tcc -N, see STKCHK below) +# and Turbo Debugger (tcc -v) code. For production versions of TECO-C +# use -DNODEBUG. This will disable stack checking (tcc -N-), disable +# Turbo Debugger (tcc -v-), enable jump and register optimizations +# (tcc -O -Z), generate for speed (-G), merge duplicate strings +# (tcc -d) and use the Pascal function calling sequence (tcc -p) +# to generate smaller and faster function calls. +# +# Note: this NODEBUG switch has *nothing* to do with the internal +# debugging code enabled by setting DEBUGGING on in ZPORT.H. +# + +COMPILE=bcc32 -c -w -DWIN32 + +!if $d(NODEBUG) # if we're not debugging +COMPILE=$(COMPILE) -O # do optimizations +!else # else +!endif # endif + +# +# TLIB options: +# +# /c case sensitive library +# /e create extended dictionary +# + +TLIB_OP=/C + +!if $d(NODEBUG) +TLIB_OP=$(TLIB_OP) /e +!endif + +# +# how to make the TECOC.EXE file +# + +tecoc.exe : tecoc.obj tecoc.lib + bcc32 tecoc.obj tecoc.lib + + +# +# how to make the TECOC.OBJ module +# + +tecoc.obj : tecoc.c zport.h tecoc.h defext.h deferr.h dscren.h + $(COMPILE) tecoc.c + +# +# what constitutes the TECOC.LIB library +# + +TECOC_OBJS=\ + baksrc.obj bldstr.obj clenup.obj cmatch.obj docjr.obj doeves.obj \ + doflag.obj echoit.obj err.obj exeats.obj exea.obj exebar.obj \ + exebsl.obj exeb.obj execcc.obj execln.obj execom.obj execrt.obj \ + execst.obj execta.obj exectc.obj exectd.obj execte.obj execti.obj \ + exectl.obj exectn.obj execto.obj exectp.obj exectq.obj exectr.obj \ + exects.obj exectt.obj exectu.obj exectv.obj exectw.obj exectx.obj \ + execty.obj exectz.obj exec.obj exedgt.obj exedot.obj exedqu.obj \ + exed.obj exeequ.obj exeesc.obj exeexc.obj exeey.obj exee.obj \ + exefb.obj exef.obj exegtr.obj exeg.obj exeh.obj exeill.obj \ + exei.obj exej.obj exek.obj exelbr.obj exelst.obj exel.obj \ + exem.obj exenul.obj exenyi.obj exen.obj exeopr.obj exeo.obj \ + exeprc.obj exepw.obj exep.obj exeqes.obj exeq.obj exerbr.obj \ + exertp.obj exer.obj exescl.obj exes.obj exet.obj exeund.obj \ + exeusc.obj exeu.obj exev.obj exew.obj exex.obj exey.obj \ + exez.obj findes.obj findqr.obj flowec.obj flowee.obj flowel.obj \ + getara.obj getnma.obj inccbp.obj init.obj insstr.obj isradx.obj \ + ln2chr.obj makdbf.obj makrom.obj popmac.obj pshmac.obj pushex.obj \ + rdline.obj rdpage.obj readcs.obj replac.obj search.obj singlp.obj \ + skpcmd.obj srclop.obj sserch.obj tabort.obj typbuf.obj typest.obj \ + uminus.obj wrpage.obj zfrsrc.obj zmsdos.obj + +# +# how to make the TECOC.LIB library +# + +!if $d(ALL) #build entire library at once + +tecoc.lib : $(TECOC_OBJS) tctlib.rsp + del tecoc.lib + tlib $(TLIB_OP) tecoc.lib @tctlib.rsp + +.c.obj: + $(COMPILE) $*.c + +!else #modules added to library after compile + +tecoc.lib : $(TECOC_OBJS) + +.c.obj: + $(COMPILE) $*.c + tlib $(TLIB_OP) tecoc.lib -+$*.obj + +!endif + +# +# The CHECKSUM_CODE routines use the ZFirst() function in ZFIRST.C +# to get an idea of where the first code module is located in memory +# when TECO-C is loaded. +# + +zfirst.obj : zfirst.c + +# +# the TECOC.LIB library modules. +# + +baksrc.obj : baksrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +bldstr.obj : bldstr.c zport.h tecoc.h defext.h deferr.h dchars.h chmacs.h +clenup.obj : clenup.c zport.h tecoc.h defext.h +cmatch.obj : cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.obj : docjr.c zport.h tecoc.h defext.h deferr.h +doeves.obj : doeves.c zport.h tecoc.h defext.h dchars.h +doflag.obj : doflag.c zport.h tecoc.h defext.h +echoit.obj : echoit.c zport.h tecoc.h defext.h dchars.h +err.obj : err.c zport.h tecoc.h defext.h chmacs.h deferr.h dchars.h +exea.obj : exea.c zport.h tecoc.h defext.h deferr.h +exeats.obj : exeats.c zport.h tecoc.h defext.h +exeb.obj : exeb.c zport.h tecoc.h defext.h +exebar.obj : exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.obj : exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.obj : exec.c zport.h tecoc.h defext.h +execcc.obj : execcc.c zport.h tecoc.h defext.h deferr.h +execln.obj : execln.c zport.h tecoc.h defext.h +execom.obj : execom.c zport.h tecoc.h defext.h deferr.h +execrt.obj : execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.obj : execst.c zport.h tecoc.h defext.h deferr.h +execta.obj : execta.c zport.h tecoc.h defext.h dchars.h +exectc.obj : exectc.c zport.h tecoc.h defext.h dchars.h +exectd.obj : exectd.c zport.h tecoc.h defext.h +execte.obj : execte.c zport.h tecoc.h defext.h +execti.obj : execti.c zport.h tecoc.h defext.h dchars.h +exectl.obj : exectl.c zport.h tecoc.h defext.h dchars.h +exectn.obj : exectn.c zport.h tecoc.h defext.h +execto.obj : execto.c zport.h tecoc.h defext.h +exectp.obj : exectp.c zport.h tecoc.h defext.h +exectq.obj : exectq.c zport.h tecoc.h defext.h +exectr.obj : exectr.c zport.h tecoc.h defext.h deferr.h +exects.obj : exects.c zport.h tecoc.h defext.h +exectt.obj : exectt.c zport.h tecoc.h defext.h deferr.h +exectu.obj : exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.obj : exectv.c zport.h tecoc.h defext.h deferr.h +exectw.obj : exectw.c zport.h tecoc.h defext.h deferr.h +exectx.obj : exectx.c zport.h tecoc.h defext.h +execty.obj : execty.c zport.h tecoc.h defext.h +exectz.obj : exectz.c zport.h tecoc.h defext.h +exed.obj : exed.c zport.h tecoc.h defext.h deferr.h +exedgt.obj : exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.obj : exedot.c zport.h tecoc.h defext.h +exedqu.obj : exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.obj : exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.obj : exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.obj : exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.obj : exeexc.c zport.h tecoc.h defext.h +exeey.obj : exeey.c zport.h tecoc.h defext.h +exef.obj : exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.obj : exefb.c zport.h tecoc.h defext.h deferr.h +exeg.obj : exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.obj : exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.obj : exeh.c zport.h tecoc.h defext.h +exei.obj : exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.obj : exeill.c zport.h tecoc.h defext.h deferr.h +exej.obj : exej.c zport.h tecoc.h defext.h +exek.obj : exek.c zport.h tecoc.h defext.h +exel.obj : exel.c zport.h tecoc.h defext.h +exelbr.obj : exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.obj : exelst.c zport.h tecoc.h defext.h deferr.h +exem.obj : exem.c zport.h tecoc.h defext.h deferr.h +exen.obj : exen.c zport.h tecoc.h defext.h deferr.h +exenul.obj : exenul.c zport.h tecoc.h defext.h +exenyi.obj : exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.obj : exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.obj : exeopr.c zport.h tecoc.h defext.h +exep.obj : exep.c zport.h tecoc.h defext.h deferr.h +exeprc.obj : exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.obj : exepw.c zport.h tecoc.h defext.h +exeq.obj : exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.obj : exeqes.c zport.h tecoc.h defext.h +exer.obj : exer.c zport.h tecoc.h defext.h +exerbr.obj : exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.obj : exertp.c zport.h tecoc.h defext.h deferr.h +exes.obj : exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.obj : exescl.c zport.h tecoc.h defext.h deferr.h +exet.obj : exet.c zport.h tecoc.h defext.h dchars.h +exeu.obj : exeu.c zport.h tecoc.h defext.h deferr.h +exeund.obj : exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.obj : exeusc.c zport.h tecoc.h defext.h dchars.h +exev.obj : exev.c zport.h tecoc.h defext.h +exew.obj : exew.c zport.h tecoc.h defext.h dscren.h +exex.obj : exex.c zport.h tecoc.h defext.h deferr.h +exey.obj : exey.c zport.h tecoc.h defext.h deferr.h +exez.obj : exez.c zport.h tecoc.h defext.h +findes.obj : findes.c zport.h tecoc.h defext.h deferr.h +findqr.obj : findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.obj : flowec.c zport.h tecoc.h defext.h deferr.h +flowee.obj : flowee.c zport.h tecoc.h defext.h deferr.h +flowel.obj : flowel.c zport.h tecoc.h defext.h deferr.h +getara.obj : getara.c zport.h tecoc.h defext.h deferr.h +getnma.obj : getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.obj : inccbp.c zport.h tecoc.h defext.h deferr.h +init.obj : init.c zport.h tecoc.h defext.h deferr.h +insstr.obj : insstr.c zport.h tecoc.h defext.h deferr.h +isradx.obj : isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.obj : ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.obj : makdbf.c zport.h tecoc.h defext.h +makrom.obj : makrom.c zport.h tecoc.h defext.h deferr.h +popmac.obj : popmac.c zport.h tecoc.h defext.h +pshmac.obj : pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.obj : pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.obj : rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.obj : rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.obj : readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h \ + dscren.h +replac.obj : replac.c zport.h tecoc.h defext.h dchars.h +search.obj : search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.obj : singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.obj : skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.obj : srclop.c zport.h tecoc.h defext.h deferr.h +sserch.obj : sserch.c zport.h tecoc.h defext.h +tabort.obj : tabort.c zport.h tecoc.h +typbuf.obj : typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.obj : typest.c zport.h tecoc.h defext.h dchars.h +uminus.obj : uminus.c zport.h tecoc.h defext.h +wrpage.obj : wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.obj : zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zmsdos.obj : zmsdos.c zport.h tecoc.h defext.h chmacs.h clpars.h deferr.h \ + dchars.h dscren.h vrbmsg.h diff --git a/src/makefile.cct b/src/makefile.cct new file mode 100644 index 0000000..f4ae4c0 --- /dev/null +++ b/src/makefile.cct @@ -0,0 +1,131 @@ +# +# This makefile builds TECOC using CodeCenter on a Sun running the SunOS +# operating system. +# +ccenter_tecoc: clpars.h + #load -DDEBUGGING -DCONSISTENCY_CHECKING baksrc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING bldstr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING clenup.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING cmatch.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING docjr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING doeves.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING doflag.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING echoit.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING err.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exea.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeats.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeb.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exebar.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exebsl.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exec.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execcc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execln.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execom.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execrt.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execst.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execta.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectd.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execte.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execti.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectl.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectn.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execto.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectp.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectq.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exects.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectt.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectu.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectv.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectw.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectx.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING execty.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exectz.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exed.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exedgt.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exedot.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exedqu.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exee.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeequ.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeesc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeexc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeey.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exef.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exefb.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeg.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exegtr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeh.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exei.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeill.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exej.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exek.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exel.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exelbr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exelst.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exem.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exen.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exenul.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exenyi.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeo.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeopr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exep.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeprc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exepw.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeq.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeqes.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exer.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exerbr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exertp.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exes.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exescl.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exet.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exetil.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeu.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeund.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exeusc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exev.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exew.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exex.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exey.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING exez.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING findes.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING findqr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING flowec.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING flowee.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING flowel.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING getara.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING getnma.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING inccbp.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING init.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING insstr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING isradx.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING ln2chr.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING makdbf.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING makrom.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING popmac.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING pshmac.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING pushex.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING rdline.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING rdpage.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING readcs.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING replac.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING search.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING singlp.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING skpcmd.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING srclop.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING sserch.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING tabort.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING tecoc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING typbuf.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING typest.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING uminus.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING wrpage.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING zfrsrc.c + #load -DDEBUGGING -DCONSISTENCY_CHECKING zunix.c + #link +clpars.h: genclp clpars.tec + genclp +genclp: genclp.o + ${LINK.c} -o $@ genclp.o +genclp.o: genclp.c diff --git a/src/makefile.dg b/src/makefile.dg new file mode 100644 index 0000000..a274262 --- /dev/null +++ b/src/makefile.dg @@ -0,0 +1,248 @@ +# +# This makefile builds TECOC on a Sun running the SunOS operating system. +# 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 +# Include files for SunOS 4.0 are different than for 4.1 (4.1's are closer +# to the ANSI Standard). Define OSVERS as -DSUNOS4_0 if you're running +# 4.0, so functions get properly declared (and to keep gcc from bitching). +#OSVERS = -DSUNOS4_0 +# To choose the compiler you want to use, uncomment one of the following +# sets of lines (between here and the line containing all "#" characters). +# If you want to compile with video support, uncomment the following lines, +# which use the System V compiler and compile/link using System V include +# files and libraries. I've found that I get "undefined symbol" errors if I +# don't unsetenv the LD_LIBRARY_PATH environment variable before linking +# with this set of lines. +# +# Note that compiling in video support is a mixed blessing. If you use +# TECO-C exclusively in video mode, there are no problems. If you turn +# video off (using a 0,7:w command) you'll notice that typeout is very slow. +# This is an artifact of curses. To get fast typeout, build TECO-C without +# video (use one of the other sets of lines below). +CC=gcc +CFLAGS=-O2 -DDGUX +TERMOBJS=-lcurses +#CC = /usr/5bin/cc +#CFLAGS = ${OSVERS}${DEBG}${CCHEK} -DCURSES -O -pipe +#TERMOBJS = -lcurses +# If you want to the standard compiler, uncomment the following line. +#CFLAGS = $(OSVERS) ${DEBG} ${CCHEK} -O -pipe +#TERMOBJS = -ltermcap +# 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 +#TERMOBJS = -ltermcap +#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 \ + exectd.c execte.c execti.c exectl.c exectn.c execto.c exectp.c \ + exectq.c exectr.c exects.c exectt.c exectu.c exectv.c exectw.c \ + exectx.c execty.c exectz.c exed.c exedgt.c exedot.c exedqu.c \ + exee.c exeequ.c exeesc.c exeexc.c exeey.c exef.c exefb.c exeg.c \ + exegtr.c exeh.c exei.c exeill.c exej.c exek.c exel.c exelbr.c \ + exelst.c exem.c exen.c exenul.c exenyi.c exeo.c exeopr.c exep.c \ + exeprc.c exepw.c exeq.c exeqes.c exer.c exerbr.c exertp.c exes.c \ + exescl.c exet.c exetil.c exeu.c exeund.c exeusc.c exev.c exew.c \ + exex.c exey.c exez.c findes.c findqr.c flowec.c flowee.c flowel.c \ + getara.c getnma.c inccbp.c init.c insstr.c isradx.c ln2chr.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 zunix.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.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 +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 + @echo 'w' >>makedep0 + @cp makefile makefile.bak + @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..." + @-(for i in ${CFILES} ; do \ + ${CPP} -M $$i >> makedep1; done) 2>makedepe + @echo "generating new version of makefile..." + @sed -e 's|: ./|: |' makedep1 > makedep2 + @awk ' { if ($$1 != prev) \ + { print rec; rec = $$0; prev = $$1; } \ + else \ + { if (length(rec $$2) > 70) \ + { print rec; rec = $$0; } \ + else \ + rec = rec " " $$2 \ + } \ + } \ + END { print rec } \ + ' \ + makedep2 >makedep3 + @awk '/:/ {printf "%s\n", $$0}' \ + makedep3 >makedep4 + @sed -e 's|:|:|' makedep4 > makedep5 + @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 +clenup.o: clenup.c zport.h tecoc.h defext.h +cmatch.o: cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.o: docjr.c zport.h tecoc.h defext.h deferr.h +doeves.o: doeves.c zport.h tecoc.h defext.h dchars.h +doflag.o: doflag.c zport.h tecoc.h defext.h +echoit.o: echoit.c zport.h tecoc.h defext.h dchars.h +err.o: err.c zport.h tecoc.h defext.h deferr.h dchars.h +exea.o: exea.c zport.h tecoc.h defext.h deferr.h +exeats.o: exeats.c zport.h tecoc.h defext.h +exeb.o: exeb.c zport.h tecoc.h defext.h +exebar.o: exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.o: exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.o: exec.c zport.h tecoc.h defext.h +execcc.o: execcc.c zport.h tecoc.h defext.h deferr.h +execln.o: execln.c zport.h tecoc.h defext.h +execom.o: execom.c zport.h tecoc.h defext.h deferr.h +execrt.o: execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.o: execst.c zport.h tecoc.h defext.h deferr.h +execta.o: execta.c zport.h tecoc.h defext.h dchars.h +exectc.o: exectc.c zport.h tecoc.h defext.h dchars.h +exectd.o: exectd.c zport.h tecoc.h defext.h +execte.o: execte.c zport.h tecoc.h defext.h +execti.o: execti.c zport.h tecoc.h defext.h dchars.h +exectl.o: exectl.c zport.h tecoc.h defext.h dchars.h +exectn.o: exectn.c zport.h tecoc.h defext.h +execto.o: execto.c zport.h tecoc.h defext.h +exectp.o: exectp.c zport.h tecoc.h defext.h +exectq.o: exectq.c zport.h tecoc.h defext.h +exectr.o: exectr.c zport.h tecoc.h defext.h deferr.h +exects.o: exects.c zport.h tecoc.h defext.h +exectt.o: exectt.c zport.h tecoc.h defext.h deferr.h +exectu.o: exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.o: exectv.c zport.h tecoc.h defext.h deferr.h +exectw.o: exectw.c zport.h tecoc.h defext.h deferr.h +exectx.o: exectx.c zport.h tecoc.h defext.h +execty.o: execty.c zport.h tecoc.h defext.h +exectz.o: exectz.c zport.h tecoc.h defext.h +exed.o: exed.c zport.h tecoc.h defext.h deferr.h +exedgt.o: exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.o: exedot.c zport.h tecoc.h defext.h +exedqu.o: exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.o: exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.o: exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.o: exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.o: exeexc.c zport.h tecoc.h defext.h +exeey.o: exeey.c zport.h tecoc.h defext.h +exef.o: exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.o: exefb.c zport.h tecoc.h defext.h deferr.h +exeg.o: exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.o: exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.o: exeh.c zport.h tecoc.h defext.h +exei.o: exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.o: exeill.c zport.h tecoc.h defext.h deferr.h +exej.o: exej.c zport.h tecoc.h defext.h +exek.o: exek.c zport.h tecoc.h defext.h +exel.o: exel.c zport.h tecoc.h defext.h +exelbr.o: exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.o: exelst.c zport.h tecoc.h defext.h deferr.h +exem.o: exem.c zport.h tecoc.h defext.h deferr.h +exen.o: exen.c zport.h tecoc.h defext.h deferr.h +exenul.o: exenul.c zport.h tecoc.h defext.h +exenyi.o: exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.o: exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.o: exeopr.c zport.h tecoc.h defext.h +exep.o: exep.c zport.h tecoc.h defext.h deferr.h +exeprc.o: exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.o: exepw.c zport.h tecoc.h defext.h +exeq.o: exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.o: exeqes.c zport.h tecoc.h defext.h +exer.o: exer.c zport.h tecoc.h defext.h +exerbr.o: exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.o: exertp.c zport.h tecoc.h defext.h deferr.h +exes.o: exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.o: exescl.c zport.h tecoc.h defext.h deferr.h +exet.o: exet.c zport.h tecoc.h defext.h dchars.h +exeu.o: exeu.c zport.h tecoc.h defext.h deferr.h +exeund.o: exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.o: exeusc.c zport.h tecoc.h defext.h dchars.h +exev.o: exev.c zport.h tecoc.h defext.h +exew.o: exew.c zport.h tecoc.h defext.h deferr.h +exex.o: exex.c zport.h tecoc.h defext.h deferr.h +exey.o: exey.c zport.h tecoc.h defext.h deferr.h +exez.o: exez.c zport.h tecoc.h defext.h +findes.o: findes.c zport.h tecoc.h defext.h deferr.h +findqr.o: findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.o: flowec.c zport.h tecoc.h defext.h deferr.h +flowee.o: flowee.c zport.h tecoc.h defext.h deferr.h +flowel.o: flowel.c zport.h tecoc.h defext.h deferr.h +getara.o: getara.c zport.h tecoc.h defext.h deferr.h +getnma.o: getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.o: inccbp.c zport.h tecoc.h defext.h deferr.h +init.o: init.c zport.h tecoc.h defext.h deferr.h +insstr.o: insstr.c zport.h tecoc.h defext.h deferr.h +isradx.o: isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.o: ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.o: makdbf.c zport.h tecoc.h defext.h +makrom.o: makrom.c zport.h tecoc.h defext.h deferr.h +popmac.o: popmac.c zport.h tecoc.h defext.h +pshmac.o: pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.o: pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.o: rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.o: rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.o: readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +readcs.o: dscren.h +replac.o: replac.c zport.h tecoc.h defext.h dchars.h +search.o: search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.o: singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.o: skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.o: srclop.c zport.h tecoc.h defext.h deferr.h +sserch.o: sserch.c zport.h tecoc.h defext.h +tabort.o: tabort.c zport.h tecoc.h +typbuf.o: typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.o: typest.c zport.h tecoc.h defext.h dchars.h +uminus.o: uminus.c zport.h tecoc.h defext.h +wrpage.o: wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.o: zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zunix.o: zunix.c tecoc.h clpars.h dchars.h deferr.h +zunix.o: defext.h dscren.h vrbmsg.h diff --git a/src/makefile.osx b/src/makefile.osx new file mode 100644 index 0000000..92d17eb --- /dev/null +++ b/src/makefile.osx @@ -0,0 +1,223 @@ +# +# 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 -DOSX +#TERMOBJS = -ltermcap +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 \ + exectd.c execte.c execti.c exectl.c exectn.c execto.c exectp.c \ + exectq.c exectr.c exects.c exectt.c exectu.c exectv.c exectw.c \ + exectx.c execty.c exectz.c exed.c exedgt.c exedot.c exedqu.c \ + exee.c exeequ.c exeesc.c exeexc.c exeey.c exef.c exefb.c exeg.c \ + exegtr.c exeh.c exei.c exeill.c exej.c exek.c exel.c exelbr.c \ + exelst.c exem.c exen.c exenul.c exenyi.c exeo.c exeopr.c exep.c \ + exeprc.c exepw.c exeq.c exeqes.c exer.c exerbr.c exertp.c exes.c \ + exescl.c exet.c exeu.c exeund.c exeusc.c exev.c exew.c exex.c \ + exey.c exez.c findes.c findqr.c flowec.c flowee.c flowel.c \ + getara.c getnma.c inccbp.c init.c insstr.c isradx.c ln2chr.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} +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 +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 + @echo 'w' >>makedep0 + @cp makefile makefile.bak + @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..." + @-(for i in ${CFILES} ; do \ + ${CPP} -M $$i >> makedep1; done) 2>makedepe + @echo "generating new version of makefile..." + @sed -e 's|: ./|: |' makedep1 > makedep2 + @awk ' { if ($$1 != prev) \ + { print rec; rec = $$0; prev = $$1; } \ + else \ + { if (length(rec $$2) > 70) \ + { print rec; rec = $$0; } \ + else \ + rec = rec " " $$2 \ + } \ + } \ + END { print rec } \ + ' \ + makedep2 >makedep3 + @awk '/:/ {printf "%s\n", $$0}' \ + makedep3 >makedep4 + @sed -e 's|:|:|' makedep4 > makedep5 + @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 +clenup.o: clenup.c zport.h tecoc.h defext.h +cmatch.o: cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.o: docjr.c zport.h tecoc.h defext.h deferr.h +doeves.o: doeves.c zport.h tecoc.h defext.h dchars.h +doflag.o: doflag.c zport.h tecoc.h defext.h +echoit.o: echoit.c zport.h tecoc.h defext.h dchars.h +err.o: err.c zport.h tecoc.h defext.h deferr.h dchars.h +exea.o: exea.c zport.h tecoc.h defext.h deferr.h +exeats.o: exeats.c zport.h tecoc.h defext.h +exeb.o: exeb.c zport.h tecoc.h defext.h +exebar.o: exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.o: exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.o: exec.c zport.h tecoc.h defext.h +execcc.o: execcc.c zport.h tecoc.h defext.h deferr.h +execln.o: execln.c zport.h tecoc.h defext.h +execom.o: execom.c zport.h tecoc.h defext.h deferr.h +execrt.o: execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.o: execst.c zport.h tecoc.h defext.h deferr.h +execta.o: execta.c zport.h tecoc.h defext.h dchars.h +exectc.o: exectc.c zport.h tecoc.h defext.h dchars.h +exectd.o: exectd.c zport.h tecoc.h defext.h +execte.o: execte.c zport.h tecoc.h defext.h +execti.o: execti.c zport.h tecoc.h defext.h dchars.h +exectl.o: exectl.c zport.h tecoc.h defext.h dchars.h +exectn.o: exectn.c zport.h tecoc.h defext.h +execto.o: execto.c zport.h tecoc.h defext.h +exectp.o: exectp.c zport.h tecoc.h defext.h +exectq.o: exectq.c zport.h tecoc.h defext.h +exectr.o: exectr.c zport.h tecoc.h defext.h deferr.h +exects.o: exects.c zport.h tecoc.h defext.h +exectt.o: exectt.c zport.h tecoc.h defext.h deferr.h +exectu.o: exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.o: exectv.c zport.h tecoc.h defext.h deferr.h +exectw.o: exectw.c zport.h tecoc.h defext.h deferr.h +exectx.o: exectx.c zport.h tecoc.h defext.h +execty.o: execty.c zport.h tecoc.h defext.h +exectz.o: exectz.c zport.h tecoc.h defext.h +exed.o: exed.c zport.h tecoc.h defext.h deferr.h +exedgt.o: exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.o: exedot.c zport.h tecoc.h defext.h +exedqu.o: exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.o: exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.o: exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.o: exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.o: exeexc.c zport.h tecoc.h defext.h +exeey.o: exeey.c zport.h tecoc.h defext.h +exef.o: exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.o: exefb.c zport.h tecoc.h defext.h deferr.h +exeg.o: exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.o: exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.o: exeh.c zport.h tecoc.h defext.h +exei.o: exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.o: exeill.c zport.h tecoc.h defext.h deferr.h +exej.o: exej.c zport.h tecoc.h defext.h +exek.o: exek.c zport.h tecoc.h defext.h +exel.o: exel.c zport.h tecoc.h defext.h +exelbr.o: exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.o: exelst.c zport.h tecoc.h defext.h deferr.h +exem.o: exem.c zport.h tecoc.h defext.h deferr.h +exen.o: exen.c zport.h tecoc.h defext.h deferr.h +exenul.o: exenul.c zport.h tecoc.h defext.h +exenyi.o: exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.o: exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.o: exeopr.c zport.h tecoc.h defext.h +exep.o: exep.c zport.h tecoc.h defext.h deferr.h +exeprc.o: exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.o: exepw.c zport.h tecoc.h defext.h +exeq.o: exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.o: exeqes.c zport.h tecoc.h defext.h +exer.o: exer.c zport.h tecoc.h defext.h +exerbr.o: exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.o: exertp.c zport.h tecoc.h defext.h deferr.h +exes.o: exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.o: exescl.c zport.h tecoc.h defext.h deferr.h +exet.o: exet.c zport.h tecoc.h defext.h dchars.h +exeu.o: exeu.c zport.h tecoc.h defext.h deferr.h +exeund.o: exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.o: exeusc.c zport.h tecoc.h defext.h dchars.h +exev.o: exev.c zport.h tecoc.h defext.h +exew.o: exew.c zport.h tecoc.h defext.h deferr.h +exex.o: exex.c zport.h tecoc.h defext.h deferr.h +exey.o: exey.c zport.h tecoc.h defext.h deferr.h +exez.o: exez.c zport.h tecoc.h defext.h +findes.o: findes.c zport.h tecoc.h defext.h deferr.h +findqr.o: findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.o: flowec.c zport.h tecoc.h defext.h deferr.h +flowee.o: flowee.c zport.h tecoc.h defext.h deferr.h +flowel.o: flowel.c zport.h tecoc.h defext.h deferr.h +getara.o: getara.c zport.h tecoc.h defext.h deferr.h +getnma.o: getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.o: inccbp.c zport.h tecoc.h defext.h deferr.h +init.o: init.c zport.h tecoc.h defext.h deferr.h +insstr.o: insstr.c zport.h tecoc.h defext.h deferr.h +isradx.o: isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.o: ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.o: makdbf.c zport.h tecoc.h defext.h +makrom.o: makrom.c zport.h tecoc.h defext.h deferr.h +popmac.o: popmac.c zport.h tecoc.h defext.h +pshmac.o: pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.o: pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.o: rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.o: rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.o: readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +readcs.o: dscren.h +replac.o: replac.c zport.h tecoc.h defext.h dchars.h +search.o: search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.o: singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.o: skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.o: srclop.c zport.h tecoc.h defext.h deferr.h +sserch.o: sserch.c zport.h tecoc.h defext.h +tabort.o: tabort.c zport.h tecoc.h +typbuf.o: typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.o: typest.c zport.h tecoc.h defext.h dchars.h +uminus.o: uminus.c zport.h tecoc.h defext.h +wrpage.o: wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.o: zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zosx.o: zosx.c tecoc.h clpars.h dchars.h deferr.h +zlinux.o: defext.h dscren.h vrbmsg.h diff --git a/src/makefile.prj b/src/makefile.prj new file mode 100644 index 0000000..897f0b4 --- /dev/null +++ b/src/makefile.prj @@ -0,0 +1,149 @@ +# +# Mix Power C v1.3.0 make (project) file for Teco-C +# Last updated: 14 November 1989 +# +# compile with: +# +# PC /1 /2 /f- /idir /j /ml /r- /s /t /w /y makefile.prj +# +# /1 (80186+ only) 80186 instructions +# /2 (80286+ only) 80286 instructions +# /f- no floating point +# /idir Power C's include file directory list +# /j default to signed char's +# /ml large memory model (1MB code, 1MB data) +# /r- (debugging only) disable register variables +# /s (debugging only) check for stack overflow +# /t (debugging only) prepare information for CTrace +# /w enable all warnings +# /y show names of functions on screen while compiling +# +# Note: Teco-C doesn't seem to work under Power C v1.3.0. I called +# MIX and they said the 'huge' keyword doesn't work yet (they wanted to +# make it work by Christmas 1989). Teco-C needs 'huge' +# pointers since 'far' pointer addition, subtraction, and comparison +# (which are done all over the place in Teco-C) isn't guaranteed to work +# correctly all the time, whereas, for 'huge' pointers it is. +# +# - Manfred Siemsen +# +tecoc.mix tecoc.c zport.h tecoc.h defext.h deferr.h dscren.h ctype.h dchars.h +baksrc.mix baksrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +bldstr.mix bldstr.c zport.h tecoc.h defext.h deferr.h dchars.h chmacs.h +cmatch.mix cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.mix docjr.c zport.h tecoc.h defext.h deferr.h +doeves.mix doeves.c zport.h tecoc.h defext.h dchars.h +doflag.mix doflag.c zport.h tecoc.h defext.h +echoit.mix echoit.c zport.h tecoc.h defext.h dchars.h +err.mix err.c zport.h tecoc.h defext.h chmacs.h deferr.h dchars.h +exea.mix exea.c zport.h tecoc.h defext.h deferr.h +exeats.mix exeats.c zport.h tecoc.h defext.h +exeb.mix exeb.c zport.h tecoc.h defext.h +exebar.mix exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.mix exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.mix exec.c zport.h tecoc.h defext.h +execcc.mix execcc.c zport.h tecoc.h defext.h deferr.h +execln.mix execln.c zport.h tecoc.h defext.h +execom.mix execom.c zport.h tecoc.h defext.h deferr.h +execrt.mix execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.mix execst.c zport.h tecoc.h defext.h deferr.h +execta.mix execta.c zport.h tecoc.h defext.h dchars.h +exectc.mix exectc.c zport.h tecoc.h defext.h dchars.h +exectd.mix exectd.c zport.h tecoc.h defext.h +execte.mix execte.c zport.h tecoc.h defext.h +execti.mix execti.c zport.h tecoc.h defext.h dchars.h +exectl.mix exectl.c zport.h tecoc.h defext.h dchars.h +exectn.mix exectn.c zport.h tecoc.h defext.h +execto.mix execto.c zport.h tecoc.h defext.h +exectp.mix exectp.c zport.h tecoc.h defext.h +exectq.mix exectq.c zport.h tecoc.h defext.h +exectr.mix exectr.c zport.h tecoc.h defext.h deferr.h +exects.mix exects.c zport.h tecoc.h defext.h +exectt.mix exectt.c zport.h tecoc.h defext.h deferr.h +exectu.mix exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.mix exectv.c zport.h tecoc.h defext.h deferr.h +exectw.mix exectw.c zport.h tecoc.h defext.h deferr.h +exectx.mix exectx.c zport.h tecoc.h defext.h +execty.mix execty.c zport.h tecoc.h defext.h +exectz.mix exectz.c zport.h tecoc.h defext.h +exed.mix exed.c zport.h tecoc.h defext.h deferr.h +exedgt.mix exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.mix exedot.c zport.h tecoc.h defext.h +exedqu.mix exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.mix exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.mix exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.mix exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.mix exeexc.c zport.h tecoc.h defext.h +exeey.mix exeey.c zport.h tecoc.h defext.h +exef.mix exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.mix exefb.c zport.h tecoc.h defext.h deferr.h +exeg.mix exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.mix exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.mix exeh.c zport.h tecoc.h defext.h +exei.mix exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.mix exeill.c zport.h tecoc.h defext.h deferr.h +exej.mix exej.c zport.h tecoc.h defext.h +exek.mix exek.c zport.h tecoc.h defext.h +exel.mix exel.c zport.h tecoc.h defext.h +exelbr.mix exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.mix exelst.c zport.h tecoc.h defext.h deferr.h +exem.mix exem.c zport.h tecoc.h defext.h deferr.h +exen.mix exen.c zport.h tecoc.h defext.h deferr.h +exenul.mix exenul.c zport.h tecoc.h defext.h +exenyi.mix exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.mix exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.mix exeopr.c zport.h tecoc.h defext.h +exep.mix exep.c zport.h tecoc.h defext.h deferr.h +exeprc.mix exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.mix exepw.c zport.h tecoc.h defext.h +exeq.mix exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.mix exeqes.c zport.h tecoc.h defext.h +exer.mix exer.c zport.h tecoc.h defext.h +exerbr.mix exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.mix exertp.c zport.h tecoc.h defext.h deferr.h +exes.mix exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.mix exescl.c zport.h tecoc.h defext.h deferr.h +exet.mix exet.c zport.h tecoc.h defext.h dchars.h +exeu.mix exeu.c zport.h tecoc.h defext.h deferr.h +exeund.mix exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.mix exeusc.c zport.h tecoc.h defext.h dchars.h +exev.mix exev.c zport.h tecoc.h defext.h +exew.mix exew.c zport.h tecoc.h defext.h dscren.h +exex.mix exex.c zport.h tecoc.h defext.h deferr.h +exey.mix exey.c zport.h tecoc.h defext.h deferr.h +exez.mix exez.c zport.h tecoc.h defext.h +findes.mix findes.c zport.h tecoc.h defext.h deferr.h +findqr.mix findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.mix flowec.c zport.h tecoc.h defext.h deferr.h +flowee.mix flowee.c zport.h tecoc.h defext.h deferr.h +flowel.mix flowel.c zport.h tecoc.h defext.h deferr.h +getara.mix getara.c zport.h tecoc.h defext.h deferr.h +getnma.mix getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.mix inccbp.c zport.h tecoc.h defext.h deferr.h +init.mix init.c zport.h tecoc.h defext.h deferr.h +insstr.mix insstr.c zport.h tecoc.h defext.h deferr.h +isradx.mix isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.mix ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.mix makdbf.c zport.h tecoc.h defext.h +makrom.mix makrom.c zport.h tecoc.h defext.h deferr.h +popmac.mix popmac.c zport.h tecoc.h defext.h +pshmac.mix pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.mix pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.mix rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.mix rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.mix readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h \ + dscren.h +replac.mix replac.c zport.h tecoc.h defext.h dchars.h +search.mix search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.mix singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.mix skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.mix srclop.c zport.h tecoc.h defext.h deferr.h +sserch.mix sserch.c zport.h tecoc.h defext.h +typbuf.mix typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.mix typest.c zport.h tecoc.h defext.h dchars.h +uminus.mix uminus.c zport.h tecoc.h defext.h +wrpage.mix wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.mix zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zmsdos.mix zmsdos.c zport.h tecoc.h defext.h chmacs.h clpars.h deferr.h \ + dchars.h dscren.h vrbmsg.h +tecoc.exe diff --git a/src/makefile.sun b/src/makefile.sun new file mode 100644 index 0000000..97f9903 --- /dev/null +++ b/src/makefile.sun @@ -0,0 +1,245 @@ +# +# This makefile builds TECOC on a Sun running the SunOS operating system. +# 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 +# Include files for SunOS 4.0 are different than for 4.1 (4.1's are closer +# to the ANSI Standard). Define OSVERS as -DSUNOS4_0 if you're running +# 4.0, so functions get properly declared (and to keep gcc from bitching). +#OSVERS = -DSUNOS4_0 +# To choose the compiler you want to use, uncomment one of the following +# sets of lines (between here and the line containing all "#" characters). +# If you want to compile with video support, uncomment the following lines, +# which use the System V compiler and compile/link using System V include +# files and libraries. I've found that I get "undefined symbol" errors if I +# don't unsetenv the LD_LIBRARY_PATH environment variable before linking +# with this set of lines. +# +# Note that compiling in video support is a mixed blessing. If you use +# TECO-C exclusively in video mode, there are no problems. If you turn +# video off (using a 0,7:w command) you'll notice that typeout is very slow. +# This is an artifact of curses. To get fast typeout, build TECO-C without +# video (use one of the other sets of lines below). +#CC = /usr/5bin/cc +#CFLAGS = ${OSVERS}${DEBG}${CCHEK} -DCURSES -O -pipe +#TERMOBJS = -lcurses +# If you want to the standard compiler, uncomment the following line. +CFLAGS = $(OSVERS) ${DEBG} ${CCHEK} -O -pipe +TERMOBJS = -ltermcap +# 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 +#TERMOBJS = -ltermcap +#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 \ + exectd.c execte.c execti.c exectl.c exectn.c execto.c exectp.c \ + exectq.c exectr.c exects.c exectt.c exectu.c exectv.c exectw.c \ + exectx.c execty.c exectz.c exed.c exedgt.c exedot.c exedqu.c \ + exee.c exeequ.c exeesc.c exeexc.c exeey.c exef.c exefb.c exeg.c \ + exegtr.c exeh.c exei.c exeill.c exej.c exek.c exel.c exelbr.c \ + exelst.c exem.c exen.c exenul.c exenyi.c exeo.c exeopr.c exep.c \ + exeprc.c exepw.c exeq.c exeqes.c exer.c exerbr.c exertp.c exes.c \ + exescl.c exet.c exeu.c exeund.c exeusc.c exev.c exew.c exex.c \ + exey.c exez.c findes.c findqr.c flowec.c flowee.c flowel.c \ + getara.c getnma.c inccbp.c init.c insstr.c isradx.c ln2chr.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 zunix.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.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 +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 + @echo 'w' >>makedep0 + @cp makefile makefile.bak + @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..." + @-(for i in ${CFILES} ; do \ + ${CPP} -M $$i >> makedep1; done) 2>makedepe + @echo "generating new version of makefile..." + @sed -e 's|: ./|: |' makedep1 > makedep2 + @awk ' { if ($$1 != prev) \ + { print rec; rec = $$0; prev = $$1; } \ + else \ + { if (length(rec $$2) > 70) \ + { print rec; rec = $$0; } \ + else \ + rec = rec " " $$2 \ + } \ + } \ + END { print rec } \ + ' \ + makedep2 >makedep3 + @awk '/:/ {printf "%s\n", $$0}' \ + makedep3 >makedep4 + @sed -e 's|:|:|' makedep4 > makedep5 + @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 +clenup.o: clenup.c zport.h tecoc.h defext.h +cmatch.o: cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.o: docjr.c zport.h tecoc.h defext.h deferr.h +doeves.o: doeves.c zport.h tecoc.h defext.h dchars.h +doflag.o: doflag.c zport.h tecoc.h defext.h +echoit.o: echoit.c zport.h tecoc.h defext.h dchars.h +err.o: err.c zport.h tecoc.h defext.h deferr.h dchars.h +exea.o: exea.c zport.h tecoc.h defext.h deferr.h +exeats.o: exeats.c zport.h tecoc.h defext.h +exeb.o: exeb.c zport.h tecoc.h defext.h +exebar.o: exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.o: exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.o: exec.c zport.h tecoc.h defext.h +execcc.o: execcc.c zport.h tecoc.h defext.h deferr.h +execln.o: execln.c zport.h tecoc.h defext.h +execom.o: execom.c zport.h tecoc.h defext.h deferr.h +execrt.o: execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.o: execst.c zport.h tecoc.h defext.h deferr.h +execta.o: execta.c zport.h tecoc.h defext.h dchars.h +exectc.o: exectc.c zport.h tecoc.h defext.h dchars.h +exectd.o: exectd.c zport.h tecoc.h defext.h +execte.o: execte.c zport.h tecoc.h defext.h +execti.o: execti.c zport.h tecoc.h defext.h dchars.h +exectl.o: exectl.c zport.h tecoc.h defext.h dchars.h +exectn.o: exectn.c zport.h tecoc.h defext.h +execto.o: execto.c zport.h tecoc.h defext.h +exectp.o: exectp.c zport.h tecoc.h defext.h +exectq.o: exectq.c zport.h tecoc.h defext.h +exectr.o: exectr.c zport.h tecoc.h defext.h deferr.h +exects.o: exects.c zport.h tecoc.h defext.h +exectt.o: exectt.c zport.h tecoc.h defext.h deferr.h +exectu.o: exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.o: exectv.c zport.h tecoc.h defext.h deferr.h +exectw.o: exectw.c zport.h tecoc.h defext.h deferr.h +exectx.o: exectx.c zport.h tecoc.h defext.h +execty.o: execty.c zport.h tecoc.h defext.h +exectz.o: exectz.c zport.h tecoc.h defext.h +exed.o: exed.c zport.h tecoc.h defext.h deferr.h +exedgt.o: exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.o: exedot.c zport.h tecoc.h defext.h +exedqu.o: exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.o: exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.o: exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.o: exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.o: exeexc.c zport.h tecoc.h defext.h +exeey.o: exeey.c zport.h tecoc.h defext.h +exef.o: exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.o: exefb.c zport.h tecoc.h defext.h deferr.h +exeg.o: exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.o: exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.o: exeh.c zport.h tecoc.h defext.h +exei.o: exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.o: exeill.c zport.h tecoc.h defext.h deferr.h +exej.o: exej.c zport.h tecoc.h defext.h +exek.o: exek.c zport.h tecoc.h defext.h +exel.o: exel.c zport.h tecoc.h defext.h +exelbr.o: exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.o: exelst.c zport.h tecoc.h defext.h deferr.h +exem.o: exem.c zport.h tecoc.h defext.h deferr.h +exen.o: exen.c zport.h tecoc.h defext.h deferr.h +exenul.o: exenul.c zport.h tecoc.h defext.h +exenyi.o: exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.o: exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.o: exeopr.c zport.h tecoc.h defext.h +exep.o: exep.c zport.h tecoc.h defext.h deferr.h +exeprc.o: exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.o: exepw.c zport.h tecoc.h defext.h +exeq.o: exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.o: exeqes.c zport.h tecoc.h defext.h +exer.o: exer.c zport.h tecoc.h defext.h +exerbr.o: exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.o: exertp.c zport.h tecoc.h defext.h deferr.h +exes.o: exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.o: exescl.c zport.h tecoc.h defext.h deferr.h +exet.o: exet.c zport.h tecoc.h defext.h dchars.h +exeu.o: exeu.c zport.h tecoc.h defext.h deferr.h +exeund.o: exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.o: exeusc.c zport.h tecoc.h defext.h dchars.h +exev.o: exev.c zport.h tecoc.h defext.h +exew.o: exew.c zport.h tecoc.h defext.h deferr.h +exex.o: exex.c zport.h tecoc.h defext.h deferr.h +exey.o: exey.c zport.h tecoc.h defext.h deferr.h +exez.o: exez.c zport.h tecoc.h defext.h +findes.o: findes.c zport.h tecoc.h defext.h deferr.h +findqr.o: findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.o: flowec.c zport.h tecoc.h defext.h deferr.h +flowee.o: flowee.c zport.h tecoc.h defext.h deferr.h +flowel.o: flowel.c zport.h tecoc.h defext.h deferr.h +getara.o: getara.c zport.h tecoc.h defext.h deferr.h +getnma.o: getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.o: inccbp.c zport.h tecoc.h defext.h deferr.h +init.o: init.c zport.h tecoc.h defext.h deferr.h +insstr.o: insstr.c zport.h tecoc.h defext.h deferr.h +isradx.o: isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.o: ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.o: makdbf.c zport.h tecoc.h defext.h +makrom.o: makrom.c zport.h tecoc.h defext.h deferr.h +popmac.o: popmac.c zport.h tecoc.h defext.h +pshmac.o: pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.o: pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.o: rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.o: rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.o: readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +readcs.o: dscren.h +replac.o: replac.c zport.h tecoc.h defext.h dchars.h +search.o: search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.o: singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.o: skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.o: srclop.c zport.h tecoc.h defext.h deferr.h +sserch.o: sserch.c zport.h tecoc.h defext.h +tabort.o: tabort.c zport.h tecoc.h +typbuf.o: typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.o: typest.c zport.h tecoc.h defext.h dchars.h +uminus.o: uminus.c zport.h tecoc.h defext.h +wrpage.o: wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.o: zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zunix.o: zunix.c tecoc.h clpars.h dchars.h deferr.h +zunix.o: defext.h dscren.h vrbmsg.h diff --git a/src/makefile.tc b/src/makefile.tc new file mode 100644 index 0000000..087d61d --- /dev/null +++ b/src/makefile.tc @@ -0,0 +1,359 @@ +# +# MAKEFILE.TC: Borland Make file for TECO-C +# Last updated: 17 July 1990 +# +# Command line: +# +# make -fmakefile.tc [-D80186] [-DALL] [-DINCDIR=?] +# [-DLIBDIR=?] [-DMAP] [-DMODEL=?] +# [-DNODEBUG] [-DTCPP100] +# +# -D80186 +# +# The default is to compile for the 8086. If you have an 80186 or +# an 80286, -D80186 will supposedly enable some 80186 instructions +# like ENTER/LEAVE and PUSH . +# +# I don't think ENTER and LEAVE are generated if a function doesn't +# have any local variables. I think ENTER and LEAVE are slower +# than the standard function entry/exit sequence; but they can +# end up being smaller (?). +# +# PUSH means a number can be pushed directly on +# the stack (ie: PUSH 10) instead of loading the number into a +# register first and then pushing the register (ie MOV AX, 10 ! +# PUSH AX). Saves a minuscule amount of space; and is faster, so +# why not? +# +# -DALL +# +# The default is to compile a TECO-C module and add it to the TECOC.LIB +# library. If you're compiling all the modules from scratch, -DALL will +# compile every module first, then build the TECOC.LIB library which is +# much faster. +# +# -DINCDIR=? +# +# I have my Turbo C libraries in C:\TC\INCLUDE +# +# -DLIBDIR=? +# +# I have my Turbo C libraries in C:\TC\LIB +# +# -DMAP +# +# The default is to not generate a TLINK .MAP file. The CHECKSUM_CODE +# #define in ZPORT.H enables runtime code checksumming to insure that +# code isn't being overwritten by stray pointers. The checksumming +# routines in TECOC.C require a current TLINK C .MAP file in order to +# work, so if you enable the CHECKSUM_CODE option, be sure to compile +# with -DMAP; and be sure you have an up-to-date .MAP file when running +# with code checksumming. Note: CHECKSUM_CODE doesn't work with Turbo +# Debugger since TD modifies code as it runs. +# +# -DMODEL=? +# +# Memory Model macro. '?' is one of the following: +# +# s small (near code, near data) +# c compact (near code, far data) +# m medium (far code, near data) +# l large (far code, far data, 64K static data) +# h huge (far code, far data, 64K static data per module) +# +# If DEBUGGING is TRUE in ZPORT.H you will have to use the large +# or huge model to get large (far) code. If DEBUGGING is FALSE +# in ZPORT.H you can use the compact model to get small (near) code. +# +# Stay with a large (far) data model. TECO-C uses huge pointers and +# we wouldn't want to send a huge pointer to a small data model C +# library routine which expects a near pointer. +# +# There *is* code in ZPORT.H which has been used to allow debugging +# completely under the small data model (look for __SMALL__), although +# there many problems. Do not use the small (near) data models. +# +# -DNODEBUG +# +# The default is to include stack checking (tcc -N, see STKCHK below) +# and Turbo Debugger (tcc -v) code. For production versions of TECO-C +# use -DNODEBUG. This will disable stack checking (tcc -N-), disable +# Turbo Debugger (tcc -v-), enable jump and register optimizations +# (tcc -O -Z), generate for speed (-G), merge duplicate strings +# (tcc -d) and use the Pascal function calling sequence (tcc -p) +# to generate smaller and faster function calls. +# +# Note: this NODEBUG switch has *nothing* to do with the internal +# debugging code enabled by setting DEBUGGING on in ZPORT.H. +# +# -DTCPP100 +# +# There is a conflict in Turbo C++ v1.00 between large model and +# stack checking. If TCPP is defined and we're including TD debugging +# code (implying we're debugging in large model?), then disable stack +# checking. +# + +!if !$d(MODEL) # if no model defined on the command line +!if $d(NODEBUG) # if we're not debugging +MODEL=c # use the compact model +!else # else +MODEL=l # use the large model +!endif # endif +!endif # endif + +!if !$d(LIBDIR) # if no library directory on the command line +LIBDIR=f:\bc4\lib # use my Turbo C library directory +!endif # endif + + +CSTARTUP=$(LIBDIR)\c0$(MODEL) +CLIB=$(LIBDIR)\c$(MODEL) + +# +# TCC options: +# +# -1 80186/286 Instructions (only if you have a 186+) +# -G Generate for speed (not debugging) +# -Idir Include file directory +# -K Default char is unsigned +# -N Check stack overflow (debugging) +# -O Optimize jumps (not debugging) +# -Z Optimize register usage (not debugging) +# -c Compile only +# -d Merge duplicate strings (not debugging) +# -m? memory model (? = c or l) +# -p use Pascal function calls (not deubgging) +# -v Source level debugging (debugging) +# -w Enable all warnings +# + +COMPILE=bcc -c -m$(MODEL) -w -K + +!if $d(NODEBUG) # if we're not debugging +COMPILE=$(COMPILE) -p -O1 # do optimizations +!else # else +COMPILE=$(COMPILE) -v # compile for Turbo Debugger +!if !$d(TCPP100)) # if not TC++ +COMPILE=$(COMPILE) -N # compile for stack checking +!endif # endif +!endif # endif + +!if $d(80186) # if we're on a 80186 or better +COMPILE=$(COMPILE) -1 # enable 80186 code +!endif # endif + +!if $d(INCDIR) +COMPILE=$(COMPILE) -I$(INCDIR) +!endif + + +# +# TLIB options: +# +# /c case sensitive library +# /e create extended dictionary +# + +TLIB_OP=/c + +!if $d(NODEBUG) +TLIB_OP=$(TLIB_OP) /e +!endif + +# +# how to make the TECOC.EXE file +# + +tecoc.exe : tecoc.obj tecoc.lib + bcc -m$(MODEL) -lm tecoc.obj noeh$(MODEL).lib tecoc.lib + + +# +# how to make the TECOC.OBJ module +# + +tecoc.obj : tecoc.c zport.h tecoc.h defext.h deferr.h dscren.h + $(COMPILE) tecoc.c + +# +# what constitutes the TECOC.LIB library +# + +TECOC_OBJS=\ + baksrc.obj bldstr.obj clenup.obj cmatch.obj docjr.obj doeves.obj \ + doflag.obj echoit.obj err.obj exeats.obj exea.obj exebar.obj \ + exebsl.obj exeb.obj execcc.obj execln.obj execom.obj execrt.obj \ + execst.obj execta.obj exectc.obj exectd.obj execte.obj execti.obj \ + exectl.obj exectn.obj execto.obj exectp.obj exectq.obj exectr.obj \ + exects.obj exectt.obj exectu.obj exectv.obj exectw.obj exectx.obj \ + execty.obj exectz.obj exec.obj exedgt.obj exedot.obj exedqu.obj \ + exed.obj exeequ.obj exeesc.obj exeexc.obj exeey.obj exee.obj \ + exefb.obj exef.obj exegtr.obj exeg.obj exeh.obj exeill.obj \ + exei.obj exej.obj exek.obj exelbr.obj exelst.obj exel.obj \ + exem.obj exenul.obj exenyi.obj exen.obj exeopr.obj exeo.obj \ + exeprc.obj exepw.obj exep.obj exeqes.obj exeq.obj exerbr.obj \ + exertp.obj exer.obj exescl.obj exes.obj exet.obj exeund.obj \ + exeusc.obj exeu.obj exev.obj exew.obj exex.obj exey.obj \ + exez.obj findes.obj findqr.obj flowec.obj flowee.obj flowel.obj \ + getara.obj getnma.obj inccbp.obj init.obj insstr.obj isradx.obj \ + ln2chr.obj makdbf.obj makrom.obj popmac.obj pshmac.obj pushex.obj \ + rdline.obj rdpage.obj readcs.obj replac.obj search.obj singlp.obj \ + skpcmd.obj srclop.obj sserch.obj tabort.obj typbuf.obj typest.obj \ + uminus.obj wrpage.obj zfrsrc.obj zmsdos.obj + +# +# how to make the TECOC.LIB library +# + +!if $d(ALL) #build entire library at once + +tecoc.lib : $(TECOC_OBJS) tctlib.rsp + del tecoc.lib + tlib $(TLIB_OP) tecoc.lib @tctlib.rsp + +.c.obj: + $(COMPILE) $*.c + +!else #modules added to library after compile + +tecoc.lib : $(TECOC_OBJS) + +.c.obj: + $(COMPILE) $*.c + tlib $(TLIB_OP) tecoc.lib -+$*.obj + +!endif + +# +# The CHECKSUM_CODE routines use the ZFirst() function in ZFIRST.C +# to get an idea of where the first code module is located in memory +# when TECO-C is loaded. +# + +zfirst.obj : zfirst.c + +# +# the TECOC.LIB library modules. +# + +baksrc.obj : baksrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +bldstr.obj : bldstr.c zport.h tecoc.h defext.h deferr.h dchars.h chmacs.h +clenup.obj : clenup.c zport.h tecoc.h defext.h +cmatch.obj : cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.obj : docjr.c zport.h tecoc.h defext.h deferr.h +doeves.obj : doeves.c zport.h tecoc.h defext.h dchars.h +doflag.obj : doflag.c zport.h tecoc.h defext.h +echoit.obj : echoit.c zport.h tecoc.h defext.h dchars.h +err.obj : err.c zport.h tecoc.h defext.h chmacs.h deferr.h dchars.h +exea.obj : exea.c zport.h tecoc.h defext.h deferr.h +exeats.obj : exeats.c zport.h tecoc.h defext.h +exeb.obj : exeb.c zport.h tecoc.h defext.h +exebar.obj : exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.obj : exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.obj : exec.c zport.h tecoc.h defext.h +execcc.obj : execcc.c zport.h tecoc.h defext.h deferr.h +execln.obj : execln.c zport.h tecoc.h defext.h +execom.obj : execom.c zport.h tecoc.h defext.h deferr.h +execrt.obj : execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.obj : execst.c zport.h tecoc.h defext.h deferr.h +execta.obj : execta.c zport.h tecoc.h defext.h dchars.h +exectc.obj : exectc.c zport.h tecoc.h defext.h dchars.h +exectd.obj : exectd.c zport.h tecoc.h defext.h +execte.obj : execte.c zport.h tecoc.h defext.h +execti.obj : execti.c zport.h tecoc.h defext.h dchars.h +exectl.obj : exectl.c zport.h tecoc.h defext.h dchars.h +exectn.obj : exectn.c zport.h tecoc.h defext.h +execto.obj : execto.c zport.h tecoc.h defext.h +exectp.obj : exectp.c zport.h tecoc.h defext.h +exectq.obj : exectq.c zport.h tecoc.h defext.h +exectr.obj : exectr.c zport.h tecoc.h defext.h deferr.h +exects.obj : exects.c zport.h tecoc.h defext.h +exectt.obj : exectt.c zport.h tecoc.h defext.h deferr.h +exectu.obj : exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.obj : exectv.c zport.h tecoc.h defext.h deferr.h +exectw.obj : exectw.c zport.h tecoc.h defext.h deferr.h +exectx.obj : exectx.c zport.h tecoc.h defext.h +execty.obj : execty.c zport.h tecoc.h defext.h +exectz.obj : exectz.c zport.h tecoc.h defext.h +exed.obj : exed.c zport.h tecoc.h defext.h deferr.h +exedgt.obj : exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.obj : exedot.c zport.h tecoc.h defext.h +exedqu.obj : exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.obj : exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.obj : exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.obj : exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.obj : exeexc.c zport.h tecoc.h defext.h +exeey.obj : exeey.c zport.h tecoc.h defext.h +exef.obj : exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.obj : exefb.c zport.h tecoc.h defext.h deferr.h +exeg.obj : exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.obj : exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.obj : exeh.c zport.h tecoc.h defext.h +exei.obj : exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.obj : exeill.c zport.h tecoc.h defext.h deferr.h +exej.obj : exej.c zport.h tecoc.h defext.h +exek.obj : exek.c zport.h tecoc.h defext.h +exel.obj : exel.c zport.h tecoc.h defext.h +exelbr.obj : exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.obj : exelst.c zport.h tecoc.h defext.h deferr.h +exem.obj : exem.c zport.h tecoc.h defext.h deferr.h +exen.obj : exen.c zport.h tecoc.h defext.h deferr.h +exenul.obj : exenul.c zport.h tecoc.h defext.h +exenyi.obj : exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.obj : exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.obj : exeopr.c zport.h tecoc.h defext.h +exep.obj : exep.c zport.h tecoc.h defext.h deferr.h +exeprc.obj : exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.obj : exepw.c zport.h tecoc.h defext.h +exeq.obj : exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.obj : exeqes.c zport.h tecoc.h defext.h +exer.obj : exer.c zport.h tecoc.h defext.h +exerbr.obj : exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.obj : exertp.c zport.h tecoc.h defext.h deferr.h +exes.obj : exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.obj : exescl.c zport.h tecoc.h defext.h deferr.h +exet.obj : exet.c zport.h tecoc.h defext.h dchars.h +exeu.obj : exeu.c zport.h tecoc.h defext.h deferr.h +exeund.obj : exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.obj : exeusc.c zport.h tecoc.h defext.h dchars.h +exev.obj : exev.c zport.h tecoc.h defext.h +exew.obj : exew.c zport.h tecoc.h defext.h dscren.h +exex.obj : exex.c zport.h tecoc.h defext.h deferr.h +exey.obj : exey.c zport.h tecoc.h defext.h deferr.h +exez.obj : exez.c zport.h tecoc.h defext.h +findes.obj : findes.c zport.h tecoc.h defext.h deferr.h +findqr.obj : findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.obj : flowec.c zport.h tecoc.h defext.h deferr.h +flowee.obj : flowee.c zport.h tecoc.h defext.h deferr.h +flowel.obj : flowel.c zport.h tecoc.h defext.h deferr.h +getara.obj : getara.c zport.h tecoc.h defext.h deferr.h +getnma.obj : getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.obj : inccbp.c zport.h tecoc.h defext.h deferr.h +init.obj : init.c zport.h tecoc.h defext.h deferr.h +insstr.obj : insstr.c zport.h tecoc.h defext.h deferr.h +isradx.obj : isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.obj : ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.obj : makdbf.c zport.h tecoc.h defext.h +makrom.obj : makrom.c zport.h tecoc.h defext.h deferr.h +popmac.obj : popmac.c zport.h tecoc.h defext.h +pshmac.obj : pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.obj : pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.obj : rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.obj : rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.obj : readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h \ + dscren.h +replac.obj : replac.c zport.h tecoc.h defext.h dchars.h +search.obj : search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.obj : singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.obj : skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.obj : srclop.c zport.h tecoc.h defext.h deferr.h +sserch.obj : sserch.c zport.h tecoc.h defext.h +tabort.obj : tabort.c zport.h tecoc.h +typbuf.obj : typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.obj : typest.c zport.h tecoc.h defext.h dchars.h +uminus.obj : uminus.c zport.h tecoc.h defext.h +wrpage.obj : wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.obj : zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zmsdos.obj : zmsdos.c zport.h tecoc.h defext.h chmacs.h clpars.h deferr.h \ + dchars.h dscren.h vrbmsg.h diff --git a/src/makefile.ulx b/src/makefile.ulx new file mode 100644 index 0000000..5a669cd --- /dev/null +++ b/src/makefile.ulx @@ -0,0 +1,245 @@ +# +# This makefile builds TECOC on a Sun running the SunOS operating system. +# 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 +# Include files for SunOS 4.0 are different than for 4.1 (4.1's are closer +# to the ANSI Standard). Define OSVERS as -DSUNOS4_0 if you're running +# 4.0, so functions get properly declared (and to keep gcc from bitching). +#OSVERS = -DSUNOS4_0 +# To choose the compiler you want to use, uncomment one of the following +# sets of lines (between here and the line containing all "#" characters). +# If you want to compile with video support, uncomment the following lines, +# which use the System V compiler and compile/link using System V include +# files and libraries. I've found that I get "undefined symbol" errors if I +# don't unsetenv the LD_LIBRARY_PATH environment variable before linking +# with this set of lines. +# +# Note that compiling in video support is a mixed blessing. If you use +# TECO-C exclusively in video mode, there are no problems. If you turn +# video off (using a 0,7:w command) you'll notice that typeout is very slow. +# This is an artifact of curses. To get fast typeout, build TECO-C without +# video (use one of the other sets of lines below). +#CC = /usr/5bin/cc +#CFLAGS = ${OSVERS}${DEBG}${CCHEK} -DCURSES -O -pipe +TERMOBJS = /usr/lib/termcap.o -lcursesX +# If you want to the standard compiler, uncomment the following line. +CFLAGS = $(OSVERS) ${DEBG} ${CCHEK} -O -pipe +TERMOBJS = -ltermcap +# 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 +#TERMOBJS = -ltermcap +#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 \ + exectd.c execte.c execti.c exectl.c exectn.c execto.c exectp.c \ + exectq.c exectr.c exects.c exectt.c exectu.c exectv.c exectw.c \ + exectx.c execty.c exectz.c exed.c exedgt.c exedot.c exedqu.c \ + exee.c exeequ.c exeesc.c exeexc.c exeey.c exef.c exefb.c exeg.c \ + exegtr.c exeh.c exei.c exeill.c exej.c exek.c exel.c exelbr.c \ + exelst.c exem.c exen.c exenul.c exenyi.c exeo.c exeopr.c exep.c \ + exeprc.c exepw.c exeq.c exeqes.c exer.c exerbr.c exertp.c exes.c \ + exescl.c exet.c exetil.c exeu.c exeund.c exeusc.c exev.c exew.c \ + exex.c exey.c exez.c findes.c findqr.c flowec.c flowee.c flowel.c \ + getara.c getnma.c inccbp.c init.c insstr.c isradx.c ln2chr.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 zunix.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.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 +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 + @echo 'w' >>makedep0 + @cp makefile makefile.bak + @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..." + @-(for i in ${CFILES} ; do \ + ${CPP} -M $$i >> makedep1; done) 2>makedepe + @echo "generating new version of makefile..." + @sed -e 's|: ./|: |' makedep1 > makedep2 + @awk ' { if ($$1 != prev) \ + { print rec; rec = $$0; prev = $$1; } \ + else \ + { if (length(rec $$2) > 70) \ + { print rec; rec = $$0; } \ + else \ + rec = rec " " $$2 \ + } \ + } \ + END { print rec } \ + ' \ + makedep2 >makedep3 + @awk '/:/ {printf "%s\n", $$0}' \ + makedep3 >makedep4 + @sed -e 's|:|:|' makedep4 > makedep5 + @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 +clenup.o: clenup.c zport.h tecoc.h defext.h +cmatch.o: cmatch.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +docjr.o: docjr.c zport.h tecoc.h defext.h deferr.h +doeves.o: doeves.c zport.h tecoc.h defext.h dchars.h +doflag.o: doflag.c zport.h tecoc.h defext.h +echoit.o: echoit.c zport.h tecoc.h defext.h dchars.h +err.o: err.c zport.h tecoc.h defext.h deferr.h dchars.h +exea.o: exea.c zport.h tecoc.h defext.h deferr.h +exeats.o: exeats.c zport.h tecoc.h defext.h +exeb.o: exeb.c zport.h tecoc.h defext.h +exebar.o: exebar.c zport.h tecoc.h defext.h deferr.h +exebsl.o: exebsl.c zport.h tecoc.h defext.h chmacs.h +exec.o: exec.c zport.h tecoc.h defext.h +execcc.o: execcc.c zport.h tecoc.h defext.h deferr.h +execln.o: execln.c zport.h tecoc.h defext.h +execom.o: execom.c zport.h tecoc.h defext.h deferr.h +execrt.o: execrt.c zport.h tecoc.h defext.h chmacs.h deferr.h +execst.o: execst.c zport.h tecoc.h defext.h deferr.h +execta.o: execta.c zport.h tecoc.h defext.h dchars.h +exectc.o: exectc.c zport.h tecoc.h defext.h dchars.h +exectd.o: exectd.c zport.h tecoc.h defext.h +execte.o: execte.c zport.h tecoc.h defext.h +execti.o: execti.c zport.h tecoc.h defext.h dchars.h +exectl.o: exectl.c zport.h tecoc.h defext.h dchars.h +exectn.o: exectn.c zport.h tecoc.h defext.h +execto.o: execto.c zport.h tecoc.h defext.h +exectp.o: exectp.c zport.h tecoc.h defext.h +exectq.o: exectq.c zport.h tecoc.h defext.h +exectr.o: exectr.c zport.h tecoc.h defext.h deferr.h +exects.o: exects.c zport.h tecoc.h defext.h +exectt.o: exectt.c zport.h tecoc.h defext.h deferr.h +exectu.o: exectu.c zport.h tecoc.h defext.h deferr.h dchars.h +exectv.o: exectv.c zport.h tecoc.h defext.h deferr.h +exectw.o: exectw.c zport.h tecoc.h defext.h deferr.h +exectx.o: exectx.c zport.h tecoc.h defext.h +execty.o: execty.c zport.h tecoc.h defext.h +exectz.o: exectz.c zport.h tecoc.h defext.h +exed.o: exed.c zport.h tecoc.h defext.h deferr.h +exedgt.o: exedgt.c zport.h tecoc.h defext.h deferr.h chmacs.h +exedot.o: exedot.c zport.h tecoc.h defext.h +exedqu.o: exedqu.c zport.h tecoc.h defext.h deferr.h chmacs.h +exee.o: exee.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +exeequ.o: exeequ.c zport.h tecoc.h defext.h dchars.h deferr.h +exeesc.o: exeesc.c zport.h tecoc.h defext.h dchars.h +exeexc.o: exeexc.c zport.h tecoc.h defext.h +exeey.o: exeey.c zport.h tecoc.h defext.h +exef.o: exef.c zport.h tecoc.h defext.h chmacs.h deferr.h +exefb.o: exefb.c zport.h tecoc.h defext.h deferr.h +exeg.o: exeg.c zport.h tecoc.h defext.h deferr.h +exegtr.o: exegtr.c zport.h tecoc.h defext.h deferr.h +exeh.o: exeh.c zport.h tecoc.h defext.h +exei.o: exei.c zport.h tecoc.h defext.h dchars.h deferr.h +exeill.o: exeill.c zport.h tecoc.h defext.h deferr.h +exej.o: exej.c zport.h tecoc.h defext.h +exek.o: exek.c zport.h tecoc.h defext.h +exel.o: exel.c zport.h tecoc.h defext.h +exelbr.o: exelbr.c zport.h tecoc.h defext.h deferr.h +exelst.o: exelst.c zport.h tecoc.h defext.h deferr.h +exem.o: exem.c zport.h tecoc.h defext.h deferr.h +exen.o: exen.c zport.h tecoc.h defext.h deferr.h +exenul.o: exenul.c zport.h tecoc.h defext.h +exenyi.o: exenyi.c zport.h tecoc.h defext.h deferr.h +exeo.o: exeo.c zport.h tecoc.h defext.h dchars.h deferr.h +exeopr.o: exeopr.c zport.h tecoc.h defext.h +exep.o: exep.c zport.h tecoc.h defext.h deferr.h +exeprc.o: exeprc.c zport.h tecoc.h defext.h deferr.h +exepw.o: exepw.c zport.h tecoc.h defext.h +exeq.o: exeq.c zport.h tecoc.h defext.h deferr.h +exeqes.o: exeqes.c zport.h tecoc.h defext.h +exer.o: exer.c zport.h tecoc.h defext.h +exerbr.o: exerbr.c zport.h tecoc.h defext.h deferr.h +exertp.o: exertp.c zport.h tecoc.h defext.h deferr.h +exes.o: exes.c zport.h tecoc.h defext.h dchars.h deferr.h +exescl.o: exescl.c zport.h tecoc.h defext.h deferr.h +exet.o: exet.c zport.h tecoc.h defext.h dchars.h +exeu.o: exeu.c zport.h tecoc.h defext.h deferr.h +exeund.o: exeund.c zport.h tecoc.h defext.h deferr.h +exeusc.o: exeusc.c zport.h tecoc.h defext.h dchars.h +exev.o: exev.c zport.h tecoc.h defext.h +exew.o: exew.c zport.h tecoc.h defext.h deferr.h +exex.o: exex.c zport.h tecoc.h defext.h deferr.h +exey.o: exey.c zport.h tecoc.h defext.h deferr.h +exez.o: exez.c zport.h tecoc.h defext.h +findes.o: findes.c zport.h tecoc.h defext.h deferr.h +findqr.o: findqr.c zport.h tecoc.h defext.h deferr.h chmacs.h +flowec.o: flowec.c zport.h tecoc.h defext.h deferr.h +flowee.o: flowee.c zport.h tecoc.h defext.h deferr.h +flowel.o: flowel.c zport.h tecoc.h defext.h deferr.h +getara.o: getara.c zport.h tecoc.h defext.h deferr.h +getnma.o: getnma.c zport.h tecoc.h defext.h deferr.h +inccbp.o: inccbp.c zport.h tecoc.h defext.h deferr.h +init.o: init.c zport.h tecoc.h defext.h deferr.h +insstr.o: insstr.c zport.h tecoc.h defext.h deferr.h +isradx.o: isradx.c zport.h tecoc.h defext.h chmacs.h +ln2chr.o: ln2chr.c zport.h tecoc.h defext.h dchars.h chmacs.h +makdbf.o: makdbf.c zport.h tecoc.h defext.h +makrom.o: makrom.c zport.h tecoc.h defext.h deferr.h +popmac.o: popmac.c zport.h tecoc.h defext.h +pshmac.o: pshmac.c zport.h tecoc.h defext.h deferr.h +pushex.o: pushex.c zport.h tecoc.h defext.h dchars.h deferr.h +rdline.o: rdline.c zport.h tecoc.h defext.h deferr.h dchars.h +rdpage.o: rdpage.c zport.h tecoc.h defext.h deferr.h +readcs.o: readcs.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +readcs.o: dscren.h +replac.o: replac.c zport.h tecoc.h defext.h dchars.h +search.o: search.c zport.h tecoc.h defext.h deferr.h dchars.h +singlp.o: singlp.c zport.h tecoc.h defext.h dchars.h +skpcmd.o: skpcmd.c zport.h tecoc.h defext.h chmacs.h dchars.h deferr.h +srclop.o: srclop.c zport.h tecoc.h defext.h deferr.h +sserch.o: sserch.c zport.h tecoc.h defext.h +tabort.o: tabort.c zport.h tecoc.h +typbuf.o: typbuf.c zport.h tecoc.h defext.h dchars.h chmacs.h +typest.o: typest.c zport.h tecoc.h defext.h dchars.h +uminus.o: uminus.c zport.h tecoc.h defext.h +wrpage.o: wrpage.c zport.h tecoc.h defext.h dchars.h deferr.h +zfrsrc.o: zfrsrc.c zport.h tecoc.h defext.h dchars.h chmacs.h deferr.h +zunix.o: zunix.c tecoc.h clpars.h dchars.h deferr.h +zunix.o: defext.h dscren.h vrbmsg.h diff --git a/src/makrom.c b/src/makrom.c new file mode 100644 index 0000000..62d47ce --- /dev/null +++ b/src/makrom.c @@ -0,0 +1,46 @@ +/***************************************************************************** + MakRom() + This function "makes room" in a q-register text area for new text. +If the text area was empty, this function simply calls ZAlloc to allocate +new memory. If the text area was not empty, this function calls ZRaloc to +add more memory to the text area. In either case, the Amount argument +specifies how much memory to add to the existing text area. + On entry, QR->Start points to the start of the text area (or NULL if +the text area was empty) and QR->End_P1 points to the end of the text area. +On return, QR->Start points to the start of the text area and QR->End_P1 +points to the BEGINNING of the newly allocated memory. This is because the +caller knows where the end is and is expected to reset QR->End_P1 after it +is used as the destination of the new text. + Note: the Amount argument is assumed to be greater than 0. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT MakRom(Amount) /* make room in q-register */ +SIZE_T Amount; /* how much additional room to make */ +{ + ptrdiff_t OldSiz; /* old size of text area */ + charptr NewBlk; /* new text area */ +#if DEBUGGING + static char *DbgFNm = "MakRom"; + sprintf(DbgSBf,"Amount = %ld bytes", (LONG)Amount); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + if (QR->Start == NULL) { /* if it was empty */ + OldSiz = 0; + NewBlk = (charptr)ZAlloc(Amount); + } else { + OldSiz = QR->End_P1 - QR->Start; + NewBlk = (charptr)ZRaloc(QR->Start, OldSiz + Amount); + } + if (NewBlk == NULL) { /* if ZAlloc/ZRaloc failed */ + ErrMsg(ERR_MEM); /* ERR = memory overflow */ + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + QR->Start = NewBlk; + QR->End_P1 = NewBlk + OldSiz; + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/popmac.c b/src/popmac.c new file mode 100644 index 0000000..91329da --- /dev/null +++ b/src/popmac.c @@ -0,0 +1,49 @@ +/***************************************************************************** + PopMac() + This function "pops" the current macro environment, which was +established by an earlier call to the PshMac function. Part of this job +is de-allocating memory consumed by local q-registers. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT PopMac() /* restore environment after macro exit */ +{ + WORD i; + MSptr MSp; /* pointer into the macro stack */ + QRptr QRp; /* pointer into local Q-register table */ + BOOLEAN RetVal; /* TRUE if macro is returning a value */ + DBGFEN(1,"PopMac",NULL); + RetVal = (EStTop > EStBot); + if (RetVal) { /* if macro is returning a value */ + if (GetNmA() == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + } +/* + * restore old environment + */ + MSp = &MStack[MStTop]; + CStBeg = MSp->CStBeg; /* restore old command string start */ + CBfPtr = MSp->CBfPtr; /* restore old command string ptr */ + CStEnd = MSp->CStEnd; /* restore old command string end */ + EStBot = MSp->EStBot; /* restore expression stack bottom */ + EStTop = MSp->EStTop; /* restore expression stack top */ + LStBot = MSp->LStBot; /* restore loop stack bottom */ + LStTop = MSp->LStTop; /* restore loop stack top */ + if (MSp->QRgstr != NULL) { /* local q-registers allocated? */ + for (QRp = MSp->QRgstr, i = 0; i < 36; ++i, ++QRp) { + if (QRp->Start != NULL) { + ZFree((voidptr)QRp->Start); + } + } + ZFree(MSp->QRgstr); + } + --MStTop; +#if DEBUGGING + sprintf(DbgSBf,"%s", (RetVal) ? "PushEx(NArgmt)" : "SUCCESS"); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + return ((RetVal) ? PushEx(NArgmt, OPERAND) : SUCCESS); +} diff --git a/src/problems.txt b/src/problems.txt new file mode 100644 index 0000000..6209824 --- /dev/null +++ b/src/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/src/pshmac.c b/src/pshmac.c new file mode 100644 index 0000000..7589e2e --- /dev/null +++ b/src/pshmac.c @@ -0,0 +1,61 @@ +/***************************************************************************** + PshMac() + This function is called when TECO needs to execute a macro. It saves +several variables which define the "current" command string environment on +the macro stack. It then defines the environment for the macro command +string, so that the macro command can be executed when this function exits. +The PopMac function reverses the effects of this function, redefining the +"current" command string environment. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT PshMac(Start, End) /* push environment for a macro call */ +charptr Start; /* start of new command string */ +charptr End; /* end of new command string, plus one */ +{ + MSptr MSp; /* pointer into the macro stack */ + BOOLEAN NumArg; /* TRUE if there is a number on the stack */ + DBGFEN(1,"PshMac",NULL); + if (++MStTop >= MCS_SIZE) { /* if macro stack is full */ + ErrMsg(ERR_PDO); /* push-down list overflow */ + DBGFEX(1,DbgFNm,"FAILURE, macro stack is full"); + return FAILURE; + } + NumArg = (EStTop != EStBot) && /* if numeric arg and */ + (EStack[EStTop].ElType == OPERAND); /* not a partial expression */ + if (NumArg) { /* if numeric argument */ + if (GetNmA() == FAILURE) { /* get the numeric argument */ + DBGFEX(1,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + } +/* + * save current environment + */ + MSp = &MStack[MStTop]; + MSp->CStBeg = CStBeg; /* save command string beginning */ + MSp->CBfPtr = CBfPtr; /* save command string pointer */ + MSp->CStEnd = CStEnd; /* save command string end */ + MSp->EStBot = EStBot; /* save expression stack bottom */ + MSp->EStTop = EStTop; /* save expression stack top */ + MSp->LStBot = LStBot; /* save loop stack bottom */ + MSp->LStTop = LStTop; /* save loop stack top */ + MSp->QRgstr = NULL; /* no local q-reg table (yet) */ +/* + * setup new environment + */ + CStBeg = CBfPtr = Start; /* set up the new command string */ + CStEnd = End - 1; /* set up the new command string */ + EStBot = EStTop; /* set new expression stack bottom */ + LStBot = LStTop; /* set new loop stack bottom */ + if (NumArg) { /* if we had a numeric argument */ + if (PushEx(NArgmt, OPERAND) == FAILURE) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/purge.c b/src/purge.c new file mode 100644 index 0000000..4c5f0fc --- /dev/null +++ b/src/purge.c @@ -0,0 +1,154 @@ + +#include +#include +#ifdef BSD43 +#include +#else +#include +#endif +/* POSIX specifies sys/dirent.h - could add another define ---*/ +#include +/* usage: purge [-n] files... */ +int plevel; +main(argc,argv) +int argc; +char *argv[]; +{ + char *q; + int fileindex; + fileindex=1; + if (argc==1) { + fprintf(stderr,"usage: purge [-n] files...\n"); + exit(1); + } + plevel = 3; + if (*argv[1]=='-') { + q=argv[1]+1; + plevel = atoi(q); + fileindex++; + } + if (plevel < 1) { + fprintf(stderr,"usage: purge [-n] files...\n"); + exit(1); + } + while(fileindex < argc) { + if (purge(argv[fileindex],plevel)<0) { + fprintf(stderr,"error purging %s\n",argv[fileindex]); + } + fileindex++; + } +} +int purge(target,plevel) +char *target; +int plevel; +{ +/* +maximum version number of target (similar to VMS mechanism) +return +-3 error - problems other than file not found and can't open directory +-2 error - did not find file +-1 error - cannot open directory containing target + 0 file found - no version numbers found + n > 0 version number of highest name;n +*/ + DIR *dirp; + int found = 0; /* file found flag */ + char *ftarget; + int maxver = 0; + char *dirname; +#ifdef BSD43 + struct direct *dp; +#else + struct dirent *dp; +#endif + int n; + char *s; + n = strlen(target); + dirname=(char *)malloc(strlen(target)+4); + ftarget=(char *)malloc(strlen(target)+4); + strcpy(dirname, target); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + strcpy(ftarget,s+1); + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + strcpy(ftarget,s+1); + *s='\0'; + } else { /* must have s==dirname and *s!='/', so current directory */ + strcpy(ftarget,target); + *dirname='.'; *(dirname+1)='\0'; + } + dirp = opendir(dirname); + if (dirp == NULL) { + fprintf(stderr,"\nerror openning directory %s\n",dirname); + free(dirname); + free(ftarget); + return(-1); + } + n=strlen(ftarget); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (strncmp(dp->d_name,ftarget,n) == 0) { + char *suffix = dp->d_name + n; + if (*suffix == '\0') { + found = 1; + if (maxver <= 0) + maxver = 0; + } + if (*suffix == ';') { /* assume no other ; in files */ + int k; + found = 1; + k=atoi(suffix+1); + if (k<=0) { + free(dirname); + free(ftarget); + closedir(dirp); + return(-3); + } + if (k>=maxver) + maxver = k; + } + } + } + closedir(dirp); + if (!found) + return(-2); + if (maxver==0) + return(1); + dirp = opendir(dirname); + if (dirp == NULL) { + fprintf(stderr,"\nerror openning directory %s\n",dirname); + free(dirname); + free(ftarget); + return(-1); + } + n=strlen(ftarget); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (strncmp(dp->d_name,ftarget,n) == 0) { + char *suffix = dp->d_name + n; + if (*suffix == ';') { + int k; + k=atoi(suffix+1); + if (k<=0) { + free(dirname); + free(ftarget); + closedir(dirp); + return(-3); + } + if (k <= maxver - plevel + 1) { + char *st; + st=dp->d_name; + fprintf(stderr,"unlink %s -- ",st); + if(unlink(st)==(-1)) + perror("failed : "); + else + fprintf(stderr,"succeeded"); + fprintf(stderr,"\n"); + } + } + } + } + closedir(dirp); + return(1); +} diff --git a/src/pushex.c b/src/pushex.c new file mode 100644 index 0000000..49e2ca9 --- /dev/null +++ b/src/pushex.c @@ -0,0 +1,162 @@ +/***************************************************************************** + PushEx () + Reduce () + Push an item on the stack and try to reduce it. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +/***************************************************************************** + Reduce() + This function attempts to reduce the expression stack. It is called +by PushEx when the stack has two or more values on it and therefore might be +reduceable. +*****************************************************************************/ +#if USE_PROTOTYPES +static DEFAULT Reduce(void); +#endif +static DEFAULT Reduce() /* reduce the expression stack */ +{ + ESptr ESp1; /* 1st thing on stack (top) */ + ESptr ESp2; /* 2nd thing on stack (top-1) */ + ESptr ESp3; /* 3rd thing on stack (top-2) */ + WORD OnStack; /* number of items on stack */ + LONG x; /* temporary operand */ + LONG y; /* temporary operand */ + FOREVER { /* reduce until you can't reduce anymore */ + OnStack = EStTop - EStBot; + if (OnStack < 0) { /* nothing on stack */ + break; + } + ESp1 = &(EStack[EStTop]); + ESp2 = ESp1 - 1; + ESp3 = ESp2 - 1; + if (OnStack >= 3) { +/* + * if it's x+y, x-y, x*y, x/y, x&y or x#y, reduce it + */ + if (ESp1->ElType == OPERAND && + ESp2->ElType == OPERATOR && + ESp3->ElType == OPERAND && + ESp2->Elemnt != ')' && + ESp2->Elemnt != '(') { + x = ESp3->Elemnt; + y = ESp1->Elemnt; + switch ((char)ESp2->Elemnt) { + case '+': x += y; break; + case '-': x -= y; break; + case '*': x *= y; break; + case '/': x /= y; break; + case '&': x &= y; break; + case '#': x |= y; break; + } + ESp3->Elemnt = x; +/* + * ESp3->ElType is already OPERAND + */ + EStTop -= 2; + continue; + } else { +/* + * if it's (x), reduce it to x + */ + if (ESp1->ElType == OPERATOR && + ESp2->ElType == OPERAND && + ESp3->ElType == OPERATOR && + ESp1->Elemnt == ')' && + ESp3->Elemnt == '(') { + ESp3->Elemnt = ESp2->Elemnt; + ESp3->ElType = OPERAND; + EStTop -= 2; + continue; + } + } + } + if (OnStack >= 2) { +/* + * if it's +x or -x, reduce it to + or - x + */ + if (ESp1->ElType == OPERAND && + ESp2->ElType == OPERATOR && + (ESp2->Elemnt == '+' || ESp2->Elemnt == '-')) { + x = ESp1->Elemnt; + if (ESp2->Elemnt == '-') { + x = -x; + } + ESp2->Elemnt = x; + ESp2->ElType = OPERAND; + --EStTop; + continue; + } + } + if (OnStack >= 1) { +/* + * check for one's complement operator ^_. This operator complements the + * PRECEDING argument. + */ + if (ESp1->ElType == OPERATOR && + ESp1->Elemnt == USCHAR) { + if (OnStack == 1 || ESp2->ElType != OPERAND) { + ErrMsg(ERR_NAB); /* no arg before ^_ */ + return FAILURE; + } + ESp2->Elemnt = ~(ESp2->Elemnt); +/* + * ESp2->ElType is already OPERAND + */ + --EStTop; + continue; + } + } + break; /* can't reduce anymore */ + } + return (SUCCESS); +} +/***************************************************************************** + PushEx() + This function pushes an item onto the expression stack. The +expression stack implement's TECO's expression handling capability. For +instance, if a command like 10+qa=$ is executed, then three values are +pushed onto the expression stack: 10, plus sign and the value of qa. Each +time a value is pushed onto the expression stack, the Reduce function is +called to see if the stack can be reduced. In the above example, Reduce +would cause the stack to be reduced when the value of qa is pushed, because +the expression can be evaluated at that time. +*****************************************************************************/ +DEFAULT PushEx(Item, EType) /* push onto expression stack */ +LONG Item; +DEFAULT EType; +{ +#if DEBUGGING + static char *DbgFNm = "PushEx"; + if (EType == OPERAND) { + sprintf(DbgSBf,"Item = %ld, EType = OPERAND", (LONG)Item); + } else if (EType == OPERATOR) { + sprintf(DbgSBf,"Item = '%c', EType = OPERATOR", (char)Item); + } else { + DbgFEn(3,DbgFNm,"FAILURE, illegal item type"); + TAbort(EXIT_FAILURE); + } + DbgFEn(3,DbgFNm,DbgSBf); +#endif + if (++EStTop >= EXS_SIZE) { /* if expression stack full */ + ErrMsg(ERR_PDO); /* push-down list overflow */ + DBGFEX(3,DbgFNm,"FAILURE, expression stack full"); + return FAILURE; + } + EStack[EStTop].Elemnt = Item; /* put item on stack */ + EStack[EStTop].ElType = EType; /* put item type on stack */ + if (EStTop > (EStBot + 1)) { /* if stack might reduce */ + if (Reduce() == FAILURE) { /* reduce expression stack */ + DBGFEX(3,DbgFNm,"FAILURE, Reduce() failed"); + return FAILURE; + } + } +#if DEBUGGING + sprintf(DbgSBf,"EStTop = %ld, EStBot = %ld", (LONG)EStTop, (LONG)EStBot); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} diff --git a/src/rdline.c b/src/rdline.c new file mode 100644 index 0000000..e1f3422 --- /dev/null +++ b/src/rdline.c @@ -0,0 +1,115 @@ +/***************************************************************************** + RdLine() + This function reads a line from the current input file into the +edit buffer. The input is placed into the edit buffer by appending it +to the edit buffer and adjusting the EBfEnd pointer. IBfEnd points to the +last byte of allocated, unused memory at the end of the edit buffer. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "dchars.h" /* define identifiers for characters */ +/* + * The input buffer needs to be expanded. If there's room in the edit buffer + * gap, then we can shuffle memory to steal some room from the gap. If + * there's still not enough room in the input buffer we re-allocate the + * entire edit/input buffer and then adjust the pointers to reflect the + * reallcatin. If the reallocation fails, set EBfFul to TRUE. + */ +#if USE_PROTOTYPES +static void expand_ibf(BOOLEAN *EBfFul) +#else +static void expand_ibf(EBfFul) +BOOLEAN *EBfFul; /* indicates edit buffer full */ +#endif +{ + SIZE_T TmpSiz; + SIZE_T NewSiz; + charptr NewBeg; + DBGFEN(3,"expabd_ibf",NULL); +/* + * If the size of the edit buffer gap exceeds GAPMIN, make it GAPMIN and + * add the leftover space to the input buffer. + * + * from: EbfBeg...GapBegGapEnd...EBfEnd...IBfEnd + * to: EbfBeg...GapBegGapEnd...EBfEnd...IBfEnd + */ + TmpSiz = GapEnd-GapBeg+1; + if (TmpSiz > GAPMIN) { + TmpSiz -= GAPMIN; + MEMMOVE(GapEnd+1-TmpSiz, GapEnd+1, (SIZE_T)(EBfEnd-GapEnd)); + GapEnd -= TmpSiz; + EBfEnd -= TmpSiz; + } +/* + * If there's still not enough room in the input buffer, expand the input + * buffer by reallocating everything. Since reallocating is expensive, + * take this opportunity to expand it by IBFEXP bytes more than what we + * need. + * + * from: EbfBeg...GapBeg...GapEnd...EBfEndIBfEnd + * to: EbfBeg...GapBeg...GapEnd...EBfEndIBfEnd + */ + TmpSiz = IBfEnd-EBfEnd; + if (TmpSiz < IBFMIN) { + NewSiz = (IBfEnd-EBfBeg+1) + (IBFMIN-TmpSiz) + IBFEXP; +#if DEBUGGING + sprintf(DbgSBf,"ZRaloc-ing EBf, NewSiz = %ld", NewSiz); + DbgFMs(3,DbgFNm,DbgSBf); +#endif + NewBeg = (charptr)ZRaloc(EBfBeg, NewSiz); + if (NewBeg == NULL) { + *EBfFul = TRUE; /* we're full: stop reading lines */ + } else { + if (NewBeg != EBfBeg) { /* if ZRaloc moved us, adjust ptrs */ + GapBeg = NewBeg + (GapBeg - EBfBeg); + GapEnd = NewBeg + (GapEnd - EBfBeg); + EBfEnd = NewBeg + (EBfEnd - EBfBeg); + EBfBeg = NewBeg; + } + IBfEnd = (NewBeg + NewSiz) - 1; + } + } + DBGFEX(3,DbgFNm,NULL); +} +DEFAULT RdLine(EBfFul) /* read a line */ +BOOLEAN *EBfFul; +{ + DEFAULT length; + DBGFEN(3,"RdLine",NULL); + FFPage = 0; /* clear the form-feed flag */ + if (!IsOpnI[CurInp]) { /* if current input stream not open */ + ErrMsg(ERR_NFI); /* NFI = "no file for input" */ + DBGFEX(3,DbgFNm,"FAILURE, no file for input"); + return FAILURE; + } + if (IsEofI[CurInp]) { /* if already at end-of-file */ + DBGFEX(3,DbgFNm,"SUCCESS, already at eof"); + return SUCCESS; + } +/* + * Before trying to read the next line from the input file, we have to be + * sure there's enough room for the record. IBFMIN is the minimum amount of + * room to provide when reading a record. If there's not IBFMIN bytes + * available, we have to get more room. + */ + if ((IBfEnd-EBfEnd) < IBFMIN) { /* if not enough room */ + expand_ibf(EBfFul); + } +/* + * Read the line from the input file. + */ + if (*EBfFul == FALSE) { + if (ZRdLin(EBfEnd+1, IBfEnd-EBfEnd, CurInp, &length) == FAILURE) { + ErrMsg(ERR_URL); /* unable to read line */ + DBGFEX(3,DbgFNm,"FAILURE, ZRdLin() failed"); + return FAILURE; + } + if (!IsEofI[CurInp]) { /* if not end-of-file */ + EBfEnd += length; + } + } + DBGFEX(3,DbgFNm,"SUCCESS, final"); + return SUCCESS; +} diff --git a/src/rdpage.c b/src/rdpage.c new file mode 100644 index 0000000..3fbc5d2 --- /dev/null +++ b/src/rdpage.c @@ -0,0 +1,27 @@ +/***************************************************************************** + RdPage() + This function reads a page from the current input file into the +edit buffer. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT RdPage() /* read a page */ +{ + BOOLEAN EBfFul; + DBGFEN(2,"RdPage",NULL); +/* + * loop, reading until end-of-file or a form feed is encountered, or the + * edit buffer fills up + */ + EBfFul = FALSE; + do { + if (RdLine(&EBfFul) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + } while (!IsEofI[CurInp] && !FFPage && !EBfFul); + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/readcs.c b/src/readcs.c new file mode 100644 index 0000000..9dd4458 --- /dev/null +++ b/src/readcs.c @@ -0,0 +1,640 @@ +/***************************************************************************** + ReadCS() + Read command string. +*****************************************************************************/ +#if CURSES +#if ULTRIX +#include /* has to come before zport.h */ +#else +#include /* has to come before zport.h */ +#endif +#endif +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "chmacs.h" /* define character processing macros */ +#include "deferr.h" /* define identifiers for error messages */ +#include "dscren.h" /* define identifiers for screen i/o */ +#if USE_PROTOTYPES +static VVOID InpDel(void); +static unsigned char FirstChar(void); +static BOOLEAN ChkHlp(charptr HlpEnd); +#endif +/***************************************************************************** + CRCnt maintains a count of the number of carriage returns that have +been typed by the user while entering a command string. It is used to +recognize when the user executes a HELP command, which is the only TECO +command that does not need to be terminated by double escapes. When the very +first carriage return in the user's command string is struck, TECO checks +if the text preceding the carriage return is a valid HELP command. This +checking is only performed when the first carriage return is struck. +*****************************************************************************/ +static LONG CRCnt; /* carriage-return count */ +static charptr Prompt = (charptr)"\n\r*"; +#if CURSES +extern int skiprefresh; +#endif +/***************************************************************************** + InpDel() + This function is called when the user types the DELETE key while +typing in a command string. What is displayed on his terminal when this +happens depends on what kind of terminal he has and what the deleted +character is. This function displays the required character(s). +*****************************************************************************/ +static VVOID InpDel() +{ + int i; + charptr TmpPtr; /* temporary pointer */ + DBGFEN(4, "InpDel", NULL); + --CBfPtr; /* back up over the DEL */ + if (CBfPtr < CBfBeg) { /* if cmd buffer is empty */ + ZDspBf(Prompt, 3); /* prompt */ + DBGFEX(4, DbgFNm, NULL); + return; + } + if (EtFlag & ET_SCOPE) { /* if it's a scope */ + if (((*CBfPtr > USCHAR) && /* if it was ... */ + (*CBfPtr < DELETE)) || /* ... printable or ... */ + (*CBfPtr == ESCAPE) || /* ... escape or ... */ + (*CBfPtr & '\200')) { /* ....eighth bit is on */ + ZDspBf("\b \b", 3); /* erase one character */ + } else { + switch (*CBfPtr) { + case LINEFD: + ZScrOp(SCR_CUP); + /* fall through */ + case DELETE: + break; + case VRTTAB: + case FORMFD: + for (i = 1; i <= FFLINS; i++) + ZScrOp(SCR_CUP); + /* fall through */ + case TABCHR: + case BAKSPC: + case CRETRN: + ZDspCh(CRETRN); + ZScrOp(SCR_EEL); + if (*CBfPtr == CRETRN) { + --CRCnt; + } + TmpPtr = CBfPtr; + while (TmpPtr > CBfBeg) { + TmpPtr--; + if (IsEOL(*TmpPtr)) { + ++TmpPtr; + break; + } + } + if (TmpPtr == CBfBeg) { + ZDspCh('*'); + } + TypBuf(TmpPtr, CBfPtr); + break; + default: + ZDspBf("\b \b\b \b", 6); + break; + } /* end of switch */ + } + } else { /* else (it's not a scope) */ + EchoIt(*CBfPtr); + } + --CBfPtr; /* actually delete the char */ + DBGFEX(4,DbgFNm,NULL); +} +/***************************************************************************** + FirstChar() + This function deals with the following immediate mode commands: + ? display previous command string up to erroneous command + / display verbose explanation of last error + *q copy last command string to q-register q + This function is called by ReadCS to read the very first command +typed by the user. It handles the above immediate mode commands without +destroying the previous command buffer. Once this function returns, the +previous command string and error are considered lost by ReadCS, which then +overwrites the old command string with a new one. + This function does not deal with the LF and BS immediate mode commands +because of the following possible sequence of events: the user starts typing +a command string, then does a ^U to delete it, then tries to use LF or BS +to position himself in the edit buffer. If this function were responsible for +LF and BS, then they would not work. ReadCS is responsible for handling the +LF and BS immediate mode commands. +*****************************************************************************/ +static unsigned char FirstChar() +{ + BOOLEAN ImdCmd; /* TRUE if it's '?' or '*' or '/' */ + unsigned char LclStr[2]; /* local string for * processing */ + DEFAULT Status; /* return value for FindQR() */ + charptr TCBfPt; /* temporary holder of CBfPtr */ + charptr TCStEn; /* temporary holder of CStEnd */ + DEFAULT TmpChr; /* temporary character */ + ptrdiff_t TmpSiz; +#if CURSES + chtype curses_char; + int yy; + int xx; +#endif + do { + if (EvFlag) { /* if EV (edit verify) flag is set */ + DoEvEs(EvFlag); /* handle EV flag */ + } +#if CURSES + if (ScroLn > 0 && !skiprefresh) + redraw(); +#endif + ZDspCh('*'); /* prompt */ +#if CURSES +/* + * This works on a Sun but may be somewhat system dependent - depending on + * the type of chtype + */ + ccs(); + keypad_on(); +l1: getyx(stdscr,yy,xx); + curses_char = ZChIn(FALSE); + TmpChr = curses_char; + if (curses_char == KEY_RIGHT) { + do_right(); + move(yy,xx); + goto l1; + } else if (curses_char == KEY_LEFT) { + do_left(); + move(yy,xx); + goto l1; + } else if (curses_char == KEY_DOWN || curses_char == KEY_B2) { + do_down(); + move(yy,xx); + goto l1; + } else if (curses_char == KEY_UP) { + do_up(); + move(yy,xx); + goto l1; + } else if ((curses_char == KEY_F(1)) || (curses_char == KEY_ENTER)) { + do_seetog(); + move(yy,xx); + goto l1; + } else if ((curses_char == KEY_SF) || (curses_char == KEY_NPAGE)) { + do_sf(); + move(yy,xx); + goto l1; + } else if ((curses_char == KEY_SR) || (curses_char == KEY_PPAGE)) { + do_sr(); + move(yy,xx); + goto l1; + } else if (curses_char >= 0400) { + ZDspCh('?'); + move(yy,xx); + goto l1; + } + keypad_off(); +#else + TmpChr = ZChIn(FALSE); /* get a character */ +#endif + ImdCmd = FALSE; /* assume not an immediate command */ + switch (TmpChr) { + case DELETE: + case CTRL_U: + ZDspCh(CRETRN); + ImdCmd = TRUE; + break; + case '/': /* display verbose error message */ + if (LstErr != ERR_XXX) { + ZDspCh('/'); + ErrVrb(LstErr); + ImdCmd = TRUE; + } + break; + case '?': /* display erroneous command string */ + if (LstErr != ERR_XXX) { /* if there was an error */ + ZDspCh('?'); + TypESt(); + ImdCmd = TRUE; + } + break; + case '*': /* store last cmd string in q-reg */ + ZDspCh('*'); /* echo the "*" */ + TmpChr = ZChIn(FALSE); /* get a q-register name */ + if (GotCtC) { /* user typed control-C? */ + GotCtC = FALSE; + return CTRL_C; + } + switch (TmpChr) { + case CRETRN: + TmpChr = 0; + break; + case DELETE: + case CTRL_U: + case BAKSPC: + ZDspCh(CRETRN); + break; + default: + EchoIt((unsigned char)TmpChr); + TCBfPt = CBfPtr; /* save CBfPtr */ + TCStEn = CStEnd; /* save CStEnd */ + LclStr[0] = (unsigned char)TmpChr; + CBfPtr = &LclStr[0]; + if (TmpChr == (DEFAULT)'.') { + LclStr[1] = (unsigned char)ZChIn(FALSE); + EchoIt((unsigned char)TmpChr); + CStEnd = &LclStr[1]; + } else { + CStEnd = &LclStr[0]; + } + Status = FindQR(); /* find q-register */ + CBfPtr = TCBfPt; /* restore CBfPtr */ + CStEnd = TCStEn; /* restore CStEnd */ + if (Status == SUCCESS) { + if (QR->Start != NULL) { + ZFree((charptr)QR->Start); + QR->Start = QR->End_P1 = NULL; + } + TmpSiz = (CStEnd-CStBeg) + 1; + if (TmpSiz > 0) { + if (MakRom((SIZE_T)TmpSiz) != FAILURE) { + MEMMOVE(QR->Start,CStBeg,(SIZE_T)TmpSiz); + QR->End_P1 = QR->Start + TmpSiz; + } + } + ZDspBf("\r\n", 2); + } + } /* end switch */ + ImdCmd = TRUE; + break; + } /* end switch */ + } while (ImdCmd); + return (unsigned char)TmpChr; +} +/***************************************************************************** + ChkHlp() + This function checks if the command string buffer contains a HELP +command. If it does, the help command is processed and a TRUE is returned. +If the command buffer does not contain a HELP command, a FALSE is returned. +A HELP command must be the only command in the command string. It takes +the form + HELP [/LIBRARY=[=]name] [key-1] [key-2] ... +*****************************************************************************/ +static BOOLEAN ChkHlp(HlpEnd) /* check for HELP command */ +charptr HlpEnd; /* end of help command */ +{ + DBGFEN(3, "ChkHlp", NULL); + if ((*CBfBeg != 'H' && *CBfBeg != 'h') || + (*(CBfBeg+1) != 'E' && *(CBfBeg+1) != 'e') || + (*(CBfBeg+2) != 'L' && *(CBfBeg+2) != 'l') || + (*(CBfBeg+3) != 'P' && *(CBfBeg+3) != 'p')) { + DBGFEX(3, DbgFNm, "FALSE"); + return FALSE; + } + if ((*(CBfBeg+4) != '/') && + (*(CBfBeg+5) != 'S') && (*(CBfBeg+5) != 's')) { + ZHelp(CBfBeg+4, HlpEnd-1, FALSE, TRUE); + } else { + ZHelp(CBfBeg+6, HlpEnd-1, TRUE, TRUE); + } + DBGFEX(3, DbgFNm, "TRUE"); + return TRUE; +} +/***************************************************************************** + ReadCS() +This function reads a command string from the terminal. It returns to it's +caller when the command buffer pointed to by CBfBeg contains a command string. +In addition to echoing the characters typed by the user, this function +handles the following special things: + 1. DEL delete last character + 2. ^G* retype command string + 3. ^G retype command line + 4. ^G^G delete command string + 5. ^U delete command line + 6. ^Z^Z^Z exit TECO-C + 7. LF immediate mode: do a 1L1T command + 8. BS immediate mode: do a -1L1T + 9. *q immediate mode: store last command string in q + 10. HELP immediate mode: access HELP subsystem + 11. / immediate mode: display explanation of last error + 12. ? immediate mode: display erroneous command string +*****************************************************************************/ +#define PRV_CTC 1 /* previous character was control-C */ +#define PRV_CTG 2 /* previous character was control-G */ +#define PRV_DEF 3 /* previous character wasn't ^Z, ^G or ESC */ +#define PRV_ESC 4 /* previous character was escape */ +#define PRV_Z1 5 /* previous character was one control-Z */ +#define PRV_Z2 6 /* previous character was two control-Z */ +VVOID ReadCS() +{ + BOOLEAN BadSeq; /* bad escape sequence indicator */ + unsigned char ctrstr[3]; /* temp buffer to display ^chars as string */ + LONG HowFar; + int PrvChr; /* previous character flags */ + unsigned char TmpChr; /* temporary character */ + charptr TmpPtr; /* temporary pointer */ + int i; + ctrstr[0] = '^'; /* caret */ + ctrstr[2] = '\0'; /* end-of-string */ + CRCnt = 0; /* count of carriage-returns */ + PrvChr = PRV_DEF; /* no previous characters */ + TmpChr = FirstChar(); /* get first character */ + CBfPtr = CBfBeg; /* make command buffer empty */ + *CBfPtr = TmpChr; + LstErr = ERR_XXX; /* last error message is undefined */ + FOREVER { + if (*CBfPtr == ESCAPE) { + if (EtFlag & ET_VT200) { /* if vt200 mode */ + *CBfPtr = (unsigned char)ZChIn(FALSE); + BadSeq = FALSE; /* initialize BadSeq */ + if (*CBfPtr != '[') { /* if not ESC sequence */ + BadSeq = TRUE; + } else { + *CBfPtr = (unsigned char)ZChIn(FALSE); + switch (*CBfPtr) { + case '2': /* f9 - f16 */ + *CBfPtr = (unsigned char)ZChIn(FALSE); + if (*CBfPtr == '4') { + TmpChr = (unsigned char)ZChIn(FALSE); + if (TmpChr != '~') { + BadSeq = TRUE; + } else { + *CBfPtr = BAKSPC; + } + } else if (*CBfPtr == '5') { + TmpChr = (unsigned char)ZChIn(FALSE); + if (TmpChr != '~') { + BadSeq = TRUE; + } else { + *CBfPtr = LINEFD; + } + } else { + BadSeq = TRUE; + } + break; +#if FALSE + case 'A': /* up arrow */ + case 'B': /* down arrow */ + case 'C': /* right arrow */ + case 'D': /* left arrow */ +#endif + default: + BadSeq = TRUE; + } /* end of switch */ + } /* */ + if (BadSeq) { + ZDspBf("\r\n\n\tInvalid escape sequence.\r\n\n", 31); + ZDspBf("\tThe 16384 bit of the ET flag is set, which means\r\n", 52); + ZDspBf("\tthat you are in VT200 mode. In this mode, the\r\n", 50); + ZDspBf("\tescape character is not used to terminate commands.\r\n", 54); + ZDspBf("\tIt is used to introduce escape sequences. This\r\n", 50); + ZDspBf("\tallows the function keys to take on meanings. The\r\n", 53); + ZDspBf("\taccent grave (~) character is the command terminator.\r\n", 56); + ZDspBf("\tIf you want to turn off VT200 mode, say 16384,0ET``\r\n", 55); + ZDspBf("\tNote that the recognition of accent grave as a\r\n", 49); + ZDspBf("\tcommand terminator is controlled by the 8192 bit\r\n", 51); + ZDspBf("\tof the ET flag, separate from the VT200 bit.\r\n\n", 49); + ZDspBf("\tThere may be a part of the unrecognized escape\r\n", 49); + ZDspBf("\tsequence in the command string. The last line of\r\n", 52); + ZDspBf("\tthe command string is shown to help you recover.\r\n", 51); + PrvChr = PRV_CTG; + CBfPtr++; + *CBfPtr = ' '; + } /* end if BadSeq) */ + } else { /* else not vt200 mode */ + ZDspCh('$'); + if (PrvChr == PRV_ESC) { + ZDspBf("\r\n", 2); + CStEnd = CBfPtr; + return; + } + PrvChr = PRV_ESC; + } + } else { /* else *CBfPtr != ESCAPE */ + switch (ChrMsk[(unsigned char)*CBfPtr] & '\17') { + case RCS_LWR: /* lowercase */ + if ((EtFlag & ET_READ_LOWER) == 0) { + *CBfPtr &= '\137'; /* convert to uppercase */ + } + /* fall through */ + case RCS_DEF: /* default case */ + ZDspCh(*CBfPtr); /* echo the character */ + PrvChr = PRV_DEF; + break; + case RCS_GRV: /* accent-grave */ + ZDspCh('`'); + if (EtFlag & ET_ACCENT_GRAVE) { + *CBfPtr = ESCAPE; + if (PrvChr == PRV_ESC) { + ZDspBf("\r\n", 2); + CStEnd = CBfPtr; + return; + } + PrvChr = PRV_ESC; + } else { + PrvChr = PRV_DEF; + } + break; + case RCS_SP: /* space */ + if (PrvChr == PRV_CTG) { /* if previous char was ^G */ + CBfPtr--; /* remove the space */ + TmpPtr = CBfPtr; + while (TmpPtr > CBfBeg) { + TmpPtr--; + if (IsEOL(*TmpPtr)) { + ++TmpPtr; + break; + } + } + ZDspBf("\r\n", 2); + if (TmpPtr == CBfBeg) { + ZDspCh('*'); + } + TypBuf(TmpPtr, CBfPtr); + CBfPtr--; /* remove ^G */ + } else { /* previous char was not ^G */ + ZDspCh(SPACE); /* just echo space */ + } + PrvChr = PRV_DEF; + break; + case RCS_DEL: /* delete */ + InpDel(); + PrvChr = PRV_DEF; + break; + case RCS_CR: /* carriage return */ + ZDspCh(CRETRN); + if ((CRCnt == 0) && ChkHlp(CBfPtr)) { + ZDspCh('*'); + CBfPtr = CBfBeg - 1; + } else { + ++CRCnt; + } + PrvChr = PRV_DEF; + break; + case RCS_LF: /* line feed */ + if (CBfPtr == CBfBeg) { /* if immediate mode */ +#if CURSES + if (ScroLn == 0 || skiprefresh) +#endif + if (EtFlag & ET_SCOPE) { + ZDspCh(CRETRN); + ZScrOp(SCR_EEL); + } + HowFar = Ln2Chr((LONG)1); + MEMMOVE(GapBeg, GapEnd+1, (SIZE_T)HowFar); + GapBeg += HowFar; + GapEnd += HowFar; + if (EvFlag) { + DoEvEs(EvFlag); + } else { +#if CURSES + if (ScroLn == 0 || skiprefresh) +#endif + TypBuf(GapEnd+1, GapEnd+Ln2Chr((LONG)1)+1); + } +#if CURSES + if (ScroLn > 0 || skiprefresh) + dolf(HowFar); + if (ScroLn == 0 || skiprefresh) +#endif + ZDspCh('*'); +#if CURSES + clrtoeol(); +#endif + CBfPtr = CBfBeg - 1; + } else { + ZDspCh(LINEFD); + } + PrvChr = PRV_DEF; + break; + case RCS_CTC: /* control-C */ + GotCtC = FALSE; /* clear "stop soon" flag */ + ctrstr[1] = 'C'; + ZDspBf(ctrstr, 2); /* display "^C" */ + if (PrvChr == PRV_CTC) { /* if second control-C */ + TAbort(EXIT_SUCCESS); /* terminate */ + } else { + PrvChr = PRV_CTC; + } + ZDspBf(Prompt, 3); /* prompt */ + CBfPtr = CBfBeg - 1; /* reset cmd-buffer pointer */ + CRCnt = 0; /* carriage-return cnt = 0 */ + break; + case RCS_BS: /* backspace */ + if (CBfPtr == CBfBeg) { /* if immediate mode */ +#if CURSES + if (ScroLn == 0 || skiprefresh) +#endif + if (EtFlag & ET_SCOPE) { + ZDspCh(CRETRN); + ZScrOp(SCR_EEL); + } + HowFar = Ln2Chr(-1L); + GapBeg += HowFar; + GapEnd += HowFar; + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)-HowFar); + if (EvFlag) { + DoEvEs(EvFlag); + } else { +#if CURSES + if (ScroLn == 0 || skiprefresh) +#endif + TypBuf(GapEnd+1, GapEnd+Ln2Chr((LONG)1)+1); + } +#if CURSES + if (ScroLn > 0 && !skiprefresh) + dobs(HowFar); + if (ScroLn == 0 || skiprefresh) +#endif + ZDspCh('*'); +#if CURSES + clrtoeol(); +#endif + CBfPtr = CBfBeg - 1; + } else { + ZDspCh(BAKSPC); + } + PrvChr = PRV_DEF; + break; + case RCS_CTG: /* control-G */ + ZBell(); /* ring the bell (or flash) */ + ZDspBf("^G", 2); + if (PrvChr == PRV_CTG) { /* if previous char was ^G */ + CBfPtr = CBfBeg - 1; + ZDspBf(Prompt, 3); + CRCnt = 0; + PrvChr = PRV_DEF; + } else { + PrvChr = PRV_CTG; + } + break; + case RCS_AST: /* asterisk */ + ZDspCh('*'); + if (PrvChr == PRV_CTG) { + CBfPtr -= 2; + ZDspBf(Prompt, 3); + CRCnt = 0; + TypBuf(CBfBeg, CBfPtr); + } + PrvChr = PRV_DEF; + break; + case RCS_CTZ: /* control-Z */ + ctrstr[1] = 'Z'; + ZDspBf(ctrstr, 2); + if (PrvChr == PRV_Z2) { + TAbort(EXIT_SUCCESS); + } else if (PrvChr == PRV_Z1) { + PrvChr = PRV_Z2; + } else { + PrvChr = PRV_Z1; + } + break; + case RCS_CCH: /* other control char */ +#if CURSES + if (*CBfPtr == CTRL_W) { + if (CBfPtr == CBfBeg) { + if (ScroLn > 0) { + centre(); + } else { + ZDspBf(Prompt, 3); + } + clrtoeol(); + CBfPtr = CBfBeg - 1; + } else { + ZDspBf("^W", 2); + } + PrvChr = PRV_DEF; + break; + } +#endif + ctrstr[1] = *CBfPtr | '\100'; + ZDspBf(ctrstr, 2); + PrvChr = PRV_DEF; + break; + case RCS_CTU: /* control-U */ + while (--CBfPtr >= CBfBeg) { + if (IsEOL(*CBfPtr)) { + break; + } + } + ZDspCh(CRETRN); + if (EtFlag & ET_SCOPE) { + ZScrOp(SCR_EEL); /* erase line */ + } else { + ZDspCh(LINEFD); + } + if (CBfPtr < CBfBeg) { + ZDspCh('*'); + } + PrvChr = PRV_DEF; + break; + case RCS_VF: /* vert. tab or form feed */ + ZDspCh(CRETRN); + for (i = 1; i <= FFLINS; i++) { + ZDspCh(LINEFD); + } + PrvChr = PRV_DEF; + break; + } /* end of switch */ + } + if (++CBfPtr > CBfEnd) { + ZDspBf("command buffer overflow\r\n", 25); /* ??? */ + TAbort(EXIT_FAILURE); /* exit TECO-C */ + } + *CBfPtr = (unsigned char)ZChIn(FALSE); /* read a character */ + } /* end of FOREVER loop */ +} diff --git a/src/readme.1st b/src/readme.1st new file mode 100644 index 0000000..0bb2d4c --- /dev/null +++ b/src/readme.1st @@ -0,0 +1,63 @@ + TECO-C (version number 146) + + Copyright 1983, 1990 by Pete Siemsen. This software is provided to +you free of charge for your own use. Use it as you see fit; if it doesn't +work, I disclaim all responsibility. You may re-distribute this software +UNCHANGED only if you include this copy-right notice. Alternatively, if +you change this software, you may re-distribute the result only if you +include BOTH this copyright notice, AND an additional notice identifying +you and indicating that you have changed the software. + + This program is still under development. See file PROBLEMS.TXT for +notes I've written to myself about things to do to the program. If you +modify this code to enhance it or fix a bug, please communicate the changes +to me. My address is + + Pete Siemsen + 645 Ohio Avenue #302 + Long Beach, Ca. 90814 + + (213) 433-3059 (home) + (213) 740-7391 (work) + Internet: siemsen@usc.edu + +[NOTE -- This is old information. Better to contact me, Tom Almy, below.] + +******************************************************* + +This archive contains TECO-C modified and compiled for DOS, Win32, +OS/2, and Linux (on Intel 32bit architecture). The modifications have been made by: + + Tom Almy + tomalmy@aracnet.com + +who is a "old time" TECO user. Not only did I port TECO-C but I also +corrected some bugs. For OS/2 modified the file backup algorithm to do +copying rather than renaming as an option. This makes it Workplace +Shell friendly. The Win32, Linux and OS/2 versions allow long file names. + +Included files in this archive: + +readme.1st This file +readme.txt Quick operating instructions for the TECO literate +readme.lnx Operating and install instructions for Linux users +wchart.txt List of all the implemented commands. +teco.doc The official teco reference. TECOC IS CLOSE TO TECO-11 IN FUNCTIONALITY +*.tes TECO command files for various things +*.tec Compressed TECO command files + +These apply to OS/2, DOS, and Windows versions: +inspect.cmd Command files to invoke tecoc +inspect.bat (cmd for OS/2, bat for DOS/Win32) +mung.cmd +mung.bat +teco.cmd +teco.bat +tmake.cmd this would be "make" but most people use the program + "make". +tmake.bat +tecocmd.btm Equivalent aliases for JPSoft products (4DOS, et cetera) + + + +The executable program is downloaded as a separate file. diff --git a/src/readme.lnx b/src/readme.lnx new file mode 100644 index 0000000..e6f2036 --- /dev/null +++ b/src/readme.lnx @@ -0,0 +1,181 @@ +Running TECOC on Linux + +Tecoc takes a first argument of mung, teco, or make to control its +operating mode. In this Linux version, the name of the executable is +tested to provide this first argument. Typically soft links are used +to the tecoc executable, however aliases could be used instead. The +mapping is: + +Make is tecoc make (note uppercase first letter) +teco is tecoc teco +mung is tecoc mung +inspect is tecoc teco -inspect + +The provided TAR file has these four soft links defined. Extract the +TAR file into a directory in your path, typically /usr/local/bin, +after making sure none of the command names already exist for other +applications. Necessary environment variables and files are described below. + +Several option switches are allowed on the TECO command line: + + -in[spect] -- Read file only, don't create an output file. + -noc[reate] -- If file doesn't exist, don't create it. + -noi[ni] -- Don't execute INI file. (valid for MAKE or MUNG as well) + -nom[emory] -- don't save filename as "last edited file" (valid for + MAKE also) + -nop[age] -- Formfeeds don't stop file reads (valid for MAKE also) + -nor[ename] -- Don't rename files, but copy them to keep references correct + (OS/2 only) + +nnn -- sets NOPAGE and positions dot to line nnn. + +The part of the switch name in the square brackets is optional. For +instance "-in" is the same as "-inspect". + +MAKE filespec + + starts tecoc to create file filespec. Does equivalent of EWfilespec$$ + +TECO filespec + + starts tecoc to edit file filespec. Does equivalent of + EBfilespec$Y$ + +TECO filespec2=filespec1 + + starts tecoc to edit filespec1, writing to filespec2. Does + equivalent of ERfilespec1$EWfilespec2$Y$$ + +TECO + + starts tecoc to edit last edited file. Filename is saved in file + named teco*.tmp in the current directory, unless overriden + (described below). + +MUNG filespec + + starts tecoc to execute filespec. Equivalent to + I$JEIfilespec$$ + + You can use "TECO @filespec " instead of MUNG. + +************** +Key Bindings + +The keys mentioned in the teco.doc file are somewhat confusing. +This should help: + + The "Esc" key, "Esc" echoes as "$", however the + teco.doc file shows it as '`'. + Type as Control-h, this isn't the "Backspace" key. + The "Backspace" key. This isn't the "Delete" key. + The "Enter" key. + Type as Control-j. + +Note that the assignments for and shown here are +swapped. can be "Backspace" and can be control-h by +clearing ET&2048, e.g. 2048,0ET + + +************** + +The Initialization File. + +Tecoc mungs (executes as teco commands) the file TECO.INI in the +current directory before processing the command line. Initialization +can be done instead by defining a TEC_INIT environment variable. The +value is either the list of teco commands to execute or a "$" followed +by the pathname of the file containing the initialization file. This +allows a single, centrally located initialization file. REMEMBER that +the "$" must be escaped, i.e. "\$" + +The initialization file can be used to make initial settings. It can +return a value, but the value setting is somewhat obscure. + +Example (csh): +setenv TEC_INIT 1es + +Example (bash): +TEC_INIT=1es +export TEC_INIT + +will cause successful searches to auto-display in all teco sessions. + +************** + +Changing the location of the memory file. + +Define the environment variable TEC_MEMORY to be "$" followed by the +pathname of the file designated the memory file. + +Example (csh): +setenv TEC_MEMORY ~/teco.mem +setenv TEC_MEMORY \$$TEC_MEMORY +Example (bash): +TEC_MEMORY = ~/teco.mem +TEC_MEMORY = \$$TEC_MEMORY +export TEC_MEMORY + +will cause the name of the last edit file to be stored in the file +teco.mem in the home directory. By default the file name is tecoN.tmp in +the current directory, where "N" is the process ID of the parent process to +teco. + + +************** + +The Libary directory + +Defining the environment variable TEC_LIBRARY to be a directory path +(including the final "/") will allow the EI command to fetch +teco commands from this directory if the file is not found in the +current directory. + +Example (csh): +setenv TEC_LIBRARY=\$/usr/local/lib/ + +will cause the directory /usr/local/lib to be searched for teco command files. + + +************** + +Implemented flags: + +ED&1 Allow carat "^" character in string searches +ED&2 Allow yank and _ unconditionally +ED&16 Failed searches preserve dot +ED&64 Move dot by one after each match in multiple occurance searches + +ET&1 Type out in image mode +ET&2 Use scope for delete and control-U (default=1) +ET&4 Accept lowercase input (default=1) +ET&8 ^T reads without echo +ET&32 ^T reads with no wait +ET&128 MUNG mode (abort on error) cleared by "*" prompt +ET&2048 Swap backspace and delete +ET&4096 We are using 8 bit characters (default=1) +ET&32768 Trap control-C + +EZ&1 Mark Henderson, who did much of the Unix port, likes the way + VAX/VMS keeps versions of files. VMS appends a semicolon followed + by a version number to files, and has the PURGE command to clean + out old versions of files. If this bit is off, TECO-C will handle + file version numbers, appending the appropriate version number to + file names. Mark supplied a "purge" program (distributed with TECO-C) + for users of this feature. Setting this flag turns off the feature, + to make TECO-C function as expected by the average Unix user. This + flag is set by default. +EZ&128 Don't stop read on formfeeds +EZ&256 If set, don't do newline translation on file read/write -- binary mode. + TECO is based on separate carriage return (CR) and line feed (LF) + line termination. Normally on file input newline (line feed) + characters are converted to CRLF pairs unless preceded + by a CR -- this allows reading DOS format files. On output CRLF pairs + are converted back to new line characters. Set this bit before starting + to edit a binary file, or when editing a DOS file for which no format + conversion is desired (ie file is saved back in DOS format). +EZ&8192 This bit is set by default, but has no significance in this release. +EZ&16384 Normally the backup file name is created by replacing the file extension + with "bak" -- foo.c becomes foo.bak, however if this bit is set then + the backup file name is created by simply adding ".bak" to the name -- foo.c + becomes foo.c.bak. This choice is overridden by EZ&1 = 0. + diff --git a/src/replac.c b/src/replac.c new file mode 100644 index 0000000..f5e759c --- /dev/null +++ b/src/replac.c @@ -0,0 +1,26 @@ +/***************************************************************************** + Replac() + This function implements "search and replace" commands, like FS and +FN. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT Replac() +{ + DBGFEN(2,"Replac",NULL); + if (Search(TRUE) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if (Matchd) { /* if successful search */ + GapBeg += RefLen; /* delete found string */ + if (InsStr(ArgPtr, CBfPtr-ArgPtr) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/search.c b/src/search.c new file mode 100644 index 0000000..7706f6e --- /dev/null +++ b/src/search.c @@ -0,0 +1,128 @@ +/***************************************************************************** + + Search() + + This function handles most of the special stuff that happens in +search commands (S, N, FS, FN, _, F_, E_, FB and FK). It + + 1. Loads the search buffer (SBfBeg, SBfEnd, SBfPtr) with the text + argument or leaves the search buffer alone if there is no + text argument. + 2. Sets variable NArgmt with the numeric argument or 1 if there + is no numeric argument. + 3. Calls SrcLop to do the basic search loop. + 4. If the search command is colon modified or if the search command + is in a loop and the next character after the search command is + a semicolon, then return appropriately. + 5. If successful search, return successfully but worry about + the ES flag. + 6. If unsuccessful search, return unsuccessfully but worry about + whether we need to skip to the end of a loop or not. + + This function is called by ExeEUn, ExeFB, ExeFK, ExeFN, ExeFS, ExeFUn, +ExeN, ExeS and ExeUnd. Each of those functions sets up the variable SrcTyp +before calling this function to do the search. + +*****************************************************************************/ + +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "dchars.h" /* define identifiers for characters */ + +DEFAULT Search(RepCmd) /* main search code */ +BOOLEAN RepCmd; /* TRUE if the command has two arguments */ +{ + DBGFEN(2,"Search",NULL); + +/* + * If there is a search argument, put it into SBf, otherwise use the + * string from the last search command. + */ + + if (*(CBfPtr+1) == ESCAPE) { /* if it's s$, n$, etc. */ + ++CBfPtr; /* skip the escape */ + } else { + if (BldStr(SBfBeg, SBfEnd, &SBfPtr) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, BldStr() failed"); + return FAILURE; + } + } +/* + * If the search is one of the "search and replace" commands, then parse the + * second argument (the replace string). We need to do this here because we + * may later need to check if a semicolon follows the command, and we need + * to be positioned at the end of the command to do so. + */ + + if (RepCmd) { /* if FC, FN, FS or F_ */ +/* + * If the command is @-modified, then we need to move the command pointer + * back by one. The call to Search will have eaten the first text argument + * of the command, leaving the pointer on the delimiter between the arguments. + * We are about to call FindES, which will call IncCBP to move to the next + * character. Moving back by one cancels the IncCBp. + */ + + if (CmdMod & ATSIGN) { /* if it's at-sign modified */ + --CBfPtr; + } + + if (FindES(ESCAPE) == FAILURE) {/* find end of 2nd argument */ + DBGFEX(2,DbgFNm,"FAILURE, FindES() failed"); + return FAILURE; + } + } + + if (EStTop == EStBot) { /* if no numeric argument */ + NArgmt = 1; /* default is 1S */ + } else { + UMinus(); /* if it's -S, make it -1S */ + if (GetNmA() == FAILURE) { /* get numeric argument */ + DBGFEX(2,DbgFNm,"FAILURE, GetNmA() failed"); + return FAILURE; + } + + if (NArgmt == 0) { /* if it's 0s, 0n, etc. */ + ErrMsg(ERR_ISA); /* illegal search argument */ + DBGFEX(2,DbgFNm,"FAILURE, NArgmt == 0"); + return FAILURE; + } + } + + if (SrcLop() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, SrcLop failed"); + return FAILURE; + } + + if ((CmdMod & COLON) || /* if colon modifier or */ + ((LStTop != LStBot) && /* (in loop and */ + (*(CBfPtr+1) == ';'))) { /* next cmd = ;) */ + if (Matchd) { /* if successful search */ + if (EsFlag&& LStTop == LStBot && MStTop < 0) { + /* if ES flag is set, not in loop or macro */ + DoEvEs(EsFlag); /* handle ES flag */ + } + DBGFEX(2,DbgFNm,"PushEx(-1)"); + return PushEx(-1L, OPERAND); + } else { /* else unsuccessful search */ + DBGFEX(2,DbgFNm,"PushEx(0)"); + return PushEx(0L, OPERAND); + } + } + + if (Matchd) { /* if successful search */ + if (EsFlag&& LStTop == LStBot && MStTop < 0) { + /* if ES flag is set, not in loop and not in macro */ + DoEvEs(EsFlag); /* handle ES flag */ + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; + } else { /* else unsuccessful search */ + *SBfPtr = '\0'; + ErrPSt(ERR_SRH, SBfBeg, SBfPtr);/* "search failure" */ + DBGFEX(2,DbgFNm,(LStTop==LStBot) ? "FAILURE" : "FlowEL()"); + return (LStTop == LStBot) ? FAILURE : FlowEL(); + } +} diff --git a/src/singlp.c b/src/singlp.c new file mode 100644 index 0000000..2cc19cd --- /dev/null +++ b/src/singlp.c @@ -0,0 +1,27 @@ +/***************************************************************************** + SinglP() + This function performs the action of a single P command. It must + 1. write the edit buffer to the output file. + 2. clear the edit buffer + 3. read a page into the edit buffer +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +DEFAULT SinglP() /* do a single P command */ +{ + DBGFEN(2,"SinglP",NULL); + if (WrPage(CurOut, EBfBeg, EBfEnd, FFPage) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, WrPage() failed"); + return FAILURE; + } + GapBeg = EBfBeg; /* clear the... */ + GapEnd = EBfEnd; /* ...edit buffer */ + if (RdPage() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, RdPage() failed"); + return FAILURE; + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/skpcmd.c b/src/skpcmd.c new file mode 100644 index 0000000..385b723 --- /dev/null +++ b/src/skpcmd.c @@ -0,0 +1,398 @@ +/***************************************************************************** + SkpCmd.c +*****************************************************************************/ +#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 "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +#if USE_PROTOTYPES +static DEFAULT SkpArg(void); /* skip command with text argument */ +static DEFAULT SkpCrt(void); /* skip a ^ (caret) command */ +static DEFAULT SkpCtA(void); /* skip control-A command */ +static DEFAULT SkpCtU(void); /* skip control-U command */ +static DEFAULT SkpDAr(void); /* skip "double text argument" command */ +static DEFAULT SkpDqu(void); /* skip a " (double quote) command */ +static DEFAULT SkpE(void); /* skip one of the E commands */ +static DEFAULT SkpExc(void); /* skip command with text argument */ +static DEFAULT SkpF(void); /* skip one of the F commands */ +static DEFAULT SkpOne(void); /* skip one command character */ +static DEFAULT SkpSkp(void); /* */ +#endif +/***************************************************************************** + SkpArg() +*****************************************************************************/ +static DEFAULT SkpArg() /* skip command with text argument */ +{ + BOOLEAN TTrace; /* temp: holds trace flag */ + TTrace = TraceM; /* save trace mode flag */ + TraceM = FALSE; /* keep FindES from tracing */ + if (FindES(ESCAPE) == FAILURE) /* find end of string */ + { + TraceM = TTrace; /* restore trace mode flag */ + return FAILURE; + } + TraceM = TTrace; /* restore trace mode flag */ + CmdMod = '\0'; /* clear modifiers flags */ + return SUCCESS; +} +/***************************************************************************** + SkpCtA() +*****************************************************************************/ +static DEFAULT SkpCtA() /* skip control-A command */ +{ + BOOLEAN TTrace; /* temp: holds trace flag */ + TTrace = TraceM; /* save trace mode flag */ + TraceM = FALSE; /* keep FindES from tracing */ + if (FindES(CTRL_A) == FAILURE) /* find end of string */ + { + TraceM = TTrace; /* restore trace mode flag */ + return FAILURE; + } + TraceM = TTrace; /* restore trace mode flag */ + CmdMod = '\0'; /* clear modifiers flags */ + return SUCCESS; +} +/***************************************************************************** + SkpCtU() +*****************************************************************************/ +static DEFAULT SkpCtU() /* skip control-U command */ +{ + BOOLEAN TTrace; /* temp: holds trace flag */ + if (CBfPtr == CStEnd) + if (MStTop < 0) /* if not in a macro */ + { + ErrUTC(); /* unterminated command */ + return FAILURE; + } + else + return SUCCESS; + ++CBfPtr; + TTrace = TraceM; /* save trace mode flag */ + TraceM = FALSE; /* keep FindES from tracing */ + if (FindES(ESCAPE) == FAILURE) /* find end of string */ + { + TraceM = TTrace; /* restore trace mode flag */ + return FAILURE; + } + TraceM = TTrace; /* restore trace mode flag */ + CmdMod = '\0'; /* clear modifiers flags */ + return SUCCESS; +} +/***************************************************************************** + SkpDAr() +*****************************************************************************/ +static DEFAULT SkpDAr() /* skip "double text argument" command */ +{ + BOOLEAN TTrace; /* saves TraceM temporarily */ + TTrace = TraceM; /* save trace mode flag */ + TraceM = FALSE; /* keep FindES from tracing */ + if (FindES(ESCAPE) == FAILURE) + { + TraceM = TTrace; /* restore trace mode flag */ + return FAILURE; + } + if (CmdMod & ATSIGN) /* if at-sign modified */ + --CBfPtr; + if (FindES(ESCAPE) == FAILURE) + { + TraceM = TTrace; /* restore trace mode flag */ + return FAILURE; + } + TraceM = TTrace; /* restore trace mode flag */ + return SUCCESS; +} +/***************************************************************************** + SkpDqu() +*****************************************************************************/ +static DEFAULT SkpDqu() /* skip a " (double quote) command */ +{ + DBGFEN(3,"SkpDqu",NULL); + if (CBfPtr == CStEnd) /* if end of command string */ + if (MStTop < 0) /* if not in a macro */ + { + ErrUTC(); /* unterminated command */ + return FAILURE; + } + else + return SUCCESS; + ++CBfPtr; + switch (To_Upper(*CBfPtr)) { + case 'A': + case 'C': + case 'D': + case 'E': + case 'F': + case 'U': + case '=': + case 'G': + case '>': + case 'L': + case 'S': + case 'T': + case '<': + case 'N': + case 'R': + case 'V': + case 'W': + break; + default: + ErrMsg(ERR_IQC); /* ill. char. after " */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + CmdMod = '\0'; /* clear modifiers flags */ + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + SkpExc() +*****************************************************************************/ +static DEFAULT SkpExc() /* skip command with text argument */ +{ + BOOLEAN TTrace; /* temp: holds trace flag */ + TTrace = TraceM; /* save trace mode flag */ + TraceM = FALSE; /* keep FindES from tracing */ + if (FindES('!') == FAILURE) /* find end of string */ + { + TraceM = TTrace; /* restore trace mode flag */ + return FAILURE; + } + TraceM = TTrace; /* restore trace mode flag */ + CmdMod = '\0'; /* clear modifiers flags */ + return SUCCESS; +} +/***************************************************************************** + SkpSkp() +*****************************************************************************/ +static DEFAULT SkpSkp() /* */ +{ + CmdMod = '\0'; /* clear ATSIGN modifier */ + return SUCCESS; +} +/***************************************************************************** + SkpF() +*****************************************************************************/ +static DEFAULT SkpF() /* skip one of the F commands */ +{ + if (CBfPtr == CStEnd) + if (MStTop < 0) /* if not in a macro */ + { + ErrUTC(); /* unterminated command */ + return FAILURE; + } + else + return SUCCESS; + ++CBfPtr; + switch (To_Upper(*CBfPtr)) { + case 'S': + case 'N': + case 'C': + case '_': return SkpDAr(); + case 'D': + case 'R': + case 'B': + case 'K': return SkpArg(); + case '>': + case '<': + case '\'': + case '|': return SkpSkp(); + default: + ErrChr(ERR_IFC, *CBfPtr); + return FAILURE; + } +} +/***************************************************************************** + SkpOne() +*****************************************************************************/ +static DEFAULT SkpOne() /* skip one command character */ +{ +#if DEBUGGING + static char *DbgFNm = "SkpOne"; + sprintf(DbgSBf,"*CBfPtr = '%c'", *CBfPtr); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + if (CBfPtr == CStEnd) { + if (MStTop < 0) { /* if not in a macro */ + ErrUTC(); /* unterminated command */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } else { + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + ++CBfPtr; +#if DEBUGGING + sprintf(DbgSBf,"*CBfPtr = '%c'", *CBfPtr); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} +/***************************************************************************** + SkpCrt() +*****************************************************************************/ +static DEFAULT SkpCrt() /* skip a ^ (caret) command */ +{ + static DEFAULT (*FCAray[])(VVOID) = { +/* ^A*/ SkpCtA, /* ^B*/ SkpSkp, /* ^C*/ SkpSkp, /* ^D*/ SkpSkp, +/* ^E*/ SkpSkp, /* ^F*/ SkpSkp, /* ^G*/ SkpSkp, /* ^H*/ SkpSkp, +/*TAB*/ SkpArg, /* LF*/ ExeNul, /* VT*/ SkpSkp, /* FF*/ SkpSkp, +/* CR*/ ExeNul, /* ^N*/ SkpSkp, /* ^O*/ SkpSkp, /* ^P*/ SkpSkp, +/* ^Q*/ SkpSkp, /* ^R*/ SkpSkp, /* ^S*/ SkpSkp, /* ^T*/ SkpSkp, +/* ^U*/ SkpCtU, /* ^V*/ SkpSkp, /* ^W*/ SkpSkp, /* ^X*/ SkpSkp, +/* ^Y*/ SkpSkp, /* ^Z*/ SkpSkp, /* ^[*/ SkpSkp, /* ^\*/ SkpSkp, +/* ^]*/ SkpSkp, /* ^^*/ SkpOne, /* ^_*/ SkpSkp + }; + WORD CDummy; + if (CBfPtr == CStEnd) /* if end of command string */ + if (MStTop < 0) /* if macro stack empty */ + { + ErrUTC(); /* unterminated command */ + return FAILURE; + } + else + return SUCCESS; + ++CBfPtr; + if ((*CBfPtr >= 'A') && (*CBfPtr <= '_')) + CDummy = *CBfPtr - 'A'; + else if (Is_Lower(*CBfPtr)) + CDummy = *CBfPtr - 'a'; /* convert to upper case */ + else { + ErrMsg(ERR_IUC); /* illegal char after ^ */ + return FAILURE; + } + return (*FCAray[CDummy])(); +} +/***************************************************************************** + SkpE() +*****************************************************************************/ +static DEFAULT SkpE() /* skip one of the E commands */ +{ + unsigned char TmpChr; + static DEFAULT (*FEAray[])(VVOID) = { +/* A */ SkpSkp, /* B */ SkpArg, /* C */ SkpSkp, /* D */ SkpSkp, +/* E */ 0, /* F */ SkpSkp, /* G */ SkpArg, /* H */ SkpSkp, +/* I */ SkpArg, /* J */ SkpSkp, /* K */ SkpSkp, /* L */ SkpArg, +/* M */ SkpSkp, /* N */ SkpSkp, /* O */ SkpSkp, /* P */ SkpSkp, +/* Q */ SkpOne, /* R */ SkpArg, /* S */ SkpSkp, /* T */ SkpSkp, +/* U */ SkpSkp, /* V */ SkpSkp, /* W */ SkpArg, /* X */ SkpSkp, +/* Y */ SkpSkp, /* Z */ SkpSkp + }; + if (CBfPtr == CStEnd) + if (MStTop < 0) /* if not in a macro */ + { + ErrUTC(); /* unterminated command */ + return FAILURE; + } + else + return SUCCESS; + ++CBfPtr; + TmpChr = To_Upper(*CBfPtr); + if (TmpChr == '%') + return SkpOne(); + else if (TmpChr == '_') + return SkpArg(); + else if (!Is_Upper(TmpChr) || (TmpChr=='E')) + { + ErrChr(ERR_IEC, *CBfPtr); + return FAILURE; + } + return (*FEAray[TmpChr-'A'])(); +} +/***************************************************************************** + SkpCmd() + This function "skips" TECO commands. It is used when TECO needs to +skip forward under one of these conditions: + 1. flow to the end of a conditional + 2. flow to the else clause of a conditional + 3. flow to the end of a loop + 4. flow while searching for a tag + When this function is called, CBfPtr points to a command. When this +function returns, CBfPtr is left pointing to the last character of the +command. In the case of a command like T, CBfPtr is not changed. In the +case of a command like Stext, CBfPtr is left pointing to the . +*****************************************************************************/ +DEFAULT SkpCmd() /* skip a "command" */ +{ + static DEFAULT (*FSAray[])(VVOID) = { +/*NUL*/ ExeNul, /* ^A*/ SkpCtA, /* ^B*/ SkpSkp, /* ^C*/ SkpSkp, +/* ^D*/ SkpSkp, /* ^E*/ SkpSkp, /* ^F*/ SkpSkp, /* ^G*/ SkpSkp, +/* BS*/ SkpSkp, /*TAB*/ SkpArg, /* LF*/ ExeNul, /* VT*/ SkpSkp, +/* FF*/ SkpSkp, /* CR*/ ExeNul, /* ^N*/ SkpSkp, /* ^O*/ SkpSkp, +/* ^P*/ SkpSkp, /* ^Q*/ SkpSkp, /* ^R*/ SkpSkp, /* ^S*/ SkpSkp, +/* ^T*/ SkpSkp, /* ^U*/ SkpCtU, /* ^V*/ SkpSkp, /* ^W*/ SkpSkp, +/* ^X*/ SkpSkp, /* ^Y*/ SkpSkp, /* ^Z*/ SkpSkp, /*ESC*/ SkpSkp, +/* ^\*/ SkpSkp, /* ^]*/ SkpSkp, /* ^^*/ SkpOne, /* ^_*/ SkpSkp, +/* SP*/ ExeNul, /* ! */ SkpExc, /* " */ SkpDqu, /* # */ SkpSkp, +/* $ */ SkpSkp, /* % */ SkpOne, /* & */ SkpSkp, /* ' */ SkpSkp, +/* ( */ SkpSkp, /* ) */ SkpSkp, /* * */ SkpSkp, /* + */ SkpSkp, +/* , */ SkpSkp, /* - */ SkpSkp, /* . */ SkpSkp, /* / */ SkpSkp, +/* 0 */ SkpSkp, /* 1 */ SkpSkp, /* 2 */ SkpSkp, /* 3 */ SkpSkp, +/* 4 */ SkpSkp, /* 5 */ SkpSkp, /* 6 */ SkpSkp, /* 7 */ SkpSkp, +/* 8 */ SkpSkp, /* 9 */ SkpSkp, /* : */ SkpSkp, /* ; */ SkpSkp, +/* < */ SkpSkp, /* = */ SkpSkp, /* > */ SkpSkp, /* ? */ SkpSkp, +/* @ */ ExeAtS, /* A */ SkpSkp, /* B */ SkpSkp, /* C */ SkpSkp, +/* D */ SkpSkp, /* E */ SkpE, /* F */ SkpF, /* G */ SkpOne, +/* H */ SkpSkp, /* I */ SkpArg, /* J */ SkpSkp, /* K */ SkpSkp, +/* L */ SkpSkp, /* M */ SkpOne, /* N */ SkpArg, /* O */ SkpArg, +/* P */ SkpSkp, /* Q */ SkpOne, /* R */ SkpSkp, /* S */ SkpArg, +/* T */ SkpSkp, /* U */ SkpOne, /* V */ SkpSkp, /* W */ SkpSkp, +/* X */ SkpOne, /* Y */ SkpSkp, /* Z */ SkpSkp, /* [ */ SkpOne, +/* \ */ SkpSkp, /* ] */ SkpOne, /* ^ */ SkpCrt, /* _ */ SkpArg, +/* ` */ SkpSkp, /* a */ SkpSkp, /* b */ SkpSkp, /* c */ SkpSkp, +/* d */ SkpSkp, /* e */ SkpE, /* f */ SkpF, /* g */ SkpOne, +/* h */ SkpSkp, /* i */ SkpArg, /* j */ SkpSkp, /* k */ SkpSkp, +/* l */ SkpSkp, /* m */ SkpOne, /* n */ SkpArg, /* o */ SkpArg, +/* p */ SkpSkp, /* q */ SkpOne, /* r */ SkpSkp, /* s */ SkpArg, +/* t */ SkpSkp, /* u */ SkpOne, /* v */ SkpSkp, /* w */ SkpSkp, +/* x */ SkpOne, /* y */ SkpSkp, /* z */ SkpSkp, /* { */ SkpSkp, +/* | */ SkpSkp, /* } */ SkpSkp, /* ~ */ SkpSkp, /*DEL*/ SkpSkp, +/*129*/ SkpSkp, /*130*/ SkpSkp, /*131*/ SkpSkp, /*132*/ SkpSkp, +/*133*/ SkpSkp, /*134*/ SkpSkp, /*135*/ SkpSkp, /*136*/ SkpSkp, +/*137*/ SkpSkp, /*138*/ SkpSkp, /*139*/ SkpSkp, /*140*/ SkpSkp, +/*141*/ SkpSkp, /*142*/ SkpSkp, /*143*/ SkpSkp, /*144*/ SkpSkp, +/*145*/ SkpSkp, /*146*/ SkpSkp, /*147*/ SkpSkp, /*148*/ SkpSkp, +/*149*/ SkpSkp, /*150*/ SkpSkp, /*151*/ SkpSkp, /*152*/ SkpSkp, +/*153*/ SkpSkp, /*154*/ SkpSkp, /*155*/ SkpSkp, /*156*/ SkpSkp, +/*157*/ SkpSkp, /*158*/ SkpSkp, /*159*/ SkpSkp, /*160*/ SkpSkp, +/*161*/ SkpSkp, /*162*/ SkpSkp, /*163*/ SkpSkp, /*164*/ SkpSkp, +/*165*/ SkpSkp, /*166*/ SkpSkp, /*167*/ SkpSkp, /*168*/ SkpSkp, +/*169*/ SkpSkp, /*170*/ SkpSkp, /*171*/ SkpSkp, /*172*/ SkpSkp, +/*173*/ SkpSkp, /*174*/ SkpSkp, /*175*/ SkpSkp, /*176*/ SkpSkp, +/*177*/ SkpSkp, /*178*/ SkpSkp, /*179*/ SkpSkp, /*180*/ SkpSkp, +/*181*/ SkpSkp, /*182*/ SkpSkp, /*183*/ SkpSkp, /*184*/ SkpSkp, +/*185*/ SkpSkp, /*186*/ SkpSkp, /*187*/ SkpSkp, /*188*/ SkpSkp, +/*189*/ SkpSkp, /*190*/ SkpSkp, /*191*/ SkpSkp, /*192*/ SkpSkp, +/*193*/ SkpSkp, /*194*/ SkpSkp, /*195*/ SkpSkp, /*196*/ SkpSkp, +/*197*/ SkpSkp, /*198*/ SkpSkp, /*199*/ SkpSkp, /*200*/ SkpSkp, +/*201*/ SkpSkp, /*202*/ SkpSkp, /*203*/ SkpSkp, /*204*/ SkpSkp, +/*205*/ SkpSkp, /*206*/ SkpSkp, /*207*/ SkpSkp, /*208*/ SkpSkp, +/*209*/ SkpSkp, /*210*/ SkpSkp, /*211*/ SkpSkp, /*212*/ SkpSkp, +/*213*/ SkpSkp, /*214*/ SkpSkp, /*215*/ SkpSkp, /*216*/ SkpSkp, +/*217*/ SkpSkp, /*218*/ SkpSkp, /*219*/ SkpSkp, /*220*/ SkpSkp, +/*221*/ SkpSkp, /*222*/ SkpSkp, /*223*/ SkpSkp, /*224*/ SkpSkp, +/*225*/ SkpSkp, /*226*/ SkpSkp, /*227*/ SkpSkp, /*228*/ SkpSkp, +/*229*/ SkpSkp, /*230*/ SkpSkp, /*231*/ SkpSkp, /*232*/ SkpSkp, +/*233*/ SkpSkp, /*234*/ SkpSkp, /*235*/ SkpSkp, /*236*/ SkpSkp, +/*237*/ SkpSkp, /*238*/ SkpSkp, /*239*/ SkpSkp, /*240*/ SkpSkp, +/*241*/ SkpSkp, /*242*/ SkpSkp, /*243*/ SkpSkp, /*244*/ SkpSkp, +/*245*/ SkpSkp, /*246*/ SkpSkp, /*247*/ SkpSkp, /*248*/ SkpSkp, +/*249*/ SkpSkp, /*250*/ SkpSkp, /*251*/ SkpSkp, /*252*/ SkpSkp, +/*253*/ SkpSkp, /*254*/ SkpSkp, /*255*/ SkpSkp, /*256*/ SkpSkp + }; + DEFAULT Status; +#if DEBUGGING + static char *DbgFNm = "SkpCmd"; + sprintf(DbgSBf,"*CBfPtr = '%c', at_sign is %s", + *CBfPtr, (CmdMod & ATSIGN) ? "TRUE" : "FALSE"); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + Status = (*FSAray[*CBfPtr])(); +#if DEBUGGING + sprintf(DbgSBf,"*CBfPtr = '%c'", *CBfPtr); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return Status; +} diff --git a/src/srclop.c b/src/srclop.c new file mode 100644 index 0000000..23e8df7 --- /dev/null +++ b/src/srclop.c @@ -0,0 +1,315 @@ +/***************************************************************************** + + SrcLop() + +*****************************************************************************/ + +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ + +/***************************************************************************** + + DoFBFC() + + This function is called only by the SrcLop function, after the +Search function has set up the SBfBeg, SBfEnd, SBfPtr and NArgmt variables. +It is called to handle the special processing needed by the FB and FC +search commands. The FB and FC commands provide TECO's bounded search +capability. + +*****************************************************************************/ + +#if USE_PROTOTYPES +static DEFAULT DoFBFC(void); +#endif + +static DEFAULT DoFBFC() /* search loop */ +{ + ptrdiff_t HowFar; + ptrdiff_t Shuffl; /* how far buffer gap is shuffled */ + +#if DEBUGGING + static char *DbgFNm = "DoFBFC"; + sprintf(DbgSBf,"MArgmt = %ld, NArgmt = %ld", MArgmt, NArgmt); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + + Shuffl = 0; + if (CmdMod & MARGIS) { /* if it's m,nFB or m,nFC */ +/* + * Call GetAra to convert m and n into addresses. A side effect of the call + * to GetAra is that MArgmt and NArgmt are sorted so that MArgmt is less than + * NArgmt. We need to know the original order, so set an indicator variable + * before calling GetAra. + */ + + SIncrm = (MArgmt < NArgmt) ? 1 : -1; + if (GetAra() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, GetAra() failed"); + return FAILURE; + } + +/* + * If the edit buffer gap falls between m and n, we need to shuffle part of + * the edit buffer to make the m,n area contiguous. The gap is shuffled so + * that it is before the m,n area, so that if part of the match string lies + * beyond the n boundary, it can still be matched. + */ + + if ((AraBeg < GapBeg) && (AraEnd > GapEnd)) { + Shuffl = AraEnd - GapEnd; + GapBeg -= Shuffl; + GapEnd -= Shuffl; + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)Shuffl); + } + +/* + * set the variables for the call to SSerch + */ + + if (SIncrm == 1) { /* forward search */ + EBPtr1 = (Shuffl!=0 ? GapEnd + 1 : AraBeg); + EndSAr = AraEnd; + } else { /* else backward search */ + EBPtr1 = AraEnd; + EndSAr = (Shuffl!=0 ? GapEnd + 1 : AraBeg); + } + RhtSid = EBfEnd; + } else { /* else it's nFB or nFC */ + if (NArgmt > 0) { /* forward search */ + SIncrm = 1; + EBPtr1 = GapEnd + 1; + EndSAr = GapEnd + Ln2Chr(NArgmt); + RhtSid = EBfEnd; + } else { /* else backward search */ + SIncrm = -1; + EBPtr1 = GapBeg - 1; + EndSAr = GapBeg + Ln2Chr(NArgmt); + RhtSid = GapBeg - 1; + } + } + + + if (SSerch() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, SSerch() failed"); + return FAILURE; + } + +/* + * If the search succeeded, position the gap to the end of the found string. + */ + + if (Matchd) { /* if search succeeded */ + if (EBPtr2 >= GapEnd) { /* if match after gap */ + HowFar = EBPtr2 - GapEnd; + MEMMOVE(GapBeg, GapEnd+1, (SIZE_T)HowFar); + GapBeg += HowFar; + GapEnd += HowFar; + } else { + HowFar = (GapBeg-1) - EBPtr2; + GapBeg -= HowFar; + GapEnd -= HowFar; + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)HowFar); + } + } else { /* else search failed */ + +/* + * If the edit buffer gap was shuffled earlier (because the gap fell into the + * m,n area), then we need to reverse shuffle it to leave things as they + * were. + */ + + if (Shuffl != 0) { /* if buffer was shuffled */ + MEMMOVE(GapBeg, GapEnd+1, (SIZE_T)Shuffl); + GapBeg += Shuffl; + GapEnd += Shuffl; + } + } +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, Matchd = %s", (Matchd) ? "TRUE" : "FALSE"); + DbgFEx(2,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} + + + +/***************************************************************************** + + SrcLop() + + This function is called by the Search function only, after the +Search function has set up the search string buffer (SBfBeg, SBfEnd, SBfPtr) +and the iteration count (NArgmt). It sets up the edit buffer bounds for the +search (EBPtr1, EndSAr) and direction indicator (SIncrm) and then calls +the SSerch function. One way to describe this function is that it handles +the numeric arguments of all search commands by handling m,n arguments or +actually doing the loop for n arguments. + +*****************************************************************************/ + +DEFAULT SrcLop() /* search loop */ +{ + ptrdiff_t HowFar; + +#if DEBUGGING + static char *DbgFNm = "SrcLop"; + sprintf(DbgSBf,"search string SBf = \"%.*s\"", + (int)(SBfPtr-SBfBeg), SBfBeg); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + + if (SrcTyp == FB_SEARCH) { /* if it's FB or FC */ + DBGFEX(2,DbgFNm,"returning DoFBFC()"); + return DoFBFC(); + } + +/* + * It's not an FB or FC search. The FB and FC commands are the only ones + * which can be preceded by an m,n argument pair. Other search commands + * can be preceded only by an iteration count. + */ + + if (NArgmt > 0) { /* if forwards search */ + SIncrm = 1; + EBPtr1 = GapEnd; + EndSAr = RhtSid = EBfEnd; + do { + EBPtr1++; + if (SSerch() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, SSerch() failed"); + return FAILURE; + } + + if (Matchd) { /* if search succeeded */ + --NArgmt; + if ((EdFlag & ED_DOT_BY_ONE) == 0) + EBPtr1 = EBPtr2; /* skip found string */ + } else { /* else search failed */ + switch (SrcTyp) { + case S_SEARCH: + case FK_SEARCH: + NArgmt = 0; /* exit loop */ + break; + + case N_SEARCH: + if (IsEofI[CurInp]) { + if (WrPage(CurOut,EBfBeg, + EBfEnd,FFPage) == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, WrPage() failed"); + return FAILURE; + } + GapBeg = EBfBeg; /* clear the.. */ + GapEnd = EBfEnd; /* ..edit buffer */ + NArgmt = 0; /* exit loop */ + } else { /* else not end-of-file */ + if (SinglP() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, SinglP() failed"); + return FAILURE; + } + EBPtr1 = GapEnd + 1; + EndSAr = RhtSid = EBfEnd; + } + break; + case U_SEARCH: + if (((EdFlag & ED_YANK_OK) == 0) && + (IsOpnO[CurOut]) && + ((GapBeg != EBfBeg) || (GapEnd != EBfEnd))) { + ErrMsg(ERR_YCA); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + /* FALL THROUGH */ + case E_SEARCH: + GapBeg = EBfBeg; /* clear the... */ + GapEnd = EBfEnd; /* ...edit buffer */ + if (IsEofI[CurInp]) { /* if end-of-file */ + NArgmt = 0; /* exit loop */ + } else { + if (RdPage() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + EBPtr1 = GapEnd + 1; + EndSAr = RhtSid = EBfEnd; + } + } /* end of switch */ + } + } while (NArgmt > 0); + } else { /* else backwards search */ + SIncrm = -1; + EBPtr1 = RhtSid = GapBeg; /* start point */ + RhtSid--; + EndSAr = EBfBeg; /* end point */ + do { + EBPtr1--; + if (SSerch() == FAILURE) { + DBGFEX(2,DbgFNm,"FAILURE, SSerch() failed"); + return FAILURE; + } + + if (Matchd) { + ++NArgmt; + } else { + if ((SrcTyp==S_SEARCH) || (SrcTyp==FK_SEARCH)) { + break; + } else { + DBGFEX(2,DbgFNm,"ExeNYI()"); + return ExeNYI(); + } + } + } while (NArgmt < 0); + } + +/* The next block of code deals with what happens to the edit buffer after + * the search. There are three possibilities: + * + * if the search was successful + * if it's an FK command + * delete spanned characters + * else + * move to after the found string + * else + * move to the start of the edit buffer + * + */ + + if (Matchd) { /* if search succeeded */ + if (SrcTyp == FK_SEARCH) { /* if FK command */ + if (SIncrm == 1) { /* if forward search */ + GapEnd = EBPtr2; /* delete */ + } else { /* else backward */ + GapBeg = EBPtr1; /* delete */ + if (EBPtr2 > GapEnd) + GapEnd = EBPtr2; + } + } else { /* else not FK */ + if ((SIncrm == 1) || (EBPtr2 > GapEnd)) { + HowFar = EBPtr2 - GapEnd; + MEMMOVE(GapBeg, GapEnd+1, (SIZE_T)HowFar); + GapBeg += HowFar; + GapEnd += HowFar; + } else { + HowFar = (GapBeg-1) - EBPtr2; + GapBeg -= HowFar; + GapEnd -= HowFar; + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)HowFar); + } + } + } else { /* else search failed */ + if ((EdFlag & ED_PRES_DOT) == 0) { /* if don't preserve dot */ + HowFar = GapBeg - EBfBeg; + GapBeg -= HowFar; + GapEnd -= HowFar; + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)HowFar); + } + } + +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, Matchd = %s", (Matchd) ? "TRUE" : "FALSE"); + DbgFEx(2,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} diff --git a/src/sserch.c b/src/sserch.c new file mode 100644 index 0000000..028304d --- /dev/null +++ b/src/sserch.c @@ -0,0 +1,102 @@ +/***************************************************************************** + SSerch() + This function does a "simple" search. It is passed a direction +and the starting and ending addresses of the contiguous area to be searched. +It sets Matchd, which indicates whether the search was successful or not. +If it was successful, EBPtr2 is left pointing to the last character of the +found string. Note that if the direction is backwards, the address of the +beginning of the search area will be greater than the address of the end of +the search area. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +DEFAULT SSerch() /* search for 1 occurrence of a string */ +{ + BOOLEAN SamChr; /* same character indicator */ +#if DEBUGGING + static char *DbgFNm = "SSerch"; + sprintf(DbgSBf,"SIncrm = %ld, EBPtr1 = %ld, EndSAr = %ld", + SIncrm, Zcp2ul(EBPtr1), Zcp2ul(EndSAr)); + DbgFEn(3,DbgFNm,DbgSBf); + sprintf(DbgSBf,"search string SBf = \"%.*s\"", + (int)(SBfPtr-SBfBeg), SBfBeg); + DbgFMs(3,DbgFNm,DbgSBf); +#endif + if (SBfPtr == SBfBeg) { /* if null search string */ + Matchd = FALSE; + DBGFEX(3,DbgFNm,"SUCCESS, Matchd = FALSE"); + return SUCCESS; + } + FOREVER { + SStPtr = SBfBeg; +/* + * find a character which matches the first + * character of the search string + */ + if (SIncrm == 1) { /* if forward search */ + if (ZFrSrc() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, ZFrSrc() failed"); + return FAILURE; + } + if (EBPtr1 > EndSAr) { /* if not found */ + Matchd = FALSE; + DBGFEX(3,DbgFNm,"SUCCESS, Matchd = FALSE"); + return SUCCESS; + } + } else { + if (BakSrc() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, BakSrc() failed"); + return FAILURE; + } + if (EBPtr1 < EndSAr) { /* if not found */ + Matchd = FALSE; + DBGFEX(3,DbgFNm,"SUCCESS, Matchd = FALSE"); + return SUCCESS; + } + } +/* + * first char is matched, now check rest of search string + */ + do { + if (++SStPtr == SBfPtr) { /* if no more to check */ + RefLen = (EBPtr1 - EBPtr2) - 1; + if ((SIncrm == -1) && (EBPtr2 >= GapEnd)) { + RefLen += GapEnd-GapBeg+1; + } + Matchd = TRUE; + DBGFEX(3,DbgFNm,"SUCCESS, Matchd = TRUE"); + return SUCCESS; + } + if (++EBPtr2 > RhtSid) { /* inc and check for eob */ + if (SIncrm == -1) { + if (EBPtr2 < GapEnd) EBPtr2 = GapEnd+1; + } else { + Matchd = FALSE; + DBGFEX(3,DbgFNm,"SUCCESS, Matchd = FALSE"); + return SUCCESS; + } + } + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, CMatch() failed"); + return FAILURE; + } + } while (SamChr); +/* + * string only partially matched, so keep looking + */ + if (SIncrm == 1) { /* if forward search */ + if (++EBPtr1 > EndSAr) { + Matchd = FALSE; + DBGFEX(3,DbgFNm,"SUCCESS, Matchd = FALSE"); + return SUCCESS; + } + } else { + if (--EBPtr1 < EndSAr) { + Matchd = FALSE; + DBGFEX(3,DbgFNm,"SUCCESS, Matchd = FALSE"); + return SUCCESS; + } + } + } /* end of FOREVER loop */ +} diff --git a/src/tabort.c b/src/tabort.c new file mode 100644 index 0000000..f869051 --- /dev/null +++ b/src/tabort.c @@ -0,0 +1,13 @@ +/***************************************************************************** + TAbort() + This function cleans up and terminates TECO-C. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +VVOID TAbort(tstat) /* terminate TECO-C */ +DEFAULT tstat; +{ + DBGFEN(2,"TAbort",NULL); + ClenUp(); /* close files, memory, etc. */ + ZExit(tstat); /* terminate with given status */ +} diff --git a/src/tecoc.c b/src/tecoc.c new file mode 100644 index 0000000..f241299 --- /dev/null +++ b/src/tecoc.c @@ -0,0 +1,1095 @@ +/***************************************************************************** + TECO-C (version number is defined as TVERSION in file TECOC.H) + Copyright 1983, 1990 by Pete Siemsen. This software is provided to +you free of charge for your own use. Use it as you see fit; if it doesn't +work, I disclaim all responsibility. You may re-distribute this software +UNCHANGED only if you include this copy-right notice. Alternatively, if +you change this software, you may re-distribute the result only if you +include BOTH this copyright notice, AND an additional notice identifying +you and indicating that you have changed the software. + This program is still under development. See file PROBLEMS.TXT for +notes I've written to myself about things to do to the program. If you +modify this code to enhance it or fix a bug, please communicate the changes +to me. My address is + Pete Siemsen + 645 Ohio Avenue #302 + Long Beach, Ca. 90814 + (213) 433-3059 (home) + (213) 740-7391 (work) + Internet: siemsen@usc.edu + The file PG.MEM (programmer's guide) contains documentation explaining +algorithms used in TECO-C. File PROBLEMS.TXT is a notes file listing ideas +and known bugs. + Global variable declarations for system-independent variables are +in this file. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "deferr.h" /* define identifiers for error messages */ +#include "dscren.h" /* define UNTERM */ +/***************************************************************************** + Test for inconsistencies in the identifiers defined in the include +files. The ANSI C way to complain is to use #error, but some compilers +will complain even when the tests succeed, because they don't recognize the +#error directive while they scan for #endif. The goofy "include" statements +are used to generate a compile-time error. +*****************************************************************************/ +#if GAPMIN > EBFINIT +#include ">>> GAPMIN can't be greater than EBFINIT <<<" +#endif +#if IBFMIN > IBFINIT +#include ">>> IBFMIN can't be greater than IBFINIT <<<" +#endif +#if IBFEXP < IBFMIN +#include ">>> IBFEXP can't be less than IBFMIN <<<" +#endif +#if NIFDBS < 3 +#include ">>> NIFDBS can't be less than 3 <<<" +#endif +#if ZBFEXP < ZBFMIN +#include ">>> ZBFEXP can't be less than ZBFMIN <<<" +#endif +/***************************************************************************** + These pointers point to the first and last characters in an "area", +which is specified when an m,n argument pair precedes a TECO command. For +instance, when the command 10,25T is executed, the GetAra function is called +to set these pointers, which are then used to display the text. +*****************************************************************************/ +GLOBAL charptr AraBeg; /* start of m,n area */ +GLOBAL charptr AraEnd; /* end of m,n area */ +/***************************************************************************** + ArgPtr points to the first character of the text argument associated +with a TECO-C command. It is set by the FindES (find end-of-string) function. +When a command that has a text argument is executed, FindES is called to +locate the end of the text argument. FindES moves the command pointer CBfPtr +to the end of the text argument, and remembers where the beginning was using +ArgPtr. +*****************************************************************************/ +GLOBAL charptr ArgPtr; /* start of text argument of a cmd */ +/***************************************************************************** + These variables point to the beginning and end of the command string +buffer. Memory for the command string buffer is allocated in the MemIni +function. CBfBeg always points to this buffer, but CStBeg changes when an M +or EI command is executed. +*****************************************************************************/ +GLOBAL charptr CBfBeg; /* command buffer beginning */ +GLOBAL charptr CBfEnd; /* command buffer end */ +/***************************************************************************** + CBfPtr is the command string buffer pointer, which moves across a +command string as it is executed. CBfPtr usually points into the command +string buffer pointed to by CBfBeg, but it points elsewhere when an M or EI +command is being executed. +*****************************************************************************/ +GLOBAL charptr CBfPtr; /* command buffer pointer */ +/***************************************************************************** + When TECO-C is executing a command string, it looks at each command +(1 or 2 characters) and calls a function to implement the command. Some +commands can be modified by preceding the command with a modifier character. +CmdMod contains bits which are set when a modifier character is "executed". +This variable is cleared by most commands before they successfully return. +The bits in CmdMod relate to the at-sign (@), colon (:), double-colon (::) +modifiers. There is also a bit which indicates that a command has 2 numeric +arguments separated by a comma. +*****************************************************************************/ +GLOBAL char CmdMod; +/***************************************************************************** + These variables point to the beginning and end of the executing +command string, whether that command string is in the command buffer, a +q-register or the EI buffer. +*****************************************************************************/ +GLOBAL charptr CStBeg; /* start of command string */ +GLOBAL charptr CStEnd; /* end of command string */ +/***************************************************************************** + CurInp and CurOut are indices into the IFiles and OFiles arrays, +respectively. They indicate the entries for the current input stream and +current output stream. +*****************************************************************************/ +GLOBAL DEFAULT CurInp = PINPFL; +GLOBAL DEFAULT CurOut = POUTFL; +/***************************************************************************** + These variables point to the digit buffer. When TECO-C needs to +convert a binary number into an ASCII string, the string is generated in this +buffer. The buffer is large enough to hold the largest integer represented +by 32 bits, plus an optional sign and maybe a carriage-return/line-feed pair. +*****************************************************************************/ +GLOBAL charptr DBfBeg; /* digit buffer */ +GLOBAL charptr DBfPtr; /* digit buffer pointer */ +/***************************************************************************** + These variables point to the first and last characters in the edit +buffer. See file PG.MEM for a description of memory management. +*****************************************************************************/ +GLOBAL charptr EBfBeg; /* first character in edit buffer */ +GLOBAL charptr EBfEnd; /* last character in edit buffer */ +/***************************************************************************** + EBPtr1 is used when a search is being performed. It is adjusted when +the edit buffer is being scanned for the first character of the search string. +When a search command succeeds, this pointer is left pointing to the first +character of the found string. +*****************************************************************************/ +GLOBAL charptr EBPtr1; +/***************************************************************************** + EBPtr2 is used when a search is being performed. After a character +matching the first character of the search string is found, this pointer is +adjusted as each remaining character of the search string is compared with +the edit buffer. When a search command succeeds, this pointer is left +pointing to the last character of the found string. +*****************************************************************************/ +GLOBAL charptr EBPtr2; +/***************************************************************************** + Bits within EdFlag have the following meanings: + 1 Allow caret (^) in search strings + 2 Allow Y and _ commands to destroy edit buffer + 4 Don't arbitrarily expand memory + 16 preserve dot on failing searches + 64 only move dot by one on multiple occurrence searches +*****************************************************************************/ +GLOBAL WORD EdFlag = 0; /* ED mode control flag */ +/***************************************************************************** + Bits within EhFlag have the following meanings: + 3 how much error message to display + 4 display failing command string after errors +*****************************************************************************/ +GLOBAL WORD EhFlag = 0; /* EH mode control flag */ +/***************************************************************************** + EndSAr is used by search code to point to the end of the area to be +searched. +*****************************************************************************/ +GLOBAL charptr EndSAr; /* end of search area */ +/***************************************************************************** + Several TECO error messages take an argument. For instance, the +"illegal command" error message shows the user the illegal command. When +these kinds of messages are required, ErrTxt is used to send the text +of the argument to the error display function (ErrMsg). +*****************************************************************************/ +GLOBAL char ErrTxt[6]; /* holds part of error message */ +/***************************************************************************** + The EsFlag flag controls what is displayed on the terminal after every +successful search command completes. EsFlag has the following meanings: + 0 don't display anything + -1 display the line containing the found string + 1-31 display the line containing the found string, + with a line feed at the character position + 32-126 display the line containing the found string, + with the character whose ASCII code is represented + by ES at the character position + m*265+n n has the meanings defined above. m is the number + of lines above and below the found string to be + displayed. +*****************************************************************************/ +GLOBAL WORD EsFlag = 0; /* ES mode control flag */ +/***************************************************************************** + The expression stack contains the components of TECO's numeric +expressions. Each entry on the expression stack is either an OPERAND or +an OPERATOR (like +, -, /, *). +*****************************************************************************/ +GLOBAL struct EStck EStack[EXS_SIZE]; /* expression stack */ +GLOBAL WORD EStBot; /* expression stack bottom */ +GLOBAL WORD EStTop; /* top of expression stack */ +/***************************************************************************** + Bits in EtFlag control TECO's handling of the terminal. Definitions +of masks for each bit and the meaning of each bit can be found in TECOC.H. +Bits in EtFlag are initialized when the terminal is set up in the ZTrmnl +function. +*****************************************************************************/ +GLOBAL WORD EtFlag = 0; /* ET mode control flag */ +/***************************************************************************** + The EuFlag is TECO's case mode control flag. This flag allows TECO to +be used to input and output upper and lower case characters even if the +terminal being used is capable of displaying only uppercase characters. If +the EU flag is -1, no case flagging is performed on type-out. If the EU flag +is 0, lowercase characters are converted to uppercase on type-out, and are +preceded by a ' character. If the EU flag is 1, then lowercase characters +are converted to uppercase on type-out, but uppercase characters are +preceded by a ' character. +*****************************************************************************/ +GLOBAL WORD EuFlag = EU_NONE; /* EU mode control flag */ +/***************************************************************************** + The EV mode control flag controls what is displayed on the terminal +after every successful command string completes. By default, nothing is +displayed (EV is 0). EV has the following meanings: + 0 don't display anything + -1 display the line containing the character position + 1-31 display the line containing the character position, + with a line feed at the character position + 32-126 display the line containing the character position, + with the character whose ASCII code is represented + by ES at the character position + m*265+n n has the meanings defined above. m is the number + of lines above and below the character position to be + displayed. +*****************************************************************************/ +GLOBAL WORD EvFlag = 0; /* EV mode control flag */ +/***************************************************************************** + These variables point to the filename buffer. +*****************************************************************************/ +GLOBAL charptr FBfBeg; /* first char of filename buffer */ +GLOBAL charptr FBfEnd; /* last chr (+1) of filename buffer */ +GLOBAL charptr FBfPtr; /* pointer into file spec buffer */ +/***************************************************************************** + Bits in the EzFlag are system-specific. See the system-specific +file for each operating system (like ZVMS.C, ZUNIX.C, etc) for the meanings +of these bits. +*****************************************************************************/ +GLOBAL WORD EzFlag = 0; /* EZ mode control flag */ +/***************************************************************************** + FFPage is the value which is returned by the ^E command. It is -1 if +the buffer currently contains a page of text that was terminated by a form +feed in the input file. It is 0 if the buffer contains only part of a page +from the input file (because the input page filled the text buffer before it +was completely read in). The FFPage flag is tested by the P command and +related operations to determine if a form feed should be appended to the +contents of the buffer when it is output. +*****************************************************************************/ +GLOBAL LONG FFPage = 0; /* form feed flag (see ^E command) */ +/***************************************************************************** + These variables point to the first and last characters in the edit +buffer gap. See file PG.MEM for a description of memory management. +*****************************************************************************/ +GLOBAL charptr GapBeg; /* first char in edit buffer gap */ +GLOBAL charptr GapEnd; /* last char in edit buffer gap */ +/***************************************************************************** + GotCtC indicates that the user has interrupted the normal execution +of TECO-C by typing a control-C. This variable is set by the special +interrupt-handling function executed when a control-C is struck, and is +cleared before a command string is entered. It is tested each time a command +terminates and when certain commands execute time-consuming loops. +*****************************************************************************/ +GLOBALV BOOLEAN GotCtC = FALSE; +/***************************************************************************** + IBfEnd is the end of the input buffer. See file PG.MEM for a +description of memory management. +*****************************************************************************/ +GLOBAL charptr IBfEnd; +/***************************************************************************** + IniSrM is the initial search mode. It is used when parsing search +strings and filenames. The value of this variable is set by ^V and +^W characters and is used to explicitly control the case (upper or lower) of +characters in a string. It can take on the values LOWER, UPPER or NONE, +which are defined in TECOC.H. +*****************************************************************************/ +GLOBAL int IniSrM = NONE; +/***************************************************************************** + IsOpnI and IsOpnO contain indicators about the status of the file +data blocks in the IFiles and OFiles arrays, respectively. An element has +the value TRUE when the corresponding file data block reflects an opened file. +IsEofI indicates that the corresponding element of IFiles reflects a file +that has reached the end. +*****************************************************************************/ +GLOBAL BOOLEAN IsEofI[NIFDBS]; +GLOBAL BOOLEAN IsOpnI[NIFDBS]; +GLOBAL BOOLEAN IsOpnO[NOFDBS]; +/***************************************************************************** + LstErr holds the code for the last error reported by TECO-C. It is +set in the error display function (ErrMsg) and used when the user executes +the ? or / immediate mode commands, to print out more information about the +last error that occurred. +*****************************************************************************/ +GLOBAL WORD LstErr = ERR_XXX; /* number of last error message */ +/***************************************************************************** + The loop stack maintains pointers to the first character of each loop +(the character following the "<"). LStTop is the element of LStack that +relates to the most recently executed "<" command. LStBot is the index of +the bottom of the stack, so that if (LStTop == LStBot), we're not in a loop +in the current macro level. When a macro is entered, LStTop and LStBot are +saved on the macro stack, and LStBot is set to LStTop, so that LStBot +defines the bottom of the LStack frame for the new macro level. +*****************************************************************************/ +GLOBAL WORD LStBot; /* bottom of loop stack */ +GLOBAL struct LStck LStack[LPS_SIZE]; /* loop stack */ +GLOBAL WORD LStTop; /* top of loop stack */ +/***************************************************************************** + MArgmt contains the m part of an m,n argument pair that precedes a +TECO command. For instance, MArgmt would contain 10 when the command +10,45T is being executed. +*****************************************************************************/ +GLOBAL LONG MArgmt; /* m part of m,n numeric arguments */ +/***************************************************************************** + MAtchd is used to indicate that a match has been found for a search +string. It is only used when a search command is being executed. +*****************************************************************************/ +GLOBAL BOOLEAN Matchd; /* indicates successful search */ +/***************************************************************************** + These variables implement the macro stack. When TECO executes a +macro, it must first save the current state, so that the state can be +restored when the macro has finished executing. Each entry in the macro +stack preserves the critical variables for one macro call. +*****************************************************************************/ +GLOBAL struct MStck MStack[MCS_SIZE]; /* macro stack */ +GLOBAL WORD MStTop = -1; /* top of macro stack */ +/***************************************************************************** + NArgmt holds the numeric argument that precedes a command. It is set +by a call to the GetNmA function. When the command is preceded by an m,n +argument pair, NArgmt holds the value of the n argument. +*****************************************************************************/ +GLOBAL LONG NArgmt; /* n argument (n part of m,n) */ +/***************************************************************************** + QR is a pointer to a structure which defines a q-register. +It is set by calling the FindQR function. Whenever a command that uses a +q-register is executed, FindQR is called first to set QR. +*****************************************************************************/ +GLOBAL QRptr QR; +/***************************************************************************** + The structures in the QRgstr array represent the global and main-level +local q-registers. The 0-9 elements are for global digit q-registers (0-9), +the 10-35 elements are for global alphabetic q-registers (a-z or A-Z), the +36-45 elements are for main-level local digit q-registers (.0-.9) and the +46-71 elements are for main-level local alphabetic q-registers (.a-.z or +.A-.Z). Local q-registers at macro levels other than the main level are +allocated dynamically. +*****************************************************************************/ +GLOBAL struct QReg QRgstr[72]; +/***************************************************************************** + QStack is the q-register stack, accessed via the [ and ] commands. +*****************************************************************************/ +GLOBAL struct QReg QStack[QRS_SIZE]; /* q-register stack */ +GLOBAL WORD QStTop = -1; /* top of q-register stack */ +/***************************************************************************** + RefLen is the length of the last inserted string or found search +string. It is accessed by the ^S command. +*****************************************************************************/ +GLOBAL LONG RefLen = 0; /* returned by ^S */ +/***************************************************************************** + Radix is TECO's radix, usually 10. It is set by the ^D, ^O and ^R +commands. +*****************************************************************************/ +GLOBAL DEFAULT Radix = 10; /* TECO's current radix */ +/***************************************************************************** + When searching, this pointer points to the farthest-right character +in the area to be searched. It is used after the first character of a string +has been found, to indicate the limit of the area in the edit buffer that +should be checked against the remaining characters in the search string. +*****************************************************************************/ +GLOBAL charptr RhtSid; +/***************************************************************************** + These variables point to the search string buffer. The search buffer +is allocated by function MemIni. +*****************************************************************************/ +GLOBAL charptr SBfBeg = NULL; /* start of search buffer */ +GLOBAL charptr SBfEnd; /* end search buffer */ +GLOBAL charptr SBfPtr; /* end of search string buffer */ +/***************************************************************************** + SIncrm is the value added to the search pointer when the edit buffer +is being searched. If SIncrm is 1, then the search proceeds in a forward +direction. If SIncrm is -1, then the search proceeds in a backward +direction. By using this variable, the rather complex code that implements +searching can easily be used to search in either direction. +*****************************************************************************/ +GLOBAL LONG SIncrm; /* search increment */ +/***************************************************************************** + SMFlag is TECOC's search mode flag, and controls case sensitivity +during searches. This variable holds the value of the ^X command. +*****************************************************************************/ +GLOBAL WORD SMFlag = 0; /* search mode control flag (^X) */ +/***************************************************************************** + SrcTyp is used to "remember" the kind of search command that we're +working on. The same search code is used by all the search commands, but +each search command is slightly different than the others. The common +search code tests this variable to implement the differences. +*****************************************************************************/ +GLOBAL WORD SrcTyp; /* type of search (E_SEARCH, etc) */ +/***************************************************************************** + SStPtr points into the search buffer, and is used only by the search +code. +*****************************************************************************/ +GLOBAL charptr SStPtr; /* search string pointer */ +/***************************************************************************** + This table serves two functions. It is used by the character macros +defined in CHMACS.H. It is also used by the command line input code in +function ReadCS. + The top four bits of each mask are used by the functions in CHMACS.H. +The top four bits are masks used to represent "uppercase", "lowercase", +"digit" and "line terminator". + The bottom four bits of each mask are used by function ReadCS. They +are treated as a number and are used in a SWITCH statement. In ReadCS, the +top four bits of each mask are not used. +*****************************************************************************/ +unsigned char ChrMsk[256] = + { + RCS_DEF, /* null */ + RCS_CCH, /* ^A */ + RCS_CCH, /* ^B */ + RCS_CTC, /* ^C */ + RCS_CCH, /* ^D */ + RCS_CCH, /* ^E */ + RCS_CCH, /* ^F */ + RCS_CTG, /* ^G (bell) */ + RCS_BS, /* ^H (bs) */ + RCS_DEF, /* ^I (tab) */ + RCS_LF | CM_LINE_TERM, /* ^J (lf) */ + RCS_VF | CM_LINE_TERM, /* ^K (vt) */ + RCS_VF | CM_LINE_TERM, /* ^L (ff) */ + RCS_CR, /* ^M (cr) */ + RCS_CCH, /* ^N */ + RCS_CCH, /* ^O */ + RCS_CCH, /* ^P */ + RCS_CCH, /* ^Q */ + RCS_CCH, /* ^R */ + RCS_CCH, /* ^S */ + RCS_CCH, /* ^T */ + RCS_CTU, /* ^U */ + RCS_CCH, /* ^V */ + RCS_CCH, /* ^W */ + RCS_CCH, /* ^X */ + RCS_CCH, /* ^Y */ + RCS_CTZ, /* ^Z */ + 0, /* escape */ + RCS_CCH, /* FS */ + RCS_CCH, /* GS */ + RCS_CCH, /* RS */ + RCS_CCH, /* US */ + RCS_SP, /* space */ + RCS_DEF, /* ! */ + RCS_DEF, /* " */ + RCS_DEF, /* # */ + RCS_DEF, /* $ */ + RCS_DEF, /* % */ + RCS_DEF, /* | */ + RCS_DEF, /* ' */ + RCS_DEF, /* ( */ + RCS_DEF, /* ) */ + RCS_AST, /* * */ + RCS_DEF, /* + */ + RCS_DEF, /* , */ + RCS_DEF, /* - */ + RCS_DEF, /* . */ + RCS_DEF, /* / */ + RCS_DEF | CM_DIGIT, /* 0 */ + RCS_DEF | CM_DIGIT, /* 1 */ + RCS_DEF | CM_DIGIT, /* 2 */ + RCS_DEF | CM_DIGIT, /* 3 */ + RCS_DEF | CM_DIGIT, /* 4 */ + RCS_DEF | CM_DIGIT, /* 5 */ + RCS_DEF | CM_DIGIT, /* 6 */ + RCS_DEF | CM_DIGIT, /* 7 */ + RCS_DEF | CM_DIGIT, /* 8 */ + RCS_DEF | CM_DIGIT, /* 9 */ + RCS_DEF, /* : */ + RCS_DEF, /* ; */ + RCS_DEF, /* < */ + RCS_DEF, /* = */ + RCS_DEF, /* > */ + RCS_DEF, /* ? */ + RCS_DEF, /* @ */ + RCS_DEF | CM_UPPER, /* A */ + RCS_DEF | CM_UPPER, /* B */ + RCS_DEF | CM_UPPER, /* C */ + RCS_DEF | CM_UPPER, /* D */ + RCS_DEF | CM_UPPER, /* E */ + RCS_DEF | CM_UPPER, /* F */ + RCS_DEF | CM_UPPER, /* G */ + RCS_DEF | CM_UPPER, /* H */ + RCS_DEF | CM_UPPER, /* I */ + RCS_DEF | CM_UPPER, /* J */ + RCS_DEF | CM_UPPER, /* K */ + RCS_DEF | CM_UPPER, /* L */ + RCS_DEF | CM_UPPER, /* M */ + RCS_DEF | CM_UPPER, /* N */ + RCS_DEF | CM_UPPER, /* O */ + RCS_DEF | CM_UPPER, /* P */ + RCS_DEF | CM_UPPER, /* Q */ + RCS_DEF | CM_UPPER, /* R */ + RCS_DEF | CM_UPPER, /* S */ + RCS_DEF | CM_UPPER, /* T */ + RCS_DEF | CM_UPPER, /* U */ + RCS_DEF | CM_UPPER, /* V */ + RCS_DEF | CM_UPPER, /* W */ + RCS_DEF | CM_UPPER, /* X */ + RCS_DEF | CM_UPPER, /* Y */ + RCS_DEF | CM_UPPER, /* Z */ + RCS_DEF, /* [ */ + RCS_DEF, /* \ */ + RCS_DEF, /* ] */ + RCS_DEF, /* ^ */ + RCS_DEF, /* _ */ + RCS_GRV, /* ` */ + RCS_LWR | CM_LOWER, /* a */ + RCS_LWR | CM_LOWER, /* b */ + RCS_LWR | CM_LOWER, /* c */ + RCS_LWR | CM_LOWER, /* d */ + RCS_LWR | CM_LOWER, /* e */ + RCS_LWR | CM_LOWER, /* f */ + RCS_LWR | CM_LOWER, /* g */ + RCS_LWR | CM_LOWER, /* h */ + RCS_LWR | CM_LOWER, /* i */ + RCS_LWR | CM_LOWER, /* j */ + RCS_LWR | CM_LOWER, /* k */ + RCS_LWR | CM_LOWER, /* l */ + RCS_LWR | CM_LOWER, /* m */ + RCS_LWR | CM_LOWER, /* n */ + RCS_LWR | CM_LOWER, /* o */ + RCS_LWR | CM_LOWER, /* p */ + RCS_LWR | CM_LOWER, /* q */ + RCS_LWR | CM_LOWER, /* r */ + RCS_LWR | CM_LOWER, /* s */ + RCS_LWR | CM_LOWER, /* t */ + RCS_LWR | CM_LOWER, /* u */ + RCS_LWR | CM_LOWER, /* v */ + RCS_LWR | CM_LOWER, /* w */ + RCS_LWR | CM_LOWER, /* x */ + RCS_LWR | CM_LOWER, /* y */ + RCS_LWR | CM_LOWER, /* z */ + RCS_DEF, /* { */ + RCS_DEF, /* | */ + RCS_DEF, /* } */ + RCS_DEF, /* ~ */ + RCS_DEL, /* delete */ + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF, + RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF,RCS_DEF + }; +/***************************************************************************** + TraceM is the trace mode flag. This variable is set to TRUE when +TECO's trace mode is on. When it is set, commands are echoed to the terminal +as they are executed. This mode is used to aid in debugging TECO macros, and +is toggled by the ? command. + If you want to trace the command line parsing macro executed in +ZPrsCL(), set this to TRUE; otherwise, set it to FALSE. +*****************************************************************************/ +GLOBAL BOOLEAN TraceM = FALSE; /* trace mode flag */ +/***************************************************************************** + CrType is the terminal type. It is used by the ZScrOp function to +drive the few screen capabilities of TECOC. See ZScrOp for a list of the +values that CrType can take. +*****************************************************************************/ +GLOBAL DEFAULT CrType = UNTERM; /* terminal type */ +#if VIDEO +GLOBAL DEFAULT HldFlg; /* value of 5:W (hold mode flag) */ +GLOBAL DEFAULT HtSize; /* value of 1:W (screen width) */ +GLOBAL DEFAULT MrkFlg; /* value of 4:W */ +GLOBAL DEFAULT ScroLn; /* value of 7:W */ +GLOBAL DEFAULT SeeAll; /* value of 3:W */ +GLOBAL DEFAULT TopDot; /* value of 6:W */ +GLOBAL DEFAULT VtSize; /* value of 2:W (screen height) */ +#if CURSES +GLOBAL DEFAULT SpcMrk = 0; /* value of 8:W */ +GLOBAL DEFAULT KeyPad; /* value of 9:W */ +#endif +#endif +/***************************************************************************** + S t a r t H e r e +*****************************************************************************/ +int _Cdecl main(argc, argv) /* _Cdecl defined in ZPORT.H */ +int argc; +char **argv; +{ +#if CHECKSUM_CODE /* MS-DOS debugging code */ + init_code_checksums (); /* calculate code checksums */ +#endif + Init(argc, argv); /* initialize TECO */ +/* + * read a command string and then execute it. This loop is infinite. + * TECO-C is exited explicitly when a lower-level function calls TAbort. + */ + CStBeg = CStEnd = CBfBeg; + CStEnd--; + FOREVER { /* loop forever */ + ReadCS(); /* read command string */ + CBfPtr = CBfBeg; /* initialize command string ptr */ + CmdMod = '\0'; /* clear modifiers flags */ + EStTop = EStBot = /* clear expression stack */ + LStTop = LStBot = /* clear loop stack */ + MStTop = -1; /* clear macro stack */ + ExeCSt(); /* execute command string */ + } +} +/***************************************************************************** + The following code is support routines for the imbedded debugging code +in TECO-C. If the "DEBUGGING" macro in ZPORT.H is set to "FALSE", then none +of this code is compiled. +*****************************************************************************/ +#if DEBUGGING +#include /* isprint() macro */ +#include "dchars.h" /* define identifiers for characters */ +static DEFAULT DbgInd = 0; /* debugging indent level */ +static DEFAULT DbgLvl = 0; /* debugging message level */ +#define DBGSBF 4000 /* huge buffer to avoid overruns */ +GLOBAL char DbgSBf[DBGSBF+1]; /* sprintf() buffer for debugging messages */ +#if USE_PROTOTYPES +static VVOID DbgDMs( /* debugging, display message */ + int DbgFLv, /* function display level */ + char *DbgFNm, /* function name */ + char *DbgWht, /* "called", "returning", or blank */ + char *DbgMsg); /* message to display */ +static VVOID DbgDsA(void); /* display address variables */ +static VVOID DbgEBf(void); /* display edit buffer details */ +static VVOID DbgHlp(void); /* display help message */ +static VVOID DbgLSt(void); /* display loop stack details */ +static VVOID DbgMSt(void); /* display macro stack details */ +static VVOID DbgPrP( /* display a pointer */ + char *s, + voidptr ptr); +static VVOID DbgQRg(void); /* display Q-register's */ +static VVOID DbgQSt(void); /* display Q-register stack */ +static VVOID DbgSLv(void); /* set debugging message level */ +#endif +/***************************************************************************** + DbgDsA() + This function displays details about address variables for 1^P. +*****************************************************************************/ +static VVOID DbgPrP (s, ptr) /* display a pointer */ +char *s; +voidptr ptr; +{ + printf ("%s %lu", s, Zcp2ul(ptr)); +} +static VVOID DbgDsA() +{ + int length; + DbgPrP ("\r\nAraBeg =", AraBeg); + DbgPrP ("\tEBfBeg =", EBfBeg); + DbgPrP ("\tGapBeg =", GapBeg); + DbgPrP ("\r\nAraEnd =", AraEnd); + DbgPrP ("\tEBfEnd =", EBfEnd); + DbgPrP ("\tGapEnd =", GapEnd); + DbgPrP ("\r\nCBfBeg =", CBfBeg); + DbgPrP ("\tCStBeg =", CStBeg); + DbgPrP ("\tFBfBeg =", FBfBeg); + DbgPrP ("\r\nCBfEnd =", CBfEnd); + DbgPrP ("\tCStEnd =", CStEnd); + DbgPrP ("\tFBfEnd =", FBfEnd); + DbgPrP ("\r\nSBfBeg =", SBfBeg); + DbgPrP ("\tEBPtr1 =", EBPtr1); + DbgPrP ("\tEBPtr2 =", EBPtr2); + DbgPrP ("\r\nSBfPtr =", SBfPtr); + DbgPrP ("\tCBfPtr =", CBfPtr); + DbgPrP ("\r\nSBfEnd =", SBfEnd); + DbgPrP ("\tSStPtr =", SStPtr); + printf ("\r\nsearch buffer = \""); + if (SBfPtr != NULL) { + length = (int) (SBfPtr-SBfBeg); + if (length > 40) { + length = 40; + } + printf ("%.*s", length, SBfBeg); + } else { + length = 0; + } + printf("\"\r\n"); +} +/***************************************************************************** + DbgEBf() + This function displays details about the edit buffer for 2^P. +*****************************************************************************/ +static VVOID DbgEBf() +{ + charptr DbgPtr; + DbgPrP ("\r\nEBfBeg =", EBfBeg); + DbgPrP ("\tGapBeg =", GapBeg); + printf (" (%ld bytes)", (LONG) (GapBeg - EBfBeg)); + DbgPrP ("\r\nGapBeg =", GapBeg); + DbgPrP ("\tGapEnd =", GapEnd); + printf (" (%ld bytes)", (LONG) (GapEnd - GapBeg)); + DbgPrP ("\r\nGapEnd =", GapEnd); + DbgPrP ("\tEBfEnd =", EBfEnd); + printf (" (%ld bytes)", (LONG) (EBfEnd - GapEnd)); + DbgPrP ("\r\nEBfEnd =", EBfEnd); + DbgPrP ("\tIBfEnd =", IBfEnd); + printf (" (%ld bytes)", (LONG) (IBfEnd - EBfEnd)); + DbgPrP ("\r\nEBfBeg =", EBfBeg); + DbgPrP ("\tIBfEnd =", IBfEnd); + printf (" (%ld bytes)", (LONG) (IBfEnd - EBfBeg)); + for (DbgPtr = EBfBeg; DbgPtr < GapBeg; ++DbgPtr) { + DbgPrP ("\r\nDbgEBf: first half, char at", DbgPtr); + printf((isprint(*DbgPtr) ? " '%c'" : " <%d>"), *DbgPtr); + } + for (DbgPtr = (GapEnd+1); DbgPtr <= EBfEnd; ++DbgPtr) { + DbgPrP ("\r\nDbgEBf: second half, char at", DbgPtr); + printf((isprint(*DbgPtr) ? " '%c'" : " <%d>"), *DbgPtr); + } + puts ("\r"); +} +/***************************************************************************** + DbgHlp() + This function displays help on ^P commands for ^P with no arguments. +*****************************************************************************/ +static VVOID DbgHlp() +{ + puts("\r\n\tArguments to ^P have the following meanings:\r\n"); + puts("\t\t^P\tno arguments - display help about ^P\r"); + puts("\t\tm,0\tset debugging message level to m (0-5)\r"); + puts("\t\t1\tdisplay global address variables\r"); + puts("\t\t2\tdisplay details about the edit buffer\r"); + puts("\t\t3\tdisplay the loop stack\r"); + puts("\t\t4\tdisplay the macro stack\r"); + puts("\t\t5\tdisplay details about the q-registers\r"); + puts("\t\t6\tdisplay the q-register stack\r\r\r"); +} +/***************************************************************************** + DbgLSt () + This function displays details about the loop stack for 3^P. +*****************************************************************************/ +static VVOID DbgLSt() +{ + int i; + printf ("\r\nLoop stack: LStBot = %d, LstTop = %d\r\n\n", LStBot, LStTop); + printf (" # LIndex LAddr\r\n"); + printf ("-- ---------- ----------\r\n"); + for (i = 0; i <= LStTop; ++i) { + printf("%2d %10ld %10lu\r\n", + i, LStack[i].LIndex, Zcp2ul(LStack[i].LAddr)); + } +} +/***************************************************************************** + DbgDMs() + This function displays a debugging message at the right indentation +level, in reverse video, if the debugging level is appropriate for the +message. It also optionally calls the consistency_check() and the +check_code_checksums() routines while debugging. + The debugging levels are: + 1 command functions + 2 functions called by command functions + 3 everything but stuff that's too noisy + 4 everything +*****************************************************************************/ +static VVOID DbgDMs(DbgFLv, DbgFNm, DbgWht, DbgMsg) +int DbgFLv; /* function display level */ +char *DbgFNm; /* function name */ +char *DbgWht; /* "called", "returning", or blank */ +char *DbgMsg; /* message to display */ +{ + if (DbgFLv <= DbgLvl) { /* is message at right level */ + printf ("%*s", DbgInd, ""); /* indent message */ + ZScrOp(SCR_RON); /* turn on reverse video */ + printf ("%s: %s %s\r\n", + DbgFNm, + DbgWht, + (DbgMsg == NULL) ? "" : DbgMsg); + ZScrOp(SCR_ROF); /* turn off reverse video */ + } + if (DbgMsg == DbgSBf) { /* clear sprintf() buffer */ + DbgSBf[0] = '\0'; + } + if (DbgSBf[DBGSBF] != '\0') { /* check sprintf() overrun */ + puts("DbgSBf[] overrun"); + exit(EXIT_FAILURE); + } +/* + * If you enable consistency checking and code checksumming here, pointers + * and code will be checked on every function entry and exit in addition to + * being checked after every successful command execution in ExeCSt(). + * + * Enabling code checksumming here r-e-a-l-l-y slows things down. + */ +#if CONSISTENCY_CHECKING + check_consistency (); +#endif +#if 0 && CHECKSUM_CODE /* MS-DOS debugging code */ + check_code_checksums (); +#endif +} +/***************************************************************************** + DbgFEn() + This function is called as the first thing upon entry to a function. +*****************************************************************************/ +VVOID DbgFEn(DbgFLv, DbgFNm, DbgMsg) /* debugging, function entry */ +int DbgFLv; /* function display level */ +char *DbgFNm; /* function name */ +char *DbgMsg; /* a function entry message */ +{ + DbgInd += 2; + DbgDMs(DbgFLv, DbgFNm, "called", DbgMsg); +} +/***************************************************************************** + DbgFEx() + This function is called as the last thing before a function returns. +*****************************************************************************/ +VVOID DbgFEx(DbgFLv, DbgFNm, DbgMsg) +int DbgFLv; +char *DbgFNm; +char *DbgMsg; +{ + DbgDMs(DbgFLv, DbgFNm, "returning", DbgMsg); + DbgInd -= 2; +} +/***************************************************************************** + DbgFMs() + This function is called in the middle of a routine if the routine +has something special to say. +*****************************************************************************/ +VVOID DbgFMs(DbgFLv, DbgFNm, DbgMsg) /* debugging, function message */ +int DbgFLv; /* function display level */ +char *DbgFNm; /* function name */ +char *DbgMsg; /* a debugging message */ +{ + DbgDMs(DbgFLv, DbgFNm, "", DbgMsg); +} +/***************************************************************************** + DbgMSt() + This function displays details about the macro stack for 4^P. +*****************************************************************************/ +static VVOID DbgMSt() +{ + int i; + MSptr MSp; + printf("Macro Stack, MStTop = %d\r\n\n", MStTop); + printf(" # CStBeg CBfPtr CStEnd EStBot EStTop LStBot LStTop QRgstr\r\n"); + printf("-- -------- -------- -------- ------ ------ ------ ------ --------\r\n"); + for (MSp = MStack, i = 0; i <= MStTop; ++i, ++MSp) { + printf("%2d %8lu %8lu %8lu %6d %6d %6d %6d %8lu\r\n", + i, + Zcp2ul(MSp->CStBeg), + Zcp2ul(MSp->CBfPtr), + Zcp2ul(MSp->CStEnd), + MSp->EStBot, + MSp->EStTop, + MSp->LStBot, + MSp->LStTop, + Zcp2ul(MSp->QRgstr)); + } +} +/***************************************************************************** + DbgQRg() + This function displays details about global Q-registers for 5^P. +*****************************************************************************/ +static VVOID DbgQRg() +{ + int i; + int length; + charptr cp; + QRptr QRp; + printf ("Non-empty Q-registers:\r\n\n"); + printf (" # Number Start End_P1 Text (possibly truncated)\r\n"); + printf ("-- ------- ------- ------- --------------------------------------------------\r\n"); + for (i = 0, QRp = QRgstr; i < 72; ++i, ++QRp) { + if (QRp->Number != 0 || QRp->Start != NULL) { + printf ("%c%c %7ld %7lu %7lu \"", + (i < 36) ? ' ' : '.', + i + ((i <= 9) ? '0' : 'A' - 10), + QRp->Number, + Zcp2ul(QRp->Start), + Zcp2ul(QRp->End_P1)); + if (QRp->Start != NULL) { + length = (int) (QRp->End_P1 - QRp->Start); + if (length > 50) { + length = 50; + } + cp = QRp->Start; + while (length-- > 0) { + if (*cp < ' ') { + ZDspCh ('^'); + ZDspCh (*cp + '@'); + --length; + } else { + ZDspCh (*cp); + } + ++cp; + } + } + printf ("\"\r\n"); + } + } + printf ("\r\n"); +} +/***************************************************************************** + DbgQSt() + This function displays details about the Q-register stack for 6^P. +*****************************************************************************/ +static VVOID DbgQSt() +{ + int i; + int length; + charptr cp; + QRptr QRp; + printf("Q-register Stack, QStTop = %d\r\n\n", QStTop); + printf ("# Number Start End_P1 Text (possibly truncated)\r\n"); + printf ("-- ------- ------- ------- --------------------------------------------------\r\n"); + for (QRp = QStack, i = 0; i <= QStTop; ++i, ++QRp) { + printf ("%2d %7ld %7lu %7lu \"", + i, + QRp->Number, + Zcp2ul(QRp->Start), + Zcp2ul(QRp->End_P1)); + if (QRp->Start != NULL) { + length = (int) (QRp->End_P1 - QRp->Start); + if (length > 50) { + length = 50; + } + cp = QRp->Start; + while (length-- > 0) { + if (*cp < ' ') { + ZDspCh ('^'); + ZDspCh (*cp + '@'); + } else { + ZDspCh (*cp); + } + ++cp; + } + } + printf ("\"\r\n"); + } + printf ("\r\n"); +} +/***************************************************************************** + DbgSLv() + This function sets DbgLvl, which controls how much debugging +information is displayed as TECO executes. If DbgLvl is 0, no debugging +messages are displayed. If (DbgLvl>=1), then messages are displayed by +all "Exexxx" functions. This means that a message is displayed for each +entry and exit of execution of a single command. If (DbgLvl>=1) then in +addition to the messages displayed for entry and exit of Exexxx functions, +a message is displayed for the "next level down" functions. This scheme +is continued for DbgLvl >= 3, DbgLvl >= 4, etc. + In most cases, setting DbgLvl to 1 and then executing a TECO +command string will reveal an error. For more detail, DbgLvl can be set +to successively higher values. Using DbgLvl, you can trade-off the amount +of time you wait for the messages to go by on the screen with the amount +of detail that's needed. + By using this system, debug messages that are placed into new code +in order to debug it can be left in the code so they're useful later. +*****************************************************************************/ +static VVOID DbgSLv() +{ + DbgLvl = (DEFAULT)MArgmt; +} +/***************************************************************************** + DbgDsp() + This function provides control of the imbedded debugging system in +TECO-C. An unused command character (currently control-P), when executed by +the user, causes this function to be executed. + Arguments to ^P have the following meanings: + no argument - display help about ^P + m,0 set debugging message level to m + 1 display global address variables + 2 display details about the edit buffer + 3 display the loop stack + 4 display the macro stack + 5 display details about the q-registers +*****************************************************************************/ +DEFAULT DbgDsp() +{ + if (EStTop == EStBot) { /* if no numeric argument */ + ZScrOp(SCR_RON); /* turn on reverse video */ + DbgHlp(); /* display debugging help */ + ZScrOp(SCR_ROF); /* turn off reverse video */ + return SUCCESS; + } + if (GetNmA() == FAILURE) { /* get numeric argument */ + return FAILURE; + } + if (CmdMod & MARGIS) { /* if it's m,n^P */ + DbgSLv(); /* set DbgLvl */ + return SUCCESS; + } + ZScrOp(SCR_RON); /* turn on reverse video */ + switch ((int)NArgmt) { + case 1: DbgDsA(); break; /* display address variable details */ + case 2: DbgEBf(); break; /* display edit buffer details */ + case 3: DbgLSt(); break; /* display loop stack */ + case 4: DbgMSt(); break; /* display macro stack */ + case 5: DbgQRg(); break; /* display q-registers */ + case 6: DbgQSt(); break; /* display q-register stack */ + default: + printf("bad argument to ^P command\r\n"); + ZScrOp(SCR_ROF); /* turn off reverse video */ + return FAILURE; + } + ZScrOp(SCR_ROF); /* turn off reverse video */ + return SUCCESS; +} +#endif /* #if DEBUGGING */ +/***************************************************************************** + The following code was needed while debugging TECO-C on the IBM PC +with it's brain-damaged memory addressing scheme. This code checks the +"consistency" of various pointers, making sure some don't change throughout +the execution of TECO-C and making sure others are in the right order. + After init_consistency_check() is called in Init(), the +check_consistency() code is called in ExeCSt() after the successful +completion of each command. For more frequent checking, it can also +be called in the DbgDMs() routine above but then the "DEBUGGING" macro +in ZPORT.H has to be set to "TRUE" as well. + If the "CONSISTENCY_CHECKING" macro in ZPORT.H is set to "FALSE", + then none of this code is compiled. +*****************************************************************************/ +#if CONSISTENCY_CHECKING +#if USE_PROTOTYPES +static int errprt(char *str, voidptr p1, voidptr p2); +#endif +static charptr ss_CBfBeg; +static charptr ss_CBfEnd; +static charptr ss_FBfBeg; +static charptr ss_FBfEnd; +static charptr ss_SBfBeg; +static charptr ss_SBfEnd; +VVOID init_consistency_check() +{ + ss_CBfBeg = CBfBeg; + ss_CBfEnd = CBfEnd; + ss_FBfBeg = FBfBeg; + ss_FBfEnd = FBfEnd; + ss_SBfBeg = SBfBeg; + ss_SBfEnd = SBfEnd; +} +static int errprt(str, p1, p2) +char *str; +voidptr p1; +voidptr p2; +{ + printf ("%s (%lu,%lu)\r\n", str, Zcp2ul(p1), Zcp2ul(p2)); + return EXIT_FAILURE; +} +#if defined(__TURBOC__) && (__TURBOC__ >= 0x0295) +#include /* prototype for heapcheck() */ +#endif +VVOID check_consistency() +{ + int ex = EXIT_SUCCESS; +/* + * is the heap corrupted? + */ +#if defined(__TURBOC__) && (__TURBOC__ >= 0x0295) + if (heapcheck () < 0) { + puts ("check_consistency: heapcheck failed"); + ex = EXIT_FAILURE; + } +#endif +/* + * the following point to the start and end of various buffers which are + * initialized at program startup and should not have changed. + */ + if (ss_CBfBeg != CBfBeg) ex=errprt("ss_CBfBeg != CBfBeg",ss_CBfBeg,CBfBeg); + if (ss_CBfEnd != CBfEnd) ex=errprt("ss_CBfEnd != CBfEnd",ss_CBfEnd,CBfEnd); + if (ss_FBfBeg != FBfBeg) ex=errprt("ss_FBfBeg != FBfBeg",ss_FBfBeg,FBfBeg); + if (ss_FBfEnd != FBfEnd) ex=errprt("ss_FBfEnd != FBfEnd",ss_FBfEnd,FBfEnd); + if (ss_SBfBeg != SBfBeg) ex=errprt("ss_SBfBeg != SBfBeg",ss_SBfBeg,SBfBeg); + if (ss_SBfEnd != SBfEnd) ex=errprt("ss_SBfEnd != SBfEnd",ss_SBfEnd,SBfEnd); +/* + * make sure the pointers into the above buffers are between the start + * and end of the buffers + * + * Note: while doing an EI or M command, CBfPtr can point outside of + * [CBfBeg..CBfEnd] but it is always within [CStBeg..CStEnd]. + */ + if (CBfPtr < CStBeg) ex=errprt("CBfPtr < CStBeg",CBfPtr,CStBeg); + if (CBfPtr > CStEnd) ex=errprt("CBfPtr > CStEnd",CBfPtr,CStEnd); + if (FBfPtr < FBfBeg) ex=errprt("FBfPtr < FBfBeg",FBfPtr,FBfBeg); + if (FBfPtr > FBfEnd) ex=errprt("FBfPtr > FBfEnd",FBfPtr,FBfEnd); + if (SBfPtr < SBfBeg) ex=errprt("SBfPtr < SBfBeg",SBfPtr,SBfBeg); + if (SBfPtr > SBfEnd) ex=errprt("SBfPtr > SBfEnd",SBfPtr,SBfEnd); +/* + * The order of pointers into the editing buffer should be: + * + * EBfBeg <= GapBeg <= GapEnd <= EBfEnd <= IBfEnd + */ + if (EBfBeg > GapBeg) ex=errprt("EBfBeg > GapBeg",EBfBeg,GapBeg); + if (GapBeg > GapEnd) ex=errprt("GapBeg > GapEnd",GapBeg,GapEnd); + if (GapEnd > EBfEnd) ex=errprt("GapEnd > EBfEnd",GapEnd,EBfEnd); + if (EBfEnd > IBfEnd) ex=errprt("EBfEnd > IBfEnd",EBfEnd,IBfEnd); + if (ex == EXIT_FAILURE) { + exit(EXIT_FAILURE); + } +} +#endif /* #if CONSISTENCY_CHECKING */ diff --git a/src/tecoc.h b/src/tecoc.h new file mode 100644 index 0000000..fd8cd90 --- /dev/null +++ b/src/tecoc.h @@ -0,0 +1,702 @@ +/***************************************************************************** + Tecoc.h + + This file contains most of the definitions needed by TECO-C files. +*****************************************************************************/ + +#define TVERSION 146 /* version number of TECO-C */ + +/***************************************************************************** + Bit masks for ED mode control flag. The ones that are commented out +are not used in TECO-C. They are included here because they are used by +TECO-11, and may be implemented in TECO-C someday. + +*****************************************************************************/ + +#define ED_CARET_OK 1 /* don't use "^" as control-char prefix */ +#define ED_YANK_OK 2 /* let yanks clear text buffer */ +/*#define ED_NO_EXP 4*/ /* don't allow arbitrary expansions */ +#define ED_PRES_DOT 16 /* preserve "dot" on failing searches */ +/*#define ED_IMMED_OK 32*/ /* allow immediate escape-sequence commands */ +#define ED_DOT_BY_ONE 64 /* move dot by one on iter. search failure */ +/*#define ED_NO_W 128*/ /* don't do automatic "^W" before prompt */ +#define ED_FF 128 /* do not stop read on FF */ +#if defined(unix) || defined(AMIGA) +#define ED_UNIXNL 256 /* use Unix-style newline line terminators */ +#endif +#define ED_VTGR 512 +#define ED_NOSCDEL 1024 /* old style delete handler */ +#define ED_BTEE 2048 /* use BTEE instead of DIAMOND */ +#define ED_STDOUT 4096 /* use standout for doeves pointer */ +#define ED_INVCR 8192 /* don't show CR in scope - closer to TECO-11 + but really not as good in my opinion (Mark Henderson)*/ + +/***************************************************************************** + Value for EH flag. +*****************************************************************************/ + +#define EH_COMMAND 4 /* on error, output failing command string */ + +/***************************************************************************** + Bit masks for ET mode control flag. The ones that are commented out +are not used in TECO-C. They are included here because they are used by +TECO-11. The 2048 bit is listed as "reserved for TECO-8" in the TECO-11 +source code. I needed another bit, so I used it. +*****************************************************************************/ + +#define ET_IMAGE_MODE 1 /* output without doing conversions */ +#define ET_SCOPE 2 /* use scope for delete and control-U */ +#define ET_READ_LOWER 4 /* accept lowercase input */ +#define ET_NO_ECHO 8 /* don't echo input on control-T */ +/*#define ET_CAN_CTRL_O 16*/ /* (TECO-11) cancel control-O on output */ +#define ET_NO_WAIT 32 /* read with no wait on control-T */ +/*#define ET_DETACH 64*/ /* process detached flag */ +#define ET_MUNG_MODE 128 /* mung mode */ +/*#define ET_TRUNCATE 256*/ /* (TECO-11) truncate lines on output */ +#define ET_WAT_SCOPE 512 /* "WATCH" code exists, terminal is scope */ +#define ET_WAT_REFRESH 1024 /* "WATCH" code exists, terminal is refresh */ +#define ET_BKSP_IS_DEL 2048 /* treat BACKSPACE like DEL on input */ +#define ET_EIGHTBIT 4096 /* it's an eight-bit terminal */ +#define ET_ACCENT_GRAVE 8192 /* accept ` as escape (for VT220 terminals) */ +#define ET_VT200 16384 /* special VT200 mode */ +#define ET_TRAP_CTRL_C 0100000 /* trap control-C */ + +/***************************************************************************** + Values for EU flag. +*****************************************************************************/ + +#define EU_NONE -1 /* no case flagging of any type */ +#define EU_LOWER 0 /* flag lowercase characters on output */ +#define EU_UPPER 1 /* flag uppercase characters on output */ + +/***************************************************************************** + These identifiers are bit masks for elements of the ChrMsk array. +The ChrMsk array is used by the macros defined in the ChrMac.h file and by +the ReadCS function to make the character input code fast. See the comment +above the definition of the ChrMsk array in file TECOC.C. +*****************************************************************************/ + +#define RCS_AST '\1' /* asterisk */ +#define RCS_BS '\2' /* backspace */ +#define RCS_CCH '\3' /* control char other than ^G, ^U or ^Z */ +#define RCS_CR '\4' /* carriage return */ +#define RCS_CTG '\5' /* control-G */ +#define RCS_CTU '\6' /* control-U */ +#define RCS_CTZ '\7' /* control-Z */ +#define RCS_DEF '\10' /* char other than RCS_AST, RCS_BS, etc. */ +#define RCS_DEL '\11' /* delete */ +#define RCS_GRV '\12' /* accent grave */ +#define RCS_LF '\13' /* line feed */ +#define RCS_LWR '\14' /* lowercase character */ +#define RCS_SP '\15' /* space */ +#define RCS_VF '\16' /* vertical tab or form feed */ +#define RCS_CTC '\17' /* control-C */ +#define CM_DIGIT '\20' /* digits */ +#define CM_LINE_TERM '\40' /* line terminators (lf, vt, ff) */ +#define CM_LOWER '\100' /* lowercase */ +#define CM_UPPER '\200' /* uppercase */ + +/***************************************************************************** + These identifiers are set by the search commands. They provide a way +for the search commands to all rely on common code, even when the commands +behave slightly differently. It's a terrible way to code, but it was only +done in the search code. +*****************************************************************************/ + +#define E_SEARCH 1 /* E_ command */ +#define FB_SEARCH 2 /* FB command */ +#define FK_SEARCH 3 /* FK command */ +#define N_SEARCH 4 /* N command */ +#define S_SEARCH 5 /* S command */ +#define U_SEARCH 6 /* _ command */ + +/***************************************************************************** + Identifiers for indices into the IFiles and OFiles arrays. +*****************************************************************************/ + +#define NOFDBS 3 /* number of output file data blocks */ + +#define POUTFL 0 /* primary output stream */ +#define SOUTFL 1 /* secondary output stream */ +#define EPRCFL 2 /* output stream used by E% command */ + +#define PINPFL 0 /* primary input stream */ +#define SINPFL 1 /* secondary input stream */ +#define EQFL 2 /* input stream used by EQ command */ +#define EIFL 3 /* first input stream used by EI command */ + +/***************************************************************************** + Identifiers for :EG special function types. +*****************************************************************************/ + +#define EG_INI 1 /* inititalization macro */ +#define EG_LIB 2 /* default macro library directory */ +#define EG_MEM 3 /* last-file-edited memory */ +#define EG_VTE 4 /* filename of video macro */ +#define EG_OTHER 5 /* system-specific :EG command */ +#define CLEAR_VAL 1 +#define GET_VAL 2 +#define SET_VAL 3 + +/***************************************************************************** + Function return codes. +*****************************************************************************/ + +#define FAILURE (-1) /* function return status */ +#define SUCCESS 0 /* function return status */ +#define FILENF 3 /* "file not found", returned by ZSWild and ZOpInp */ + +/***************************************************************************** + CmdMod Bits. +*****************************************************************************/ + +#define ATSIGN '\1' /* mask of "at sign" bit in CmdMod */ +#define COLON '\2' /* mask of "colon" bit in CmdMod */ +#define DCOLON '\4' /* mask of "double colon" bit in CmdMod */ +#define MARGIS '\10' /* mask of "m defined" bit in CmdMod */ + +/***************************************************************************** + Arguments to ZSetTT function. +*****************************************************************************/ + +#define TT8BIT 1 /* whether terminal can handle 8-bit characters */ +#define TTWIDTH 2 /* number of columns of charactes */ +#define TTHEIGHT 3 /* number of rows of characters */ + +/***************************************************************************** + Miscellaneous identifiers. +*****************************************************************************/ + +#define FFLINS 5 /* number of blank lines displayed for form feed */ +#define INFINITE -1L /* loop count value for infinite loops */ + +#define PRIMARY '\0' /* primary input or output stream specifier */ +#define SECNDARY '\1' /* secondary input or output stream specifier */ + +#define OPERAND 0 /* means element is an integer */ +#define OPERATOR 1 /* means element is + - * / & or | */ + +#define LOWER 0 /* case conversion mode specifier, for ^V, ^W */ +#define NONE 1 /* case conversion mode specifier */ +#define UPPER 2 /* case conversion mode specifier, for ^V, ^W */ + +/***************************************************************************** + define structure for expression stack +*****************************************************************************/ + +struct EStck { + LONG Elemnt; /* integer or operand character */ + int ElType; /* Entry's type: OPERATOR or OPERAND */ +}; + +/***************************************************************************** + define structure for loop stack +*****************************************************************************/ + +struct LStck { + LONG LIndex; /* loop repetition count */ + charptr LAddr; /* pointer to start of loop in command buf */ +}; + +/***************************************************************************** + define structure for q-registers +*****************************************************************************/ + +struct QReg { + charptr Start; /* start of text */ + charptr End_P1; /* end of text, plus one */ + LONG Number; /* numeric part of q-register */ +}; + +/***************************************************************************** + define structure for macro stack +*****************************************************************************/ + +struct MStck { + charptr CStBeg; /* saves CStBeg */ + charptr CBfPtr; /* saves CBfPtr */ + charptr CStEnd; /* saves CStEnd */ + WORD EStBot; /* saves EStBot */ + WORD EStTop; /* saves EStTop */ + WORD LStBot; /* saves LStBot */ + WORD LStTop; /* saves LStTop */ + QRptr QRgstr; /* local q-register table */ +}; + +/***************************************************************************** + Debugging macros +*****************************************************************************/ + +#if DEBUGGING +#define DBGFEN(lv,fnm,msg) static char *DbgFNm = fnm; DbgFEn(lv, DbgFNm, msg) +#define DBGFEX(lv,fnm,msg) DbgFEx(lv, fnm, msg) +#define DBGFMS(lv,fnm,msg) DbgFMs(lv, fnm, msg) +#else +#define DBGFEN(lv,fnm,msg) +#define DBGFEX(lv,fnm,msg) +#define DBGFMS(lv,fnm,msg) +#endif + +/***************************************************************************** + function definitions +*****************************************************************************/ + +#if USE_PROTOTYPES + +#if CHECKSUM_CODE +VVOID init_code_checksums(void); +VVOID check_code_checksums(void); +#endif + +#if CONSISTENCY_CHECKING +VVOID init_consistency_check(void); +VVOID check_consistency(void); +#endif + +DEFAULT BakSrc(void); /* backwards search to match 1st character */ +DEFAULT BldStr( /* build a string */ + charptr XBfBeg, /* beginning of build-string buffer */ + charptr XBfEnd, /* end of build-string buffer */ + charptr (*XBfPtr)); /* pointer into build-string buffer */ +VVOID ClenUp(void); /* clean up for TECO-C abort */ +DEFAULT CMatch( /* match a character */ + BOOLEAN *SamChr); /* returned match indicator */ +#if DEBUGGING +DEFAULT DbgDsp(void); /* debugging, control debugging display (^P) */ +VVOID DbgFEn( /* debugging, function entry */ + int DbgFLv, /* function display level */ + char *DbgFNm, /* function name */ + char *DbgMsg); /* an entry message, usually parameters */ +VVOID DbgFEx( /* debugging, function exit */ + int DbgFLv, /* function display level */ + char *DbgFNm, /* function name */ + char *DbgMsg); /* an exit message, usually return value */ +VVOID DbgFMs( /* debugging, function message */ + int DbgFLv, /* function display level */ + char *DbgFNm, /* function name */ + char *DbgMsg); /* an message */ +#endif +DEFAULT DoCJR( /* do C, J or R stuff */ + LONG HowFar); /* positive or negative displacement */ +VVOID DoEvEs( /* do an EV or ES mode control flag function */ + WORD Flag); +DEFAULT DoFlag( /* handle mode control flag */ + WORD *Flag); +VVOID EchoIt( /* echo a character to to terminal */ + unsigned char Charac); +VVOID ErrChr( /* display error message with character arg */ + WORD ErrNum, /* the error number */ + unsigned char EChr); /* character to imbed in message */ +VVOID ErrMsg( /* display error message */ + WORD ErrNum); /* the error number */ +VVOID ErrPSt( /* display error message with string arg */ + WORD ErrNum, /* the error number */ + charptr EBeg, /* string to imbed in message */ + charptr EPtr); /* ptr to end-of-string, plus one */ +VVOID ErrStr( /* display error message with string arg */ + WORD ErrNum, /* the error number */ + char *EStr); /* string to imbed in message */ +VVOID ErrUTC(void); /* unterminated command or macro */ +VVOID ErrVrb( /* display a verbose error message */ + WORD ErrNum); /* error message number */ +DEFAULT ExeA(void); /* execute an A command */ +DEFAULT ExeAtS(void); /* execute an at-sign (@) command */ +DEFAULT ExeB(void); /* execute a B command */ +DEFAULT ExeBar(void); /* execute a bar (|) command */ +DEFAULT ExeBSl(void); /* execute a backslash (\) command */ +DEFAULT ExeC(void); /* execute a C command */ +DEFAULT ExeCCC(void); /* execute a control-^ command */ +DEFAULT ExeCln(void); /* execute a colon (:) command */ +DEFAULT ExeCom(void); /* execute a comma (,) command */ +DEFAULT ExeCrt(void); /* execute a caret (^) command */ +DEFAULT ExeCSt(void); /* execute a command string */ +DEFAULT ExeCtA(void); /* execute a control-A command */ +DEFAULT ExeCtC(void); /* execute a control-C command */ +DEFAULT ExeCtD(void); /* execute a control-D command */ +DEFAULT ExeCtE(void); /* execute a control-E command */ +DEFAULT ExeCtI(void); /* execute a control-I (tab) command */ +DEFAULT ExeCtL(void); /* execute a control-L (form feed) command */ +DEFAULT ExeCtN(void); /* execute a control-N command */ +DEFAULT ExeCtO(void); /* execute a control-O command */ +DEFAULT ExeCtP(void); /* execute a control-P command */ +DEFAULT ExeCtQ(void); /* execute a control-Q command */ +DEFAULT ExeCtR(void); /* execute a control-R command */ +DEFAULT ExeCtS(void); /* execute a control-S command */ +DEFAULT ExeCtT(void); /* execute a control-T command */ +DEFAULT ExeCtU(void); /* execute a control-U command */ +DEFAULT ExeCtV(void); /* execute a control-V command */ +DEFAULT ExeCtW(void); /* execute a control-W command */ +DEFAULT ExeCtX(void); /* execute a control-X command */ +DEFAULT ExeCtY(void); /* execute a control-Y command */ +DEFAULT ExeCtZ(void); /* execute a control-Z command */ +DEFAULT ExeD(void); /* execute a D command */ +DEFAULT ExeDgt(void); /* execute a digit command */ +DEFAULT ExeDot(void); /* execute a dot (.) command */ +DEFAULT ExeDQu(void); /* execute a double-quote (") command */ +DEFAULT ExeE(void); /* execute on of the E commands */ +DEFAULT ExeEqu(void); /* execute an equals-sign (=) command */ +DEFAULT ExeEsc(void); /* execute an ESCAPE command */ +DEFAULT ExeExc(void); /* execute an exclamation-mark (!) command */ +DEFAULT ExeEY(void); /* execute an EY command */ +DEFAULT ExeF(void); /* execute one of the F commands */ +DEFAULT ExeFB(void); /* execute an FB command */ +DEFAULT ExeG(void); /* execute a G command */ +DEFAULT ExeGtr(void); /* execute a greater-than (>) command */ +DEFAULT ExeH(void); /* execute an H command */ +DEFAULT ExeI(void); /* execute an I command */ +DEFAULT ExeIll(void); /* execute an "illegal" command */ +DEFAULT ExeJ(void); /* execute a J command */ +DEFAULT ExeK(void); /* execute a K command */ +DEFAULT ExeK(void); /* execute a K command */ +DEFAULT ExeL(void); /* execute an L command */ +DEFAULT ExeLBr(void); /* execute a left-bracket ([) command */ +DEFAULT ExeLst(void); /* execute a less-than (<) command */ +DEFAULT ExeM(void); /* execute an M command */ +DEFAULT ExeN(void); /* execute a N command */ +DEFAULT ExeNul(void); /* execute a null command */ +DEFAULT ExeNYI(void); /* "not yet implemented" function */ +DEFAULT ExeO(void); /* execute an O command */ +DEFAULT ExeOpr(void); /* execute a operator (+,-,*, etc.) command */ +DEFAULT ExeP(void); /* execute a P or PW command */ +DEFAULT ExePrc(void); /* execute a percent {%} command */ +DEFAULT ExePW(void); /* execute a PW command */ +DEFAULT ExeQ(void); /* execute a Q command */ +DEFAULT ExeQes(void); /* execute a question-mark (?) command */ +DEFAULT ExeR(void); /* execute an R command */ +DEFAULT ExeRBr(void); /* execute a right-bracket (]) command */ +DEFAULT ExeRtP(void); /* execute a right-parenthesis command */ +DEFAULT ExeS(void); /* execute an S command */ +DEFAULT ExeSCl(void); /* execute a semi-colon (;) command */ +DEFAULT ExeT(void); /* execute a T command */ +DEFAULT ExeU(void); /* execute a U command */ +DEFAULT ExeUnd(void); /* execute an underbar (_) command */ +DEFAULT ExeUsc(void); /* execute control-_ command */ +DEFAULT ExeV(void); /* execute a V command */ +DEFAULT ExeW(void); /* execute a W command */ +DEFAULT ExeX(void); /* execute a X command */ +DEFAULT ExeY(void); /* execute a Y command */ +DEFAULT ExeZ(void); /* execute a Z command */ +DEFAULT FindES( /* find end of string */ + unsigned char TrmChr); /* termination char if no @ modifier */ +DEFAULT FindQR(void); /* find a q-register index */ +DEFAULT FlowEC(void); /* flow to end of conditional */ +DEFAULT FlowEE(void); /* flow to | or ' */ +DEFAULT FlowEL(void); /* flow to end of loop */ +DEFAULT GetAra(void); /* get m,n area */ +DEFAULT GetNmA(void); /* get numeric argument */ +DEFAULT IncCBP(void); /* increment CBfPtr */ +VVOID Init( /* initialize TECO-C */ + int argc, + char *argv[]); +DEFAULT InsStr( /* insert string into edit buffer */ + charptr string, + ptrdiff_t length); +BOOLEAN IsRadx( /* is the character in the radix set? */ + unsigned char Charac); +LONG Ln2Chr( /* convert line offset to character offset */ + LONG Value); +VVOID MakDBf( /* make digit buffer */ + LONG Binary, /* binary number to be converted */ + DEFAULT NRadix); /* radix to be used: 8, 10 or 16 */ +DEFAULT MakRom( /* make room in q-register */ + SIZE_T Amount); /* how much room to make */ +DEFAULT PopMac(void); /* pop variables after macro call */ +DEFAULT PshMac( /* push variables for macro call */ + charptr Start, /* start of new command string */ + charptr End); /* end of new command string, plus one */ +DEFAULT PushEx( /* push onto expression stack */ + LONG Item, + DEFAULT EType); +DEFAULT RdLine( /* read a line */ + BOOLEAN *EBfFul); /* returned "edit buffer is full" indicator */ +DEFAULT RdPage(void); /* read a page from a file */ +VVOID ReadCS(void); /* read command string */ +DEFAULT Replac(void); /* replace a string */ +DEFAULT Search( /* top level search */ + BOOLEAN RepCmd); /* TRUE if the command has two arguments */ +DEFAULT SinglP(void); /* execute a single P function */ +DEFAULT SkpCmd(void); /* skip a single command */ +DEFAULT SrcLop(void); /* search loop */ +DEFAULT SSerch(void); /* single search */ +VVOID TAbort( /* terminate TECO-C */ + DEFAULT tstat); +VVOID TypBuf( /* type a buffer on the terminal */ + charptr YBfBeg, + charptr YBfEnd); +VVOID TAbort( /* cleanup for TECO-C abort */ + DEFAULT tstat); +VVOID TypESt(void); /* type error string on terminal */ +VVOID UMinus(void); /* handle unary minus */ +DEFAULT WrPage( /* write to output file */ + DEFAULT OfIndx, /* index into OFiles array */ + charptr OBfBeg, /* address of output buffer beginning */ + charptr OBfEnd, /* address of output buffer end */ + LONG AddFF); /* -1 means add form feed, 0 means don't */ +voidptr ZAlloc( /* like standard malloc function */ + SIZE_T MemSiz); +VVOID ZBell(void); /* ring the terminal bell */ +DEFAULT ZChIn( /* input a character from the terminal */ + BOOLEAN NoWait); /* return immediately? */ +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 */ +VVOID ZClnUp(void); /* cleanup for TECO-C abort */ +#if DEBUGGING || CONSISTENCY_CHECKING +ULONG Zcp2ul( /* convert voidptr to unsigned long */ + voidptr cp); +#endif +VVOID ZDoCmd( /* terminate and pass command string to OS */ + charptr GBfBeg, + charptr GBfPtr); +VVOID ZDspBf( /* output a buffer to the terminal */ + charptr buffer, + SIZE_T length); +VVOID ZDspCh( /* display a character */ + char Charac); +DEFAULT ZExCtB(void); /* execute a ^B command */ +DEFAULT ZExCtH(void); /* execute a ^H command */ +DEFAULT ZExeEJ(void); /* execute an EJ command */ +VVOID ZExit( /* terminate TECO-C */ + DEFAULT estat); +VVOID ZFree( /* like standard free() function */ + voidptr pointer); +DEFAULT ZFrSrc(void); /* forward search to match 1st character */ +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? */ +VVOID ZIClos( /* close input file */ + DEFAULT IfIndx); /* index into IFiles array */ +VVOID ZOClDe( /* close and delete output file */ + DEFAULT OfIndx); /* index into OFiles array */ +VVOID ZOClos( /* close output file */ + DEFAULT OfIndx); /* index into OFiles array */ +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? */ +DEFAULT ZOpOut( /* open output file */ + DEFAULT OfIndx, /* output file indicator */ + BOOLEAN RepErr, /* report errors? */ + BOOLEAN Backup); /* create backup? TAA MOD */ +VVOID ZPrsCL( /* parse the command line */ + int argc, + char **argv); +DEFAULT ZPWild(void); /* preset the wildcard lookup filespec */ +voidptr ZRaloc( /* re-allocate memory*/ + voidptr OldBlk, + SIZE_T NewSiz); +DEFAULT ZRdLin( /* read a line */ + charptr ibuf, /* where to put string */ + ptrdiff_t ibuflen, /* max length of buf */ + int IfIndx, /* index into IFiles[] */ + DEFAULT *retlen); /* returned length of string */ +VVOID ZScrOp( /* do a screen operation */ + int OpCode); /* code for operation */ +DEFAULT ZSetTT( /* set a terminal parameter */ + DEFAULT TTWhat, /* what terminal parameter to set */ + DEFAULT TTVal); /* new value for the terminal parameter */ +DEFAULT ZSWild(void); /* search for next wildcard filename */ +VVOID ZTrmnl(void); /* open terminal input and output */ +VVOID ZVrbos( /* display verbose form of an error message */ + WORD ErrNum, /* error number (see DEFERR.h) */ + char *ErMnem); /* error mnemonic */ +DEFAULT ZWrBfr( /* write a buffer */ + DEFAULT OfIndx, /* index into OFiles array */ + charptr BfrBeg, /* address of output buffer beginning */ + charptr BfrEnd); /* address of output buffer end */ + + +#else /* else (not USE_PROTOTYPES) */ + +#if CHECKSUM_CODE +VVOID init_code_checksums (); +VVOID check_code_checksums (); +#endif + +#if CONSISTENCY_CHECKING +VVOID init_consistency_check(); +VVOID check_consistency(); +#endif + +DEFAULT BakSrc(); /* backwards search to match 1st character */ +DEFAULT BldStr(); /* build a string */ +VVOID ClenUp(); /* clean up for TECO-C abort */ +DEFAULT CMatch(); /* match a character */ +#if DEBUGGING +DEFAULT DbgDsp(); /* debugging, control debugging display */ +VVOID DbgFEn(); /* debugging, function entry */ +VVOID DbgFEx(); /* debugging, function exit */ +VVOID DbgFMs(); /* debugging, function message */ +#endif +DEFAULT DoCJR(); /* do C, J or R stuff */ +VVOID DoEvEs(); /* do an EV or ES mode control flag function */ +DEFAULT DoFlag(); /* handle mode control flag */ +VVOID EchoIt(); /* echo a character to to terminal */ +VVOID ErrChr(); /* display error message with character argument */ +VVOID ErrMsg(); /* display error message */ +VVOID ErrPSt(); /* display error message with string argument */ +VVOID ErrStr(); /* display error message with string argument */ +VVOID ErrUTC(); /* unterminated command or macro */ +VVOID ErrVrb(); /* display a verbose error message */ +DEFAULT ExeA(); /* execute an A command */ +DEFAULT ExeAtS(); /* execute an at-sign (@) command */ +DEFAULT ExeB(); /* execute a B command */ +DEFAULT ExeBar(); /* execute a bar (|) command */ +DEFAULT ExeBSl(); /* execute a backslash (\) command */ +DEFAULT ExeC(); /* execute a C command */ +DEFAULT ExeCCC(); /* execute a control-^ command */ +DEFAULT ExeCln(); /* execute a colon (:) command */ +DEFAULT ExeCom(); /* execute a comma (,) command */ +DEFAULT ExeCrt(); /* execute a caret (^) command */ +DEFAULT ExeCSt(); /* execute a command string */ +DEFAULT ExeCtA(); /* execute a control-A command */ +DEFAULT ExeCtC(); /* execute a control-C command */ +DEFAULT ExeCtD(); /* execute a control-D command */ +DEFAULT ExeCtE(); /* execute a control-E command */ +DEFAULT ExeCtI(); /* execute a control-I (tab) command */ +DEFAULT ExeCtL(); /* execute a control-L (form feed) command */ +DEFAULT ExeCtN(); /* execute a control-N command */ +DEFAULT ExeCtO(); /* execute a control-O command */ +DEFAULT ExeCtP(); /* execute a control-P command */ +DEFAULT ExeCtQ(); /* execute a control-Q command */ +DEFAULT ExeCtR(); /* execute a control-R command */ +DEFAULT ExeCtS(); /* execute a control-S command */ +DEFAULT ExeCtT(); /* execute a control-T command */ +DEFAULT ExeCtU(); /* execute a control-U command */ +DEFAULT ExeCtV(); /* execute a control-V command */ +DEFAULT ExeCtW(); /* execute a control-W command */ +DEFAULT ExeCtX(); /* execute a control-X command */ +DEFAULT ExeCtY(); /* execute a control-Y command */ +DEFAULT ExeCtZ(); /* execute a control-Z command */ +DEFAULT ExeD(); /* execute a D command */ +DEFAULT ExeDgt(); /* execute a digit command */ +DEFAULT ExeDot(); /* execute a dot (.) command */ +DEFAULT ExeDQu(); /* execute a double-quote (") command */ +DEFAULT ExeE(); /* execute on of the E commands */ +DEFAULT ExeEqu(); /* execute an equals-sign (=) command */ +DEFAULT ExeEsc(); /* execute an ESCAPE command */ +DEFAULT ExeExc(); /* execute an exclamation-mark (!) command */ +DEFAULT ExeEY(); /* execute an EY command */ +DEFAULT ExeF(); /* execute one of the F commands */ +DEFAULT ExeFB(); /* execute an FB command */ +DEFAULT ExeG(); /* execute a G command */ +DEFAULT ExeGtr(); /* execute a greater-than (>) command */ +DEFAULT ExeH(); /* execute an H command */ +DEFAULT ExeI(); /* execute an I command */ +DEFAULT ExeIll(); /* execute an "illegal" command */ +DEFAULT ExeJ(); /* execute a J command */ +DEFAULT ExeK(); /* execute a K command */ +DEFAULT ExeK(); /* execute a K command */ +DEFAULT ExeL(); /* execute an L command */ +DEFAULT ExeLBr(); /* execute a left-bracket ([) command */ +DEFAULT ExeLst(); /* execute a less-than (<) command */ +DEFAULT ExeM(); /* execute an M command */ +DEFAULT ExeN(); /* execute a N command */ +DEFAULT ExeNul(); /* execute a null command */ +DEFAULT ExeNYI(); /* "not yet implemented" function */ +DEFAULT ExeO(); /* execute an O command */ +DEFAULT ExeOpr(); /* execute a operator (+,-,*, etc.) command */ +DEFAULT ExeP(); /* execute a P or PW command */ +DEFAULT ExePrc(); /* execute a percent {%} command */ +DEFAULT ExePW(); /* execute a PW command */ +DEFAULT ExeQ(); /* execute a Q command */ +DEFAULT ExeQes(); /* execute a question-mark (?) command */ +DEFAULT ExeR(); /* execute an R command */ +DEFAULT ExeRBr(); /* execute a right-bracket (]) command */ +DEFAULT ExeRtP(); /* execute a right-parenthesis command */ +DEFAULT ExeS(); /* execute an S command */ +DEFAULT ExeSCl(); /* execute a semi-colon (;) command */ +DEFAULT ExeT(); /* execute a T command */ +DEFAULT ExeU(); /* execute a U command */ +DEFAULT ExeUnd(); /* execute an underbar (_) command */ +DEFAULT ExeUsc(); /* execute control-_ command */ +DEFAULT ExeV(); /* execute a V command */ +DEFAULT ExeW(); /* execute a W command */ +DEFAULT ExeX(); /* execute a X command */ +DEFAULT ExeY(); /* execute a Y command */ +DEFAULT ExeZ(); /* execute a Z command */ +DEFAULT FindES(); /* find end of string */ +DEFAULT FindQR(); /* find a q-register index */ +DEFAULT FlowEC(); /* flow to end of conditional */ +DEFAULT FlowEE(); /* flow to | or ' */ +DEFAULT FlowEL(); /* flow to end of loop */ +DEFAULT GetAra(); /* get m,n area */ +DEFAULT GetNmA(); /* get numeric argument */ +DEFAULT IncCBP(); /* increment CBfPtr */ +VVOID Init(); /* initialize TECO-C */ +DEFAULT InsStr(); /* insert string into edit buffer */ +BOOLEAN IsRadx(); /* is the character in the radix set? */ +LONG Ln2Chr(); /* convert line offset to character offset */ +VVOID MakDBf(); /* make digit buffer */ +DEFAULT MakRom(); /* make room in q-register */ +DEFAULT PopMac(); /* pop variables after macro call */ +DEFAULT PshMac(); /* push variables for macro call */ +DEFAULT PushEx(); /* push onto expression stack */ +DEFAULT RdLine(); /* read a line */ +DEFAULT RdPage(); /* read a page from a file */ +VVOID ReadCS(); /* read command string */ +DEFAULT Replac(); /* replace a string */ +DEFAULT Search(); /* top level search */ +DEFAULT SinglP(); /* execute a single P function */ +DEFAULT SkpCmd(); /* skip a single command */ +DEFAULT SrcLop(); /* search loop */ +DEFAULT SSerch(); /* single search */ +VVOID TAbort(); /* terminate TECO-C */ +VVOID TypBuf(); /* type a buffer on the terminal */ +VVOID TypESt(); /* type error string on terminal */ +VVOID UMinus(); /* handle unary minus */ +DEFAULT WrPage(); /* write to output file */ +voidptr ZAlloc(); /* like standard malloc function */ +VVOID ZBell(); /* ring the terminal bell */ +DEFAULT ZChIn(); /* input a character from the terminal */ +LONG ZClnEG(); /* execute special :EG command */ +VVOID ZClnUp(); /* cleanup for TECO-C abort */ +#if DEBUGGING || CONSISTENCY_CHECKING +ULONG Zcp2ul(); /* convert charptr to unsigned long */ +#endif +VVOID ZDoCmd(); /* terminate and pass command string to OS */ +VVOID ZDspBf(); /* output a buffer to the terminal */ +VVOID ZDspCh(); /* display a character */ +DEFAULT ZExCtB(); /* execute a ^B command */ +DEFAULT ZExCtH(); /* execute a ^H command */ +DEFAULT ZExeEJ(); /* execute an EJ command */ +VVOID ZExit(); /* terminate TECO-C */ +VVOID ZFree(); /* like standard free() function */ +DEFAULT ZFrSrc(); /* forward search to match 1st character */ +VVOID ZHelp(); /* display a help message */ +VVOID ZIClos(); /* close input file */ +VVOID ZOClDe(); /* close and delete output file */ +VVOID ZOClos(); /* close output file */ +DEFAULT ZOpInp(); /* open input file */ +DEFAULT ZOpOut(); /* open output file */ +VVOID ZPrsCL(); /* parse the command line */ +DEFAULT ZPWild(); /* preset the wildcard lookup filespec */ +voidptr ZRaloc(); /* re-allocate memory*/ +DEFAULT ZRdLin(); /* read a line */ +VVOID ZScrOp(); /* do a screen operation */ +DEFAULT ZSetTT(); /* set a terminal parameter */ +DEFAULT ZSWild(); /* search for next wildcard filename */ +VVOID ZTrmnl(); /* open terminal input and output */ +VVOID ZVrbos(); /* display verbose form of an error message */ +DEFAULT ZWrBfr(); /* write line to file */ +#endif +#if CURSES +void Scope(); +void centre(); +void dolf(); +void dobs(); +void ccs(); +void do_right(); +void do_left(); +void do_sf(); +void do_sr(); +void do_down(); +void do_up(); +void do_seetog(); +void redraw(); +void keypad_on(); +void keypad_off(); +#endif diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..d336e04 --- /dev/null +++ b/src/test.c @@ -0,0 +1,13 @@ +#include +void main(void) { + char *names="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + while (*names) { + printf("\001Q Register %c \001q%c:=\001 \001:q%c=", + *names, *names, *names); + printf("\001Q Register .%c \001q.%c:=\001 \001:q.%c=", + *names, *names, *names); + names++; + printf("^T\033\n"); + } +} diff --git a/src/tstsrc.tec b/src/tstsrc.tec new file mode 100644 index 0000000..e6d8365 --- /dev/null +++ b/src/tstsrc.tec @@ -0,0 +1,544 @@ + + + This file tests search commands. + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test some simple searches + + +hk iabcdefghi j +forward search for 1st char  sa .-1"e passed + | failed!!! + ' +forward search for 4th char  sd .-4"e passed + | failed!!! +' +forward search for last char  si .-9"e passed + | failed!!! +' +backwards search for 4th char  -sd .-4"e passed + | failed!!! +' +backwards search for 1st char  -sa .-1"e passed + | failed!!! +' + + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Ea match construct + + +test 1  jsa .-1"e passed + | failed!!! +' +test 2  jsba .-3"e passed + | failed!!! +' +test 3  jsha .-9"e passed + | failed!!! +' +test 4  jsbad .-4"e passed + | failed!!! +' +test 5  jsbaaa .-5"e passed + | failed!!! +' +test 6  jsaaaaaaaaa .-9"e passed + | failed!!! +' +hk +0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./0123456789:;<=>?@[\]^_`{|}~127iiA +test 7  jsa .-77"e passed + | failed!!! +' + + Test the ^Eb match construct + + +hki!@#$%&*() +jsb.-1"etest 1 passed +|test 1 failed!!! +' +js!b.-2"etest 2 passed +|test 2 failed!!! +' +js(b.-9"etest 3 passed +|test 3 failed!!! +' +js!b#.-3"etest 4 passed +|test 4 failed!!! +' +js!bbb.-4"etest 5 passed +|test 5 failed!!! +' +jsbbbbbbbbb.-9"etest 6 passed +|test 6 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! +jsb.-63"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Ec match construct + + +hkiabcdefghi +jsc.-1"etest 1 passed +|test 1 failed!!! +' +jsbc.-3"etest 2 passed +|test 2 failed!!! +' +jshc.-9"etest 3 passed +|test 3 failed!!! +' +jsbcd.-4"etest 4 passed +|test 4 failed!!! +' +jsbccc.-5"etest 5 passed +|test 5 failed!!! +' +jsccccccccc.-9"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#%&'()*+,-/:;<=>?@[\]^`{|}~127iiA +jsc.-64"etest 7 passed +|test 7 failed!!! +' +hki0123456789$. +jscccccccccccc.-12"etest 8 passed +|test 8 failed!!! +' + + Test the ^Ed match construct + + +hki0123456789 +jsd.-1"etest 1 passed +|test 1 failed!!! +' +js1d.-3"etest 2 passed +|test 2 failed!!! +' +js8d.-10"etest 3 passed +|test 3 failed!!! +' +js2d4.-5"etest 4 passed +|test 4 failed!!! +' +js2ddd.-6"etest 5 passed +|test 5 failed!!! +' +jsdddddddddd.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTU +iVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127ii0 +jsd.-119"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Eg match construct + + +^Uadef +hkiabcdefghi +jsGa.-4"etest 1 passed +|test 1 failed!!! +' +0^Ua1:^Ua2:^Ua3:^Ua4:^Ua5:^Ua6:^Ua7:^Ua8:^Ua9:^Ua10:^Ua11:^Ua +12:^Ua13:^Ua14:^Ua15:^Ua16:^Ua17:^Ua18:^Ua19:^Ua20:^Ua21:^Ua +22:^Ua23:^Ua24:^Ua25:^Ua26:^Ua27:^Ua28:^Ua29:^Ua30:^Ua31:^Ua +:^Ua !"#$%&'()*+,-./0123456789:;<=>?@JKLMNOPQRSTU +:^UaVWXYZ[\]^_`jklmnopqrstuvwxyz{|}127i +j:sga"ftest 2 passed +|test 2 failed!!! +' +hkiabcdefghi@ +jsga.-10"etest 3 passed +|test 3 failed!!! +' +hki@ +jsga.-1"etest 4 passed +|test 4 failed!!! +' + + Test the ^El match construct + + + +!10 is line feed, 11 is vertical tab, 12 is form feed! + +hk10i10i10i10i10i10i10i10i11i12i +jsl.-1"etest 1 passed +|test 1 failed!!! +' +hkixx10i10i10i10i10i10i10i11i12i +jsxxl.-3"etest 2 passed +|test 2 failed!!! +' +hkixxxxxxxx11i12i +js l.-10"etest 3 passed +|test 3 failed!!! +' +hk10i10i10i10i10i10i10i10i11i12i +jsllllllllll.-10"etest 4 passed +|test 4 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i13i14i15i16i17i18i19i20i21i22i +23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU +iVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127i12i +jsl.-126"etest 5 passed +|test 5 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Er match construct + + +hki0123456789 +jsr.-1"etest 1 passed +|test 1 failed!!! +' +js1r.-3"etest 2 passed +|test 2 failed!!! +' +js8r.-10"etest 3 passed +|test 3 failed!!! +' +js2r4.-5"etest 4 passed +|test 4 failed!!! +' +js2rrr.-6"etest 5 passed +|test 5 failed!!! +' +jsrrrrrrrrrr.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~127iia +jsr.-67"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Es match construct + + +hki  +jss.-1"etest 1 passed +|test 1 failed!!! +' +hkiab cde +jsbs.-3"etest 2 passed +|test 2 failed!!! +' +hkiab de +jss.-7"etest 3 passed +|test 3 failed!!! +' +hkiab de +jsbsd.-4"etest 4 passed +|test 4 failed!!! +' +hkiab de +jsbsd.-11"etest 5 passed +|test 5 failed!!! +' +hk0i1i2i3i4i5i6i7i8i10i11i12i13i14i15i16i17i18i +19i20i21i22i23i24i25i26i27i28i29i30i31i +i!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ +i[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127ii  +jss.-127"etest 6 passed +|test 6 failed!!! +' + + Test the ^Ev match construct + + +hkiabcdefghij +jsv.-1"etest 1 passed +|test 1 failed!!! +' +jsabv.-3"etest 2 passed +|test 2 failed!!! +' +jsiv.-10"etest 3 passed +|test 3 failed!!! +' +jsbvd.-4"etest 4 passed +|test 4 failed!!! +' +jsbvvv.-5"etest 5 passed +|test 5 failed!!! +' +jsvvvvvvvvvv.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`{|}~127iia +jsv.-93"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^Ew match construct + + +hkiABCDEFGHIJ +jsw.-1"etest 1 passed +|test 1 failed!!! +' +jsabw.-3"etest 2 passed +|test 2 failed!!! +' +jsiw.-10"etest 3 passed +|test 3 failed!!! +' +jsbwd.-4"etest 4 passed +|test 4 failed!!! +' +jsbwww.-5"etest 5 passed +|test 5 failed!!! +' +jswwwwwwwwww.-10"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$%&'()*+,-./:;<=>?@[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127iiA +jsw.-93"etest 7 passed +|test 7 failed!!! +' + + Test the ^Ex match construct + + +hki0123456789 +jsx.-1"etest 1 passed +|test 1 failed!!! +' +js1x.-3"etest 2 passed +|test 2 failed!!! +' +js8x.-10"etest 3 passed +|test 3 failed!!! +' +js2x4.-5"etest 4 passed +|test 4 failed!!! +' +js2xxx.-6"etest 5 passed +|test 5 failed!!! +' +jsxxxxxxxxxx.-10"etest 6 passed +|test 6 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^N match construct + + +hkiaaaaaaaaab +jsa.-10"etest 1 passed +|test 1 failed!!! +' +jsa^Na.-10"etest 2 passed +|test 2 failed!!! +' +hkiAAAbAAA +jsaaa.-5"etest 3 passed +|test 3 failed!!! +' +hki0123456789x9876543210 +jsd.-11"etest 4 passed +|test 4 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZaZZZZZ +js^N^EW.-27"etest 5 passed +|test 5 failed!!! +' +hkiabcdefghijklmnopqrstuvwxyz#oooo +jsv.-27"etest 6 passed +|test 6 failed!!! +' + + Test the ^S match construct + + +hki!@#$%&*() +js^S.-1"etest 1 passed +|test 1 failed!!! +' +js!^S.-2"etest 2 passed +|test 2 failed!!! +' +js(^S.-9"etest 3 passed +|test 3 failed!!! +' +js!^S#.-3"etest 4 passed +|test 4 failed!!! +' +js!^S^S^S.-4"etest 5 passed +|test 5 failed!!! +' +js^S^S^S^S^S^S^S^S^S.-9"etest 6 passed +|test 6 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! +js^S.-63"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^X match construct + + +hki0123456789 +js^X.-1"etest 1 passed +|test 1 failed!!! +' +js1^X.-3"etest 2 passed +|test 2 failed!!! +' +js8^X.-10"etest 3 passed +|test 3 failed!!! +' +js2^X4.-5"etest 4 passed +|test 4 failed!!! +' +js2^x^x^x.-6"etest 5 passed +|test 5 failed!!! +' +js^X^x^x^X^X^X^X^X^X^X.-10"etest 6 passed +|test 6 failed!!! +' + + The remaining tests test features not found in TECO-11. + +eo-99"lexiting. +oexit' + + Test the ^Em match construct + + +hkiabcdefghi +jsma.-1"etest 1 passed +|test 1 failed!!! +' +jsmd.-4"etest 2 passed +|test 2 failed!!! +' +jsmi.-9"etest 3 passed +|test 3 failed!!! +' +hkiabbbbbc +jsmb.-6"etest 4 passed +|test 4 failed!!! +' +jsa^Embc.-7"etest 5 passed +|test 5 failed!!! +' +jsabbbbb^Emc.-7"etest 6 passed +|test 6 failed!!! +' + + Test the ^E match construct + + +hkiabcdefghi +js<141>.-1"etest 1 passed +|test 1 failed!!! +' +jsb<143>.-3"etest 2 passed +|test 2 failed!!! +' +jsh<151>.-9"etest 3 passed +|test 3 failed!!! +' +jsb<143>d.-4"etest 4 passed +|test 4 failed!!! +' +jsb<143><144><145>.-5"etest 5 passed +|test 5 failed!!! +' +js<141><142><143><144><145><146><147><150><151>.-9"etest 6 passed +|test 6 failed!!! +' +hk0i1i2i3i4i5i6i7i8i9i10i11i12i13i14i15i16i17i +18i19i20i21i22i23i24i25i26i27i28i29i30i31i +i !"#$&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU +iVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~127ii% +js<45>.-128"etest 7 passed +|test 7 failed!!! +' + + Please press the space bar to continue, or CTRL-A to exit + +-1"eex' + + Test the ^E[a,b,c...] match construct ??? + + +hki!@#$%&*() +js[a,b,%,d].-5"etest 1 passed +|test 1 failed!!! +' +js![a,b,c,@].-2"etest 2 passed +|test 2 failed!!! +' +js([)].-9"etest 3 passed +|test 3 failed!!! +' +js![a,b,c,d,e,f,g,h,i,j,k,l,m,@]#.-3"etest 4 passed +|test 4 failed!!! +' +js!^S^S^S.-4"etest 5 passed +|test 5 failed!!! +' +js^S^S^S^S^S^S^S^S^S.-9"etest 6 passed +|test 6 failed!!! +' +hkiABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! +js^S.-63"etest 7 passed +|test 7 failed!!! +' +!exit! +ex diff --git a/src/typbuf.c b/src/typbuf.c new file mode 100644 index 0000000..4512355 --- /dev/null +++ b/src/typbuf.c @@ -0,0 +1,132 @@ +/***************************************************************************** + TypBuf() + This function displays a buffer on the terminal screen. YBfBeg +points to the first character of the buffer, and YBfEnd points to the +character following the last character of the buffer. + If the "no conversions" bit is not set in the ET flag, then this +function will convert non-displayable characters into a displayable form +before displaying them. The following conversions are performed: + 1. uppercase and lowercase conversions based on EU flag + 2. is not output + 3. to + 4. to + 5. ^G to and ^G + 6. to $ + 7. all control characters except , , , and the + ones listed above to the ^x format, where x is uppercase + It is inefficient (though easy) to simply output each character in the +buffer to be displayed individually, one after the other. To make output +to the terminal fast requires calls to ZDspBf, which outputs a group of +characters in one operation. The following code groups each sequence of +characters containing no "convertable" characters and calls ZDspBf with the +group. Whenever a character which needs to be converted is encountered, +the group up to the character is output, a separate output call is made +for the special character, and another group is started. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "chmacs.h" /* define character processing macros */ +VVOID TypBuf(YBfBeg, YBfEnd) /* type a buffer on the terminal */ +charptr YBfBeg; +charptr YBfEnd; +{ + charptr YBfPtr; +#if DEBUGGING + static char *DbgFNm = "TypBuf"; + sprintf(DbgSBf,"YBfBeg = %ld, YBfEnd = %ld, (length = %ld)", + Zcp2ul(YBfBeg), Zcp2ul(YBfEnd), (YBfEnd-YBfBeg)); + DbgFEn(5,DbgFNm,DbgSBf); +#endif + if (EtFlag & ET_IMAGE_MODE) { /* if no conversions */ + ZDspBf(YBfBeg, YBfEnd-YBfBeg); + DBGFEX(5,DbgFNm,NULL); + return; + } + YBfPtr = YBfBeg; + while (YBfPtr < YBfEnd && !GotCtC) { + if (EuFlag != EU_NONE) { /* do case flagging? */ + if (Is_Lower(*YBfPtr)) { +/* + * It is lowercase. If EuFlag is EU_LOWER, flag it. In any case, convert + * to uppercase for display. + */ + if (YBfPtr != YBfBeg) { + ZDspBf(YBfBeg, YBfPtr-YBfBeg); + } + if (EuFlag == EU_LOWER) { + ZDspCh('\''); /* flag it */ + } + ZDspCh(*YBfPtr & '\137'); + YBfBeg = ++YBfPtr; + continue; + } else if (Is_Upper(*YBfPtr) && (EuFlag == EU_UPPER)) { +/* + * it is uppercase and we're flagging uppercase. + */ + if (YBfPtr != YBfBeg) { + ZDspBf(YBfBeg, YBfPtr-YBfBeg); + } + ZDspCh('\''); /* flag it */ + ZDspCh(*YBfPtr); + YBfBeg = ++YBfPtr; + continue; + } +/* else it isn't lower or uppercase, fall through...*/ + } +/* + * if *YBfPtr is a line feed, display what we've accumulated so far. + * We do this so ^C's can interrupt the display of a large buffer. + * + * else if the character is displayable, accumulate it + * + * else (the character is a control character), handle it + */ + if (*YBfPtr == LINEFD) { + ++YBfPtr; + ZDspBf(YBfBeg, YBfPtr-YBfBeg); + YBfBeg = YBfPtr; + } else if (((*YBfPtr > USCHAR) && (*YBfPtr < DELETE)) || + (*YBfPtr == TABCHR) || + (*YBfPtr == CRETRN)) { + ++YBfPtr; + } else if (*YBfPtr & '\200') { /* MSB set? */ + if (EtFlag & ET_EIGHTBIT) { + ++YBfPtr; + } else { + if (YBfPtr != YBfBeg) { + ZDspBf(YBfBeg, YBfPtr-YBfBeg); + } + ZDspCh('['); + MakDBf((LONG)*YBfPtr, 16); + *DBfPtr++ = ']'; + ZDspBf(DBfBeg, DBfPtr-DBfBeg); + YBfBeg = ++YBfPtr; + } + } else { /* it's a control character */ + if (YBfPtr != YBfBeg) { + ZDspBf(YBfBeg, YBfPtr-YBfBeg); + } + switch (*YBfPtr) { + case ESCAPE: ZDspCh('$'); + break; + case BAKSPC: ZDspBf("^H",2); + break; + case FORMFD: ZDspCh('\r'); + /* fall through */ + case VRTTAB: ZDspBf("\n\n\n\n",4); + /* fall through */ + case DELETE: break; + case CTRL_G: ZDspCh(CTRL_G); + default: ZDspCh('^'); + ZDspCh(*YBfPtr | '\100'); + } + YBfBeg = ++YBfPtr; + } + } + if (YBfPtr != YBfBeg) { + ZDspBf(YBfBeg, YBfPtr-YBfBeg); + } + DBGFEX(5,DbgFNm,NULL); +} diff --git a/src/typest.c b/src/typest.c new file mode 100644 index 0000000..859e6e4 --- /dev/null +++ b/src/typest.c @@ -0,0 +1,13 @@ +/***************************************************************************** + TypESt() + This function types the erroneous command string. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +VVOID TypESt() /* type erroneous command str */ +{ + TypBuf(CStBeg,CBfPtr); + ZDspBf("?\r\n", 3); +} diff --git a/src/uminus.c b/src/uminus.c new file mode 100644 index 0000000..34e21fc --- /dev/null +++ b/src/uminus.c @@ -0,0 +1,22 @@ +/***************************************************************************** + UMinus() + This function is called when a command is executed which can have a +numeric argument of "-", like "-C". The command "-C" really means "-1C". +This function looks at the expression stack to see if it contains only a +minus-sign operand. It it does, it is replaced with a -1 operator. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +VVOID UMinus() /* turn '-' arg into -1 */ +{ + ESptr ESp; + if (EStTop == (EStBot + 1)) { /* if only one guy */ + ESp = &(EStack[EStTop]); + if (ESp->ElType == OPERATOR && /* and it's an operator */ + ESp->Elemnt == '-') { /* and it's a minus sign */ + ESp->Elemnt = -1L; /* then convert to -1 */ + ESp->ElType = OPERAND; + } + } +} diff --git a/src/video.txt b/src/video.txt new file mode 100644 index 0000000..2d46eb6 --- /dev/null +++ b/src/video.txt @@ -0,0 +1,70 @@ +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/vrbmsg.h b/src/vrbmsg.h new file mode 100644 index 0000000..8d0cfab --- /dev/null +++ b/src/vrbmsg.h @@ -0,0 +1,288 @@ +/**************************************************************************** + This file contains the verbose forms of TECO error messages. It is +an include file because the contents are shared by at least two of the "Z" +files, and the contents are large. + IMPORTANT: If you change this file, you will need to change +TECOC.RNH, ERR.C and DEFERR.H !!! +*****************************************************************************/ +#if defined(__POWERC) +static char *ParaTx[] = { + "Verbose messages not loaded", + NULL +}; +static int StartP[] = { + /* ERR_ARG 0 */ 0, /* ERR_BNI 1 */ 0, /* ERR_DTB 2 */ 0, + /* ERR_FNF 3 */ 0, /* ERR_ICE 4 */ 0, /* ERR_IEC 5 */ 0, + /* ERR_IFC 6 */ 0, /* ERR_IIA 7 */ 0, /* ERR_ILL 8 */ 0, + /* ERR_ILN 9 */ 0, /* ERR_IPA 10 */ 0, /* ERR_IQC 11 */ 0, + /* ERR_IQN 12 */ 0, /* ERR_IRA 13 */ 0, /* ERR_ISA 14 */ 0, + /* ERR_ISS 15 */ 0, /* ERR_IUC 16 */ 0, /* ERR_MAP 17 */ 0, + /* ERR_MEM 18 */ 0, /* ERR_NAB 19 */ 0, /* ERR_NAC 20 */ 0, + /* ERR_NAE 21 */ 0, /* ERR_NAP 22 */ 0, /* ERR_NAQ 23 */ 0, + /* ERR_NAS 24 */ 0, /* ERR_NAU 25 */ 0, /* ERR_NCA 26 */ 0, + /* ERR_NFI 27 */ 0, /* ERR_NFO 28 */ 0, /* ERR_NYA 29 */ 0, + /* ERR_NYI 30 */ 0, /* ERR_OFO 31 */ 0, /* ERR_PDO 32 */ 0, + /* ERR_PES 33 */ 0, /* ERR_POP 34 */ 0, /* ERR_SNI 35 */ 0, + /* ERR_SRH 36 */ 0, /* ERR_STL 37 */ 0, /* ERR_TAG 38 */ 0, + /* ERR_UTC 39 */ 0, /* ERR_UTM 40 */ 0, /* ERR_XAB 41 */ 0, + /* ERR_YCA 42 */ 0, /* ERR_IFE 43 */ 0, /* ERR_SYS 44 */ 0, + /* ERR_UCD 45 */ 0, /* ERR_UCI 46 */ 0, /* ERR_UCO 47 */ 0, + /* ERR_UFI 48 */ 0, /* ERR_UFO 49 */ 0, /* ERR_URC 50 */ 0, + /* ERR_URE 51 */ 0, /* ERR_URL 52 */ 0, /* ERR_UWL 53 */ 0 +}; +#else +static char *ParaTx[] = { + /* ERR_ARG 0 improper arguments */ + /* 0*/ "Three arguments are given (a,b,c or H,c).", + /* 1*/ NULL, + /* ERR_BNI 1 > not in iteration */ + /* 2*/ "There is a close angle bracket not matched by an open", + /* 3*/ "angle bracket somewhere to its left. (Note: an", + /* 4*/ "iteration in a macro stored in a Q-register must be", + /* 5*/ "complete within the Q-register.)", + /* 6*/ NULL, + /* ERR_DTB 2 delete too big */ + /* 7*/ "An nD command has been attempted which is not contained", + /* 8*/ "within the current page.", + /* 9*/ NULL, + /* ERR_FNF 3 file not found "filename" */ + /* 10*/ "The requested input file could not be located. If this", + /* 11*/ "occurred within a macro, the colon modified ER or EB", + /* 12*/ "command may be necessary.", + /* 13*/ NULL, + /* ERR_ICE 4 illegal ^E command in search argument */ + /* 14*/ "A search argument contains a ^E command that is either", + /* 15*/ "not defined or incomplete. The only valid ^E commands", + /* 16*/ "in search arguments are: ^EA, ^ED, ^EV, ^EW, ^EL, ^ES,", + /* 17*/ "^E and ^E[a,b,c...]", + /* 18*/ NULL, + /* ERR_IEC 5 illegal character "x" after E */ + /* 19*/ "An invalid E command has been executed. The E character", + /* 20*/ "must be followed by an alphabetic to form a legal E", + /* 21*/ "command (i.e. ER or EX).", + /* 22*/ NULL, + /* ERR_IFC 6 illegal character "x" after F */ + /* 23*/ "An illegal F command has been executed.", + /* 24*/ NULL, + /* ERR_IIA 7 illegal insert argument */ + /* 25*/ "A command of the form \"nItext$\" was attempted. This", + /* 26*/ "combination of character and text insertion is illegal.", + /* 27*/ NULL, + /* ERR_ILL 8 illegal command "x" */ + /* 28*/ "An attempt has been made to execute an invalid TECO", + /* 29*/ "command.", + /* 30*/ NULL, + /* ERR_ILN 9 illegal number */ + /* 31*/ "An 8 or 9 has been entered when the radix of TECO is set", + /* 32*/ "to octal.", + /* 33*/ NULL, + /* ERR_IPA 10 negative or 0 argument to P */ + /* 34*/ "The argument preceding a P or PW command is negative or", + /* 35*/ "0.", + /* 36*/ NULL, + /* ERR_IQC 11 illegal character "x" following " */ + /* 37*/ "One of the valid \" commands did not follow the \". Refer", + /* 38*/ "to Section 5.14 (conditional execution commands) for", + /* 39*/ "the legal set of commands.", + /* 40*/ NULL, + /* ERR_IQN 12 illegal q-register name "x" */ + /* 41*/ "An illegal Q-register name was specified in one of the", + /* 42*/ "Q-register commands.", + /* 43*/ NULL, + /* ERR_IRA 13 illegal radix argument to ^R */ + /* 44*/ "The argument to a ^R radix command must be 8, 10 or 16.", + /* 45*/ NULL, + /* ERR_ISA 14 illegal search argument */ + /* 46*/ "The argument preceding a search command is 0. This", + /* 47*/ "argument must not be 0.", + /* 48*/ NULL, + /* ERR_ISS 15 illegal search string */ + /* 49*/ "One of the search string special characters (^Q, ^V, ^W,", + /* 50*/ "etc.) would have modified the search string delimiter", + /* 51*/ "(usually ESCAPE).", + /* 52*/ NULL, + /* ERR_IUC 16 illegal character "x" following ^ */ + /* 53*/ "The character following a ^ must have an ASCII value", + /* 54*/ "between 100 and 137 inclusive or between 141 and 172", + /* 55*/ "inclusive.", + /* 56*/ NULL, + /* ERR_MAP 17 missing ' */ + /* 57*/ "Every conditional (opened with the \" command) must be", + /* 58*/ "closed with the ' command.", + /* 59*/ NULL, + /* ERR_MEM 18 memory overflow */ + /* 60*/ "Insufficient memory available to complete the current", + /* 61*/ "command. Make sure the Q-register area does not contain", + /* 62*/ "much unnecessary text. Breaking up the text area into", + /* 63*/ "multiple pages might be useful.", + /* 64*/ NULL, + /* ERR_NAB 19 no argument before ^_ */ + /* 65*/ "The ^_ command must be preceded by either a specific", + /* 66*/ "numeric argument or a command that returns a numeric", + /* 67*/ "value.", + /* 68*/ NULL, + /* ERR_NAC 20 no argument before , */ + /* 69*/ "A command has been executed in which a , is not preceded", + /* 70*/ "by a numeric argument.", + /* 71*/ NULL, + /* ERR_NAE 21 no argument before = */ + /* 72*/ "The =, ==, or === command must be preceded by either a", + /* 73*/ "specific numeric argument or a command that returns a", + /* 74*/ "numeric value.", + /* 75*/ NULL, + /* ERR_NAP 22 no argument before ) */ + /* 76*/ "A ) parenthesis has been encountered and is not properly", + /* 77*/ "preceded by a specific numeric argument or a command", + /* 78*/ "that returns a numeric value.", + /* 79*/ NULL, + /* ERR_NAQ 23 no argument before " */ + /* 80*/ "The \" commands must be preceded by a single numeric", + /* 81*/ "argument on which the decision to execute the following", + /* 82*/ "commands or skip to the matching ' is based.", + /* 83*/ NULL, + /* ERR_NAS 24 no argument before ; */ + /* 84*/ "The ; command must be preceded by a single numeric", + /* 85*/ "argument on which the decision to execute the following", + /* 86*/ "commands or skip to the matching > is based.", + /* 87*/ NULL, + /* ERR_NAU 25 no argument before U */ + /* 88*/ "The U comand must be preceded by either a specific", + /* 89*/ "numeric argument or a command that returns a numeric", + /* 90*/ "value.", + /* 91*/ NULL, + /* ERR_NCA 26 negative argument to , */ + /* 92*/ "A comma was preceded by a negative number.", + /* 93*/ NULL, + /* ERR_NFI 27 no file for input */ + /* 94*/ "Before issuing an input command, such as Y, it is", + /* 95*/ "necessary to open an input file by use of a command such", + /* 96*/ "as ER or EB.", + /* 97*/ NULL, + /* ERR_NFO 28 no file for output */ + /* 98*/ "Before issuing an output command, such as N or P,", + /* 99*/ "it is necessary to open an output file by use of a", + /*100*/ "command such as EW or EB.", + /*101*/ NULL, + /* ERR_NYA 29 numeric argument with Y */ + /*102*/ "The Y command must not be preceded by either a numeric", + /*103*/ "argument or a command that returns a numeric value.", + /*104*/ NULL, + /* ERR_NYI 30 not yet implemented */ + /*105*/ "A command was issued that is not yet implemented in this", + /*106*/ "version of TECO.", + /*107*/ NULL, + /* ERR_OFO 31 output file already open */ + /*108*/ "A command has been executed which tried to create an", + /*109*/ "output file, but an output file currently is open. It", + /*110*/ "is typically appropriate to use the EC or EK command as", + /*111*/ "the situation calls for to close the output file.", + /*112*/ NULL, + /* ERR_PDO 32 push-down list overflow */ + /*113*/ "The command string has become too complex. Simplify it.", + /*114*/ NULL, + /* ERR_PES 33 attempt to pop empty stack */ + /*115*/ "A ] command (pop off q-register stack into a q-register)", + /*116*/ "was encountered when there was nothing on the q-register", + /*117*/ "stack.", + /*118*/ NULL, + /* ERR_POP 34 attempt to move pointer off page with "x" */ + /*119*/ "A J, C or R command has been executed which attempted to", + /*120*/ "move the pointer off the page. The result of executing", + /*121*/ "one of these commands must leave the pointer between 0", + /*122*/ "and Z, inclusive. The characters referenced by a D or", + /*123*/ "nA command must also be within the buffer boundary.", + /*124*/ NULL, + /* ERR_SNI 35 ; not in iteration */ + /*125*/ "A ; command has been executed outside of an open", + /*126*/ "iteration bracket. This command may only be executed", + /*127*/ "within iteration brackets.", + /*128*/ NULL, + /* ERR_SRH 36 search failure "text" */ + /*129*/ "A search command not preceded by a colon modifier and", + /*130*/ "not within an iteration has failed to find the specified", + /*131*/ "\"text\". After an S search fails the pointer is left at", + /*132*/ "the beginning of the buffer. After an N or _ search", + /*133*/ "fails the last page of the input file has been input", + /*134*/ "and, in the case of N, output, and the buffer is", + /*135*/ "cleared. In the case of an N search it is usually", + /*136*/ "necessary to close the output file and reopen it for", + /*137*/ "continued editing.", + /*138*/ NULL, + /* ERR_STL 37 string too long */ + /*139*/ "A search or file name string is too long. This is most", + /*140*/ "likely the result of a missing ESCAPE after the string.", + /*141*/ NULL, + /* ERR_TAG 38 missing tag !tag! */ + /*142*/ "The tag !tag! specified by an O command cannot be", + /*143*/ "found. This tag must be in the same macro level as the", + /*144*/ "O command referencing it.", + /*145*/ NULL, + /* ERR_UTC 39 unterminated command "x" */ + /*146*/ "This is a general error which is usually caused by an", + /*147*/ "unterminated insert, search, or filename argument, an", + /*148*/ "unterminated ^A message, an unterminated tag or comment", + /*149*/ "(i.e., unterminated ! construct), or a missing '", + /*150*/ "character which closes a conditional execution command.", + /*151*/ NULL, + /* ERR_UTM 40 unterminated macro */ + /*152*/ "This error is that same as the ?UTC error except that the", + /*153*/ "unterminated command was executing from a Q-register", + /*154*/ "(i.e., it was a macro). (Note: An entire command", + /*155*/ "sequence stored in a q-register must be complete within", + /*156*/ "the Q-register.)", + /*157*/ NULL, + /* ERR_XAB 41 execution aborted */ + /*158*/ "Execution of TECO was aborted. This is usually due to", + /*159*/ "the typing of .", + /*160*/ NULL, + /* ERR_YCA 42 Y command aborted */ + /*161*/ "An attempt has been made to execute a Y or _ search", + /*162*/ "command with an output file open, that would cause text", + /*163*/ "in the text buffer to be erased without outputting it to", + /*164*/ "the output file. The ED command controls this check.", + /*165*/ NULL, + /* ERR_IFE 43 ill-formed numeric expression */ + /*166*/ "The numeric expression preceding a command doesn't make", + /*167*/ "sense. For example, 5+ isn't a complete expression.", + /* ERR_SYS 44 %s */ + /*168*/ NULL, + /* ERR_UCD 45 unable to close and delete output file */ + /*169*/ NULL, + /* ERR_UCI 46 unable to close input file */ + /*170*/ NULL, + /* ERR_UCO 47 unable to close output file */ + /*171*/ NULL, + /* ERR_UFI 48 unable to open file "x" for input */ + /*172*/ NULL, + /* ERR_UFO 49 unable to open file "x" for output */ + /*173*/ NULL, + /* ERR_URC 50 unable to read character from terminal */ + /*174*/ NULL, + /* ERR_URE 51 unable to read TECO command file */ + /*175*/ NULL, + /* ERR_URL 52 unable to read line from input file */ + /*176*/ NULL, + /* ERR_UWL 53 unable to write line to output file */ + /*177*/ NULL +}; +static int StartP[] = { + /* ERR_ARG 0 */ 0, /* ERR_BNI 1 */ 2, /* ERR_DTB 2 */ 7, + /* ERR_FNF 3 */ 10, /* ERR_ICE 4 */ 14, /* ERR_IEC 5 */ 19, + /* ERR_IFC 6 */ 23, /* ERR_IIA 7 */ 25, /* ERR_ILL 8 */ 28, + /* ERR_ILN 9 */ 31, /* ERR_IPA 10 */ 34, /* ERR_IQC 11 */ 37, + /* ERR_IQN 12 */ 41, /* ERR_IRA 13 */ 44, /* ERR_ISA 14 */ 46, + /* ERR_ISS 15 */ 49, /* ERR_IUC 16 */ 53, /* ERR_MAP 17 */ 57, + /* ERR_MEM 18 */ 60, /* ERR_NAB 19 */ 65, /* ERR_NAC 20 */ 69, + /* ERR_NAE 21 */ 72, /* ERR_NAP 22 */ 76, /* ERR_NAQ 23 */ 80, + /* ERR_NAS 24 */ 84, /* ERR_NAU 25 */ 88, /* ERR_NCA 26 */ 92, + /* ERR_NFI 27 */ 94, /* ERR_NFO 28 */ 98, /* ERR_NYA 29 */ 102, + /* ERR_NYI 30 */ 105, /* ERR_OFO 31 */ 108, /* ERR_PDO 32 */ 113, + /* ERR_PES 33 */ 115, /* ERR_POP 34 */ 119, /* ERR_SNI 35 */ 125, + /* ERR_SRH 36 */ 129, /* ERR_STL 37 */ 139, /* ERR_TAG 38 */ 142, + /* ERR_UTC 39 */ 146, /* ERR_UTM 40 */ 152, /* ERR_XAB 41 */ 158, + /* ERR_YCA 42 */ 161, /* ERR_IFE 43 */ 166, /* ERR_SYS 44 */ 168, + /* ERR_UCD 45 */ 169, /* ERR_UCI 46 */ 170, /* ERR_UCO 47 */ 171, + /* ERR_UFI 48 */ 172, /* ERR_UFO 49 */ 173, /* ERR_URC 50 */ 174, + /* ERR_URE 51 */ 175, /* ERR_URL 52 */ 176, /* ERR_UWL 53 */ 177 +}; +#endif diff --git a/src/win/clpars.ori b/src/win/clpars.ori new file mode 100644 index 0000000..33209e9 --- /dev/null +++ b/src/win/clpars.ori @@ -0,0 +1,801 @@ +!CLPARS.TEC V2.2 5-June-1991 Pete Siemsen and Mark Henderson! + +!+*************************************************************************** + This macro is the imbedded command-line parsing macro for TECOC. It + was created by extracting the imbedded command-line parsing macro from the + TECO-11 executable file and then modifying it. + + This macro is compiled into TECO-C. This is the human-readable + source code. To compress it (remove comments, extra whitespace, etc.) + into an unreadable version in file CLPARS.TEC, do the following command + with a working TECO: + + mung squ clpars.tec=clpars.tes/d:n/l:y/b:y/t:n/c:+/w:n/a:y/e:n + + Then run genclp to convert CLPARS.TEC into CLPARS.H, a C include file. + + Notes: + + 1. On entry, Q1 contains a value + + 2. Bits in Q-register 1 have the following meanings: + + 1 /VTEDIT + 2 /INSPECT + 4 /NOMEMORY + 8 /FIND + 16 /SEEALL + 32 /HOLD + 64 /NOPAGE + 128 /SCROLL + 256 /NOCREATE + 512 /NORENAME + 1024 unused + 2048 input file is open + 4096 /NOINI + 8192 force setting of filespec memory + 16384 input filename is in edit buffer + 32768 ??? + + 3. Q-register 2 holds numeric argument of /SCROLL:n switch + + 4. Q-register Y holds the command-line option character, which + is a slash on most systems, and a dash under Unix. + + 5. Q-register .T holds a macro which is needed only when the :EGMEM + command isn't supported. It generates (in q-register F) the + name of a file that holds filename memory. + + 6. Q-register F holds the name of the file used to save file names. + +****************************************************************************! + +!+ save the q-registers that we'll be changing ! +[F0,0XF +[90,0X9 +[00,0X0 +[20,0X2 +10U0[0 !+ radix 10 ! +U0[00 !+ case independent searching ! +EDU0[0ED&4ED !+ turn on automatic memory expansion ! +EUU0[0-1EU !+ no case flagging on typeout ! +ESU0[00ES !+ no typeout after searches ! +ETU0[032768#32#8#1,0ET !+ ^C trap, read nowait and noecho, image typeout ! +Q1U0 !+ Q0 = Q1 ! +0U1[1 +0,0X1 +-1EJ-25600"E !+ if Unix ! + 0u4 + ^^-UY !+ Unix command lines delimit options with '-' ! +| + ^^/UY !+ VMS command lines delimit options with '/' ! +' + +!+*************************************************************************** + Put a subroutine into Q-register .T which, when called, fills Q-register + F with a filename to be used to store filespec memory. This subroutine + will only be needed if the :EGMEM isn't supported. +****************************************************************************! +@^U.T/ + :QF"E !+ if we haven't already set q-register F ! + .U.1 !+ remember where we are in edit buffer ! + Iteco !+ start building "tecoxxxx.tmp" ! + 0EJ\ !+ insert process id into edit buffer ! + .-Q1U.L !+ length of "tecoxxxx" part of filename ! + Q.L-8"G !+ if it's longer than 8 characters ! + Q.1+4J !+ go to front of the digits ! + Q.L-8D !+ prune most significant digits from front ! + 4C !+ and move to the end again ! + ' + I.tmp !+ finish it off ! +!+ RSTS/E and RT-11 aren't supported by TECO-C + -1EJ-4"E ~* if RSTS/E ~ + I<60>-MODE:#3000 + | + -1EJ-7"N ~* if not RT-11 ~ + I;1--CR + ' + ' +! + Q.1,.XFQ.1,.D !+ save it in q-register F and clean up ! + '/ +27:^U.T +!+*************************************************************************** + If we're on RSTS/E, do something special +****************************************************************************! +!+-1EJ-4"E:QZ#Z"E-1G_J::FSdcl tecoTECO"UHK':S ^[J0''! + +Q0+1"E !+ if Q1 was equal to -1 on entry ! + 32768U0 !+ Q0 = 32768 ! +' +32768"E !+ if we're on a 16-bit machine (?) ! + :EITECO"S !+ try to execute macro in file TECO ! + ]1 + Q0#32768U1 + [1 + J + ODONE + ' +' + +!+*************************************************************************** + Get the command line string from q-register Z into the edit buffer +****************************************************************************! + +Z"EGZ0,0XZ' !+ get command line string from Z and clear Z ! +J +::S^ES"S^SD' !+ remove leading whitespace ! +::STECO32"S-2D' !+ change TECO32 to TECO, if needed ! +ZJ-:S^ES"S.-Z"EFR'' !+ remove trailing whitespace ! +Z"EODONE' !+ if there's no command line, don't initialize ! + +Q0&32767U1 +0,0X1 +0,0X9 + +!+*************************************************************************** + If there's a -NOINI switch, (-NOINI if under Unix) delete it, compact + any trailing whitespace, and set the 4096 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOI"SONOINI' +J:S^EUYNOI"FONONOINI' +!NOINI! +^SD::SN"S-D::SI"S-D'' +::S^ES"S^SD0A"AI '' +Q1#4096U1 +!NONOINI! + +!+*************************************************************************** + Execute the initialization file. +****************************************************************************! + +Q1&4096"E !+ if there's no NOINI switch ! + HX0HK !+ save the command line in Q0 ! + EPEA !+ switch to secondary I-O streams ! + EF + +!+ Get the INI macro into the edit buffer ! + + :EGINI"S !+ get the INI file specification ! + G* + J0A-36"ED !+ if the first character is a dollar-sign ! + HX1 + HK + :ER^EQ1"S !+ open the file for reading ! + YHX1HKECG1 !+ and put it's contents into the edit buffer ! + | + %Can't find initialization file ":G1"1310 + ' + ' + 0,0X1 + | !+ else (no defined INI filename) ! + 0,0X1 + (-1EJ-5)*(-1EJ-1024)"E !+ if VAX/VMS ! + EN[]*.*:EN"S !+ get current dir spec into Q1 ! + G*JS[R0KFS.]JS]0,.X1HK + ' + ' + :ER^EQ1TECO.INI"S !+ if TECO.INI exists in current directory ! + YHX9HKECG90,0X9 !+ get it's contents into the edit buffer ! + ' + ' + EREW !+ switch back to primary streams ! + + Z"N !+ if there's an INI macro to execute ! + ZJ + .U0 + G1 + I= + G0 + Q0J + ZX9 + ZK + ]1 + ]0Q0ET + ]0Q0ES + ]0Q0EU + ]0Q0ED + ]0Q0 + ]0Q0 + ]2 + HX0 + HK + G9 + J + S= + 0,.-1X9 + 0,.K + M0+0U9 !+ execute INI macro, save result in Q9 ! + 0,0X0 + [2 + 0,0X2 + 10U0[0 !+ radix 10 ! + U0[00 !+ case independent searching ! + EDU0[0ED&4ED !+ turn on no-memory-expansion bit ! + EUU0[0-1EU !+ no case flagging on typeout ! + ESU0[00ES !+ no typeout after searches ! + ETU0[032768#32#8#1,0ET !+ image mode, ^T noecho and nowait, ^C trap ! + [1 + G9 + X1 + K + 0,0X9 + Q9U1 + J::S^ES"S^SD' !+ delete leading whitespace ! + ZJ-:S^ES"S.-Z"EFR'' !+ delete trailing whitespace ! + Z"E + OSCOPES + ' + | + G0 + ' +' + + +!+*************************************************************************** + If there's a -NOMEMORY switch (-NOMEMORY under Unix), delete it, compact + any trailing whitespace, and set the 4 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOM"SONOMEMORY' +J:S^EUYNOM"FONONOMEMORY' +!NOMEMORY! +^SD::SE"S-D::SM"S-D::SO"S-D::SR"S-D::SY"S-D''''' +::S^ES"S^SD0A"AI '' +Q1#4U1 +!NONOMEMORY! + + +!+*************************************************************************** + If there's a /NOCREATE switch, (-NOCREATE under Unix), delete it, compact + any trailing whitespace, and set the 256 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOC"SONOCREATE' +J:S^EUYNOC"FONONOCREATE' +!NOCREATE! +^SD::SR"S-D::SE"S-D::SA"S-D::ST"S-D::SE"S-D''''' +::S^ES"S^SD0A"AI '' +Q1#256U1 +!NONOCREATE! + + +!+*************************************************************************** + If there's a /NOPAGE switch, (-NOPAGE under Unix), delete it, compact + any trailing whitespace, and set the 64 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOP"SONOPAGE' +J:S^EUYNOP"FONONOPAGE' +!NOPAGE! +^SD::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"S^SD0A"AI '' +Q1#64U1 +!NONOPAGE! + + +!+*************************************************************************** + If there's a /NORENAME switch, (-NORENAME under Unix), delete it, compact + any trailing whitespace, and set the 512 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOR"SONORENAME' +J:S^EUYNOR"FONONORENAME' +!NORENAME! +^SD::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"S^SD0A"AI '' +Q1#512U1 +!NONORENAME! + + +!+*************************************************************************** + If we're not under RSTS/E, and the command is "TECO @file", then change + it to "MUNG file". +****************************************************************************! + +!+ -1EJ-4"N! !+ if not RSTS/E ! +J::STE"S<0A"AC|1;'>::S^ES@"S0KIMUNG '' +!+ '! + + +!+*************************************************************************** + If it's a MUNG command, find the file specification, delete it from + the edit buffer, and do an EI on the file. +****************************************************************************! + +J::SMU"S-2D !+ if it's a MUNG command ! + <0A"AD|1;'> !+ delete alphabetics following MU ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + (-1EJ-5)*(-1EJ-1024)"E !+ if VAX/VMS ! + J::S""S-D !+ and it starts with double quote ! + ::S^ES"S^SD' !+ remove whitespace following the " ! + ' + ' + +!+ The MUNG file specification might be followed by data to be put into + the edit buffer. The file specification and the data are separated by + a comma, a slash, or whitespace. Set Q0 to point to the end of the + file specification, regardless of how its terminated.! + + ZU0 !+ put edit buffer length in Q0 ! + -1EJ-25600"E !+ if Unix ! + J:S-"SR.-Q0"L.U0'' !+ if - precedes Q0, change Q0 ! + | + J:S/"SR.-Q0"L.U0'' !+ if / precedes Q0, change Q0 ! + ' + J:S^ES"S.-Q0"L.U0'' !+ if whitespace precedes Q0, change Q0 ! + + J"S.-Q1"GF<''' + Q1-1J-:S("S:S)"S.-Q1"GF<''' + Q1-1J.-1-Q0"LD.U0' + 0; + > + + Q0J<-.;-1A-32"N-1A-9"N0;''-D> !+ delete whitespace preceding Q0 ! + +!+ copy the file specification into q-register .0. If there's no file + specification, complain and die. ! + + 0,.X.0 + :Q.0"E?How can I MUNG nothing?1310' + +!+ delete the file specification and trailing whitespace (if any) from the + edit buffer, execute the MUNG file and we're done. ! + + ::S^ES^[ !+ locate end of whitespace, if any ! + 0,.K !+ delete spec + trailing whitespace ! + 0U0 !+ don't leave trash in Q0 ! + EI^EQ.0 !+ execute the MUNG file ! + JODONE !+ and we're done ! +' + +!+*************************************************************************** + If there's a /VTEDIT (-VTEDIT under Unix), switch... +****************************************************************************! + +J:S^ES^EUYVT"SOVTEDIT' +J:S^EUYVT"FONOVTEDIT' +!VTEDIT! +The VTEDIT command line option is not supported by TECOC1310 + +!+ + ::SE"S^SD::SD"S^SD::SI"S^SD::ST"S^SD'''' + ::S:H"S-2D::SO"S-D::SL"S-D::SD"S-D'''Q1#32U1' + ::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D'''''Q1#16U1' + ::S:H"S-2D::SO"S-D::SL"S-D::SD"S-D'''Q1#32U1' + ::S^ES"S^SD0A"AI '' + Q1#1U1 +! +!NOVTEDIT! + +!+*************************************************************************** + If we're running Unix, check for a +nnn option. If there is one, set + the 128 bit of the EZ flag (to read in the whole file, regardless of form + feeds) and put the number in Q-register 4. +****************************************************************************! + +-1EJ-25600"E !+ if Unix ! + J:S^ES+"S + ^SD\U40,128EZ^sd::ss"S^sD0A"AI '' + ' +' +!+Set EZ flag if nopage! +Q1&64"N0,128ez' + +!+*************************************************************************** + If there's a /SCROLL switch (-SCROLL under Unix), delete it, get the + numeric argument (or default to 0) into q-register 2. + If :SEEALL follows -SCROLL, then set bit 16 of q-register 1. + Delete any trailing whitespace and set bit 128 of q-register 1. +****************************************************************************! + +J:S^ES^EUYSC"SOSCROLL' +J:S^EUYSC"FONOSCROLL' +!SCROLL! +^SD::SR"S-D::SO"S-D::SL"S-D::SL"S-D'''' +::S:^ED"SR-D\U2FR|0U2' !+ get numeric arg into Q2! +::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D''''' + Q1#16U1 +' +::S^ES"S^SD0A"AI '' !+ delete trailing whitespace! +Q1#128U1 +!NOSCROLL! + + +!+*************************************************************************** + If it's a TECO command... +****************************************************************************! + +J::STE"S-2D !+ if it's a TE command ! + <0A"AD|1;'> !+ delete alphabetics following TE ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + +!+*************************************************************************** + If there's a /INSPECT switch, (-INSPECT if under Unix) delete it, compact + any trailing whitespace, and set the 2 bit of q-register 1. +****************************************************************************! + + J:S^ES^EUYIN"SOINSPECT' + J:S^EUYIN"FONOINSPECT' + !INSPECT! + ^SD::SS"S-D::SP"S-D::SE"S-D::SC"S-D::ST"S-D''''' + ::S^ES"S^SD0A"AI '' + Q1#2U1 + !NOINSPECT! + +!+*************************************************************************** + If there's a /FIND switch, (-FIND if under Unix) delete it, compact + any trailing whitespace, and set the 8 bit of q-register 1. +****************************************************************************! + + J:S^ES^EUYFI"SOFIND' + J:S^EUYFI"FONOFIND' + !FIND! + The /FIND command line option is not supported by TECOC1310 +  +!+ + ^SD::SN"S-D::SD"S-D'' + ::S^ES"S^SD0A"AI '' + Q1#8U1 +! + !NOFIND! + +!+ If there's more to the command, then delete preceding whitespace and + if the remainder of the command line contains a quoted string, do a ZJ. ! + + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""UZJ'' + > + +!+ Get the remembered file specification into the edit buffer. ! + + Q1&4#Z"E !+ if there's no file name and no -NOMEMORY ! + :EGMEM"S !+ if :EGMEM is supported ! + G*J !+ get it into the edit buffer ! + ::S$"S^SD !+ if leading dollar sign, delete and... ! + |OGOTIT' !+ otherwise got it and get outa here ! + | !+ else :EGMEM isn't supported ! + M.T !+ generate file name in F ! + GF !+ and get it ! + ' + HX0HK !+ save filename in Q0 and clear buffer ! + EPEA !+ select secondary I-O streams ! + EF !+ close current output file ! + :ER^EQ0"S !+ open file (name is in Q0) ! + Y + L + ."N-1A-10"E-D'' !+ remove trailing lf, if any ! + ."N-1A-13"E-D'' !+ remove trailing cr, if any ! + ZK + HX0HK + EC !+ copy input to output and close streams ! + G0 + ' + EREW !+ select primary I-O streams ! + 0,0X0 + !GOTIT! + +!+ If there's a file specification, then delete preceding whitespace and + if the remainder of the filespec contains a quoted string, do a ZJ. ! + + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""UZJ'' + > + + Z"N + Q1#32768#16384U1 + ' + ' !+ endif (no filename and no -NOMEMORY) ! + + Q1&16384"N !+ if input filename in edit buffer ! + Q1&2"E !+ if not -INSPECT ! + Edi + | + Inspec + ' + ting file "HT"1310 + ' + + Z"E !+ if there's no file name ! + Q1&2"EOSCOPES' !+ if not -INSPECT, goto SCOPES ! + ?How can I inspect nothing?1310 +  + ' + + Q1&2"E !+ if not -INSPECT ! + J:S="S !+ if it's ofile=ifile ! + 0,.-1X00,.K !+ save ofile name in Q0 ! + ZU0 !+ save length of ifile name in Q0 ! + HX2HK !+ save ifile name in Q2 ! + :Q2"N !+ if there's an ifile name ! + :ER^EQ2"U !+ try to open the ifile ! + G2HX0HKONOTFND !+ and goto NOTFND if it fails ! + ' + ' + :Q0"N !+ if there's an ofile name ! + EW^EQ0 !+ open the ofile ! + ' + Q0"N !+ if the ifile name length not = 0 ! + Q1#2048U1 !+ remember: input file is open ! + ' + OREMEM + ' + ' + + HX0HK + Q1&2"E !+ if not -INSPECT ! + :EB^EQ0"S !+ open it for reading-writing ! + Q1#2048U1 !+ remember: input file is open ! + OREMEM + ' + :ERQ0"S !+ TAA Added -- try to open for read ! + Q1#2048U1 + %Can't write to file -- opening for input only1310 + OREMEM + ' + Q1&256"N !+ EB failed, so if -NOCREATE ! + Q1&32768"E + ONOTFND + ' + ' + %Can't find file ":G0"1310 + Q1&32768"E + %Creating new file1310 + OCREATE + | + %Ignoring TECO's memory1310 + Q1#8192U1 + 0,0X0 + OREMEM + ' + ' + + :ER^EQ0"S !+ it's -INSPECT, open input file ! + Q1#2048U1 !+ remember: input file is open ! + OSCOPES + ' + + !NOTFND! + ?Can't find file ":G0"?1310 +  +' + + +!+*************************************************************************** + If it's a MAKE command... +****************************************************************************! + +J::SMA"S-2D + <0A"AD|1;'> !+ delete letters following MA ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""UZJ'' + > + + Z"E?How can I MAKE nothing?1310' + + Z-4"EJ::SLOVE"SNot war?1310'' + + HX0HK !+ save the filespec in Q0 for REMEM ! + !CREATE! + EW^EQ0 !+ Open file for writing ! + OREMEM !+ and go remember ! +' +%Unrecognized command "HTHK"1310 +OSCOPES +!+*************************************************************************** + Remember the filename in filespec memory. The filespec is in Q0. +****************************************************************************! + +!REMEM! +Q1&8192"E !+ if 8192 bit is off in Q1 ! + Q1&(32768#4)"NOSCOPES' !+ if ??? or -NOMEMORY, goto SCOPES ! + :Q0"EOSCOPES' !+ if Q0 is empty, goto SCOPES ! +' + +!+ The file specification is now in Q0. If :EGMEM is unsupported, a file + is used to implement filespec memory. +! + +:EGMEM"S !+ if :EGMEM is supported ! + ZJG*C !+ append remembered spec to buffer ! + ::S$"U !+ no leading $ ! + ZK:EGMEM ^EQ0 !+ set remembered filespec to Q0 ! + OSCOPES !+ Goto SCOPES ! + | + -1D !+ delete dollar ! + ZXFZK !+ Save in q reg F ! + ' +| + M.T !+ Generate file name ! +' +EA !+ switch to secondary output stream ! +:EW^EQF"S !+ open the file ! + G0 HPW HK EF !+ and write the filespec into it ! + ' + EW !+ switch to primary output stream ! + + +!+*************************************************************************** +****************************************************************************! + +!SCOPES! +!+ -VTEDIT is not supported +Q1&1"N ~* if /VTEDIT ~ + ET&512"E + %Your terminal is not an interactive scope1310 + Q1#1-1U1 + | + 0,3:W ~* clear SEEALL mode ~ + Q1&16"N-1,3:W' ~* if /SEEALL, set SEEALL mode ~ + 0,5:W ~* clear hold mode ~ + Q1&32"N/1,5:W' ~* if /HOLD, set hold mode ~ + ' +' + +Q1&1"E + OYANK +' + +~* load the VTEDIT macro file name into q-register 9 ~ + +:EGVTE"S ~* if :EGVTE is supported ~ + 1G*X9K +| + :@9%DIT% + :Q1"E + (-1EJ-5)*(-1EJ-1024)"E + EN[]*.*:EN"S + ZJ + .U0 + G* + Q0J + S[ R + Q0,.K + FS.] Q0J + S] Q0,.X1 + Q0,ZK + ' + ' + ' +' + +:Q9"N ~* if Q9 isn't empty ~ + :EI^EQ1^EQ9"S + Q1#2048-2048U1 + OYANK + ' +' + +~**************************************************************************** + Get the library directory specification into q-register 1. + If there's no defined library directory, define the default one. +****************************************************************************~ + +:EGLIB"S ~* if there's a defined lib dir ~ + G*X1K ~* use it ~ +| ~* else ~ + -1EJ-0"E @1%LB:[1,2]% | ~* if RSX-11D: LB:[1,2] else~ + -1EJ-1"E @1%LB:[1,2]% | ~* if RSX-11M: LB:[1,2] else~ + -1EJ-2"E @1%LB:[1,2]% | ~* if RSX-11S: LB:[1,2] else~ + -1EJ-3"E @1%LB:[1,2]% | ~* if IAS: LB:[1,2] else~ + (-1EJ-5)*(-1EJ-1024)"E ~* if VAX/VMS ~ + @1%SYS$LIBRARY:% | ~* SYS$LIBRARY: else~ + -1EJ-6"E @1%LB:[1,2]% | ~* if RSX-11S: LB:[1,2] else~ + -1EJ-7"E @1%SY:% | ~* if RT-11: SY: else~ + @1%% ~* default: nothing ~ + ''''''' +' + +:Q1"N ~* if there's a library directory ~ + :EI^EQ1VTEDIT"S ~* execute the macro in there ~ + Q1#2048-2048U1 + OYANK + ' +' +%The :G9 macro is not available1310 +! + + +!+**************************************************************************! + +!YANK! +Q1&2048"N !+ if input file is open ! + Y !+ read in the first page ! +' + +J +!+ +Q1&8"N ~* if /FIND ~ + Finding position marker...1310 + EW G* + X0 + K + -1 + :Q0"N + :N~~/\~~ +"S^SD' + U0 + | + :_~~/\~~ +"S^SD' + U0 + ' + 0 + Q0"U + ?Position marker not found?1310 +  + ' +' +! + + +!+*************************************************************************** + On entry, Q2 contains the numeric argument given in the -SCROLL:n + switch, or 0 if no -SCROLL switch was specified. +****************************************************************************! + +Q1&128"N !+ if -SCROLL ! + ET&512"E + %Your terminal is not an interactive scope1310 + | + Q2"E + 2:W-4U2 + ' + 0,3:W Q1&16"N !+ if -SEEALL ! + 1,3:W ' + 0,5:W Q1&32"N !+ if -HOLD! + 1,5:W ' + Q2,7:W-Q2"N + %Your terminal doesn't support scrolling1310 + ' + ' +' + +!+*************************************************************************** +****************************************************************************! + +!DONE! +q4-1"G !+ if q4 greater than 1 ! + q4-1:s^J"U0J' !+ search for q4th line feed ! +' +q1&64"N !+ no NOPAGE switch? ! + 1u8 +| + 0u8 +' +q1&512"N !+ NORENAME switch? ! + 0,2EZ +' +]1 +]0Q0ET +]0Q0ES +]0Q0EU +]0Q0ED +]0Q0 +]0Q0 +]2 +]0 +]9 +]F +q8"N0,128ez' + diff --git a/src/win/clpars.tec b/src/win/clpars.tec new file mode 100644 index 0000000..8c7c21f --- /dev/null +++ b/src/win/clpars.tec @@ -0,0 +1,71 @@ +!CLPARS.TEC V2.2 5-June-1991 Pete Siemsen and Mark Henderson![F0,0XF +[90,0X9[00,0X0[20,0X210U0[0U0[00EDU0[0ED&4EDEUU0[0-1EUESU0[00ES +ETU0[032768#32#8#1,0ETQ1U00U1[10,0X10U4-1EJ-25600"E-UY|/UY'@.T/ +:QF"E.U.1Iteco0EJ\.-Q1U.LQ.L-8"GQ.1+4JQ.L-8D4C'I.tmpQ.1,.XFQ.1,.D'/ +27:.TQ0+1"E32768U0'32768"E:EITECO"S]1Q0#32768U1[1JODONE'' +Z"EGZ0,0XZ'J::S^ES"SD'::STECO32"S-2D'ZJ-:S^ES"S.-Z"EFR'' +Z"EODONE'Q0&32767U10,0X10,0X9J:S^ES^EUYNOI"SONOINI' +J:S^EUYNOI"FONONOINI'!NOINI!D::SN"S-D::SI"S-D'' +::S^ES"SD0A"AI ''Q1#4096U1!NONOINI!Q1&4096"EHX0HKEPEAEF:EGINI"SG* +J0A-36"EDHX1HK:ER^EQ1"SYHX1HKECG1| +%Can't find initialization file ":G1"1310''0,0X1|0,0X1 +(-1EJ-5)*(-1EJ-1024)"EEN[]*.*:EN"SG*JS[R0KFS.]JS]0,.X1HK'' +:ER^EQ1TECO.INI"SYHX9HKECG90,0X9''EREWZ"NZJ.U0G1I=G0Q0JZX9ZK]1 +]0Q0ET]0Q0ES]0Q0EU]0Q0ED]0Q0]0Q0]2HX0HKG9JS=0,.-1X90,.KM0+0U90,0X0 +[20,0X210U0[0U0[00EDU0[0ED&4EDEUU0[0-1EUESU0[00ES +ETU0[032768#32#8#1,0ET[1G9X1K0,0X9Q9U1J::S^ES"SD' +ZJ-:S^ES"S.-Z"EFR''Z"EOSCOPES'|G0''J:S^ES^EUYNOM"SONOMEMORY' +J:S^EUYNOM"FONONOMEMORY'!NOMEMORY! +D::SE"S-D::SM"S-D::SO"S-D::SR"S-D::SY"S-D''''' +::S^ES"SD0A"AI ''Q1#4U1!NONOMEMORY!J:S^ES^EUYNOC"SONOCREATE' +J:S^EUYNOC"FONONOCREATE'!NOCREATE! +D::SR"S-D::SE"S-D::SA"S-D::ST"S-D::SE"S-D''''' +::S^ES"SD0A"AI ''Q1#256U1!NONOCREATE!J:S^ES^EUYNOP"SONOPAGE' +J:S^EUYNOP"FONONOPAGE'!NOPAGE!D::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"SD0A"AI ''Q1#64U1!NONOPAGE!J:S^ES^EUYNOR"SONORENAME' +J:S^EUYNOR"FONONORENAME'!NORENAME!D::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"SD0A"AI ''Q1#512U1!NONORENAME! +J::STE"S<0A"AC|1;'>::S^ES@"S0KIMUNG ''J::SMU"S-2D<0A"AD|1;'> +::S^ES"SD'(-1EJ-5)*(-1EJ-1024)"EJ::S""S-D::S^ES"SD'''ZU0 +-1EJ-25600"EJ:S-"SR.-Q0"L.U0''|J:S/"SR.-Q0"L.U0''' +J:S^ES"S.-Q0"L.U0''J"S.-Q1"GF<'''Q1-1J-:S("S:S)"S.-Q1"GF<''' +Q1-1J.-1-Q0"LD.U0'0;>Q0J<-.;-1A-32"N-1A-9"N0;''-D>0,.X.0 +:Q.0"E?How can I MUNG nothing?1310'::S^ES 0,.K0U0EI^EQ.0 +JODONE'J:S^ES^EUYVT"SOVTEDIT'J:S^EUYVT"FONOVTEDIT'!VTEDIT! +The VTEDIT command line option is not supported by TECOC1310 +!NOVTEDIT!J:S^ES+"SD\U40,128EZD::Ss"SD0A"AI '''Q1&64"N0,128EZ' +J:S^ES^EUYSC"SOSCROLL'J:S^EUYSC"FONOSCROLL'!SCROLL! +D::SR"S-D::SO"S-D::SL"S-D::SL"S-D''''::S:^ED"SR-D\U2FR|0U2' +::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D'''''Q1#16U1' +::S^ES"SD0A"AI ''Q1#128U1!NOSCROLL!J::STE"S-2D<0A"AD|1;'> +::S^ES"SD'J:S^ES^EUYIN"SOINSPECT'J:S^EUYIN"FONOINSPECT'!INSPECT! +D::SS"S-D::SP"S-D::SE"S-D::SC"S-D::ST"S-D''''' +::S^ES"SD0A"AI ''Q1#2U1!NOINSPECT!J:S^ES^EUYFI"SOFIND' +J:S^EUYFI"FONOFIND'!FIND! +The /FIND command line option is not supported by TECOC1310 +!NOFIND!J<.-Z;0A-9"EDF<'0A-32"EDF<'C-1A-""E:S""S-1EJ-25857"E +0J2<@FS/"//>ZJ'|ZJ''>Q1&4#Z"E:EGMEM"SG*J::S$"SD|OGOTIT'|M.TGF' +HX0HKEPEAEF:ER^EQ0"SYL."N-1A-10"E-D''."N-1A-13"E-D''ZKHX0HKECG0' +EREW0,0X0!GOTIT!ZJZ"NQ1#32768#16384U1''Q1&16384"NQ1&2"EEdi| +Inspec'ting file "HT"1310'Z"EQ1&2"EOSCOPES' +?How can I inspect nothing?1310'Q1&2"EJ:S="S0,.-1X00,.KZU0HX2HK +:Q2"N:ER^EQ2"UG2HX0HKONOTFND'':Q0"NEW^EQ0'Q0"NQ1#2048U1'OREMEM'' +HX0HKQ1&2"E:EB^EQ0"SQ1#2048U1OREMEM':ERQ0"SQ1#2048U1 +%Can't write to file -- opening for input only1310OREMEM'Q1&256"N +Q1&32768"EONOTFND''%Can't find file ":G0"1310Q1&32768"E +%Creating new file1310OCREATE|%Ignoring TECO's memory1310 +Q1#8192U10,0X0OREMEM'':ER^EQ0"SQ1#2048U1OSCOPES'!NOTFND! +?Can't find file ":G0"?1310'J::SMA"S-2D<0A"AD|1;'> +::S^ES"SD'J<.-Z;0A-9"EDF<'0A-32"EDF<'C-1A-""E:S""S-1EJ-25857"E +0J2<@FS/"//>ZJ'|ZJ''>Z"E?How can I MAKE nothing?1310' +Z-4"EJ::SLOVE"SNot war?1310''HX0HK!CREATE!EW^EQ0OREMEM' +%Unrecognized command "HTHK"1310OSCOPES!REMEM!Q1&8192"E +Q1&(32768#4)"NOSCOPES':Q0"EOSCOPES'':EGMEM"SZJG*C::S$"U +ZK:EGMEM ^EQ0OSCOPES|-1DZXFZK'|M.T'EA:EW^EQF"SG0HPWHKEF'EW!SCOPES! +!YANK!Q1&2048"NY'JQ1&128"NET&512"E +%Your terminal is not an interactive scope1310|Q2"E2:W-4U2'0,3:W +Q1&16"N1,3:W'0,5:WQ1&32"N1,5:W'Q2,7:W-Q2"N +%Your terminal doesn't support scrolling1310'''!DONE!Q4-1"G +Q4-1:S^J"U0J''Q1&64"N0,128EZ'Q1&512"N0,2EZ']1]0Q0ET]0Q0ES]0Q0EU]0Q0ED +]0Q0]0Q0]2]0]9]F0U.10U.L0U40UY0,0X.T diff --git a/src/win/clpars.tes b/src/win/clpars.tes new file mode 100644 index 0000000..432cf8c --- /dev/null +++ b/src/win/clpars.tes @@ -0,0 +1,808 @@ +!CLPARS.TEC V2.2 5-June-1991 Pete Siemsen and Mark Henderson! + +!+*************************************************************************** + This macro is the imbedded command-line parsing macro for TECOC. It + was created by extracting the imbedded command-line parsing macro from the + TECO-11 executable file and then modifying it. + + This macro is compiled into TECO-C. This is the human-readable + source code. To compress it (remove comments, extra whitespace, etc.) + into an unreadable version in file CLPARS.TEC, do the following command + with a working TECO: + + mung squ clpars.tec=clpars.tes/d:n/l:y/b:y/t:n/c:+/w:n/a:y/e:n + + Then run genclp to convert CLPARS.TEC into CLPARS.H, a C include file. + + Notes: + + 1. On entry, Q1 contains a value + + 2. Bits in Q-register 1 have the following meanings: + + 1 /VTEDIT + 2 /INSPECT + 4 /NOMEMORY + 8 /FIND + 16 /SEEALL + 32 /HOLD + 64 /NOPAGE + 128 /SCROLL + 256 /NOCREATE + 512 /NORENAME + 1024 unused + 2048 input file is open + 4096 /NOINI + 8192 force setting of filespec memory + 16384 input filename is in edit buffer + 32768 ??? + + 3. Q-register 2 holds numeric argument of /SCROLL:n switch + + 4. Q-register Y holds the command-line option character, which + is a slash on most systems, and a dash under Unix. + + 5. Q-register .T holds a macro which is needed only when the :EGMEM + command isn't supported. It generates (in q-register F) the + name of a file that holds filename memory. + + 6. Q-register F holds the name of the file used to save file names. + + 7. Q-register 4 holds the line number to go to. + +****************************************************************************! + +!+ save the q-registers that we'll be changing ! +[F0,0XF +[90,0X9 +[00,0X0 +[20,0X2 +10U0[0 !+ radix 10 ! +U0[00 !+ case independent searching ! +EDU0[0ED&4ED !+ turn on automatic memory expansion ! +EUU0[0-1EU !+ no case flagging on typeout ! +ESU0[00ES !+ no typeout after searches ! +ETU0[032768#32#8#1,0ET !+ ^C trap, read nowait and noecho, image typeout ! +Q1U0 !+ Q0 = Q1 ! +0U1[1 +0,0X1 +0U4 +-1EJ-25600"E !+ if Unix ! + ^^-UY !+ Unix command lines delimit options with '-' ! +| + ^^/UY !+ VMS command lines delimit options with '/' ! +' + +!+*************************************************************************** + Put a subroutine into Q-register .T which, when called, fills Q-register + F with a filename to be used to store filespec memory. This subroutine + will only be needed if the :EGMEM isn't supported. +****************************************************************************! +@^U.T/ + :QF"E !+ if we haven't already set q-register F ! + .U.1 !+ remember where we are in edit buffer ! + Iteco !+ start building "tecoxxxx.tmp" ! + 0EJ\ !+ insert process id into edit buffer ! + .-Q1U.L !+ length of "tecoxxxx" part of filename ! + Q.L-8"G !+ if it's longer than 8 characters ! + Q.1+4J !+ go to front of the digits ! + Q.L-8D !+ prune most significant digits from front ! + 4C !+ and move to the end again ! + ' + I.tmp !+ finish it off ! +!+ RSTS/E and RT-11 aren't supported by TECO-C + -1EJ-4"E ~* if RSTS/E ~ + I<60>-MODE:#3000 + | + -1EJ-7"N ~* if not RT-11 ~ + I;1--CR + ' + ' +! + Q.1,.XFQ.1,.D !+ save it in q-register F and clean up ! + '/ +27:^U.T +!+*************************************************************************** + If we're on RSTS/E, do something special +****************************************************************************! +!+-1EJ-4"E:QZ#Z"E-1G_J::FSdcl tecoTECO"UHK':S ^[J0''! + +Q0+1"E !+ if Q1 was equal to -1 on entry ! + 32768U0 !+ Q0 = 32768 ! +' +32768"E !+ if we're on a 16-bit machine (?) ! + :EITECO"S !+ try to execute macro in file TECO ! + ]1 + Q0#32768U1 + [1 + J + ODONE + ' +' + +!+*************************************************************************** + Get the command line string from q-register Z into the edit buffer +****************************************************************************! + +Z"EGZ0,0XZ' !+ get command line string from Z and clear Z ! +J +::S^ES"S^SD' !+ remove leading whitespace ! +::STECO32"S-2D' !+ change TECO32 to TECO, if needed ! +ZJ-:S^ES"S.-Z"EFR'' !+ remove trailing whitespace ! +Z"EODONE' !+ if there's no command line, don't initialize ! + +Q0&32767U1 +0,0X1 +0,0X9 + +!+*************************************************************************** + If there's a -NOINI switch, (-NOINI if under Unix) delete it, compact + any trailing whitespace, and set the 4096 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOI"SONOINI' +J:S^EUYNOI"FONONOINI' +!NOINI! +^SD::SN"S-D::SI"S-D'' +::S^ES"S^SD0A"AI '' +Q1#4096U1 +!NONOINI! + +!+*************************************************************************** + Execute the initialization file. +****************************************************************************! + +Q1&4096"E !+ if there's no NOINI switch ! + HX0HK !+ save the command line in Q0 ! + EPEA !+ switch to secondary I-O streams ! + EF + +!+ Get the INI macro into the edit buffer ! + + :EGINI"S !+ get the INI file specification ! + G* + J0A-36"ED !+ if the first character is a dollar-sign ! + HX1 + HK + :ER^EQ1"S !+ open the file for reading ! + YHX1HKECG1 !+ and put it's contents into the edit buffer ! + | + %Can't find initialization file ":G1"1310 + ' + ' + 0,0X1 + | !+ else (no defined INI filename) ! + 0,0X1 + (-1EJ-5)*(-1EJ-1024)"E !+ if VAX/VMS ! + EN[]*.*:EN"S !+ get current dir spec into Q1 ! + G*JS[R0KFS.]JS]0,.X1HK + ' + ' + :ER^EQ1TECO.INI"S !+ if TECO.INI exists in current directory ! + YHX9HKECG90,0X9 !+ get it's contents into the edit buffer ! + ' + ' + EREW !+ switch back to primary streams ! + + Z"N !+ if there's an INI macro to execute ! + ZJ + .U0 + G1 + I= + G0 + Q0J + ZX9 + ZK + ]1 + ]0Q0ET + ]0Q0ES + ]0Q0EU + ]0Q0ED + ]0Q0 + ]0Q0 + ]2 + HX0 + HK + G9 + J + S= + 0,.-1X9 + 0,.K + M0+0U9 !+ execute INI macro, save result in Q9 ! + 0,0X0 + [2 + 0,0X2 + 10U0[0 !+ radix 10 ! + U0[00 !+ case independent searching ! + EDU0[0ED&4ED !+ turn on no-memory-expansion bit ! + EUU0[0-1EU !+ no case flagging on typeout ! + ESU0[00ES !+ no typeout after searches ! + ETU0[032768#32#8#1,0ET !+ image mode, ^T noecho and nowait, ^C trap ! + [1 + G9 + X1 + K + 0,0X9 + Q9U1 + J::S^ES"S^SD' !+ delete leading whitespace ! + ZJ-:S^ES"S.-Z"EFR'' !+ delete trailing whitespace ! + Z"E + OSCOPES + ' + | + G0 + ' +' + + +!+*************************************************************************** + If there's a -NOMEMORY switch (-NOMEMORY under Unix), delete it, compact + any trailing whitespace, and set the 4 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOM"SONOMEMORY' +J:S^EUYNOM"FONONOMEMORY' +!NOMEMORY! +^SD::SE"S-D::SM"S-D::SO"S-D::SR"S-D::SY"S-D''''' +::S^ES"S^SD0A"AI '' +Q1#4U1 +!NONOMEMORY! + + +!+*************************************************************************** + If there's a /NOCREATE switch, (-NOCREATE under Unix), delete it, compact + any trailing whitespace, and set the 256 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOC"SONOCREATE' +J:S^EUYNOC"FONONOCREATE' +!NOCREATE! +^SD::SR"S-D::SE"S-D::SA"S-D::ST"S-D::SE"S-D''''' +::S^ES"S^SD0A"AI '' +Q1#256U1 +!NONOCREATE! + + +!+*************************************************************************** + If there's a /NOPAGE switch, (-NOPAGE under Unix), delete it, compact + any trailing whitespace, and set the 64 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOP"SONOPAGE' +J:S^EUYNOP"FONONOPAGE' +!NOPAGE! +^SD::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"S^SD0A"AI '' +Q1#64U1 +!NONOPAGE! + + +!+*************************************************************************** + If there's a /NORENAME switch, (-NORENAME under Unix), delete it, compact + any trailing whitespace, and set the 512 bit of q-register 1. +****************************************************************************! + +J:S^ES^EUYNOR"SONORENAME' +J:S^EUYNOR"FONONORENAME' +!NORENAME! +^SD::SA"S-D::SG"S-D::SE"S-D''' +::S^ES"S^SD0A"AI '' +Q1#512U1 +!NONORENAME! + + +!+*************************************************************************** + If we're not under RSTS/E, and the command is "TECO @file", then change + it to "MUNG file". +****************************************************************************! + +!+ -1EJ-4"N! !+ if not RSTS/E ! +J::STE"S<0A"AC|1;'>::S^ES@"S0KIMUNG '' +!+ '! + + +!+*************************************************************************** + If it's a MUNG command, find the file specification, delete it from + the edit buffer, and do an EI on the file. +****************************************************************************! + +J::SMU"S-2D !+ if it's a MUNG command ! + <0A"AD|1;'> !+ delete alphabetics following MU ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + (-1EJ-5)*(-1EJ-1024)"E !+ if VAX/VMS ! + J::S""S-D !+ and it starts with double quote ! + ::S^ES"S^SD' !+ remove whitespace following the " ! + ' + ' + +!+ The MUNG file specification might be followed by data to be put into + the edit buffer. The file specification and the data are separated by + a comma, a slash, or whitespace. Set Q0 to point to the end of the + file specification, regardless of how its terminated.! + + ZU0 !+ put edit buffer length in Q0 ! + -1EJ-25600"E !+ if Unix ! + J:S-"SR.-Q0"L.U0'' !+ if - precedes Q0, change Q0 ! + | + J:S/"SR.-Q0"L.U0'' !+ if / precedes Q0, change Q0 ! + ' + J:S^ES"S.-Q0"L.U0'' !+ if whitespace precedes Q0, change Q0 ! + + J"S.-Q1"GF<''' + Q1-1J-:S("S:S)"S.-Q1"GF<''' + Q1-1J.-1-Q0"LD.U0' + 0; + > + + Q0J<-.;-1A-32"N-1A-9"N0;''-D> !+ delete whitespace preceding Q0 ! + +!+ copy the file specification into q-register .0. If there's no file + specification, complain and die. ! + + 0,.X.0 + :Q.0"E?How can I MUNG nothing?1310' + +!+ delete the file specification and trailing whitespace (if any) from the + edit buffer, execute the MUNG file and we're done. ! + + ::S^ES^[ !+ locate end of whitespace, if any ! + 0,.K !+ delete spec + trailing whitespace ! + 0U0 !+ don't leave trash in Q0 ! + EI^EQ.0 !+ execute the MUNG file ! + JODONE !+ and we're done ! +' + +!+*************************************************************************** + If there's a /VTEDIT (-VTEDIT under Unix), switch... +****************************************************************************! + +J:S^ES^EUYVT"SOVTEDIT' +J:S^EUYVT"FONOVTEDIT' +!VTEDIT! +The VTEDIT command line option is not supported by TECOC1310 + +!+ + ::SE"S^SD::SD"S^SD::SI"S^SD::ST"S^SD'''' + ::S:H"S-2D::SO"S-D::SL"S-D::SD"S-D'''Q1#32U1' + ::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D'''''Q1#16U1' + ::S:H"S-2D::SO"S-D::SL"S-D::SD"S-D'''Q1#32U1' + ::S^ES"S^SD0A"AI '' + Q1#1U1 +! +!NOVTEDIT! + +!+*************************************************************************** + If we're running Unix, check for a +nnn option. If there is one, set + the 128 bit of the EZ flag (to read in the whole file, regardless of form + feeds) and put the number in Q-register 4. +****************************************************************************! + +!+ -1EJ-25600"E if Unix ! + J:S^ES+"S + ^SD\U40,128EZ^sd::ss"S^sD0A"AI '' + ' +!+ ' ! +!+Set EZ flag if nopage! +Q1&64"N0,128ez' + +!+*************************************************************************** + If there's a /SCROLL switch (-SCROLL under Unix), delete it, get the + numeric argument (or default to 0) into q-register 2. + If :SEEALL follows -SCROLL, then set bit 16 of q-register 1. + Delete any trailing whitespace and set bit 128 of q-register 1. +****************************************************************************! + +J:S^ES^EUYSC"SOSCROLL' +J:S^EUYSC"FONOSCROLL' +!SCROLL! +^SD::SR"S-D::SO"S-D::SL"S-D::SL"S-D'''' +::S:^ED"SR-D\U2FR|0U2' !+ get numeric arg into Q2! +::S:S"S-2D::SE"S-D::SE"S-D::SA"S-D::SL"S-D::SL"S-D''''' + Q1#16U1 +' +::S^ES"S^SD0A"AI '' !+ delete trailing whitespace! +Q1#128U1 +!NOSCROLL! + + +!+*************************************************************************** + If it's a TECO command... +****************************************************************************! + +J::STE"S-2D !+ if it's a TE command ! + <0A"AD|1;'> !+ delete alphabetics following TE ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + +!+*************************************************************************** + If there's a /INSPECT switch, (-INSPECT if under Unix) delete it, compact + any trailing whitespace, and set the 2 bit of q-register 1. +****************************************************************************! + + J:S^ES^EUYIN"SOINSPECT' + J:S^EUYIN"FONOINSPECT' + !INSPECT! + ^SD::SS"S-D::SP"S-D::SE"S-D::SC"S-D::ST"S-D''''' + ::S^ES"S^SD0A"AI '' + Q1#2U1 + !NOINSPECT! + +!+*************************************************************************** + If there's a /FIND switch, (-FIND if under Unix) delete it, compact + any trailing whitespace, and set the 8 bit of q-register 1. +****************************************************************************! + + J:S^ES^EUYFI"SOFIND' + J:S^EUYFI"FONOFIND' + !FIND! + The /FIND command line option is not supported by TECOC1310 +  +!+ + ^SD::SN"S-D::SD"S-D'' + ::S^ES"S^SD0A"AI '' + Q1#8U1 +! + !NOFIND! + +!+ If there's more to the command, then delete preceding whitespace and + if the remainder of the command line contains a quoted string, do a ZJ. ! + + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""S + -1EJ-25857"E !+ If OS/2 then delete quotes ! + 0J2<@FS/"//>ZJ'| + ZJ'' !+ if no second quote, go to end ! + > + +!+ Get the remembered file specification into the edit buffer. ! + + Q1&4#Z"E !+ if there's no file name and no -NOMEMORY ! + :EGMEM"S !+ if :EGMEM is supported ! + G*J !+ get it into the edit buffer ! + ::S$"S^SD !+ if leading dollar sign, delete and... ! + |OGOTIT' !+ otherwise got it and get outa here ! + | !+ else :EGMEM isn't supported ! + M.T !+ generate file name in F ! + GF !+ and get it ! + ' + HX0HK !+ save filename in Q0 and clear buffer ! + EPEA !+ select secondary I-O streams ! + EF !+ close current output file ! + :ER^EQ0"S !+ open file (name is in Q0) ! + Y + L + ."N-1A-10"E-D'' !+ remove trailing lf, if any ! + ."N-1A-13"E-D'' !+ remove trailing cr, if any ! + ZK + HX0HK + EC !+ copy input to output and close streams ! + G0 + ' + EREW !+ select primary I-O streams ! + 0,0X0 + !GOTIT! + +!+ If there's a file specification, then delete preceding whitespace and + if the remainder of the filespec contains a quoted string, do a ZJ. ! +!+ However there shouldn't be any whitespace -- don't do this step + because it messes up names with embedded spaces + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""UZJ'' + > +! ZJ !+ but move to end just in case ! + Z"N + Q1#32768#16384U1 + ' + ' !+ endif (no filename and no -NOMEMORY) ! + + Q1&16384"N !+ if input filename in edit buffer ! + Q1&2"E !+ if not -INSPECT ! + Edi + | + Inspec + ' + ting file "HT"1310 + ' + + Z"E !+ if there's no file name ! + Q1&2"EOSCOPES' !+ if not -INSPECT, goto SCOPES ! + ?How can I inspect nothing?1310 +  + ' + + Q1&2"E !+ if not -INSPECT ! + J:S="S !+ if it's ofile=ifile ! + 0,.-1X00,.K !+ save ofile name in Q0 ! + ZU0 !+ save length of ifile name in Q0 ! + HX2HK !+ save ifile name in Q2 ! + :Q2"N !+ if there's an ifile name ! + :ER^EQ2"U !+ try to open the ifile ! + G2HX0HKONOTFND !+ and goto NOTFND if it fails ! + ' + ' + :Q0"N !+ if there's an ofile name ! + EW^EQ0 !+ open the ofile ! + ' + Q0"N !+ if the ifile name length not = 0 ! + Q1#2048U1 !+ remember: input file is open ! + ' + OREMEM + ' + ' + + HX0HK + Q1&2"E !+ if not -INSPECT ! + :EB^EQ0"S !+ open it for reading-writing ! + Q1#2048U1 !+ remember: input file is open ! + OREMEM + ' + :ERQ0"S !+ TAA Added -- try to open for read ! + Q1#2048U1 + %Can't write to file -- opening for input only1310 + OREMEM + ' + Q1&256"N !+ EB failed, so if -NOCREATE ! + Q1&32768"E + ONOTFND + ' + ' + %Can't find file ":G0"1310 + Q1&32768"E + %Creating new file1310 + OCREATE + | + %Ignoring TECO's memory1310 + Q1#8192U1 + 0,0X0 + OREMEM + ' + ' + + :ER^EQ0"S !+ it's -INSPECT, open input file ! + Q1#2048U1 !+ remember: input file is open ! + OSCOPES + ' + + !NOTFND! + ?Can't find file ":G0"?1310 +  +' + + +!+*************************************************************************** + If it's a MAKE command... +****************************************************************************! + +J::SMA"S-2D + <0A"AD|1;'> !+ delete letters following MA ! + ::S^ES"S^SD' !+ delete trailing whitespace ! + J + < + .-Z; + 0A-9"EDF<' + 0A-32"EDF<' + C + -1A-""E:S""S + -1EJ-25857"E !+ If OS/2 then delete quotes ! + 0J2<@FS/"//>ZJ'| + ZJ'' !+ if no second quote, go to end ! + > + + Z"E?How can I MAKE nothing?1310' + + Z-4"EJ::SLOVE"SNot war?1310'' + + HX0HK !+ save the filespec in Q0 for REMEM ! + !CREATE! + EW^EQ0 !+ Open file for writing ! + OREMEM !+ and go remember ! +' +%Unrecognized command "HTHK"1310 +OSCOPES +!+*************************************************************************** + Remember the filename in filespec memory. The filespec is in Q0. +****************************************************************************! + +!REMEM! +Q1&8192"E !+ if 8192 bit is off in Q1 ! + Q1&(32768#4)"NOSCOPES' !+ if ??? or -NOMEMORY, goto SCOPES ! + :Q0"EOSCOPES' !+ if Q0 is empty, goto SCOPES ! +' + +!+ The file specification is now in Q0. If :EGMEM is unsupported, a file + is used to implement filespec memory. +! + +:EGMEM"S !+ if :EGMEM is supported ! + ZJG*C !+ append remembered spec to buffer ! + ::S$"U !+ no leading $ ! + ZK:EGMEM ^EQ0 !+ set remembered filespec to Q0 ! + OSCOPES !+ Goto SCOPES ! + | + -1D !+ delete dollar ! + ZXFZK !+ Save in q reg F ! + ' +| + M.T !+ Generate file name ! +' +EA !+ switch to secondary output stream ! +:EW^EQF"S !+ open the file ! + G0 HPW HK EF !+ and write the filespec into it ! + ' + EW !+ switch to primary output stream ! + + +!+*************************************************************************** +****************************************************************************! + +!SCOPES! +!+ -VTEDIT is not supported +Q1&1"N ~* if /VTEDIT ~ + ET&512"E + %Your terminal is not an interactive scope1310 + Q1#1-1U1 + | + 0,3:W ~* clear SEEALL mode ~ + Q1&16"N-1,3:W' ~* if /SEEALL, set SEEALL mode ~ + 0,5:W ~* clear hold mode ~ + Q1&32"N/1,5:W' ~* if /HOLD, set hold mode ~ + ' +' + +Q1&1"E + OYANK +' + +~* load the VTEDIT macro file name into q-register 9 ~ + +:EGVTE"S ~* if :EGVTE is supported ~ + 1G*X9K +| + :@9%DIT% + :Q1"E + (-1EJ-5)*(-1EJ-1024)"E + EN[]*.*:EN"S + ZJ + .U0 + G* + Q0J + S[ R + Q0,.K + FS.] Q0J + S] Q0,.X1 + Q0,ZK + ' + ' + ' +' + +:Q9"N ~* if Q9 isn't empty ~ + :EI^EQ1^EQ9"S + Q1#2048-2048U1 + OYANK + ' +' + +~**************************************************************************** + Get the library directory specification into q-register 1. + If there's no defined library directory, define the default one. +****************************************************************************~ + +:EGLIB"S ~* if there's a defined lib dir ~ + G*X1K ~* use it ~ +| ~* else ~ + -1EJ-0"E @1%LB:[1,2]% | ~* if RSX-11D: LB:[1,2] else~ + -1EJ-1"E @1%LB:[1,2]% | ~* if RSX-11M: LB:[1,2] else~ + -1EJ-2"E @1%LB:[1,2]% | ~* if RSX-11S: LB:[1,2] else~ + -1EJ-3"E @1%LB:[1,2]% | ~* if IAS: LB:[1,2] else~ + (-1EJ-5)*(-1EJ-1024)"E ~* if VAX/VMS ~ + @1%SYS$LIBRARY:% | ~* SYS$LIBRARY: else~ + -1EJ-6"E @1%LB:[1,2]% | ~* if RSX-11S: LB:[1,2] else~ + -1EJ-7"E @1%SY:% | ~* if RT-11: SY: else~ + @1%% ~* default: nothing ~ + ''''''' +' + +:Q1"N ~* if there's a library directory ~ + :EI^EQ1VTEDIT"S ~* execute the macro in there ~ + Q1#2048-2048U1 + OYANK + ' +' +%The :G9 macro is not available1310 +! + + +!+**************************************************************************! + +!YANK! +Q1&2048"N !+ if input file is open ! + Y !+ read in the first page ! +' + +J +!+ +Q1&8"N ~* if /FIND ~ + Finding position marker...1310 + EW G* + X0 + K + -1 + :Q0"N + :N~~/\~~ +"S^SD' + U0 + | + :_~~/\~~ +"S^SD' + U0 + ' + 0 + Q0"U + ?Position marker not found?1310 +  + ' +' +! + + +!+*************************************************************************** + On entry, Q2 contains the numeric argument given in the -SCROLL:n + switch, or 0 if no -SCROLL switch was specified. +****************************************************************************! + +Q1&128"N !+ if -SCROLL ! + ET&512"E + %Your terminal is not an interactive scope1310 + | + Q2"E + 2:W-4U2 + ' + 0,3:W Q1&16"N !+ if -SEEALL ! + 1,3:W ' + 0,5:W Q1&32"N !+ if -HOLD! + 1,5:W ' + Q2,7:W-Q2"N + %Your terminal doesn't support scrolling1310 + ' + ' +' + +!+*************************************************************************** +****************************************************************************! + +!DONE! +q4-1"G !+ if q4 greater than 1 ! + q4-1:s^J"U0J' !+ search for q4th line feed ! +' +q1&64"N !+ NOPAGE switch? ! + 0,128EZ +' +q1&512"N !+ NORENAME switch? ! + 0,2EZ +' +]1 +]0Q0ET +]0Q0ES +]0Q0EU +]0Q0ED +]0Q0 +]0Q0 +]2 +]0 +]9 +]F +0U.10U.L0U40UY0,0X.T !+ reset q registers ! + diff --git a/src/win/makecl.bat b/src/win/makecl.bat new file mode 100644 index 0000000..7e92221 --- /dev/null +++ b/src/win/makecl.bat @@ -0,0 +1,2 @@ +rsx tecocos2 mung squ clpars.tec=clpars.tes/d:n/l:y/b:y/t:n/c:+/w:y/a:y/e:n +genclp diff --git a/src/win/maketeco.bat b/src/win/maketeco.bat new file mode 100644 index 0000000..46a1c55 --- /dev/null +++ b/src/win/maketeco.bat @@ -0,0 +1,2 @@ +REM maker -fmakefile.tc -DMODEL=l -DALL -DNODEBUG %1 %2 %3 %4 %5 %6 %7 %8 %9 +maker -fmakefile.tc -DALL -DNODEBUG %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/src/win/mung.bat b/src/win/mung.bat new file mode 100644 index 0000000..e912041 --- /dev/null +++ b/src/win/mung.bat @@ -0,0 +1 @@ +@tecoc mung %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/src/win/squ.bat b/src/win/squ.bat new file mode 100644 index 0000000..163dd33 --- /dev/null +++ b/src/win/squ.bat @@ -0,0 +1,26 @@ +@echo off +if "%1"=="" goto usage + +echo tecoc mung squ %1.tec=%1.tes/d:n/l:y/b:y/t:y/c:y/w:n/a:y/e:n +tecoc mung squ %1.tec=%1.tes/d:n/l:y/b:y/t:y/c:y/w:n/a:y/e:n +goto fini + +:usage +echo : usage: squ filespec +echo : +echo : squ.bat will run the squ.tec "squish" macro on the teco macro +echo : source file filespec.tes, and produce a filespec.tec squished +echo : file. the following squish switches are used: +echo : +echo : /d:n don't simply delete unnecessary CR/LF's... +echo : /l:y ...delete CR/LF's then go back & add them for 70 char lines +echo : /b:y delete blank lines +echo : /t:y delete unnecessary tabs and formfeeds +echo : /c:y delete comments !(SP)...! and !(TAB)...! +echo : /w:n don't watch progress +echo : /a:y automatic mode, don't subsquish @^U%% macros +echo : /e:n don't allow adjacent escapes +echo : + +:fini +exit diff --git a/src/win/tctlib.rsp b/src/win/tctlib.rsp new file mode 100644 index 0000000..9deab63 --- /dev/null +++ b/src/win/tctlib.rsp @@ -0,0 +1,20 @@ ++baksrc.obj +bldstr.obj +clenup.obj +cmatch.obj +docjr.obj +doeves.obj & ++doflag.obj +echoit.obj +err.obj +exeats.obj +exea.obj +exebar.obj & ++exebsl.obj +exeb.obj +execcc.obj +execln.obj +execom.obj +execrt.obj & ++execst.obj +execta.obj +exectc.obj +exectd.obj +execte.obj +execti.obj & ++exectl.obj +exectn.obj +execto.obj +exectp.obj +exectq.obj +exectr.obj & ++exects.obj +exectt.obj +exectu.obj +exectv.obj +exectw.obj +exectx.obj & ++execty.obj +exectz.obj +exec.obj +exedgt.obj +exedot.obj +exedqu.obj & ++exed.obj +exeequ.obj +exeesc.obj +exeexc.obj +exeey.obj +exee.obj & ++exefb.obj +exef.obj +exegtr.obj +exeg.obj +exeh.obj +exeill.obj & ++exei.obj +exej.obj +exek.obj +exelbr.obj +exelst.obj +exel.obj & ++exem.obj +exenul.obj +exenyi.obj +exen.obj +exeopr.obj +exeo.obj & ++exeprc.obj +exepw.obj +exep.obj +exeqes.obj +exeq.obj +exerbr.obj & ++exertp.obj +exer.obj +exescl.obj +exes.obj +exet.obj +exeund.obj & ++exeusc.obj +exeu.obj +exev.obj +exew.obj +exex.obj +exey.obj & ++exez.obj +findes.obj +findqr.obj +flowec.obj +flowee.obj +flowel.obj & ++getara.obj +getnma.obj +inccbp.obj +init.obj +insstr.obj +isradx.obj & ++ln2chr.obj +makdbf.obj +makrom.obj +popmac.obj +pshmac.obj +pushex.obj & ++rdline.obj +rdpage.obj +readcs.obj +replac.obj +search.obj +singlp.obj & ++skpcmd.obj +srclop.obj +sserch.obj +tabort.obj +typbuf.obj +typest.obj & ++uminus.obj +wrpage.obj +zfrsrc.obj +zmsdos.obj diff --git a/src/win/teco.bat b/src/win/teco.bat new file mode 100644 index 0000000..6fe03a4 --- /dev/null +++ b/src/win/teco.bat @@ -0,0 +1 @@ +@tecoc teco %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/src/win/teco.cmd b/src/win/teco.cmd new file mode 100644 index 0000000..a354ed8 --- /dev/null +++ b/src/win/teco.cmd @@ -0,0 +1 @@ +tecoc teco %$ diff --git a/src/win/tecoc.lnk b/src/win/tecoc.lnk new file mode 100644 index 0000000..1006a92 --- /dev/null +++ b/src/win/tecoc.lnk @@ -0,0 +1,122 @@ +from lib:c.o +tecoc.o +baksrc.o +bldstr.o +clenup.o +cmatch.o +docjr.o +doeves.o +doflag.o +echoit.o +err.o +exea.o +exeats.o +exeb.o +exebar.o +exebsl.o +exec.o +execcc.o +execln.o +execom.o +execrt.o +execst.o +execta.o +exectc.o +exectd.o +execte.o +execti.o +exectl.o +exectn.o +execto.o +exectp.o +exectq.o +exectr.o +exects.o +exectt.o +exectu.o +exectv.o +exectw.o +exectx.o +execty.o +exectz.o +exed.o +exedgt.o +exedot.o +exedqu.o +exee.o +exeequ.o +exeesc.o +exeexc.o +exeey.o +exef.o +exefb.o +exeg.o +exegtr.o +exeh.o +exei.o +exeill.o +exej.o +exek.o +exel.o +exelbr.o +exelst.o +exem.o +exen.o +exenul.o +exenyi.o +exeo.o +exeopr.o +exep.o +exeprc.o +exepw.o +exeq.o +exeqes.o +exer.o +exerbr.o +exertp.o +exes.o +exescl.o +exet.o +exeu.o +exeund.o +exeusc.o +exev.o +exew.o +exex.o +exey.o +exez.o +findes.o +findqr.o +flowec.o +flowee.o +flowel.o +getara.o +getnma.o +inccbp.o +init.o +insstr.o +isradx.o +ln2chr.o +makdbf.o +makrom.o +popmac.o +pshmac.o +pushex.o +rdline.o +rdpage.o +readcs.o +replac.o +search.o +singlp.o +skpcmd.o +srclop.o +sserch.o +tabort.o +typbuf.o +typest.o +uminus.o +wrpage.o +zfrsrc.o +zamiga.o +to tecoc +library lib:lc.lib lib:amiga.lib diff --git a/src/win/tecocmd.btm b/src/win/tecocmd.btm new file mode 100644 index 0000000..b0a8da0 --- /dev/null +++ b/src/win/tecocmd.btm @@ -0,0 +1,4 @@ +alias teco tecoc teco/norename +alias inspect tecoc/inspect +alias mung tecoc mung +alias tmake tecoc make diff --git a/src/win/tst.bat b/src/win/tst.bat new file mode 100644 index 0000000..87df613 --- /dev/null +++ b/src/win/tst.bat @@ -0,0 +1,11 @@ +tecoc mung tstbsl.tec +pause +tecoc mung tstcss.tec +pause +tecoc mung tstequ.tec +pause +tecoc mung tsto.tec +pause +tecoc mung tstqr.tec +pause +tecoc mung tstsrc.tec diff --git a/src/wrpage.c b/src/wrpage.c new file mode 100644 index 0000000..8b56965 --- /dev/null +++ b/src/wrpage.c @@ -0,0 +1,103 @@ +/***************************************************************************** + WrPage() + This function handles all TECOC's file output, except for the E%q +command. The commands that can cause output are: + P write out edit buffer, with a form feed depending on AddFF + PW write out edit buffer, with a form feed + m,nPW write out characters between m and n, without form feed + HPW write out edit buffer, without a form feed + This function is passed the index of the file's data block in array +OFiles, the beginning and ending addresses in the edit buffer of the text +to be output, and a form feed flag indicating whether a form feed is to be +appended to the output or not. + The addresses of the text in the edit buffer might specify an area +that spans the edit buffer gap. In order to avoid writing the edit buffer +gap to the file, this function temporarily "shuffles" the second half of +the edit buffer, appending it to the first half to produce a contiguous +buffer for output. After the text is output, the text is shuffled back. + If a form feed is to be appended to the text, then the character +following the last character of the text area is temporarily overwritten +with a form feed character. After the text is output, the character that +was overwritten is restored. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +DEFAULT WrPage(OfIndx, OBfBeg, OBfEnd, AddFF) +DEFAULT OfIndx; /* index into OFiles array */ +charptr OBfBeg; /* address of output buffer beginning */ +charptr OBfEnd; /* address of output buffer end */ +LONG AddFF; /* add form feed: -1 is TRUE, 0 is FALSE */ +{ + unsigned char SavChr; /* saved char overwritten with form feed */ + ptrdiff_t Shuffl; /* size of shuffled area */ + DEFAULT status; +#if DEBUGGING + static char *DbgFNm = "WrPage"; + sprintf(DbgSBf,"OBfBeg = %ld, OBfEnd = %ld, AddFF = %ld", + Zcp2ul(OBfBeg), Zcp2ul(OBfEnd), AddFF); + DbgFEn(2,DbgFNm,DbgSBf); + sprintf(DbgSBf,"line 2: GapBeg = %ld, GapEnd = %ld", + Zcp2ul(GapBeg), Zcp2ul(GapEnd)); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (!IsOpnO[OfIndx]) { /* if no output file */ + ErrMsg(ERR_NFO); /* no file for output */ + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } +/* + * If the text area spans the edit buffer gap, then "shuffle", which + * means temporarily copying the second half of the edit buffer to the + * first half. Later, the reverse opertion will be done. + */ + if ((OBfBeg < GapBeg) && (OBfEnd > GapEnd)) { /* shuffle? */ + Shuffl = OBfEnd - GapEnd; + MEMMOVE(GapBeg, GapEnd+1, (SIZE_T)Shuffl); + OBfEnd = (GapBeg + Shuffl) - 1; + } else { + Shuffl = 0; /* 0 indicates no shuffle */ + if (OBfBeg == GapBeg) { /* if there's no first half */ + OBfBeg = GapEnd + 1; + } + if (OBfEnd == GapEnd) { /* if no second half */ + OBfEnd = GapBeg - 1; + } + if (OBfBeg > OBfEnd) { /* if both halves are empty */ + OBfBeg = OBfEnd + 1; /* make it a 0 length area */ + } + } +/* + * If we need to append a form feed, then save the character being + * overwritten and overwrite it with a form feed. + */ + if (AddFF) { + ++OBfEnd; + SavChr = *OBfEnd; + *OBfEnd = FORMFD; + } +/* + * Write the buffer. + */ + if (OBfBeg <= OBfEnd) { + status = ZWrBfr(OfIndx, OBfBeg, OBfEnd); + } else { + status = SUCCESS; + } +/* + * If we overwrote with a form feed, restore the overwritten character. + */ + if (AddFF) { + *OBfEnd = SavChr; + } +/* + * If we previously shuffled the edit buffer, then shuffle it back. + */ + if (Shuffl) { + MEMMOVE(GapEnd+1, GapBeg, (SIZE_T)Shuffl); + } + DBGFEX(2,DbgFNm,NULL); + return status; +} diff --git a/src/zamiga.c b/src/zamiga.c new file mode 100644 index 0000000..c8e9579 --- /dev/null +++ b/src/zamiga.c @@ -0,0 +1,1065 @@ +/***************************************************************************** + ZAmiga.c + System dependent code for Amiga (SAS/C 5.10) + This file created by Ben Mesander, ben@piglet.cr.usgs.gov, by + starting with zunix.c and making the necessary changes. +*****************************************************************************/ +/* + * RCS information + * + * $Header: Elros:src/c/teco/zamiga.c,v 1.4 91/01/26 22:40:31 ben Exp Locker: ben $ + * + * $Log: zamiga.c,v $ + * Revision 1.4 91/01/26 22:40:31 ben + * Removed possible recursive call of TAbort() in function sendpkt(). + * + * Revision 1.3 91/01/26 22:21:51 ben + * Cleaned up program exit logic: + * changed calls to ZExit() to TAbort(). + * + * Revision 1.2 91/01/26 21:23:12 ben + * Added RCS information + * + */ +/* + * Define standard functions. + */ +#include /* define errno */ +#include /* to catch ^C signal */ +#include /* define stdin */ +#include /* strncpy(), strlen(), etc. */ +#include /* stuff for time commands */ +#include /* for isatty() call */ +/* + * Stuff used to fake a tempnam() call. + */ +char *tempnam(); /* not in Amiga libraries */ +/* + * Amiga-specific stuff + */ +#include "exec/types.h" +#include "exec/ports.h" +#include "exec/io.h" +#include "exec/memory.h" +#include "libraries/dos.h" +#include "libraries/dosextens.h" +#undef GLOBAL /* name conflict here, doesn't matter */ +#define MAXARGS 7L /* limit in packet structure (dosextens.h) */ +#define NARGS 1L /* number of arguments */ +#define ESC 27L +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "clpars.h" /* command-line parsing macro */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +#include "defext.h" /* define external global variables */ +#include "dscren.h" /* define identifiers for screen i/o */ +extern int sys_nerr; /* number of system error messages */ +extern char *sys_errlist[]; /* error message text */ +static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */ +/***************************************************************************** + 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]; +/***************************************************************************** + sendpkt() + This function sends a message packet to an AmigaDOS handler + It is used in teco to send control messages to the console - + (turn on and off echo of characters) +*****************************************************************************/ +static long sendpkt(pid,action,args,nargs) +struct MsgPort *pid; /* process indentifier ... (handlers message port ) */ +long action, /* packet type ... (what you want handler to do ) */ + args[], /* a pointer to a argument list */ + nargs; /* number of arguments in list */ +{ + + struct MsgPort *replyport; + struct StandardPacket *packet; + + long count, *pargs, res1; + if(nargs > MAXARGS) ZExit(EXIT_FAILURE); /* not TAbort due to possible loop */ + + replyport = (struct MsgPort *) CreatePort(NULL,NULL); /* make reply port */ + if(!replyport) return(NULL); + packet = (struct StandardPacket *) + AllocMem((long)sizeof(*packet),MEMF_PUBLIC | MEMF_CLEAR); + if(!packet) + { + DeletePort(replyport); + return(NULL); + } + packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt); /* link packet- */ + packet->sp_Pkt.dp_Link = &(packet->sp_Msg); /* to message */ + packet->sp_Pkt.dp_Port = replyport; /* set-up reply port */ + packet->sp_Pkt.dp_Type = action; /* what to do... */ +/* move all the arguments to the packet */ + pargs = &(packet->sp_Pkt.dp_Arg1); /* address of first argument */ + for(count=NULL;count < nargs;count++) + pargs[count]=args[count]; + PutMsg(pid,packet); /* send packet */ +#if DEBUGGING + printf("Waiting for packet...\n"); +#endif + WaitPort(replyport); /* wait for packet to come back */ + GetMsg(replyport); /* pull message */ + res1 = packet->sp_Pkt.dp_Res1; /* get result */ +/* all done clean up */ + FreeMem(packet,(long)sizeof(*packet)); + DeletePort(replyport); + return(res1); + +} +/***************************************************************************** + Non-ANSI-contemptible tempnam() call. Would that the SAS Institute ever + really live up to their promise of an "ANSI-compatible" library. Sigh. +*****************************************************************************/ +static char *tempnam(dir,pfx) +char *dir, *pfx; +{ + char *s; + long timeVal; + char timeAry[4]; + char tBuf[7]; + struct tm *ut; + s = (char *)calloc(strlen(dir)+strlen(pfx)+8, sizeof(char)); + /* pathological case */ + if (s==NULL) return s; + /* get current time to make a unique filename */ + + timeVal = time(NULL); + ut = localtime(&timeVal); + timeAry[0] = (unsigned char)ut->tm_hour; + timeAry[1] = (unsigned char)ut->tm_min; + timeAry[2] = (unsigned char)ut->tm_sec; + timeAry[3] = (unsigned char)0; + stptime(tBuf, 1, timeAry); + + return(strcat(strcat(strcat(s,dir),pfx),tBuf)); +} +/***************************************************************************** + ZErMsg() + This function displays 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() +{ + if (errno < sys_nerr) + ErrStr(ERR_SYS, sys_errlist[errno]); +} +/***************************************************************************** + 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(MemSize) /* allocate memory */ +SIZE_T MemSize; +{ + return (voidptr *)malloc(MemSize); +} +/***************************************************************************** + ZBell() + Thus function rings the terminal bell. For most platforms, this +means just writing a bell character (control-G) to the terminal. An amusing +hack makes the Amiga SAY 'ding' out loud whenever a bell is hit... +*****************************************************************************/ +VVOID ZBell(VVOID) +{ + FILE *fp; + + if ((fp=fopen("SPEAK:","w"))==NULL) { +/* + * can't open speak device, just flash the screen + */ + ZDspCh('\7'); + } else { +/* + * say 'ding'. + */ + fputs("ding",fp); + fclose(fp); + } +} +/***************************************************************************** + 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(NoWait) /* input a character from terminal */ +BOOLEAN NoWait; /* return immediately? */ +{ + unsigned char Charac; + static BOOLEAN LastLF = FALSE; + if (LastLF) { + LastLF = FALSE; + return (DEFAULT)LINEFD; + } + if (read(fileno(stdin), &Charac, 1) != 1) { + if (!GotCtC) { + ZErMsg(); + ErrMsg(ERR_URC); + exit(EXIT_FAILURE); + } + } + if (Charac == CRETRN) { + LastLF = TRUE; + return (DEFAULT)CRETRN; + } + 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. +*****************************************************************************/ +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 */ +{ + DBGFEN(1,"ZClnEG",NULL); + DBGFEX(1,DbgFNm,"0"); + return 0; /* :EG is unsupported */ +} +/***************************************************************************** + See the definition of MEMMOVE in ZPORT.H for a description of this + function. +*****************************************************************************/ +VVOID ZCpyBl(Destin, Source, Length) +charptr Destin; +charptr Source; +SIZE_T Length; +{ + if (Source < Destin) { + Source += Length; + Destin += Length; + while (Length-- > 0) { + *--Destin = *--Source; + } + } else { + while (Length-- > 0) { + *Destin++ = *Source++; + } + } +} +#if DEBUGGING +ULONG Zcp2ul(cp) /* convert charptr to ULONG */ +voidptr cp; +{ + return (ULONG)(cp); +} +#endif +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +VVOID ZClnUp (VVOID) /* cleanup for TECO-C abort */ +{ + DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); + if (tty_set == TRUE) { + struct MsgPort *conid; /* for process id */ + long arg[NARGS]; /* array of arguments */ + struct Process *myprocess; /* me! */ + myprocess = (struct Process *) FindTask(NULL); +/* + * get console handler + */ + conid = (struct MsgPort *) myprocess->pr_ConsoleTask; + arg[0]=FALSE; /* turn RAW mode off */ +/* + * No point in checking result here - we're going to exit anyway. + */ + sendpkt(conid,ACTION_SCREEN_MODE,arg,NARGS); +#if DEBUGGING + printf("CON: mode set...\n"); +#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() /* die and pass command to OS */ +{ + char buf[128+1]; + char *space_p; + 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'; + (void)strncpy(buf, FBfBeg, 128); + if ((space_p = strchr(buf,' ')) != NULL) { + *space_p++ = '\0'; + } + ZClnUp(); +/* + * We should unload teco before calling system() - this will require some + * low-level dorking about with AmigaDOS which I don't want to do right now. + */ + if (*buf) { + system(buf); + } + TAbort(EXIT_SUCCESS); +/* + * We should never reach this statement. + */ + (void)perror (""); + TAbort (EXIT_FAILURE); +} +/***************************************************************************** + 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 call ZDspCh for every character +in the buffer. +*****************************************************************************/ +VVOID ZDspBf(buffer, length) /* output a buffer to terminal */ +charptr buffer; +SIZE_T length; +{ + if (write(fileno(stdout), buffer, length) == -1) { + /* Like this will work!??? */ + puts("Unable to write to terminal in function ZDspBf"); + TAbort(EXIT_FAILURE); + } +} +/***************************************************************************** + ZDspCh() + This function outputs a single character to the terminal. +*****************************************************************************/ +VVOID ZDspCh(Charac) /* output a character to terminal */ +char Charac; +{ + if (write(fileno(stdout), &Charac, 1) == -1) { + puts("Unable to write to terminal in function ZDspCh"); + TAbort(EXIT_FAILURE); + } +} +/***************************************************************************** + 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() /* 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 +*****************************************************************************/ +DEFAULT ZExCtH() /* 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) + 26112 under AmigaDOS 1.3 (102*256 = Amiga, 0 = AmigaDOS 1.3) + 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() /* 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"); + return FAILURE; + } + } + if (NArgmt == -1) { + DBGFEX(1,DbgFNm,"PushEx(26112)"); + return PushEx((LONG)26112, OPERAND); /* means "Amiga" */ + } + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"PushEx(0)"); + return PushEx((LONG)0, OPERAND); + } + DBGFEX(1,DbgFNm,"ExeNYI()"); + return ExeNYI(); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +VVOID ZExit(estat) /* terminate TECO-C */ +DEFAULT estat; +{ + exit(estat); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(pointer) /* free memory allocated by ZAlloc */ +voidptr pointer; +{ + free(pointer); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt) +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? */ +{ + (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(IfIndx) /* close input file */ +DEFAULT IfIndx; /* index into IFiles array */ +{ + DBGFEN(2,"ZIClos",NULL); + if (IsOpnI[IfIndx]) { /* if it's open */ + if (fclose(IFiles[IfIndx]) == EOF) { + ZErMsg(); + ErrMsg(ERR_UCI); + ZExit(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(OfIndx) /* close and delete output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + 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); + exit(EXIT_FAILURE); + } + if (remove(OFiles[OfIndx].OFNam) != 0) { + ZErMsg(); + ErrStr(ERR_UCD, OFiles[OfIndx].OFNam); + 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(OfIndx) /* close output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + char *DotPtr; + char TmpFsp[FILENAME_MAX]; + DBGFEN(2,"ZOClos",NULL); + if (!IsOpnO[OfIndx]) /* if it's not open */ + return; /* we're done */ + if (fclose(OFiles[OfIndx].OStrem) == EOF) { /* close it */ + ZErMsg(); + ErrMsg(ERR_UCO); /* unable to close */ + exit(EXIT_FAILURE); + } + if (OFiles[OfIndx].OTNam[0] != '\0') { /* if temporary output file */ + (void)strcpy(TmpFsp, OFiles[OfIndx].OTNam);/* copy to TmpFsp */ + DotPtr = strchr(TmpFsp, '.'); /* find the "." */ + if (DotPtr != NULL) { /* if "." exists */ + *DotPtr = '\0'; /* make it null */ + } + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + exit(EXIT_FAILURE); + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OTNam, TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (rename(OFiles[OfIndx].OTNam,TmpFsp)) { + ZErMsg(); + ErrMsg(ERR_UCO); + exit(EXIT_FAILURE); + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OFNam, OFiles[OfIndx].OTNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (rename(OFiles[OfIndx].OFNam,OFiles[OfIndx].OTNam)) { + ZErMsg(); + ErrMsg(ERR_UCO); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + 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 opens files in response to the EB, ER and EQ +commands. It does not open input files for the EI command. +*****************************************************************************/ +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 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(FBfBeg,'.') == NULL) { + (void)strcat(FBfBeg,".tec"); + FBfPtr += 4; + } + } + if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) == NULL) { + if (!RepFNF && ((errno == ENODEV) || (errno == ENOENT))) { + DBGFEX(2,DbgFNm,"FILENF"); + return FILENF; + } + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + 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. +*****************************************************************************/ +/* + * Unix file names do not have version numbers, 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 close routine 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 close routine will only rename files if a temporary file was created + * by this routine. + */ +DEFAULT ZOpOut(OfIndx, RepErr) /* open output file */ +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +{ + char *tfname; +#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. Note: the + * tempnam function is used instead of the ANSI C tmpnam function because + * tmpnam will make a file name in /usr/tmp, which we may not be able to + * rename later if /usr/tmp is across disk partitions. + * (That's for UNIX) AmigaDOS is similar. The tempdir, 't:' isn't going to + * have files in it that are 'renamable' to the current directory. + */ + *FBfPtr = '\0'; + if (access(FBfBeg, 0) == 0) { /* if file already exists */ + tfname = (char *)tempnam("","tecoc"); /* null = current dir */ + (void)strcpy(OFiles[OfIndx].OFNam, tfname); + free(tfname); + (void)strcpy(OFiles[OfIndx].OTNam, FBfBeg); +#if DEBUGGING + sprintf(DbgSBf, + "file %s already exists\r\n", + FBfBeg); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + } else { + (void)strcpy(OFiles[OfIndx].OFNam, FBfBeg); + OFiles[OfIndx].OTNam[0] = '\0'; + } +#if DEBUGGING + sprintf(DbgSBf, + "creating file %s\r\n", + OFiles[OfIndx].OFNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + OFiles[OfIndx].OStrem = fopen(OFiles[OfIndx].OFNam, "w"); + if (OFiles[OfIndx].OStrem == NULL) { + if (RepErr) + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE"); + 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(argc, argv) /* parse a TECOC command line */ +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; iStart, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +#if USE_ANSI_CLPARS +/* + * execute imbedded 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 +/* + * 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 = (charptr)"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 + 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. +*****************************************************************************/ +DEFAULT ZPWild() /* preset the wildcard lookup filename */ +{ +/* ??? use sh -c ? */ + return ExeNYI(); +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(OldBlk, NewSiz) /* re-allocate memory */ +voidptr OldBlk; +SIZE_T NewSiz; +{ + return (voidptr *)realloc(OldBlk, NewSiz); +} +/***************************************************************************** + ZRdLin() + This function reads a line from a file. It is passed a buffer, the +size of the buffer, and a file pointer. It returns the length of the line, +or sets IsEofI[] to TRUE if the end of file is encountered. +*****************************************************************************/ +DEFAULT ZRdLin(ibuf, ibuflen, IfIndx, retlen) +charptr ibuf; +ptrdiff_t ibuflen; +int IfIndx; +DEFAULT *retlen; +{ + DBGFEN(3,"ZRdLin",NULL); +/* + * make sure ibuflen is < 32K since fgets() requires an int + */ + if (ibuflen > (ptrdiff_t) 32767) { + ibuflen = (ptrdiff_t) 32767; + } +/* + * guarantee a trailing NUL in the buffer so strlen() always works + */ + --ibuflen; + ibuf[ibuflen] = '\0'; + if (fgets((char *)ibuf, (int)ibuflen, IFiles[IfIndx]) == NULL) { + if (ferror (IFiles[IfIndx])) { + ZErMsg(); + DBGFEX(3,DbgFNm,"FAILURE, ferror() after fgets()"); + return (FAILURE); + } + IsEofI[IfIndx] = TRUE; + DBGFEX(3,DbgFNm,"SUCCESS, eof after fgets()"); + } else { + *retlen = strlen((char *)ibuf); + if ((EzFlag & EZ_UNIXNL) == 0) { /* cnvrt \n to \r\n? */ + if (ibuf[(*retlen)-1] == '\n') { + ibuf[(*retlen)-1] = CRETRN; + ibuf[*retlen] = LINEFD; + *retlen += 1; + } + } +#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. + This is not yet finished... +*****************************************************************************/ +VVOID ZScrOp(OpCode) /* do a screen operation */ +int OpCode; /* code for operation */ +{ + if (CrType == UNTERM) { /* if unknown terminal type */ + return; /* can't do screen operations */ + } + switch (OpCode) { + case SCR_CUP: fputs("\0x1b[1A",stdout); /* cursor up */ + break; + case SCR_EEL: fputs("\0x1b[1K",stdout); /* clear to end of line */ + break; + case SCR_ROF: fputs("\0x1b[31m",stdout); /* reset standout mode */ + break; + case SCR_RON: fputs("\0x1b[33m",stdout); /* standout mode on */ + 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(TTWhat, TTVal) /* tell operating system we set the term. */ +DEFAULT TTWhat; /* what terminal parameter to set */ +DEFAULT TTVal; /* what to set it to */ +{ + 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() /* search for next wildcard filename */ +{ + return ExeNYI(); +} +/***************************************************************************** + 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 command procedure (under VMS) or a script file (under Unix), 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) + When TECO is started, the terminal will probably be set up for +buffered I/O, so characters won't be received until a RETURN is hit, and +they will be automatically echoed. Set the terminal up for raw I/O, so each +character is received when it is struck, and no echoing is performed. Save +the terminal characteristics so when we exit we can reset them (in ZClnUp) +to what they were before we changed them. +*****************************************************************************/ +static VVOID CntrlC() +{ + 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 */ + } + signal(SIGINT, CntrlC); +} +/* + * ZTrmnl - set up terminal modes + * + */ +VVOID ZTrmnl() /* set up I/O to the terminal */ +{ + EtFlag = ET_READ_LOWER | /* guess: term has lowercase and */ + ET_SCOPE; /* it's a scope, not hardcopy */ +/* + * get terminal characteristics and set some signals + */ + if (isatty(fileno(stdin))) tty_set = TRUE; /* tell ZClnUp to clean up */ + signal(SIGINT, CntrlC); /* call CntrlC on interrupt */ +/* + * set window to RAW: mode instead of CON: mode - this gets rid of echo. + */ + if (tty_set) { + struct MsgPort *conid; /* for process id */ + long arg[NARGS],res1; /* holds result */ + struct Process *myprocess; /* me! */ + myprocess = (struct Process *) FindTask(NULL); +/* + * get console handler. + */ + conid = (struct MsgPort *) myprocess->pr_ConsoleTask; + arg[0]=DOSTRUE; /* arg1=TRUE - set RAW mode */ + res1 = sendpkt(conid,ACTION_SCREEN_MODE,arg,NARGS); +/* + * If it is not possible to talk to our console, something really strange + * has happened to AmigaDOS. The system will probably GURU soon. + * We best exit immediately. + */ + if(!res1) + TAbort(EXIT_FAILURE); +#if DEBUGGING + puts("In RAW: mode."); +#endif + } + CrType = VT102; /* Let's pretend we are a VT102 */ +#if VIDEO + VtSize = HtSize = 0; +#endif +} +/***************************************************************************** + ZVrbos() + This function displays the verbose form of an error message. +*****************************************************************************/ +VVOID ZVrbos(ErrNum, ErMnem) +WORD ErrNum; +char *ErMnem; +{ + char **TmpPtr; +#include "vrbmsg.h" + 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, one line at a time. It is +passed an output file index and pointers to the beginning and end of the +buffer to be output. +*****************************************************************************/ +DEFAULT ZWrBfr(OfIndx, BfrBeg, BfrEnd) +DEFAULT OfIndx; /* index into OFiles array */ +charptr BfrBeg; /* address of output buffer beginning */ +charptr BfrEnd; /* address of output buffer end */ +{ +#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 we're doing Unix-style editing, where lines are terminated with a + * line feed (newline) instead of a carriage-return/line-feed pair, then + * we can just fwrite the buffer. Otherwise, we have to scan the buffer + * and convert CR/LF pairs to just LF for output. + */ + if (EzFlag & EZ_UNIXNL) { + ptrdiff_t bufsiz = BfrEnd-BfrBeg+1; + if (fwrite(BfrBeg, sizeof(char), bufsiz, + OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"Zfwrite() failed"); + return FAILURE; + } + } else { + charptr BfrPtr = BfrBeg; /* output buffer pointer */ + while (BfrPtr <= BfrEnd) { + if (*BfrPtr == CRETRN) { + BfrPtr++; + if ((BfrPtr > BfrEnd) || (*BfrPtr != LINEFD)) { + BfrPtr--; + } + } + if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + ++BfrPtr; + } + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} diff --git a/src/zfirst.c b/src/zfirst.c new file mode 100644 index 0000000..f005a4b --- /dev/null +++ b/src/zfirst.c @@ -0,0 +1,15 @@ +/* + * ZFirst.c + * + * This function is used to implement memory validity checking + * for TURBO-C. It is only needed if CHECKSUM_CODE is defined. + * + * Link this as the first object module in the TLINK command line. + * The CHECKSUM_CODE routines use the address of ZFirst() to get + * an idea of where the first function is in memory. + * + * To include this routine, specify -DMAP on the MAKE command line. + */ + void ZFirst (void) + { + } diff --git a/src/zfrsrc.c b/src/zfrsrc.c new file mode 100644 index 0000000..fe5abcb --- /dev/null +++ b/src/zfrsrc.c @@ -0,0 +1,783 @@ +/***************************************************************************** + ZFrSrc() + This recursive function does a forward search in the edit buffer, +looking for a string which will match the first match construct in the search +buffer. Basically, it is the high-speed part of the search algorithm: it +scans the edit buffer looking for the first character in the search string. + The VAX SCANC instruction implements most of the meat of this +function so well that I couldn't resist using it. For environments other +than VMS, the generic code exists to do the search. That's why this has to +be a system-dependent piece of code. Note that I did not use SCANC for some +of the match constructs, including the "default" case. I started to, but +the resulting code was real clumsy and in timing tests it didn't seem worth +the confusion. + On entry, SStPtr points to the first match construct in the search +buffer. On exit, SStPtr points to the last character of the first match +construct in the search buffer. + SBfPtr points to the character following the last character in +the search string. This function does not modify SBfPtr. + On entry, EBPtr1 points to the place in the edit buffer where +the search starts. On exit, if the search was successful, EBPtr1 will +point to the found character. If the search was unsuccessful, EBPtr1 will +be greater than EndSAr. + On entry, EBPtr2 is undefined. On exit, if the search was +successful, EBPtr2 points to the last character of the found string. If +the search was unsuccessful, EBPtr2 is undefined. + EndSAr points to the end of the search area (where the search ends). +This function does not modify EndSAr. + Match constructs are: + ^X match any character + ^S match a separator character (not letter or digit) + ^N match anything but following match construct + ^EA match any alphabetic + ^EB match a separator character (not letter or digit) + ^EC match symbol constituent + ^ED match any digit + ^EGq match any character in q-register q + ^EL match any line terminator (LF, VT, FF) + ^EM match non-null string of following match construct + ^ER match any alphanumeric + ^ES match non-null string of spaces and/or tabs + ^EV match lowercase alphabetic + ^EW match uppercase alphabetic + ^EX match any character + ^E match character with ASCII code nnn (octal) + ^E[x1,x2,...xn] match any of the match constructs x1, x2, etc. + else match the character itself +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "defext.h" /* define external global variables */ +#include "dchars.h" /* define identifiers for characters */ +#include "chmacs.h" /* define character processing macros */ +#include "deferr.h" /* define identifiers for error messages */ +#if defined(VAX11C) +#include descrip /* define "$descriptor" macro */ +int lib$scanc(); /* scan for characters */ +DEFAULT ZFrSrc() /* forward search for 1st search charptr */ +{ + char Charac; /* holds a character */ + int indx; /* returned by lib$scanc */ + charptr LstBeg; /* beginning of ^E[x,x,x] list */ + char mask; + char OtCase; /* "other" case character */ + charptr QTPtr; /* pointer into q-register text */ + int real_length; /* length of area to be searched */ + BOOLEAN SamChr; /* same character indicator */ + charptr SavEP2; /* temporary holder of EBPtr2 */ + charptr SavSSP; /* temporary holder of SStPtr */ + struct dsc$descriptor_s src_str = { + 0, /* dsc$w_length */ + DSC$K_DTYPE_T, /* dsc$b_dtype */ + DSC$K_CLASS_S, /* dsc$b_class */ + 0 /* dsc$a_pointer */ + }; + DEFAULT Status; + charptr TCBfPt; /* temporary holder of CBfPtr */ + charptr TCStEn; /* temporary holder of CStEnd */ + LONG TmpLng; +#define SEPARATOR '\001' /* separators (not a letter or digit) */ +#define ALPHA '\002' /* alphabetics */ +#define SYMBOL '\004' /* symbol constituents */ +#define DIGIT '\010' /* digits */ +#define LINE_TERMINATOR '\020' /* line terminators (lf, vt, ff) */ +#define ALPHANUMERIC '\040' /* alphanumerics */ +#define LOWER '\100' /* lowercase */ +#define UPPER '\200' /* uppercase */ +static readonly char table_1[256] = + { + SEPARATOR, /* null */ + SEPARATOR, /* ^A */ + SEPARATOR, /* ^B */ + SEPARATOR, /* ^C */ + SEPARATOR, /* ^D */ + SEPARATOR, /* ^E */ + SEPARATOR, /* ^F */ + SEPARATOR, /* ^G (bell) */ + SEPARATOR, /* ^H (bs) */ + SEPARATOR, /* ^I (tab) */ + LINE_TERMINATOR | SEPARATOR, /* ^J (lf) */ + LINE_TERMINATOR | SEPARATOR, /* ^K (vt) */ + LINE_TERMINATOR | SEPARATOR, /* ^L (ff) */ + SEPARATOR, /* ^M (cr) */ + SEPARATOR, /* ^N */ + SEPARATOR, /* ^O */ + SEPARATOR, /* ^P */ + SEPARATOR, /* ^Q */ + SEPARATOR, /* ^R */ + SEPARATOR, /* ^S */ + SEPARATOR, /* ^T */ + SEPARATOR, /* ^U */ + SEPARATOR, /* ^V */ + SEPARATOR, /* ^W */ + SEPARATOR, /* ^X */ + SEPARATOR, /* ^Y */ + SEPARATOR, /* ^Z */ + SEPARATOR, /* escape */ + SEPARATOR, /* FS */ + SEPARATOR, /* GS */ + SEPARATOR, /* RS */ + SEPARATOR, /* US */ + SEPARATOR, /* space */ + SEPARATOR, /* ! */ + SEPARATOR, /* " */ + SEPARATOR, /* # */ + SYMBOL & SEPARATOR, /* $ */ + SEPARATOR, /* % */ + SEPARATOR, /* | */ + SEPARATOR, /* ' */ + SEPARATOR, /* ( */ + SEPARATOR, /* ) */ + SEPARATOR, /* * */ + SEPARATOR, /* + */ + SEPARATOR, /* , */ + SEPARATOR, /* - */ + SYMBOL | SEPARATOR, /* . */ + SEPARATOR, /* / */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 0 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 1 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 2 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 3 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 4 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 5 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 6 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 7 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 8 */ + ALPHANUMERIC | DIGIT | SYMBOL, /* 9 */ + SEPARATOR, /* : */ + SEPARATOR, /* ; */ + SEPARATOR, /* < */ + SEPARATOR, /* = */ + SEPARATOR, /* > */ + SEPARATOR, /* ? */ + SEPARATOR, /* @ */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* A */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* B */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* C */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* D */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* E */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* F */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* G */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* H */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* I */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* J */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* K */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* L */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* M */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* N */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* O */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* P */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* Q */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* R */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* S */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* T */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* U */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* V */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* W */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* X */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* Y */ + UPPER | ALPHANUMERIC | SYMBOL | ALPHA, /* Z */ + SEPARATOR, /* [ */ + SEPARATOR, /* \ */ + SEPARATOR, /* ] */ + SEPARATOR, /* ^ */ + SYMBOL | SEPARATOR, /* _ */ + SEPARATOR, /* ` */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* a */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* b */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* c */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* d */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* e */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* f */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* g */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* h */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* i */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* j */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* k */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* l */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* m */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* n */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* o */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* p */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* q */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* r */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* s */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* t */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* u */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* v */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* w */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* x */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* y */ + LOWER | ALPHANUMERIC | SYMBOL | ALPHA, /* z */ + SEPARATOR, /* { */ + SEPARATOR, /* | */ + SEPARATOR, /* } */ + SEPARATOR, /* ~ */ + SEPARATOR, /* delete */ + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' + }; +#if DEBUGGING + static char *DbgFNm = "ZFrSrc"; + sprintf(DbgSBf,"*SStPtr = '%c', *EBPtr1 = '%c'", *SStPtr, *EBPtr1); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + switch (*SStPtr) { + case CTRL_X: + break; + case CTRL_S: + mask = SEPARATOR; + goto scanc; + case CTRL_N: + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ISS); /* ill. search str. */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + SavSSP = SStPtr; + for (; EBPtr1 <= EndSAr; ++EBPtr1) { + EBPtr2 = EBPtr1; + SStPtr = SavSSP; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE, CMatch() failed"); + return FAILURE; + } + if (!SamChr) + break; + } + break; + case CTRL_E: + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); /* ICE = illegal ^E */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + switch (To_Upper(*SStPtr)) { + case 'A': + mask = ALPHA; + goto scanc; + case 'B': + mask = SEPARATOR; + goto scanc; + case 'C': + mask = SYMBOL; + goto scanc; + case 'D': + mask = DIGIT; + goto scanc; + case 'G': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + TCBfPt = CBfPtr; /* save CBfPtr */ + TCStEn = CStEnd; /* save CStEnd */ + CBfPtr = SStPtr; + CStEnd = SBfPtr; + Status = FindQR(); + SStPtr = CBfPtr; + SBfPtr = CStEnd; + CBfPtr = TCBfPt; /* restore CBfPtr */ + CStEnd = TCStEn; /* restore CStEnd */ + if (Status == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + for (;EBPtr1<=EndSAr;++EBPtr1) { + QTPtr = QR->Start; + while (QTPtr < QR->End_P1) + if (*QTPtr++ == *EBPtr1) + goto kludge; + } +kludge: break; + case 'L': + mask = LINE_TERMINATOR; + goto scanc; + case 'M': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + SavSSP = SStPtr; + if (ZFrSrc() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (EBPtr1 > EndSAr) { /* if not found */ + break; + } + while (EBPtr2 < EndSAr) { + SavEP2 = EBPtr2++; + SStPtr = SavSSP; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (!SamChr) { + EBPtr2 = SavEP2; + break; + } + } + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + case 'R': + mask = ALPHANUMERIC; + goto scanc; + case 'S': + for (;EBPtr1<=EndSAr;++EBPtr1) { + if ((*EBPtr1 == SPACE) || (*EBPtr1 == TABCHR)) { + EBPtr2 = EBPtr1; + while (EBPtr2 < EndSAr) { + ++EBPtr2; + if ((*EBPtr2 != SPACE) && (*EBPtr2 != TABCHR)) { + EBPtr2--; + break; + } + } + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + break; + case 'V': + mask = LOWER; + goto scanc; + case 'W': + mask = UPPER; + goto scanc; + case 'X': + break; + case '<': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + TmpLng = 0; + while (Is_Digit(*SStPtr)) { + TmpLng *= 8; + TmpLng += *SStPtr - '0'; + if (TmpLng > 127) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + if (*SStPtr != '>') { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + Charac = (char)TmpLng; + for (; EBPtr1 <= EndSAr; ++EBPtr1) { + if (*EBPtr1 == Charac) { + break; + } + } + break; + case '[': + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + LstBeg = SStPtr; + for (;EBPtr1<=EndSAr;++EBPtr1) { + while (*SStPtr != ']') { + if (*SStPtr == ', ') { + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } else { + EBPtr2 = EBPtr1; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (SamChr) { + while (*SStPtr != ']') { + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + EBPtr2 = EBPtr1; + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + } + if (++SStPtr == SBfPtr) { + ErrMsg(ERR_ISS); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + SStPtr = LstBeg; + } + break; + default: + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + break; + default: + if (SMFlag) { /* if case dependence */ + for (;EBPtr1<=EndSAr;++EBPtr1) { + if (*EBPtr1 == *SStPtr) { + break; + } + } + } else { /* else case independence */ + OtCase = (Is_Upper(*SStPtr)) ? + To_Lower(*SStPtr) : + To_Upper(*SStPtr); + for (;EBPtr1<=EndSAr;++EBPtr1) { + if ((*EBPtr1 == *SStPtr) || + (*EBPtr1 == OtCase)) { + break; + } + } + } + break; + } /* end of switch */ + EBPtr2 = EBPtr1; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, EBPtr1 = %ld, EndSAr = %ld", + Zcp2ul(EBPtr1), Zcp2ul(EndSAr)); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; +scanc: real_length = EndSAr - EBPtr1; + real_length++; + src_str.dsc$a_pointer = EBPtr1; + while (real_length > 0) { + src_str.dsc$w_length = (real_length > 65535) ? + 65535 : + real_length; + indx = lib$scanc(&src_str, table_1, &mask); + if (indx) { /* if scan succeeded */ + EBPtr1 += indx; + EBPtr1--; + EBPtr2 = EBPtr1; + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + real_length -= 65535; + src_str.dsc$a_pointer += 65535; + } + EBPtr1 = EndSAr; + EBPtr1++; + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; +} +#else +DEFAULT ZFrSrc() /* forward search for 1st search charptr */ +{ + char Charac; /* holds a character */ + charptr LstBeg; /* beginning of ^E[x,x,x] list */ + char OtCase; /* "other" case character */ + charptr QTPtr; /* pointer into q-register text */ + BOOLEAN SamChr; /* same character indicator */ + charptr SavEP2; /* temporary holder of EBPtr2 */ + charptr SavSSP; /* temporary holder of SStPtr */ + DEFAULT Status; + charptr TCBfPt; /* temporary holder of CBfPtr */ + charptr TCStEn; /* temporary holder of CStEnd */ + LONG TmpLng; +#if DEBUGGING + static char *DbgFNm = "ZFrSrc"; + sprintf(DbgSBf,"*SStPtr = '%c', *EBPtr1 = '%c'", *SStPtr, *EBPtr1); + DbgFEn(3,DbgFNm,DbgSBf); +#endif + switch (*SStPtr) { + case CTRL_X: + break; + case CTRL_S: + for (;EBPtr1<=EndSAr;++EBPtr1) + if (!Is_Alnum(*EBPtr1)) + break; + break; + case CTRL_N: + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ISS); /* ill. search str. */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + SavSSP = SStPtr; + for (;EBPtr1<=EndSAr;++EBPtr1) + { + EBPtr2 = EBPtr1; + SStPtr = SavSSP; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (!SamChr) + break; + } + break; + case CTRL_E: + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); /* ICE = illegal ^E */ + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + switch (To_Upper(*SStPtr)) { + case 'A': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (Is_Alpha(*EBPtr1)) + break; + break; + case 'B': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (!Is_Alnum(*EBPtr1)) + break; + break; + case 'C': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (Is_SyCon(*EBPtr1)) + break; + break; + case 'D': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (Is_Digit(*EBPtr1)) + break; + break; + case 'G': + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + TCBfPt = CBfPtr; /* save CBfPtr */ + TCStEn = CStEnd; /* save CStEnd */ + CBfPtr = SStPtr; + CStEnd = SBfPtr; + Status = FindQR(); + SStPtr = CBfPtr; + SBfPtr = CStEnd; + CBfPtr = TCBfPt; /* restore CBfPtr */ + CStEnd = TCStEn; /* restore CStEnd */ + if (Status == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + for (;EBPtr1<=EndSAr;++EBPtr1) + { + QTPtr = QR->Start; + while (QTPtr < QR->End_P1) + if (*QTPtr++ == *EBPtr1) + goto kludge; + } +kludge: break; + case 'L': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (IsEOL(*EBPtr1)) + break; + break; + case 'M': + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + SavSSP = SStPtr; + if (ZFrSrc() == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (EBPtr1 > EndSAr) /* if not found */ + break; + while (EBPtr2 < EndSAr) + { + SavEP2 = EBPtr2++; + SStPtr = SavSSP; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (!SamChr) + { + EBPtr2 = SavEP2; + break; + } + } + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + case 'R': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (Is_Alnum(*EBPtr1)) + break; + break; + case 'S': + for (;EBPtr1<=EndSAr;++EBPtr1) + if ((*EBPtr1 == SPACE) || + (*EBPtr1 == TABCHR)) + { + EBPtr2 = EBPtr1; + while (EBPtr2 < EndSAr) + { + ++EBPtr2; + if ((*EBPtr2 != SPACE) && + (*EBPtr2 != TABCHR)) + { + EBPtr2--; + break; + } + } + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + break; + case 'V': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (Is_Lower(*EBPtr1)) + break; + break; + case 'W': + for (;EBPtr1<=EndSAr;++EBPtr1) + if (Is_Upper(*EBPtr1)) + break; + break; + case 'X': + break; + case '<': + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + TmpLng = 0; + while (Is_Digit(*SStPtr)) + { + TmpLng *= 8; + TmpLng += *SStPtr - '0'; + if (TmpLng > 127) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + if (*SStPtr != '>') + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"SUCCESS"); + return FAILURE; + } + Charac = (char)TmpLng; + for (;EBPtr1<=EndSAr;++EBPtr1) + if (*EBPtr1 == Charac) + break; + break; + case '[': + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + LstBeg = SStPtr; + for (;EBPtr1<=EndSAr;++EBPtr1) + { + while (*SStPtr != ']') + if (*SStPtr == ',') + { + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + else + { + EBPtr2 = EBPtr1; + if (CMatch(&SamChr) == FAILURE) { + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + if (SamChr) + { + while (*SStPtr != ']') + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + EBPtr2 = EBPtr1; + DBGFEX(3,DbgFNm,"SUCCESS"); + return SUCCESS; + } + if (++SStPtr == SBfPtr) + { + ErrMsg(ERR_ISS); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + } + SStPtr = LstBeg; + } + break; + default: + ErrMsg(ERR_ICE); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + break; + default: + if (SMFlag) /* if case dependence */ + { + for (;EBPtr1<=EndSAr;++EBPtr1) + if (*EBPtr1 == *SStPtr) + break; + } + else /* else case independence */ + { + OtCase = (Is_Upper(*SStPtr)) ? + To_Lower(*SStPtr) : + To_Upper(*SStPtr); + for (;EBPtr1<=EndSAr;++EBPtr1) + if ((*EBPtr1 == *SStPtr) || + (*EBPtr1 == OtCase)) + break; + } + } /* end of switch */ + EBPtr2 = EBPtr1; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, EBPtr1 = %ld, EndSAr = %ld", + Zcp2ul(EBPtr1), Zcp2ul(EndSAr)); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; +} +#endif diff --git a/src/zlinux.c b/src/zlinux.c new file mode 100644 index 0000000..5d65a0f --- /dev/null +++ b/src/zlinux.c @@ -0,0 +1,1356 @@ +/***************************************************************************** + ZLinux.c + System dependent code for Linux + This is based on zunix.c, with changes (see comments "TAA") + for enhanced functionality. +*****************************************************************************/ +/* + * Define standard functions. + */ +#include /* needed before sys/param.h is included */ +#include /* define errno */ +#include /* malloc() and realloc() */ +#include /* to catch ^C and ^Z signals */ +#include /* define stdin */ +#include /* strncpy(), strlen(), etc. */ +#include /* define tm struct */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Rewritten 05/04 by TAA to use glob function */ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "chmacs.h" /* define character processing macros */ +#include "clpars.h" /* command-line parsing macro */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +#include "defext.h" /* define external global variables */ +#include "dscren.h" /* define identifiers for screen i/o */ +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 */ +// 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 */ +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; +/***************************************************************************** + 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]; +/* TAA Mod 5/04 -- keep track of last character being CR so we will + * have CRLF -> CRLF instead of CRLFLF in case input file is DOS + * format. */ +static int IFisCR[NIFDBS] = {0}; +/***************************************************************************** + 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 */ + BOOLEAN forBackup; /* TAA Mod */ +} OFiles[NOFDBS]; +/***************************************************************************** + ZErMsg() + This function displays 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() +{ + if (errno < sys_nerr) + ErrStr(ERR_SYS, sys_errlist[errno]); +} +/***************************************************************************** + 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(MemSize) /* allocate memory */ +SIZE_T MemSize; +{ + return (voidptr)malloc(MemSize); +} +/***************************************************************************** + 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(VVOID) +{ + ZDspCh('\7'); +} +/***************************************************************************** + 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(NoWait) /* input a character from terminal */ +BOOLEAN NoWait; /* return immediately? */ +{ + char Charac; + static BOOLEAN LastLF = FALSE; + if (LastLF) { + LastLF = FALSE; + return (DEFAULT)LINEFD; + } + if (read(fileno(stdin), &Charac, 1) != 1) { + if (GotCtC || SupGotCtC) + return (DEFAULT)CTRL_C; + if (!GotCtC) { + ZErMsg(); + ErrMsg(ERR_URC); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + GotCtC = FALSE; + if (Charac == CRETRN) { + LastLF = TRUE; + return (DEFAULT)CRETRN; + } + 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. +*****************************************************************************/ + 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 { + /* Cannot set value */ +// 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 */ + retval = 0L; + } + return retval; + } +/***************************************************************************** + See the definition of MEMMOVE in ZPORT.H for a description of this + function. +*****************************************************************************/ +VVOID ZCpyBl(Destin, Source, Length) +charptr Destin; +charptr Source; +SIZE_T Length; +{ + if (Source < Destin) { + Source += Length; + Destin += Length; + while (Length-- > 0) { + *--Destin = *--Source; + } + } else { + while (Length-- > 0) { + *Destin++ = *Source++; + } + } +} +#if DEBUGGING +ULONG Zcp2ul(cp) /* convert charptr to ULONG */ +voidptr cp; +{ + return (ULONG)(cp); +} +#endif +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */ +{ + DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); + if (tty_set == TRUE) + tcsetattr(0, TCSANOW, &out); +} +/***************************************************************************** + 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. +*****************************************************************************/ +VVOID ZDoCmd(charptr GBfBeg, charptr GBfPtr) /* die and pass command to OS */ +{ + char buf[128+1]; + char *space_p; + DBGFEN(1,"ZDoCmd",NULL); +/* + * 1. Terminate buf[] and command line in GBf + * 2. make local copy since GBf 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] = *GBfPtr = '\0'; + (void)strncpy(buf, GBfBeg, 128); + if ((space_p = strchr(buf,' ')) != NULL) { + *space_p++ = '\0'; + } + ZClnUp(); + execlp ("/bin/sh", "sh", "-c", buf, (space_p) ? space_p : NULL, NULL); + /* we should never reach this statement */ + (void)perror (""); + 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 call ZDspCh for every character +in the buffer. +*****************************************************************************/ +VVOID ZDspBf(buffer, length) /* output a buffer to terminal */ +charptr buffer; +SIZE_T length; +{ + if (write(fileno(stdout), buffer, length) == -1) { + puts("Unable to write to terminal in function ZDspBf"); + TAbort(EXIT_FAILURE); + } +} +/***************************************************************************** + ZDspCh() + This function outputs a single character to the terminal. +*****************************************************************************/ +VVOID ZDspCh(Charac) /* output a character to terminal */ +char Charac; +{ + if (write(fileno(stdout), &Charac, 1) == -1) { + puts("Unable to write to terminal in function ZDspCh"); + TAbort(EXIT_FAILURE); + } +} +/***************************************************************************** + 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() /* return current date */ +{ + time_t clockt; + struct tm *time_of_day; + int tecodate; + DBGFEN(1,"ZExCtB",""); + 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()"); + 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 +*****************************************************************************/ +DEFAULT ZExCtH() /* return current time */ +{ + time_t clockt; + struct tm *time_of_day; + int tecotime; + DBGFEN(1,"ZExCtH",""); + 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; + 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) + 25857 under OS/2 (101*256 = IBM-PC, 1 = OS/2) + 25858 under Linux (101*256 = IBM-PC, 2 = Linux) + 0EJ process id on VAXen or Unix/Linux, 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() /* 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"); + return FAILURE; + } + } + if (NArgmt == -1) { + DBGFEX(1,DbgFNm,"PushEx(25858)"); + return PushEx((LONG)25858, OPERAND); /* means "PC Linux" */ + } + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"PushEx(getppid())"); + return PushEx((LONG)getppid(), OPERAND); + } + DBGFEX(1,DbgFNm,"ExeNYI()"); + return ExeNYI(); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +VVOID ZExit(estat) /* terminate TECO-C */ +DEFAULT estat; +{ + ZClnUp(); + exit(estat); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(pointer) /* free memory allocated by ZAlloc */ +voidptr pointer; +{ + free(pointer); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt) +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? */ +{ + (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(IfIndx) /* close input file */ +DEFAULT IfIndx; /* index into IFiles array */ +{ + DBGFEN(2,"ZIClos",NULL); + if (IsOpnI[IfIndx]) { /* if it's open */ + if (fclose(IFiles[IfIndx]) == EOF) { + ZErMsg(); + ErrMsg(ERR_UCI); + ZExit(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(OfIndx) /* close and delete output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + 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); + ZExit(EXIT_FAILURE); + } + if (remove(OFiles[OfIndx].OFNam) != 0) { + ZErMsg(); + ErrStr(ERR_UCD, OFiles[OfIndx].OFNam); + ZExit(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(OfIndx) /* close output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + int ver; + char TmpFsp[FILENAME_MAX]; + char move_err[1024]; + 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 */ + ZExit(EXIT_FAILURE); + } + if (OFiles[OfIndx].OTNam[0] != '\0') { /* if temporary output file */ + if (OFiles[OfIndx].forBackup) { + (void)strcpy(TmpFsp, OFiles[OfIndx].OTNam);/* copy to TmpFsp */ + if ((EzFlag&EZ_NO_STRIP)==0) { + char *DotPtr = strchr(TmpFsp, '.'); /* find the "." */ + if (DotPtr != NULL) { /* if "." exists */ + *DotPtr = '\0'; /* make it null */ + } + } + if (EzFlag&EZ_NO_VER) { + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else { + ver = vernum(TmpFsp); + if (ver==(-3)) { + puts("\nWARNING: Versioning disabled\n"); + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else if (ver==(-2) || ver==0) { + (void)strcat(TmpFsp, ";1"); + } else if (ver==(-1)) { /* can't read dir */ + ZErMsg(); + ErrMsg(ERR_UCO); /* una to close o */ + ZClnUp(); + exit(EXIT_FAILURE); + } else { /* ver > 0 */ + int ln = strlen(TmpFsp); + ver++; + strcat(TmpFsp, ";"); + MakDBf((LONG)ver, 10); + strncat(TmpFsp, DBfBeg, DBfPtr-DBfBeg); + *(TmpFsp+ln+(1+DBfPtr-DBfBeg)+1) = '\0'; + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OTNam, TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (rename(OFiles[OfIndx].OTNam, TmpFsp)) { /* TAA changed to use rename */ + ZErMsg(); + ZDspBf("Edit saved in ", 14); + ZDspBf(OFiles[OfIndx].OFNam, + strlen(OFiles[OfIndx].OFNam)); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } else { /* Delete original if not backing up */ + if (remove(OFiles[OfIndx].OTNam) != 0) { + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"remove() failed"); + exit(EXIT_FAILURE); + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OFNam, OFiles[OfIndx].OTNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (rename(OFiles[OfIndx].OFNam, + OFiles[OfIndx].OTNam)) { + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + 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, "r")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + IFisCR[IfIndx] = 0; + 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, "r")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + IFisCR[IfIndx] = 0; + 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, "r")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + IFisCR[IfIndx] = 0; + return SUCCESS; + } + if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + (void)strcat(FBfBeg,".tec"); /* append .tec */ + FBfPtr += 4; + if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { + IFisCR[IfIndx] = 0; + 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. +*****************************************************************************/ +/* + * Unix file names do not have version numbers, 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 close routine will deal + * with renaming files to make them come out right. If no file with the + * same name already exists, then the output file can simply be opened. + * The close routine will only rename files if a temporary file was created + * by this routine. + */ +DEFAULT ZOpOut(OfIndx, RepErr, Backup) /* open output file */ +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +BOOLEAN Backup; /* TAA Added */ +{ + char *tfname; + struct stat *bufstat = NULL; + int tmpflag = 0; +#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(FBfBeg, 0) == 0) { /* if file already exists */ + char *dirname,*s; + int n; + bufstat = (struct stat *)malloc(sizeof(struct stat)); + stat(FBfBeg, bufstat); + tmpflag = 1; + n = FBfPtr - FBfBeg; /* strlen(FBfBeg) */ + dirname = (char *)malloc(n+4); + strcpy(dirname, FBfBeg); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + *s='\0'; + } else { /* must have s==dirname and + *s != '/', so current + directory */ + *dirname='.'; *(dirname+1)='\0'; + } + tfname = tempnam(dirname,"tecoc"); + (void)strcpy(OFiles[OfIndx].OFNam, tfname); + free(tfname); + free(dirname); + (void)strcpy(OFiles[OfIndx].OTNam, FBfBeg); +#if DEBUGGING + sprintf(DbgSBf, "file %s already exists\r\n", FBfBeg); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + } else { + (void)strcpy(OFiles[OfIndx].OFNam, FBfBeg); + OFiles[OfIndx].OTNam[0] = '\0'; + } +#if DEBUGGING + sprintf(DbgSBf, "creating file %s\r\n", OFiles[OfIndx].OFNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + OFiles[OfIndx].OStrem = fopen(OFiles[OfIndx].OFNam, "w"); + if (OFiles[OfIndx].OStrem == NULL) { + if (RepErr) + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if (tmpflag) { + fchmod(fileno(OFiles[OfIndx].OStrem), + bufstat->st_mode | S_IRUSR | S_IWUSR); + free(bufstat); + } + DBGFEX(2,DbgFNm,"SUCCESS"); + OFiles[OfIndx].forBackup = Backup; + if (OFiles[OfIndx].OTNam[0] != '\0' && RepErr && !Backup) { + ZDspBf("% Superseding existing file\r\n", 29); + } + 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(argc, argv) /* parse a TECOC command line */ +int argc; +char *argv[]; +{ + int i; + char TmpBuf[256]; + SIZE_T line_len; + char *cmd; + 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. + */ + TmpBuf[0] = '\0'; + cmd = strrchr(argv[0], '/'); + if (cmd) { + cmd++; + } else { + cmd = argv[0]; + } + if (strcmp(cmd, "teco") == 0 || + strcmp(cmd, "mung") == 0) { + strcat(TmpBuf, cmd); + strcat(TmpBuf, " "); + } else if (strcmp(cmd, "inspect") == 0) { + strcat(TmpBuf, "teco -inspect "); + } else if (strcmp(cmd, "Make") == 0) { + strcat(TmpBuf, "make "); + } + if (argc > 1 || TmpBuf[0] != '\0') { + for (i=1; iStart, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +#if USE_ANSI_CLPARS +/* + * execute imbedded command line-parsing macro directly from clpars[] + */ + 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 */ +#else +/* + * 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()"); + ZExit(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 = (charptr)"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 + 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. +*****************************************************************************/ +/* Rewritten 05/04 by TAA */ +DEFAULT ZPWild() /* preset the wildcard lookup filename */ +{ + int result,i; +/* + * if we didn't process all names from a previous EN` call then discard them + */ + globfree(&pglob); + globindex = 0; + *FBfPtr='\0'; /* terminate string */ + result = glob(FBfBeg, GLOB_ERR|GLOB_MARK, NULL, &pglob); + if (result != 0) { + return FAILURE; + } + result = 0; /* Count files matched */ + for (i = 0; i < pglob.gl_pathc; i++) { + if (pglob.gl_pathv[i][strlen(pglob.gl_pathv[i])-1] != '/') { + result++; + } + } + if (result > 0) { + return SUCCESS; + } + return FAILURE; +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(OldBlk, NewSiz) /* re-allocate memory */ +voidptr OldBlk; +SIZE_T NewSiz; +{ + return (voidptr)realloc(OldBlk, NewSiz); +} +/***************************************************************************** + ZRdLin() + This function reads a line from a file. It is passed a buffer, the +size of the buffer, and a file pointer. It returns the length of the line, +or sets IsEofI[] to TRUE if the end of file is encountered. +*****************************************************************************/ +DEFAULT ZRdLin(ibuf, ibuflen, IfIndx, retlen) +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) { + *retlen = shortBuf - charsLeft + 1; + if ((EzFlag & EZ_UNIXNL) == 0 && IFisCR[IfIndx] == 0) { + ibuf[(*retlen) -1] = CRETRN; + ibuf[(*retlen)] = LINEFD; + (*retlen)++; + } + IFisCR[IfIndx] = 0; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + IFisCR[IfIndx] = character == '\r'; /* last character was a CR -- DOS file? */ + if (character == FORMFD && !(EzFlag & ED_FF)) { + /* 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; + } + /* TAA Mod 5/04 -- must allow for extra character if + * UNIXNL since LF becomes CRLF */ + if (--charsLeft == ((EzFlag&EZ_UNIXNL) ? 0 : 1)) { + /* 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(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); +// } +} +/***************************************************************************** + 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(TTWhat, TTVal) /* tell operating system we set the term. */ +DEFAULT TTWhat; /* what terminal parameter to set */ +DEFAULT TTVal; /* what to set it to */ +{ + 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 +*****************************************************************************/ +/* Rewritten 05/04 by TAA */ +DEFAULT ZSWild() /* search for next wildcard filename */ +{ + int filename_length; + if (pglob.gl_pathc == 0) + return FAILURE; + do { + if (globindex >= pglob.gl_pathc) return FILENF; + if (pglob.gl_pathv[globindex][strlen(pglob.gl_pathv[globindex]-1)] != '/') break; + globindex++; + } while (1); +/* + * we really have a file name now + */ + filename_length = strlen(pglob.gl_pathv[globindex]); + MEMMOVE(FBfBeg, pglob.gl_pathv[globindex], filename_length); + FBfPtr = FBfBeg + filename_length; + globindex++; + 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 command procedure (under VMS) or a script file (under __UNIX__), 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) + When TECO is started, the terminal will probably be set up for +buffered I/O, so characters won't be received until a RETURN is hit, and +they will be automatically echoed. Set the terminal up for raw I/O, so each +character is received when it is struck, and no echoing is performed. Save +the terminal characteristics so when we exit we can reset them (in ZClnUp) +to what they were before we changed them. +*****************************************************************************/ +static VVOID CntrlC() +{ + signal(SIGINT, SIG_IGN); + SupGotCtC = 0; + if (EtFlag & ET_TRAP_CTRL_C) { /* if user wants it */ + EtFlag &= ~ET_TRAP_CTRL_C; /* turn off bit */ + SupGotCtC = 1; + } else { /* user doesn't want it */ + if (EtFlag & ET_MUNG_MODE) { /* if in MUNG mode */ + TAbort(EXIT_SUCCESS); + } + GotCtC = TRUE; /* set "stop soon" flag */ + } + signal(SIGINT, CntrlC); +} +/* + * sighup - what we do if we get a hang up? + */ +static void sighup() +{ + TAbort(EXIT_FAILURE); +} +/* + * sigstop - what to do if we get a ^Z + */ +static void sigstop() +{ + tcsetattr(0, TCSANOW, &out); + puts("[Suspending...]\r\n"); + kill(getpid(), SIGSTOP); + puts("[Resuming...]\r\n"); + tcsetattr(0, TCSANOW, &cur); +} +/* + * ZTrmnl - set up terminal modes + */ +VVOID ZTrmnl() /* set up I/O to the terminal */ +{ + EtFlag = ET_READ_LOWER | /* guess: term has lowercase and */ + 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 */ + EZ_INVCR; /* don't show little c/r characters */ +/* + * get terminal characteristics and set some signals + */ + 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 +/* + * set CBREAK/noECHO/noCRMOD + */ + cur.c_lflag &= ~ICANON; + cur.c_lflag &= ~ECHO; + cur.c_oflag &= ~ONLCR; + cur.c_iflag &= ~(ICRNL | INLCR); + tcsetattr(0, TCSANOW, &cur); + 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! */ +} +/***************************************************************************** + ZVrbos() + This function displays the verbose form of an error message. +*****************************************************************************/ +VVOID ZVrbos(ErrNum, ErMnem) +WORD ErrNum; +char *ErMnem; +{ + char **TmpPtr; +#include "vrbmsg.h" + 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, one line at a time. It is +passed an output file index and pointers to the beginning and end of the +buffer to be output. +*****************************************************************************/ +DEFAULT ZWrBfr(OfIndx, BfrBeg, BfrEnd) +DEFAULT OfIndx; /* index into OFiles array */ +charptr BfrBeg; /* address of output buffer beginning */ +charptr BfrEnd; /* address of output buffer end */ +{ +#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 we're doing Unix-style editing, where lines are terminated with a + * line feed (newline) instead of a carriage-return/line-feed pair, then + * we can just fwrite the buffer. Otherwise, we have to scan the buffer + * and convert CR/LF pairs to just LF before output. + */ + if (EzFlag & EZ_UNIXNL) { + ptrdiff_t bufsiz = BfrEnd-BfrBeg+1; + if (fwrite(BfrBeg, sizeof(char), bufsiz, + OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"Zfwrite() failed"); + return FAILURE; + } + } else { + charptr BfrPtr = BfrBeg; /* output buffer pointer */ + while (BfrPtr <= BfrEnd) { + if (*BfrPtr == CRETRN) { + BfrPtr++; + if ((BfrPtr > BfrEnd) || (*BfrPtr != LINEFD)) { + BfrPtr--; + } + } + if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + ++BfrPtr; + } + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/**************************************************************************** + vernum() + From Mark Henderson, was in a separate file named vernum.c. +*****************************************************************************/ +static int vernum(target) +/* +maximum version number of target (similar to VMS mechanism) +return +-3 error - problems other than file not found and can't open directory +-2 error - did not find file +-1 error - cannot open directory containing target + 0 file found - no version numbers found + n > 0 version number of highest name;n +*/ +char *target; +{ + DIR *dirp; + int found = 0; /* file found flag */ + char *ftarget; + int maxver = 0; + char *dirname; + struct dirent *dp; + int n; + char *s; + n = strlen(target); + dirname=(char *)malloc(strlen(target)+4); + ftarget=(char *)malloc(strlen(target)+4); + strcpy(dirname, target); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + strcpy(ftarget,s+1); + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + strcpy(ftarget,s+1); + *s='\0'; + } else { /* must have s==dirname and *s!='/', so current directory */ + strcpy(ftarget,target); + *dirname='.'; *(dirname+1)='\0'; + } + dirp = opendir(dirname); + if (dirp == NULL) { + ZDspBf("\nerror openning directory ", 26); + ZDspBf(dirname, strlen(dirname)); + ZDspCh('\n'); + free(dirname); + free(ftarget); + return(-1); + } + n=strlen(ftarget); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (strncmp(dp->d_name,ftarget,n) == 0) { + char *suffix = dp->d_name + n; + if (*suffix == '\0') { + found = 1; + if (maxver <= 0) + maxver = 0; + } + if (*suffix == ';') { + int k; + found = 1; + k=atoi(suffix+1); + if (k<=0) { + free(dirname); + free(ftarget); + closedir(dirp); + return(-3); + } + if (k>=maxver) + maxver = k; + } + } + } + free(dirname); + free(ftarget); + closedir(dirp); + return (found) ? maxver : -2; +} diff --git a/src/zmsdos.c b/src/zmsdos.c new file mode 100644 index 0000000..1f87763 --- /dev/null +++ b/src/zmsdos.c @@ -0,0 +1,2282 @@ +/***************************************************************************** + Zmsdos.c + + System dependent code for MS-DOS and the Turbo C v2.0 compiler. +*****************************************************************************/ + +#include /* prototype for farfree(), farmalloc() */ +#include /* prototype for findfirst(), findnext() */ +#include /* prototypes for sound(), nosound(), etc. */ +#include /* for tolower() */ +#include /* define errno */ +#include /* O_BINARY */ +#include /* prototype for access() */ +#include /* prototype for execlp() */ +#include /* prototype for fread(), fwrite()... */ +#include /* prototype for exit(), system() */ +#include /* prototypes for strlen(), strcat(), ... */ +#include /* prototype for utime() */ +#include /* prototype for stat() */ + +#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 */ + +#define CHUNK 0xFFF0U /* 64K-16 bytes, used in ZCpyBl & Zfwrite */ + +#if USE_PROTOTYPES +static SIZE_T Zfwrite(charptr Buffer, SIZE_T Length, FILE *fp); +static int _Cdecl CntrlC(void); +#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). +*****************************************************************************/ + +#if defined (__POWERC) +#include +#define wherex() (curscol()+1) +#define wherey() (cursrow()+1) +#define gotoxy(x,y) poscurs((x)-1,(y)-1) +#endif + +/***************************************************************************** + 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[MAXDIR]; /* filename path name */ +static char ff_drive[MAXDRIVE]; /* filename drive code */ +static char ff_path[MAXPATH]; /* 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 */ + BOOLEAN forBackup; /* TAA Mod */ +} 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); +} + +/***************************************************************************** + + Zfwrite() + + This function implements fwrite() for the large model. The Turbo C +v2.0 fwrite() returns and takes size_t as it's size arguments. Under Turbo, +size_t is always a 16-bit unsigned int. Therefore, fwrite() can't write more +than 64K at a time. Zfwrite() decomposes writes larger than 64K into CHUNK +size bytes. CHUNK is 16 bytes less than 64K since writes close to 64K can be +dangerous. + +*****************************************************************************/ + +static SIZE_T Zfwrite(charptr Buffer, SIZE_T Length, FILE *fp) +{ + size_t NBytes; /* number of bytes to write (0-64K) */ + size_t WBytes; /* number of bytes written */ + SIZE_T RetVal; /* return value */ + + RetVal = 0; + while (Length != 0) { + NBytes = (Length > CHUNK) ? CHUNK : (size_t) Length; + WBytes = fwrite((char *)Buffer, sizeof(char), NBytes, fp); + RetVal += WBytes; + if (WBytes != NBytes) { + break; + } + Length -= NBytes; + Buffer += NBytes; + } + return RetVal; +} + +/***************************************************************************** + + 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 = farmalloc(MemSiz); + +#if DEBUGGING + +/* + * is the heap corrupted? + */ + +#if defined(__TURBOC__) && (__TURBOC__ >= 0x0295) + if (heapcheck () < 0) { + puts ("ZAlloc: heapcheck failed"); + exit (1); + } +#endif + +/* + * 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) +{ +#ifdef WIN32 + putch('\a'); +#else + 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 */ +#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 (); + 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. This functions returns 0L on failure +or -1L on success. + + Under MS-DOS, the values of the INI, MEM, LIB, and VTE functions are +stored in the TEC$INIT, TEC$MEMORY, TEC$LIBRARY, and TEC$VTEDIT environment +variables. + +*****************************************************************************/ + +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 */ +{ +#if 0 + EGWhat = EGWhat; /* stop TC parameter not used warnings */ + EGOper = EGOper; + TxtPtr = TxtPtr; + return 0L; /* return failure */ +#else + + 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; +#endif +} + +/***************************************************************************** + + 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 */ +} + +/***************************************************************************** + + ZCpyBl() + + This function implements memmove() for the large data model. The +Turbo C v2.0 memory move functions all deal with size_t bytes. Since size_t +is always a 16-bit unsigned int, memmove() and memcpy() can't move blocks +larger than 64K. ZCpyBl() decomposes moves larger than 64K into CHUNK size +bytes. CHUNK is 16 bytes less than 64K since moves close to 64K can be +dangerous. + +*****************************************************************************/ + +VVOID ZCpyBl(charptr Destin, charptr Source, SIZE_T Length) +{ + size_t NBytes; /* number of bytes to move (0-64K) */ + + if (Source < Destin) { /* do move backwards */ + Source += Length; + Destin += Length; + while (Length > 0) { + NBytes = (Length > CHUNK) ? CHUNK : (size_t) Length; + Length -= NBytes; + Source -= NBytes; + Destin -= NBytes; + memmove((void *) Destin, (void *) Source, NBytes); + } + } else { /* do move forwards */ + while (Length > 0) { + NBytes = (Length > CHUNK) ? CHUNK : (size_t) Length; + memcpy((void *) Destin, (void *) Source, NBytes); + Length -= NBytes; + Source += NBytes; + Destin += NBytes; + } + } +} + +/***************************************************************************** + + 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 + 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(charptr GBfBeg, charptr GBfPtr) /* die and pass command to OS */ +{ + char *space_p; + char *comspec; + + DBGFEN(1,"ZDoCmd",NULL); + +/* + * 1. Terminate command line in GBf + * 2. separate program name from arguments, if any + * 3. Call ZClnUp to free up everything + * 4. Execute the command line, with optional arguments. If we know where + * the command processor is, use it so we can execute .BAT batch files + * 5. we shouldn't be here, exit + */ + + *GBfPtr = '\0'; + if ((space_p = strchr ((char *)GBfBeg,' ')) != NULL) { + *space_p++ = '\0'; + } + ZClnUp (); + + if ((comspec = getenv("COMSPEC")) != NULL) { + execlp (comspec, + comspec, + " /c ", + GBfBeg, + (space_p) ? space_p : NULL, NULL); + } else { +#ifdef WIN32 + execlp ((char *)GBfBeg, + (char *)GBfBeg, + (space_p) ? space_p : NULL, NULL); +#else + execlp ((char _far *)GBfBeg, + (char _far *)GBfBeg, + (space_p) ? space_p : NULL, NULL); +#endif + } + 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 (Zfwrite (buffer, length, stdout) != length) { + puts("\nZDspBf: Zfwrite() 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); + } + + DBGFEX(5,DbgFNm,NULL); +} + +/***************************************************************************** + + ZDspCh() + + This function outputs a single character to the terminal. + +*****************************************************************************/ + +VVOID ZDspCh(char Charac) /* output a character to terminal */ +{ + if (fwrite(&Charac, sizeof(char), 1, stdout) != 1) + TAbort(EXIT_FAILURE); +} + +/***************************************************************************** + + ZExCtB() + + This function implements the TECO ^B command, which returns the +current date encoded in the following way: + + ((year-1900)*16+month)*32+day + + This function calls DOS to get the current date. + +*****************************************************************************/ + +DEFAULT ZExCtB(void) /* return current date */ +{ +#ifdef WIN32 + struct date foo; + getdate(&foo); + return PushEx(((foo.da_year-1900)*16+foo.da_mon)*32+foo.da_day, OPERAND); +#else + unsigned int m; /* month */ + unsigned int d; /* day */ + unsigned int y; /* year */ + LONG td; /* encoded teco date */ + union REGS regs; /* registers for intdos() */ + + memset (®s, 0, sizeof (union REGS)); + td = 0; + + regs.h.ah = 0x2A; /* AH = get date function */ + intdos (®s, ®s); /* call DOS via INT 0x21 */ + + if (regs.x.cflag != 0) { /* if DOS error */ + /* should we report DOS error??? */ + } else { + m = regs.h.dh; /* DH = month (1-12) */ + d = regs.h.dl; /* DL = day (1-31) */ + y = regs.x.cx; /* CX = year (1980-2099) */ + if (m < 1 || m > 12 || + d < 1 || d > 31 || + y < 1980 || y > 2099) { + /* should we report illegal date??? */ + } else { + td = (((LONG)y - 1900) * 16 + (LONG)m) * 32 + (LONG)d; + } + } + + return PushEx(td, OPERAND); /* return date on stack */ +#endif +} + +/***************************************************************************** + + ZExCtH() + + This function implements the TECO ^H command, which returns the +current time encoded in the following way: + + (seconds since midnight) / 2 + + This function calls DOS to get the current time. Alternatively, +this function could directly interrogate the master clock count at 0040:006C +which is the number of timer ticks since midnight. + + Note: to execute this function, enter H, as ^H is interpreted +as a backspace. + +*****************************************************************************/ + +DEFAULT ZExCtH(void) /* return current time */ +{ +#ifdef WIN32 + struct time foo; + gettime(&foo); + return PushEx((foo.ti_hour*60+foo.ti_min)*30+foo.ti_sec/2, OPERAND); +#else + unsigned int h; /* hours */ + unsigned int m; /* minutes */ + unsigned int s; /* seconds */ + LONG tt; /* encoded teco time */ + union REGS regs; /* registers for intdos() */ + + memset (®s, 0, sizeof (union REGS)); + tt = 0; + + regs.h.ah = 0x2C; /* AH = get time function */ + intdos (®s, ®s); /* call DOS via INT 0x21 */ + + if (regs.x.cflag != 0) { /* if DOS error */ + /* should we report DOS error? */ + } else { + h = regs.h.ch; /* CH = hour (0-23) */ + m = regs.h.cl; /* CL = minutes (0-59) */ + s = regs.h.dh; /* DH = seconds (0-59) */ + if (h > 23 || m > 59 || s > 59) { + /* should we report illegal time? */ + } else { +/* + * this is the same as (h * 3600 + m * 60 + s) / 2 + */ + tt = (LONG)h * 1800 + (LONG)m * 30 + (LONG)s / 2; + } + } + + return PushEx(tt, OPERAND); /* return time on stack */ +#endif +} + +/***************************************************************************** + + 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) { +#ifdef WIN32 + DBGFEX(1,DbgFNm,"PushEx(25857)"); + return PushEx((LONG)25857, OPERAND); /* means "WIN-32" or OS/2 */ +#else + DBGFEX(1,DbgFNm,"PushEx(25856)"); + return PushEx((LONG)25856, OPERAND); /* means "MS-DOS" */ +#endif + } + + 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 */ +{ + 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); + +/* + * is the heap corrupted? + */ + +#if defined(__TURBOC__) && (__TURBOC__ >= 0x0295) + if (heapcheck () < 0) { + puts ("ZFree: heapcheck failed"); + exit (1); + } +#endif + +/* + * 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 + + farfree ((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 + +*****************************************************************************/ + +static DEFAULT fastcopy(char *srcname, char *dstname) { + /* fastcopy copies from srcname to dstname then deletes the source + file. It returns a 0 on success. */ + int srchandle, dsthandle; +#define BUFSIZE 4096 + char *buffer; + struct utimbuf times; + struct stat statbuf; + int size; + + if ((buffer = (char *)malloc(BUFSIZE)) == NULL) return 1; + + if ((srchandle = open(srcname, O_RDONLY|O_BINARY)) == -1) { + free(buffer); + return 1; + } + if ((dsthandle = open(dstname, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, + S_IREAD|S_IWRITE)) == -1) { + close(srchandle); + free(buffer); + return 1; + } + while ((size=read(srchandle, buffer, BUFSIZE)) >0) { + if (write(dsthandle, buffer, size) != size) { + size = -1; /* signal an error */ + break; + } + } + close(srchandle); + close(dsthandle); + free(buffer); + if (size < 0) { + remove(dstname); + return 1; + } +#if (TC_SMALL_CODE==0) /* Not enough room to update stamp if medium model */ + stat(srcname, &statbuf); + times.actime = statbuf.st_atime; + times.modtime = statbuf.st_mtime; + utime(dstname, ×); +#endif + remove(srcname); + return 0; +} + + + +VVOID ZOClos(DEFAULT OfIndx) /* close output file */ +{ + char *DotPtr; + char *SlaPtr1, *SlaPtr2; + 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 */ + + if (OFiles[OfIndx].forBackup) { + /* only do backup thing if we were doing EB originally */ + /* + * build "filename.bak" filespec in TmpFsp[] + */ + + strcpy(TmpFsp, OFiles[OfIndx].OTNam); /* copy to TmpFsp */ + SlaPtr1 = strrchr(TmpFsp, '/'); + SlaPtr2 = strrchr(TmpFsp, '\\'); + if ((SlaPtr1 == NULL) || + (SlaPtr2 != NULL && SlaPtr2 > SlaPtr1)) + SlaPtr1 = SlaPtr2; + DotPtr = strrchr(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) && + fastcopy(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 + } /* End backup renaming */ + else { /* delete original if not backing up */ + if (remove(OFiles[OfIndx].OTNam) != 0) { + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"remove() failed"); + exit(EXIT_FAILURE); + } + } + + + /* + * rename "tmpnam" to "filename" + */ + + if (rename(OFiles[OfIndx].OFNam,OFiles[OfIndx].OTNam) && + fastcopy(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); +} + +/***************************************************************************** + + 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 (EIFile) { + char fnbuf[FILENAME_MAX]; + char *envp; + envp = getenv("TEC$LIBRARY"); + if (envp) { + strcpy(fnbuf, envp); + strcat(fnbuf, (char *)FBfBeg); + if ((IFiles[IfIndx] = fopen(fnbuf, "rb"))!= NULL) { + return SUCCESS; + } + } + } + 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; +} + +/***************************************************************************** + + 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, BOOLEAN Backup) +{ +#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 */ + if (access((char *)FBfBeg, 2) != 0) { /* Can't write it? */ + if (RepErr) { + ZErMsg(); + } + return FAILURE; + } + 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"); + + OFiles[OfIndx].forBackup = Backup; + + if (OFiles[OfIndx].OTNam[0] != '\0' && RepErr && !Backup) { + ZDspBf("% Superseding existing file\r\n", 29); + } + 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++) { +#ifdef WIN32 + if ( strchr(*++argv, ' ') != NULL ) { + // There is embedded space, turn into quoted string + strcat(TmpBuf, "\""); + strcat(TmpBuf, *argv); + strcat(TmpBuf, "\" "); + } + else { + strcat(TmpBuf, *argv); + strcat(TmpBuf, " "); + } +#else + strcat(TmpBuf, *++argv); + strcat(TmpBuf, " "); +#endif + } + 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[] + */ + +#ifdef WIN32 + CStBeg = CBfPtr = (unsigned char *)clpars;/* command string start */ + CStEnd = (unsigned char *)clpars + CLPARS_LEN; /* command string end */ +#else + CStBeg = CBfPtr = (unsigned char _far *)clpars;/* command string start */ + CStEnd = (unsigned char _far *)clpars + CLPARS_LEN; /* command string end */ +#endif + EStTop = EStBot; /* clear expression stack */ + ExeCSt(); /* execute command string */ + +#else + +/* + * 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 + + 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, MAXDRIVE); + memset (ff_dir, 0, MAXDIR); + memset (ff_path, 0, MAXPATH); + +/* + * 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, MAXPATH-1); + strlwr (ff_path); + fnsplit (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 + +/* + * The Turbo C v2.0 farrealloc() calls movedata() to move the data + * from the old block to the new block. Unfortunately, movedata() takes an + * unsigned int for the number of bytes to move; so, if the old buffer was + * greater than 64K bytes long, the old data wasn't correctly moved to the + * new block. This version of ZRaloc simulates what farrealloc() does, using + * Teco-C's MEMMOVE() to move the data. + * + * TC++ v1.0 has __TURBOC__ as 0x0295 + */ + +#if defined(__TURBOC__) && (__TURBOC__ < 0x0295) && !TC_SMALL_DATA + +/* + * the far memory allocation functions deal with a structure which + * look something like: + * + * struct _blk { + * unsigned long size; + * unsigned long something; + * char block[size]; + * } + * + * size: the size of the allocated block in bytes, this might + * be rounded to the next paragraph (16-byte) boundary + * something: ? pointer to next block on free list when free'ed ? + * block: a region "size" bytes long. a pointer to this + * region is what the memory allocation functions + * actually return to the user. + * + * Thus, to get to the size of the old block, we simply subtract + * 8 (2 * sizeof(unsigned long)) from the pointer we have, treat + * that like an unsigned long pointer, and look at what's there. + */ + +/* + * manually allocate a new block + */ + + NewBlk = ZAlloc (NewSiz); + +/* + * if there was old data and the malloc was successful, + * move the data from the old block to the new block and + * free the old block. + */ + + if (OldBlk != NULL && NewBlk != NULL) { + SIZE_T OldSiz; + OldSiz = *((unsigned long far *)((charptr)OldBlk - 8)); + OldSiz += -9L; /* TC's farrealloc() does this (?) */ + MEMMOVE(NewBlk, OldBlk, (NewSiz > OldSiz) ? OldSiz : NewSiz); + ZFree (OldBlk); + } + +#else + + NewBlk = farrealloc ((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 +#endif + +#if DEBUGGING +/* + * is the heap corrupted? + */ + +#if defined(__TURBOC__) && (__TURBOC__ >= 0x0295) + if (heapcheck () < 0) { + puts ("ZRaloc: heapcheck failed"); + exit (1); + } +#endif + + + 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 && !(EzFlag & ED_FF)) { + /* 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 */ +{ +#if VIDEO + 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) { +#endif + switch (OpCode) { + case SCR_CUP: /* cursor up one line */ + gotoxy(wherex(), wherey()-1); + break; + + case SCR_EEL: /* erase to end-of-line */ + { + int x = wherex(); + char spaces[80]; + memset(spaces, ' ', 80); + ZDspBf(spaces, 80 - x); + gotoxy(x,wherey()); + } + break; + + case SCR_ROF: /* turn on reverse video */ + case SCR_RON: /* turn off reverse video */ + break; + } + return; +#if VIDEO + } + +/* + * 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; + } +#endif +} + +/***************************************************************************** + + 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 ffblk ff_blk; /* wildcard control block */ + const size_t ff_exp = (MAXPATH*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; + + 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 */ + ff_status = findfirst (ff_path, &ff_blk, 0); + while (ff_status == 0) { + +/* + * allocate if ff_names is not big enough to hold a full filename + */ + if (ff_max - ff_size < MAXPATH) { + 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.ff_name; *cp; ++ff_size, ++cp) { + *ffp++ = tolower (*cp); + } + *ffp++ = '\0'; + ++ff_size; + +/* + * find next match + */ + ff_status = findnext (&ff_blk); + } + +/* + * 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 int _Cdecl CntrlC(void) /* 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 */ + } + return 1; +} + +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); +#if defined(__TURBOC__) + stdout->flags |= _F_BIN; +#endif + + EtFlag = ET_READ_LOWER | /* don't convert lower to upper */ + 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 */ +#ifndef WIN32 + ctrlbrk(CntrlC); +#endif + CrType = IBMPC; /* use ROM BIOS routines */ + +#if VIDEO + VtSize = HtSize = 0; +#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 (Zfwrite(BfrBeg,bufsiz,OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"Zfwrite() 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 */ diff --git a/src/zos2.c b/src/zos2.c new file mode 100644 index 0000000..2a633df --- /dev/null +++ b/src/zos2.c @@ -0,0 +1,1355 @@ +/***************************************************************************** + ZOS2.c + System dependent code for OS/2 + +*****************************************************************************/ + +#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 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct termio oldstate, newstate; /* saved and current terminal states */ + +/***************************************************************************** + The following static data is used in ZPWild and ZSWild to +perform wildcard filename lookups under OS/2. + +*****************************************************************************/ +static char **ff_names = NULL; /* filenames found */ +static char **ff_names_p = NULL; /* pointer into ff_names */ + +/***************************************************************************** + 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 */ + BOOLEAN forBackup; /* TAA Mod */ +} OFiles[NOFDBS]; + +/***************************************************************************** + + ZErMsg() + + This function displays 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 void 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(MemSize) /* allocate memory */ +SIZE_T MemSize; +{ + return malloc(MemSize); +} + +/***************************************************************************** + + 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() +{ + ZDspCh('\7'); +} + +/***************************************************************************** + + 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 set, 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 + +*****************************************************************************/ + +static void CntrlC(void) +{ + 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 */ + } +} + +DEFAULT ZChIn(NoWait) /* input a character from terminal */ +BOOLEAN NoWait; /* return immediately? */ +{ + char Charac; + static BOOLEAN NeedLF = FALSE; + + if (NeedLF) { + NeedLF = FALSE; + return (DEFAULT)LINEFD; + } + + if (NoWait) { + int i; + ioctl(0, FIONREAD, &i); + if (i==0) return -1; + } + for (;;) { + if (read(0, &Charac, 1) <= 0) { + /* Read fails -- EOF?? */ + return -1; + } + if (Charac == 0x03) { /* ^C? */ + CntrlC (); + break; + } + if (Charac != 0) { /* not an IBM PC scan code? */ + break; /* ??? what happens on ^@? */ + } + read(0, &Charac, 1); + 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. + +*****************************************************************************/ + +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; + case EG_VTE: cp = "TEC$VTEDIT"; break; + } + + 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; +} + +/***************************************************************************** + + ZClnUp() + + This function cleans up in preparation for terminating TECO-C. + +*****************************************************************************/ + +VVOID ZClnUp(void) /* clean up for exit */ +{ + ioctl(0,TCSETA,&oldstate); + setmode(1, O_TEXT); +} + +/***************************************************************************** + + Zcp2ul() + + This function converts a pointer to an unsigned long. + +*****************************************************************************/ + +#if DEBUGGING +ULONG Zcp2ul(voidptr cp) /* convert charptr to ULONG */ +{ + return ((ULONG)(cp)); +} +#endif + +/***************************************************************************** + + ZDoCmd() + + This function terminates TECO and feeds a command line to the +command line interpreter. + +*****************************************************************************/ + +VVOID ZDoCmd(charptr GBfBeg, charptr GBfPtr) /* die and pass command to OS */ +{ + char *space_p; + char *comspec; + + DBGFEN(1,"ZDoCmd",NULL); + +/* + * 1. Terminate command line in GBf + * 2. separate program name from arguments, if any + * 3. Call ZClnUp to free up everything + * 4. Execute the command line, with optional arguments. If we know where + * the command processor is, use it so we can execute .BAT batch files + * 5. we shouldn't be here, exit + */ + + *GBfPtr = '\0'; + if ((space_p = strchr (GBfBeg,' ')) != NULL) { + *space_p++ = '\0'; + } + + ZClnUp (); + + + if ((comspec = getenv("OS2_SHELL")) != NULL) { + execlp (comspec, + comspec, + "/c", + GBfBeg, + (space_p) ? space_p : NULL, NULL); + } else { + execlp (GBfBeg, + GBfBeg, + (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 call ZDspCh for every character +in the buffer. + +*****************************************************************************/ + +VVOID ZDspBf(buffer, length) /* output a buffer to terminal */ +charptr buffer; +SIZE_T length; +{ + write(1, buffer, length); +} + +/***************************************************************************** + + ZDspCh() + + This function outputs a single character to the terminal. + +*****************************************************************************/ + +VVOID ZDspCh(Charac) /* output a character to terminal */ +char Charac; +{ + char c = Charac; + write(1, &c, 1); +} + +/***************************************************************************** + + 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 + +*****************************************************************************/ + +DEFAULT ZExCtH() /* 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(25857)"); + return PushEx((LONG)25857, OPERAND); /* means "OS/2" */ + } + + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"PushEx(getppid())"); + return PushEx((LONG)getppid(), 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 */ +{ + exit(estat); +} + +/***************************************************************************** + + ZFree() + + This function frees memory previously allocated by the ZAlloc +function. + +*****************************************************************************/ + +VVOID ZFree(pointer) /* free memory allocated by ZAlloc */ +voidptr pointer; +{ + free(pointer); +} + +/***************************************************************************** + + ZHelp() + + This function accepts a help string and displays the corresponding +help text. + + it should be control-C interrupt-able. + +*****************************************************************************/ + +VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt) +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? */ +{ + (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(IfIndx) /* close input file */ +DEFAULT IfIndx; /* index into IFiles array */ +{ +#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 + +*****************************************************************************/ + +static DEFAULT fastcopy(char *srcname, char *dstname) { + /* fastcopy copies from srcname to dstname then deletes the source + file. It returns a 0 on success. */ + int srchandle, dsthandle; +#define BUFSIZE 20480 + char *buffer; + struct utimbuf times; + struct stat statbuf; + int size; + + if ((buffer = (char *)malloc(BUFSIZE)) == NULL) return 1; + + if ((srchandle = open(srcname, O_RDONLY|O_BINARY)) == -1) { + free(buffer); + return 1; + } + if ((dsthandle = open(dstname, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, + S_IREAD|S_IWRITE)) == -1) { + close(srchandle); + free(buffer); + return 1; + } + while ((size=read(srchandle, buffer, BUFSIZE)) >0) { + if (write(dsthandle, buffer, size) != size) { + size = -1; /* signal an error */ + break; + } + } + close(srchandle); + close(dsthandle); + free(buffer); + if (size < 0) { + remove(dstname); + return 1; + } + stat(srcname, &statbuf); + times.actime = statbuf.st_atime; + times.modtime = statbuf.st_mtime; + utime(dstname, ×); + return 0; +} + + +VVOID ZOClos(DEFAULT OfIndx) /* close output file */ +{ + char *DotPtr; + char *SlaPtr1, *SlaPtr2; + char TmpFsp[FILENAME_MAX]; + int failflag; + + 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 */ + + if (OFiles[OfIndx].forBackup) { + /* only do backup thing if we were doing EB originally */ + /* + * build "filename.bak" filespec in TmpFsp[] + */ + + strcpy(TmpFsp, OFiles[OfIndx].OTNam); /* copy to TmpFsp */ + + SlaPtr1 = strrchr(TmpFsp, '/'); + SlaPtr2 = strrchr(TmpFsp, '\\'); + if ((SlaPtr1 == NULL) || + (SlaPtr2 != NULL && SlaPtr2 > SlaPtr1)) + SlaPtr1 = SlaPtr2; + DotPtr = strrchr(TmpFsp, '.'); /* find the "." */ + /* We will ignore dot if it is before a slash */ + if (DotPtr != NULL && (SlaPtr1==NULL || DotPtr > SlaPtr1)) { + *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 NORENAME flag not set. + * If NORENAME flag set or if rename fails, try copying file + * If a copy is done, then the original file will remain, which + * is a good thing for OS/2 anyway! + */ + + if (EzFlag&EZ_NORENAME || + (failflag = rename(OFiles[OfIndx].OTNam, TmpFsp))) { + failflag = fastcopy(OFiles[OfIndx].OTNam, TmpFsp); + } + if (failflag) { + 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 + } /* End backup renaming */ + else { /* delete original if not backing up and not "norename" */ + if (!(EzFlag&EZ_NORENAME) && + remove(OFiles[OfIndx].OTNam) != 0) { + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"remove() failed"); + exit(EXIT_FAILURE); + } + } + + + /* + * rename "tmpnam" to "filename" if NORENAME flag not set. + * If NORENAME flag set or if rename fails (which can occur if filename + * not in current directory) then try copying the file + */ + + if (EzFlag&EZ_NORENAME || + (failflag = rename(OFiles[OfIndx].OFNam,OFiles[OfIndx].OTNam))) { + failflag = fastcopy(OFiles[OfIndx].OFNam,OFiles[OfIndx].OTNam); + } + if (failflag) { + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"rename() failed, calling exit()"); + exit(EXIT_FAILURE); + } + /* delete the temporary file, if it is still around */ + remove(OFiles[OfIndx].OFNam); + } + + IsOpnO[OfIndx] = FALSE; /* mark it as closed */ + + DBGFEX(2,DbgFNm,NULL); +} + +/***************************************************************************** + + 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(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 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 (EIFile) { + char fnbuf[FILENAME_MAX]; + char *envp; + envp = getenv("TEC$LIBRARY"); + if (envp) { + strcpy(fnbuf, envp); + strcat(fnbuf, (char *)FBfBeg); + if ((IFiles[IfIndx] = fopen(fnbuf, "rb"))!= NULL) { + return SUCCESS; + } + } + } + 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; +} + +/***************************************************************************** + + 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. + +*****************************************************************************/ + +DEFAULT ZOpOut(OfIndx, RepErr, Backup) /* open output file */ +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +BOOLEAN Backup; /* EB */ +{ +#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 */ + if (access((char *)FBfBeg, 2) != 0) { /* Can't write it? */ + if (RepErr) { + ZErMsg(); + } + return FAILURE; + } + 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"); + + OFiles[OfIndx].forBackup = Backup; + + if (OFiles[OfIndx].OTNam[0] != '\0' && RepErr && !Backup) { + ZDspBf("% Superseding existing file\r\n", 29); + } + 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++) { + if (strchr(*++argv, ' ') != NULL) { + /* embedded space in argument */ + strcat(TmpBuf, "\""); + strcat(TmpBuf, *argv); + strcat(TmpBuf, "\""); + } + else + 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, + "MakRom(line_len) failed, calling exit()"); + exit(EXIT_FAILURE); + } + MEMMOVE(QR->Start, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } + +#if USE_ANSI_CLPARS + +/* + * execute imbedded 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 + +/* + * 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 + + 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. + +*****************************************************************************/ + +DEFAULT ZPWild() /* preset the wildcard lookup filename */ +{ + +/* + * if they didn't process all of the filenames from a + * previous EN' call, discard them + */ + + if (ff_names != NULL) { + _fnexplodefree(ff_names); + } + + +/* + * Find all matching files (and, alas, directories) + */ + + *FBfPtr = '\0'; + ff_names_p = ff_names = _fnexplode((char *)FBfBeg); + + return SUCCESS; +} + +/***************************************************************************** + + ZRaloc() + + This function performs the standard C library function realloc. + +*****************************************************************************/ + +voidptr ZRaloc(OldBlk, NewSiz) +voidptr OldBlk; +SIZE_T NewSiz; +{ + return realloc(OldBlk, NewSiz); +} + +/***************************************************************************** + + ZRdLin() + + This function reads a line from a file. It is passed a buffer, the +size of the buffer, a file pointer. It returns the length of the line, or +sets IsEofI[] to TRUE if the end of file is encountered. + +*****************************************************************************/ + +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 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 + + charsLeft = ibuflen; + 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 = ibuflen - charsLeft + 1; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + if (character == FORMFD && !(EzFlag & EZ_FF)) { + /* toss form feed, then finished */ + *retlen = ibuflen - 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 = ibuflen; +#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 = ibuflen-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(OpCode) /* do a screen operation */ +int OpCode; /* code for operation */ + +{ + switch (OpCode) { + case SCR_CUP: ZDspBf("\033[A", 3); break; + case SCR_EEL: ZDspBf("\033[K", 3); break; + case SCR_ROF: ZDspBf("\033[m", 3); break; + case SCR_RON: ZDspBf("\033[7m", 4); 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 */ +{ + 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() /* search for next wildcard filename */ +{ + struct stat statistics; + int filename_length; + + /* FNfilename not called? */ + if (ff_names == NULL) return FILENF; + + while (*ff_names_p) { + /* check that it is a file */ + stat(*ff_names_p, &statistics); + if (!S_ISREG(statistics.st_mode)) { + ff_names_p++; + continue; + } + filename_length = strlen (*ff_names_p); + MEMMOVE (FBfBeg, *ff_names_p, filename_length); + FBfPtr = FBfBeg + filename_length; + ff_names_p++; + return SUCCESS; + } + + /* list exhausted -- free memory */ + + _fnexplodefree(ff_names); + ff_names = ff_names_p = NULL; + + return FILENF; + +} + +/***************************************************************************** + + 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 command procedure (under VMS) or a script file (under __UNIX__), 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 CntrlCTrap() +{ + signal(SIGBREAK, SIG_ACK); + CntrlC(); +} + + +VVOID ZTrmnl() /* set up I/O to the terminal */ +{ + DBGFEN(2,"ZTrmnl",NULL); + + ioctl(0,TCGETA,&oldstate); /* switch to raw mode */ + newstate = oldstate; + newstate.c_iflag = 0; + newstate.c_lflag = 0; + ioctl(0,TCSETA,&newstate); + setmode(1, O_BINARY); + + EtFlag = ET_READ_LOWER | /* don't convert lower to upper */ + 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 */ + + CrType = VT100; /* Codes are enough like VT100 */ + signal(SIGBREAK, CntrlCTrap); + +#if VIDEO + VtSize = HtSize = 0; +#endif + + DBGFEX(2,DbgFNm,NULL); +} + +/***************************************************************************** + + ZVrbos() + + This function s a buffer to a file. + +*****************************************************************************/ + +VVOID ZVrbos(ErrNum, ErMnem) +WORD ErrNum; +char *ErMnem; +{ + char **TmpPtr; +#include "vrbmsg.h" + + 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 */ +{ + unsigned long bufsiz = BfrEnd - BfrBeg + 1; + + if (fwrite(BfrBeg,sizeof(char),bufsiz,OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"Zfwrite() failed"); + return FAILURE; + } + + DBGFEX(2,DbgFNm,"SUCCESS"); + + return SUCCESS; +} diff --git a/src/zosx.c b/src/zosx.c new file mode 100644 index 0000000..21cc7d9 --- /dev/null +++ b/src/zosx.c @@ -0,0 +1,1355 @@ +/***************************************************************************** + ZLinux.c + System dependent code for Linux + This is based on zunix.c, with changes (see comments "TAA") + for enhanced functionality. +*****************************************************************************/ +/* + * Define standard functions. + */ +#include /* needed before sys/param.h is included */ +#include /* define errno */ +#include /* to catch ^C and ^Z signals */ +#include /* define stdin */ +#include /* strncpy(), strlen(), etc. */ +#include /* define tm struct */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Rewritten 05/04 by TAA to use glob function */ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "chmacs.h" /* define character processing macros */ +#include "clpars.h" /* command-line parsing macro */ +#include "dchars.h" /* define identifiers for characters */ +#include "deferr.h" /* define identifiers for error messages */ +#include "defext.h" /* define external global variables */ +#include "dscren.h" /* define identifiers for screen i/o */ +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 */ +// 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 */ +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; +/***************************************************************************** + 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]; +/* TAA Mod 5/04 -- keep track of last character being CR so we will + * have CRLF -> CRLF instead of CRLFLF in case input file is DOS + * format. */ +static int IFisCR[NIFDBS] = {0}; +/***************************************************************************** + 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 */ + BOOLEAN forBackup; /* TAA Mod */ +} OFiles[NOFDBS]; +/***************************************************************************** + ZErMsg() + This function displays 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() +{ + if (errno < sys_nerr) + ErrStr(ERR_SYS, sys_errlist[errno]); +} +/***************************************************************************** + 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(MemSize) /* allocate memory */ +SIZE_T MemSize; +{ + return (voidptr)malloc(MemSize); +} +/***************************************************************************** + 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(VVOID) +{ + ZDspCh('\7'); +} +/***************************************************************************** + 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(NoWait) /* input a character from terminal */ +BOOLEAN NoWait; /* return immediately? */ +{ + char Charac; + static BOOLEAN LastLF = FALSE; + if (LastLF) { + LastLF = FALSE; + return (DEFAULT)LINEFD; + } + if (read(fileno(stdin), &Charac, 1) != 1) { + if (GotCtC || SupGotCtC) + return (DEFAULT)CTRL_C; + if (!GotCtC) { + ZErMsg(); + ErrMsg(ERR_URC); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + GotCtC = FALSE; + if (Charac == CRETRN) { + LastLF = TRUE; + return (DEFAULT)CRETRN; + } + 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. +*****************************************************************************/ + 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 { + /* Cannot set value */ +// 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 */ + retval = 0L; + } + return retval; + } +/***************************************************************************** + See the definition of MEMMOVE in ZPORT.H for a description of this + function. +*****************************************************************************/ +VVOID ZCpyBl(Destin, Source, Length) +charptr Destin; +charptr Source; +SIZE_T Length; +{ + if (Source < Destin) { + Source += Length; + Destin += Length; + while (Length-- > 0) { + *--Destin = *--Source; + } + } else { + while (Length-- > 0) { + *Destin++ = *Source++; + } + } +} +#if DEBUGGING +ULONG Zcp2ul(cp) /* convert charptr to ULONG */ +voidptr cp; +{ + return (ULONG)(cp); +} +#endif +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */ +{ + DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); + if (tty_set == TRUE) + tcsetattr(0, TCSANOW, &out); +} +/***************************************************************************** + 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. +*****************************************************************************/ +VVOID ZDoCmd(charptr GBfBeg, charptr GBfPtr) /* die and pass command to OS */ +{ + char buf[128+1]; + char *space_p; + DBGFEN(1,"ZDoCmd",NULL); +/* + * 1. Terminate buf[] and command line in GBf + * 2. make local copy since GBf 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] = *GBfPtr = '\0'; + (void)strncpy(buf, GBfBeg, 128); + if ((space_p = strchr(buf,' ')) != NULL) { + *space_p++ = '\0'; + } + ZClnUp(); + execlp ("/bin/sh", "sh", "-c", buf, (space_p) ? space_p : NULL, NULL); + /* we should never reach this statement */ + (void)perror (""); + 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 call ZDspCh for every character +in the buffer. +*****************************************************************************/ +VVOID ZDspBf(buffer, length) /* output a buffer to terminal */ +charptr buffer; +SIZE_T length; +{ + if (write(fileno(stdout), buffer, length) == -1) { + puts("Unable to write to terminal in function ZDspBf"); + TAbort(EXIT_FAILURE); + } +} +/***************************************************************************** + ZDspCh() + This function outputs a single character to the terminal. +*****************************************************************************/ +VVOID ZDspCh(Charac) /* output a character to terminal */ +char Charac; +{ + if (write(fileno(stdout), &Charac, 1) == -1) { + puts("Unable to write to terminal in function ZDspCh"); + TAbort(EXIT_FAILURE); + } +} +/***************************************************************************** + 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() /* return current date */ +{ + time_t clockt; + struct tm *time_of_day; + int tecodate; + DBGFEN(1,"ZExCtB",""); + 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()"); + 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 +*****************************************************************************/ +DEFAULT ZExCtH() /* return current time */ +{ + time_t clockt; + struct tm *time_of_day; + int tecotime; + DBGFEN(1,"ZExCtH",""); + 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; + 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) + 25857 under OS/2 (101*256 = IBM-PC, 1 = OS/2) + 25858 under Linux (101*256 = IBM-PC, 2 = Linux) + 0EJ process id on VAXen or Unix/Linux, 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() /* 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"); + return FAILURE; + } + } + if (NArgmt == -1) { + DBGFEX(1,DbgFNm,"PushEx(25858)"); + return PushEx((LONG)25858, OPERAND); /* means "PC Linux" */ + } + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"PushEx(getppid())"); + return PushEx((LONG)getppid(), OPERAND); + } + DBGFEX(1,DbgFNm,"ExeNYI()"); + return ExeNYI(); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +VVOID ZExit(estat) /* terminate TECO-C */ +DEFAULT estat; +{ + ZClnUp(); + exit(estat); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(pointer) /* free memory allocated by ZAlloc */ +voidptr pointer; +{ + free(pointer); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt) +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? */ +{ + (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(IfIndx) /* close input file */ +DEFAULT IfIndx; /* index into IFiles array */ +{ + DBGFEN(2,"ZIClos",NULL); + if (IsOpnI[IfIndx]) { /* if it's open */ + if (fclose(IFiles[IfIndx]) == EOF) { + ZErMsg(); + ErrMsg(ERR_UCI); + ZExit(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(OfIndx) /* close and delete output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + 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); + ZExit(EXIT_FAILURE); + } + if (remove(OFiles[OfIndx].OFNam) != 0) { + ZErMsg(); + ErrStr(ERR_UCD, OFiles[OfIndx].OFNam); + ZExit(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(OfIndx) /* close output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + int ver; + char TmpFsp[FILENAME_MAX]; + char move_err[1024]; + 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 */ + ZExit(EXIT_FAILURE); + } + if (OFiles[OfIndx].OTNam[0] != '\0') { /* if temporary output file */ + if (OFiles[OfIndx].forBackup) { + (void)strcpy(TmpFsp, OFiles[OfIndx].OTNam);/* copy to TmpFsp */ + if ((EzFlag&EZ_NO_STRIP)==0) { + char *DotPtr = strchr(TmpFsp, '.'); /* find the "." */ + if (DotPtr != NULL) { /* if "." exists */ + *DotPtr = '\0'; /* make it null */ + } + } + if (EzFlag&EZ_NO_VER) { + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else { + ver = vernum(TmpFsp); + if (ver==(-3)) { + puts("\nWARNING: Versioning disabled\n"); + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else if (ver==(-2) || ver==0) { + (void)strcat(TmpFsp, ";1"); + } else if (ver==(-1)) { /* can't read dir */ + ZErMsg(); + ErrMsg(ERR_UCO); /* una to close o */ + ZClnUp(); + exit(EXIT_FAILURE); + } else { /* ver > 0 */ + int ln = strlen(TmpFsp); + ver++; + strcat(TmpFsp, ";"); + MakDBf((LONG)ver, 10); + strncat(TmpFsp, DBfBeg, DBfPtr-DBfBeg); + *(TmpFsp+ln+(1+DBfPtr-DBfBeg)+1) = '\0'; + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OTNam, TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (rename(OFiles[OfIndx].OTNam, TmpFsp)) { /* TAA changed to use rename */ + ZErMsg(); + ZDspBf("Edit saved in ", 14); + ZDspBf(OFiles[OfIndx].OFNam, + strlen(OFiles[OfIndx].OFNam)); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } else { /* Delete original if not backing up */ + if (remove(OFiles[OfIndx].OTNam) != 0) { + ZErMsg(); + ErrMsg(ERR_UCO); + DBGFEX(2,DbgFNm,"remove() failed"); + exit(EXIT_FAILURE); + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OFNam, OFiles[OfIndx].OTNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (rename(OFiles[OfIndx].OFNam, + OFiles[OfIndx].OTNam)) { + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + 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, "r")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + IFisCR[IfIndx] = 0; + 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, "r")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + IFisCR[IfIndx] = 0; + 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, "r")) != NULL) { + DBGFEX(1,DbgFNm,"SUCCESS"); + IFisCR[IfIndx] = 0; + return SUCCESS; + } + if (strchr(FBfBeg,'.') == NULL) { /* if no dot */ + (void)strcat(FBfBeg,".tec"); /* append .tec */ + FBfPtr += 4; + if ((IFiles[IfIndx] = fopen(FBfBeg, "r")) != NULL) { + IFisCR[IfIndx] = 0; + 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. +*****************************************************************************/ +/* + * Unix file names do not have version numbers, 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 close routine will deal + * with renaming files to make them come out right. If no file with the + * same name already exists, then the output file can simply be opened. + * The close routine will only rename files if a temporary file was created + * by this routine. + */ +DEFAULT ZOpOut(OfIndx, RepErr, Backup) /* open output file */ +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +BOOLEAN Backup; /* TAA Added */ +{ + char *tfname; + struct stat *bufstat = NULL; + int tmpflag = 0; +#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(FBfBeg, 0) == 0) { /* if file already exists */ + char *dirname,*s; + int n; + bufstat = (struct stat *)malloc(sizeof(struct stat)); + stat(FBfBeg, bufstat); + tmpflag = 1; + n = FBfPtr - FBfBeg; /* strlen(FBfBeg) */ + dirname = (char *)malloc(n+4); + strcpy(dirname, FBfBeg); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + *s='\0'; + } else { /* must have s==dirname and + *s != '/', so current + directory */ + *dirname='.'; *(dirname+1)='\0'; + } + tfname = tempnam(dirname,"tecoc"); + (void)strcpy(OFiles[OfIndx].OFNam, tfname); + free(tfname); + free(dirname); + (void)strcpy(OFiles[OfIndx].OTNam, FBfBeg); +#if DEBUGGING + sprintf(DbgSBf, "file %s already exists\r\n", FBfBeg); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + } else { + (void)strcpy(OFiles[OfIndx].OFNam, FBfBeg); + OFiles[OfIndx].OTNam[0] = '\0'; + } +#if DEBUGGING + sprintf(DbgSBf, "creating file %s\r\n", OFiles[OfIndx].OFNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + OFiles[OfIndx].OStrem = fopen(OFiles[OfIndx].OFNam, "w"); + if (OFiles[OfIndx].OStrem == NULL) { + if (RepErr) + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if (tmpflag) { + fchmod(fileno(OFiles[OfIndx].OStrem), + bufstat->st_mode | S_IRUSR | S_IWUSR); + free(bufstat); + } + DBGFEX(2,DbgFNm,"SUCCESS"); + OFiles[OfIndx].forBackup = Backup; + if (OFiles[OfIndx].OTNam[0] != '\0' && RepErr && !Backup) { + ZDspBf("% Superseding existing file\r\n", 29); + } + 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(argc, argv) /* parse a TECOC command line */ +int argc; +char *argv[]; +{ + int i; + char TmpBuf[256]; + SIZE_T line_len; + char *cmd; + 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. + */ + TmpBuf[0] = '\0'; + cmd = strrchr(argv[0], '/'); + if (cmd) { + cmd++; + } else { + cmd = argv[0]; + } + if (strcmp(cmd, "teco") == 0 || + strcmp(cmd, "mung") == 0) { + strcat(TmpBuf, cmd); + strcat(TmpBuf, " "); + } else if (strcmp(cmd, "inspect") == 0) { + strcat(TmpBuf, "teco -inspect "); + } else if (strcmp(cmd, "Make") == 0) { + strcat(TmpBuf, "make "); + } + if (argc > 1 || TmpBuf[0] != '\0') { + for (i=1; iStart, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +#if USE_ANSI_CLPARS +/* + * execute imbedded command line-parsing macro directly from clpars[] + */ + 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 */ +#else +/* + * 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()"); + ZExit(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 = (charptr)"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 + 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. +*****************************************************************************/ +/* Rewritten 05/04 by TAA */ +DEFAULT ZPWild() /* preset the wildcard lookup filename */ +{ + int result,i; +/* + * if we didn't process all names from a previous EN` call then discard them + */ + globfree(&pglob); + globindex = 0; + *FBfPtr='\0'; /* terminate string */ + result = glob(FBfBeg, GLOB_ERR|GLOB_MARK, NULL, &pglob); + if (result != 0) { + return FAILURE; + } + result = 0; /* Count files matched */ + for (i = 0; i < pglob.gl_pathc; i++) { + if (pglob.gl_pathv[i][strlen(pglob.gl_pathv[i])-1] != '/') { + result++; + } + } + if (result > 0) { + return SUCCESS; + } + return FAILURE; +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(OldBlk, NewSiz) /* re-allocate memory */ +voidptr OldBlk; +SIZE_T NewSiz; +{ + return (voidptr)realloc(OldBlk, NewSiz); +} +/***************************************************************************** + ZRdLin() + This function reads a line from a file. It is passed a buffer, the +size of the buffer, and a file pointer. It returns the length of the line, +or sets IsEofI[] to TRUE if the end of file is encountered. +*****************************************************************************/ +DEFAULT ZRdLin(ibuf, ibuflen, IfIndx, retlen) +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) { + *retlen = shortBuf - charsLeft + 1; + if ((EzFlag & EZ_UNIXNL) == 0 && IFisCR[IfIndx] == 0) { + ibuf[(*retlen) -1] = CRETRN; + ibuf[(*retlen)] = LINEFD; + (*retlen)++; + } + IFisCR[IfIndx] = 0; +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + IFisCR[IfIndx] = character == '\r'; /* last character was a CR -- DOS file? */ + if (character == FORMFD && !(EzFlag & ED_FF)) { + /* 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; + } + /* TAA Mod 5/04 -- must allow for extra character if + * UNIXNL since LF becomes CRLF */ + if (--charsLeft == ((EzFlag&EZ_UNIXNL) ? 0 : 1)) { + /* 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(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); +// } +} +/***************************************************************************** + 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(TTWhat, TTVal) /* tell operating system we set the term. */ +DEFAULT TTWhat; /* what terminal parameter to set */ +DEFAULT TTVal; /* what to set it to */ +{ + 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 +*****************************************************************************/ +/* Rewritten 05/04 by TAA */ +DEFAULT ZSWild() /* search for next wildcard filename */ +{ + int filename_length; + if (pglob.gl_pathc == 0) + return FAILURE; + do { + if (globindex >= pglob.gl_pathc) return FILENF; + if (pglob.gl_pathv[globindex][strlen(pglob.gl_pathv[globindex]-1)] != '/') break; + globindex++; + } while (1); +/* + * we really have a file name now + */ + filename_length = strlen(pglob.gl_pathv[globindex]); + MEMMOVE(FBfBeg, pglob.gl_pathv[globindex], filename_length); + FBfPtr = FBfBeg + filename_length; + globindex++; + 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 command procedure (under VMS) or a script file (under __UNIX__), 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) + When TECO is started, the terminal will probably be set up for +buffered I/O, so characters won't be received until a RETURN is hit, and +they will be automatically echoed. Set the terminal up for raw I/O, so each +character is received when it is struck, and no echoing is performed. Save +the terminal characteristics so when we exit we can reset them (in ZClnUp) +to what they were before we changed them. +*****************************************************************************/ +static VVOID CntrlC() +{ + signal(SIGINT, SIG_IGN); + SupGotCtC = 0; + if (EtFlag & ET_TRAP_CTRL_C) { /* if user wants it */ + EtFlag &= ~ET_TRAP_CTRL_C; /* turn off bit */ + SupGotCtC = 1; + } else { /* user doesn't want it */ + if (EtFlag & ET_MUNG_MODE) { /* if in MUNG mode */ + TAbort(EXIT_SUCCESS); + } + GotCtC = TRUE; /* set "stop soon" flag */ + } + signal(SIGINT, CntrlC); +} +/* + * sighup - what we do if we get a hang up? + */ +static void sighup() +{ + TAbort(EXIT_FAILURE); +} +/* + * sigstop - what to do if we get a ^Z + */ +static void sigstop() +{ + tcsetattr(0, TCSANOW, &out); + puts("[Suspending...]\r\n"); + kill(getpid(), SIGSTOP); + puts("[Resuming...]\r\n"); + tcsetattr(0, TCSANOW, &cur); +} +/* + * ZTrmnl - set up terminal modes + */ +VVOID ZTrmnl() /* set up I/O to the terminal */ +{ + EtFlag = ET_READ_LOWER | /* guess: term has lowercase and */ + 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 */ + EZ_INVCR; /* don't show little c/r characters */ +/* + * get terminal characteristics and set some signals + */ + 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 +/* + * set CBREAK/noECHO/noCRMOD + */ + cur.c_lflag &= ~ICANON; + cur.c_lflag &= ~ECHO; + cur.c_oflag &= ~ONLCR; + cur.c_iflag &= ~(ICRNL | INLCR); + tcsetattr(0, TCSANOW, &cur); + 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! */ +} +/***************************************************************************** + ZVrbos() + This function displays the verbose form of an error message. +*****************************************************************************/ +VVOID ZVrbos(ErrNum, ErMnem) +WORD ErrNum; +char *ErMnem; +{ + char **TmpPtr; +#include "vrbmsg.h" + 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, one line at a time. It is +passed an output file index and pointers to the beginning and end of the +buffer to be output. +*****************************************************************************/ +DEFAULT ZWrBfr(OfIndx, BfrBeg, BfrEnd) +DEFAULT OfIndx; /* index into OFiles array */ +charptr BfrBeg; /* address of output buffer beginning */ +charptr BfrEnd; /* address of output buffer end */ +{ +#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 we're doing Unix-style editing, where lines are terminated with a + * line feed (newline) instead of a carriage-return/line-feed pair, then + * we can just fwrite the buffer. Otherwise, we have to scan the buffer + * and convert CR/LF pairs to just LF before output. + */ + if (EzFlag & EZ_UNIXNL) { + ptrdiff_t bufsiz = BfrEnd-BfrBeg+1; + if (fwrite(BfrBeg, sizeof(char), bufsiz, + OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"Zfwrite() failed"); + return FAILURE; + } + } else { + charptr BfrPtr = BfrBeg; /* output buffer pointer */ + while (BfrPtr <= BfrEnd) { + if (*BfrPtr == CRETRN) { + BfrPtr++; + if ((BfrPtr > BfrEnd) || (*BfrPtr != LINEFD)) { + BfrPtr--; + } + } + if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + ++BfrPtr; + } + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/**************************************************************************** + vernum() + From Mark Henderson, was in a separate file named vernum.c. +*****************************************************************************/ +static int vernum(target) +/* +maximum version number of target (similar to VMS mechanism) +return +-3 error - problems other than file not found and can't open directory +-2 error - did not find file +-1 error - cannot open directory containing target + 0 file found - no version numbers found + n > 0 version number of highest name;n +*/ +char *target; +{ + DIR *dirp; + int found = 0; /* file found flag */ + char *ftarget; + int maxver = 0; + char *dirname; + struct dirent *dp; + int n; + char *s; + n = strlen(target); + dirname=(char *)malloc(strlen(target)+4); + ftarget=(char *)malloc(strlen(target)+4); + strcpy(dirname, target); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + strcpy(ftarget,s+1); + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + strcpy(ftarget,s+1); + *s='\0'; + } else { /* must have s==dirname and *s!='/', so current directory */ + strcpy(ftarget,target); + *dirname='.'; *(dirname+1)='\0'; + } + dirp = opendir(dirname); + if (dirp == NULL) { + ZDspBf("\nerror openning directory ", 26); + ZDspBf(dirname, strlen(dirname)); + ZDspCh('\n'); + free(dirname); + free(ftarget); + return(-1); + } + n=strlen(ftarget); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (strncmp(dp->d_name,ftarget,n) == 0) { + char *suffix = dp->d_name + n; + if (*suffix == '\0') { + found = 1; + if (maxver <= 0) + maxver = 0; + } + if (*suffix == ';') { + int k; + found = 1; + k=atoi(suffix+1); + if (k<=0) { + free(dirname); + free(ftarget); + closedir(dirp); + return(-3); + } + if (k>=maxver) + maxver = k; + } + } + } + free(dirname); + free(ftarget); + closedir(dirp); + return (found) ? maxver : -2; +} diff --git a/src/zport.h b/src/zport.h new file mode 100644 index 0000000..4e21c63 --- /dev/null +++ b/src/zport.h @@ -0,0 +1,649 @@ +/***************************************************************************** + ZPort.h + + This file contains portability identifiers. It is the only file +that should need modification when porting the code. It is assumed that the +compiler supports the #elif and "defined()" preprocessor directives, but +it need not be fully ANSI C compatible in all ways. +*****************************************************************************/ + +/**************************************************************************** + These identifiers enhance code readability as well as providing the +capability to avoid machine-dependent data type problems. The following +types work for the VAX/VMS and SAGE/CPM-68K compilers. If a compiler does +not have 8-bit chars, 16 or 32-bit shorts and 32-bit longs, then problems +will arise. + There are many places in TECOC where one pointer is subtracted from +another. If the result is stored in a variable or sent to a function, I +have tried to define the type of the destination as ptrdiff_t. + The mode control flags (like ES, ED) are 16-bit entities defined as +WORD. The DoEvEs function will not function correctly if WORD does not +produce signed 16-bit variables. + The MakDBf function will not work properly if LONG does not +produce 32-bit variables. +*****************************************************************************/ + +typedef int BOOLEAN; /* holds FALSE or TRUE */ +typedef int DEFAULT; /* signed, at least 16 bits */ +typedef short WORD; /* 16 bits signed */ +typedef long LONG; /* 32 bits signed */ +typedef unsigned long ULONG; /* 32 bits unsigned */ + +#define FOREVER for(;;) /* Infinite loop declaration */ + +/* + * Define TRUE and FALSE if they haven't been defined already. + */ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +/***************************************************************************** + The following identifiers determine which compiler is being used. +Only ONE of the following identifiers should be defined. + The UNKNOWN identifier should only be used when porting TECO-C to a +new environment. When set, it will cause stubs to be compiled for all the +system-dependent functions. +*****************************************************************************/ + +#ifdef OSX +#define LINUX +#define __GNUCC__ +#endif + +/*#define __GNUC__ automatically defined by FSF GNU C */ +/*#define __POWERC automatically defined by Mix Power C */ +/*#define unix automatically defined by unix C */ +/*#define __TURBOC__ automatically defined by Borland Turbo C */ +/*#define UNKNOWN unknown compiler */ +/*#define VAX11C automatically defined by DEC VAX-11 C */ +/*#define AMIGA automatically defined by SAS Institute C */ +/*#define EMX defined for OS/2, GCC/EMX compiler */ +/*#define WIN32 defined for Borland, 32 bit windows version */ + +/***************************************************************************** + There are three things which can be enabled during debugging: + + CHECKSUM_CODE (under Turbo C only) will verify at run-time that +code isn't being corrupted by stray pointers. + + CONSISTENCY_CHECKING will check various pointers after each command +is executed and verify that they are "consistent"; for example, that edit +buffer pointers point into the edit buffer and not elsewhere. + + DEBUGGING enables code included at the entry and exit of every +function so a "function trace" can be displayed. The unused TECO command +^P sets the level of detail which is displayed by the debugging routines +in TECOC.C. +*****************************************************************************/ + +#ifndef CHECKSUM_CODE /* if not defined on command line */ +#define CHECKSUM_CODE (FALSE && defined(__TURBOC__)) +#endif +#ifndef CONSISTENCY_CHECKING /* if not defined on command line */ +#define CONSISTENCY_CHECKING FALSE /* check pointer consistency */ +#endif +#ifndef DEBUGGING /* if not defined on command line */ +#define DEBUGGING FALSE /* compile debugging code */ +#endif + +/***************************************************************************** + Determine what memory model we're running under Turbo C and set +whether we have small (near, 64K) or large (far, 1MB) code and data +references. +*****************************************************************************/ + +#if defined(__TURBOC__)&&!defined(WIN32) + +#define TC_SMALL_DATA (defined(__SMALL__) || defined(__MEDIUM__)) +#define TC_SMALL_CODE (defined(__SMALL__) || defined(__COMPACT__)) + +#if DEBUGGING && TC_SMALL_CODE +/* GNU C objects to this #error directive even though it should skip it? */ +/* redefining main() should stop the compiler */ +/* #error DEBUGGING=TRUE needs large code model */ +main() {} +#endif + +#else + +#define TC_SMALL_DATA FALSE +#define TC_SMALL_CODE FALSE + +#endif + +/***************************************************************************** + The debugging code uses the standard library so we need to get +prototypes for the standard functions. When not debugging, the only TECO-C +functions which need the standard library are in the Z*.C system-specific +code files which explicitly #include these header files. +*****************************************************************************/ + +#if (CHECKSUM_CODE || CONSISTENCY_CHECKING || DEBUGGING) +#if defined(unix) +extern int printf(); +/*extern int sprintf();*/ +extern int puts(); +#else +#include +#include +#include +#endif +#endif + +/***************************************************************************** + Define VIDEO, which compiles in some kind of video code, even if +it's just stubs. Define CURSES to get video support. Note that the CURSES +is checked in some files before this file is included, so it HAS to be +defined on the command line. +*****************************************************************************/ + +#ifdef CURSES /* if CURSES is defined on command line */ +#define VIDEO TRUE +#else +#define CURSES FALSE +#ifndef VIDEO /* if VIDEO is not defined on command line */ +#define VIDEO FALSE +#endif +#endif + +/**************************************************************************** + The brain-damaged memory addressing of the IBM PC requires that all +character pointers used in TECO-C be "huge" pointers. "Huge" pointers are +like "far" pointers in that they are 32-bits (a 16-bit SEGMENT and a 16-bit +OFFSET); however, when you do far pointer arithmetic, only the OFFSET is +affected so adding to a far pointer eventually causes the OFFSET to wrap +around to zero. When you do huge pointer arithmetic, both the OFFSET and +the SEGMENT are properly updated. Huge pointers are also normalized so +pointer comparisons work correctly. For these reasons, all pointers +are declared using the following typedefs, which are special on PCs. +****************************************************************************/ + +#if (defined(__TURBOC__) && !TC_SMALL_DATA && !defined(WIN32)) || defined(__POWERC) +#define _Huge huge +#else +#define _Huge /**/ +#endif + +typedef unsigned char _Huge * charptr; +#if defined(unix) +typedef unsigned char * voidptr; +#else +typedef void _Huge * voidptr; +#endif +typedef struct EStck _Huge * ESptr; +typedef struct MStck _Huge * MSptr; +typedef struct QReg _Huge * QRptr; + +#undef _Huge + +/**************************************************************************** + Some compilers allow function prototypes to be defined for functions +even when the function declarations aren't written in prototype form. This +allows checking of function calls for correctness, but doesn't guarantee +that prototypes and declarations match. I choose to leave the actual +function declarations in non-prototype form, so they work with older +compilers. Defining USE_PROTOTYPES to TRUE causes prototypes to be defined +in TECOC.H for all functions. Defining it FALSE causes old-style definitions +in TECOC.H. + GNU C is one of the compilers that forces consistency: if you use +prototypes, then declarations have to match the prototypes. The only way +I can do this in TECOC code is to surround each function declarations with +"#if USE_PROTOTYPES...#else...#endif" directives. This looks hideous, so I +just don't use prototypes in GNU C. +****************************************************************************/ + +#if defined(VAX11C) || defined(__TURBOC__) || defined(__POWERC) || defined(ULTRIX) +#define USE_PROTOTYPES TRUE +#else +#define USE_PROTOTYPES FALSE +#endif + +/**************************************************************************** + ANSI C compilers are supposed to concatenate adjacent string literals +in source code. If they do, a superior form of the command-line parsing +macro (in CLPARS.H, used by ZPrsCL), is used. If not, a klunkier form needs +to be used. + Note: The clpars[] string is over 3 Kbytes long, so in addition to +supporting string concatenation, the compiler must support long strings. The +Power C v1.3.0 compiler, for example, supports ANSI string concatenation, but +does not like the 3 Kbyte clpars[] string. +****************************************************************************/ + +#if defined(__TURBOC__) || defined(__GNUC__) +#define USE_ANSI_CLPARS TRUE +#else +#define USE_ANSI_CLPARS FALSE +#endif + +/***************************************************************************** + Define ptrdiff_t (the type of things that can hold the result when +one pointer is subtracted from another), size_t (the size of memory objects +and repeat counts), and NULL. +*****************************************************************************/ + +#if defined(unix) || defined(UNKNOWN) || defined(AMIGA) && !defined(ULTRIX) + +#if sun +#ifdef SUNOS4_0 +typedef int ptrdiff_t; /* not in /sys/types.h yet */ +#endif +#include /* size_t (and maybe ptrdiff_t) */ +#else /* sun */ +#ifdef LINUX +#define ptrdiff_t int +#else +typedef int ptrdiff_t; +typedef ULONG size_t; +#endif +#endif /* sun */ + +#ifdef AMIGA +#define NULL 0L +#else +#ifdef LINUX +#ifndef NULL +#define NULL (void *)0 +#endif +#else +#define NULL 0 +#endif +#endif + +#else +#include /* define ptrdiff_t, size_t and NULL */ +#endif + +/***************************************************************************** + Define SIZE_T, which on most machines will be the same as size_t. +There are problems (as usual) on the IBM PC. In various places, TECO-C +subtracts two pointers and puts the resulting value in a variable of type +SIZE_T. Under Turbo C, size_t is 16 bits, which won't work, so we +use unsigned long for SIZE_T for TURBO C. +*****************************************************************************/ + +#if (defined(__TURBOC__) && !TC_SMALL_DATA && !defined(WIN32)) || defined(__POWERC) +typedef ULONG SIZE_T; /* PCs suck */ +#elif defined(unix) +typedef unsigned int SIZE_T; /* override their size_t, which is "int" */ +#else +typedef size_t SIZE_T; /* use size_t as defined above */ +#endif + +/***************************************************************************** + The values of the following identifiers are system-dependent. + +EXTERN usually "extern", this identifier lets the more useful keyword + "globalref" be used to define an external variable in VAX C. +GLOBAL used for the single definition of a variable. This identifier + allows the use of the keyword "globaldef" in VAX C. +EXTERNV used only for GotCtC, this means "extern volatile" for compilers that + support the "volatile" keyword. +GLOBALV used only for GotCtC, this means "volatile" for compilers that + support the "volatile" keyword. +VVOID if the compiler supports the keyword "void", then this should be + defined as such, else it should be meaningless. It would be nice + to use "VOID" instead of "VVOID", but the damn curses.h file defines + "VOID". + +EBFEXP amount by which the edit buffer is expanded each time the user tries + to insert too much text. +EBFINIT initial size of the edit buffer. This value is added to IBFINIT + to create a value used to initially allocate both buffers. +ERBFSIZ Size of error message buffer. A missing tag message for a bad Otag$ + command might be long... +GAPMIN minimum size of the edit buffer gap. This value should be set such + that there's enough room to hold the text of the largest expected + insertion command. +IBFEXP amount by which the input buffer is expanded each time it becomes + too small for a reasonable-length line (IBFMIN) to be read. +IBFINIT initial size of the input buffer. This value is added to EBFINIT + to create a value used to initially allocate both buffers. +IBFMIN minimum size of the input buffer. This value is checked before each + read operation. +NIFDBS number of input file data blocks. This should be 3 plus the + number of levels that EI files may be nested. 8 is a good number. +SBFINIT size of search string buffer +TBFINIT size of tag buffer for O command, max size of label to search for +ZBFEXP amount by which the EI file buffer is expanded when there are less + than ZBFMIN bytes left in the buffer. +ZBFINIT initial size of the file buffer used to read in a macro executed by + an "EIfilespec$$" command. +ZBFMIN minimum size of the EI file buffer before it is expanded. +*****************************************************************************/ + +#if defined(VAX11C) + +#define EXTERN globalref /* to reference an external symbol */ +#define GLOBAL globaldef /* to define an external symbol */ +#define EXTERNV extern volatile /* to reference an external volatile symbol */ +#define GLOBALV volatile /* to define an external volatile symbol */ +#define VVOID void /* Void function return */ + +#define CBFINIT 20000 /* command buffer initial size */ +#define EBFEXP 64000 /* edit buffer expansion value */ +#define EBFINIT 64000 /* edit buffer initial size */ +#define ERBFSIZ 1024 /* error message buffer */ +#define GAPMIN 64000 /* edit buffer gap minimum size */ +#define IBFEXP 64000 /* input buffer expansion size */ +#define IBFINIT 64000 /* input buffer initial size */ +#define IBFMIN 10000 /* input buffer minimum size */ +#define NIFDBS 8 /* number of input file data blocks */ +#define SBFINIT 1000 /* size of search string buffer */ +#define TBFINIT 1000 /* size of tag buffer for O command */ +#define WBFINIT 1000 /* batch input and output buffer size */ +#define ZBFEXP 64000 /* EI file buffer expansion value */ +#define ZBFINIT 64000 /* EI file buffer initial size */ +#define ZBFMIN 1000 /* EI file buffer minimum size */ + +#define EXS_SIZE 64 /* size of expression stack */ +#define LPS_SIZE 32 /* size of loop stack */ +#define MCS_SIZE 32 /* size of macro stack */ +#define QRS_SIZE 32 /* size of q-register stack */ + +#elif defined(__TURBOC__) || defined(__POWERC) || defined(unix) || defined(AMIGA) || defined(OSX) + +#define EXTERN extern /* to reference an external symbol */ +#define GLOBAL /**/ /* to define an external symbol */ +#if defined(AMIGA) || defined(unix) && !defined(__GNUC__) +#define EXTERNV extern /* to reference an external volatile symbol */ +#define GLOBALV /**/ /* to define an external volatile symbol */ +#else +#define EXTERNV extern volatile /* to reference an external volatile symbol */ +#define GLOBALV volatile /* to define an external volatile symbol */ +#endif + +#if defined(__TURBOC__) || defined(__POWERC) || defined(__GNUC__) || defined(AMIGA) || defined(OSX) +#define VVOID void /* Void function return */ +#else +#define VVOID /**/ /* Void function return */ +#endif + +#if TC_SMALL_DATA + +/* + * with the DEBUGGING #define off, Turbo C can compile teco-c for the small + * data model which is sometimes easier to debug. use "make -DMODEL=s or m". + * + * define smaller buffer sizes + */ + +#define CBFINIT 100 /* command buffer initial size */ +#define EBFEXP 1000 /* edit buffer expansion value */ +#define EBFINIT 8000 /* edit buffer initial size */ +#define ERBFSIZ 100 /* error message buffer */ +#define GAPMIN 1000 /* edit buffer gap minimum size */ +#define IBFEXP 1000 /* input buffer expansion size */ +#define IBFINIT 8000 /* input buffer initial size */ +#define IBFMIN 1000 /* input buffer minimum size */ +#define NIFDBS 6 /* number of input file data blocks */ +#define SBFINIT 100 /* size of search string buffer */ +#define TBFINIT 100 /* size of tag buffer for O command */ +#define ZBFEXP 1000 /* EI file buffer expansion value */ +#define ZBFINIT 8000 /* EI file buffer initial size */ +#define ZBFMIN 1000 /* EI file buffer minimum size */ + +/* + * define far heap management calls used in ZMSDOS.C in terms of + * near heap functions. + */ + +#define farfree(p) free(p) +#define farmalloc(ul) malloc((unsigned int)ul) +#define farrealloc(p,ul) realloc((p),((unsigned int)ul)) + +#else + +#define CBFINIT 20000 /* command buffer initial size */ +#define EBFEXP 64000L /* edit buffer expansion value */ +#define EBFINIT 64000L /* edit buffer initial size */ +#define ERBFSIZ 128 /* error message buffer */ +#define GAPMIN 64000L /* edit buffer gap minimum size */ +#define IBFEXP 64000L /* input buffer expansion size */ +#define IBFINIT 64000L /* input buffer initial size */ +#define IBFMIN 1000 /* input buffer minimum size */ +#define NIFDBS 8 /* number of input file data blocks */ +#define SBFINIT 1000 /* size of search string buffer */ +#define TBFINIT 1000 /* size of tag buffer for O command */ +#define ZBFEXP 8000 /* EI file buffer expansion value */ +#define ZBFINIT 16000 /* EI file buffer initial size */ +#define ZBFMIN 1000 /* EI file buffer minimum size */ + +#ifdef WIN32 +/* + * define far heap management calls used in ZMSDOS.C in terms of + * near heap functions. + */ + +#undef farfree +#undef farmalloc +#undef farrealloc + +#define farfree(p) free(p) +#define farmalloc(ul) malloc((unsigned int)ul) +#define farrealloc(p,ul) realloc((p),((unsigned int)ul)) +#endif + +#endif + +#define EXS_SIZE 64 /* size of expression stack */ +#define LPS_SIZE 32 /* size of loop stack */ +#define MCS_SIZE 32 /* size of macro stack */ +#define QRS_SIZE 32 /* size of q-register stack */ + +#elif defined(EMX) + +#define EXTERN extern /* to reference an external symbol */ +#define GLOBAL /**/ /* to define an external symbol */ +#define EXTERNV extern volatile /* to reference an external volatile symbol */ +#define GLOBALV volatile /* to define an external volatile symbol */ +#define VVOID void /* Void function return */ + +#define CBFINIT 20000 /* command buffer initial size */ +#define EBFEXP 64000 /* edit buffer expansion value */ +#define EBFINIT 64000 /* edit buffer initial size */ +#define ERBFSIZ 128 /* error message buffer */ +#define GAPMIN 64000 /* edit buffer gap minimum size */ +#define IBFEXP 64000 /* input buffer expansion size */ +#define IBFINIT 64000 /* input buffer initial size */ +#define IBFMIN 1000 /* input buffer minimum size */ +#define NIFDBS 8 /* number of input file data blocks */ +#define SBFINIT 1000 /* size of search string buffer */ +#define TBFINIT 1000 /* size of tag buffer for O command */ +#define ZBFEXP 8000 /* EI file buffer expansion value */ +#define ZBFINIT 16000 /* EI file buffer initial size */ +#define ZBFMIN 1000 /* EI file buffer minimum size */ + +#define EXS_SIZE 64 /* size of expression stack */ +#define LPS_SIZE 32 /* size of loop stack */ +#define MCS_SIZE 32 /* size of macro stack */ +#define QRS_SIZE 32 /* size of q-register stack */ + +#elif defined(UNKNOWN) + +#define EXTERN extern /* to reference an external symbol */ +#define GLOBAL /**/ /* to define an external symbol */ +#define EXTERNV extern volatile /* to reference an external volatile symbol */ +#define GLOBALV volatile /* to define an external volatile symbol */ +#define VVOID void /* Void function return */ + +#define CBFINIT 100 /* command buffer initial size */ +#define EBFEXP 100 /* edit buffer expansion value */ +#define EBFINIT 100 /* edit buffer initial size */ +#define ERBFSIZ 100 /* error message buffer */ +#define GAPMIN 100 /* edit buffer gap minimum size */ +#define IBFEXP 100 /* input buffer expansion size */ +#define IBFINIT 100 /* input buffer initial size */ +#define IBFMIN 100 /* input buffer minimum size */ +#define NIFDBS 4 /* number of input file data blocks */ +#define SBFINIT 100 /* size of search string buffer */ +#define TBFINIT 100 /* size of tag buffer for O command */ +#define ZBFEXP 100 /* EI file buffer expansion value */ +#define ZBFINIT 100 /* EI file buffer initial size */ +#define ZBFMIN 100 /* EI file buffer minimum size */ + +#define EXS_SIZE 5 /* size of expression stack */ +#define LPS_SIZE 5 /* size of loop stack */ +#define MCS_SIZE 5 /* size of macro stack */ +#define QRS_SIZE 5 /* size of q-register stack */ + +#endif + +/***************************************************************************** + Define ZCHKKB, a macro that does a keyboard check under MS-DOS to keep +the Control-Break (Control-C) handler happy. Under MS-DOS a Control-C isn't +checked for until you make a DOS call to the keyboard, screen, or printer. +To make loops Control-C'able in ExeCSt we make a call to ZCHKKB before +checking GotCtC so that if a Control-C was pressed in a TECO-C loop which +doesn't make an explicit DOS call, ZCHKKB makes a no-op DOS call, which +allows GotCtC to be set correctly. + + Should we use Turbo C's setcbrk to make sure BREAK is on ??? + + Under other operating systems, ZCHKKB() expands to nothing. +*****************************************************************************/ + +#if defined(__TURBOC__) +#include /* kbhit() prototype */ +#define ZCHKKB() ((void)kbhit()) /* check keyboard */ +#else +#define ZCHKKB() /**/ /* expand to nothing */ +#endif + +/***************************************************************************** + Define ZMKOFN, a macro called only by ExeEB. It's needed because the +semicolon and file version number have to be stripped off of the end of the +fully expanded file name that's in FBf before we can call ZOpOut. +*****************************************************************************/ + +#if defined(VAX11C) +#define ZMKOFN() do { FBfPtr--;} while (*FBfPtr != ';'); +#else +#define ZMKOFN() /**/ /* expand to nothing */ +#endif + +/***************************************************************************** + Define MEMMOVE, a macro that copies "len" bytes from "source" to +"dest" correctly, even if "source" and "dest" overlap. In most cases, this +maps to the ANSI C function "memmove". If it doesn't, there's C code that +does the job in function ZCpyBl, which is in the Z*.C system-specific code +files. +*****************************************************************************/ + +#if defined(sun) + +EXTERN VVOID bcopy(); +#define MEMMOVE(dest,source,len) bcopy((source),(dest),(len)) + +#elif defined(unix) || defined(AMIGA) || (defined(UNKNOWN) && !defined(__STDC__)) + +EXTERN VVOID ZCpyBl(); +#define MEMMOVE(dest,source,len) ZCpyBl((dest),(source),(len)) + +#elif defined(__TURBOC__) || defined(__POWERC) + +EXTERN VVOID ZCpyBl(charptr dest, charptr source, SIZE_T len); +#define MEMMOVE(dest,source,len) ZCpyBl((dest),(source),(len)) + +#else + +#define MEMMOVE(dest,source,len) memmove((dest),(source),(len)) + +#endif + +/***************************************************************************** + Define EXIT_SUCCESS and EXIT_FAILURE +*****************************************************************************/ + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + +/***************************************************************************** + Define FILENAME_MAX, which is used in Init() and in the Z*.C files. +This is the maximum size of a filename. It's supposed to be defined in +stdio.h by ANSI C compilers, but some compilers don't. + + In VAX C v3.0, STDIO.H defines FILENAME_MAX as 39, which is the +length of only the name part of a full file specification. I'm not sure what +use this is to anybody, because most VAX file names include a file type, if +not a version number, directory specification or node specification. So if +we're on a VAX, we override stdio's definition with the right one here. +*****************************************************************************/ + +#if defined(unix) + +#ifndef FILENAME_MAX +#define FILENAME_MAX 64 +#endif + +#elif defined(VAX11C) + +#undef FILENAME_MAX /* undefine stdio.h's definition */ +#include nam +#define FILENAME_MAX NAM$C_MAXRSS /* and define the correct one */ + +#elif defined(__TURBOC__) || defined(__POWERC) + +#ifndef FILENAME_MAX +#define FILENAME_MAX 80 /* MAXPATH */ +#endif + +#elif defined(AMIGA) +/* + * This is filesystem dependent on the Amiga, and there is no real good + * way to get at it. This value is true for FileSystem and FastFileSystem, + * but probably isn't for other things (like mounted MS-DOS partitions...) + */ +#define FILENAME_MAX 255 + +#elif defined(UNKNOWN) + +#define FILENAME_MAX 20 + +#endif + +/***************************************************************************** + When compiling with Turbo C set to use smaller and faster Pascal +function calling sequences (tcc -p), main() in TECOC.C and CntrlC() in +ZMSDOS.C have to be specifically declared as C functions. The _Cdecl +#define in STDDEF.H takes care of this for Turbo. Define it as nothing +for everyone else. +*****************************************************************************/ + +#if !defined(_Cdecl) +#define _Cdecl /**/ +#endif + + +/***************************************************************************** + Bit masks for EZ mode control flag. These are system-dependent. +*****************************************************************************/ + +#if defined(unix) | defined(OSX) +#define EZ_NO_VER 1 /* do not do VMS style versions */ +#define EZ_ARROW 8 /* */ +#define EZ_AUDIO_BEEP 16 /* (CURSES only) on = beep , off = flash */ +#define EZ_WIN_LINE 32 /* (CURSES only) line between windows */ +#define EZ_FF 128 /* do not stop read on FF */ +#define EZ_UNIXNL 256 /* use Unix-style newline terminators */ +#define EZ_VT100GRAPHICS 512 +#define EZ_BTEE 2048 /* use BTEE instead of DIAMOND */ +#define EZ_INVCR 8192 /* don't show CR in scope - closer to */ + /* TECO-11, but really not as good in */ + /* my opinion (Mark Henderson) */ +#if defined(LINUX) | defined(OSX) +#define EZ_NO_STRIP 16384 /* Don't strip the extension */ +#endif +#elif defined(AMIGA) +#define EZ_FF 128 /* do not stop read on FF */ +#define EZ_UNIXNL 256 /* use Unix-style newline terminators */ +#endif diff --git a/src/zunix.c b/src/zunix.c new file mode 100644 index 0000000..906e13a --- /dev/null +++ b/src/zunix.c @@ -0,0 +1,2851 @@ +/***************************************************************************** + ZUnix.c + System dependent code for a UNIX compiler (run on BSD Unix). +*****************************************************************************/ +/* + * Define STRIPEXT if you'd like the backup file for foo.c to be foo.bak, + * otherwise it will be foo.c.bak. i.e. if STRIPEXT is defined the .bak will + * replace everything to the right of the first . in the backup file name + */ +#define STRIPEXT FALSE +/* + * Define standard functions. This section does what's needed by SunOS 4.0, + * which doesn't have all the definitions in it's include files. It will be + * different for any other system. + */ +#include /* needed before sys/param.h is included */ +#include /* define errno */ +#include /* malloc() and realloc() */ +#include /* to catch ^C and ^Z signals */ +#include /* define stdin */ +#include /* strncpy(), strlen(), etc. */ +#ifdef SUNOS4_0 +#include +#else +#include /* define tm struct */ +#endif +#ifdef BSD43 +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#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 */ +#include "clpars.h" /* command-line parsing macro */ +#include "dchars.h" /* define identifiers for characters */ +#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) ----------------------*/ +#include /* define CBREAK, ECHO, TIOCGETP, etc. */ +static BOOLEAN tty_set = FALSE; /* Has the terminal been set? */ +static struct sgttyb out, cur; /* terminal characteristics buffers */ +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 +int access(); /* determine accessibility of a file */ +int atoi(); /* convert ASCII digits to inary integer */ +int execlp(); /* terminate and execute a system command */ +void exit(); /* exit the program */ +int fchmod(); /* change mode of a file */ +int fclose(); /* close a stream */ +int fstat(); /* get information about an open file */ +#ifndef ULTRIX /* defined somewhere already */ +int fwrite(); /* write to a stream */ +#endif +int fputc(); /* put character on stream */ +char *getenv(); /* return value of an environment name */ +int getppid(); /* return pid of parent of current process */ +int ioctl(); /* get/set device characteristics */ +int kill(); /* send a signal to a process */ +void perror(); /* write a message on stdout */ +int puts(); /* write string to stdout, with newline */ +int read(); /* read from file */ +int rename(); /* rename a file */ +int siginterrupt(); /* allow signals to interrupt system calls */ +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 */ +/* + * 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 + * declarations. + */ +#ifdef SUNOS4_0 +int close(); /* close a file */ +int fchown(); /* change owner of a file */ +int fputs(); /* write string to file stream */ +void free(); /* free memory */ +int open(); /* open a file */ +int utimes(); /* set file access and modification times */ +int vfork(); /* spawn a fork process */ +int wait(); /* wait for a process to finish */ +#endif +#if defined(sun) /* remove is ANSI C's version of unlink... */ +#define remove(x) unlink(x) /* which is not yet supported by SunOS cc */ +#endif +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 */ +extern char *sys_errlist[]; /* error message text */ +static int SupGotCtC = 0; +static char **wild_list = (char **)0; /* wild-card file name list */ +/***************************************************************************** + 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 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() +{ + if (errno < sys_nerr) + ErrStr(ERR_SYS, sys_errlist[errno]); +} +/***************************************************************************** + 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(MemSize) /* allocate memory */ +SIZE_T MemSize; +{ + return (voidptr)malloc(MemSize); +} +/***************************************************************************** + 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(VVOID) +{ +#if CURSES + if (EzFlag & EZ_AUDIO_BEEP) + beep(); /* audio beep */ + else + flash(); /* visible flash */ +#else + ZDspCh('\7'); +#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(NoWait) /* input a character from terminal */ +BOOLEAN NoWait; /* return immediately? */ +{ + char Charac; + static BOOLEAN LastLF = FALSE; + if (LastLF) { + 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) { + ZErMsg(); + ErrMsg(ERR_URC); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + GotCtC = FALSE; + if (Charac == CRETRN) { + LastLF = TRUE; + return (DEFAULT)CRETRN; + } + 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[20]; + static BOOLEAN first_time_called = TRUE; + if (first_time_called) { + first_time_called = FALSE; + strcpy(memname, "/tmp/teco"); + MakDBf((LONG)getppid(), 10); + strncat(memname, DBfBeg, DBfPtr-DBfBeg); + strcat(memname, ".tmp"); + } + 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) == NULL) { + 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" */ +} +/***************************************************************************** + See the definition of MEMMOVE in ZPORT.H for a description of this + function. +*****************************************************************************/ +#ifndef sun /* suns use bcopy() */ +VVOID ZCpyBl(Destin, Source, Length) +charptr Destin; +charptr Source; +SIZE_T Length; +{ + if (Source < Destin) { + Source += Length; + Destin += Length; + while (Length-- > 0) { + *--Destin = *--Source; + } + } else { + while (Length-- > 0) { + *Destin++ = *Source++; + } + } +} +#endif +#if DEBUGGING +ULONG Zcp2ul(cp) /* convert charptr to ULONG */ +voidptr cp; +{ + return (ULONG)(cp); +} +#endif +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +VVOID ZClnUp(VVOID) /* cleanup for TECO-C abort */ +{ + DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); +#if !CURSES + if (tty_set == TRUE) + ioctl(0, TIOCSETP, &out); +#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() /* die and pass command to OS */ +{ + char buf[128+1]; + char *space_p; + 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'; + (void)strncpy(buf, FBfBeg, 128); + if ((space_p = strchr(buf,' ')) != NULL) { + *space_p++ = '\0'; + } + ZClnUp(); + execlp ("/bin/sh", "sh", "-c", buf, (space_p) ? space_p : NULL, NULL); + /* we should never reach this statement */ + (void)perror (""); + 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 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() + This function outputs a single character to the terminal. +*****************************************************************************/ +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() + 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() /* 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 +*****************************************************************************/ +DEFAULT ZExCtH() /* 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) + 25600 under Unix + 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() /* 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"); + return FAILURE; + } + } + if (NArgmt == -1) { + DBGFEX(1,DbgFNm,"PushEx(25600)"); + return PushEx((LONG)25600, OPERAND); /* means "Unix" */ + } + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"PushEx(getppid())"); + return PushEx((LONG)getppid(), OPERAND); + } + DBGFEX(1,DbgFNm,"ExeNYI()"); + return ExeNYI(); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +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); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(pointer) /* free memory allocated by ZAlloc */ +voidptr pointer; +{ + free(pointer); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt) +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? */ +{ + (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(IfIndx) /* close input file */ +DEFAULT IfIndx; /* index into IFiles array */ +{ + DBGFEN(2,"ZIClos",NULL); + if (IsOpnI[IfIndx]) { /* if it's open */ + if (fclose(IFiles[IfIndx]) == EOF) { + ZErMsg(); + ErrMsg(ERR_UCI); + ZExit(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(OfIndx) /* close and delete output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + 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); + ZExit(EXIT_FAILURE); + } + if (remove(OFiles[OfIndx].OFNam) != 0) { + ZErMsg(); + ErrStr(ERR_UCD, OFiles[OfIndx].OFNam); + ZExit(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(OfIndx) /* close output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + int ver; + char TmpFsp[FILENAME_MAX]; + char move_err[1024]; + 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 */ + ZExit(EXIT_FAILURE); + } + if (OFiles[OfIndx].OTNam[0] != '\0') { /* if temporary output file */ + (void)strcpy(TmpFsp, OFiles[OfIndx].OTNam);/* copy to TmpFsp */ +#if STRIPEXT + { + char *DotPtr = strchr(TmpFsp, '.'); /* find the "." */ + if (DotPtr != NULL) { /* if "." exists */ + *DotPtr = '\0'; /* make it null */ + } + } +#endif + if (EzFlag&EZ_NO_VER) { + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else { + ver = vernum(TmpFsp); + if (ver==(-3)) { + puts("\nWARNING: Versioning disabled\n"); + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else if (ver==(-2) || ver==0) { + (void)strcat(TmpFsp, ";1"); + } else if (ver==(-1)) { /* can't read dir */ + ZErMsg(); + ErrMsg(ERR_UCO); /* una to close o */ + ZClnUp(); + exit(EXIT_FAILURE); + } else { /* ver > 0 */ + int ln = strlen(TmpFsp); + ver++; + strcat(TmpFsp, ";"); + MakDBf((LONG)ver, 10); + strncat(TmpFsp, DBfBeg, DBfPtr-DBfBeg); + *(TmpFsp+ln+(1+DBfPtr-DBfBeg)+1) = '\0'; + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OTNam, TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (movefile(OFiles[OfIndx].OTNam, TmpFsp, move_err)) { + ErrStr(ERR_SYS, move_err); + ZDspBf("Edit saved in ", 14); + ZDspBf(OFiles[OfIndx].OFNam, + strlen(OFiles[OfIndx].OFNam)); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OFNam, OFiles[OfIndx].OTNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (movefile(OFiles[OfIndx].OFNam, + OFiles[OfIndx].OTNam, + move_err)) { + ErrStr(ERR_SYS, move_err); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + 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, "r")) != 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, "r")) != 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, "r")) != 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, "r")) != 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. +*****************************************************************************/ +/* + * Unix file names do not have version numbers, 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 close routine will deal + * with renaming files to make them come out right. If no file with the + * same name already exists, then the output file can simply be opened. + * The close routine will only rename files if a temporary file was created + * by this routine. + */ +DEFAULT ZOpOut(OfIndx, RepErr) /* open output file */ +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +{ + char *tfname; + struct stat *bufstat = NULL; + int tmpflag = 0; +#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(FBfBeg, 0) == 0) { /* if file already exists */ + char *dirname,*s; + int n; + bufstat = (struct stat *)malloc(sizeof(struct stat)); + stat(FBfBeg, bufstat); + tmpflag = 1; + n = FBfPtr - FBfBeg; /* strlen(FBfBeg) */ + dirname = (char *)malloc(n+4); + strcpy(dirname, FBfBeg); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + *s='\0'; + } else { /* must have s==dirname and + *s != '/', so current + directory */ + *dirname='.'; *(dirname+1)='\0'; + } + tfname = tempnam(dirname,"tecoc"); + (void)strcpy(OFiles[OfIndx].OFNam, tfname); + free(tfname); + free(dirname); + (void)strcpy(OFiles[OfIndx].OTNam, FBfBeg); +#if DEBUGGING + sprintf(DbgSBf, "file %s already exists\r\n", FBfBeg); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + } else { + (void)strcpy(OFiles[OfIndx].OFNam, FBfBeg); + OFiles[OfIndx].OTNam[0] = '\0'; + } +#if DEBUGGING + sprintf(DbgSBf, "creating file %s\r\n", OFiles[OfIndx].OFNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + OFiles[OfIndx].OStrem = fopen(OFiles[OfIndx].OFNam, "w"); + if (OFiles[OfIndx].OStrem == NULL) { + if (RepErr) + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if (tmpflag) { + fchmod(fileno(OFiles[OfIndx].OStrem), + bufstat->st_mode | S_IRUSR | S_IWUSR); + free(bufstat); + } + 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(argc, argv) /* parse a TECOC command line */ +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; iStart, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +#if USE_ANSI_CLPARS +/* + * execute imbedded 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 +/* + * 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()"); + ZExit(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 = (charptr)"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 + 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. +*****************************************************************************/ +DEFAULT ZPWild() /* preset the wildcard lookup filename */ +{ +/* + * if we didn't process all names from a previous EN` call then discard them + */ + if (wild_list) { + while (*wild_list) { + free(*wild_list); + wild_list++; + } + wild_list = (char **) 0; + } + *FBfPtr='\0'; /* terminate string */ + wild_list = glob(FBfBeg); + if (!wild_list) { + return FAILURE; + } + if (*wild_list) { + return SUCCESS; + } + free(wild_list); /* oops - no files found */ + wild_list = 0; + return FAILURE; +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(OldBlk, NewSiz) /* re-allocate memory */ +voidptr OldBlk; +SIZE_T NewSiz; +{ + return (voidptr)realloc(OldBlk, NewSiz); +} +/***************************************************************************** + ZRdLin() + This function reads a line from a file. It is passed a buffer, the +size of the buffer, and a file pointer. It returns the length of the line, +or sets IsEofI[] to TRUE if the end of file is encountered. +*****************************************************************************/ +DEFAULT ZRdLin(ibuf, ibuflen, IfIndx, retlen) +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) { + *retlen = shortBuf - charsLeft + 1; + if ((EzFlag & EZ_UNIXNL) == 0) { + ibuf[(*retlen) -1] = CRETRN; + ibuf[(*retlen)] = LINEFD; + (*retlen)++; + } +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + if (character == FORMFD && !(EzFlag & ED_FF)) { + /* 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(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(); +#else + 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 +} +/***************************************************************************** + 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(TTWhat, TTVal) /* tell operating system we set the term. */ +DEFAULT TTWhat; /* what terminal parameter to set */ +DEFAULT TTVal; /* what to set it to */ +{ + 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() /* search for next wildcard filename */ +{ + int filename_length; + if (!wild_list) + return FAILURE; + if (!(*wild_list)) + return FILENF; +/* + * we really have a file name now + */ + filename_length = strlen(*wild_list); + MEMMOVE(FBfBeg, *wild_list, filename_length); + FBfPtr = FBfBeg + filename_length; + free(*wild_list); + wild_list++; + 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 command procedure (under VMS) or a script file (under __UNIX__), 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) + When TECO is started, the terminal will probably be set up for +buffered I/O, so characters won't be received until a RETURN is hit, and +they will be automatically echoed. Set the terminal up for raw I/O, so each +character is received when it is struck, and no echoing is performed. Save +the terminal characteristics so when we exit we can reset them (in ZClnUp) +to what they were before we changed them. +*****************************************************************************/ +static VVOID CntrlC() +{ + signal(SIGINT, SIG_IGN); + SupGotCtC = 0; + if (EtFlag & ET_TRAP_CTRL_C) { /* if user wants it */ + EtFlag &= ~ET_TRAP_CTRL_C; /* turn off bit */ + SupGotCtC = 1; + } else { /* user doesn't want it */ + if (EtFlag & ET_MUNG_MODE) { /* if in MUNG mode */ + TAbort(EXIT_SUCCESS); + } + GotCtC = TRUE; /* set "stop soon" flag */ + } + signal(SIGINT, CntrlC); +} +/* + * sighup - what we do if we get a hang up? + */ +static void sighup() +{ + TAbort(EXIT_FAILURE); +} +#if !CURSES +/* + * sigstop - what to do if we get a ^Z + */ +static void sigstop() +{ + ioctl(0, TIOCSETP, &out); + puts("[Suspending...]\r\n"); + kill(getpid(), SIGSTOP); + puts("[Resuming...]\r\n"); + ioctl(0, TIOCSETP, &cur); +} +/* + * 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 +/* + * 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_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 (ioctl(0, TIOCGETP, &out) != -1) + tty_set = TRUE; /* tell ZClnUp to clean up */ + ioctl(0, TIOCGETP, &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 + 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 + 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 */ +#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() + This function displays the verbose form of an error message. +*****************************************************************************/ +VVOID ZVrbos(ErrNum, ErMnem) +WORD ErrNum; +char *ErMnem; +{ + char **TmpPtr; +#include "vrbmsg.h" + 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, one line at a time. It is +passed an output file index and pointers to the beginning and end of the +buffer to be output. +*****************************************************************************/ +DEFAULT ZWrBfr(OfIndx, BfrBeg, BfrEnd) +DEFAULT OfIndx; /* index into OFiles array */ +charptr BfrBeg; /* address of output buffer beginning */ +charptr BfrEnd; /* address of output buffer end */ +{ +#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 we're doing Unix-style editing, where lines are terminated with a + * line feed (newline) instead of a carriage-return/line-feed pair, then + * we can just fwrite the buffer. Otherwise, we have to scan the buffer + * and convert CR/LF pairs to just LF before output. + */ + if (EzFlag & EZ_UNIXNL) { + ptrdiff_t bufsiz = BfrEnd-BfrBeg+1; + if (fwrite(BfrBeg, sizeof(char), bufsiz, + OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"Zfwrite() failed"); + return FAILURE; + } + } else { + charptr BfrPtr = BfrBeg; /* output buffer pointer */ + while (BfrPtr <= BfrEnd) { + if (*BfrPtr == CRETRN) { + BfrPtr++; + if ((BfrPtr > BfrEnd) || (*BfrPtr != LINEFD)) { + BfrPtr--; + } + } + if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + ++BfrPtr; + } + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/**************************************************************************** + vernum() + From Mark Henderson, was in a separate file named vernum.c. +*****************************************************************************/ +static int vernum(target) +/* +maximum version number of target (similar to VMS mechanism) +return +-3 error - problems other than file not found and can't open directory +-2 error - did not find file +-1 error - cannot open directory containing target + 0 file found - no version numbers found + n > 0 version number of highest name;n +*/ +char *target; +{ + DIR *dirp; + int found = 0; /* file found flag */ + char *ftarget; + int maxver = 0; + char *dirname; +#ifdef BSD43 + struct direct *dp; +#else + struct dirent *dp; +#endif + int n; + char *s; + n = strlen(target); + dirname=(char *)malloc(strlen(target)+4); + ftarget=(char *)malloc(strlen(target)+4); + strcpy(dirname, target); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + strcpy(ftarget,s+1); + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + strcpy(ftarget,s+1); + *s='\0'; + } else { /* must have s==dirname and *s!='/', so current directory */ + strcpy(ftarget,target); + *dirname='.'; *(dirname+1)='\0'; + } + dirp = opendir(dirname); + if (dirp == NULL) { + ZDspBf("\nerror openning directory ", 26); + ZDspBf(dirname, strlen(dirname)); + ZDspCh('\n'); + free(dirname); + free(ftarget); + return(-1); + } + n=strlen(ftarget); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (strncmp(dp->d_name,ftarget,n) == 0) { + char *suffix = dp->d_name + n; + if (*suffix == '\0') { + found = 1; + if (maxver <= 0) + maxver = 0; + } + if (*suffix == ';') { + int k; + found = 1; + k=atoi(suffix+1); + if (k<=0) { + free(dirname); + free(ftarget); + closedir(dirp); + return(-3); + } + if (k>=maxver) + maxver = k; + } + } + } + free(dirname); + free(ftarget); + closedir(dirp); + return (found) ? maxver : -2; +} + +/* + * Everything from here to the end of the file supports the "glob" and + * "movefile" functions, which support wild-card file names and fast + * file renaming, respectively. + */ +/**************************************************************************** + glob() + Was originally from berkeley, in a file named glob.c. Modified to +fit into TECO-C. +****************************************************************************/ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#define MAXGL 10000 +#define QUOTE 0200 +#define TRIM 0177 +#define eq(a,b) (strcmp(a, b)==0) +#define GAVSIZ (MAXGL/6) +#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR) +static char **gargv; /* Pointer to the (stack) arglist */ +static short gargc; /* Number args in gargv */ +static short gnleft; +static short gflag; +char *globerr; +char *home; +extern int errno; +static VVOID expand(); +static int amatch(); +struct passwd *getpwnam(); +char *strcpy(); +char *strcat(); +static int globcnt; +char *globchars = "`{[*?"; +static char *gpath; +static char *gpathp; +static char *lastgpathp; +static int globbed; +static char *entp; +static char **sortbas; +static VVOID gfatal(s, ln) +char *s; +int ln; +{ + ZDspBf("\nfatal error (glob code in zunix.c): ", 37); + ZDspBf(s, ln); + ZDspCh('\n'); + TAbort(EXIT_FAILURE); +} +static char *strend(cp) +register char *cp; +{ + while (*cp) + cp++; + return (cp); +} +static char *strspl(cp, dp) +register char *cp, *dp; +{ + register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1)); + if (ep == (char *)0) + gfatal("Out of memory", 13); + (void) strcpy(ep, cp); + (void) strcat(ep, dp); + return (ep); +} +static VVOID Gcat(s1, s2) +register char *s1, *s2; +{ + register int len = strlen(s1) + strlen(s2) + 1; + if (len >= gnleft || gargc >= GAVSIZ - 1) { + globerr = "Arguments too long"; + } else { + gargc++; + gnleft -= len; + gargv[gargc] = 0; + gargv[gargc - 1] = strspl(s1, s2); + } +} +static VVOID sort() +{ + register char **p1, **p2, *c; + char **Gvp = &gargv[gargc]; + p1 = sortbas; + while (p1 < Gvp-1) { + p2 = p1; + while (++p2 < Gvp) + if (strcmp(*p1, *p2) > 0) + c = *p1, *p1 = *p2, *p2 = c; + p1++; + } + sortbas = Gvp; +} +static VVOID addpath(c) +char c; +{ + if (gpathp >= lastgpathp) { + globerr = "Pathname too long"; + } else { + *gpathp++ = c; + *gpathp = 0; + } +} +static int execbrc(p, s) +char *p, *s; +{ + char restbuf[BUFSIZ + 2]; + register char *pe, *pm, *pl; + int brclev = 0; + char *lm, savec, *sgpathp; + for (lm = restbuf; *p != '{'; *lm++ = *p++) + continue; + for (pe = ++p; *pe; pe++) + switch (*pe) { + case '{': + brclev++; + continue; + case '}': + if (brclev == 0) + goto pend; + brclev--; + continue; + case '[': + for (pe++; *pe && *pe != ']'; pe++) + continue; + continue; + } +pend: + brclev = 0; + for (pl = pm = p; pm <= pe; pm++) + switch (*pm & (QUOTE|TRIM)) { + case '{': + brclev++; + continue; + case '}': + if (brclev) { + brclev--; + continue; + } + goto doit; + case ','|QUOTE: + case ',': + if (brclev) + continue; +doit: + savec = *pm; + *pm = 0; + (void) strcpy(lm, pl); + (void) strcat(restbuf, pe + 1); + *pm = savec; + if (s == 0) { + sgpathp = gpathp; + expand(restbuf); + gpathp = sgpathp; + *gpathp = 0; + } else if (amatch(s, restbuf)) + return (1); + sort(); + pl = pm + 1; + if (brclev) + return (0); + continue; + case '[': + for (pm++; *pm && *pm != ']'; pm++) + continue; + if (!*pm) + pm--; + continue; + } + if (brclev) + goto doit; + return (0); +} +static int amatch(s, p) +register char *s, *p; +{ + register int scc; + int ok, lc; + char *sgpathp; + struct stat stb; + int c, cc; + globbed = 1; + for (;;) { + scc = *s++ & TRIM; + switch (c = *p++) { + case '{': + return (execbrc(p - 1, s - 1)); + case '[': + ok = 0; + lc = 077777; + while (cc = *p++) { + if (cc == ']') { + if (ok) + break; + return (0); + } + if (cc == '-') { + if (lc <= scc && scc <= *p++) + ok++; + } else + if (scc == (lc = cc)) + ok++; + } + if (cc == 0) + if (ok) + p--; + else + return 0; + continue; + case '*': + if (!*p) + return (1); + if (*p == '/') { + p++; + goto slash; + } + s--; + do { + if (amatch(s, p)) + return (1); + } while (*s++); + return (0); + case 0: + return (scc == 0); + default: + if (c != scc) + return (0); + continue; + case '?': + if (scc == 0) + return (0); + continue; + case '/': + if (scc) + return (0); +slash: + s = entp; + sgpathp = gpathp; + while (*s) + addpath(*s++); + addpath('/'); + if (stat(gpath, &stb) == 0 && isdir(stb)) + if (*p == 0) { + Gcat(gpath, ""); + globcnt++; + } else + expand(p); + gpathp = sgpathp; + *gpathp = 0; + return (0); + } + } +} +static int match(s, p) +char *s, *p; +{ + register int c; + register char *sentp; + char sglobbed = globbed; + if (*s == '.' && *p != '.') + return (0); + sentp = entp; + entp = s; + c = amatch(s, p); + entp = sentp; + globbed = sglobbed; + return (c); +} +static VVOID matchdir(pattern) +char *pattern; +{ + struct stat stb; + register struct dirent *dp; + DIR *dirp; + dirp = opendir(gpath); + if (dirp == NULL) { + if (globbed) + return; + goto p_err2; + } + if (fstat(dirp->dd_fd, &stb) < 0) + goto p_err1; + if (!isdir(stb)) { + errno = ENOTDIR; + goto p_err1; + } + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_ino == 0) + continue; + if (match(dp->d_name, pattern)) { + Gcat(gpath, dp->d_name); + globcnt++; + } + } + closedir(dirp); + return; +p_err1: + closedir(dirp); +p_err2: + globerr = "Bad directory components"; +} +static int any(c, s) +register int c; +register char *s; +{ + while (*s) + if (*s++ == c) + return(1); + return(0); +} +/* + * Extract a home directory from the password file + * The argument points to a buffer where the name of the + * user whose home directory is sought is currently. + * We write the home directory of the user back there. + */ +static int gethdir(ghome) +char *ghome; +{ + register struct passwd *pp = getpwnam(ghome); + if (pp == 0) + return (1); + (void) strcpy(ghome, pp->pw_dir); + return (0); +} +static VVOID expand(as) +char *as; +{ + register char *cs; + register char *sgpathp, *oldcs; + struct stat stb; + sgpathp = gpathp; + cs = as; + if (*cs == '~' && gpathp == gpath) { + addpath('~'); + for (cs++; Is_Alnum(*cs) || *cs == '_' || *cs == '-';) + addpath(*cs++); + if (!*cs || *cs == '/') { + if (gpathp != gpath + 1) { + *gpathp = 0; + if (gethdir(gpath + 1)) + globerr = "Unknown user name after ~"; + (void) strcpy(gpath, gpath + 1); + } else + (void) strcpy(gpath, home); + gpathp = strend(gpath); + } + } + while (!any(*cs, globchars)) { + if (*cs == 0) { + if (!globbed) + Gcat(gpath, ""); + else if (stat(gpath, &stb) >= 0) { + Gcat(gpath, ""); + globcnt++; + } + goto endit; + } + addpath(*cs++); + } + oldcs = cs; + while (cs > as && *cs != '/') + cs--, gpathp--; + if (*cs == '/') + cs++, gpathp++; + *gpathp = 0; + if (*oldcs == '{') { + (void) execbrc(cs, ((char *)0)); + return; + } + matchdir(cs); +endit: + gpathp = sgpathp; + *gpathp = 0; +} +static VVOID acollect(as) +register char *as; +{ + register int ogargc = gargc; + gpathp = gpath; *gpathp = 0; globbed = 0; + expand(as); + if (gargc != ogargc) + sort(); +} +static VVOID collect(as) +register char *as; +{ + if (eq(as, "{") || eq(as, "{}")) { + Gcat(as, ""); + sort(); + } else + acollect(as); +} +static VVOID ginit(agargv) +char **agargv; +{ + agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; + gnleft = MAXGL - 4; +} +static int tglob(c) +register char c; +{ + if (any(c, globchars)) + gflag |= c == '{' ? 2 : 1; + return (c); +} +static VVOID rscan(t, f) +register char **t; /* wild-card file specification */ +int (*f)(); /* function */ +{ + register char *p, c; + while (p = *t++) { + if (f == tglob) + if (*p == '~') + gflag |= 2; + else if (eq(p, "{") || eq(p, "{}")) + continue; + while (c = *p++) + (*f)(c); + } +} +static int blklen(av) +register char **av; +{ + register int i = 0; + while (*av++) + i++; + return (i); +} +static char **blkcpy(oav, bv) +char **oav; +register char **bv; +{ + register char **av = oav; + while (*av++ = *bv++) + continue; + return (oav); +} +static VVOID blkfree(av0) +char **av0; +{ + register char **av = av0; + while (*av) + free(*av++); + free((char *)av0); +} +static char **copyblk(v) +register char **v; +{ + register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) * + sizeof(char **))); + if (nv == (char **)0) + gfatal("Out of memory", 13); + return (blkcpy(nv, v)); +} +/* + * Passed a wild-card file specification. Returns ??? + */ +static char **glob(v) +register char *v; +{ + char agpath[BUFSIZ]; + char *agargv[GAVSIZ]; + char *vv[2]; + vv[0] = v; + vv[1] = 0; + gflag = 0; + rscan(vv, tglob); + if (gflag == 0) + return (copyblk(vv)); + globerr = 0; + gpath = agpath; + gpathp = gpath; + *gpathp = 0; + lastgpathp = &gpath[sizeof agpath - 2]; + ginit(agargv); + globcnt = 0; + collect(v); + if (globcnt == 0 && (gflag&1)) { + blkfree(gargv), gargv = 0; + return (0); + } + return (gargv = copyblk(gargv)); +} + +/**************************************************************************** + movefile() + Was originally from berkeley, in a file named move.c. Modified to +fit into TECO-C. +****************************************************************************/ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ken Smith of The State University of New York at Buffalo. + * + * Redistribution and use in source and binary forms are permitted provided + * that: (1) source distributions retain this entire copyright notice and + * comment, and (2) distributions including binaries display the following + * acknowledgement: ``This product includes software developed by the + * University of California, Berkeley and its contributors'' in the + * documentation or other materials provided with the distribution and in + * all advertising materials mentioning features or use of this software. + * Neither the name of the University nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#define strerror(n) sys_errlist[n] +static int +fastcopy(from, to, sbp, move_err) +char *from, *to; +struct stat *sbp; +char *move_err; +{ + struct timeval tval[2]; + u_int blen; + static char *bp; + register int nread, from_fd, to_fd; + blen = sbp->st_blksize; + if ((from_fd = open(from, O_RDONLY, 0)) < 0) { + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } + if ((to_fd = open(to, O_WRONLY|O_CREAT|O_TRUNC, sbp->st_mode)) < 0) { + (void)close(from_fd); + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } + if (!(bp = malloc(blen))) { + strcpy(move_err,"out of memory\n"); + return 1; + } + while ((nread = read(from_fd, bp, blen)) > 0) + if (write(to_fd, bp, nread) != nread) { + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + goto err; + } + if (nread < 0) { +err: (void)unlink(to); + (void)close(from_fd); + (void)close(to_fd); + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } + (void)fchown(to_fd, sbp->st_uid, sbp->st_gid); + (void)fchmod(to_fd, sbp->st_mode); + (void)close(from_fd); + (void)close(to_fd); + tval[0].tv_sec = sbp->st_atime; + tval[1].tv_sec = sbp->st_mtime; + tval[0].tv_usec = tval[1].tv_usec = 0; + (void)utimes(to, tval); + (void)unlink(from); + return 0; +} +#ifdef SUNOS4_0 +#define WEXITSTATUS(x) ((x).w_retcode) +#endif +#ifdef SUNOS4_0 +static int +waitpid( pid, statusp ) +int pid; +int *statusp; +{ + int rc; + while( (rc = wait( statusp )) != pid && rc != -1 ) + ; + return rc; +} +#endif +static int +copy(from, to, move_err) +char *from, *to, *move_err; +{ +#ifdef SUNOS4_0 + int pid; + union wait status; +#else + int pid, status; +#endif + if (!(pid = vfork())) { + execlp("/bin/cp", "mv", "-pr", from, to); + strcpy(move_err, "can't execute /bin/cp, "); + strcat(move_err, strerror(errno)); + return 1; + } +#ifdef SUNOS4_0 + (void)waitpid(pid, (union wait *) &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) + return 1; +#else + (void)waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) + return 1; +#endif + if (!(pid = vfork())) { + execlp("/bin/rm", "mv", "-rf", from); + strcpy(move_err, "can't execute /bin/rm, "); + strcat(move_err, strerror(errno)); + return 1; + } +#ifdef SUNOS4_0 + (void)waitpid(pid, (union wait *)&status, 0); +#else + (void)waitpid(pid, &status, 0); +#endif + return !WIFEXITED(status) || WEXITSTATUS(status); +} +static int +movefile(from, to, move_err) +char *from, *to, *move_err; +{ + struct stat sbuf; + if (!rename(from, to)) /* if rename succeeds */ + return 0; /* we're done */ +/* + * if rename failed because the two files are on differet partitions, + * and it's a regular file, do the copy internally (fastcopy); otherwise, + * use cp and rm (copy). + */ + if (errno == EXDEV) { + if (stat(from, &sbuf)) { + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } +#ifdef SUNOS4_0 + return (S_IFREG & sbuf.st_mode) + ? fastcopy(from, to, &sbuf, move_err) + : copy(from, to, move_err); +#else /* 4.1 or 4.1.1 */ + return (S_ISREG(sbuf.st_mode)) + ? fastcopy(from, to, &sbuf, move_err) + : copy(from, to, move_err); +#endif + } + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; +} +#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.save b/src/zunix.c.save new file mode 100644 index 0000000..509e7c4 --- /dev/null +++ b/src/zunix.c.save @@ -0,0 +1,2952 @@ +/***************************************************************************** + ZUnix.c + System dependent code for a UNIX compiler (run on BSD Unix). +*****************************************************************************/ +/* + * Define STRIPEXT if you'd like the backup file for foo.c to be foo.bak, + * otherwise it will be foo.c.bak. i.e. if STRIPEXT is defined the .bak will + * replace everything to the right of the first . in the backup file name + */ +#define STRIPEXT FALSE +/* + * Define standard functions. This section does what's needed by SunOS 4.0, + * which doesn't have all the definitions in it's include files. It will be + * different for any other system. + */ +#include /* needed before sys/param.h is included */ +#include /* define errno */ +#include /* malloc() and realloc() */ +#include /* to catch ^C and ^Z signals */ +#include /* define stdin */ +#include /* strncpy(), strlen(), etc. */ +#ifdef SUNOS4_0 +#include +#else +#include /* define tm struct */ +#endif +#ifdef BSD43 +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#ifdef LINUX +#include +#include +#include +#include +#endif +#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 */ +#include "clpars.h" /* command-line parsing macro */ +#include "dchars.h" /* define identifiers for characters */ +#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 +#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 */ +void exit(); /* exit the program */ +int fchmod(); /* change mode of a file */ +int fclose(); /* close a stream */ +int fstat(); /* get information about an open file */ +#ifndef ULTRIX /* defined somewhere already */ +int fwrite(); /* write to a stream */ +#endif +int fputc(); /* put character on stream */ +char *getenv(); /* return value of an environment name */ +int getppid(); /* return pid of parent of current process */ +int ioctl(); /* get/set device characteristics */ +int kill(); /* send a signal to a process */ +void perror(); /* write a message on stdout */ +int puts(); /* write string to stdout, with newline */ +int read(); /* read from file */ +int rename(); /* rename a file */ +int siginterrupt(); /* allow signals to interrupt system calls */ +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 + * declarations. + */ +#ifdef SUNOS4_0 +int close(); /* close a file */ +int fchown(); /* change owner of a file */ +int fputs(); /* write string to file stream */ +void free(); /* free memory */ +int open(); /* open a file */ +int utimes(); /* set file access and modification times */ +int vfork(); /* spawn a fork process */ +int wait(); /* wait for a process to finish */ +#endif +#if defined(sun) /* remove is ANSI C's version of unlink... */ +#define remove(x) unlink(x) /* which is not yet supported by SunOS cc */ +#endif +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 */ +/***************************************************************************** + 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 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() +{ + if (errno < sys_nerr) + ErrStr(ERR_SYS, sys_errlist[errno]); +} +/***************************************************************************** + 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(MemSize) /* allocate memory */ +SIZE_T MemSize; +{ + return (voidptr)malloc(MemSize); +} +/***************************************************************************** + 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(VVOID) +{ +#if CURSES + if (EzFlag & EZ_AUDIO_BEEP) + beep(); /* audio beep */ + else + flash(); /* visible flash */ +#else + ZDspCh('\7'); +#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(NoWait) /* input a character from terminal */ +BOOLEAN NoWait; /* return immediately? */ +{ + char Charac; + static BOOLEAN LastLF = FALSE; + if (LastLF) { + 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) { + ZErMsg(); + ErrMsg(ERR_URC); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + GotCtC = FALSE; + if (Charac == CRETRN) { + LastLF = TRUE; + return (DEFAULT)CRETRN; + } + 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. +*****************************************************************************/ +#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 */ +{ + FILE *memfile; + static char memname[20]; + static BOOLEAN first_time_called = TRUE; + if (first_time_called) { + first_time_called = FALSE; + strcpy(memname, "/tmp/teco"); + MakDBf((LONG)getppid(), 10); + strncat(memname, DBfBeg, DBfPtr-DBfBeg); + strcat(memname, ".tmp"); + } + 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) == NULL) { + 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" */ +} +#endif +/***************************************************************************** + See the definition of MEMMOVE in ZPORT.H for a description of this + function. +*****************************************************************************/ +#ifndef sun /* suns use bcopy() */ +VVOID ZCpyBl(Destin, Source, Length) +charptr Destin; +charptr Source; +SIZE_T Length; +{ + if (Source < Destin) { + Source += Length; + Destin += Length; + while (Length-- > 0) { + *--Destin = *--Source; + } + } else { + while (Length-- > 0) { + *Destin++ = *Source++; + } + } +} +#endif +#if DEBUGGING +ULONG Zcp2ul(cp) /* convert charptr to ULONG */ +voidptr cp; +{ + return (ULONG)(cp); +} +#endif +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +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() + 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() /* die and pass command to OS */ +{ + char buf[128+1]; + char *space_p; + 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'; + (void)strncpy(buf, FBfBeg, 128); + if ((space_p = strchr(buf,' ')) != NULL) { + *space_p++ = '\0'; + } + ZClnUp(); + execlp ("/bin/sh", "sh", "-c", buf, (space_p) ? space_p : NULL, NULL); + /* we should never reach this statement */ + (void)perror (""); + 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 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() + This function outputs a single character to the terminal. +*****************************************************************************/ +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() + 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() /* return current date */ +{ + time_t clockt; + struct tm *time_of_day; + int tecodate; + DBGFEN(1,"ZExCtB",""); + 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()"); + 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 +*****************************************************************************/ +DEFAULT ZExCtH() /* return current time */ +{ + time_t clockt; + struct tm *time_of_day; + int tecotime; + DBGFEN(1,"ZExCtH",""); + 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; + 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) + 25600 under Unix + 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() /* 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"); + return FAILURE; + } + } + if (NArgmt == -1) { + DBGFEX(1,DbgFNm,"PushEx(25600)"); + return PushEx((LONG)25600, OPERAND); /* means "Unix" */ + } + if (NArgmt == 0) { + DBGFEX(1,DbgFNm,"PushEx(getppid())"); + return PushEx((LONG)getppid(), OPERAND); + } + DBGFEX(1,DbgFNm,"ExeNYI()"); + return ExeNYI(); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +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); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(pointer) /* free memory allocated by ZAlloc */ +voidptr pointer; +{ + free(pointer); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt) +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? */ +{ + (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(IfIndx) /* close input file */ +DEFAULT IfIndx; /* index into IFiles array */ +{ + DBGFEN(2,"ZIClos",NULL); + if (IsOpnI[IfIndx]) { /* if it's open */ + if (fclose(IFiles[IfIndx]) == EOF) { + ZErMsg(); + ErrMsg(ERR_UCI); + ZExit(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(OfIndx) /* close and delete output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + 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); + ZExit(EXIT_FAILURE); + } + if (remove(OFiles[OfIndx].OFNam) != 0) { + ZErMsg(); + ErrStr(ERR_UCD, OFiles[OfIndx].OFNam); + ZExit(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(OfIndx) /* close output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + int ver; + char TmpFsp[FILENAME_MAX]; + char move_err[1024]; + 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 */ + ZExit(EXIT_FAILURE); + } + if (OFiles[OfIndx].OTNam[0] != '\0') { /* if temporary output file */ + (void)strcpy(TmpFsp, OFiles[OfIndx].OTNam);/* copy to TmpFsp */ +#if STRIPEXT + { + char *DotPtr = strchr(TmpFsp, '.'); /* find the "." */ + if (DotPtr != NULL) { /* if "." exists */ + *DotPtr = '\0'; /* make it null */ + } + } +#endif + if (EzFlag&EZ_NO_VER) { + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else { + ver = vernum(TmpFsp); + if (ver==(-3)) { + puts("\nWARNING: Versioning disabled\n"); + (void)strcat(TmpFsp, ".bak"); /* append ".bak" */ + if (access(TmpFsp, 0) == 0) { /* old "x.bak"? */ +#if DEBUGGING + sprintf(DbgSBf, + "deleting old version of %s\r\n", + TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (remove(TmpFsp) != 0) { /* delete it */ + ZErMsg(); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + } else if (ver==(-2) || ver==0) { + (void)strcat(TmpFsp, ";1"); + } else if (ver==(-1)) { /* can't read dir */ + ZErMsg(); + ErrMsg(ERR_UCO); /* una to close o */ + ZClnUp(); + exit(EXIT_FAILURE); + } else { /* ver > 0 */ + int ln = strlen(TmpFsp); + ver++; + strcat(TmpFsp, ";"); + MakDBf((LONG)ver, 10); + strncat(TmpFsp, DBfBeg, DBfPtr-DBfBeg); + *(TmpFsp+ln+(1+DBfPtr-DBfBeg)+1) = '\0'; + } + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OTNam, TmpFsp); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (movefile(OFiles[OfIndx].OTNam, TmpFsp, move_err)) { + ErrStr(ERR_SYS, move_err); + ZDspBf("Edit saved in ", 14); + ZDspBf(OFiles[OfIndx].OFNam, + strlen(OFiles[OfIndx].OFNam)); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } +#if DEBUGGING + sprintf(DbgSBf,"renaming %s to %s\r\n", + OFiles[OfIndx].OFNam, OFiles[OfIndx].OTNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + if (movefile(OFiles[OfIndx].OFNam, + OFiles[OfIndx].OTNam, + move_err)) { + ErrStr(ERR_SYS, move_err); + ErrMsg(ERR_UCO); + ZClnUp(); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; + DBGFEX(2,DbgFNm,NULL); +} +/***************************************************************************** + 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, "r")) != 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, "r")) != 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, "r")) != 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, "r")) != 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. +*****************************************************************************/ +/* + * Unix file names do not have version numbers, 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 close routine will deal + * with renaming files to make them come out right. If no file with the + * same name already exists, then the output file can simply be opened. + * The close routine will only rename files if a temporary file was created + * by this routine. + */ +DEFAULT ZOpOut(OfIndx, RepErr) /* open output file */ +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +{ + char *tfname; + struct stat *bufstat = NULL; + int tmpflag = 0; +#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(FBfBeg, 0) == 0) { /* if file already exists */ + char *dirname,*s; + int n; + bufstat = (struct stat *)malloc(sizeof(struct stat)); + stat(FBfBeg, bufstat); + tmpflag = 1; + n = FBfPtr - FBfBeg; /* strlen(FBfBeg) */ + dirname = (char *)malloc(n+4); + strcpy(dirname, FBfBeg); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + *s='\0'; + } else { /* must have s==dirname and + *s != '/', so current + directory */ + *dirname='.'; *(dirname+1)='\0'; + } + tfname = tempnam(dirname,"tecoc"); + (void)strcpy(OFiles[OfIndx].OFNam, tfname); + free(tfname); + free(dirname); + (void)strcpy(OFiles[OfIndx].OTNam, FBfBeg); +#if DEBUGGING + sprintf(DbgSBf, "file %s already exists\r\n", FBfBeg); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + } else { + (void)strcpy(OFiles[OfIndx].OFNam, FBfBeg); + OFiles[OfIndx].OTNam[0] = '\0'; + } +#if DEBUGGING + sprintf(DbgSBf, "creating file %s\r\n", OFiles[OfIndx].OFNam); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + OFiles[OfIndx].OStrem = fopen(OFiles[OfIndx].OFNam, "w"); + if (OFiles[OfIndx].OStrem == NULL) { + if (RepErr) + ZErMsg(); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + if (tmpflag) { + fchmod(fileno(OFiles[OfIndx].OStrem), + bufstat->st_mode | S_IRUSR | S_IWUSR); + free(bufstat); + } + 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(argc, argv) /* parse a TECOC command line */ +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; iStart, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +#if USE_ANSI_CLPARS +/* + * execute imbedded command line-parsing macro directly from clpars[] + */ + 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 */ +#else +/* + * 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()"); + ZExit(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 = (charptr)"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 + 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. +*****************************************************************************/ +DEFAULT ZPWild() /* preset the wildcard lookup filename */ +{ +/* + * if we didn't process all names from a previous EN` call then discard them + */ + if (wild_list) { + while (*wild_list) { + free(*wild_list); + wild_list++; + } + wild_list = (char **) 0; + } + *FBfPtr='\0'; /* terminate string */ + wild_list = glob(FBfBeg); + if (!wild_list) { + return FAILURE; + } + if (*wild_list) { + return SUCCESS; + } + free(wild_list); /* oops - no files found */ + wild_list = 0; + return FAILURE; +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(OldBlk, NewSiz) /* re-allocate memory */ +voidptr OldBlk; +SIZE_T NewSiz; +{ + return (voidptr)realloc(OldBlk, NewSiz); +} +/***************************************************************************** + ZRdLin() + This function reads a line from a file. It is passed a buffer, the +size of the buffer, and a file pointer. It returns the length of the line, +or sets IsEofI[] to TRUE if the end of file is encountered. +*****************************************************************************/ +DEFAULT ZRdLin(ibuf, ibuflen, IfIndx, retlen) +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) { + *retlen = shortBuf - charsLeft + 1; + if ((EzFlag & EZ_UNIXNL) == 0) { + ibuf[(*retlen) -1] = CRETRN; + ibuf[(*retlen)] = LINEFD; + (*retlen)++; + } +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, retlen = %d", *retlen); + DbgFEx(3,DbgFNm,DbgSBf); +#endif + return SUCCESS; + } + if (character == FORMFD && !(EzFlag & ED_FF)) { + /* 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(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(); +#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() + 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(TTWhat, TTVal) /* tell operating system we set the term. */ +DEFAULT TTWhat; /* what terminal parameter to set */ +DEFAULT TTVal; /* what to set it to */ +{ + 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() /* search for next wildcard filename */ +{ + int filename_length; + if (!wild_list) + return FAILURE; + if (!(*wild_list)) + return FILENF; +/* + * we really have a file name now + */ + filename_length = strlen(*wild_list); + MEMMOVE(FBfBeg, *wild_list, filename_length); + FBfPtr = FBfBeg + filename_length; + free(*wild_list); + wild_list++; + 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 command procedure (under VMS) or a script file (under __UNIX__), 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) + When TECO is started, the terminal will probably be set up for +buffered I/O, so characters won't be received until a RETURN is hit, and +they will be automatically echoed. Set the terminal up for raw I/O, so each +character is received when it is struck, and no echoing is performed. Save +the terminal characteristics so when we exit we can reset them (in ZClnUp) +to what they were before we changed them. +*****************************************************************************/ +static VVOID CntrlC() +{ + signal(SIGINT, SIG_IGN); + SupGotCtC = 0; + if (EtFlag & ET_TRAP_CTRL_C) { /* if user wants it */ + EtFlag &= ~ET_TRAP_CTRL_C; /* turn off bit */ + SupGotCtC = 1; + } else { /* user doesn't want it */ + if (EtFlag & ET_MUNG_MODE) { /* if in MUNG mode */ + TAbort(EXIT_SUCCESS); + } + GotCtC = TRUE; /* set "stop soon" flag */ + } + signal(SIGINT, CntrlC); +} +/* + * sighup - what we do if we get a hang up? + */ +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_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; +#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() + This function displays the verbose form of an error message. +*****************************************************************************/ +VVOID ZVrbos(ErrNum, ErMnem) +WORD ErrNum; +char *ErMnem; +{ + char **TmpPtr; +#include "vrbmsg.h" + 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, one line at a time. It is +passed an output file index and pointers to the beginning and end of the +buffer to be output. +*****************************************************************************/ +DEFAULT ZWrBfr(OfIndx, BfrBeg, BfrEnd) +DEFAULT OfIndx; /* index into OFiles array */ +charptr BfrBeg; /* address of output buffer beginning */ +charptr BfrEnd; /* address of output buffer end */ +{ +#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 we're doing Unix-style editing, where lines are terminated with a + * line feed (newline) instead of a carriage-return/line-feed pair, then + * we can just fwrite the buffer. Otherwise, we have to scan the buffer + * and convert CR/LF pairs to just LF before output. + */ + if (EzFlag & EZ_UNIXNL) { + ptrdiff_t bufsiz = BfrEnd-BfrBeg+1; + if (fwrite(BfrBeg, sizeof(char), bufsiz, + OFiles[OfIndx].OStrem) != bufsiz) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"Zfwrite() failed"); + return FAILURE; + } + } else { + charptr BfrPtr = BfrBeg; /* output buffer pointer */ + while (BfrPtr <= BfrEnd) { + if (*BfrPtr == CRETRN) { + BfrPtr++; + if ((BfrPtr > BfrEnd) || (*BfrPtr != LINEFD)) { + BfrPtr--; + } + } + if (fputc(*BfrPtr, OFiles[OfIndx].OStrem) == EOF) { + ZErMsg(); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + ++BfrPtr; + } + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/**************************************************************************** + vernum() + From Mark Henderson, was in a separate file named vernum.c. +*****************************************************************************/ +static int vernum(target) +/* +maximum version number of target (similar to VMS mechanism) +return +-3 error - problems other than file not found and can't open directory +-2 error - did not find file +-1 error - cannot open directory containing target + 0 file found - no version numbers found + n > 0 version number of highest name;n +*/ +char *target; +{ + DIR *dirp; + int found = 0; /* file found flag */ + char *ftarget; + int maxver = 0; + char *dirname; +#ifdef BSD43 + struct direct *dp; +#else + struct dirent *dp; +#endif + int n; + char *s; + n = strlen(target); + dirname=(char *)malloc(strlen(target)+4); + ftarget=(char *)malloc(strlen(target)+4); + strcpy(dirname, target); + s=dirname + n; + while (*s != '/' && s > dirname) + s--; + if (*s=='/' && s==dirname) { /* must be root directory */ + strcpy(ftarget,s+1); + *(s+1)='\0'; + } else if (*s=='/') { /* we have string/name */ + strcpy(ftarget,s+1); + *s='\0'; + } else { /* must have s==dirname and *s!='/', so current directory */ + strcpy(ftarget,target); + *dirname='.'; *(dirname+1)='\0'; + } + dirp = opendir(dirname); + if (dirp == NULL) { + ZDspBf("\nerror openning directory ", 26); + ZDspBf(dirname, strlen(dirname)); + ZDspCh('\n'); + free(dirname); + free(ftarget); + return(-1); + } + n=strlen(ftarget); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (strncmp(dp->d_name,ftarget,n) == 0) { + char *suffix = dp->d_name + n; + if (*suffix == '\0') { + found = 1; + if (maxver <= 0) + maxver = 0; + } + if (*suffix == ';') { + int k; + found = 1; + k=atoi(suffix+1); + if (k<=0) { + free(dirname); + free(ftarget); + closedir(dirp); + return(-3); + } + if (k>=maxver) + maxver = k; + } + } + } + free(dirname); + free(ftarget); + closedir(dirp); + return (found) ? maxver : -2; +} + +/* + * Everything from here to the end of the file supports the "glob" and + * "movefile" functions, which support wild-card file names and fast + * file renaming, respectively. + */ +/**************************************************************************** + glob() + Was originally from berkeley, in a file named glob.c. Modified to +fit into TECO-C. +****************************************************************************/ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#define MAXGL 10000 +#define QUOTE 0200 +#define TRIM 0177 +#define eq(a,b) (strcmp(a, b)==0) +#define GAVSIZ (MAXGL/6) +#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR) +static char **gargv; /* Pointer to the (stack) arglist */ +static short gargc; /* Number args in gargv */ +static short gnleft; +static short gflag; +char *globerr; +char *home; +extern int errno; +static VVOID expand(); +static int amatch(); +struct passwd *getpwnam(); +char *strcpy(); +char *strcat(); +static int globcnt; +char *globchars = "`{[*?"; +static char *gpath; +static char *gpathp; +static char *lastgpathp; +static int globbed; +static char *entp; +static char **sortbas; +static VVOID gfatal(s, ln) +char *s; +int ln; +{ + ZDspBf("\nfatal error (glob code in zunix.c): ", 37); + ZDspBf(s, ln); + ZDspCh('\n'); + TAbort(EXIT_FAILURE); +} +static char *strend(cp) +register char *cp; +{ + while (*cp) + cp++; + return (cp); +} +static char *strspl(cp, dp) +register char *cp, *dp; +{ + register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1)); + if (ep == (char *)0) + gfatal("Out of memory", 13); + (void) strcpy(ep, cp); + (void) strcat(ep, dp); + return (ep); +} +static VVOID Gcat(s1, s2) +register char *s1, *s2; +{ + register int len = strlen(s1) + strlen(s2) + 1; + if (len >= gnleft || gargc >= GAVSIZ - 1) { + globerr = "Arguments too long"; + } else { + gargc++; + gnleft -= len; + gargv[gargc] = 0; + gargv[gargc - 1] = strspl(s1, s2); + } +} +static VVOID sort() +{ + register char **p1, **p2, *c; + char **Gvp = &gargv[gargc]; + p1 = sortbas; + while (p1 < Gvp-1) { + p2 = p1; + while (++p2 < Gvp) + if (strcmp(*p1, *p2) > 0) + c = *p1, *p1 = *p2, *p2 = c; + p1++; + } + sortbas = Gvp; +} +static VVOID addpath(c) +char c; +{ + if (gpathp >= lastgpathp) { + globerr = "Pathname too long"; + } else { + *gpathp++ = c; + *gpathp = 0; + } +} +static int execbrc(p, s) +char *p, *s; +{ + char restbuf[BUFSIZ + 2]; + register char *pe, *pm, *pl; + int brclev = 0; + char *lm, savec, *sgpathp; + for (lm = restbuf; *p != '{'; *lm++ = *p++) + continue; + for (pe = ++p; *pe; pe++) + switch (*pe) { + case '{': + brclev++; + continue; + case '}': + if (brclev == 0) + goto pend; + brclev--; + continue; + case '[': + for (pe++; *pe && *pe != ']'; pe++) + continue; + continue; + } +pend: + brclev = 0; + for (pl = pm = p; pm <= pe; pm++) + switch (*pm & (QUOTE|TRIM)) { + case '{': + brclev++; + continue; + case '}': + if (brclev) { + brclev--; + continue; + } + goto doit; + case ','|QUOTE: + case ',': + if (brclev) + continue; +doit: + savec = *pm; + *pm = 0; + (void) strcpy(lm, pl); + (void) strcat(restbuf, pe + 1); + *pm = savec; + if (s == 0) { + sgpathp = gpathp; + expand(restbuf); + gpathp = sgpathp; + *gpathp = 0; + } else if (amatch(s, restbuf)) + return (1); + sort(); + pl = pm + 1; + if (brclev) + return (0); + continue; + case '[': + for (pm++; *pm && *pm != ']'; pm++) + continue; + if (!*pm) + pm--; + continue; + } + if (brclev) + goto doit; + return (0); +} +static int amatch(s, p) +register char *s, *p; +{ + register int scc; + int ok, lc; + char *sgpathp; + struct stat stb; + int c, cc; + globbed = 1; + for (;;) { + scc = *s++ & TRIM; + switch (c = *p++) { + case '{': + return (execbrc(p - 1, s - 1)); + case '[': + ok = 0; + lc = 077777; + while ((cc = *p++) != 0) { + if (cc == ']') { + if (ok) + break; + return (0); + } + if (cc == '-') { + if (lc <= scc && scc <= *p++) + ok++; + } else + if (scc == (lc = cc)) + ok++; + } + if (cc == 0) + if (ok) + p--; + else + return 0; + continue; + case '*': + if (!*p) + return (1); + if (*p == '/') { + p++; + goto slash; + } + s--; + do { + if (amatch(s, p)) + return (1); + } while (*s++); + return (0); + case 0: + return (scc == 0); + default: + if (c != scc) + return (0); + continue; + case '?': + if (scc == 0) + return (0); + continue; + case '/': + if (scc) + return (0); +slash: + s = entp; + sgpathp = gpathp; + while (*s) + addpath(*s++); + addpath('/'); + if (stat(gpath, &stb) == 0 && isdir(stb)) + if (*p == 0) { + Gcat(gpath, ""); + globcnt++; + } else + expand(p); + gpathp = sgpathp; + *gpathp = 0; + return (0); + } + } +} +static int match(s, p) +char *s, *p; +{ + register int c; + register char *sentp; + char sglobbed = globbed; + if (*s == '.' && *p != '.') + return (0); + sentp = entp; + entp = s; + c = amatch(s, p); + entp = sentp; + globbed = sglobbed; + return (c); +} +static VVOID matchdir(pattern) +char *pattern; +{ + struct stat stb; + register struct dirent *dp; + DIR *dirp; + dirp = opendir(gpath); + if (dirp == NULL) { + if (globbed) + 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; + if (match(dp->d_name, pattern)) { + Gcat(gpath, dp->d_name); + globcnt++; + } + } + closedir(dirp); + return; +p_err1: + closedir(dirp); +p_err2: + globerr = "Bad directory components"; +} +static int any(c, s) +register int c; +register char *s; +{ + while (*s) + if (*s++ == c) + return(1); + return(0); +} +/* + * Extract a home directory from the password file + * The argument points to a buffer where the name of the + * user whose home directory is sought is currently. + * We write the home directory of the user back there. + */ +static int gethdir(ghome) +char *ghome; +{ + register struct passwd *pp = getpwnam(ghome); + if (pp == 0) + return (1); + (void) strcpy(ghome, pp->pw_dir); + return (0); +} +static VVOID expand(as) +char *as; +{ + register char *cs; + register char *sgpathp, *oldcs; + struct stat stb; + sgpathp = gpathp; + cs = as; + if (*cs == '~' && gpathp == gpath) { + addpath('~'); + for (cs++; Is_Alnum(*cs) || *cs == '_' || *cs == '-';) + addpath(*cs++); + if (!*cs || *cs == '/') { + if (gpathp != gpath + 1) { + *gpathp = 0; + if (gethdir(gpath + 1)) + globerr = "Unknown user name after ~"; + (void) strcpy(gpath, gpath + 1); + } else + (void) strcpy(gpath, home); + gpathp = strend(gpath); + } + } + while (!any(*cs, globchars)) { + if (*cs == 0) { + if (!globbed) + Gcat(gpath, ""); + else if (stat(gpath, &stb) >= 0) { + Gcat(gpath, ""); + globcnt++; + } + goto endit; + } + addpath(*cs++); + } + oldcs = cs; + while (cs > as && *cs != '/') + cs--, gpathp--; + if (*cs == '/') + cs++, gpathp++; + *gpathp = 0; + if (*oldcs == '{') { + (void) execbrc(cs, ((char *)0)); + return; + } + matchdir(cs); +endit: + gpathp = sgpathp; + *gpathp = 0; +} +static VVOID acollect(as) +register char *as; +{ + register int ogargc = gargc; + gpathp = gpath; *gpathp = 0; globbed = 0; + expand(as); + if (gargc != ogargc) + sort(); +} +static VVOID collect(as) +register char *as; +{ + if (eq(as, "{") || eq(as, "{}")) { + Gcat(as, ""); + sort(); + } else + acollect(as); +} +static VVOID ginit(agargv) +char **agargv; +{ + agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; + gnleft = MAXGL - 4; +} +static int tglob(c) +register char c; +{ + if (any(c, globchars)) + gflag |= c == '{' ? 2 : 1; + return (c); +} +static VVOID rscan(t, f) +register char **t; /* wild-card file specification */ +int (*f)(); /* function */ +{ + register char *p, c; + while (p = *t++) { + if (f == tglob) + if (*p == '~') + gflag |= 2; + else if (eq(p, "{") || eq(p, "{}")) + continue; + while (c = *p++) + (*f)(c); + } +} +static int blklen(av) +register char **av; +{ + register int i = 0; + while (*av++) + i++; + return (i); +} +static char **blkcpy(oav, bv) +char **oav; +register char **bv; +{ + register char **av = oav; + while (*av++ = *bv++) + continue; + return (oav); +} +static VVOID blkfree(av0) +char **av0; +{ + register char **av = av0; + while (*av) + free(*av++); + free((char *)av0); +} +static char **copyblk(v) +register char **v; +{ + register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) * + sizeof(char **))); + if (nv == (char **)0) + gfatal("Out of memory", 13); + return (blkcpy(nv, v)); +} +/* + * Passed a wild-card file specification. Returns ??? + */ +static char **glob(v) +register char *v; +{ + char agpath[BUFSIZ]; + char *agargv[GAVSIZ]; + char *vv[2]; + vv[0] = v; + vv[1] = 0; + gflag = 0; + rscan(vv, tglob); + if (gflag == 0) + return (copyblk(vv)); + globerr = 0; + gpath = agpath; + gpathp = gpath; + *gpathp = 0; + lastgpathp = &gpath[sizeof agpath - 2]; + ginit(agargv); + globcnt = 0; + collect(v); + if (globcnt == 0 && (gflag&1)) { + blkfree(gargv), gargv = 0; + return (0); + } + return (gargv = copyblk(gargv)); +} + +/**************************************************************************** + movefile() + Was originally from berkeley, in a file named move.c. Modified to +fit into TECO-C. +****************************************************************************/ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ken Smith of The State University of New York at Buffalo. + * + * Redistribution and use in source and binary forms are permitted provided + * that: (1) source distributions retain this entire copyright notice and + * comment, and (2) distributions including binaries display the following + * acknowledgement: ``This product includes software developed by the + * University of California, Berkeley and its contributors'' in the + * documentation or other materials provided with the distribution and in + * all advertising materials mentioning features or use of this software. + * Neither the name of the University nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#define strerror(n) sys_errlist[n] +static int +fastcopy(from, to, sbp, move_err) +char *from, *to; +struct stat *sbp; +char *move_err; +{ + struct timeval tval[2]; + u_int blen; + static char *bp; + register int nread, from_fd, to_fd; + blen = sbp->st_blksize; + if ((from_fd = open(from, O_RDONLY, 0)) < 0) { + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } + if ((to_fd = open(to, O_WRONLY|O_CREAT|O_TRUNC, sbp->st_mode)) < 0) { + (void)close(from_fd); + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } + if (!(bp = malloc(blen))) { + strcpy(move_err,"out of memory\n"); + return 1; + } + while ((nread = read(from_fd, bp, blen)) > 0) + if (write(to_fd, bp, nread) != nread) { + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + goto err; + } + if (nread < 0) { +err: (void)unlink(to); + (void)close(from_fd); + (void)close(to_fd); + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } + (void)fchown(to_fd, sbp->st_uid, sbp->st_gid); + (void)fchmod(to_fd, sbp->st_mode); + (void)close(from_fd); + (void)close(to_fd); + tval[0].tv_sec = sbp->st_atime; + tval[1].tv_sec = sbp->st_mtime; + tval[0].tv_usec = tval[1].tv_usec = 0; + (void)utimes(to, tval); + (void)unlink(from); + return 0; +} +#ifdef SUNOS4_0 +#define WEXITSTATUS(x) ((x).w_retcode) +#endif +#ifdef SUNOS4_0 +static int +waitpid( pid, statusp ) +int pid; +int *statusp; +{ + int rc; + while( (rc = wait( statusp )) != pid && rc != -1 ) + ; + return rc; +} +#endif +static int +copy(from, to, move_err) +char *from, *to, *move_err; +{ +#ifdef SUNOS4_0 + int pid; + union wait status; +#else + int pid, status; +#endif + if (!(pid = vfork())) { + execlp("/bin/cp", "mv", "-pr", from, to); + strcpy(move_err, "can't execute /bin/cp, "); + strcat(move_err, strerror(errno)); + return 1; + } +#ifdef SUNOS4_0 + (void)waitpid(pid, (union wait *) &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) + return 1; +#else + (void)waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status)) + return 1; +#endif + if (!(pid = vfork())) { + execlp("/bin/rm", "mv", "-rf", from); + strcpy(move_err, "can't execute /bin/rm, "); + strcat(move_err, strerror(errno)); + return 1; + } +#ifdef SUNOS4_0 + (void)waitpid(pid, (union wait *)&status, 0); +#else + (void)waitpid(pid, &status, 0); +#endif + return !WIFEXITED(status) || WEXITSTATUS(status); +} +static int +movefile(from, to, move_err) +char *from, *to, *move_err; +{ + struct stat sbuf; + if (!rename(from, to)) /* if rename succeeds */ + return 0; /* we're done */ +/* + * if rename failed because the two files are on differet partitions, + * and it's a regular file, do the copy internally (fastcopy); otherwise, + * use cp and rm (copy). + */ + if (errno == EXDEV) { + if (stat(from, &sbuf)) { + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; + } +#ifdef SUNOS4_0 + return (S_IFREG & sbuf.st_mode) + ? fastcopy(from, to, &sbuf, move_err) + : copy(from, to, move_err); +#else /* 4.1 or 4.1.1 */ + return (S_ISREG(sbuf.st_mode)) + ? fastcopy(from, to, &sbuf, move_err) + : copy(from, to, move_err); +#endif + } + strcpy(move_err, strerror(errno)); + strcat(move_err,", "); + strcat(move_err, from); + strcat(move_err, " --> "); + strcat(move_err, to); + strcat(move_err, "\n"); + return 1; +} +#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/zunkn.c b/src/zunkn.c new file mode 100644 index 0000000..6feb34a --- /dev/null +++ b/src/zunkn.c @@ -0,0 +1,585 @@ +/***************************************************************************** + ZUnkn.c + System dependent code for an unknown compiler, computer, or +operating system. +*****************************************************************************/ +#include "zport.h" /* define portability identifiers */ +#include "tecoc.h" /* define general identifiers */ +#include "dchars.h" /* define identifiers for characters */ +#include "clpars.h" /* command-line parsing macro */ +VVOID exit(); +VVOID free(); +char *malloc(); +char *realloc(); +char *strcat(); +char *strchr(); +char *strcpy(); +DEFAULT strlen(); +/***************************************************************************** + 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. +*****************************************************************************/ +/*static struct IFDBST 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 OFDBST OFiles[NOFDBS];*/ +/***************************************************************************** + ZErMsg() + This function displays 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. +*****************************************************************************/ +VVOID ZErMsg(stat1, stat2) +int stat1; +int stat2; +{ + puts("Terminating in function ZErMsg.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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(MemSize) /* allocate memory */ +SIZE_T MemSize; +{ + return malloc(MemSize); +} +/***************************************************************************** + 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() +{ + ZDspCh('\7'); +} +/***************************************************************************** + 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 set, 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(NoWait) /* input a character from terminal */ +BOOLEAN NoWait; /* return immediately? */ +{ + puts("Terminating in function ZChIn.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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. +*****************************************************************************/ +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 */ +{ + puts("Terminating in function ZClnEG.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +VVOID ZClnUp(void) /* clean up for exit */ +{ + puts("Terminating in function ZClnUp.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + Zcp2ul() + This function converts a pointer to an unsigned long. +*****************************************************************************/ +#if DEBUGGING +ULONG Zcp2ul(voidptr cp) /* convert charptr to ULONG */ +{ + return ((ULONG)(cp)); +} +#endif +/***************************************************************************** + ZDoCmd() + This function terminates TECO and feeds a command line to the +command line interpreter. +*****************************************************************************/ +VVOID ZDoCmd() /* die and pass command to OS */ +{ + (void)ExeNYI(); +} +/***************************************************************************** + 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 call ZDspCh for every character +in the buffer. +*****************************************************************************/ +VVOID ZDspBf(buffer, length) /* output a buffer to terminal */ +charptr buffer; +SIZE_T length; +{ + puts("Terminating in function ZDspBf.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + ZDspCh() + This function outputs a single character to the terminal. +*****************************************************************************/ +VVOID ZDspCh(Charac) /* output a character to terminal */ +char Charac; +{ + puts("Terminating in function ZDspCh.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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() /* return current date */ +{ + return ExeNYI(); +} +/***************************************************************************** + ZExCtH() + This function implements the TECO ^H command, which returns the +current time encoded in the following way: + (seconds since midnight) / 2 +*****************************************************************************/ +DEFAULT ZExCtH() /* return current time */ +{ + return ExeNYI(); +} +/***************************************************************************** + 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() /* execute an EJ command */ +{ + return ExeNYI(); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +VVOID ZExit(DEFAULT estat) /* terminate TECO-C */ +{ + exit(estat); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(pointer) /* free memory allocated by ZAlloc */ +voidptr pointer; +{ + puts("Terminating in function ZFree.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +VVOID ZHelp(HlpBeg, HlpEnd, SysLib, Prompt) +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? */ +{ + puts("Terminating in function ZHelp.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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(IfIndx) /* close input file */ +DEFAULT IfIndx; /* index into IFiles array */ +{ + puts("Terminating in function ZIClos.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + ZCpyBl() + See the definition of MEMMOVE in ZPORT.H for a description of this +function. +*****************************************************************************/ +#if defined(NEEDS_ZCPYBL) +VVOID ZCpyBl(Destin, Source, Length) +charptr Destin; +charptr Source; +SIZE_T Length; +{ + if (Source < Destin) { + Source += Length; + Destin += Length; + while (Length-- > 0) { + *--Destin = *--Source; + } + } else { + while (Length-- > 0) { + *Destin++ = *Source++; + } + } +} +/***************************************************************************** + 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(OfIndx) /* close and delete output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + puts("Terminating in function ZOClDe.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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(OfIndx) /* close output file */ +DEFAULT OfIndx; /* index into OFiles array */ +{ + puts("Terminating in function ZOClos.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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(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? */ +{ + puts("Terminating in function ZOpInp.\n"); + exit(EXIT_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. +*****************************************************************************/ +DEFAULT ZOpOut(OfIndx, RepErr) /* open output file */ +DEFAULT OfIndx; /* output file indicator */ +BOOLEAN RepErr; /* report errors? */ +{ + puts("Terminating in function ZOpOut.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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, + "MakRom(line_len) failed, calling exit()"); + exit(EXIT_FAILURE); + } + MEMMOVE(QR->Start, TmpBuf, line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +#if USE_ANSI_CLPARS +/* + * execute imbedded 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 +/* + * 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 + 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. +*****************************************************************************/ +DEFAULT ZPWild() /* preset the wildcard lookup filename */ +{ + puts("Terminating in function ZPWild.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(OldBlk, NewSiz) +voidptr OldBlk; +SIZE_T NewSiz; +{ + return realloc(OldBlk, NewSiz); +} +/***************************************************************************** + ZRdLin() + This function reads a line from a file. It is passed a buffer, the +size of the buffer, a file pointer. It returns the length of the line, or +sets IsEofI[] to TRUE if the end of file is encountered. +*****************************************************************************/ +DEFAULT ZRdLin(buf, buflen, fidx, length) +charptr buf; +SIZE_T buflen; +int fidx; +DEFAULT *length; +{ + puts("Terminating in function ZRdLin.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + ZScrOp() + This function is called to perform special screen functions. +*****************************************************************************/ +VVOID ZScrOp(OpCode) /* do a screen operation */ +int OpCode; /* code for 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 */ + } +/* + * 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 */ +{ + 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() /* search for next wildcard filename */ +{ + puts("Terminating in function ZSWild.\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + 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 command procedure (under VMS) or a script file (under __UNIX__), 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) +*****************************************************************************/ +VVOID ZTrmnl() /* set up I/O to the terminal */ +{ + puts("Failing in function ZTrmnl\n"); + exit(EXIT_FAILURE); +} +/***************************************************************************** + ZVrbos() + This function s a buffer to a file. +*****************************************************************************/ +VVOID ZVrbos(ErrNum, ErMnem) +WORD ErrNum; +char *ErMnem; +{ + char **TmpPtr; +#include "vrbmsg.h" + ZDspBf("\r\n",2); + for (TmpPtr = &ParaTx[StartP[LstErr]]; *TmpPtr; ++TmpPtr) { + ZDspBf((charptr)*TmpPtr, strlen(*TmpPtr)); + ZDspBf("\r\n",2); + } +} +/***************************************************************************** + ZWrLin() + This function writes a line to a file. +*****************************************************************************/ +DEFAULT ZWrLin(OfIndx, BfrBeg, RecSiz) +DEFAULT OfIndx; /* index into OFiles array */ +charptr BfrBeg; /* address of output buffer */ +ptrdiff_t RecSiz; /* record size */ +{ + puts("Terminating in function ZWrLin.\n"); + exit(EXIT_FAILURE); +} diff --git a/src/zvms.c b/src/zvms.c new file mode 100644 index 0000000..5b0cb04 --- /dev/null +++ b/src/zvms.c @@ -0,0 +1,1935 @@ +/***************************************************************************** + Zvms.c + System dependent code for VAX/VMS. +*****************************************************************************/ +#include +#include /* EXIT_SUCCESS and EXIT_FAILURE */ +#include /* prototype for strlen */ +#include dcdef /* device class identifiers */ +#include descrip /* string descriptor macros */ +#include dvidef /* dvi item identifier codes */ +#include fab /* RMS file access block structures */ +#include hlpdef /* HLP$... identifiers */ +#include iodef /* i/o code identifiers */ +#include jpidef /* JPI$_... identifiers */ +#include libclidef /* LIB$K_CLI_LOCAL_SYM */ +#include lib$routines /* lib$ routines */ +#include rab /* RMS record access block structures */ +#include rmsdef /* RMS return status identifiers */ +#include signal /* arguments to function signal() */ +#include ssdef /* SS$_NORMAL and SS$_BADESCAPE */ +#include stsdef /* $VMS_STATUS_SUCCESS macro */ +#include starlet /* sys$ routines */ +#include ttdef /* ttdef union */ +#include tt2def /* tt2def union */ +#include "zport.h" /* portability identifiers */ +#include "tecoc.h" /* general identifiers */ +#include "chmacs.h" /* character processing macros */ +#include "clpars.h" /* command-line parsing macro */ +#include "dchars.h" /* identifiers for characters */ +#include "deferr.h" /* identifiers for error messages */ +#include "defext.h" /* external global variables */ +#include "dscren.h" /* identifiers for screen i/o */ +#define SOBSIZE 1024 +#define TERM_IN_EFN 1 /* terminal input event flag */ +#define TERM_OUT_EFN 2 /* terminal output event flag */ +struct getxxx_iosb_struct { /* for calling $getdvi or $getjpi */ + unsigned int io_status; + unsigned int reserved_to_Digital; +}; +struct tt_mode_iosb_struct { /* for setting/sensing term. modes */ + unsigned short io_status; + unsigned char transmit_speed; + unsigned char receive_speed; + unsigned char CR_fill_count; + unsigned char LF_fill_count; + unsigned char parity_flags; + unsigned char unused; +}; +struct tt_rw_iosb_struct { /* for reading/writing to terminal */ + unsigned short io_status; + unsigned short byte_count; + unsigned short terminator; + unsigned short terminator_size; +}; +struct tt_mode_characteristics_struct { + unsigned char class; /* device class */ + unsigned char type; /* terminal type */ + unsigned short nbr_columns; /* number of columns */ + union ttdef lw2; /* longword 2 */ +}; +static struct FAB IFab; /* input file access block */ +static struct NAM INam; /* input name block */ +static struct RAB IRab; /* input file record access block */ +static struct FAB OFab; /* output file access block */ +static struct NAM ONam; /* output name block */ +static struct RAB ORab; /* output file record access block */ +static unsigned char *TIBBeg; /* SYS$INPUT buffer */ +static unsigned char *TIBEnd; /* SYS$INPUT buffer end */ +static unsigned char *TIBERc; /* ptr to end of record in buffer */ +static unsigned char *TIBPtr; /* ptr to current char in record */ +static unsigned char TOBBeg[SOBSIZE]; /* SYS$OUTPUT buffer */ +static unsigned char *TOBEnd; /* SYS$OUTPUT buffer end (+1) */ +static unsigned char *TOBPtr; /* SYS$OUTPUT buffer pointer */ +static struct FAB TIFab; /* SYS$INPUT file access block */ +static struct RAB TIRab; /* SYS$INPUT record access block */ +static struct FAB TOFab; /* SYS$OUTPUT file access block */ +static struct RAB TORab; /* SYS$OUTPUT record access block */ +static short TCChan = 0; /* terminal command channel */ +static short TIChan = 0; /* terminal input channel */ +static short TOChan = 0; /* terminal output channel */ +static struct tt_mode_characteristics_struct tt_chars; +static char WBfExp[NAM$C_MAXRSS]; /* wildcard expanded filename buf */ +static struct FAB WFab; /* wildcard file access block */ +static struct NAM WNam; /* wildcard name block */ +/***************************************************************************** + 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. +*****************************************************************************/ +static struct IFile_struct { + struct FAB IFab; /* file access block */ + struct NAM INam; /* NAM block */ + struct RAB IRab; /* record access block */ + BOOLEAN leftover_input_exists; /* after-FF text saved? (ZRdLin) */ + char *leftover_input; /* after-FF text (see ZRdLin) */ + size_t leftover_size; /* after-FF text size (see ZRdLin) */ +} 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 { + struct FAB OFab; /* file access block */ + struct NAM ONam; /* NAM block */ + struct RAB ORab; /* record access block */ +} OFiles[NOFDBS]; +/***************************************************************************** + ZErMsg() + This function displays 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 int v_action( struct dsc$descriptor_s *msg_desc, + struct dsc$descriptor_s *errstr_desc) +{ + MEMMOVE( errstr_desc->dsc$a_pointer, /* destination */ + msg_desc->dsc$a_pointer, /* source */ + msg_desc->dsc$w_length); /* size */ + errstr_desc->dsc$w_length = msg_desc->dsc$w_length; + return SS$_ACCVIO; +} +static VVOID ZErMsg( /* display an operating-system-supplied message */ + int stat1, + int stat2) +{ + struct + { + short argcnt; /* argument count */ + short msgflg; /* message flags */ + int msgcod; /* message code */ + int rmsstv; /* RMS alternate status */ + } msgvec; + unsigned int status; + charptr tptr; + struct dsc$descriptor errstr_desc; + char errstr[132]; + errstr_desc.dsc$w_length = sizeof(errstr) - 1; + errstr_desc.dsc$a_pointer = &errstr[1]; + msgvec.argcnt = 2; /* number of longwords in msgvec */ + msgvec.msgflg = 15; /* display all parts of message */ + msgvec.msgcod = stat1; /* message code */ + msgvec.rmsstv = stat2; /* RMS alternate status */ + status = sys$putmsg( &msgvec, /* message vector */ + v_action, /* action routine */ + 0, /* facility name */ + &errstr_desc); /* errstr descriptor */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } +/* + * If the message is a successful one, then inform the user by surrounding + * the text in brackets. That way the user won't think an actual error has + * occurred. If it's not successful, just display it. + */ + if ($VMS_STATUS_SUCCESS(stat1)) { + errstr[0] = '['; + tptr = &errstr[errstr_desc.dsc$w_length]; + tptr++; + *tptr++ = ']'; + errstr[errstr_desc.dsc$w_length] = '\0'; + TypBuf(errstr, tptr); + } else { + errstr[errstr_desc.dsc$w_length+1] = '\0'; + ErrStr(ERR_SYS, &errstr[1]); + } +} +/***************************************************************************** + 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 MemSize) /* allocate memory */ +{ + return malloc(MemSize); +} +/***************************************************************************** + 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) +{ + ZDspCh('\7'); +} +/***************************************************************************** + 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 the terminal */ +{ + unsigned char Charac; + int io_function = IO$_READVBLK| + IO$M_NOFILTR| + IO$M_NOECHO; + static BOOLEAN LastCR = FALSE; + unsigned int status; + struct tt_rw_iosb_struct ttread_iosb; + if (TIChan) { /* if it's a terminal */ + if (LastCR) { /* if last char was a */ + LastCR = FALSE; + return (DEFAULT)LINEFD; + } + if (NoWait) { + io_function |= IO$M_TIMED; + } else { + io_function &= ~IO$M_TIMED; + } + status = sys$qiow( + TERM_IN_EFN, /* event flag number */ + TIChan, /* channel */ + io_function, /* I/O function */ + &ttread_iosb, /* I/O status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + &Charac, /* input buffer */ + 1, /* input buffer size */ + 0, /* p3 */ + 0, /* p4 */ + 0, /* p5 */ + 0); /* p6 */ + if (!$VMS_STATUS_SUCCESS(status)) { + ZErMsg(status, 0); + ErrMsg(ERR_URC); + exit(EXIT_FAILURE); + } + switch (ttread_iosb.io_status) { + case SS$_NORMAL: + case SS$_ABORT: + break; + case SS$_CONTROLC: + return 3; + case SS$_TIMEOUT: + return -1; + default: + lib$stop(ttread_iosb.io_status); + } + if (Charac == CRETRN) { + LastCR = TRUE; + } + } else { /* else not term. */ + if (TIBPtr = TIBERc) { /* if rec used up */ + status = sys$get(&TIRab); /* get next record */ + if (status != RMS$_NORMAL) { + ZErMsg(status, TIRab.rab$l_stv); + ErrMsg(ERR_URC); + exit(EXIT_FAILURE); + } + TIBERc = &TIBBeg[TIRab.rab$w_rsz]; + *TIBERc++ = CRETRN; + *TIBERc++ = LINEFD; + TIBPtr = TIBBeg; + } + Charac = *TIBPtr++; + } + 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 + :EGSYM$ sets a DCL local symbol (only for VAX/VMS) +although more functions may be defined. +*****************************************************************************/ +static SetSym(charptr TxtPtr) /* set a DCL local symbol */ +{ + struct dsc$descriptor_s symbol_desc; + struct dsc$descriptor_s value_desc; + unsigned int status; + DBGFEN(1,"SetSym",""); + symbol_desc.dsc$b_dtype = value_desc.dsc$b_dtype = DSC$K_DTYPE_T; + symbol_desc.dsc$b_class = value_desc.dsc$b_class = DSC$K_CLASS_S; + while (*TxtPtr == ' ') { /* skip extra spaces */ + if (TxtPtr == '\0') { + DBGFEX(1,DbgFNm,"1 (supported, but failed)"); + return 1; /* supported, but failed */ + } + TxtPtr++; + } + symbol_desc.dsc$a_pointer = TxtPtr; /* find delimiter */ + while (*TxtPtr != ' ') { + if (TxtPtr == '\0') { + DBGFEX(1,DbgFNm,"1 (supported, but failed)"); + return 1; /* supported, but failed */ + } + TxtPtr++; + } + symbol_desc.dsc$w_length = TxtPtr - symbol_desc.dsc$a_pointer; + while (*TxtPtr == ' ') { /* skip extra spaces */ + if (TxtPtr == '\0') { + DBGFEX(1,DbgFNm,"1 (supported, but failed)"); + return 1; /* supported, but failed */ + } + TxtPtr++; + } + value_desc.dsc$w_length = strlen(TxtPtr); + value_desc.dsc$a_pointer = TxtPtr; + status = lib$set_symbol( + &symbol_desc, /* symbol name */ + &value_desc, /* value string */ + &LIB$K_CLI_LOCAL_SYM); /* local or global */ + if (!$VMS_STATUS_SUCCESS(status)) { + DBGFEX(1,DbgFNm,"supported, but failed"); + return status; /* return "failed" */ + } + DBGFEX(1,DbgFNm,"-1 (success)"); + return -1; /* return "success" */ +} +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, null-terminated value to set */ +{ + unsigned int status; + struct dsc$descriptor_s *log_desc; + static readonly $DESCRIPTOR(mem_desc,"TEC$MEMORY"); + static readonly $DESCRIPTOR(ini_desc,"TEC$INIT"); + static readonly $DESCRIPTOR(lib_desc,"TEC$LIBRARY"); + static readonly $DESCRIPTOR(vte_desc,"TEC$VTEDIT"); + DBGFEN(1,"ZClnEG",""); + switch (EGWhat) { + case EG_INI: log_desc = &ini_desc; break; + case EG_LIB: log_desc = &lib_desc; break; + case EG_MEM: log_desc = &mem_desc; break; + case EG_VTE: log_desc = &vte_desc; break; + default: if (To_Upper(*TxtPtr) == 'S') { + TxtPtr++; + if (To_Upper(*TxtPtr) == 'Y') { + TxtPtr++; + if (To_Upper(*TxtPtr) == 'M') { + TxtPtr++; + if (*TxtPtr == ' ') { + return SetSym(++TxtPtr); + } + } + } + } + DBGFEX(1,DbgFNm,"0 (unsupported)"); + return 0; + } + if (EGOper == GET_VAL) { + short length; + struct dsc$descriptor_s RSL_desc; + RSL_desc.dsc$w_length = NAM$C_MAXRSS; + RSL_desc.dsc$b_dtype = DSC$K_DTYPE_T; + RSL_desc.dsc$b_class = DSC$K_CLASS_S; + RSL_desc.dsc$a_pointer = FBfBeg; + status = sys$trnlog( log_desc, /* logical name */ + &length, /* returned string length */ + &RSL_desc, /* returned string buffer */ + 0, /* logical name table */ + 0, /* access mode */ + 3); /* table search mask */ + if (status == SS$_NORMAL) { /* if it translated */ + FBfPtr = FBfBeg + length; + *FBfPtr = '\0'; /* null-terminate it */ + DBGFEX(1,DbgFNm,"-1 (success)"); + return -1; /* return "success" */ + } + FBfPtr = FBfBeg; /* nullify the "result" */ + if (!$VMS_STATUS_SUCCESS(status)) { /* if problem */ + DBGFEX(1,DbgFNm,"supported, but failed"); + return status; /* return "failed" */ + } + DBGFEX(1,DbgFNm,"-1 (success)"); + return -1; /* return "success" */ + } + if (EGOper == CLEAR_VAL) { + status = lib$delete_logical( + log_desc, /* logical name */ + 0); /* table name */ + } else { + struct dsc$descriptor_s EQU_desc; + EQU_desc.dsc$w_length = strlen(TxtPtr); + EQU_desc.dsc$b_dtype = DSC$K_DTYPE_T; + EQU_desc.dsc$b_class = DSC$K_CLASS_S; + EQU_desc.dsc$a_pointer = TxtPtr; + status = lib$set_logical( + log_desc, /* logical name */ + &EQU_desc); /* equivalence name */ + } + if (!$VMS_STATUS_SUCCESS(status)) { /* if not successful */ + DBGFEX(1,DbgFNm,"supported, but failed"); + return status; /* return "failed" */ + } + DBGFEX(1,DbgFNm,"-1 (success0"); + return -1; /* return "success" */ +} +/***************************************************************************** + ZClnUp() + This function cleans up in preparation for terminating TECO-C. +*****************************************************************************/ +VVOID ZClnUp(void) /* clean up for exit */ +{ + unsigned int status; + DBGFEN(3,"ZClnUp","closing terminal channels and exiting"); + if (TIChan) { /* if it's a terminal */ + status = sys$dassgn(TIChan); /* de-assign the channel */ + if (!$VMS_STATUS_SUCCESS(status)) + lib$stop(status); + } else { /* else process-perm file */ + status = sys$close(&TIFab); /* close the file */ + if (status != RMS$_NORMAL) { + lib$stop(status); + } + } + if (TOChan) { /* if it's a terminal */ + status = sys$dassgn(TOChan); /* de-assign the channel */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + } else { /* else process-perm file */ + if (TOBPtr != TOBBeg) { + TORab.rab$w_rsz = TOBPtr - TOBBeg; + status = sys$put(&TORab); /* output the record */ + if (status != RMS$_NORMAL) { + lib$stop(status, TORab.rab$l_stv); + } + } + status = sys$close(&TOFab); /* close the file */ + if (status != RMS$_NORMAL) { + lib$stop(status); + } + } + if (TCChan) { /* if it was assigned */ + status = sys$dassgn(TCChan); /* de-assign the channel */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + } +} +#if DEBUGGING +ULONG Zcp2ul(voidptr cp) /* convert charptr to ULONG */ +{ + return (ULONG)(cp); +} +#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 */ +{ + unsigned int status; + struct dsc$descriptor_s CS_descriptor; + DBGFEN(1,"ZDoCmd",""); + CS_descriptor.dsc$w_length = FBfPtr - FBfBeg; + CS_descriptor.dsc$b_dtype = DSC$K_DTYPE_T; + CS_descriptor.dsc$b_class = DSC$K_CLASS_S; + CS_descriptor.dsc$a_pointer = FBfBeg; + DBGFEX(1,DbgFNm,"calling lib$do_command"); + status = lib$do_command(&CS_descriptor); + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } +} +/***************************************************************************** + 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 call ZDspCh for every character +in the buffer. +*****************************************************************************/ +#define MAXTOUT 500 +VVOID ZDspBf( /* output a buffer to the terminal */ + charptr buffer, + SIZE_T length) +{ + int iolength; + struct tt_rw_iosb_struct ttwrite_iosb; + unsigned int status; + DEFAULT TmpLng; + if (TOChan) { /* if it's a terminal */ + while ((length > 0) && !GotCtC) { + iolength = (length > MAXTOUT) ? MAXTOUT : length; + status = sys$qiow( + TERM_OUT_EFN, /* event flag number */ + TOChan, /* channel */ + IO$_WRITEVBLK, /* I/O func */ + &ttwrite_iosb, /* I/O status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + buffer, /* p1 */ + iolength, /* p2 */ + 0, /* p3 */ + 0, /* p4 */ + 0, /* p5 */ + 0); /* p6 */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + if ((!$VMS_STATUS_SUCCESS(ttwrite_iosb.io_status)) && + (ttwrite_iosb.io_status != SS$_ABORT) && + (ttwrite_iosb.io_status != SS$_CONTROLC) && + (ttwrite_iosb.io_status != SS$_CONTROLO)) { + lib$stop(ttwrite_iosb.io_status); + } + buffer += iolength; + length -= iolength; + } + } else { /* else it's not a terminal */ + for (TmpLng=1; TmpLng<=length; ++TmpLng) { + ZDspCh(*buffer++); + } + } +} +/***************************************************************************** + ZDspCh() + This function outputs a single character to the terminal. +*****************************************************************************/ +VVOID ZDspCh(char Charac) /* output a character to the terminal */ +{ + unsigned int status; + struct tt_rw_iosb_struct ttwrite_iosb; + if (TOChan) { /* if it's a terminal */ + status = sys$qiow( + TERM_OUT_EFN, /* event flag number */ + TOChan, /* channel */ + IO$_WRITEVBLK, /* I/O func */ + &ttwrite_iosb, /* I/O status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + &Charac, /* p1 */ + 1, /* p2 */ + 0, /* p3 */ + 0, /* p4 */ + 0, /* p5 */ + 0); /* p6 */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + if ((!$VMS_STATUS_SUCCESS(ttwrite_iosb.io_status)) && + (ttwrite_iosb.io_status != SS$_CONTROLO)) { + lib$stop(ttwrite_iosb.io_status); + } + } else { /* else it's not a terminal */ + if (IsEOL(Charac)) { + if (Charac == LINEFD) { + if (TOBPtr > TOBBeg) { + --TOBPtr; + if (*TOBPtr != CRETRN) { + ++TOBPtr; + } + } + } else { + *TOBPtr = Charac; + if (++TOBPtr > TOBEnd) { + lib$stop(SS$_NORMAL); + } + } + TORab.rab$w_rsz = TOBPtr - TOBBeg; + status = sys$put(&TORab); /* output the record */ + if (status != RMS$_NORMAL) { /* if it didn't work */ + lib$stop(status, TORab.rab$l_stv); + } + TOBPtr = TOBBeg; + } else { + *TOBPtr = Charac; + if (++TOBPtr > TOBEnd) { + lib$stop(SS$_NORMAL); + } + } + } +} +/***************************************************************************** + ZEgSym() + This macro gets or sets or clears a CLI symbol.name. This function +is called to implement the :EGSYM command under VAX/VMS. +*****************************************************************************/ +DEFAULT ZEgSym(SFOpTp,TxtPtr) /* get/set/clear DCL symbol value */ +DEFAULT SFOpTp; +charptr TxtPtr; +{ + unsigned int status; + struct dsc$descriptor_s Sym_desc = { + 0, /* dsc$w_length */ + DSC$K_DTYPE_T, /* dsc$b_dtype */ + DSC$K_CLASS_S, /* dsc$b_class */ + 0 /* dsc$a_pointer */ + }; + struct dsc$descriptor_s Val_desc = { + NAM$C_MAXRSS, /* dsc$w_length */ + DSC$K_DTYPE_T, /* dsc$b_dtype */ + DSC$K_CLASS_S, /* dsc$b_class */ + FBfBeg /* dsc$a_pointer */ + }; + short length; + DBGFEN(1,"ZEgSym",""); + Sym_desc.dsc$w_length = FBfPtr-TxtPtr; + Sym_desc.dsc$a_pointer = TxtPtr; + if (SFOpTp == GET_VAL) { + status = lib$get_symbol( + &Sym_desc, /* symbol */ + &Val_desc, /* return string buffer */ + &length, /* returned string length */ + 0); /* table indicator */ + if (!$VMS_STATUS_SUCCESS(status)) { /* if something is wrong */ + FBfPtr = FBfBeg; /* nullify the "result" */ + DBGFEX(1,DbgFNm,""); + return status; /* return "failed" */ + } + FBfPtr = FBfBeg + length; + *FBfPtr = '\0'; + DBGFEX(1,DbgFNm,"-1"); + return -1; /* return "success" */ + } + if (SFOpTp == CLEAR_VAL) { + Val_desc.dsc$w_length = 0; + } else { + Val_desc.dsc$w_length = FBfPtr-TxtPtr; + } + Val_desc.dsc$a_pointer = TxtPtr; + status = lib$set_symbol(&Sym_desc, /* symbol */ + &Val_desc, /* value */ + 0); /* table indicator */ + if (!$VMS_STATUS_SUCCESS(status)) { + DBGFEX(1,DbgFNm,""); + return status; /* return "failed" */ + } + DBGFEX(1,DbgFNm,"-1"); + return -1; /* return "success" */ +} +/***************************************************************************** + 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 */ +{ + unsigned int status; + short system_time[7]; + LONG teco_date; + DBGFEN(1,"ZExCtB",""); + status = sys$numtim( system_time, /* returned time */ + 0); /* time to convert */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + teco_date = (system_time[0] - 1900) << 4; /* (year-1900) * 16 */ + teco_date += system_time[1]; /* month */ + teco_date = teco_date << 5; /* multiply by 32 */ + teco_date += system_time[2]; /* day of month */ + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(teco_date, OPERAND); +} +/***************************************************************************** + ZExCtH() + This function implements the TECO ^H command, which returns the +current time encoded in the following way: + (seconds since midnight) / 2 +*****************************************************************************/ +DEFAULT ZExCtH(void) /* return current time */ +{ + unsigned int status; + short system_time[7]; + LONG teco_time; + DBGFEN(1,"ZExCtH",""); + status = sys$numtim( system_time, /* returned time */ + 0); /* time to convert */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + teco_time = system_time[3] * 60; /* hours * 60 */ + teco_time += system_time[4]; /* minutes */ + teco_time *= 30; + teco_time += system_time[5] >> 1; /* seconds / 2 */ + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(teco_time, 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 */ +{ + LONG RetVal; + DBGFEN(1,"ZExeEJ",""); + 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"); + return FAILURE; + } + } + if (NArgmt < 0) { /* oper. system dependent */ + if (NArgmt == -1) { + RetVal = 1024; /* means "VAX running VMS" */ + } else { + return ExeNYI(); + } + } else if (NArgmt == 1) { /* 1EJ (terminal unit) */ + RetVal = 0; + } else { + struct getxxx_iosb_struct getjpi_iosb; + struct { + short buflen1; /* buffer length */ + short itmcode1; /* item code */ + charptr buffer1; /* buffer address */ + short *retlen1; /* returned length */ + int termin; /* item list terminator */ + } item_list = { + 4, /* buffer length */ + JPI$_UIC, /* uic (2EJ) */ + &RetVal, /* buffer address */ + 0, /* returned length */ + 0 /* item list terminator */ + }; + unsigned int status; + if (NArgmt == 0) { /* 0EJ (process id) */ + item_list.itmcode1 = JPI$_PID; + } + status = sys$getjpiw( 0, /* event flag */ + 0, /* pid address */ + 0, /* process name */ + &item_list, /* item list */ + &getjpi_iosb, /* i/o status block */ + 0, /* AST routine */ + 0); /* AST parameter */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + if (!$VMS_STATUS_SUCCESS(getjpi_iosb.io_status)) { + lib$stop(getjpi_iosb.io_status); + } + } + DBGFEX(1,DbgFNm,"PushEx()"); + return PushEx(RetVal,OPERAND); +} +/***************************************************************************** + ZExit() + This function terminates TECO-C with a status value. +*****************************************************************************/ +VVOID ZExit(DEFAULT estat) /* terminate TECO-C */ +{ +/* + * Exit with a success status if we're exiting normally. If we're exiting + * because something went wrong, then exit with a VMS error status. Since + * we don't have a message file, just steal a system-defined code (ABORT) + * which is somewhat meaningful. + */ + sys$exit((estat == EXIT_SUCCESS) ? SS$_NORMAL : SS$_ABORT); +} +/***************************************************************************** + ZFree() + This function frees memory previously allocated by the ZAlloc +function. +*****************************************************************************/ +VVOID ZFree(voidptr pointer) /* free memory allocated by ZAlloc */ +{ + free(pointer); +} +/***************************************************************************** + ZHelp() + This function accepts a help string and displays the corresponding +help text. + it should be control-C interrupt-able. +*****************************************************************************/ +/***************************************************************************** + Help on the VAX is accessed through the help library routines. +*****************************************************************************/ +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? */ +{ + struct dsc$descriptor_s line_desc; + struct dsc$descriptor_s lib_desc; + unsigned int flags; + unsigned int status; + $DESCRIPTOR(syshelp_desc, "SYS$HELP:HELPLIB"); + $DESCRIPTOR(techelp_desc, "TEC$HELP"); +#if DEBUGGING + static char *DbgFNm = "ZHelp"; + sprintf(DbgSBf,"text = \"%.*s\"", (int)(HlpEnd-HlpBeg), HlpBeg); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + line_desc.dsc$a_pointer = HlpBeg; + line_desc.dsc$w_length = (HlpEnd - HlpBeg) + 1; + lib_desc = (SysLib ? syshelp_desc : techelp_desc); + flags = HLP$M_PROCESS | HLP$M_GROUP | HLP$M_SYSTEM | HLP$M_HELP; + if (Prompt) { + flags |= HLP$M_PROMPT; + } + status = lbr$output_help( lib$put_output, /* output routine */ + 0, /* output width */ + &line_desc, /* line-desc */ + &lib_desc, /* library name */ + &flags, /* flags */ + lib$get_input); /* input rotuine */ + if (status != SS$_NORMAL) { + ZErMsg(status,0); + } + DBGFEX(2,DbgFNm,""); +} +/***************************************************************************** + 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 */ +{ + unsigned int status; + DBGFEN(2,"ZIClos",""); + if (IsOpnI[IfIndx]) { /* if it's open */ + status = sys$close(&IFiles[IfIndx].IFab); + if (status != RMS$_NORMAL) { + ZErMsg(status, IFiles[IfIndx].IFab.fab$l_stv); + if (!$VMS_STATUS_SUCCESS(status)) { + ErrMsg(ERR_UCI); +#if DEBUGGING + DbgFMs(2,DbgFNm,"dying"); +#endif + exit(EXIT_FAILURE); + } + } + IsOpnI[IfIndx] = FALSE; + } + DBGFEX(2,DbgFNm,""); +} +/***************************************************************************** + 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 */ +{ + unsigned int status; + DBGFEN(2,"ZOClDe",""); + if (IsOpnO[OfIndx]) { /* if output stream is open */ + OFiles[OfIndx].OFab.fab$l_fop |= FAB$M_DLT; + status = sys$close(&OFiles[OfIndx].OFab); + if (status != RMS$_NORMAL) { + ZErMsg(status, OFiles[OfIndx].OFab.fab$l_stv); + if (!$VMS_STATUS_SUCCESS(status)) { + ErrMsg(ERR_UCD); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; + } + DBGFEX(2,DbgFNm,""); +} +/***************************************************************************** + 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 */ +{ + unsigned int status; + DBGFEN(2,"ZOClos",""); + if (IsOpnO[OfIndx]) { /* if it's open */ + status = sys$close(&OFiles[OfIndx].OFab); + if (status != RMS$_NORMAL) { + ZErMsg(status, OFiles[OfIndx].OFab.fab$l_stv); + if (!$VMS_STATUS_SUCCESS(status)) { + ErrMsg(ERR_UCO); + exit(EXIT_FAILURE); + } + } + IsOpnO[OfIndx] = FALSE; + } + DBGFEX(2,DbgFNm,""); +} +/***************************************************************************** + 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( /* 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? */ +{ + char ExpFBf[NAM$C_MAXRSS]; /* expanded filename buffer */ + struct FAB *IF; /* pointer to FAB */ + struct NAM *IN; /* pointer to NAM block */ + struct RAB *IR; /* pointer to RAB */ + unsigned int status; /* temporary status */ +#if DEBUGGING + static char *DbgFNm = "ZOpInp"; + sprintf(DbgSBf,", FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + IN = &IFiles[IfIndx].INam; + *IN = cc$rms_nam; /* initialize NAM defaults */ + IN->nam$l_esa = ExpFBf; /* expanded file spec buffer addr. */ + IN->nam$b_ess = sizeof ExpFBf; /* expanded file spec buffer size */ + IN->nam$l_rsa = FBfBeg; /* resultant file spec buffer addr. */ + IN->nam$b_rss = NAM$C_MAXRSS; /* resultant file spec buffer size */ + IF = &IFiles[IfIndx].IFab; + *IF = cc$rms_fab; /* initialize FAB defaults */ + IF->fab$l_nam = IN; /* address of NAM block */ + IF->fab$b_fac = FAB$M_GET; /* file access = read only */ + IF->fab$b_shr = FAB$M_SHRGET; /* allow others to read the file */ + if (EIFile) { /* if use default file type ".TEC" */ + IF->fab$l_dna = ".TEC"; /* default filename */ + IF->fab$b_dns = 4; /* default filename size */ + } + IF->fab$l_fna = FBfBeg; /* set file name address */ + IF->fab$b_fns = FBfPtr - FBfBeg; /* set file name size */ + IR = &IFiles[IfIndx].IRab; + *IR = cc$rms_rab; /* initialize RAB defaults */ + IR->rab$l_fab = IF; /* address of associated FAB */ + IR->rab$b_rac = RAB$C_SEQ; /* record access mode = sequential */ + status = sys$open(IF); /* open the file */ + if (status != RMS$_NORMAL) { /* if failed for some reason */ + if ((status == RMS$_FNF) && EIFile) { /* if couldn't find EI file */ + charptr dummyp = NULL; + char TmpBfr[NAM$C_MAXRSS]; + ptrdiff_t TmpLen = FBfPtr-FBfBeg; + 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; + IF->fab$b_fns = FBfPtr - FBfBeg; /* set file name size */ + status = sys$open(IF); /* open the file */ + if (status != RMS$_NORMAL) { + goto open_failed; + } + } else { +open_failed: + if (!RepFNF && (status == RMS$_FNF)) { + DBGFEX(2,DbgFNm,"FILENF"); + return FILENF; + } + ZErMsg(status, IF->fab$l_stv); + if (!$VMS_STATUS_SUCCESS(status)) { + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + } + } + FBfPtr = FBfBeg + IN->nam$b_rsl; /* resultant name length */ + status = sys$connect(IR); /* connect RAB to FAB */ + if (status != RMS$_NORMAL) { + ZErMsg(status, IR->rab$l_stv); + if (!$VMS_STATUS_SUCCESS(status)) { + status = sys$close(IF); /* close the file */ + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + } + IFiles[IfIndx].leftover_input_exists = FALSE; + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + 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. +*****************************************************************************/ +DEFAULT ZOpOut(DEFAULT OfIndx, BOOLEAN RepErr) /* open output file */ +{ + char ExpFBf[NAM$C_MAXRSS]; /* expanded filename buffer */ + struct FAB *OF; + struct NAM *ON; + struct RAB *OR; + unsigned int status; +#if DEBUGGING + static char *DbgFNm = "ZOpOut"; + sprintf(DbgSBf,", FBf = \"%.*s\"",(int)(FBfPtr-FBfBeg),FBfBeg); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + ON = &OFiles[OfIndx].ONam; + *ON = cc$rms_nam; /* initialize NAM defaults */ + ON->nam$l_esa = ExpFBf; /* expanded file spec buffer address */ + ON->nam$b_ess = sizeof ExpFBf; /* expanded file spec buffer size */ + ON->nam$l_rsa = FBfBeg; /* resultant file spec buffer address */ + ON->nam$b_rss = NAM$C_MAXRSS; /* resultant file spec buffer size */ + OF = &OFiles[OfIndx].OFab; + *OF = cc$rms_fab; /* initialize FAB defaults */ + OF->fab$b_fac = FAB$M_PUT; /* file access = write only */ + OF->fab$b_org = FAB$C_SEQ; /* file organization = sequential */ + OF->fab$b_rat = FAB$M_CR; /* carriage return record attribute */ + OF->fab$b_rfm = FAB$C_VAR; /* variable length record format */ + OF->fab$b_shr = FAB$M_NIL; /* no sharing */ + OF->fab$l_nam = ON; /* address of NAM block */ + OF->fab$l_fna = FBfBeg; /* file name address */ + OF->fab$b_fns = FBfPtr - FBfBeg; /* file name size */ + OR = &OFiles[OfIndx].ORab; + *OR = cc$rms_rab; /* initialize RAB defaults */ + OR->rab$l_fab = OF; /* address of associated FAB */ + OR->rab$b_rac = RAB$C_SEQ; /* record access mode = sequential */ + status = sys$create(OF); /* create the file */ + if (status != RMS$_NORMAL) { + if (RepErr) { + ZErMsg(status, OF->fab$l_stv); + } + if (!$VMS_STATUS_SUCCESS(status)) { + DBGFEX(2,DbgFNm,"FAILURE, sys$create failed"); + return FAILURE; + } + } + FBfPtr = FBfBeg + ON->nam$b_rsl; /* resultant name length */ + status = sys$connect(OR); /* connect RAB to FAB */ + if (status != RMS$_NORMAL) { + if (RepErr) { + ZErMsg(status, OR->rab$l_stv); + } + if (!$VMS_STATUS_SUCCESS(status)) { + OF->fab$l_fop |= FAB$M_DLT; /* delete on close */ + status = sys$close(OF); /* close the file */ + DBGFEX(2,DbgFNm,"FAILURE, sys$connect failed"); + return FAILURE; + } + } + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ZPrsCL() + This function parses the command line. It does so using the classic +TECO-11 method: use a TECO macro to do it! The macros is stored in array +"clpars". The macro is in file "clpars.h", and is over 3k long. The VMS C +compiler (version 3.0) can't handle a string literal that's that long, so +it loads a piece of memory 1 line at a time. +*****************************************************************************/ +/* + Under VAX/VMS, the logic is: + load q-register Z with the command line + load q-register Y with a command-line parsing macro + IF logical name "TECO" is defined THEN + do an EITECO$$ + ELSEIF the file "SYS$LOGIN:TECO.TEC" exists, THEN + do an EISYS$LOGIN:TECO.TEC$$ + ELSE + do an MY$$ +*/ +VVOID ZPrsCL( /* parse the command line */ + int argc, + char *argv[]) +{ + char MngBeg[4+NAM$C_MAXRSS]; /* temporary command string buffer */ + charptr MngPtr; /* pointer into mung buffer */ + charptr TmpPtr; /* temporary pointer */ + BOOLEAN filefound; + short length; + unsigned int status; + char CLPars_name[NAM$C_MAXRSS]; + $DESCRIPTOR(teco_desc,"TECO"); + $DESCRIPTOR(fil_desc,"SYS$LOGIN:TECO.TEC"); + $DESCRIPTOR(res_desc, CLPars_name); + int i; + SIZE_T line_len; + char cmd_line[1024]; + $DESCRIPTOR(cmd_line_desc, cmd_line); + DBGFEN(2,"ZPrsCL",""); +/* + * If the command line contains arguments, load them into Q-register Z. + */ + status = lib$get_foreign( /* get command line */ + &cmd_line_desc, /* returned string */ + 0, /* user prompt */ + &cmd_line_desc.dsc$w_length, /* returned string length */ + 0); /* force prompt */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + if (cmd_line_desc.dsc$w_length != 0) { + QR = &QRgstr[35]; /* 35 = q-register Z */ + if (MakRom((SIZE_T)cmd_line_desc.dsc$w_length) == FAILURE) + exit(EXIT_FAILURE); + MEMMOVE(QR->Start, /* destination */ + cmd_line, /* source */ + cmd_line_desc.dsc$w_length); /* length */ + QR->End_P1 += cmd_line_desc.dsc$w_length; + } +/* + * load imbedded command-line parsing macro into q-register Y + */ + QR = &QRgstr[34]; /* 34 = q-register Y */ + if (MakRom((SIZE_T)CLPARS_LEN) == FAILURE) { + exit(EXIT_FAILURE); + } + for (i=0; iEnd_P1, clpars[i], line_len); + QR->End_P1 += line_len; /* length of q-reg text */ + } +/* + * If the logical name "TECO" is defined, then do EITECO$$. If not, look + * for file SYS$LOGIN:TECO.TEC, and "EI" it if it exists. If it also doesn't + * exist, just execute the macro in q-register Y. + */ + status = sys$trnlog( &teco_desc, /* logical name */ + &length, /* returned string length */ + &res_desc, /* returned string buffer */ + 0, /* logical name table */ + 0, /* access mode */ + 3); /* table search mask */ + if (status == SS$_NORMAL) { /* if logical exists */ + filefound = TRUE; /* do EITECO$$ later*/ + } else if (status == SS$_NOTRAN) { /* if logical doesn't exist */ + int context; + int user_flags; + context = 0; + user_flags = 1; + status = lib$find_file( &fil_desc, /* file spec */ + &res_desc, /* resultant spec */ + &context, /* context */ + 0, /* default spec */ + 0, /* related spec */ + 0, /* stv address */ + &user_flags); /* user flags */ + if (status == RMS$_NORMAL) { + length = res_desc.dsc$w_length; + filefound = TRUE; + } else { + if (status != RMS$_FNF) { + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + } + filefound = FALSE; + } + status = lib$find_file_end(&context); + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + } else { + lib$stop(status); /* terminate */ + } +/* + * If there is a user-defined command-parsing macro file, do an EI on it. + * Otherwise, execute q-register Y. + */ + MngPtr = MngBeg; + if (filefound) { + *MngPtr++ = 'e'; + *MngPtr++ = 'i'; + TmpPtr = res_desc.dsc$a_pointer; + for (;length>0;length--) { + *MngPtr++ = *TmpPtr++; + } + } else { + *MngPtr++ = 'm'; + *MngPtr++ = 'y'; + } + *MngPtr++ = ESCAPE; + *MngPtr = ESCAPE; + CBfPtr = MngBeg; /* command string start */ + CStEnd = MngPtr; /* command string end */ + EStTop = EStBot; /* clear expression stack */ + ExeCSt(); /* execute command string */ + DBGFEX(2,DbgFNm,""); +} +/***************************************************************************** + 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. +*****************************************************************************/ +DEFAULT ZPWild(void) /* preset the wildcard lookup filename */ +{ + unsigned int status; + static BOOLEAN first_time_called = TRUE; +#if DEBUGGING + static char *DbgFNm = "ZPWild"; + sprintf(DbgSBf, ", FBf = \"%.*s\"", (int)(FBfPtr-FBfBeg), FBfBeg); + DbgFEn(1,DbgFNm,DbgSBf); +#endif + if (first_time_called) { + first_time_called = FALSE; + WNam = cc$rms_nam; /* initialize NAM defaults */ + WNam.nam$l_esa = WBfExp; /* expanded file spec buf */ + WNam.nam$b_ess = NAM$C_MAXRSS; /* expanded f. s. buf size */ + WNam.nam$l_rsa = FBfBeg; /* res file spec buf */ + WNam.nam$b_rss = NAM$C_MAXRSS; /* res file spec buf size */ + WFab = cc$rms_fab; /* initialize FAB defaults */ + WFab.fab$l_fna = FBfBeg; /* addr. wildcard file spec */ + WFab.fab$l_nam = &WNam; /* address of NAM block */ + WFab.fab$b_fac = FAB$M_GET; /* file access = read only */ + } + WFab.fab$b_fns = FBfPtr - FBfBeg; /* file name size */ + status = sys$parse(&WFab); + if (status != RMS$_NORMAL) { + ZErMsg(status, WFab.fab$l_stv); + if (!$VMS_STATUS_SUCCESS(status)) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + DBGFEX(1,DbgFNm,"SUCCESS"); + return SUCCESS; +} +/***************************************************************************** + ZRaloc() + This function performs the standard C library function realloc. +*****************************************************************************/ +voidptr ZRaloc(voidptr OldBlk, SIZE_T NewSiz) +{ + return realloc(OldBlk, NewSiz); +} +/***************************************************************************** + 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. + What this function does may be confusing, so here's a description +of it from the Standard TECO manual, Appendix G (VAX/VMS Operating +Characteristics), section 11: "File Record Format". TECO-C supports only +implied-carriage-control files under VMS, so I removed the discussion of +other formats. + Files-11 files are record structured, while TECO'S text buffer is + ASCII stream. Thus TECO must make format conversions when reading + and writing files. While reading a file, the records are packed + into the buffer. TECO inserts a carriage return and line feed + after each record to make each record appear as a line of text in + the buffer, unless the record ends with ESCAPE, carriage return, + line feed, vertical tab, or form feed. A record ending in form + feed is interpreted as an end of page mark; it stops the read + operation and the form feed is not entered in the buffer. The + portion of the record after the form feed, if any, is saved for + the next input command. +File output is similarly screwy. See the comment for the ZWrBfr function. +*****************************************************************************/ +DEFAULT ZRdLin( /* read a line */ + charptr ibuf, /* where to put the line */ + ptrdiff_t ibuflen, /* length of buf */ + int IfIndx, /* index into IFiles[] */ + DEFAULT *retlen) /* returned length of the line */ +{ + unsigned int status; + struct IFile_struct *ifile = &IFiles[IfIndx]; + char *ffptr; + char lastchr; + DBGFEN(3,"ZRdLin",""); +/* + * Get the next input line into ibuf, and length into *retlen. + */ + if (ifile->leftover_input_exists) { + memcpy(ibuf, + ifile->leftover_input, + ifile->leftover_size); + free(ifile->leftover_input); + *retlen = ifile->leftover_size; + ifile->leftover_input_exists = FALSE; + } else { + ifile->IRab.rab$l_ubf = ibuf; /* input buffer */ + ifile->IRab.rab$w_usz = (ibuflen > 65535) ? 65535 + : ibuflen; + status = sys$get(&ifile->IRab); /* get a record */ + if (status == RMS$_EOF) { /* if end of file */ + DBGFEX(3,DbgFNm,"SUCCESS, hit end-of-file"); + IsEofI[IfIndx] = TRUE; + return SUCCESS; + } + if (status != RMS$_NORMAL) { + ZErMsg(status, IRab.rab$l_stv); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + *retlen = ifile->IRab.rab$w_rsz; + } +/* + * Now do all the weird handling of special characters (see the main comment + * for this function). + */ + if (*retlen > 0) { /* if not an empty line */ + if ((ffptr = memchr(ibuf, FORMFD, *retlen)) != NULL) { + ifile->leftover_size = *retlen - (ffptr - ibuf + 1); + if (ifile->leftover_size > 0) { + if ((ifile->leftover_input = + malloc(ifile->leftover_size))==NULL) { + ErrMsg(ERR_MEM); + DBGFEX(3,DbgFNm,"FAILURE"); + return FAILURE; + } + memcpy(ifile->leftover_input, + ffptr+1, + ifile->leftover_size); + ifile->leftover_input_exists = TRUE; + } + FFPage = -1; /* set "form feed hit" flag */ + *retlen = ffptr - ibuf; + DBGFEX(3,DbgFNm,"SUCCESS, hit formfeed"); + return SUCCESS; + } + lastchr = ibuf[(*retlen)-1]; + if ((lastchr == ESCAPE) || + (lastchr == CRETRN) || + (lastchr == LINEFD) || + (lastchr == VRTTAB)) { + DBGFEX(3,DbgFNm,"SUCCESS, hit ESC, CR, LF or VT"); + return SUCCESS; + } + } + ibuf[*retlen] = CRETRN; /* append carriage return */ + *retlen += 1; + ibuf[*retlen] = LINEFD; /* append line feed */ + *retlen += 1; + DBGFEX(3,DbgFNm,"SUCCESS"); + 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 */ +/* + * 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 */ +{ + unsigned int status; + struct tt_mode_iosb_struct mode_iosb; + if (!TOChan) /* if it's not a terminal */ + return(SUCCESS); +/* + * Modify the terminal characteristics. + */ + switch (TTWhat) { + case TT8BIT: tt_chars.lw2.tt$v_eightbit = TTVal; break; + case TTWIDTH: tt_chars.nbr_columns = TTVal; break; + case TTHEIGHT: tt_chars.lw2.tt$v_page = TTVal; break; + } +/* + * Set the new terminal characteristics. + */ + status = sys$qiow( 0, /* event flag number */ + TOChan, /* channel */ + IO$_SETMODE, /* I/O function */ + &mode_iosb, /* I/O status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + &tt_chars, /* p1 */ + 0, /* p2 */ + 0, /* p3 */ + 0, /* p4 */ + 0, /* p5 */ + 0); /* p6 */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + if (!$VMS_STATUS_SUCCESS(mode_iosb.io_status)) { + lib$stop(mode_iosb.io_status); + } + return SUCCESS; +} +/***************************************************************************** + 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 */ +{ + unsigned int status; + DBGFEN(1,"ZSWild",""); + status = sys$search(&WFab); /* search for file */ + if ((status == RMS$_FNF) || /* if file not found or */ + (status == RMS$_NMF)) { /* no more files */ + DBGFEX(1,DbgFNm,"FILENF"); + return FILENF; + } + if (status != RMS$_NORMAL) { + ZErMsg(status, WFab.fab$l_stv); + if (!$VMS_STATUS_SUCCESS(status)) { + DBGFEX(1,DbgFNm,"FAILURE"); + return FAILURE; + } + } + FBfPtr = FBfBeg + WNam.nam$b_rsl; /* resultant name length */ +#if DEBUGGING + sprintf(DbgSBf,"SUCCESS, FBf = \"%.*s\"",(int)(FBfPtr-FBfBeg),FBfBeg); + DbgFEx(1,DbgFNm,DbgSBf); +#endif + 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 command procedure (under VMS) or a script file (under __UNIX__), 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) +*****************************************************************************/ +/***************************************************************************** + On the VAX, TECO-C can be run under two environments: interactive or +non-interactive (like batch). In an interactive session, it uses the +terminal for input and output. In non-interactive mode, it goes through RMS. +The difference is the way the I/O completes. + In interactive mode, each character the user types is immediately +received by TECO-C (forget type-ahead for now). This allows TECO-C to echo +the character immediately. + In non-interactive mode, input comes from a file and output goes to +another file, so RMS is used. RMS returns a bunch of characters to TECO-C +when the user types a "terminator" character, which is defined by VMS. +In non-interactive mode, it isn't important that TECO-C echo characters +immediately. + Because both modes must be supported, there are two separate i/o +systems in the code. TECO-C determines if it is in interactive mode when +this function is called. It sets TIChan to be the a channel associated with +the terminal for interactive mode, or leaves TIChan unset (zero) for +non-interactive mode. Other functions (ZDSpCh, ZDspBf, ZChin) test TIChan and +use either QIOs or RMS to perform I/O. + Under VMS, input comes from SYS$INPUT, output goes to SYS$OUTPUT, +and control-C's come from SYS$COMMAND. Control-Y's are not explicitly +handled by TECOC. If SYS$COMMAND is not a terminal device, then control-C's +are not enabled. +*****************************************************************************/ +int devclass; /* device class */ +union ttdef devdepend; /* device dependent attributes */ +union tt2def devdepend2; /* device dependent attributes */ +readonly $DESCRIPTOR(ter_c_desc,"SYS$COMMAND"); +readonly $DESCRIPTOR(ter_i_desc,"SYS$INPUT"); +readonly $DESCRIPTOR(ter_o_desc,"SYS$OUTPUT"); +struct { + short buflen1; /* buffer length */ + short itmcode1; /* item code */ + charptr buffer1; /* buffer address */ + short *retlen1; /* returned length */ + short buflen2; /* buffer length */ + short itmcode2; /* item code */ + charptr buffer2; /* buffer address */ + short *retlen2; /* returned length */ + short buflen3; /* buffer length */ + short itmcode3; /* item code */ + charptr buffer3; /* buffer address */ + short *retlen3; /* returned length */ + short buflen4; /* buffer length */ + short itmcode4; /* item code */ + charptr buffer4; /* buffer address */ + short *retlen4; /* returned length */ + int termin; /* item list terminator */ +} itmlst = { + 4, /* buffer length */ + DVI$_DEVCLASS, /* device class */ + &devclass, /* buffer address */ + 0, /* no returned length */ + 4, /* buffer length */ + DVI$_DEVDEPEND, /* device dependent data */ + &devdepend, /* buffer address */ + 0, /* no returned length */ + 4, /* buffer length */ + DVI$_DEVDEPEND2, /* device dependent data */ + &devdepend2, /* buffer address */ + 0, /* no returned length */ + 0 /* item list terminator */ +}; +unsigned short output_sys_vfc = 1; +unsigned int rms_status; +unsigned int status; +VVOID CntrlC(void); /* make the compiler happy */ +static VVOID enable_ctrl_c_ast(void) +{ + unsigned int status; + struct tt_mode_iosb_struct mode_iosb; + status = sys$qiow( 0, /* event flag number */ + TCChan, /* channel */ + IO$_SETMODE| + IO$M_CTRLCAST, /* I/O function */ + &mode_iosb, /* I/O status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + CntrlC, /* control-C routine */ + 0, /* p2 */ + 0, /* p3 */ + 0, /* p4 */ + 0, /* p5 */ + 0); /* p6 */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + if (!$VMS_STATUS_SUCCESS(mode_iosb.io_status)) { + lib$stop(mode_iosb.io_status); + } +} +/***************************************************************************** + This function is called whenever a control-C is typed by the user. +It is called asynchronously. +*****************************************************************************/ +static VVOID CntrlC(void) /* control-C AST routine */ +{ + unsigned int status; + 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 */ + } + status = sys$cancel((long)TOChan); /* cancel current output */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + enable_ctrl_c_ast(); /* re-enable the AST */ +} +static VVOID open_terminal_input(void) +{ + struct getxxx_iosb_struct getdvi_iosb; + status = sys$getdviw( 1, /* event flag number */ + 0, /* channel */ + &ter_i_desc, /* device name */ + &itmlst, /* item list */ + &getdvi_iosb, /* i/o status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + 0); /* reserved by DEC */ + if (!$VMS_STATUS_SUCCESS(status)) { + devclass = DC$_MISC; + } else { + if ((!$VMS_STATUS_SUCCESS(getdvi_iosb.io_status)) && + (getdvi_iosb.io_status != SS$_CONCEALED)) { + lib$stop(getdvi_iosb.io_status); + } + } + EtFlag = ET_READ_LOWER; +#if VIDEO + EtFlag |= ET_WAT_SCOPE; +#endif + if (devclass == DC$_TERM) { /* if it's a terminal */ + if (!devdepend.tt$v_lower) { /* if has no lowercase */ + EtFlag &= ~ET_READ_LOWER; /* don't read lowercase */ + } + status = sys$assign( &ter_i_desc, /* device name */ + &TIChan, /* channel */ + 0, /* access mode */ + 0); /* mailbox name */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + return; + } + TIBERc = TIBBeg = ZAlloc((SIZE_T)SOBSIZE); + TIBEnd = (TIBBeg + SOBSIZE) - 1; + TIBPtr = TIBERc; /* causes the initial read */ + TIFab = cc$rms_fab; /* initialize FAB defaults */ + TIFab.fab$b_fac = FAB$M_GET; /* file access = read only */ + TIFab.fab$l_fna = ter_i_desc.dsc$a_pointer; + TIFab.fab$b_fns = ter_i_desc.dsc$w_length; + TIFab.fab$l_fop = FAB$M_INP | /* this is SYS$INPUT and */ + FAB$M_SQO; /* sequential access only */ + rms_status = sys$open(&TIFab); /* open terminal input */ + if (rms_status != RMS$_NORMAL) { + lib$stop(rms_status, TIFab.fab$l_stv); + } + TIRab = cc$rms_rab; /* initialize RAB defaults */ + TIRab.rab$l_fab = &TIFab; /* address of associated FAB */ + TIRab.rab$b_rac = RAB$C_SEQ; /* rec. access = sequential */ + TIRab.rab$l_rop = RAB$M_LOC | /* use locate mode and */ + RAB$M_RAH; /* read ahead */ + TIRab.rab$l_ubf = TIBBeg; /* input buffer */ + TIRab.rab$w_usz = SOBSIZE; /* input buffer size */ + rms_status = sys$connect(&TIRab); /* connect terminal input */ + if (rms_status != RMS$_NORMAL) { + lib$stop(rms_status, TIRab.rab$l_stv); + } +} +static VVOID open_terminal_output(void) +{ + struct getxxx_iosb_struct getdvi_iosb; + struct tt_mode_iosb_struct mode_iosb; + status = sys$getdviw( 1, /* event flag number */ + 0, /* channel */ + &ter_o_desc, /* device name */ + &itmlst, /* item list */ + &getdvi_iosb, /* i/o status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + 0); /* reserved by DEC */ + if (!$VMS_STATUS_SUCCESS(status)) { + devclass = DC$_MISC; + } else if ((!$VMS_STATUS_SUCCESS(getdvi_iosb.io_status)) && + (getdvi_iosb.io_status != SS$_CONCEALED)) { + lib$stop(getdvi_iosb.io_status); + } + if (devclass == DC$_TERM) { /* if it's a terminal */ + if (!devdepend.tt$v_lower) /* if won't show lowercase */ + EuFlag = EU_LOWER; /* set lowercase */ + if (devdepend.tt$v_scope) /* if scope */ + EtFlag |= ET_SCOPE; /* set scope bit */ + if (devdepend.tt$v_eightbit) /* can show 8-bit */ + EtFlag |= ET_EIGHTBIT; + if (devdepend2.tt2$v_deccrt2) { /* VT200 compatible? */ + CrType = VT200; + EtFlag |= ET_VT200; /* VT200 mode */ + EtFlag |= ET_ACCENT_GRAVE; /* VT200 mode */ + } else if (devdepend2.tt2$v_deccrt) /* VT100 compatible? */ + CrType = VT100; + else if (devdepend2.tt2$v_ansicrt) /* ANSI compatible? */ + CrType = VK100; + else /* default is VT52 */ + CrType = VT52; + status = sys$assign( &ter_o_desc, /* device name */ + &TOChan, /* channel */ + 0, /* access mode */ + 0); /* mailbox name */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } +/* + * Get the current terminal characteristics so that later setmodes work. + */ + status = sys$qiow( 0, /* event flag number */ + TOChan, /* channel */ + IO$_SENSEMODE, /* I/O function */ + &mode_iosb, /* I/O status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + &tt_chars, /* p1 */ + 0, /* p2 */ + 0, /* p3 */ + 0, /* p4 */ + 0, /* p5 */ + 0); /* p6 */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + if (!$VMS_STATUS_SUCCESS(mode_iosb.io_status)) { + lib$stop(mode_iosb.io_status); + } +#if VIDEO + HtSize = tt_chars.nbr_columns; /* horizontal size */ + VtSize = tt_chars.lw2.tt$v_page; /* vertical size */ +#endif + return; + } else { /* else not a terminal */ + TOBEnd = &TOBBeg[SOBSIZE]-1; + TOBPtr = &TOBBeg[0]; + TOFab = cc$rms_fab; /* initialize FAB defaults */ + TOFab.fab$b_fac = FAB$M_PUT; /* file access = write only */ + TOFab.fab$l_fna = ter_o_desc.dsc$a_pointer; + TOFab.fab$b_fns = ter_o_desc.dsc$w_length; + TOFab.fab$b_fsz = 2; /* fixed size cntrl area=2 */ + TOFab.fab$b_org = FAB$C_SEQ; /* organization=sequential */ + TOFab.fab$b_rat = FAB$M_PRN; /* print file format */ + TOFab.fab$b_rfm = FAB$C_VFC; /* variable w/fixed control */ + rms_status = sys$create(&TOFab); /* open terminal output */ + if (rms_status != RMS$_NORMAL) { + lib$stop(rms_status, TOFab.fab$l_stv); + } + TORab = cc$rms_rab; /* initialize RAB defaults */ + TORab.rab$l_fab = &TOFab; /* addr of associated FAB */ + TORab.rab$l_rhb = &output_sys_vfc; /* print control buffer */ + TORab.rab$l_rop = RAB$M_WBH; /* write behind */ + TORab.rab$l_rbf = &TOBBeg[0]; /* output buffer */ + rms_status = sys$connect(&TORab); /* connect terminal output */ + if (rms_status != RMS$_NORMAL) { + lib$stop(rms_status, TORab.rab$l_stv); + } + } +} +static VVOID open_terminal_command(void) +{ + struct getxxx_iosb_struct getdvi_iosb; + status = sys$getdviw( 1, /* event flag number */ + 0, /* channel */ + &ter_c_desc, /* device name */ + &itmlst, /* item list */ + &getdvi_iosb, /* i/o status block */ + 0, /* AST routine address */ + 0, /* AST parameter */ + 0); /* reserved by DEC */ + if (!$VMS_STATUS_SUCCESS(status)) { + devclass = DC$_MISC; + } else { + if ((!$VMS_STATUS_SUCCESS(getdvi_iosb.io_status)) && + (getdvi_iosb.io_status != SS$_CONCEALED)) { + lib$stop(getdvi_iosb.io_status); + } + } + if (devclass == DC$_TERM) { /* if terminal */ + status = sys$assign( &ter_c_desc, /* device name */ + &TCChan, /* channel */ + 0, /* access mode */ + 0); /* mailbox name */ + if (!$VMS_STATUS_SUCCESS(status)) { + lib$stop(status); + } + signal(SIGINT,SIG_IGN); /* ignore SIGINT */ + enable_ctrl_c_ast(); /* enable control-C */ + } +} +VVOID ZTrmnl(void) /* set up I/O to the terminal */ +{ + open_terminal_input(); /* open SYS$INPUT */ + open_terminal_output(); /* open SYS$OUTPUT */ + open_terminal_command(); /* open SYS$COMMAND */ +} +/***************************************************************************** + ZVrbos() + This function displays the verbose form of error messages. +*****************************************************************************/ +VVOID ZVrbos(WORD ErrNum, char *ErMnem) +{ + static char HlpStr[12] = " Errors xxx"; + MEMMOVE(&HlpStr[8], ErMnem, (SIZE_T)3); + ZHelp(HlpStr, &HlpStr[10], FALSE, FALSE); +} +/***************************************************************************** + ZWrBfr() + This function writes a buffer to a file, one line at a time. It is +passed an output file index and pointers to the beginning and end of the +buffer to be output. + On output, TECO scans the text buffer for carriage return, line +feed, vertical tab and form feed characters. Each such character delimits +the end of an output record. If the line ends with exactly CR/LF, the CR/LF +are not output with the record, otherwise the record is output in its +entirety. If a record ends with a CR/LF preceded by an ESCAPE, then the +ESCAPE and the CR/LF are output with the record. +*****************************************************************************/ +DEFAULT ZWrBfr( + DEFAULT OfIndx, /* index into OFiles array */ + charptr BfrBeg, /* address of output buffer beginning */ + charptr BfrEnd) /* address of output buffer end */ +{ + charptr BfrPtr = BfrBeg; /* output buffer pointer */ + ptrdiff_t line_len; /* length of current output line */ +#if DEBUGGING + static char *DbgFNm = "ZWrBfr"; + sprintf(DbgSBf,"OfIndx = %d, BfrBeg = %ld, BfrEnd = %ld", + OfIndx, Zcp2ul(BfrBeg), Zcp2ul(BfrEnd)); + DbgFEn(2,DbgFNm,DbgSBf); +#endif + do { /* do for each line */ +/* + * Set BfrBeg to the beginning of the line to be output. Find the end of the + * line, set BfrPtr to the character after it. + */ + BfrBeg = BfrPtr; + while (BfrPtr <= BfrEnd) { + if (*BfrPtr == CRETRN) { + BfrPtr++; + if ((BfrPtr <= BfrEnd) && (*BfrPtr == LINEFD)) { + line_len = BfrPtr - BfrBeg - 1; + BfrPtr ++; + break; + } else { + BfrPtr--; + } + } else if (*BfrPtr == ESCAPE) { + if ((BfrPtr+2 <= BfrEnd) && (*(BfrPtr+1) == CRETRN) && + (*(BfrPtr+2) == LINEFD)) { + BfrPtr += 3; + line_len = BfrPtr - BfrBeg; + break; + } + } else if (IsEOL(*BfrPtr)) { /* LF, VT or FF? */ + BfrPtr++; + line_len = BfrPtr - BfrBeg; + break; + } + ++BfrPtr; + } + OFiles[OfIndx].ORab.rab$l_rbf = BfrBeg; /* buffer */ + OFiles[OfIndx].ORab.rab$w_rsz = line_len; /* size */ +#if DEBUGGING + sprintf(DbgSBf,"calling sys$put, line_len = %d", line_len); + DbgFMs(2,DbgFNm,DbgSBf); +#endif + status = sys$put(&OFiles[OfIndx].ORab); /* output the record */ + if (status != RMS$_NORMAL) { /* if it didn't work */ + ZErMsg(status, OFiles[OfIndx].ORab.rab$l_stv); + ErrMsg(ERR_UWL); + DBGFEX(2,DbgFNm,"FAILURE"); + return FAILURE; + } + } while (BfrPtr <= BfrEnd); + DBGFEX(2,DbgFNm,"SUCCESS"); + return SUCCESS; +}