Parallel Programming - Commit before I break things
[matches/honours.git] / course / semester2 / pprog / assignment1 / single-thread / main.c
1 /**
2  * @file main.c
3  * @author Sam Moore (20503628) - 2012
4  * @purpose Contains main function, argument handling
5  * NOTE: This file is identical for both the single-threaded and multi-threaded versions of the program
6  */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <time.h>
11 #include <signal.h>
12 #include <string.h> // For parsing arguments
13
14 #include "nbody.h"
15 #include "graphics.h"
16
17 // --- Variable definitions --- //
18 System universe; // global variable declared in "nbody.h" - The universe of bodies
19 Options options; // global variable declared in "nbody.h" - Options passed to program through arguments
20
21
22 // --- Function forward declarations --- //
23 void HandleArguments(int argc, char ** argv); //Interprets program arguments and sets up the "options" variable
24 unsigned UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store, unsigned * store2); //Helper function to get switch value for unsigned
25 void FloatArgument(unsigned * i, int argc, char ** argv, float * store); //Helper function to get switch value for float
26 void DisplayStatistics(); //Called on exit of program, displays information about computation time, steps computed, etc
27 void Interrupt(int dummy); // Interrupt handler function, called when SIGINT (Ctrl-C) is sent to program
28
29 // --- Function implementations --- //
30
31 /**
32  * @function main
33  * @purpose The main function. Calls HandleArguments to set up options, 
34  *              sets up functions to call at exit, starts simulation and graphics loops
35  * @param argc - Number of arguments
36  * @param argv - The argument strings
37  */
38 int main(int argc, char** argv)
39 {
40         //Set default options values here
41         options.program = argv[0];
42         options.input = NULL;
43         options.output = NULL;
44         options.num_threads = 0;
45         options.nested_threads = 0;
46         options.num_steps = 0;
47         options.timeout = 0;
48         options.draw_graphics = true;
49         options.pedantic_graphics = false;
50         options.print_positions = false;
51         options.verbosity = 0;
52
53         //If there are no arguments, print information about usage
54         if (argc == 1)
55         {
56                 printf("Usage: %s [OPTIONS] field\n", argv[0]);
57                 printf("Controls:\n X - exit\n I, J, K, M - rotate\n W, Z, A, S - move to view"
58                         " point\n ./, - zoom in/out\n +/- - scaled zoom in/out\n");
59                 exit(EXIT_SUCCESS);
60         }
61
62         //Parse the arguments
63         HandleArguments(argc, argv);
64         
65         //Check there is an initial field.
66         if (options.input == NULL)
67         {
68                 fprintf(stderr, "Usage: %s [OPTIONS] field\n", argv[0]);
69                 fprintf(stderr, " (You did not provide a file for the initial field of bodies)\n");
70                 exit(EXIT_FAILURE);
71         }
72
73         signal(SIGINT, Interrupt); //Handle SIGINT signals
74         atexit(Universe_Cleanup); //On exit, cleanup universe (and write positions of bodies to file if supplied).
75         atexit(DisplayStatistics); //On exit, print information about the computations done
76         System_Init(&universe,options.input); //Initialise the universe from the initial field
77         
78         //Setup the time of day at which the simulation starts
79         if (gettimeofday(&(options.start_time), NULL) != 0)
80         {
81                 perror("Couldn't get time of day");
82                 exit(EXIT_FAILURE);
83         }
84         
85         options.start_clock = clock(); //Get CPU cycles executed before simulation starts
86         Simulation_Run(argc, argv); // Start the simulation
87         
88         printf("Got here!\n");
89         exit(EXIT_FAILURE); //Should never get to this line
90 }
91
92
93 /**
94  * @function HandleArguments
95  * @purpose Fill the "options" variable by parsing command line arguments
96  * @param argc - Number of arguments
97  * @param argv - Argument strings
98  */
99 void HandleArguments(int argc, char ** argv)
100 {
101         for (unsigned i = 1; i < argc; ++i) //For all arguments
102         {
103                 if (argv[i][0] != '-') //If the argument is not a switch value...
104                 {
105                         //Interpret first non switch as input file, and second as output file.
106                         //If there are too many non switch arguments, give an error.
107                         if (options.input == NULL) 
108                                 options.input = argv[i];
109                         else if (options.output == NULL)
110                                 options.output = argv[i];
111                         else
112                         {
113                                 fprintf(stderr,"Usage: %s [OPTIONS] field [output]\n", argv[0]);
114                                 fprintf(stderr," (You provided too many file names)\n");
115                                 exit(EXIT_FAILURE);
116                         }
117                         continue;
118                 }
119                 switch (argv[i][1]) //The argument is a switch if we get here
120                 {
121                         case 'n': //Number of threads switch
122                                 UnsignedArgument(&i, argc, argv, &(options.num_threads), &(options.nested_threads));
123                                 #ifdef SINGLE_THREADED
124                                 fprintf(stderr, "Warning: -%c switch has no effect in the single-threaded program.\n", argv[i][1]);
125                                 
126                                 #endif //SINGLE_THREADED
127                                 break;
128                         case 's': //Number of steps switch
129                                 UnsignedArgument(&i, argc, argv, &(options.num_steps), NULL);
130                                 break;
131                         case 't': //Timeout switch (in seconds)
132                                 UnsignedArgument(&i, argc, argv, &(options.timeout), NULL);
133                                 break;
134                         case 'g': //Graphics switch
135                                 options.draw_graphics = !options.draw_graphics;
136                                 break;
137                         case 'v': //Verbosity switch
138                                 UnsignedArgument(&i, argc, argv, &(options.verbosity), NULL);
139                                 break;
140
141                         case '-':
142                                 if (strcmp(argv[i]+1, "pedantic-graphics"))
143                                 {
144                                         options.pedantic_graphics = true;
145                                         #ifdef SINGLE_THREADED
146                                         fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
147                                         #endif //SINGLE_THREADED
148                                 }
149                                 else if (strcmp(argv[i]+1, "fast-graphics"))
150                                 {
151                                         options.pedantic_graphics = false;
152                                         #ifdef SINGLE_THREADED
153                                         fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
154                                         #endif //SINGLE_THREADED
155
156                                 }
157                                 else
158                                 {
159                                         fprintf(stderr, "Unrecognised switch -%s\n", argv[i]);
160                                         exit(EXIT_FAILURE);
161                                 }
162                                 break;
163
164
165                         default:
166                                 fprintf(stderr, "Unrecognised switch -%c\n", argv[i][1]);
167                                 exit(EXIT_FAILURE);
168                                 break;
169                 }
170                 
171         }
172 }
173
174 /**
175  * @function UnsignedArgument
176  * @purpose Helper function to get an unsigned integer following a argument switch
177  * @param i - position in the argument array, will be updated after this function
178  * @param argc - number of arguments
179  * @param argv - argument strings
180  * @param store - pointer to unsigned to store result in
181  * @param store2 - pointer to second unsigned
182  * @returns 1 if store was filled, 2 if both store1 and store2 were filled
183  */
184 unsigned UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store, unsigned * store2)
185 {
186         if (*i >= argc-1)
187         {
188                 fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
189                 exit(EXIT_FAILURE);
190         }
191
192         char * seperator = strstr(argv[*i+1], ":");
193         if (seperator != NULL)
194         {
195                 if (store2 == NULL)
196                 {
197                         fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
198                         exit(EXIT_FAILURE);     
199                 }
200                 int val = atoi(seperator+1);
201                 if (val <= 0)
202                 {
203                         fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
204                         exit(EXIT_FAILURE);     
205                 }       
206                 *store2 = (unsigned)val;
207
208                 *seperator = '\0';
209         }
210         
211         int val = atoi(argv[*i+1]);
212         if (val <= 0)
213         {
214                 fprintf(stderr,"Supply a positive integer for the -%c switch. %s is invalid.\n", argv[*i][1], argv[*i+1]);
215                 exit(EXIT_FAILURE);
216         }
217         *store = (unsigned)val;
218         *i += 1;
219
220         return (seperator == NULL) ? 1 : 2;
221 }
222 /**
223  * @function FloatArgument
224  * @purpose Helper function to get a float following a argument switch
225  * @param i - position in the argument array, will be updated after this function
226  * @param argc - number of arguments
227  * @param argv - argument strings
228  * @param store - pointer to float to store result in
229  */
230 void FloatArgument(unsigned * i, int argc, char ** argv, float * store)
231 {
232         if (*i >= argc-1)
233         {
234                 fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]);
235                 exit(EXIT_FAILURE);
236         }
237         *store = atof(argv[*i+1]);
238         if (*store == 0.0 && argv[*i+1][0] != '0')
239         {
240                 fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]);
241                 exit(EXIT_FAILURE);
242         }
243         *i += 1;
244 }
245
246
247
248 /**
249  * @function Interrupt
250  * @purpose Handle SIGINT signal; quit the program gracefully, so that statistics are still displayed
251  * @param dummy - a dummy
252  */
253
254 void Interrupt(int dummy)
255 {
256         QuitProgram(false);
257 }
258

UCC git Repository :: git.ucc.asn.au