// File: /workspace/github_cpp_makefile_star2_O2/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 0x80(%rsp), %rdi
movaps %xmm0, (%rdi)
andq $0x0, 0x10(%rdi)
callq 0x41e8
leaq 0x80(%rsp), %rdi
callq 0x3196
leaq 0x6abb(%rip), %rdi      # 0x96d0
movl $0x1000, %esi           # imm = 0x1000
callq 0x2140
callq 0x404c
movq %rax, %r14
movq %rax, %rdi
callq 0x2040
callq 0x21e0
leaq 0x18(%rsp), %rbp
callq 0x29f7
movq %rax, %rdi
callq 0x2260
testq %rax, %rax
je 0x2ff6
movq %rax, %r12
cmpb $0x0, (%rax)
jne 0x2c61
movq %r12, %rdi
callq 0x2310
jmp 0x2c39
movq %r12, %rdi
callq 0x2390
movq %r14, %rdi
callq 0x24d0
movq %rbp, %rdi
movq %r12, %rsi
callq 0x3780
movq %r12, %rdi
callq 0x2310
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x31b8
movq %rbx, %rdi
callq 0x297c
movl %eax, %r12d
movq %rbx, %rdi
callq 0x3196
testl %r12d, %r12d
js 0x2cfb
movl %r12d, %eax
imulq $0x48, %rax, %rsi
addq 0x65f3(%rip), %rsi      # 0x92b0
leaq 0x38(%rsp), %rdi
callq 0x320c
movq 0x38(%rsp), %rbx
leaq 0xe8(%rsp), %r12
movq %r12, %rdi
movq %rbp, %rsi
callq 0x31b8
movq %r12, %rdi
callq *%rbx
movq %r12, %rdi
callq 0x3196
leaq 0x38(%rsp), %rdi
callq 0x3132
jmp 0x2ecc
movq 0x20(%rsp), %rdi
addq $-0x20, %rdi
leaq 0x24e1(%rip), %rsi      # 0x51ec
callq 0x3259
movl %eax, %r12d
testb %al, %al
je 0x2d2a
movq 0x20(%rsp), %rdi
addq $-0x20, %rdi
movq %rdi, 0x20(%rsp)
callq 0x2120
movq 0x18(%rsp), %rdi
movq 0x20(%rsp), %rsi
leaq 0x24b3(%rip), %rdx      # 0x51ee
callq 0x3603
cmpq 0x20(%rsp), %rax
je 0x2ef0
leaq 0xd0(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x31b8
movb %r12b, 0xb(%rsp)
movq %r14, 0x30(%rsp)
leaq 0x38(%rsp), %rdi
movq %rbx, %rsi
callq 0x3a0d
movq %rbx, %rdi
callq 0x3196
movq 0x40(%rsp), %rax
subq 0x38(%rsp), %rax
cqto
pushq $0x18
popq %rcx
idivq %rcx
movq %rax, %r12
leaq -0x1(%rax), %r14
xorl %ebx, %ebx
xorl %ebp, %ebp
cmpq %rbp, %r12
je 0x2ea6
cmpq %rbp, %r14
je 0x2db2
leaq 0x10(%rsp), %rdi
callq 0x23b0
callq 0x20a0
testl %eax, %eax
je 0x2def
jle 0x2e79
testq %rbp, %rbp
je 0x2dd7
movl %r15d, %edi
callq 0x24f0
movl 0xc(%rsp), %edi
callq 0x24f0
cmpq %rbp, %r14
je 0x2e6d
movl 0x10(%rsp), %r15d
movl 0x14(%rsp), %eax
movl %eax, 0xc(%rsp)
jmp 0x2e6d
testq %rbp, %rbp
je 0x2e18
movl %r15d, %edi
xorl %esi, %esi
callq 0x2280
cmpl $-0x1, %eax
je 0x2e87
movl %r15d, %edi
callq 0x24f0
movl 0xc(%rsp), %edi
callq 0x24f0
cmpq %rbp, %r14
je 0x2e40
movl 0x14(%rsp), %edi
pushq $0x1
popq %rsi
callq 0x2280
cmpl $-0x1, %eax
je 0x2e98
movl 0x10(%rsp), %edi
callq 0x24f0
movl 0x14(%rsp), %edi
callq 0x24f0
movq 0x38(%rsp), %rsi
addq %rbx, %rsi
leaq 0xa0(%rsp), %rdi
callq 0x31b8
leaq 0xa0(%rsp), %r13
movq %r13, %rdi
callq 0x485f
movq %r13, %rdi
callq 0x3196
incq %rbp
addq $0x18, %rbx
jmp 0x2d9a
leaq 0x23a2(%rip), %rdi      # 0x5222
callq 0x2240
jmp 0x2e6d
leaq 0x23a2(%rip), %rdi      # 0x5230
callq 0x2240
jmp 0x2e07
leaq 0x2391(%rip), %rdi      # 0x5230
callq 0x2240
jmp 0x2e2e
cmpb $0x0, 0xb(%rsp)
movq 0x30(%rsp), %r14
leaq 0x18(%rsp), %rbp
jne 0x2ec2
xorl %edi, %edi
callq 0x2360
testl %eax, %eax
jg 0x2eb7
leaq 0x38(%rsp), %rdi
callq 0x3266
movq %rbp, %rdi
callq 0x3288
movq 0x60ed(%rip), %rax      # 0x8fc8
movq (%rax), %rdi
callq 0x22f0
movq %rbp, %rdi
callq 0x3196
jmp 0x2c39
movl %r12d, %ebx
callq 0x20a0
testl %eax, %eax
je 0x2f80
jle 0x2fba
testb %bl, %bl
jne 0x2ecc
movl %eax, %r12d
movl %eax, %edi
movl %eax, %esi
callq 0x2480
cmpl $-0x1, %eax
je 0x2fc3
movl 0x6383(%rip), %edi      # 0x92a8
movl %r12d, %esi
callq 0x2400
testl %eax, %eax
jne 0x2fd4
movl %r12d, %edi
leaq 0x38(%rsp), %rsi
pushq $0x2
popq %rdx
callq 0x2210
testl %eax, %eax
js 0x300a
pushq $0x16
popq %r12
movl %r12d, %edi
pushq $0x1
popq %rsi
callq 0x2300
movl 0x6346(%rip), %edi      # 0x92a8
movl 0x6344(%rip), %esi      # 0x92ac
callq 0x2400
testl %eax, %eax
jne 0x2fe5
movl %r12d, %edi
xorl %esi, %esi
callq 0x2300
jmp 0x2ecc
testb %bl, %bl
je 0x2f8d
xorl %edi, %edi
xorl %esi, %esi
callq 0x2480
leaq 0xb8(%rsp), %rdi
movq %rbp, %rsi
callq 0x31b8
leaq 0xb8(%rsp), %r12
movq %r12, %rdi
callq 0x485f
movq %r12, %rdi
callq 0x3196
jmp 0x2ecc
leaq 0x2261(%rip), %rdi      # 0x5222
jmp 0x2fdb
leaq 0x2226(%rip), %rdi      # 0x51f0
callq 0x2240
jmp 0x2f1f
leaq 0x2234(%rip), %rdi      # 0x520f
callq 0x2240
jmp 0x2ecc
leaq 0x2223(%rip), %rdi      # 0x520f
callq 0x2240
jmp 0x2f71
xorl %eax, %eax
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x21f0(%rip), %rdi      # 0x5201
callq 0x2240
pushq $0x1
popq %rdi
callq 0x2320
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
jmp 0x306c
jmp 0x3073
movq %rax, %rbx
leaq 0xd0(%rsp), %rdi
jmp 0x306c
jmp 0x3073
jmp 0x3073
movq %rax, %rbx
leaq 0xe8(%rsp), %rdi
callq 0x3196
jmp 0x3053
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x3132
jmp 0x30aa
jmp 0x3073
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
callq 0x3196
jmp 0x30aa
movq %rax, %rbx
jmp 0x30aa
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
jmp 0x30af
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
callq 0x3196
jmp 0x30a0
jmp 0x309d
jmp 0x309d
jmp 0x309d
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x3266
leaq 0x18(%rsp), %rdi
callq 0x3196
movq %rbx, %rdi
callq 0x24a0