From a8d2c8044dbdd7cffa475d894843e32747a30eee Mon Sep 17 00:00:00 2001 From: Thorsten Töpper Date: Sat, 14 Jun 2025 19:26:57 +0200 Subject: dir_monitor.c: Sort by time, and reversal option --- src/dir_monitor.c | 164 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 132 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/dir_monitor.c b/src/dir_monitor.c index 9e993a8..8d70262 100644 --- a/src/dir_monitor.c +++ b/src/dir_monitor.c @@ -35,6 +35,7 @@ /* === DEFINITIONS === */ #define PATH_SEP '/' +enum esort_type { SORT_BY_SIZE, SORT_BY_TIME, SORT_UNDEFINED }; struct list_node { struct list_node *next; size_t fsize; @@ -47,28 +48,34 @@ struct list_head { }; struct list_node *create_node(char *fname, size_t fsize, time_t ftime); +struct list_head *create_list_sort_reversed(struct list_head *list); void destroy_list(struct list_head *list); int fputc_all_cols(char c, FILE *fdout); int fputc_width_x(char c, size_t x, FILE *fdout); struct list_head *get_data_from_directory(char *path); int insert_sorted_by_size(struct list_head *list, struct list_node *node); +int insert_sorted_by_time(struct list_head *list, struct list_node *node); int parse_arguments(int argc, char **argv); void print_list(struct list_head *list); void set_option(const char *option_name, char *option_argument); +void usage(char *executable); /* === GLOBAL VARIABLES === */ struct option long_options[] = { + { "reverse-sort", no_argument, 0, 0 }, { "show-hidden-entries", no_argument, 0, 0 }, + { "sort-by", required_argument, 0, 0 }, { "long-timestamp", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; +bool option_sort_reverse_order = false; +enum esort_type option_sort_type = SORT_BY_SIZE; bool option_show_hidden_entries = false; bool option_timestamp_long = false; - /* === IMPLEMENTATION === */ inline struct list_node *create_node(char *fname, size_t fsize, time_t ftime) { struct list_node *node = NULL; @@ -137,10 +144,21 @@ inline int fputc_width_x(char c, size_t x, FILE *fdout) { } +#define INSERT_BY_NUMERIC_FIELD(list, node, field) \ +{ struct list_node *ptr = NULL; \ + if (node->field > list->first->field) { \ + node->next = list->first; list->first = node; return 0; } \ + ptr = list->first; \ + while (ptr != NULL) { \ + if (ptr->next == NULL) { ptr->next = node; return 0; } \ + if (node->field > ptr->next->field) { \ + node->next = ptr->next; ptr->next = node; \ + return 0; } \ + ptr = ptr->next; } } + + /* TODO: later when, other parameters are actively used move the action to a template */ inline int insert_sorted_by_size(struct list_head *list, struct list_node *node) { - struct list_node *ptr = NULL; - if (list == NULL) { LOGERR("ERROR: No list given.\n"); return -1; } if (node == NULL) { LOGERR("ERROR: No node given.\n"); return -2; } @@ -148,41 +166,40 @@ inline int insert_sorted_by_size(struct list_head *list, struct list_node *node) list->first = node; return 0; } + INSERT_BY_NUMERIC_FIELD(list, node, fsize); + return -3; +} + +int insert_sorted_by_time(struct list_head *list, struct list_node *node) { + if (list == NULL) { LOGERR("ERROR: No list given.\n"); return -1; } + if (node == NULL) { LOGERR("ERROR: No node given.\n"); return -2; } - if (node->fsize > list->first->fsize) { - node->next = list->first; + if (list->first == NULL) { list->first = node; return 0; } - - ptr = list->first; - while (ptr != NULL) { - if (ptr->next == NULL) { - ptr->next = node; - return 0; - } - if (node->fsize > ptr->next->fsize) { - node->next = ptr->next; - ptr->next = node; - return 0; - } - ptr = ptr->next; - } - - return -3; + INSERT_BY_NUMERIC_FIELD(list, node, ftime); } - +#undef INSERT_BY_NUMERIC_FIELD /* The most simple default output, formatted output is planned */ void print_list(struct list_head *list) { + struct list_head *lh = list; struct list_node *ptr; struct tm *tm = NULL; char timestamp[128]; size_t total_size = 0; if (list == NULL) return; + if (option_sort_reverse_order) { + lh = create_list_sort_reversed(list); + /* be tolerant */ + if (lh == NULL) { + lh = list; + } + } - ptr = list->first; + ptr = lh->first; while (ptr != NULL) { printf(" %8lu %2s ", ((ptr->fsize>=1024) ? (ptr->fsize/1024) : ptr->fsize), ((ptr->fsize >= 1024) ? "kB" : "")); @@ -202,6 +219,39 @@ void print_list(struct list_head *list) { fputc_all_cols('=', stdout); printf("\nTotal size: %llu %s\n", ((total_size>1024) ? total_size/1024 : total_size), ((total_size >= 1024) ? "kB" : "")); + + if (lh != list) destroy_list(lh); +} + + + +struct list_head *create_list_sort_reversed(struct list_head *list) { + struct list_head *lh = NULL; + struct list_node *cpynode = NULL, *ptr = NULL; + if (list == NULL) { + LOGERR("ERROR: No list given\n"); + return NULL; + } + if ((lh = calloc(1, sizeof(struct list_head))) == NULL) { + LOGERR("ERROR: Failed to allocate memory for a struct list_head\n"); + return NULL; + } + + lh->first = NULL; + ptr = list->first; + + while (ptr != NULL) { + cpynode = create_node(ptr->fname, ptr->fsize, ptr->ftime); + if (cpynode == NULL) { + destroy_list(lh); + return NULL; + } + cpynode->next = lh->first; + lh->first = cpynode; + ptr = ptr->next; + } + + return lh; } @@ -257,7 +307,14 @@ struct list_head *get_data_from_directory(char *path) { } /* currently ignoring return values */ tmp = create_node(de->d_name, stat_res.st_size, stat_res.st_mtime); - insert_sorted_by_size(list, tmp); + switch (option_sort_type) { + case SORT_BY_SIZE: + insert_sorted_by_size(list, tmp); + break; + case SORT_BY_TIME: + insert_sorted_by_time(list, tmp); + break; + }; } free(fullpath); @@ -267,9 +324,14 @@ struct list_head *get_data_from_directory(char *path) { void set_option(const char *option_name, char *option_argument) { + + DBGTRC("DEBUG: called with option_name '%s' and option_argument '%s'\n", + option_name, option_argument); + if (option_name == NULL) return; + /* options WITHOUT arguments */ if (strcmp(option_name, "show-hidden-entries") == 0) { option_show_hidden_entries = true; return; @@ -280,6 +342,30 @@ void set_option(const char *option_name, char *option_argument) { return; } + if (strcmp("reverse-sort", option_name) == 0) { + option_sort_reverse_order = true; + return; + } + + /* options WITH arguments */ + if (option_argument == NULL || option_argument[0] == '\0') { + LOGERR("ERROR: option_name %s with missing option_argument\n", + option_name); + return; + } + + if (strcmp(option_name, "sort-by") == 0) { + if (strncmp("size", option_argument, 4) == 0) { + option_sort_type = SORT_BY_SIZE; + } else if (strncmp("time", option_argument, 4) == 0) { + option_sort_type = SORT_BY_TIME; + } else { + LOGERR("WARNING: '%s' is an invalig argument for %s\n", + option_argument, option_name); + } + return; + } + LOGERR("ERROR: Option '%s' not recognized\n.", option_name); } @@ -304,8 +390,10 @@ int parse_arguments(int argc, char **argv) { case 'v': option_show_hidden_entries = true; break; + case '?': + break; default: - LOGERR("ERROR: unrecognized option '0x%02X'\n", c); + LOGERR("ERROR: unrecognized option 0x%02X '%c'\n", c); break; } } @@ -314,21 +402,33 @@ int parse_arguments(int argc, char **argv) { } +void usage(char *executable) { + fprintf(stderr, "Call: %s OPTIONS path_to_open\n", executable); + fprintf(stderr, "\nOPTIONS are\n"); + /* long name, short name, optional argument, explanation */ + fprintf(stderr, " %-25s %2s %10s %s\n", "--long-timestamp", "-t", "", + "Print timestamp in long form yyyymmdd HH:MM:SS ZONE"); + fprintf(stderr, " %-25s %2s %10s %s\n", "--reverse-sort", "", "", + "Sort reversed"); + fprintf(stderr, " %-25s %2s %10s %s\n", "--show-hidden-entries", "-v", "", + "Show hidden entries in the directory"); + fprintf(stderr, " %-25s %2s %10s %s\n", "--sort-by", "", "size|time", + "Sort either by time or size"); +} + int main(int argc, char **argv) { struct list_head *list = NULL; int path_index = 1; /* TODO: Handle options */ if (argc < 2) { - fprintf(stderr, "Call: %s OPTIONS path_to_open\n", argv[0]); - fprintf(stderr, "\nOPTIONS are\n"); - /* long name, short name, optional argument, explanation */ - fprintf(stderr, " %-25s %2s %10s %s\n", "--long-timestamp", "-t", "", - "Print timestamp in long form yyyymmdd HH:MM:SS ZONE"); - fprintf(stderr, " %-25s %2s %10s %s\n", "--show-hidden-entries", "-v", "", - "Show hidden entries in the directory"); + usage(argv[0]); return EXIT_FAILURE; } path_index = parse_arguments(argc, argv); + if (path_index == argc) { + usage(argv[0]); + return EXIT_FAILURE; + } list = get_data_from_directory(argv[path_index]); print_list(list); destroy_list(list); -- cgit v1.2.3-70-g09d2