commit: fa27634fad776bfdec053e1b92290b0b16592ad3
parent d1a535971579513d3ab6dd3b517194c1f90cef01
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Thu, 29 May 2025 09:03:47 +0200
cmd/echo: write escape() function similar to cmd/printf to avoid malloc
Diffstat:
M | cmd/echo.c | 153 | +++++++++++++++++++++++++++++++++++-------------------------------------------- |
1 file changed, 67 insertions(+), 86 deletions(-)
diff --git a/cmd/echo.c b/cmd/echo.c
@@ -5,10 +5,73 @@
#define _POSIX_C_SOURCE 200809L
#include <stdbool.h>
#include <stdio.h> // perror
-#include <stdlib.h> // malloc
#include <string.h> // strlen
#include <unistd.h> // write
+static void
+escape(char *str, size_t *len)
+{
+ char *start = str;
+ char *store = str;
+
+ for(; str < (start + *len); ++str, ++store)
+ {
+ if(*str != '\\')
+ {
+ *store = *str;
+ continue;
+ }
+
+ switch(*++str)
+ {
+ case '\\': // POSIX
+ default:
+ *store = *str;
+ break;
+ case 'a':
+ *store = '\a';
+ break;
+ case 'b':
+ *store = '\b';
+ break;
+ case 'c':
+ goto escape_end;
+ case 'f':
+ *store = '\f';
+ break;
+ case 'n':
+ *store = '\n';
+ break;
+ case 'r':
+ *store = '\r';
+ break;
+ case 't':
+ *store = '\t';
+ break;
+ case 'v':
+ *store = '\v';
+ break;
+ case '0': /* \0 \0n \0nn \0nnn */
+ {
+ int value = 0;
+ int i = 0;
+ for(; i < 4 && str[i] >= '0' && str[i] <= '7'; i++)
+ {
+ value <<= 3;
+ value += str[i] - '0';
+ }
+ str += (i - 1);
+ *store = (char)value;
+ break;
+ }
+ }
+ }
+
+escape_end:
+ *store = '\0';
+ *len = (size_t)(store - start);
+}
+
int
main(int argc, char *argv[])
{
@@ -71,96 +134,14 @@ main(int argc, char *argv[])
if(opt_n) arg_len--; // no newline
- char *d = *argv;
- size_t d_len = arg_len;
+ if(opt_e) escape(*argv, &arg_len);
- char *newd = NULL;
- if(opt_e)
- {
- newd = malloc(arg_len);
- if(!newd)
- {
- fprintf(stderr, "echo: error: Failed to allocate for a copy of the strings\n");
- return 1;
- }
-
- int di = 0;
-
- for(size_t argi = 0; argi < arg_len; argi++)
- {
- if(d[argi] != '\\')
- {
- newd[di++] = d[argi];
- continue;
- }
-
- switch(d[++argi])
- {
- case 'a':
- newd[di++] = '\a';
- break;
- case 'b':
- newd[di++] = '\b';
- break;
- case 'c':
- newd[di++] = '\0';
- goto p_break;
- case 'f':
- newd[di++] = '\f';
- break;
- case 'n':
- newd[di++] = '\n';
- break;
- case 'r':
- newd[di++] = '\r';
- break;
- case 't':
- newd[di++] = '\t';
- break;
- case 'v':
- newd[di++] = '\v';
- break;
- case '\\':
- newd[di++] = '\\';
- break;
- case '0': /* \0 \0n \0nn \0nnn */
- {
- int nl = 1; // skip leading 0
- int num = 0;
- for(; nl < 4; nl++)
- {
- if(d[argi + nl] >= '0' && d[argi + nl] <= '7')
- {
- num = (num * 8) + (d[argi + nl] - '0');
- }
- else
- break;
- }
- newd[di++] = num;
- argi += (nl - 1);
- break;
- }
- default:
- newd[di++] = d[argi];
- break;
- }
- }
-
- newd[di] = '\0';
- p_break:
- d = newd;
- d_len = di;
- }
-
- ssize_t nwrite = write(1, d, d_len);
- if(nwrite < (ssize_t)d_len)
+ ssize_t nwrite = write(1, *argv, arg_len);
+ if(nwrite < (ssize_t)arg_len)
{
perror("echo: error: Failed writing");
- if(opt_e) free(newd);
return 1;
}
- if(opt_e) free(newd);
-
return 0;
}