aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dir_monitor.c6
-rw-r--r--src/options.c17
-rw-r--r--src/output.c173
3 files changed, 161 insertions, 35 deletions
diff --git a/src/dir_monitor.c b/src/dir_monitor.c
index 509e99f..46409cd 100644
--- a/src/dir_monitor.c
+++ b/src/dir_monitor.c
@@ -30,7 +30,11 @@ int main(int argc, char **argv) {
}
list = get_data_from_directory(argv[path_index]);
- print_list(list);
+ if (option_format_string == NULL) {
+ print_list(list);
+ } else {
+ print_list_formatted(option_format_string, list);
+ }
destroy_list(list);
return EXIT_SUCCESS;
diff --git a/src/options.c b/src/options.c
index 8a2216d..293ca3d 100644
--- a/src/options.c
+++ b/src/options.c
@@ -19,6 +19,7 @@
/* === GLOBAL VARIABLES === */
struct option long_options[] = {
{ "help", no_argument, 0, 0 },
+ { "format-string", required_argument, 0, 0 },
{ "long-timestamp", no_argument, 0, 0 },
{ "reverse-sort", no_argument, 0, 0 },
{ "show-hidden-entries", no_argument, 0, 0 },
@@ -31,6 +32,7 @@ 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;
+char *option_format_string = NULL;
/* There are three fields regarding time, valid values 'a','c', 'm':
* st_atime / st_atim.tv_sec - time of the last access
@@ -49,6 +51,8 @@ void usage(char *executable) {
/* long name, short name, optional argument, explanation */
fprintf(stderr, " %-25s %2s %10s - %s\n", "--help", "-h", "",
"Show this message and exit");
+ fprintf(stderr, " %-25s %2s %10s - %s\n", "--format-string", "", "format",
+ "define columns to print, details below");
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", "", "",
@@ -63,6 +67,14 @@ void usage(char *executable) {
/* fputc_width_x('-', 72, stderr); */
fprintf(stderr, "\n\n--sort-by variants: name | size | time\n");
+
+ fprintf(stderr, "\n--format-string: Characters unlike the following are ignored\n");
+ fprintf(stderr, " n - name\n");
+ fprintf(stderr, " s - size\n");
+ fprintf(stderr, " t - time defined by --time-field (default: modification time)\n");
+ fprintf(stderr, " A - access time\n");
+ fprintf(stderr, " C - change time\n");
+ fprintf(stderr, " M - modification time\n");
}
@@ -102,6 +114,11 @@ void set_option(const char *option_name, char *option_argument) {
exit(EXIT_FAILURE);
}
+ if (strcmp("format-string", option_name) == 0) {
+ option_format_string = option_argument;
+ return;
+ }
+
if (strcmp("sort-by", option_name) == 0) {
if (strncmp("name", option_argument, 4) == 0) {
option_sort_type = SORT_BY_NAME;
diff --git a/src/output.c b/src/output.c
index 53a0ff3..254d73f 100644
--- a/src/output.c
+++ b/src/output.c
@@ -5,6 +5,7 @@
* vim:ts=4:sw=4:expandtab
*/
+#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
@@ -16,6 +17,20 @@
+/* === DEFINITIONS === */
+
+#define out_vsep fputc('|', stdout)
+
+#define out_print_newline() fputc('\n', stdout)
+#define out_print_fname(x) printf(" %s ", x->fname)
+
+void out_print_size(struct list_node *ptr);
+void out_print_time(time_t tv);
+void out_print_time_by_option(struct list_node *ptr);
+
+
+/* === IMPLEMENTATION === */
+
inline int fputc_all_cols(char c, FILE *fdout) {
struct winsize terminal;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminal);
@@ -45,13 +60,57 @@ inline int fputc_width_x(char c, size_t x, FILE *fdout) {
}
+
+/* === FORMATTING RELATED FUNCTIONS === */
+inline void out_print_size(struct list_node *ptr) {
+ printf(" %8ld %2s ", ((ptr->ln_stat.st_size>=1024) ? (ptr->ln_stat.st_size/1024) : ptr->ln_stat.st_size),
+ ((ptr->ln_stat.st_size >= 1024) ? "kB" : ""));
+}
+
+inline void out_print_time(time_t tv) {
+ struct tm *tm = NULL;
+ char timestamp[128];
+
+ tm = localtime(&tv);
+ 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);
+ }
+}
+
+inline void out_print_time_by_option(struct list_node *ptr) {
+ time_t time_value = 0;
+
+ switch (option_time_field) {
+ case 'm':
+ time_value = ptr->ln_stat.st_mtim.tv_sec;
+ break;
+ case 'a':
+ time_value = ptr->ln_stat.st_atim.tv_sec;
+ break;
+ case 'c':
+ time_value = ptr->ln_stat.st_ctim.tv_sec;
+ break;
+ default:
+ LOGERR("WARNING: option_time_field has invalid value %c 0x%02X - going by default m\n",
+ option_time_field, option_time_field);
+ option_time_field = 'm';
+ time_value = ptr->ln_stat.st_mtim.tv_sec;
+ break;
+ };
+ out_print_time(time_value);
+}
+/* === END OF FORMATTING FUNCTIONS === */
+
+
+
/* 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;
- time_t time_value = 0;
- char timestamp[128];
size_t total_size = 0;
if (list == NULL) return;
@@ -65,38 +124,11 @@ void print_list(struct list_head *list) {
ptr = lh->first;
while (ptr != NULL) {
- time_value = 0;
-
- switch (option_time_field) {
- case 'm':
- time_value = ptr->ln_stat.st_mtim.tv_sec;
- break;
- case 'a':
- time_value = ptr->ln_stat.st_atim.tv_sec;
- break;
- case 'c':
- time_value = ptr->ln_stat.st_ctim.tv_sec;
- break;
- default:
- LOGERR("WARNING: option_time_field has invalid value %c 0x%02X - going by default m\n",
- option_time_field, option_time_field);
- option_time_field = 'm';
- time_value = ptr->ln_stat.st_mtim.tv_sec;
- break;
- };
-
- printf(" %8ld %2s ", ((ptr->ln_stat.st_size>=1024) ? (ptr->ln_stat.st_size/1024) : ptr->ln_stat.st_size),
- ((ptr->ln_stat.st_size >= 1024) ? "kB" : ""));
+ out_print_size(ptr);
+ out_print_time_by_option(ptr);
+ out_print_fname(ptr);
+ out_print_newline();
- tm = localtime(&time_value);
- 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);
/* Linux: Neither man stat(2) nor stat(3type) declare why struct stat field st_size
* would get a negative value assigned. The type off_t masks __off_t or __off64_t
* which themselves mask bits/types.h __SLONGWORD_TYPE on x86_64 that's long int.
@@ -113,3 +145,76 @@ void print_list(struct list_head *list) {
if (lh != list) destroy_list(lh);
}
+
+/* For now with a large walk around common format strings and prevention of attack vectors.
+ * n - name
+ * s - file size
+ *
+ * Time related
+ * t - timestamp set by option_time_field
+ * A - timestamp from atim.tv_sec
+ * C - timestamp from ctim.tv_sec
+ * M - timestamp from mtim.tv_sec
+ */
+void print_list_formatted(const char *format, struct list_head *list) {
+ struct list_head *lh = list;
+ struct list_node *ptr;
+ size_t format_len = 0, i = 0;
+
+ if (format == NULL || format[0] == '\0') {
+ LOGERR("ERROR: No format string given");
+ return;
+ }
+
+ if (list == NULL || list->first == NULL) {
+ LOGERR("ERROR: No data to print.\n");
+ return;
+ }
+
+ if (option_sort_reverse_order) {
+ lh = create_list_sort_reversed(list);
+ /* be tolerant */
+ if (lh == NULL) {
+ lh = list;
+ }
+ }
+
+ /* Note: the maximum length needs to be adjusted if the strings
+ * shall contain more complicated settings */
+ format_len = strnlen(format, 80);
+
+ ptr = lh->first;
+ while (ptr != NULL) {
+ for (i=0; i < format_len; i++) {
+ switch (format[i]) {
+ case 'n':
+ out_print_fname(ptr);
+ break;
+ case 's':
+ out_print_size(ptr);
+ break;
+ case 't':
+ out_print_time_by_option(ptr);
+ break;
+ case 'A':
+ out_print_time(ptr->ln_stat.st_atim.tv_sec);
+ break;
+ case 'C':
+ out_print_time(ptr->ln_stat.st_ctim.tv_sec);
+ break;
+ case 'M':
+ out_print_time(ptr->ln_stat.st_mtim.tv_sec);
+ break;
+ case ' ': /* just ignore this without warning */
+ break;
+ default:
+ LOGERR("WARNING: Invalid character 0x%02X ignoring it\n", format[i]);
+ break;
+ };
+ }
+ out_print_newline();
+ ptr = ptr->next;
+ }
+ if (lh != list) destroy_list(lh);
+}
+