Login

Subversion Repositories NedoOS

Rev

Rev 1845 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

        ;TODO %~dp0 (драйв и путь запуска)
;TODO %~t1 (дата-время 1-го параметра)
;TODO goto и метки :label
;TODO if ???==??? goto
;TODO for
;TODO PATH (где хранить? должна подгружаться при старте новой копии cmd)

        DEVICE ZXSPECTRUM128
        include "../_sdk/sys_h.asm"
DEBUG=0

MAXCMDSZ=COMMANDLINE_sz-1;127 ;не считая терминатора
;txtscrhgt=25
txtscrwid=80
CMDLINEY=24

_COLOR=0x0007;7
_ERRORCOLOR=0x0009;0x42

        org PROGSTART
cmd_begin
        ld sp,0x4000 ;не должен опускаться ниже 0x3b00! иначе возможна порча OS        
        call initstdio

        OS_GETSTDINOUT ;e=stdin, d=stdout, h=stderr
        ld a,d
        ld (stdouthandle_wasatstart),a
        ld a,e
        ld (stdinhandle_wasatstart),a

        OS_GETMAINPAGES
;dehl=номера страниц в 0000,4000,8000,c000
        push hl
        OS_DELPAGE
        pop hl
        push hl
        ld e,h
        OS_DELPAGE
        pop hl
        ld e,l
        OS_DELPAGE

        ld hl,COMMANDLINE ;command line
        push hl
        ld de,params
        call strcopy
       
        pop hl ;ld hl,COMMANDLINE ;command line
        ld de,wordbuf
        call getword
        call skipspaces
        ld (cmdlineword2),hl
        ld a,(hl)
        or a
        jr z,cmd_interactive
;command line = "cmd <command to run>"
        ld de,cmdbuf
        call strcopy
       
        call makeprompt ;иначе запустится из неправильной директории
       
        call execcmd_maybepipes ;can show errors ;a!=0: no such internal command
        ;or a
        ;call nz,callcmd;strcpexec_tryrun ;запускает по фону
        YIELD ;чтобы запущенная задача успела захватить фокус ;???
;если командная строка была со словом autoexec.bat в параметре, то это начальный запуск autoexec.bat, из него надо входить в интерактивный режим
        ld hl,tautoexecbat
cmdlineword2=$+1
        ld de,0
        call strcp ;z=yes
        jr z,cmd_interactive
cmd_exit
lastresult=$+1
       ld hl,0
        QUIT
       
tautoexecbat
        db "autoexec.bat",0
               
version_text
                defb "Command line interpreter. rev.",0
               
cmd_interactive
        ld hl,version_text
        call prtext
        ifdef SVNREVISION
                ld de,(SVNREVISION + 1 >> 16) & 0xffff
                ld hl,(SVNREVISION + 1) & 0xffff
                call prdword_dehl
                call prcrlf      
        endif
       
cmdmainloop
       if DEBUG
        call printcurdir
       endif
        call makeprompt
        call editcmd
        call prcrlf
       
        ld hl,cmdbuf
        ld de,oldcmd
        ld bc,MAXCMDSZ+1
        ldir

        call execcmd_maybepipes
        ;or a
        ;call nz,callcmd;strcpexec_tryrun ;запускает по фону
        xor a
        ld (cmdbuf),a
        ld (curcmdscroll),a
        jp cmdmainloop

execcmd_maybepipes
;out:a!=0: no such internal command
;если command pars >file, то create file, перенаправить вывод в него, execcmd, close file, перенаправить вывод обратно
        ld hl,cmdbuf
        ld a,'|'
        ld bc,MAXCMDSZ
        cpir
        jp z,execcmd_pipe

        ld hl,cmdbuf
        ld a,'<'
        ld bc,MAXCMDSZ
        cpir
        jr z,execcmd_changestdin ;jr nz,cmd_noexeccmdtofile

        ld hl,cmdbuf
        ld a,'>'
        ld bc,MAXCMDSZ
        cpir
        jp nz,callcmd ;exec or run ;execcmd_or_runprog ;jr nz,cmd_noexeccmdtofile
         cp (hl)
         jr nz,redirect_noadd
         ld (hl),' '
         xor a
redirect_noadd
         ld (redirect_mode),a
;change stdout
        dec hl
        ld (hl),0
        inc hl
         call skipspaces
        ex de,hl ;de=filename
redirect_mode=$+1
         ld a,0 ;0=open, else create
         or a
         jr nz,redirect_create
        push de
        OS_OPENHANDLE
        pop de
        or a
        jr nz,redirect_create
        push bc
        OS_GETFILESIZE
        pop bc
        push bc
        OS_SEEKHANDLE ;b=file handle, dehl=offset
        pop bc
        jr redirect_openq
redirect_create
        OS_CREATEHANDLE
redirect_openq
        ld a,b
        ld (execcmdtofile_handle),a
        call setstdouthandle
;changestdin_stdout_execcmd
        ;call execcmd ;can show errors ;a!=0: no such internal command
        ; or a
        ; call nz,callcmd
         call callcmd ;exec or run
        ;push af
;команда выполнилась в блокирующем режиме и вышла
execcmdtofile_handle=$+1
        ld b,0
        OS_CLOSEHANDLE ;закрыли выходной файл
stdouthandle_wasatstart=$+1
        ld a,0
        call setstdouthandle
;stdinhandle_wasatstart=$+1
;        ld a,0
;        call setstdinhandle

        ;pop af
        ret
        ;jr cmd_noexeccmdtofileq
;cmd_noexeccmdtofile
;        jp execcmd ;a!=0: no such internal command
;cmd_noexeccmdtofileq
;        ret

execcmd_changestdin
        dec hl
        ld (hl),0
        inc hl
         call skipspaces
        ex de,hl ;de=filename
        OS_OPENHANDLE
        ld a,b
        ;ld (execcmdtofile_changestdin_handle),a
        call setstdinhandle
        call setstdinout
        ;jr changestdin_stdout_execcmd
        ;call execcmd ;can show errors ;a!=0: no such internal command
        ; or a
        ; call nz,callcmd
         call callcmd ;exec or run
        ;push af
;команда выполнилась в блокирующем режиме и вышла (или запустилась программа по фону)

;execcmdtofile_changestdin_handle=$+1
;        ld b,0
;        OS_CLOSEHANDLE ;закрыли входной файл программы
;stdouthandle_wasatstart=$+1
;        ld a,0
;        call setstdouthandle
stdinhandle_wasatstart=$+1
        ld a,0
        call setstdinhandle
        call setstdinout

        ;pop af
        ret
        ;jr cmd_noexeccmdtofileq

