You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/kpat/freecell-solver/cmd_line.c

966 lines
28 KiB

#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;
const 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, (char*)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, (char*)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;
const char * s;
char * 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,
(const char **)(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((char*)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,
(const char**)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
);
}