diff --git a/readme.md b/readme.md index 0d07854..ef7e7ca 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ A terrible busybox/gnu coreutils clone. Currently the only supported commands are: -`dd`, `cat`, `yes` +`dd`, `cat`, `yes`, `echo`, `printf` ## How to diff --git a/src/command.h b/src/command.h index 4f44ab0..d1161c4 100644 --- a/src/command.h +++ b/src/command.h @@ -11,3 +11,5 @@ COMMAND(dd); COMMAND(cat); COMMAND(yes); +COMMAND(echo); +COMMAND(print); diff --git a/src/commands/echo.c b/src/commands/echo.c new file mode 100644 index 0000000..b80f872 --- /dev/null +++ b/src/commands/echo.c @@ -0,0 +1,103 @@ +#include "../command.h" + +#include +#include + +static void print_with_escape_codes(const char* str) { + + size_t index = 0; + while (true) { + char c = str[index]; + index++; + + if (c == '\0') break; + if (c != '\\') { + putchar(c); + continue; + } + + char n = str[index]; + index++; + + switch (n) { + case '\\': + putchar('\\'); + break; + case 'b': + putchar('\b'); + break; + case 'c': + exit(EXIT_SUCCESS); + case 'n': + putchar('\n'); + break; + case 'r': + putchar('\r'); + break; + case 't': + putchar('\t'); + break; + case 'v': + putchar('\v'); + break; + default: + putchar(c); + putchar(n); + } + } +} + +COMMAND(echo) { + + if (argc < 1) { + return EXIT_SUCCESS; + } + + bool escape_codes = false; + bool newline = true; + + int start = 0; + + if (prefix("-", argv[0])) { + + start = 1; + + for (size_t i = 0; i < strlen(argv[0] + 1); i++) { + char c = argv[0][i + 1]; + switch (c) { + case 'e': + escape_codes = true; + break; + case 'E': + escape_codes = false; + break; + case 'n': + newline = false; + break; + default: + escape_codes = false; + newline = true; + start = 0; + break; + } + } + } + + for (int i = start; i < argc; i++) { + if (escape_codes) { + print_with_escape_codes(argv[i]); + } else { + printf("%s", argv[i]); + } + + if (i + 1 != argc) { + putchar(' '); + } + } + + if (newline) { + putchar('\n'); + } + + return EXIT_SUCCESS; +} 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 + +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; +} diff --git a/src/main.c b/src/main.c index a2582c2..98c0e81 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,7 @@ int main (ARGUMENTS) { if (argc < 2) { printf("usage: lazysphere [function [arguments]...]\n\n"); printf("currently defined functions:\n"); - printf("\tdd, cat, yes\n"); + printf("\tdd, cat, yes, echo, printf\n"); return EXIT_SUCCESS; } argc--; @@ -40,6 +40,10 @@ int main (ARGUMENTS) { return cat(NEXT_ARGS); } else if (streql(cmd, "yes")) { return yes(NEXT_ARGS); + } else if (streql(cmd, "echo")) { + return echo(NEXT_ARGS); + } else if (streql(cmd, "printf")) { + return print(NEXT_ARGS); } else { error("error: invalid command %s", cmd); }