; 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 ps1 = "C:\\> " main: .print_prompt: call print, ps1 ; empty argbuf mov rcx, argbuf.size mov rdx, argbuf stosb.rep rdx, 0 ; iterator through argbuf mov rcx, zero mov q[argv1pos], zero .input_loop: pause pause pause ; Fill .buf with user input scan rax b.z rax, zero, .input_loop ; backspace character? b.nz rax, 8, .handle_input ; anything to delete? b.z rcx, zero, .input_loop ; delete it sub rcx, rcx, 1 add rdx, rcx, argbuf mov b[rdx], zero ; update screen cmp b[stdin_echoing], 1 prn.z 8 jmp .input_loop .handle_input: cmp b[stdin_echoing], 1 prn.z rax b.z rax, 10, .extract_argv0 ; when max line length is reached, ; force a newline b.z rcx, argbuf.size, .extract_argv0 ; add character to buffer and increase iterator (rcx) add rdx, rcx, argbuf mov b[rdx], rax add rcx, rcx, 1 ; another one jmp .input_loop .extract_argv0: ; did we read anything at all? ; if not, just go back to waiting input b.z rcx, zero, .print_prompt ; find first whitespace or null-terminator mov rcx, argbuf.size mov rdx, argbuf scasb.rep.nz rdx, ' ' ; argv1 exists? if so, save its position mov r11, rdx b.z b[r11], zero, .no_argv1 add r11, r11, 1 .next_space: mov r10, b[r11] b.z r10, zero, .no_argv1 ; skip spaces cmp r10, ' ' add.z r11, r11, 1 jmp.z .next_space mov q[argv1pos], r11 ; fallthrough .no_argv1: ; empty argv0 mov rcx, argbuf.size mov rax, argv0 stosb.rep rax, 0 ; extract argv0 sub rcx, rdx, argbuf mov rdx, argbuf mov rax, argv0 .mmove: jmp.cxz .detect_builtin mov r11, b[rdx] mov b[rax], r11 add rdx, rdx, 1 add rax, rax, 1 sub rcx, rcx, 1 jmp .mmove .detect_builtin: .builtin_cls = "cls" call strcmp, argv0, .builtin_cls b.z rax, 0, .handle_CLS .builtin_date = "date" call strcmp, argv0, .builtin_date b.z rax, 0, .handle_DATE .builtin_dir = "dir" call strcmp, argv0, .builtin_dir b.z rax, 0, .handle_DIR .builtin_dump = "dump" call strcmp, argv0, .builtin_dump b.z rax, 0, .handle_DUMP .builtin_echo = "echo" call strcmp, argv0, .builtin_echo b.z rax, 0, .handle_ECHO .builtin_exit = "exit" call strcmp, argv0, .builtin_exit b.z rax, 0, .handle_EXIT .builtin_help = "help" call strcmp, argv0, .builtin_help b.z rax, 0, .handle_HELP .builtin_print = "print" call strcmp, argv0, .builtin_print b.z rax, 0, .handle_PRINT .builtin_time = "time" call strcmp, argv0, .builtin_time b.z rax, 0, .handle_TIME .builtin_ver = "ver" call strcmp, argv0, .builtin_ver b.z rax, 0, .handle_VER jmp .command_not_found ; ; call builtins ; .handle_CLS: prn 0xC15000AF jmp .print_prompt .handle_DATE: call GetTimeUTC push b[rax+3] mov rcx, b[rax+4] add rcx, rcx, 1 push rcx push w[rax+6] call printf, .datefmt add rsp, 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 rdx, q[argv1pos] b.z rdx, 0, .echo.end mov rcx, argbuf.size prns.rep.nz rdx .echo.end: prn 10 jmp .print_prompt .handle_EXIT: mov rax, Sys.Shutdown trap 0 .handle_PRINT: mov rax, Sys.OpenFile mov ax0, q[argv1pos] b.z ax0, zero, .need_params trap 0 b.l rax, zero, .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 b.l rax, zero, .couldnt_read b.z rax, zero, .empty_file mov rdx, FILE_LOADP prns.rep rdx jmp .print_prompt .handle_TIME: call GetTimeUTC push b[rax] push b[rax+1] push b[rax+2] call printf, .timefmt add rsp, rsp, 24 jmp .print_prompt .timefmt = "%d:%d:%d\n" .handle_VER: 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.exit call print, .helpmsg.help call print, .helpmsg.print 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.exit = " EXIT Initiate machine shutdown\n" .helpmsg.help = " HELP Display these messages\n" .helpmsg.print = " PRINT Display contents of text file\n" .helpmsg.time = " TIME Display current time of day\n" .helpmsg.ver = " VER Display current COMMAND.COM and DOS kernel versions\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] push argv0 call printf, .fnf_errmsg add rsp, rsp, 16 jmp .print_prompt .fnf_errmsg = "%s: %s: file not found\n" .empty_file: push q[argv1pos] push argv0 call printf, .ef_errmsg add rsp, rsp, 16 jmp .print_prompt .ef_errmsg = "%s: %s: file is empty\n" .couldnt_read: push q[argv1pos] push argv0 call printf, .cno_errmsg add rsp, rsp, 16 jmp .print_prompt .cno_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"