diff options
| -rw-r--r-- | CMakeLists.txt | 7 | ||||
| -rw-r--r-- | include/list_management.h | 35 | ||||
| -rw-r--r-- | include/options.h | 44 | ||||
| -rw-r--r-- | include/output.h | 29 | ||||
| -rw-r--r-- | src/dir_monitor.c | 331 | ||||
| -rw-r--r-- | src/list_management.c | 131 | ||||
| -rw-r--r-- | src/options.c | 131 | ||||
| -rw-r--r-- | src/output.c | 87 |
8 files changed, 466 insertions, 329 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e9238a..163f941 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,18 +10,23 @@ set (CMAKE_C_STANDARD 17) add_compile_options(-Wall) -set(SOURCE_DM src/dir_monitor.c) +set(SOURCE_DM src/dir_monitor.c src/list_management.c src/options.c src/output.c) add_executable(dir_monitor_debug ${SOURCE_DM}) +target_include_directories(dir_monitor_debug PRIVATE include) target_compile_options(dir_monitor_debug PUBLIC -g -DDEBUGBUILD -Werror) add_executable(dir_monitor_debug_asan ${SOURCE_DM}) +target_include_directories(dir_monitor_debug_asan PRIVATE include) target_compile_options(dir_monitor_debug_asan PUBLIC -g -DDEBUGBUILD -fsanitize=address -Werror) target_link_libraries(dir_monitor_debug_asan asan) add_executable(dir_monitor_asan ${SOURCE_DM}) +target_include_directories(dir_monitor_asan PRIVATE include) target_compile_options(dir_monitor_asan PUBLIC -fsanitize=address) target_link_libraries(dir_monitor_asan asan) add_executable(dir_monitor ${SOURCE_DM}) +target_include_directories(dir_monitor PRIVATE include) +target_compile_options(dir_monitor_debug PUBLIC -O2 -Werror) diff --git a/include/list_management.h b/include/list_management.h new file mode 100644 index 0000000..0a887c7 --- /dev/null +++ b/include/list_management.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Copyright 2025 Thorsten Töpper + * + * list_management - data handling related code + * + * vim:ts=4:sw=4:expandtab + */ + +#ifndef LIST_MANAGEMENT_H +#define LIST_MANAGEMENT_H + +#include <time.h> + +/* === DEFINITIONS === */ +struct list_node { + struct list_node *next; + size_t fsize; + char fname[256]; + time_t ftime; /* can be creation, access or modification */ +}; + +struct list_head { + struct list_node *first; +}; + +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 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); + + +#endif + diff --git a/include/options.h b/include/options.h new file mode 100644 index 0000000..70f22e4 --- /dev/null +++ b/include/options.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Copyright 2025 Thorsten Töpper + * + * dir_monitor - print specified stat() information from entries of a given + * directory to stdout. Call it via watch for repeated output to a terminal. + * + * vim:ts=4:sw=4:expandtab + */ + +#ifndef OPTIONS_H +#define OPTIONS_H + +#include <stdbool.h> + +#include "output.h" +#include "list_management.h" + + + +/* === DEFINITIONS === */ +#define PATH_SEP '/' + +enum esort_type { SORT_BY_SIZE, SORT_BY_TIME }; + + +/* === GLOBAL VARIABLES === */ +extern bool option_sort_reverse_order; +extern enum esort_type option_sort_type; +extern bool option_show_hidden_entries; +extern bool option_timestamp_long; + + +int parse_arguments(int argc, char **argv); +void set_option(const char *option_name, char *option_argument); +/* In theory a part of output, but it's easier to place it near the struct + * containing the options in options.c */ +void usage(char *executable); + + + + +#endif + diff --git a/include/output.h b/include/output.h new file mode 100644 index 0000000..22f3885 --- /dev/null +++ b/include/output.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Copyright 2025 Thorsten Töpper + * + * output related functions and definitions + * + * vim:ts=4:sw=4:expandtab + */ +#ifndef OUTPUT_H +#define OUTPUT_H +#include <stdio.h> + +#include "list_management.h" + + +#define LOGERR(...) {fprintf(stderr, "[%s:%d] %s: ", __FILE__, __LINE__, __func__); fprintf(stderr, __VA_ARGS__);} + +#ifdef DEBUGBUILD +#define DBGTRC(...) LOGERR(__VA_ARGS__) +#else +#define DBGTRC(...) +#endif + + +int fputc_all_cols(char c, FILE *fdout); +int fputc_width_x(char c, size_t x, FILE *fdout); +void print_list(struct list_head *list); +#endif + diff --git a/src/dir_monitor.c b/src/dir_monitor.c index 5323ce8..b2257ce 100644 --- a/src/dir_monitor.c +++ b/src/dir_monitor.c @@ -10,254 +10,22 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> -#include <ctype.h> -#include <getopt.h> -#include <stdint.h> -#include <stdbool.h> #include <errno.h> -#include <sys/types.h> #include <dirent.h> #include <sys/stat.h> -#include <time.h> -#include <sys/ioctl.h> - -#define LOGERR(...) {fprintf(stderr, "[%s:%d] %s: ", __FILE__, __LINE__, __func__); fprintf(stderr, __VA_ARGS__);} - -#ifdef DEBUGBUILD -#define DBGTRC(...) LOGERR(__VA_ARGS__) -#else -#define DBGTRC(...) -#endif +#include "output.h" +#include "list_management.h" +#include "options.h" /* === DEFINITIONS === */ -#define PATH_SEP '/' - -enum esort_type { SORT_BY_SIZE, SORT_BY_TIME }; -struct list_node { - struct list_node *next; - size_t fsize; - char fname[256]; - time_t ftime; /* can be creation, access or modification */ -}; - -struct list_head { - struct list_node *first; -}; -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; - - if (fname == NULL || fname[0] == '\0') { - LOGERR("ERROR: No valid filename given\n"); - return NULL; - } - - if ((node = calloc(1, sizeof(struct list_node))) == NULL) { - LOGERR("ERROR: Failed allocate memory for node: %s\n", strerror(errno)); - return NULL; - } - - node->next = NULL; - node->fsize = fsize; - node->ftime = ftime; - strncpy(node->fname, fname, 256); - return node; -} - - -inline void destroy_list(struct list_head *list) { - struct list_node *ptr = NULL; - if (list == NULL) - return; - while (list->first != NULL) { - ptr = list->first->next; - if (ptr == NULL) { - free(list->first); - break; - } - list->first->next = ptr->next; - free(ptr); - } - free(list); -} - - -inline int fputc_all_cols(char c, FILE *fdout) { - struct winsize terminal; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminal); - return fputc_width_x(c, ((terminal.ws_col == 0) ? 72 : terminal.ws_col), fdout); -} - - -/* Not the most performant way, but during output the time critical tasks are already done. */ -inline int fputc_width_x(char c, size_t x, FILE *fdout) { - size_t i=0; - - if (fdout == NULL) { - LOGERR("ERROR: No output stream given.\n"); - return EOF; - } - - if ( ! isprint(c) ) { c = '?'; } - - for (i=0; i<x; i++) { - if (fputc(c, fdout) == EOF) { - LOGERR("ERROR: Failed to write char 0x%02X to stream %d\n", c, fdout->_fileno); - return EOF; - } - } - - return 1; -} - -/* dirty... */ -#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) { - if (list == NULL) { LOGERR("ERROR: No list given.\n"); return -1; } - if (node == NULL) { LOGERR("ERROR: No node given.\n"); return -2; } - - if (list->first == NULL) { - list->first = node; - return 0; - } - INSERT_BY_NUMERIC_FIELD(list, node, fsize); - return -3; -} - -inline 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 (list->first == NULL) { - list->first = node; - return 0; - } - INSERT_BY_NUMERIC_FIELD(list, node, ftime); - return -3; -} -#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 = lh->first; - while (ptr != NULL) { - printf(" %8lu %2s ", ((ptr->fsize>=1024) ? (ptr->fsize/1024) : ptr->fsize), - ((ptr->fsize >= 1024) ? "kB" : "")); - - tm = localtime(&ptr->ftime); - if (option_timestamp_long) { - strftime(timestamp, sizeof(timestamp), "%Y%m%d %H:%M:%S %Z", tm); - printf(" %20s ", timestamp); - } else { - strftime(timestamp, sizeof(timestamp), "%H:%M:%S", tm); - printf(" %8s ", timestamp); - } - printf(" %s\n", ptr->fname); - total_size += ptr->fsize; - ptr = ptr->next; - } - fputc_all_cols('=', stdout); - printf("\nTotal size: %lu %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; -} - /* This function contains the only time critical code. The loop over * the directory content. @@ -339,99 +107,6 @@ 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; - } - - if (strcmp(option_name, "long-timestamp") == 0) { - option_timestamp_long = true; - 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); -} - -int parse_arguments(int argc, char **argv) { - int c = 0, index; - - while(1) { - index = 0; - c = getopt_long(argc, argv, "tv", long_options, &index); - - if (c == -1) { - break; - } - - switch (c) { - case 0: - set_option(long_options[index].name, optarg); - break; - case 't': - option_timestamp_long = true; - break; - case 'v': - option_show_hidden_entries = true; - break; - case '?': - break; - default: - LOGERR("ERROR: unrecognized option 0x%02X '%c'\n", c, c); - break; - } - } - - return optind; -} - - -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; diff --git a/src/list_management.c b/src/list_management.c new file mode 100644 index 0000000..634b884 --- /dev/null +++ b/src/list_management.c @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Copyright 2025 Thorsten Töpper + * + * vim:ts=4:sw=4:expandtab + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "output.h" +#include "list_management.h" + + + +/* === IMPLEMENTATION === */ +inline struct list_node *create_node(char *fname, size_t fsize, time_t ftime) { + struct list_node *node = NULL; + + if (fname == NULL || fname[0] == '\0') { + LOGERR("ERROR: No valid filename given\n"); + return NULL; + } + + if ((node = calloc(1, sizeof(struct list_node))) == NULL) { + LOGERR("ERROR: Failed allocate memory for node: %s\n", strerror(errno)); + return NULL; + } + + node->next = NULL; + node->fsize = fsize; + node->ftime = ftime; + /* With strncpy and strict compiler options it complained. A file name + * can't be longer than 256 bytes, including the string terminating \0 + * byte at the end. As the code no longer's in the same file...*/ + memcpy(node->fname, fname, 255); + node->fname[255] = '\0'; + return node; +} + + +inline void destroy_list(struct list_head *list) { + struct list_node *ptr = NULL; + if (list == NULL) + return; + while (list->first != NULL) { + ptr = list->first->next; + if (ptr == NULL) { + free(list->first); + break; + } + list->first->next = ptr->next; + free(ptr); + } + free(list); +} + + +/* dirty... */ +#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) { + if (list == NULL) { LOGERR("ERROR: No list given.\n"); return -1; } + if (node == NULL) { LOGERR("ERROR: No node given.\n"); return -2; } + + if (list->first == NULL) { + list->first = node; + return 0; + } + INSERT_BY_NUMERIC_FIELD(list, node, fsize); + return -3; +} + +inline 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 (list->first == NULL) { + list->first = node; + return 0; + } + INSERT_BY_NUMERIC_FIELD(list, node, ftime); + return -3; +} +#undef INSERT_BY_NUMERIC_FIELD + + +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; +} + diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..848eaf5 --- /dev/null +++ b/src/options.c @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Copyright 2025 Thorsten Töpper + * + * options - + * + * vim:ts=4:sw=4:expandtab + */ +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <stdbool.h> + + +#include "output.h" +#include "options.h" + + + + + +/* === 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 === */ + +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"); +} + + +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; + } + + if (strcmp(option_name, "long-timestamp") == 0) { + option_timestamp_long = true; + 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); +} + +int parse_arguments(int argc, char **argv) { + int c = 0, index; + + while(1) { + index = 0; + c = getopt_long(argc, argv, "tv", long_options, &index); + + if (c == -1) { + break; + } + + switch (c) { + case 0: + set_option(long_options[index].name, optarg); + break; + case 't': + option_timestamp_long = true; + break; + case 'v': + option_show_hidden_entries = true; + break; + case '?': + break; + default: + LOGERR("ERROR: unrecognized option 0x%02X '%c'\n", c, c); + break; + } + } + + return optind; +} + diff --git a/src/output.c b/src/output.c new file mode 100644 index 0000000..9dd274b --- /dev/null +++ b/src/output.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Copyright 2025 Thorsten Töpper + * + * vim:ts=4:sw=4:expandtab + */ + +#include <unistd.h> +#include <ctype.h> +#include <time.h> +#include <sys/ioctl.h> + +#include "output.h" +#include "options.h" + + + +inline int fputc_all_cols(char c, FILE *fdout) { + struct winsize terminal; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminal); + return fputc_width_x(c, ((terminal.ws_col == 0) ? 72 : terminal.ws_col), fdout); +} + + +/* Not the most performant way, but during output the time critical tasks are already done. */ +inline int fputc_width_x(char c, size_t x, FILE *fdout) { + size_t i=0; + + if (fdout == NULL) { + LOGERR("ERROR: No output stream given.\n"); + return EOF; + } + + if ( ! isprint(c) ) { c = '?'; } + + for (i=0; i<x; i++) { + if (fputc(c, fdout) == EOF) { + LOGERR("ERROR: Failed to write char 0x%02X to stream %d\n", c, fdout->_fileno); + return EOF; + } + } + + return 1; +} + + +/* 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 = lh->first; + while (ptr != NULL) { + printf(" %8lu %2s ", ((ptr->fsize>=1024) ? (ptr->fsize/1024) : ptr->fsize), + ((ptr->fsize >= 1024) ? "kB" : "")); + + tm = localtime(&ptr->ftime); + if (option_timestamp_long) { + strftime(timestamp, sizeof(timestamp), "%Y%m%d %H:%M:%S %Z", tm); + printf(" %20s ", timestamp); + } else { + strftime(timestamp, sizeof(timestamp), "%H:%M:%S", tm); + printf(" %8s ", timestamp); + } + printf(" %s\n", ptr->fname); + total_size += ptr->fsize; + ptr = ptr->next; + } + fputc_all_cols('=', stdout); + printf("\nTotal size: %lu %s\n", ((total_size>1024) ? total_size/1024 : total_size), + ((total_size >= 1024) ? "kB" : "")); + + if (lh != list) destroy_list(lh); +} + |
