aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Cabergs <me@cacharle.xyz>2020-08-23 20:09:42 +0200
committerCharles Cabergs <me@cacharle.xyz>2020-08-23 20:09:42 +0200
commita1824752a0606ec1a4c4d995624133128cbac61a (patch)
treec1063ebfe41d692acc6753ef4b97526215637bbd
parent8cf1635366eed1e760b317a401c0a4748ee4befe (diff)
downloadcoreutils-a1824752a0606ec1a4c4d995624133128cbac61a.tar.gz
coreutils-a1824752a0606ec1a4c4d995624133128cbac61a.tar.bz2
coreutils-a1824752a0606ec1a4c4d995624133128cbac61a.zip
Added echo
-rw-r--r--README.md15
-rw-r--r--src/echo.c105
2 files changed, 115 insertions, 5 deletions
diff --git a/README.md b/README.md
index e6a4a74..11ca0f7 100644
--- a/README.md
+++ b/README.md
@@ -10,26 +10,31 @@ Rewrite of some core utilities for educational purposes.
| `seq` | print a sequence of numbers |
| `tee` | read from standard input and write to standard output and files |
| `shuf` | generate random permutations |
+| `echo` | display a line of text |
-# TODO
+## Pending
| Name | Description |
|------------|-----------------------------------------------------------------|
| `cut` | remove sections from each line of files |
+| `uniq` | report or omit repeated lines |
+| `tr` | translate or delete characters |
+| `chown` | change file owner and group |
+
+## TODO
+
+| Name | Description |
+|------------|-----------------------------------------------------------------|
| `cp` | |
| `chmod` | |
-| `chown` | |
| `ln` | |
| `mv` | |
| `touch` | |
| `cat` | |
| `tail` | |
-| `tr` | |
| `test` | |
| `sort` | |
-| `uniq` | |
| `dirname` | |
| `date` | |
| `du` | |
-| `echo` | |
| `expr` | |
diff --git a/src/echo.c b/src/echo.c
new file mode 100644
index 0000000..fbf74bd
--- /dev/null
+++ b/src/echo.c
@@ -0,0 +1,105 @@
+#define _POSIX_C_SOURCE 2
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+
+bool isodigit(char c)
+{
+ return c >= '0' && c < '8';
+}
+
+int main(int argc, char **argv)
+{
+ int option;
+ bool escape = false;
+ bool newline = true;
+
+ while ((option = getopt(argc, argv, "neE")) != -1)
+ {
+ switch (option)
+ {
+ case 'e': escape = true; break;
+ case 'E': escape = false; break;
+ case 'n': newline = false; break;
+ }
+ }
+ for (; optind < argc; optind++)
+ {
+ char *str = argv[optind];
+ if (escape)
+ {
+ for (size_t i = 0; str[i] != '\0'; i++)
+ {
+ if (str[i] == '\\')
+ {
+ uint8_t c = 0;
+ int shift = 1;
+
+ switch (str[i + 1])
+ {
+ case '\\': c = '\\'; break;
+ case 'a': c = '\a'; break;
+ case 'b': c = '\b'; break;
+ case 'e': c = '\033'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = '\v'; break;
+
+ case '0':
+ c = 0;
+ for (int j = 0; isodigit(str[i + 2 + j]) && j < 3; j++)
+ {
+ c *= 8;
+ c += str[i + 2 + j] - '0';
+ shift++;
+ }
+ break;
+
+ case 'x':
+ c = 0;
+ for (int j = 0; isxdigit(str[i + 2 + j]) && j < 2; j++)
+ {
+ c *= 16;
+ if (islower(str[i + 2 + j]))
+ c += 10 + str[i + 2 + j] - 'a';
+ else if (isupper(str[i + 2 + j]))
+ c += 10 + str[i + 2 + j] - 'A';
+ else
+ c += str[i + 2 + j] - '0';
+ shift++;
+ }
+ break;
+
+ case 'c':
+ str[i] = '\0';
+ fputs(str, stdout);
+ fflush(stdout);
+ exit(EXIT_SUCCESS);
+ break;
+
+ default:
+ shift = -1;
+ break;
+ }
+ if (shift != -1)
+ {
+ str[i] = c;
+ memmove(&str[i + 1], &str[i + 1 + shift], strlen(&str[i + 1 + shift]) + 1);
+ }
+ }
+ }
+ }
+ fputs(str, stdout);
+ if (optind + 1 != argc)
+ putchar(' ');
+ }
+ if (newline)
+ putchar('\n');
+ return EXIT_SUCCESS;
+}