execcmd_pipe
;cmd |app
        dec hl
        ld (hl),0
        inc hl
         call skipspaces
        ;hl=right app filename
        ld (rightapp_filename),hl
        push hl
        call skipword
        ld (rightapp_filename_end),hl
        ld a,(hl)
        ld (rightapp_filename_endchar),a
        ld (hl),0
        pop hl
       
        ex de,hl ;de=right app filename

        OS_OPENHANDLE
        or a
        jr nz,execcmd_pipe_error

        push bc ;b=right app file handle
        ld de,tpipename
        OS_CREATEHANDLE
        ld a,b
        ld (pipehandle),a
        call setstdouthandle
        pop bc ;b=right app file handle
       
        call readapp ;out: dehl=номера страниц в 0000,4000,8000,c000 нового приложения, b=id, a=error ;делает CLOSE ;TODO через loadapp, чтобы дописывать .com и грузить из /bin
        push bc ;b=id
;dehl=номера страниц в 0000,4000,8000,c000 нового приложения, b=id, a=error
        ld a,d
        SETPGC000
rightapp_filename_end=$+1
        ld hl,0
rightapp_filename_endchar=$+1
        ld (hl),0
rightapp_filename=$+1
        ld hl,0
        ld de,0xc000+COMMANDLINE
        ld bc,COMMANDLINE_sz
        ldir ;command line      
        pop bc ;b=id
        push bc
pipehandle=$+1
        ld e,0 ;stdin for right app
        ld a,(stdouthandle_wasatstart)
        ld d,a ;stdout for right app
        ld h,0xff ;rnd
;b=id, e=stdin, d=stdout, h=stderr        
        OS_SETSTDINOUT
        pop af ;id
        ld e,a ;e=id
        ;ld (waitpid_id),a
        push de ;e=id
        OS_RUNAPP
       
        ;call execcmd ;can show errors ;a!=0: no such internal command
        ; or a
        ; call nz,callcmd
         call callcmd ;exec or run
        pop de ;e=id
        ;push af ;a=error
        push de ;e=id
        ld a,(pipehandle)
        ld b,a
        OS_CLOSEHANDLE ;закрыли источник данных
        pop de ;e=id
       ;call waitpid_keepresult
        ;WAITPID ;hl=result
        ;ld (lastresult),hl
        ;call prword_hl_crlf

        ld a,(stdouthandle_wasatstart)
        call setstdouthandle
;закрыть входной файл правой программы
        ;ld a,(pipehandle)
        ;ld b,a
        ;OS_CLOSEHANDLE

        ;pop af ;a=error
execcmd_pipe_error
        ret

tpipename
        db "z:",0

;;;;;;;;;;;;;;;;;;
       
editcmd_up
        xor a
        ld (curcmdscroll),a
        ld de,cmdbuf
        ld hl,oldcmd
        ld bc,MAXCMDSZ+1
        ldir
        ;jp editcmd

editcmd
        ld hl,cmdbuf
        call strlen
        ld a,l
        ld (curcmdx),a
editcmd0
        call fixscroll_prcmd
        call cmdcalccurxy
        SETX_;SETXY_
        ;ld e,CURSORCOLOR;0x38
        ;OS_PRATTR ;нарисовать курсор
        call yieldgetkeyloop ;YIELDGETKEYLOOP
       ;push af
       ;ld a,r
       ;out (0xfe),a
       ;pop af
         ;ld a,c ;keynolang
        ;push af
        ;call cmdcalccurxy
        ;SETXY_
        ;ld e,COLOR;7
        ;OS_PRATTR ;стереть курсор
        ;pop af
        cp key_enter
        ret z
        cp key_up
        jr z,editcmd_up
         ld hl,editcmd0
         push hl
        ;ld hl,cmdbuf
        cp key_backspace
        jr z,editcmd_backspace
        cp key_left
        jr z,editcmd_left
        cp key_right
        jr z,editcmd_right
        cp key_home
        jr z,editcmd_home
        cp key_end
        jr z,editcmd_end
        cp key_del
        jr z,editcmd_del
        cp 0x20
        ret c ;jr c,editcmdok ;прочие системные кнопки не нужны
;type in
editcmdtypein
        ld e,a
        ld hl,cmdbuf
        call strlen ;hl=length
        ld bc,MAXCMDSZ
        or a
        sbc hl,bc
        ret nc ;jr nc,editcmdok ;некуда вводить
        call cmdcalctextaddr ;hl=addr, a=curcmdx
        inc a
        ld (curcmdx),a
        jp strinsch ;e=ch
       
editcmd_backspace
        call cmdcalctextaddr ;hl=addr, a=curcmdx
        or a
        ret z ;jr z,editcmdok ;нечего удалять
        dec a
        ld (curcmdx),a
        jp strdelch ;удаляет предыдущий символ
     
editcmd_del
        call cmdcalctextaddr ;hl=addr, a=curcmdx
        inc hl
        jp strdelch ;удаляет предыдущий символ
     
editcmd_left
        ld a,(curcmdx)
        or a
        ret z ;jr z,editcmdok ;некуда влево
        dec a
editcmd_leftq
        ld (curcmdx),a
        ret
editcmd_home
        xor a
        jr editcmd_leftq
editcmd_end
        ld hl,cmdbuf
        call strlen ;hl=length
        ld a,l
        jr editcmd_leftq

editcmd_right
        call cmdcalctextaddr ;hl=addr, a=curcmdx
        inc (hl)
        dec (hl)
        ret z ;jr z,editcmdok ;некуда право, стоим на терминаторе
        inc a
        ld (curcmdx),a
        ret

getword
;hl=string
;de=wordbuf
;out: hl=terminator/space addr
getword0
        ld a,(hl)
        or a
        jr z,getwordq
        sub ' '
        jr z,getwordq
        ldi
        jp getword0
getwordq
        ;xor a
        ld (de),a
        ret

execcmd
;a=0: command executed
;a!=0: no such internal command
        ld hl,cmdbuf
        ld a,(hl)
        or a
        ret z
                ;display $
                ;display wordbuf
        ld de,wordbuf
        call getword ;hl=terminator/space addr
        call skipspaces
        ld (execcmd_pars),hl
                inc hl
                ld a,(wordbuf+1)
                cp ':'
                jp nz,execcmd0
                ld a,(wordbuf+2)
                or a
                jp z,cmd_t0
execcmd0
        ld hl,commandslist ;list of internal commands
strcpexec0
        ld c,(hl)
        inc hl
        ld b,(hl)
        inc hl
        ld a,b
        cp -1
        ret z ;jr z,strcpexec_tryrun ;a!=0: no such internal command
        ld de,wordbuf
        push hl
        call strcp
        pop hl
        jr nz,strcpexec_fail
        ld h,b
        ld l,c
        call jphl ;execute command
        xor a
        ret ;a=0: command executed
