solstice_args.c (21454B)
1 /* Copyright (C) 2018-2026 |Méso|Star> (contact@meso-star.com) 2 * Copyright (C) 2016-2018 CNRS 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #define _XOPEN_SOURCE /* strptime support */ 18 #define _POSIX_C_SOURCE 2 19 20 #include "solstice_args.h" 21 #include "solstice_version.h" 22 23 #include <rsys/cstr.h> 24 #include <rsys/double2.h> 25 #include <rsys/double3.h> 26 #include <rsys/stretchy_array.h> 27 28 #include <unistd.h> 29 30 #include <string.h> 31 #include <time.h> 32 33 /******************************************************************************* 34 * Helper functions 35 ******************************************************************************/ 36 static const char* ALGO_NAMES[] = { "meeus", "psa" }; 37 38 static const char* 39 algo_to_str(enum solstice_args_sun_direction_algorithm algo) { 40 ASSERT((unsigned)algo < (sizeof(ALGO_NAMES)/sizeof(*ALGO_NAMES))); 41 return ALGO_NAMES[algo]; 42 } 43 44 static void 45 print_help(const char* program) 46 { 47 printf( 48 "Usage: %s [OPTIONS] [FILE]\n" 49 "Integrate the solar flux in a complex solar facility described in FILE. If not\n" 50 "define, the solar facility is read from standard input. Refer to solstice(1)\n" 51 "man page for more informations.\n\n", 52 program); 53 printf( 54 " -A <algo> set the algorithm to compute sun directions. Default is %s.\n", 55 algo_to_str(SOLSTICE_ARGS_DEFAULT.sun_algorithm)); 56 printf( 57 " -D <dir> request a computation for a sun direction.\n"); 58 printf( 59 " -f overwrite the output files if they already exist, i.e. the\n" 60 " OUTPUT file and the output RNG state.\n"); 61 printf( 62 " -G <rng> save and restore the state of the random number generator.\n"); 63 printf( 64 " -g <dump> switch in dump geometry mode and configure it.\n"); 65 printf( 66 " -h display this help and exit.\n"); 67 printf( 68 " -I <DNI> set the DNI value.\n"); 69 printf( 70 " -n SAMPLES number of Monte Carlo samples. Default is %lu.\n", 71 SOLSTICE_ARGS_DEFAULT.nexperiments); 72 printf( 73 " -L <location> set the location of the plant on earth surface.\n"); 74 printf( 75 " -o OUTPUT write results to OUTPUT. If not defined, write results to\n" 76 " standard output.\n"); 77 printf( 78 " -p <dump-paths> switch in dump radiative paths mode and configure it.\n"); 79 printf( 80 " -q do not print the helper message when no FILE is submitted.\n"); 81 printf( 82 " -R RECEIVERS define the file from which the list of receivers are read.\n"); 83 printf( 84 " -r <rendering> switch in rendering mode and configure it.\n"); 85 printf( 86 " -T <time> request a computation at a given time at the last specified\n" 87 " location.\n"); 88 printf( 89 " -t THREADS hint on the number of threads to use. By default use as\n" 90 " many threads as CPU cores.\n"); 91 printf( 92 " -v make the program more verbose.\n"); 93 printf( 94 " --version display version information and exit.\n"); 95 printf("\n"); 96 printf( 97 "Copyright (C) 2018-2026 |Méso|Star> (contact@meso-star.com).\n" 98 "Copyright (C) 2016-2018 CNRS.\n" 99 "Solstice is a free software released under the GNU GPL license, version 3 or\n" 100 "later. You are free to change or redistribute it under certain conditions\n" 101 "<http://gnu.org/licenses/gpl.html>.\n"); 102 } 103 104 static res_T 105 parse_fov(const char* str, double* out_fov) 106 { 107 double fov; 108 res_T res = RES_OK; 109 ASSERT(str && out_fov); 110 111 res = cstr_to_double(str, &fov); 112 if(res != RES_OK) { 113 fprintf(stderr, "Invalid field of view `%s'.\n", str); 114 return RES_BAD_ARG; 115 } 116 117 if(fov < 30 || fov > 120) { 118 fprintf(stderr, "The field of view %g is not in [30, 120].\n", fov); 119 return RES_BAD_ARG; 120 } 121 *out_fov = fov; 122 return RES_OK; 123 } 124 125 static res_T 126 parse_multiple_options 127 (const char* str, 128 struct solstice_args* args, 129 res_T (*parse_option)(const char* str, struct solstice_args* args)) 130 { 131 char buf[512]; 132 char* tk; 133 char* ctx; 134 res_T res = RES_OK; 135 ASSERT(args && str); 136 137 if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { 138 fprintf(stderr, "Could not duplicate the option string `%s'.\n", str); 139 res = RES_MEM_ERR; 140 goto error; 141 } 142 strncpy(buf, str, sizeof(buf)); 143 144 tk = strtok_r(buf, ":", &ctx); 145 do { 146 res = parse_option(tk, args); 147 if(res != RES_OK) goto error; 148 tk = strtok_r(NULL, ":", &ctx); 149 } while(tk); 150 151 exit: 152 return res; 153 error: 154 goto exit; 155 } 156 157 static res_T 158 parse_sun_spherical(const char* str, struct solstice_args* args) 159 { 160 size_t len; 161 struct solstice_args_sun_dir sun_dir; 162 double tmp[2]; 163 res_T res = RES_OK; 164 ASSERT(str && args); 165 166 res = cstr_to_list_double(str, ',', tmp, &len, 2); 167 if(res != RES_OK || len != 2) { 168 if(res == RES_OK) res = RES_BAD_ARG; 169 fprintf(stderr, "Invalid sun direction `%s'.\n", str); 170 goto error; 171 } 172 173 if(tmp[0] < 0 || tmp[0] >= 360) { 174 fprintf(stderr, 175 "Invalid azimuth angle `%g'. Azimuth must be in [0, 360[ degrees.\n", 176 tmp[0]); 177 res = RES_BAD_ARG; 178 goto error; 179 } 180 if(tmp[1] < 0 || tmp[1] > 90) { 181 fprintf(stderr, 182 "Invalid elevation angle `%g'. Elevation must be in [0, 90] degrees.\n", 183 tmp[1]); 184 res = RES_BAD_ARG; 185 goto error; 186 } 187 188 sun_dir.type = SOLSTICE_ARGS_SPHERICAL; 189 sun_dir.spherical.azimuth = tmp[0]; 190 sun_dir.spherical.elevation = tmp[1]; 191 sa_push(args->sun_dirs, sun_dir); 192 args->nsun_dirs++; 193 194 exit: 195 return res; 196 error: 197 if(args->sun_dirs) { 198 sa_release(args->sun_dirs); 199 args->sun_dirs = NULL; 200 args->nsun_dirs = 0; 201 } 202 goto exit; 203 } 204 205 static res_T 206 parse_sun_algorithm(const char* str, struct solstice_args* args) 207 { 208 res_T res = RES_OK; 209 ASSERT(str && args); 210 211 if(0 == strcmp(str, "meeus")) { 212 args->sun_algorithm = SOLSTICE_ARGS_SUN_DIRECTION_ALGORITHM_meeus; 213 } 214 else if(0 == strcmp(str, "psa")) { 215 args->sun_algorithm = SOLSTICE_ARGS_SUN_DIRECTION_ALGORITHM_psa; 216 } 217 else { 218 res = RES_BAD_ARG; 219 fprintf(stderr, "Invalid sun algorithm `%s'.\n", str); 220 goto error; 221 } 222 223 exit: 224 return res; 225 error: 226 goto exit; 227 } 228 229 static res_T 230 parse_location 231 (const char* str, 232 double current_loc[2]) 233 { 234 size_t len; 235 double tmp[2]; 236 res_T res = RES_OK; 237 ASSERT(str && current_loc); 238 239 res = cstr_to_list_double(str, ',', tmp, &len, 2); 240 if(res != RES_OK || len != 2) { 241 if(res == RES_OK) res = RES_BAD_ARG; 242 fprintf(stderr, "Invalid location: `%s'.\n", str); 243 goto error; 244 } 245 246 if(tmp[0] < -90 || tmp[0] > 90) { 247 fprintf(stderr, 248 "Invalid latitude `%g'. Must be in [-90, 90] degrees.\n", 249 tmp[0]); 250 res = RES_BAD_ARG; 251 goto error; 252 } 253 if(tmp[1] < -180 || tmp[1] > 180) { 254 fprintf(stderr, 255 "Invalid longitude `%g'. Must be in [-180, 180] degrees.\n", 256 tmp[1]); 257 res = RES_BAD_ARG; 258 goto error; 259 } 260 261 d2_set(current_loc, tmp); 262 exit: 263 return res; 264 error: 265 goto exit; 266 } 267 268 static res_T 269 parse_time 270 (const char* str, 271 const double current_loc[2], 272 struct solstice_args* args) 273 { 274 res_T res = RES_OK; 275 struct solstice_args_sun_dir sun_dir; 276 char* p; 277 ASSERT(str && current_loc && args); 278 279 p = strptime(str, "%Y-%m-%dT%H:%M:%S", &sun_dir.location_time.time); 280 if(p == NULL || *p != '\0') { 281 res = RES_BAD_ARG; 282 fprintf(stderr, "Invalid time `%s'.\n", str); 283 goto error; 284 } 285 286 sun_dir.type = SOLSTICE_ARGS_LOCATION_TIME; 287 sun_dir.location_time.latitude = current_loc[0]; 288 sun_dir.location_time.longitude = current_loc[1]; 289 sa_push(args->sun_dirs, sun_dir); 290 args->nsun_dirs++; 291 292 exit: 293 return res; 294 error: 295 if(args->sun_dirs) { 296 sa_release(args->sun_dirs); 297 args->sun_dirs = NULL; 298 args->nsun_dirs = 0; 299 } 300 goto exit; 301 } 302 303 static res_T 304 parse_image_definition 305 (const char* str, 306 unsigned long* width, 307 unsigned long* height) 308 { 309 char buf[64]; 310 char* tk; 311 char* ctx; 312 res_T res = RES_OK; 313 ASSERT(str && width && height); 314 315 if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { 316 fprintf(stderr, 317 "Could not duplicate the image definition string `%s'.\n", str); 318 return RES_MEM_ERR; 319 } 320 strncpy(buf, str, sizeof(buf)); 321 322 tk = strtok_r(buf, "x", &ctx); 323 res = cstr_to_ulong(tk, width); 324 if(res == RES_OK && !*width) res = RES_BAD_ARG; 325 if(res != RES_OK) { 326 fprintf(stderr, "Invalid image width `%s'\n", tk); 327 return res; 328 } 329 330 tk = strtok_r(NULL, "", &ctx); 331 res = cstr_to_ulong(tk, height); 332 if(res == RES_OK && !*height) res = RES_BAD_ARG; 333 if(res != RES_OK) { 334 fprintf(stderr, "Invalid image height `%s'\n", tk); 335 return res; 336 } 337 338 return res; 339 } 340 341 static res_T 342 parse_render_mode(const char* str, enum solstice_args_render_mode* mode) 343 { 344 res_T res = RES_OK; 345 ASSERT(str && mode); 346 347 if(!strcmp(str, "draft")) { 348 *mode = SOLSTICE_ARGS_RENDER_DRAFT; 349 } else if(!strcmp(str, "pt")) { 350 *mode = SOLSTICE_ARGS_RENDER_PATH_TRACING; 351 } else { 352 fprintf(stderr, "Invalid render mode `%s'.\n", str); 353 res = RES_BAD_ARG; 354 goto error; 355 } 356 exit: 357 return res; 358 error: 359 goto exit; 360 } 361 362 static res_T 363 parse_rendering_option(const char* str, struct solstice_args* args) 364 { 365 char buf[128]; 366 char* key; 367 char* val; 368 char* ctx; 369 size_t len; 370 res_T res = RES_OK; 371 ASSERT(str && args); 372 373 if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { 374 fprintf(stderr, 375 "Could not duplicate the rendering option string `%s'\n", str); 376 res = RES_MEM_ERR; 377 goto error; 378 } 379 strncpy(buf, str, sizeof(buf)); 380 381 key = strtok_r(buf, "=", &ctx); 382 val = strtok_r(NULL, "", &ctx); 383 384 if(!val) { 385 fprintf(stderr, "Missing a value to the rendering option `%s'.\n", key); 386 res = RES_BAD_ARG; 387 goto error; 388 } 389 390 if(!strcmp(key, "fov")) { /* Camera horizontal field of view in degrees */ 391 res = parse_fov(val, &args->camera.fov_x); 392 if(res != RES_OK) goto error; 393 } else if(!strcmp(key, "img")) { /* Image definition */ 394 res = parse_image_definition(val, &args->img.width, &args->img.height); 395 if(res != RES_OK) goto error; 396 } else if(!strcmp(key, "pos")) { /* Camera position */ 397 res = cstr_to_list_double(val, ',', args->camera.pos, &len, 3); 398 if(res == RES_OK && len != 3) res = RES_BAD_ARG; 399 if(res != RES_OK ) { 400 fprintf(stderr, "Invalid camera position `%s'.\n", val); 401 goto error; 402 } 403 args->camera.auto_look_at = 0; /* Disable auto look at */ 404 } else if(!strcmp(key, "rmode")) { /* Render mode */ 405 res = parse_render_mode(val, &args->render_mode); 406 if(res != RES_OK) goto error; 407 } else if(!strcmp(key, "spp")) { /*# Samples per pixel */ 408 res = cstr_to_uint(val, &args->img.spp); 409 if(res == RES_OK && !args->img.spp) res = RES_BAD_ARG; 410 if(res != RES_OK) { 411 fprintf(stderr, "Invalid number of samples per pixel `%s'.\n", val); 412 goto error; 413 } 414 } else if(!strcmp(key, "tgt")) { /* Camera target */ 415 res = cstr_to_list_double(val, ',', args->camera.tgt, &len, 3); 416 if(res == RES_OK && len != 3) res = RES_BAD_ARG; 417 if(res != RES_OK) { 418 fprintf(stderr, "Invalid camera target `%s'.\n", val); 419 goto error; 420 } 421 args->camera.auto_look_at = 0; /* Disable auto look at */ 422 } else if(!strcmp(key, "up")) { /* Camera up vector */ 423 res = cstr_to_list_double(val, ',', args->camera.up, &len, 3); 424 if(res == RES_OK && len != 3) res = RES_BAD_ARG; 425 if(res != RES_OK) { 426 fprintf(stderr, "Invalid camera up vector `%s'.\n", val); 427 goto error; 428 } 429 } else { 430 fprintf(stderr, "Invalid rendering option `%s'.\n", key); 431 res = RES_BAD_ARG; 432 goto error; 433 } 434 435 exit: 436 return res; 437 error: 438 goto exit; 439 } 440 441 static res_T 442 parse_dump_format(const char* str, enum solstice_args_dump_format* fmt) 443 { 444 res_T res = RES_OK; 445 ASSERT(str && fmt); 446 447 if(!strcmp(str, "obj")) { 448 *fmt = SOLSTICE_ARGS_DUMP_OBJ; 449 } else { 450 fprintf(stderr, "Invalid dump format `%s'.\n", str); 451 res = RES_BAD_ARG; 452 goto error; 453 } 454 455 exit: 456 return res; 457 error: 458 goto exit; 459 } 460 461 static res_T 462 parse_dump_split_mode(const char* str, enum solstice_args_dump_split_mode* mode) 463 { 464 res_T res = RES_OK; 465 ASSERT(str && mode); 466 467 if(!strcmp(str, "geometry")) { 468 *mode = SOLSTICE_ARGS_DUMP_SPLIT_GEOMETRY; 469 } else if(!strcmp(str, "none")) { 470 *mode = SOLSTICE_ARGS_DUMP_SPLIT_NONE; 471 } else if(!strcmp(str, "object")) { 472 *mode = SOLSTICE_ARGS_DUMP_SPLIT_OBJECT; 473 } else { 474 fprintf(stderr, "Invalid dump split mode `%s'.\n", str); 475 res = RES_BAD_ARG; 476 goto error; 477 } 478 exit: 479 return res; 480 error: 481 goto exit; 482 } 483 484 static res_T 485 parse_dump_option(const char* str, struct solstice_args* args) 486 { 487 char buf[128]; 488 char* key; 489 char* val; 490 char* ctx; 491 res_T res = RES_OK; 492 ASSERT(str && args); 493 494 if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { 495 fprintf(stderr, 496 "Could not duplicate the dump geometry option string `%s'\n", str); 497 res = RES_MEM_ERR; 498 goto error; 499 } 500 strncpy(buf, str, sizeof(buf)); 501 502 key = strtok_r(buf, "=", &ctx); 503 val = strtok_r(NULL, "", &ctx); 504 505 if(!val) { 506 fprintf(stderr, "Missing a value to the dump option `%s'.\n", key); 507 res = RES_BAD_ARG; 508 goto error; 509 } 510 511 if(!strcmp(key, "format")) { 512 res = parse_dump_format(val, &args->dump_format); 513 } else if(!strcmp(key, "split")) { 514 res = parse_dump_split_mode(val, &args->dump_split_mode); 515 } else { 516 fprintf(stderr, "Invalid dump option `%s'.\n", val); 517 res = RES_BAD_ARG; 518 goto error; 519 } 520 if(res != RES_OK) goto error; 521 522 exit: 523 return res; 524 error: 525 goto exit; 526 } 527 528 static res_T 529 parse_dump_paths_option(const char* str, struct solstice_args* args) 530 { 531 char buf[128]; 532 char* key; 533 char* val; 534 char* ctx; 535 res_T res = RES_OK; 536 ASSERT(str && args); 537 538 if(!strcmp(str, "default")) { 539 args->infinite_ray_length = SOLSTICE_ARGS_DEFAULT.infinite_ray_length; 540 args->sun_ray_length = SOLSTICE_ARGS_DEFAULT.sun_ray_length; 541 goto exit; 542 } 543 544 if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { 545 fprintf(stderr, 546 "Could not duplicate the dump radiative paths option string `%s'.\n", str); 547 res = RES_MEM_ERR; 548 goto error; 549 } 550 551 strncpy(buf, str, sizeof(buf)); 552 553 key = strtok_r(buf, "=", &ctx); 554 val = strtok_r(NULL, "", &ctx); 555 556 if(!val) { 557 fprintf(stderr, 558 "Missing a value to the dump radiative paths option `%s'.\n", key); 559 res = RES_BAD_ARG; 560 goto error; 561 } 562 563 if(!strcmp(key, "irlen")) { 564 res = cstr_to_double(val, &args->infinite_ray_length); 565 if(res != RES_OK) { 566 fprintf(stderr, "Invalid infinite ray length `%s'.\n", val); 567 goto error; 568 } 569 } else if(!strcmp(key, "srlen")) { 570 res = cstr_to_double(val, &args->sun_ray_length); 571 if(res != RES_OK) { 572 fprintf(stderr, "Invalid sun ray length `%s'.\n", val); 573 goto error; 574 } 575 } else { 576 fprintf(stderr, "Invalid dump radiative paths option `%s'.\n", val); 577 res = RES_BAD_ARG; 578 goto error; 579 } 580 if(res != RES_OK) goto error; 581 582 exit: 583 return res; 584 error: 585 goto exit; 586 } 587 588 static res_T 589 parse_rng_option(const char* str, struct solstice_args* args) 590 { 591 char buf[128]; 592 char* key; 593 char* val; 594 char* ctx; 595 size_t len; 596 res_T res = RES_OK; 597 ASSERT(str && args); 598 599 if(strlen(str) >= sizeof(buf)-1/*NULL char*/) { 600 fprintf(stderr, 601 "Could not duplicate the RNG option string `%s'\n", str); 602 res = RES_MEM_ERR; 603 goto error; 604 } 605 strncpy(buf, str, sizeof(buf)); 606 607 key = strtok_r(buf, "=", &ctx); 608 val = strtok_r(NULL, "", &ctx); 609 610 if(!val) { 611 fprintf(stderr, "Missing a value to the RNG option `%s'.\n", key); 612 res = RES_BAD_ARG; 613 goto error; 614 } 615 616 if(!strcmp(key, "istate")) { /* Input state */ 617 len = strlen(val); 618 args->rng_state_input_filename = mem_calloc(len+1, sizeof(char)); 619 if(!args->rng_state_input_filename) { res = RES_MEM_ERR; goto error; } 620 strcpy(args->rng_state_input_filename, val); 621 } else if(!strcmp(key, "ostate")) { /* Output state */ 622 len = strlen(val); 623 args->rng_state_output_filename = mem_calloc(len+1, sizeof(char)); 624 if(!args->rng_state_output_filename) { res = RES_MEM_ERR; goto error; } 625 strcpy(args->rng_state_output_filename, val); 626 } else { 627 fprintf(stderr, "Invalid RNG option `%s'.\n", key); 628 res = RES_BAD_ARG; 629 goto error; 630 } 631 632 exit: 633 return res; 634 error: 635 goto exit; 636 } 637 638 /******************************************************************************* 639 * Local function 640 ******************************************************************************/ 641 res_T 642 solstice_args_init(struct solstice_args* args, const int argc, char** argv) 643 { 644 int opt; 645 int i, L_defined = 0; 646 double current_loc[2]; 647 res_T res = RES_OK; 648 ASSERT(args && argc && argv); 649 650 *args = SOLSTICE_ARGS_DEFAULT; 651 652 FOR_EACH(i, 1, argc) { 653 if(!strcmp(argv[i], "--version")) { 654 printf("Solstice %d.%d.%d\n", 655 SOLSTICE_VERSION_MAJOR, 656 SOLSTICE_VERSION_MINOR, 657 SOLSTICE_VERSION_PATCH); 658 args->quit = 1; 659 goto exit; 660 } 661 } 662 663 optind = 0; 664 while((opt = getopt(argc, argv, "A:D:fG:g:hI:n:L:o:p:qR:r:T:t:v")) != -1) { 665 switch(opt) { 666 case 'A': /* 1 sun direction */ 667 res = parse_sun_algorithm(optarg, args); 668 break; 669 case 'D': /* 1 sun direction */ 670 res = parse_sun_spherical(optarg, args); 671 break; 672 case 'f': args->force_overwriting = 1; break; 673 case 'G': /* Setup the random number generator */ 674 res = parse_multiple_options(optarg, args, parse_rng_option); 675 break; 676 case 'g': /* Switch in dump geometry mode and configure it */ 677 res = parse_multiple_options(optarg, args, parse_dump_option); 678 if(res == RES_OK && args->dump_format == SOLSTICE_ARGS_DUMP_NONE) { 679 fprintf(stderr, "%s: missing a dump format -- `%s'.\n", 680 argv[0], optarg); 681 res = RES_BAD_ARG; 682 goto error; 683 } 684 break; 685 case 'h': /* Print short help and exit */ 686 print_help(argv[0]); 687 solstice_args_release(args); 688 args->quit = 1; 689 goto exit; 690 case 'I': /* DNI */ 691 res = cstr_to_double(optarg, &args->dni); 692 if(res == RES_OK && args->dni <= 0) { 693 fprintf(stderr, "%s: invalid DNI value -- `%s'.\n", 694 argv[0], optarg); 695 res = RES_BAD_ARG; 696 goto error; 697 } 698 break; 699 case 'L': /* Plant location */ 700 L_defined = 1; 701 res = parse_location(optarg, current_loc); 702 break; 703 case 'n': /* Define the number of MC samples */ 704 res = cstr_to_ulong(optarg, &args->nexperiments); 705 if(res == RES_OK && !args->nexperiments) res = RES_BAD_ARG; 706 break; 707 case 'o': args->output_filename = optarg; break; 708 case 'p': /* Switch in dump radiative paths mode and configure it */ 709 args->dump_paths = 1; 710 res = parse_multiple_options(optarg, args, parse_dump_paths_option); 711 break; 712 case 'q': args->quiet = 1; break; 713 case 'R': args->receivers_filename = optarg; break; 714 case 'r': /* Switch in rendering mode and configure it */ 715 args->rendering = 1; 716 res = parse_multiple_options(optarg, args, parse_rendering_option); 717 break; 718 case 'T': /* 1 time */ 719 if(!L_defined) { 720 fprintf(stderr, 721 "%s: cannot use the -%c option with no location defined '%s'\n", 722 argv[0], opt, optarg); 723 res = RES_BAD_ARG; 724 goto error; 725 break; 726 } 727 res = parse_time(optarg, current_loc, args); 728 break; 729 case 't': /* Submit an hint on the number of threads to use */ 730 res = cstr_to_uint(optarg, &args->nthreads); 731 if(res == RES_OK && !args->nthreads) res = RES_BAD_ARG; 732 break; 733 case 'v': args->verbose = 1; break; 734 default: res = RES_BAD_ARG; break; 735 } 736 if(res != RES_OK) { 737 if(optarg) { 738 fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n", 739 argv[0], optarg, opt); 740 } 741 goto error; 742 } 743 } 744 745 if(!args->rendering 746 && args->dump_format == SOLSTICE_ARGS_DUMP_NONE 747 && args->nsun_dirs == 0) 748 { 749 fprintf(stderr, "No computation request.\n"); 750 res = RES_BAD_ARG; 751 goto error; 752 } 753 754 if(args->dump_format != SOLSTICE_ARGS_DUMP_NONE && args->rendering) { 755 fprintf(stderr, "The '-g' and '-r' options are exclusives.\n"); 756 res = RES_BAD_ARG; 757 goto error; 758 } 759 760 if(args->dump_format != SOLSTICE_ARGS_DUMP_NONE && args->dump_paths) { 761 fprintf(stderr, "The '-g' and '-p' options are exclusives.\n"); 762 res = RES_BAD_ARG; 763 goto error; 764 } 765 766 if(args->dump_paths && args->rendering) { 767 fprintf(stderr, "The '-p' and '-r' options are exclusives.\n"); 768 res = RES_BAD_ARG; 769 goto error; 770 } 771 772 if(optind < argc) { 773 args->input_filename = argv[optind]; 774 } 775 776 exit: 777 optind = 1; 778 return res; 779 error: 780 solstice_args_release(args); 781 goto exit; 782 } 783 784 void 785 solstice_args_release(struct solstice_args* args) 786 { 787 ASSERT(args); 788 sa_release(args->sun_dirs); 789 if(args->rng_state_input_filename) mem_rm(args->rng_state_input_filename); 790 if(args->rng_state_output_filename) mem_rm(args->rng_state_output_filename); 791 *args = SOLSTICE_ARGS_NULL; 792 } 793