diff options
Diffstat (limited to 'src/commands/printf.c')
-rw-r--r-- | src/commands/printf.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/commands/printf.c b/src/commands/printf.c new file mode 100644 index 0000000..7539316 --- /dev/null +++ b/src/commands/printf.c @@ -0,0 +1,118 @@ +#include "../command.h" +#include <stdlib.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); + } +} + +COMMAND(print) { + if (argc < 1) { + error("usage: printf FORMAT [ARG]...\n"); + } + + 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; +} |