static int process_trimming(const char *input, char **storage, const char *input_end, int fail_when_empty) { const char *left, *right; int trimmed_input_length; left = skip_leading_spaces(input, input_end); right = skip_trailing_spaces(input, input_end - 1); if (right < left) { if (fail_when_empty) return git__throw(GIT_EINVALIDARGS, "Failed to trim. Input is either empty or only contains spaces"); else right = left - 1; } trimmed_input_length = right - left + 1; *storage = git__malloc(trimmed_input_length + 1); if (*storage == NULL) return GIT_ENOMEM; memcpy(*storage, left, trimmed_input_length); (*storage)[trimmed_input_length] = 0; return GIT_SUCCESS; }
static int process_trimming(const char *input, char **storage, const char *input_end, int fail_when_empty) { const char *left, *right; size_t trimmed_input_length; assert(storage); left = skip_leading_spaces(input, input_end); right = skip_trailing_spaces(input, input_end - 1); if (right < left) { if (fail_when_empty) return signature_error("input is either empty of contains only spaces"); right = left - 1; } trimmed_input_length = right - left + 1; *storage = git__malloc(trimmed_input_length + 1); GITERR_CHECK_ALLOC(*storage); memcpy(*storage, left, trimmed_input_length); (*storage)[trimmed_input_length] = 0; return 0; }
static void parse_header(char* header, char** name, long* bytes, int nparam, int* params) { char* saveptr = NULL; int i; assert(header != NULL); header = strtok_r(header, ":", &saveptr); if (name) { *name = header; skip_leading_spaces(name); cut_trailing_spaces(*name); } strtok_r(NULL, "<", &saveptr); header = strtok_r(NULL, ">", &saveptr); if (bytes) sscanf(header, "%ld", bytes); for (i = 0; i < nparam; ++i) { header = strtok_r(NULL, " \n", &saveptr); sscanf(header, "%d", ¶ms[i]); } }
/* Process the argument character and its associated value. * This function processes arguments from the command line and * from an argument file associated with the -A argument. * * An argument -ofile.pgn would be passed in as: * 'o' and "file.pgn". * A zero-length string for associated_value is not necessarily * an error, e.g. -e has an optional following filename. * NB: If the associated_value is to be used beyond this function, * it must be copied. */ void process_argument(char arg_letter,const char *associated_value) { /* Provide an alias for associated_value because it will * often represent a file name. */ const char *filename = skip_leading_spaces(associated_value); switch(arg_letter){ case WRITE_TO_OUTPUT_FILE_ARGUMENT: case APPEND_TO_OUTPUT_FILE_ARGUMENT: if(GlobalState.ECO_level > 0){ fprintf(GlobalState.logfile,"-%c conflicts with -E\n", arg_letter); } else if(GlobalState.games_per_file > 0){ fprintf(GlobalState.logfile,"-%c conflicts with -#\n", arg_letter); } else if(GlobalState.output_filename != NULL){ fprintf(GlobalState.logfile, "-%c: File %s has already been selected for output.\n", arg_letter,GlobalState.output_filename); exit(1); } else if(*filename == '\0'){ fprintf(GlobalState.logfile,"Usage: -%cfilename.\n",arg_letter); exit(1); } else{ if(GlobalState.outputfile != NULL){ (void) fclose(GlobalState.outputfile); } if(arg_letter == WRITE_TO_OUTPUT_FILE_ARGUMENT){ GlobalState.outputfile = must_open_file(filename,"w"); } else{ GlobalState.outputfile = must_open_file(filename,"a"); } GlobalState.output_filename = filename; } break; case WRITE_TO_LOG_FILE_ARGUMENT: case APPEND_TO_LOG_FILE_ARGUMENT: /* Take precautions against multiple log files. */ if((GlobalState.logfile != stderr) && (GlobalState.logfile != NULL)){ (void) fclose(GlobalState.logfile); } if(arg_letter == WRITE_TO_LOG_FILE_ARGUMENT){ GlobalState.logfile = fopen(filename,"w"); } else{ GlobalState.logfile = fopen(filename,"a"); } if(GlobalState.logfile == NULL){ fprintf(stderr,"Unable to open %s for writing.\n",filename); GlobalState.logfile = stderr; } break; case DUPLICATES_FILE_ARGUMENT: if(*filename == '\0'){ fprintf(GlobalState.logfile,"Usage: -%cfilename.\n",arg_letter); exit(1); } else if(GlobalState.suppress_duplicates){ fprintf(GlobalState.logfile, "-%c clashes with the -%c flag.\n",arg_letter, DONT_KEEP_DUPLICATES_ARGUMENT); exit(1); } else{ GlobalState.duplicate_file = must_open_file(filename,"w"); } break; case USE_ECO_FILE_ARGUMENT: GlobalState.add_ECO = TRUE; if(*filename != '\0'){ GlobalState.eco_file = copy_string(filename); } else if((filename = getenv("ECO_FILE")) != NULL){ GlobalState.eco_file = filename; } else{ /* Use the default which is already set up. */ } initEcoTable(); break; case ECO_OUTPUT_LEVEL_ARGUMENT: { unsigned level; if(GlobalState.output_filename != NULL){ fprintf(GlobalState.logfile, "-%c: File %s has already been selected for output.\n", arg_letter, GlobalState.output_filename); exit(1); } else if(GlobalState.games_per_file > 0){ fprintf(GlobalState.logfile, "-%c conflicts with -#.\n", arg_letter); exit(1); } else if(sscanf(associated_value,"%u",&level) != 1){ fprintf(GlobalState.logfile, "-%c requires a number attached, e.g., -%c1.\n", arg_letter,arg_letter); exit(1); } else if((level < MIN_ECO_LEVEL) || (level > MAX_ECO_LEVEL)){ fprintf(GlobalState.logfile, "-%c level should be between %u and %u.\n", MIN_ECO_LEVEL,MAX_ECO_LEVEL,arg_letter); exit(1); } else{ GlobalState.ECO_level = level; } } break; case CHECK_FILE_ARGUMENT: if(*filename != '\0'){ /* See if it is a single PGN file, or a list * of files. */ size_t len = strlen(filename); /* Check for a .PGN suffix. */ const char *suffix = output_file_suffix(SAN); if((len > strlen(suffix)) && (stringcompare(&filename[len-strlen(suffix)], suffix) == 0)){ add_filename_to_source_list(filename,CHECKFILE); } else{ FILE *fp = must_open_file(filename,"r"); add_filename_list_from_file(fp,CHECKFILE); (void) fclose(fp); } } break; case FILE_OF_FILES_ARGUMENT: if(*filename != '\0'){ FILE *fp = must_open_file(filename,"r"); add_filename_list_from_file(fp,NORMALFILE); (void) fclose(fp); } else{ fprintf(GlobalState.logfile,"Filename expected with -%c\n", arg_letter); } break; case BOUNDS_ARGUMENT: { /* Bounds on the number of moves are to be found. * "l#" means less-than-or-equal-to. * "g#" means greater-than-or-equal-to. * Otherwise "#" (or "e#") means that number. */ /* Equal by default. */ char which = 'e'; unsigned value; Boolean Ok = TRUE; const char *bound = associated_value; switch(*bound){ case 'l': case 'u': case 'e': which = *bound; bound++; break; default: if(!isdigit((int) *bound)){ fprintf(GlobalState.logfile, "-%c must be followed by e, l, or u.\n", arg_letter); Ok = FALSE; } break; } if(Ok && (sscanf(bound,"%u",&value) == 1)){ GlobalState.check_move_bounds = TRUE; switch(which){ case 'e': GlobalState.lower_move_bound = value; GlobalState.upper_move_bound = value; break; case 'l': if(value <= GlobalState.upper_move_bound){ GlobalState.lower_move_bound = value; } else{ fprintf(GlobalState.logfile, "Lower bound is greater than the upper bound; -%c ignored.\n", arg_letter); Ok = FALSE; } break; case 'u': if(value >= GlobalState.lower_move_bound){ GlobalState.upper_move_bound = value; } else{ fprintf(GlobalState.logfile, "Upper bound is smaller than the lower bound; -%c ignored.\n", arg_letter); Ok = FALSE; } break; } } else{ fprintf(GlobalState.logfile, "-%c should be in the form -%c[elu]number.\n", arg_letter,arg_letter); Ok = FALSE; } if(!Ok){ exit(1); } } break; case GAMES_PER_FILE_ARGUMENT: if(GlobalState.ECO_level > 0){ fprintf(GlobalState.logfile, "-%c conflicts with -E.\n",arg_letter); exit(1); } else if(GlobalState.output_filename != NULL){ fprintf(GlobalState.logfile, "-%c: File %s has already been selected for output.\n", arg_letter, GlobalState.output_filename); exit(1); } else if(sscanf(associated_value,"%u", &GlobalState.games_per_file) != 1){ fprintf(GlobalState.logfile, "-%c should be followed by an unsigned integer.\n", arg_letter); exit(1); } else{ /* Value set. */ } break; case FILE_OF_ARGUMENTS_ARGUMENT: if(*filename != '\0'){ /* @@@ Potentially recursive call. Is this safe? */ read_args_file(filename); } else{ fprintf(GlobalState.logfile,"Usage: -%cfilename.\n", arg_letter); } break; case NON_MATCHING_GAMES_ARGUMENT: if(*filename != '\0'){ if(GlobalState.non_matching_file != NULL){ (void) fclose(GlobalState.non_matching_file); } GlobalState.non_matching_file = must_open_file(filename,"w"); } else{ fprintf(GlobalState.logfile,"Usage: -%cfilename.\n",arg_letter); exit(1); } break; case TAG_EXTRACTION_ARGUMENT: /* A single tag extraction criterion. */ extract_tag_argument(associated_value); break; case LINE_WIDTH_ARGUMENT: { /* Specify an output line width. */ unsigned length; if(sscanf(associated_value,"%u",&length) > 0){ set_output_line_length(length); } else{ fprintf(GlobalState.logfile, "-%c should be followed by an unsigned integer.\n", arg_letter); exit(1); } } break; case HELP_ARGUMENT: usage_and_exit(); break; case OUTPUT_FORMAT_ARGUMENT: /* Whether to use the source form of moves or * rewrite them into another format. */ { OutputFormat format = which_output_format(associated_value); if(format == UCI) { /* Rewrite the game in a format suitable for input to * a UCI-compatible engine. * This is actually LALG but involves adjusting a lot of * the other statuses, too. */ GlobalState.keep_NAGs = FALSE; GlobalState.keep_comments = FALSE; GlobalState.keep_move_numbers = FALSE; GlobalState.keep_checks = FALSE; GlobalState.keep_variations = FALSE; set_output_line_length(5000); format = LALG; } GlobalState.output_format = format; } break; case SEVEN_TAG_ROSTER_ARGUMENT: if(GlobalState.tag_output_format == ALL_TAGS || GlobalState.tag_output_format == SEVEN_TAG_ROSTER) { GlobalState.tag_output_format = SEVEN_TAG_ROSTER; } else { fprintf(GlobalState.logfile, "-%c clashes with another argument.\n", SEVEN_TAG_ROSTER_ARGUMENT); exit(1); } break; case DONT_KEEP_COMMENTS_ARGUMENT: GlobalState.keep_comments = FALSE; break; case DONT_KEEP_DUPLICATES_ARGUMENT: /* Make sure that this doesn't clash with -d. */ if(GlobalState.duplicate_file == NULL){ GlobalState.suppress_duplicates = TRUE; } else{ fprintf(GlobalState.logfile, "-%c clashes with -%c flag.\n", DONT_KEEP_DUPLICATES_ARGUMENT, DUPLICATES_FILE_ARGUMENT); exit(1); } break; case DONT_MATCH_PERMUTATIONS_ARGUMENT: GlobalState.match_permutations = FALSE; break; case DONT_KEEP_NAGS_ARGUMENT: GlobalState.keep_NAGs = FALSE; break; case OUTPUT_FEN_STRING_ARGUMENT: /* Output a FEN string of the final position. * This is displayed in a comment. */ if(GlobalState.add_FEN_comments) { /* Already implied. */ GlobalState.output_FEN_string = FALSE; } else { GlobalState.output_FEN_string = TRUE; } break; case CHECK_ONLY_ARGUMENT: /* Report errors, but don't convert. */ GlobalState.check_only = TRUE; break; case KEEP_SILENT_ARGUMENT: /* Turn off progress reporting. */ GlobalState.verbose = FALSE; break; case USE_SOUNDEX_ARGUMENT: /* Use soundex matches for player tags. */ GlobalState.use_soundex = TRUE; break; case MATCH_CHECKMATE_ARGUMENT: /* Match only games that end in checkmate. */ GlobalState.match_only_checkmate = TRUE; break; case SUPPRESS_ORIGINALS_ARGUMENT: GlobalState.suppress_originals = TRUE; break; case DONT_KEEP_VARIATIONS_ARGUMENT: GlobalState.keep_variations = FALSE; break; case USE_VIRTUAL_HASH_TABLE_ARGUMENT: GlobalState.use_virtual_hash_table = TRUE; break; case TAGS_ARGUMENT: if(*filename != '\0'){ read_tag_file(filename); } break; case TAG_ROSTER_ARGUMENT: if(*filename != '\0'){ read_tag_roster_file(filename); } break; case MOVES_ARGUMENT: if(*filename != '\0'){ /* Where the list of variations of interest are kept. */ FILE *variation_file = must_open_file(filename,"r"); /* We wish to search for particular variations. */ add_textual_variations_from_file(variation_file); fclose(variation_file); } break; case POSITIONS_ARGUMENT: if(*filename != '\0'){ FILE *variation_file = must_open_file(filename,"r"); /* We wish to search for positional variations. */ add_positional_variations_from_file(variation_file); fclose(variation_file); } break; case ENDINGS_ARGUMENT: if(*filename != '\0'){ if(!build_endings(filename)){ exit(1); } } break; default: fprintf(GlobalState.logfile, "Unrecognized argument -%c\n", arg_letter); } }
void read_args_file(const char *infile) { char *line; FILE *fp = fopen(infile,"r"); if(fp == NULL){ fprintf(GlobalState.logfile,"Cannot open %s for reading.\n",infile); exit(1); } else{ ArgType linetype = NO_ARGUMENT_MATCH; ArgType nexttype; while((line = read_line(fp)) != NULL){ if(blank_line(line)){ (void) free(line); continue; } nexttype = classify_arg(line); if(nexttype == NO_ARGUMENT_MATCH){ if(*line == argument_prefix[0]){ /* Treat the line as a source file name. */ add_filename_to_source_list(&line[1],NORMALFILE); } else if(linetype != NO_ARGUMENT_MATCH){ /* Handle the line. */ switch(linetype){ case MOVES_ARGUMENT: add_textual_variation_from_line(line); break; case POSITIONS_ARGUMENT: add_positional_variation_from_line(line); break; case TAGS_ARGUMENT: process_tag_line(infile,line); break; case TAG_ROSTER_ARGUMENT: process_roster_line(line); break; case ENDINGS_ARGUMENT: process_ending_line(line); (void) free(line); break; default: fprintf(GlobalState.logfile, "Internal error: unknown linetype %d in read_args_file\n", linetype); (void) free(line); exit(-1); } } else{ /* It should have been a line applying to the * current linetype. */ fprintf(GlobalState.logfile, "Missing argument type for line %s in the argument file.\n", line); exit(1); } } else{ switch(nexttype){ /* Arguments with a possible additional * argument value. * All of these apply only to the current * line in the argument file. */ case WRITE_TO_OUTPUT_FILE_ARGUMENT: case APPEND_TO_OUTPUT_FILE_ARGUMENT: case WRITE_TO_LOG_FILE_ARGUMENT: case APPEND_TO_LOG_FILE_ARGUMENT: case DUPLICATES_FILE_ARGUMENT: case USE_ECO_FILE_ARGUMENT: case CHECK_FILE_ARGUMENT: case FILE_OF_FILES_ARGUMENT: case BOUNDS_ARGUMENT: case GAMES_PER_FILE_ARGUMENT: case ECO_OUTPUT_LEVEL_ARGUMENT: case FILE_OF_ARGUMENTS_ARGUMENT: case NON_MATCHING_GAMES_ARGUMENT: case TAG_EXTRACTION_ARGUMENT: case LINE_WIDTH_ARGUMENT: case OUTPUT_FORMAT_ARGUMENT: process_argument(line[argument_prefix_len], &line[argument_prefix_len+1]); linetype = NO_ARGUMENT_MATCH; break; case LONG_FORM_ARGUMENT: { char *arg = &line[argument_prefix_len+1]; char *space = strchr(arg, ' '); if(space != NULL) { /* We need to drop an associated value from arg. */ int arglen = space - arg; char *just_arg = (char *) MallocOrDie(arglen + 1); strncpy(just_arg, arg, arglen); just_arg[arglen] = '\0'; process_long_form_argument(just_arg, skip_leading_spaces(space)); } else { process_long_form_argument(arg, ""); linetype = NO_ARGUMENT_MATCH; } } break; /* Arguments with no additional * argument value. * All of these apply only to the current * line in the argument file. */ case SEVEN_TAG_ROSTER_ARGUMENT: case HELP_ARGUMENT: case ALTERNATIVE_HELP_ARGUMENT: case DONT_KEEP_COMMENTS_ARGUMENT: case DONT_KEEP_DUPLICATES_ARGUMENT: case DONT_MATCH_PERMUTATIONS_ARGUMENT: case DONT_KEEP_NAGS_ARGUMENT: case OUTPUT_FEN_STRING_ARGUMENT: case CHECK_ONLY_ARGUMENT: case KEEP_SILENT_ARGUMENT: case USE_SOUNDEX_ARGUMENT: case MATCH_CHECKMATE_ARGUMENT: case SUPPRESS_ORIGINALS_ARGUMENT: case DONT_KEEP_VARIATIONS_ARGUMENT: case USE_VIRTUAL_HASH_TABLE_ARGUMENT: process_argument(line[argument_prefix_len],""); linetype = NO_ARGUMENT_MATCH; break; /* Arguments whose values persist beyond * the current line. */ case MOVES_ARGUMENT: case POSITIONS_ARGUMENT: case ENDINGS_ARGUMENT: case TAGS_ARGUMENT: case TAG_ROSTER_ARGUMENT: process_argument(line[argument_prefix_len], &line[argument_prefix_len+1]); /* Apply this type to subsequent lines. */ linetype = nexttype; break; default: linetype = nexttype; break; } (void) free(line); } } (void) fclose(fp); } }