aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile7
-rw-r--r--README.md11
-rw-r--r--src/basename.c1
-rw-r--r--src/cut.c17
-rw-r--r--src/head.c1
-rw-r--r--src/seq.c4
-rw-r--r--src/xargs.c228
m---------trand0
9 files changed, 253 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index 11269e8..09b23ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
a.out
*.o
bin/*
+tags
diff --git a/Makefile b/Makefile
index 450a5f4..1421b3f 100644
--- a/Makefile
+++ b/Makefile
@@ -2,11 +2,11 @@ BINDIR = bin
SRCDIR = src
CC = gcc
-CCFLAGS = -Wall -Wextra -Wpedantic
+CCFLAGS = -std=c99 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough
all: prebuild $(BINDIR)/basename $(BINDIR)/chown $(BINDIR)/cut $(BINDIR)/head \
$(BINDIR)/mkdir $(BINDIR)/mv $(BINDIR)/rm $(BINDIR)/seq \
- $(BINDIR)/shuf $(BINDIR)/tee $(BINDIR)/tr \
+ $(BINDIR)/shuf $(BINDIR)/tee $(BINDIR)/tr $(BINDIR)/xargs \
$(BINDIR)/shuf_trand
prebuild:
@@ -45,6 +45,9 @@ $(BINDIR)/tee: $(SRCDIR)/tee.c
$(BINDIR)/tr: $(SRCDIR)/tr.c
$(CC) $(CCFLAGS) -o $@ $^
+$(BINDIR)/xargs: $(SRCDIR)/xargs.c
+ $(CC) $(CCFLAGS) -o $@ $^
+
#### shuf using trand
TRAND_PATH = trand
diff --git a/README.md b/README.md
index b287118..308cfe0 100644
--- a/README.md
+++ b/README.md
@@ -16,11 +16,12 @@ Rewrite of some core utilities for educational purposes.
## 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 |
+|------------|----------------------------------------------------------------- |
+| `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 |
+| `xargs` | construct argument lists and invoke utility |
## TODO
diff --git a/src/basename.c b/src/basename.c
index 83f3b8f..3e58cb6 100644
--- a/src/basename.c
+++ b/src/basename.c
@@ -1,3 +1,4 @@
+#define _POSIX_C_SOURCE 2
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/cut.c b/src/cut.c
index 2a7990d..38e1cd8 100644
--- a/src/cut.c
+++ b/src/cut.c
@@ -46,18 +46,17 @@ int parse_uint(char *s, char **endptr)
int main(int argc, char **argv)
{
- int option;
- int list_start = LIST_VALUE_INFINITY;
- int list_end = LIST_VALUE_INFINITY;
- t_list_type list_type = LIST_UNDEFINED;
- wchar_t delimiter = '\t';
- bool print_only_delimiter = false;
- char line_delimiter = '\n';
+ int option;
+ int list_start = LIST_VALUE_INFINITY;
+ int list_end = LIST_VALUE_INFINITY;
+ t_list_type list_type = LIST_UNDEFINED;
+ wchar_t delimiter = '\t';
+ bool print_only_delimiter = false;
+ char line_delimiter = '\n';
g_name = argv[0];
while ((option = getopt(argc, argv, "b:c:d:f:sz")) > 0)
{
-
switch (option)
{
case 'b':
@@ -188,6 +187,8 @@ int main(int argc, char **argv)
counter++;
}
break;
+ default:
+ fatal_errno();
}
putchar('\n');
}
diff --git a/src/head.c b/src/head.c
index f2201b5..98e3b57 100644
--- a/src/head.c
+++ b/src/head.c
@@ -1,3 +1,4 @@
+#define _POSIX_C_SOURCE 200809L
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/seq.c b/src/seq.c
index 8307fc4..20d65cd 100644
--- a/src/seq.c
+++ b/src/seq.c
@@ -109,13 +109,13 @@ int main(int argc, char **argv)
{
int precision = MAX(first.precision, increment.precision);
if (!padding)
- printf("%.*llf", precision, first.value);
+ printf("%.*Lf", precision, first.value);
else
{
int width = MAX(last.integer_len, first.integer_len);
if (precision != 0)
width += precision + 1;
- printf("%0*.*llf", width, precision, first.value);
+ printf("%0*.*Lf", width, precision, first.value);
}
first.value += increment.value;
if (increment.value > 0 ? (first.value <= last.value) : (first.value >= last.value))
diff --git a/src/xargs.c b/src/xargs.c
new file mode 100644
index 0000000..9c2a5e6
--- /dev/null
+++ b/src/xargs.c
@@ -0,0 +1,228 @@
+#define _POSIX_C_SOURCE 200809L
+#define _DEFAULT_SOURCE 1
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/wait.h>
+
+static char *g_eofstr = NULL;
+static char *g_replstr = NULL;
+static size_t g_line_count = -1;
+static size_t g_arg_count = -1;
+static bool g_prompt = false;
+static size_t g_size = -1;
+static bool g_trace = false;
+static bool g_terminate = false;
+
+static char *g_name = "xargs";
+
+void die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "%s: ", g_name);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+ exit(1);
+}
+
+void *xmalloc(size_t size)
+{
+ void *ret = malloc(size);
+ if (ret == NULL)
+ die(strerror(errno));
+ return ret;
+}
+
+char *xstrdup(const char *src)
+{
+ char *ret = strdup(src);
+ if (ret == NULL)
+ die(strerror(errno));
+ return ret;
+}
+
+size_t parse_uint(const char *optarg)
+{
+ unsigned long n;
+ char *end;
+
+ errno = 0;
+ n = strtoul(optarg, &end, 10);
+ if (!isdigit(*optarg) || errno != 0 || *end != '\0')
+ die("invalid number \"%s\"", optarg);
+ return n;
+}
+
+size_t args_len(char **args)
+{
+ size_t len;
+ for (len = 0; args[len] != NULL; len++);
+ return len;
+}
+
+void args_free(char **args)
+{
+ for (size_t i = 0; args[i] != NULL; i++)
+ free(args[i]);
+ free(args);
+}
+
+char **args_cpy(char **dst, char **src)
+{
+ size_t i;
+
+ for (i = 0; src[i] != NULL; i++)
+ dst[i] = xstrdup(src[i]);
+ dst[i] = NULL;
+ return dst;
+}
+
+char **args_dup(char **src)
+{
+ char **ret = xmalloc((args_len(src) + 1) * sizeof(char*));
+ return args_cpy(ret, src);
+}
+
+int main(int argc, char **argv)
+{
+ int option;
+
+ while ((option = getopt(argc, argv, "E:I:L:n:ps:tx")) > 0)
+ {
+ switch (option)
+ {
+ case 'E': g_eofstr = optarg; break;
+ case 'I': g_replstr = optarg; break;
+ case 'L': g_line_count = parse_uint(optarg); break;
+ case 'n': g_arg_count = parse_uint(optarg); break;
+ case 'p': g_prompt = true; break;
+ case 's': g_size = parse_uint(optarg); break;
+ case 't': g_trace = true; break;
+ case 'x': g_terminate = true; break;
+ }
+ }
+ if (g_line_count == 0)
+ die("value 0 for -L option should be >= 1");
+ if (g_arg_count == 0)
+ die("value 0 for -n option should be >= 1");
+ if (g_prompt)
+ g_trace = true;
+
+ char *cmd = optind != argc ? argv[optind] : "echo";
+ char **args_prefix;
+ if (optind == argc || optind + 1 == argc)
+ {
+ args_prefix = xmalloc(2 * sizeof(char*));
+ args_prefix[0] = cmd;
+ args_prefix[1] = NULL;
+ }
+ else
+ {
+ size_t len = argc - optind;
+ args_prefix = xmalloc((len + 1) * sizeof(char*));
+ size_t i;
+ for (i = 0; i < len; i++)
+ args_prefix[i] = argv[optind + i];
+ args_prefix[len] = NULL;
+ }
+
+ size_t len;
+ bool eof = false;
+ size_t command_count = 0;
+ while (!eof)
+ {
+ char **args = args_dup(args_prefix);
+ char *line = NULL;
+ size_t line_size = 0;
+ size_t count = 0;
+
+ while (getline(&line, &line_size, stdin) > 0)
+ {
+ // removing newline
+ char *last = line + strlen(line) - 1;
+ if (*last == '\n')
+ *last = '\0';
+ // trim blank characters
+ while (isblank(*line))
+ memmove(line, line + 1, strlen(line));
+ len = strlen(line);
+ while (len > 0 && isblank(line[len - 1]))
+ {
+ line[len - 1] = '\0';
+ len--;
+ }
+ // skipping blank lines
+ if (*line == '\0')
+ continue;
+ // stopping if eof string encountered
+ if (g_eofstr != NULL && strcmp(g_eofstr, line) == 0)
+ {
+ eof = true;
+ break;
+ }
+ // add line to arguments
+ len = args_len(args);
+ char **new_args = xmalloc((len + 2) * sizeof(char*));
+ args_cpy(new_args, args);
+ new_args[len] = xstrdup(line);
+ new_args[len + 2] = NULL;
+ /* args_free(args); */
+ args = new_args;
+ count++;
+ if ((g_line_count != (size_t)-1 && count >= g_line_count) ||
+ (g_arg_count != (size_t)-1 && count >= g_arg_count))
+ break;
+ }
+ if (feof(stdin))
+ eof = true;
+ if (eof && command_count != 0 && !g_prompt)
+ break;
+ command_count++;
+
+ pid_t child_pid;
+ child_pid = fork();
+ switch (child_pid)
+ {
+ case -1:
+ die(strerror(errno));
+ break;
+ case 0:
+ if (g_trace)
+ for (size_t i = 0; args[i] != NULL; i++)
+ {
+ fputs(args[i], stderr);
+ if (args[i + 1] != NULL)
+ fputc(' ', stderr);
+ }
+ bool confirmation = true;
+ if (g_prompt)
+ {
+ FILE *tty_file = fopen("/dev/tty", "r");
+ if (tty_file == NULL)
+ die("Couldn't open tty file");
+ fputs(" ?...", stderr);
+ int c = fgetc(tty_file);
+ confirmation = c == 'y' || c == 'Y';
+ }
+ else if (g_trace)
+ fputc('\n', stderr);
+ if (!confirmation)
+ exit(0);
+ execvp(cmd, args);
+ die(strerror(errno));
+ }
+ waitpid(child_pid, &child_pid, 0);
+ if (WEXITSTATUS(child_pid) == 255)
+ break;
+ }
+ return 0;
+}
diff --git a/trand b/trand
-Subproject 994744a3edc74c88271ffe57958a08b70f9f507
+Subproject 638f21e4a3f7dd04d33a147f54b97046800ba1f