; The OS/K Team licenses this file to you under the MIT license. ; See the LICENSE file in the project root for more information. argbuf.size := 256 argbuf = [argbuf.size] argv0 = [argbuf.size] argv1pos = 0 stdin_echoing = 1 prompt = [32] main: mov rsi, prompt mov b[rsi+0], 'C' mov b[rsi+1], ':' mov b[rsi+2], '\' mov b[rsi+3], '>' mov b[rsi+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 rcx .input_loop: pause pause pause ; Fill .buf with user input scan rax jraxz .input_loop ; ESC key pressed? beq rax, 0x1B, .handle_EXIT ; backspace character? bne rax, 8, .handle_input ; anything to delete? jrcxz .input_loop ; no ; yes, delete it dec rcx, 1 add rdx, rcx, argbuf nul b[rdx] ; update screen bzr b[stdin_echoing], .input_loop prn 8 jmp .input_loop .handle_input: bzr b[stdin_echoing], .se.z prn rax .se.z: beq rax, 10, .extract_argv0 ; when max line length is reached, ; force a newline beq rcx, argbuf.size, .extract_argv0 ; add character to buffer and increase iterator (rcx) add rdx, rcx, argbuf mov b[rdx], rax inc rcx, 1 ; 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 rcx, argbuf.size mov rdx, argbuf scasb rdx, ' ' ; argv1 exists? if so, save its position mov rsi, rdx .next_space: mov rcx, b[rsi] jrcxz .do_extract ; skip spaces bne rcx, ' ', .not_a_space inc rsi, 1 jmp .next_space .not_a_space: ; if we're here, we found a ; non-zero non-space character mov q[argv1pos], rsi ; fallthrough .do_extract: ; how much do we copy? sub rcx, rdx, argbuf jrcxz .detect_builtin dec rcx, 1 mov rdi, argbuf mov rsi, argv0 .copy_loop: mov b[rsi], b[rdi] inc rdi, 1 inc rsi, 1 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 .command_not_found ; ; call builtins ; .handle_CLS: prn PRN_CLEAR jmp .print_prompt .handle_CRASH: mov rax, 0xDEADBEEF trap 0 jmp .print_prompt .handle_DATE: call GetTimeUTC mov rcx, b[rax+4] inc rcx, 1 push b[rax+3], rcx, w[rax+6] call printf, .datefmt inc rsp, 40 jmp .print_prompt .datefmt = "%d/%d/%d\n" .handle_DIR: call builtins.dir jmp .print_prompt .handle_DUMP: dump jmp .print_prompt .handle_ECHO: mov rax, q[argv1pos] jraxz .echo.end call print, rax .echo.end: prn 10 jmp .print_prompt .handle_ERASE: mov rax, Sys.RemoveFile mov ax0, q[argv1pos] bzr ax0, .need_params trap 0 bltz rax, .couldnt_remove jmp .handle_MAKE ; re-create it back .handle_EXIT: mov rax, Sys.Shutdown trap 0 jmp .print_prompt .handle_HALT: mov rax, Sys.EnterHaltMode trap 0 jmp .print_prompt .handle_MAKE: mov rax, Sys.CreateFile mov ax0, q[argv1pos] bzr ax0, .need_params trap 0 bltz rax, .couldnt_open jmp .print_prompt .handle_PRINT: mov rax, Sys.OpenFile mov ax0, q[argv1pos] bzr ax0, .need_params trap 0 bltz rax, .file_not_found mov ax0, rax mov ax1, FILE_LOADP mov ax2, FILE_MAXSZ mov rax, Sys.ReadFile trap 0 mov rcx, rax mov rax, Sys.CloseFile trap 0 bltz rcx, .couldnt_read jrcxz .empty_file call nprint, FILE_LOADP, rcx jmp .print_prompt .handle_PROMPT: mov ax0, prompt mov ax1, q[argv1pos] bzr ax1, .need_params call strcpy jmp .print_prompt .handle_REMOVE: mov rax, Sys.RemoveFile mov ax0, q[argv1pos] bzr ax0, .need_params trap 0 bltz rax, .couldnt_remove jmp .print_prompt .handle_TIME: call GetTimeUTC push b[rax], b[rax+1], b[rax+2] call printf, .timefmt inc rsp, 24 jmp .print_prompt .timefmt = "%d:%d:%d\n" .handle_VERS: call print, cmd.versionstr 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 version\n" .command_not_found: call print, argv0 call print, .cnf_errmsg jmp .print_prompt .cnf_errmsg = ": command not found\n" .file_not_found: push q[argv1pos], argv0 call printf, .fnf_errmsg inc rsp, 16 jmp .print_prompt .fnf_errmsg = "%s: %s: file not found\n" .empty_file: push q[argv1pos], argv0 call printf, .ef_errmsg inc rsp, 16 jmp .print_prompt .ef_errmsg = "%s: %s: file was empty\n" .couldnt_open: push q[argv1pos], argv0 call printf, .cno_errmsg inc rsp, 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 inc rsp, 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 inc rsp, 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"