# 1 "command.k" # 1 "" # 1 "" # 31 "" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 32 "" 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_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 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"