diff --git a/TODO b/TODO index e7dc62c..5ee4076 100644 --- a/TODO +++ b/TODO @@ -49,5 +49,6 @@ BUGS: xargs (getopt with glibc) FIX: + xargs (-d) echo (escape) que (unicode) diff --git a/libmu/parse_escape.c b/libmu/parse_escape.c new file mode 100644 index 0000000..32ee30b --- /dev/null +++ b/libmu/parse_escape.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +char *mu_parse_escape(const char *prog_name, const char *src) { + size_t size = 0; + size_t src_len = strlen(src); + + for (size_t i = 0; i < src_len; i++) { + size++; + size -= (src[i] == '\\'); + } + + char *buf = malloc(size + 1); + if (buf == NULL) { + if (prog_name) + fprintf(stderr, "%s: malloc: %s\n", prog_name, strerror(errno)); + + return NULL; + } + + size = 0; + for (size_t i = 0; i < src_len; i++) { + char c = src[i]; + if (c == '\\' && i < src_len) { + switch (src[i + 1]) { + case 'n': + c = '\n'; + break; + + case 'a': + c = '\a'; + break; + + case 't': + c = '\t'; + break; + + case 'b': + c = '\b'; + break; + + case 'e': + c = '\033'; + break; + + case 'r': + c = '\r'; + break; + + case 'f': + c = '\f'; + break; + + case 'v': + c = '\v'; + break; + + default: + c = '\\'; + } + + i++; + } + + buf[size] = c; + size++; + } + + buf[size + 1] = '\0'; + return buf; +} diff --git a/libmu/parse_escape.h b/libmu/parse_escape.h new file mode 100644 index 0000000..3363f07 --- /dev/null +++ b/libmu/parse_escape.h @@ -0,0 +1,5 @@ +#ifndef PARSE_ESCAPE_H +#define PARSE_ESCAPE_H + +char *mu_parse_escape(const char *prog_name, const char *src); +#endif diff --git a/src/echo.c b/src/echo.c index 114cb37..1c774bd 100644 --- a/src/echo.c +++ b/src/echo.c @@ -3,62 +3,11 @@ #include #include #include - -static char n_flag = 0; -static char e_flag = 0; - -static void format(char *str) { - for (size_t i = 0; i < strlen(str); i++) { - unsigned int c = str[i]; - if (c == '\\') { - switch (str[i + 1]) { - case 'a': - c = '\a'; - break; - - case 'n': - c = '\n'; - break; - - case 't': - c = '\t'; - break; - - case 'c': - exit(0); - - case 'v': - c = '\v'; - break; - - case 'r': - c = '\r'; - break; - - case 'f': - c = '\f'; - break; - - case 'e': - c = '\033'; - break; - - case 'b': - c = '\b'; - break; - - default: - c = '\\'; - } - - i++; - } - - putchar(c); - } -} +#include "parse_escape.h" int main(int argc, char **argv) { + char n_flag = 0; + char e_flag = 0; argv++; argc--; @@ -77,8 +26,14 @@ int main(int argc, char **argv) { } for (int i = 0; i < argc; i++) { - if (e_flag) - format(argv[i]); + if (e_flag) { + char *str = mu_parse_escape(NULL, argv[i]); + if (str == NULL) + return 1; + + fputs(str, stdout); + free(str); + } else fputs(argv[i], stdout); diff --git a/src/xargs.c b/src/xargs.c index ea54e08..6c26b98 100644 --- a/src/xargs.c +++ b/src/xargs.c @@ -7,6 +7,7 @@ #include #include #include +#include "parse_escape.h" #ifndef ARG_MAX #define ARG_MAX 10000 @@ -21,6 +22,8 @@ static char r_flag; static char nl_flag; static int n_flag; static size_t s_flag; +static char *d_flag; +static char i_flag; enum { NORMAL, @@ -102,7 +105,16 @@ static int add_arg(const char *str, size_t chars, int flag) { static int is_correct(char c) { if (nl_flag) - return c == '\0'; + return (c == '\0'); + + else if (d_flag) { + for (size_t i = 0; i < strlen(d_flag); i++) { + if (c == d_flag[i]) + return 1; + } + + return 0; + } else return isspace(c); @@ -134,7 +146,7 @@ static int xargs(void) { break; } - if (flag == NONE && is_correct(c) && index > 0) { + if ((i_flag || flag == NONE) && is_correct(c) && index > 0) { arg[index] = '\0'; int r = add_arg(arg, chars, 0); @@ -161,7 +173,7 @@ static int xargs(void) { } else { - if (c == '"' || c == '\'') { + if (!i_flag && (c == '"' || c == '\'')) { if (flag == QUOTE) flag = NONE; @@ -227,9 +239,10 @@ static int spawn(void) { int main(int argc, char **argv) { /* For -s flag */ char *p = NULL; + int ret = 0; int opt; - while ((opt = getopt(argc, argv, "tn:s:rP:0I:")) != -1) { + while ((opt = getopt(argc, argv, "tn:s:rP:0I:d:i")) != -1) { switch (opt) { case 't': t_flag = 1; @@ -239,7 +252,7 @@ int main(int argc, char **argv) { n_flag = atoi(optarg); if (n_flag <= 0) { fprintf(stderr, "xargs: -n: invalid number: %s\n", optarg); - return 1; + ret = 1; } break; @@ -248,7 +261,7 @@ int main(int argc, char **argv) { s_flag = strtoul(optarg, &p, 0); if (s_flag <= 0 || *p) { fprintf(stderr, "xargs: -s: invalid number: %zu%s\n", s_flag, (p) ? p : ""); - return 1; + ret = 1; } break; @@ -265,16 +278,33 @@ int main(int argc, char **argv) { I_flag = optarg; break; + case 'd': + d_flag = mu_parse_escape("xargs", optarg); + if (d_flag == NULL) + return 1; + + break; + + case 'i': + i_flag = 1; + break; + default: - puts("xargs [tnsrP0I] [cmd [arg1] [arg2...]\n\t-t Print the command before start\n\t-n Pass no more than N args\n\t-r Don't run command if input is empty\n\t-s Pass command line of no more than N bytes\n\t-0 NUL terminated input\n\t-I STR Replace STR within PROG ARGS with input line"); + puts("xargs [tnsrP0Idt] [cmd [arg1] [arg2...]\n\t-t Print the command before start\n\t-n Pass no more than N args\n\t-r Don't run command if input is empty\n\t-s Pass command line of no more than N bytes\n\t-0 NUL terminated input\n\t-I STR Replace STR within PROG ARGS with input line\n\t-d CHR Use char as delimeter\n\t-i Ignore quotes"); return 0; } } + if (ret) { + if (d_flag) + free(d_flag); + + return 1; + } + argv += optind; argc -= optind; - int ret = 0; while (1) { /* Arg */ @@ -314,5 +344,8 @@ int main(int argc, char **argv) { break; } + if (d_flag) + free(d_flag); + return ret; }