jphl
        jp (hl) ;run internal command
strcpexec_fail
        ld b,-1 ;чтобы точно найти терминатор
        xor a
        cpir ;найдём обязательно
        jr strcpexec0

cmd_start
;выполнить командную строку по фону (нужно из .bat)
        ld hl,cmdbuf
        ld a,(hl)
        or a
        ret z
        ld de,wordbuf
        call getword ;hl=terminator/space addr
        call skipspaces
        ld de,cmdbuf
        ld bc,MAXCMDSZ+1
        ldir
        call strcpexec_tryrun ;выполнить файл с именем cmdbuf или SYSDIR/cmdbuf и параметрами там, e=id, nz=error, cy=end of .bat
        ret z
execcmd_error
        ld hl,tunknowncommand
        jp cmderror
       
strcpexec_tryrun
;выполнить файл с именем cmdbuf или SYSDIR/cmdbuf и параметрами там, e=id, nz=error, cy=end of .bat
        call loadapp ;загрузить файл с именем cmdbuf, e=id, nz=error, cy=end of .bat
        ret c ;cy=end of .bat        
        jr nz,execcmd_tryrunerror
execcmd_tryrunok
        ret c ;cy=end of .bat
        if 1==1
       push de
        ld b,e ;id
        ld a,(stdinhandle)
        ld e,a
        ld a,(stdouthandle)
        ld d,a
        ld h,0xff ;rnd
;b=id, e=stdin, d=stdout, h=stderr        
        OS_SETSTDINOUT
       pop de
        endif
        push de        
        OS_RUNAPP ;e=id
        pop de
         xor a ;z
        ret

execcmd_tryrunerror
;выполнить файл с именем SYSDIR/cmdbuf и параметрами там (через loadapp)
        call loadapp_keeppath
        OS_SETSYSDRV
        ld de,sysdir
        push de
        OS_GETPATH
        call loadapp_setoldpath ;TODO из prompt
         ;OS_SETSYSDRV
         ;ld de,wordbuf2
         ;OS_GETPATH
        ;ld de,cmdprompt
        ;OS_CHDIR
        ;call makeprompt
        ;ld de,cmdprompt
        ;OS_CHDIR
        pop hl
        push hl
;если в конце нет слеша, то добавим:
        ;ld bc,0 ;чтобы точно найти терминатор
        xor a
        ld b,a
        ld c,a;0
        cpir ;найдём обязательно, если длина=0, то bc=-1 и т.д.
        dec hl ;на терминаторе
        dec hl ;перед терминатором
        ld a,'/'
        cp (hl)
        jr z,$+2+5
         inc hl
         ld (hl),a
         inc hl
         ld (hl),0
        pop hl ;sysdir
        call strlen
        ld b,h
        ld c,l ;bc=SYSDIR_size
         push bc ;SYSDIR_size
        ld hl,MAXCMDSZ+1
        or a
        sbc hl,bc
        push hl ;MAXCMDSZ+1-SYSDIR_size
;bc=SYSDIR_size
        ld hl,cmdbuf+MAXCMDSZ;+1
        or a
        sbc hl,bc
        ld de,cmdbuf+MAXCMDSZ;+1
        pop bc ;MAXCMDSZ+1-SYSDIR_size
        lddr
        ld hl,sysdir
        ld de,cmdbuf
         pop bc ;SYSDIR_size
        ldir ;нельзя strcopy, т.к. не нужен терминатор
         ;ld hl,sysdir
         ;ld de,oldpath
         ;ld bc,MAXPATH_sz;MAXCMDSZ+1
         ;ldir ;TODO рекурсивно (для .bat)
         ;jr $
        call loadapp ;загрузить файл с именем cmdbuf, e=id, nz=error, cy=end of .bat
        jr z,execcmd_tryrunok
        ret ;nz=error
       
openparams
;open %0 (progname), %1...
        ld hl,cmdbuf
        call strlen
        ld b,h
        ld c,l ;bc=len (without terminator)
        ld hl,cmdbuf
        add hl,bc ;at terminator
        ld de,cmdbuf+MAXCMDSZ ;at last byte of buffer
        inc bc ;bc=len (with terminator)
        lddr
        ex de,hl
        inc hl
        ld de,cmdbuf
chgparams0
        ld a,(hl)
        ld (de),a
        or a
        jr z,chgparams0q
        inc hl
        cp '%'
        jr nz,chgparams0skip
        ld a,(hl)
        ld (de),a
        or a
        jr z,chgparams0q
        inc hl
        sub '0' ;a=param
        cp 10
        jr nc,chgparams0skip ;%%
        push hl
        ld hl,params
        inc a
        ld b,a
chgparams1
        call skipword ;doesn't move at terminator
        call skipspaces ;doesn't move at terminator
        djnz chgparams1
;hl=param text (end=space or terminator)        
chgparams2
        ld a,(hl)
        or a
        jr z,chgparams2q
        cp ' '
        jr z,chgparams2q
        ld (de),a
        inc hl
        inc de
        djnz chgparams2
chgparams2q
        pop hl
        dec de
chgparams0skip
        inc de
        jr chgparams0
chgparams0q
        ret

;execcmd_or_runprog
;        call execcmd
;        or a
;        ret z
;        jp callcmd;strcpexec_tryrun ;запускает по фону

callcmd
;call command (cmdbuf) with waiting
        call execcmd ;a!=0: no such internal command
        or a
        ret z ;command executed
        ;call loadapp ;загрузить файл с именем cmdbuf, e=id
        call strcpexec_tryrun ;загрузить файл с именем cmdbuf или SYSDIR/cmdbuf, e=id, nz=error, CY=end of .bat
        ret c
        jp nz,execcmd_error
        ;push de
        ;OS_RUNAPP
        ;pop de
waitpid_keepresult
        WAITPID ;не должно быть, если команда была .bat!
       ld (lastresult),hl
;hl=result
        ret
        ;jp prword_hl_crlf

loadapp_keeppath
        ld hl,cmdprompt
        ld de,oldpath
        ld bc,MAXPATH_sz;MAXCMDSZ+1
        ldir ;TODO рекурсивно (для .bat)
        ret

loadapp_setoldpath
        push de
        ld de,oldpath ;TODO рекурсивно (для .bat)
        OS_CHDIR
        pop de
        xor a
        ret ;Z
       
loadapp
;out: nz=error, cy=end of .bat, or else e=id
        ld hl,cmdbuf
        ld de,wordbuf
        call getword
;учесть путь в имени (TODO использовать OS_OPENHANDLE)
        ld hl,wordbuf
        push hl
        call findlastslash. ;de=after last slash or beginning of path
        pop hl

        ;push hl
