Changeset 4812


Ignore:
Timestamp:
Dec 10, 2021, 7:59:36 PM (3 years ago)
Author:
Andreas Schnellbacher
Message:
  • Completely reworked the shell code. It uses bookmarks and, when finished, will be a big improvement for the old code. This is an interim state. It still contains activated dprintf output. Still to do for this state:
    • Handle init better. Suppress output until init is done.

ShellWriteCmdQuiet is used, but apparently it doesn't work during init.

  • Restore of a shell window should readd the prompt bookmarks.
  • Dialog for chars or line input when an app is waiting for input.
  • Give the Ctrl key together with the shell toolbar button or the

shell menu item for create/switch a useful meaning.

This is a preparation for saving and restoring shell environments.
A proc for extracting current dir (from the environment, not from the
prompt) already works.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/src/netlabs/macros/epmshell.e

    r4811 r4812  
    2424
    2525define
    26    INCLUDING_FILE = 'FINDDEF.E'
     26   INCLUDING_FILE = 'EPMSHELL.E'
    2727
    2828   include 'stdconst.e'
     
    4848; ---------------------------------------------------------------------------
    4949; Called from ShellStart
    50 defproc Sue_New( var shell_handle, shellnum)
     50defproc Sue_New( var shell_handle, ShellNum)
    5151   thandle = '????'
    5252   result = dynalink32( ERES_DLL,
     
    5454                         address( thandle)             ||
    5555                         GethWndC( EPMINFO_EDITCLIENT) ||
    56                          atol( shellnum))
     56                         atol( ShellNum))
    5757   shell_handle = thandle
    5858   return result
     
    7070; ---------------------------------------------------------------------------
    7171; Called from ShellOutputLines
    72 defproc Sue_ReadLn( shell_handle, var buffe, var bytesmoved)
     72defproc Sue_ReadLn( shell_handle, var buffe, var BytesMoved)
    7373   bufstring = buffe  -- just to insure the same amount of space is available
    7474   bm        = "??"
     
    7979                        atol( length( bufstring)) ||
    8080                        address( bm))
    81    bytesmoved = itoa( bm, 10)
     81   BytesMoved = itoa( bm, 10)
    8282   buffe      = bufstring
    8383   return result
     
    8585; ---------------------------------------------------------------------------
    8686; Called from ShellWrite
    87 defproc Sue_Write( shell_handle, buffe, var bytesmoved)
     87defproc Sue_Write( shell_handle, buffe, var BytesMoved)
    8888   bm     = "??"
    8989   result = dynalink32( ERES_DLL,
     
    9393                        atol( length( buffe)) ||
    9494                        address( bm))
    95    bytesmoved = itoa( bm, 10)
     95   BytesMoved = itoa( bm, 10)
    9696   return result
    9797
     
    122122compile endif
    123123
     124; ---------------------------------------------------------------------------
     125defproc ShellGetPromptValue
     126   KeyPath = '\NEPMD\User\Shell\PromptValue'
     127   PromptVal = QueryConfigKey( KeyPath)
     128   if PromptVal = '' then
     129      PromptVal = EPM_SHELL_PROMPT
     130   endif
     131   -- Strip leading 'prompt' or '@prompt'
     132   UpPromptVal = upcase( PromptVal)
     133   if wordpos( word( UpPromptVal, 1), 'PROMPT @PROMPT') then
     134      PromptVal = subword( PromptVal, 2)
     135   endif
     136   return PromptVal
     137
    124138; ===========================================================================
    125139; Find and parse prompt
     
    127141
    128142; ---------------------------------------------------------------------------
    129 ; Returns 1 if prompt not supported, 0 if prompt supported, but not on a
    130 ; prompt line, otherwise the col for the end of the prompt (> or ]).
    131 defproc ShellPromptPos
    132    if not IsAShell() then
    133       return 0
    134    endif
    135    LineStr = arg( 1)
    136    if LineStr = '' then
     143; Converts a prompt value to an egrep search string.
     144defproc ShellPromptToSearchStr( PromptVal)
     145   SearchStr = ''
     146
     147   call ShellPromptToSearchStrCommon( PromptVal, 0, SearchStr, junk)
     148   --dprintf( 'PromptVal = 'PromptVal)
     149   --dprintf( 'SearchStr = 'SearchStr)
     150
     151   return SearchStr
     152
     153; ---------------------------------------------------------------------------
     154; Converts a prompt value to 2 egrep search strings. 2 search strings are
     155; used to place the cursor aroound the path output $p. That allows for to
     156; determine the current path from a shell output and is used in emergancy
     157; cases, when the shell is not able to save its environment.
     158defproc ShellPromptToSearchStr2( PromptVal, var SearchStr1, var SearchStr2)
     159   SearchStr1 = ''
     160   SearchStr2 = ''
     161
     162   call ShellPromptToSearchStrCommon( PromptVal, 1, SearchStr1, SearchStr2)
     163   --dprintf( 'PromptVal  = 'PromptVal)
     164   --dprintf( 'SearchStr1 = 'SearchStr1)
     165   --dprintf( 'SearchStr2 = 'SearchStr2)
     166
     167   return
     168
     169; ---------------------------------------------------------------------------
     170defproc ShellPromptToSearchStrCommon( PromptVal, fPlaceCursor,
     171                                      var SearchStr1, var SearchStr2)
     172   fPlaceCursor = (fPlaceCursor = 1)
     173   SearchStr1 = ''
     174   SearchStr2 = ''
     175   Rest = PromptVal
     176
     177   -- Filter out ANSI Esc sequences
     178   pStart = 1
     179   do forever
     180      pEscStart = pos( '$E[', upcase( Rest), pStart)
     181      if pEscStart = 0 then
     182         leave
     183      else
     184         pEscEnd = verify( Rest, 'ABCDHJKnfRhlmpsu', 'M', pEscStart + 3)
     185         if pEscEnd = 0 then
     186            leave
     187         endif
     188         Rest = delstr( Rest, pEscStart, pEscEnd - pEscStart + 1)
     189         pStart = pEscStart
     190      endif
     191   enddo
     192
     193   -- Escape egrep search chars, allowed for a prompt macro
     194   -- '$|&' as normal chars cannot be used in a prompt. They are
     195   -- removed here compared to EGREP_METACHARACTERS.
     196   AddEscapeChars = '\[]()?*+^.:~#@'
     197   pStart = 1
     198   do forever
     199      if Rest == '' then
     200         leave
     201      endif
     202      pFound = verify( Rest, AddEscapeChars, 'M', pStart)
     203      if not pFound then
     204         leave
     205      else
     206         Rest = leftstr( Rest, pFound - 1)'\'substr( Rest, pFound)
     207         pStart = pFound + 2
     208      endif
     209   enddo
     210
     211   -- Convert prompt macros ('$' + single char)
     212   PathConvertStr = ':a\:.#'
     213   pStart = 1
     214   do forever
     215      pMacroStart = pos( '$', Rest, pStart)
     216      if pMacroStart = 0 then
     217         leave
     218      else
     219         MacroChar = substr( Rest, pMacroStart + 1, 1)
     220         UpMacroChar = upcase( MacroChar)
     221         ConvertStr = '???'
     222         if MacroChar = '$' then
     223            ConvertStr = '\$'
     224         elseif UpMacroChar = 'A' then
     225            ConvertStr = '\&'
     226         elseif UpMacroChar = 'B' then
     227            ConvertStr = '\|'
     228         elseif UpMacroChar = 'C' then
     229            ConvertStr = '\('
     230         elseif UpMacroChar = 'D' then
     231            ConvertStr = '.#'
     232         elseif UpMacroChar = 'E' then
     233            ConvertStr = \27
     234         elseif UpMacroChar = 'F' then
     235            ConvertStr = '\)'
     236         elseif UpMacroChar = 'G' then
     237            ConvertStr = '\>'
     238         elseif UpMacroChar = 'H' then
     239            -- Processed below: Backspace
     240            -- /Backspace not supported, just print char
     241            --/ConvertStr = \8
     242         elseif UpMacroChar = 'I' then
     243            ConvertStr = ''
     244         elseif UpMacroChar = 'L' then
     245            ConvertStr = '\<'
     246         elseif UpMacroChar = 'N' then
     247            ConvertStr = ':a\:'
     248         elseif UpMacroChar = 'P' then
     249            if fPlaceCursor then
     250               ConvertStr = '\c'PathConvertStr
     251            else
     252               ConvertStr = PathConvertStr
     253            endif
     254         elseif UpMacroChar = 'Q' then
     255            ConvertStr = '='
     256         elseif UpMacroChar = 'R' then
     257            ConvertStr = '(-|):i'
     258         elseif UpMacroChar = 'S' then
     259            ConvertStr = ' '
     260         elseif UpMacroChar = 'T' then
     261            ConvertStr = '.#'
     262         elseif UpMacroChar = 'V' then
     263            ConvertStr = '.#'
     264         elseif MacroChar = '_' then
     265            -- Processed below: Linebreak
     266         endif
     267         if ConvertStr <> '???' then
     268            -- Insert ConvertStr
     269            pDelta = length( ConvertStr) - 2  -- 2 = length( SearchStr)
     270            Rest = leftstr( Rest, pMacroStart - 1)''ConvertStr''substr( Rest, pMacroStart + 2)
     271            pStart = pMacroStart + pDelta
     272         elseif UpMacroChar = 'H' then
     273            -- Backspace
     274            pDelta = 1 - 2  -- 2 = length( SearchStr)
     275            Rest = leftstr( Rest, pMacroStart - 2)''substr( Rest, pMacroStart + 2)
     276            pStart = pMacroStart + pDelta
     277         elseif MacroChar = '_' then
     278            -- Linebreak: skip everything before
     279            Rest = substr( Rest, pMacroStart + 2)
     280            pStart = pMacroStart
     281         endif
     282      endif
     283   enddo
     284
     285   SearchStr1 = '^'Rest
     286   if fPlaceCursor then
     287      -- Place the cursor after the path in a second search if '$p' specified
     288      pCursor = pos( '\c'PathConvertStr, SearchStr1)
     289      if pCursor then
     290         SearchStr2 = leftstr( SearchStr1, pCursor - 1) ||
     291                      PathConvertStr'\c'                ||
     292                      substr( SearchStr1, pCursor + 2 + length( PathConvertStr))
     293      endif
     294   endif
     295
     296   return
     297
     298; ---------------------------------------------------------------------------
     299defproc ShellParsePromptLine( LineNum, var Prompt, var Cmd)
     300   Prompt = ''
     301   Cmd    = ''
     302
     303   getline LineStr, LineNum
     304   PromptVal = ShellGetPromptValue()
     305   SearchStr = ShellPromptToSearchStr( PromptVal)
     306
     307   do n = 1 to 2
     308      -- If not found, repeat search with stripped SearchStr
     309      if n = 2 then
     310         SearchStr = strip( SearchStr, 'T')
     311      endif
     312      pFound = pos( SearchStr, LineStr, 1, 'x')
     313      if pFound then
     314         PromptLen = getpminfo( EPMINFO_LSLENGTH)
     315         Prompt = leftstr( LineStr, PromptLen)
     316         Cmd    = substr( LineStr, PromptLen + 1)
     317         leave
     318      endif
     319   enddo
     320
     321   return
     322
     323; ---------------------------------------------------------------------------
     324defproc ShellGetPrevDir
     325   do once = 1 to 1
     326      Dir = ''
     327      SavedRc = rc
     328      pSave_Pos( SavedPos)
     329      getsearch SavedSearch
     330
     331      LineNum = arg( 1)
     332      if LineNum = '' then
     333         LineNum = .line
     334      elseif not IsNum( LineNum) then
     335         LineNum = .line
     336      else
     337         .lineg = LineNum
     338      endif
     339
     340      PromptVal = ShellGetPromptValue()
     341      call ShellPromptToSearchStr2( PromptVal, SearchStr1, SearchStr2)
     342
     343      display -15  -- disables all messsage output and screen updates
     344      do n = 1 to 2
     345         .lineg = LineNum
     346         endline
     347dprintf( '.line = '.line', .col = '.col)
     348         -- If not found, repeat search with stripped SearchStr
     349         if n = 2 then
     350            SearchStr1 = strip( SearchStr1, 'T')
     351            SearchStr2 = strip( SearchStr2, 'T')
     352         endif
     353         'xcom l '\1''SearchStr1''\1'x-R'
     354         if not rc & .line = LineNum then
     355            -- Found
     356            leave
     357         endif
     358      enddo
     359      display 15
     360dprintf( 'SearchStr1 = 'SearchStr1', rc = 'rc)
     361      if rc | .line <> LineNum then
     362         -- Not found
     363         leave
     364      endif
     365      pFound1 = .col
     366dprintf( 'pFound1 = 'pFound1)
     367
     368      display -15  -- disables all messsage output and screen updates
     369      endline
     370dprintf( '.line = '.line', .col = '.col)
     371      'xcom l '\1''SearchStr2''\1'x-R'
     372      display 15
     373dprintf( 'SearchStr2 = 'SearchStr2', rc = 'rc)
     374      if rc | .line <> LineNum then
     375         -- Not found
     376         leave
     377      endif
     378      pFound2 = .col
     379dprintf( 'pFound2 = 'pFound2)
     380
    137381      getline LineStr
    138    endif
    139 
    140 compile if not (EPM_SHELL_PROMPT = '@prompt epm: $p $g' | EPM_SHELL_PROMPT = '@prompt [epm: $p ]')
    141    return 1
    142 compile endif
    143 
    144 compile if EPM_SHELL_PROMPT = '@prompt epm: $p $g'
    145    p = pos( '>', LineStr)
    146    if leftstr( LineStr, 5) = 'epm: ' & p then
    147 compile else
    148    p = pos( ']', LineStr)
    149    if leftstr( LineStr, 6) = '[epm: ' & p then
    150 compile endif
    151       return p
    152    else
    153       return 0
    154    endif
     382      Dir = substr( LineStr, pFound1, pFound2 - pFound1)
     383   enddo
     384   setsearch SavedSearch
     385   pRestore_Pos( SavedPos)
     386   rc = SavedRc
     387
     388   return Dir
    155389
    156390; ---------------------------------------------------------------------------
     
    160394; Sets rc from 'xcom l'.
    161395defproc ShellGotoNextPrompt
     396--dprintf( 'ShellGotoNextPrompt 'arg( 1))
    162397   pSave_Pos( SavedPos)
    163398   getsearch SavedSearch
    164399   if upcase( arg( 1)) = 'P' then
    165400      Direction = '-r'
     401--dprintf( 'ShellGotoNextPrompt: .col = 1 on .line = '.line)
    166402      .col = 1
    167403   else
    168404      Direction = ''
    169       .col = length( textline( .line)) + 1
    170    endif
     405   endif
     406
     407   PromptVal = ShellGetPromptValue()
     408   SearchStr = ShellPromptToSearchStr( PromptVal)
     409
    171410   display -2
    172 compile if EPM_SHELL_PROMPT = '@prompt epm: $p $g'
    173    'xcom l /^epm\: .*>:o\c/x'Direction
    174 compile else  -- else EPM_SHELL_PROMPT = '@prompt [epm: $p ]'
    175    'xcom l /^\[epm\: .*\]:o\c/x'Direction
    176 compile endif -- EPM_SHELL_PROMPT
     411   'xcom l '\1''SearchStr\1'x'Direction
    177412   display 2
    178413   if rc then
    179414      pRestore_Pos( SavedPos)
    180    endif
     415   else
     416      call ShellParsePromptLine( .line, CurPrompt, CurCmd)
     417      .col = length( CurPrompt) + 1
     418   endif
     419
    181420   setsearch SavedSearch
    182421   return
     
    200439
    201440; ---------------------------------------------------------------------------
    202 ; Parses current line and set Dir and Cmd via call by reference.
    203 defproc ShellParsePromptLine( var Dir, var Cmd)
    204 compile if EPM_SHELL_PROMPT = '@prompt epm: $p $g'
    205    parse value textline( .line) with 'epm:' Dir '>' Cmd
    206 compile else
    207    parse value textline( .line) with 'epm:' Dir ']' Cmd
    208 compile endif -- EPM_SHELL_PROMPT
    209    Dir = strip( Dir)
    210    Cmd = strip( Cmd)
    211    return
    212 
    213 ; ---------------------------------------------------------------------------
    214 ; Called by IsADirList.
     441; Called by IsADirList and here.
    215442defproc ShellGetLastCmd
    216    LastCmd = ''
     443--dprintf( 'ShellGetLastCmd')
    217444   call pSave_Pos( SavedPos)
    218445   SavedRc = rc
    219    call ShellGotoNextPrompt( 'P')
    220    if not rc then
    221       call ShellParsePromptLine( Dir, Cmd)
    222       LastCmd = Cmd
    223    endif
     446
     447   -- Use current Cmd if Cmd is about to process
     448   CurCmd = GetAVar( 'shellcurrentcmd')
     449   if not CurCmd then
     450      -- Check previous prompt line
     451      call ShellGotoNextPrompt( 'P')
     452      if not rc then
     453         call ShellParsePromptLine( .line, CurPrompt, CurCmd)
     454         if CurCmd <> '' then
     455            -- Store shellcurrentcmd
     456            call SetAVar( 'shellcurrentcmd', CurCmd)
     457         endif
     458      endif
     459   endif
     460
    224461   rc = SavedRc
    225462   call pRestore_Pos( SavedPos)
    226    return LastCmd
     463   return CurCmd
    227464
    228465; ===========================================================================
     
    429666      endif
    430667
    431       ShellAppWaiting = GetAVar( ShellFid'.shellappwaiting')
    432       if words( ShellAppWaiting) < 2 then
     668      call ShellParsePromptLine( .last, LastPrompt, LastCmd)
     669      if LastPrompt | .last = 1 then
    433670         -- Execute Cmd
    434671         if Cmd then
    435             'ShellWrite' ShellNum Cmd
     672            --'ShellWriteQuiet' ShellNum Cmd
     673            'ShellWriteCmd' ShellNum Cmd
    436674         endif
    437675         -- Use real case of current dir, even when XWP has uppercased it.
     
    489727
    490728      -- This is required for restored shell files to delete the initial lines
    491       call SetAVar( ShellFid'.startlinenum', .last)
     729      call SetAVar( ShellFid'.shellstartlinenum', .last)
    492730
    493731      -- Alias file
     
    499737
    500738      -- Change prompt
    501       if EPM_SHELL_PROMPT <> '' then
    502          'ShellWrite' shell_index EPM_SHELL_PROMPT
    503       endif
     739      PromptValue = ShellGetPromptValue()
     740      CurCmd = '@prompt 'PromptValue
     741      call SetAVar( 'shellcurrentcmd', CurCmd)
     742      --'ShellWriteCmdQuiet' ShellNum CurCmd
     743      'ShellWriteCmdQuiet' ShellNum CurCmd
    504744
    505745      -- Execute InitCmd
     
    507747      InitCmd = QueryConfigKey( KeyPath)
    508748      if InitCmd <> '' then
    509          'ShellWrite' ShellNum InitCmd
    510       endif
    511 
    512       ShellAppWaiting = GetAVar( ShellFid'.shellappwaiting')
    513       if words( ShellAppWaiting) < 2 then
     749         CurCmd = InitCmd
     750         call SetAVar( 'shellcurrentcmd', CurCmd)
     751         --'ShellWriteCmdQuiet' ShellNum CurCmd
     752         'ShellWriteCmdQuiet' ShellNum CurCmd
     753      endif
     754
     755      call ShellParsePromptLine( .last, LastPrompt, LastCmd)
     756      if LastPrompt | .last = 1 then
    514757         -- Execute Cmd
    515758         if Cmd then
    516             'ShellWrite' ShellNum Cmd
     759            --'ShellWriteCmdQuiet' ShellNum Cmd
     760            'ShellWriteCmd' ShellNum Cmd
    517761         endif
    518762         -- Use real case of current dir, even when XWP has uppercased it.
     
    538782; SHELL. Can be used to "reactivate" a shell, whose .command_shell_ output
    539783; was saved before and then gets reloaded.
     784; This is executed by defc Mode.
    540785defc ShellRestore
    541786   universal shell_index
     
    574819
    575820      -- Determine previous work dir
    576       call pSave_Pos( save_pos)
    577       SavedRc = rc
    578821      display -3
    579822      .lineg = .last
    580823      endline
    581       call ShellGotoNextPrompt( 'P')
    582       Dir = ''
    583       Cmd = ''
    584       if not rc then
    585          call ShellParsePromptLine( Dir, Cmd)
    586       else
    587          call pRestore_Pos( save_pos)
    588       endif
    589       rc = SavedRc
     824      Dir = ShellGetPrevDir()
    590825      display 3
    591826
     
    593828         if directory() <> Dir then
    594829            CdCmd = 'cdd' EnquoteFilespec( Dir)
    595             'ShellWrite' shell_index CdCmd
     830            --'ShellWrite' shell_index CdCmd
     831            'ShellWriteCmdQuiet' shell_index CdCmd
    596832         endif
    597833      endif
     
    678914      call SetAVar( 'shell_f'ShellNum, '')
    679915      call SetAVar( 'shell_h'ShellNum, '')
    680       call SetAVar( SellFid'.shellnum', '')
     916      call SetAVar( ShellFid'.shellnum', '')
    681917      if fClose then
    682918         if curfid <> ShellFid then
     
    688924; ---------------------------------------------------------------------------
    689925defc ShellClose
    690    .modify = 0
     926   'ShellResetModify'
    691927   'ShellKill'
     928
     929; ---------------------------------------------------------------------------
     930defmodify
     931--   'ShellResetModify'
     932
     933; ---------------------------------------------------------------------------
     934defc ShellResetModify
     935   if IsAShell() then
     936      if .modify then
     937         -- This ensures that special files can be closed without
     938         -- popping up a message box that asks "Are you sure?"
     939         if FileShouldBeDiscarded() then
     940            .modify = 0
     941         endif
     942
     943         -- This doesn't work:
     944         'RefreshInfoLine DATETIMEMODIFIED'
     945         -- This works:
     946         --'SetStatusLine'
     947         --'RefreshInfoLine FILE'  -- as well
     948      endif
     949   endif
    692950
    693951; ===========================================================================
     
    699957; If first word is not a number, then last opened shell is used as
    700958; <shellnum>.
    701 ; If <input> is missing, the 'Write to shell' EntryBox opens.
    702959defc ShellWrite, Shell_Write
    703    universal shelllastwrite
     960
     961   call ShellWriteParseCommon( arg( 1), ShellNum, Input, fCallAgain,
     962                               'ShellWrite')
     963   if fCallAgain then
     964      return
     965   endif
     966
     967   -- Write to shell
     968   fAppendLineEnd = 1
     969dprintf( 'ShellWrite: -------- Input = 'Input' --------')
     970   call ShellWriteCommon( ShellNum, fAppendLineEnd, Input)
     971
     972; ---------------------------------------------------------------------------
     973; Syntax: ShellWriteCmd [<shellnum>] [<input>]
     974; If first word is not a number, then last opened shell is used as
     975; <shellnum>.
     976defc ShellWriteCmd
     977
     978   call ShellWriteParseCommon( arg( 1), ShellNum, Input, fCallAgain,
     979                               'ShellWriteCmd')
     980   if fCallAgain then
     981      return
     982   endif
     983
     984   -- Store shellcurrentcmd
     985   call SetAVar( 'shellcurrentcmd', Input)
     986
     987   -- Write to shell
     988   fAppendLineEnd = 1
     989dprintf( 'ShellWriteCmd: -------- Input = 'Input' --------')
     990   call ShellWriteCommon( ShellNum, fAppendLineEnd, Input)
     991
     992; ---------------------------------------------------------------------------
     993; Syntax: ShellWriteCmdQuiet [<shellnum>] [<input>]
     994; If first word is not a number, then last opened shell is used as
     995; <shellnum>.
     996; The output of <input> is not displayed. The previous last line (the empty
     997; prompt) is replaced with a new one.
     998defc ShellWriteCmdQuiet
     999
     1000   call ShellWriteParseCommon( arg( 1), ShellNum, Input, fCallAgain,
     1001                               'ShellWriteCmdQuiet')
     1002   if fCallAgain then
     1003      return
     1004   endif
     1005
     1006   -- Store shellcurrentcmd
     1007   call SetAVar( 'shellcurrentcmd', Input)
     1008
     1009   -- Ignore output for Cmd
     1010   imax = GetFileAVar( 'shellignorecmd.0')
     1011   if imax = '' then
     1012      imax = 0
     1013   endif
     1014   i = imax + 1
     1015   SetFileAVar( 'shellignorecmd.'i, Input)
     1016   SetFileAVar( 'shellignorecmd.0', i)
     1017
     1018   fAppendLineEnd = 1
     1019dprintf( 'ShellWriteCmdQuiet: -------- Input = 'Input' --------')
     1020   call ShellWriteCommon( ShellNum, fAppendLineEnd, Input)
     1021
     1022; ---------------------------------------------------------------------------
     1023; Syntax: ShellWriteChars [<shellnum>] [<input>]
     1024; If first word is not a number, then last opened shell is used as
     1025; <shellnum>.
     1026defc ShellWriteChars
     1027
     1028   call ShellWriteParseCommon( arg( 1), ShellNum, Input, fCallAgain,
     1029                               'ShellWriteChars')
     1030   if fCallAgain then
     1031      return
     1032   endif
     1033
     1034   -- Split at line end and strip it
     1035   pLF = pos( \10, Input)
     1036   if pLF then
     1037      Input = leftstr( Input, pLF)
     1038   endif
     1039   if rightstr( Input, 1) = \13 then
     1040      Input = leftstr( Input, length( Input) - 1)
     1041   endif
     1042   --dprintf( 'ShellWriteChars: Input = 'Input', pLF = 'pLF)
     1043
     1044   -- Type Input
     1045   fAppendLineEnd = 0
     1046dprintf( 'ShellWriteChars: -------- Input = 'Input', pLF = 'pLF' --------')
     1047   call ShellWriteCommon( ShellNum, fAppendLineEnd, Input)
     1048
     1049   if pLF then
     1050      -- Write cmd or line
     1051      'ShellEnterLine'
     1052   endif
     1053
     1054; ---------------------------------------------------------------------------
     1055; This returns fCallAgain and ensures that ShellNum is set.
     1056; -  If ShellNum is specified, it is verified. If it's of current file,
     1057;    fCallAgain is set to 0.
     1058; -  If ShellNum is not in ring or not specified, a new shell is opened and
     1059;    fCallAgain is set to 1.
     1060; -  If ShellNum is not specified, the last opened shell is used and
     1061;    fCallAgain is set to 1.
     1062defproc ShellVerifyShellNum( var fCallAgain, var ShellNum)
    7041063   universal shell_index
    7051064
    7061065   do once = 1 to 1
     1066      fCallAgain  = 0
    7071067      fShellFound = 0
    7081068
    709       parse arg ShellNum Input
    710       --dprintf( 'ShellWrite: ShellNum Input = 'ShellNum Input)
     1069      -- Keep topmost shell
     1070      if IsAShell() then
     1071         ShellNum = GetFileAVar( 'shellnum')
     1072         getfileid ShellFid
     1073         fShellFound = 1
     1074         --dprintf( '   ShellVerifyShellNum 1: ShellNum = 'ShellNum)
     1075         leave
     1076      endif
     1077
     1078      -- Switch to specified ShellNum if in ring
    7111079      if IsNum( ShellNum) then
    7121080         ShellFid = GetAVar( 'shell_f'ShellNum)
     
    7141082            pActivateFile( ShellFid)
    7151083            fShellFound = 1
     1084            --dprintf( '   ShellVerifyShellNum 2: ShellNum = 'ShellNum)
     1085            fCallAgain = 1
    7161086            leave
    7171087         endif
    7181088      endif
    7191089
    720       if IsAShell() then
    721          ShellNum = GetFileAVar( 'shellnum')
    722          getfileid ShellFid
    723          fShellFound = 1
    724          parse arg Input
    725          leave
    726       endif
    727 
     1090      -- Switch to last created shell if in ring
    7281091      do s = shell_index to 1 by -1
    7291092         ShellFid = GetAVar( 'shell_f'shell_index)
     
    7321095            pActivateFile( ShellFid)
    7331096            fShellFound = 1
    734             parse arg Input
    735             -- After switching to the shell, Input must be posted.
    736             -- Otherwise it won't be written to the shell.
    737             'PostMe ShellWrite 'ShellNum Input
    738             return
     1097            --dprintf( '   ShellVerifyShellNum 3: ShellNum = 'ShellNum)
     1098            fCallAgain = 1
     1099            leave
    7391100         endif
    7401101      enddo
    7411102
    7421103      -- Open a new shell if none in ring
    743       'Shell'
     1104      if not fShellFound then
     1105         'Shell'
     1106         --dprintf( '   ShellVerifyShellNum 4: ShellNum = 'ShellNum)
     1107         fCallAgain = 1
     1108         leave
     1109      endif
     1110
     1111   enddo  -- once
     1112
     1113   return
     1114
     1115; ---------------------------------------------------------------------------
     1116defproc ShellWriteParseCommon( Args, var ShellNum, var Input, var fCallAgain,
     1117                               CallingCmd)
     1118   parse value Args with ShellNum Input
     1119
     1120   ShellNum = strip( ShellNum)
     1121   Input    = strip( Input, 'L')
     1122   if ShellNum = '' then
     1123      -- nop
     1124   elseif not IsNum( ShellNum) then
     1125      ShellNum = ''
    7441126      parse arg Input
    745       'PostMe ShellWrite 'Input
    746       return
    747    enddo  -- once
    748 
    749    ShellAppWaiting = GetFileAVar( 'shellappwaiting')
     1127      Input = strip( Input, 'L')
     1128   endif
     1129   --dprintf( 'ShellWriteCmd after parse : ShellNum = 'ShellNum', Input = 'Input)
     1130
     1131   -- Ensure that ShellNum is set
     1132   call ShellVerifyShellNum( fCallAgain, ShellNum)
     1133   --dprintf( 'ShellWriteCmd after verify: ShellNum = 'ShellNum', Input = 'Input)
     1134   if fCallAgain then
     1135      -- After switching to the shell, Input must be posted.
     1136      -- Otherwise it won't be written to the shell.
     1137      'PostMe 'CallingCmd ShellNum Input
     1138   endif
     1139
     1140   return
     1141
     1142; ---------------------------------------------------------------------------
     1143defproc ShellWriteCommon( ShellNum, fAppendLineEnd, Input)
    7501144   ShellHandle = GetAVar( 'Shell_h'ShellNum)
    7511145
    752    if Input = '' & words( ShellAppWaiting) < 2 then  -- disable this silly box for Return in a waiting shell
    753       'ShellHistory 'ShellNum
    754    endif
    755 
    756    if Input <> '' then
    757       -- Set universal
    758       shelllastwrite = Input
    759       -- Append line end
    760       WriteBuf = Input\13\10
     1146   -- Determine if cmd output should be ignored
     1147   fIgnored = 0
     1148   imax = GetFileAVar( 'shellignorecmd.0')
     1149   if imax then
     1150      do i = 1 to imax
     1151         IgnoreCmd = GetFileAVar( 'shellignorecmd.'i)
     1152         if Input = IgnoreCmd then
     1153            fIgnored = 1
     1154            leave
     1155         endif
     1156      enddo
     1157   endif
     1158
     1159   -- Determine if app is waiting (LastPrompt = '') and read CurCmd
     1160   call ShellParsePromptLine( .last, LastPrompt, LastCmd)
     1161   call ShellParsePromptLine( .line, CurPrompt,  CurCmd)
     1162--dprintf( 'ShellWriteCommon: Input = 'Input', .line = '.line', CurCmd = 'CurCmd', CurPrompt = 'CurPrompt)
     1163
     1164   if not fIgnored then
     1165
     1166      if LastPrompt & fAppendLineEnd then
     1167
     1168         ---- Prompt on last line: write cmd ----
     1169         -- Change bookmark name from 'Last' to cmd
     1170         -- Get bmidx for last bookmark
     1171         bmidxmax = GetFileAVar( 'bmname.0')
     1172         --Input = CurCmd
     1173--dprintf( 'ShellWriteCommon: fAppendLineEnd = 'fAppendLineEnd', no app is waiting, set bookmark to 'Input)
     1174         --dprintf( 'Change bookmark name for bmidx 'bmidxmax' to "'Input'".')
     1175dprintf( "#  ShellWriteCommon: Bookmark name with index "bmidxmax" changed from 'Last' to >"Input"<")
     1176         call SetFileAVar( 'bmname.'bmidxmax, Input)
     1177
     1178         if .line = .last then
     1179--dprintf( 'ShellWriteCommon: Delete CurCmd = 'CurCmd', .line = '.line)
     1180            .col = length( CurPrompt) + 1
     1181            eraseendline
     1182         elseif IsADirectoryOfLine() then
     1183            -- Restore the previous 'Directory of' line from bookmark
     1184            getfileid ShellFid
     1185            bmidx  = GetBookmarkIdx( ShellFid, .line, 1)
     1186            bmname = GetBmName( ShellFid, bmidx)
     1187            bmline = .line
     1188            bmcol = 1
     1189            -- Replaceline deletes the bookmark
     1190dprintf( '#  ShellWriteCommon: Restore bmname = 'bmname', .line = '.line)
     1191            replaceline bmname
     1192            -- Set the bookmark back to col 1
     1193            SetBookmark( 3, bmline, bmcol, bmname)
     1194dprintf( '#  Bookmark set on line 'bmline' to >'bmname'<')
     1195         elseif CurPrompt then
     1196            -- Restore the previous Cmd from bookmark
     1197            getfileid ShellFid
     1198            bmidx  = GetBookmarkIdx( ShellFid, .line, 1)
     1199            bmname = GetBmName( ShellFid, bmidx)
     1200dprintf( '#  ShellWriteCommon: Restore bmname = 'bmname', .line = '.line)
     1201            .col = length( CurPrompt) + 1
     1202            -- Eraseendline preserves the bookmark in col 1
     1203            eraseendline
     1204            keyin bmname
     1205            -- Ensure that text after prompt in last line is deleted
     1206            .line = .last
     1207            .col = length( CurPrompt) + 1
     1208            eraseendline
     1209         endif
     1210
     1211      endif  -- LastPrompt & fAppendLineEnd
     1212
     1213   endif  -- not fIgnored
     1214
     1215   WriteBuff = Input
     1216   if fAppendLineEnd then
     1217      WriteBuff = WriteBuff\13\10
     1218   endif
     1219
     1220--dprintf( 'ShellWriteCommon: fAppendLineEnd = 'fAppendLineEnd', LastPrompt = 'LastPrompt)
     1221   if (LastPrompt & fAppendLineEnd) | not LastPrompt then
    7611222      -- Write to shell
    762       rc = Sue_Write( ShellHandle, WriteBuf, BytesMoved)
     1223--dprintf( 'ShellWriteCommon: Write Input = 'Input)
     1224      rc = Sue_Write( ShellHandle, WriteBuff, BytesMoved)
    7631225      -- Check rc
    764       if rc | (BytesMoved <> length( WriteBuf)) then
    765          'SayError ShellWrite: rc =' rc', byteswritten =' BytesMoved 'of' length( WriteBuf)
     1226      if rc | (BytesMoved <> length( WriteBuff)) then
     1227         'SayError ShellWriteCommon: rc =' rc', byteswritten =' BytesMoved 'of' length( WriteBuff)
    7661228         'ShellBreak'
    7671229      endif
    7681230   endif
     1231
     1232   return
    7691233
    7701234   -- The above code is not really complete.  It should also deal with
     
    7741238
    7751239; ---------------------------------------------------------------------------
    776 ; Opens a list box with last commands. The selected one can be submitted and
    777 ; optionally be edited in an entry box before. This was previously a part of
    778 ; ShellWrite, except that the order of both boxes was changed. It starts
    779 ; with the list box, not with the entry box. Main idea by Joerg Tiemann.
    780 defc ShellHistory, Shell_History
    781    universal shelllastwrite
    782 
    783    do once = 1 to 1
    784       parse arg ShellNum Input
    785       if ShellNum = '' & IsAShell() then
    786          ShellNum = GetFileAVar( 'shellnum')
    787       endif
    788       if ShellNum = '' then
    789          'SayError 'NOT_IN_SHELL__MSG
    790          return
    791       endif
    792 
    793       ShellHandle = GetAVar( 'shell_h'ShellNum)
    794 
    795       if ShellHandle = '' then
    796          leave
    797       endif
    798 
    799       BoxTitle = strip( WRITE_SHELL_MENU__MSG, 'T', '.')  -- '~Write to shell...'
    800       pTilde = pos( '~', BoxTitle)
    801       if pTilde then
    802          BoxTitle = delstr( BoxTitle, pTilde, 1)
    803       endif
    804 
    805       do forever
    806 
    807          getfileid ShellFid
    808          call pSave_Pos( SavedPos)
    809          'xcom e /c cmdslist'
    810          if rc <> -282 then  -- -282 = sayerror( "New file")
    811             'SayError 'ERROR__MSG rc BAD_TMP_FILE__MSG sayerrortext( rc)
    812             return
    813          endif
    814          browse_mode = browse()  -- Query current state
    815          if browse_mode then
    816             call browse( 0)
    817          endif
    818          .autosave = 0
    819          getfileid lb_fid
    820          activatefile ShellFid
    821          display -2
    822          getsearch SavedSearch
    823          0
    824 
    825 compile if EPM_SHELL_PROMPT = '@prompt epm: $p $g'
    826          'xcom l /^epm\: .*>:o./x'
    827 compile else  -- else EPM_SHELL_PROMPT = '@prompt [epm: $p ]'
    828          'xcom l /^\[epm\: .*\]:o./x'
    829 compile endif -- EPM_SHELL_PROMPT
    830 
    831          do while rc = 0
    832 compile if EPM_SHELL_PROMPT = '@prompt epm: $p $g'
    833             parse value textline( .line) with '>' Cmd
    834 compile else
    835             parse value textline( .line) with ']' Cmd
    836 compile endif -- EPM_SHELL_PROMPT
    837            insertline strip( Cmd, 'L'), lb_fid.last + 1, lb_fid
    838            repeatfind
    839          enddo
    840 
    841          setsearch SavedSearch
    842          call pRestore_Pos( SavedPos)
    843          if browse_mode then
    844             call browse( 1)   -- Restore browse state
    845          endif
    846          activatefile lb_fid
    847          display 2
    848          if not .modify then  -- Nothing added?
    849             'xcom quit'
    850             activatefile ShellFid
    851             'SayError -273'   -- String not found
    852             return
    853          endif
    854 
    855          if ListBox_Buffer_From_File( ShellFid, bufhndl, noflines, usedsize) then
    856             return
    857          endif
    858          Text = ''
    859          ListBoxButtons = '/'OK__MSG'/'EDIT__MSG'.../'Cancel__MSG
    860          DefaultItem = noflines - 1  -- Last item, first line of lb_fid is empty
    861          DefaultButton = 1
    862          HelpId = 0
    863          parse value ListBox( BoxTitle,
    864                               \0 || atol( usedsize) || atoi( 32) || atoi( bufhndl),
    865                               ListBoxButtons,
    866                                0, 0,  -- top, left
    867                               12, 0,  -- height, width,
    868                               GethWndC( APP_HANDLE) ||
    869                               atoi( DefaultItem)    ||
    870                               atoi( DefaultButton)  ||
    871                               atoi( HelpId) ||
    872                               Text\0) with LbButton 2 Input \0
    873          call buffer( FREEBUF, bufhndl)
    874 
    875          if LbButton = \1 then
    876             leave
    877          elseif LbButton = \2 then  -- 'Edit' selected
    878             -- Set universal
    879             shelllastwrite = Input
    880 
    881             Text = SHELL_PROMPT__MSG ShellNum
    882             Text = Text''copies( ' ', Max( 0, 100 - length( Text)))
    883 compile if EPM_SHELL_PROMPT = '@prompt epm: $p $g' | EPM_SHELL_PROMPT = '@prompt [epm: $p ]'
    884             EntryBoxButtons = '/'OK__MSG'/'LIST__MSG'/'Cancel__MSG'/'
    885             NumEntryBoxButtons = 3
    886 compile else
    887             EntryBoxButtons = '/'OK__MSG'/'Cancel__MSG'/'
    888             NumEntryBoxButtons = 2
    889 compile endif
    890             DefaultButton = 1
    891             --HelpId = 0
    892             parse value EntryBox( BoxTitle,
    893                                   EntryBoxButtons,
    894                                   shelllastwrite,  -- entrytext
    895                                   0, 254,          -- cols, maxchars
    896                                   atoi( DefaultButton)  ||
    897                                   atoi( HelpId)         ||
    898                                   GethWndC( APP_HANDLE) ||
    899                                   Text) with EbButton 2 Input \0
    900             if EbButton = \1 then
    901                leave
    902             elseif EbButton = \2 & NumEntryBoxButtons = 3 then  -- 'List' selected
    903                iterate
    904             else
    905                return
    906             endif
    907 
    908          else
    909             return
    910          endif
    911 
    912       enddo  -- forever
    913 
    914       'ShellWrite 'Input
    915    enddo
    916 
    917 ; ---------------------------------------------------------------------------
    9181240; Shell object sends this command to inform the editor that there is
    9191241; room for additional data to be written.
    9201242defc NowCanWriteShell
    921    'SayError 'SHELL_OBJECT__MSG arg( 1) SHELL_READY__MSG -- Use ShellWrite with argumentstring
     1243    -- Use ShellWrite with argumentstring
     1244   'SayError 'SHELL_OBJECT__MSG arg( 1) SHELL_READY__MSG
     1245
     1246; ===========================================================================
     1247; Current dir and E cmd
     1248; ===========================================================================
     1249
     1250; ---------------------------------------------------------------------------
     1251; Instead of writing to a tmp file, put it out to shell, read line
     1252; and disable output.
     1253defproc ShellGetCmdOutput
     1254   Cmd     = arg( 1)
     1255   LineNum = arg( 2)  -- Which line of LogFile should be read
     1256   if LineNum = '' then
     1257      LineNum = 1
     1258   endif
     1259   OutputLine = ''
     1260   display -1
     1261   do once = 1 to 1
     1262      if Cmd = '' then
     1263         leave
     1264      endif
     1265      if not IsAShell() then
     1266         leave
     1267      endif
     1268      LogFile = GetTmpPath()'nepmd\shellcmd.log'
     1269      if Exist( LogFile) then
     1270         DeleteFile( LogFile)
     1271      endif
     1272
     1273      'ShellWriteCmdQuiet 'Cmd'>'LogFile
     1274      getfileid ShellFid
     1275
     1276      -- Delay loop until file exists
     1277      fLogFileFound = 0
     1278      TimeOutMs     = 1000
     1279      NumIterations = 1000  -- 1000 means: a check every 1 ms
     1280      do i = 1 to NumIterations
     1281         if Exist( LogFile) then
     1282            --dprintf( 'LogFile found after '(i - 1) * TimeOutMs / NumIterations' ms')
     1283            fLogFileFound = 1
     1284            leave
     1285         else
     1286            Sleep( TimeOutMs / NumIterations)
     1287         endif
     1288      enddo
     1289      if not fLogFileFound then
     1290         rc = 2
     1291         leave
     1292      endif
     1293
     1294      -- xcom e /d always loads a file. If it doesn't exist, it's created.
     1295      'xcom e /d /q 'LogFile
     1296      if rc then
     1297dprintf( sayerrortext( rc))
     1298         activatefile ShellFid
     1299         leave
     1300      endif
     1301
     1302      getfileid LogFid
     1303      getline OutputLine, LineNum, LogFid
     1304      activatefile LogFid
     1305      .modify = 0
     1306      'xcom q'
     1307      DeleteFile( LogFile)
     1308      activatefile ShellFid
     1309   enddo
     1310   display 1
     1311   return OutputLine
     1312
     1313; ---------------------------------------------------------------------------
     1314; Instead of writing to a tmp file, put it out to shell, read line
     1315; and disable output.
     1316defproc ShellGetCurDir
     1317   CurDir = ''
     1318   display -1
     1319   do once = 1 to 1
     1320      if not IsAShell() then
     1321         leave
     1322      endif
     1323      LogFile = GetTmpPath()'nepmd\curdir.log'
     1324      Cmd = 'cd>'LogFile
     1325      if Exist( LogFile) then
     1326         DeleteFile( LogFile)
     1327      endif
     1328
     1329      'ShellWriteCmdQuiet 'Cmd
     1330      getfileid ShellFid
     1331
     1332      -- Delay loop until file exists
     1333      fLogFileFound = 0
     1334      TimeOutMs     = 1000
     1335      NumIterations = 1000  -- 1000 means: a check every 1 ms
     1336      do i = 1 to NumIterations
     1337         if Exist( LogFile) then
     1338            --dprintf( 'LogFile found after '(i - 1) * TimeOutMs / NumIterations' ms')
     1339            fLogFileFound = 1
     1340            leave
     1341         else
     1342            Sleep( TimeOutMs / NumIterations)  -- usually 1 iteration required
     1343         endif
     1344      enddo
     1345      if not fLogFileFound then
     1346         rc = 2
     1347         leave
     1348      endif
     1349
     1350      -- xcom e /d always loads a file. If it doesn't exist, it's created.
     1351      'xcom e /d /q 'LogFile
     1352      if rc then
     1353--dprintf( sayerrortext( rc))
     1354         activatefile ShellFid
     1355         leave
     1356      endif
     1357
     1358      getfileid LogFid
     1359      LogFid.visible = 0
     1360      getline CurDir, 1, LogFid
     1361      activatefile LogFid
     1362      .modify = 0
     1363      'xcom q'
     1364      DeleteFile( LogFile)
     1365      --'PostMe 'ShellGetCurDirFromLog LogFile
     1366      activatefile ShellFid
     1367   enddo
     1368   display 1
     1369   return CurDir
     1370
     1371defc ShellGetCurDir
     1372   CurDir = ShellGetCurDir()
     1373   dprintf( 'CurDir = 'CurDir', rc = 'rc)
     1374   'SayError CurDir = 'CurDir', rc = 'rc
     1375
     1376; ---------------------------------------------------------------------------
     1377defc ShellGetCurDirFromLog
     1378   do once = 1 to 1
     1379      LogFile = strip( arg( 1))
     1380      LineStr = ''
     1381/*
     1382      'xcom e /c 'LogFile
     1383      getfileid
     1384      --Read first line
     1385      LineStr = '...'
     1386      .modify = 0
     1387      'xcom q'
     1388      DeleteFile( LogFile)
     1389      call ShellGetCurDir( LineStr)
     1390*/
     1391   enddo
     1392
     1393; ---------------------------------------------------------------------------
     1394defproc ShellECmd( ECmd, Line, Col)
     1395   .line = Line
     1396   .col  = Col
     1397
     1398   if .line = .last then
     1399      eraseendline
     1400   else
     1401      -- Restore the previous Cmd from bookmark
     1402      getfileid ShellFid
     1403      bmidx  = GetBookmarkIdx( ShellFid, .line, 1)
     1404      bmname = GetBmName( ShellFid, bmidx)
     1405      eraseendline
     1406      keyin bmname
     1407   endif
     1408
     1409   -- Execute ECmd
     1410   ECmd
     1411
     1412   return
    9221413
    9231414; ===========================================================================
     
    9401431; -  Recognize if an app is waiting for user input (then last line is not the
    9411432;    EPM prompt).
    942 ; -  Set ShellAppWaiting to 0 or to line and col.
     1433; -  Stores line and col after output to shelloutputpos.
    9431434; -  Right margin setting of current shell is not respected.
    9441435; -  The prompt after executing a start command (maybe "start epm config.sys")
     
    9601451   pActivateFile( ShellFid)
    9611452
    962    -- Enable ititial line deletion
    963    StartLineNum = GetAVar( ShellFid'.startlinenum')
     1453   -- Enable initial line deletion
     1454   StartLineNum = GetAVar( ShellFid'.shellstartlinenum')
    9641455   fFilterInitLines = 0
     1456/*
    9651457   if IsNum( StartLineNum) then
    9661458      if StartLineNum = .last then
     
    9691461      endif
    9701462   endif
     1463*/
    9711464   --dprintf( 'ShellOutputLines: StartLineNum = 'StartLineNum', .last = '.last', fFilterInitLines = 'fFilterInitLines)
    9721465
    973    TotalBytesMoved = 0
     1466   CurCmd = GetAVar( 'shellcurrentcmd')
     1467
     1468   TotalBytesMoved    = 0
     1469   fIgnoreCurrentCmd  = 0
     1470   fReplaceLastPrompt = 0
    9741471   do forever  -- (until (BytesMoved = 0) = (RestLineStr == ''))
    9751472
     
    9821479      retval = Sue_ReadLn( ShellHandle, ReadBuff, BytesMoved)
    9831480      ReadBuff = leftstr( ReadBuff, BytesMoved)
     1481if fIgnoreCurrentCmd then
     1482--dprintf( 'ReadBuff = 'translate( ReadBuff, \1\2'~', \10\13\20))
     1483endif
    9841484      if not BytesMoved then
    9851485         leave
     
    9871487
    9881488      TotalBytesMoved = TotalBytesMoved + BytesMoved
    989       RestLineStr = ReadBuff
    9901489      --dprintf( 'ShellOutputLines: ReadBuff = 'translate( RestLineStr, \1\2'~', \10\13\20))
    9911490
    992       -- Write ReadBuff line-wise to current file. Split at LF, ignore CR.
    9931491      -- Both CR and LF end a line (read by Sue_ReadLn) and start a new one.
     1492      if ReadBuff = \13 then
     1493         iterate  -- ignore CR
     1494      endif
     1495
     1496      -- Ignore ANSI Esc sequences. Determine if current line should be
     1497      -- ignored because of quiet output set by ShellWriteCmdQuiet.
     1498      call ShellFilterReadLineBuff( ReadBuff, fIgnoreCurrentCmd, fReplaceLastPrompt)
     1499dprintf( 'ShellOutputLines after filter: fIgnoreCurrentCmd = 'fIgnoreCurrentCmd', fReplaceLastPrompt = 'fReplaceLastPrompt)
     1500
     1501      -- Write ReadBuff line-wise to current file.
    9941502      -- ReadBuff may contain additional LF chars. That is handled here.
    995       if RestLineStr = \13 then
    996          iterate  -- ignore CR
    997       endif
    998 
    999       -- Filter out ANSI Esc sequences.
    1000       do forever
    1001          pEscStart = pos( \27'[', RestLineStr)
    1002          if pEscStart = 0 then
    1003             leave
    1004          else
    1005             pEscEnd = verify( RestLineStr, 'ABCDHJKnfRhlmpsu', 'M', pEscStart + 2)
    1006             if pEscEnd = 0 then
    1007                leave
    1008             endif
    1009             RestLineStr = delstr( RestLineStr, pEscStart, pEscEnd - pEscStart + 1)
    1010          endif
    1011       enddo
    1012 
    1013       -- Write output lines to the shell file
    1014       -- Slow output and missing spaces in the prompt with
    1015       -- "do while RestLineStr <> ''". See the description at the proc begin.
    1016       do forever  -- (until RestLineStr == '')
    1017          -- Split at further LF chars from col 2 on
    1018          pLF = pos( \10, RestLineStr, 2)
    1019          if pLF > 0 then
    1020             --dprintf( '*  LF found in RestLineStr = 'leftstr( translate( RestLineStr, \1\2'~', \10\13\20), Min( 40, length( RestLineStr))))
    1021             NextLineStr = leftstr( RestLineStr, pLF - 1)
    1022             RestLineStr = substr( RestLineStr, pLF)
    1023          else
    1024             NextLineStr = RestLineStr
    1025             RestLineStr = ''
    1026          endif
    1027 
    1028          -- Handle LF char at col 1
    1029          if leftstr( NextLineStr, 1) = \10 then  -- LF is lineend
    1030             insertline substr( NextLineStr, 2), .last + 1
    1031          else
    1032             getline PrevLineStr, .last
    1033             AppendedLen = length( PrevLineStr) + length( NextLineStr)
    1034             if AppendedLen <= MAXCOL then
    1035                -- Append NextLineStr to PrevLineStr.
    1036                -- Instead of replaceline, keyin preserves bookmarks
    1037                -- in PrevLineStr.
    1038                .line = .last
    1039                .col  = length( PrevLineStr) + 1
    1040                keyin NextLineStr
    1041             else
    1042                insertline NextLineStr, .last + 1
    1043             endif
    1044          endif
    1045 
    1046          if RestLineStr == '' then
    1047             -- Get next ReadBuf from output stream
    1048             leave
    1049          endif
    1050       enddo  -- forever (until RestLineStr == '')
     1503      call ShellProcessReadLineBuff( ReadBuff, fIgnoreCurrentCmd, fReplaceLastPrompt)
     1504--dprintf( 'ShellOutputLines after write : fIgnoreCurrentCmd = 'fIgnoreCurrentCmd', fReplaceLastPrompt = 'fReplaceLastPrompt)
    10511505
    10521506   enddo  -- forever (until (BytesMoved = 0) = (RestLineStr == ''))
     
    10581512      .line = .last
    10591513      .col = Min( MAXCOL, length( LastLineStr) + 1)
    1060 
    1061       -- This searches the prompt in LastLineStr
    1062       -- Check if last written line was the EPM prompt
    1063       -- in order to accept input by a waiting application directly
    1064       -- in the shell buffer, not only in the Write to shell dialog.
    1065 compile if EPM_SHELL_PROMPT = '@prompt epm: $p $g'
    1066       p1 = leftstr( LastLineStr, 5) = 'epm: '
    1067       p2 = rightstr( strip( LastLineStr, 't'), 1) = '>'
    1068 compile else  -- else EPM_SHELL_PROMPT = '@prompt [epm: $p ]'
    1069       p1 = leftstr( LastLineStr, 6) = '[epm: '
    1070       p2 = rightstr( strip( LastLineStr, 't'), 1) = ']'
    1071 compile endif -- EPM_SHELL_PROMPT
    1072       -- Set array var
    1073       if p1 > 0 & p2 > 0 then
    1074          -- Set to 0
    1075          ShellAppWaiting = 0
    1076          --dprintf( 'App terminated')
    1077          -- Set bookmark
     1514      call ShellParsePromptLine( .last, LastPrompt, LastCmd)
     1515      do once = 1 to 1
     1516         if not LastPrompt then
     1517            leave
     1518         endif
     1519         -- Reset shellcurrentcmd
     1520         SetAVar( 'shellcurrentcmd', '')
     1521dprintf( '#  Reset shellcurrentcmd')
     1522
     1523         -- Prepare to set bookmark 'Last'
    10781524         bmline = .last
    10791525         bmcol = 1
    1080          SetBookmark( 3, bmline, bmcol, 'Last')
    1081          NextCmdAltersText()
    1082          --bmidxmax = GetAVar( ShellFid'.bmname.0')
    1083          --dprintf( 'Set bookmark for last line '.last' and bmidx 'bmidxmax' to "Last"')
    1084       else
    1085          -- Set to '.line .col' if app is waiting for user input
    1086          ShellAppWaiting = .line .col
    1087          --dprintf( 'app waiting for input or further output will follow')
    1088       endif
    1089       call SetAVar( ShellFid'.shellappwaiting', ShellAppWaiting)  -- save
     1526         bmval = 'Last'
     1527         -- In case of slow output, each char of the prompt arrives separately.
     1528         -- If the prompt has a trailing space, LastPrompt parsing is in both
     1529         -- cases true and the same bookmark is added two times.
     1530         SavedRc = rc
     1531         Checkidx = GetBookmarkIdx( ShellFid, bmline, bmcol)
     1532         if not rc then
     1533            CheckName = GetBmName( ShellFid, Checkidx)
     1534            if CheckName = bmval then
     1535               -- Already set
     1536               leave
     1537            endif
     1538         endif
     1539         rc = SavedRc
     1540         -- Set bookmark
     1541         SetBookmark( 3, bmline, bmcol, bmval)
     1542dprintf( '#  Bookmark set on line 'bmline' to >'bmval'< ShellGetLastCmd() = 'ShellGetLastCmd())
     1543         --NextCmdAltersText()
     1544      enddo
     1545
     1546/*
     1547      -- Store pos. after output
     1548      call SetAVar( ShellFid'.shelloutputpos', .line .col)
     1549*/
    10901550   endif
    10911551
     
    10961556      -- For a restored shell file, the previous last line is deleted.
    10971557      do l = LastDeleteLineNum to StartLineNum by -1
    1098          --dprintf( 'l = 'l', deleteline 'l':'textline( l))
    1099          deleteline l
     1558dprintf( 'l = 'l', deleteline 'l':'textline( l))
     1559         -- This deletes bookmarks, too:
     1560         pSave_Pos( SavedPos)
     1561         .lineg = l
     1562         call DelAttrInLine()
     1563         deleteline
     1564         pRestore_Pos( SavedPos)
    11001565      enddo
    1101       --.last        -- This causes sometimes the compiler to stop with:
    1102       --             --    Invalid field name?
    1103       --             -- Strange: It depends on the code before.
    1104       .line = .last  -- This compiles always.
    1105       -- Disable future line deletion
    1106       SetAVar( ShellFid'.startlinenum', '')
    1107    endif
     1566      .modify = 0
     1567   endif
     1568
     1569   .line = .last
     1570   endline
     1571   -- Store pos. after output
     1572   PrevOutputPos = GetAVar( ShellFid'.shelloutputpos')
     1573   fInitEnded = 0
     1574   if PrevOutputPos = '' then
     1575      fInitEnded = 1
     1576   endif
     1577   call SetAVar( ShellFid'.shelloutputpos', .line .col)
     1578
     1579   -- Disable future line deletion
     1580   SetAVar( ShellFid'.shellstartlinenum', '')
     1581dprintf( 'ShellOutputLines: -------- End of init at '.line .col' -------- PrevOutputPos = 'PrevOutputPos', fInitEnded = 'fInitEnded)
    11081582
    11091583   return
    11101584
    1111 ; ===========================================================================
    1112 ; ShellInput
    1113 ; ===========================================================================
    1114 
    1115 ; ---------------------------------------------------------------------------
    1116 ; Writes user input to the shell if EPM prompt is in current line.
    1117 ; Enhanced for filename completion. Prepend 'cd ' to input if a directory.
    1118 ; Remove trailing \ from directories for 'cd'.
    1119 ; Works with spaces in filenames and surrounding "...".
    1120 ; This is the defproc called by the Enter key def.
    1121 ; Sets rc = 0 on success; 1 when not on a EPM prompt line.
    1122 ; If rc = 1 is set, then ShellEnterWriteToApp() should be called by the
    1123 ; Enter key def.
    1124 ;
    1125 ; ECHO must be ON. That is the default setting in CMD.EXE, but not in 4OS2.EXE.
    1126 ; Otherwise no prompt is inserted after the command execution and further commands
    1127 ; won't work (CMD.EXE) or the command is deleted (4OS2.EXE).
    1128 ; Therefore ECHO ON must be executed _after_ every call of 4OS2.EXE.
    1129 defproc ShellEnterWrite
    1130    do once = 1 to 1
    1131       rcx = 1
    1132       ShellNum = GetFileAVar( 'shellnum')
    1133       p = ShellPromptPos()
    1134       if not p then
    1135          leave
    1136       endif
    1137 
    1138       getfileid ShellFid
    1139 
    1140       -- Parse Input
    1141       getline LineStr
    1142       Input = substr( LineStr, p + 1)
    1143       Input = strip( Input, 'L')
    1144 
    1145       -- Process alias in Input
    1146       KeyPath = '\NEPMD\User\Shell\Alias'
    1147       on = (QueryConfigKey( KeyPath) <> 0)
    1148       if on then
    1149          Input = ShellAliasResolve( Input)
    1150       endif
    1151 
    1152       -- Parse Input into CmdWord, CmdArgs and CmdName
    1153       fCmdWordEnquoted = 0
    1154       if leftstr( Input, 1) = '"' then
    1155          fCmdWordEnquoted = 1
    1156          parse value Input with '"'CmdWord'"' CmdArgs
     1585; ---------------------------------------------------------------------------
     1586; Ignores ANSI Esc sequences. Determines if current line should be
     1587; ignored because of quiet output set by ShellWriteCmdQuiet.
     1588defproc ShellFilterReadLineBuff( var RestLineStr, var fIgnoreCurrentCmd,
     1589                                 var fReplaceLastPrompt)
     1590   -- Filter out ANSI Esc sequences
     1591   do forever
     1592      pEscStart = pos( \27'[', RestLineStr)
     1593      if pEscStart = 0 then
     1594         leave
     1595      endif
     1596      pEscEnd = verify( RestLineStr, 'ABCDHJKnfRhlmpsu', 'M', pEscStart + 2)
     1597      if pEscEnd = 0 then
     1598         leave
     1599      endif
     1600      RestLineStr = delstr( RestLineStr, pEscStart, pEscEnd - pEscStart + 1)
     1601   enddo
     1602--dprintf( 'RestLineStr = 'translate( RestLineStr, \1\2'~', \10\13\20))
     1603
     1604   -- Flag: reset fIgnoreCurrentCmd on the next prompt
     1605   if fIgnoreCurrentCmd then
     1606      PromptVal = ShellGetPromptValue()
     1607      SearchStr = ShellPromptToSearchStr( PromptVal)
     1608      if leftstr( RestLineStr, 1) = \10 then
     1609         CheckLineStr = substr( RestLineStr, 2)
    11571610      else
    1158          parse value Input with CmdWord CmdArgs
    1159       endif
    1160       CmdName = upcase( StripExt( StripPath( CmdWord)))
    1161 
    1162       -- Handle the silly M$ syntax extension for CD like "cd\", "cd.." etc.
    1163       -- Not required for CMD.EXE, just for to determine CmdName.
    1164       if wordpos( leftstr( upcase( CmdWord), 3), 'CD\ CD.') then
    1165          CmdArgs = substr( CmdWord, 3)
    1166          CmdWord = 'cd'
    1167          CmdName = 'CD'
    1168       endif
    1169 
    1170       -- Prepend "cd" if no CmdName given (true for a trailing '\')
    1171       if CmdName = '' & CmdWord <> '' & CmdArgs = '' then
    1172          CmdArgs = CmdWord
    1173          CmdWord = 'cd'
    1174          CmdName = 'CD'
    1175          fCmdWordEnquoted = 0
    1176 
    1177          -- Strip trailing \ from CmdArgs
    1178          if rightstr( CmdArgs, 1) = '\' &
    1179             CmdArgs <> '\' &
    1180             rightstr( CmdArgs, 2) <> ':\' then
    1181             CmdArgs = strip( CmdArgs, 'T', '\')
    1182          endif
    1183          CmdArgs = EnquoteFileSpec( CmdArgs)
    1184       endif
    1185 
    1186       if CmdName = '4OS2' then
    1187          -- Insert "echo on" when 4os2 is called
    1188          if CmdArgs = '' then
    1189             CmdArgs = 'echo on'
     1611         CheckLineStr = RestLineStr
     1612      endif
     1613      if CheckLineStr <> '' then
     1614         pPromptFound = pos( SearchStr, CheckLineStr, 1, 'x')
     1615         if pPromptFound then
     1616            -- Reset shellignorecmd
     1617            fIgnoreCurrentCmd = 0
     1618            imax = GetFileAVar( 'shellignorecmd.0')
     1619            do i = 1 to imax
     1620               DropFileAVar( 'shellignorecmd.'i)
     1621               SetFileAVar( 'shellignorecmd.0', 0)
     1622            enddo
     1623dprintf( 'ShellFilterReadLineBuff: Reset shellignorecmd')
     1624         endif
     1625--dprintf( 'fIgnoreCurrentCmd = 'fIgnoreCurrentCmd', pPromptFound = 'pPromptFound)
     1626      endif
     1627   else
     1628--dprintf( 'fIgnoreCurrentCmd = 'fIgnoreCurrentCmd)
     1629   endif
     1630
     1631   -- Flag: determine if current Cmd should be ignored
     1632   --CurCmd = GetAVar( 'shellcurrentcmd')
     1633   CurCmd = ShellGetLastCmd()
     1634   if not fIgnoreCurrentCmd then
     1635      imax = GetFileAVar( 'shellignorecmd.0')
     1636dprintf( 'ShellFilterReadLineBuff: imax = 'imax', CurCmd = 'CurCmd)
     1637      if imax then
     1638         do i = 1 to imax
     1639            IgnoreCmd = GetFileAVar( 'shellignorecmd.'i)
     1640dprintf( 'ShellFilterReadLineBuff: IgnoreCmd = 'IgnoreCmd', i = 'i)
     1641            if CurCmd = IgnoreCmd & IgnoreCmd then
     1642               fIgnoreCurrentCmd = 1
     1643               fReplaceLastPrompt = 1
     1644               leave
     1645            endif
     1646         enddo
     1647      endif
     1648   endif
     1649
     1650   return
     1651
     1652; ---------------------------------------------------------------------------
     1653; Writes RestLineStr line-wise to current file.
     1654; RestLineStr may contain additional LF chars. That is handled here.
     1655defproc ShellProcessReadLineBuff( var RestLineStr, var fIgnoreCurrentCmd,
     1656                                  var fReplaceLastPrompt)
     1657   -- Write output lines to the shell file
     1658   -- Slow output and missing spaces in the prompt with
     1659   --    "do while RestLineStr <> ''"
     1660   -- See the description at the begin of ShellOutputLines.
     1661   do forever  -- (until RestLineStr == '')
     1662
     1663      -- Split RestLineStr at further LF chars into NextLineStr and
     1664      -- RestLineStr. A read line usually starts with LF. (CR is already
     1665      -- filtered out at this point.)
     1666      pLF = pos( \10, RestLineStr, 2)
     1667      if pLF > 0 then
     1668         --dprintf( '*  LF found in RestLineStr = 'leftstr( translate( RestLineStr, \1\2'~', \10\13\20), Min( 40, length( RestLineStr))))
     1669         NextLineStr = leftstr( RestLineStr, pLF - 1)
     1670         RestLineStr = substr( RestLineStr, pLF)
     1671      else
     1672         NextLineStr = RestLineStr
     1673         RestLineStr = ''
     1674      endif
     1675
     1676      -- TODO: Improve fIgnoreCurrentCmd handling, fix fReplaceLastPrompt
     1677      if not fIgnoreCurrentCmd then
     1678
     1679         -- Replace last prompt
     1680         if fReplaceLastPrompt then
     1681            deleteline .last
     1682            fReplaceLastPrompt = 0
     1683         endif
     1684
     1685         -- Put out NextLineStr
     1686         -- Handle LF char at col 1
     1687         if leftstr( NextLineStr, 1) = \10 then  -- LF is lineend
     1688            TextStr = substr( NextLineStr, 2)
     1689            insertline TextStr, .last + 1
    11901690         else
    1191             CmdArgs = 'echo on&'CmdArgs
    1192          endif
    1193       endif
    1194 
    1195       -- Reconcatenate Input args
    1196       if fCmdWordEnquoted = 0 then
    1197          Input = CmdWord
    1198       else
    1199          Input = '"'CmdWord'"'
    1200       endif
    1201       if CmdArgs <> '' then
    1202          Input = Input CmdArgs
    1203       endif
    1204 
    1205       if .line = .last then
    1206          .col = p + 1  -- After prompt
    1207          if rightstr( EPM_SHELL_PROMPT, 1) == ' ' |
    1208             rightstr( EPM_SHELL_PROMPT, 2) == '$s' then
    1209             keyin ' '  -- For the trailing space of the prompt
    1210          endif
    1211          --dprintf( 'Cursor on last line '.last' and col '.col)
    1212          eraseendline  -- Delete the rest, because echo is on to avoid
    1213                        -- doubled Cmd.
    1214                        -- Echo off, executed in CMD.EXE, would suppress the
    1215                        -- prompt as well.
    1216       else
    1217           -- The Undo statement doesn't restore the prompt line well (only
    1218           -- last change, depending on .modify). Therefore the line is
    1219           -- restored by an array var, set by the defproc for the Enter key.
    1220          'PostMe ShellRestoreOrgCmd' .line
    1221       endif
    1222 
    1223       -- Change bookmark name from 'Last' to Input
    1224       -- Get bmidx for last bookmark
    1225       bmidxmax = GetAVar( ShellFid'.bmname.0')
    1226       --dprintf( 'Change bookmark name for bmidx 'bmidxmax' to "'Input'".')
    1227       call SetAVar( ShellFid'.bmname.'bmidxmax, Input)
    1228 
    1229       'ShellWrite' ShellNum Input
    1230 
    1231       rcx = 0
    1232 
    1233    enddo
    1234    rc = rcx
    1235 
    1236    return
    1237 
    1238 ; ---------------------------------------------------------------------------
    1239 ; Restore previously saved Cmd from bmname
    1240 defc ShellRestoreOrgCmd
    1241    -- Get bmname from bmline and bmcol
    1242    getfileid ShellFid
    1243    bmline = .line
    1244    bmcol  = 1
    1245    bmidx = GetBookmarkIdx( ShellFid, bmline, bmcol)
    1246    bmname = GetAVar( ShellFid'.bmname.'bmidx)
    1247 
    1248    -- Find prompt
    1249    p = ShellPromptPos()
    1250    --dprintf( 'ShellPromptPos = 'p', bmline = 'bmline', bmname = 'bmname)
    1251    if p then
    1252       -- Reinsert cmd, saved as bmname
    1253       .col = p + 1
    1254       eraseendline
    1255       if rightstr( EPM_SHELL_PROMPT, 1) == ' ' |
    1256          rightstr( EPM_SHELL_PROMPT, 2) == '$s' then
    1257          keyin ' '  -- For the trailing space of the prompt
    1258       endif
    1259       keyin bmname
    1260    endif
    1261 
    1262 ; ---------------------------------------------------------------------------
    1263 ; Write user input to a prompting (waiting) app.
    1264 ; For differing the output that comes from the app from the user input, the
    1265 ; array var "ShellAppWaiting" is used. It holds line and col from the last
    1266 ; write of the shell object to the EPM window, set in defc NowCanReadShell.
    1267 ; In case of a terminated app, the EPM prompt was the last output and
    1268 ; ShellAppWaiting holds the value 0.
    1269 ; Sets rc = 0 on success; 1 when no app is waiting.
    1270 defproc ShellEnterWriteToApp
    1271    rcx = 1
    1272    ShellNum = GetFileAVar( 'shellnum')
    1273    ShellAppWaiting = GetFileAVar( 'shellappwaiting')
    1274    if words( ShellAppWaiting) = 2 then
    1275       parse value ShellAppWaiting with lastl lastc
    1276       Input = ''
    1277       l = lastl
    1278       do while l <= .line
    1279          getline line, l
    1280          if l = lastl then
    1281             startc = lastc
    1282          else
    1283             startc = 1
    1284          endif
    1285          Input = Input''substr( line, startc)
    1286          if l = .last then
    1287             insertline '', .last + 1
    1288             leave
    1289          else
    1290             l = l + 1
    1291          endif
    1292       enddo
    1293       'ShellWrite' ShellNum Input
    1294       rcx = 0
    1295    endif
    1296    rc = rcx
     1691            getline LastLineStr, .last
     1692            LastLen = length( LastLineStr)
     1693            NextLen = length( NextLineStr)
     1694            if LastLen + NextLen <= MAXCOL then
     1695               -- Append NextLineStr to LastLineStr
     1696               -- Instead of replaceline, keyin preserves bookmarks
     1697               -- in LastLineStr.
     1698dprintf( 'ShellProcessReadLineBuff: Appending: 'NextLineStr)
     1699dprintf( 'ShellProcessReadLineBuff:        to: 'LastLineStr)
     1700               .line = .last
     1701               .col  = LastLen + 1
     1702               keyin NextLineStr
     1703               TextStr = LastLineStr''NextLineStr
     1704            else
     1705               -- Insert TextStr
     1706               TextStr = NextLineStr
     1707               insertline TextStr, .last + 1
     1708            endif
     1709         endif
     1710dprintf( 'TextStr = 'TextStr', ShellGetLastCmd() = 'ShellGetLastCmd())
     1711
     1712         -- For a 'Directory of' line, add bookmark
     1713         -- for later restore after editing
     1714         if IsADirectoryOfLine( TextStr) then
     1715            -- Set bookmark
     1716            bmline = .last
     1717            bmcol = 1
     1718            bmval = TextStr
     1719            SetBookmark( 3, bmline, bmcol, bmval)
     1720dprintf( '#  Bookmark set on line 'bmline' to >'bmval'<')
     1721         endif
     1722
     1723      endif  -- fIgnoreCurrentCmd else
     1724
     1725      if RestLineStr == '' then
     1726         -- Get next ReadBuf from output stream
     1727         leave
     1728      endif
     1729
     1730   enddo  -- forever (until RestLineStr == '')
    12971731
    12981732   return
     
    13191753
    13201754   -- Confirm on a prompt line
    1321    if ShellPromptPos() then
     1755   call ShellParsePromptLine( .line, CurPrompt,  CurCmd)
     1756   if CurPrompt then
    13221757      refresh
    13231758      if MBID_OK <> WinMessageBox( 'Sending a Break signal not required',  -- title
     
    13791814         call SetAVar( 'shell_h'ShellNum, ShellHandle)
    13801815         InitCmd = ''
    1381 compile if EPM_SHELL_PROMPT <> ''
    1382          InitCmd = EPM_SHELL_PROMPT
    1383 compile endif
    1384          if InitCmd <> '' then
    1385             'ShellWrite' ShellNum InitCmd
    1386          endif
     1816         ShellValue = ShellGetPromptValue()
     1817         InitCmd = '@prompt 'ShellValue
     1818         'ShellWriteCmdQuiet' ShellNum InitCmd
    13871819
    13881820         -- Determine previous work dir
    1389          call pSave_Pos( save_pos)
    1390          SavedRc = rc
    13911821         display -3
    13921822         .lineg = .last
    13931823         endline
    1394          call ShellGotoNextPrompt( 'P')
    1395          if rc then
    1396             fFound = 0
    1397          else
    1398             fFound = 1
    1399          endif
    1400          Dir = ''
    1401          Cmd = ''
    1402          if fFound then
    1403             call ShellParsePromptLine( Dir, Cmd)
    1404          else
    1405             call pRestore_Pos( save_pos)
    1406          endif
    1407          rc = SavedRc
     1824         Dir = ShellGetPrevDir()
    14081825         display 3
     1826
    14091827         if Dir <> '' then
    14101828            CdCmd = 'cdd' Dir
    1411             'ShellWrite' ShellNum CdCmd
     1829            'ShellWriteCmdQuiet' ShellNum CdCmd
    14121830         endif
    14131831      endif
     
    14201838
    14211839; ---------------------------------------------------------------------------
    1422 defc ShellNewLine
     1840; Enhanced for filename completion. Prepends 'cd ' to input if a directory.
     1841; Removes trailing \ from directories for 'cd'.
     1842; Works with spaces in filenames and surrounding "...".
     1843; ECHO must be ON. That is the default setting in CMD.EXE, but not in
     1844; 4OS2.EXE. Otherwise no prompt is inserted after the command execution and
     1845; further commands won't work (CMD.EXE) or the command is deleted (4OS2.EXE).
     1846; Therefore ECHO ON must be executed _after_ every call of 4OS2.EXE.
     1847defproc ShellFilterCmd( Input)
     1848
     1849   -- Process alias in Input
     1850   KeyPath = '\NEPMD\User\Shell\Alias'
     1851   on = (QueryConfigKey( KeyPath) <> 0)
     1852   if on then
     1853      Input = ShellAliasResolve( Input)
     1854   endif
     1855
     1856   -- Parse Input into CmdWord, CmdArgs and CmdName
     1857   fCmdWordEnquoted = 0
     1858   if leftstr( Input, 1) = '"' then
     1859      fCmdWordEnquoted = 1
     1860      parse value Input with '"'CmdWord'"' CmdArgs
     1861   else
     1862      parse value Input with CmdWord CmdArgs
     1863   endif
     1864   CmdName = upcase( StripExt( StripPath( CmdWord)))
     1865
     1866   -- Handle the silly M$ syntax extension for CD like "cd\", "cd.." etc.
     1867   -- Not required for CMD.EXE, just for to determine CmdName.
     1868   if wordpos( leftstr( upcase( CmdWord), 3), 'CD\ CD.') then
     1869      CmdArgs = substr( CmdWord, 3)
     1870      CmdWord = 'cd'
     1871      CmdName = 'CD'
     1872   endif
     1873
     1874   -- Prepend "cd" if no CmdName given (true for a trailing '\')
     1875   if CmdName = '' & CmdWord <> '' & CmdArgs = '' then
     1876      CmdArgs = CmdWord
     1877      CmdWord = 'cd'
     1878      CmdName = 'CD'
     1879      fCmdWordEnquoted = 0
     1880
     1881      -- Strip trailing \ from CmdArgs
     1882      if rightstr( CmdArgs, 1) = '\' &
     1883         CmdArgs <> '\' &
     1884         rightstr( CmdArgs, 2) <> ':\' then
     1885         CmdArgs = strip( CmdArgs, 'T', '\')
     1886      endif
     1887      CmdArgs = EnquoteFileSpec( CmdArgs)
     1888   endif
     1889
     1890   if CmdName = '4OS2' then
     1891      -- Insert "echo on" when 4os2 is called
     1892      if CmdArgs = '' then
     1893         CmdArgs = 'echo on'
     1894      else
     1895         CmdArgs = 'echo on&'CmdArgs
     1896      endif
     1897   endif
     1898
     1899   -- Reconcatenate Input args
     1900   if fCmdWordEnquoted = 0 then
     1901      Input = CmdWord
     1902   else
     1903      Input = '"'CmdWord'"'
     1904   endif
     1905   if CmdArgs <> '' then
     1906      Input = Input CmdArgs
     1907   endif
     1908
     1909   return Input
     1910
     1911; ---------------------------------------------------------------------------
     1912defc ShellEnterLine
     1913   NormalCmd = strip( arg( 1))
     1914   fExecNormalCmd = 1
     1915   SavedRc = rc
     1916
    14231917   do once = 1 to 1
    1424       StdNewLine = arg( 1)
    1425       SavedRc = rc
    1426 
     1918
     1919--dprintf( 'ShellEnterLine: IsADirList() = 'IsADirList())
     1920      ---- Dir list ----
    14271921      if IsADirList() then
    1428          call DirProcessDirectoryOfLine()
     1922         call DirProcessDirectoryOfLine2()
    14291923         if not rc then
     1924            -- Processed
     1925            fExecNormalCmd = 0
    14301926            leave
    14311927         endif
    14321928      endif
    14331929
    1434       if IsAShell() then
    1435          call ShellEnterWrite()
    1436          --dprintf( 'ShellNewLine: ShellEnterWrite: rc = 'rc)
    1437          if not rc then
     1930      if not IsAShell() then
     1931         leave
     1932      endif
     1933
     1934      ---- Shell ----
     1935      -- Determine prompt and cmd at last line and current line
     1936      CurPrompt = ''
     1937      CurCmd    = ''
     1938      PromptVal = ShellGetPromptValue()
     1939      SearchStr = ShellPromptToSearchStr( PromptVal)
     1940      call ShellParsePromptLine( .last, LastPrompt, LastCmd)
     1941      call ShellParsePromptLine( .line, CurPrompt,  CurCmd)
     1942
     1943      -- Determine fWriteToApp
     1944      if CurPrompt = '' then
     1945         fWriteToApp = 1
     1946      else
     1947         fWriteToApp = 0
     1948      endif
     1949
     1950      -- Determine Input from current line
     1951      if fWriteToApp then
     1952dprintf( 'ShellEnterLine: App is waiting for user input')
     1953         parse value GetFileAVar( 'shelloutputpos') with lastl lastc
     1954         if lastc = '' then
    14381955            leave
    14391956         endif
    1440 
    1441          call ShellEnterWriteToApp()
    1442          --dprintf( 'ShellNewLine: ShellEnterWriteToApp: rc = 'rc)
    1443          if not rc then
    1444             leave
    1445          endif
    1446       endif
    1447 
    1448       StdNewLine
     1957         Input = ''
     1958         l = lastl
     1959         do while l <= .line
     1960            getline line, l
     1961            if l = lastl then
     1962               startc = lastc
     1963            else
     1964               startc = 1
     1965            endif
     1966            Input = Input''substr( line, startc)
     1967            if l = .last then
     1968               insertline '', .last + 1
     1969               leave
     1970            else
     1971               l = l + 1
     1972            endif
     1973         enddo
     1974      else
     1975--dprintf( 'ShellEnterLine: CurCmd before ShellFilterCmd = 'CurCmd)
     1976         CurCmd = ShellFilterCmd( CurCmd)
     1977--dprintf( 'ShellEnterLine: CurCmd after  ShellFilterCmd = 'CurCmd)
     1978         Input = CurCmd
     1979      endif
     1980
     1981      if Input == '' then
     1982         -- Ask for Input
     1983         if fWriteToApp then
     1984            -- If Input empty, open EntryBox 9) ################################
     1985            'ShellWrite' Input
     1986         else
     1987            'ShellHistory'
     1988         endif
     1989      else
     1990/*
     1991         NextCmdAltersText()
     1992*/
     1993         -- Write Input to shell
     1994         if fWriteToApp then
     1995            'ShellWrite' Input
     1996         else
     1997            'ShellWriteCmd 'Input
     1998         endif
     1999      endif
     2000
     2001      -- Processed
     2002      fExecNormalCmd = 0
    14492003   enddo
     2004
    14502005   rc = SavedRc
    1451 
    1452 ; ---------------------------------------------------------------------------
    1453 defc ShellTab
     2006   if fExecNormalCmd then
     2007      ---- Normal NewLine (specified as arg) ----
     2008      NormalCmd
     2009   endif
     2010
     2011; ---------------------------------------------------------------------------
     2012defc ShellFnc
    14542013   universal prevkey
     2014
     2015   NormalCmd = strip( arg( 1))
     2016   fExecNormalCmd = 1
     2017
    14552018   parse value prevkey with PrevKeyName \1 .
    14562019   KeyPath = '\NEPMD\User\Shell\FilenameCompletion'
     
    14612024      endif
    14622025      'ShellFncProcess'
    1463    else
    1464       'Tab'      -- standard definition, keep in sync with STDKEYS.E or
    1465    endif         -- additional keyset definitions
    1466 
    1467 ; ---------------------------------------------------------------------------
    1468 defc ShellBackTab
     2026      fExecNormalCmd = 0
     2027   endif
     2028
     2029   if fExecNormalCmd then
     2030      NormalCmd
     2031   endif
     2032
     2033; ---------------------------------------------------------------------------
     2034defc ShellFncBack
    14692035   universal prevkey
     2036
     2037   NormalCmd = strip( arg( 1))
     2038   fExecNormalCmd = 1
     2039
    14702040   parse value prevkey with PrevKeyName \1 .
    14712041   KeyPath = '\NEPMD\User\Shell\FilenameCompletion'
     
    14762046      endif
    14772047      'ShellFncProcess -'
    1478    else
    1479       'BackTab'  -- standard definition, keep in sync with STDKEYS.E or
    1480    endif         -- additional keyset definitions
     2048      fExecNormalCmd = 0
     2049   endif
     2050
     2051   if fExecNormalCmd then
     2052      NormalCmd
     2053   endif
     2054
     2055; ---------------------------------------------------------------------------
     2056defc ShellDeleteCmd
     2057   NormalCmd = strip( arg( 1))
     2058   fExecNormalCmd = 1
     2059
     2060   do once = 1 to 1
     2061      if not IsAShell() then
     2062         leave
     2063      endif
     2064      call ShellParsePromptLine( .line, CurPrompt, CurCmd)
     2065      if not CurPrompt then
     2066         leave
     2067      endif
     2068      -- Process only if cursor is at the end or after
     2069      if .col < length( CurPrompt''CurCmd) + 1 then
     2070         leave
     2071      endif
     2072      -- Delete CurCmd
     2073      .col = length( CurPrompt) + 1
     2074      eraseendline
     2075      fExecNormalCmd = 0
     2076   enddo
     2077
     2078   if fExecNormalCmd then
     2079      NormalCmd
     2080   endif
     2081
     2082; ===========================================================================
     2083; History
     2084; ===========================================================================
     2085
     2086; ---------------------------------------------------------------------------
     2087; Opens a list box with last commands. The selected one can be submitted and
     2088; optionally be edited in an entry box before. This was previously a part of
     2089; ShellWrite, except that the order of both boxes was changed. It starts
     2090; with the list box, not with the entry box. Main idea by Joerg Tiemann.
     2091defc ShellHistory, Shell_History
     2092   do once = 1 to 1
     2093      parse arg ShellNum .
     2094      if ShellNum = '' & IsAShell() then
     2095         ShellNum = GetFileAVar( 'shellnum')
     2096      endif
     2097      if ShellNum = '' then
     2098         'SayError 'NOT_IN_SHELL__MSG
     2099         return
     2100      endif
     2101      NewCmd = ''
     2102
     2103      ShellHandle = GetAVar( 'shell_h'ShellNum)
     2104      if ShellHandle = '' then
     2105         leave
     2106      endif
     2107
     2108      BoxTitle = strip( WRITE_SHELL_MENU__MSG, 'T', '.')  -- '~Write to shell...'
     2109      pTilde = pos( '~', BoxTitle)
     2110      if pTilde then
     2111         BoxTitle = delstr( BoxTitle, pTilde, 1)
     2112      endif
     2113
     2114      -- Get NewCmd
     2115      do forever
     2116
     2117         -- Open ListBox
     2118         getfileid ShellFid
     2119         call pSave_Pos( SavedPos)
     2120
     2121         'xcom e /c cmdslist'
     2122         if rc <> -282 then  -- -282 = sayerror( "New file")
     2123            'SayError 'ERROR__MSG rc BAD_TMP_FILE__MSG sayerrortext( rc)
     2124            return
     2125         endif
     2126         .autosave = 0
     2127         getfileid lb_fid
     2128
     2129         activatefile ShellFid
     2130         0
     2131         do forever
     2132            PrevPos = .line .col
     2133            call ShellGoToNextPrompt()
     2134            if rc then
     2135               leave
     2136            elseif .line .col = PrevPos then
     2137               leave
     2138            endif
     2139            call ShellParsePromptLine( .line, CurPrompt, CurCmd)
     2140            if CurCmd = '' then
     2141               iterate
     2142            endif
     2143            insertline strip( CurCmd, 'L'), lb_fid.last + 1, lb_fid
     2144         enddo
     2145
     2146         call pRestore_Pos( SavedPos)
     2147
     2148         activatefile lb_fid
     2149         if not .modify then  -- Nothing added?
     2150            -- ListBox needs at least one empty entry
     2151            insertline '', lb_fid.last + 1, lb_fid  -- empty line
     2152         endif
     2153
     2154         if ListBox_Buffer_From_File( ShellFid, bufhndl, noflines, usedsize) then
     2155            return
     2156         endif
     2157         Text = ''
     2158         ListBoxButtons = '/'OK__MSG'/'EDIT__MSG'.../'Cancel__MSG
     2159         DefaultItem = noflines - 1  -- Last item, first line of lb_fid is empty
     2160         DefaultButton = 1
     2161         HelpId = 0
     2162         parse value ListBox( BoxTitle,
     2163                              \0 || atol( usedsize) || atoi( 32) || atoi( bufhndl),
     2164                              ListBoxButtons,
     2165                               0, 0,  -- top, left
     2166                              12, 0,  -- height, width,
     2167                              GethWndC( APP_HANDLE) ||
     2168                              atoi( DefaultItem)    ||
     2169                              atoi( DefaultButton)  ||
     2170                              atoi( HelpId) ||
     2171                              Text\0) with LbButton 2 NewCmd \0
     2172         call buffer( FREEBUF, bufhndl)
     2173
     2174         if LbButton = \1 then      -- OK
     2175            leave
     2176         elseif LbButton = \2 then  -- Edit...
     2177
     2178            -- Open EntryBox
     2179            -- Use same BoxTitle as ListBox
     2180            -- Use selected entry from ListBox
     2181            EntryText = NewCmd
     2182            Text = SHELL_PROMPT__MSG ShellNum
     2183            Text = Text''copies( ' ', Max( 0, 100 - length( Text)))
     2184            EntryBoxButtons = '/'OK__MSG'/'LIST__MSG'/'Cancel__MSG'/'
     2185            DefaultButton = 1
     2186            --HelpId = 0
     2187            parse value EntryBox( BoxTitle,
     2188                                  EntryBoxButtons,
     2189                                  EntryText,
     2190                                  0, 254,          -- cols, maxchars
     2191                                  atoi( DefaultButton)  ||
     2192                                  atoi( HelpId)         ||
     2193                                  GethWndC( APP_HANDLE) ||
     2194                                  Text) with EbButton 2 NewCmd \0
     2195            if EbButton = \1 then        -- OK
     2196               leave
     2197            elseif EbButton = \2 then    -- List...
     2198               iterate
     2199            else                         -- Cancel
     2200               return
     2201            endif
     2202
     2203         else                       -- Cancel
     2204            return
     2205         endif
     2206
     2207      enddo  -- forever -- Get NewCmd
     2208
     2209      -- Write NewCmd
     2210      'ShellWriteCmd 'NewCmd
     2211   enddo
    14812212
    14822213; ===========================================================================
     
    15062237      return
    15072238   endif
    1508    p = ShellPromptPos()
    1509    if not p then
    1510       return
    1511    endif
    1512    getline Line
    1513    Prompt = leftstr( Line, p)
    1514    PromptChar = substr( Prompt, p, 1)
    1515    parse value Prompt with 'epm:' ShellDir (PromptChar)
    1516    ShellDir = strip( ShellDir)
    1517 
    1518    -- Get the part of the line between prompt and cursor
    1519    Input = substr( Line, p + 1, .col - 1 - p)
    1520    -- Strip leading spaces only, because a trailing space identifies the word before
    1521    -- to have ended:
    1522    --    > dir |   ->   dir *
    1523    --    > dir|    ->   dir*   (this will search for names starting with dir)
    1524    Input = strip( Input, 'L')
     2239
     2240   call ShellParsePromptLine( .line, CurPrompt, CurCmd)
     2241   Input = CurCmd
     2242   ShellDir = ShellGetPrevDir()
    15252243
    15262244   -- Todo:
     
    17082426   endif
    17092427   call SetAVar( 'fncshellnum', ShellNum)
    1710    call SetAVar( 'fncprompt', Prompt)
    1711    call SetAVar( 'fnccmdpart', CmdPart)
     2428   call SetAVar( 'fncprompt',   CurPrompt)
     2429   call SetAVar( 'fnccmdpart',  CmdPart)
    17122430
    17132431; ---------------------------------------------------------------------------
     
    17632481; Make -dName possible
    17642482      if CmdPart <> '' then
    1765          NewLine = Prompt strip( CmdPart) Name
     2483         NewLine = Prompt''strip( CmdPart) Name
    17662484      else
    1767          NewLine = Prompt Name
     2485         NewLine = Prompt''Name
    17682486      endif
    17692487      replaceline NewLine
     
    17812499compile endif
    17822500compile if not defined( ALIAS_SEP_CHARS)
    1783    ALIAS_SEP_CHARS = ' |<>'
     2501   ALIAS_SEP_CHARS = ' |<>&'
    17842502compile endif
    17852503
     
    18142532         if abbrev( UpRest, UpKey) = 1 then
    18152533            -- Get surrounding chars to check for separators
     2534-- ################################################################################
    18162535            PrevChar = rightstr( ResolvedString, 1)
    18172536            NextChar = substr( Rest, length( Key) + 1, 1)
     
    18372556         pDelta = length( Key)
    18382557      else
     2558-- ################################################################################
    18392559         -- Not found, advance search pos by 1
    18402560         pDelta = 1
     
    18422562      endif
    18432563
     2564-- ################################################################################
    18442565      ResolvedString = ResolvedString''Val
    18452566      Rest = substr( Rest, pDelta + 1)
     
    19852706   call ShellAliasFileRead()
    19862707
    1987 ; ===========================================================================
    1988 ; Remaining cmds from ShellKram
    1989 ; ===========================================================================
    1990 
    1991 ; ---------------------------------------------------------------------------
    1992 ; Following definitions are mainly copied from Joerg Tiemann's SHELLKRAM.E
    1993 ; package:
    1994 
    1995 /********************************************************************************/
    1996 /* Shell_Input                                                                  */
    1997 /* This is a cut off ShellWrite.  Initially the idea was to use it to be able   */
    1998 /* to use 4OS2 as the command line interpreter.  But that did not work.  In the */
    1999 /* meantime I've come to the conclusion that it is a nice command for use in    */
    2000 /* the toolbar "* Shell_Input somecommand parameters".                          */
    2001 /********************************************************************************/
    2002 
    2003 defc ShellInput, Shell_Input
    2004    universal shelllastwrite
    2005 
    2006    parse arg Input
    2007    ShellNum = ''
    2008    if IsAShell() then
    2009       ShellNum = GetFileAVar( 'shellnum')
    2010    endif
    2011    if ShellNum = '' then
    2012       'SayError 'NOT_IN_SHELL__MSG
    2013       return
    2014    endif
    2015 
    2016    ShellHandle = GetAVar( 'shell_h'ShellNum)
    2017 
    2018    if ShellHandle <> '' then
    2019       if Input <> '' then
    2020          -- Set universal
    2021          shelllastwrite = Input
    2022       endif
    2023       writebuf = Input\13\10  -- input text + CRLF
    2024       retval   = Sue_Write( ShellHandle, writebuf, bytesmoved)
    2025       if retval | (bytesmoved <> length( writebuf)) then
    2026          'SayError Shell_Input: write.retval = 'retval', byteswritten = 'bytesmoved' of 'length( writebuf)
    2027       endif
    2028    endif
    2029 
    2030 /******************************************************************/
    2031 /* Shell_SendKey                                                  */
    2032 /* Now yet another variation. This time to send single keystrokes */
    2033 /* to the command line interpreter, for example the often needed  */
    2034 /* 'y' and 'n'.                                                   */
    2035 /******************************************************************/
    2036 
    2037 defc ShellSendKey, Shell_SendKey
    2038    parse arg Input
    2039    ShellNum = ''
    2040    if IsAShell() then
    2041       ShellNum = GetFileAVar( 'shellnum')
    2042    endif
    2043    if ShellNum = '' then
    2044       'SayError 'NOT_IN_SHELL__MSG
    2045       return
    2046    endif
    2047    if Input = '' then
    2048       'SayError Shell_SendKey: no key to send to shell specified'
    2049       return
    2050    endif
    2051 
    2052    ShellHandle = GetAVar( 'shell_h'ShellNum)
    2053 
    2054    if ShellHandle <> '' then
    2055       writebuf = Input  -- just the pure input w/o CRLF
    2056       retval   = Sue_Write( ShellHandle, writebuf, bytesmoved)
    2057       if retval | (bytesmoved <> length( writebuf)) then
    2058          'SayError Shell_SendKey: write.retval = 'retval', byteswritten = 'bytesmoved 'of' length( writebuf)
    2059       endif
    2060    endif
    2061 
    2062 /*
    2063 defc esk_About
    2064    rcx = WinMessageBox( 'About EPM Shellkram',
    2065                         'EPM Shellkram v.0.88 beta'\10 ||
    2066                         'Wed, 3 Oct 2001'\10 ||
    2067                         'Copyright (c) 1998-2001 by Joerg Tiemann'\10 ||
    2068                         'Joerg Tiemann <tiemannj@gmx.de>', 16432)
    2069 */
     2708
Note: See TracChangeset for help on using the changeset viewer.