diff options
Diffstat (limited to 'kpat/freecell-solver/cmd_line.c')
-rw-r--r-- | kpat/freecell-solver/cmd_line.c | 964 |
1 files changed, 964 insertions, 0 deletions
diff --git a/kpat/freecell-solver/cmd_line.c b/kpat/freecell-solver/cmd_line.c new file mode 100644 index 00000000..63fbf6c9 --- /dev/null +++ b/kpat/freecell-solver/cmd_line.c @@ -0,0 +1,964 @@ +#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 + ); +} + |