;ищем точку, проверяем, что после неё стоит .com или .bat
loadapp_finddot0
        ld a,(hl)
        or a
        jr z,loadapp_nodot
        cp '.'
        inc hl
        jr nz,loadapp_finddot0
;проверяем, что после неё стоит .com или .bat
        ld (exthlpointer),hl
        ld a,(hl)
        or 0x20
        cp 'b'
; TODO где проверка на остальные буквы?
        jp z,strcpexec_tryrun_bat
;считаем, что написано .com (в принципе расширение безразлично - просто запускаем)
        jr loadapp_finddotok1
loadapp_nodot
;a=0
        ld (hl),'.'
        inc hl
        ld (exthlpointer),hl
        ld (hl),'c'
        inc hl
        ld (hl),'o'
        inc hl
        ld (hl),'m'
        inc hl
        ld (hl),a ;0        
loadapp_finddotok
        call open_file_exec
        jp z,fileopenok
        ld hl,(exthlpointer)  
        ld (hl),'b'
        inc hl
        ld (hl),'a'
        inc hl
        ld (hl),'t'
        inc hl
        xor a
        ld (hl),a ;0
        ;ret nz ;jr nz,execcmd_error ;NC!
        jp strcpexec_tryrun_bat

loadapp_finddotok1
        call open_file_exec
        ret nz ;jr nz,execcmd_error ;NC!
fileopenok
        OS_NEWAPP ;на момент создания должна быть включена текущая директория!!!
        or a
        ret nz ;error ;NC!
;dehl=номера страниц в 0000,4000,8000,c000 нового приложения, b=id, a=error
        push bc ;b=id
        ld a,d
        SETPGC000
        push de
        push hl
        ld hl,cmdbuf
        ld de,0xc000+COMMANDLINE
        ld bc,COMMANDLINE_sz
        ldir ;command line
        pop hl
        pop de
        call readfile_pages_dehl

        ld a,(curhandle)
        ld b,a
        OS_CLOSEHANDLE
        pop de
        ld e,d ;e=id
        xor a
        ret ;Z
open_file_exec
        ld de,wordbuf ;pop de
        OS_OPENHANDLE
        or a
        push af
        ld a,b
        ld (curhandle),a
         ;call loadapp_setoldpath
       if DEBUG
         call printcurdir
         ;call yieldgetkeyloop
       endif
        pop af
        ret
exthlpointer
        dw 0000
        dw 0000    

readapp
        ld a,b
        ld (curhandle),a
       
        OS_NEWAPP ;для первой создаваемой задачи будут созданы первые два пайпа и подключены
;dehl=номера страниц в 0000,4000,8000,c000 нового приложения, b=id, a=error
        push bc ;b=id

        ld a,d
        SETPGC000
        push de
        push hl
        ld hl,COMMANDLINE ;command line
        call skipword
        call skipspaces ;пропустили первое слово (там было term.com, а дальше, например, cmd.com autoexec.bat)
        ld de,0xc080
        ld bc,128  
        ldir ;command line
        pop hl
        pop de

        push de
        push hl
        call readfile_pages_dehl
       push af
        ld a,(curhandle)
        ld b,a
        OS_CLOSEHANDLE
       pop af ;error
        pop hl
        pop de

        pop bc ;id
        ret

skipword
;hl=string
;out: hl=terminator/space addr
skipword0
        ld a,(hl)
        or a
        ret z ;jr z,skipwordq
        sub ' '
        ret z ;jr z,skipwordq
        inc hl ;ldi
        jr skipword0

readfile_pages_dehl
        ld a,d
        SETPGC000
        ld a,0xc100/256
        call cmd_loadpage
        ret nz
        ld a,e
        call cmd_loadfullpage
        ret nz
        ld a,h
        call cmd_loadfullpage
        ret nz
        ld a,l
cmd_loadfullpage
        SETPGC000
        ld a,0xc000/256
cmd_loadpage
;out: a=error
;keeps hl,de
        push de
        push hl
        ld d,a
        xor a
        ld l,a
        ld e,a
        sub d
        ld h,a ;de=buffer, hl=size
curhandle=$+1
        ld b,0
        OS_READHANDLE
        pop hl
        pop de
        or a
        ret
     
strcpexec_tryrun_bat
        ;display "strcpexec_tryrun_bat",strcpexec_tryrun_bat
;out: nz=error, cy=end of .bat
;open .bat
;filename in wordbuf
        ld de,wordbuf ;pop de
        OS_OPENHANDLE
        or a
        ld a,b
        ld (curbathandle),a    
        ret nz ;jp nz,execcmd_error ;NC!
       
         ld a,0x3c ;"inc a"
         ld (readbyte_readbuf_last),a
        ld iy,file_buf_end
strcpexec_tryrun_bat0
;load line to cmdbuf
        ld hl,cmdbuf
        LD (hl),0
        call readstr ;nz=EOF
        push af ;jr nz,strcpexec_tryrun_batq ;чтобы последнюю строку всё-таки выполнить

        push iy
        ld hl,cmdbuf
        call prtext
        call prcrlf
        pop iy
       
;call command in cmdbuf
        push iy
        call openparams
        call execcmd_maybepipes ;callcmd
        pop iy
       
        pop af
        jr z,strcpexec_tryrun_bat0 ;nz=EOF
strcpexec_tryrun_batq
;close .bat
        ld a,(curbathandle)
        ld b,a
        OS_CLOSEHANDLE
        xor a
         scf ;чтобы на выходе не делать RUNAPP
        ret ;Z

        macro READBYTE_A
;out: z=EOF
        inc ly
        call m,readbyte_readbuf
        ld a,(iy)
        endm

readstr
;out: nz=EOF
;skips empty lines!
        READBYTE_A ;z=EOF
        jr z,readstrEOF
        cp 0x0d
        jr z,readstr ;empty string - retry
        cp 0x0a
        jr z,readstr ;empty string - retry
        ld b,MAXCMDSZ
        jr readstr0go
readstr0
        READBYTE_A ;z=EOF
        jr z,readstrEOF ;возвращает NZ
        ;jr z,readstrq ;возвращает Z
        cp 0x0d
        jr z,readstrq
        cp 0x0a
        jr z,readstrq
readstr0go
        ld (hl),a
        inc hl
        djnz readstr0
readstrq
        xor a ;Z
        ld (hl),a
        inc hl
        ret ;Z
readstrEOF
        xor a
        ld (hl),a
        inc hl
        dec a
        ret ;NZ

readbyte_readbuf
;out: z=EOF
        push bc
        push de
        push hl
        push ix
         ;jr $
        xor a
