// File: mukul-mehta[P]meta/shell.cc
// Function: main
int main(int argc, char** argv) {
    metash_help(vector<string>{});
    getcwd(__CWD, BUFSIZE);
    const char* HISTORYFILE = getHistoryFilename();

    read_history(HISTORYFILE);
    using_history();

    char* line;

    while ((line = readline(getShellPrompt())) != nullptr) {
        if (strlen(line) > 0) {
            add_history(line);
            write_history(HISTORYFILE);
        } else {
            free(line);
            continue;
        }

        vector<string> tokens = tokenize(line);

        free(line);

        // Check if command is a builtin using the `checkBuiltin` call. If yes, execute it
        int isBuiltin = checkBuiltin(tokens);

        if (isBuiltin >= 0) {
            builtinFunction builtin = builtins[isBuiltin];
            builtin.builtin_fp(tokens);
        } else {
            // If the last token of the input is &, the command is to be run in background
            // Set the bool isBackground and remove the token because execvp does not need it
            unused bool isBackground = false;
            if (tokens[tokens.size() - 1] == "&") {
                isBackground = true;
                tokens.pop_back();
            }

            // If there is a pipe character, set isPipe to true. Piped inputs are handled differently
            bool isPipe = false;
            vector<string>::iterator it = find(tokens.begin(), tokens.end(), "|");
            if (it != tokens.end()) {
                isPipe = true;
            }

            if (!isPipe) {
                /*
					Execute all commands that don't have any pipe in them

					To execute a command, use the usual fork/exec method. A child process
					is spawned and then we pass the tokens to `metash_execute` which runs `execvp`
					in the child, replacing it with the desired program

					In the parent, if the process was not a background process, wait for the
					child to finish executing before issuing a prompt again
				*/
                pid_t pid = fork();
                int status;

                if (pid == 0) {
                    if (isBackground)
                        setpgid(0, 0);
                    metash_execute(tokens);
                } else if (pid > 0) {
                    if (!isBackground) {
                        if (setpgid(pid, pid) == -1)
                            perror("setpgid() failed");

                        if (tcsetpgrp(shell_terminal, pid) == 0) {
                            if ((waitpid(pid, &status, WUNTRACED)) < 0) {
                                perror("wait() failed");
                                exit(EXIT_FAILURE);
                            }

                            signal(SIGTTOU, SIG_IGN);
                            if (tcsetpgrp(shell_terminal, shell_pgid) != 0)
                                perror("tcsetpgrp() failed");
                            signal(SIGTTOU, SIG_DFL);
                        } else {
                            perror("tcsetpgrp() failed");
                        }
                    }
                } else {
                    perror("fork() failed");
                }
            } else {
                /*
					Execute all commands that have pipes in them

					Firstly we split the tokens into token groups, with each group representing
					one command in the pipe. Then we iterate over each of these commands
					We use the `pipe` system call to create a pipe. Then the correct file
					descriptors are set. For a command of form `a | b | c`, the output of a is
					set as the input of b, the output of b is set as input of c and so on

					After setting descriptors, the usual fork/exec method is called and the function
					`metash_execute` is called. The parent closes file descriptors as we progress to
					the next command in the pipe call

					Once all pipes have been set, we wait for all children to finish execution
				*/
                vector<vector<string>> parsedTokens = parsePipeTokens(tokens);

                size_t num_commands = parsedTokens.size();
                int pipeFD[2];
                int tempFD[2];

                for (size_t i = 0; i < num_commands; i++) {
                    if (i != num_commands - 1)
                        pipe(pipeFD);

                    pid_t pid = fork();

                    if (pid == 0) {
                        if (i != 0) {
                            int dupStatus = dup2(tempFD[0], STDIN_FILENO);
                            if (dupStatus == -1)
                                perror("dup2() failed");

                            close(tempFD[0]);
                            close(tempFD[1]);
                        }

                        if (i != num_commands - 1) {
                            int dupStatus = dup2(pipeFD[1], STDOUT_FILENO);
                            if (dupStatus == -1)
                                perror("dup2() failed");

                            close(pipeFD[0]);
                            close(pipeFD[1]);
                        }

                        metash_execute(parsedTokens[i]);
                    } else if (pid > 0) {

                        if (i != 0) {
                            close(tempFD[0]);
                            close(tempFD[1]);
                        }

                        if (i != num_commands - 1) {
                            tempFD[0] = pipeFD[0];
                            tempFD[1] = pipeFD[1];
                        }
                    } else {
                        perror("fork() failed");
                    }
                }
                if (!isBackground) {
                    int ret;
                    do {
                        ret = wait(NULL);
                    } while (ret > 0);
                }
            }
        }
        tokens.clear();
        fflush(stdin);
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x200, %rsp            # imm = 0x200
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
xorps %xmm0, %xmm0
movaps %xmm0, -0x30(%rbp)
movq $0x0, -0x20(%rbp)
leaq -0x30(%rbp), %rdi
movq %rdi, -0x1b8(%rbp)
callq 0x5230
movq -0x1b8(%rbp), %rdi
callq 0x8d40
jmp 0x4766
leaq -0x30(%rbp), %rdi
callq 0x5250
leaq 0xbfca(%rip), %rdi      # 0x10740
movl $0x1000, %esi           # imm = 0x1000
callq 0x3170
callq 0x8940
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rdi
callq 0x3050
callq 0x3240
callq 0x43c0
movq %rax, %rdi
callq 0x32d0
movq %rax, -0x50(%rbp)
cmpq $0x0, %rax
je 0x4ea2
movq -0x50(%rbp), %rdi
callq 0x3140
cmpq $0x0, %rax
jbe 0x47ef
movq -0x50(%rbp), %rdi
callq 0x3450
movq -0x48(%rbp), %rdi
callq 0x35b0
jmp 0x47fa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x5250
jmp 0x4ead
movq -0x50(%rbp), %rdi
callq 0x33c0
jmp 0x4797
movq -0x50(%rbp), %rsi
leaq -0x68(%rbp), %rdi
movq %rdi, -0x1c0(%rbp)
callq 0x6fb0
movq -0x50(%rbp), %rdi
callq 0x33c0
movq -0x1c0(%rbp), %rsi
leaq -0x88(%rbp), %rdi
callq 0x52b0
jmp 0x482c
leaq -0x88(%rbp), %rdi
callq 0x4310
movl %eax, -0x1c4(%rbp)
jmp 0x4840
leaq -0x88(%rbp), %rdi
callq 0x5250
movl -0x1c4(%rbp), %eax
movl %eax, -0x6c(%rbp)
cmpl $0x0, -0x6c(%rbp)
jl 0x4934
movslq -0x6c(%rbp), %rsi
leaq 0xbab6(%rip), %rdi      # 0x10320
callq 0x51a0
movq %rax, %rsi
leaq -0xd0(%rbp), %rdi
callq 0x53a0
jmp 0x4880
movq -0xd0(%rbp), %rax
movq %rax, -0x1d0(%rbp)
leaq -0xe8(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x52b0
jmp 0x48a0
movq -0x1d0(%rbp), %rax
leaq -0xe8(%rbp), %rdi
callq *%rax
jmp 0x48b2
leaq -0xe8(%rbp), %rdi
callq 0x5250
leaq -0xd0(%rbp), %rdi
callq 0x5030
jmp 0x4e6f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
jmp 0x4e97
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x88(%rbp), %rdi
callq 0x5250
jmp 0x4e97
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
jmp 0x4923
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0xe8(%rbp), %rdi
callq 0x5250
leaq -0xd0(%rbp), %rdi
callq 0x5030
jmp 0x4e97
movb $0x0, -0xe9(%rbp)
leaq -0x68(%rbp), %rdi
movq %rdi, -0x1e0(%rbp)
callq 0x5450
movq -0x1e0(%rbp), %rdi
movq %rax, %rsi
decq %rsi
callq 0x50c0
movq %rax, %rdi
leaq 0x6895(%rip), %rsi      # 0xb1fc
callq 0x5420
movb %al, -0x1d1(%rbp)
jmp 0x4974
movb -0x1d1(%rbp), %al
testb $0x1, %al
jne 0x4980
jmp 0x4990
movb $0x1, -0xe9(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x5470
movb $0x0, -0xea(%rbp)
leaq -0x68(%rbp), %rdi
movq %rdi, -0x1f0(%rbp)
callq 0x54f0
movq -0x1f0(%rbp), %rdi
movq %rax, -0x100(%rbp)
callq 0x5520
movq %rax, -0x108(%rbp)
movq -0x100(%rbp), %rdi
movq -0x108(%rbp), %rsi
leaq 0x6828(%rip), %rdx      # 0xb1fe
callq 0x54a0
movq %rax, -0x1e8(%rbp)
jmp 0x49e4
movq -0x1e8(%rbp), %rax
movq %rax, -0xf8(%rbp)
leaq -0x68(%rbp), %rdi
callq 0x5520
movq %rax, -0x110(%rbp)
leaq -0xf8(%rbp), %rdi
leaq -0x110(%rbp), %rsi
callq 0x5550
testb $0x1, %al
jne 0x4a1b
jmp 0x4a22
movb $0x1, -0xea(%rbp)
testb $0x1, -0xea(%rbp)
jne 0x4baf
callq 0x30c0
movl %eax, -0x114(%rbp)
cmpl $0x0, -0x114(%rbp)
jne 0x4aa3
testb $0x1, -0xe9(%rbp)
je 0x4a55
xorl %esi, %esi
movl %esi, %edi
callq 0x3530
leaq -0x130(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x52b0
jmp 0x4a67
leaq -0x130(%rbp), %rdi
callq 0x96c0
jmp 0x4a75
leaq -0x130(%rbp), %rdi
callq 0x5250
jmp 0x4baa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x130(%rbp), %rdi
callq 0x5250
jmp 0x4e97
cmpl $0x0, -0x114(%rbp)
jle 0x4b98
testb $0x1, -0xe9(%rbp)
jne 0x4b96
movl -0x114(%rbp), %edi
movl -0x114(%rbp), %esi
callq 0x3530
cmpl $-0x1, %eax
jne 0x4ae3
leaq 0x6726(%rip), %rdi      # 0xb200
callq 0x32a0
jmp 0x4ae1
jmp 0x4ae3
movl 0xb82f(%rip), %edi      # 0x10318
movl -0x114(%rbp), %esi
callq 0x34c0
cmpl $0x0, %eax
jne 0x4b84
movl -0x114(%rbp), %edi
leaq -0x118(%rbp), %rsi
movl $0x2, %edx
callq 0x3270
movl %eax, -0x1f4(%rbp)
jmp 0x4b1c
movl -0x1f4(%rbp), %eax
cmpl $0x0, %eax
jge 0x4b3f
leaq 0x66e3(%rip), %rdi      # 0xb211
callq 0x32a0
jmp 0x4b35
movl $0x1, %edi
callq 0x33d0
movl $0x16, %edi
movl $0x1, %esi
callq 0x33b0
movl 0xb7c4(%rip), %edi      # 0x10318
movl 0xb7c2(%rip), %esi      # 0x1031c
callq 0x34c0
cmpl $0x0, %eax
je 0x4b74
leaq 0x66b4(%rip), %rdi      # 0xb21f
callq 0x32a0
jmp 0x4b72
jmp 0x4b74
movl $0x16, %edi
xorl %eax, %eax
movl %eax, %esi
callq 0x33b0
jmp 0x4b94
leaq 0x6694(%rip), %rdi      # 0xb21f
callq 0x32a0
jmp 0x4b92
jmp 0x4b94
jmp 0x4b96
jmp 0x4ba8
leaq 0x6693(%rip), %rdi      # 0xb232
callq 0x32a0
jmp 0x4ba6
jmp 0x4ba8
jmp 0x4baa
jmp 0x4e6d
leaq -0x160(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x52b0
jmp 0x4bc1
leaq -0x148(%rbp), %rdi
leaq -0x160(%rbp), %rsi
callq 0x7470
jmp 0x4bd6
leaq -0x160(%rbp), %rdi
callq 0x5250
leaq -0x148(%rbp), %rdi
callq 0x5590
movq %rax, -0x168(%rbp)
movq $0x0, -0x180(%rbp)
movq -0x180(%rbp), %rax
cmpq -0x168(%rbp), %rax
jae 0x4e1e
movq -0x180(%rbp), %rax
movq -0x168(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
je 0x4c56
leaq -0x170(%rbp), %rdi
callq 0x3480
jmp 0x4c56
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x160(%rbp), %rdi
callq 0x5250
jmp 0x4e97
callq 0x30c0
movl %eax, -0x184(%rbp)
cmpl $0x0, -0x184(%rbp)
jne 0x4d93
cmpq $0x0, -0x180(%rbp)
je 0x4cd1
movl -0x178(%rbp), %edi
xorl %esi, %esi
callq 0x32f0
movl %eax, -0x188(%rbp)
cmpl $-0x1, -0x188(%rbp)
jne 0x4cb5
leaq 0x65a5(%rip), %rdi      # 0xb240
callq 0x32a0
jmp 0x4ca2
jmp 0x4cb5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
jmp 0x4e5f
movl -0x178(%rbp), %edi
callq 0x35c0
jmp 0x4cc2
movl -0x174(%rbp), %edi
callq 0x35c0
jmp 0x4ccf
jmp 0x4cd1
movq -0x180(%rbp), %rax
movq -0x168(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
je 0x4d33
movl -0x16c(%rbp), %edi
movl $0x1, %esi
callq 0x32f0
movl %eax, -0x18c(%rbp)
cmpl $-0x1, -0x18c(%rbp)
jne 0x4d17
leaq 0x6532(%rip), %rdi      # 0xb240
callq 0x32a0
jmp 0x4d15
jmp 0x4d17
movl -0x170(%rbp), %edi
callq 0x35c0
jmp 0x4d24
movl -0x16c(%rbp), %edi
callq 0x35c0
jmp 0x4d31
jmp 0x4d33
movq -0x180(%rbp), %rsi
leaq -0x148(%rbp), %rdi
callq 0x55c0
movq %rax, %rsi
leaq -0x1a8(%rbp), %rdi
callq 0x52b0
jmp 0x4d57
leaq -0x1a8(%rbp), %rdi
callq 0x96c0
jmp 0x4d65
leaq -0x1a8(%rbp), %rdi
callq 0x5250
jmp 0x4e05
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x1a8(%rbp), %rdi
callq 0x5250
jmp 0x4e5f
cmpl $0x0, -0x184(%rbp)
jle 0x4df3
cmpq $0x0, -0x180(%rbp)
je 0x4dc2
movl -0x178(%rbp), %edi
callq 0x35c0
jmp 0x4db3
movl -0x174(%rbp), %edi
callq 0x35c0
jmp 0x4dc0
jmp 0x4dc2
movq -0x180(%rbp), %rax
movq -0x168(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
je 0x4df1
movl -0x170(%rbp), %eax
movl %eax, -0x178(%rbp)
movl -0x16c(%rbp), %eax
movl %eax, -0x174(%rbp)
jmp 0x4e03
leaq 0x6438(%rip), %rdi      # 0xb232
callq 0x32a0
jmp 0x4e01
jmp 0x4e03
jmp 0x4e05
jmp 0x4e07
movq -0x180(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x180(%rbp)
jmp 0x4c00
testb $0x1, -0xe9(%rbp)
jne 0x4e51
jmp 0x4e29
xorl %eax, %eax
movl %eax, %edi
callq 0x3420
movl %eax, -0x1f8(%rbp)
jmp 0x4e3a
movl -0x1f8(%rbp), %eax
movl %eax, -0x1ac(%rbp)
cmpl $0x0, -0x1ac(%rbp)
jg 0x4e29
jmp 0x4e51
leaq -0x148(%rbp), %rdi
callq 0x55e0
jmp 0x4e6d
leaq -0x148(%rbp), %rdi
callq 0x55e0
jmp 0x4e97
jmp 0x4e6f
leaq -0x68(%rbp), %rdi
callq 0x5640
movq 0xb151(%rip), %rax      # 0xffd0
movq (%rax), %rdi
callq 0x33a0
jmp 0x4e89
leaq -0x68(%rbp), %rdi
callq 0x5250
jmp 0x4797
leaq -0x68(%rbp), %rdi
callq 0x5250
jmp 0x4ead
xorl %eax, %eax
addq $0x200, %rsp            # imm = 0x200
popq %rbp
retq
movq -0x38(%rbp), %rdi
callq 0x3570
nopw %cs:(%rax,%rax)