// File: iamlouk[P]asbi/src/procenv.cc
// Function: macro_system(int, asbi::Context*, std::shared_ptr<asbi::Env>)
static Value macro_system(int n, Context* ctx, std::shared_ptr<Env>) {
	if (n != 2)
		throw std::runtime_error("env:$ usage error");

	auto arg = ctx->pop();
	auto callback = ctx->pop();
	if (arg.type != type_t::String || callback.type != type_t::Lambda)
		throw std::runtime_error("env:$ usage error");

	std::string cmd = arg._string->data;
	auto task = [ctx, cmd](evts::callback_t cb) -> void {
		pid_t pid = fork();
		if (pid == -1) {
			std::vector<Value> args;
			args.push_back(Value::symbol(ctx->names.err));
			args.push_back(Value::number(errno));
			cb(&args, true);
			return;
		}

		if (pid == 0) {
			const char* shell = getenv("SHELL");
			shell = shell != NULL ? shell : "/bin/sh";
			execl(shell, shell, "-c", cmd.c_str(), NULL);
			return;
		}

		int wstatus;
		if (waitpid(pid, &wstatus, 0) == -1) {
			// TODO...
			throw std::runtime_error("waitpid failed");
		}

		std::vector<Value> args;
		if (WIFEXITED(wstatus)) {
			args.push_back(Value::symbol(ctx->names.ok));
			args.push_back(Value::number(WEXITSTATUS(wstatus)));
		} else {
			args.push_back(Value::symbol(ctx->names.err));
			args.push_back(Value::number(WTERMSIG(wstatus)));
		}
		cb(&args, true);
	};

	ctx->evtloop.addTask(callback._lambda, task);

	return Value::nil();
}

// Assembly:
subq $0xf8, %rsp
movl %edi, 0xe4(%rsp)
movq %rsi, 0xd8(%rsp)
movq %rdx, 0xd0(%rsp)
cmpl $0x2, 0xe4(%rsp)
je 0x2dbe6
movl $0x10, %edi
callq 0x6200
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x30(%rsp)
leaq 0xb9f6(%rip), %rsi      # 0x3959a
callq 0x6160
jmp 0x2dbab
movq 0x30(%rsp), %rdi
movq 0x1e439(%rip), %rsi     # 0x4bff0
movq 0x1e3e2(%rip), %rdx     # 0x4bfa0
callq 0x6780
movq 0x30(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc8(%rsp)
movl %eax, 0xc4(%rsp)
callq 0x6320
jmp 0x2ddd2
movq 0xd8(%rsp), %rdi
callq 0x26b50
movl %eax, 0xb0(%rsp)
movq %rdx, 0xb8(%rsp)
movq 0xd8(%rsp), %rdi
callq 0x26b50
movl %eax, 0xa0(%rsp)
movq %rdx, 0xa8(%rsp)
cmpl $0x4, 0xb0(%rsp)
jne 0x2dc32
cmpl $0x5, 0xa0(%rsp)
je 0x2dc90
movl $0x10, %edi
callq 0x6200
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x28(%rsp)
leaq 0xb94c(%rip), %rsi      # 0x3959a
callq 0x6160
jmp 0x2dc55
movq 0x28(%rsp), %rdi
movq 0x1e38f(%rip), %rsi     # 0x4bff0
movq 0x1e338(%rip), %rdx     # 0x4bfa0
callq 0x6780
movq 0x28(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc8(%rsp)
movl %eax, 0xc4(%rsp)
callq 0x6320
jmp 0x2ddd2
movq 0xb8(%rsp), %rsi
addq $0x20, %rsi
leaq 0x80(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x61a0
movq 0x20(%rsp), %rsi
movq 0xd8(%rsp), %rax
movq %rax, 0x58(%rsp)
leaq 0x60(%rsp), %rdi
callq 0x61a0
jmp 0x2dccc
movq 0xd8(%rsp), %rax
addq $0x318, %rax            # imm = 0x318
movq %rax, 0x10(%rsp)
movq 0xa8(%rsp), %rax
movq %rax, 0x18(%rsp)
leaq 0x38(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x2dee0
jmp 0x2dcfd
movq 0x18(%rsp), %rsi
movq 0x10(%rsp), %rdi
leaq 0x38(%rsp), %rdx
callq 0x302f0
jmp 0x2dd13
leaq 0x38(%rsp), %rdi
callq 0x2cda0
callq 0x1d110
movq %rdx, (%rsp)
movl %eax, 0xc(%rsp)
jmp 0x2dd2c
movq (%rsp), %rax
movl 0xc(%rsp), %ecx
movl %ecx, 0xe8(%rsp)
movq %rax, 0xf0(%rsp)
leaq 0x58(%rsp), %rdi
callq 0x2df90
leaq 0x80(%rsp), %rdi
callq 0x6290
movl 0xe8(%rsp), %eax
movq 0xf0(%rsp), %rdx
addq $0xf8, %rsp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc8(%rsp)
movl %eax, 0xc4(%rsp)
jmp 0x2ddc5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc8(%rsp)
movl %eax, 0xc4(%rsp)
jmp 0x2ddbb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc8(%rsp)
movl %eax, 0xc4(%rsp)
leaq 0x38(%rsp), %rdi
callq 0x2cda0
leaq 0x58(%rsp), %rdi
callq 0x2df90
leaq 0x80(%rsp), %rdi
callq 0x6290
movq 0xc8(%rsp), %rdi
callq 0x67a0
nop