summaryrefslogtreecommitdiff
path: root/src/commands/printf.c
blob: 2a84b80440c69d2f4fe366ec5b60c5df032b0d4c (plain)
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
116
117
118
119
120
121
122
123
124
125
#include "../command.h"

static long cast_long(const char* arg) {
    char* end;
    long l = strtol(arg, &end, 10);
    if (end == arg) {
        return 0;
    } else {
        return l;
    }
}

static double cast_double(const char* arg) {
    char* end;
    double d = strtod(arg, &end);
    if (end == arg) {
        return 0.0;
    } else {
        return d;
    }
}

#define NUMBER(name, type, arg) \
    long l = cast_long(arg); \
    type* t = (type*) &l; \
    type name = *t;

static void handle_percent(char n, const char* arg) {
    switch (n) {
        case 'd':
        case 'z': {
            NUMBER(i, int, arg)
            printf("%d", i);
            break;
        }
        case 'u': {
            NUMBER(u, unsigned int, arg);
            printf("%u", u);
            break;
        }
        case 'f': {
            double d = cast_double(arg);
            printf("%lf", d);
            break;
        }
        case 'c': {
            putchar(arg[0]);
            break;
        }
        case 's': {
            printf("%s", arg);
            break;
        }
        default: {
            putchar('%');
            putchar(n);
        }
    }
}

static void handle_slash(char n) {
    switch (n) {
        case 'n':
            putchar('\n');
            break;
        case 't':
            putchar('\t');
            break;
        case 'v':
            putchar('\v');
            break;
        case 'b':
            putchar('\b');
            break;
        default:
            putchar('\\');
            putchar(n);
    }
}

static void help() {
    printf("Usage printf FORMAT [ARG]...\n\n");
    printf("Format and print ARG(s) according to FORMAT (a-la C prinf)\n");
    exit(EXIT_SUCCESS);
}

COMMAND(print) {
    if (argc < 1) {
        error("usage: printf FORMAT [ARG]...\n");
    }

    if (streql("--help", argv[0])) help();

    size_t index = 0;
    int arg_index = 0;

    while (true) {
        char c = argv[0][index];
        index++;

        if (c == '\0') break;
        if (c != '%' && c != '\\') {
            putchar(c);
            continue;
        }

        char n = argv[0][index];
        index++;

        char* arg = NULL;
        if (arg_index < argc) {
            arg = argv[arg_index + 1];
        }

        if (c == '%') {
            handle_percent(n, arg);
        } else {
            handle_slash(n);
        }

        arg_index++;
    }

    return EXIT_SUCCESS;
}