kvisc/vm/ob/command.k

1657 lines
26 KiB
Plaintext

# 1 "command.k"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "command.k"
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
cmdstart:
jmp start
# 1 "crt/crt.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; Limits
;
# 31 "crt/crt.k"
;
; Magic numbers
;
;
; CRT librairies
;
# 1 "./crt/sys.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; SHUTDOWN syscall
;
; End virtual machine
;
Sys.Shutdown := 0x00
;
; EXIT syscall
;
; Return to COMMAND.COM
;
Sys.Exit := 0x01
;
; EXEC syscall
;
; IN
; ax0 = new RIP to load
; ax1 = frame ID to switch to
;
; New frame ID must be higher than current
; frame ID, and cannot be below 5
;
; New CR1 is set so that new RIP corresponds to 1MB
;
Sys.ExecuteInFrame := 0x02
; FIND syscalls
;
; Find file on disk
;
; IN
; ax0 = address of name buffer
; ax1 = size of name buffer
;
; OUT
; rax = # of bytes written in name buffer
; rdx = size of file
;
;
Sys.FindFirst := 0x20
Sys.FindNext := 0x21
;
; OPEN syscall
;
; IN
; ax0 = name string
;
; OUT
; rax = handle of file, or <0 if couldn't open
;
Sys.OpenFile := 0x30
;
; CREATE syscall
;
; IN
; ax0 = name string
;
; OUT
; rax = 0 on success, or <0 if couldn't open
;
Sys.CreateFile := 0x31
;
; REMOVE syscall
;
; IN
; ax0 = name string
;
; OUT
; rax = 0 on success, or <0 if couldn't open
;
Sys.RemoveFile := 0x32
;
; CLOSE syscall
;
; IN
; ax0 = file handle
;
Sys.CloseFile := 0x35
;
; READ syscall
;
; IN
; ax0 = file handle
; ax1 = buffer address
; ax2 = buffer size
;
; OUT
; rax = number of bytes read, <0 on error
;
Sys.ReadFile := 0x38
; Halt mode
Sys.EnterHaltMode := 0x999
# 43 "crt/crt.k" 2
# 1 "./crt/str.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; int strnlen(char *, int)
;
strnlen:
mov rcx, ax1
scasb ax0, zero
sub rax, ax1, rcx
ret
;
; int strlen(char *)
;
strlen:
mov rcx, 0x7AFFFFFF
mov rdx, rcx
scasb ax0, zero
sub rax, rdx, rcx
ret
;
; void strcpy(char *, const char *)
;
strcpy:
.l:
mov rcx, b[ax1]
mov b[ax0], rcx
jrcxz .r
inc ax0
inc ax1
jmp .l
.r:
ret
;
; void strncpy(char *, const char *, int)
;
strncpy:
mov rcx, ax2
jrcxz .r
.l:
mov b[ax0], b[ax1]
inc ax0
inc ax1
loop .l
.r:
ret
;
; void strnzcpy(char *, const char *, int)
;
strnzcpy:
mov rcx, ax2
jrcxz .r
.l:
mov rax, b[ax1]
mov b[ax0], rax
jraxz .r
inc ax0
inc ax1
loop .l
.z:
nul b[ax0]
.r:
ret
;
; int strcmp(const char *str1, const char *str2)
;
; Returns:
; 0 if the contents of both strings are equal
; >0 if the first character that does not match has a greater value in str1 than in str2
; <0 if the first character that does not match has a lower value in str1 than in str2
;
strcmp:
nul rsi
.l:
movzx rax, b[ax0+rsi]
movzx rdx, b[ax1+rsi]
bne rax, rdx, .r
; both zero?
add rcx, rax, rdx
jrcxz .r
inc rsi
jmp .l
.r:
sub rax, rdx
ret
;
; int strncmp(const char *str1, const char *str2, int maxn)
;
strncmp:
mov rcx, ax2
jrcxz .r
.l:
movzx rax, b[ax0]
movzx rdx, b[ax1]
bne rax, rdx, .r
inc ax0
inc ax1
loop .l
.r:
sub rax, rdx
ret
;
; char *strchrnul(const char *str, int ch)
;
strchrnul:
mov rcx, 0x7AFFFFFF
scasb ax0, ax1
mov rax, ax0
ret
;
; char *strchr(const char *str, int ch)
;
strchr:
mov rcx, 0x7AFFFFFF
scasb ax0, ax1
bnz b[ax0], .r
nul rax
ret
.r:
mov rax, ax0
ret
;
; void strrev(char *buf, const char *str)
;
; buf and src must NOT overlap
;
strrev:
bzr b[ax1], .z
; save str's location
mov rsi, ax1
; go to str's end, just before
; the null terminator
mov rcx, 0x7AFFFFFF
scasb ax1, zero
dec ax1
.l:
; copy, going backward though str
; and forward through buf
mov b[ax0], b[ax1]
beq ax1, rsi, .r
inc ax0
dec ax1
jmp .l
.r:
nul b[ax0+1]
ret
.z:
nul b[ax0]
ret
;
; void strrev2(char *str)
;
; Inverses str
;
strrev2:
bzr b[ax0], .r
mov ax1, ax0
; go to str's end, just before
; the null terminator
mov rcx, 0x7AFFFFFF
scasb ax1, zero
dec ax1
; increase ax0 while decreasing ax1, performing exchanges
.l:
blteu ax1, ax0, .r
xchg b[ax0], b[ax1]
inc ax0
dec ax1
jmp .l
.r:
ret
# 44 "crt/crt.k" 2
# 1 "./crt/mem.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; void memcpy(void *, const void *, int)
;
memcpy:
mov rcx, ax2
jrcxz .r
.l:
sub rdx, ax2, rcx
mov b[ax0+rdx], b[ax1+rdx]
loop .l
.r:
ret
;
; void memzero(void *, int)
;
memzero:
mov rcx, ax1
jrcxz .r
.l:
nul b[ax0]
inc ax0
loop .l
.r:
ret
# 45 "crt/crt.k" 2
# 1 "./crt/time.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; struct TIME
; {
; byte sec; +0 (0-59)
; byte min; +1 (0-59)
; byte hour; +2 (0-23)
; byte mday; +3 (0-31)
; byte month; +4 (0-11)
; byte; +5 (pad)
; word year; +6 (0-65536)
; word yday; +8 (0-365)
; word; +10 (pad)
; dword; +12 (pad)
; } 16 bytes
;
;
; int DaysInYear(int year)
;
DaysInYear:
mov rax, 365
; divisible by 4?
rem rcx, ax0, 4
jrcxnz .end
; divisible by 100?
rem rcx, ax0, 100
jrcxnz .leap
; divisible by 400?
rem rcx, ax0, 400
jrcxnz .end
.leap:
inc rax
.end:
ret
;
; TIME *GetTimeUTC(void)
;
GetTimeUTC:
ytime
mov rdi, .buf
; seconds
rem rsi, rax, 60
mov b[rdi], rsi
; minutes
div rsi, rax, 60
rem rsi, 60
mov b[rdi+1], rsi
; hours
div rsi, rax, 3600
rem rsi, 24
mov b[rdi+2], rsi
; month days
div rsi, rax, 3600*24
mov b[rdi+3], rsi
; month
mov b[rdi+4], rbx
; years
mov w[rdi+6], rcx
;
; ydays (TODO)
;
mov rax, .buf
ret
.buf = [24]
# 46 "crt/crt.k" 2
# 1 "./crt/fmt/ltostr.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; void itoa(char *buf, int num, int base)
;
itoa:
mov ax3, 1
jmp ltostr
;
; void utoa(char *buf, int num, int base)
;
utoa:
nul ax3
jmp ltostr
;
; void ltostr(char *buf, int num, int base, bool signed)
;
ltostr:
mov rax, ax0
nul rcx
; make sure base is in [2, 32]
bltu ax2, 2, .bad
bltu 36, ax2, .bad
; deal with zero
bzr ax1, .is_zero
; deal with base 10 signedness
bzr ax3, .conv
bne ax2, 10, .conv ; base 10
shr rcx, ax1, 63 ; extract ax1 sign
jrcxz .conv
neg ax1 ; NEG if negative
; main loop
.conv:
bzr ax1, .fini
rem rdx, ax1, ax2 ; ax1 % base
blt 9, rdx, .nondec ; rdx > 9 ?
add rdx, '0'
jmp .next
.nondec:
add rdx, 55 ; 'A' - 10
.next:
mov b[ax0], rdx
inc ax0
div ax1, ax2
jmp .conv
; add minus flag, null-terminate and reverse
.fini:
jrcxz .cxz
mov b[ax0], '-'
inc ax0
.cxz:
nul b[ax0]
call strrev2, rax
ret
;
; exceptional cases
;
.bad:
mov b[ax0], 0
ret
.is_zero:
mov b[ax0], 48 ; '0'
mov b[ax0+1], 0
ret
# 48 "crt/crt.k" 2
# 1 "./crt/fmt/strtol.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; int strtol(const char *str, int base)
;
; rax = integer extracted from str
; rdx = pointer to first invalid byte
;
strtol:
mov ax2, 1
jmp strtoq
;
; int strtoul(const char *str, int base)
;
; rax = integer extracted from str
; rdx = pointer to first invalid byte
;
strtoul:
nul ax2
jmp strtoq
;
; int strtoq(const char *str, int base, bool signed)
;
; guesses base when 'base'=0
;
strtoq:
nul rax, rsi
mov rdx, ax0
; make sure base is in [2, 32]
beq ax1, 1, .bad
bltu 36, ax1, .bad
; empty string?
bzr b[rdx], .done
.skip_spc:
bne b[rdx], ' ', .no_spc
inc rdx
jmp .skip_spc
.no_spc:
; skip +
bne b[rdx], '+', .no_plus
inc rdx
.no_plus:
; unsigned?
bzr ax2, .unsigned
; parse '-'
bne b[rdx], '-', .unsigned
inc rdx
mov rsi, 1
.unsigned:
; base 0
bzr ax1, .base_0
; base prefix?
bne b[rdx], '0', .main_loop
inc rdx
movzx rcx, b[rdx]
; "0x"/"0b" prefix
jrcxz .done ; "0"
beq rcx, 'x', .parsed_0x
beq rcx, 'b', .parsed_0b
; may be octal, but we don't care
; we accept "0110101010" (despite base=2) for instance
jmp .main_loop
.parsed_0x:
; are we in base 16?
; if not, leave rax = 0 and *rdx = 'x'
bne ax1, 16, .done
; else
inc rdx
jmp .main_loop
.parsed_0b:
; are we in base 2?
; if not, leave rax = 0 and *rdx = 'b'
bne ax1, 2, .done
; else
inc rdx
jmp .main_loop
.base_0:
; guess base
beq b[rdx], '0', .b0_not10
; must be base 10
mov ax1, 10
jmp .main_loop
.b0_not10:
inc rdx
bne b[rdx], 'x', .b0_not16
inc rdx
mov ax1, 16
jmp .main_loop
.b0_not16:
bne b[rdx], 'b', .b0_not2
inc rdx
mov ax1, 2
jmp .main_loop
.b0_not2:
; take octal by default
mov ax1, 8
.main_loop:
movzx rcx, b[rdx]
inc rdx
; between 0 and 9?
bltu rcx, '0', .done
bltu '9', rcx, .not_digit10
; yes
sub rcx, '0'
jmp .next
.not_digit10:
bltu rcx, 'A', .done
bltu 'Z', rcx, .not_digitAZ
sub rcx, 55 ; 'A' - 10
jmp .next
.not_digitAZ:
bltu rcx, 'a', .done
bltu 'z', rcx, .done
sub rcx, 87 ; 'a' - 10
jmp .next
.next:
; too large for base?
blteu ax1, rcx, .done
mul rax, ax1
add rax, rcx
jmp .main_loop
.done:
; negative?
bzr rsi, .r
; yes
neg rax
.r:
ret
.bad:
ret
# 49 "crt/crt.k" 2
# 1 "./crt/fmt/doprnt.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; typedef int (*PUTC)(int ch)
; int doprnt(PUTC putc, int n, const char *fmt, va_list ap)
;
doprnt:
push rbp
mov rbp, rsp
push r12, r13, r14
push r15, r16, r17
mov r12, ax2 ; fmt
mov r14, ax3 ; va_list
mov r15, ax1 ; n
mov r17, ax0 ; putc
nul r16 ; return value
.main_loop:
; find '%' or null-terminator
mov rcx, 0x7AFFFFFF
mov r13, r12
scasb r13, '%'
; everything below r13 is a regular character; print it
.print_regular:
beq r12, r13, .check_modf
call .doput, b[r12]
inc r12
jmp .print_regular
.check_modf:
; did we find a '%' ?
; if not, then we found fmt's null-terminator; we're done
bne b[r12], '%', .epilogue
; we did find a modifier / '%'
mov rax, b[r12+1]
add r12, 2
beq rax, 's', .modf_s
beq rax, 'c', .modf_c
beq rax, 'p', .modf_p
beq rax, 'x', .modf_x
beq rax, 'd', .modf_d
beq rax, 'o', .modf_o
beq rax, 'b', .modf_b
beq rax, '%', .modf_percent
; unrecognized
jmp .bad_modifier
.modf_s:
; get string address
mov r13, q[r14]
add r14, 8
bzr r13, .nullstring
.print_string:
movzx ax0, b[r13]
bzr ax0, .main_loop
inc r13
call .doput
jmp .print_string
.modf_c:
call .doput, q[r14]
add r14, 8
jmp .main_loop
.modf_p:
call .doput, '0'
call .doput, 'x'
; Fallthrough
.modf_x:
mov ax2, 16
jmp .print_number
.modf_d:
mov ax2, 10
jmp .print_number
.modf_o:
mov ax2, 8
jmp .print_number
.modf_b:
mov ax2, 2
jmp .print_number
.print_number:
; allocate itoa conversion buffer
sub rsp, 80
mov r13, rsp
; assume modifier already set up ax2
call itoa, rsp, q[r14]
add r14, 8
.print_itoa_buf:
movzx ax0, b[r13]
bzr ax0, .pib_end_loop
inc r13
call .doput
jmp .print_itoa_buf
.pib_end_loop:
add rsp, 80
jmp .main_loop
.modf_percent:
call .doput, '%'
jmp .main_loop
.bad_modifier:
; print "%?" to clearly indicate that something is wrong
call .doput, '%'
call .doput, '?'
jmp .main_loop
.nullstring:
; %s was passed a NULL
call .doput, '('
call .doput, 'n'
call .doput, 'u'
call .doput, 'l'
call .doput, 'l'
call .doput, ')'
jmp .main_loop
.epilogue:
mov rax, r16
pop r17, r16
pop r15, r14
pop r13, r12
leave
ret
;
; prints ax0
;
.doput:
; update print count
inc r16
; if n==0, don't print
; we follow the C convention that sprintf()-like functions
; should return the number of characters that would have
; been printed/written if 'n' were big enough
bzr r15, .r
; decrement n and print
dec r15
call r17
; did putc fail?
jraxz .r
; yes, so artificially set n=0
nul r15
.r:
ret
# 50 "crt/crt.k" 2
# 1 "./crt/fmt/printf.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
;
; int putc(int ch)
;
putc:
prn ax0
nul rax
ret
;
; int printf(const char *fmt, ...)
;
printf:
mov ax2, ax0
mov ax0, putc
mov ax1, 0x7AFFFFFF
add ax3, rsp, 8
jmp doprnt
;
; int nprintf(const char *fmt, int n, ...)
;
nprintf:
mov ax2, ax0
mov ax0, putc
add ax3, rsp, 8
jmp doprnt
;
; Print a string
; Guaranteed to only affect rcx and ax0
;
print:
.l:
movzx rax, b[ax0]
jraxz .r
prn rax
inc ax0
jmp .l
.r:
ret
;
; Print exactly ax1 characters
;
nprint:
mov rcx, ax1
jrcxz .r
.l:
prn b[ax0]
inc ax0
loop .l
.r:
ret
# 51 "crt/crt.k" 2
exit:
mov rax, Sys.Exit
trap 0
abort:
crash
# 8 "command.k" 2
; COMMAND.COM guarantees that programs
; are always loaded on a 16KB boundary
; This is guaranteed to be the case
; in all future veesions as well
start:
mov esp, 0x104000
mov ebp, zero
call main
mov eax, Sys.EnterHaltMode
trap 0
crash
cmd.veesionstr = "COMMAND.COM, veesion 0.1 (KVISC)\nCopyright (C) 2019, The OS/K Team\nMIT license (permissive), see LICENCE file in source tree"
argbuf.size := 256
argbuf = [argbuf.size]
argv0 = [argbuf.size]
argv1pos = 0
stdin_echoing = 1
prompt = [32]
main:
mov esi, prompt
mov b[esi+0], 'C'
mov b[esi+1], ':'
mov b[esi+2], '\'
mov b[esi+3], '>'
mov b[esi+4], ' '
.print_prompt:
call print, prompt
; empty stuff
call memzero, argbuf, argbuf.size
call memzero, argv0, argbuf.size
nul q[argv1pos]
; call nprint, argv0, argbuf.size
; iterator through argbuf
nul ecx
.input_loop:
pause
pause
pause
; Fill .buf with user input
scan eax
jraxz .input_loop
; ESC key pressed?
beq eax, 0x1B, .handle_EXIT
; backspace character?
bne eax, 8, .handle_input
; anything to delete?
jrcxz .input_loop ; no
; yes, delete it
dec ecx
add edx, ecx, argbuf
nul b[edx]
; update screen
bzr b[stdin_echoing], .input_loop
prn 8
jmp .input_loop
.handle_input:
bzr b[stdin_echoing], .se.z
prn eax
.se.z:
beq eax, 10, .extract_argv0
; when max line length is reached,
; force a newline
beq ecx, argbuf.size, .extract_argv0
; add character to buffer and increase iterator (ecx)
add edx, ecx, argbuf
mov b[edx], eax
inc ecx
; another one
jmp .input_loop
.extract_argv0:
; did we read anything at all?
; if not, just go back to waiting input
jrcxz .print_prompt
; find first whitespace or null-terminator
mov ecx, argbuf.size
mov edx, argbuf
scasb edx, ' '
; argv1 exists? if so, save its position
mov esi, edx
.next_space:
mov ecx, b[esi]
jrcxz .do_extract
; skip spaces
bne ecx, ' ', .not_a_space
inc esi
jmp .next_space
.not_a_space:
; if we're here, we found a
; non-zero non-space character
mov q[argv1pos], esi
; fallthrough
.do_extract:
; how much do we copy?
sub ecx, edx, argbuf
jrcxz .detect_builtin
dec ecx
mov edi, argbuf
mov esi, argv0
.copy_loop:
mov b[esi], b[edi]
inc edi
inc esi
loop .copy_loop
.detect_builtin:
.builtin_cls = "cls"
call strcmp, argv0, .builtin_cls
jraxz .handle_CLS
.builtin_crash = "crash"
call strcmp, argv0, .builtin_crash
jraxz .handle_CRASH
.builtin_date = "date"
call strcmp, argv0, .builtin_date
jraxz .handle_DATE
.builtin_dir = "dir"
call strcmp, argv0, .builtin_dir
jraxz .handle_DIR
.builtin_dump = "dump"
call strcmp, argv0, .builtin_dump
jraxz .handle_DUMP
.builtin_echo = "echo"
call strcmp, argv0, .builtin_echo
jraxz .handle_ECHO
.builtin_erase = "erase"
call strcmp, argv0, .builtin_erase
jraxz .handle_ERASE
.builtin_exit = "exit"
call strcmp, argv0, .builtin_exit
jraxz .handle_EXIT
.builtin_help = "help"
call strcmp, argv0, .builtin_help
jraxz .handle_HELP
.builtin_halt = "halt"
call strcmp, argv0, .builtin_halt
jraxz .handle_HALT
.builtin_make = "make"
call strcmp, argv0, .builtin_make
jraxz .handle_MAKE
.builtin_print = "print"
call strcmp, argv0, .builtin_print
jraxz .handle_PRINT
.builtin_prompt = "prompt"
call strcmp, argv0, .builtin_prompt
jraxz .handle_PROMPT
.builtin_remove = "remove"
call strcmp, argv0, .builtin_remove
jraxz .handle_REMOVE
.builtin_time = "time"
call strcmp, argv0, .builtin_time
jraxz .handle_TIME
.builtin_vers = "vers"
call strcmp, argv0, .builtin_vers
jraxz .handle_VERS
jmp .try_exec
;
; call builtins
;
# 1 "usr/cmd-dir.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
.handle_DIR:
push ebp
mov ebp, esp
push nx0, nx1
push nx2, nx3
nul nx0 ; no. of files found
nul nx1 ; no. of directories found
nul nx2 ; total amount of bytes found
call print, .dirmsg
.dir_first:
mov eax, Sys.FindFirst
mov ax0, .dir_buf
mov ax1, 0x80
trap 0
jmp .dir_list
.dir_next:
mov eax, Sys.FindNext
mov ax0, .dir_buf
mov ax1, 0x80
trap 0
.dir_list:
jraxz .dir_end
mov nx3, ecx ; file size
add nx2, ecx
; directory?
bnz edx, .dir_is_dir
; found a file
inc nx0
; separate extension from file name
mov ecx, 0x80
mov esi, .dir_buf
mov edi, esi
scasb esi, '.'
; print file name
sub ax1, esi, edi
dec ax1
call nprint, edi
; calculate where to put extension
sub edi, esi, .dir_buf
dec edi
.dir_ext_pad:
; print at least 11 non-space characters before extension
blte 11, edi, .dir_print_ext
prn ' '
inc edi
jmp .dir_ext_pad
.dir_print_ext:
prn ' '
; here we print at least 4 characters excluding '.'
mov ecx, 4
bne b[esi], '.', .dir_print_ext.1
inc esi
.dir_print_ext.1:
bzr b[esi], .dir_print_ext.2
; print and decrease ecx, unless it's already 0
prn b[esi]
inc esi
jrcxz .dir_print_ext.1
dec ecx
jmp .dir_print_ext.1
.dir_print_ext.2:
; did we print at least 4 bytes?
jrcxz .dir_print_bytes ; yes, carry on
.dir_pe2.l:
prn ' '
loop .dir_pe2.l
.dir_print_bytes:
; print file size in bytes
prn ' '
prn ' '
prn ' '
shr eax, nx3, 10
and nx3, 1023
push nx3, eax
call printf, .dir_bytesstr
add esp, 16
.dir_prepare_next:
; go find next entry
prn 10
jmp .dir_next
.dir_end:
shr eax, nx2, 10
shr edx, eax, 10
and eax, 1023
and nx2, 1023
push nx2, eax, edx
call printf, .dir_endstr0
add esp, 24
push nx1, nx0
call printf, .dir_endstr1
add esp, 16
pop nx3, nx2
pop nx1, nx0
leave
jmp .print_prompt
; special case: direcory
.dir_is_dir:
inc nx1
; use printf instead of print
; because it returns the # of
; printed characters
call printf, .dir_buf
blte 11, eax, .dir_no_pad
sub ecx, 11, eax
dec ecx
.dir.l:
prn ' '
loop .dir.l
.dir_no_pad:
call print, .dir_ext
jmp .dir_print_bytes
.dir_buf = [0x80]
.dir_ext = " <DIR> "
.dir_endstr0 = " total %dMB + %dKB + %dB\n"
.dir_endstr1 = " found %d file(s), %d dir(s)\n"
.dirmsg = "Directory of C:\\\n\n"
.dir_bytesstr = "%d kilobytes + %d bytes"
; .dir_bytesstr = "%dMB + %dKB + %dB" # too soon
# 228 "command.k" 2
# 1 "usr/cmd-exec.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
.try_exec:
; try without appending ".com"
mov eax, Sys.OpenFile
mov ax0, argv0
trap 0
; we good?
blte zero, eax, .do_exec
; nope, append ".com" and try again
sub ecx, argbuf.size, 5
scasb ax0, zero ; find null-term
mov b[ax0+0], '.' ; ".com"
mov b[ax0+1], 'c'
mov b[ax0+2], 'o'
mov b[ax0+3], 'm'
nul b[ax0+4]
; try again
mov eax, Sys.OpenFile
mov ax0, argv0
trap 0
; still no good?
bltz eax, .exec_not_found
.do_exec:
; load file into memory
mov ax0, eax
mov ax1, 0x108000
mov ax2, 0x8000
mov eax, Sys.ReadFile
trap 0
; save load address
mov ecx, eax
; close file
mov eax, Sys.CloseFile
trap 0
; read anything?
bltz ecx, .couldnt_read
jrcxz .empty_file
; all good, let's go
mov eax, Sys.ExecuteInFrame
mov ax0, 0x108000
mov ax1, 5
trap 0
; unreachable
jmp abort
# 229 "command.k" 2
# 1 "usr/cmd-fsmisc.k" 1
; The OS/K Team licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
.handle_ERASE:
mov eax, Sys.RemoveFile
mov ax0, q[argv1pos]
bzr ax0, .need_params
trap 0
bltz eax, .couldnt_remove
jmp .handle_MAKE ; re-create it back
.handle_MAKE:
mov eax, Sys.CreateFile
mov ax0, q[argv1pos]
bzr ax0, .need_params
trap 0
bltz eax, .couldnt_open
jmp .print_prompt
.handle_PRINT:
mov eax, Sys.OpenFile
mov ax0, q[argv1pos]
bzr ax0, .need_params
trap 0
bltz eax, .file_not_found
mov ax0, eax
mov ax1, 0x108000
mov ax2, 0x8000
mov eax, Sys.ReadFile
trap 0
mov ecx, eax
mov eax, Sys.CloseFile
trap 0
bltz ecx, .couldnt_read
jrcxz .empty_file
call nprint, 0x108000, ecx
jmp .print_prompt
.handle_REMOVE:
mov eax, Sys.RemoveFile
mov ax0, q[argv1pos]
bzr ax0, .need_params
trap 0
bltz eax, .couldnt_remove
jmp .print_prompt
# 230 "command.k" 2
.handle_CLS:
prn 0x8BF00001
jmp .print_prompt
.handle_CRASH:
jmp abort
.handle_DATE:
call GetTimeUTC
mov ecx, b[eax+4]
inc ecx
push b[eax+3], ecx, w[eax+6]
call printf, .datefmt
add esp, 40
jmp .print_prompt
.datefmt = "%d/%d/%d\n"
.handle_DUMP:
dump
jmp .print_prompt
.handle_ECHO:
mov eax, q[argv1pos]
jraxz .echo.end
call print, eax
.echo.end:
prn 10
jmp .print_prompt
.handle_EXIT:
mov eax, Sys.Shutdown
trap 0
jmp .print_prompt
.handle_HALT:
mov eax, Sys.EnterHaltMode
trap 0
jmp .print_prompt
.handle_PROMPT:
mov ax0, prompt
mov ax1, q[argv1pos]
bzr ax1, .need_params
call strcpy
jmp .print_prompt
.handle_TIME:
call GetTimeUTC
push b[eax], b[eax+1], b[eax+2]
call printf, .timefmt
add esp, 24
jmp .print_prompt
.timefmt = "%d:%d:%d\n"
.handle_VERS:
call print, cmd.veesionstr
prn 10
jmp .print_prompt
.handle_HELP:
call print, .helpmsg
call print, .helpmsg.cls
call print, .helpmsg.date
call print, .helpmsg.dir
call print, .helpmsg.dump
call print, .helpmsg.echo
call print, .helpmsg.erase
call print, .helpmsg.exit
call print, .helpmsg.help
call print, .helpmsg.halt
call print, .helpmsg.make
call print, .helpmsg.print
call print, .helpmsg.prompt
call print, .helpmsg.remove
call print, .helpmsg.time
call print, .helpmsg.ver
jmp .print_prompt
.helpmsg = "The following commands are built-in:\n"
.helpmsg.cls = " CLS Clear screen\n"
.helpmsg.date = " DATE Display current date\n"
.helpmsg.dir = " DIR Print contents of current directory\n"
.helpmsg.dump = " DUMP Toggles debug instruction dumping\n"
.helpmsg.echo = " ECHO Write arguments to standard output\n"
.helpmsg.erase = " ERASE Clear a file, making it blank\n"
.helpmsg.exit = " EXIT Initiate machine shutdown\n"
.helpmsg.help = " HELP Display these messages\n"
.helpmsg.halt = " HALT Put processor in halt mode\n"
.helpmsg.make = " MAKE Create an empty file\n"
.helpmsg.print = " PRINT Display contents of text file\n"
.helpmsg.prompt = " PROMPT Change the command line prompt\n"
.helpmsg.remove = " REMOVE Delete a file (permanently)\n"
.helpmsg.time = " TIME Display current time of day\n"
.helpmsg.ver = " VERS Display current COMMAND.COM veesion\n"
.exec_not_found:
push argv0
call printf, .enf_errmsg
add esp, 8
jmp .print_prompt
.enf_errmsg = "%s: file not found\n"
.file_not_found:
push q[argv1pos], argv0
call printf, .fnf_errmsg
add esp, 16
jmp .print_prompt
.fnf_errmsg = "%s: %s: file not found\n"
.empty_file:
push q[argv1pos], argv0
call printf, .ef_errmsg
add esp, 16
jmp .print_prompt
.ef_errmsg = "%s: %s: file was empty\n"
.couldnt_open:
push q[argv1pos], argv0
call printf, .cno_errmsg
add esp, 16
jmp .print_prompt
.cno_errmsg = "%s: %s: an error occured while opening file\n"
.couldnt_remove:
push q[argv1pos], argv0
call printf, .cne_errmsg
add esp, 16
jmp .print_prompt
.cne_errmsg = "%s: %s: an error occured while removing file\n"
.couldnt_read:
push q[argv1pos], argv0
call printf, .cnr_errmsg
add esp, 16
jmp .print_prompt
.cnr_errmsg = "%s: %s: an error occured while reading file\n"
.need_params:
call print, argv0
call print, .np_errmsg
jmp .print_prompt
.np_errmsg = ": need more parameters\n"