diff --git a/userprog/argument_parsing.h b/userprog/argument_parsing.h index 37b47e8003c0e7bdbc9cd3cabcb1eca421e8aa82..b84be707d1c4adb0e17dfeb8f92c75ce4908e8e7 100644 --- a/userprog/argument_parsing.h +++ b/userprog/argument_parsing.h @@ -1,14 +1,26 @@ +/* + * argument_parsing.h --prototypes functions required for parsing arguments from + * command line and placing these into the program stack structure. + * + * Authored by Joshua Saxby + */ #ifndef USERPROG_ARGUMENT_PARSING_H #define USERPROG_ARGUMENT_PARSING_H + +// some macros for argument length and count limits +// TODO: decide how many arguments we want --is 255 the standard number? +#define USERPROG_ARGV_COUNT 255 +// TODO: clarify what a sensible value for this is +#define USERPROG_RAW_ARGV_LENGTH 255 + /* * Given a string containing the command invoking the program `command_line` - * and a pointer to an array of C strings (pointer to `char* argv[]`), parse - * `command_line` into individual arguments, populate `argv` with these and - * return the number of arguments that were parsed (this is the value that can - * be used for `argc`). + * and an array of C strings (pointer to `char* argv[]`), parse `command_line` + * into individual arguments, populate `argv` with these and return the number + * of arguments that were parsed (this is the value that can be used for `argc`). */ -int parse_arguments(const char* command_line, char***argv); +int parse_arguments(const char* command_line, char**argv); /* * Given stack pointer `esp`, argument count `argc` and arguments array `argv`, diff --git a/userprog/parse_arguments.c b/userprog/parse_arguments.c index aeaefd0778156808a54f8c2b1da7b1197886efbc..9de6f294fa5d77fc3319b6a36cb7c52458ed1241 100644 --- a/userprog/parse_arguments.c +++ b/userprog/parse_arguments.c @@ -1,6 +1,29 @@ +/* + * parse_arguments.c --implements function for parsing a command-line string + * into the program arguments contained within it. + * + * Authored by Joshua Saxby + */ +#include <stddef.h> +#include <string.h> + #include "userprog/argument_parsing.h" -int parse_arguments(const char* command_line, char***argv) { - #warning "Implement me" +int parse_arguments(const char* command_line, char**argv) { + int argc = 0; + // the state pointer required by strtok_r() for use between calls + char* state_pointer; + // first call to strtok_r() is the only one where string to parse is passed + argv[0] = strtok_r(command_line, " ", &state_pointer); + argc++; + // now, parse token-by-token for any additional arguments + char* token = strtok_r(NULL, " ", &state_pointer); + // continue while still tokens to read and maximum arg count is not reached + while (token != NULL && argc < USERPROG_ARGV_COUNT) { + argv[argc] = token; + argc++; + token = strtok_r(NULL, " ", &state_pointer); + } + return argc; } diff --git a/userprog/process.c b/userprog/process.c index e5b66aa9108910c254ec627497800cadc2c3b0bb..98ff0aaff1c93c0851eefa08c7a947534314f5d0 100644 --- a/userprog/process.c +++ b/userprog/process.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "userprog/argument_parsing.h" #include "userprog/gdt.h" #include "userprog/pagedir.h" #include "userprog/tss.h" @@ -20,7 +21,6 @@ static thread_func start_process NO_RETURN; static bool load (const char *cmdline, void (**eip) (void), void **initial_stack_pointer); - /* Starts a new thread running a user program loaded by parsing COMMAND. The new thread may be scheduled (and may even exit) before process_execute() returns. Returns the new process's @@ -29,24 +29,22 @@ tid_t process_execute (const char *command) { char *command_copy; - tid_t tid; - /* Make a copy of COMMAND. Otherwise there's a race between the caller and load(). */ command_copy = palloc_get_page (0); if (command_copy == NULL) return TID_ERROR; strlcpy (command_copy, command, PGSIZE); + // we need to extract out the filename from the command string + char* file_name; + char* save_ptr; // this is the save pointer expected by strtok_r() + // file name is the first part of the command-line (space-delimited) + file_name = strtok_r(command, " ", &save_ptr); + tid_t tid; + /* Create a new thread to execute COMMAND. */ - /* - * FIXME: right now, COMMAND is assumed to be just the filename on its own - * - * If this is not the case (if the user passed a program name with arguments), - * then loading will fail. - * NOTE: remove this comment block when argument parsing is implemented. - */ - tid = thread_create (command, PRI_DEFAULT, start_process, command_copy); + tid = thread_create (file_name, PRI_DEFAULT, start_process, command_copy); if (tid == TID_ERROR) palloc_free_page (command_copy); @@ -218,7 +216,7 @@ static bool load_segment (struct file *file, off_t ofs, uint8_t *upage, uint32_t read_bytes, uint32_t zero_bytes, bool writable); -/* Loads an ELF executable from FILE_NAME into the current thread. +/* Loads an ELF executable from COMMAND into the current thread. Stores the executable's entry point into *EIP and its initial stack pointer into *initial_stack_pointer. Returns true if successful, false otherwise. */ @@ -232,6 +230,14 @@ load (const char *cmdline, void (**eip) (void), void **initial_stack_pointer) bool success = false; int i; + // extract arguments (including file name) + char* argv[USERPROG_ARGV_COUNT]; + // copy the command string so we have a separate copy to manipulate + char command_copy[USERPROG_RAW_ARGV_LENGTH]; + strlcpy(command_copy, cmdline, USERPROG_RAW_ARGV_LENGTH); + int argc = parse_arguments(command_copy, argv); + char* file_name = argv[0]; // file name is always argument 0 + /* Allocate and activate page directory. */ t->pagedir = pagedir_create (); if (t->pagedir == NULL) @@ -239,7 +245,7 @@ load (const char *cmdline, void (**eip) (void), void **initial_stack_pointer) process_activate (); /* Open executable file. */ - file = filesys_open (cmdline); + file = filesys_open (file_name); if (file == NULL) { @@ -320,7 +326,7 @@ load (const char *cmdline, void (**eip) (void), void **initial_stack_pointer) } /* Set up stack. */ - if (!setup_stack (initial_stack_pointer)) + if (!setup_stack (initial_stack_pointer, argv, argc)) goto done; /* Start address. */ @@ -456,6 +462,7 @@ setup_stack (void **initial_stack_pointer, char **argv, int argc) success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true); if (success) { *initial_stack_pointer = PHYS_BASE - 12; + populate_stack(initial_stack_pointer, argc, argv); } else palloc_free_page (kpage); }