#include <string.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include "fcs_user.h" #include "fcs_cl.h" #include "cl_chop.h" #include "prefix.h" #ifdef DMALLOC #include "dmalloc.h" #endif static int read_preset(char * preset_name, args_man_t * * args, char * * opened_files_dir_to_assign, char * user_preset_dir) { int ret_code = 1; char * home_dir_presetrc = NULL, * global_presetrc = NULL, * env_var_presetrc = NULL; char * path; char * * presetrc_pathes[5] = {&env_var_presetrc, &home_dir_presetrc, &global_presetrc, &user_preset_dir, NULL}; int path_idx; char line[8192]; FILE * f = NULL; char * fgets_ret; char * opened_files_dir = NULL; int read_next_preset = 0; { char * home_dir; home_dir = getenv("HOME"); if (home_dir) { home_dir_presetrc = malloc(strlen(home_dir) + 50); sprintf(home_dir_presetrc, "%s/.freecell-solver/presetrc", home_dir ); } } env_var_presetrc = getenv("FREECELL_SOLVER_PRESETRC"); global_presetrc = (FREECELL_SOLVER_PKG_DATA_DIR "/presetrc"); for(path_idx=0;(presetrc_pathes[path_idx] != NULL) ; path_idx++) { path = (*presetrc_pathes[path_idx]); if (path == NULL) { continue; } f = fopen(path, "rt"); if (f == NULL) { continue; } while(1) { fgets_ret = fgets(line, sizeof(line), f); if (fgets_ret == NULL) { break; } if (!strncmp(line, "dir=", 4)) { #define nullify_newline() \ { \ char * s; \ \ s = strchr(line, '\n'); \ if (s != NULL) \ { \ *s = '\0'; \ } \ } nullify_newline(); if (opened_files_dir != NULL) { free(opened_files_dir); } opened_files_dir = strdup(line+4); } else if (!strncmp(line, "name=", 5)) { nullify_newline(); if (!strcmp(line+5, preset_name)) { read_next_preset = 1; } } else if (!strncmp(line, "command=", 8)) { if (read_next_preset) { *args = freecell_solver_args_man_alloc(); freecell_solver_args_man_chop(*args, line+8); ret_code = 0; goto HAVE_PRESET; } } } fclose(f); f = NULL; #undef nullify_newline } HAVE_PRESET: if (f) { fclose(f); } if (home_dir_presetrc) { free(home_dir_presetrc); } if (ret_code == 0) { *opened_files_dir_to_assign = opened_files_dir; } else { if (opened_files_dir) { free(opened_files_dir); } } return ret_code; } int freecell_solver_user_cmd_line_parse_args_with_file_nesting_count( void * instance, int argc, const char * argv[], int start_arg, char * * known_parameters, freecell_solver_user_cmd_line_known_commands_callback_t callback, void * callback_context, char * * error_string, int * last_arg, int file_nesting_count, char * opened_files_dir ) { int arg; char * * known_param; int num_to_skip; int callback_ret; int ret; *error_string = NULL; for(arg=start_arg;arg<argc;arg++) { /* First check for the parameters that the user recognizes */ known_param = known_parameters; while((*known_param) && strcmp(*known_param, argv[arg])) { known_param++; } if ((*known_param) != NULL ) { callback_ret = callback(instance, argc, argv, arg, &num_to_skip, &ret, callback_context); if (callback_ret == FCS_CMD_LINE_SKIP) { arg += num_to_skip-1; continue; } else if (callback_ret == FCS_CMD_LINE_STOP) { *last_arg = arg; return ret; } } if (0) { } else if ((!strcmp(argv[arg], "-md")) || (!strcmp(argv[arg], "--max-depth"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } freecell_solver_user_limit_depth(instance, atoi(argv[arg])); } else if ((!strcmp(argv[arg], "-mi")) || (!strcmp(argv[arg], "--max-iters"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } freecell_solver_user_limit_current_instance_iterations(instance, atoi(argv[arg])); } else if ((!strcmp(argv[arg], "-to")) || (!strcmp(argv[arg], "--tests-order"))) { char * fcs_user_errstr; arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } ret = freecell_solver_user_set_tests_order(instance, argv[arg], &fcs_user_errstr); if (ret != 0) { char * errstr = malloc(strlen(fcs_user_errstr)+500); sprintf( errstr, "Error in tests' order!\n%s\n", fcs_user_errstr ); free(fcs_user_errstr); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } } else if ((!strcmp(argv[arg], "--freecells-num"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (freecell_solver_user_set_num_freecells(instance, atoi(argv[arg])) != 0) { char * errstr; errstr = malloc(500); sprintf(errstr, "Error! The freecells\' number " "exceeds the maximum of %i.\n" "Recompile the program if you wish to have more.\n", freecell_solver_user_get_max_num_freecells() ); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } } else if ((!strcmp(argv[arg], "--stacks-num"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (freecell_solver_user_set_num_stacks(instance, atoi(argv[arg])) != 0) { char * errstr; errstr = malloc(500); sprintf(errstr, "Error! The stacks\' number " "exceeds the maximum of %i.\n" "Recompile the program if you wish to have more.\n", freecell_solver_user_get_max_num_stacks() ); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } } else if ((!strcmp(argv[arg], "--decks-num"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (freecell_solver_user_set_num_decks(instance, atoi(argv[arg])) != 0) { char * errstr; errstr = malloc(500); sprintf(errstr, "Error! The decks\' number " "exceeds the maximum of %i.\n" "Recopmile the program if you wish to have more.\n", freecell_solver_user_get_max_num_decks() ); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } } else if ((!strcmp(argv[arg], "--sequences-are-built-by"))) { int sbb; arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (!strcmp(argv[arg], "suit")) { sbb = FCS_SEQ_BUILT_BY_SUIT; } else if (!strcmp(argv[arg], "rank")) { sbb = FCS_SEQ_BUILT_BY_RANK; } else { sbb = FCS_SEQ_BUILT_BY_ALTERNATE_COLOR; } freecell_solver_user_set_sequences_are_built_by_type(instance, sbb); } else if ((!strcmp(argv[arg], "--sequence-move"))) { int unlimited; arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (!strcmp(argv[arg], "unlimited")) { unlimited = 1; } else { unlimited = 0; } freecell_solver_user_set_sequence_move(instance, unlimited); } else if (!strcmp(argv[arg], "--empty-stacks-filled-by")) { int es_fill; arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (!strcmp(argv[arg], "kings")) { es_fill = FCS_ES_FILLED_BY_KINGS_ONLY; } else if (!strcmp(argv[arg], "none")) { es_fill = FCS_ES_FILLED_BY_NONE; } else { es_fill = FCS_ES_FILLED_BY_ANY_CARD; } freecell_solver_user_set_empty_stacks_filled_by( instance, es_fill ); } else if ( (!strcmp(argv[arg], "--game")) || (!strcmp(argv[arg], "--preset")) || (!strcmp(argv[arg], "-g")) ) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } ret = freecell_solver_user_apply_preset(instance, argv[arg]); if (ret == FCS_PRESET_CODE_NOT_FOUND) { char * errstr; errstr = malloc(strlen(argv[arg])+500); sprintf(errstr, "Unknown game \"%s\"!\n\n", argv[arg]); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } else if (ret == FCS_PRESET_CODE_FREECELLS_EXCEED_MAX) { char * errstr; errstr = malloc(strlen(argv[arg])+500); sprintf(errstr, "The game \"%s\" exceeds the maximal number " "of freecells in the program.\n" "Modify the file \"config.h\" and recompile, " "if you wish to solve one of its boards.\n", argv[arg] ); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } else if (ret == FCS_PRESET_CODE_STACKS_EXCEED_MAX) { char * errstr; errstr = malloc(strlen(argv[arg])+500); sprintf(errstr, "The game \"%s\" exceeds the maximal number " "of stacks in the program.\n" "Modify the file \"config.h\" and recompile, " "if you wish to solve one of its boards.\n", argv[arg] ); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } else if (ret != FCS_PRESET_CODE_OK) { char * errstr; errstr = malloc(strlen(argv[arg])+500); sprintf(errstr, "The game \"%s\" exceeds the limits of the program.\n" "Modify the file \"config.h\" and recompile, if you wish to solve one of its boards.\n", argv[arg] ); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } } else if ((!strcmp(argv[arg], "-me")) || (!strcmp(argv[arg], "--method"))) { int method; arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (!strcmp(argv[arg], "dfs")) { method = FCS_METHOD_HARD_DFS; } else if (!strcmp(argv[arg], "soft-dfs")) { method = FCS_METHOD_SOFT_DFS; } else if (!strcmp(argv[arg], "bfs")) { method = FCS_METHOD_BFS; } else if (!strcmp(argv[arg], "a-star")) { method = FCS_METHOD_A_STAR; } else if (!strcmp(argv[arg], "random-dfs")) { method = FCS_METHOD_RANDOM_DFS; } else { char * errstr; errstr = malloc(strlen(argv[arg])+500); sprintf( errstr, "Unknown solving method \"%s\".\n", argv[arg] ); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } freecell_solver_user_set_solving_method(instance, method); } else if ((!strcmp(argv[arg], "-asw")) || (!strcmp(argv[arg], "--a-star-weights"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } { int a; const char * start_num; char * end_num; char * num_copy; start_num = argv[arg]; for(a=0;a<5;a++) { while ((*start_num > '9') && (*start_num < '0') && (*start_num != '\0')) { start_num++; } if (*start_num == '\0') { break; } end_num = start_num+1; while ((((*end_num >= '0') && (*end_num <= '9')) || (*end_num == '.')) && (*end_num != '\0')) { end_num++; } num_copy = malloc(end_num-start_num+1); memcpy(num_copy, start_num, end_num-start_num); num_copy[end_num-start_num] = '\0'; freecell_solver_user_set_a_star_weight( instance, a, atof(num_copy) ); free(num_copy); start_num=end_num+1; } } } else if ((!strcmp(argv[arg], "-opt")) || (!strcmp(argv[arg], "--optimize-solution"))) { freecell_solver_user_set_solution_optimization(instance, 1); } else if ((!strcmp(argv[arg], "-seed"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } freecell_solver_user_set_random_seed(instance, atoi(argv[arg])); } else if ((!strcmp(argv[arg], "-mss")) || (!strcmp(argv[arg], "--max-stored-states"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } freecell_solver_user_limit_num_states_in_collection( instance, atoi(argv[arg]) ); } else if ( (!strcmp(argv[arg], "-nst")) || (!strcmp(argv[arg], "--next-soft-thread")) || (!strcmp(argv[arg], "-nht")) || (!strcmp(argv[arg], "--next-hard-thread")) ) { int ret; int is_st = ((!strcmp(argv[arg], "-nst")) || (!strcmp(argv[arg], "--next-soft-thread"))); ret = is_st ? freecell_solver_user_next_soft_thread(instance) : freecell_solver_user_next_hard_thread(instance) ; if (ret) { char * errstr; errstr = strdup("The maximal number of soft threads has been exceeded\n"); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } } else if ((!strcmp(argv[arg], "-step")) || (!strcmp(argv[arg], "--soft-thread-step"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } freecell_solver_user_set_soft_thread_step( instance, atoi(argv[arg]) ); } else if ((!strcmp(argv[arg], "--reparent-states"))) { freecell_solver_user_set_reparent_states( instance, 1 ); } else if ((!strcmp(argv[arg], "--calc-real-depth"))) { freecell_solver_user_set_calc_real_depth( instance, 1); } else if ((!strcmp(argv[arg], "--st-name"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } freecell_solver_user_set_soft_thread_name(instance, argv[arg]); } else if ((!strcmp(argv[arg], "--prelude"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } freecell_solver_user_set_hard_thread_prelude(instance, argv[arg]); } else if ((!strcmp(argv[arg], "-opt-to")) || (!strcmp(argv[arg], "--optimization-tests-order"))) { char * fcs_user_errstr; arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } ret = freecell_solver_user_set_optimization_scan_tests_order( instance, argv[arg], &fcs_user_errstr ); if (ret != 0) { char * errstr = malloc(strlen(fcs_user_errstr)+500); sprintf( errstr, "Error in the optimization scan's tests' order!\n%s\n", fcs_user_errstr ); free(fcs_user_errstr); *error_string = errstr; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } } else if ((!strcmp(argv[arg], "--scans-synergy"))) { int value; arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (!strcmp(argv[arg], "none")) { value = 0; } else if (!strcmp(argv[arg], "dead-end-marks")) { value = 1; } else { char * errstr; errstr = malloc(strlen(argv[arg])+500); sprintf(errstr, "Unknown scans' synergy type \"%s\"!\n", argv[arg]); *last_arg = arg; *error_string = errstr; return FCS_CMD_LINE_ERROR_IN_ARG; } freecell_solver_user_set_scans_synergy( instance, value ); } else if ((!strcmp(argv[arg], "-ni")) || (!strcmp(argv[arg], "--next-instance"))) { freecell_solver_user_next_instance(instance); } else if (!strcmp(argv[arg], "--reset")) { freecell_solver_user_reset(instance); } else if (!strcmp(argv[arg], "--read-from-file")) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } if (file_nesting_count == 0) { /* do nothing */ } else { int num_to_skip = 0; char * s, * buffer; FILE * f; long file_len; int ret; size_t num_read; args_man_t * args_man; s = argv[arg]; while(isdigit(*s)) { s++; } if (*s == ',') { num_to_skip = atoi(argv[arg]); s++; } if (opened_files_dir) { char * complete_path; complete_path = malloc(strlen(opened_files_dir)+strlen(s)+1); sprintf(complete_path, "%s%s", opened_files_dir, s); f = fopen(complete_path, "rt"); free(complete_path); } else { /* * Initialize f to NULL so it will be initialized * */ f = NULL; } /* Try to open from the local path */ if (f == NULL) { f = fopen(s, "rt"); } /* If we still could not open it return an error */ if (f == NULL) { char * err_str; err_str = malloc(strlen(s)+100); sprintf(err_str, "Could not open file \"%s\"!\nQuitting.\n", s); *error_string = err_str; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } fseek(f, 0, SEEK_END); file_len = ftell(f); buffer=malloc(file_len+1); if (buffer == NULL) { *error_string = strdup("Could not allocate enough memory to parse the file. Quitting.\n"); fclose(f); *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } fseek(f,0,SEEK_SET); num_read = fread(buffer, 1, file_len, f); fclose(f); buffer[num_read] = '\0'; args_man = freecell_solver_args_man_alloc(); ret = freecell_solver_args_man_chop(args_man, buffer); free(buffer); if (ret != 0) { *error_string = strdup("Could not parse the file. Quitting\n"); freecell_solver_args_man_free(args_man); *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } if (num_to_skip >= args_man->argc) { /* Do nothing */ } else { ret = freecell_solver_user_cmd_line_parse_args_with_file_nesting_count( instance, args_man->argc - num_to_skip, args_man->argv + num_to_skip, 0, known_parameters, callback, callback_context, error_string, last_arg, ((file_nesting_count < 0) ? file_nesting_count : (file_nesting_count-1)), opened_files_dir ); if (ret == FCS_CMD_LINE_UNRECOGNIZED_OPTION) { /* Do nothing - continue */ } else if (ret != FCS_CMD_LINE_OK) { freecell_solver_args_man_free(args_man); return ret; } } freecell_solver_args_man_free(args_man); } } else if ((!strcmp(argv[arg], "-l")) || (!strcmp(argv[arg], "--load-config"))) { arg++; if (arg == argc) { *last_arg = arg-1; return FCS_CMD_LINE_PARAM_WITH_NO_ARG; } { int status; args_man_t * preset_args = 0; char * dir = NULL; status = read_preset(argv[arg], &preset_args, &dir, NULL); if (status != 0) { char * err_str; err_str = malloc(strlen(argv[arg]) + 100); sprintf(err_str, "Unable to load the \"%s\" configuration!\n", argv[arg]); *error_string = err_str; *last_arg = arg; return FCS_CMD_LINE_ERROR_IN_ARG; } else { ret = freecell_solver_user_cmd_line_parse_args_with_file_nesting_count( instance, preset_args->argc, preset_args->argv, 0, known_parameters, callback, callback_context, error_string, last_arg, ((file_nesting_count < 0) ? file_nesting_count : (file_nesting_count-1)), dir ? dir : opened_files_dir ); if (dir) { free(dir); } freecell_solver_args_man_free(preset_args); if (ret == FCS_CMD_LINE_UNRECOGNIZED_OPTION) { /* Do nothing - continue */ } else if (ret != FCS_CMD_LINE_OK) { return ret; } } } } else { *last_arg = arg; return FCS_CMD_LINE_UNRECOGNIZED_OPTION; } } *last_arg = arg; return FCS_CMD_LINE_OK; } int freecell_solver_user_cmd_line_parse_args( void * instance, int argc, const char * argv[], int start_arg, char * * known_parameters, freecell_solver_user_cmd_line_known_commands_callback_t callback, void * callback_context, char * * error_string, int * last_arg ) { return freecell_solver_user_cmd_line_parse_args_with_file_nesting_count( instance, argc, argv, start_arg, known_parameters, callback, callback_context, error_string, last_arg, -1, NULL ); }