readbyte_readbuf_last=$ ;TODO keep if recursive!
        inc a ;/nop(z)=last, inc a(nz)=not last
        jr z,readbyte_readbufq

        if 1==1
;B = file handle, DE = Buffer address, HL = Number of bytes to read
curbathandle=$+1
        ld b,0
        ld de,file_buf
        push de
        ld hl,128
        OS_READHANDLE
        pop iy
;HL = Number of bytes actually read, A=error
        ;sub 1
        ;sbc a,a ;error=0 => a=255, else a=0 (Z)
        ;jr z,readbyte_readbufq ;error (=>EOF)
         ;jr $
        ld a,l
        or a
        jr z,readbyte_readbufq ;0 bytes (=>EOF)
        jp m,readbyte_readbufq ;128 bytes (NZ no EOF) (not last block)
       
        else ;CP/M-like
       
        ld de,file_buf
        push de
        OS_SETDTA ;set disk transfer address = de
        ld de,fcb_bat
        OS_FREAD
        pop iy
        xor 128 ;a = bytes read
        jr z,readbyte_readbufq
        jp m,readbyte_readbufq ;full block = not last block
       
        endif
       
;last block: shift data to the end of buf, mark last
        ld c,a ;1..128
        ld b,0 ;nz!
        ld a,b
        ld (readbyte_readbuf_last),a ;last block
        ld hl,file_buf
        add hl,bc
        dec hl ;end of data
        ld de,file_buf+127
        lddr
        inc de
        push de
        pop iy
        ;nz!
readbyte_readbufq
;iy=addr
;z=EOF
        pop ix
        pop hl
        pop de
        pop bc
        ret

cmd_dir
        ld de,(execcmd_pars)
        ;ld de,emptypath
        OS_OPENDIR
        or a
        ld bc,0 ;nfiles
        jp nz,loaddir2_error
cmd_dir2_0
       push bc
        ld de,filinfo
        OS_READDIR
       pop bc
        or a
        jr nz,loaddir2q
        ld a,(filinfo+FILINFO_FNAME)
        or a
        jr z,loaddir2q
       push bc
        ld ix,(filinfo+FILINFO_FDATE)
        ld hl,(filinfo+FILINFO_FTIME)
        call prdate_time

        ld a,' '
        PRCHAR_

        ld hl,(filinfo+FILINFO_FSIZE)
        ld de,(filinfo+FILINFO_FSIZE+2)
        call prdword_dehl
        ld a,' '
        PRCHAR_

        ld hl,filinfo+FILINFO_LNAME
        ld a,(hl)
        or a
        jr nz,$+5
        ld hl,filinfo+FILINFO_FNAME
        ;ld c,0 ;c=x
        call prtext
;c=x
       
        call prcrlf
       pop bc ;nfiles
        inc bc ;nfiles
        or a
        jr cmd_dir2_0
loaddir2_error
loaddir2q
;bc=nfiles
        ld h,b
        ld l,c
        call prword
        ld hl,t_files_crlf
        jp prtext

prdate_time
;ix=date, hl=time
        ld de,datetimebuf
       push de
       push hl ;time
        ;push ix ;date
        ld a,hx
        srl a
        sub 20
        jr nc,$+4
        add a,100 ;XX century
        call prNNcmd ;year
        ;ld a,'-'
        ;PRCHAR_
         inc de
        ;pop hl
        ld a,lx
        push af
        add ix,ix
        add ix,ix
        add ix,ix
        ld a,hx
        and 0x0f
        call prNNcmd ;month
        ;ld a,'-'
        ;PRCHAR_
         inc de
        pop af
        and 0x1f
        call prNNcmd ;day

        ;ld a,' '
        ;PRCHAR_
         inc de
       pop hl ;time
        push hl
        ld a,h
        rra
        rra
        rra
        and 0x1f
        call prNNcmd ;hour
        ;ld a,':'
        ;PRCHAR_
         inc de
        pop hl
        ld a,l
        push af
        add hl,hl
        add hl,hl
        add hl,hl
        ld a,h
        and 0x3f
        call prNNcmd ;minute
        ;ld a,':'
        ;PRCHAR_
         inc de
        pop af
        add a,a
        and 0x3f
        call prNNcmd ;second
       pop hl
        ld de,8+1+8
        jp cmdprNchars

prNNcmd
;a=NN
;de=buf
        ld bc,10+(256*('0'-1))
        sub c
        inc b
        jr nc,$-2
         ex de,hl
         ld (hl),b
         ex de,hl
         inc de
        add a,'0'+10
         ld (de),a
         inc de
        ret

datetimebuf
        db "00-00-00 00:00:00"
       
skipspaces
;hl=string
;out: hl=after last space
        ld a,(hl)
        cp ' '
        ret nz
        inc hl
        jr skipspaces

strcopy
;hl->de
strcopy0
        ld a,(hl)
        ldi
        or a
        jr nz,strcopy0
        ret

cmd_cd
execcmd_pars=$+1
        ld hl,0
        ld a,(hl)
        or a
        jr z,cmd_error_nopars
        ex de,hl ;de=path
        OS_CHDIR
        or a
        ret z
        ld hl,twrongpath
        jp cmderror
       
cmd_error_nopars
        ld hl,tnopars
        jp cmderror
cmd_error_notenoughpars
        ld hl,tnotenoughpars
        jp cmderror

cmd_md
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jr z,cmd_error_nopars
        ex de,hl ;de=dirname
        OS_MKDIR
        or a
        ret z
cmd_error_cantmakedir
        ld hl,tcantmakedir
        jp cmderror
       
cmd_del
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jr z,cmd_error_nopars
        ex de,hl
        OS_DELETE
        or a
        ret z
cmd_error_wrongfile
        ld hl,twrongfile
        jp cmderror
       
cmd_ren
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jr z,cmd_error_nopars
        ld de,wordbuf
        call getword ;hl=terminator/space addr
        call skipspaces
        ld a,(hl)
        or a
        jr z,cmd_error_notenoughpars
        ld de,wordbuf2
        call getword ;hl=terminator/space addr
        ld de,wordbuf
        ld hl,wordbuf2
       ld a,(de)
       cp '*'
       jr z,cmd_ren_star
        OS_RENAME
        or a
        ret z
cmd_ren_star_error
        ld hl,tcantrename
        jp cmderror
cmd_ren_star
       cp (hl)
       jr nz,cmd_ren_star_error
;поддерживаем только переименование вида ren *.ext1 *.ext2
        inc hl
        inc de
        ld a,(de)
       cp '.'
       jr nz,cmd_ren_star_error
       cp (hl)
       jr nz,cmd_ren_star_error
        inc hl
        inc de
