; 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: mov rcx, STRLEN_MAX mov rdx, ps1 prns.rep.nz rdx ; empty argbuf mov rcx, argbuf.size mov rdx, argbuf stosb.rep rdx, 0 ; iterator through argbuf xor rcx, rcx mov q[argv1pos], 0 .input_loop: pause pause ; Fill .buf with user input scan rax b.z rax, 0, .input_loop ; backspace character? b.nz rax, 8, .handle_input ; anything to delete? b.z rcx, 0, .input_loop ; delete it dec rcx add rdx, rcx, argbuf mov b[rdx], 0 ; 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 inc rcx ; another one jmp .input_loop .extract_argv0: ; did we read anything at all? ; if not, just go back to waiting input b.z rcx, 0, .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], 0, .no_argv1 inc r11 .next_space: mov r10, b[r11] b.z r10, 0, .no_argv1 ; skip spaces cmp r10, ' ' inc.z r11 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 movsb.rep rax, rdx .detect_builtin: .builtin_cls = "cls" mov ax0, argv0 mov ax1, .builtin_cls call strcmp b.z rax, 0, .handle_CLS .builtin_date = "date" mov ax0, argv0 mov ax1, .builtin_date call strcmp b.z rax, 0, .handle_DATE .builtin_dir = "dir" mov ax0, argv0 mov ax1, .builtin_dir call strcmp b.z rax, 0, .handle_DIR .builtin_echo = "echo" mov ax0, argv0 mov ax1, .builtin_echo call strcmp b.z rax, 0, .handle_ECHO .builtin_exit = "exit" mov ax0, argv0 mov ax1, .builtin_exit call strcmp b.z rax, 0, .handle_EXIT .builtin_help = "help" mov ax0, argv0 mov ax1, .builtin_help call strcmp b.z rax, 0, .handle_HELP .builtin_print = "print" mov ax0, argv0 mov ax1, .builtin_print call strcmp b.z rax, 0, .handle_PRINT .builtin_time = "time" mov ax0, argv0 mov ax1, .builtin_time call strcmp b.z rax, 0, .handle_TIME .builtin_ver = "ver" mov ax0, argv0 mov ax1, .builtin_ver call strcmp b.z rax, 0, .handle_VER jmp .command_not_found ; ; call builtins ; .handle_CLS: prn 0xC15000AF jmp .print_prompt .handle_DATE: time ax0 call GetTimeUTC push b[rax+3] mov rcx, b[rax+4] inc rcx push rcx push w[rax+6] mov ax0, .datefmt call printf add rsp, 5*8 jmp .print_prompt .datefmt = "%d/%d/%d\n" .handle_DIR: call builtins.dir 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, 0, .need_params trap 0 b.l rax, 0, .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, 0, .couldnt_read b.z rax, 0, .empty_file mov rdx, FILE_LOADP prns.rep rdx jmp .print_prompt .handle_TIME: time ax0 call GetTimeUTC push b[rax] push b[rax+1] push b[rax+2] mov ax0, .timefmt call printf add rsp, 3*8 jmp .print_prompt .timefmt = "%d:%d:%d\n" .handle_VER: mov rcx, STRLEN_MAX mov rdx, cmd.versionstr prns.rep.nz rdx prn 10 jmp .print_prompt .handle_HELP: mov rcx, STRLEN_MAX mov rdx, .helpmsg prns.rep.nz rdx mov rdx, .helpmsg.cls prns.rep.nz rdx mov rdx, .helpmsg.date prns.rep.nz rdx mov rdx, .helpmsg.dir prns.rep.nz rdx mov rdx, .helpmsg.echo prns.rep.nz rdx mov rdx, .helpmsg.exit prns.rep.nz rdx mov rdx, .helpmsg.help prns.rep.nz rdx mov rdx, .helpmsg.print prns.rep.nz rdx mov rdx, .helpmsg.time prns.rep.nz rdx mov rdx, .helpmsg.ver prns.rep.nz rdx 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.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: mov rcx, STRLEN_MAX mov rdx, argv0 prns.rep.nz rdx mov rdx, .cnf_errmsg prns.rep.nz rdx jmp .print_prompt .cnf_errmsg = ": command not found\n" .file_not_found: mov ax0, .fnf_errmsg push q[argv1pos] push argv0 call printf add rsp, 16 jmp .print_prompt .fnf_errmsg = "%s: %s: file not found\n" .empty_file: mov ax0, .ef_errmsg push q[argv1pos] push argv0 call printf add rsp, 16 jmp .print_prompt .ef_errmsg = "%s: %s: file is empty\n" .couldnt_read: mov ax0, .cno_errmsg push q[argv1pos] push argv0 call printf add rsp, 16 jmp .print_prompt .cno_errmsg = "%s: %s: an error occured while reading file\n" .need_params: mov rcx, STRLEN_MAX mov rdx, argv0 prns.rep.nz rdx mov rdx, .np_errmsg prns.rep.nz rdx jmp .print_prompt .np_errmsg = ": need more parameters\n"