kvisc/vm/ob/command.k

1661 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 ecx, ax1
scasb ax0, zero
sub eax, ax1, ecx
ret
;
; int strlen(char *)
;
strlen:
mov ecx, 0x7AFFFFFF
mov edx, ecx
scasb ax0, zero
sub eax, edx, ecx
ret
;
; void strcpy(char *, const char *)
;
strcpy:
.l:
mov ecx, b[ax1]
mov b[ax0], ecx
jecxz .r
inc ax0
inc ax1
jmp .l
.r:
ret
;
; void strncpy(char *, const char *, int)
;
strncpy:
mov ecx, ax2
jecxz .r
.l:
mov b[ax0], b[ax1]
inc ax0
inc ax1
loop .l
.r:
ret
;
; void strnzcpy(char *, const char *, int)
;
strnzcpy:
mov ecx, ax2
jecxz .r
.l:
mov eax, b[ax1]
mov b[ax0], eax
jeaxz .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 esi
.l:
movzx eax, b[ax0+esi]
movzx edx, b[ax1+esi]
bne eax, edx, .r
; both zero?
add ecx, eax, edx
jecxz .r
inc esi
jmp .l
.r:
sub eax, edx
ret
;
; int strncmp(const char *str1, const char *str2, int maxn)
;
strncmp:
mov ecx, ax2
jecxz .r
.l:
movzx eax, b[ax0]
movzx edx, b[ax1]
bne eax, edx, .r
inc ax0
inc ax1
loop .l
.r:
sub eax, edx
ret
;
; char *strchrnul(const char *str, int ch)
;
strchrnul:
mov ecx, 0x7AFFFFFF
scasb ax0, ax1
mov eax, ax0
ret
;
; char *strchr(const char *str, int ch)
;
strchr:
mov ecx, 0x7AFFFFFF
scasb ax0, ax1
bnz b[ax0], .r
nul eax
ret
.r:
mov eax, 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 esi, ax1
; go to str's end, just before
; the null terminator
mov ecx, 0x7AFFFFFF
scasb ax1, zero
dec ax1
.l:
; copy, going backward though str
; and forward through buf
mov b[ax0], b[ax1]
beq ax1, esi, .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 ecx, 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 ecx, ax2
jecxz .r
.l:
sub edx, ax2, ecx
mov b[ax0+edx], b[ax1+edx]
loop .l
.r:
ret
;
; void memzero(void *, int)
;
memzero:
mov ecx, ax1
jecxz .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 eax, 365
; divisible by 4?
rem ecx, ax0, 4
jecxnz .end
; divisible by 100?
rem ecx, ax0, 100
jecxnz .leap
; divisible by 400?
rem ecx, ax0, 400
jecxnz .end
.leap:
inc eax
.end:
ret
;
; TIME *GetTimeUTC(void)
;
GetTimeUTC:
ytime
mov edi, .buf
; seconds
rem esi, eax, 60
mov b[edi], esi
; minutes
div esi, eax, 60
rem esi, 60
mov b[edi+1], esi
; hours
div esi, eax, 3600
rem esi, 24
mov b[edi+2], esi
; month days
div esi, eax, 3600*24
mov b[edi+3], esi
; month
mov b[edi+4], rbx
; years
mov w[edi+6], ecx
;
; ydays (TODO)
;
mov eax, .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 eax, ax0
nul ecx
; 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 ecx, ax1, 63 ; extract ax1 sign
jecxz .conv
neg ax1 ; NEG if negative
; main loop
.conv:
bzr ax1, .fini
rem edx, ax1, ax2 ; ax1 % base
blt 9, edx, .nondec ; edx > 9 ?
add edx, '0'
jmp .next
.nondec:
add edx, 55 ; 'A' - 10
.next:
mov b[ax0], edx
inc ax0
div ax1, ax2
jmp .conv
; add minus flag, null-terminate and reverse
.fini:
jecxz .cxz
mov b[ax0], '-'
inc ax0
.cxz:
nul b[ax0]
call strrev2, eax
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)
;
; eax = integer extracted from str
; edx = pointer to first invalid byte
;
strtol:
mov ax2, 1
jmp strtoq
;
; int strtoul(const char *str, int base)
;
; eax = integer extracted from str
; edx = 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 eax, esi
mov edx, ax0
; make sure base is in [2, 32]
beq ax1, 1, .bad
bltu 36, ax1, .bad
; empty string?
bzr b[edx], .done
.skip_spc:
bne b[edx], ' ', .no_spc
inc edx
jmp .skip_spc
.no_spc:
; skip +
bne b[edx], '+', .no_plus
inc edx
.no_plus:
; unsigned?
bzr ax2, .unsigned
; parse '-'
bne b[edx], '-', .unsigned
inc edx
mov esi, 1
.unsigned:
; base 0
bzr ax1, .base_0
; base prefix?
bne b[edx], '0', .main_loop
inc edx
movzx ecx, b[edx]
; "0x"/"0b" prefix
jecxz .done ; "0"
beq ecx, 'x', .parsed_0x
beq ecx, '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 eax = 0 and *edx = 'x'
bne ax1, 16, .done
; else
inc edx
jmp .main_loop
.parsed_0b:
; are we in base 2?
; if not, leave eax = 0 and *edx = 'b'
bne ax1, 2, .done
; else
inc edx
jmp .main_loop
.base_0:
; guess base
beq b[edx], '0', .b0_not10
; must be base 10
mov ax1, 10
jmp .main_loop
.b0_not10:
inc edx
bne b[edx], 'x', .b0_not16
inc edx
mov ax1, 16
jmp .main_loop
.b0_not16:
bne b[edx], 'b', .b0_not2
inc edx
mov ax1, 2
jmp .main_loop
.b0_not2:
; take octal by default
mov ax1, 8
.main_loop:
movzx ecx, b[edx]
inc edx
; between 0 and 9?
bltu ecx, '0', .done
bltu '9', ecx, .not_digit10
; yes
sub ecx, '0'
jmp .next
.not_digit10:
bltu ecx, 'A', .done
bltu 'Z', ecx, .not_digitAZ
sub ecx, 55 ; 'A' - 10
jmp .next
.not_digitAZ:
bltu ecx, 'a', .done
bltu 'z', ecx, .done
sub ecx, 87 ; 'a' - 10
jmp .next
.next:
; too large for base?
blteu ax1, ecx, .done
mul eax, ax1
add eax, ecx
jmp .main_loop
.done:
; negative?
bzr esi, .r
; yes
neg eax
.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 ebp
mov ebp, esp
push nx0, nx1, nx2
push nx3, nx4, nx5
mov nx0, ax2 ; fmt
mov nx2, ax3 ; va_list
mov nx3, ax1 ; n
mov nx5, ax0 ; putc
nul nx4 ; return value
.main_loop:
; find '%' or null-terminator
mov ecx, 0x7AFFFFFF
mov nx1, nx0
scasb nx1, '%'
; everything below nx1 is a regular character; print it
.print_regular:
beq nx0, nx1, .check_modf
call .doput, b[nx0]
inc nx0
jmp .print_regular
.check_modf:
; did we find a '%' ?
; if not, then we found fmt's null-terminator; we're done
bne b[nx0], '%', .epilogue
; we did find a modifier / '%'
mov eax, b[nx0+1]
add nx0, 2
beq eax, 's', .modf_s
beq eax, 'c', .modf_c
beq eax, 'p', .modf_p
beq eax, 'x', .modf_x
beq eax, 'd', .modf_d
beq eax, 'o', .modf_o
beq eax, 'b', .modf_b
beq eax, '%', .modf_percent
; unrecognized
jmp .bad_modifier
.modf_s:
; get string address
mov nx1, q[nx2]
add nx2, 8
bzr nx1, .nullstring
.print_string:
movzx ax0, b[nx1]
bzr ax0, .main_loop
inc nx1
call .doput
jmp .print_string
.modf_c:
call .doput, q[nx2]
add nx2, 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 esp, 80
mov nx1, esp
; assume modifier already set up ax2
call itoa, esp, q[nx2]
add nx2, 8
.print_itoa_buf:
movzx ax0, b[nx1]
bzr ax0, .pib_end_loop
inc nx1
call .doput
jmp .print_itoa_buf
.pib_end_loop:
add esp, 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 eax, nx4
pop nx5, nx4
pop nx3, nx2
pop nx1, nx0
leave
ret
;
; prints ax0
;
.doput:
; update print count
inc nx4
; 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 nx3, .r
; decrement n and print
dec nx3
call nx5
; did putc fail?
jeaxz .r
; yes, so artificially set n=0
nul nx3
.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 eax
ret
;
; int printf(const char *fmt, ...)
;
printf:
mov ax2, ax0
mov ax0, putc
mov ax1, 0x7AFFFFFF
add ax3, esp, 8
jmp doprnt
;
; int nprintf(const char *fmt, int n, ...)
;
nprintf:
mov ax2, ax0
mov ax0, putc
add ax3, esp, 8
jmp doprnt
;
; Print a string
; Guaranteed to only affect ecx and ax0
;
print:
.l:
movzx eax, b[ax0]
jeaxz .r
prn eax
inc ax0
jmp .l
.r:
ret
;
; Print exactly ax1 characters
;
nprint:
mov ecx, ax1
jecxz .r
.l:
prn b[ax0]
inc ax0
loop .l
.r:
ret
# 51 "crt/crt.k" 2
exit:
mov eax, 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
jeaxz .input_loop
; ESC key pressed?
beq eax, 0x1B, .handle_EXIT
; backspace character?
bne eax, 8, .handle_input
; anything to delete?
jecxz .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
jecxz .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]
jecxz .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
jecxz .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
jeaxz .handle_CLS
.builtin_crash = "crash"
call strcmp, argv0, .builtin_crash
jeaxz .handle_CRASH
.builtin_date = "date"
call strcmp, argv0, .builtin_date
jeaxz .handle_DATE
.builtin_dir = "dir"
call strcmp, argv0, .builtin_dir
jeaxz .handle_DIR
.builtin_dump = "dump"
call strcmp, argv0, .builtin_dump
jeaxz .handle_DUMP
.builtin_echo = "echo"
call strcmp, argv0, .builtin_echo
jeaxz .handle_ECHO
.builtin_erase = "erase"
call strcmp, argv0, .builtin_erase
jeaxz .handle_ERASE
.builtin_exit = "exit"
call strcmp, argv0, .builtin_exit
jeaxz .handle_EXIT
.builtin_help = "help"
call strcmp, argv0, .builtin_help
jeaxz .handle_HELP
.builtin_halt = "halt"
call strcmp, argv0, .builtin_halt
jeaxz .handle_HALT
.builtin_make = "make"
call strcmp, argv0, .builtin_make
jeaxz .handle_MAKE
.builtin_print = "print"
call strcmp, argv0, .builtin_print
jeaxz .handle_PRINT
.builtin_prompt = "prompt"
call strcmp, argv0, .builtin_prompt
jeaxz .handle_PROMPT
.builtin_remove = "remove"
call strcmp, argv0, .builtin_remove
jeaxz .handle_REMOVE
.builtin_time = "time"
call strcmp, argv0, .builtin_time
jeaxz .handle_TIME
.builtin_vers = "vers"
call strcmp, argv0, .builtin_vers
jeaxz .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:
jeaxz .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
jecxz .dir_print_ext.1
dec ecx
jmp .dir_print_ext.1
.dir_print_ext.2:
; did we print at least 4 bytes?
jecxz .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
mov esi, argv0
sub ecx, argbuf.size, 5
scasb esi, zero ; find null-term
mov b[esi], '.' ; ".com"
mov b[esi+1], 'c'
mov b[esi+2], 'o'
mov b[esi+3], 'm'
nul b[esi+4]
; try again
mov eax, Sys.OpenFile
mov ax0, argv0
trap 0
; we good?
blte zero, eax, .do_exec
nul b[esi] ; erase ".com"
jmp .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
jecxz .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
jecxz .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]
jeaxz .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"