#include "track_remove_parser.h" #include typedef enum { TR_TOK_RANGE, TR_TOK_END_OF_FILE, TR_TOK_INVALID } TrackRemoveToken; typedef struct { const char *str; size_t size; size_t offset; Range range; } TrackRemoveTokenizer; static int is_number(char c) { return c >= '0' && c <= '9'; } /* Returns non-0 value on overflow */ static int string_to_num_unchecked(const char *str, size_t size, int *number) { int result = 0; for(size_t i = 0; i < size; ++i) { const int result_before = result; result *= 10; result += (str[i] - '0'); /* overflow */ if(result <= result_before) return 1; } *number = result; return 0; } static void track_remover_tokenizer_init(TrackRemoveTokenizer *self, const char *str, size_t size) { self->str = str; self->size = size; self->offset = 0; self->range.start = 0; self->range.end = 0; } static int track_remover_tokenizer_get_char(TrackRemoveTokenizer *self) { if(self->offset < self->size) return self->str[self->offset]; else return '\0'; } static TrackRemoveToken track_remover_tokenizer_next(TrackRemoveTokenizer *self) { char c; for(;;) { c = track_remover_tokenizer_get_char(self); if(c != ' ' && c != '\t') break; ++self->offset; } if(c >= '1' && c <= '9') { size_t number_start = self->offset; ++self->offset; for(;;) { c = track_remover_tokenizer_get_char(self); if(!is_number(c)) break; ++self->offset; } if(string_to_num_unchecked(self->str + number_start, self->offset - number_start, &self->range.start) != 0) return TR_TOK_INVALID; self->range.end = self->range.start; if(c != '-') return TR_TOK_RANGE; ++self->offset; c = track_remover_tokenizer_get_char(self); if(!is_number(c)) return TR_TOK_INVALID; number_start = self->offset; ++self->offset; for(;;) { c = track_remover_tokenizer_get_char(self); if(!is_number(c)) break; ++self->offset; } if(string_to_num_unchecked(self->str + number_start, self->offset - number_start, &self->range.end) != 0) return TR_TOK_INVALID; return TR_TOK_RANGE; } else if(c == '\0') { return TR_TOK_END_OF_FILE; } else { return TR_TOK_INVALID; } } int track_remove_parser_parse(const char *str, size_t size, Buffer /*Range*/ *ranges) { int num_ranges = 0; TrackRemoveTokenizer tokenizer; track_remover_tokenizer_init(&tokenizer, str, size); for(;;) { TrackRemoveToken token = track_remover_tokenizer_next(&tokenizer); if(token == TR_TOK_RANGE) { if(tokenizer.range.start > tokenizer.range.end) { fprintf(stderr, "Invalid number range. The start range can't be past the end range\n"); return 1; } buffer_append(ranges, &tokenizer.range, sizeof(tokenizer.range)); ++num_ranges; } else if(token == TR_TOK_END_OF_FILE) { break; } else { fprintf(stderr, "Invalid input. Expected numbers and/or number ranges\n"); return 1; } } if(num_ranges == 0) { fprintf(stderr, "Invalid input. Expected numbers and/or number ranges\n"); return 1; } return 0; }