;de,hl указывают на ext1, ext2
        ld (cmd_ren_star_ext1),de
        ld (cmd_ren_star_ext2),hl
        ld de,emptypath
        OS_OPENDIR
;проверяем все файлы в текущей директории на соответствие filename.ext1
;если совпало, то переименовываем в filename.ext2
cmd_ren_star0
        ld de,filinfo
;de=buf for FILINFO (if no LNAME, use FNAME), 0x00 in FILINFO_FNAME = end dir
        OS_READDIR
;out in A=error(0 - no error, 4 - no more files, other - critical error)
        or a
        ret nz ;todo show N files renamed
        ld hl,filinfo+FILINFO_LNAME ;длинного имени может не быть
        ld a,(hl)
        or a
        jr nz,$+5
         ld hl,filinfo+FILINFO_FNAME
       push hl ;from name
        call findlastdot
;de=after last dot
cmd_ren_star_ext1=$+1
        ld hl,0
        call strcp ;z=yes
       pop hl ;from name
        jr nz,cmd_ren_star0

        ;ld hl,filinfo+FILINFO_LNAME
       push hl ;from name
        ld de,filenamebuf
       push de
        call strcopy
       pop hl ;to name
       push hl
        call findlastdot
;de=after last dot in toname
cmd_ren_star_ext2=$+1
        ld hl,0
        call strcopy ;z=yes ;возможное переполнение уходит в filenamebuf2
       pop hl ;to name
       pop de ;from name
        ;ld hl,filenamebuf2 ;to name
        OS_RENAME
;TODO inc count
        jr cmd_ren_star0

cmd_copy
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jp z,cmd_error_nopars
        ld de,filenamebuf;wordbuf
        call getword ;hl=terminator/space addr
        call skipspaces
        ld a,(hl)
        or a
        jp z,cmd_error_notenoughpars
        ld de,filenamebuf2;wordbuf2
        call getword ;hl=terminator/space addr

        ld de,filenamebuf;wordbuf ;de=drive/path/file
        OS_OPENHANDLE
        or a
        jp nz,cmd_error_wrongfile
        ld a,b
        ld (close_file1_handle),a
        ld hl,close_file1
        push hl
       
        ld de,filenamebuf2;wordbuf2 ;de=drive/path/file
        OS_CREATEHANDLE
        or a
        jp nz,cmd_error_cant_copy
        ld a,b
        ld (cmd_copy_close_file2_handle),a
        ld hl,cmd_copy_close_file2
        push hl
cmd_copy0
        ld hl,copybuf_sz
        ld de,copybuf
        ld a,(close_file1_handle)
        ld b,a
;B = file handle, DE = Buffer address, HL = Number of bytes to read
        push de
        OS_READHANDLE
;HL = Number of bytes actually read, A=error
        pop de
        ld a,h
        or l
        ret z ;0 bytes remain
        ld a,(cmd_copy_close_file2_handle)
        ld b,a
;B = file handle, DE = Buffer address, HL = Number of bytes to write
        OS_WRITEHANDLE
        jr cmd_copy0
       
close_file1
close_file1_handle=$+1
        ld b,0
        OS_CLOSEHANDLE
        ret
       
cmd_copy_close_file2
cmd_copy_close_file2_handle=$+1
        ld b,0
        OS_CLOSEHANDLE
        ld de,filenamebuf;wordbuf;filenametext
        OS_GETFILETIME ;ix=date, hl=time
        ld de,filenamebuf2;wordbuf2
        OS_SETFILETIME
        ret      
       
cmd_error_cant_copy
        ld hl,tcantcopy
        jp cmderror

cmd_rem
        ret
       
cmd_mem
        ld hl,tfree
        call prtext
        ld b,0
cmd_mem0
        push bc
        OS_NEWPAGE
        pop bc
        or a
        jr nz,cmd_mem_del
        inc b
        push de
        jr cmd_mem0
cmd_mem_del
        ld c,b
        inc b
        dec b
        jr z,cmd_mem_q
cmd_mem_del0
        pop de
        push bc
        OS_DELPAGE
        pop bc
        djnz cmd_mem_del0
cmd_mem_q
;c=free pages
        ld l,c
        ld h,0
prword_hl_crlf
        call prword
        jp prcrlf

cmd_drop
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jp z,cmd_error_nopars
        xor a
        ld d,a
cmd_drop_par0
        add a,d
        ld e,a ;id
        add a,a
        add a,a
        add a,e
        add a,a
        ld d,a ;d=e*10
        ld a,(hl)
        inc hl
        sub '0'
        cp 10
        jr c,cmd_drop_par0
        ;e=id
        OS_DROPAPP
        or a
        ret z
        ld hl,twrongid
        jp cmderror
       
cmd_proc
        ld e,1 ;no id 0
cmd_proc0
       ld a,e
       ld (cmd_proc_id),a
        push de
        OS_GETAPPMAINPAGES ;d,e,h,l=pages in 0000,4000,8000,c000, c=flags
        or a
        jr nz,cmd_proc_skip
        ld a,d
        pop de ;e=id
        push de ;e=id
         push bc
        push af ;main page
        ex de,hl ;l=id
        ld h,0
        call prword
        ld a,' '
        PRCHAR_
        pop af ;main page
        SETPGC000
         pop bc ;c=flags
         push bc
         bit factive,c
         ld a,'-'
         jr z,$+4
         ld a,'+'
         PRCHAR_
         pop bc
         push bc
         bit fgfx,c
         ld a,' '
         jr z,$+4
         ld a,'g'
         PRCHAR_
         pop bc
          bit fwaiting,c
          ld a,' '
          jr z,$+4
          ld a,'w'
          PRCHAR_
         ld a,' '
         PRCHAR_

        ld de,0 ;e=page, d=number of pages for this id
cmd_proc_countmem0
       push de
        OS_GETPAGEOWNER
        ld a,e
       pop de
cmd_proc_id=$+1
        cp 0
        jr nz,$+3
         inc d
        inc e
        jr nz,cmd_proc_countmem0
        ld l,d ;print number of used pages
        ld h,0
        call prword

         ld a,' '
         PRCHAR_
         
        ld hl,0xc000+COMMANDLINE
        call prtext
        call prcrlf
cmd_proc_skip
        pop de
        inc e
        ld a,e
        inc a ;no id 0xff
        jr nz,cmd_proc0
        ret

cmd_date
        OS_GETTIME ;ix=date, hl=time
        call prdate_time
        jp prcrlf
       
cmd_t0
        ld a,(wordbuf)
        and 0xdf
        sub 'A'
        call cmdsetdrive
        or a
        ret z
        ld hl,tdrivenotfound
        jp cmderror
       
