X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=course%2Fsemester2%2Fpprog%2Fassignment1%2Fsingle-thread%2Fmain.c;h=e9ccb4111b1426479e57a151eb47a9c5a67978f9;hb=46fe12165ce898eb47d2a2b9ce9945dbd65987a6;hp=63f0d2ede44976c171af7652f05cdf10111d7d3a;hpb=7a341db1fbf5db94b711135b2a79e852c6fb1bc4;p=matches%2Fhonours.git diff --git a/course/semester2/pprog/assignment1/single-thread/main.c b/course/semester2/pprog/assignment1/single-thread/main.c index 63f0d2ed..e9ccb411 100644 --- a/course/semester2/pprog/assignment1/single-thread/main.c +++ b/course/semester2/pprog/assignment1/single-thread/main.c @@ -1,50 +1,258 @@ +/** + * @file main.c + * @author Sam Moore (20503628) - 2012 + * @purpose Contains main function, argument handling + * NOTE: This file is identical for both the single-threaded and multi-threaded versions of the program + */ #include #include +#include +#include +#include // For parsing arguments #include "nbody.h" #include "graphics.h" -unsigned numberOfProcessors; +// --- Variable definitions --- // +System universe; // global variable declared in "nbody.h" - The universe of bodies +Options options; // global variable declared in "nbody.h" - Options passed to program through arguments -System universe; -// This is main function. Do not change it. +// --- Function forward declarations --- // +void HandleArguments(int argc, char ** argv); //Interprets program arguments and sets up the "options" variable +unsigned UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store, unsigned * store2); //Helper function to get switch value for unsigned +void FloatArgument(unsigned * i, int argc, char ** argv, float * store); //Helper function to get switch value for float +void DisplayStatistics(); //Called on exit of program, displays information about computation time, steps computed, etc +void Interrupt(int dummy); // Interrupt handler function, called when SIGINT (Ctrl-C) is sent to program + +// --- Function implementations --- // + +/** + * @function main + * @purpose The main function. Calls HandleArguments to set up options, + * sets up functions to call at exit, starts simulation and graphics loops + * @param argc - Number of arguments + * @param argv - The argument strings + */ int main(int argc, char** argv) { - glutInit(&argc, argv); + //Set default options values here + options.program = argv[0]; + options.input = NULL; + options.output = NULL; + options.num_threads = 0; + options.nested_threads = 0; + options.num_steps = 0; + options.timeout = 0; + options.draw_graphics = true; + options.pedantic_graphics = false; + options.print_positions = false; + options.verbosity = 0; - if (argc < 2) + //If there are no arguments, print information about usage + if (argc == 1) { - printf("Please provide the filename, i.e. \'%s bodiesfield.dat\'\n", argv[0]); + printf("Usage: %s [OPTIONS] field\n", argv[0]); + printf("Controls:\n X - exit\n I, J, K, M - rotate\n W, Z, A, S - move to view" + " point\n ./, - zoom in/out\n +/- - scaled zoom in/out\n"); exit(EXIT_SUCCESS); } - if (argc == 2) + + //Parse the arguments + HandleArguments(argc, argv); + + //Check there is an initial field. + if (options.input == NULL) { - System_Init(&universe,argv[1]); - atexit(Universe_Cleanup); + fprintf(stderr, "Usage: %s [OPTIONS] field\n", argv[0]); + fprintf(stderr, " (You did not provide a file for the initial field of bodies)\n"); + exit(EXIT_FAILURE); } - if (argc == 3) + + signal(SIGINT, Interrupt); //Handle SIGINT signals + atexit(Universe_Cleanup); //On exit, cleanup universe (and write positions of bodies to file if supplied). + atexit(DisplayStatistics); //On exit, print information about the computations done + System_Init(&universe,options.input); //Initialise the universe from the initial field + + //Setup the time of day at which the simulation starts + if (gettimeofday(&(options.start_time), NULL) != 0) { - numberOfProcessors = atoi(argv[2]); + perror("Couldn't get time of day"); + exit(EXIT_FAILURE); } + + options.start_clock = clock(); //Get CPU cycles executed before simulation starts + Simulation_Run(argc, argv); // Start the simulation + + //printf("Got here!\n"); + exit(EXIT_FAILURE); //Should never get to this line +} +/** + * @function HandleArguments + * @purpose Fill the "options" variable by parsing command line arguments + * @param argc - Number of arguments + * @param argv - Argument strings + */ +void HandleArguments(int argc, char ** argv) +{ + for (unsigned i = 1; i < argc; ++i) //For all arguments + { + if (argv[i][0] != '-') //If the argument is not a switch value... + { + //Interpret first non switch as input file, and second as output file. + //If there are too many non switch arguments, give an error. + if (options.input == NULL) + options.input = argv[i]; + else if (options.output == NULL) + options.output = argv[i]; + else + { + fprintf(stderr,"Usage: %s [OPTIONS] field [output]\n", argv[0]); + fprintf(stderr," (You provided too many file names)\n"); + exit(EXIT_FAILURE); + } + continue; + } + switch (argv[i][1]) //The argument is a switch if we get here + { + case 'n': //Number of threads switch + UnsignedArgument(&i, argc, argv, &(options.num_threads), &(options.nested_threads)); + #ifdef SINGLE_THREADED + fprintf(stderr, "Warning: -%c switch has no effect in the single-threaded program.\n", argv[i][1]); + + #endif //SINGLE_THREADED + break; + case 's': //Number of steps switch + UnsignedArgument(&i, argc, argv, &(options.num_steps), NULL); + break; + case 't': //Timeout switch (in seconds) + UnsignedArgument(&i, argc, argv, &(options.timeout), NULL); + break; + case 'g': //Graphics switch + options.draw_graphics = !options.draw_graphics; + break; + case 'v': //Verbosity switch + UnsignedArgument(&i, argc, argv, &(options.verbosity), NULL); + break; - glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); - glutInitWindowSize(WIDTH, HEIGHT); - glutInitWindowPosition(POSITION_X, POSITION_Y); - glutCreateWindow("N-Body : Single Threaded"); - glutDisplayFunc(Graphics_Display); - glutIdleFunc(Graphics_Animate); - glutKeyboardFunc(Graphics_Keyboard); - glutReshapeFunc(Graphics_Reshape); - Graphics_Init(); + case '-': + if (strcmp(argv[i]+1, "pedantic-graphics")) + { + options.pedantic_graphics = true; + #ifdef SINGLE_THREADED + fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]); + #endif //SINGLE_THREADED + } + else if (strcmp(argv[i]+1, "fast-graphics")) + { + options.pedantic_graphics = false; + #ifdef SINGLE_THREADED + fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]); + #endif //SINGLE_THREADED + } + else + { + fprintf(stderr, "Unrecognised switch -%s\n", argv[i]); + exit(EXIT_FAILURE); + } + break; - printf("Use:\n X - exit\n I, J, K, M - rotate\n W, Z, A, S - move to view" - " point\n ./, - zoom in/out\n +/- - scaled zoom in/out\n"); - glutMainLoop(); + default: + fprintf(stderr, "Unrecognised switch -%c\n", argv[i][1]); + exit(EXIT_FAILURE); + break; + } + + } +} + +/** + * @function UnsignedArgument + * @purpose Helper function to get an unsigned integer following a argument switch + * @param i - position in the argument array, will be updated after this function + * @param argc - number of arguments + * @param argv - argument strings + * @param store - pointer to unsigned to store result in + * @param store2 - pointer to second unsigned + * @returns 1 if store was filled, 2 if both store1 and store2 were filled + */ +unsigned UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store, unsigned * store2) +{ + if (*i >= argc-1) + { + fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]); + exit(EXIT_FAILURE); + } + + char * seperator = strstr(argv[*i+1], ":"); + if (seperator != NULL) + { + if (store2 == NULL) + { + fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]); + exit(EXIT_FAILURE); + } + int val = atoi(seperator+1); + if (val <= 0) + { + fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]); + exit(EXIT_FAILURE); + } + *store2 = (unsigned)val; + + *seperator = '\0'; + } + int val = atoi(argv[*i+1]); + if (val <= 0) + { + fprintf(stderr,"Supply a positive integer for the -%c switch. %s is invalid.\n", argv[*i][1], argv[*i+1]); + exit(EXIT_FAILURE); + } + *store = (unsigned)val; + *i += 1; + + return (seperator == NULL) ? 1 : 2; +} +/** + * @function FloatArgument + * @purpose Helper function to get a float following a argument switch + * @param i - position in the argument array, will be updated after this function + * @param argc - number of arguments + * @param argv - argument strings + * @param store - pointer to float to store result in + */ +void FloatArgument(unsigned * i, int argc, char ** argv, float * store) +{ + if (*i >= argc-1) + { + fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]); + exit(EXIT_FAILURE); + } + *store = atof(argv[*i+1]); + if (*store == 0.0 && argv[*i+1][0] != '0') + { + fprintf(stderr,"Supply a float for the -%c switch.\n", argv[*i][1]); + exit(EXIT_FAILURE); + } + *i += 1; } + + + +/** + * @function Interrupt + * @purpose Handle SIGINT signal; quit the program gracefully, so that statistics are still displayed + * @param dummy - a dummy + */ + +void Interrupt(int dummy) +{ + QuitProgram(false); +} +