aboutsummaryrefslogtreecommitdiffstats
path: root/src/standalone
diff options
context:
space:
mode:
authorklaar36 <klas.arvidsson@liu.se>2017-03-20 17:59:45 +0100
committerklaar36 <klas.arvidsson@liu.se>2017-03-20 17:59:45 +0100
commitf9003d89b17c039ab903f622580e61925e137523 (patch)
treeb46ab4f9745c96a78685ca29b6a18ed2531205d6 /src/standalone
parentd9ae213323d0a036b7f3594de6822413a4c312c6 (diff)
downloadpintos-rs-f9003d89b17c039ab903f622580e61925e137523.tar.gz
added given files for standalone labs
Diffstat (limited to 'src/standalone')
-rw-r--r--src/standalone/upg1/basics.c6
-rw-r--r--src/standalone/upg2/about-main.c6
-rw-r--r--src/standalone/upg3/fork-wait.c95
-rw-r--r--src/standalone/upg4/use-list.c42
-rw-r--r--src/standalone/upg5/pagedir.c8
-rw-r--r--src/standalone/upg5/pagedir.h42
-rw-r--r--src/standalone/upg5/thread.h16
-rw-r--r--src/standalone/upg5/verify_adr.c90
-rw-r--r--src/standalone/upg6/main.c124
-rw-r--r--src/standalone/upg6/map.c1
-rw-r--r--src/standalone/upg6/map.h1
-rw-r--r--src/standalone/upg7/debug.c27
-rw-r--r--src/standalone/upg8/setup-argv.c265
13 files changed, 723 insertions, 0 deletions
diff --git a/src/standalone/upg1/basics.c b/src/standalone/upg1/basics.c
new file mode 100644
index 0000000..62bc52c
--- /dev/null
+++ b/src/standalone/upg1/basics.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+}
diff --git a/src/standalone/upg2/about-main.c b/src/standalone/upg2/about-main.c
new file mode 100644
index 0000000..2407c23
--- /dev/null
+++ b/src/standalone/upg2/about-main.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char* argv[])
+{
+}
diff --git a/src/standalone/upg3/fork-wait.c b/src/standalone/upg3/fork-wait.c
new file mode 100644
index 0000000..2e7729d
--- /dev/null
+++ b/src/standalone/upg3/fork-wait.c
@@ -0,0 +1,95 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* The printf text serve as further comments. Read it. */
+
+int main(int argc, char* argv[])
+{
+ pid_t pid;
+ char dummy[16];
+
+ if (argc < 2)
+ {
+ printf("You need to specify a program as argument 1.\n");
+ exit(1); /* Terminate the process with error (1). */
+ }
+
+ printf("P | Switch to a differen terminal.\n"
+ "P | Execute the command \"ptree $USER\".\n"
+ "P | It will show a list of processes you are running.\n"
+ "P | You should see the process '%s' once.\n"
+ "P | Press enter when you verified that.\n\n", argv[0]);
+
+ /* Wait until enter is pressed (gives you time...) */
+ fgets(dummy, 16, stdin);
+
+ printf("P | This process will now clone itself with fork.\n"
+ "P | One (almost) identical copy will be started.\n"
+ "P | The only difference is the result of fork()\n\n");
+
+ pid = fork();
+
+ if (pid == 0)
+ {
+ printf(" C | This is printed by the new process (the CHILD)\n"
+ " C | The child get a 0 return value from fork.\n\n");
+
+ printf(" C | Repeat the previous command in the other terminal.\n"
+ " C | You should see the process '%s' twice now.\n"
+ " C | (grep for it if you run many processes)\n"
+ " C | Press enter when you verified that.\n\n", argv[0]);
+
+ /* Wait until enter is pressed (gives you time...) */
+ fgets(dummy, 16, stdin);
+
+ printf(" C | The program specified as first argument (%s) on the \n"
+ " C | command line will now be started by the child process.\n"
+ " C | This will REPLACE the code of the child with the code\n"
+ " C | of the specified program.\n\n", argv[1]);
+
+ /* specify a terminal as argument 1 and check ptree again ...
+ * you will see that the child is replaced, it have the same
+ * process number, but a new command line
+ */
+ execv(argv[1], argv + 1);
+
+ printf(" C | This will never be printed, since after starting the new\n"
+ " C | program by calling exec this old program is replaced by\n"
+ " C | the new. This is only printed if the new program could not\n"
+ " C | be started for some reason.\n\n");
+
+ exit(-1); /* Terminate the child with error (-1). */
+ }
+ else
+ {
+ int ret = 0; /* Used to save the result of the child. */
+
+ printf("P | This is printed by the origingal process (the PARENT)\n"
+ "P | It got the number (%d) from fork to identify the child.\n"
+ "P | This process will now work for 5 seconds.\n\n", (int)pid);
+ sleep(5); /* pretend */
+
+ printf("P | This is printed by the origingal process (the PARENT)\n"
+ "P | It got the number (%d) from fork to identify the child.\n"
+ "P | It is now used to wait for the result of that child\n\n",
+ (int)pid);
+
+ /* Wait for the child to finish and get it's status in ret. */
+ waitpid(pid, &ret, 0);
+
+ /* Print the exit status of the child. */
+ if (WIFEXITED(ret))
+ {
+ printf("P | Child finished with code %d\n\n", WEXITSTATUS(ret));
+ }
+ else if (WIFSIGNALED(ret))
+ {
+ printf("P | Child finished due to signal %d\n\n", WTERMSIG(ret));
+ }
+ }
+
+ return 0;
+}
diff --git a/src/standalone/upg4/use-list.c b/src/standalone/upg4/use-list.c
new file mode 100644
index 0000000..065f71a
--- /dev/null
+++ b/src/standalone/upg4/use-list.c
@@ -0,0 +1,42 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Pintos contain an implementation of a doubly linked list. It is
+ * found in ../../lib/kernel/list.[ch].
+ *
+ * Recommended compilation commands:
+ *
+ * This is done once:
+ * gcc -Wall -Wextra -std=gnu99 -pedantic -g -c ../../lib/kernel/list.c
+ *
+ * Then use the precomplied list.o:
+ * gcc -Wall -Wextra -std=gnu99 -pedantic -g use-list.c list.o
+ */
+#error Read comments above, then remove this line.
+
+#include "../../lib/kernel/list.h"
+
+int main()
+{
+ int i, j;
+ int N = 1000;
+
+ /* create a list */
+ for (i = 2; i < N; ++i)
+ {
+ /* insert the value of the loop variable 'i' in the list */
+ }
+
+ for (i = 2; i < N; ++i)
+ {
+ for (j = i*2; j < N; j += i)
+ {
+ /* remove every with 'j' even divisible number from the list */
+ }
+ }
+
+ /* print all remaining numbers in the list and free any memory
+ * allocated */
+ return 0;
+}
diff --git a/src/standalone/upg5/pagedir.c b/src/standalone/upg5/pagedir.c
new file mode 100644
index 0000000..7ef78a3
--- /dev/null
+++ b/src/standalone/upg5/pagedir.c
@@ -0,0 +1,8 @@
+/* The code that simulates and tests your address verification. How
+ this is done is disclosed. As a student you shall not compile this
+ file, but instead compile your program with the .o file as:
+
+ gcc -Wall -Wextra -std=c99 -pedantic -g verify_adr.c pagedir.o
+ */
+#error Read comment above. Leave this line in place.
+
diff --git a/src/standalone/upg5/pagedir.h b/src/standalone/upg5/pagedir.h
new file mode 100644
index 0000000..2919d1a
--- /dev/null
+++ b/src/standalone/upg5/pagedir.h
@@ -0,0 +1,42 @@
+#ifndef PAGEDIR_H
+#define PAGEDIR_H
+
+typedef int bool;
+#define false 0
+#define true 1
+
+/* Returns true iff 'adr' contains a null-character ('\0'). */
+bool is_end_of_string(char* adr);
+
+/* Returns the start address of the page that contains 'adr'. */
+void* pg_round_down(const void* adr);
+
+/* Returns the page number of the page that contains 'adr'.
+ * Page numbers are counted with start at zero (0).
+ */
+unsigned pg_no(const void* adr);
+
+/* Uses the page table to translate from logic to physical
+ * address. Returns NULL if the translation fail.
+ *
+ * The first parameter specify the top level page table to
+ * use. Normally you will find it in the structure corresponding
+ * to your operating systems PCB (Process Control Block).
+ */
+void *pagedir_get_page (void *pagetable, const void *adr);
+
+/* Page size: The number of bytes in each page. */
+#define PGSIZE 100
+
+/* Functions used to simulate a paging system and testing your
+ * solution. */
+void start_evaluate_algorithm(void* start, int size);
+void evaluate(bool result);
+void end_evaluate_algorithm();
+
+/* Let us decide how costly a simulated page fault is in terms of
+ * time. Does not exist in Pintos. Set to zero (0) for faster
+ * testing. */
+void simulator_set_pagefault_time(unsigned i);
+
+#endif
diff --git a/src/standalone/upg5/thread.h b/src/standalone/upg5/thread.h
new file mode 100644
index 0000000..62568ab
--- /dev/null
+++ b/src/standalone/upg5/thread.h
@@ -0,0 +1,16 @@
+#ifndef THREAD_H
+#define THREAD_H
+
+struct thread
+{
+ /* This is just a part of the Pintos Thread. */
+ void* pagedir;
+};
+
+/* Initiate the threading system. */
+void thread_init();
+
+/* Return a pointer to the currently active thread. */
+struct thread* thread_current();
+
+#endif
diff --git a/src/standalone/upg5/verify_adr.c b/src/standalone/upg5/verify_adr.c
new file mode 100644
index 0000000..6aba06e
--- /dev/null
+++ b/src/standalone/upg5/verify_adr.c
@@ -0,0 +1,90 @@
+#include <stdlib.h>
+#include "pagedir.h"
+#include "thread.h"
+
+/* verfy_*_lenght are intended to be used in a system call that accept
+ * parameters containing suspisious (user mode) adresses. The
+ * operating system (executng the system call in kernel mode) must not
+ * be fooled into using (reading or writing) addresses not available
+ * to the user mode process performing the system call.
+ *
+ * In pagedir.h you can find some supporting functions that will help
+ * you dermining if a logic address can be translated into a physical
+ * addrerss using the process pagetable. A single translation is
+ * costly. Work out a way to perform as few translations as
+ * possible.
+ *
+ * Recommended compilation command:
+ *
+ * gcc -Wall -Wextra -std=gnu99 -pedantic -g pagedir.o verify_adr.c
+ */
+#error Read comment above and then remove this line.
+
+/* Verify all addresses from and including 'start' up to but excluding
+ * (start+length). */
+bool verify_fix_length(void* start, int length)
+{
+ // ADD YOUR CODE HERE
+}
+
+/* Verify all addresses from and including 'start' up to and including
+ * the address first containg a null-character ('\0'). (The way
+ * C-strings are stored.)
+ */
+bool verify_variable_length(char* start)
+{
+ // ADD YOUR CODE HERE
+}
+
+/* Definition of test cases. */
+struct test_case_t
+{
+ void* start;
+ unsigned length;
+};
+
+#define TEST_CASE_COUNT 6
+
+const struct test_case_t test_case[TEST_CASE_COUNT] =
+{
+ {(void*)100, 100}, /* one full page */
+ {(void*)199, 102},
+ {(void*)101, 98},
+ {(void*)250, 190},
+ {(void*)250, 200},
+ {(void*)250, 210}
+};
+
+/* This main program will evalutate your solution. */
+int main(int argc, char* argv[])
+{
+ int i;
+ bool result;
+
+ if ( argc == 2 )
+ {
+ simulator_set_pagefault_time( atoi(argv[1]) );
+ }
+ thread_init();
+
+ /* Test the algorithm with a given intervall (a buffer). */
+ for (i = 0; i < TEST_CASE_COUNT; ++i)
+ {
+ start_evaluate_algorithm(test_case[i].start, test_case[i].length);
+ result = verify_fix_length(test_case[i].start, test_case[i].length);
+ evaluate(result);
+ end_evaluate_algorithm();
+ }
+
+ /* Test the algorithm with a C-string (start address with
+ * terminating null-character).
+ */
+ for (i = 0; i < TEST_CASE_COUNT; ++i)
+ {
+ start_evaluate_algorithm(test_case[i].start, test_case[i].length);
+ result = verify_variable_length(test_case[i].start);
+ evaluate(result);
+ end_evaluate_algorithm();
+ }
+ return 0;
+}
diff --git a/src/standalone/upg6/main.c b/src/standalone/upg6/main.c
new file mode 100644
index 0000000..c481d40
--- /dev/null
+++ b/src/standalone/upg6/main.c
@@ -0,0 +1,124 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "map.h"
+
+/* Recommended compile commmand:
+ *
+ * gcc -Wall -Wextra -std=gnu99 -pedantic -g main.c map.c
+ *
+ * Recommended way to test your solution:
+ *
+ * valgrind --tool=memcheck ./a.out
+ */
+#error Read comments above, then remove this line.
+
+
+/* Can be used to inform compiler about unused parameters (prevent
+ * warning). Useful when a funtion pointer expect a certain set of
+ * parameters, but you only need some of them. */
+#define UNUSED __attribute__((unused))
+
+/* The code assumes that key_t is `int' and value_t is `char*' */
+
+/* function passed as parameter to map_remove_if in order to free the
+ * memory for all inseted values, and return true to remove them from
+ * the map */
+bool do_free(key_t k UNUSED, value_t v, int aux UNUSED)
+{
+ free(v); /*! free memory */
+ return true; /* and remove from collection */
+}
+
+/* function to display all values in the map that are less than the
+ * aux argument */
+void print_less(key_t k UNUSED, value_t v, int aux)
+{
+ /* atoi converst from sequence of character to integer, it will fail
+ * when the characters are letters, check the manpage to see how */
+ if ( atoi(v) < aux)
+ {
+ printf("%s ", v);
+ }
+}
+
+
+#define LOOPS 10
+
+char* my_strdup(char* str)
+{
+ /*! calculate the length and add space for '\0' */
+ int len = strlen(str) + 1;
+ /*! allocate memory just large enough */
+ char* dst = (char*)malloc(len);
+ /*! copy all characters in src to dst */
+ strncpy(dst, str, len);
+
+ return dst; /*(!) return our deep copy of str */
+}
+
+int main()
+{
+ struct map container;
+ char input_buffer[10];
+ char* obj;
+ int id;
+ int i;
+
+ map_init(&container);
+
+ /* remember to try to insert more values than you map can hold */
+ printf("Insert values: ");
+ for ( i = 0; i < LOOPS; ++i)
+ {
+ /* insecure, scanf may overflow the input buffer array *
+ * very serious, but we ignore it in this test program */
+ scanf("%s", input_buffer);
+
+ /*! allocates a copy of the input and inserts in map */
+ obj = my_strdup(input_buffer);
+ id = map_insert(&container, obj);
+ }
+
+ /* remember to test with invalid keys (like 4711, or -1) */
+ for ( i = 0; i < LOOPS; ++i)
+ {
+ printf("Enter id to find value for: ");
+ scanf("%d", &id);
+
+ /*! find the value for a key in the map */
+ obj = map_find(&container, id);
+
+ /*! if it was found, display it */
+YOUR CODE
+
+ /* since we leave the value in the map we may use it again and
+ * should not free the memory */
+ }
+
+ /* remember to test with invalid keys (like 4711, or -1) */
+ for ( i = 0; i < LOOPS; ++i)
+ {
+ printf("Enter id to remove value for: ");
+ scanf("%d", &id);
+
+ /*! find and remove a value for a key in the map */
+ obj = map_remove(&container, id);
+
+ /*! if it was found, display it */
+YOUR CODE
+ /* since we removed the value from the map we will never use it again and
+ * must properly free the memory (if it was allocated) */
+ }
+
+ /*! print all strings representing an integer less than N */
+ printf("Will now display all values less than N. Choose N: ");
+ scanf("%d", &i);
+ map_for_each(&container, print_less, i);
+
+ /*! free all remaining memory and remove from map */
+ map_remove_if(&container, do_free, 0);
+
+ return 0;
+}
diff --git a/src/standalone/upg6/map.c b/src/standalone/upg6/map.c
new file mode 100644
index 0000000..b323fbb
--- /dev/null
+++ b/src/standalone/upg6/map.c
@@ -0,0 +1 @@
+#include "map.h"
diff --git a/src/standalone/upg6/map.h b/src/standalone/upg6/map.h
new file mode 100644
index 0000000..9029ff5
--- /dev/null
+++ b/src/standalone/upg6/map.h
@@ -0,0 +1 @@
+/* do not forget the guard against multiple includes */
diff --git a/src/standalone/upg7/debug.c b/src/standalone/upg7/debug.c
new file mode 100644
index 0000000..d6a3707
--- /dev/null
+++ b/src/standalone/upg7/debug.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+
+int main()
+{
+ char str[] = "sihtgubed";
+ char *stri = &str[8];
+ char *buf[9];
+ char **bufi, **bufend;
+ bufi = buf;
+ bufend = &buf[9];
+
+ while (bufi != bufend){
+ *bufi = stri;
+ bufi++;
+ stri--;
+ }
+
+ while (bufi != buf){
+ *(*bufi) -= 32;
+ bufi--;
+ }
+
+ while (bufi != bufend){
+ printf("%c", **bufi);
+ bufi++;
+ }
+}
diff --git a/src/standalone/upg8/setup-argv.c b/src/standalone/upg8/setup-argv.c
new file mode 100644
index 0000000..dd326d2
--- /dev/null
+++ b/src/standalone/upg8/setup-argv.c
@@ -0,0 +1,265 @@
+#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 -pedantic -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;
+
+ printf("Adress \thex-data \tchar-data\n");
+
+ for (i = size - 1; i >= 0; --i)
+ {
+ void** adr = (void**)((unsigned)ptr + i);
+ unsigned char* byte = (unsigned char*)((unsigned)ptr + i);
+
+ printf("%08x\t", (unsigned)ptr + i); /* address */
+
+ if ((i % 4) == 0)
+ /* seems we're actually forbidden to read unaligned adresses */
+ printf("%08x\t", (unsigned)*adr); /* content interpreted as address */
+ else
+ printf(" \t"); /* fill */
+
+ if(*byte >= 32 && *byte < 127)
+ printf("%c\n", *byte); /* content interpreted as character */
+ else
+ printf("\\%o\n", *byte);
+
+ if ((i % 4) == 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;
+ /* "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 = ??? ;
+ STACK_DEBUG("# line_size = %d\n", line_size);
+
+ /* round up to make it even divisible by 4 */
+ line_size = ??? ;
+ STACK_DEBUG("# line_size (aligned) = %d\n", line_size);
+
+ /* calculate how many words the command_line contain */
+ argc = ??? ;
+ STACK_DEBUG("# argc = %d\n", argc);
+
+ /* calculate the size needed on our simulated stack */
+ total_size = ??? ;
+ STACK_DEBUG("# total_size = %d\n", total_size);
+
+
+ /* calculate where the final stack top will be located */
+ esp = ??? ;
+
+ /* setup return address and argument count */
+ esp->ret = ??? ;
+ esp->argc = ??? ;
+ /* calculate where in the memory the argv array starts */
+ esp->argv = ??? ;
+
+ /* calculate where in the memory the words is stored */
+ cmd_line_on_stack = ??? ;
+
+ /* 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)simulated_stack + 4096);
+ int i;
+
+ /* read one line of input, this will be the command-line */
+ printf("Mata in en mening: ");
+ custom_getline(line, LINE_SIZE);
+
+ /* put initial content on our simulated stack */
+ esp = setup_main_stack(line, simulated_stack_top);
+ printf("# esp = %08x\n", (unsigned)esp);
+
+ /* dump memory area for verification */
+ dump(esp, (unsigned)simulated_stack_top - (unsigned)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;
+}