// PID: 730677144 // I pledge the COMP 211 honor code. // All necessary libraries are included in shell.h #include "shell.h" void alloc_mem_for_argv(command_t* p_cmd) { p_cmd->argv = (char**)malloc((p_cmd->argc + 1) * sizeof(char*)); for (int i = 0; i < p_cmd->argc; i++) { p_cmd->argv[i] = (char*)malloc(MAX_ARG_LEN * sizeof(char)); } p_cmd->argv[p_cmd->argc] = NULL; } void cleanup(command_t* p_cmd) { for (int i = 0; i < p_cmd->argc; i++) { free(p_cmd->argv[i]); p_cmd->argv[i] = NULL; } } /** * Parses line (input from user) into command_t* p_cmd. * * Determine the number of arguments via string parsing. * Then, set p_cmd->argc to the correct value, * and allocate memory for p_cmd->argv. * Finally, ***copy*** the arguments from line into p_cmd->argv. * * When copying the arguments, do not simply assign pointers. You must * use str(n)cpy (or reimplement its logic) to copy the arguments. * * p_cmd is NULL when this function is called (see main.c). * * Example 1: If line is "cd /mnt/cdrom", then the fields in p_cmd should be * {argc = 2, argv = {"cd", "mnt/cdrom", NULL}} * * Example 2: If line is "ls -la", then the fields in p_cmd should be * {argc = 2, argv = {"ls, "-la", NULL}} * * Example 3: If line is NULL, then the fields in p_cmd should be {argc = * 0, argv = {NULL}} * * Example 4: If line is " ls -la ", then the fields in p_cmd should be * the same as in example 2. Note the additional whitespace in the input. * * We recommend using strtok to handle this parsing. * https://systems-encyclopedia.cs.illinois.edu/articles/c-strtok/ * * strtok's functionality is similar to that of split in Python or Java. * For example, in Python, we can do * * >>> "cd /mnt/cdrom".split(" ") * ['cd', '/mnt/cdrom'] * * When used correctly, strtok will handle all of the above cases correctly. * Alternatively, you may reimplement tokenizing logic yourself, but be sure to * handle example 4 (extra whitespace) correctly. * * NOTE: strtok mutates the input char* (by inserting null terminators). So, to * be safe, you should use strtok on a clone of the input char*. You can create * a clone using strdup. * * @param line string input from user * @param p_cmd pointer to struct that will store the parsed command * @return void */ void parse(char* line, command_t* p_cmd) { char* line_copy = strdup(line); char* argc_token = strtok(line_copy, " "); p_cmd->argc = 0; while (argc_token != NULL) { p_cmd->argc++; argc_token = strtok(NULL, " "); } alloc_mem_for_argv(p_cmd); line_copy = strdup(line); char* argv_token = strtok(line_copy, " "); for (int i = 0; i < p_cmd->argc; i++) { strcpy(p_cmd->argv[i], argv_token); argv_token = strtok(NULL, " "); } } bool find_full_path(command_t* p_cmd) { // TODO: return true; } int execute(command_t* p_cmd) { // TODO: return 0; } bool is_builtin(command_t* p_cmd) { // Do not modify char* executable = p_cmd->argv[0]; if (strcmp(executable, "cd") == 0 || strcmp(executable, "exit") == 0) { return true; } return false; } int do_builtin(command_t* p_cmd) { // Do not modify if (strcmp(p_cmd->argv[0], "exit") == 0) { exit(SUCCESS); } // cd if (p_cmd->argc == 1) { // cd with no arguments return chdir(getenv("HOME")); } else if (p_cmd->argc == 2) { // cd with 1 arg return chdir(p_cmd->argv[1]); } else { fprintf(stderr, "cd: Too many arguments\n"); return ERROR; } }