// File: /workspace/github_cpp_makefile_star2_O3/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 0x4894
leaq 0xa0(%rsp), %rdi
callq 0x366c
leaq 0x66ed(%rip), %rdi      # 0x96c0
movl $0x1000, %esi           # imm = 0x1000
callq 0x2110
callq 0x46a4
movq %rax, %rbx
movq %rax, %rdi
callq 0x2040
callq 0x21b0
callq 0x2d68
movq %rax, %rdi
callq 0x2230
testq %rax, %rax
je 0x34e1
movq %rax, %r13
leaq 0x18(%rsp), %r15
leaq 0x100(%rsp), %r14
cmpb $0x0, (%r13)
jne 0x3041
movq %r13, %rdi
callq 0x2300
callq 0x2d68
movq %rax, %rdi
callq 0x2230
movq %rax, %r13
testq %rax, %rax
jne 0x3018
jmp 0x34e1
movq %r13, %rdi
callq 0x2370
movq %rbx, %rdi
callq 0x24d0
movq %r15, %rdi
movq %r13, %rsi
callq 0x3bf4
movq %r13, %rdi
callq 0x2300
movq %r14, %rdi
movq %r15, %rsi
callq 0x36ca
movq %r14, %rdi
callq 0x2c9c
movl %eax, %r12d
movq %r14, %rdi
callq 0x366c
testl %r12d, %r12d
movq %rbx, 0x80(%rsp)
js 0x3156
movl %r12d, %eax
movq 0x6203(%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 0x398c
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 0x398c
movq 0x38(%rsp), %rbx
leaq 0xe8(%rsp), %r15
movq %r15, %rdi
leaq 0x18(%rsp), %rsi
callq 0x36ca
movq %r15, %rdi
callq *%rbx
movq %r15, %rdi
callq 0x366c
movq 0x60(%rsp), %rdi
leaq 0x70(%rsp), %rax
cmpq %rax, %rdi
je 0x3131
movq 0x70(%rsp), %rsi
incq %rsi
callq 0x2290
movq 0x40(%rsp), %rdi
leaq 0x50(%rsp), %rax
cmpq %rax, %rdi
je 0x334d
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x2290
jmp 0x334d
movq 0x20(%rsp), %rdi
addq $-0x20, %rdi
leaq 0x3077(%rip), %rsi      # 0x61dd
callq 0x20b0
movl %eax, %ebp
movq 0x20(%rsp), %rax
testl %ebp, %ebp
je 0x317b
movq %rax, %rsi
jmp 0x31a1
leaq -0x20(%rax), %rsi
movq %rsi, 0x20(%rsp)
movq -0x20(%rax), %rdi
addq $-0x10, %rax
cmpq %rax, %rdi
je 0x31a1
movq (%rax), %rsi
incq %rsi
callq 0x2290
movq 0x20(%rsp), %rsi
movq 0x18(%rsp), %rdi
leaq 0x3032(%rip), %rdx      # 0x61df
callq 0x3b01
cmpq 0x20(%rsp), %rax
je 0x33ce
leaq 0xd0(%rsp), %r12
movq %r12, %rdi
movq %r15, %rsi
callq 0x36ca
leaq 0x38(%rsp), %rdi
movq %r12, %rsi
callq 0x3eb5
movl %ebp, 0x34(%rsp)
movq %r12, %rdi
callq 0x366c
movq 0x40(%rsp), %r12
subq 0x38(%rsp), %r12
je 0x3331
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 0x322c
leaq 0x10(%rsp), %rdi
callq 0x2390
callq 0x2090
testl %eax, %eax
je 0x3270
jle 0x3304
testq %rbx, %rbx
je 0x3252
movl 0xc(%rsp), %edi
callq 0x24e0
movl 0x8(%rsp), %edi
callq 0x24e0
cmpq %rbx, %r13
je 0x32f2
movl 0x10(%rsp), %eax
movl %eax, 0xc(%rsp)
movl 0x14(%rsp), %eax
movl %eax, 0x8(%rsp)
jmp 0x32f2
testq %rbx, %rbx
je 0x329b
movl 0xc(%rsp), %ebp
movl %ebp, %edi
xorl %esi, %esi
callq 0x2250
cmpl $-0x1, %eax
je 0x3312
movl %ebp, %edi
callq 0x24e0
movl 0x8(%rsp), %edi
callq 0x24e0
cmpq %rbx, %r13
je 0x32c5
movl 0x14(%rsp), %edi
movl $0x1, %esi
callq 0x2250
cmpl $-0x1, %eax
je 0x3323
movl 0x10(%rsp), %edi
callq 0x24e0
movl 0x14(%rsp), %edi
callq 0x24e0
movq 0x38(%rsp), %rsi
addq %r15, %rsi
leaq 0xb8(%rsp), %rdi
callq 0x36ca
leaq 0xb8(%rsp), %rbp
movq %rbp, %rdi
callq 0x5093
movq %rbp, %rdi
callq 0x366c
incq %rbx
addq $0x18, %r15
cmpq %rbx, %r12
jne 0x321d
jmp 0x3331
leaq 0x2f08(%rip), %rdi      # 0x6213
callq 0x2210
jmp 0x32f2
leaq 0x2f08(%rip), %rdi      # 0x6221
callq 0x2210
jmp 0x328b
leaq 0x2ef7(%rip), %rdi      # 0x6221
callq 0x2210
jmp 0x32b3
cmpl $0x0, 0x34(%rsp)
je 0x3343
xorl %edi, %edi
callq 0x2350
testl %eax, %eax
jg 0x3338
leaq 0x38(%rsp), %rdi
callq 0x3754
movq 0x18(%rsp), %rbx
movq 0x20(%rsp), %r15
cmpq %rbx, %r15
je 0x338c
leaq 0x10(%rbx), %r12
movq -0x10(%r12), %rdi
cmpq %rdi, %r12
je 0x3376
movq (%r12), %rsi
incq %rsi
callq 0x2290
leaq 0x20(%r12), %rax
addq $0x10, %r12
cmpq %r15, %r12
movq %rax, %r12
jne 0x3360
movq %rbx, 0x20(%rsp)
movq 0x5c3d(%rip), %rax      # 0x8fd0
movq (%rax), %rdi
callq 0x22e0
leaq 0x18(%rsp), %r15
movq %r15, %rdi
callq 0x366c
callq 0x2d68
movq %rax, %rdi
callq 0x2230
movq %rax, %r13
testq %rax, %rax
movq 0x80(%rsp), %rbx
jne 0x3018
jmp 0x34e1
callq 0x2090
testl %eax, %eax
je 0x3463
jle 0x34a5
testl %ebp, %ebp
je 0x334d
movl %eax, %r12d
movl %eax, %edi
movl %eax, %esi
callq 0x2460
cmpl $-0x1, %eax
je 0x34ae
movl 0x5e94(%rip), %edi      # 0x9298
movl %r12d, %esi
callq 0x23d0
testl %eax, %eax
jne 0x34bf
movl %r12d, %edi
leaq 0x38(%rsp), %rsi
movl $0x2, %edx
callq 0x21e0
testl %eax, %eax
js 0x34f5
movl $0x1, %esi
movl $0x16, %edi
callq 0x22f0
movl 0x5e55(%rip), %edi      # 0x9298
movl 0x5e53(%rip), %esi      # 0x929c
callq 0x23d0
testl %eax, %eax
jne 0x34d0
movl $0x16, %edi
xorl %esi, %esi
callq 0x22f0
jmp 0x334d
testl %ebp, %ebp
leaq 0x88(%rsp), %rdi
jne 0x3480
xorl %edi, %edi
xorl %esi, %esi
callq 0x2460
leaq 0x88(%rsp), %rdi
movq %r15, %rsi
callq 0x36ca
leaq 0x88(%rsp), %r15
movq %r15, %rdi
callq 0x5093
movq %r15, %rdi
callq 0x366c
jmp 0x334d
leaq 0x2d67(%rip), %rdi      # 0x6213
jmp 0x34c6
leaq 0x2d2c(%rip), %rdi      # 0x61e1
callq 0x2210
jmp 0x33fe
leaq 0x2d3a(%rip), %rdi      # 0x6200
callq 0x2210
jmp 0x334d
leaq 0x2d29(%rip), %rdi      # 0x6200
callq 0x2210
jmp 0x3452
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 0x3569
jmp 0x3570
movq %rax, %rbx
leaq 0xd0(%rsp), %rdi
jmp 0x3569
jmp 0x3570
jmp 0x3570
movq %rax, %rbx
leaq 0xe8(%rsp), %rdi
callq 0x366c
jmp 0x352f
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x3604
jmp 0x35a7
movq %rax, %rbx
movq 0x40(%rsp), %rdi
leaq 0x50(%rsp), %rax
cmpq %rax, %rdi
je 0x35a7
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x2290
jmp 0x35a7
jmp 0x3570
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
callq 0x366c
jmp 0x35a7
movq %rax, %rbx
jmp 0x35a7
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
jmp 0x35ac
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
callq 0x366c
jmp 0x359d
jmp 0x359a
jmp 0x359a
jmp 0x359a
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x3754
leaq 0x18(%rsp), %rdi
callq 0x366c
movq %rbx, %rdi
callq 0x2490
nop