ARGH
[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 IntegerArgument(unsigned * i, int argc, char ** argv, int * store, int * store2); //Helper function to get integer switch
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
30 // --- Function implementations --- //
31
32 /**
33  * @function main
34  * @purpose The main function. Calls HandleArguments to set up options, 
35  *              sets up functions to call at exit, starts simulation and graphics loops
36  * @param argc - Number of arguments
37  * @param argv - The argument strings
38  */
39 int main(int argc, char** argv)
40 {
41         //Set default options values here
42         options.program = argv[0];
43         options.input = NULL;
44         options.output = NULL;
45         options.num_threads = 0;
46         options.nested_threads = 0;
47         options.num_steps = -1; // Negative values => simulation runs forever unless otherwise specified
48         options.timeout = -1;
49         options.draw_graphics = true;
50         options.pedantic_graphics = true;
51         options.print_positions = false;
52         options.verbosity = 0;
53         options.theta = 0.50;
54         options.random = 0;
55
56         //If there are no arguments, print information about usage
57         if (argc == 1)
58         {
59                 printf("Usage: %s [OPTIONS] field\n", argv[0]);
60                 printf("Controls:\n X - exit\n I, J, K, M - rotate\n W, Z, A, S - move to view"
61                         " point\n ./, - zoom in/out\n +/- - scaled zoom in/out\n");
62                 exit(EXIT_SUCCESS);
63         }
64
65         //Parse the arguments
66         HandleArguments(argc, argv);
67         
68         //Check there is an initial field.
69         if (options.input == NULL && options.random <= 0)
70         {
71                 fprintf(stderr, "Usage: %s [OPTIONS] field\n", argv[0]);
72                 fprintf(stderr, " (You did not provide a file for the initial field of bodies)\n");
73                 exit(EXIT_FAILURE);
74         }
75
76
77
78         signal(SIGINT, Interrupt); //Handle SIGINT signals
79         atexit(Universe_Cleanup); //On exit, cleanup universe (and write positions of bodies to file if supplied).
80         atexit(DisplayStatistics); //On exit, print information about the computations done
81         if (options.input != NULL)
82                 System_Init(&universe,options.input); //Initialise the universe from the initial field
83         else
84                 System_Random(&universe, options.random); //Randomly create bodies
85         
86         
87         //Setup the time of day at which the simulation starts
88         if (gettimeofday(&(options.start_time), NULL) != 0)
89         {
90                 perror("Couldn't get time of day");
91                 exit(EXIT_FAILURE);
92         }
93         
94         options.start_clock = clock(); //Get CPU cycles executed before simulation starts
95         Simulation_Run(argc, argv); // Start the simulation
96         
97         //printf("Main thread done!\n");
98         
99         //pthread_exit(NULL);
100         exit(EXIT_SUCCESS); //Should never get to this line
101 }
102
103
104 /**
105  * @function HandleArguments
106  * @purpose Fill the "options" variable by parsing command line arguments
107  * @param argc - Number of arguments
108  * @param argv - Argument strings
109  */
110 void HandleArguments(int argc, char ** argv)
111 {
112         for (unsigned i = 1; i < argc; ++i) //For all arguments
113         {
114                 if (argv[i][0] != '-') //If the argument is not a switch value...
115                 {
116                         //Interpret first non switch as input file, and second as output file.
117                         //If there are too many non switch arguments, give an error.
118                         if (options.input == NULL) 
119                                 options.input = argv[i];
120                         else if (options.output == NULL)
121                                 options.output = argv[i];
122                         else
123                         {
124                                 fprintf(stderr,"Usage: %s [OPTIONS] field [output]\n", argv[0]);
125                                 fprintf(stderr," (You provided too many file names)\n");
126                                 exit(EXIT_FAILURE);
127                         }
128                         continue;
129                 }
130                 switch (argv[i][1]) //The argument is a switch if we get here
131                 {
132                         case 'n': //Number of threads switch
133                                 IntegerArgument(&i, argc, argv, &(options.num_threads), &(options.nested_threads));
134                                 #ifdef SINGLE_THREADED
135                                 fprintf(stderr, "Warning: -%c switch has no effect in the single-threaded program.\n", 'n');
136                                 
137                                 #else
138                                 if (options.num_threads <= 0)
139                                 {
140                                         fprintf(stderr, "Require at least one thread (-%c %s is invalid).\n",'n', argv[i]);
141                                         exit(EXIT_FAILURE);
142                                 }
143                                 #endif //SINGLE_THREADED
144                                 break;
145                         case 's': //Number of steps switch
146                                 IntegerArgument(&i, argc, argv, &(options.num_steps), NULL);
147                                 if (options.num_steps < 0)
148                                 {
149                                         fprintf(stderr, "Require zero or more steps to run (-%c %s is invalid).\n", 's', argv[i]);
150                                         exit(EXIT_FAILURE);
151                                 }
152                                 break;
153                         case 't': //Timeout switch (in seconds)
154                                 IntegerArgument(&i, argc, argv, &(options.timeout), NULL);
155                                 if (options.timeout < 0)
156                                 {
157                                         fprintf(stderr, "Require a timeout greater or equal to zero (-%c %s is invalid).", 't', argv[i]);
158                                         exit(EXIT_FAILURE);
159                                 }                               
160                                 break;
161                         case 'r': //Random initial field
162                                 IntegerArgument(&i, argc, argv, &(options.random), NULL);
163                                 if (options.random < 0)
164                                 {
165                                         fprintf(stderr, "Require a positive integer number of bodies (-%c %s is invalid).", 'r', argv[i]);
166                                         exit(EXIT_FAILURE);
167                                 }
168                                 break;
169                         case 'g': //Graphics switch
170                                 options.draw_graphics = !options.draw_graphics;
171                                 break;
172                         case 'v': //Verbosity switch
173                                 IntegerArgument(&i, argc, argv, &(options.verbosity), NULL);
174                                 break;
175
176                         case '-':
177                                 if (strcmp(argv[i]+2, "pedantic-graphics") == 0)
178                                 {
179                                         options.pedantic_graphics = true;
180                                         #ifdef SINGLE_THREADED
181                                         fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
182                                         #endif //SINGLE_THREADED
183                                 }
184                                 else if (strcmp(argv[i]+2, "fast-graphics") == 0)
185                                 {
186                                         options.pedantic_graphics = false;
187                                         #ifdef SINGLE_THREADED
188                                         fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
189                                         #endif //SINGLE_THREADED
190
191                                 }
192                                 else if (strcmp(argv[i]+2, "theta") == 0)
193                                 {
194                                         FloatArgument(&i, argc, argv, &(options.theta));
195                                         #ifndef BARNES_HUT
196                                         fprintf(stderr, "Warning: %s switch only works in Barnes Hut version.\n", argv[i-1]);
197                                         #else
198                                         if (options.theta < 0)
199                                         {
200                                                 fprintf(stderr, "Require a theta value greater or equal to zero (%s %s is invalid).\n", argv[i-1], argv[i]);
201                                                 exit(EXIT_FAILURE);
202                                         }
203                                         
204                                         #endif //BARNS_HUT
205                                         
206                                 }
207                                 else
208                                 {
209                                         fprintf(stderr, "Unrecognised switch %s\n", argv[i]);
210                                         exit(EXIT_FAILURE);
211                                 }
212                                 break;
213
214
215                         default:
216                                 fprintf(stderr, "Unrecognised switch -%c\n", argv[i][1]);
217                                 exit(EXIT_FAILURE);
218                                 break;
219                 }
220                 
221         }
222 }
223
224 /**
225  * @function IntegerArgument
226  * @purpose Helper function to get up to two integers following a argument switch, seperated by ':'
227  * @param i - position in the argument array, will be updated after this function
228  * @param argc - number of arguments
229  * @param argv - argument strings
230  * @param store - pointer to unsigned to store result in
231  * @param store2 - pointer to second integer (set to NULL if there is only one integer)
232  * @returns 1 if store was filled, 2 if both store1 and store2 were filled
233  */
234 unsigned IntegerArgument(unsigned * i, int argc, char ** argv, int * store, int * store2)
235 {
236         if (*i >= argc-1)
237         {
238                 fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
239                 exit(EXIT_FAILURE);
240         }
241
242         char * seperator = strstr(argv[*i+1], ":");
243         if (seperator != NULL)
244         {
245                 if (store2 == NULL)
246                 {
247                         fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
248                         exit(EXIT_FAILURE);     
249                 }
250                 int val = atoi(seperator+1);
251                 if (val <= 0)
252                 {
253                         fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
254                         exit(EXIT_FAILURE);     
255                 }       
256                 *store2 = (unsigned)val;
257
258                 *seperator = '\0';
259         }
260         
261         int val = atoi(argv[*i+1]);
262         if (val <= 0 && strcmp("0", argv[*i+1]) != 0)
263         {
264                 fprintf(stderr,"Supply a positive integer for the -%c switch. %s is invalid.\n", argv[*i][1], argv[*i+1]);
265                 exit(EXIT_FAILURE);
266         }
267         *store = val;
268         *i += 1;
269
270         return (seperator == NULL) ? 1 : 2;
271 }
272 /**
273  * @function FloatArgument
274  * @purpose Helper function to get a float following a argument switch
275  * @param i - position in the argument array, will be updated after this function
276  * @param argc - number of arguments
277  * @param argv - argument strings
278  * @param store - pointer to float to store result in
279  */
280 void FloatArgument(unsigned * i, int argc, char ** argv, float * store)
281 {
282         if (*i >= argc-1)
283         {
284                 fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]);
285                 exit(EXIT_FAILURE);
286         }
287         *store = atof(argv[*i+1]);
288         if (*store == 0.0 && argv[*i+1][0] != '0')
289         {
290                 fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]);
291                 exit(EXIT_FAILURE);
292         }
293         *i += 1;
294 }
295
296
297
298 /**
299  * @function Interrupt
300  * @purpose Handle SIGINT signal; quit the program gracefully, so that statistics are still displayed
301  * @param dummy - a dummy
302  */
303
304 void Interrupt(int dummy)
305 {
306         QuitProgram(false);
307 }
308
309

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