cmderror
        push hl
        ld de,_ERRORCOLOR
        SETCOLOR_
        pop hl
        call prtext
        ld de,_COLOR
        SETCOLOR_
prcrlf
        ;ld a,0x0d
        ;PRCHAR_
        ;ld a,0x0a
        ;PRCHAR_
        ld hl,crlfbuf
        ld de,2
        jp cmdprNchars
crlfbuf
        db 0x0d,0x0a
       
cmdsetdrive
        ld e,a
        OS_SETDRV
        ret

cmd_type
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jp z,cmd_error_nopars
        ld de,wordbuf
        call getword ;hl=terminator/space addr

       if DEBUG
        ld hl,wordbuf
        ld c,0
        call prtext
        call prcrlf
       endif

        ld de,wordbuf ;de=drive/path/file
        OS_OPENHANDLE
        or a
        jp nz,cmd_error_wrongfile
        ld a,b
        ld (close_file1_handle),a
        ld hl,close_file1
        push hl
       
cmd_type0
;B = file handle, DE = Buffer address, HL = Number of bytes to read
        push bc
        ld de,cmd_type_buf
        ld hl,1
        OS_READHANDLE
;HL = Number of bytes actually read, A=error
        pop bc
        ld a,h
        or l
        ret z ;0 bytes remain
        push bc
cmd_type_buf=$+1
        ld a,0
        PRCHAR_
        pop bc
        jr cmd_type0
       
cmd_tee
;tee filename
;copy stdin to filename and to stdout
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jp z,cmd_error_nopars
        ld de,wordbuf
        call getword ;hl=terminator/space addr

        ld de,wordbuf ;de=drive/path/file
        OS_CREATEHANDLE
        or a
        jp nz,cmd_error_wrongfile
        ld a,b
        ld (close_file1_handle),a
        ld hl,close_file1
        push hl
       
cmd_tee0
        push bc
        GETKEY_
        ld (cmd_type_buf),a
        pop bc
        ret c ;input pipe closed
        ld a,(cmd_type_buf)
        PRCHAR_
;B = file handle, DE = Buffer address, HL = Number of bytes to read
        push bc
        ld de,cmd_type_buf
        ld hl,1 ;TODO набивать буфер, потом писать много
        OS_WRITEHANDLE
;HL = Number of bytes actually written, A=error?
        pop bc
        jr cmd_tee0
cmd_uname
                ld hl,nedostr
        call prtext
                OS_GETCONFIG
                push ix
                pop de
                ld h,b
                ld l,c
                call prdword_dehl
        call prcrlf
                ret
nedostr defb "NedoOS Kernel revision ",0

cmd_echo
        ld hl,(execcmd_pars)
        call prtext
        jp prcrlf
               
cmd_pause
        call getkey
        ld hl,(execcmd_pars)
                ld a,(hl)
        or a
        jp z,cmd_pause_infin
                ld de,copybuf
                call strtobyte_hltode
                ld hl,(copybuf) ;умножаем на 48 интов в секунде
                add hl,hl
                add hl,hl
                add hl,hl
                add hl,hl
                ld d,h
                ld e,l
                add hl,hl
                add hl,de
                display "cmd_pause ",cmd_pause
cmd_pause_loop  ;ждем окончания счетчика, либо кнопку
                ld a,h
                or l
                ret z
                push hl
                        ld c,CMD_YIELD
                        call BDOS       ;YIELD
                        call getkey
                pop hl
        ret c ;error
                or a
                ret nz
                dec hl
                jr cmd_pause_loop
               
cmd_pause_infin
        call yieldgetkeyloop ;YIELDGETKEYLOOP
         cp key_redraw
         jr z,cmd_pause
        ret

cmd_copydir
        ld hl,(execcmd_pars)
        ld a,(hl)
        or a
        jp z,cmd_error_nopars
        ld de,wordbuf
        call getword ;hl=terminator/space addr
        call skipspaces
        ld a,(hl)
        or a
        jp z,cmd_error_notenoughpars
        ld de,wordbuf2
        call getword ;hl=terminator/space addr

cmd_copydir_go
        ld hl,wordbuf
        call prtext
        ld a,'>'
        PRCHAR_
        ld hl,wordbuf2
        call prtext
        call prcrlf
       
        ld de,wordbuf2
        OS_MKDIR

        ld bc,0 ;номер файла в директории
cmd_copydir0
        push bc
        ld de,cmdprompt
        OS_CHDIR
        ld de,wordbuf
        OS_CHDIR
        pop bc
        push bc
        call getdirfcb_bc
        pop bc
        ret nz ;jr nz,cmd_copydirq

        ld a,(fcb_filename)
        cp '.'
        jr z,cmd_copydir0_skip
        ld a,(fcb+FCB_FATTRIB)
        and FATTRIB_DIR
        jr nz,cmd_copydir0_recursive
       
        push bc
        ld hl,fcb_filename
        ld de,filenamebuf
        call cpmname_to_dotname
        call open_setdir2_create_copy
        pop bc
cmd_copydir0_skip
        inc bc
        jr cmd_copydir0

        macro STRPUSH
;hl=string addr
        xor a
        push af
         ld a,(hl)
         inc hl
         or a
         push af
        jr nz,$-4
        pop af
;в стеке лежит \0, текст (без терминатора)
        endm
       
        macro STRPOP
;hl=string addr
        ld d,h
        ld e,l
         pop af
         ld (hl),a
         inc hl
         or a
        jr nz,$-4
        ex de,hl
        call strmirror
        endm
       
strmirror
;hl=string addr
        ld d,h
        ld e,l
        call strlen
        ld b,h
        ld c,l
         ld a,b
         or c
         ret z
;de=начало, bc=hl=длина
        ;ld h,b
        ;ld l,c
        add hl,de ;hl=конец+1
        srl b
        rr c ;bc=wid/2
mirrorbytes0
        dec hl
        ld a,(de)
        ldi
        dec hl
        ld (hl),a
        jp pe,mirrorbytes0
        ret
       
cmd_copydir0_recursive
;recursive copydir <wordbuf>/<filename> <wordbuf2>/<filename>
        push bc
        ld hl,wordbuf
        STRPUSH
        ld hl,wordbuf2
        STRPUSH
        ;ld hl,cmdprompt
        ;STRPUSH

        ld hl,wordbuf
        ld bc,0
        xor a
        cpir
        dec hl ;hl=terminator addr
        ld (hl),'/'
        inc hl
        ex de,hl
        ld hl,fcb_filename
        ;ld de,filenamebuf
        call cpmname_to_dotname
       
        ld hl,wordbuf2
        ld bc,0
        xor a
        cpir
        dec hl ;hl=terminator addr
        ld (hl),'/'
        inc hl
        ex de,hl
        ld hl,fcb_filename
        ;ld de,filenamebuf
        call cpmname_to_dotname
       
        call cmd_copydir_go

