Subversion Repositories NedoOS

Rev

Rev 680 | Rev 875 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download

  1. ;TODO %~dp0 (драйв и путь запуска)
  2. ;TODO %~t1 (дата-время 1-го параметра)
  3. ;TODO goto и метки :label
  4. ;TODO if ???==??? goto
  5. ;TODO for
  6. ;TODO PATH (где хранить? должна подгружаться при старте новой копии cmd)
  7.  
  8.         DEVICE ZXSPECTRUM128
  9.         include "../_sdk/sys_h.asm"
  10. MAXCMDSZ=COMMANDLINE_sz-1;127 ;не считая терминатора
  11. txtscrhgt=25
  12. txtscrwid=80
  13. CMDLINEY=24
  14.  
  15. _COLOR=0x0007;7
  16. _ERRORCOLOR=0x0009;0x42
  17.  
  18.         org PROGSTART
  19. cmd_begin
  20.         ld sp,0x4000 ;не должен опускаться ниже 0x3b00! иначе возможна порча OS        
  21.         call initstdio
  22.  
  23.         OS_GETSTDINOUT ;e=stdin, d=stdout, h=stderr
  24.         ld a,d
  25.         ld (stdouthandle_wasatstart),a
  26.         ld a,e
  27.         ld (stdinhandle_wasatstart),a
  28.  
  29.         OS_GETMAINPAGES
  30. ;dehl=номера страниц в 0000,4000,8000,c000
  31.         push hl
  32.         OS_DELPAGE
  33.         pop hl
  34.         push hl
  35.         ld e,h
  36.         OS_DELPAGE
  37.         pop hl
  38.         ld e,l
  39.         OS_DELPAGE
  40.  
  41.         ld hl,COMMANDLINE ;command line
  42.         push hl
  43.         ld de,params
  44.         call strcopy
  45.        
  46.         pop hl ;ld hl,COMMANDLINE ;command line
  47.         ld de,wordbuf
  48.         call getword
  49.         call skipspaces
  50.         ld (cmdlineword2),hl
  51.         ld a,(hl)
  52.         or a
  53.         jr z,cmd_interactive
  54. ;command line = "cmd <command to run>"
  55.         ld de,cmdbuf
  56.         call strcopy
  57.        
  58.         call makeprompt ;иначе запустится из неправильной директории
  59.        
  60.         call execcmd_maybepipes ;can show errors ;a!=0: no such internal command
  61.         ;or a
  62.         ;call nz,callcmd;strcpexec_tryrun ;запускает по фону
  63.         YIELD ;чтобы запущенная задача успела захватить фокус ;???
  64. ;если командная строка была со словом autoexec.bat в параметре, то это начальный запуск autoexec.bat, из него надо входить в интерактивный режим
  65.         ld hl,tautoexecbat
  66. cmdlineword2=$+1
  67.         ld de,0
  68.         call strcp ;z=yes
  69.         jr z,cmd_interactive
  70. cmd_exit
  71.         QUIT
  72.        
  73. tautoexecbat
  74.         db "autoexec.bat",0
  75.  
  76. cmd_interactive
  77.        
  78. cmdmainloop
  79.         call makeprompt
  80.         call editcmd
  81.         call prcrlf
  82.        
  83.         ld hl,cmdbuf
  84.         ld de,oldcmd
  85.         ld bc,MAXCMDSZ+1
  86.         ldir
  87.  
  88.         call execcmd_maybepipes
  89.         ;or a
  90.         ;call nz,callcmd;strcpexec_tryrun ;запускает по фону
  91.         ld hl,cmdbuf
  92.         ld (hl),0
  93.         jp cmdmainloop
  94.  
  95. execcmd_maybepipes
  96. ;out:a!=0: no such internal command
  97. ;если command pars >file, то create file, перенаправить вывод в него, execcmd, close file, перенаправить вывод обратно
  98.         ld hl,cmdbuf
  99.         ld a,'|'
  100.         ld bc,MAXCMDSZ
  101.         cpir
  102.         jr z,execcmd_pipe
  103.  
  104.         ld hl,cmdbuf
  105.         ld a,'<'
  106.         ld bc,MAXCMDSZ
  107.         cpir
  108.         jr z,execcmd_changestdin ;jr nz,cmd_noexeccmdtofile
  109.  
  110.         ld hl,cmdbuf
  111.         ld a,'>'
  112.         ld bc,MAXCMDSZ
  113.         cpir
  114.         jp nz,callcmd ;exec or run ;execcmd_or_runprog ;jr nz,cmd_noexeccmdtofile
  115. ;change stdout
  116.         dec hl
  117.         ld (hl),0
  118.         inc hl
  119.          call skipspaces
  120.         ex de,hl ;de=filename
  121.         OS_CREATEHANDLE
  122.         ld a,b
  123.         ld (execcmdtofile_handle),a
  124.         call setstdouthandle
  125. ;changestdin_stdout_execcmd
  126.         ;call execcmd ;can show errors ;a!=0: no such internal command
  127.         ; or a
  128.         ; call nz,callcmd
  129.          call callcmd ;exec or run
  130.         ;push af
  131. ;команда выполнилась в блокирующем режиме и вышла
  132. execcmdtofile_handle=$+1
  133.         ld b,0
  134.         OS_CLOSEHANDLE ;закрыли выходной файл
  135. stdouthandle_wasatstart=$+1
  136.         ld a,0
  137.         call setstdouthandle
  138. ;stdinhandle_wasatstart=$+1
  139. ;        ld a,0
  140. ;        call setstdinhandle
  141.  
  142.         ;pop af
  143.         ret
  144.         ;jr cmd_noexeccmdtofileq
  145. ;cmd_noexeccmdtofile
  146. ;        jp execcmd ;a!=0: no such internal command
  147. ;cmd_noexeccmdtofileq
  148. ;        ret
  149.  
  150. execcmd_changestdin
  151.         dec hl
  152.         ld (hl),0
  153.         inc hl
  154.          call skipspaces
  155.         ex de,hl ;de=filename
  156.         OS_OPENHANDLE
  157.         ld a,b
  158.         ;ld (execcmdtofile_changestdin_handle),a
  159.         call setstdinhandle
  160.         call setstdinout
  161.         ;jr changestdin_stdout_execcmd
  162.         ;call execcmd ;can show errors ;a!=0: no such internal command
  163.         ; or a
  164.         ; call nz,callcmd
  165.          call callcmd ;exec or run
  166.         ;push af
  167. ;команда выполнилась в блокирующем режиме и вышла (или запустилась программа по фону)
  168.  
  169. ;execcmdtofile_changestdin_handle=$+1
  170. ;        ld b,0
  171. ;        OS_CLOSEHANDLE ;закрыли входной файл программы
  172. ;stdouthandle_wasatstart=$+1
  173. ;        ld a,0
  174. ;        call setstdouthandle
  175. stdinhandle_wasatstart=$+1
  176.         ld a,0
  177.         call setstdinhandle
  178.         call setstdinout
  179.  
  180.         ;pop af
  181.         ret
  182.         ;jr cmd_noexeccmdtofileq
  183.  
  184. execcmd_pipe
  185. ;cmd |app
  186.         dec hl
  187.         ld (hl),0
  188.         inc hl
  189.          call skipspaces
  190.         ex de,hl ;de=app filename
  191.  
  192.         OS_OPENHANDLE
  193.         or a
  194.         jr nz,execcmd_pipe_error
  195.  
  196.         push bc
  197.         ld de,tpipename
  198.         OS_CREATEHANDLE
  199.         ld a,b
  200.         ld (pipehandle),a
  201.         call setstdouthandle
  202.         pop bc
  203.        
  204.         call readapp ;делает CLOSE ;TODO через loadapp, чтобы дописывать .com и грузить из /bin
  205.        
  206.         if 1==1
  207.         push af
  208.         ld b,a
  209.         ;ld a,(stdinhandle)
  210.         ;ld d,a
  211. pipehandle=$+1
  212.         ld d,0
  213.         ld a,(stdouthandle)
  214.         ld e,a
  215.         ld h,0xff ;rnd
  216. ;b=id, e=stdin, d=stdout, h=stderr        
  217.         OS_SETSTDINOUT
  218.         endif
  219.        
  220.         pop af ;id
  221.  
  222.         ld e,a ;id
  223.         ;ld (waitpid_id),a
  224.         push de
  225.         OS_RUNAPP
  226.        
  227.         ;call execcmd ;can show errors ;a!=0: no such internal command
  228.         ; or a
  229.         ; call nz,callcmd
  230.          call callcmd ;exec or run
  231.         pop de
  232.         ;push af ;a=error
  233.         push de
  234.         ld a,(pipehandle)
  235.         ld b,a
  236.         OS_CLOSEHANDLE ;закрыли источник данных
  237.         pop de
  238.         WAITPID
  239.  
  240.         ld a,(stdouthandle_wasatstart)
  241.         call setstdouthandle
  242. ;закрыть входной файл правой программы
  243.         ;ld a,(pipehandle)
  244.         ;ld b,a
  245.         ;OS_CLOSEHANDLE
  246.  
  247.         ;pop af ;a=error
  248. execcmd_pipe_error
  249.         ret
  250.  
  251. tpipename
  252.         db "z:",0
  253.  
  254. ;;;;;;;;;;;;;;;;;;
  255.        
  256. editcmd_up
  257.         ld de,cmdbuf
  258.         ld hl,oldcmd
  259.         ld bc,MAXCMDSZ+1
  260.         ldir
  261.         ;jp editcmd
  262.  
  263. editcmd
  264.         ld hl,cmdbuf
  265.         call strlen
  266.         ld a,l
  267.         ld (curcmdx),a
  268. editcmd0
  269.         call fixscroll_prcmd
  270.         call cmdcalccurxy
  271.         SETX_;SETXY_
  272.         ;ld e,CURSORCOLOR;0x38
  273.         ;OS_PRATTR ;нарисовать курсор
  274.         call yieldgetkeyloop ;YIELDGETKEYLOOP
  275.          ;ld a,c ;keynolang
  276.         ;push af
  277.         ;call cmdcalccurxy
  278.         ;SETXY_
  279.         ;ld e,COLOR;7
  280.         ;OS_PRATTR ;стереть курсор
  281.         ;pop af
  282.         cp key_enter
  283.         ret z
  284.         cp key_up
  285.         jr z,editcmd_up
  286.          ld hl,editcmd0
  287.          push hl
  288.         ;ld hl,cmdbuf
  289.         cp key_backspace
  290.         jr z,editcmd_backspace
  291.         cp key_left
  292.         jr z,editcmd_left
  293.         cp key_right
  294.         jr z,editcmd_right
  295.         cp key_home
  296.         jr z,editcmd_home
  297.         cp key_end
  298.         jr z,editcmd_end
  299.         cp key_del
  300.         jr z,editcmd_del
  301.         cp 0x20
  302.         ret c ;jr c,editcmdok ;прочие системные кнопки не нужны
  303. ;type in
  304. editcmdtypein
  305.         ld e,a
  306.         ld hl,cmdbuf
  307.         call strlen ;hl=length
  308.         ld bc,MAXCMDSZ
  309.         or a
  310.         sbc hl,bc
  311.         ret nc ;jr nc,editcmdok ;некуда вводить
  312.         call cmdcalctextaddr ;hl=addr, a=curcmdx
  313.         inc a
  314.         ld (curcmdx),a
  315.         jp strinsch ;e=ch
  316.        
  317. editcmd_backspace
  318.         call cmdcalctextaddr ;hl=addr, a=curcmdx
  319.         or a
  320.         ret z ;jr z,editcmdok ;нечего удалять
  321.         dec a
  322.         ld (curcmdx),a
  323.         jp strdelch ;удаляет предыдущий символ
  324.      
  325. editcmd_del
  326.         call cmdcalctextaddr ;hl=addr, a=curcmdx
  327.         inc hl
  328.         jp strdelch ;удаляет предыдущий символ
  329.      
  330. editcmd_left
  331.         ld a,(curcmdx)
  332.         or a
  333.         ret z ;jr z,editcmdok ;некуда влево
  334.         dec a
  335. editcmd_leftq
  336.         ld (curcmdx),a
  337.         ret
  338. editcmd_home
  339.         xor a
  340.         jr editcmd_leftq
  341. editcmd_end
  342.         ld hl,cmdbuf
  343.         call strlen ;hl=length
  344.         ld a,l
  345.         jr editcmd_leftq
  346.  
  347. editcmd_right
  348.         call cmdcalctextaddr ;hl=addr, a=curcmdx
  349.         inc (hl)
  350.         dec (hl)
  351.         ret z ;jr z,editcmdok ;некуда право, стоим на терминаторе
  352.         inc a
  353.         ld (curcmdx),a
  354.         ret
  355.  
  356. getword
  357. ;hl=string
  358. ;de=wordbuf
  359. ;out: hl=terminator/space addr
  360. getword0
  361.         ld a,(hl)
  362.         or a
  363.         jr z,getwordq
  364.         sub ' '
  365.         jr z,getwordq
  366.         ldi
  367.         jp getword0
  368. getwordq
  369.         ;xor a
  370.         ld (de),a
  371.         ret
  372.  
  373. execcmd
  374. ;a=0: command executed
  375. ;a!=0: no such internal command
  376.         ld hl,cmdbuf
  377.         ld a,(hl)
  378.         or a
  379.         ret z
  380.                 ;display $
  381.                 ;display wordbuf
  382.         ld de,wordbuf
  383.         call getword ;hl=terminator/space addr
  384.         call skipspaces
  385.         ld (execcmd_pars),hl
  386.                 inc hl
  387.                 ld a,(wordbuf+1)
  388.                 cp ':'
  389.                 jp nz,execcmd0
  390.                 ld a,(wordbuf+2)
  391.                 or a
  392.                 jp z,cmd_t0
  393. execcmd0
  394.         ld hl,commandslist ;list of internal commands
  395. strcpexec0
  396.         ld c,(hl)
  397.         inc hl
  398.         ld b,(hl)
  399.         inc hl
  400.         ld a,b
  401.         cp -1
  402.         ret z ;jr z,strcpexec_tryrun ;a!=0: no such internal command
  403.         ld de,wordbuf
  404.         push hl
  405.         call strcp
  406.         pop hl
  407.         jr nz,strcpexec_fail
  408.         ld h,b
  409.         ld l,c
  410.         call jphl ;execute command
  411.         xor a
  412.         ret ;a=0: command executed
  413. jphl
  414.         jp (hl) ;run internal command
  415. strcpexec_fail
  416.         ld b,-1 ;чтобы точно найти терминатор
  417.         xor a
  418.         cpir ;найдём обязательно
  419.         jr strcpexec0
  420.  
  421. cmd_start
  422. ;выполнить командную строку по фону (нужно из .bat)
  423.         ld hl,cmdbuf
  424.         ld a,(hl)
  425.         or a
  426.         ret z
  427.         ld de,wordbuf
  428.         call getword ;hl=terminator/space addr
  429.         call skipspaces
  430.         ld de,cmdbuf
  431.         ld bc,MAXCMDSZ+1
  432.         ldir
  433.         call strcpexec_tryrun ;выполнить файл с именем cmdbuf или SYSDIR/cmdbuf и параметрами там, e=id, nz=error, cy=end of .bat
  434.         ret z
  435. execcmd_error
  436.         ld hl,tunknowncommand
  437.         jp cmderror
  438.        
  439. strcpexec_tryrun
  440. ;выполнить файл с именем cmdbuf или SYSDIR/cmdbuf и параметрами там, e=id, nz=error, cy=end of .bat
  441.         call loadapp ;загрузить файл с именем cmdbuf, e=id, nz=error, cy=end of .bat
  442.         ret c ;cy=end of .bat        
  443.         jr nz,execcmd_tryrunerror
  444. execcmd_tryrunok
  445.         ret c ;cy=end of .bat
  446.         push de
  447.         OS_RUNAPP ;e=id
  448.         pop de
  449.          xor a ;z
  450.         ret
  451.  
  452. execcmd_tryrunerror
  453. ;выполнить файл с именем SYSDIR/cmdbuf и параметрами там
  454.         call loadapp_keeppath
  455.         OS_SETSYSDRV
  456.         ld de,sysdir
  457.         push de
  458.         OS_GETPATH
  459.         call loadapp_setoldpath ;TODO из prompt
  460.          ;OS_SETSYSDRV
  461.          ;ld de,wordbuf2
  462.          ;OS_GETPATH
  463.         ;ld de,cmdprompt
  464.         ;OS_CHDIR
  465.         ;call makeprompt
  466.         ;ld de,cmdprompt
  467.         ;OS_CHDIR
  468.         pop hl
  469.         push hl
  470. ;если в конце нет слеша, то добавим:
  471.         ;ld bc,0 ;чтобы точно найти терминатор
  472.         xor a
  473.         ld b,a
  474.         ld c,a;0
  475.         cpir ;найдём обязательно, если длина=0, то bc=-1 и т.д.
  476.         dec hl ;на терминаторе
  477.         dec hl ;перед терминатором
  478.         ld a,'/'
  479.         cp (hl)
  480.         jr z,$+2+5
  481.          inc hl
  482.          ld (hl),a
  483.          inc hl
  484.          ld (hl),0
  485.         pop hl ;sysdir
  486.         call strlen
  487.         ld b,h
  488.         ld c,l ;bc=SYSDIR_size
  489.          push bc ;SYSDIR_size
  490.         ld hl,MAXCMDSZ+1
  491.         or a
  492.         sbc hl,bc
  493.         push hl ;MAXCMDSZ+1-SYSDIR_size
  494. ;bc=SYSDIR_size
  495.         ld hl,cmdbuf+MAXCMDSZ;+1
  496.         or a
  497.         sbc hl,bc
  498.         ld de,cmdbuf+MAXCMDSZ;+1
  499.         pop bc ;MAXCMDSZ+1-SYSDIR_size
  500.         lddr
  501.         ld hl,sysdir
  502.         ld de,cmdbuf
  503.          pop bc ;SYSDIR_size
  504.         ldir ;нельзя strcopy, т.к. не нужен терминатор
  505.          ;ld hl,sysdir
  506.          ;ld de,oldpath
  507.          ;ld bc,MAXPATH_sz;MAXCMDSZ+1
  508.          ;ldir ;TODO рекурсивно (для .bat)
  509.          ;jr $
  510.         call loadapp ;загрузить файл с именем cmdbuf, e=id, nz=error, cy=end of .bat
  511.         jr z,execcmd_tryrunok
  512.         ret ;nz=error
  513.        
  514. openparams
  515. ;open %0 (progname), %1...
  516.         ld hl,cmdbuf
  517.         call strlen
  518.         ld b,h
  519.         ld c,l ;bc=len (without terminator)
  520.         ld hl,cmdbuf
  521.         add hl,bc ;at terminator
  522.         ld de,cmdbuf+MAXCMDSZ ;at last byte of buffer
  523.         inc bc ;bc=len (with terminator)
  524.         lddr
  525.         ex de,hl
  526.         inc hl
  527.         ld de,cmdbuf
  528. chgparams0
  529.         ld a,(hl)
  530.         ld (de),a
  531.         or a
  532.         jr z,chgparams0q
  533.         inc hl
  534.         cp '%'
  535.         jr nz,chgparams0skip
  536.         ld a,(hl)
  537.         ld (de),a
  538.         or a
  539.         jr z,chgparams0q
  540.         inc hl
  541.         sub '0' ;a=param
  542.         cp 10
  543.         jr nc,chgparams0skip ;%%
  544.         push hl
  545.         ld hl,params
  546.         inc a
  547.         ld b,a
  548. chgparams1
  549.         call skipword ;doesn't move at terminator
  550.         call skipspaces ;doesn't move at terminator
  551.         djnz chgparams1
  552. ;hl=param text (end=space or terminator)        
  553. chgparams2
  554.         ld a,(hl)
  555.         or a
  556.         jr z,chgparams2q
  557.         cp ' '
  558.         jr z,chgparams2q
  559.         ld (de),a
  560.         inc hl
  561.         inc de
  562.         djnz chgparams2
  563. chgparams2q
  564.         pop hl
  565.         dec de
  566. chgparams0skip
  567.         inc de
  568.         jr chgparams0
  569. chgparams0q
  570.         ret
  571.  
  572. ;execcmd_or_runprog
  573. ;        call execcmd
  574. ;        or a
  575. ;        ret z
  576. ;        jp callcmd;strcpexec_tryrun ;запускает по фону
  577.  
  578. callcmd
  579. ;call command (cmdbuf) with waiting
  580.         call execcmd ;a!=0: no such internal command
  581.         or a
  582.         ret z ;command executed
  583.         ;call loadapp ;загрузить файл с именем cmdbuf, e=id
  584.         call strcpexec_tryrun ;загрузить файл с именем cmdbuf или SYSDIR/cmdbuf, e=id, nz=error, CY=end of .bat
  585.         ret c
  586.         jp nz,execcmd_error
  587.         ;push de
  588.         ;OS_RUNAPP
  589.         ;pop de
  590.         WAITPID ;не должно быть, если команда была .bat!
  591.         ret
  592.  
  593. loadapp_keeppath
  594.         ld hl,cmdprompt
  595.         ld de,oldpath
  596.         ld bc,MAXPATH_sz;MAXCMDSZ+1
  597.         ldir ;TODO рекурсивно (для .bat)
  598.         ret
  599.  
  600. loadapp_setoldpath
  601.         push de
  602.         ld de,oldpath ;TODO рекурсивно (для .bat)
  603.         OS_CHDIR
  604.         pop de
  605.         xor a
  606.         ret ;Z
  607.        
  608. loadapp
  609. ;out: nz=error, cy=end of .bat, or else e=id
  610.         ld hl,cmdbuf
  611.         ld de,wordbuf
  612.         call getword
  613. ;учесть путь в имени (TODO использовать OS_OPENHANDLE)
  614.         ld hl,wordbuf
  615.         push hl
  616.         call findlastslash. ;de=after last slash or beginning of path
  617.         pop hl
  618.  
  619.         ;push hl
  620. ;ищем точку, проверяем, что после неё стоит .com или .bat
  621. loadapp_finddot0
  622.         ld a,(hl)
  623.         or a
  624.         jr z,loadapp_nodot
  625.         cp '.'
  626.         inc hl
  627.         jr nz,loadapp_finddot0
  628. ;проверяем, что после неё стоит .com или .bat
  629.         ld a,(hl)
  630.         or 0x20
  631.         cp 'b'
  632. ; TODO где проверка на остальные буквы?
  633.         jp z,strcpexec_tryrun_bat
  634. ;считаем, что написано .com (в принципе расширение безразлично - просто запускаем)
  635.         jr loadapp_finddotok
  636. loadapp_nodot
  637. ;a=0
  638.         ld (hl),'.'
  639.         inc hl
  640.         ld (hl),'c'
  641.         inc hl
  642.         ld (hl),'o'
  643.         inc hl
  644.         ld (hl),'m'
  645.         inc hl
  646.         ld (hl),a ;0        
  647. loadapp_finddotok
  648.         ld de,wordbuf ;pop de
  649.         OS_OPENHANDLE
  650.         or a
  651.          push af
  652.         ld a,b
  653.         ld (curhandle),a
  654.          call loadapp_setoldpath
  655.          pop af
  656.         ret nz ;jr nz,execcmd_error ;NC!
  657.         OS_NEWAPP ;на момент создания должна быть включена текущая директория!!!
  658.         or a
  659.         ret nz ;error ;NC!
  660. ;dehl=номера страниц в 0000,4000,8000,c000 нового приложения, b=id, a=error
  661.         push bc ;b=id
  662.         ld a,d
  663.         SETPG32KHIGH
  664.         push de
  665.         push hl
  666.         ld hl,cmdbuf
  667.         ld de,0xc000+COMMANDLINE
  668.         ld bc,COMMANDLINE_sz
  669.         ldir ;command line
  670.         pop hl
  671.         pop de
  672.         call readfile_pages_dehl
  673.  
  674.         ld a,(curhandle)
  675.         ld b,a
  676.         OS_CLOSEHANDLE
  677.         pop de
  678.         ld e,d ;e=id
  679.         xor a
  680.         ret ;Z
  681.      
  682. readapp
  683.         ld a,b
  684.         ld (curhandle),a
  685.        
  686.         OS_NEWAPP ;для первой создаваемой задачи будут созданы первые два пайпа и подключены
  687. ;dehl=номера страниц в 0000,4000,8000,c000 нового приложения, b=id, a=error
  688.         push bc ;b=id
  689.  
  690.         ld a,d
  691.         SETPG32KHIGH
  692.         push de
  693.         push hl
  694.         ld hl,COMMANDLINE ;command line
  695.         call skipword
  696.         call skipspaces ;пропустили первое слово (там было term.com, а дальше, например, cmd.com autoexec.bat)
  697.         ld de,0xc080
  698.         ld bc,128  
  699.         ldir ;command line
  700.         pop hl
  701.         pop de
  702.  
  703.         call readfile_pages_dehl
  704.  
  705.         ld a,(curhandle)
  706.         ld b,a
  707.         OS_CLOSEHANDLE
  708.  
  709.         pop af ;id
  710.         ret
  711.  
  712. skipword
  713. ;hl=string
  714. ;out: hl=terminator/space addr
  715. skipword0
  716.         ld a,(hl)
  717.         or a
  718.         ret z ;jr z,skipwordq
  719.         sub ' '
  720.         ret z ;jr z,skipwordq
  721.         inc hl ;ldi
  722.         jr skipword0
  723.  
  724. readfile_pages_dehl
  725.         ld a,d
  726.         SETPG32KHIGH
  727.         ld a,0xc100/256
  728.         call cmd_loadpage
  729.         ret nz
  730.         ld a,e
  731.         call cmd_loadfullpage
  732.         ret nz
  733.         ld a,h
  734.         call cmd_loadfullpage
  735.         ret nz
  736.         ld a,l
  737. cmd_loadfullpage
  738.         SETPG32KHIGH
  739.         ld a,0xc000/256
  740. cmd_loadpage
  741. ;out: a=error
  742. ;keeps hl,de
  743.         push de
  744.         push hl
  745.         ld d,a
  746.         xor a
  747.         ld l,a
  748.         ld e,a
  749.         sub d
  750.         ld h,a ;de=buffer, hl=size
  751. curhandle=$+1
  752.         ld b,0
  753.         OS_READHANDLE
  754.         pop hl
  755.         pop de
  756.         or a
  757.         ret
  758.      
  759. strcpexec_tryrun_bat
  760.         ;display "strcpexec_tryrun_bat",strcpexec_tryrun_bat
  761. ;out: nz=error, cy=end of .bat
  762. ;open .bat
  763. ;filename in wordbuf
  764.         ld de,wordbuf ;pop de
  765.         OS_OPENHANDLE
  766.         or a
  767.         ld a,b
  768.         ld (curbathandle),a    
  769.         ret nz ;jp nz,execcmd_error ;NC!
  770.        
  771.          ld a,0x3c ;"inc a"
  772.          ld (readbyte_readbuf_last),a
  773.         ld iy,file_buf_end
  774. strcpexec_tryrun_bat0
  775. ;load line to cmdbuf
  776.         ld hl,cmdbuf
  777.         LD (hl),0
  778.         call readstr ;nz=EOF
  779.         push af ;jr nz,strcpexec_tryrun_batq ;чтобы последнюю строку всё-таки выполнить
  780.  
  781.         push iy
  782.         ld hl,cmdbuf
  783.         call prtext
  784.         call prcrlf
  785.         pop iy
  786.        
  787. ;call command in cmdbuf
  788.         push iy
  789.         call openparams
  790.         call execcmd_maybepipes ;callcmd
  791.         pop iy
  792.        
  793.         pop af
  794.         jr z,strcpexec_tryrun_bat0 ;nz=EOF
  795. strcpexec_tryrun_batq
  796. ;close .bat
  797.         ld a,(curbathandle)
  798.         ld b,a
  799.         OS_CLOSEHANDLE
  800.         xor a
  801.          scf ;чтобы на выходе не делать RUNAPP
  802.         ret ;Z
  803.  
  804.         macro READBYTE_A
  805. ;out: z=EOF
  806.         inc ly
  807.         call m,readbyte_readbuf
  808.         ld a,(iy)
  809.         endm
  810.  
  811. readstr
  812. ;out: nz=EOF
  813. ;skips empty lines!
  814.         READBYTE_A ;z=EOF
  815.         jr z,readstrEOF
  816.         cp 0x0d
  817.         jr z,readstr ;empty string - retry
  818.         cp 0x0a
  819.         jr z,readstr ;empty string - retry
  820.         ld b,MAXCMDSZ
  821.         jr readstr0go
  822. readstr0
  823.         READBYTE_A ;z=EOF
  824.         jr z,readstrEOF ;возвращает NZ
  825.         ;jr z,readstrq ;возвращает Z
  826.         cp 0x0d
  827.         jr z,readstrq
  828.         cp 0x0a
  829.         jr z,readstrq
  830. readstr0go
  831.         ld (hl),a
  832.         inc hl
  833.         djnz readstr0
  834. readstrq
  835.         xor a ;Z
  836.         ld (hl),a
  837.         inc hl
  838.         ret ;Z
  839. readstrEOF
  840.         xor a
  841.         ld (hl),a
  842.         inc hl
  843.         dec a
  844.         ret ;NZ
  845.  
  846. readbyte_readbuf
  847. ;out: z=EOF
  848.         push bc
  849.         push de
  850.         push hl
  851.         push ix
  852.          ;jr $
  853.         xor a
  854. readbyte_readbuf_last=$ ;TODO keep if recursive!
  855.         inc a ;/nop(z)=last, inc a(nz)=not last
  856.         jr z,readbyte_readbufq
  857.  
  858.         if 1==1
  859. ;B = file handle, DE = Buffer address, HL = Number of bytes to read
  860. curbathandle=$+1
  861.         ld b,0
  862.         ld de,file_buf
  863.         push de
  864.         ld hl,128
  865.         OS_READHANDLE
  866.         pop iy
  867. ;HL = Number of bytes actually read, A=error
  868.         ;sub 1
  869.         ;sbc a,a ;error=0 => a=255, else a=0 (Z)
  870.         ;jr z,readbyte_readbufq ;error (=>EOF)
  871.          ;jr $
  872.         ld a,l
  873.         or a
  874.         jr z,readbyte_readbufq ;0 bytes (=>EOF)
  875.         jp m,readbyte_readbufq ;128 bytes (NZ no EOF) (not last block)
  876.        
  877.         else ;CP/M-like
  878.        
  879.         ld de,file_buf
  880.         push de
  881.         OS_SETDTA ;set disk transfer address = de
  882.         ld de,fcb_bat
  883.         OS_FREAD
  884.         pop iy
  885.         xor 128 ;a = bytes read
  886.         jr z,readbyte_readbufq
  887.         jp m,readbyte_readbufq ;full block = not last block
  888.        
  889.         endif
  890.        
  891. ;last block: shift data to the end of buf, mark last
  892.         ld c,a ;1..128
  893.         ld b,0 ;nz!
  894.         ld a,b
  895.         ld (readbyte_readbuf_last),a ;last block
  896.         ld hl,file_buf
  897.         add hl,bc
  898.         dec hl ;end of data
  899.         ld de,file_buf+127
  900.         lddr
  901.         inc de
  902.         push de
  903.         pop iy
  904.         ;nz!
  905. readbyte_readbufq
  906. ;iy=addr
  907. ;z=EOF
  908.         pop ix
  909.         pop hl
  910.         pop de
  911.         pop bc
  912.         ret
  913.  
  914. cmd_dir
  915.         ld de,(execcmd_pars)
  916.         ;ld de,emptypath
  917.         OS_OPENDIR
  918.         or a
  919.         ld bc,0 ;nfiles
  920.         jp nz,loaddir2_error
  921. cmd_dir2_0
  922.        push bc
  923.         ld de,filinfo
  924.         OS_READDIR
  925.        pop bc
  926.         or a
  927.         jr nz,loaddir2q
  928.         ld a,(filinfo+FILINFO_FNAME)
  929.         or a
  930.         jr z,loaddir2q
  931.        push bc
  932.         ld ix,(filinfo+FILINFO_FDATE)
  933.         ld hl,(filinfo+FILINFO_FTIME)
  934.         call prdate_time
  935.  
  936.         ld a,' '
  937.         PRCHAR_
  938.  
  939.         ld hl,(filinfo+FILINFO_FSIZE+2)
  940.         exx
  941.         ld hl,(filinfo+FILINFO_FSIZE)
  942.         call prdword
  943.         ld a,' '
  944.         PRCHAR_
  945.  
  946.         ld hl,filinfo+FILINFO_LNAME
  947.         ld a,(hl)
  948.         or a
  949.         jr nz,$+5
  950.         ld hl,filinfo+FILINFO_FNAME
  951.         ;ld c,0 ;c=x
  952.         call prtext
  953. ;c=x
  954.        
  955.         call prcrlf
  956.        pop bc ;nfiles
  957.         inc bc ;nfiles
  958.         or a
  959.         jr cmd_dir2_0
  960. loaddir2_error
  961. loaddir2q
  962. ;bc=nfiles
  963.         ld h,b
  964.         ld l,c
  965.         call prword
  966.         ld hl,t_files_crlf
  967.         jp prtext
  968.  
  969. prdate_time
  970. ;ix=date, hl=time
  971.         ld de,datetimebuf
  972.        push de
  973.        push hl ;time
  974.         ;push ix ;date
  975.         ld a,hx
  976.         srl a
  977.         sub 20
  978.         jr nc,$+4
  979.         add a,100 ;XX century
  980.         call prNNcmd ;year
  981.         ;ld a,'-'
  982.         ;PRCHAR_
  983.          inc de
  984.         ;pop hl
  985.         ld a,lx
  986.         push af
  987.         add ix,ix
  988.         add ix,ix
  989.         add ix,ix
  990.         ld a,hx
  991.         and 0x0f
  992.         call prNNcmd ;month
  993.         ;ld a,'-'
  994.         ;PRCHAR_
  995.          inc de
  996.         pop af
  997.         and 0x1f
  998.         call prNNcmd ;day
  999.  
  1000.         ;ld a,' '
  1001.         ;PRCHAR_
  1002.          inc de
  1003.        pop hl ;time
  1004.         push hl
  1005.         ld a,h
  1006.         rra
  1007.         rra
  1008.         rra
  1009.         and 0x1f
  1010.         call prNNcmd ;hour
  1011.         ;ld a,':'
  1012.         ;PRCHAR_
  1013.          inc de
  1014.         pop hl
  1015.         ld a,l
  1016.         push af
  1017.         add hl,hl
  1018.         add hl,hl
  1019.         add hl,hl
  1020.         ld a,h
  1021.         and 0x3f
  1022.         call prNNcmd ;minute
  1023.         ;ld a,':'
  1024.         ;PRCHAR_
  1025.          inc de
  1026.         pop af
  1027.         add a,a
  1028.         and 0x3f
  1029.         call prNNcmd ;second
  1030.        pop hl
  1031.         ld de,8+1+8
  1032.         jp cmdprNchars
  1033.  
  1034. prNNcmd
  1035. ;a=NN
  1036. ;de=buf
  1037.         ld bc,10+(256*('0'-1))
  1038.         sub c
  1039.         inc b
  1040.         jr nc,$-2
  1041.          ex de,hl
  1042.          ld (hl),b
  1043.          ex de,hl
  1044.          inc de
  1045.         add a,'0'+10
  1046.          ld (de),a
  1047.          inc de
  1048.         ret
  1049.  
  1050. datetimebuf
  1051.         db "00-00-00 00:00:00"
  1052.        
  1053. skipspaces
  1054. ;hl=string
  1055. ;out: hl=after last space
  1056.         ld a,(hl)
  1057.         cp ' '
  1058.         ret nz
  1059.         inc hl
  1060.         jr skipspaces
  1061.  
  1062. strcopy
  1063. ;hl->de
  1064. strcopy0
  1065.         ld a,(hl)
  1066.         ldi
  1067.         or a
  1068.         jr nz,strcopy0
  1069.         ret
  1070.  
  1071. cmd_cd
  1072. execcmd_pars=$+1
  1073.         ld hl,0
  1074.         ld a,(hl)
  1075.         or a
  1076.         jr z,cmd_error_nopars
  1077.         ex de,hl ;de=path
  1078.         OS_CHDIR
  1079.         or a
  1080.         ret z
  1081.         ld hl,twrongpath
  1082.         jp cmderror
  1083.        
  1084. cmd_error_nopars
  1085.         ld hl,tnopars
  1086.         jp cmderror
  1087. cmd_error_notenoughpars
  1088.         ld hl,tnotenoughpars
  1089.         jp cmderror
  1090.  
  1091. cmd_md
  1092.         ld hl,(execcmd_pars)
  1093.         ld a,(hl)
  1094.         or a
  1095.         jr z,cmd_error_nopars
  1096.         ex de,hl ;de=dirname
  1097.         OS_MKDIR
  1098.         or a
  1099.         ret z
  1100. cmd_error_cantmakedir
  1101.         ld hl,tcantmakedir
  1102.         jp cmderror
  1103.        
  1104. cmd_del
  1105.         ld hl,(execcmd_pars)
  1106.         ld a,(hl)
  1107.         or a
  1108.         jr z,cmd_error_nopars
  1109.         ex de,hl
  1110.         OS_DELETE
  1111.         or a
  1112.         ret z
  1113. cmd_error_wrongfile
  1114.         ld hl,twrongfile
  1115.         jp cmderror
  1116.        
  1117. cmd_ren
  1118.         ld hl,(execcmd_pars)
  1119.         ld a,(hl)
  1120.         or a
  1121.         jr z,cmd_error_nopars
  1122.         ld de,wordbuf
  1123.         call getword ;hl=terminator/space addr
  1124.         call skipspaces
  1125.         ld a,(hl)
  1126.         or a
  1127.         jr z,cmd_error_notenoughpars
  1128.         ld de,wordbuf2
  1129.         call getword ;hl=terminator/space addr
  1130.         ld de,wordbuf
  1131.         ld hl,wordbuf2
  1132.         OS_RENAME
  1133.         or a
  1134.         ret z
  1135.         ld hl,tcantrename
  1136.         jp cmderror
  1137.        
  1138. cmd_copy
  1139.         ld hl,(execcmd_pars)
  1140.         ld a,(hl)
  1141.         or a
  1142.         jr z,cmd_error_nopars
  1143.         ld de,filenamebuf;wordbuf
  1144.         call getword ;hl=terminator/space addr
  1145.         call skipspaces
  1146.         ld a,(hl)
  1147.         or a
  1148.         jr z,cmd_error_notenoughpars
  1149.         ld de,filenamebuf2;wordbuf2
  1150.         call getword ;hl=terminator/space addr
  1151.  
  1152.         ld de,filenamebuf;wordbuf ;de=drive/path/file
  1153.         OS_OPENHANDLE
  1154.         or a
  1155.         jp nz,cmd_error_wrongfile
  1156.         ld a,b
  1157.         ld (close_file1_handle),a
  1158.         ld hl,close_file1
  1159.         push hl
  1160.        
  1161.         ld de,filenamebuf2;wordbuf2 ;de=drive/path/file
  1162.         OS_CREATEHANDLE
  1163.         or a
  1164.         jp nz,cmd_error_cant_copy
  1165.         ld a,b
  1166.         ld (cmd_copy_close_file2_handle),a
  1167.         ld hl,cmd_copy_close_file2
  1168.         push hl
  1169. cmd_copy0
  1170.         ld hl,copybuf_sz
  1171.         ld de,copybuf
  1172.         ld a,(close_file1_handle)
  1173.         ld b,a
  1174. ;B = file handle, DE = Buffer address, HL = Number of bytes to read
  1175.         push de
  1176.         OS_READHANDLE
  1177. ;HL = Number of bytes actually read, A=error
  1178.         pop de
  1179.         ld a,h
  1180.         or l
  1181.         ret z ;0 bytes remain
  1182.         ld a,(cmd_copy_close_file2_handle)
  1183.         ld b,a
  1184. ;B = file handle, DE = Buffer address, HL = Number of bytes to write
  1185.         OS_WRITEHANDLE
  1186.         jr cmd_copy0
  1187.        
  1188. close_file1
  1189. close_file1_handle=$+1
  1190.         ld b,0
  1191.         OS_CLOSEHANDLE
  1192.         ret
  1193.        
  1194. cmd_copy_close_file2
  1195. cmd_copy_close_file2_handle=$+1
  1196.         ld b,0
  1197.         OS_CLOSEHANDLE
  1198.         ld de,filenamebuf;wordbuf;filenametext
  1199.         OS_GETFILETIME ;ix=date, hl=time
  1200.         ld de,filenamebuf2;wordbuf2
  1201.         OS_SETFILETIME
  1202.         ret      
  1203.        
  1204. cmd_error_cant_copy
  1205.         ld hl,tcantcopy
  1206.         jp cmderror
  1207.  
  1208. cmd_rem
  1209.         ret
  1210.        
  1211. cmd_mem
  1212.         ld hl,tfree
  1213.         call prtext
  1214.         ld b,0
  1215. cmd_mem0
  1216.         push bc
  1217.         OS_NEWPAGE
  1218.         pop bc
  1219.         or a
  1220.         jr nz,cmd_mem_del
  1221.         inc b
  1222.         push de
  1223.         jr cmd_mem0
  1224. cmd_mem_del
  1225.         ld c,b
  1226.         inc b
  1227.         dec b
  1228.         jr z,cmd_mem_q
  1229. cmd_mem_del0
  1230.         pop de
  1231.         push bc
  1232.         OS_DELPAGE
  1233.         pop bc
  1234.         djnz cmd_mem_del0
  1235. cmd_mem_q
  1236. ;c=free pages
  1237.         ld l,c
  1238.         ld h,0
  1239.         call prword
  1240.         jp prcrlf
  1241.  
  1242. cmd_drop
  1243.         ld hl,(execcmd_pars)
  1244.         ld a,(hl)
  1245.         or a
  1246.         jp z,cmd_error_nopars
  1247.         xor a
  1248.         ld d,a
  1249. cmd_drop_par0
  1250.         add a,d
  1251.         ld e,a ;id
  1252.         add a,a
  1253.         add a,a
  1254.         add a,e
  1255.         add a,a
  1256.         ld d,a ;d=e*10
  1257.         ld a,(hl)
  1258.         inc hl
  1259.         sub '0'
  1260.         cp 10
  1261.         jr c,cmd_drop_par0
  1262.         ;e=id
  1263.         OS_DROPAPP
  1264.         or a
  1265.         ret z
  1266.         ld hl,twrongid
  1267.         jp cmderror
  1268.        
  1269. cmd_proc
  1270.         ld e,1 ;no id 0
  1271. cmd_proc0
  1272.         push de
  1273.         OS_GETAPPMAINPAGES ;d,e,h,l=pages in 0000,4000,8000,c000, c=flags
  1274.         or a
  1275.         jr nz,cmd_proc_skip
  1276.         ld a,d
  1277.         pop de
  1278.         push de
  1279.          push bc
  1280.         push af
  1281.         ex de,hl
  1282.         ld h,0
  1283.         call prword
  1284.         ld a,' '
  1285.         PRCHAR_
  1286.         pop af ;main page
  1287.         SETPG32KHIGH
  1288.          pop bc ;c=flags
  1289.          push bc
  1290.          bit factive,c
  1291.          ld a,'-'
  1292.          jr z,$+4
  1293.          ld a,'+'
  1294.          PRCHAR_
  1295.          pop bc
  1296.          push bc
  1297.          bit fgfx,c
  1298.          ld a,' '
  1299.          jr z,$+4
  1300.          ld a,'g'
  1301.          PRCHAR_
  1302.          pop bc
  1303.           bit fwaiting,c
  1304.           ld a,' '
  1305.           jr z,$+4
  1306.           ld a,'w'
  1307.           PRCHAR_
  1308.          ld a,' '
  1309.          PRCHAR_
  1310.         ld hl,0xc000+COMMANDLINE
  1311.         call prtext
  1312.         call prcrlf
  1313. cmd_proc_skip
  1314.         pop de
  1315.         inc e
  1316.         ld a,e
  1317.         inc a ;no id 0xff
  1318.         jr nz,cmd_proc0
  1319.         ret
  1320.  
  1321. cmd_date
  1322.         OS_GETTIME ;ix=date, hl=time
  1323.         call prdate_time
  1324.         jp prcrlf
  1325.        
  1326. cmd_t0
  1327.         ld a,(wordbuf)
  1328.         and 0xdf
  1329.         sub 'A'
  1330.         call cmdsetdrive
  1331.         or a
  1332.         ret z
  1333.         ld hl,tdrivenotfound
  1334.         jp cmderror
  1335.        
  1336. cmderror
  1337.         push hl
  1338.         ld de,_ERRORCOLOR
  1339.         SETCOLOR_
  1340.         pop hl
  1341.         call prtext
  1342.         ld de,_COLOR
  1343.         SETCOLOR_
  1344. prcrlf
  1345.         ;ld a,0x0d
  1346.         ;PRCHAR_
  1347.         ;ld a,0x0a
  1348.         ;PRCHAR_
  1349.         ld hl,crlfbuf
  1350.         ld de,2
  1351.         jp cmdprNchars
  1352. crlfbuf
  1353.         db 0x0d,0x0a
  1354.        
  1355. cmdsetdrive
  1356.         ld e,a
  1357.         OS_SETDRV
  1358.         ret
  1359.  
  1360. cmd_type
  1361.         ld hl,(execcmd_pars)
  1362.         ld a,(hl)
  1363.         or a
  1364.         jp z,cmd_error_nopars
  1365.         ld de,wordbuf
  1366.         call getword ;hl=terminator/space addr
  1367.  
  1368.         ld de,wordbuf ;de=drive/path/file
  1369.         OS_OPENHANDLE
  1370.         or a
  1371.         jp nz,cmd_error_wrongfile
  1372.         ld a,b
  1373.         ld (close_file1_handle),a
  1374.         ld hl,close_file1
  1375.         push hl
  1376.        
  1377. cmd_type0
  1378. ;B = file handle, DE = Buffer address, HL = Number of bytes to read
  1379.         push bc
  1380.         ld de,cmd_type_buf
  1381.         ld hl,1
  1382.         OS_READHANDLE
  1383. ;HL = Number of bytes actually read, A=error
  1384.         pop bc
  1385.         ld a,h
  1386.         or l
  1387.         ret z ;0 bytes remain
  1388.         push bc
  1389. cmd_type_buf=$+1
  1390.         ld a,0
  1391.         PRCHAR_
  1392.         pop bc
  1393.         jr cmd_type0
  1394.        
  1395. cmd_tee
  1396. ;tee filename
  1397. ;copy sdtin to filename and to stdout
  1398.         ld hl,(execcmd_pars)
  1399.         ld a,(hl)
  1400.         or a
  1401.         jp z,cmd_error_nopars
  1402.         ld de,wordbuf
  1403.         call getword ;hl=terminator/space addr
  1404.  
  1405.         ld de,wordbuf ;de=drive/path/file
  1406.         OS_CREATEHANDLE
  1407.         or a
  1408.         jp nz,cmd_error_wrongfile
  1409.         ld a,b
  1410.         ld (close_file1_handle),a
  1411.         ld hl,close_file1
  1412.         push hl
  1413.        
  1414. cmd_tee0
  1415.         push bc
  1416.         GETKEY_
  1417.         ld (cmd_type_buf),a
  1418.         pop bc
  1419.         ret c ;input pipe closed
  1420.         ld a,(cmd_type_buf)
  1421.         PRCHAR_
  1422. ;B = file handle, DE = Buffer address, HL = Number of bytes to read
  1423.         push bc
  1424.         ld de,cmd_type_buf
  1425.         ld hl,1 ;TODO набивать буфер, потом писать много
  1426.         OS_WRITEHANDLE
  1427. ;HL = Number of bytes actually written, A=error?
  1428.         pop bc
  1429.         jr cmd_tee0
  1430.        
  1431. cmd_echo
  1432.         ld hl,(execcmd_pars)
  1433.         call prtext
  1434.         jp prcrlf
  1435.        
  1436. cmd_pause
  1437.         call yieldgetkeyloop ;YIELDGETKEYLOOP
  1438.          cp key_redraw
  1439.          jr z,cmd_pause
  1440.         ret
  1441.  
  1442. cmd_copydir
  1443.         ld hl,(execcmd_pars)
  1444.         ld a,(hl)
  1445.         or a
  1446.         jp z,cmd_error_nopars
  1447.         ld de,wordbuf
  1448.         call getword ;hl=terminator/space addr
  1449.         call skipspaces
  1450.         ld a,(hl)
  1451.         or a
  1452.         jp z,cmd_error_notenoughpars
  1453.         ld de,wordbuf2
  1454.         call getword ;hl=terminator/space addr
  1455.  
  1456. cmd_copydir_go
  1457.         ld hl,wordbuf
  1458.         call prtext
  1459.         ld a,'>'
  1460.         PRCHAR_
  1461.         ld hl,wordbuf2
  1462.         call prtext
  1463.         call prcrlf
  1464.        
  1465.         ld de,wordbuf2
  1466.         OS_MKDIR
  1467.  
  1468.         ld bc,0 ;номер файла в директории
  1469. cmd_copydir0
  1470.         push bc
  1471.         ld de,cmdprompt
  1472.         OS_CHDIR
  1473.         ld de,wordbuf
  1474.         OS_CHDIR
  1475.         pop bc
  1476.         push bc
  1477.         call getdirfcb_bc
  1478.         pop bc
  1479.         ret nz ;jr nz,cmd_copydirq
  1480.  
  1481.         ld a,(fcb_filename)
  1482.         cp '.'
  1483.         jr z,cmd_copydir0_skip
  1484.         ld a,(fcb+FCB_FATTRIB)
  1485.         and FATTRIB_DIR
  1486.         jr nz,cmd_copydir0_recursive
  1487.        
  1488.         push bc
  1489.         ld hl,fcb_filename
  1490.         ld de,filenamebuf
  1491.         call cpmname_to_dotname
  1492.         call open_setdir2_create_copy
  1493.         pop bc
  1494. cmd_copydir0_skip
  1495.         inc bc
  1496.         jr cmd_copydir0
  1497.  
  1498.         macro STRPUSH
  1499. ;hl=string addr
  1500.         xor a
  1501.         push af
  1502.          ld a,(hl)
  1503.          inc hl
  1504.          or a
  1505.          push af
  1506.         jr nz,$-4
  1507.         pop af
  1508. ;в стеке лежит \0, текст (без терминатора)
  1509.         endm
  1510.        
  1511.         macro STRPOP
  1512. ;hl=string addr
  1513.         ld d,h
  1514.         ld e,l
  1515.          pop af
  1516.          ld (hl),a
  1517.          inc hl
  1518.          or a
  1519.         jr nz,$-4
  1520.         ex de,hl
  1521.         call strmirror
  1522.         endm
  1523.        
  1524. strmirror
  1525. ;hl=string addr
  1526.         ld d,h
  1527.         ld e,l
  1528.         call strlen
  1529.         ld b,h
  1530.         ld c,l
  1531.          ld a,b
  1532.          or c
  1533.          ret z
  1534. ;de=начало, bc=hl=длина
  1535.         ;ld h,b
  1536.         ;ld l,c
  1537.         add hl,de ;hl=конец+1
  1538.         srl b
  1539.         rr c ;bc=wid/2
  1540. mirrorbytes0
  1541.         dec hl
  1542.         ld a,(de)
  1543.         ldi
  1544.         dec hl
  1545.         ld (hl),a
  1546.         jp pe,mirrorbytes0
  1547.         ret
  1548.        
  1549. cmd_copydir0_recursive
  1550. ;recursive copydir <wordbuf>/<filename> <wordbuf2>/<filename>
  1551.         push bc
  1552.         ld hl,wordbuf
  1553.         STRPUSH
  1554.         ld hl,wordbuf2
  1555.         STRPUSH
  1556.         ;ld hl,cmdprompt
  1557.         ;STRPUSH
  1558.  
  1559.         ld hl,wordbuf
  1560.         ld bc,0
  1561.         xor a
  1562.         cpir
  1563.         dec hl ;hl=terminator addr
  1564.         ld (hl),'/'
  1565.         inc hl
  1566.         ex de,hl
  1567.         ld hl,fcb_filename
  1568.         ;ld de,filenamebuf
  1569.         call cpmname_to_dotname
  1570.        
  1571.         ld hl,wordbuf2
  1572.         ld bc,0
  1573.         xor a
  1574.         cpir
  1575.         dec hl ;hl=terminator addr
  1576.         ld (hl),'/'
  1577.         inc hl
  1578.         ex de,hl
  1579.         ld hl,fcb_filename
  1580.         ;ld de,filenamebuf
  1581.         call cpmname_to_dotname
  1582.        
  1583.         call cmd_copydir_go
  1584.  
  1585. ;restore dirnames, file #
  1586.         ;ld hl,cmdprompt
  1587.         ;STRPOP
  1588.         ld hl,wordbuf2
  1589.         STRPOP
  1590.         ld hl,wordbuf
  1591.         STRPOP
  1592.         pop bc
  1593.         jp cmd_copydir0_skip
  1594.        
  1595. open_setdir2_create_copy
  1596.         ;open....
  1597.         ld de,filenamebuf;wordbuf ;de=drive/path/file
  1598.         OS_OPENHANDLE
  1599.         or a
  1600.         jp nz,cmd_error_wrongfile
  1601.         ld a,b
  1602.         ld (close_file1_handle),a
  1603.         ld hl,close_file1
  1604.         push hl
  1605.  
  1606.         ;set dir2...
  1607.         ld de,cmdprompt
  1608.         OS_CHDIR
  1609.         ld de,wordbuf2
  1610.         OS_CHDIR
  1611.  
  1612.         ;create....
  1613.         ld de,filenamebuf;2;wordbuf2 ;de=drive/path/file
  1614.         OS_CREATEHANDLE
  1615.         or a
  1616.         jp nz,cmd_error_cant_copy
  1617.         ld a,b
  1618.         ld (cmd_copy_close_file2_handle),a
  1619.         ld hl,cmd_copy_close_file2
  1620.         push hl
  1621.  
  1622.         ;copy....
  1623.         jp cmd_copy0
  1624.        
  1625.        
  1626. getdirfcb_bc
  1627. ;bc=file number in current dir to read to fcb
  1628. ;nz=error
  1629.         push bc
  1630.         ld de,fcb
  1631.         OS_SETDTA
  1632.         ld de,fcbmask
  1633.         OS_FSEARCHFIRST ;de = pointer to unopened FCB (filename with ????????), read matching FCB to DTA
  1634.         pop bc
  1635.         or a
  1636.         ret nz
  1637.        
  1638. getdirfcb_bc0
  1639.         ld a,b
  1640.         or c
  1641.         ret z
  1642.         dec bc
  1643.         push bc
  1644.         ld de,fcb
  1645.         OS_SETDTA
  1646.         ld de,fcbmask
  1647.         OS_FSEARCHNEXT ;(NOT CP/M!!!)de = pointer to unopened FCB (filename with ????????), read matching FCB to DTA
  1648.         pop bc
  1649.         or a
  1650.         jr z,getdirfcb_bc0
  1651.         ret        
  1652.        
  1653. ;hl = poi to filename in string
  1654. findlastslash.
  1655. nfopenfnslash.
  1656.         ld d,h
  1657.         ld e,l ;de = after last slash
  1658. ;find last slash
  1659. nfopenfnslash0.
  1660.         ld a,[hl]
  1661.         inc hl
  1662.         or a
  1663.         jr z,nfopenfnslashq.
  1664.         cp '/'
  1665.         jr nz,nfopenfnslash0.
  1666.         jr nfopenfnslash.
  1667. nfopenfnslashq.
  1668. ;de = after last slash
  1669.         ret
  1670.  
  1671. commandslist
  1672.         dw cmd_dir
  1673.         db "ls",0
  1674.         dw cmd_dir
  1675.         db "dir",0
  1676.         dw cmd_del
  1677.         db "del",0
  1678.         dw cmd_del
  1679.         db "rm",0
  1680.         dw cmd_exit
  1681.         db "exit",0
  1682.         dw cmd_cd
  1683.         db "cd",0
  1684.         dw cmd_copy
  1685.         db "copy",0
  1686.         dw cmd_copy
  1687.         db "cp",0
  1688.         dw cmd_rem
  1689.         db "rem",0
  1690.         dw cmd_md
  1691.         db "md",0
  1692.         dw cmd_md
  1693.         db "mkdir",0
  1694.         dw cmd_ren
  1695.         db "ren",0
  1696.         dw cmd_ren
  1697.         db "mv",0
  1698.         dw cmd_mem
  1699.         db "mem",0
  1700.         dw cmd_mem
  1701.         db "free",0
  1702.         dw cmd_proc
  1703.         db "proc",0
  1704.         dw cmd_proc
  1705.         db "ps",0
  1706.         dw cmd_tee
  1707.         db "tee",0
  1708.         dw cmd_drop
  1709.         db "drop",0
  1710.         dw cmd_drop
  1711.         db "kill",0
  1712.         dw cmd_date
  1713.         db "date",0
  1714.         dw cmd_start
  1715.         db "start",0
  1716.         dw cmd_copydir
  1717.         db "copydir",0
  1718.         dw cmd_type
  1719.         db "type",0
  1720.         dw cmd_type
  1721.         db "cat",0
  1722.         dw cmd_echo
  1723.         db "echo",0
  1724.         dw cmd_pause
  1725.         db "pause",0
  1726.        
  1727.         dw -1 ;конец таблицы команд
  1728.  
  1729. tunknowncommand
  1730.         db "Unknown command",0
  1731. tdrivenotfound
  1732.         db "Drive not found",0
  1733. tnopars
  1734.         db "No parameters",0
  1735. tnotenoughpars
  1736.         db "Not enough parameters",0
  1737. tcantcopy
  1738.         db "Can't copy",0
  1739. tcantwrite
  1740.         db "Can't write",0
  1741. twrongpath
  1742.         db "Wrong path",0
  1743. twrongfile
  1744.         db "Wrong file",0
  1745. tcantmakedir
  1746.         db "Can't make the directory",0
  1747. tcantrename
  1748.         db "Can't rename",0
  1749. t_files_crlf
  1750.         db " files",0x0d,0x0a,0
  1751. tfree
  1752.         db "free pages=",0
  1753. twrongid
  1754.         db "Wrong ID",0
  1755.        
  1756. ;oldtimer
  1757. ;        dw 0
  1758.        
  1759.         db 0 ;для запарывания на случай отсутствия пути
  1760. wordbuf
  1761.         ds MAXCMDSZ+1
  1762. wordbuf2
  1763.         ds MAXCMDSZ+1
  1764. filenamebuf
  1765.         ds MAXCMDSZ+1
  1766. filenamebuf2
  1767.         ds MAXCMDSZ+1
  1768.  
  1769. fcb
  1770.         ds FCB_sz
  1771. fcb_filename=fcb+FCB_FNAME        
  1772.  
  1773. fcbmask
  1774.         db 0
  1775.         db "???????????"
  1776.         ds FCB_sz-11-1
  1777. fcbmask_filename=fcbmask+FCB_FNAME
  1778.  
  1779. fcb2
  1780.         ds FCB_sz
  1781. fcb2_filename=fcb2+FCB_FNAME        
  1782.  
  1783. fcb_bat
  1784.         ds FCB_sz
  1785. fcb_bat_filename=fcb_bat+FCB_FNAME        
  1786.  
  1787. oldpath ;TODO убрать (когда будет loadapp через OPENHANDLE)
  1788.         ds MAXPATH_sz;MAXCMDSZ+1
  1789.  
  1790. sysdir
  1791.         ds MAXPATH_sz
  1792.        
  1793. oldcmd
  1794.         ds MAXCMDSZ+1
  1795.        
  1796. copybuf
  1797.         ds 4096;128 ;можно сколько угодно
  1798. copybuf_sz=$-copybuf
  1799.  
  1800. params
  1801.         ds MAXCMDSZ+1
  1802.  
  1803. filinfo
  1804.         ds FILINFO_sz
  1805.  
  1806. emptypath
  1807.         db 0
  1808.  
  1809.         align 256
  1810. file_buf
  1811.         ds 128 ;buf for reading .bat
  1812. file_buf_end=$-1
  1813.  
  1814.         include "prdword.asm"
  1815.         include "cmdpr.asm"
  1816.         include "../_sdk/stdio.asm"
  1817.  
  1818. cmd_end
  1819.  
  1820.         ;display "cmd size ",/d,cmd_end-cmd_begin," bytes"
  1821.  
  1822.         savebin "cmd.com",cmd_begin,cmd_end-cmd_begin
  1823.        
  1824.         LABELSLIST "..\..\us\user.l"
  1825.