diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-05-26 03:39:06 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-05-26 03:39:06 +0200 |
commit | 3757fe80b30801119bda41ab0445e915271129fc (patch) | |
tree | 62d282f929d02b96656ec3f8fab5ccef1f839a14 | |
parent | 4fabc85d2a59383c67239c488fb2c717657b5954 (diff) |
Allow use of multiple ranges when using cleanup command
-rwxr-xr-x | automedia | bin | 116640 -> 116664 bytes | |||
-rwxr-xr-x | build.sh | 2 | ||||
-rwxr-xr-x | open_media.py | 2 | ||||
-rwxr-xr-x | read_manga.py | 2 | ||||
-rw-r--r-- | src/main.c | 169 | ||||
-rw-r--r-- | src/track_remove_parser.c | 133 | ||||
-rw-r--r-- | src/track_remove_parser.h | 17 |
7 files changed, 237 insertions, 88 deletions
Binary files differ @@ -2,4 +2,4 @@ CFLAGS="-O3 -s -flto -Wall -Wextra -Werror" [ -z "$RELEASE" ] && CFLAGS="-O0 -g3 -Wall -Wextra -Werror"; -musl-gcc -static src/main.c src/program.c src/alloc.c src/buffer.c src/fileutils.c src/transmission.c src/rss.c src/html.c src/rss_html_common.c src/download.c src/stringutils.c src/episode.c depends/cJSON.c -o automedia $CFLAGS +musl-gcc -static src/main.c src/program.c src/alloc.c src/buffer.c src/fileutils.c src/transmission.c src/rss.c src/html.c src/rss_html_common.c src/download.c src/stringutils.c src/episode.c src/track_remove_parser.c depends/cJSON.c -o automedia $CFLAGS diff --git a/open_media.py b/open_media.py index 1f87975..ded438e 100755 --- a/open_media.py +++ b/open_media.py @@ -82,7 +82,7 @@ def main(): files.append(filename) files = sorted(files, key=sort_images) - process = subprocess.Popen(["sxiv", "-a", "-i", "-f"], stdin=subprocess.PIPE) + process = subprocess.Popen(["sxiv", "-a", "-i"], stdin=subprocess.PIPE) files_fullpath = [] for filename in files: files_fullpath.append(os.path.join(media_path, filename)) diff --git a/read_manga.py b/read_manga.py index 4ad25c7..bff0955 100755 --- a/read_manga.py +++ b/read_manga.py @@ -77,5 +77,5 @@ for chapter in chapters_by_oldest[start_index:]: images_str.append(os.path.join(image_dir, image)) index += 1 -process = subprocess.Popen(["sxiv", "-a", "-i", "-f"], stdin=subprocess.PIPE) +process = subprocess.Popen(["sxiv", "-a", "-i"], stdin=subprocess.PIPE) process.communicate("\n".join(images_str).encode()) @@ -7,6 +7,7 @@ #include "rss.h" #include "rss_html_common.h" #include "html.h" +#include "track_remove_parser.h" #include "../depends/cJSON.h" #include "alloc.h" @@ -734,6 +735,13 @@ static void command_cleanup(int argc, char **argv, const char *rss_config_dir, c ++index; } + char *track_items_selected = alloc_or_crash(num_tracked_items); + Buffer /*size_t*/ tracks_to_remove; + buffer_init(&tracks_to_remove); + + Buffer /*Range*/ track_remove_ranges; + buffer_init(&track_remove_ranges); + if(tracked_items.size == 0) { fprintf(stderr, "There is no media that hasn't been updated in the last %ld %s\n", days, days == 1 ? "day" : "days"); goto cleanup; @@ -744,117 +752,108 @@ static void command_cleanup(int argc, char **argv, const char *rss_config_dir, c fprintf(stderr, "==> "); fflush(stderr); - char resp[128]; + char resp[512]; if(!fgets(resp, sizeof(resp), stdin)) { fprintf(stderr, "Failed to read response from stdin\n"); goto cleanup; } + char *response_str = strip(resp); int response_len = strlen(response_str); if(response_len == 0) { - fprintf(stderr, "Invalid input, expected number range\n"); + fprintf(stderr, "Invalid input. Expected numbers and/or number ranges\n"); continue; } - int start_range = 0; - int end_range = 0; - int num_variables_read = sscanf(response_str, "%d-%d", &start_range, &end_range); + memset(track_items_selected, 0, num_tracked_items); + buffer_clear(&tracks_to_remove); + buffer_clear(&track_remove_ranges); - if(num_variables_read == 0) { - fprintf(stderr, "Invalid input, expected number range\n"); - } else if(num_variables_read == 1) { - int index = start_range - 1; - if(index < 0 || index >= num_tracked_items) { - fprintf(stderr, "Invalid item selected: %d, expected a value between 1 and %d\n", start_range, num_tracked_items); - continue; - } + if(track_remove_parser_parse(response_str, response_len, &track_remove_ranges) != 0) + continue; - const char *name = path_get_filename((list_begin + index)->item_tracked_path); - for(;;) { - fprintf(stderr, "==> Are you sure you want to stop tracking %s/%s? Yes/No: \n", index < num_rss_items ? "rss" : "html", name); - fprintf(stderr, "==> "); - fflush(stderr); - - char resp[128]; - if(!fgets(resp, sizeof(resp), stdin)) { - fprintf(stderr, "Failed to read response from stdin\n"); - goto cleanup; - } - char *response_str = strip(resp); - int response_len = strlen(response_str); - if(response_len == 0) - continue; + Range *track_remove_it = buffer_begin(&track_remove_ranges); + Range *track_remove_end = buffer_end(&track_remove_ranges); - if(response_str[0] == 'n' || response_str[0] == 'N') { - goto cleanup; - } else if(response_str[0] == 'y' || response_str[0] == 'Y') { - if(remove_recursive((list_begin + index)->item_tracked_path) != 0) { - fprintf(stderr, "Failed to remove %s/%s\n", index < num_rss_items ? "rss" : "html", name); - goto cleanup; - } - - fprintf(stderr, "Removed %s/%s\n", index < num_rss_items ? "rss" : "html", name); - goto cleanup; - } - } - } else if(num_variables_read == 2) { - int start_index_f = start_range - 1; + int valid_ranges = 1; + for(; track_remove_it != track_remove_end; ++track_remove_it) { + int start_index_f = track_remove_it->start - 1; if(start_index_f < 0 || start_index_f >= num_tracked_items) { - fprintf(stderr, "Invalid item start range: %d, expected a value between 1 and %d\n", start_range, num_tracked_items); - continue; + fprintf(stderr, "Invalid item start range: %d, expected a value between 1 and %d\n", track_remove_it->start, num_tracked_items); + valid_ranges = 0; + break; } - int end_index_f = end_range - 1; + int end_index_f = track_remove_it->end - 1; if(end_index_f < start_index_f || end_index_f >= num_tracked_items) { - fprintf(stderr, "Invalid item end range: %d, expected a value between %d and %d\n", end_index_f, start_range, num_tracked_items); - continue; + fprintf(stderr, "Invalid item end range: %d, expected a value between %d and %d\n", end_index_f, track_remove_it->start, num_tracked_items); + valid_ranges = 0; + break; } - for(;;) { - fprintf(stderr, "==> Are you sure you want to stop tracking:\n"); - TrackedItemData *list_it = list_begin + start_index_f; - TrackedItemData *list_end = list_begin + end_range; - int index = 0; - for(; list_it != list_end; ++list_it) { - const char *name = path_get_filename(list_it->item_tracked_path); - printf(" %s/%s\n", index < num_rss_items ? "rss" : "html", name); - ++index; - } - - fprintf(stderr, "==> Yes/No: "); - fflush(stderr); - - char resp[128]; - if(!fgets(resp, sizeof(resp), stdin)) { - fprintf(stderr, "Failed to read response from stdin\n"); - goto cleanup; - } - char *response_str = strip(resp); - int response_len = strlen(response_str); - fprintf(stderr, "response len: %d\n", response_len); - if(response_len == 0) + for(size_t i = start_index_f; i <= (size_t)end_index_f; ++i) { + if(track_items_selected[i]) continue; - if(response_str[0] == 'n' || response_str[0] == 'N') { - goto cleanup; - } else if(response_str[0] == 'y' || response_str[0] == 'Y') { - TrackedItemData *list_it = list_begin + start_index_f; - TrackedItemData *list_end = list_begin + end_range; - for(; list_it != list_end; ++list_it) { - const char *name = path_get_filename(list_it->item_tracked_path); - if(remove_recursive(list_it->item_tracked_path) != 0) { - fprintf(stderr, "Failed to remove %s/%s\n", index < num_rss_items ? "rss" : "html", name); - goto cleanup; - } - fprintf(stderr, "Removed %s/%s\n", index < num_rss_items ? "rss" : "html", name); - } - goto cleanup; - } + track_items_selected[i] = 1; + buffer_append(&tracks_to_remove, &i, sizeof(i)); + } + } + + if(!valid_ranges) + continue; + + for(;;) { + size_t *tracks_to_remove_it = buffer_begin(&tracks_to_remove); + size_t *tracks_to_remove_end = buffer_end(&tracks_to_remove); + fprintf(stderr, "==> Are you sure you want to stop tracking:\n"); + for(; tracks_to_remove_it != tracks_to_remove_end; ++tracks_to_remove_it) { + const size_t track_index = *tracks_to_remove_it; + TrackedItemData *track_item = &list_begin[track_index]; + const char *name = path_get_filename(track_item->item_tracked_path); + printf(" %s/%s\n", track_index < (size_t)num_rss_items ? "rss" : "html", name); } + + fprintf(stderr, "==> Yes/No: "); + fflush(stderr); + + if(!fgets(resp, sizeof(resp), stdin)) { + fprintf(stderr, "Failed to read response from stdin\n"); + goto cleanup; + } + + response_str = strip(resp); + response_len = strlen(response_str); + if(response_len == 0) + continue; + + if(response_str[0] == 'n' || response_str[0] == 'N') { + goto cleanup; + } else if(response_str[0] == 'y' || response_str[0] == 'Y') { + break; + } + } + + size_t *tracks_to_remove_it = buffer_begin(&tracks_to_remove); + size_t *tracks_to_remove_end = buffer_end(&tracks_to_remove); + for(; tracks_to_remove_it != tracks_to_remove_end; ++tracks_to_remove_it) { + const size_t track_index = *tracks_to_remove_it; + TrackedItemData *track_item = &list_begin[track_index]; + const char *name = path_get_filename(track_item->item_tracked_path); + if(remove_recursive(track_item->item_tracked_path) != 0) { + fprintf(stderr, "Failed to remove %s/%s\n", track_index < (size_t)num_rss_items ? "rss" : "html", name); + goto cleanup; + } + fprintf(stderr, "Removed %s/%s\n", track_index < (size_t)num_rss_items ? "rss" : "html", name); } + break; } cleanup: + buffer_deinit(&track_remove_ranges); + buffer_deinit(&tracks_to_remove); + free(track_items_selected); + list_it = buffer_begin(&tracked_items); list_end = buffer_end(&tracked_items); for(; list_it != list_end; ++list_it) { diff --git a/src/track_remove_parser.c b/src/track_remove_parser.c new file mode 100644 index 0000000..61c2375 --- /dev/null +++ b/src/track_remove_parser.c @@ -0,0 +1,133 @@ +#include "track_remove_parser.h" +#include <stdio.h> + +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; +} diff --git a/src/track_remove_parser.h b/src/track_remove_parser.h new file mode 100644 index 0000000..1783cc8 --- /dev/null +++ b/src/track_remove_parser.h @@ -0,0 +1,17 @@ +#ifndef TRACK_REMOVE_PARSER_H +#define TRACK_REMOVE_PARSER_H + +#include "buffer.h" + +typedef struct { + int start; + int end; +} Range; + +/* + |ranges| should be initialized before calling this. + Returns 0 on success. +*/ +int track_remove_parser_parse(const char *str, size_t size, Buffer /*Range*/ *ranges); + +#endif |