home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / cmdpk164.zip / cmdshl.cmd < prev    next >
OS/2 REXX Batch file  |  1997-12-22  |  51KB  |  1,488 lines

  1. /* cmdshl.cmd - an improved cmd shell                          971222 */
  2. /* (c) martin lafaix 1994 - 1997                                      */
  3.  
  4. /* user dependant values */
  5. insertState = 1
  6. cmdQueue = 1
  7. impCD = 1
  8. nl = '0d0a'x
  9. defHelp = 'Use the DEFINE command to (re)define keyboard keys'nl||nl||,
  10.           'SYNTAX:    DEF key [value]'nl||,
  11.           '        DEFINE key [value]'nl||nl||,
  12.           '         key    The name of the key to be redefined.'nl||,
  13.           '         value  The new key value. It can be an internal command,'nl||,
  14.           '                OSNowait xxx or TEXT yyy.'nl||nl||,
  15.           'Examples:'nl||,
  16.           '         DEF F12 TEXT dir /w'nl||,
  17.           '      DEFINE F3  OSNOWAIT exit'nl||,
  18.           '         DEF F12'
  19. aliasHelp = 'Use the ALIAS command to view, add or remove an alias'nl||nl||,
  20.             'SYNTAX: ALIAS [LIST|alias=[string]|@file]'nl||nl||,
  21.             '         LIST    View all currently defined aliases.'nl||,
  22.             '         alias   An alias name (case sensitive).'nl||,
  23.             '         string  The new value for alias.'nl||,
  24.             '         file    A file containing one (or more) alias definitions.'nl||nl||,
  25.             'In an alias definition, %n[*] denotes command line parameters.'
  26. ruleHelp = 'Use the RULE command to view, add or remove a rule'nl||nl||,
  27.            'SYNTAX: RULE [LIST|rule=[string]|@file]'nl||nl||,
  28.            '         LIST    View all currently defined rules.'nl||,
  29.            '         rule    A rule name (case sensitive for aliases).'nl||,
  30.            '         string  The new value for rule.'nl||,
  31.            '         file    A file containing one (or more) rule definitions.'nl||nl||,
  32.            'In a rule definition, %*, %c, %d, %e, %f, %l, %o and %x denotes'nl||,
  33.            'parameters types.'
  34. cmdHelp = 'Use the CMDSHL command to enhance your command shell.'nl||nl||,
  35.           'SYNTAX: CMDSHL [/I|/O] [/P profile] [/C cmd|/K cmd]'nl||nl||,
  36.           '         /I    Insert mode is the default.'nl||,
  37.           '         /O    Overstrike mode is the default.'nl||,
  38.           '         /P    Use the specified profile file.'nl||,
  39.           '         /C    Execute cmd and exit CMDSHL.'nl||,
  40.           '         /K    Execute cmd without exiting CMDSHL.'nl||nl||,
  41.           'By default, Insert mode is on and PROFILE.SHL is used as profile'nl||,
  42.           'file if it exists along the path specified by the DPATH environment'nl||,
  43.           'variable.'
  44. cdHelp = 'Enter CD -     To go back to the previous current directory'nl||,
  45.          'Enter CD s1 s2 To substitute s1 by s2 in current directory'
  46. quitHelp = 'Use the QUIT command to leave CMDSHL.'nl||nl||,
  47.            'SYNTAX: QUIT'
  48. /* nothing to translate beyond this point */
  49.  
  50. /*====================================================================
  51.  * The Main Loop.
  52.  *====================================================================*/
  53. '@echo off'; trace off
  54.  
  55. call init
  56.  
  57. if arg() then
  58.    call doarg arg(1)
  59.  
  60. call profile
  61.  
  62. loop:
  63. do forever
  64.    call charout ,print()
  65.  
  66.    if (eval(getline()) = 0) then
  67.       leave
  68. end /* do */
  69.  
  70. call terminate
  71.  
  72. exit
  73.  
  74. /*====================================================================
  75.  * A cmd.exe-like Command Prompt.
  76.  *====================================================================*/
  77. print:
  78.    prompt = value('CMDSHL.PROMPT.'address(),,'OS2ENVIRONMENT')
  79.    if (prompt == '') then
  80.      prompt = value('CMDSHL.PROMPT',,'OS2ENVIRONMENT')
  81.    if (prompt == '') then
  82.       prompt = value('PROMPT',,'OS2ENVIRONMENT')
  83.    if (prompt == '') then
  84.       prompt = '[$p]'
  85.  
  86.    str = ''
  87.  
  88.    do i = 1 to length(prompt)
  89.       key = substr(prompt,i,1)
  90.       if (key = '$') then
  91.          do
  92.          i = i+1; key = translate(substr(prompt,i,1))
  93.          select
  94.             when key = '$' then str = str||'$'
  95.             when key = 'A' then str = str||'&'
  96.             when key = 'B' then str = str||'|'
  97.             when key = 'C' then str = str||'('
  98.             when key = 'D' then str = str||date()
  99.             when key = 'E' then str = str||'1b'x
  100.             when key = 'F' then str = str||')'
  101.             when key = 'G' then str = str||'>'
  102.             when key = 'H' then str = str||'08'x
  103.             when key = 'I' then str = str||'1b'x'[s'||'1b'x'[0;0H'helpColor1||helpstring'1b'x'[K'helpColor2'1b'x'[u'
  104.             when key = 'L' then str = str||'<'
  105.             when key = 'N' then str = str||filespec("d",directory())
  106.             when key = 'P' then str = str||directory()
  107.             when key = 'Q' then str = str||'='
  108.             when key = 'R' then str = str||rc
  109.             when key = 'S' then str = str||' '
  110.             when key = 'T' then str = str||time()
  111.             when key = 'V' then str = str||verString
  112.             when key = '_' then str = str||'0d0a'x
  113.          otherwise
  114.          end  /* select */
  115.          end
  116.       else
  117.          str = str||key
  118.    end /* do */
  119.    return str
  120.  
  121. /*====================================================================
  122.  * A cmd.exe-like Command Shell, w/ Filename Completion.
  123.  *====================================================================*/
  124. init:
  125.    if RxFuncQuery("SysLoadFuncs") then
  126.       do
  127.       call RxFuncAdd 'SysLoadFuncs','RexxUtil','SysLoadFuncs'
  128.       call SysLoadFuncs
  129.       end
  130.  
  131.    if RxFuncQuery("VioLoadFuncs") then
  132.       do
  133.       call RxFuncAdd 'VioLoadFuncs','RexxVIO','VioLoadFuncs'
  134.       call VioLoadFuncs
  135.       end
  136.  
  137.    oldCur = VioGetCurType()
  138.  
  139.    insertMode.1 = '-80 -90'
  140.    insertMode.0 = '0 -100'
  141.  
  142.    fileSeparator = ' =;<>|(&'
  143.  
  144.    prevLine.0 = 0
  145.  
  146.    helpSwitches = value('HELP.SWITCHES',,'OS2ENVIRONMENT')
  147.    if helpSwitches = '' then
  148.       helpSwitches = '/?'
  149.  
  150.    cmdList = 'CALL CD CHCP CHDIR CLS COPY DATE DETACH DIR DPATH ECHO',
  151.              'ERASE DEL EXIT FOR IF KEYS MD MKDIR MOVE PATH PAUSE PROMPT',
  152.              'REM REN RENAME RD RMDIR SET START TIME TYPE VER VERIFY VOL'
  153.  
  154.    shlList = 'ALIAS CD DEF DEFI DEFIN DEFINE KEYS QUIT RX RULE'
  155.  
  156.    extList = 'exe cmd bat com'
  157.  
  158.    rulesList = 'START DETACH CD SET FOR RD RMDIR'
  159.  
  160.    /*
  161.     * %c = command      %d = directory    %e = env. var.    %f = file
  162.     * %l = letter       %o = option       %x = expression   %* = anything
  163.     */
  164.    rules.START = '"%*" %o %x^|"%*" %o^|%o %x^|%o'
  165.    rules.DETACH = '%x'
  166.    rules.CD = '%d^|%f %f^|/?^|'
  167.    rules.CHDIR = '%d^|/?^|'
  168.    rules.SET = '%e=%*^|/?^|'
  169.    rules.FOR = '%%%l IN (%*) DO %x'
  170.    rules.RD = '%d %d*^|/?'
  171.    rules.RMDIR = '%d %d*^|/?'
  172.  
  173.    invalidCmd = "call VioWrtNAttr origRow + xlen % col, xlen // col, length(xline), 12;",
  174.                 "xOfs = currOfs+1"
  175.  
  176.    helpColor1 = '1b'x'[34;47m'
  177.    helpColor2 = '1b'x'[0m'
  178.  
  179.    _LEVEL_ = 0
  180.  
  181.    A_C = '002e'x;                   key._002e = 'mark copy'
  182.    A_D = '0020'x;                   key._0020 = 'mark delete'
  183.    C_E = '05'x;                     key._05   = 'ctrlend'
  184.    C_K = '0B'x;                     key._0B   = 'dup'
  185.    A_M = '0032'x;                   key._0032 = 'mark move'
  186.    A_U = '0016'x;                   key._0016 = 'mark clear'
  187.    A_W = '0011'x;                   key._0011 = 'mark word'
  188.    C_X = '18'x;                     key._18   = 'expand'
  189.    A_Z = '002c'x;                   key._002c = 'mark char'
  190.    A_F10 = '0071'x
  191.    BKSP = '08'x;                    key._08   = 'backsp'
  192.    CURD = '0050'x;                  key._0050 = 'cdown'
  193.    CURL = '004b'x;                  key._004B = 'cleft'
  194.    CURR = '004d'x;                  key._004D = 'cright'
  195.    CURU = '0048'x;                  key._0048 = 'cup'
  196.    C_CURL = '0073'x;                key._0073 = "ctrlleft"
  197.    C_CURR = '0074'x;                key._0074 = "ctrlright"
  198.    C_END = '0075'x;                 key._0075 = "ctrlend"
  199.    C_HOME = '0077'x;                key._0077 = "ctrlhome"
  200.    C_PGDN = '0076'x
  201.    C_PGUP = '0084'x
  202.    DEL = '0053'x;                   key._0053 = 'del'
  203.    END = '004F'x;                   key._004F = 'end'
  204.    ENTER = '0d'x;                   key._0D   = 'enter'
  205.    ESC = '1b'x;                     key._1B   = 'esc'
  206.    F1 = '003b'x;                    key._003B = 'match'
  207.    F2 = '003c'x
  208.    F3 = '003d'x
  209.    F4 = '003e'x
  210.    F5 = '003f'x
  211.    F6 = '0040'x
  212.    F7 = '0041'x
  213.    F8 = '0042'x
  214.    F9 = '0043'x
  215.    F10 = '0044'x
  216.    F11 = '0085'x
  217.    F12 = '0086'x
  218.    HOME = '0047'x;                  key._0047 = 'home'
  219.    INS = '0052'x;                   key._0052 = 'ins'
  220.    PGDN = '0051'x
  221.    PGUP = '0049'x
  222.    S_TAB = '000F'x;                 key._000F = 'backtab'
  223.    TAB = '09'x;                     key._09   = 'tab'
  224.    SPACE = '20'x;                   key._20   = 'space'
  225.  
  226.    aliasNames = ''
  227.    profileName = 'profile.shl'
  228.  
  229.    oldDir = directory()
  230.    secondaryPrompt = SysGetMessage(1093)
  231.    parse value SysGetMessage(1492) with helpString '0d0a'x
  232.  
  233.    parse value SysOS2Ver() with osmajor "." osminor
  234.    if osmajor = '2' & osminor = '30' then /* Warp kludge :-) */
  235.       parse value '3.00' with osmajor "." osminor
  236.    else
  237.    if osmajor = '2' & osminor = '40' then /* Merlin kludge :-) */
  238.       parse value '4.00' with osmajor "." osminor
  239.    verString = SysGetMessage(1090,,osmajor,osminor)
  240.  
  241.    interactive = 0
  242.  
  243.    global = 'helpString profileName profileFile verString aliasNames oldDir RC',
  244.             'cmdList impCD shlList invalidCmd interactive helpColor1 helpColor2',
  245.             'insertMode. fileSeparator aliasStem. _LEVEL_ extList rulesList',
  246.             'rules. helpSwitches'
  247.    return
  248.  
  249. terminate:
  250.    call VioSetCurType word(oldCur,1),word(oldCur,2),word(oldCur,3),word(oldCur,4)
  251.    return
  252.  
  253. profile:
  254.    signal on syntax name profilesyntax
  255.    interactive = 0; profileline = 0
  256.    profileFile = SysSearchPath('DPATH',profileName)
  257.    if profileFile \= '' then do
  258.       do while lines(profileFile) > 0
  259.          line = linein(profileFile); profileline = profileline+1
  260.          do while lines(profileFile) > 0 & right(line,1) = ','
  261.             line = left(line,length(line)-1) linein(profileFile)
  262.          end /* do */
  263.          if left(line,1) = "'" | left(line,1) = '"' then
  264.             interpret 'call eval' line
  265.          else
  266.             interpret line
  267.       end /* do */
  268.       call stream profileFile, 'c', 'close'
  269.       end
  270.    interactive = 1
  271.    signal off syntax
  272.    return
  273.  
  274. profilesyntax:
  275.    call charout ,'REX'right(rc,4,'0')': Error' rc 'running' profileFile', line' profileline':' errortext(rc)nl
  276.    call stream profileFile, 'c', 'close'
  277.    rc = -rc
  278.    signal loop
  279.  
  280. getline:
  281.    procedure expose prevLine. key. insertState cmdQueue secondaryPrompt (global)
  282.  
  283.    parse value SysCurPos() with origRow origCol .
  284.    parse value SysTextScreenSize() with row col
  285.  
  286.    parse value origRow origCol '1 0 0 0 0 0' insertState,
  287.          with currRow currCol firstCup currOfs currTab len olen xOfs insert key line
  288.  
  289.    parse value 0 0 with markLen markOfs
  290.  
  291.    call VioSetCurType word(insertMode.insert,1), word(insertMode.insert,2)
  292.  
  293.    if arg(1) \= '' then
  294.       do
  295.       line = arg(1)
  296.       len = length(line)
  297.       call charout , left(line,max(len,olen))
  298.       if origRow + (origCol + len) % col >= row then
  299.          origRow = row - (origCol + len) % col - 1
  300.       olen = len
  301.       call SysCurPos origRow + (origCol + currOfs) % col, (origCol + currOfs) // col
  302.       end
  303.  
  304.    currLine = prevLine.0
  305.  
  306.    do while (key <> "enter")
  307.       lastKey = key
  308.       key = getKey()
  309.       oline = line
  310.  
  311. dokey:
  312.       select
  313.          when (length(key) = 1) then
  314.             do
  315.             if (insert) then
  316.                line = insert(key,line,currOfs)
  317.             else
  318.                line = overlay(key,line,currOfs+1)
  319.  
  320.             currOfs = currOfs + 1
  321.             end
  322.  
  323.          when (key = "backsp") then
  324.             do
  325.             if (currOfs <= 0) then
  326.                if mc = 1 then return; else iterate
  327.             line = delstr(line,currOfs,1)
  328.             currOfs = currOfs - 1
  329.             end
  330.  
  331.          when (key = "space") then
  332.             do
  333.             oldOfs = xOfs; xOfs = 0; xyzzy = findcontexttype()
  334.  
  335.             if (insert) then
  336.                line = insert(' ',line,currOfs)
  337.             else
  338.                line = overlay(' ',line,currOfs+1)
  339.  
  340.             dif = compare(line,oline)
  341.             if dif = 0 & olen \= length(line) then
  342.                dif = length(line)
  343.             if dif \= 0 then
  344.                do
  345.                len = length(line)
  346.                if dif <= xOfs then dif = 1
  347.                call SysCurPos origRow + (origCol + dif - 1) % col, (origCol + dif - 1) // col
  348.                call charout , substr(line,dif,max(len,olen)-dif+1)
  349.  
  350.                if origRow + (origCol + len) % col >= row then
  351.                   origRow = row - (origCol + len) % col - 1
  352.                olen = len; oline = line
  353.                end
  354.  
  355.             xlen = origCol + currOfs - length(strip(xline,'L'))
  356.             if xyzzy = 'c' then do
  357.                if findcommand() = '' then
  358.                   interpret invalidCmd
  359.                end
  360.             else
  361.             if xyzzy = '0' then
  362.                interpret invalidCmd
  363.  
  364.             currOfs = currOfs + 1
  365.             xOfs = max(oldOfs, xOfs)
  366.             end
  367.  
  368.          when (key = "tab") | (key = "backtab") then
  369.             do
  370.             if (currTab \= 0) then
  371.                if (key = "tab") then
  372.                   if (currTab = tree.0) then
  373.                      currTab = 1
  374.                   else
  375.                      currTab = currTab+1
  376.                else
  377.                   if (currTab = 1) then
  378.                      currTab = tree.0
  379.                   else
  380.                      currTab = currTab-1
  381.             else
  382.                if findcontextcompletion() = 0 then
  383.                   if mc = 1 then return; else iterate
  384.                else
  385.                   if (key = "tab") then
  386.                      currTab = 1
  387.                   else
  388.                      currTab = tree.0
  389.  
  390.             newf = filespec("d",file)filespec("p",file)filespec("n",tree.currTab)
  391.             if (pos(' ',newf) > 0) then newf = '"'newf'"'
  392.             line = left(line,fileOfs)newf||substr(line,currOfs+1)
  393.             currOfs = fileOfs+length(newf)
  394.             end
  395.  
  396.          when (key = "match") & (line \= "") then
  397.             do prevLine.0
  398.                currLine = currLine-1
  399.                if (currLine <= 0) then
  400.                   currLine = prevLine.0
  401.  
  402.                if compare(prevLine.currLine,line) > currOfs then
  403.                   do
  404.                   xOfs = 0
  405.                   line = prevLine.currLine
  406.                   if mc = 1 then return; else leave
  407.                   end
  408.             end
  409.  
  410.          when (key = "backmatch") & (line \= "") then
  411.             do prevLine.0
  412.                currLine = currLine+1
  413.                if (currLine > prevLine.0) then
  414.                   currLine = 1
  415.  
  416.                if compare(prevLine.currLine,line) > currOfs then
  417.                   do
  418.                   xOfs = 0
  419.                   line = prevLine.currLine
  420.                   if mc = 1 then return; else leave
  421.                   end
  422.             end
  423.  
  424.          when (key = "cright") & (currOfs < len) then
  425.             currOfs = currOfs + 1
  426.  
  427.          when (key = "cleft") & (currOfs > 0) then
  428.             currOfs = currOfs - 1
  429.  
  430.          when (key = "cup") | (key = "cdown") then
  431.             do
  432.             if (prevLine.0 = 0) then
  433.                if mc = 1 then return; else iterate
  434.  
  435.             if (key = "cup") then
  436.                do
  437.                if (firstCup) then
  438.                   firstCup = 0
  439.                else
  440.                   currLine = currLine - 1
  441.                end
  442.             else
  443.                currLine = currLine + 1
  444.  
  445.             if (currLine <= 0) then
  446.                currLine = prevLine.0
  447.  
  448.             if (currLine > prevLine.0) then
  449.                currLine = 1
  450.  
  451.             line = prevLine.currLine
  452.             currOfs = length(line)
  453.             xOfs = 0
  454.             end
  455.  
  456.          when (key = "del") then
  457.             line = delstr(line,currOfs+1,1)
  458.  
  459.          when (key = "home") then
  460.             currOfs = 0
  461.  
  462.          when (key = "end") then
  463.             currOfs = len
  464.  
  465.          when (key = "esc") then
  466.             do
  467.             line = ""
  468.             currOfs = 0
  469.             xOfs = 0
  470.             end
  471.  
  472.          when (key = "ctrlend") then
  473.             line = left(line,currOfs)
  474.  
  475.          when (key = "ctrlhome") then
  476.             do
  477.             line = substr(line,currOfs+1)
  478.             currOfs = 0
  479.             end
  480.  
  481.          when (key = "ctrlleft") & (currOfs > 0) then
  482.             currOfs = wordindex(line,words(left(line,currOfs)))-1
  483.  
  484.          when (key = "ctrlright") then
  485.             do
  486.             currTab = wordindex(line,words(left(line,currOfs+1))+1)-1
  487.             if (currTab >= 0) then
  488.                currOfs = currTab
  489.             end
  490.  
  491.          when (key = "ins") then
  492.             do
  493.             insert = \ insert
  494.             call VioSetCurType word(insertMode.insert,1), word(insertMode.insert,2)
  495.             if mc = 1 then return; else iterate
  496.             end
  497.  
  498.          when (abbrev('OSNOWAIT',translate(word(key,1)),3)) | (translate(word(key,1)) = 'SHELL') then
  499.             call eval subword(key,2)
  500.  
  501.          when (translate(word(key,1)) = 'TEXT') then
  502.             do
  503.             if (insert) then
  504.                line = insert(subword(key,2),line,currOfs)
  505.             else
  506.                line = overlay(subword(key,2),line,currOfs+1)
  507.  
  508.             currOfs = currOfs + length(subword(key,2))
  509.             end
  510.  
  511.          when (key = "expand") & (currOfs > 0) then
  512.             do
  513.             xyzzy = findcontexttype()
  514.             xlen = origCol + currOfs - length(strip(xline,'L'))
  515.             what = getFileSpec(left(line,currOfs))
  516.             subl = left(line,currOfs-length(what))
  517.             if substr(line,currOfs,1) = '=' then
  518.                if translate(fcccmd) = 'ALIAS' then do
  519.                   what = reverse(word(reverse(left(line,currOfs-1)),1))
  520.                   if wordpos(what,aliasNames) > 0 then
  521.                      line = insert(aliasStem.what,line,currOfs)
  522.                   end
  523.                else
  524.                if translate(fcccmd) = 'RULE' then do
  525.                   what = reverse(word(reverse(left(line,currOfs-1)),1))
  526.                   if wordpos(what,rulesList) > 0 then
  527.                      line = insert(rules.what,line,currOfs)
  528.                   end
  529.                else
  530.                   line = insert(value(reverse(word(reverse(left(line,currOfs-1)),1)),,'OS2ENVIRONMENT'),line,currOfs)
  531.             else
  532.             if xyzzy = 'c' then do
  533.                what = findcommand('real')
  534.                if what = '' then
  535.                   interpret 'subl = subl || xline;' invalidCmd
  536.                else
  537.                   subl = subl || what
  538.                end
  539.             else
  540.                subl = subl || expand(what)
  541.             line = subl||substr(line,currOfs+1)
  542.             currOfs = length(subl)
  543.             end
  544.  
  545.          when (word(key,1) = "mark") then
  546.             call mark
  547.  
  548.          when (key = "dup") then
  549.             do
  550.                what = getFileSpec(left(line, currOfs))
  551.                line = insert(' 'what, line, currOfs)
  552.                currOfs = currOfs + length(what) + 1
  553.                if currTab \= 0 then do
  554.                   key = "tab"
  555.                   fileOfs = fileOfs + length(what) + 1
  556.                   end
  557.             end
  558.  
  559.          when (translate(word(key,1)) = "MC") then
  560.             do
  561.             mc = 1
  562.             parse value subword(key,2) with sep 2 seq
  563.             do while seq \= ''
  564.                parse value seq with key (sep) seq
  565.                call dokey
  566.             end /* do */
  567.             mc = 0
  568.             end
  569.  
  570.          otherwise
  571.             nop
  572.       end
  573.  
  574.       if (key \= "tab" & key \= "backtab") then
  575.          currTab = 0
  576.  
  577.       dif = compare(line,oline)
  578.       if dif \= 0 then
  579.          do
  580.          len = length(line)
  581.          if dif <= xOfs then dif = 1
  582.          call SysCurPos origRow + (origCol + dif - 1) % col, (origCol + dif - 1) // col
  583.          call charout , substr(line,dif,max(len,olen)-dif+1)
  584.  
  585.          if origRow + (origCol + len) % col >= row then
  586.             origRow = row - (origCol + len) % col - 1
  587.          olen = len
  588.          end
  589.  
  590.       if markLine = currLine then
  591.          call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 248
  592.       call SysCurPos origRow + (origCol + currOfs) % col, (origCol + currOfs) // col
  593.  
  594. if mc = 1 then return
  595.  
  596.    end
  597.  
  598.    if (line <> "") & (lastKey <> "cup") & (lastKey <> "cdown") then
  599.       do
  600.       o = prevLine.0 + 1
  601.       prevLine.0 = o
  602.       prevLine.o = line
  603.       end
  604.    else
  605.    if (cmdQueue = 1) & ((lastKey = "cup") | (lastKey = "cdown")) then
  606.       do
  607.       do i = currLine to prevLine.0 - 1
  608.          j = i + 1
  609.          prevLine.i = prevLine.j
  610.       end /* do */
  611.       call value 'prevLine.'prevLine.0, line
  612.       end
  613.  
  614.    call SysCurPos origRow + (origCol + len) % col, (origCol + len) // col
  615.    say
  616.  
  617.    if (line \= "" & verify(reverse(line),"^") // 2 = 0) then
  618.       do
  619.       call charout , secondaryPrompt
  620.       line = left(line,len-1) getLine()
  621.       end
  622.  
  623.    return line
  624.  
  625. /*------------------------------------------------------------------
  626.  * get file spec
  627.  *------------------------------------------------------------------*/
  628. getFileSpec:
  629.    fileOfs = length(arg(1))
  630.    do forever
  631.       select
  632.          when (fileOfs < 1) then do; fileOfs = 0; leave; end
  633.          when pos(substr(arg(1),fileOfs,1), fileSeparator) > 0 then leave
  634.          when (substr(arg(1),fileOfs,1) = '"') & fileOfs > 1 then fileOfs = lastpos('"',arg(1),fileOfs-1)
  635.       otherwise
  636.          nop
  637.       end
  638.       fileOfs = fileOfs - 1
  639.    end
  640.    return substr(arg(1),fileOfs+1)
  641.  
  642. /*------------------------------------------------------------------
  643.  * get key
  644.  *------------------------------------------------------------------*/
  645. getKey:
  646.    call on halt name ignore
  647.  
  648.    key  = SysGetKey("NOECHO")
  649.    ckey = c2x(key)
  650.  
  651.    /*---------------------------------------------------------------
  652.     * get second 'key' if needed
  653.     *---------------------------------------------------------------*/
  654.    if (ckey = "E0") | (ckey = "00") then
  655.       ckey = "00" || c2x(SysGetKey("NOECHO"))
  656.  
  657.    /*---------------------------------------------------------------
  658.     * look it up
  659.     *---------------------------------------------------------------*/
  660.    ckey = "_"ckey
  661.  
  662.    if (symbol("key."ckey) = "LIT") then
  663.       return key
  664.    else
  665.       return key.ckey
  666.  
  667. /*------------------------------------------------------------------
  668.  * handle break
  669.  *------------------------------------------------------------------*/
  670. ignore:
  671.    return ""
  672.  
  673. /*====================================================================
  674.  * Interpret Command-line Arguments.
  675.  *====================================================================*/
  676. doarg:
  677.    lineArg = arg(1)
  678.  
  679.    do while lineArg \= ''
  680.       parse value lineArg with switch lineArg
  681.  
  682.       select
  683.          when switch = '/O' | switch = '/o' then insertState = 0
  684.          when switch = '/I' | switch = '/i' then insertState = 1
  685.          when wordpos(switch,helpSwitches) > 0 then do
  686.             if value('HELP.COMMAND',,'OS2ENVIRONMENT') \= '' then
  687.                '@call %HELP.COMMAND% CMDSHL' lineArg
  688.             else
  689.                say cmdHelp
  690.             exit
  691.             end
  692.          when switch = '/C' | switch = '/c' then do
  693.             if left(lineArg,1) = '"' & right(lineArg,1) = '"' then
  694.                call eval strip(lineArg, 'b', '"')
  695.             else
  696.                call eval lineArg
  697.             exit
  698.             end
  699.          when switch = '/K' | switch = '/k' then do
  700.             if left(lineArg,1) = '"' & right(lineArg,1) = '"' then
  701.                call eval strip(lineArg, 'b', '"')
  702.             else
  703.                call eval lineArg
  704.             leave
  705.             end
  706.          when switch = '/P' | switch = '/p' then
  707.             parse value lineArg with profileName lineArg
  708.       otherwise
  709.          say SysGetMessage(1003)
  710.          exit 1
  711.       end  /* select */
  712.  
  713.    end /* do */
  714.  
  715.    return
  716.  
  717. /*====================================================================
  718.  * A cmd.exe-like Command Evaluator.
  719.  *====================================================================*/
  720. eval:
  721.    signal on halt
  722.    _LEVEL_ = _LEVEL_ + 1
  723.  
  724.    eval._LEVEL_.cmdLine = strip(arg(1),'L')
  725.    needcr = 1; eval._LEVEL_.xlen = length(eval._LEVEL_.cmdLine); eval._LEVEL_.xpos = 1
  726.  
  727.    do while eval._LEVEL_.xpos <= eval._LEVEL_.xlen
  728.       /* parsing command line */
  729.       inStr = 0; inSub = 0; redir = 0; eval._LEVEL_.xcur = eval._LEVEL_.xpos
  730.       do while eval._LEVEL_.xpos <= eval._LEVEL_.xlen
  731.          redir = (ch = '>')
  732.          ch = substr(eval._LEVEL_.cmdLine,eval._LEVEL_.xpos,1); eval._LEVEL_.xpos = eval._LEVEL_.xpos + 1
  733.  
  734.          if ch = '"' then inStr = inStr && 1
  735.          else
  736.          if \inStr then do
  737.             if ch = '^' then eval._LEVEL_.xpos = eval._LEVEL_.xpos + 1
  738.             else
  739.             if ch = '&' & redir = 0 & inSub = 0 then
  740.                if substr(eval._LEVEL_.cmdLine,eval._LEVEL_.xpos,1) \= '&' then
  741.                   leave
  742.                else
  743.                   eval._LEVEL_.xpos = eval._LEVEL_.xpos + 1
  744.             else
  745.             if ch = '(' then inSub = inSub + 1
  746.             else
  747.             if ch = ')' then inSub = inSub - 1
  748.             end
  749.       end /* do */
  750.  
  751.       parse value substr(eval._LEVEL_.cmdLine,eval._LEVEL_.xcur,eval._LEVEL_.xpos-eval._LEVEL_.xcur) with cmd args
  752.  
  753.       if pos('"', cmd) \= 0 then do
  754.          args = cmd args; cmd = getArg(args); args = substr(args, length(cmd)+1)
  755.          end
  756.  
  757.       if inStr = 0 & right(args,1) = '&' & right(args,2) \= '&&' & right(args,2) \= '^&' then
  758.          args = left(args,length(args)-1)
  759.  
  760.       ucmd = translate(cmd)
  761.  
  762.       if args = '' & impCD = 1 then do
  763.          curDir = directory()
  764.          if dir(cmd) \= '' then do
  765.             oldDir = curDir
  766.             iterate
  767.             end
  768.          end
  769.  
  770.       select
  771.          when (wordpos(cmd,arg(2)) = 0) & (wordpos(cmd,aliasNames) > 0) then do
  772.             call eval substitute(aliasStem.cmd,cmd args), arg(2) cmd
  773.             needcr = 0
  774.             end
  775.          when wordpos(ucmd,shlList) > 0 then
  776.             select
  777.                when (ucmd = 'CD') then call cd args
  778.                when (ucmd = 'RX') then do
  779.                   signal on syntax name error
  780.                   interpret args
  781.                   needcr = 0
  782.                   end
  783.                when (ucmd = 'ALIAS') then call alias args
  784.                when (ucmd = 'RULE') then call rule args
  785.                when (ucmd = 'KEYS') then
  786.                   if translate(args) = 'LIST' then
  787.                      do key = 1 to prevLine.0
  788.                         say right(key,5)':' prevLine.key
  789.                      end /* do */
  790.                   else
  791.                      ''cmd args
  792.                when abbrev('DEFINE',ucmd,3) then do
  793.                   parse value args with key rest
  794.                   if wordpos(args,helpSwitches) > 0 then
  795.                      if value('HELP.COMMAND',,'OS2ENVIRONMENT') \= '' then
  796.                         '@call %HELP.COMMAND% DEFINE' args
  797.                      else
  798.                         say defHelp
  799.                   else do
  800.                      needcr = 0
  801.                      if length(key) > 1 then
  802.                         if symbol(translate(key,'_','-')) = 'VAR' then
  803.                            key = value(translate(key,'_','-'))
  804.                         else do
  805.                            say SysGetMessage(1003)
  806.                            iterate
  807.                            end
  808.                      if rest \= '' then
  809.                         call value 'key._'c2x(key), rest
  810.                      else
  811.                         interpret 'drop key._'c2x(key)
  812.                      end
  813.                   end
  814.                when (ucmd = 'QUIT') then
  815.                   if wordpos(args,helpSwitches) > 0 then
  816.                      if value('HELP.COMMAND',,'OS2ENVIRONMENT') \= '' then
  817.                         '@call %HELP.COMMAND% QUIT' args
  818.                      else
  819.                         say quitHelp
  820.                   else
  821.                      return 0
  822.             otherwise
  823.             end
  824.          when wordpos(ucmd, cmdList) > 0 | left(ucmd,1) = '(' then
  825.             double(expand(cmd args))
  826.       otherwise
  827.          if args = '' & impCD = 2 then do
  828.             xline = ucmd
  829.             xyzzy = findcommand('REAL')
  830.             if xyzzy \= '' then
  831.                if stream(xyzzy,'c','query exists') = '' | (length(xyzzy)=3 & right(xyzzy,2) = ':\' & datatype(left(xyzzy,1),'M')) then do
  832.                   curDir = directory()
  833.                   if dir(cmd) \= '' then do
  834.                      oldDir = curDir
  835.                      iterate
  836.                      end
  837.                   end
  838.             'call' double(double(expand(cmd args)))
  839.             end
  840.          else
  841.             'call' double(double(expand(cmd args)))
  842.       end /* select */
  843.    end
  844.  
  845.    if arg(1) \= '' & interactive & needcr then say
  846.  
  847.    _LEVEL_ = _LEVEL_ - 1
  848.  
  849.    return 1
  850.  
  851. error:
  852.    say 'REX'right(rc,4,'0')':' errortext(rc)nl
  853.    if condition('I') = 'SIGNAL' then
  854.       signal loop
  855.    else
  856.       return
  857.  
  858. double:
  859.    procedure
  860.    expr = arg(1); doubled = ''
  861.    do while pos('%',expr) > 0
  862.       doubled = doubled||left(expr,pos('%',expr))||'%'
  863.       expr = substr(expr,pos('%',expr)+1)
  864.    end /* do */
  865.    doubled = doubled||expr
  866.    return doubled
  867.  
  868. substitute:
  869.    procedure
  870.    symb = arg(1); actual = arg(2); xpos = 1; xlen = length(symb); r = ''; inSubst = 0
  871.    do while xpos <= xlen
  872.       ch = substr(symb,xpos,1); xpos = xpos + 1
  873.       if ch = '^' then do
  874.          r = r || substr(symb,xpos,1)
  875.          xpos = xpos + 1
  876.          end
  877.       else
  878.       if ch = '%' & inSubst = 0 then inSubst=1
  879.       else
  880.       if inSubst = 1 then do
  881.          inSubst = 0
  882.          if pos(ch,0123456789) > 0 then
  883.             if substr(symb,xpos,1) = '*' then do
  884.                r = r || subword(actual,ch+1)
  885.                xpos = xpos+1
  886.                end
  887.             else
  888.                r = r || word(actual,ch+1)
  889.          else
  890.          if ch = '*' then
  891.             r = r || subword(actual,2)
  892.          else
  893.             r = r'%'ch
  894.          end
  895.       else
  896.          r = r || ch
  897.    end /* do */
  898.    if inSubst = 1 then
  899.       r = r'%'
  900.    return r
  901.  
  902. expand:
  903.    procedure
  904.    args = arg(1); xpos = pos('%',args)+1
  905.    if xpos > 1 then do
  906.       ypos = pos('%',args,xpos)
  907.       if ypos > 0 then do
  908.          envi = substr(args,xpos,ypos-xpos)
  909.          valu = value(envi,,'OS2ENVIRONMENT')
  910.          if valu = '' then
  911.             args = left(args,xpos-1) || envi || expand(substr(args,ypos))
  912.          else
  913.             args = left(args,xpos-2) || valu || expand(substr(args,ypos+1))
  914.          end
  915.       end
  916.    return args
  917.  
  918. dir:
  919.    procedure expose rc
  920.    rc = 0
  921.    parse value expand(arg(1)) with args
  922.    args = translate(space(translate(args, ' "', '" '), 0), ' "', '" ')
  923.    if left(args,1) = '"' then args = strip(args,,'"')
  924.    if pos(right(args,1),'\/') \= 0 then
  925.       if length(args) > 1 & left(right(args,2),1) \= ':' then args = left(args,length(args)-1)
  926.    if directory(args) = '' then do
  927.       cdpath = value('CDPATH',,'OS2ENVIRONMENT')
  928.       do while cdpath \= ''
  929.          parse value cdpath with path ';' cdpath
  930.          if pos(right(path,1),'\/') = 0 then
  931.             path = path'\'
  932.          if directory(path||args) \= '' then do
  933.             return directory()
  934.             end
  935.       end /* do */
  936.       rc = 1
  937.       return ''
  938.       end
  939.    return directory()
  940.  
  941. cd:
  942.    parse value arg(1) with args
  943.  
  944.    curDir = directory()
  945.    select
  946.       when args = '-' then do
  947.          call directory oldDir
  948.          oldDir = curDir
  949.          end
  950.       when wordpos(args,helpSwitches) > 0 then do
  951.          if value('HELP.COMMAND',,'OS2ENVIRONMENT') \= '' then
  952.             '@call %HELP.COMMAND% CD' args
  953.          else do
  954.             '@CD /?'
  955.             say cdHelp
  956.          end
  957.          end
  958.       when args = '' | (length(strip(args)) = 2 & right(args,1) = ':') then do
  959.          say directory(args)
  960.          call directory(curDir)
  961.          end
  962.    otherwise
  963.       arg1 = getArg(args)
  964.       if args = arg1 then
  965.         if dir(args) = '' then do
  966.            say SysGetMessage(0003)
  967.            needcr = 0
  968.            end
  969.         else
  970.            oldDir = curDir
  971.       else do
  972.          arg2 = strip(substr(args, length(arg1)+1))
  973.          arg1 = translate(space(translate(translate(arg1), ' "', '" '), 0), ' "', '" ')
  974.          if pos(arg1,translate(curDir)) = 0 then do
  975.             say SysGetMessage(1171,,arg1)
  976.             rc = 1
  977.             needcr = 0
  978.             end
  979.          else
  980.          if dir(left(curDir,pos(arg1,translate(curDir))-1)arg2||substr(curDir,pos(translate(arg1),translate(curDir))+length(arg1))) = '' then do
  981.             say SysGetMessage(0003)
  982.             needcr = 0
  983.             end
  984.          else
  985.             oldDir = curDir
  986.        end
  987.    end  /* select */
  988.  
  989.    return
  990.  
  991. alias:
  992.    procedure expose aliasHelp aliasNames aliasStem. helpSwitches
  993.  
  994.    parse value arg(1) with subcmd '>' file
  995.  
  996.    select
  997.       when translate(subcmd) = 'LIST' then
  998.          if (file \= '') then do
  999.             do alias = 1 to words(aliasNames)
  1000.                name = word(aliasNames,alias)
  1001.                call lineout file,name'='aliasStem.name
  1002.             end /* do */
  1003.             call stream file,'c','close'
  1004.             end
  1005.          else
  1006.             do alias = 1 to words(aliasNames)
  1007.                name = word(aliasNames,alias)
  1008.                say right(alias,4) left(name,10) '=' aliasStem.name
  1009.             end
  1010.       when left(subcmd,1) = '@' then do
  1011.          file = substr(subcmd,2)
  1012.          do while lines(file) > 0
  1013.             call addalias linein(file)
  1014.          end /* do */
  1015.          call stream file,'c','close'
  1016.          end
  1017.       when wordpos(subcmd,helpSwitches) > 0 then do
  1018.          if value('HELP.COMMAND',,'OS2ENVIRONMENT') \= '' then
  1019.             '@call %HELP.COMMAND% ALIAS' subcmd
  1020.          else
  1021.             say aliasHelp
  1022.          end
  1023.    otherwise
  1024.       call addalias arg(1)
  1025.    end /* select */
  1026.    return
  1027.  
  1028. addalias:
  1029.    parse value arg(1) with alias '=' cmd
  1030.    alias = strip(alias)
  1031.    if cmd \= '' then do
  1032.       if wordpos(alias,aliasNames) = 0 then
  1033.          aliasNames = aliasNames alias
  1034.       aliasStem.alias = cmd
  1035.       end
  1036.    else do
  1037.       parse value aliasNames with first (alias) last
  1038.       aliasNames = first last
  1039.       end
  1040.    return
  1041.  
  1042. rule:
  1043.    procedure expose ruleHelp rulesList rules. helpSwitches
  1044.  
  1045.    parse value arg(1) with subcmd '>' file
  1046.  
  1047.    select
  1048.       when translate(subcmd) = 'LIST' then
  1049.          if (file \= '') then do
  1050.             do rule = 1 to words(rulesList)
  1051.                name = word(rulesList,rule)
  1052.                call lineout file,name'='rules.name
  1053.             end /* do */
  1054.             call stream file,'c','close'
  1055.             end
  1056.          else
  1057.             do rule = 1 to words(rulesList)
  1058.                name = word(rulesList,rule)
  1059.                say right(rule,4) left(name,10) '=' rules.name
  1060.             end
  1061.       when left(subcmd,1) = '@' then do
  1062.          file = substr(subcmd,2)
  1063.          do while lines(file) > 0
  1064.             call addrule linein(file)
  1065.          end /* do */
  1066.          call stream file,'c','close'
  1067.          end
  1068.       when wordpos(subcmd,helpSwitches) > 0 then do
  1069.          if value('HELP.COMMAND',,'OS2ENVIRONMENT') \= '' then
  1070.             '@call %HELP.COMMAND% RULE' subcmd
  1071.          else
  1072.             say ruleHelp
  1073.          end
  1074.    otherwise
  1075.       call addrule arg(1)
  1076.    end /* select */
  1077.    return
  1078.  
  1079. addrule:
  1080.    parse value arg(1) with rule '=' cmd
  1081.    rule = strip(rule)
  1082.    if cmd \= '' then do
  1083.       if wordpos(rule,rulesList) = 0 then
  1084.          rulesList = rulesList rule
  1085.       rules.rule = cmd
  1086.       end
  1087.    else do
  1088.       parse value rulesList with first (rule) last
  1089.       rulesList = first last
  1090.       end
  1091.    return
  1092.  
  1093. mark:
  1094.    select
  1095.       when word(key,2) = "word" then
  1096.          do
  1097.          if markLine = currLine then
  1098.             call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 7
  1099.          markLen = 0
  1100.          markLine= currLine
  1101.          select
  1102.             when line = '' then
  1103.                iterate
  1104.             when currOfs = 0 then
  1105.                markOfs = wordindex(line,1)-1
  1106.             when left(line,currOfs) = '' then
  1107.                markOfs = wordindex(line,1)-1
  1108.             when substr(line,currOfs,1) = ' ' then
  1109.                markOfs = currOfs+wordindex(substr(line,currOfs),1)-2
  1110.             otherwise
  1111.                markOfs = wordindex(line,words(left(line,currOfs)))-1
  1112.          end  /* select */
  1113.          markLen = length(word(substr(line,markOfs+1),1))
  1114.          call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 248
  1115.          end
  1116.       when (word(key,2) = "char") then
  1117.          do
  1118.          if markLine \= currLine | (markLen = 0 & markOfs = 0) then
  1119.             do
  1120.             markOfs = currOfs
  1121.             markLen = 1
  1122.             markLine= currLine
  1123.             end
  1124.          else
  1125.             do
  1126.             call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 7
  1127.             if markOfs > currOfs then
  1128.                do
  1129.                markLen = markLen+markOfs-currOfs+1
  1130.                markOfs = currOfs
  1131.                end
  1132.             else
  1133.                markLen = currOfs-markOfs+1
  1134.             end
  1135.          call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 248
  1136.          end
  1137.       when (word(key,2) = "clear") then
  1138.          do
  1139.          if markLine = currLine then
  1140.             call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 7
  1141.          markLen = 0
  1142.          markOfs = 0
  1143.          end
  1144.       when (word(key,2) = "copy") then
  1145.          do
  1146.          if markLine = currLine then
  1147.             do
  1148.             call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 7
  1149.             line = left(line,currOfs)substr(line,markOfs+1,markLen)substr(line,currOfs+1)
  1150.             end
  1151.          else
  1152.             line = left(line,currOfs)substr(prevline.markLine,markOfs+1,markLen)substr(line,currOfs+1)
  1153.          markOfs = currOfs
  1154.          markLine= currLine
  1155.          currOfs = currOfs+markLen
  1156.          end
  1157.       when (word(key,2) = "delete") then
  1158.          if markLine = currLine then
  1159.             do
  1160.             call VioWrtNAttr origRow + (origCol + markOfs) % col, (origCol + markOfs) // col, markLen, 7
  1161.             line = left(line,markOfs)substr(line,markOfs+markLen+1)
  1162.             if currOfs > markLen + markOfs then currOfs = currOfs - markLen
  1163.             else
  1164.             if currOfs > markOfs then currOfs = markOfs
  1165.             markLen = 0
  1166.             end
  1167.          else
  1168.             markLen = 0
  1169.       when (word(key,2) = "move") then
  1170.          do
  1171.          if markLine = currLine then
  1172.             do
  1173.             if currOfs > markLen + markOfs then currOfs = currOfs - markLen
  1174.             else
  1175.             if currOfs > markOfs then return
  1176.             line = insert(substr(line,markOfs+1,markLen),left(line,markOfs)substr(line,markOfs+markLen+1),currOfs)
  1177.             end
  1178.          else
  1179.             do
  1180.             line = left(line,currOfs)substr(prevline.markLine,markOfs+1,markLen)substr(line,currOfs+1)
  1181.             markLine= currLine
  1182.             end
  1183.          markOfs = currOfs
  1184.          end
  1185.       otherwise
  1186.          nop
  1187.    end /* select */
  1188.    return
  1189.  
  1190. getArg:
  1191.    procedure
  1192.    args = arg(1)
  1193.    if pos('"', args) \= 0 then do
  1194.       inStr = 0; arg = ''
  1195.       do while \ (\inStr & left(args, 1) = ' ') & args \= ''
  1196.          if left(args, 1) = '"' then inStr = inStr && 1
  1197.          arg = arg || left(args, 1)
  1198.          args = substr(args, 2)
  1199.       end /* do */
  1200.       return arg
  1201.       end
  1202.    else
  1203.      return word(args, 1)
  1204.  
  1205. findcompletion:
  1206.    file = translate(space(translate(getFileSpec(left(line,currOfs)),' "','" '),0),' ','"')
  1207.    if (pos('*',file) = 0) then
  1208.       file = file'*'
  1209.    call SysFileTree expand(translate(file,'\','/')),'tree',arg(1)'O','**-*-'
  1210.    if (tree.0 = 0) then
  1211.       return 0
  1212.    if (tree.0 = 1 & tree.1'*' = expand(translate(file,'\','/'))) then
  1213.       return 0
  1214.    return 1
  1215.  
  1216. findmulticompletion:
  1217.    fmcarg = translate(arg(1),'   ','(,)')
  1218.    fmcfile = translate(space(translate(getFileSpec(left(line,currOfs)),' "','" '),0),' ','"')
  1219.    fmctree = 1
  1220.    do fmci = 1 to words(fmcarg)
  1221.       call SysFileTree expand(translate(fmcfile||word(fmcarg,fmci),'\','/')),'multi','FO','**-*-'
  1222.       do fmcj = 1 to multi.0
  1223.          tree.fmctree = multi.fmcj
  1224.          fmctree = fmctree+1
  1225.       end /* do */
  1226.    end /* do */
  1227.    if pos('*',fmcfile) = 0 then
  1228.       call SysFileTree expand(translate(fmcfile'*','\','/')),'multi','DO','**-*-'
  1229.    else
  1230.       call SysFileTree expand(translate(fmcfile,'\','/')),'multi','DO','**-*-'
  1231.    do fmcj = 1 to multi.0
  1232.       tree.fmctree = multi.fmcj
  1233.       fmctree = fmctree+1
  1234.    end /* do */
  1235.    fmctree = fmctree-1
  1236.    tree.0 = fmctree
  1237.    return fmctree \= 0
  1238.  
  1239. findcommand:
  1240.    if xline = '' then
  1241.       return ''
  1242.    fccmd = expand(translate(space(translate(xline, ' "', '" '), 0), ' "', '" '))
  1243.    command = ''
  1244.    if arg(1) \= '' then /* return the real command */
  1245.       do
  1246.       if impCD = 1 then do
  1247.          if length(fccmd) > 1 & pos(right(fccmd,1),'/\') > 0 then zline = left(fccmd,length(fccmd)-1); else zline = fccmd
  1248.          command = SysSearchPath('CDPATH',zline)
  1249.          if command = '' then if stream(zline,'c','query datetime') \= '' then command = zline
  1250.          end
  1251.       if command = '' then if wordpos(fccmd,aliasNames) > 0 then command = fccmd
  1252.       if command = '' then if wordpos(translate(fccmd),cmdList shlList) > 0 then command = fccmd
  1253.       end
  1254.    else                 /* return a possible command -- fast */
  1255.       do
  1256.       if wordpos(fccmd,aliasNames) > 0 then command = fccmd
  1257.       if command = '' then if wordpos(translate(fccmd),cmdList shlList) > 0 then command = fccmd
  1258.       if command = '' then if impCD \= 0 then
  1259.          do
  1260.          if length(fccmd) > 1 & pos(right(fccmd,1),'/\') > 0 then zline = left(fccmd,length(fccmd)-1); else zline = fccmd
  1261.          command = SysSearchPath('CDPATH',zline)
  1262.          if command = '' then if stream(zline,'c','query datetime') \= '' then command = zline
  1263.          end
  1264.       end
  1265.    if command = '' then
  1266.       if pos(left(fccmd,1),'/\') \= 0 | substr(fccmd,2,1) = ':' then
  1267.          do
  1268.          if length(fccmd) = 2 & right(fccmd,1) = ':' then if pos(translate(left(fccmd,1)),'ABCDEFGHIJKLMNOPQRSTUVWXYZ') > 0 then command = fccmd
  1269.          if command = '' then command = stream(fccmd,'c','query exist')
  1270.          do ext = 1 to words(extList) while command = ''
  1271.             command = stream(fccmd'.'word(extList,ext),'c','query exist')
  1272.          end /* do */
  1273.          end
  1274.       else
  1275.          do
  1276.          command = SysSearchPath('PATH',fccmd)
  1277.          if command \= '' & impCD = 2 then
  1278.             command = stream(command,'c','query exists')
  1279.          do ext = 1 to words(extList) while command = ''
  1280.             command = SysSearchPath('PATH',fccmd'.'word(extList,ext))
  1281.          end /* do */
  1282.          end
  1283.    if command = '' & arg(1) \= '' & impCD = 2 then do
  1284.       if length(fccmd) > 1 & pos(right(fccmd,1),'/\') > 0 then zline = left(fccmd,length(fccmd)-1); else zline = fccmd
  1285.       command = SysSearchPath('CDPATH',zline)
  1286.       if command = '' then if stream(zline,'c','query datetime') \= '' then command = zline
  1287.       end
  1288.    if pos(' ', command) = 0 then
  1289.       return command
  1290.    else
  1291.       return '"'command'"'
  1292.  
  1293. findenvcompletion:
  1294.    file = ''
  1295.    fecenv = DosGetEnv()
  1296.    fecvar = translate(translate(space(translate(getFileSpec(left(line,currOfs)),' "','" '),0),' ','"'))
  1297.    feci = 0
  1298.    do while length(fecenv) > 1
  1299.       parse var fecenv fecname '=' fecvalue '0'x fecenv
  1300.       if abbrev(fecname, fecvar) then do
  1301.          feci = feci+1
  1302.          tree.feci = fecname
  1303.       end
  1304.    end /* do */
  1305.    tree.0 = feci
  1306.    if feci = 0 then
  1307.      return 0
  1308.    return 1
  1309.  
  1310. findcurrentcommand:
  1311.    procedure expose xline
  1312.    xOfs = 0; xline = translate(arg(1),'  ','()'); xlen = lastpos('&',xline)
  1313.    if lastpos('|',xline) > xlen then xlen = lastpos('|',xline)
  1314.    if xlen > 0 then
  1315.       if verify(reverse(substr(xline,1,xlen-1)),"^") // 2 = 1 then
  1316.          if left(strip(reverse(substr(xline,1,xlen-1)),'L'),1) = '>' then
  1317.             xline = ''
  1318.          else
  1319.             xline = substr(xline,xlen+1)
  1320.       else
  1321.          xline = ''
  1322.    xline = strip(xline, 'L')
  1323.  
  1324.    /*
  1325.     * les divers cas possibles :
  1326.     *
  1327.     * - pas d'espaces et un guillemet -> #2
  1328.     * - pas d'espaces et pas de guillemets -> #1
  1329.     * - un espace et pas de guillemets -> ignore
  1330.     * - un espace et un guillemet -> ignore si espace avant guillemet, #2 sinon
  1331.     */
  1332.    if xline \= '' then
  1333.       do
  1334.       spos = pos(' ', xline)
  1335.       gpos = pos('"', xline)
  1336.       if spos = gpos then
  1337.          return xline
  1338.       else
  1339.       if gpos = 0 | (spos < gpos) then
  1340.          return word(xline, 1)
  1341.       else
  1342.          do
  1343.          /* command quoted */
  1344.          curCmd = xline; inStr = 0; xline = ''
  1345.          do while \ (\inStr & left(curCmd, 1) = ' ') & curCmd \= ''
  1346.             if left(curCmd, 1) = '"' then inStr = inStr && 1
  1347.             xline = xline || left(curCmd, 1)
  1348.             curCmd = substr(curCmd, 2)
  1349.          end /* do */
  1350.          if curCmd = '' & \inStr then
  1351.             return xline
  1352.          end
  1353.       end
  1354.    return ''
  1355.  
  1356. findcontextcompletion:
  1357.    fcc = findcontexttype()
  1358.    if fcc = 'd' then
  1359.       return findcompletion('D')
  1360.    else
  1361.    if fcc = 'f' | fcc = 'c' | fcc = 'a' then
  1362.       return findcompletion()
  1363.    else
  1364.    if fcc = 'e' then
  1365.       return findenvcompletion()
  1366.    if left(fcc,1) = '(' then
  1367.       return findmulticompletion(fcc)
  1368.    else
  1369.       return 0
  1370.  
  1371. findcontexttype:
  1372.    if arg() = 0 then
  1373.       context = left(line, currOfs)
  1374.    else
  1375.       context = arg(1)
  1376.    fcccmd = findcurrentcommand(context)
  1377.    if xline == fcccmd then
  1378.       return 'c'
  1379.    if wordpos(fcccmd, rulesList) > 0 | symbol('rules.'fcccmd) = 'VAR' then do
  1380.       /* use specified rule */
  1381.       if wordpos(fcccmd, rulesList) > 0 then
  1382.          fccrules = rules.fcccmd
  1383.       else
  1384.          fccrules = value('rules.'fcccmd)
  1385.       do while fccrules \= ''
  1386.          parse var fccrules fccrule '|' fccrules
  1387.          fccargs = strip(substr(right(context, length(xline)), length(fcccmd)+1), 'L')
  1388.          do while fccrule \== ''
  1389.             if left(fccrule, 1) = '%' then do
  1390.                fccch2 = substr(fccrule,2,1)
  1391.                if length(fccrule) = 2 then
  1392.                   fccch3 = ''
  1393.                else
  1394.                   fccch3 = substr(fccrule,3,1)
  1395.                select
  1396.                   when pos(fccch2, 'fd') > 0 then do
  1397.                      fcci = verify(fccargs, fileSeparator||fccch3, 'M')
  1398.                      if fcci = 0 then
  1399.                         return fccch2
  1400.                      fccargs = substr(fccargs, fcci)
  1401.                      end
  1402.                  when fccch2 = '(' then do
  1403.                      parse var fccrule '%(' spec ')' . +1 fccch3 +1 .
  1404.                      fcci = verify(fccargs, fileSeparator||fccch3, 'M')
  1405.                      if fcci = 0 then
  1406.                         return '('spec')'
  1407.                      fccargs = substr(fccargs, fcci)
  1408.                      if fccch3 \= '*' then
  1409.                         fccrule = substr(fccrule,pos(')',fccrule)-1)
  1410.                      end
  1411.                   when fccch2 = 'c' then do
  1412.                      xline = fccargs
  1413.                      fcci = verify(fccargs, fileSeparator||fccch3, 'M')
  1414.                      if fcci = 0 then
  1415.                         return fccch2
  1416.                      fccargs = substr(fccargs, fcci)
  1417.                      end
  1418.                   when fccch2 = 'e' then do
  1419.                      fcci = verify(fccargs, '<>=|'fccch3, 'M')
  1420.                      if fcci = 0 then
  1421.                         return fccch2
  1422.                      fccargs = substr(fccargs, fcci)
  1423.                      end
  1424.                   when fccch2 = 'o' then do
  1425.                      do while left(fccargs, 1) = '/'
  1426.                         fcci = pos(' ', fccargs)
  1427.                         if fcci = 0 then
  1428.                            return ''
  1429.                         else
  1430.                            fccargs = strip(substr(fccargs, fcci), 'L')
  1431.                      end /* do */
  1432.                      fccargs = ' 'fccargs
  1433.                      end
  1434.                   when fccch2 = '*' then do
  1435.                      if length(fccrule) = 2 then
  1436.                         return 'a'
  1437.                      fcci = verify(fccargs, fccch3, 'M')
  1438.                      if fcci = 0 then
  1439.                         return 'a'
  1440.                      fccargs = substr(fccargs, fcci)
  1441.                      end
  1442.                   when fccch2 = 'l' then
  1443.                      if length(fccargs) > 0 then
  1444.                         fccargs = substr(fccargs, 2)
  1445.                   when fccch2 = 'x' then
  1446.                      return findcontexttype(fccargs)
  1447.                   when fccargs == '' then
  1448.                      return ''
  1449.                   when fccch2 = '%' then do
  1450.                      if left(fccargs, 1) \= '%' then
  1451.                         leave
  1452.                      fccargs = substr(fccargs, 2)
  1453.                      end
  1454.                otherwise
  1455.                end  /* select */
  1456.                if fccch3 = '*' then do
  1457.                   fccargs = substr(fccargs, 2)
  1458.                   iterate
  1459.                   end
  1460.                fccrule = substr(fccrule, 2)
  1461.                end
  1462.             else
  1463.             if fccargs == '' then
  1464.                return ''
  1465.             else
  1466.             if left(fccrule, 1) = ' ' & left(fccargs, 1) = ' ' then
  1467.                fccargs = strip(fccargs, 'L')
  1468.             else
  1469.             if translate(left(fccrule, 1)) \= translate(left(fccargs,1)) then
  1470.                leave
  1471.             else
  1472.             if translate(left(fccrule, 1)) = translate(left(fccargs, 1)) then
  1473.                fccargs = substr(fccargs, 2)
  1474.             fccrule = substr(fccrule, 2)
  1475.          end /* do */
  1476.          if fccargs = '' then
  1477.             return ''
  1478.       end /* do */
  1479.       return 0
  1480.    end
  1481.    else
  1482.      return 'a'
  1483.  
  1484. halt:
  1485.   call charout ,SysGetMessage(1048)
  1486.   call directory orgdir
  1487.   signal loop
  1488.