;restore dirnames, file #
        ;ld hl,cmdprompt
        ;STRPOP
        ld hl,wordbuf2
        STRPOP
        ld hl,wordbuf
        STRPOP
        pop bc
        jp cmd_copydir0_skip
       
open_setdir2_create_copy
        ;open....
        ld de,filenamebuf;wordbuf ;de=drive/path/file
        OS_OPENHANDLE
        or a
        jp nz,cmd_error_wrongfile
        ld a,b
        ld (close_file1_handle),a
        ld hl,close_file1
        push hl

        ;set dir2...
        ld de,cmdprompt
        OS_CHDIR
        ld de,wordbuf2
        OS_CHDIR

        ;create....
        ld de,filenamebuf;2;wordbuf2 ;de=drive/path/file
        OS_CREATEHANDLE
        or a
        jp nz,cmd_error_cant_copy
        ld a,b
        ld (cmd_copy_close_file2_handle),a
        ld hl,cmd_copy_close_file2
        push hl

        ;copy....
        jp cmd_copy0
       
       
getdirfcb_bc
;bc=file number in current dir to read to fcb
;nz=error
        push bc
        ld de,fcb
        OS_SETDTA
        ld de,fcbmask
        OS_FSEARCHFIRST ;de = pointer to unopened FCB (filename with ????????), read matching FCB to DTA
        pop bc
        or a
        ret nz
       
getdirfcb_bc0
        ld a,b
        or c
        ret z
        dec bc
        push bc
        ld de,fcb
        OS_SETDTA
        ld de,fcbmask
        OS_FSEARCHNEXT ;(NOT CP/M!!!)de = pointer to unopened FCB (filename with ????????), read matching FCB to DTA
        pop bc
        or a
        jr z,getdirfcb_bc0
        ret        
       
;hl = poi to filename in string
;out: ;de = after last slash
findlastslash.
nfopenfnslash.
        ld d,h
        ld e,l ;de = after last slash
nfopenfnslash0.
        ld a,[hl]
        inc hl
        or a
        ret z ;jr z,nfopenfnslashq.
        cp '/'
        jr nz,nfopenfnslash0.
        jr nfopenfnslash.
;nfopenfnslashq.
;de = after last slash
        ;ret

;hl = poi to filename in string
;out: ;de = after last slash
findlastdot
nfopenfndot.
        ld d,h
        ld e,l ;de = after last dot
nfopenfndot0.
        ld a,[hl]
        inc hl
        or a
        ret z
        cp '.'
        jr nz,nfopenfndot0.
        jr nfopenfndot.

commandslist
        dw cmd_dir
        db "ls",0
        dw cmd_dir
        db "dir",0
        dw cmd_del
        db "del",0
        dw cmd_del
        db "rm",0
        dw cmd_exit
        db "exit",0
        dw cmd_exit
        db "quit",0
        dw cmd_cd
        db "cd",0
        dw cmd_copy
        db "copy",0
        dw cmd_copy
        db "cp",0
        dw cmd_rem
        db "rem",0
        dw cmd_md
        db "md",0
        dw cmd_md
        db "mkdir",0
        dw cmd_ren
        db "ren",0
        dw cmd_ren
        db "mv",0
        dw cmd_mem
        db "mem",0
        dw cmd_mem
        db "free",0
        dw cmd_proc
        db "proc",0
        dw cmd_proc
        db "ps",0
        dw cmd_tee
        db "tee",0
        dw cmd_drop
        db "drop",0
        dw cmd_drop
        db "kill",0
        dw cmd_date
        db "date",0
        dw cmd_start
        db "start",0
        dw cmd_copydir
        db "copydir",0
        dw cmd_type
        db "type",0
        dw cmd_type
        db "cat",0
        dw cmd_echo
        db "echo",0
        dw cmd_pause
        db "pause",0
        dw cmd_cls
        db "cls",0
        dw cmd_uname
        db "uname",0
       
        dw -1 ;конец таблицы команд


tunknowncommand
        db "Unknown command",0
tdrivenotfound
        db "Drive not found",0
tnopars
        db "No parameters",0
tnotenoughpars
        db "Not enough parameters",0
tcantcopy
        db "Can't copy",0
tcantwrite
        db "Can't write",0
twrongpath
        db "Wrong path",0
twrongfile
        db "Wrong file",0
tcantmakedir
        db "Can't make the directory",0
tcantrename
        db "Can't rename",0
t_files_crlf
        db " files",0x0d,0x0a,0
tfree
        db "free pages=",0
twrongid
        db "Wrong ID",0
       
;oldtimer
;        dw 0
       
        db 0 ;для запарывания на случай отсутствия пути
wordbuf
        ds MAXCMDSZ+1
wordbuf2
        ds MAXCMDSZ+1
filenamebuf
        ds MAXCMDSZ+1
filenamebuf2
        ds MAXCMDSZ+1

fcb
        ds FCB_sz
fcb_filename=fcb+FCB_FNAME        

fcbmask
        db 0
        db "???????????"
        ds FCB_sz-11-1
fcbmask_filename=fcbmask+FCB_FNAME

fcb2
        ds FCB_sz
fcb2_filename=fcb2+FCB_FNAME        

fcb_bat
        ds FCB_sz
fcb_bat_filename=fcb_bat+FCB_FNAME        

oldpath ;TODO убрать (когда будет loadapp через OPENHANDLE)
        ds MAXPATH_sz;MAXCMDSZ+1

sysdir
        ds MAXPATH_sz
       
oldcmd
        ds MAXCMDSZ+1
       
copybuf
        ds 4096;128 ;можно сколько угодно
copybuf_sz=$-copybuf

params
        ds MAXCMDSZ+1

filinfo
        ds FILINFO_sz

emptypath
        db 0

        align 256
file_buf
        ds 128 ;buf for reading .bat
file_buf_end=$-1

        if DEBUG
printcurdir
        ld de,curdir__
        push de
        OS_GETPATH
        pop hl
        ld c,0
        call prtext
        call prcrlf
        ret

curdir__
        ds 256
        endif

prword
        ld de,0
        jp prdword_dehl

        include "../_sdk/prdword.asm"
        include "../_sdk/string.asm"
        include "cmdpr.asm"
        include "../_sdk/stdio.asm"

cmd_cls=clearterm ;print 25 lines of spaces except one

cmd_end

        ;display "cmd size ",/d,cmd_end-cmd_begin," bytes"

        savebin "cmd.com",cmd_begin,cmd_end-cmd_begin
       
        LABELSLIST "../../us/user.l",1