home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 283 / Shell5SourceCode.sis / sh5_021 (.txt) < prev    next >
Encoding:
EPOC OPL Source  |  1998-08-30  |  113.1 KB  |  5,031 lines

  1.  
  2.  
  3. Rem   Shell5, a command line interpreter for the Psion Series 5 Computer.
  4. Rem   Version 2.0 beta 2, build 21
  5. Rem   Copyright (C) 1998  Nick Murray
  6. Rem
  7. Rem   This program is free software; you can redistribute it and/or
  8. Rem   modify it under the terms of the GNU General Public License
  9. Rem   as published by the Free Software Foundation; either version 2
  10. Rem   of the License, or (at your option) any later version.
  11. Rem
  12. Rem   This program is distributed in the hope that it will be useful,
  13. Rem   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. Rem   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. Rem   See the GNU General Public License for more details.
  16. Rem
  17. Rem   You should have received a copy of the GNU General Public License
  18. Rem   along with this program; if not, write to the Free Software Foundation,
  19. Rem   Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20. Rem
  21. INCLUDE "system.oxh"
  22. INCLUDE "sysram1.oxh"
  23. INCLUDE "toolbar.oph"
  24. INCLUDE "const.oph"
  25. INCLUDE "date.oxh"
  26. CONST _VERSION$="2.0(b2)"
  27. Rem VERY, VERY important. If the order of the offsets below is
  28. Rem    changed the source MUST be checked, as many of these
  29. Rem    values are set simultaneously with POKEW & POKEL's
  30. CONST PR_ARGC%=0
  31. CONST PR_LEV%=1
  32. CONST PR_FLAG%=2
  33. CONST PR_ARGN%=3
  34. CONST PR_OUT%=4
  35. CONST PR_IN%=6
  36. CONST PR_INPST%=8
  37. CONST PR_INPPS%=9
  38. CONST PR_OFFSET%=10
  39. CONST PR_BACK%=11
  40. CONST PR_NUM%=15
  41. CONST PR_STATUS%=17
  42. CONST PR_ARGV%=19
  43. CONST SEG_SIZE%=531
  44. CONST varUNIXPath%=1
  45. CONST varUNIXVar%=2
  46. CONST varAppend%=3
  47. CONST varEcho%=4
  48. CONST varcwdcmd%=5
  49. CONST ShellUID&=&10000C64        Rem also used in edit% so define once
  50. APP Shell5,ShellUID&
  51.     ICON "shell5.mbm"
  52.     CAPTION "Shell5",1
  53. ENDA
  54.  
  55. CONST NBUILTIN%=40
  56.  
  57. PROC main:
  58. GLOBAL ScrWid%                                Rem pixel width initially
  59. GLOBAL ScrHght%                            Rem pixel height initially
  60.     ScrWid%=gWidth
  61.     ScrHght%=gHeight
  62.     LOADM "z:\system\opl\Toolbar"
  63.     TBarLink:("_main")            Rem 'links' toolbar globals and then calls _main
  64. ENDP
  65.  
  66. Rem PROC ALLOC&:(size&,name$)
  67. Rem wrapper for ALLOC such that memory leaks and debugging can be
  68. Rem performed as well as finding where memory leaks are
  69. Rem LOCAL p&
  70. Rem    p&=ALLOC(size&+20+4)
  71. Rem    Rem pointer to next, member number, name$ pointer, length,
  72. Rem    Rem 4-byte-check, ALLOC, 4-byte check
  73. Rem    IF p&=0
  74. Rem NoMem::
  75. Rem        PRINT "OUT OF┬áMEMORY"
  76. Rem        GET
  77. Rem        STOP
  78. Rem    ENDIF
  79. Rem    IF _palloc&=0
  80. Rem        _palloc&=ADDR(_alloc&)
  81. Rem    ENDIF
  82. Rem    POKEL _palloc&,p&
  83. Rem    _palloc&=p&
  84. Rem    POKEL p&,0                            Rem next
  85. Rem    POKEL p&+4,_nalloc&    Rem counter
  86. Rem    POKEL p&+8,ALLOC((LEN(name$)+16) AND $FFF0)
  87. Rem    IF PEEKL(p&+8)=0
  88. Rem        GOTO NoMem::
  89. Rem    ENDIF
  90. Rem    POKE$ PEEKL(p&+8),name$
  91. Rem    POKEL p&+12,size&
  92. Rem    POKEL p&+16,NOT _nalloc&        Rem check for overflows
  93. Rem    POKEL p&+size&+20,NOT _nalloc&        Rem check for overflows
  94. Rem    _talloc&=_talloc&+1
  95. Rem    IF varMemDebug%>1
  96. Rem        PRINT p&,_alloc&,_palloc&,_nalloc&,"Allocated",size&,"bytes, procedure:",name$,"Total:",
  97. Rem    ENDIF
  98. Rem    IF varMemDebug%
  99. Rem        PRINT "[";_talloc&;"]",
  100. Rem        IF varMemDebug%>1
  101. Rem            PRINT
  102. Rem        ENDIF
  103. Rem    ENDIF
  104. Rem    _nalloc&=_nalloc&+1
  105. Rem    RETURN p&+20        Rem start of block that can be used
  106. Rem ENDP
  107.  
  108. Rem PROC FREEALLOC&:(addr&)
  109. Rem wrapper for FREEALLOC. Check elements in _alloc& structure for
  110. Rem one matching addr&
  111. Rem LOCAL p&,q&,n&
  112. Rem    p&=ADDR(_alloc&)
  113. Rem    IF varMemDebug%>1
  114. Rem        PRINT "Checking for",addr&,"in",
  115. Rem    ENDIF
  116. Rem    WHILE PEEKL(p&)
  117. Rem        q&=p&
  118. Rem        p&=PEEKL(p&)
  119. Rem        IF varMemDebug%>1
  120. Rem            PRINT p&,
  121. Rem        ENDIF
  122. Rem        IF p&+20=addr&
  123. Rem            IF varMemDebug%>1
  124. Rem                PRINT "Found it!!!!",PEEKL(p&+4),PEEK$(PEEKL(p&+8)),"Length",PEEKL(p&+12),
  125. Rem            ENDIF
  126. Rem            n&=PEEKL(p&+4)        Rem number
  127. Rem            IF PEEKL(p&+16) <> NOT n&
  128. Rem                PRINT PEEK$(PEEKL(p&+8)),"ERROR: corruption at start"
  129. Rem            ELSEIF PEEKL(p&+20+PEEKL(p&+12)) <> NOT n&
  130. Rem                PRINT PEEK$(PEEKL(p&+8)),"ERROR: corruption at end"
  131. Rem            ENDIF
  132. Rem            FREEALLOC(PEEKL(p&+8))            Rem name$
  133. Rem            POKEL q&,PEEKL(p&)                    Rem patch structure
  134. Rem            IF PEEKL(p&)=0        Rem last
  135. Rem                _palloc&=q&
  136. Rem            ENDIF
  137. Rem            FREEALLOC(p&)                                Rem free rest of struture
  138. Rem            _talloc&=_talloc&-1
  139. Rem            IF varMemDebug%
  140. Rem                PRINT "[";_talloc&;"]",
  141. Rem                IF varMemDebug%>1
  142. Rem                    PRINT
  143. Rem                ENDIF
  144. Rem            ENDIF
  145. Rem            p&=0
  146. Rem            BREAK
  147. Rem        ENDIF
  148. Rem    ENDWH
  149. Rem    IF p&
  150. Rem        PRINT p&,"ERROR: NOT found!!!!"
  151. Rem        GET
  152. Rem    ENDIF
  153. Rem ENDP
  154.  
  155. PROC _main:
  156. REM Continue from toolbar link TBarLink:
  157. GLOBAL _stat%,_key%(2)            Rem for KEYA Esc key...
  158. GLOBAL _spec$(19)
  159. GLOBAL _bltin$(NBUILTIN%,7)
  160. GLOBAL _curr&                    Rem address of current argument block
  161. GLOBAL _pid%                        Rem current subshell counter
  162. GLOBAL _hash&                    Rem base of hashed path list
  163. GLOBAL _dirB&,_dirC&
  164. GLOBAL _atab&
  165. GLOBAL _cwd$(255)
  166. GLOBAL _hpos&,_hnum%,_hsz%,_hrsz%
  167. GLOBAL _cpos&                    Rem this allows set, etc to reset the position in the
  168.                                                 Rem history list for getin$
  169. GLOBAL ScrInfo%(10)
  170. GLOBAL _opts%(5)
  171. GLOBAL _opts$(38)                Rem EXACT max size when all variables are set
  172. Rem GLOBAL varUNIX%,varApp%,varEcho%,varStyl%
  173. GLOBAL _out%                        Rem handle for redirected output
  174. GLOBAL _in%                        Rem handle for redirected/piped input
  175. GLOBAL argv&(128)
  176. GLOBAL _vars&
  177. GLOBAL _keys&                    Rem address of key table (512 bytes)
  178. GLOBAL _syspath$(255)        Rem location of files, e.g. pipes
  179. GLOBAL _here$(64)                Rem flag and string to search for in "here"
  180.                                                 Rem    redirection (<< here$)
  181. GLOBAL _logid%,_logw%,_logh%
  182. GLOBAL _logs&                    Rem base of log entry structure
  183. GLOBAL _logn%                    Rem current "end viewing postion" in the log
  184. GLOBAL _logl%                    Rem current end position in SHlogs%
  185. GLOBAL _extevent%            Rem used to indicate buttons, etc.
  186. GLOBAL _pushc&                Rem current location in pushd table
  187. GLOBAL _help&                    Rem base of linked list of open help files
  188. GLOBAL _sndstat&                Rem sound status word
  189. GLOBAL _style%                    Rem text window current style!!
  190. GLOBAL _act$(13,12)            Rem names of 13 key operations
  191. Rem GLOBAL _alloc&            Rem debug alloc list
  192. Rem GLOBAL _nalloc&        Rem counter for debug alloc
  193. Rem GLOBAL _palloc&        Rem current last element
  194. Rem GLOBAL _talloc&        Rem current number of heap entities
  195. Rem GLOBAL varMemDebug%
  196. LOCAL line$(255),p&,q&
  197. Rem main loop
  198.     ONERR ErrTrap::
  199.     _init:    Rem initialize things...
  200.     DO
  201.         DO
  202.             line$=_getin$:(_mkpr$:(GetVar$:("prompt")))
  203.         UNTIL LEN(line$)
  204.         IF PEEKL(_hpos&+8)        Rem Data part is used so free first
  205.             FREEALLOC(PEEKL(_hpos&+8))
  206. Rem            FREEALLOC&:(PEEKL(_hpos&+8))
  207.         ENDIF
  208.         POKEL _hpos&+8,ALLOC((LEN(line$)+16) AND $FFF0)
  209. Rem        POKEL _hpos&+8,ALLOC&:((LEN(line$)+16) AND $FFF0,"main1")
  210. Rem size = 1 for size of string, 15 to ensure minimum memory is allocated
  211.         IF PEEKL(_hpos&+8)=0
  212.             RAISE -10
  213.         ENDIF
  214.         POKE$ PEEKL(_hpos&+8),line$
  215.         IF _hsz% > _hrsz%
  216.         Rem history is set larger than it currently is, so allocate another member
  217.             p&=_hpos&
  218.             q&=PEEKL(p&)
  219.             POKEL p&,ALLOC(16)        Rem 12, but rounded to 16 to avoid fragmentation
  220. Rem            POKEL p&,ALLOC&:(16,"main2")        Rem 12, but rounded to 16 to avoid fragmentation
  221.             _hpos&=PEEKL(p&)
  222.             IF _hpos&=0
  223.                 RAISE -10
  224.             ENDIF
  225.             POKEL _hpos&,q&        Rem glue 'next'
  226.             POKEL _hpos&+4,p&    Rem glue 'previous'
  227.             POKEL _hpos&+8,0
  228.             POKEL q&+4,_hpos&        Rem glue reference
  229.             _hrsz%=_hrsz%+1
  230.         ELSE
  231.             _hpos&=PEEKL(_hpos&)
  232.         ENDIF
  233.         POKEB _curr&+PR_FLAG%,0        Rem reset exit flag
  234.         _proc%:(line$)
  235.         _hnum%=_hnum%+1
  236.     UNTIL PEEKB(_curr&+PR_FLAG%)        Rem until exit!
  237. Rem    PRINT "Exiting, status",PEEKB(_curr&+PR_FLAG%)
  238.     _exit:            Rem clean up and never return
  239. ErrTrap::
  240.     ONERR off
  241.     PRINT "Fatal:",errx$,err$:(ERR)
  242.     GET
  243. ENDP
  244.  
  245. PROC _store%:(addr&,store%,pa&)
  246. Rem pa& is the proc structure to use, could be globals!
  247. LOCAL v%,e%,out$(255),f%,p&,buf$(255),n%,attr%(8),ret%,oldn%
  248.     f%=PEEKW(addr&)
  249.     out$=PEEK$(addr&+7)
  250. Rem    PRINT f%,out$,pa&
  251.     IF f% AND $40
  252.         f%=f% AND $FFBF    Rem clear var flag
  253.         v%=PEEKW(addr&+2)
  254.         IF v% <> LEN(out$)    Rem ignore a$, $
  255.             buf$=RIGHT$(out$,LEN(out$)-v%)
  256.             out$=LEFT$(out$,v%)
  257.             IF LEN(buf$)=1    Rem $x
  258. Rem                PRINT "One character lookup:",buf$
  259.                 n%=ASC(buf$)
  260.                 p&=PEEKL(pa&+PR_BACK%)    Rem parent args
  261.                 IF n%=%?
  262.                     buf$=NUM$(PEEKW(p&+PR_STATUS%),5)
  263. Rem                    PRINT "Got $?, status, returning",buf$,PEEKW(p&+PR_STATUS%),p&+PR_STATUS%
  264.                     GOTO Floozy::
  265.                 ELSEIF n%=%#
  266.                     Rem parent args-1
  267.                     buf$=NUM$(PEEKB(p&)-PEEKB(p&+PR_OFFSET%)-1,5)
  268. Rem                    PRINT "Got $#, no of args, returning",buf$
  269.                     GOTO Floozy::
  270.                 ELSEIF n%>=%0 AND n%<=%9
  271. Rem                    PRINT "Got $";CHR$(n%)
  272.                     n%=n%-%0    Rem get number 0-9
  273. Rem                    PRINT "n% is:",n%
  274.                     IF n%            Rem 1-9
  275. Rem                        PRINT "$1 to $9"
  276.                         n%=n%+PEEKB(p&+PR_OFFSET%)
  277.                         Rem don't shift in $0 OR have n% > no of args
  278.                         IF n%>=PEEKB(p&)
  279. Rem                            PRINT "Out of range"
  280.                             GOTO DoNowt::
  281.                         ENDIF
  282.                     ENDIF
  283.                     buf$=PEEK$(PEEKL(p&+4*n%+PR_ARGV%))
  284. Rem                PRINT p&,n%,buf$
  285. Floozy::        out$=out$+buf$
  286.                     GOTO DoNowt::
  287.                 ENDIF
  288.             ENDIF
  289.             p&=PEEKL(_vars&)
  290.             WHILE p&
  291.                 IF PEEK$(PEEKL(p&+4))=buf$
  292.                     out$=out$+PEEK$(PEEKL(p&+8))
  293.                     BREAK
  294.                 ENDIF
  295.                 p&=PEEKL(p&)
  296.             ENDWH
  297. DoNowt::
  298.             POKEW addr&+2,0    Rem clear v%
  299.         ENDIF
  300.     ENDIF
  301.     IF (f% AND $81) = $81    Rem ${ completed (} resets flag)
  302.         e%=PEEKW(addr&+4)
  303.         IF e%<>LEN(out$)    Rem ${..} isn't empty
  304.             out$=LEFT$(out$,e%)+GEN$(EVAL(RIGHT$(out$,LEN(out$)-e%)),20)
  305.         ENDIF
  306.         f%=f% AND $FF7E
  307.         POKEW addr&+4,0    Rem clear e%
  308.     ENDIF
  309.     IF store%
  310.         IF f% AND $F00    Rem check for redirection
  311.             IF f% AND $20    Rem operator
  312. Rem                PRINT "Debug: Trying to redirect on an operator"
  313.                 RAISE 10
  314.             ENDIF
  315.             IF f% AND $800    Rem Here doc (<<)
  316.                 _here$=out$
  317.                 IF PEEKB(pa&+PR_LEV%)=%1
  318.                     POKEB pa&+PR_LEV%,%2
  319.                 ELSE
  320.                     POKEB pa&+PR_LEV%,%1
  321.                 ENDIF
  322.                 out$=_syspath$+NUM$(PEEKW(pa&+PR_NUM%),5)+"pipe."+CHR$(PEEKB(pa&+PR_LEV%))
  323. Rem set filename to write "here"
  324. Rem    to and for the command to get it's input from
  325.             ENDIF
  326.             ret%=Fparse%:(ADDR(buf$),out$)    Rem parse filename
  327.             IF ret%<0    AND ret%<>-33
  328.                 RAISE ret%    Rem any error except file doesn't exist
  329.             ENDIF
  330.             IF f% AND $300    Rem either redirect replace or append
  331. Rem check for existing redirection
  332.                 IF PEEKW(pa&+PR_OUT%)
  333.                     GOTO Tidy::    Rem forget it!!!!
  334.                 ENDIF
  335.                 IF (f% AND $200) OR (_opts%(varAppend%))    Rem append, not replace?
  336. Rem Append to file, or append to flag is set
  337.                     ret%=IOOPEN(#pa&+PR_OUT%,buf$,$0123)
  338.                     IF ret%=-33    Rem file doesn't exist
  339. Create::            ret%=IOOPEN(#pa&+PR_OUT%,buf$,$0122)
  340.                     ENDIF
  341.                     IF ret%                Rem file doesn't exist
  342.                         RAISE ret%
  343.                     ENDIF
  344.                 ELSE
  345.                     GOTO Create::
  346.                 ENDIF
  347.             ELSE                    Rem input redirection ($400 or $800)
  348.                 IF PEEKW(pa&+PR_IN%)            Rem check for existing redirection
  349.                     GOTO Tidy::    Rem forget it!!!!
  350.                 ENDIF
  351.                 IF f% AND $400    Rem normal input redirection
  352.                     ret%=$0120
  353.                 ELSE    Rem << redirection
  354.                     ret%=$0322    Rem create, random access for seek
  355.                 ENDIF
  356.                     ret%=IOOPEN(#pa&+PR_IN%,buf$,ret%)
  357.                 IF ret%
  358.                     RAISE ret%
  359.                 ENDIF
  360.             ENDIF
  361. Tidy::    f%=f% AND $F0FF    Rem clear flag
  362.             GOTO Skip::
  363.         ENDIF
  364.         IF f% AND $20    Rem operator
  365.             IF out$=">"
  366.                 f%=f% OR $100
  367.                 GOTO skip::
  368.             ELSEIF out$=">>"
  369.                 f%=f% OR $200
  370.                 GOTO skip::
  371.             ELSEIF out$="<"
  372.                 f%=f% OR $400
  373.                 GOTO skip::
  374.             ELSEIF out$="<<"
  375.                 f%=f% OR $800
  376.                 GOTO skip::
  377.             ENDIF
  378.         ENDIF    Rem not a redirection operator, store it
  379.         n%=PEEKB(pa&)    Rem number of arguments
  380.         IF f% AND $10    Rem wildcard
  381.             parse%:(out$,ADDR(buf$),ADDR(attr%()))
  382.             buf$=DIR$(buf$)
  383.             IF LEN(buf$)=0
  384.                 RAISE 4        Rem flag null wildcard
  385.             ENDIF
  386.             oldn%=n%        Rem store old value of n%
  387.             WHILE LEN(buf$)
  388.                 IF n%>=PEEKB(pa&+PR_ARGN%)
  389.                     RAISE -6    Rem overflow
  390.                 ENDIF
  391.                 p&=pa&+PR_ARGV%+n%*4
  392.                 POKEL p&, ALLOC((LEN(buf$)+16) AND $FFF0)
  393. Rem                POKEL p&, ALLOC&:((LEN(buf$)+16) AND $FFF0,"store1")
  394.                 IF PEEKL(p&)=0    Rem no memory
  395.                     RAISE -10
  396.                 ENDIF
  397.                 n%=n%+1
  398.                 POKE$ PEEKL(p&),PrPath$:(buf$)
  399.                 buf$=DIR$("")
  400.             ENDWH
  401.             IF oldn%=0 AND n%>1    Rem this was the first argument
  402.                                             Rem and there's more than 1 match
  403.                 RAISE 11    Rem not unique so fail it!
  404.             ENDIF
  405.         ELSE    Rem not wildcards
  406.             IF n%>=PEEKB(pa&+PR_ARGN%)
  407.                 RAISE -6    Rem overflow
  408.             ENDIF
  409.             p&=pa&+PR_ARGV%+n%*4
  410.             POKEL p&, ALLOC((LEN(out$)+16) AND $FFF0)
  411. Rem            POKEL p&, ALLOC&:((LEN(out$)+16) AND $FFF0,"store2")
  412. Rem            PRINT "Storing",out$,n%,pa&,"at",p&,PEEKL(p&)
  413.             IF PEEKL(p&)=0    Rem no memory
  414.                 RAISE -10
  415.             ENDIF
  416.             n%=n%+1
  417.             POKE$ PEEKL(p&),out$
  418.         ENDIF
  419.         POKEB pa&,n%    Rem store no. of arguments
  420. Skip::
  421.         f%=f% AND $FFC7    Rem clear wild,store and special flag
  422.         out$=""
  423.     ENDIF
  424.     POKEW(addr&),f%
  425.     POKE$ addr&+7,out$
  426. ENDP
  427.  
  428. PROC fprint%:(p$)
  429. LOCAL ret%,buf$(255)
  430.     IF _out%
  431.         buf$=p$+CHR$(13)            Rem for 0x0D 0x0A
  432.         ret%=IOWRITE(_out%,ADDR(buf$)+1,LEN(buf$))
  433.         IF ret%
  434.             RAISE ret%    Rem any error here MUST be fatal
  435.         ENDIF
  436.     ELSE
  437.         PRINT p$
  438.     ENDIF
  439. ENDP
  440.  
  441. PROC _clrA:(pa&)    Rem close redirection file and unallocate arg. heap
  442. LOCAL i%
  443.     IF PEEKW(pa&+PR_OUT%)
  444.         IOCLOSE(PEEKW(pa&+PR_OUT%))
  445.         POKEW(pa&+PR_OUT%),0
  446.     ENDIF
  447.     IF PEEKW(pa&+PR_IN%)
  448.         IOCLOSE(PEEKW(pa&+PR_IN%))
  449.         POKEW(pa&+PR_IN%),0
  450.     ENDIF
  451.     i%=PEEKB(pa&)*4    Rem number of stored arguments
  452.     WHILE i%
  453.         i%=i%-4
  454. Rem        PRINT "Freeing:",pa&+PR_ARGV%+i%,PEEKL(pa&+PR_ARGV%+i%),PEEK$(PEEKL(pa&+PR_ARGV%+i%))
  455.         FREEALLOC PEEKL(pa&+PR_ARGV%+i%)
  456. Rem        FREEALLOC&:(PEEKL(pa&+PR_ARGV%+i%))
  457.     ENDWH
  458.     POKEB pa&,0    Rem set no arguments
  459. ENDP
  460.  
  461. PROC _inpar%:(in$,pa&,spec$)
  462. REM parse the input, creating the argv& structure and return thr
  463. REM number of arguments in n%
  464. LOCAL i%,len%,c$(1),p%,ret%,handle%
  465. LOCAL flag%,varpos%,evalpos%,out$(255)    Rem KEEP THESE TOGETHER
  466. Rem flag%:
  467. Rem Bit 0 - set if we're in a $(...)
  468. Rem Bit 1 - set if we're in a '...'
  469. Rem Bit 2 - set if we're in a "..."
  470. Rem Bit 3 - set if we're storing something
  471. Rem Bit 4 - set if we have a wildcard
  472. Rem Bit 5 - set if we're storing an operator
  473. Rem Bit 6 - set if we're in a variable
  474. Rem Bit 7 - set when ${..} terminates
  475. Rem Bit 8 - set if output redirection
  476. Rem Bit 9 - set if output redirection + appending
  477. Rem Bit 10 - set if input redirection
  478. Rem Bit 11 - set if here document, ie. <<
  479.     POKEB pa&+PR_OFFSET%,0            Rem initialize shift offset
  480.     len%=LEN(in$)
  481.     WHILE i%<len%
  482.         i%=i%+1
  483.         c$=MID$(in$,i%,1)
  484.         p%=LOC(spec$,c$)
  485. Rem        PRINT c$,p%,flag%
  486.         VECTOR p%
  487.             Spc,Dbl,Sgl,Wld,Wld,OpB,ClB,Spl,Spl,Spl,Op,Op,Op,Com,Semi,Pipe,Spl,Vbl
  488.         ENDV
  489.         GOTO Nullp    Rem no-op
  490. Spc::    Rem space
  491.         IF (flag% AND $E) = 8    Rem store, not in quotes
  492.             IF flag% AND $1
  493.                 IF flag% AND $40        Rem ${..$var..}
  494.                     _store%:(ADDR(flag%),0,pa&)
  495.                 Rem COULD put an ELSE out$=out$+c$
  496.                 ENDIF
  497.             ELSE    Rem normal variable or word
  498.                 _store%:(ADDR(flag%),1,pa&)
  499.             ENDIF
  500.         ELSEIF flag% AND 6    Rem any quote, 7 to save spaces in ${}
  501.             out$=out$+c$
  502.         ENDIF
  503.         CONTINUE
  504. Vbl::    Rem $ (OR %)
  505.         IF (flag% AND 6)=0    Rem not in ' or "
  506.             IF (flag% AND $40)    Rem already storing
  507.                 _store%:(ADDR(flag%),0,pa&)
  508.             ELSE
  509.                 IF (flag% AND $21)=$20    Rem was a special, not in ${}
  510.                     _store%:(ADDR(flag%),1,pa&)
  511.                 ENDIF
  512.                 varpos%=LEN(out$)
  513.                 flag%=flag% OR $48
  514.             ENDIF
  515.             CONTINUE
  516.         ENDIF
  517.         GOTO Nullp::
  518. Dbl::    IF flag% AND $02        Rem ", check for '
  519.             out$=out$+c$        Rem just store it normally            
  520.         ELSEIF flag% AND $04    Rem Already "?
  521.             flag%=flag% AND $FFFB
  522.         ELSE
  523.             IF flag% AND $40    Rem were storing a variable
  524.                 _store%:(ADDR(flag%),0,pa&)
  525.             ELSEIF flag% AND $20    Rem operator
  526.                 _store%:(ADDR(flag%),1,pa&)
  527.             ENDIF
  528.             flag%=flag% OR $0C
  529.         ENDIF
  530.         CONTINUE
  531. Sgl::    IF flag% AND $04    REM "
  532.             out$=out$+c$    Rem just store it normally            
  533.         ELSEIF flag% AND $02    Rem Already '?
  534.             flag%=flag% AND $FFFD
  535.         ELSE
  536.             IF flag% AND $40    Rem were storing a variable
  537.                 _store%:(ADDR(flag%),0,pa&)
  538.             ELSEIF flag% AND $20    Rem operator
  539.                 _store%:(ADDR(flag%),1,pa&)
  540.             ENDIF
  541.             flag%=flag% OR $0A
  542.         ENDIF
  543.         CONTINUE
  544. Wld::
  545.         IF flag% AND $1    Rem ${..} so not a wildcard but a special
  546.             GOTO spl::
  547.         ELSEIF (flag% AND $46) = 0    Rem not quoted OR a variable
  548.             flag%=flag% OR $10    Rem flag wildcard
  549.         ENDIF
  550.         Rem fall through to normal processing
  551.         GOTO Nullp::
  552. OpB::
  553.         IF (flag% AND $6)=0    Rem not quoted
  554.             IF LEN(out$)=varpos% AND (flag% AND $40)
  555.                 Rem Found ${
  556.                 IF flag% AND 1    Rem already storing a ${..}
  557.                     RAISE 8
  558.                 ENDIF
  559.                 flag%=flag% AND $FFBF OR $1
  560. Rem                varpos%=0    Rem necessary?
  561.                 evalpos%=LEN(out$)
  562.                 CONTINUE
  563.             ENDIF
  564.         ENDIF
  565.         GOTO Nullp::    Rem NOT ${ or already in one or quoted
  566. ClB::    IF (flag% AND $7)=1    Rem In ${..}, NOT quoted
  567. Rem    IF (flag% AND $6)=0    Rem NOT quoted
  568. Rem            IF flag% AND $1
  569.                 flag%=flag% OR $80            Rem flag store evaluate
  570.                 _store%:(ADDR(flag%),0,pa&)
  571.                 flag%=flag% AND $FFFE        Rem clear ${..}
  572.                 CONTINUE
  573. Rem            ENDIF
  574.         ENDIF
  575.         GOTO Nullp::
  576. Spl::    IF (flag% AND $26)=0    Rem not in the middle of one
  577.             IF flag% AND 1    Rem in ${..}
  578.                 IF flag% AND $40    Rem variable store in ${..}
  579.                     _store%:(ADDR(flag%),0,pa&)
  580.                 ENDIF
  581.             ELSE
  582.                 IF flag% AND 8    Rem normal store
  583.                     _store%:(ADDR(flag%),1,pa&)
  584.                 ENDIF
  585.                 flag%=flag% OR $28    Rem flag special & store
  586.             ENDIF
  587.         ENDIF
  588.         out$=out$+c$    Rem store it...
  589.         CONTINUE
  590. Semi::    Rem semi-colon
  591.         IF flag% AND $7    Rem only allow semi-colon out of ',",${..}
  592.             GOTO Nullp
  593.         ELSE
  594.             POKEB pa&+PR_INPST%,1    Rem flag multi-commands per line
  595.             POKEB pa&+PR_INPPS%,i%    Rem mark current position
  596.             BREAK
  597.         ENDIF
  598. Pipe::    Rem pipe
  599.         IF flag% AND $7    Rem only allow pipes out of ',",${..}
  600.             GOTO Nullp
  601.         ELSE
  602.             POKEB pa&+PR_INPST%,2    Rem flag pipe per line
  603.             Rem ALWAYS create _syspath$\pipe.x
  604.             Rem    - why??? - so that the next command in the pipe
  605.             Rem    has something to open!!
  606.             IF PEEKB(pa&+PR_LEV%)=%1
  607.                 POKEB pa&+PR_LEV%,%2
  608.             ELSE
  609.                 POKEB pa&+PR_LEV%,%1
  610.             ENDIF
  611. Rem            PRINT _syspath$+NUM$(PEEKW(pa&+PR_NUM%),5)+"pipe."+CHR$(PEEKB(pa&+PR_LEV%))
  612.             ret%=IOOPEN(handle%,_syspath$+NUM$(PEEKW(pa&+PR_NUM%),5)+"pipe."+CHR$(PEEKB(pa&+PR_LEV%)),$0122)
  613.             IF ret%
  614.                 RAISE ret%
  615.             ENDIF
  616.             IF PEEKW(pa&+PR_OUT%) OR (flag% AND $300)
  617. Rem Already redirected or in the middle of one
  618.                 IOCLOSE(handle%)
  619.             ELSE
  620.                 POKEW pa&+PR_OUT%,handle%
  621.             ENDIF
  622.             POKEB pa&+PR_INPPS%,i%    Rem mark current position
  623.             BREAK
  624.         ENDIF
  625. Com::    Rem comment char #, valid at start of token
  626.         IF flag%    Rem only allow comments if in white space
  627.             GOTO Nullp
  628.         ELSE
  629.             BREAK
  630.         ENDIF
  631. Op::    Rem +,- or /, only treat as special within ${..}
  632.         IF flag% AND 1
  633.             GOTO spl::
  634.         ENDIF
  635.         Rem drop through
  636. NullP::
  637.         IF (flag% AND $6F) = 0    Rem no flags set
  638.             flag%=flag% OR $8        Rem start the store
  639.         ELSEIF (flag% AND $21)=$20    Rem were in <>= but NOT ${..}
  640.             _store%:(ADDR(flag%),1,pa&)
  641.             flag%=flag%  OR $8    Rem start the store
  642.         ENDIF
  643.         out$=out$+c$    Rem store it...
  644.     ENDWH
  645.     IF (flag% AND $F08F)=8    Rem ignore wildycards, <>= and variables
  646.         _store%:(ADDR(flag%),1,pa&)
  647.     ELSEIF flag% AND $FFEF    Rem fail for ' " and ${..}
  648.         IF flag% AND $1
  649.             RAISE 8
  650.         ELSEIF flag% AND $2
  651.             RAISE 7
  652.         ELSEIF flag% AND $4
  653.             RAISE -70
  654.         ENDIF
  655.     ENDIF
  656.     IF flag% AND $800    Rem any of the redirection flags bits 8-10
  657. Rem        PRINT "Debug: redirection isn't complete and we're finished"
  658.         RAISE 10
  659.     ENDIF
  660.     RETURN PEEKB(pa&)    Rem return number of arguments
  661. ENDP
  662.  
  663. PROC _subpr%:(pa&)
  664. Rem From the data in argv%, find output redirection, and
  665. Rem process according to argv&(1)
  666. LOCAL i%,ret%,narg%
  667. LOCAL buf$(255)
  668.     narg%=PEEKB(pa&)
  669.     IF narg%    Rem may be 0 after redirection
  670.         Rem copy pa& to argv&!!!
  671.         i%=PEEKB(pa&)*4        Rem number of items to copy
  672.         WHILE i%
  673.             i%=i%-4
  674. Rem            PRINT "Copying",i%,PEEK$(PEEKL(pa&+i%+PR_ARGV%))
  675.             POKEL ADDR(argv&())+i%,PEEKL(pa&+i%+PR_ARGV%)
  676.         ENDWH
  677.         _in%=PEEKW(pa&+PR_IN%)
  678.         _out%=PEEKW(pa&+PR_OUT%)
  679.         i%=NBUILTIN%
  680.         buf$=LOWER$(PEEK$(PEEKL(pa&+PR_ARGV%)))    Rem 1st arg
  681.         WHILE i%
  682.             IF _bltin$(i%)=buf$
  683.                 BREAK
  684.             ENDIF
  685.             i%=i%-1
  686.         ENDWH
  687.         IF i%
  688.             ret%=@%(_bltin$(i%)):(narg%)
  689.         ELSE    Rem check buf$ in path, absolute file, OPO, OPA, BAT
  690.             ret%=_chkp%:(buf$,narg%)    Rem or directory
  691.         ENDIF
  692.     ENDIF
  693.     RETURN ret%
  694. ENDP
  695.  
  696. PROC _chkp%:(in$,n%)
  697. LOCAL buf$(255),attr%(8),ret%,i%,ext$(255),load%,pid%,buf2$(255),k&
  698. LOCAL arg$(255),m%,code%,h%,Uid2&,p&,mode%
  699.     ONERR ErrTrap::
  700.     IF _opts%(varUNIXpath%)
  701.         i%=LOC(in$,"/")
  702.     ELSE
  703.         i%=LOC(in$,"\")
  704.     ENDIF
  705.     IF i% OR LOC(in$,":")    Rem absolute pathname (: or filename separator)
  706. Rem        PRINT "Searching for an absolute path",buf$
  707.         ret%=parse%:(in$,ADDR(buf$),ADDR(attr%()))
  708.         IF ret%<0
  709.             RAISE ret%
  710.         ENDIF
  711.         ret%=stat%:(ADDR(buf$))        Rem REALLY┬ácheck if it exists
  712.         IF LEN(buf$)>attr%(5)    Rem extension
  713.             IF ret%>=0    Rem file/directory exists
  714.                 IF (ret% AND 16)=0            Rem a files
  715.                     ext$=LOWER$(RIGHT$(buf$,LEN(buf$)-attr%(5)))
  716.                     IF ext$<>"opo" AND ext$<>"bat" AND ext$<>"app"
  717. Rem                        PRINT "Bad extension"
  718.                         GOTO NotFnd::
  719.                     ELSE
  720. Rem                        PRINT "Running",buf$,"extension",ext$
  721.                         GOTO Run::
  722.                     ENDIF
  723.                 ELSE
  724. Rem                    buf$=buf$+"\"
  725.                     GOTO Direct::
  726.                 ENDIF
  727.             ELSE
  728.                 GOTO NotFnd::
  729.             ENDIF
  730.         ELSE
  731. Rem    No extension
  732. Rem ignore a file of the correct name without an extension
  733. Rem because without an extension we don't know it's type...
  734. Rem            PRINT "No extension"
  735.             IF (ret%>=0) AND  ((ret% AND 16)=16)
  736.                 i%=1    Rem flag it's a directory
  737.             ELSE
  738.                 i%=0
  739.             ENDIF
  740.             arg$="bat,opo,app,"
  741.             WHILE LEN(arg$)
  742.                 m%=LOC(arg$,",")
  743.                 buf2$=buf$+"."+LEFT$(arg$,m%-1)
  744.                 ret%=stat%:(ADDR(buf2$))
  745.                 IF (ret%>=0) AND ((ret% AND 16)=0)    Rem File
  746.                     buf$=buf2$
  747.                     GOTO Run::
  748.                 ENDIF
  749.                 arg$=RIGHT$(arg$,LEN(arg$)-m%)
  750.             ENDWH
  751.             IF i%    Rem it's a directory
  752.                 GOTO Direct::
  753.             ELSE
  754.                 GOTO NotFnd::
  755.             ENDIF
  756.         ENDIF
  757.     ELSE
  758. Rem currently in$ is lower case - use UPPER$(in$) to change
  759. Rem        PRINT "Should look",in$,"in hash table here"
  760.         buf$=_hshf$:(in$)    Rem look for in$ in the hash table
  761.     ENDIF
  762.     IF LEN(buf$)
  763.         GOTO Run::
  764.     ENDIF
  765.     ret%=Fparse%:(ADDR(buf$),in$)
  766.     IF (ret%>=0) AND ((ret% AND 16)=16)    Rem directory
  767.         GOTO Direct::
  768.     ELSE
  769.         GOTO NotFnd::
  770.     ENDIF
  771.     RETURN
  772. Direct::
  773.     _cd%:(buf$)
  774.     RETURN
  775. Run::
  776.     ext$=LOWER$(RIGHT$(buf$,3))
  777. Rem    PRINT "Want to run",buf$
  778.     IF ext$="opo"
  779.         LOADM buf$
  780. Rem necessary to get the attr% information to extract the command
  781. Rem name == the procedure name
  782.         ret%=parse%:(buf$,ADDR(buf$),ADDR(attr%()))
  783.         ONERR LoadErr::    Rem special trap handler that will goto RunOpp if
  784. Rem the .OPO file doesn't look like a shell 3a module - procedure NOT
  785. Rem found (-99) or Wrong number of arguments (-97)
  786.         load%=1
  787. Rem execute the command
  788.         code%=@%(MID$(buf$,attr%(4),attr%(5)-attr%(4))):(n%)
  789.         load%=0
  790.         ONERR ErrTrap::    Rem return to normal error trapping
  791.         UNLOADM buf$
  792.     ELSEIF ext$="bat"
  793.         IF _in% OR _out%     Rem in a pipe or input/output redirection
  794.             RAISE 5
  795.         ENDIF
  796.         code%=_run%:(buf$)
  797.     ELSEIF ext$="app"        Rem check whether it's an OPL application
  798. Rem buf$ contains the full pathname, it exists and is a file
  799.         ret%=IOOPEN(h%,buf$,$0400)            Rem open existing file
  800.         IF ret%
  801.             RAISE ret%
  802.         ENDIF
  803.         p&=ADDR(buf2$)
  804.         ret%=IOREAD(h%,p&+1,16)                    Rem read first 16 bytes
  805.         IOCLOSE(h%)
  806.         IF ret%<0                    Rem this includes short reads...
  807.             IF ret%=-36            Rem EOF
  808.                 GOTO BadApp::
  809.             ENDIF
  810.             RAISE ret%
  811.         ELSE
  812.             POKEB p&,16                Rem length of string
  813.             Uid2&=PEEKL(p&+5)    Rem the Uid we're actually interested in
  814.             IF buf2$<>CheckUid$:(PEEKL(p&+1),Uid2&,PEEKL(p&+9))
  815. BadApp::
  816.                 PRINT "Not a valid application"
  817.                 GOTO End::
  818.             ENDIF
  819.         ENDIF
  820. Rem check if we've more arguments and whether files specified exist
  821. Rem An enhancement would be to check do type vs. application type
  822. Rem  but for the moment we'll keep it simple.
  823.         mode%=2                Rem default to "run"
  824.         IF n%>1                    Rem arguments to program
  825.             ret%=Fparse%:(ADDR(buf2$),PEEK$(argv&(2)))
  826.             IF ret%<0
  827.                 IF ret%=-33                Rem file doesn't exist
  828.                     mode%=1                Rem create
  829.                 ELSE
  830.                     RAISE ret%
  831.                 ENDIF
  832.             ELSEIF ret%
  833.                 RAISE -7
  834.             ELSE
  835.                 mode%=0                    Rem file exists
  836.             ENDIF
  837.         ENDIF
  838.         IF Uid2&=KUidOplApp&
  839. Rem            PRINT "Running as OPL"
  840.             GOTO RunOPL::
  841.         ELSE
  842. Rem            PRINT "Running as stand-alone",buf$,buf2$,mode%
  843.             RunApp&:(buf$,buf2$,"",mode%)
  844.         ENDIF
  845.     ENDIF
  846.     GOTO End::
  847. LoadErr::                                            Rem error on running LOADM'd module
  848.     ONERR off
  849.     IF load%                        Rem error during execution - MUST unload module
  850.         UNLOADM buf$
  851.         load%=0
  852.     ENDIF
  853.     IF ERR=-97 OR ERR=-99    Rem .opo wasn't a shell3a module - exec instead
  854. Rem        PRINT "DEBUG,Module not for Shell5, executing as normal .OPO module"
  855.         ONERR ErrTrap::
  856.         buf2$=""        Rem arguments
  857.         mode%=2    Rem run mode in "run", ie. no arguments
  858. RunOPL::
  859.         code%=RUNAPP&:("OPL",buf2$,"R"+buf$,mode%)
  860.     ELSE
  861.         GOTO ErrTrap::    Rem otherwise some other OPO error
  862.     ENDIF
  863. End::
  864.     RETURN code%
  865. NotFnd::
  866.     PRINT "Command not found"
  867.     RETURN            Rem nothing has been run, so no error!??
  868. ErrTrap::
  869.     ONERR off
  870.     PRINT err$:(ERR)
  871.     RETURN ERR            Rem is this correct??
  872. ENDP
  873.  
  874. PROC _hshf$:(in$)
  875. Rem The input MUST be     (with/out) an extension
  876. Rem Outputs an empty string or the found/stored pathname
  877. LOCAL ret%,p&,q&,buf$(255),ext$(255),res$(255),f%
  878.     ret%=LOC(in$,".")    Rem look for extension
  879.     IF ret%    Rem one exists
  880.         ext$=LOWER$(RIGHT$(in$,LEN(in$)-ret%))
  881.         IF ext$<>"opo" AND ext$<>"bat" AND ext$<>"app"
  882. Rem            PRINT "Bad extension"
  883.             RETURN
  884.         ENDIF
  885.         buf$=LEFT$(in$,ret%-1)
  886.         f%=1    Rem flag that we've a supplied extension
  887.     ELSE
  888.         buf$=in$
  889.         ext$="bat,opo,app"
  890.     ENDIF
  891. Rem    PRINT "Looking for",buf$
  892.     Rem buf$ is in$ without the extension
  893.     p&=_hash&
  894.     WHILE PEEKL(p&)
  895.         q&=p&    Rem previous item
  896.         p&=PEEKL(p&)
  897. Rem always do the checks in lower case
  898.         res$=LOWER$(PEEK$(p&+4))
  899.         IF f%    Rem SUPPLIED extension
  900.             IF res$=in$
  901.                 GOTO Found::
  902.             ENDIF
  903.         ELSE    Rem ANY extension
  904.             IF buf$=LEFT$(res$,LEN(res$)-4)
  905. Found::    Rem MUST preserve buf$ - path uses it later
  906.                 res$=PEEK$(p&+LEN(res$)+5)
  907.                 ret%=Fparse%:(ADDR(res$),res$)
  908.                 Rem check if the hashed file exists
  909.                 IF (ret%>=0) AND ((ret% AND 16)=0)    Rem file
  910. Rem                    PRINT "Found",res$
  911.                     RETURN res$
  912.                 ELSE    Rem not a file so remove from the hash table
  913.                     POKEL q&,PEEKL(p&)
  914.                     FREEALLOC(p&)
  915. Rem                    FREEALLOC&:(p&)
  916.                     p&=q&    Rem set current record=last
  917.                 ENDIF
  918.             ENDIF
  919.         ENDIF
  920.     ENDWH
  921.     Rem not in the hash table
  922.     res$=_path$:(GetVar$:("path"),buf$,ext$)
  923.     IF LEN(res$)    Rem found
  924. Rem        PRINT "Storing:",buf$;".";RIGHT$(res$,3),"as",res$
  925.         Rem add to PATH, p% already is the last HASH element
  926.         Rem pointer(4), name, extension (4), +1, path +1,+16
  927.         POKEL p&,ALLOC((LEN(buf$)+LEN(res$)+26) AND $FFF0)
  928. Rem        POKEL p&,ALLOC&:((LEN(buf$)+LEN(res$)+26) AND $FFF0,"hshf1")
  929.         p&=PEEKL(p&)
  930.         IF p&=0
  931.             RAISE -10
  932.         ENDIF
  933.         POKEL p&,0
  934.         POKE$ p&+4,buf$+RIGHT$(res$,4)
  935.         POKE$ p&+LEN(buf$)+9,res$
  936.         RETURN res$
  937.     ENDIF
  938. ENDP
  939.  
  940. PROC _path$:(path$,file$,ext$)
  941. Rem path$ is the path to search in
  942. Rem file$ is the filename to search for
  943. Rem ext$ is a , separated list of extensions to look for
  944. Rem  and it returns the first occurance or ""
  945. LOCAL p$(255),n%,m%,ep$(255),ret%,buf$(255),buf2$(255)    Rem ,attr%(8)
  946. Rem    PRINT "Searching for",file$,"in",path$,"with extensions",ext$
  947.     p$=path$+","    Rem ensure a terminating ,
  948.     WHILE LEN(p$)
  949.         n%=LOC(p$,",")
  950. Rem        ret%=parse%:(LEFT$(p$,n%-1),ADDR(buf$),ADDR(attr%()))
  951. Rem        IF ret%<0
  952. Rem            GOTO Bad::    Rem bad component
  953. Rem        ENDIF
  954. Rem        ret%=stat%:(ADDR(buf$))
  955.         ret%=Fparse%:(ADDR(buf$),LEFT$(p$,n%-1))
  956.         IF (ret%<0) OR ((ret% AND 16)=0)    Rem Not directory
  957. Rem Bad::
  958. Rem    IF file$<>"autoexec"    Rem don't flag path errors for this
  959.             _log:(3,"Bad path component:  "+LEFT$(p$,n%-1))
  960. Rem                PRINT "Bad path component:  "+LEFT$(p$,n%-1)
  961. Rem            ENDIF
  962.         ELSE
  963.             buf$=buf$+file$+"."
  964.             ep$=ext$+","    Rem ensure terminating ,
  965.             WHILE LEN(ep$)
  966.                 m%=LOC(ep$,",")
  967.                 buf2$=buf$+LEFT$(ep$,m%-1)
  968.                 ret%=stat%:(ADDR(buf2$))
  969.                 IF (ret%>=0) AND ((ret% AND 16)=0)    Rem Not directory
  970.                     RETURN buf2$
  971.                 ENDIF
  972.                 ep$=RIGHT$(ep$,LEN(ep$)-m%)
  973.             ENDWH
  974.         ENDIF
  975.         p$=RIGHT$(p$,LEN(p$)-n%)
  976.     ENDWH
  977.     RETURN
  978. ENDP
  979.  
  980. PROC PrPath$:(p$)
  981. LOCAL q$(255),i%
  982.     q$=p$
  983.     IF _opts%(varUNIXpath%)
  984.         DO
  985.             i%=LOC(q$,"\")
  986.             IF i%=0
  987.                 BREAK
  988.             ENDIF
  989.             q$=LEFT$(q$,i%-1)+"/"+RIGHT$(q$,LEN(q$)-i%)    
  990.         UNTIL 0
  991.     ENDIF
  992.     RETURN q$
  993. ENDP
  994.  
  995. PROC parse%:(i$,retstr&,addr&)
  996. LOCAL out$(255),store$(255),c$(1)
  997. LOCAL len%,p&,i%,off%,in$(255)
  998.     ONERR ErrTrap::
  999.     in$=i$
  1000.     IF _opts%(varUNIXpath%)
  1001.         DO
  1002.             i%=LOC(in$,"/")
  1003.             IF i%=0
  1004.                 BREAK
  1005.             ENDIF
  1006.             in$=LEFT$(in$,i%-1)+"\"+RIGHT$(in$,LEN(in$)-i%)
  1007.         UNTIL 0
  1008.     ENDIF
  1009.     len%=LEN(in$)    Rem length of input to be parsed
  1010.     off%=1                    Rem offset within input
  1011.     p&=PEEKL(_dirB&)
  1012.     IF len%>1            Rem COULD┬ábe x:
  1013.         IF MID$(in$,2,1)=":"
  1014.             len%=len%-2
  1015.             off%=off%+2
  1016. Rem check if this device exists
  1017.             WHILE p&
  1018.                 IF LEFT$(PEEK$(p&+4),2)=UPPER$(LEFT$(in$,2))        Rem compare device parts
  1019.                     out$=LEFT$(PEEK$(p&+4),2)        Rem store this part
  1020.                     GOTO Found::
  1021.                 ENDIF
  1022.                 p&=PEEKL(p&)
  1023.             ENDWH
  1024.             RAISE -41    Rem no such device
  1025.         ENDIF
  1026.     ENDIF
  1027. Rem We haven't a supplied node, so get the node from the curr dir.
  1028.     out$=LEFT$(PEEK$(_dirC&+4),2)
  1029.     p&=_dirC&
  1030. Found::
  1031. Rem    PRINT "Current:",out$,"Left to process:",MID$(in$,off%,len%)
  1032. Rem    PRINT "Current device:",PEEK$(p&+4)
  1033.     IF MID$(in$,off%,1)="\"    Rem absolute pathname
  1034.         out$=out$+"\"
  1035.         len%=len%-1
  1036.         off%=off%+1
  1037.     ELSE    Rem Relative path, so take it directly
  1038.         out$=PEEK$(p&+4)
  1039.     ENDIF
  1040.     DO
  1041.         IF len%=0
  1042.             GOTO PrcSeq::
  1043.         ENDIF
  1044.         c$=MID$(in$,off%,1)
  1045.         IF ASC(c$)=%\
  1046. PrcSeq::
  1047.             IF store$=".."
  1048.                 i%=LEN(out$)
  1049.                 WHILE i%>3        Rem after the first \
  1050.                     i%=i%-1
  1051.                     IF ASC(MID$(out$,i%,1))=%\
  1052.                         BREAK
  1053.                     ENDIF
  1054.                 ENDWH
  1055.                 out$=LEFT$(out$,i%)
  1056.             ELSEIF store$<>"." AND LEN(store$)
  1057.                 out$=out$+store$+"\"
  1058.             ENDIF
  1059.             store$=""
  1060.         ELSE
  1061.             store$=store$+c$
  1062.         ENDIF
  1063.         off%=off%+1: len%=len%-1
  1064.     UNTIL len%<0
  1065. Rem strip off trailing \
  1066.     IF ASC(RIGHT$(out$,1))=%\ AND LEN(out$)>3        Rem AND ASC(RIGHT$(in$,1))<>%\
  1067.         out$=LEFT$(out$,LEN(out$)-1)
  1068.     ENDIF
  1069. Rem    PRINT "Current:",out$        Rem ,"Left to process:",MID$(in$,off%,len%)
  1070.     out$=parse$("",out$,#addr&)
  1071.     POKEL addr&+12,p&        Rem store address of device in _bdev&
  1072.     POKE$ retstr&,out$
  1073.     RETURN
  1074. ErrTrap::
  1075.     ONERR off
  1076.     RETURN ERR
  1077. ENDP
  1078.  
  1079. PROC _getin$:(pr$)
  1080. REM Get the user's next line of input
  1081. LOCAL i$(248),ret%,i%
  1082.     _cpos&=_hpos&
  1083.     DO
  1084.         ret%=_edit%:(ADDR(i$),248,pr$)
  1085.         IF _cpos&=_hpos& AND ret%<>3    Rem 3=enter
  1086.             Rem if we are editing 'our' line store it
  1087.             IF PEEKL(_cpos&+8)
  1088.                 FREEALLOC(PEEKL(_cpos&+8))
  1089. Rem                FREEALLOC&:(PEEKL(_cpos&+8))
  1090.             ENDIF
  1091.             POKEL _cpos&+8,ALLOC((LEN(i$)+16) AND $FFF0)
  1092. Rem            POKEL _cpos&+8,ALLOC&:((LEN(i$)+16) AND $FFF0,"getin1")
  1093.             IF PEEKL(_cpos&+8)=0
  1094.                 RAISE -10
  1095.             ENDIF
  1096.             POKE$ PEEKL(_cpos&+8),i$
  1097.         ENDIF
  1098.         IF ret%=10                    Rem Pagedown
  1099.             IF _logid%
  1100.                 _log:(6,"")
  1101.             ELSE
  1102.                 _cpos&=_hpos&
  1103.                 GOTO Here
  1104.             ENDIF
  1105.         ELSEIF ret%=9            Rem Pageup
  1106.             IF _logid%
  1107.                 _log:(5,"")
  1108.             ELSE
  1109.                 _cpos&=PEEKL(_hpos&)
  1110.                 GOTO Here
  1111.             ENDIF
  1112.         ELSEIF ret%=5    Rem up
  1113.             IF PEEKL(_cpos&+4)=_hpos&
  1114.                 PRINT CHR$(7);
  1115.             ELSE
  1116. Rem                PRINT
  1117.                 _cpos&=PEEKL(_cpos&+4)        Rem previous
  1118.                 GOTO Here
  1119.             ENDIF
  1120.         ELSEIF ret%=6                Rem down
  1121.             IF _cpos&=_hpos&
  1122.                 PRINT CHR$(7);
  1123.             ELSE
  1124. Rem                PRINT
  1125.                 _cpos&=PEEKL(_cpos&)    Rem next
  1126. Here::        i$=PEEK$(PEEKL(_cpos&+8))
  1127.             ENDIF
  1128.         ENDIF
  1129.     UNTIL ret%=3    Rem Enter
  1130.     PRINT
  1131.     RETURN i$
  1132. ENDP
  1133.  
  1134. PROC _edit%:(addr&,max%,pr$)
  1135. LOCAL i$(255),c%,wx%,off%,k$(255),oldc%,event&(16),ev&
  1136. LOCAL y%,xmin%,width%,a%(6),i%,l%
  1137.     LOCK OFF                        Rem allow events
  1138.     SETCOMPUTEMODE:(KComputeModeOff&)        Rem raise priority
  1139.     i$=PEEK$(addr&)
  1140. reset::
  1141.     off%=LEN(i$)
  1142.     wx%=0
  1143. start::
  1144.     PRINT
  1145.     a%(1)=ScrInfo%(1):a%(2)=ScrInfo%(2)
  1146.     a%(3)=a%(1)+ScrInfo%(3):a%(4)=a%(2)+ScrInfo%(4)
  1147.     IOW(-2,8,a%(),a%())
  1148. Rem    AT 30,10: PRINT a%(6)+1,a%(5)+1,wx%,off%,width%
  1149.     AT 1,a%(6): PRINT pr$;
  1150. Repeat::
  1151.     IOW(-2,8,a%(),a%())
  1152.     xmin%=a%(5)+1
  1153.     width%=ScrInfo%(3)-xmin%+1
  1154.     IF width%=0    Rem don't allow a width of 0 or 1
  1155.         PRINT " ";
  1156.         GOTO Repeat::
  1157.     ELSEIF width%>255
  1158.         width%=255
  1159.     ENDIF
  1160.     y%=a%(6)+1
  1161.     AT xmin%,y%
  1162.     IF LEN(i$)>=width%
  1163.         IF off%<>LEN(i$)
  1164.             GOTO Print::
  1165.         ELSE
  1166.             wx%=off%-width%+1
  1167.             PRINT RIGHT$(i$,LEN(i$)-wx%);" "
  1168.         ENDIF
  1169.     ELSE
  1170.         PRINT i$;REPT$(" ",width%-LEN(i$))
  1171.     ENDIF
  1172.     WHILE 1
  1173.         AT xmin%+off%-wx%,y%
  1174.         CURSOR ON
  1175.         oldc%=c%
  1176.         
  1177. Rem        PRINT "Waiting for an event...";
  1178.         GetEvent32 event&()
  1179. Rem        PRINT "Got one."
  1180.         ev&=event&(KEvaType%)
  1181.  
  1182.         IF NOT ev& AND KEvNotKeyMask&
  1183.             c%=ev&
  1184.             IF ev&>255                        Rem not a "normal" char
  1185.                 c%=c%-$0E80            Rem cursor or menu keys
  1186.             ELSEIF event&(KEvAKMod%) AND KKmodFn%
  1187. Rem many keys CAN'T┬átake these modifiers!!, (eg. cursor keys, Y,U,I,
  1188. Rem numeric key, etc. Allow only on a-z (upper and lower case).
  1189.                 IF (c%>=%A AND c%<=%Z) OR (c%>=%a AND c%<=%z)
  1190.                     c%=$0100+c%
  1191.                 ENDIF
  1192. Rem precedence is Fn, Shift
  1193.             ELSEIF event&(KEvAKMod%) AND KKmodShift%
  1194.                 IF c%<=32                    Rem control and special keys + SHIFT
  1195.                     c%=$0100+c%        Rem use the same "space" as Fn...
  1196.                 ENDIF            
  1197.             ENDIF
  1198.         ELSEIF ev&=KEvCommand&
  1199.             IF ASC(getcmd$)=%X
  1200.                 _exit:                    Rem never, ever returns
  1201.             ENDIF
  1202.         ELSEIF ev&=KEvPtr&
  1203.             IF TBarOffer%:(event&(KEvAPtrOplWindowId%),event&(KEvAPtrType%),event&(KEvAPtrPositionX%),event&(KEvAPtrPositionY%)) rem Handles tbar events
  1204.             Rem was used, check for an external event
  1205.                 IF _extevent%            Rem a button has been pressed
  1206.                     IF _extevent%=1        Rem generic event, eg. log window..
  1207.                         _extevent%=0
  1208.                         GOTO start::
  1209.                     ENDIF
  1210.                     k$=GetVar$:("button"+CHR$(_extevent%))
  1211.                     _extevent%=0
  1212.                     GOTO UserCommon::        Rem this checks if k$ contains anything
  1213.                 ENDIF
  1214.             ENDIF
  1215.             CONTINUE
  1216.         ELSE                Rem pointer events & key-up, key-down things, etc
  1217. Rem            PRINT "Not a keyboard event!"
  1218.             CONTINUE
  1219.         ENDIF
  1220. Rem        AT 40,4: PRINT "Raw:";c%;"   "
  1221.         IF c%>511 OR c%<0        Rem catch overflow conditions
  1222.             c%=0
  1223.         ELSE
  1224.             c%=PEEKB (_keys&+c%)
  1225.         ENDIF
  1226. Rem        AT 40,5: PRINT c%;"   "
  1227.         CURSOR OFF
  1228.         VECTOR c%            Rem position 14 & 15, marked Char, is unused
  1229.             Del,SDel,Leave,Esc,Leave,Leave,Right,Left,Leave,Leave
  1230.             PLeft,PRight,Expand,Char,Char
  1231. Rem 16-31 are "user-defined"
  1232.             User,User,User,User,User,User,User,User
  1233.             User,User,User,User,User,User,User,User
  1234.         ENDV
  1235.         GOTO Char::
  1236. Del::    Rem delete key
  1237.         IF off%
  1238.             i$=LEFT$(i$,off%-1)+MID$(i$,off%+1,LEN(i$)-off%)
  1239.             off%=off%-1
  1240.             IF wx% AND (off%-11 < wx%)
  1241.                 wx%=wx%-1
  1242.             ENDIF
  1243.             GOTO Print::
  1244.         ENDIF
  1245.         CONTINUE
  1246. SDel::    Rem shift delete
  1247.         IF off%<LEN(i$)
  1248.             i$=LEFT$(i$,off%)+MID$(i$,off%+2,LEN(i$)-off%-1)
  1249.             GOTO Print::
  1250.         ENDIF
  1251.         CONTINUE
  1252. Leave::    Rem anything that returns (Enter, PSION-arrows,etc)
  1253.         BREAK
  1254. Esc::
  1255.         AT xmin%,y% : PRINT REPT$(" ",width%)
  1256.         wx%=0
  1257.         off%=0
  1258.         i$=""
  1259.         CONTINUE
  1260. Right::
  1261.         IF off% < LEN(i$)
  1262.             off%=off%+1
  1263.             IF off%-wx% >= width%
  1264.                 wx%=wx%+1
  1265.                 GOTO Print::
  1266.             ENDIF
  1267.         ENDIF
  1268.         CONTINUE
  1269. Left::
  1270.         IF off%
  1271.             off%=off%-1
  1272.             IF wx% AND (off%-11 < wx%)
  1273.                 wx%=wx%-1
  1274.                 GOTO Print::
  1275.             ENDIF
  1276.         ENDIF
  1277.         CONTINUE
  1278. PLeft::
  1279.         off%=0
  1280.         wx%=0
  1281.         GOTO Print::
  1282. PRight::
  1283.         off%=LEN(i$)
  1284.         IF off%>=width%
  1285.             wx%=off%-width%+1
  1286.             GOTO Print::
  1287.         ENDIF
  1288.         CONTINUE
  1289. Rem TogLog::
  1290. Rem        _log:((_logid%=0)+2,"")
  1291. Rem If logid% is 0, this will be -1 + 2 = 1 = create message window
  1292. Rem If logid% is <> 0, this will be 0 + 2 = 2 = remove message window!!
  1293. Rem        GOTO start::
  1294. Expand::            Rem YES! filename expansion!!
  1295.         i%=off%
  1296.         WHILE i%>0
  1297.             IF LOC(" ,",MID$(i$,i%,1))    Rem check for , and " "
  1298.                 BREAK
  1299.             ENDIF
  1300.             i%=i%-1
  1301.         ENDWH
  1302.         k$=_expand$:(MID$(i$,i%+1,off%-i%),-(c%=oldc%))
  1303. Rem Spot -(c%=oldc%)!!! - set  for not a single expansion, but a sequence
  1304.         IF LEN(k$)<>off%-i%
  1305.             c%=0    Rem if length has changed stop expansion
  1306.         ENDIF
  1307.         l%=LEN(MID$(i$,i%+1,off%-i%))
  1308.         IF LEN(k$)+LEN(i$)-l%<=max%
  1309.             i$=LEFT$(i$,i%)+k$+RIGHT$(i$,LEN(i$)-off%)
  1310.             off%=off%+LEN(k$)-l%
  1311.             IF off%-wx%>width%-1
  1312.                 wx%=off%-width%+1
  1313.             ENDIF
  1314.             GOTO start::
  1315.         ELSE
  1316.             PRINT CHR$(7);
  1317.             GOTO start::
  1318.         ENDIF
  1319. User::
  1320.         k$=GetVar$:("macro"+num$(c%-15,2))
  1321. UserCommon::
  1322.         IF LEN(k$)    Rem keyc% exists
  1323.             IF ASC(k$)<>%@    Rem macro, not execute
  1324.                 IF LEN(k$)+LEN(i$)<=max%
  1325.                     i$=LEFT$(i$,off%)+k$+RIGHT$(i$,LEN(i$)-off%)
  1326.                     off%=off%+LEN(k$)
  1327.                     IF off%-wx%>width%-1
  1328.                         wx%=off%-width%+1
  1329.                     ENDIF
  1330.                     GOTO Print::
  1331.                 ELSE
  1332.                     PRINT CHR$(7)
  1333.                     CONTINUE
  1334.                 ENDIF
  1335.             ELSE    Rem execute the macro
  1336. Rem                AT 1,y% : PRINT REPT$(" ",ScrInfo%(3));
  1337. Rem                AT 1,y%
  1338.                 Rem skip 1st char which will be @
  1339.                 _proc%:(RIGHT$(k$,LEN(k$)-1))
  1340.                 IF PEEKB(_curr&+PR_FLAG%)        Rem check for exit...
  1341.                     _exit:
  1342.                 ENDIF
  1343. Rem                GOTO reset::
  1344.                 GOTO start::
  1345.             ENDIF
  1346.         ELSE
  1347.             CONTINUE    Rem keyc% is empty, ignore
  1348.         ENDIF
  1349. Char::
  1350.         IF c%    Rem if it's 0 do nothing
  1351.             IF LEN(i$)<max%
  1352.                 i$=LEFT$(i$,off%)+CHR$(c%)+RIGHT$(i$,LEN(i$)-off%)
  1353.                 off%=off%+1
  1354.                 IF off%-wx%>width%-1
  1355.                     wx%=wx%+1
  1356.                 ENDIF
  1357.             ELSE
  1358.                 PRINT CHR$(7)
  1359.             ENDIF
  1360. Print::    AT xmin%,y%
  1361.             IF (LEN(i$) - wx%) >= width%
  1362.                 PRINT MID$(i$,wx%+1,width%)
  1363.             ELSE
  1364.                 PRINT MID$(i$,wx%+1,LEN(i$)-wx%);" "
  1365.             ENDIF
  1366.         ENDIF
  1367.     ENDWH
  1368.     POKE$ addr&,i$
  1369.     AT xmin%,y%
  1370.     SETCOMPUTEMODE:(KComputeModeOn&)        Rem lower priority
  1371.     LOCK ON        Rem stop events
  1372.     RETURN c%
  1373. ENDP
  1374.  
  1375. PROC _proc%:(in$)
  1376. Rem Processing loop for command line
  1377. LOCAL line$(255),ret%,ticks&,pa&,i%,elapsed&
  1378.     ONERR ErrTrap::
  1379.     IF _stat%<>-46
  1380.         _key%(1)=0
  1381.         KEYA(_stat%,_key%())
  1382.     ENDIF
  1383.     pa&=ALLOC(SEG_SIZE%)    Rem new argument block
  1384. Rem    pa&=ALLOC&:(SEG_SIZE%,"proc1")    Rem new argument block
  1385.     IF pa&=0
  1386.         RAISE -10    Rem no memory
  1387.     ENDIF
  1388.     POKEL pa&+PR_BACK%,_curr&        Rem store old arg block
  1389.     POKEL pa&+PR_OUT%,0                Rem initialize output&input handles
  1390. Rem initialize no. args,level,flag and set ARGN to 128
  1391.     POKEL pa&,&80000000
  1392.     _pid%=UADD(_pid%,1)
  1393.     POKEW pa&+PR_NUM%,_pid%        Rem set argument block id
  1394.     _curr&=pa&                                    Rem make this current
  1395.     line$=in$
  1396. Rem    _esc%=0                                            Rem init escape flag
  1397. Repeat::
  1398.     line$=_afind$:(line$)                        Rem find aliases in command line
  1399.     POKEW pa&+PR_INPST%,0                        Rem reset input line status & pos
  1400.     _inpar%:(line$,pa&,_spec$)            Rem sets pa&, not ARGV
  1401.     WHILE PEEKB(pa&)
  1402.         IF LOWER$(PEEK$(PEEKW(pa&+PR_ARGV%)))="if"
  1403.             _if%:(pa&)
  1404.         ELSEIF LOWER$(PEEK$(PEEKL(pa&+PR_ARGV%)))="time"
  1405.             IF ticks&
  1406.                 PRINT "Nested times not allowed"
  1407.             ELSE
  1408.                 ticks&=DTNow&:
  1409.             ENDIF
  1410.             FREEALLOC PEEKL(pa&+PR_ARGV%)    Rem free "time" arg
  1411. Rem            FREEALLOC&:(PEEKL(pa&+PR_ARGV%))    Rem free "time" arg
  1412.             pa&=ADJUSTALLOC(pa&,PR_ARGV%,-4)        Rem remove time!
  1413.             IF pa&=0        Rem apparently this should never happen. If it did there'd
  1414.                 STOP            Rem be no easy way to clean-up. Is the old pa& still
  1415.             ENDIF                Rem valid, etc.
  1416.             POKEB pa&,PEEKB(pa&)-1
  1417.         ELSE
  1418.             BREAK
  1419.         ENDIF
  1420.     ENDWH
  1421.     ret%=_subpr%:(pa&)
  1422.     POKEW PEEKL(_curr&+PR_BACK%)+PR_STATUS%,ret%    Rem store the status
  1423.     _clrA:(pa&)    Rem Deallocate memory for argument list
  1424.     IF PEEKB(pa&+PR_FLAG%)    Rem exit flag, set parent's
  1425.         POKEB PEEKL(_curr&+PR_BACK%)+PR_FLAG%,1
  1426.         GOTO Cleanup::
  1427.     ENDIF
  1428.     IOYIELD
  1429.     IF _stat%<>-46
  1430.         IF _key%(1)=27
  1431.             GIPRINT ERR$(-114)
  1432.             GOTO Cleanup::
  1433.         ELSE
  1434.             KEYA(_stat%,_key%())
  1435.         ENDIF
  1436.     ENDIF
  1437.  
  1438.     IF PEEKB(pa&+PR_INPST%)
  1439.         line$=RIGHT$(line$,LEN(line$)-PEEKB(pa&+PR_INPPS%))
  1440.         IF PEEKB(pa&+PR_INPST%)=2    Rem Bloody heck it's a pipe!
  1441.             Rem it's a pipe, so OPEN _syspath$\pipe as stdin
  1442.             Rem There CAN be no way SHin% is already set...
  1443.             Rem    (< redirection comes AFTER this - next command!)
  1444.             ret%=IOOPEN(#pa&+PR_IN%,_syspath$+NUM$(PEEKW(pa&+PR_NUM%),5)+"pipe."+CHR$(PEEKB(pa&+PR_LEV%)),$0120)
  1445.             IF ret%    Rem check for original AND creation
  1446.                 RAISE ret%
  1447.             ENDIF
  1448.         ENDIF
  1449.         GOTO Repeat::
  1450.     ENDIF
  1451.     GOTO Cleanup::
  1452. ErrTrap::
  1453.     ONERR off
  1454.     PRINT err$:(ERR)
  1455.     _clrA:(pa&)
  1456. Cleanup::
  1457.     IF ticks&
  1458.         elapsed&=DTNow&:
  1459.         PRINT "Elapsed time:",fix$(DTMicrosDiff&:(ticks&,DTNow&:)/1000000.0,3,12),"secs"
  1460.         DTDeleteDateTime:(ticks&)
  1461.         ticks&=0
  1462.     ENDIF
  1463.     IF PEEKB(pa&+PR_LEV%)    Rem some pipes - delete
  1464.         TRAP DELETE _syspath$+NUM$(PEEKW(pa&+PR_NUM%),5)+"pipe.?"
  1465.         _here$=""    Rem how does this fit with no argv?
  1466.     ENDIF
  1467.     _curr&=PEEKL(pa&+PR_BACK%)
  1468. Rem here's where we'd restore ARGV
  1469.     FREEALLOC(pa&)
  1470. Rem    FREEALLOC&:(pa&)
  1471.     RETURN
  1472. ENDP
  1473.  
  1474. PROC _if%:(pa&)
  1475. Rem Parse 'if' args, shift argv& as necessary
  1476. Rem NEW: allow arguments without "==", ie. if $fred echo "fred exists!"
  1477. LOCAL i%,neg%,txt$(255),condOK%,j%,p&,args%
  1478.     args%=PEEKB(pa&)
  1479.     IF args%<3                Rem Must be at least 3 args
  1480. Error::
  1481.         RAISE -77
  1482.     ENDIF
  1483.     txt$=PEEK$(PEEKL(pa&+PR_ARGV%+4))    Rem 1st argument, argv&(2)
  1484.     i%=8                                            Rem offset of next argument
  1485.     IF LOWER$(txt$)="not"
  1486.         IF args%<4            Rem with "not" we need at least 4 arguments
  1487.             GOTO Error::
  1488.         ENDIF
  1489.         neg%=-1
  1490.         txt$=PEEK$(PEEKL(pa&+PR_ARGV%+8))
  1491.         i%=12                                    Rem offset of next argument
  1492.     ENDIF
  1493.     IF LOWER$(txt$)="exist"
  1494.         IF args% < 4 - neg%            Rem 5 args for "not", 4 otherwise
  1495.             GOTO Error::
  1496.         ENDIF
  1497.         IF Fparse%:(ADDR(txt$),PEEK$(PEEKL(pa&+PR_ARGV%+i%)))>=0
  1498.             condOK%=1
  1499.         ENDIF
  1500.         i%=i%+4
  1501.     ELSEIF PEEK$(PEEKL(pa&+PR_ARGV%+i%))="=="
  1502.         IF args%<5-neg%
  1503.             GOTO Error
  1504.         ENDIF
  1505. Rem        PRINT "Comparing",txt$,"with",PEEK$(PEEKL(pa&+PR_ARGV%+i%+4))
  1506.         IF txt$=PEEK$(PEEKL(pa&+PR_ARGV%+i%+4))
  1507.             condOK%=1
  1508.         ENDIF
  1509.         i%=i%+8                    Rem skip == and following argument
  1510.     ELSE                                Rem no ==, so just evaluate txt$
  1511.         IF LEN(txt$) AND txt$<>"0"
  1512.             condOK%=1        Rem set if non-zero argument exists
  1513.         ENDIF
  1514.     ENDIF
  1515. Rem    PRINT "CondOK:";Condok%,
  1516. Rem    PRINT "neg:";neg%,
  1517. Rem    PRINT "i:";i%
  1518.     Rem always free the arguments
  1519.     IF (CondOK% + neg%)
  1520.         WHILE j%<i%
  1521. Rem            PRINT "Freeing",PEEK$(PEEKL(pa&+PR_ARGV%+j%))
  1522.             FREEALLOC(PEEKL(pa&+PR_ARGV%+j%))
  1523. Rem            FREEALLOC&:(PEEKL(pa&+PR_ARGV%+j%))
  1524.             j%=j%+4
  1525.         ENDWH
  1526.         p&=ADJUSTALLOC(pa&,PR_ARGV%,-i%)
  1527.         IF p&=0 OR p&<>pa&    Rem apparently this should never happen. If it did
  1528.             STOP                            Rem  there'd be no easy way to clean-up. Is the
  1529.         ENDIF                                Rem  old pa& stillvalid, etc.
  1530.         POKEB pa&,args%-i%/4
  1531.     ELSE
  1532.         _clrA:(pa&)    Rem clear args!
  1533.     ENDIF
  1534. ENDP
  1535.  
  1536. PROC _afind$:(src$)
  1537. LOCAL len%,c$(255),n%,p&,c%,l%
  1538.     len%=LEN(src$)
  1539.     WHILE n%<len%
  1540.         n%=n%+1
  1541.         c%=ASC(MID$(src$,n%,1))
  1542.         IF c%<>32
  1543.             IF c%=%%
  1544.                 RETURN RIGHT$(src$,len%-n%)    Rem rest of line
  1545.             ELSE    Rem Not a space, so start the 1st word
  1546.                 c$=RIGHT$(src$,LEN(src$)-n%+1)
  1547.                 p&=_atab&
  1548.                 WHILE PEEKL(p&)
  1549.                     p&=PEEKL(p&)
  1550.                     Rem get length of what we're searching for
  1551.                     l%=PEEKB(PEEKL(p&+4))
  1552.                     IF LEFT$(c$,l%)=PEEK$(PEEKL(p&+4))
  1553.                         Rem check character after the "match"
  1554.                         IF LOC(_spec$,MID$(c$,l%+1,1))
  1555.                             RETURN PEEK$(PEEKL(p&+8))+RIGHT$(src$,len%-l%-n%+1)
  1556.                         ENDIF
  1557.                     ENDIF
  1558.                 ENDWH
  1559.                 RETURN src$    Rem nothing found
  1560.             ENDIF
  1561.         ENDIF
  1562.     ENDWH
  1563.     RETURN    Rem nothing but blanks!
  1564. ENDP
  1565.  
  1566. PROC SetVar%:(var$,x$)
  1567. Rem set the variable var$ to x$
  1568. Rem reusing a member of the structure if possible
  1569. LOCAL p&,q&,r&,h%,i%,f&,s%,val$(255)
  1570.     ONERR  ErrTrap::
  1571.     IF ASC(var$)=%_
  1572.         RAISE 9                Rem can't write read-only variables
  1573.     ENDIF
  1574.     val$=x$
  1575.     IF var$="history"
  1576.         h%=EVAL(val$)
  1577.         IF h%<0
  1578.             RAISE -7
  1579.         ELSE
  1580.             _hsz%=h%
  1581.             IF _hsz%<_hrsz%    Rem must remove some members
  1582.                 i%=1
  1583.                 p&=PEEKL(_hpos&+4)
  1584.                 q&=_hpos&
  1585.                 WHILE (p&<>_hpos&)
  1586.                     r&=PEEKL(p&+4)                Rem previous
  1587.                     IF i%>_hsz%
  1588.                         FREEALLOC(PEEKL(p&+8))
  1589. Rem                        FREEALLOC&:(PEEKL(p&+8))
  1590.                         FREEALLOC(p&)
  1591. Rem                        FREEALLOC&:(p&)
  1592.                         _hrsz%=_hrsz%-1
  1593.                     ELSE
  1594.                         q&=p&
  1595.                     ENDIF
  1596.                     p&=r&                                                    Rem previous
  1597.                     i%=i%+1
  1598.                 ENDWH
  1599.                 POKEL q&+4,_hpos&
  1600.                 POKEL _hpos&,q&
  1601.                 _cpos&=_hpos&            Rem possibly reset history editting pos.
  1602.             ENDIF
  1603.         ENDIF
  1604.     ELSEIF var$="toolbar"
  1605.         IF val$="toggle"
  1606.             i%=(TbVis%=0)
  1607.         ELSEIF val$="on"
  1608.             i%=-1
  1609.         ELSEIF val$="off"
  1610.             i%=0
  1611.         ELSE
  1612.             RAISE -80
  1613.         ENDIF
  1614.         IF i%<>TbVis%
  1615.             IF i%
  1616.                 val$="on"
  1617.                 TBarShow:
  1618.             ELSE
  1619.                 val$="off"
  1620.                 TBarHide:
  1621.             ENDIF    
  1622.             _setw%:    Rem set display window
  1623.         ENDIF
  1624.     ELSEIF var$="path"
  1625. Rem clear hash table
  1626.         p&=PEEKL(_hash&)
  1627.         WHILE p&
  1628.             q&=p&
  1629.             p&=PEEKL(p&)
  1630.             FREEALLOC(q&)
  1631.         ENDWH
  1632.         POKEL _hash&,0
  1633.     ELSEIF var$="font"
  1634.         i%=LOC(val$,",")
  1635.         IF i%
  1636.             f&=EVAL(LEFT$(val$,i%-1))
  1637.             s%=EVAL(RIGHT$(val$,LEN(val$)-i%))
  1638.         ELSE
  1639.             f&=EVAL(val$)
  1640.             s%=-1
  1641.         ENDIF
  1642.         IF f&=-1
  1643.             f&=ScrInfo%(9)+&10000*ScrInfo%(10)    Rem old font
  1644.         ENDIF
  1645.         IF s%=-1
  1646.             s%=_style%
  1647.         ENDIF
  1648.         FONT f&,s%
  1649. Rem assignments are here so if 'FONT' produces an error the old
  1650. Rem values are preserved.
  1651.         _style%=s%
  1652.         val$=GEN$(f&,10)+","+GEN$(s%,6)
  1653.         _setw%:    Rem this is needed as FONT doesn't take the log
  1654.                         Rem window into account. ie. the end of screen is
  1655.                         Rem not stopped at the log window!!
  1656.     ENDIF
  1657.     p&=_vars&
  1658.     WHILE PEEKL(p&)
  1659.         q&=p&
  1660.         p&=PEEKL(p&)
  1661.         IF PEEK$(PEEKL(p&+4))=var$
  1662.             FREEALLOC(PEEKL(p&+8))
  1663. Rem            FREEALLOC&:(PEEKL(p&+8))
  1664.             Goto Store::
  1665.         ENDIF
  1666.     ENDWH
  1667.     q&=p&
  1668.     POKEL p&,ALLOC(16)        Rem 12 rounded to 16 to avoid fragmentation
  1669.     Rem POKEL p&,ALLOC&:(16,"setvar1")        Rem 12 rounded to 16 to avoid fragmentation
  1670.     p&=PEEKL(p&)
  1671.     IF p&=0
  1672.         RAISE -10
  1673.     ENDIF
  1674.     POKEL p&,0
  1675.     POKEL p&+4,ALLOC((LEN(var$)+16) AND $FFF0)
  1676. Rem    POKEL p&+4,ALLOC&:((LEN(var$)+16) AND $FFF0,"setvar2")
  1677.     IF PEEKL(p&+4)=0
  1678.         Goto Common::
  1679.     ENDIF
  1680. Store::
  1681.     POKEL p&+8,ALLOC((LEN(val$)+16) AND $FFF0)
  1682. Rem    POKEL p&+8,ALLOC&:((LEN(val$)+16) AND $FFF0,"setvar3")
  1683.     IF PEEKL(p&+8)=0
  1684.         FREEALLOC(p&+4)
  1685. Rem        FREEALLOC&:(p&+4)
  1686. Common::
  1687.         POKEL q&,PEEKL(p&)    Rem clear reference
  1688.         FREEALLOC(p&)
  1689. Rem        FREEALLOC&:(p&)
  1690.         RAISE -10
  1691.     ENDIF
  1692.     POKE$ PEEKL(p&+4),var$
  1693.     POKE$ PEEKL(p&+8),val$
  1694.     RETURN
  1695. ErrTrap::
  1696.     ONERR off
  1697.     PRINT err$:(ERR)
  1698. ENDP
  1699.  
  1700. PROC GetVar$:(var$)
  1701. Rem Return variable given in var$
  1702. LOCAL p&
  1703.     p&=PEEKL(_vars&)
  1704.     WHILE p&
  1705.         IF PEEK$(PEEKL(p&+4))=var$
  1706.             RETURN PEEK$(PEEKL(p&+8))
  1707.         ENDIF
  1708.         p&=PEEKL(p&)
  1709.     ENDWH
  1710. ENDP
  1711.  
  1712. PROC FreeVar%:(var$)
  1713. Rem Free variable given in var$
  1714. LOCAL p&,q&
  1715.     q&=_vars&
  1716.     p&=PEEKL(q&)
  1717.     WHILE p&
  1718.         IF PEEK$(PEEKL(p&+4))=var$
  1719.             IF ASC(var$)=%_
  1720.                 RAISE 9                    Rem can't write read-only variables
  1721.             ENDIF
  1722.             FREEALLOC(PEEKL(p&+4))
  1723. Rem            FREEALLOC&:(PEEKL(p&+4))
  1724.             FREEALLOC(PEEKL(p&+8))
  1725. Rem            FREEALLOC&:(PEEKL(p&+8))
  1726.             POKEL q&,PEEKL(p&)
  1727.             FREEALLOC(p&)
  1728. Rem            FREEALLOC&:(p&)
  1729.             BREAK
  1730.         ENDIF
  1731.         q&=p&
  1732.         p&=PEEKL(p&)
  1733.     ENDWH
  1734.     IF p&=0
  1735.         PRINT var$, "- Variable not set"
  1736.     ENDIF
  1737. ENDP
  1738.  
  1739. PROC _mkpr$:(p$)
  1740. LOCAL i%,flag%,q$(255),c$(255),l%,x$(1),attr%(8)
  1741.     ONERR ErrTrap::            Rem otherwise an error ends the program!
  1742.     x$=RIGHT$(_spec$,1)    Rem last position of SHspec$
  1743.     l%=LEN(p$)
  1744.     WHILE i%<l%
  1745.         i%=i%+1
  1746.         c$=MID$(p$,i%,1)
  1747.         IF flag%
  1748.             IF c$="H"
  1749.                 c$=NUM$(_hnum%,6)
  1750.             ELSEIF c$="P"
  1751.                 c$=PrPath$:(_cwd$)
  1752.             ELSEIF c$="p"
  1753.                 parse$(LEFT$(_cwd$,LEN(_cwd$)-1),"",attr%())
  1754.                 IF LEN(_cwd$)<attr%(4)
  1755.                     attr%(4)=attr%(4)-1
  1756.                 ENDIF
  1757.                 c$=PrPath$:(MID$(_cwd$,attr%(4),LEN(_cwd$)-attr%(4)+1))
  1758.             ELSEIF c$<>x$
  1759.                 CONTINUE
  1760.             ENDIF
  1761.             flag%=0
  1762.         ELSEIF c$=x$
  1763.             flag%=1
  1764.             CONTINUE
  1765.         ENDIF
  1766.         q$=q$+c$
  1767.     ENDWH
  1768.     RETURN q$
  1769. ErrTrap::
  1770.     ONERR off
  1771.     PRINT err$:(ERR)
  1772. ENDP
  1773.  
  1774. PROC Fparse%:(addr&,p$)
  1775. Rem top level single return wrapper around parse$: and stat%:
  1776. Rem that also append '\' (or another sepator) to directories
  1777. Rem returns:
  1778. Rem -33 : File doesn't exist
  1779. Rem -41 : Bad devices
  1780. Rem -127 : Wildcards
  1781. Rem Else file info
  1782. Rem note that on an "error" addr&'s contents may be undefined
  1783. LOCAL attr%(8),ret%
  1784.     ONERR ErrTrap::
  1785.     ret%=parse%:(p$,addr&,ADDR(attr%()))
  1786.     IF ret%
  1787.         RETURN ret%
  1788.     ENDIF
  1789.     ret%=stat%:(addr&)
  1790. Rem stat% now also does this
  1791. Rem    IF (ret%>=0) AND ((ret% AND 16)=16)    Rem AND ASC(RIGHT$(buf$,1))<>%\
  1792. Rem        buf$=buf$+"\"                        Rem must be a directory
  1793. Rem    ENDIF
  1794.     IF attr%(6)    Rem wilcards
  1795.         RETURN -127
  1796.     ELSE
  1797.         RETURN ret%
  1798.     ENDIF
  1799. ErrTrap::
  1800.     RETURN ERR
  1801. ENDP
  1802.  
  1803. PROC stat%:(addr&)
  1804. Rem Takes a pathname and the data returned by parse$:() and
  1805. Rem finds the status of the file. Returns ERR or file flags
  1806. REM - Directories/files MUST NOT BE terminated by \
  1807. REM - Only FULL pathnames work
  1808. REM - Returns the wrong value for a directory open on Z: - now returns -69
  1809. REM - So should only be called on directories known to exist, e.g. via DIR$
  1810. REM Should only be run after parse% as we don't check if the device exists
  1811. LOCAL ret%,h%,out%,buf$(255)
  1812.     ONERR ErrTrap::
  1813.     IF PEEKB(addr&)<4        Rem length of input string
  1814.         RETURN 16        Rem ONLY x:\
  1815.     ENDIF
  1816.     buf$=DIR$(PEEK$(addr&))
  1817.     IF LEN(buf$)                    Rem exists
  1818.         ret%=IOOPEN(h%,buf$,$0400)        Rem this is faster than another DIR$
  1819. Rem 0=file, -9 file in use, anything else counted as a directory!!
  1820.         IF ret%=0
  1821.             IOCLOSE(h%)
  1822.         ELSEIF ret%<>-9                                Rem for z: this could be -33!!!
  1823.             buf$=buf$+"\"
  1824.             out%=16
  1825.         ENDIF
  1826.         POKE$ addr&,buf$
  1827.     ELSE
  1828.         out%=-33
  1829.     ENDIF
  1830.     RETURN out%
  1831. ErrTrap::
  1832.     RETURN ERR
  1833. ENDP
  1834.  
  1835. PROC xstat%:(p$)
  1836. Rem Version of stat% that doesn't use DIR$, so is safe within other DIR$
  1837. Rem returns a bad value (-33) for a directory on ROM
  1838. LOCAL ret%,h%,out%
  1839.     ONERR ErrTrap::
  1840.     IF LEN(p$)<4
  1841.         RETURN 16        Rem ONLY x:\
  1842.     ENDIF
  1843.     ret%=IOOPEN(h%,p$,$0400)
  1844. Rem    PRINT "HANDLE:",h%,"RETURN",ret%
  1845.     IF ret%=0 OR ret%=-9
  1846.         IF ret%=0
  1847.             IOCLOSE(h%)
  1848.         ENDIF
  1849.     ELSEIF ret%<>-33                            Rem not a file
  1850.         out%=16
  1851.     ELSE
  1852.         out%=-33
  1853.     ENDIF
  1854. Rem check attributes here? Check what I say this routine does
  1855.     RETURN out%
  1856. ErrTrap::
  1857.     RETURN ERR
  1858. ENDP
  1859.  
  1860. PROC _run%:(p$)
  1861. Rem .bat program executor, read the whole batch file into memory,
  1862. Rem    after all they aren't exactly going to be very long....
  1863. LOCAL ret%,handle%,p&,labels&,WaitLbl%,params%,exit%
  1864. LOCAL line$(255),baseadr&,q&,i%,txt$(255),label$(8)
  1865. LOCAL offset&,pa&,xpa&
  1866.     ONERR ErrTrap::
  1867.     IF _stat%<>-46
  1868.         _key%(1)=0
  1869.         KEYA(_stat%,_key%())
  1870.     ENDIF
  1871.     pa&=ALLOC(SEG_SIZE%)
  1872. Rem    pa&=ALLOC&:(SEG_SIZE%,"run1")
  1873.     baseadr&=ALLOC(4)    Rem list for storing batch commands
  1874. Rem    baseadr&=ALLOC&:(4,"run2")    Rem list for storing batch commands
  1875.     labels&=ALLOC(8)        Rem start of list of labels
  1876. Rem    labels&=ALLOC&:(8,"run3")        Rem start of list of labels
  1877.     IF labels&=0 OR baseadr&=0 OR pa&=0
  1878.         RAISE -10
  1879.     ENDIF
  1880.     POKEL pa&+PR_BACK%,_curr&        Rem store old arg block
  1881.     POKEL pa&+PR_OUT%,0    Rem initialize output&input handles
  1882. Rem initialize no. args,level,flag and set ARGN to 128
  1883.     POKEL pa&,&80000000
  1884.     _pid%=UADD(_pid%,1)            Rem keep this as UADD to allow wraps
  1885.     POKEW pa&+PR_NUM%,_pid%        Rem set argument block id
  1886.     _curr&=pa&                                    Rem make this current
  1887.     POKEL baseadr&,0
  1888.     POKEL labels&,0
  1889.     ret%=IOOPEN(handle%,p$,$0420)
  1890.     IF ret%<0
  1891.         RAISE ret%
  1892.     ENDIF
  1893.     p&=baseadr&    Rem start of linked list for storing commands
  1894.     DO
  1895.         ret%=IOREAD(handle%,ADDR(line$)+1,255)
  1896.         IF ret%<0
  1897.             IF  ret%<>-36    Rem EOF
  1898.                 RAISE ret%
  1899.             ENDIF
  1900.         ELSE    Rem not EOF
  1901.             POKEB ADDR(line$),ret%
  1902.             POKEL p&,ALLOC((LEN(line$)+20) AND $FFF0)
  1903. Rem            POKEL p&,ALLOC&:((LEN(line$)+20) AND $FFF0,"run4")
  1904.             Rem space for pointer + 1 + 15
  1905.             p&=PEEKL(p&)    Rem  next element
  1906.             IF p&=0
  1907.                 RAISE -10
  1908.             ENDIF
  1909.             POKEL p&,0    Rem mark end
  1910.             POKE$ p&+4,line$
  1911.         ENDIF
  1912.     UNTIL ret%=-36
  1913.  
  1914.     Rem commands file in baseadr% list
  1915. Rem    _esc%=0            Rem clear Esc flag
  1916.     p&=PEEKL(baseadr&)
  1917.     WHILE p&
  1918.         line$=PEEK$(p&+4)
  1919.         IF _opts%(varEcho%)                Rem if varEcho is on, print lines of batch file
  1920.             PRINT line$
  1921.         ENDIF
  1922.         IF LEN(_here$)    Rem <<
  1923.             IF line$<>_here$
  1924.                 IF xpa&=0    Rem no argument block
  1925.                     xpa&=ALLOC(SEG_SIZE%)
  1926. Rem                    xpa&=ALLOC&:(SEG_SIZE%,"run6")
  1927.                     IF xpa&=0
  1928.                         RAISE -10
  1929.                     ENDIF
  1930.                     POKEB xpa&+PR_ARGN%,128    Rem initialize max args
  1931.                     POKEB xpa&+PR_LEV%,0
  1932.                     POKEW xpa&+PR_STATUS%,0
  1933.                     POKEL xpa&+PR_BACK%,pa&    Rem store old arg block
  1934.                 ENDIF                
  1935.                 POKEB xpa&,0                Rem initialize no. args
  1936. Rem                Rem don't look for >,<,; or ├¥
  1937.                 _inpar%:(line$,xpa&," ""'*?{}  =+-/#  !"+RIGHT$(_spec$,2))
  1938.                 i%=0
  1939.                 line$=""
  1940.                 WHILE i%<PEEKB(xpa&)    Rem while there are arguments
  1941.                     q&=PEEKL(xpa&+PR_ARGV%+4*i%)
  1942.                     txt$=PEEK$(q&)
  1943.                             FREEALLOC q&
  1944. Rem                    FREEALLOC&:(q&)
  1945.                     Rem mustcontinue to free, even if line$ is too long
  1946.                     IF LEN(line$) AND LEN(line$)<255    Rem not the first entry
  1947.                         line$=line$+" "
  1948.                     ENDIF
  1949.                     IF LEN(line$)+LEN(txt$)<=255
  1950.                         line$=line$+txt$
  1951.                     ELSE
  1952.                         line$=line$+LEFT$(txt$,255-LEN(line$))
  1953.                     ENDIF
  1954.                     i%=i%+1
  1955.                 ENDWH
  1956.                 IOWRITE(PEEKW(pa&+PR_IN%),ADDR(line$)+1,LEN(line$))
  1957.                 IF PEEKL(p&)    Rem not last line in file
  1958.                     GOTO skip::
  1959.                 ELSE
  1960.                     GOTO end::
  1961.                 ENDIF
  1962.             ELSE
  1963. end::        IOSEEK(PEEKW(pa&+PR_IN%),6,offset&)
  1964.                 POKEB(pa&+PR_INPST%),0    Rem cancel multicommand lines
  1965.                 FREEALLOC(xpa&)
  1966. Rem                FREEALLOC&:(xpa&)
  1967.                 xpa&=0
  1968.                 _here$=""
  1969.                 GOTO Again::
  1970.             ENDIF
  1971.         ENDIF
  1972. Repeat::
  1973.         line$=_afind$:(line$)    Rem find aliases
  1974.         POKEW pa&+PR_INPST%,0    Rem reset input line status & pos
  1975.         _inpar%:(line$,pa&,_spec$)
  1976.         IF LEN(_here$)    Rem "here" redirection
  1977.             GOTO skip::
  1978.         ENDIF
  1979. Again::    Rem check for batch specific stuff
  1980.         IF PEEKB(pa&)=0
  1981.             GOTO Next::
  1982.         ENDIF
  1983.         txt$=LOWER$(PEEK$(PEEKL(pa&+PR_ARGV%)))
  1984.         IF txt$="if"
  1985.             _if%:(pa&)
  1986.             GOTO Again::
  1987.         ELSEIF ASC(txt$)=%:
  1988.             txt$=RIGHT$(PEEK$(PEEKL(pa&+PR_ARGV%)),LEN(txt$)-1)
  1989.             GOTO Here::
  1990.         ELSEIF  RIGHT$(txt$,2)="::"
  1991. Rem use argv%(1) as txt$ is the lower case version of it
  1992.             txt$=LEFT$(PEEK$(PEEKL(pa&+PR_ARGV%)),LEN(txt$)-2)
  1993. Here::    IF LEN(txt$) > 8
  1994.                 txt$=LEFT$(txt$,8)
  1995.             ENDIF
  1996.             Rem store the label
  1997. Rem            PRINT "Storing label:",txt$
  1998.             q&=labels&
  1999.             WHILE PEEKL(q&)
  2000.                 q&=PEEKL(q&)
  2001.                 IF PEEK$(q&+8)=txt$
  2002.                     PRINT "DEBUG: Duplicate label."
  2003.                     q&=0
  2004.                     BREAK
  2005.                 ENDIF
  2006.             ENDWH
  2007.             IF q&
  2008.                 Rem space for next pointer and pointer to line
  2009.                 POKEL q&,ALLOC((LEN(txt$)+24) AND $FFF0)
  2010. Rem                POKEL q&,ALLOC&:((LEN(txt$)+24) AND $FFF0,"run5")
  2011.                 q&=PEEKL(q&)
  2012.                 IF q&=0
  2013.                     RAISE -10
  2014.                 ENDIF
  2015.                 POKEL q&,0    Rem terminate list
  2016.                 POKEL q&+4,p&    Rem address of line
  2017.                 POKE$ q&+8,txt$    Rem label
  2018.             ENDIF
  2019.             IF txt$=label$
  2020.                 WaitLbl%=0
  2021.             ENDIF
  2022.         ELSEIF WaitLbl%    Rem do nothing, MUST be after :.. & ..:: check
  2023.         ELSEIF txt$="goto"
  2024.             IF PEEKB(pa&)<>2
  2025.                 PRINT "Bad GOTO"
  2026.                 BREAK
  2027.             ENDIF
  2028.             txt$=PEEK$(PEEKL(pa&+PR_ARGV%+4))
  2029.             Rem Search for txt$ in the list of labels
  2030. Rem            PRINT "Searching for label",txt$
  2031.             q&=PEEKL(labels&)
  2032.             WHILE q&
  2033. Rem                PRINT "Comparing with",PEEK$(q&+8)
  2034.                 IF PEEK$(q&+8)=txt$
  2035. Rem                    PRINT "Found!!!"
  2036.                     Rem found the label
  2037.                     p&=PEEKL(q&+4)    Rem stored line
  2038.                     Rem normal processing will get p&=PEEKL(p&)
  2039.                     BREAK
  2040.                 ENDIF
  2041.                 q&=PEEKL(q&)
  2042.             ENDWH
  2043.             IF q&=0    Rem not found
  2044.                 label$=txt$
  2045.                 WaitLbl%=1
  2046.             ENDIF
  2047.         ELSE
  2048.             ret%=_subpr%:(pa&)
  2049.             Rem this is the PARENT'S status!
  2050.             POKEW PEEKL(_curr&+PR_BACK%)+PR_STATUS%,ret%
  2051.             Rem store the status
  2052.         ENDIF
  2053. Next::
  2054.         _clrA:(pa&)
  2055.         IF PEEKB(pa&+PR_FLAG%)    Rem have an exit
  2056.             exit%=ret%    Rem should have just come from SHsubpr
  2057.             BREAK
  2058.         ENDIF
  2059.         IOYIELD
  2060.         IF _stat%<>-46                        Rem here, so it's just after a SHclrA
  2061.             IF _key%(1)=27
  2062. Rem                GIPRINT ERR$(-114)    Rem this will be done in calling procedure
  2063.                 BREAK
  2064.             ELSE
  2065.                 KEYA(_stat%,_key%())
  2066.             ENDIF
  2067.         ENDIF
  2068.  
  2069.         IF PEEKB(pa&+PR_INPST%)
  2070.             line$=RIGHT$(line$,LEN(line$)-PEEKB(pa&+PR_INPPS%))
  2071.             IF PEEKB(pa&+PR_INPST%)=2    Rem Bloody heck it's a pipe!
  2072.                 Rem There CAN be no way _in% is already set...
  2073.                 ret%=IOOPEN(#pa&+PR_IN%,_syspath$+NUM$(PEEKW(pa&+PR_NUM%),5)+"pipe."+CHR$(PEEKB(pa&+PR_LEV%)),$0120)
  2074.                 IF ret%    Rem check for original AND creation
  2075.                     RAISE ret%
  2076.                 ENDIF
  2077.             ENDIF
  2078.             GOTO Repeat::
  2079.         ENDIF
  2080. Skip::
  2081.         p&=PEEKL(p&)
  2082.     ENDWH
  2083.     IF WaitLbl%
  2084.         PRINT "No such label:",label$
  2085.     ENDIF
  2086.     GOTO DelArg
  2087. ErrTrap::
  2088.     ONERR off
  2089.     PRINT err$:(ERR)
  2090.     exit%=ERR
  2091. DelArg::    Rem common clean up - error and normal termination
  2092.     IF xpa&    Rem this shouldn't really happen
  2093.         PRINT "DEBUG: How did xpa& get set?"
  2094.         FREEALLOC(xpa&)
  2095. Rem        FREEALLOC&:(xpa&)
  2096. Rem        Rem We'll trust there are no arguments to clear!!
  2097.     ENDIF
  2098.     _clrA:(pa&)
  2099.     IF PEEKB(pa&+PR_LEV%)    Rem some pipes - delete
  2100.         TRAP DELETE _syspath$+NUM$(PEEKW(pa&+PR_NUM%),5)+"pipe.?"
  2101.         _here$=""    Rem how does this fit with no argv?
  2102.     ENDIF
  2103.     _curr&=PEEKL(pa&+PR_BACK%)
  2104. Rem here's where we'd restore ARGV
  2105.     FREEALLOC(pa&)
  2106. Rem    FREEALLOC&:(pa&)
  2107.     IOCLOSE(handle%)
  2108.     p&=labels&
  2109.     WHILE p&
  2110.         q&=PEEKL(p&)
  2111.         FREEALLOC(p&)
  2112. Rem        FREEALLOC&:(p&)
  2113.         p&=q&
  2114.     ENDWH
  2115.     p&=baseadr&
  2116.     WHILE p&
  2117.         q&=PEEKL(p&)
  2118.         FREEALLOC(p&)
  2119. Rem        FREEALLOC&:(p&)
  2120.         p&=q&
  2121.     ENDWH
  2122.     RETURN exit%
  2123. ENDP
  2124.  
  2125. PROC _expand$:(in$,f%)
  2126. Rem f% is set if it's the 2nd or more expansion
  2127. LOCAL buf$(255),attr%(8),ret%,file$(255),i%,x$(255),dlen%,dlist&,dcurr&
  2128. LOCAL n%,l%,end$(3),sep$(1),p&,q&,h%,s1%,s2%,dbuf$(255)
  2129.     ONERR ErrTrap::
  2130.     IF _stat%<>-46
  2131.         _key%(1)=0
  2132.         KEYA(_stat%,_key%())
  2133.     ENDIF
  2134.     IF parse%:(in$+"*",ADDR(buf$),ADDR(attr%()))
  2135.         GOTO exit::
  2136.     ENDIF
  2137. Rem    PRINT buf$,attr%(1),attr%(2),attr%(3),attr%(4),attr%(5),attr%(6),LEN(buf$),f%
  2138.     IF _opts%(varUNIXpath%)
  2139.         end$="/\:"
  2140.         sep$="/"
  2141.     ELSE
  2142.         end$="\:"
  2143.         sep$="\"
  2144.     ENDIF
  2145.  
  2146.     l%=LEN(in$)
  2147.     WHILE l%
  2148. Rem end$ contains the characters that could delimit the pathname
  2149.         IF LOC(end$,MID$(in$,l%,1))
  2150.             BREAK
  2151.         ENDIF
  2152.         l%=l%-1
  2153.     ENDWH
  2154.  
  2155.     Rem if the part we're "replacing" is . or .. and the device can have
  2156.     Rem    subdirectories, just return the input + separator
  2157.     IF RIGHT$(in$,LEN(in$)-l%)=".." OR RIGHT$(in$,LEN(in$)-l%)="."
  2158.         RETURN in$+sep$
  2159.     ENDIF
  2160. Rem    PRINT buf$
  2161. Rem    IF LOC(RIGHT$(buf$,LEN(buf$)-attr%(4)+1),":")
  2162. Rem        Rem this covers a whole load of badness - : in filename part
  2163. Rem        GOTO exit::
  2164. Rem    ENDIF
  2165.     dlen%=attr%(4)-1    Rem length of directory part
  2166.     x$=DIR$(buf$)
  2167. Rem workaround for the bug that if a directory is exactly 8 chars, a DIR┬áof
  2168. Rem the directory+* yields nothing. Retry without the wildcard
  2169.     IF LEN(x$)=0
  2170.         x$=LEFT$(buf$,LEN(buf$)-1)
  2171.         x$=DIR$(x$)
  2172.     ENDIF    
  2173.     IF LEN(x$)
  2174.         file$=RIGHT$(x$,LEN(x$)-dlen%)
  2175. Rem initialize the display list
  2176.         dlist&=ALLOC(16)
  2177. Rem        dlist&=ALLOC&:(16,"expand1")
  2178.         IF dlist&=0
  2179.             RAISE -10        Rem no memory
  2180.         ENDIF
  2181.         POKEL dlist&,0                Rem clear "next"┬ápointer
  2182.         dcurr&=dlist&                    Rem current position in display list
  2183.         POKEW dlist&+4,0        Rem set max width=0
  2184.         WHILE LEN(x$)
  2185.             IOYIELD
  2186.             IF _stat%<>-46
  2187.                 IF _key%(1)=27
  2188.                     GIPRINT ERR$(-114)
  2189.                     GOTO exit::
  2190.                 ELSE
  2191.                     KEYA(_stat%,_key%())
  2192.                 ENDIF
  2193.             ENDIF
  2194.             x$=RIGHT$(x$,LEN(x$)-dlen%)
  2195.             i%=1
  2196.             IF LEN(file$)                
  2197.                 WHILE i%<=LEN(file$)
  2198.                     IF UPPER$(MID$(x$,i%,1))<>UPPER$(MID$(file$,i%,1))
  2199.                         file$=LEFT$(file$,i%-1)
  2200.                         BREAK
  2201.                     ENDIF
  2202.                     i%=i%+1
  2203.                 ENDWH
  2204.             ELSEIF f%=0        Rem not showing expansions so exit if
  2205.                                         Rem file$ has "gone" completely
  2206.                 BREAK
  2207.             ENDIF
  2208.                     
  2209.             n%=n%+1
  2210.             POKEL dcurr&,ALLOC((LEN(x$)+20) AND $FFF0)
  2211. Rem            POKEL dcurr&,ALLOC&:((LEN(x$)+20) AND $FFF0,"expand2")
  2212. Rem length of file$ + 1 + 15 for 16 byte boundry + long pointer
  2213.             IF PEEKL(dcurr&)=0
  2214.                 RAISE -10
  2215.             ENDIF
  2216.             IF LEN(x$)>PEEKW(dlist&+4)
  2217.                 POKEW(dlist&+4),LEN(x$)
  2218.             ENDIF
  2219.             dcurr&=PEEKL(dcurr&)
  2220.             POKEL dcurr&,0                                    Rem clear next
  2221. Rem            PRINT "Storing",x$
  2222.             POKE$ dcurr&+4,x$
  2223.             x$=DIR$("")
  2224.         ENDWH
  2225.         IF n%>1    Rem more than a single match
  2226.             IF f%
  2227.                 i%=PEEKW(dlist&+4)+2
  2228.                 n%=i%
  2229.                 p&=PEEKL(dlist&)
  2230.                 PRINT
  2231.                 x$=""                Rem display list
  2232.                 WHILE p&
  2233.                     x$=x$+PEEK$(p&+4)
  2234.                     ret%=IOOPEN(h%,LEFT$(buf$,dlen%)+PEEK$(p&+4),$0400)    Rem read-only, shared
  2235.                     IF ret%=-9                    Rem file in use
  2236.                         x$=x$+"#"
  2237.                     ELSEIF ret%=0            Rem -9 is file in use
  2238.                         x$=x$+" "
  2239.                         IOCLOSE(h%)
  2240.                     ELSE
  2241.                         x$=x$+sep$
  2242.                     ENDIF
  2243.                     n%=n%+i%
  2244. Rem subtlety here. x$ is only appended with white space if the line ISN'T printed
  2245. Rem This has two functions - firstly it's more efficient and secondly it allows us
  2246. Rem to print nearer to the right-hand margin
  2247.                     IF n%>ScrInfo%(3)
  2248.                         PRINT x$
  2249.                         x$=""
  2250.                         n%=i%
  2251. Rem only test for escape key every so often. Else the slowdown IS noticable
  2252.                         IOYIELD
  2253.                         IF _stat%<>-46
  2254.                             IF _key%(1)=27
  2255.                                 GIPRINT ERR$(-114)
  2256.                                 GOTO exit::
  2257.                             ELSE
  2258.                                 KEYA(_stat%,_key%())
  2259.                             ENDIF
  2260.                         ENDIF
  2261.                     ELSE
  2262.                         x$=x$+REPT$(" ",i%-PEEKB(p&+4)-1)    
  2263.                     ENDIF
  2264.                     p&=PEEKL(p&)
  2265.                 ENDWH
  2266.                 IF n%<>i%
  2267.                     PRINT x$
  2268.                 ENDIF
  2269.             ELSE
  2270.                 PRINT CHR$(7);
  2271.             ENDIF
  2272.         ELSE
  2273. Rem            PRINT "Checking if",LEFT$(buf$,dlen%)+file$,"is a directory"
  2274.             ret%=xstat%:(LEFT$(buf$,dlen%)+file$)
  2275. Rem a bit of a hack!! Because the string has come via a DIR$ it MUST
  2276. Rem exist. But IOOPEN┬áon a directory in z: returns -33 so is incorrectly
  2277. Rem flagged. Workaround is to check the other way - ie. for the file
  2278. Rem It worked before as we checked for a file too
  2279.             IF ret%=0
  2280.                     file$=file$+" "
  2281.             ELSE
  2282.                     file$=file$+sep$
  2283.             ENDIF
  2284.         ENDIF
  2285.         x$=PrPath$:(LEFT$(in$,l%)+file$)
  2286.         GOTO Common::
  2287.     ENDIF
  2288. ErrTrap::
  2289.     ONERR off
  2290. exit::
  2291.     PRINT CHR$(7);
  2292.     x$=in$
  2293. Common::
  2294.     IF dlist&        Rem if the display list was ever used, clean it up
  2295.         p&=PEEKL(dlist&)
  2296.         WHILE p&
  2297.             q&=PEEKL(p&)
  2298. Rem        PRINT "Freeing:",PEEK$(p&+4)
  2299.             FREEALLOC(p&)
  2300. Rem            FREEALLOC&:(p&)
  2301.             p&=q&
  2302.         ENDWH
  2303.         FREEALLOC(dlist&)
  2304. Rem        FREEALLOC&:(dlist&)
  2305.     ENDIF
  2306.     RETURN x$
  2307. ENDP
  2308.  
  2309. PROC err$:(err%)
  2310.     VECTOR err%
  2311.         l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11
  2312.     ENDV
  2313.     IF err%=-111
  2314.         RETURN "Argument overflow"
  2315.     ELSEIF err%=-127
  2316.         RETURN "Wildcards not allowed"
  2317.     ELSEIF err%=-71
  2318.         RETURN "Buffer overflow"
  2319.     ELSEIF err%=-33
  2320.         RETURN "No such file or directory"
  2321.     ELSE
  2322.         RETURN ERR$(err%)
  2323.     ENDIF
  2324. l1::
  2325.     RETURN "Not a directory"
  2326. l2::
  2327.     RETURN "Must be a directory"
  2328. l3::
  2329.     RETURN "Not a plain file"
  2330. l4::
  2331.     RETURN "No match"
  2332. l5::
  2333.     RETURN "Input/output redirection invalid for batch files"
  2334. l6::
  2335.     RETURN "No such variable"
  2336. l7::
  2337.     RETURN "Missing '"
  2338. l8::
  2339.     RETURN "Bad ${..}"
  2340. l9::
  2341.     RETURN "Cannot write system read-only variables"
  2342. l10::
  2343.     RETURN "Bad redirection"
  2344. l11::
  2345.     RETURN "Not unique"
  2346. ENDP
  2347.  
  2348. PROC PrFmt$:(buf$,len%)
  2349.     IF LEN(buf$)<len%
  2350.         RETURN buf$+REPT$(" ",len%-LEN(buf$))
  2351.     ELSE
  2352.         RETURN buf$+" "
  2353.     ENDIF
  2354. ENDP
  2355.  
  2356. PROC _setw%:
  2357. Rem set the size of the text window
  2358. Rem - status and/or log window may be visible
  2359. LOCAL w%,width%
  2360.     width%=ScrWid%+TbVis%*TbWidth%
  2361.     SCREENINFO ScrInfo%()    Rem get current settings
  2362.     gUSE 1
  2363.     gSETWIN 0,0,width%,ScrHght%-_logh%
  2364.     w%=width%/ScrInfo%(7)        Rem screen width/char width
  2365.     IF w% < ScrInfo%(3)
  2366.         Rem screen has shrunk!
  2367.         IF width% > (w%*ScrInfo%(7)+ScrInfo%(1))
  2368.             Rem there are pixel columns visible that aren't part of the
  2369.             Rem    text screen. If these have pixels set they won't be
  2370.             Rem    scrolled off the screen. This will happen when the
  2371.             Rem    font is changed and the status window is displayed
  2372.             Rem    and this is redundant. It's needed when the status
  2373.             Rem    window is displayed without clearing the screen
  2374.             gAT w%*ScrInfo%(7)+ScrInfo%(1),0
  2375.             gFILL width%-w%*ScrInfo%(7)-ScrInfo%(1),ScrHght%-_logh%,1
  2376. Rem            PRINT width%-w%*ScrInfo%(7)
  2377.         ENDIF
  2378.     ENDIF
  2379.     SCREEN w%,(ScrHght%-_logh%-ScrInfo%(2))/ScrInfo%(8),1,1
  2380.     IF _logid% AND width%<>_logw%    Rem width changed
  2381.         gUSE _logid%
  2382.         gSETWIN 0,ScrHght%-_logh%,width%,_logh%
  2383.         _logw%=width%
  2384.         _log:(1,"")    Rem redraw log window
  2385.     ENDIF
  2386.     SCREENINFO ScrInfo%()    Rem save any new state
  2387. ENDP
  2388.  
  2389. PROC _log:(op%,val$)
  2390. Rem op%: 1 - create/redisplay log window
  2391. Rem op%: 2 - delete log window
  2392. Rem op%: 3 - new message
  2393. Rem op%: 4 - append message
  2394. Rem op%: 5 - scroll back
  2395. Rem op%: 6 - scroll forward
  2396. Rem op%: 7 - clear log
  2397. LOCAL a%(6),i%,width%
  2398. LOCAL p&,inf&(48),y%,h%,buf$(255),pos%
  2399.     ONERR ErrTrap::
  2400.     gUPDATE OFF
  2401.     width%=ScrWid%+TbVis%*TbWidth%
  2402.     VECTOR op%
  2403.         make,destroy,new,appnd,bck,forward,clear
  2404.     ENDV
  2405.     PRINT "Unknown operation",op%
  2406.     GOTO exit::
  2407. make::    Rem create     
  2408.     IF _logid%    Rem already exists, just redraw
  2409.         gUSE _logid%
  2410.         gAT 0,0: gFILL _logw%,_logh%,1    Rem clear old one
  2411.         GOTO Common::
  2412.     ELSE
  2413.         _logw%=width%
  2414.         buf$=GetVar$:("logheight")
  2415.         IF LEN(buf$)
  2416.             _logh%=VAL(buf$)
  2417.         ELSE
  2418.             _logh%=48
  2419.         ENDIF
  2420.         IF _logh%>ScrHght%/2
  2421.             _logh%=ScrHght%/2        Rem max out at half the screen height
  2422.         ENDIF
  2423.         a%(1)=ScrInfo%(1):a%(2)=ScrInfo%(2)
  2424.         a%(3)=a%(1)+ScrInfo%(3):a%(4)=a%(2)+ScrInfo%(4)
  2425.         IOW(-2,8,a%(),a%())
  2426.         i%=(ScrHght%-_logh%-ScrInfo%(2))/ScrInfo%(8)
  2427.         Rem i% = number of lines in new text window
  2428.         IF a%(6)>=i%
  2429.             gUSE 1
  2430.             gAT 0,ScrInfo%(2)
  2431.             gCOPY 1,0,(a%(6)-i%+1)*ScrInfo%(8)+ScrInfo%(2),width%,i%*ScrInfo%(8),3
  2432.             gAT 0,ScrInfo%(2)+i%*ScrInfo%(8)
  2433.             gFILL width%,ScrHght%-_logh%-i%*ScrInfo%(8)-ScrInfo%(2),1
  2434.             AT 1,i%
  2435.         ENDIF
  2436.         _setw%:    Rem here so SHlogid% ISN'T used/taken into account
  2437.                         Rem but we reset windows according to the new
  2438.                         Rem SHlogh%,SHlogw%
  2439.         _logid%=gCREATE(0,ScrHght%-_logh%,_logw%,_logh%,1,0)
  2440. Common::
  2441.         gBORDER 0
  2442.         gFONT KFontTimesNormal15&
  2443.         gSTYLE 1
  2444. Rem        gGREY 1
  2445. Rem        gAT 19,18: gPRINT "Shell3a"
  2446. Rem        gGREY 0
  2447.         gAT 98,0: gLINEBY 0,_logh%
  2448.         IF _logh%>17
  2449.             gAT 22,16: gPRINT "Shell 5"
  2450.             gAT 1,19
  2451.             gLINEBY 97,0
  2452.             IF _logh%>30
  2453.                 gFONT KFontArialNormal8&
  2454.                 gAT 4,30: gPRINT "v"+_VERSION$
  2455.                 gSTYLE 0
  2456.                 gAT 63,30: gPRINT "┬⌐1998"
  2457.                 IF _logh%>40
  2458.                     gSTYLE 32
  2459.                     gAT 39,39: gPRINT "Nick Murray"
  2460.                     IF _logh%>43
  2461.                         gAT 1,41
  2462.                         gLINEBY 97,0
  2463.                         gAT 0,42
  2464.                         gFILL 98,_logh%-42,1
  2465.                     ENDIF
  2466.                 ENDIF
  2467.             ENDIF
  2468.         ENDIF
  2469.     ENDIF
  2470.     y%=_logn%            Rem keep position in log
  2471.     GOTO Display::
  2472. destroy::
  2473.     IF _logid%
  2474.         gCLOSE _logid%
  2475.         _logw%=0
  2476.         _logh%=0
  2477.         _logid%=0
  2478.         _setw%:
  2479.     ENDIF
  2480.     GOTO exit::
  2481. new::
  2482.     IF _logl%
  2483.         p&=REALLOC(_logs&,(_logl%*4+17) AND $FFF0)
  2484.     ELSE
  2485.         p&=ALLOC(16)    Rem round 4 to 16!
  2486.     ENDIF
  2487.     IF p&
  2488.         _logs&=p&
  2489.     ELSE
  2490.         RAISE -10
  2491.     ENDIF
  2492.     buf$=RIGHT$(DATIM$,9)+": "+val$
  2493.     p&=ALLOC((LEN(buf$)+16) AND $FFF0)
  2494.     IF p&
  2495.         POKE$ p&,buf$
  2496.         POKEL _logs&+_logl%*4,p&
  2497.     ELSE
  2498.         RAISE -10
  2499.     ENDIF
  2500.     _logl%=_logl%+1    Rem number of items in log    
  2501.     y%=_logl%
  2502. Display::
  2503.     IF _logid%
  2504.         gUSE _logid%
  2505.         gFONT KFontArialNormal8&
  2506.         gSTYLE 0
  2507.         gINFO32 inf&()
  2508.         Rem height of log window in character units
  2509.         h%=(_logh%-2)/(inf&(3)+1)
  2510.         IF y%<h%
  2511.             y%=h%
  2512.         ENDIF
  2513.         IF y%>_logl%
  2514.             y%=_logl%
  2515.         ENDIF
  2516.         i%=y%-h%
  2517.         IF i%<0
  2518.             i%=0
  2519.         ENDIF
  2520.         pos%=9
  2521.         WHILE i%<y%
  2522.             gAT 100,pos%
  2523.             gPRINTB PEEK$(PEEKL(_logs&+i%*4)),_logw%-102
  2524.             pos%=pos%+inf&(3)+1
  2525.             i%=i%+1
  2526.         ENDWH
  2527.     ENDIF
  2528.     _logn%=y%    Rem both when displayed and when not
  2529.     GOTO exit::
  2530. appnd::
  2531.     IF _logl%
  2532.         buf$=PEEK$(PEEKL(_logs&+_logl%*4-4))
  2533.         IF LEN(buf$)+LEN(val$)>255
  2534.             GOTO new::    Rem new thing is too long
  2535.         ENDIF
  2536.         buf$=buf$+val$
  2537.         p&=REALLOC(PEEKL(_logs&+_logl%*4-4),(LEN(buf$)+16) AND $FFF0)
  2538.         IF p&
  2539.             POKEL _logs&+_logl%*4-4,p&    
  2540.         ELSE
  2541.             RAISE -10
  2542.         ENDIF
  2543.         POKE$ p&,buf$
  2544.     ELSE
  2545.         GOTO new::    Rem no previous line - start a new one
  2546.     ENDIF
  2547.     IF _logid%
  2548.         y%=_logl%
  2549.         GOTO Display::
  2550.     ENDIF
  2551.     GOTO exit::
  2552. bck::
  2553.     y%=_logn%-1
  2554.     GOTO Display::
  2555. forward::
  2556.     y%=_logn%+1
  2557.     GOTO Display::
  2558. clear::
  2559.     IF _logl%    Rem anything here?
  2560.         IF _logid%    Rem displayed?
  2561.             gUSE _logid%
  2562.             gAT 100,1
  2563.             gFILL _logw%-102,_logh%-2,1
  2564.         ENDIF
  2565.         WHILE _logl%
  2566. Rem            PRINT PEEK$(PEEKW(UADD(SHlogs%,SHlogl%*2-2)))
  2567.             FREEALLOC PEEKL(_logs&+_logl%*4-4)
  2568.             _logl%=_logl%-1
  2569.         ENDWH
  2570.         FREEALLOC _logs&
  2571.     ENDIF
  2572. exit::
  2573.     gUPDATE ON
  2574.     RETURN
  2575. ErrTrap::
  2576.     ONERR off
  2577.     PRINT err$:(ERR)
  2578.     gUPDATE ON
  2579. ENDP
  2580.  
  2581. PROC _nodes:
  2582. LOCAL i%,p&,d$(3)
  2583.     ONERR ErrTrap::
  2584.     p&=_dirB&        Rem Set current end
  2585.     POKEL p&,0        Rem denote limit of linked list
  2586.     _dirC&=0
  2587.     _log:(3,"Scanning for attached drives...")        Rem bold
  2588.     DO
  2589.         d$=CHR$(%A+i%)+":\"
  2590.         ONERR BadDir::
  2591.         DIR$(d$)        Rem if this fails we'll jump to BadDir::
  2592.         ONERR ErrTrap::    Rem back to normal exception handling
  2593.         _log:(4,"  "+LEFT$(d$,2))    Rem append
  2594. Rem Store on the heap the data about this dir
  2595. Rem format:
  2596. Rem 0: Pointer to next entry
  2597. Rem 4: Max 256 of path +size
  2598.         POKEL p&,ALLOC(260)
  2599. Rem        POKEL p&,ALLOC&:(260,"nodes1")
  2600.         IF PEEKL(p&)=0                Rem memory NOT allocated
  2601.             RAISE -10        Rem no system memory
  2602.         ENDIF
  2603.         p&=PEEKL(p&)
  2604.         POKEL p&,0
  2605.         POKE$ p&+4,d$
  2606.         IF d$="C:\"    Rem found starting directory
  2607.             _dirC&=p&
  2608.         ENDIF
  2609. next::
  2610.         i%=i%+1
  2611.     UNTIL i%>25
  2612.  
  2613.     IF _dirC&
  2614.         _cwd$=PEEK$(_dirC&+4)
  2615.     ELSE
  2616.         ALERT("No filesystems found!!")
  2617.         STOP
  2618.     ENDIF
  2619. Rem    _log:(3,"...completed.")
  2620.     RETURN
  2621. BadDir::
  2622.     ONERR ErrTrap::
  2623.     GOTO next::    
  2624. ErrTrap::
  2625.     ONERR off
  2626.     PRINT err$:(ERR)
  2627. ENDP
  2628.  
  2629. PROC _Err:(i%,n%)
  2630.     PRINT PrPath$:(PEEK$(argv&(i%))),"-",err$:(n%)
  2631. ENDP
  2632.  
  2633. PROC _cd%:(path$)
  2634. Rem change current directory. Error handling to be done in calling procedure
  2635. LOCAL buf$(255),ret%,attr%(8)
  2636.     parse%:(path$,ADDR(buf$),ADDR(attr%()))
  2637.     ret%=stat%:(ADDR(buf$))
  2638.     IF ret%<0
  2639.         RAISE ret%
  2640.     ELSEIF ret% AND (ret% AND 16)
  2641.         _cwd$=buf$
  2642.         _dirC&=PEEKL(ADDR(attr%())+12)
  2643.         POKE$ _dirC&+4,buf$
  2644.     ELSE
  2645.         RAISE 1            Rem not a directory
  2646.     ENDIF            
  2647.     IF _opts%(varcwdcmd%)
  2648.         buf$=GetVar$:("cwdcmd")
  2649.         IF LEN(buf$)
  2650.             _proc%:(buf$)
  2651.         ENDIF
  2652.     ENDIF
  2653. ENDP
  2654.  
  2655. PROC alias%:(n%)
  2656. REM narg%=1 - print all aliases
  2657. REM narg%=2 - print alias for arg2
  2658. REM narg%>2 - set alias of arg2 = arg3.....
  2659. LOCAL buf$(255),p&,i%,q&
  2660.     ONERR ErrTrap::
  2661.     IF n%=2
  2662.         p&=PEEKL(_atab&)
  2663.         WHILE p&
  2664.             IF PEEK$(PEEKL(p&+4))=PEEK$(argv&(2))
  2665.                 fprint%:(PrFmt$:(PEEK$(PEEKL(p&+4)),10)+PEEK$(PEEKL(p&+8)))
  2666.                 BREAK
  2667.             ENDIF
  2668.             p&=PEEKW(p&)
  2669.         ENDWH
  2670.         IF p&=0
  2671.             PRINT "Alias not found"
  2672.         ENDIF
  2673.     ELSEIF n%=1
  2674.         p&=PEEKL(_atab&)
  2675.         WHILE p&
  2676.             fprint%:(PrFmt$:(PEEK$(PEEKL(p&+4)),10)+PEEK$(PEEKL(p&+8)))
  2677.             p&=PEEKL(p&)
  2678.         ENDWH
  2679.     ELSE
  2680.         i%=3
  2681.         WHILE i%<=n%
  2682.             buf$=buf$+PEEK$(argv&(i%))+" "
  2683.             i%=i%+1
  2684.         ENDWH
  2685.         buf$=LEFT$(buf$,LEN(buf$)-1)    Rem remove last " "
  2686. Rem add new aliases from the start of the list so they are 1st
  2687.         p&=ALLOC(16)                    Rem new element - only needs 12
  2688. Rem        p&=ALLOC&:(16,"alias1")                    Rem new element - only needs 12
  2689.         IF p&=0
  2690.             RAISE -10
  2691.         ENDIF
  2692.         POKEL p&,PEEKW(_atab&)    Rem address of next element
  2693.         POKEL _atab&,p&                        Rem insert new 1st element
  2694.         q&=ALLOC((LEN(PEEK$(argv&(2)))+16) AND $FFF0)
  2695. Rem        q&=ALLOC&:((LEN(PEEK$(argv&(2)))+16) AND $FFF0,"alias2")
  2696.         IF q&=0    Rem 2nd alloc failed, clear 1st
  2697.             GOTO Common::
  2698.         ENDIF
  2699.         POKEL p&+4,q&
  2700.         POKE$ q&,PEEK$(argv&(2))
  2701.         q&=ALLOC((LEN(buf$)+16) AND $FFF0)
  2702. Rem        q&=ALLOC&:((LEN(buf$)+16) AND $FFF0,"alias3")
  2703.         IF q&=0    Rem 3rd failed, clear 1&2
  2704.             FREEALLOC(p&+4)        Rem clear allocation above
  2705. Rem            FREEALLOC&:(p&+4)        Rem clear allocation above
  2706. Common::
  2707.             POKEL _atab&,PEEKL(p&)    Rem reattach old list
  2708.             FREEALLOC(p&)
  2709. Rem            FREEALLOC&:(p&)
  2710.             RAISE -10
  2711.         ENDIF
  2712.         POKEL p&+8,q&
  2713.         POKE$ q&,buf$
  2714.     ENDIF            
  2715.     RETURN
  2716. ErrTrap::
  2717.     ONERR off
  2718.     PRINT err$:(ERR)
  2719.     RETURN ERR
  2720. ENDP
  2721.  
  2722. PROC at%:(n%)
  2723. LOCAL i%,x%,y%,buf$(255)
  2724.     ONERR ErrTrap::
  2725.     IF n%<>2
  2726. Usage::
  2727.         PRINT "Usage: at <xpos>,<ypos>"
  2728.         RETURN -2
  2729.     ELSE
  2730.         buf$=PEEK$(argv&(2))
  2731.         i%=LOC(buf$,",")
  2732.         IF i%
  2733.             AT VAL(LEFT$(buf$,i%-1)),VAL(RIGHT$(buf$,LEN(buf$)-i%))
  2734.         ELSE
  2735.             GOTO Usage::
  2736.         ENDIF
  2737.     ENDIF
  2738.     RETURN
  2739. ErrTrap::
  2740.     ONERR off
  2741.     PRINT err$:(ERR)
  2742.     RETURN ERR
  2743. ENDP
  2744.  
  2745. PROC banner%:(n%)
  2746. LOCAL id%,xlim&,y%,i&(48),d%(16),bit%,c%,line$(255),s%,f&,ch%,a&,l%,arg%
  2747. LOCAL flag%,count%
  2748.     ONERR ErrTrap::
  2749.     ch%=%#        Rem default character
  2750.     f&=10            Rem default font
  2751.     arg%=2
  2752.     WHILE arg%<=n%
  2753.         line$=PEEK$(argv&(arg%))
  2754.         IF line$="-c"
  2755.             IF arg%<n%    Rem at least one more argument
  2756.                 arg%=arg%+1
  2757.                 ch%=ASC(PEEK$(argv&(arg%)))
  2758.             ELSE
  2759.                 GOTO Usage::
  2760.             ENDIF
  2761.         ELSEIF line$="-s"
  2762.             IF arg%<n%    Rem at least one more argument
  2763.                 arg%=arg%+1
  2764.                 s%=EVAL(PEEK$(argv&(arg%)))
  2765.             ELSE
  2766.                 GOTO Usage::
  2767.             ENDIF
  2768.         ELSEIF line$="-f"
  2769.             IF arg%<n%    Rem at least one more argument
  2770.                 arg%=arg%+1
  2771.                 f&=EVAL(PEEK$(argv&(arg%)))
  2772.             ELSE
  2773.                 GOTO Usage::
  2774.             ENDIF
  2775.         ELSE            Rem none of the flags, so go ahead
  2776.             BREAK
  2777.         ENDIF
  2778.         arg%=arg%+1
  2779.     ENDWH
  2780.     IF arg%>n%    Rem no textual arguments
  2781. Usage::
  2782.         PRINT "Usage: banner [-c char] [-f font] [-s style] <string>"
  2783.         RETURN -2
  2784.     ENDIF
  2785.     WHILE arg%<n%            Rem concatenate remaining arguments
  2786.         arg%=arg%+1
  2787.         line$=line$+" "+PEEK$(argv&(arg%))
  2788.     ENDWH            
  2789.     id%=gCREATEBIT(256,32)
  2790.     gFILL 256,32,1
  2791.     gFONT f&
  2792.     gSTYLE s%
  2793.     gINFO32 i&()
  2794.     Rem i%(4)=font descent
  2795.     gAT 0,i&(3)-i&(4):gPRINT line$
  2796.     IF _out%        Rem output redirection
  2797.         l%=gX                Rem length=length of printed string
  2798.     ELSE
  2799.         l%=ScrInfo%(3)-1        Rem to the screen, so max out at text width
  2800.     ENDIF
  2801.     IF l%>255
  2802.         l%=255
  2803.     ENDIF
  2804.     IF i&(3)>32    Rem limit to 32 number of scanlines
  2805.         i&(3)=32
  2806.     ENDIF
  2807.     xlim&=ADDR(line$)+l%+1
  2808.     POKEB ADDR(line$),l%    Rem set length of string
  2809.     DO
  2810.         gPEEKLINE id%,0,y%,d%(),l%
  2811.         bit%=1
  2812.         c%=1
  2813.         a&=ADDR(line$)+1
  2814.         DO
  2815.             IF d%(c%) AND bit%
  2816.                 POKEB a&,ch%
  2817.                 flag%=1
  2818.             ELSE
  2819.                 POKEB a&,32
  2820.             ENDIF
  2821.             bit%=UADD(bit%,bit%)
  2822.             IF bit%=0
  2823.                 bit%=1
  2824.                 c%=c%+1
  2825.             ENDIF
  2826.             a&=a&+1
  2827.         UNTIL a&>xlim&
  2828.         IF flag%                Rem Something was printed on this line
  2829.             WHILE count%                Rem count% is number of empty lines
  2830.                 fprint%:("")
  2831.                 count%=count%-1    Rem this auto-magically sets count%=0
  2832.             ENDWH
  2833.             fprint%:(line$)
  2834.             flag%=0
  2835.         ELSE
  2836.             count%=count%+1
  2837.         ENDIF
  2838.         y%=y%+1
  2839.     UNTIL y%=i&(3)
  2840.     gCLOSE id%
  2841.     RETURN
  2842. ErrTrap::
  2843.     ONERR off
  2844.     PRINT err$:(ERR)
  2845.     IF id%
  2846.         gCLOSE id%
  2847.     ENDIF
  2848.     RETURN ERR
  2849. ENDP
  2850.  
  2851. PROC bg%:(n%)
  2852.     SETBACKGROUND:
  2853. ENDP
  2854.  
  2855. PROC bindkey%:(n%)
  2856. LOCAL c%,i%,char$(255),buf$(255),d$(255),f%,mod%,args%,sep%
  2857. LOCAL l%,dkeys$(20),keys$(10,6),vkeys$(30)
  2858.     keys$(1)="left"
  2859.     keys$(2)="right"
  2860.     keys$(3)="up"
  2861.     keys$(4)="down"
  2862.     keys$(5)="menu"
  2863.     keys$(6)="delete"
  2864.     keys$(7)="enter"
  2865.     keys$(8)="space"
  2866.     keys$(9)="esc"
  2867.     keys$(10)="tab"
  2868.     vkeys$="391392393394438008013032027009"
  2869.     dkeys$="08070506000103320413"
  2870.     ONERR ErrTrap::
  2871.     IF n%=1
  2872.         WHILE i%<10
  2873.             i%=i%+1
  2874.             l%=VAL(MID$(vkeys$,i%*3-2,3))
  2875.             IF PEEKB(_keys&+l%) <>  VAL(MID$(dkeys$,i%*2-1,2))
  2876.                 _kdisp%:(keys$(i%),_gact$:(PEEKB(_keys&+l%)),ADDR(d$))
  2877.             ENDIF
  2878.             IF l%<=32            Rem only for keys like escape, enter, space
  2879.                 IF PEEKB(_keys&+l%+256)
  2880.                     _kdisp%:("Shift-"+keys$(i%),_gact$:(PEEKB(_keys&+l%+256)),ADDR(d$))
  2881.                 ENDIF    
  2882.             ENDIF    
  2883.         ENDWH
  2884.         i%=1
  2885.         WHILE i%<27        Rem check for Ctrl-?
  2886.             IF PEEKB(_keys&+i%) AND i%<>9 AND i%<>13 AND i%<>8
  2887.                 _kdisp%:("Ctrl-"+CHR$(i%+96),_gact$:(PEEKB(_keys&+i%)),ADDR(d$))
  2888.             ENDIF
  2889.             IF PEEKB(_keys&+$100+i%) AND i%<>8            Rem delete-right
  2890.                 _kdisp%:("Shift-Ctrl-"+CHR$(i%+96),_gact$:(PEEKB(_keys&+$100+i%)),ADDR(d$))
  2891.             ENDIF
  2892.             IF PEEKB(_keys&+$100+i%+96)
  2893.                 _kdisp%:("Fn-"+CHR$(i%+96),_gact$:(PEEKB(_keys&+$100+i%+96)),ADDR(d$))
  2894.             ENDIF
  2895.             IF PEEKB(_keys&+$100+i%+64)
  2896.                 _kdisp%:("Shift-Fn-"+CHR$(i%+96),_gact$:(PEEKB(_keys&+$100+i%+64)),ADDR(d$))
  2897.             ENDIF
  2898.             i%=i%+1
  2899.         ENDWH
  2900.         IF LEN(d$)
  2901.             fprint%:(d$)
  2902.         ENDIF
  2903.         i%=1
  2904.         WHILE i%<17
  2905.             buf$=GetVar$:("macro"+NUM$(i%,2))
  2906.             IF LEN(buf$)
  2907.                 IF f%=0    Rem first one found
  2908.                     fprint%:("")
  2909.                     f%=1
  2910.                 ENDIF
  2911.                 fprint%:(PrFmt$:("macro"+NUM$(i%,2),8)+buf$)
  2912.             ENDIF
  2913.             i%=i%+1
  2914.         ENDWH
  2915.     ELSE    Rem n%>1
  2916.         args%=2    
  2917.         DO
  2918.             mod%=0
  2919.             char$=PEEK$(argv&(args%))
  2920.             sep%=LOC(char$,":")
  2921.             IF sep%
  2922.                 char$=LEFT$(char$,sep%-1)
  2923.             ENDIF
  2924.             i%=LOC(char$,"-")
  2925.             WHILE i%
  2926.                 buf$=LOWER$(LEFT$(char$,i%-1))
  2927.                 IF buf$="shift"
  2928.                     mod%=mod% OR $1
  2929.                 ELSEIF buf$="ctrl"
  2930.                     mod%=mod% OR $2
  2931.                 ELSEIF buf$="fn"
  2932.                     mod%=mod% OR $4
  2933.                 ELSE
  2934.                     buf$="Unknown modifier """+LEFT$(char$,i%-1)+""". Only Fn-, Shift- or Ctrl- are recognized"
  2935.                     GOTO Err::
  2936.                 ENDIF
  2937.                 char$=RIGHT$(char$,LEN(char$)-i%)
  2938.                 i%=LOC(char$,"-")
  2939.             ENDWH
  2940.             IF (mod% AND $6)=$6
  2941.                 buf$="Cannot have both Fn- and Ctrl- modifiers."
  2942.                 GOTO Err::
  2943.             ENDIF
  2944.             i%=1
  2945.             WHILE i%<11
  2946.                 IF LOWER$(char$)=keys$(i%)
  2947.                     c%=VAL(MID$(vkeys$,i%*3-2,3))
  2948.                     IF mod% AND $6                Rem special keys can only take shift modifiers
  2949.                         buf$="This key may only accept a Shift- modifier."
  2950.                         GOTO Err::
  2951.                     ENDIF
  2952.                     IF mod%                            Rem can only be shift
  2953.                         IF c%>32
  2954.                             buf$="This key can't take the Shift- modifier."
  2955.                             GOTO Err::
  2956.                         ELSE
  2957.                             c%=c%+256
  2958.                         ENDIF
  2959.                     ENDIF
  2960.                     GOTO Foundc::
  2961.                 ENDIF
  2962.                 i%=i%+1
  2963.             ENDWH
  2964.             IF LEN(char$)=1 AND mod%
  2965.                 c%=ASC(LOWER$(char$))
  2966.             ELSEIF ASC(char$)=%#
  2967.                 c%=VAL(RIGHT$(char$,LEN(char$)-1))
  2968.                 GOTO Foundc::
  2969.             ELSE
  2970.                 buf$="Key not recognised"
  2971.                 GOTO Err::
  2972.             ENDIF
  2973.             IF c%<%a OR c%>%z OR mod%=$1
  2974.                 buf$="This key can't accept this modifier."
  2975.                 GOTO Err::
  2976.             ENDIF
  2977.             IF mod% AND $2                Rem Ctrl
  2978.                 c%=c%-96                        Rem "a" -> 1, etc
  2979.                 IF mod% AND $1            Rem shift too
  2980.                     c%=c% + 256
  2981.                 ENDIF
  2982.             ELSEIF mod% AND $4    Rem can't be both Ctrl- and Fn-
  2983.                 c%=c%+256
  2984.                 IF mod% AND $1
  2985.                     c%=c% - 32                Rem lower to upper case
  2986.                 ENDIF
  2987.             ENDIF
  2988. Foundc::
  2989. Rem c% Now contains 0-511, the keycode that is to be redefined
  2990. Rem        IF c%<0 OR c%>511
  2991. Rem            RAISE -7
  2992. Rem        ENDIF
  2993.             IF sep%=0            Rem only have 1st part, just display the current value
  2994.                 _kdisp%:(PEEK$(argv&(args%)),_gact$:(PEEKB(_keys&+c%)),ADDR(d$))
  2995.             ELSE
  2996.                 char$=RIGHT$(PEEK$(argv&(args%)),PEEKB(argv&(args%))-sep%)
  2997.                 i%=0
  2998.                 IF LEN(char$)=1    Rem single key
  2999.                     i%=ASC(char$)    Rem redefine as a simple key press
  3000.                 ELSEIF LEN(char$)            Rem only allow if something is there, else 0
  3001.                     char$=LOWER$(char$)
  3002.                     i%=1
  3003.                     WHILE i%<13
  3004.                         IF char$=_act$(i%)
  3005.                             GOTO Found::
  3006.                         ENDIF
  3007.                         i%=i%+1
  3008.                     ENDWH
  3009.                     Rem not found
  3010.                     IF LEFT$(char$,5)="macro"
  3011.                         i%=VAL(RIGHT$(char$,LEN(char$)-5))
  3012.                         IF i%<1 OR i%>16
  3013.                             RAISE -7
  3014.                         ENDIF
  3015.                         i%=i%+15
  3016.                     ELSEIF ASC(char$)=%#    Rem a number??
  3017.                         i%=VAL(RIGHT$(char$,LEN(char$)-1))
  3018.                     ELSE    Rem auto-set key??
  3019.                         Rem find empty key??
  3020.                         i%=PEEKB(_keys&+c%)
  3021.                         IF i%>15 AND i%<32
  3022.                             buf$="macro"+NUM$(i%-15,2)
  3023.                             PRINT "Key is already set to:",buf$;", reusing."
  3024.                             FreeVar%:(buf$)
  3025.                             SetVar%:(buf$,char$)
  3026.                             GOTO Next::
  3027.                         ENDIF
  3028.                         i%=0
  3029.                         WHILE i%<16
  3030.                             i%=i%+1
  3031.                             IF LEN(GetVar$:("macro"+NUM$(i%,2)))
  3032.                                 CONTINUE
  3033.                             ENDIF
  3034.                             SetVar%:("macro"+NUM$(i%,2),char$)
  3035.                             PRINT "Storing """;char$;""" in ""macro";NUM$(i%,2);""""
  3036.                             i%=i%+15    Rem set for key i%
  3037.                             GOTO Found::
  3038.                         ENDWH
  3039.                         PRINT "No free macros.."
  3040.                         GOTO Next::
  3041.                     ENDIF
  3042.                 ENDIF
  3043. Found::
  3044.                 POKEB _keys&+c%,i%
  3045.             ENDIF
  3046. Next::
  3047.             args%=args%+1
  3048.         UNTIL args%>n%
  3049.         IF LEN(d$)
  3050.             fprint%:(d$)
  3051.         ENDIF
  3052.     ENDIF
  3053.     RETURN
  3054. Err::
  3055.     PRINT PEEK$(argv&(args%));":",buf$
  3056.     GOTO Next::
  3057. ErrTrap::
  3058.     ONERR off
  3059.     PRINT err$:(ERR)
  3060. ENDP
  3061.  
  3062. PROC cat%:(n%)
  3063. rem args=1 read from standard input
  3064. rem args>1 foreach argument print it
  3065. LOCAL d$(255),txt$(255)
  3066. LOCAL handle%,ret%,i%
  3067.     ONERR ErrTrap::
  3068.     IF n%>1 OR _in%        Rem we have files or stdin
  3069.         i%=2
  3070.         IF _in%
  3071.             handle%=_in%
  3072.             GOTO Loop::
  3073.         ENDIF
  3074.         WHILE i%<=n%
  3075.             IOYIELD
  3076.             IF _stat%<>-46
  3077.                 IF _key%(1)=27
  3078.                     BREAK
  3079.                 ELSE
  3080.                     KEYA(_stat%,_key%())
  3081.                 ENDIF
  3082.             ENDIF
  3083.             ret%=Fparse%:(ADDR(d$),PEEK$(argv&(i%)))
  3084.             IF ret%<0
  3085.                 _Err:(i%,ret%)
  3086.             ELSEIF ret% AND 16    Rem directory
  3087.                 _Err:(i%,3)
  3088.             ELSE
  3089.                 Rem open=$0000, text=$0020, share=$0400
  3090.                 ret%=IOOPEN(handle%,d$,$0420)
  3091.                 IF ret%<0
  3092.                     _Err:(i%,ret%)
  3093.                 ELSE
  3094. Loop::            WHILE 1
  3095.                         IOYIELD
  3096.                         IF _stat%<>-46
  3097.                             IF _key%(1)=27
  3098.                                 IF handle%<>_in%
  3099.                                     IOCLOSE(handle%)
  3100.                                 ENDIF
  3101.                                 RETURN
  3102.                             ELSE
  3103.                                 KEYA(_stat%,_key%())
  3104.                             ENDIF
  3105.                         ENDIF
  3106.                         ret%=IOREAD(handle%,ADDR(txt$)+1,255)
  3107.                         IF ret% = -36        Rem EOF
  3108.                             BREAK
  3109.                         ELSEIF ret%<0
  3110.                             _Err:(i%,ret%)
  3111.                         ELSE
  3112.                             POKEB ADDR(txt$),ret%
  3113.                             fprint%:(txt$)
  3114.                         ENDIF
  3115.                     ENDWH
  3116.                     IF _in%<>handle%
  3117.                         IOCLOSE(handle%)                                Rem what's the point in
  3118.                     ENDIF
  3119.                 ENDIF
  3120.             ENDIF
  3121.             i%=i%+1
  3122.         ENDWH
  3123.     ELSE
  3124. rem    Input from command line
  3125.         DO
  3126.             d$=""
  3127.             TRAP EDIT d$
  3128.             IF ERR=-114    Rem escape key
  3129.                 BREAK
  3130.             ENDIF
  3131.             fprint%:(d$)
  3132.         UNTIL 0
  3133.     ENDIF
  3134.     RETURN
  3135. ErrTrap::
  3136.     ONERR off
  3137.     PRINT err$:(ERR)
  3138.     RETURN ERR
  3139. ENDP
  3140.  
  3141. PROC cd%:(n%)
  3142.     ONERR ErrTrap::
  3143.     IF n%<>2
  3144.         PRINT "Usage: cd <directory>"
  3145.         RETURN -2
  3146.     ENDIF
  3147.     _cd%:(PEEK$(argv&(2)))
  3148.     RETURN
  3149. ErrTrap::
  3150.     ONERR off
  3151.     PRINT err$:(ERR)
  3152.     RETURN ERR
  3153. ENDP    
  3154.  
  3155. PROC chmod%:(n%)
  3156. LOCAL i%,buf$(255),flagSet&,ret%,bits%
  3157.     ONERR ErrTrap::
  3158. Rem 3 or more args. Arg 2 = absolute flags or - unset or + set
  3159. Rem firsr work out attribute changes
  3160.     IF n%<3
  3161. Usage::
  3162.         PRINT "Usage: chmod [+┬ª-][RHS] <filename>"
  3163.         RETURN -2
  3164.     ENDIF
  3165.     buf$=UPPER$(PEEK$(argv&(2)))
  3166.     IF ASC(buf$)=%+
  3167.         flagSet&=1
  3168.     ELSEIF ASC(buf$)<>%-
  3169.         GOTO Usage::
  3170.     ENDIF
  3171.     WHILE LEN(buf$)-1
  3172.         buf$=RIGHT$(buf$,LEN(buf$)-1)
  3173.         ret%=ASC(buf$)
  3174.         IF ret%=%R
  3175.             bits%=bits% OR 1
  3176.         ELSEIF ret%=%H
  3177.             bits%=bits% OR 2
  3178.         ELSEIF ret%=%S
  3179.             bits%=bits% OR 4
  3180.         ELSE
  3181. Rem            PRINT "Bad attribute:",CHR$(ret%)
  3182.             GOTO Usage::    
  3183.         ENDIF
  3184.     ENDWH
  3185.     i%=3
  3186.     WHILE i%<=n%
  3187.         IOYIELD
  3188.         IF _stat%<>-46
  3189.             IF _key%(1)=27
  3190.                 BREAK
  3191.             ELSE
  3192.                 KEYA(_stat%,_key%())
  3193.             ENDIF
  3194.         ENDIF
  3195.         ret%=Fparse%:(ADDR(buf$),PEEK$(argv&(i%)))
  3196.         IF ret%<0
  3197.             _Err:(i%,ret%)
  3198.         ELSE
  3199.             IF bits% AND $0001            Rem read-only
  3200.                 SETREADONLY:(buf$,flagSet&)
  3201.             ENDIF
  3202.             IF bits% AND $0002            Rem hidden
  3203.                 SETHIDDENFILE:(buf$,flagSet&)
  3204.             ENDIF
  3205.             IF bits% AND $0004            Rem system
  3206.                 SETSYSTEMFILE:(buf$,flagSet&)
  3207.             ENDIF
  3208.         ENDIF
  3209.         i%=i%+1
  3210.     ENDWH
  3211.     RETURN
  3212. ErrTrap::
  3213.     ONERR off
  3214.     PRINT err$:(ERR)
  3215.     RETURN ERR
  3216. ENDP
  3217.  
  3218. PROC cls%:(n%)
  3219.     CLS
  3220. ENDP
  3221.  
  3222. PROC cp%:(n%)
  3223.     ONERR ErrTrap::
  3224.     IF n%<3
  3225.         PRINT "Usage: cp <source> <destination>"
  3226.         RETURN -2
  3227.     ENDIF
  3228.     _cpmv%:(n%,0)
  3229.     RETURN
  3230. ErrTrap::
  3231.     ONERR off
  3232.     PRINT err$:(ERR)
  3233.     RETURN ERR
  3234. ENDP
  3235.  
  3236. PROC date%:(n%)
  3237.     fprint%:(DATIM$)
  3238. ENDP
  3239.  
  3240. PROC df%:(n%)
  3241. LOCAL p&,drive&,d$(9),buf$(81),id$(8)
  3242.     ONERR ErrTrap::
  3243.     buf$="No media Unknown  Floppy   Hard diskCD-ROM   RAM      Flash    ROM      Remote   "
  3244.     p&=PEEKL(_dirB&)
  3245.     fprint%:("Drive   Type       ID      Capacity     Used       Free")
  3246.     fprint%:(REPT$("ΓÇö",57))
  3247.     WHILE p&
  3248.         drive&=PEEKB(p&+5)-%A                Rem first character of pathname
  3249.         d$=MID$(buf$,(MEDIATYPE&:(drive&)*9)+1,9)
  3250.         id$=HEX$(VOLUMEUNIQUEID&:(drive&))
  3251.         fprint%:("  "+CHR$(drive&+%A)+"   "+d$+REPT$(" ",9-LEN(id$))+id$+NUM$(VOLUMESIZE&:(drive&),-8)+" KB"+NUM$(VOLUMESIZE&:(drive&)-VOLUMESPACEFREE&:(drive&),-8)+" KB"+NUM$(VOLUMESPACEFREE&:(drive&),-8)+" KB")
  3252.         p&=PEEKL(p&)
  3253.     ENDWH
  3254.     RETURN
  3255. ErrTrap::
  3256.     ONERR off
  3257.     PRINT err$:(ERR)
  3258.     RETURN ERR
  3259. ENDP
  3260.  
  3261. PROC dirs%:(n%)
  3262. LOCAL p&
  3263.     ONERR ErrTrap::
  3264. Rem initially, takes no arguments, COULD enhance later
  3265.     p&=_pushc&
  3266.     PRINT PrPath$:(_cwd$),
  3267.     IF p&
  3268.         DO
  3269.             PRINT PrPath$:(PEEK$(p&+8)),
  3270.             p&=PEEKL(p&+4)
  3271.         UNTIL p&=_pushc&                Rem until it loops round
  3272.     ENDIF
  3273.     PRINT
  3274.     RETURN
  3275. ErrTrap::
  3276.     ONERR off
  3277.     PRINT err$:(ERR)
  3278.     RETURN ERR
  3279. ENDP
  3280.  
  3281. PROC echo%:(n%)
  3282. LOCAL i%,buf$(255)
  3283.     ONERR ErrTrap::
  3284.     i%=2
  3285.     WHILE i%<=n%
  3286.         IOYIELD
  3287.         IF _stat%<>-46
  3288.             IF _key%(1)=27
  3289.                 BREAK
  3290.             ELSE
  3291.                 KEYA(_stat%,_key%())
  3292.             ENDIF
  3293.         ENDIF
  3294.         IF LEN(buf$)+LEN(PEEK$(argv&(i%))) >= 254    Rem test for overflow
  3295.             fprint%:(buf$)
  3296.             buf$=""
  3297.         ENDIF
  3298.         buf$=buf$+PEEK$(argv&(i%))
  3299.         i%=i%+1
  3300.         IF i%<=n%    Rem add " " unless it's the last entry
  3301.             buf$=buf$+" "
  3302.         ENDIF
  3303.     ENDWH
  3304.     fprint%:(buf$)
  3305.     RETURN
  3306. ErrTrap::
  3307.     ONERR off
  3308.     PRINT err$:(ERR)
  3309.     RETURN ERR
  3310. ENDP
  3311.  
  3312. PROC edit%:(n%)
  3313. LOCAL ret%,buf$(255),h%,size&,p&,base&,end&,c%,eol&,App&
  3314.     ONERR ErrTrap::
  3315.     IF n%<>2
  3316.         PRINT "Usage: edit <filename>"
  3317.         RETURN
  3318.     ENDIF
  3319.     eol&=&00000A0D            Rem 0D0A
  3320. Rem get thread ID of running process, so that a keypress event can be
  3321. Rem sent later. NOTE: this won't work if multiple shells are running!
  3322.     App&=GetThreadIDFromAppUID&:(ShellUID&,p&)
  3323.     ret%=Fparse%:(ADDR(buf$),PEEK$(argv&(2)))
  3324.     IF ret%=0                                                        Rem ordinary file
  3325.         ret%=IOOPEN(h%,buf$,$0600)                Rem random access opening first
  3326.         IF ret%
  3327.             RAISE ret%
  3328.         ENDIF
  3329.         IOSEEK(h%,2,size&)                                Rem get size
  3330.         IOCLOSE(h%)
  3331.         h%=0
  3332.     ELSEIF ret%<>-33                                        Rem No such file, so we'll create
  3333.         RAISE 3            Rem not a plain file - could be directory, or something else
  3334.     ENDIF
  3335.     base&=ALLOC(size&+8192)            Rem increase this to 8192 say?
  3336. Rem    base&=ALLOC&:(size&+8192,"edit")            Rem increase this to 8192 say?
  3337.     IF base&=0
  3338.         RAISE -10
  3339.     ENDIF
  3340.     IF size&                                                    Rem existing non-zero file
  3341.         p&=base&+4
  3342.         ret%=IOOPEN(h%,buf$,$0020)                    Rem sequential access
  3343.         IF ret%
  3344.             RAISE ret%
  3345.         ENDIF
  3346.         DO
  3347.             ret%=IOREAD(h%,p&,255)
  3348.             IF ret%<0
  3349.                 IF ret%=-36
  3350.                     BREAK
  3351.                 ELSE
  3352.                     RAISE ret%
  3353.                 ENDIF
  3354.             ELSE
  3355.                 p&=p&+ret%+1
  3356.                 POKEB p&-1,6                            Rem end of line in dEDITMULTI
  3357.             ENDIF
  3358.         UNTIL 0                                Rem break out above
  3359.         POKEL base&,p&-base&-4                Rem actual chars in buffer
  3360.         IOCLOSE(h%)
  3361.         h%=0
  3362.     ELSE
  3363.         POKEL base&,0                                Rem no data
  3364.     ENDIF    
  3365.     dINIT "",$1F
  3366.     dEDITMULTI base&,"",80,10,size&+8188        Rem 4 bytes LESS than was allocated
  3367.     dBUTTONS "Save",%s,"Cancel",27                Rem 27=Escape
  3368. Rem send the application an uparrow event (keycode 4105, scan 16)
  3369. Rem this deselects the file contents and moves cursor to top of file.
  3370.     SendKeyEventToApp&:(App&,0,4105,16,0,0)
  3371.     ret%=DIALOG
  3372.     IF ret%<>%s                                            Rem not saving, so ask for confirmation
  3373.         dINIT "Confirm discard of edits",0
  3374.         dBUTTONS "No",%n+$100,"Yes",%y+$100
  3375.         ret%=DIALOG
  3376.     ENDIF
  3377.     IF ret%=%s OR ret%=%n                    Rem save (%n from no to discard edits)
  3378. Rem write out new buffer
  3379.         PRINT "Saving",PrPath$:(buf$)
  3380.         ret%=IOOPEN(h%,buf$,$0302)
  3381.         IF ret%
  3382.             RAISE ret%
  3383.         ENDIF
  3384.         p&=base&+4
  3385.         end&=p&+PEEKL(base&)
  3386.         WHILE p& <= end&
  3387.             IF (PEEKB(p&)=6) OR c%=253 OR p&=end&
  3388. Rem newline in dialog or max characters or last character
  3389.                 IOWRITE(h%,p&-c%,c%)
  3390.                 IF p&<>end&
  3391.                     IOWRITE(h%,ADDR(eol&),2)        Rem 0D0A
  3392.                 ENDIF
  3393.                 c%=-(c%=253 AND PEEKB(p&)<>6)            Rem we use this character
  3394.             ELSE
  3395.                 c%=c%+1
  3396.             ENDIF
  3397.             p&=p&+1
  3398.         ENDWH
  3399.         IOCLOSE(h%)
  3400.     ENDIF
  3401. Rem    FREEALLOC&:(base&)
  3402.     FREEALLOC(base&)
  3403.     RETURN
  3404. ErrTrap::
  3405.     ONERR off
  3406.     IF h%
  3407.         IOCLOSE(h%)
  3408.     ENDIF
  3409.     IF base&
  3410. Rem        FREEALLOC&:(base&)
  3411.         FREEALLOC(base&)
  3412.     ENDIF
  3413.     PRINT err$:(ERR)
  3414.     RETURN ERR
  3415. ENDP
  3416.  
  3417. PROC exit%:(n%)
  3418. LOCAL ret%
  3419.     ONERR ErrTrap::
  3420.     IF n%>2
  3421.         PRINT "Usage: exit [code]"
  3422.         RETURN -2
  3423.     ELSEIF n%=2
  3424.         ret%=VAL(PEEK$(argv&(2)))
  3425.     ENDIF
  3426.     Rem flag it's an exit
  3427.     POKEB _curr&+PR_FLAG%,1
  3428.     RETURN ret%
  3429. ErrTrap::
  3430.     ONERR off
  3431.     PRINT err$:(ERR)
  3432.     RETURN ERR
  3433. ENDP
  3434.  
  3435. PROC hash%:(n%)
  3436. LOCAL p&,q&,buf$(255),i%,flag%,in$(255)
  3437.     ONERR ErrTrap::
  3438.     i%=2
  3439.     IF n%>1
  3440.         IF PEEK$(argv&(2))="-r"
  3441.             IF n%=2                                Rem no more arguments!
  3442.                 p&=PEEKL(_hash&)        Rem clear hash table
  3443.                 WHILE p&
  3444.                     q&=p&
  3445.                     p&=PEEKL(p&)
  3446.                     FREEALLOC(q&)
  3447.                 ENDWH
  3448.                 POKEL _hash&,0
  3449.                 RETURN
  3450.             ELSE
  3451.                 flag%=1
  3452.                 i%=3
  3453.             ENDIF
  3454.         ENDIF
  3455.         IF n%>i%
  3456.             PRINT "Usage: hash [-r] [command]"
  3457.             RETURN -2
  3458.         ENDIF
  3459.     ENDIF
  3460.     p&=_hash&
  3461.     IF i%>n%    Rem ran out of arguments, so show all entries
  3462.         WHILE PEEKL(p&)
  3463.             p&=PEEKL(p&)
  3464.             buf$=PEEK$(p&+4)
  3465.             fprint%:(PrFmt$:(buf$,14)+PrPath$:(PEEK$(p&+LEN(buf$)+5)))
  3466.         ENDWH
  3467.     ELSE    Rem display or remove a single entry
  3468.         in$=PEEK$(argv&(i%))
  3469.         i%=LOC(in$,".")
  3470.         WHILE PEEKL(p&)
  3471.             q&=p&
  3472.             p&=PEEKL(p&)
  3473.             buf$=PEEK$(p&+4)
  3474.             IF i%    Rem found some "." so do an exact match
  3475.                 IF LOWER$(buf$)=LOWER$(in$)
  3476.                     Goto Found::
  3477.                 ENDIF
  3478.             ELSE
  3479.                 IF in$=LEFT$(buf$,LEN(buf$)-4)
  3480. Found::        IF flag%
  3481.                         POKEL q&,PEEKL(p&)
  3482.                         FREEALLOC(p&)
  3483. Rem                        FREEALLOC&:(p&)
  3484.                         RETURN
  3485.                     ELSE
  3486.                         fprint%:(PrFmt$:(buf$,14)+PrPath$:(PEEK$(p&+LEN(buf$)+5)))
  3487.                         RETURN
  3488.                     ENDIF
  3489.                 ENDIF
  3490.             ENDIF
  3491.         ENDWH
  3492.         PRINT "Command not in the hashed list"
  3493.     ENDIF
  3494.     RETURN
  3495. ErrTrap::
  3496.     ONERR off
  3497.     PRINT err$:(ERR)
  3498.     RETURN ERR
  3499. ENDP
  3500.  
  3501. PROC help%:(n%)
  3502. Rem with no arguements, searches for shell5.hlp
  3503. Rem with an arguments searches for argument.hlp
  3504. Rem keeps a linked list of help files open (with associated thread ID's)
  3505. LOCAL file$(255),sep%,ret%,buf$(255),d$(255),p&,attr%(8),q&
  3506.     ONERR ErrTrap::
  3507.     IF n%=1
  3508.         file$="shell5"
  3509.         GOTO Search::
  3510.     ELSEIF n%=2
  3511.         file$=LOWER$(PEEK$(argv&(2)))
  3512.         IF file$="-l"
  3513.             file$=GetVar$:("helppath")+","
  3514.             WHILE LEN(file$)
  3515.                 sep%=LOC(file$,",")
  3516.                 ret%=Fparse%:(ADDR(buf$),LEFT$(file$,sep%-1))
  3517.                 IF (ret%<0) OR ((ret% AND 16)=0)    Rem Not directory
  3518.                     _log:(3,"Bad helppath component:  "+LEFT$(file$,sep%-1))
  3519.                 ELSE
  3520.                     d$=DIR$(buf$+"*.hlp")
  3521.                     WHILE LEN(d$)
  3522.                         fprint%:(RIGHT$(d$,LEN(d$)-LEN(buf$)))
  3523.                         d$=DIR$("")
  3524.                     ENDWH
  3525.                 ENDIF
  3526.                 file$=RIGHT$(file$,LEN(file$)-sep%)
  3527.             ENDWH
  3528.         ELSE
  3529. Search::            Rem search for file$ in list of open help files first
  3530.             p&=_help&
  3531.             WHILE PEEKL(p&)                Rem this way so p& is valid after loop
  3532.                 q&=p&                                Rem previous entry
  3533.                 p&=PEEKL(p&)
  3534.                 IF PEEK$(p&+8)=file$
  3535.                     ONERR Restart::
  3536.                     SETFOREGROUNDBYTHREAD&:(PEEKL(p&+4),0)
  3537.                     GOTO End::                    Rem nothing else to do, valid thread
  3538. Restart::        ONERR ErrTrap::            Rem thread no longer around, retry
  3539.                     POKEL q&,PEEKL(p&)    Rem glue to the next entry
  3540.                     FREEALLOC(p&)        Rem delete current entry
  3541. Rem                    FREEALLOC&:(p&)        Rem delete current entry
  3542.                     p&=q&
  3543.                 ENDIF
  3544.             ENDWH
  3545.             buf$=_path$:(GetVar$:("helppath"),file$,"hlp")
  3546.             IF LEN(buf$)
  3547.                 parse%:(buf$,ADDR(file$),ADDR(attr%()))    Rem this *can't* fail
  3548.                 file$=MID$(file$,attr%(4),attr%(5)-attr%(4))
  3549.                 POKEL p&,ALLOC((LEN(file$)+24) AND $FFF0)
  3550. Rem                POKEL p&,ALLOC&:(((LEN(file$)+24) AND $FFF0),"nman1")
  3551.                 Rem 4+4+LEN+1+15
  3552.                 IF PEEKL(p&)=0
  3553.                     RAISE -10
  3554.                 ENDIF
  3555.                 p&=PEEKL(p&)
  3556.                 POKEL p&,0
  3557.                 POKE$ p&+8,file$
  3558.                 POKEL p&+4,RUNAPP&:("Data",buf$,"",0)
  3559.             ELSE
  3560.                 PRINT "Can't find help file:",file$;".hlp"
  3561.             ENDIF
  3562.         ENDIF
  3563.     ELSE
  3564.         PRINT "Usage: help [-l] [help file]"
  3565.     ENDIF
  3566. End::
  3567.     RETURN
  3568. ErrTrap::
  3569.     ONERR off
  3570.     PRINT err$:(ERR)
  3571.     RETURN ERR
  3572. ENDP
  3573.  
  3574. PROC history%:(n%)
  3575. LOCAL p&,i%,Start%
  3576.     ONERR ErrTrap::
  3577.     p&=PEEKL(_hpos&)
  3578.     IF n%>2
  3579.         PRINT "Usage: history [no. of commands]"
  3580.         RETURN -2
  3581.     ELSEIF n%=2
  3582.         Start%=EVAL(PEEK$(argv&(2)))+1
  3583.         Rem check for terms < 0 or larger than the history size
  3584.         IF Start%<=_hrsz% AND Start%>0
  3585.             i%=_hnum%-Start%+2
  3586.             DO
  3587.                 p&=PEEKL(p&+4)
  3588.                 Start%=Start%-1
  3589.             UNTIL Start%=0
  3590.             GOTO Show::
  3591.         ENDIF
  3592.     ENDIF
  3593.     i%=_hnum%-_hrsz%+1
  3594. Show::
  3595.     WHILE p&<>_hpos&
  3596.         IF PEEKL(p&+8)
  3597.             fprint%:(GEN$(i%,-5)+" "+PEEK$(PEEKL(p&+8)))
  3598.         ENDIF
  3599.         IOYIELD
  3600.         IF _stat%<>-46
  3601.             IF _key%(1)=27
  3602.                 BREAK
  3603.             ELSE
  3604.                 KEYA(_stat%,_key%())
  3605.             ENDIF
  3606.         ENDIF
  3607.         p&=PEEKL(p&)
  3608.         i%=i%+1
  3609.     ENDWH
  3610.     RETURN
  3611. ErrTrap::
  3612.     ONERR off
  3613.     PRINT err$:(ERR)
  3614.     RETURN ERR
  3615. ENDP
  3616.  
  3617. PROC log%:(n%)
  3618. LOCAL i%,buf$(255)
  3619.     ONERR ErrTrap::
  3620.     IF n%=1
  3621.         IF _logid%=0
  3622.             _log:(1,"")    Rem if the log isn't displayed, display it
  3623.         ENDIF
  3624.     ELSE
  3625.         buf$=PEEK$(argv&(2))
  3626.         IF buf$="-t"
  3627.             _log:((_logid%=0)+2,"")
  3628.         ELSEIF buf$="-c"
  3629.             _log:(7,"")
  3630.         ELSEIF buf$="-b"
  3631.             _log:(5,"")
  3632.         ELSEIF buf$="-f"
  3633.             _log:(6,"")
  3634.         ELSEIF buf$="-r"
  3635.             _log:(2,"")
  3636.         ELSEIF buf$="-a" AND n%=3
  3637.             _log:(4,PEEK$(argv&(3)))
  3638.         ELSEIF n%=2
  3639.             _log:(3,buf$)
  3640.         ELSE
  3641.             PRINT "Usage: log [-c┬ª-b┬ª-f┬ª-r┬ª-a┬ª-t] [""message""]"
  3642.         ENDIF
  3643.     ENDIF
  3644.     RETURN
  3645. ErrTrap::
  3646.     ONERR off
  3647.     PRINT err$:(ERR)
  3648.     RETURN ERR
  3649. ENDP
  3650.  
  3651. PROC ls%:(n%)
  3652. LOCAL buf$(255),d$(255),ret%,attr%(8),dispFL%,i%,len%,usage&
  3653. LOCAL dlist&,dcurr&,p&,j%,m%,q&,sep$(1),h%,dbuf$(255),Fsize&,date&
  3654. LOCAL x%,Files%,pm$(2),dir%
  3655.     ONERR ErrTrap::
  3656.     i%=2
  3657.     WHILE i%<=n%
  3658.         buf$=PEEK$(argv&(i%))
  3659.         IF buf$="-l"
  3660.             dispFL%=1                Rem full info
  3661.         ELSEIF buf$="-s"
  3662.             dispFL%=2                Rem summary type info
  3663.         ELSE
  3664.             BREAK
  3665.         ENDIF
  3666.         i%=i%+1
  3667.     ENDWH
  3668.     IF i%>n%
  3669.         buf$=_cwd$
  3670.     ENDIF
  3671.     IF _opts%(varUNIXpath%)
  3672.         sep$="/"
  3673.     ELSE
  3674.         sep$="\"
  3675.     ENDIF
  3676.     date&=DTNOW&:                Rem create date/time object
  3677.     DO
  3678.         IOYIELD
  3679.         IF _stat%<>-46
  3680.             IF _key%(1)=27
  3681.                 GOTO Tidy::
  3682.             ELSE
  3683.                 KEYA(_stat%,_key%())
  3684.             ENDIF
  3685.         ENDIF
  3686.         usage&=0
  3687.         Files%=0
  3688.         ret%=parse%:(buf$,ADDR(buf$),ADDR(attr%()))
  3689.         IF ret%>=0 AND attr%(6)=0            Rem no wildcards
  3690.             ret%=stat%:(ADDR(buf$))
  3691.         ENDIF
  3692.         IF ret%<0
  3693.             IF i%>n%    Rem no directories given
  3694.                 PRINT err$:(ret%)
  3695.             ELSE
  3696.                 _Err:(i%,ret%)
  3697.             ENDIF
  3698.             GOTO Next::
  3699.         ELSEIF ret% AND 16        Rem directory
  3700.             len%=LEN(buf$)
  3701.             dbuf$="[Listing of "+PrPath$:(buf$)+"]"
  3702. Rem            fprint%:("[Listing of "+PrPath$:(buf$)+"]")
  3703.             dir%=1
  3704.         ELSE                                    Rem file
  3705.             len%=attr%(4)-1        Rem length of last part of the filename
  3706.             dir%=0
  3707.             dbuf$=""
  3708.         ENDIF
  3709.         d$=DIR$(buf$)
  3710. Rem empty - either empty directory or null wildcard
  3711. Rem initialize the display list
  3712.         dlist&=ALLOC(16)
  3713. Rem        dlist&=ALLOC&:(16,"ls1")
  3714.         IF dlist&=0
  3715.             RAISE -10        Rem no memory
  3716.         ENDIF
  3717.         POKEL dlist&,0                Rem clear "next"┬ápointer
  3718.         dcurr&=dlist&                    Rem current position in display list
  3719.         POKEW dlist&+4,0        Rem set max width=0
  3720.         WHILE LEN(d$)
  3721.             IOYIELD
  3722.             IF _stat%<>-46
  3723.                 IF _key%(1)=27
  3724.                     GOTO Tidy::
  3725.                 ELSE
  3726.                     KEYA(_stat%,_key%())
  3727.                 ENDIF
  3728.             ENDIF
  3729.             d$=RIGHT$(d$,LEN(d$)-len%)
  3730.             POKEL dcurr&,ALLOC((LEN(d$)+20) AND $FFF0)
  3731. Rem            POKEL dcurr&,ALLOC&:((LEN(d$)+20) AND $FFF0,"expand2")
  3732. Rem length of file$ + 1 + 15 for 16 byte boundry + long pointer
  3733.             IF PEEKL(dcurr&)=0
  3734.                 RAISE -10
  3735.             ENDIF
  3736.             IF LEN(d$)>PEEKW(dlist&+4)
  3737.                 POKEW(dlist&+4),LEN(d$)
  3738.             ENDIF
  3739.             dcurr&=PEEKL(dcurr&)
  3740.             POKEL dcurr&,0                                    Rem clear next
  3741.             POKE$ dcurr&+4,d$
  3742.             d$=DIR$("")
  3743.         ENDWH
  3744.         IF dispFL%                                                    Rem summary or long listing
  3745.             j%=PEEKW(dlist&+4)+8                            Rem space for size an <DIR>
  3746.         ELSE
  3747.             j%=PEEKW(dlist&+4)+2                            Rem space for size an <DIR>
  3748.         ENDIF        
  3749.         m%=j%
  3750.         p&=PEEKL(dlist&)
  3751.         IF LEN(dbuf$)
  3752.             fprint%:(dbuf$)                                            Rem listing of...
  3753.             dbuf$=""
  3754.         ENDIF
  3755.         WHILE p&
  3756.             d$=PEEK$(p&+4)
  3757.             dbuf$=dbuf$+d$
  3758.             ret%=IOOPEN(h%,LEFT$(buf$,len%)+d$,$0600)    Rem read-only, shared, random access
  3759.             IF ret%=0
  3760.                 IF dispFL%
  3761.                     Fsize&=0
  3762.                     IOSEEK(h%,2,Fsize&)
  3763. Rem                    Fsize&=GetFileSize&:(LEFT$(buf$,len%)+d$)
  3764.                     Files%=Files%+1
  3765.                     Usage&=Usage&+Fsize&
  3766.                     dbuf$=dbuf$+REPT$(" ",j%-LEN(d$)-8)
  3767.                     IF dispFL%=2                    Rem summary
  3768.                         IF Fsize&<100000
  3769.                             dbuf$=dbuf$+NUM$(Fsize&,-6)+"  "
  3770.                         ELSEIF Fsize&>10000000
  3771.                             dbuf$=dbuf$+NUM$(Fsize&/10000000,-5)+"  M"
  3772.                         ELSE
  3773.                             dbuf$=dbuf$+NUM$(Fsize&/1000,-5)+"K  "
  3774.                         ENDIF
  3775.                     ELSE
  3776.                         dbuf$=dbuf$+NUM$(Fsize&,-10)
  3777.                     ENDIF
  3778.                 ELSE
  3779.                     dbuf$=dbuf$+REPT$(" ",j%-LEN(d$))
  3780.                 ENDIF
  3781.                 IOCLOSE(h%)        Rem ret%=0, -9 is handled differently now
  3782.                 h%=0
  3783.             ELSEIF ret%=-9            Rem in use
  3784.                 IF dispFL%=0
  3785.                     dbuf$=dbuf$+"#"+REPT$(" ",j%-LEN(d$)-1)
  3786.                 ELSEIF dispFL%=2            Rem summary
  3787.                     dbuf$=dbuf$+REPT$(" ",j%-LEN(d$)-8)+"<OPEN>  "
  3788.                 ELSE                                    Rem full listing
  3789.                     dbuf$=dbuf$+REPT$(" ",j%-LEN(d$)-8)+"  <IN USE>"
  3790.                 ENDIF
  3791.             ELSE
  3792.                 IF dispFL%=0
  3793.                     dbuf$=dbuf$+sep$+REPT$(" ",j%-LEN(d$)-1)
  3794.                 ELSEIF dispFL%=2                        Rem summary listing
  3795.                     dbuf$=dbuf$+REPT$(" ",j%-LEN(d$)-8)+" <DIR>  "
  3796.                 ELSE
  3797.                     dbuf$=dbuf$+REPT$(" ",j%-LEN(d$)-8)+"     <DIR>"
  3798.                 ENDIF
  3799.             ENDIF
  3800.             IF dispFL%=1        Rem print attributes and date
  3801.                 d$=LEFT$(buf$,len%)+d$    Rem absolute pathname
  3802.                 IF ISREADONLY&:(d$)
  3803.                     dbuf$=dbuf$+"  R"
  3804.                 ELSE
  3805.                     dbuf$=dbuf$+"  -"
  3806.                 ENDIF
  3807.                 IF ISHIDDEN&:(d$)
  3808.                     dbuf$=dbuf$+"H"
  3809.                 ELSE
  3810.                     dbuf$=dbuf$+"-"
  3811.                 ENDIF
  3812.                 IF ISSYSTEM&:(d$)
  3813.                     dbuf$=dbuf$+"S"
  3814.                 ELSE
  3815.                     dbuf$=dbuf$+"-"
  3816.                 ENDIF
  3817.                 GETFILETIME:(d$,date&)
  3818.                 x%=DTHour&:(date&)
  3819.                 IF x%>11
  3820.                     x%=x%-12
  3821.                     pm$="pm"
  3822.                 ELSE
  3823.                     pm$="am"
  3824.                 ENDIF
  3825.                 IF x%=0
  3826.                     x%=12
  3827.                 ENDIF
  3828.                 dbuf$=dbuf$+NUM$(x%,-4)+":"
  3829.                 x%=DTMinute&:(date&)
  3830.                 dbuf$=dbuf$+CHR$(x%/10+48)+CHR$(x%-(x%/10)*10+48)+pm$
  3831.                 dbuf$=dbuf$+NUM$(DTDay&:(date&),-3)+"-"+MONTH$(DTMonth&:(date&))+NUM$(DTYear&:(date&),-5)
  3832.                 fprint%:(dbuf$)
  3833.                 dbuf$=""
  3834.             ELSE
  3835.                 m%=m%+j%
  3836.                 IF m%>=ScrInfo%(3)
  3837.                     fprint%:(dbuf$)
  3838.                     dbuf$=""
  3839.                     m%=j%
  3840.                 ENDIF
  3841.             ENDIF
  3842.             IOYIELD
  3843.             IF _stat%<>-46
  3844.                 IF _key%(1)=27
  3845.                     GOTO Tidy::
  3846.                 ELSE
  3847.                     KEYA(_stat%,_key%())
  3848.                 ENDIF
  3849.             ENDIF
  3850.             p&=PEEKL(p&)
  3851.         ENDWH
  3852.         p&=PEEKL(dlist&)        Rem do this separately so if an err or ESC happens
  3853.         WHILE p&                        Rem the clean-up routine will actually work!!
  3854.             q&=PEEKL(p&)
  3855.             FREEALLOC(p&)
  3856. Rem            FREEALLOC&:(p&)
  3857.             p&=q&
  3858.         ENDWH
  3859.         FREEALLOC(dlist&)
  3860. Rem        FREEALLOC&:(dlist&)
  3861.         dlist&=0
  3862.         IF m%<>j%
  3863.             fprint%:(dbuf$)
  3864.         ENDIF
  3865.         IF dir% AND (dispFl%<>0)        Rem size only recorded in -s or -l modes
  3866.             fprint%:(NUM$(Files%,4)+" File(s), "+NUM$(usage&,10)+" Bytes,"+NUM$(VOLUMESPACEFREE&:(ASC(buf$)-%A),10)+" KB free.")
  3867.         ENDIF
  3868. Next::
  3869.         i%=i%+1
  3870.         IF i%<=n%
  3871.             buf$=PEEK$(argv&(i%))
  3872.         ENDIF
  3873.     UNTIL i%>n%
  3874.     DTDELETEDATETIME:(date&)
  3875.     RETURN
  3876. ErrTrap::
  3877.     ONERR off
  3878.     PRINT err$:(ERR)
  3879. Tidy::
  3880.     IF date&
  3881.         DTDELETEDATETIME:(date&)
  3882.     ENDIF    
  3883.     IF h%
  3884.         IOCLOSE(h%)
  3885.     ENDIF
  3886.     IF dlist&
  3887.         p&=PEEKL(dlist&)
  3888.         WHILE p&
  3889.             q&=PEEKL(p&)
  3890.             FREEALLOC(p&)
  3891. Rem            FREEALLOC&:(p&)
  3892.             p&=q&
  3893.         ENDWH
  3894.         FREEALLOC(dlist&)
  3895. Rem        FREEALLOC&:(dlist&)
  3896.         dlist&=0
  3897.     ENDIF
  3898.     RETURN ERR
  3899. ENDP
  3900.  
  3901. PROC mkdir%:(n%)
  3902. LOCAL i%,buf$(255),ret%
  3903.     ONERR ErrTrap::
  3904.     i%=2
  3905.     IF n%<2
  3906.         PRINT "Usage: mkdir <directory>"
  3907.         RETURN -2
  3908.     ENDIF
  3909.     WHILE i%<=n%
  3910.         IOYIELD
  3911.         IF _stat%<>-46
  3912.             IF _key%(1)=27
  3913.                 BREAK
  3914.             ELSE
  3915.                 KEYA(_stat%,_key%())
  3916.             ENDIF
  3917.         ENDIF
  3918.         ret%=Fparse%:(ADDR(buf$),PEEK$(argv&(i%)))
  3919.         IF ret%<0 AND ret%<>-33
  3920.             _Err:(i%,ret%)
  3921.         ELSE
  3922.             TRAP MKDIR buf$
  3923.             IF ERR
  3924.                 _Err:(i%,ERR)
  3925.             ENDIF
  3926.         ENDIF
  3927.         i%=i%+1
  3928.     ENDWH
  3929.     RETURN
  3930. ErrTrap::
  3931.     ONERR off
  3932.     PRINT err$:(ERR)
  3933.     RETURN ERR
  3934. ENDP
  3935.  
  3936. PROC more%:(n%)
  3937.     LOCAL txt$(255),d$(255)
  3938.     LOCAL handle%,ret%,row%,key%,i%,files%
  3939.     ONERR ErrTrap::
  3940.     IF n%<2 AND _in%=0
  3941.         PRINT "Usage: more <filename>"
  3942.         RETURN -2
  3943.     ENDIF
  3944.     i%=2
  3945.     IF n%=1 AND _in%    Rem only stdin
  3946.         handle%=_in%
  3947.         row%=1
  3948.         GOTO loop::
  3949.     ENDIF
  3950.     WHILE i%<=n%
  3951.         ret%=Fparse%:(ADDR(d$),PEEK$(argv&(i%)))
  3952.         IF ret%<0
  3953.             _Err:(i%,ret%)
  3954.         ELSEIF ret% AND 16    Rem this is a directory
  3955.             _Err:(i%,3)
  3956.         ELSE
  3957.             IF files%
  3958.                 PRINT
  3959.                 AT 1,ScrInfo%(4)
  3960.                 STYLE _style% OR $4
  3961.                 PRINT "Next file:";d$
  3962.                 STYLE _style%
  3963.                 AT 1,ScrInfo%(4)
  3964.                 key%=GET
  3965.                 IF key%=27 OR key%=%q
  3966.                     RETURN
  3967.                 ENDIF
  3968.                 CLS
  3969.             ENDIF
  3970.             row%=1
  3971.             files%=files%+1
  3972.             REM open=$0000, text=$0020, share=$0400
  3973.             ret%=IOOPEN(handle%,d$,$0420)
  3974.             IF ret%<0
  3975.                 _Err:(i%,ret%)
  3976.             ELSE
  3977. Loop::        WHILE 1
  3978.                     IOYIELD
  3979.                     IF _stat%<>-46
  3980.                         IF _key%(1)=27
  3981.                             GOTO quit::
  3982.                         ELSE
  3983.                             KEYA(_stat%,_key%())
  3984.                         ENDIF
  3985.                     ENDIF
  3986.                     ret%=IOREAD(handle%,ADDR(txt$)+1,255)
  3987.                     IF ret%<0
  3988.                         IF ret%<>-36                REM not EOF
  3989.                             RAISE ret%
  3990.                         ENDIF
  3991.                         BREAK
  3992.                     ENDIF
  3993.                     POKEB ADDR(txt$),ret%
  3994.                     PRINT txt$
  3995.                     row%=row%+1
  3996.                     IF row%>=ScrInfo%(4)
  3997.                         STYLE _style% OR $4
  3998.                         PRINT "<MORE>";PrPath$:(d$)
  3999.                         STYLE _style%
  4000.                         AT 1,ScrInfo%(4)
  4001.                         key%=GET
  4002.                         IF key%=27 OR key%=%q
  4003.                             GOTO quit::
  4004.                         ELSEIF key%=13
  4005.                             row%=row%-1
  4006.                         ELSEIF key%=%n
  4007.                             BREAK
  4008.                         ELSE
  4009.                             row%=1
  4010.                         ENDIF
  4011.                         PRINT REPT$(" ",ScrInfo%(3))    Rem blank out <More>...
  4012.                         AT 1,ScrInfo%(4)
  4013.                     ENDIF
  4014.                 ENDWH
  4015.                 IF handle%<>_in%
  4016.                     IOCLOSE(handle%)
  4017.                 ENDIF
  4018.             ENDIF
  4019.         ENDIF
  4020.         i%=i%+1
  4021.     ENDWH
  4022.     RETURN
  4023. ErrTrap::
  4024.     ONERR off
  4025.     PRINT err$:(ERR)
  4026. quit::
  4027.     IF handle%<>_in%
  4028.         IOCLOSE(handle%)
  4029.     ENDIF
  4030.     RETURN ERR
  4031. ENDP
  4032.  
  4033. PROC mv%:(n%)
  4034.     ONERR ErrTrap::
  4035.     IF n%<3
  4036.         PRINT "Usage: mv <source> <destination>"
  4037.         RETURN -2
  4038.     ENDIF
  4039.     _cpmv%:(n%,1)
  4040.     RETURN ERR
  4041. ErrTrap::
  4042.     ONERR off
  4043.     PRINT err$:(ERR)
  4044.     RETURN ERR
  4045. ENDP
  4046.  
  4047. PROC od%:(n%)
  4048. LOCAL d$(255),h$(255),char$(42),input$(255),c%
  4049. LOCAL handle%,ret%,row%,key%,i%,files%,items%,j%,offset%
  4050.     ONERR ErrTrap::
  4051.     IF n%<2 AND _in%=0
  4052.         PRINT "Usage: od <filename>"
  4053.         RETURN -2
  4054.     ENDIF
  4055.     i%=2
  4056.     items%=(ScrInfo%(3)-2)/4    Rem columns
  4057.     offset%=ScrInfo%(3)-items%-1
  4058.     IF _in%
  4059.         row%=1
  4060.         handle%=_in%
  4061.         GOTO loop::
  4062.     ENDIF
  4063.     WHILE i%<=n%
  4064.         ret%=Fparse%:(ADDR(d$),PEEK$(argv&(i%)))
  4065.         IF ret%<0
  4066.             _Err:(i%,ret%)
  4067.             GOTO Next::
  4068.         ELSEIF ret% AND 16    Rem this is a directory
  4069.             _Err:(i%,3)
  4070.             GOTO Next::
  4071.         ENDIF
  4072.         IF files%
  4073.             PRINT
  4074.             AT 1,ScrInfo%(4)
  4075.             STYLE _style% OR 4
  4076.             PRINT "Next file:";d$
  4077.             STYLE _style%
  4078.             AT 1,ScrInfo%(4)
  4079.             key%=GET
  4080.             IF key%=27 OR key%=%q
  4081.                 RETURN
  4082.             ENDIF
  4083.             CLS
  4084.         ENDIF
  4085.         row%=1
  4086.         files%=1
  4087.         REM open=$0000, binary=$0000, share=$0400
  4088.         ret%=IOOPEN(handle%,d$,$0400)
  4089.         IF ret%<0
  4090.             _Err:(i%,ret%)
  4091.         ELSE
  4092. loop::    WHILE 1
  4093.                 j%=items%
  4094.                 h$=""
  4095.                 char$=""
  4096.                 WHILE j%
  4097.                     IOYIELD
  4098.                     IF _stat%<>-46
  4099.                         IF _key%(1)=27
  4100.                             GOTO quit::
  4101.                         ELSE
  4102.                             KEYA(_stat%,_key%())
  4103.                         ENDIF
  4104.                     ENDIF
  4105.                     IF LEN(input$)=0    Rem end of last line
  4106.                         ret%=IOREAD(handle%,ADDR(input$)+1,255)
  4107.                         IF ret%<0
  4108.                             IF ret%<>-36
  4109.                                 RAISE ret%
  4110.                             ELSE
  4111.                                 IF LEN(h$)
  4112.                                     PRINT h$+REPT$(" ",offset%-LEN(h$))+char$
  4113.                                 ENDIF
  4114.                                 GOTO Endfile::
  4115.                             ENDIF
  4116.                         ENDIF
  4117.                         POKEB ADDR(input$),ret%
  4118.                         IF _in%    Rem stdin - text rather than binary
  4119.                             input$=input$+CHR$(13)+CHR$(10)    Rem add linefeed/newline
  4120.                         ENDIF
  4121.                     ENDIF
  4122.                     c%=ASC(input$)
  4123.                     input$=RIGHT$(input$,LEN(input$)-1)
  4124.                     IF c%<16
  4125.                         h$=h$+"0"
  4126.                     ENDIF
  4127.                     h$=h$+HEX$(c%)+" "
  4128.                     IF c%<32
  4129.                         c%=%?
  4130.                     ENDIF
  4131.                     char$=char$+CHR$(c%)
  4132.                     j%=j%-1
  4133.                 ENDWH
  4134.                 PRINT h$+REPT$(" ",offset%-LEN(h$))+char$
  4135.                 row%=row%+1
  4136.                 IF row%>=ScrInfo%(4)
  4137.                     STYLE _style% OR $4
  4138.                     PRINT "<OD>";PrPath$:(d$)
  4139.                     STYLE _style%
  4140.                     AT 1,ScrInfo%(4)
  4141.                     key%=GET
  4142.                     IF key%=27 OR key%=%q
  4143.                         GOTO quit::
  4144.                     ELSEIF key%=13
  4145.                         row%=row%-1
  4146.                     ELSEIF key%=%n
  4147.                         BREAK
  4148.                     ELSE
  4149.                         row%=1
  4150.                     ENDIF
  4151.                     PRINT REPT$(" ",ScrInfo%(3))    Rem blank out <Od>...
  4152.                     AT 1,ScrInfo%(4)
  4153.                 ENDIF
  4154.             ENDWH
  4155. EndFile::
  4156.             IF handle%<>_in%
  4157.                 IOCLOSE(handle%)
  4158.             ENDIF
  4159.         ENDIF
  4160. Next::
  4161.         i%=i%+1
  4162.     ENDWH
  4163.     RETURN
  4164. ErrTrap::
  4165.     ONERR off
  4166.     PRINT err$:(ERR)
  4167. quit::
  4168.     IF handle%<>_in%
  4169.         IOCLOSE(handle%)
  4170.     ENDIF
  4171.     RETURN ERR
  4172. ENDP
  4173.  
  4174. PROC pause%:(n%)
  4175.     ONERR ErrTrap::
  4176.     IF n%=1
  4177.         PAUSE 0
  4178.     ELSEIF n%=2
  4179.         PAUSE VAL(PEEK$(argv&(2)))
  4180.     ELSE
  4181.         PRINT "Usage: pause [interval]"
  4182.         RETURN -2
  4183.     ENDIF
  4184.     RETURN
  4185. ErrTrap::
  4186.     ONERR off
  4187.     PRINT err$:(ERR)
  4188.     RETURN ERR
  4189. ENDP
  4190.  
  4191. PROC popd%:(n%)
  4192. LOCAL p&,old$(255)
  4193.     ONERR ErrTrap::
  4194.     IF _pushc&
  4195.         p&=PEEKL(_pushc&+4)
  4196.         old$=PEEK$(_pushc&+8)
  4197.         POKEL PEEKL(_pushc&)+4,p&        Rem glue next previous
  4198.         POKEL p&,PEEKL(_pushc&)                Rem glue previous next
  4199.         FREEALLOC(_pushc&)
  4200. Rem        FREEALLOC&:(_pushc&)
  4201.         IF p&=_pushc&
  4202.             _pushc&=0
  4203.         ELSE
  4204.             _pushc&=p&
  4205.         ENDIF
  4206.         _cd%:(old$)
  4207.     ELSE
  4208.         PRINT "directory stack empty"
  4209.     ENDIF
  4210.     RETURN
  4211. ErrTrap::
  4212.     ONERR off
  4213.     PRINT ERR$(ERR)
  4214.     RETURN ERR
  4215. ENDP
  4216.  
  4217. Rem this code is really rather nasty in places!!
  4218. PROC pushd%:(n%)
  4219. LOCAL p&,d$(255),q&,old$(255),i%,newp&
  4220.     ONERR ErrTrap::
  4221.     IF n%<>2
  4222.         PRINT "Usage: pushd <+n┬ª-n┬ªdirectory>"
  4223.         RETURN
  4224.     ENDIF
  4225.     d$=PEEK$(argv&(2))
  4226.     p&=_pushc&
  4227.     IF ASC(d$)=%-
  4228.         IF p&=0
  4229.             GOTO Empty::
  4230.         ELSE
  4231.             i%=EVAL(RIGHT$(d$,LEN(d$)-1))
  4232.             p&=PEEKL(p&)
  4233.             WHILE (i%>0) AND (p&<>_pushc&)
  4234.                 i%=i%-1
  4235.                 p&=PEEKL(p&)
  4236.             ENDWH
  4237.             IF (p&=_pushc&) AND (i%>0)            Rem we didn't shift all the way....
  4238.                 IF i%<>1            Rem i%=1 we do nothing, drop out to end
  4239.                     GOTO BadIndex::
  4240.                 ENDIF
  4241.             ELSE
  4242.                 GOTO Del_Old::
  4243.             ENDIF
  4244.         ENDIF
  4245.     ELSEIF ASC(d$)=%+
  4246.         IF p&=0
  4247.             GOTO Empty::
  4248.         ELSE
  4249.             i%=EVAL(RIGHT$(d$,LEN(d$)-1))-1
  4250.             IF i%>=0
  4251.                 WHILE i%>0
  4252.                     p&=PEEKL(p&+4)
  4253.                     IF p&=_pushc&
  4254.                         BREAK
  4255.                     ENDIF
  4256.                     i%=i%-1
  4257.                 ENDWH
  4258.                 IF (p&=_pushc&) AND (i%>0)            Rem we didn't shift all the way....
  4259.                     GOTO BadIndex::
  4260.                 ELSE
  4261. Del_Old::        old$=_cwd$
  4262.                     _cd%:(PEEK$(p&+8))                            Rem if this fails...
  4263.                     IF p&=PEEKL(p&)                                        Rem only one entry
  4264.                         FREEALLOC(p&)
  4265. Rem                        FREEALLOC&:(p&)
  4266.                         p&=0
  4267.                         newp&=0
  4268.                         GOTO Common::
  4269.                     ENDIF
  4270.                     POKEL PEEKL(p&)+4,PEEKL(p&+4)        Rem glue next previous
  4271.                     POKEL PEEKL(p&+4),PEEKL(p&)                Rem glue previous next
  4272.                     newp&=PEEKL(p&+4)
  4273.                     FREEALLOC(p&)
  4274. Rem                    FREEALLOC&:(p&)
  4275.                     IF p&=_pushc&
  4276.                         p&=newp&
  4277.                     ELSE
  4278.                         p&=_pushc&
  4279.                     ENDIF
  4280.                     GOTO Common::
  4281.                 ENDIF    
  4282.             ENDIF
  4283.         ENDIF
  4284.     ELSE
  4285.         old$=_cwd$                Rem save current cwd$
  4286.         _cd%:(d$)                    Rem this will either work or will have RAISE'd
  4287. Common::
  4288.         q&=ALLOC((LEN(old$)+24) AND $FFF0)
  4289. Rem        q&=ALLOC&:((LEN(old$)+24) AND $FFF0,"pushd1")
  4290.         Rem 4+4+LEN(old$)+1+15
  4291.         Rem set q& so that if a memory allocation error occurs the list is OK
  4292.         IF q&=0
  4293.             RAISE -10
  4294.         ENDIF
  4295.         IF p&                                                    Rem NOT first entry or just shifting
  4296.             POKEL q&,PEEKL(p&)                Rem glue to NEXT
  4297.             POKEL PEEKL(q&)+4,q&            Rem glue NEXT to here
  4298.         ELSE                                                    Rem FIRST entry
  4299.             p&=q&
  4300.         ENDIF
  4301.         POKEL q&+4,p&                            Rem glue to PREVIOUS
  4302.         POKEL p&,q&                                Rem glue PREVIOUS to here
  4303.         POKE$ q&+8,old$
  4304. Rem For -0 and +(n-1), we actually want SH_pushc& to be the new entry..
  4305.         IF (newp&<>0) AND (newp&<>_pushc&)
  4306.             _pushc&=newp&
  4307.         ELSE
  4308.             _pushc&=q&                            Rem set new current pointer
  4309.         ENDIF
  4310.     ENDIF
  4311.     dirs%:(1)
  4312. End::
  4313.     RETURN
  4314. BadIndex::
  4315.     PRINT d$;": bad directory stack index"
  4316.     RETURN
  4317. Empty::
  4318.     PRINT "Directory stack empty"
  4319.     RETURN
  4320. ErrTrap::
  4321.     ONERR off
  4322.     PRINT err$:(ERR)
  4323.     RETURN ERR    
  4324. ENDP
  4325.  
  4326. PROC pwd%:(n%)
  4327.     fprint%:(PrPath$:(_cwd$))
  4328. ENDP
  4329.  
  4330. PROC rename%:(n%)
  4331.     LOCAL src$(255),dest$(255),ret%
  4332.     ONERR ErrTrap::
  4333.     IF n% <> 3
  4334.         PRINT "Usage: rename <source> <destination>"
  4335.         RETURN -2
  4336.     ENDIF
  4337.     ret%=Fparse%:(ADDR(src$),PEEK$(argv&(2)))
  4338.     IF ret%<0
  4339.         _Err:(2,ret%)
  4340.         RETURN
  4341.     ENDIF
  4342.     ret%=Fparse%:(ADDR(dest$),PEEK$(argv&(3)))
  4343.     IF ret%<0 AND ret%<>-33
  4344.         _Err:(3,ret%)
  4345.         RETURN
  4346.     ENDIF
  4347.     RENAME src$,dest$    
  4348.     RETURN
  4349. ErrTrap::
  4350.     ONERR off
  4351.     PRINT err$:(ERR)
  4352.     RETURN ERR
  4353. ENDP
  4354.  
  4355. PROC rescan%:(n%)
  4356. Rem delete linked list of connected devices and rescan
  4357. LOCAL p&,q&
  4358.     ONERR ErrTrap::
  4359.     p&=PEEKL(_dirB&)    Rem first element in the list
  4360.     WHILE p&
  4361.         q&=p&
  4362.         p&=PEEKL(p&)    Rem next element
  4363.         FREEALLOC q&
  4364. Rem        FREEALLOC&:(q&)
  4365.     ENDWH
  4366.     _nodes:
  4367.     RETURN
  4368. ErrTrap::
  4369.     ONERR off
  4370.     PRINT err$:(ERR)
  4371.     RETURN ERR
  4372. ENDP
  4373.  
  4374. PROC rm%:(n%)
  4375. LOCAL flag%,buf$(255),i%,ret%
  4376.     ONERR ErrTrap::
  4377.     i%=2
  4378.     IF n% < 2
  4379.         PRINT "Usage: rm [-r] <file1> <file2> ..."
  4380.         RETURN
  4381.     ELSEIF PEEK$(argv&(2))="-r"
  4382.         i%=3
  4383.         flag%=1    Rem flag recursive    
  4384.     ENDIF
  4385.     WHILE i%<=n%
  4386.         IF flag%                    Rem recursive
  4387.             _del%:(PEEK$(argv&(i%)))
  4388.         ELSE
  4389.             ret%=Fparse%:(ADDR(buf$),PEEK$(argv&(i%)))
  4390.             IF ret%<0
  4391.                 _Err:(i%,ret%)
  4392.             ELSEIF ret% AND 16
  4393.                 _Err:(i%,3)
  4394.             ELSE
  4395.                 IF n%>2
  4396.                     PRINT "Deleting",PrPath$:(buf$)
  4397.                 ENDIF
  4398.                 TRAP DELETE buf$
  4399.                 IF ERR
  4400.                     _Err:(i%,ERR)
  4401.                 ENDIF
  4402.             ENDIF
  4403.         ENDIF
  4404.         IOYIELD
  4405.         IF _stat%<>-46
  4406.             IF _key%(1)=27
  4407.                 BREAK
  4408.             ELSE
  4409.                 KEYA(_stat%,_key%())
  4410.             ENDIF
  4411.         ENDIF
  4412.         i%=i%+1
  4413.     ENDWH
  4414.     RETURN
  4415. ErrTrap::
  4416.     ONERR off
  4417.     PRINT err$:(ERR)
  4418.     RETURN ERR
  4419. ENDP
  4420.  
  4421. PROC rmdir%:(n%)
  4422. LOCAL buf$(255),i%,ret%
  4423.     ONERR ErrTrap::
  4424.     IF n%<2
  4425.         PRINT "Usage: rmdir <directory>"
  4426.         RETURN -2
  4427.     ENDIF
  4428.     i%=2
  4429.     WHILE i%<=n%
  4430.         IOYIELD
  4431.         IF _stat%<>-46
  4432.             IF _key%(1)=27
  4433.                 BREAK
  4434.             ELSE
  4435.                 KEYA(_stat%,_key%())
  4436.             ENDIF
  4437.         ENDIF
  4438.         ret%=Fparse%:(ADDR(buf$),PEEK$(argv&(i%)))
  4439.         IF ret%<0 AND ret%<>-33
  4440.             _Err:(i%,ret%)
  4441.         ELSE
  4442.             TRAP RMDIR buf$
  4443.             IF ERR
  4444.                 _Err:(i%,ERR)
  4445.             ENDIF
  4446.         ENDIF
  4447.         i%=i%+1
  4448.     ENDWH
  4449.     RETURN
  4450. ErrTrap::
  4451.     ONERR off
  4452.     PRINT err$:(ERR)
  4453.     RETURN ERR
  4454. ENDP
  4455.  
  4456. PROC set%:(n%)
  4457. LOCAL p&,txt$(255),i%,k%,opts$(5,8),set%
  4458.     ONERR ErrTrap::
  4459.     IF n%=1
  4460.         p&=PEEKL(_vars&)
  4461.         WHILE p&    
  4462.             fprint%:(PrFmt$:(PEEK$(PEEKL(p&+4)),11)+PEEK$(PEEKL(p&+8)))
  4463.             p&=PEEKL(p&)
  4464.         ENDWH
  4465.         RETURN
  4466.     ENDIF
  4467.     opts$(1)="unixpath"
  4468.     opts$(2)="unixvar"
  4469.     opts$(3)="append"
  4470.     opts$(4)="echo"
  4471.     opts$(5)="cwdcmd"
  4472.     txt$=PEEK$(argv&(2))
  4473.     IF txt$="-o"                    Rem set options
  4474.         IF n%=2                        Rem no more arguments
  4475.             WHILE i%<5
  4476.                 i%=i%+1
  4477.                 IF _opts%(i%)
  4478.                     txt$="on"
  4479.                 ELSE
  4480.                     txt$="off"
  4481.                 ENDIF
  4482.                 fprint%:(PrFmt$:(opts$(i%),11)+txt$)
  4483.             ENDWH
  4484.         ELSE
  4485.             set%=1
  4486. Common::
  4487.             i%=3
  4488.             WHILE i%<=n%
  4489.                 k%=0
  4490.                 WHILE k%<5
  4491.                     k%=k%+1
  4492.                     IF LOWER$(PEEK$(argv&(i%)))=opts$(k%)
  4493.                         VECTOR k%
  4494.                             Simple,UnixVar,Simple,Simple,Simple
  4495.                         ENDV
  4496. UnixVar::        IF set%        Rem set variable designated by $ and prompt vars by %
  4497.                             _spec$=LEFT$(_spec$,17)+"$%"
  4498.                         ELSE            Rem set variable designated by % and prompt vars by $
  4499.                             _spec$=LEFT$(_spec$,17)+"%$"
  4500.                         ENDIF        Rem fall through to simple to set the variable
  4501. Simple::        Rem settings that have no side effects
  4502.                         _opts%(k%)=set%
  4503.                     ENDIF
  4504.                 ENDWH
  4505.                 i%=i%+1
  4506.             ENDWH
  4507.             _opts$=""
  4508.             k%=0
  4509.             WHILE k%<5
  4510.                 k%=k%+1
  4511.                 IF _opts%(k%)
  4512.                     _opts$=_opts$+opts$(k%)+":"
  4513.                 ENDIF
  4514.             ENDWH
  4515.             _opts$=LEFT$(_opts$,LEN(_opts$)-1)
  4516.         ENDIF
  4517.     ELSEIF txt$="+o"        Rem clear options
  4518.         IF n%=2                        Rem no more arguments
  4519. Rem produce one -o list and one +o list
  4520.             WHILE i%<5
  4521.                 i%=i%+1
  4522.                 IF _opts%(i%)
  4523.                     txt$="-o "
  4524.                 ELSE
  4525.                     txt$="+o "
  4526.                 ENDIF
  4527.                 fprint%:("set "+txt$+opts$(i%))
  4528.             ENDWH
  4529.         ELSE
  4530.             set%=0
  4531.             GOTO Common::
  4532.         ENDIF
  4533.     ELSEIF n%=2
  4534. ClrVar::
  4535.         FreeVar%:(txt$)
  4536.     ELSE
  4537.         IF PEEK$(argv&(3))="="
  4538.             IF n%=3
  4539.                 GOTO ClrVar::
  4540.             ENDIF
  4541.             i%=4
  4542.         ELSE
  4543.             i%=3
  4544.         ENDIF
  4545.         txt$=PEEK$(argv&(i%))
  4546.         WHILE i%<n%
  4547.             i%=i%+1
  4548.             txt$=txt$+" "+PEEK$(argv&(i%))
  4549.         ENDWH
  4550.         SetVar%:(PEEK$(argv&(2)),txt$)
  4551.     ENDIF
  4552.     RETURN
  4553. ErrTrap::
  4554.     ONERR off
  4555.     PRINT err$:(ERR)
  4556.     RETURN ERR
  4557. ENDP
  4558.  
  4559. PROC shift%:(n%)
  4560. LOCAL count%,offset%,p&
  4561.     ONERR ErrTrap
  4562.     IF n%>2
  4563.         PRINT "Usage: shift [count]"
  4564.         RETURN -2
  4565.     ELSE
  4566.         IF n%=2
  4567.             count%=VAL(PEEK$(argv&(2)))
  4568.         ELSE
  4569.             count%=1
  4570.         ENDIF
  4571.         p&=PEEKL(_curr&+PR_BACK%)
  4572.         offset%=PEEKB(p&+PR_OFFSET%)
  4573.         IF PEEKB(p&)-offset%-count% >= 1
  4574.             POKEB(p&+PR_OFFSET%),offset%+count%
  4575.         ELSE
  4576.             PRINT "shift count must be <= $#"
  4577.         ENDIF
  4578.     ENDIF
  4579.     RETURN
  4580. ErrTrap::
  4581.     ONERR off
  4582.     PRINT Err$:(ERR)
  4583.     RETURN ERR
  4584. ENDP
  4585.  
  4586. PROC sysinfo%:(n%)
  4587. LOCAL stat$(32),low&,high&
  4588.     ONERR ErrTrap::
  4589.     stat$="Zero    Very LowLow     Good    "
  4590.     fprint%:(MACHINENAME$:)
  4591.     fprint%:("Main battery:   "+MID$(stat$,MAINBATTERYSTATUS&:*8+1,8))
  4592.     fprint%:("Backup battery: "+MID$(stat$,BACKUPBATTERYSTATUS&:*8+1,8))
  4593.     IF ExternalPower&:
  4594.         stat$="ON"
  4595.     ELSE
  4596.         stat$="OFF"
  4597.     ENDIF
  4598.     fprint%:("Mains power:    "+stat$)
  4599.     fprint%:("OS version:     "+NUM$(OsVersionMajor&:,3)+"."+NUM$(OsVersionMinor&:,3)+" (build "+NUM$(OsVersionBuild&:,3)+")")
  4600.     fprint%:("ROM version:    "+NUM$(RomVersionMajor&:,3)+"."+NUM$(RomVersionMinor&:,3)+" (build "+NUM$(RomVersionBuild&:,3)+")")
  4601.     MACHINEUNIQUEID:(high&,low&)
  4602.     fprint%:("Machine ID:     "+HEX$(high&)+"-"+HEX$(low&))
  4603.     RETURN
  4604. ErrTrap::
  4605.     ONERR off
  4606.     PRINT err$:(ERR)
  4607.     RETURN ERR
  4608. ENDP
  4609.  
  4610. PROC unalias%:(n%)
  4611. LOCAL p&,q&,i%
  4612.     ONERR ErrTrap::
  4613.     IF n%<2
  4614.         PRINT "Usage: unalias <alias>"
  4615.         RETURN -2
  4616.     ELSE
  4617.         i%=2
  4618.         DO
  4619.             q&=_atab&
  4620.             p&=PEEKL(q&)
  4621.             WHILE p&
  4622.                 IF PEEK$(argv&(i%)) = PEEK$(PEEKL(p&+4))
  4623.                     FREEALLOC(PEEKL(p&+4))
  4624. Rem                    FREEALLOC&:(PEEKL(p&+4))
  4625.                     FREEALLOC(PEEKL(p&+8))
  4626. Rem                    FREEALLOC&:(PEEKL(p&+8))
  4627.                     POKEL q&,PEEKL(p&)
  4628.                     FREEALLOC(p&)
  4629. Rem                    FREEALLOC&:(p&)
  4630.                     BREAK
  4631.                 ENDIF
  4632.                 q&=p&
  4633.                 p&=PEEKL(p&)
  4634.             ENDWH
  4635.             IF p&=0
  4636.                 PRINT PEEK$(argv&(i%)),"- No such alias"
  4637.             ENDIF
  4638.         i%=i%+1
  4639.         UNTIL i%>n%
  4640.     ENDIF
  4641.     RETURN
  4642. ErrTrap::
  4643.     ONERR off
  4644.     PRINT err$:(ERR)
  4645.     RETURN ERR
  4646. ENDP
  4647.  
  4648. PROC unset%:(n%)
  4649. LOCAL i%
  4650.     ONERR ErrTrap::
  4651.     IF n%<2
  4652.         PRINT "Usage: unset <variable>"
  4653.         RETURN -2
  4654.     ELSE
  4655.         i%=2
  4656.         DO
  4657.             FreeVar%:(PEEK$(argv&(i%)))
  4658.             i%=i%+1
  4659.         UNTIL i%>n%
  4660.     ENDIF
  4661.     RETURN
  4662. ErrTrap::
  4663.     ONERR off
  4664.     PRINT err$:(ERR)
  4665.     RETURN ERR
  4666. ENDP
  4667.  
  4668. PROC ver%:(n%)
  4669.     fprint%:("Shell5 v"+_VERSION$+"┬╕ Nick Murray 1998")
  4670. ENDP
  4671.  
  4672. PROC which%:(n%)
  4673. LOCAL buf$(255),i%,p&,com$(255)
  4674.     ONERR ErrTrap::
  4675.     IF n%<>2
  4676.         PRINT "Usage: which <command>"
  4677.         RETURN -2
  4678.     ENDIF
  4679.     com$=PEEK$(argv&(2))
  4680.     PRINT com$;":",
  4681.     p&=PEEKL(_atab&)
  4682.     WHILE p&
  4683.         IF com$=PEEK$(PEEKL(p&+4))
  4684.             PRINT "aliased to",PEEK$(PEEKL(p&+8))
  4685.             RETURN
  4686.         ENDIF
  4687.         p&=PEEKL(p&)
  4688.     ENDWH
  4689.     IF com$="goto" OR com$="if" OR com$="time"
  4690.         GOTO BuiltIn::
  4691.     ENDIF
  4692.     WHILE i%<NBUILTIN%
  4693.         i%=i%+1
  4694.         IF com$=_bltin$(i%)
  4695.             GOTO BuiltIn::
  4696.         ENDIF
  4697.     ENDWH
  4698.     com$=_hshf$:(com$)    Rem find/put com$ in the hashed path
  4699.     IF LEN(com$)
  4700.         PRINT PrPath$:(com$)
  4701.     ELSE
  4702.         PRINT "Command not found"
  4703.     ENDIF
  4704.     RETURN
  4705. BuiltIn::
  4706.     PRINT "Built-in"
  4707.     RETURN
  4708. ErrTrap::
  4709.     ONERR off
  4710.     PRINT err$:(ERR)
  4711.     RETURN ERR
  4712. ENDP
  4713.  
  4714. PROC _cpmv%:(n%,mv%)
  4715. Rem common copy/move routine. mv%=delete source file
  4716. LOCAL dest$(255),i%,ret%,buf$(255)
  4717.     ret%=Fparse%:(ADDR(dest$),PEEK$(argv&(n%)))
  4718.     IF n%=3
  4719.         IF (ret%<0) AND (ret%<>-33)    Rem dest must be valid without wilds
  4720.             _Err:(n%,ret%)
  4721.             RETURN
  4722.         ENDIF
  4723.     ELSE
  4724.         IF ret%<0
  4725.             _Err:(n%,ret%)
  4726.             RETURN
  4727.         ELSEIF    (ret% AND 16) = 0
  4728.             _Err:(n%,2)
  4729.             RETURN
  4730.         ENDIF
  4731.     ENDIF
  4732.     i%=2
  4733.     WHILE i%<n%
  4734.         IOYIELD
  4735.         IF _stat%<>-46
  4736.             IF _key%(1)=27
  4737.                 BREAK
  4738.             ELSE
  4739.                 KEYA(_stat%,_key%())
  4740.             ENDIF
  4741.         ENDIF
  4742.         ret%=Fparse%:(ADDR(buf$),PEEK$(argv&(i%)))
  4743.         IF ret%<0    Rem any error
  4744.             _Err:(i%,ret%)
  4745.         ELSEIF ret% AND 16    Rem directory
  4746.             _Err:(i%,3)    Rem wanted a file, source is a directory
  4747.         ELSE
  4748.             IF n%>3
  4749.                 IF mv%
  4750.                     PRINT "Moving",PrPath$:(buf$)
  4751.                 ELSE
  4752.                     PRINT "Copying",PrPath$:(buf$)
  4753.                 ENDIF
  4754.             ENDIF
  4755.             TRAP COPY buf$,dest$
  4756.             IF ERR
  4757.                 _Err:(i%,ERR)
  4758.             ELSEIF mv%
  4759.                 TRAP DELETE buf$
  4760.                 IF ERR=-33    Rem No such file, try d$+"."
  4761.                     TRAP DELETE buf$+"."
  4762.                 ENDIF
  4763.                 IF ERR
  4764.                     _Err:(i%,ERR)
  4765.                 ENDIF
  4766.             ENDIF
  4767.         ENDIF
  4768.         i%=i%+1
  4769.     ENDWH
  4770. ENDP
  4771.  
  4772. PROC _del%:(p$)
  4773. Rem delete the file in p$ (can be a directory)
  4774. LOCAL buf$(255),ret%,d$(255),attr%(8)
  4775.     ret%=Fparse%:(ADDR(d$),p$)
  4776.     IF ret%<0
  4777.         PRINT PrPath$:(d$),"-",err$:(ret%)
  4778.         RETURN
  4779.     ENDIF
  4780.     buf$=DIR$(d$)
  4781. Start::
  4782.     WHILE LEN(buf$)
  4783.         IOYIELD
  4784.         IF _stat%<>-46
  4785.             IF _key%(1)=27
  4786.                 RETURN
  4787.             ELSE
  4788.                 KEYA(_stat%,_key%())
  4789.             ENDIF
  4790.         ENDIF
  4791.         ret%=xstat%:(buf$)        Rem don't check for error, buf$ is returned by DIR$!
  4792.         IF ret% AND 16            Rem directory
  4793.             _del%:(buf$)
  4794.             IOYIELD                        Rem capture ESC events immediately
  4795.             IF _stat%<>-46
  4796.                 IF _key%(1)=27
  4797.                     RETURN
  4798.                 ELSE
  4799.                     KEYA(_stat%,_key%())
  4800.                 ENDIF
  4801.             ENDIF
  4802.             buf$=DIR$(d$)
  4803.             GOTO Start::
  4804.         ELSE
  4805.             PRINT "Deleting",PrPath$:(buf$)
  4806.             TRAP DELETE buf$
  4807.             IF ERR
  4808.                 PRINT PrPath$:(buf$),"-",err$:(ERR)
  4809.             ENDIF
  4810.         ENDIF
  4811.         buf$=DIR$("")
  4812.     ENDWH
  4813.     ret%=Fparse%:(ADDR(d$),d$)
  4814.     IF ret%>0 AND ((ret% AND 16)=16)
  4815.         PRINT "Deleting",PrPath$:(d$)
  4816.         TRAP RMDIR d$
  4817.         IF ERR
  4818.             PRINT PrPath$:(d$),"-",err$:(ERR)
  4819.         ENDIF
  4820.     ENDIF
  4821. ENDP
  4822.  
  4823. PROC _gact$:(c%)
  4824. Rem print the act that c% represents
  4825. LOCAL i%
  4826.     IF c%=0
  4827.         RETURN "undefined"
  4828.     ELSEIF c%<16    Rem one of the internals
  4829.         WHILE i%<15
  4830.             i%=i%+1
  4831.             IF i%=c%
  4832.                 RETURN _act$(i%)
  4833.             ENDIF
  4834.         ENDWH
  4835.     ELSEIF c%<32
  4836.         RETURN "macro"+NUM$(c%-15,2)
  4837.     ELSE
  4838.         RETURN CHR$(c%)
  4839.     ENDIF
  4840. ENDP
  4841.  
  4842. PROC _kdisp%:(k$,value$,addr&)
  4843. LOCAL d$(255)
  4844.     d$=PEEK$(addr&)+REPT$(" ",12-LEN(k$))+k$+":"+value$+REPT$(" ",12-LEN(value$))
  4845.     IF LEN(d$)+28>ScrInfo%(3)
  4846.         fprint%:(d$)
  4847.         d$=""
  4848.     ELSE
  4849.         d$=d$+"  "                    Rem only add inter-entry space if it's not the last entry
  4850.     ENDIF
  4851.     POKE$ addr&,d$
  4852. ENDP
  4853.  
  4854. Rem PROC cmdl%:
  4855. Rem procedure to toggle display of log window
  4856. Rem    _log:((_logid%=0)+2,"")
  4857. Rem If logid% is 0, this will be -1 + 2 = 1 = create message window
  4858. Rem If logid% is <> 0, this will be 0 + 2 = 2 = remove message window!!
  4859. Rem    _extevent%=1        Rem flag something has happened!
  4860. Rem ENDP
  4861.  
  4862. PROC cmdS1%:
  4863.     _extevent%=%1        Rem flag something has happened!
  4864. ENDP
  4865.         
  4866. PROC cmdS2%:
  4867.     _extevent%=%2        Rem flag something has happened!
  4868. ENDP
  4869.  
  4870. PROC cmdS3%:
  4871.     _extevent%=%3        Rem flag something has happened!
  4872. ENDP
  4873.  
  4874. PROC cmdS4%:
  4875.     _extevent%=%4        Rem flag something has happened!
  4876. ENDP
  4877.  
  4878. PROC _init:
  4879. LOCAL t$(206),i%,j%,off%(6),p&,bitmapId1&,bitmapId2&
  4880. Rem no error trapping. Any errors here will be (rightly) fatal
  4881. Rem set the PATH for temp files, inc. pipes
  4882.     PARSE$(cmd$(1),"",off%())
  4883.     _syspath$=LEFT$(cmd$(1),off%(4)-1)
  4884. Rem CHANGE THIS!!! This is faked so we have a semi-permanent path!!
  4885. Rem    _syspath$="c:\System\Apps\Shell5\"
  4886. Rem    t$=_syspath$+"buttons.mbm"
  4887. Rem    IF EXIST(t$)        Rem if it's not installed DON'T┬áPANIC
  4888. Rem        bitmapId1&=gLoadBit(t$,0,0)
  4889. Rem        bitmapId2&=gLoadBit(t$,0,1)
  4890. Rem    ENDIF
  4891.     TBarInit:("Shell 5",ScrWid%,ScrHght%)
  4892. Rem    TBarButt:("l",1,"Toggle"+CHR$(10)+"  Log",0,bitmapId1&,bitmapId2&,0)
  4893.     i%=1
  4894.     WHILE i%<5
  4895.         TBarButt:(CHR$(i%+%0),i%,"Button"+CHR$(10)+"    "+CHR$(i%+%0),0,0,0,0)
  4896.         i%=i%+1
  4897.     ENDWH
  4898.     TBarShow:
  4899.     
  4900.     _setw%:        Rem set the window size, etc.
  4901.  
  4902. Rem    ESCAPE OFF
  4903.     LOCK ON    Rem tell the system we don't want events...
  4904.     KEYA(_stat%,_key%())            Rem initialize getting ESC
  4905.     _spec$=" ""'*?{}<>=+-/#;┬ª!$%"
  4906. Rem space, ", ', *, ?, , {, }, <, >, =. +, -, /, #, ;, ┬ª, !,$, %
  4907. Rem $% Must be last - shell and prompt variable designators resp.
  4908.     t$="alias,at,banner,bg,bindkey,cat,cd,chmod,cls,cp,date,df,dirs,echo,edit,exit,hash,help,history,log,ls,mkdir,more,mv,od,pause,popd,pushd,pwd,rename,rescan,rm,rmdir,set,shift,sysinfo,unalias,unset,ver,which,"
  4909.     j%=1
  4910.     WHILE LEN(t$)
  4911.         i%=LOC(t$,",")
  4912.         _bltin$(j%)=LEFT$(t$,i%-1)
  4913.         t$=RIGHT$(t$,LEN(t$)-i%)
  4914.         j%=j%+1
  4915.     ENDWH
  4916.     t$="delete,delete-right,enter,esc,previous,next,right,left,first,last,start,end,expand,"
  4917.     j%=1
  4918.     WHILE LEN(t$)
  4919.         i%=LOC(t$,",")
  4920.         _act$(j%)=LEFT$(t$,i%-1)
  4921.         t$=RIGHT$(t$,LEN(t$)-i%)
  4922.         j%=j%+1
  4923.     ENDWH
  4924.     _hnum%=1
  4925.     Rem allocate everything at once!!
  4926.     _keys&=ALLOC(616+PR_ARGV%)    Rem keys table
  4927.     _hpos&=ALLOC(12)        Rem 12 for first entry in alias table
  4928.     IF _keys&=0 OR _hpos&=0
  4929.         RAISE -10
  4930.     ENDIF
  4931.     _atab&=_keys&+512            Rem 512 for keys table
  4932.     _dirB&=_keys&+524            Rem 12 for first entry in alias table
  4933.     _hash&=_keys&+528        Rem 4 for base of the drives
  4934.     _vars&=_keys&+532            Rem 4 for base of hash table
  4935.     _help&=_keys&+536            Rem 4 for base of variables table
  4936.             Rem 4 for base of open help list
  4937.             Rem 64 used later for READ-ONLY variables
  4938.     _curr&=_keys&+604
  4939.     Rem add PR_ARGV%+12=616+PR_ARGV% -  enough space for ARGS +
  4940.     Rem pointer + "Shell5" (11 needed)
  4941.  
  4942. Rem initialize base argv segment
  4943. Rem argc & argn = 1,clear flag and level
  4944.     POKEL _curr&,&1000001    
  4945.     POKEB _curr&+PR_OFFSET%,0    Rem clear offset
  4946. Rem set fake first entry for base shell
  4947.     POKEL _curr&+PR_ARGV%,_curr&+PR_ARGV%+4
  4948.     POKE$ _curr&+PR_ARGV%+4,"Shell5"
  4949. Rem initialize the keys table
  4950.     i%=256
  4951.     WHILE i%
  4952.         i%=i%-1
  4953.         IF i%<32
  4954.             POKEB _keys&+i%,0
  4955.         ELSE
  4956.             POKEB _keys&+i%,i%
  4957.         ENDIF
  4958.         POKEB _keys&+i%+256,0
  4959.     ENDWH
  4960.     POKEW _keys&+8,$D01
  4961.             Rem delete & Tab
  4962.     POKEB _keys&+264,2            Rem SHIFT delete
  4963.     POKEB _keys&+13,3            Rem enter
  4964.     POKEB _keys&+27,4            Rem esc
  4965. REM big+endian, ie highest byte in highest memory
  4966.     POKEL _keys&+391,&6050708        Rem up,down,right & left
  4967.     POKEL _keys&+386,&0A090C0B        Rem Pg Up,Pg Dn,Home & end
  4968.     POKEB _keys&+363,166                        Rem pipe
  4969.  
  4970.     POKEL _hpos&,_hpos&            Rem set next=current
  4971.     Rem clear _hpos&+8 and set _hpos&+4
  4972.     POKEL _hpos&+4,_hpos&        Rem set prev=current
  4973.     POKEL _hpos&+8,0
  4974.     POKEL _hash&,0                Rem set current end of hash table
  4975.     POKEL _atab&,0                Rem current end of alias table
  4976.     POKEL _vars&,0                Rem Delimit vars structure
  4977.     POKEL _help&,0                Rem delimit help structure
  4978. Rem initialize the READ-ONLY "system" variables
  4979.     p&=_keys&+540                Rem part of "big" allocation - 40 bytes
  4980. Rem 2 * 12 + LEN("_cwd") + 1 + LEN("_syspath")+1
  4981.     POKEL _vars&,p&        Rem link in read-only vars
  4982.     POKEL p&,p&+12                Rem second of the two variable blocks
  4983.     POKEL p&+4,p&+36        Rem after 3 variable blocks
  4984.     POKE$ p&+36,"_shellopts"
  4985.     POKEL p&+8,ADDR(_opts$)
  4986.     POKEL p&+12,p&+24        Rem new end of variable block
  4987.     POKEL p&+16,p&+47        Rem after variable blocks and "_shellopts"
  4988.     POKE$ p&+47,"_cwd"
  4989.     POKEL p&+20,ADDR(_cwd$)
  4990.     POKEL p&+24,0
  4991.     POKEL p&+28,p&+52
  4992.     POKE$ p&+52,"_syspath"
  4993.     POKEL p&+32,ADDR(_syspath$)
  4994. Rem initialize the message window
  4995.     _log:(1,"")            Rem create log window
  4996.     _log:(3,"Initializing...")
  4997.     _log:(3,"   Shell5 comes with ABSOLUTELY NO WARRANTY; for details see the file ""COPYING""")
  4998.     _log:(3,"   This is free software, and you are welcome to distribute it under certain conditions; for")
  4999.     _log:(3,"   details see the file ""COPYING""")
  5000.     _nodes:
  5001.     SetVar%:("path",_syspath$+"bin")                Rem NOTE we've dropped the .
  5002.     SetVar%:("helppath",_syspath$+"help")
  5003.     SetVar%:("prompt","%P>")
  5004.     SetVar%:("history","10")
  5005.     _opts%(varUNIXpath%)=1
  5006.     _opts%(varUNIXvar%)=1
  5007.     SetVar%:("toolbar","on")
  5008.     _log:(3,"Executing autoexec.bat...")
  5009.     _chkp%:(_syspath$+"autoexec",0)
  5010.     _log:(4,"...completed.")
  5011.     _log:(2,"")    Rem close log window
  5012. ENDP
  5013.  
  5014. PROC _exit:
  5015. Rem tidy up - eg. kill help sessions
  5016. LOCAL p&
  5017.     ONERR ErrTrap::
  5018.     p&=PEEKL(_help&)
  5019.     WHILE p&
  5020.         ONERR ErrCatch::            Rem catch if ENDTASK tries a non-existant thread
  5021.         ENDTASK&:(PEEKL(p&+4),0)
  5022. ErrCatch::
  5023.         ONERR ErrTrap::
  5024.         p&=PEEKL(p&)
  5025.     ENDWH
  5026. ErrTrap::
  5027.     STOP
  5028. ENDP
  5029.  
  5030.  
  5031.