aboutsummaryrefslogtreecommitdiff
path: root/src/output.c
blob: 64971fac05120e6990a29c1bc296e4179ec864f1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* 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 "list_management.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;
    time_t time_value = 0;
    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) {
        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" : ""));

        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.
         * Haven't checked libc/kernel code but regardless why, I assume that a negative
         * value would imply a corrupt filesystem.
         */
        total_size += (ptr->ln_stat.st_size>0) ? (unsigned long int)ptr->ln_stat.st_size : 0;
        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);
}