// File: /workspace/github_cpp_makefile_star2_O1/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
xorps %xmm0, %xmm0
leaq 0xa0(%rsp), %rdi
movaps %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
callq 0x4a54
leaq 0xa0(%rsp), %rdi
callq 0x37f8
leaq 0x655b(%rip), %rdi      # 0x96c0
movl $0x1000, %esi           # imm = 0x1000
callq 0x2110
callq 0x4864
movq %rax, %rbx
movq %rax, %rdi
callq 0x2040
callq 0x21b0
callq 0x2efa
movq %rax, %rdi
callq 0x2230
testq %rax, %rax
je 0x366e
movq %rax, %r13
leaq 0x18(%rsp), %r15
leaq 0x100(%rsp), %r14
cmpb $0x0, (%r13)
jne 0x31d3
movq %r13, %rdi
callq 0x2300
callq 0x2efa
movq %rax, %rdi
callq 0x2230
movq %rax, %r13
testq %rax, %rax
jne 0x31aa
jmp 0x366e
movq %r13, %rdi
callq 0x2370
movq %rbx, %rdi
callq 0x24d0
movq %r15, %rdi
movq %r13, %rsi
callq 0x3d6c
movq %r13, %rdi
callq 0x2300
movq %r14, %rdi
movq %r15, %rsi
callq 0x3854
movq %r14, %rdi
callq 0x2e2c
movl %eax, %r12d
movq %r14, %rdi
callq 0x37f8
testl %r12d, %r12d
movq %rbx, 0x80(%rsp)
js 0x32e8
movl %r12d, %eax
movq 0x6071(%rip), %rbx      # 0x92a0
leaq (%rax,%rax,8), %r15
movq (%rbx,%r15,8), %rax
movq %rax, 0x38(%rsp)
leaq 0x50(%rsp), %rax
movq %rax, 0x40(%rsp)
movq 0x8(%rbx,%r15,8), %rsi
movq 0x10(%rbx,%r15,8), %rdx
addq %rsi, %rdx
leaq 0x40(%rsp), %rdi
callq 0x3b10
leaq (%rbx,%r15,8), %rax
leaq 0x70(%rsp), %rcx
movq %rcx, 0x60(%rsp)
movq 0x28(%rax), %rsi
movq 0x30(%rax), %rdx
addq %rsi, %rdx
leaq 0x60(%rsp), %rdi
callq 0x3b10
movq 0x38(%rsp), %rbx
leaq 0xe8(%rsp), %r15
movq %r15, %rdi
leaq 0x18(%rsp), %rsi
callq 0x3854
movq %r15, %rdi
callq *%rbx
movq %r15, %rdi
callq 0x37f8
movq 0x60(%rsp), %rdi
leaq 0x70(%rsp), %rax
cmpq %rax, %rdi
je 0x32c3
movq 0x70(%rsp), %rsi
incq %rsi
callq 0x2290
movq 0x40(%rsp), %rdi
leaq 0x50(%rsp), %rax
cmpq %rax, %rdi
je 0x34da
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x2290
jmp 0x34da
movq 0x20(%rsp), %rdi
addq $-0x20, %rdi
leaq 0x2ee5(%rip), %rsi      # 0x61dd
callq 0x20b0
movl %eax, %ebp
testl %eax, %eax
jne 0x3329
movq 0x20(%rsp), %rax
leaq -0x20(%rax), %rcx
movq %rcx, 0x20(%rsp)
movq -0x20(%rax), %rdi
addq $-0x10, %rax
cmpq %rax, %rdi
je 0x3329
movq (%rax), %rsi
incq %rsi
callq 0x2290
movq 0x18(%rsp), %rdi
movq 0x20(%rsp), %rsi
leaq 0x2ea5(%rip), %rdx      # 0x61df
callq 0x3c81
cmpq 0x20(%rsp), %rax
je 0x355b
leaq 0xd0(%rsp), %r12
movq %r12, %rdi
movq %r15, %rsi
callq 0x3854
leaq 0x38(%rsp), %rdi
movq %r12, %rsi
callq 0x4032
movl %ebp, 0x34(%rsp)
movq %r12, %rdi
callq 0x37f8
movq 0x40(%rsp), %r12
subq 0x38(%rsp), %r12
je 0x34be
sarq $0x3, %r12
movabsq $-0x5555555555555555, %rax # imm = 0xAAAAAAAAAAAAAAAB
imulq %rax, %r12
leaq -0x1(%r12), %r13
cmpq $0x1, %r12
adcq $0x0, %r12
xorl %r15d, %r15d
xorl %ebx, %ebx
cmpq %rbx, %r13
je 0x33b9
leaq 0x10(%rsp), %rdi
callq 0x2390
callq 0x2090
testl %eax, %eax
je 0x33fd
jle 0x3491
testq %rbx, %rbx
je 0x33df
movl 0xc(%rsp), %edi
callq 0x24e0
movl 0x8(%rsp), %edi
callq 0x24e0
cmpq %rbx, %r13
je 0x347f
movl 0x10(%rsp), %eax
movl %eax, 0xc(%rsp)
movl 0x14(%rsp), %eax
movl %eax, 0x8(%rsp)
jmp 0x347f
testq %rbx, %rbx
je 0x3428
movl 0xc(%rsp), %ebp
movl %ebp, %edi
xorl %esi, %esi
callq 0x2250
cmpl $-0x1, %eax
je 0x349f
movl %ebp, %edi
callq 0x24e0
movl 0x8(%rsp), %edi
callq 0x24e0
cmpq %rbx, %r13
je 0x3452
movl 0x14(%rsp), %edi
movl $0x1, %esi
callq 0x2250
cmpl $-0x1, %eax
je 0x34b0
movl 0x10(%rsp), %edi
callq 0x24e0
movl 0x14(%rsp), %edi
callq 0x24e0
movq 0x38(%rsp), %rsi
addq %r15, %rsi
leaq 0xb8(%rsp), %rdi
callq 0x3854
leaq 0xb8(%rsp), %rbp
movq %rbp, %rdi
callq 0x5253
movq %rbp, %rdi
callq 0x37f8
incq %rbx
addq $0x18, %r15
cmpq %rbx, %r12
jne 0x33aa
jmp 0x34be
leaq 0x2d7b(%rip), %rdi      # 0x6213
callq 0x2210
jmp 0x347f
leaq 0x2d7b(%rip), %rdi      # 0x6221
callq 0x2210
jmp 0x3418
leaq 0x2d6a(%rip), %rdi      # 0x6221
callq 0x2210
jmp 0x3440
cmpl $0x0, 0x34(%rsp)
je 0x34d0
xorl %edi, %edi
callq 0x2350
testl %eax, %eax
jg 0x34c5
leaq 0x38(%rsp), %rdi
callq 0x38de
movq 0x18(%rsp), %rbx
movq 0x20(%rsp), %r15
cmpq %rbx, %r15
je 0x3519
leaq 0x10(%rbx), %r12
movq -0x10(%r12), %rdi
cmpq %rdi, %r12
je 0x3503
movq (%r12), %rsi
incq %rsi
callq 0x2290
leaq 0x20(%r12), %rax
addq $0x10, %r12
cmpq %r15, %r12
movq %rax, %r12
jne 0x34ed
movq %rbx, 0x20(%rsp)
movq 0x5ab0(%rip), %rax      # 0x8fd0
movq (%rax), %rdi
callq 0x22e0
leaq 0x18(%rsp), %r15
movq %r15, %rdi
callq 0x37f8
callq 0x2efa
movq %rax, %rdi
callq 0x2230
movq %rax, %r13
testq %rax, %rax
movq 0x80(%rsp), %rbx
jne 0x31aa
jmp 0x366e
callq 0x2090
testl %eax, %eax
je 0x35f0
jle 0x3632
testl %ebp, %ebp
je 0x34da
movl %eax, %r12d
movl %eax, %edi
movl %eax, %esi
callq 0x2460
cmpl $-0x1, %eax
je 0x363b
movl 0x5d07(%rip), %edi      # 0x9298
movl %r12d, %esi
callq 0x23d0
testl %eax, %eax
jne 0x364c
movl %r12d, %edi
leaq 0x38(%rsp), %rsi
movl $0x2, %edx
callq 0x21e0
testl %eax, %eax
js 0x3682
movl $0x1, %esi
movl $0x16, %edi
callq 0x22f0
movl 0x5cc8(%rip), %edi      # 0x9298
movl 0x5cc6(%rip), %esi      # 0x929c
callq 0x23d0
testl %eax, %eax
jne 0x365d
movl $0x16, %edi
xorl %esi, %esi
callq 0x22f0
jmp 0x34da
testl %ebp, %ebp
leaq 0x88(%rsp), %rdi
jne 0x360d
xorl %edi, %edi
xorl %esi, %esi
callq 0x2460
leaq 0x88(%rsp), %rdi
movq %r15, %rsi
callq 0x3854
leaq 0x88(%rsp), %r15
movq %r15, %rdi
callq 0x5253
movq %r15, %rdi
callq 0x37f8
jmp 0x34da
leaq 0x2bda(%rip), %rdi      # 0x6213
jmp 0x3653
leaq 0x2b9f(%rip), %rdi      # 0x61e1
callq 0x2210
jmp 0x358b
leaq 0x2bad(%rip), %rdi      # 0x6200
callq 0x2210
jmp 0x34da
leaq 0x2b9c(%rip), %rdi      # 0x6200
callq 0x2210
jmp 0x35df
xorl %eax, %eax
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x2500
movq %rax, %rbx
leaq 0x88(%rsp), %rdi
jmp 0x36f6
jmp 0x36fd
movq %rax, %rbx
leaq 0xd0(%rsp), %rdi
jmp 0x36f6
jmp 0x36fd
jmp 0x36fd
movq %rax, %rbx
leaq 0xe8(%rsp), %rdi
callq 0x37f8
jmp 0x36bc
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x3790
jmp 0x3734
movq %rax, %rbx
movq 0x40(%rsp), %rdi
leaq 0x50(%rsp), %rax
cmpq %rax, %rdi
je 0x3734
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x2290
jmp 0x3734
jmp 0x36fd
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
callq 0x37f8
jmp 0x3734
movq %rax, %rbx
jmp 0x3734
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
jmp 0x3739
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
callq 0x37f8
jmp 0x372a
jmp 0x3727
jmp 0x3727
jmp 0x3727
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x38de
leaq 0x18(%rsp), %rdi
callq 0x37f8
movq %rbx, %rdi
callq 0x2490