aboutsummaryrefslogtreecommitdiffstats
path: root/src/standalone/lab07/setup-argv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/standalone/lab07/setup-argv.c')
-rw-r--r--src/standalone/lab07/setup-argv.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/standalone/lab07/setup-argv.c b/src/standalone/lab07/setup-argv.c
new file mode 100644
index 0000000..f2bd04a
--- /dev/null
+++ b/src/standalone/lab07/setup-argv.c
@@ -0,0 +1,277 @@
+#define _POSIX_C_SOURCE 2
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ YOUR WORK:
+
+ You will complete the function setup_main_stack below. Missing code
+ and calculations are expressed with a questionmark (?). The
+ assignment is mostly about doing the correct math. To do that math
+ you will need to learn or understand:
+
+ - How the stack is used during program execution
+ - How the stack is expected to look like at start of a C-program
+ - What a pointer variable is, how it is used
+ - How a C-array (pointer to many) is laid-out in memory
+ - How pointer arithmetic behaves
+ - How to cast from one pointer type to another
+ - How to use printf to print good debug information
+ - How to use a C-struct, both object and pointer to
+
+ Some manual-pages of interest:
+
+ man -s3 printf
+ man -s3 strlen
+ man -s3 strncpy
+ man -s3 strtok_r
+
+ The prototype for above functions:
+
+ int printf(const char *restrict format, ...);
+ size_t strlen(const char *s);
+ size_t strncpy(char *dst, const char *src, size_t dstsize);
+ char *strtok_r(char *s1, const char *s2, char **lasts);
+
+ The above functions exist in Pintos code. Note the Pintos use
+ 'strlcpy' instead of 'strncpy'. If 'dst' is large enough they behave
+ identical. You can find Pintos implementations in
+ /home/TDIU16/labs/skel/pintos/src/lib, see string.c and stdio.c. It
+ is strongly recommendable to look at the strtok_r examples given in
+ string.c
+
+ About *restrict: http://en.wikipedia.org/wiki/Pointer_alias
+
+
+ Recommended compile command:
+
+ gcc -m32 -Wall -Wextra -std=gnu99 -g setup-argv.c
+
+*/
+#error Read comments above, then remove this line.
+
+#define true 1
+#define false 0
+
+typedef int bool;
+
+/* "struct main_args" represent the stack as it must look when
+ * entering main. The only issue: argv must point somewhere...
+ *
+ * The members of this structure is is directly related to the
+ * arguments of main in a C-program, of course.
+ *
+ * int main(int argc, char* argv[]);
+ *
+ * (char** argv is a more generic form of char* argv[])
+ *
+ * The function pointer is normally handled by the compiler
+ * automatically, and determine the address at where a function shall
+ * continue when it returns. The main function does not use it, as the
+ * operating system arrange for the program to stop execution when
+ * main is finished.
+ */
+struct main_args
+{
+ /* Hint: When try to interpret C-declarations, read from right to
+ * left! It is often easier to get the correct interpretation,
+ * altough it does not always work. */
+
+ /* Variable "ret" that stores address (*ret) to a function taking no
+ * parameters (void) and returning nothing. */
+ void (*ret)(void);
+
+ /* Just a normal integer. */
+ int argc;
+
+ /* Variable "argv" that stores address to an address storing char.
+ * That is: argv is a pointer to char*
+ */
+ char** argv;
+};
+
+/* A function that dumps 'size' bytes of memory starting at 'ptr'
+ * it will dump the higher adress first letting the stack grow down.
+ */
+void dump(void* ptr, int size)
+{
+ int i;
+ const int S = sizeof(void*);
+
+ printf("%2$-*1$s \t%3$-*1$s \t%4$-*1$s\n", S*2, "Address", "hex-data", "char-data");
+
+ for (i = size - 1; i >= 0; --i)
+ {
+ void** adr = (void**)((unsigned long)ptr + i);
+ unsigned char* byte = (unsigned char*)((unsigned long)ptr + i);
+
+ printf("%0*lx\t", S*2, (unsigned long)ptr + i); /* address */
+
+ if ((i % S) == 0)
+ /* seems we're actually forbidden to read unaligned adresses */
+ printf("%0*lx\t", S*2, (unsigned long)*adr); /* content interpreted as address */
+ else
+ printf("%*c\t", S*2, ' '); /* fill */
+
+ if(*byte >= 32 && *byte < 127)
+ printf("%c\n", *byte); /* content interpreted as character */
+ else
+ printf("\\%o\n", *byte);
+
+ if ((i % S) == 0)
+ printf("----------------------------------------------------------------\n");
+ }
+}
+
+/* Read one line of input ...
+ */
+void custom_getline(char buf[], int size)
+{
+ int i;
+ for (i = 0; i < (size - 1); ++i)
+ {
+ buf[i] = getchar();
+ if (buf[i] == '\n')
+ break;
+ }
+ buf[i] = '\0';
+}
+
+/* Return true if 'c' is fount in the c-string 'd'
+ * NOTE: 'd' must be a '\0'-terminated c-string
+ */
+bool exists_in(char c, const char* d)
+{
+ int i = 0;
+ while (d[i] != '\0' && d[i] != c)
+ ++i;
+ return (d[i] == c);
+}
+
+/* Return the number of words in 'buf'. A word is defined as a
+ * sequence of characters not containing any of the characters in
+ * 'delimeters'.
+ * NOTE: arguments must be '\0'-terminated c-strings
+ */
+int count_args(const char* buf, const char* delimeters)
+{
+ int i = 0;
+ bool prev_was_delim;
+ bool cur_is_delim = true;
+ int argc = 0;
+
+ while (buf[i] != '\0')
+ {
+ prev_was_delim = cur_is_delim;
+ cur_is_delim = exists_in(buf[i], delimeters);
+ argc += (prev_was_delim && !cur_is_delim);
+ ++i;
+ }
+ return argc;
+}
+
+/* Replace calls to STACK_DEBUG with calls to printf. All such calls
+ * easily removed later by replacing with nothing. */
+#define STACK_DEBUG(...) printf(__VA_ARGS__)
+
+void* setup_main_stack(const char* command_line, void* stack_top)
+{
+ /* Variable "esp" stores an address, and at the memory loaction
+ * pointed out by that address a "struct main_args" is found.
+ * That is: "esp" is a pointer to "struct main_args" */
+ struct main_args* esp;
+ int argc;
+ int total_size;
+ int line_size;
+ int cmdl_size;
+
+ /* "cmd_line_on_stack" and "ptr_save" are variables that each store
+ * one address, and at that address (the first) char (of a possible
+ * sequence) can be found. */
+ char* cmd_line_on_stack;
+ char* ptr_save;
+ int i = 0;
+
+
+ /* calculate the bytes needed to store the command_line */
+ line_size = YOUR_CODE_HERE;
+ STACK_DEBUG("# line_size = %d\n", line_size);
+
+ /* round up to make it even divisible by 4 */
+ line_size = YOUR_CODE_HERE;
+ STACK_DEBUG("# line_size (aligned) = %d\n", line_size);
+
+ /* calculate how many words the command_line contain */
+ argc = YOUR_CODE_HERE;
+ STACK_DEBUG("# argc = %d\n", argc);
+
+ /* calculate the size needed on our simulated stack */
+ total_size = YOUR_CODE_HERE;
+ STACK_DEBUG("# total_size = %d\n", total_size);
+
+
+ /* calculate where the final stack top will be located */
+ esp = YOUR_CODE_HERE;
+
+ /* setup return address and argument count */
+ esp->ret = YOUR_CODE_HERE;
+ esp->argc = YOUR_CODE_HERE;
+ /* calculate where in the memory the argv array starts */
+ esp->argv = YOUR_CODE_HERE;
+
+ /* calculate where in the memory the words is stored */
+ cmd_line_on_stack = YOUR_CODE_HERE;
+
+ /* copy the command_line to where it should be in the stack */
+
+ /* build argv array and insert null-characters after each word */
+
+ return esp; /* the new stack top */
+}
+
+/* The C way to do constants ... */
+#define LINE_SIZE 1024
+
+int main()
+{
+ struct main_args* esp;
+ char line[LINE_SIZE];
+ void* simulated_stack = malloc(4096);
+ void* simulated_stack_top = (void*)((unsigned long)simulated_stack + 4096);
+ int i;
+ const int S = sizeof(void*);
+
+ /* read one line of input, this will be the command-line */
+ printf("Enter a command line: ");
+ custom_getline(line, LINE_SIZE);
+
+ /* put initial content on our simulated stack */
+ esp = setup_main_stack(line, simulated_stack_top);
+ printf("# esp = %0*lx\n", 2*S, (unsigned long)esp);
+
+ if ( (char*)esp >= (char*)simulated_stack_top ||
+ (char*)esp < (char*)simulated_stack )
+ {
+ printf("# ERROR: esp is not inside the allocated stack\n");
+ return 1;
+ }
+
+ /* dump memory area for verification */
+ dump(esp, (char*)simulated_stack_top - (char*)esp);
+
+ /* original command-line should not be needed anymore */
+ for (i = 0; i < LINE_SIZE; ++i)
+ line[i] = (char)0xCC;
+
+ /* print the argument vector to see if it worked */
+ for (i = 0; i < esp->argc; ++i)
+ {
+ printf("argv[%d] = %s\n", i, esp->argv[i]);
+ }
+ printf("argv[%d] = %p\n", i, esp->argv[i]);
+
+ free(simulated_stack);
+
+ return 0;
+}