utils: Add xargs from ELKS
authorAlan Cox <alan@linux.intel.com>
Tue, 30 Dec 2014 11:39:05 +0000 (11:39 +0000)
committerAlan Cox <alan@linux.intel.com>
Tue, 30 Dec 2014 11:39:05 +0000 (11:39 +0000)
Applications/util/Makefile
Applications/util/xargs.c [new file with mode: 0644]

index 5cebaba..2614877 100644 (file)
@@ -89,6 +89,7 @@ SRCS  = banner.c \
        wc.c \
        which.c \
        whoami.c \
+       xargs.c \
        yes.c
 
 OBJS = $(SRCS:.c=.rel)
diff --git a/Applications/util/xargs.c b/Applications/util/xargs.c
new file mode 100644 (file)
index 0000000..e9b1319
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * xargs.c
+ *
+ * Copyright 2000 Alistair Riddoch
+ * ajr@ecs.soton.ac.uk
+ *
+ * This file may be distributed under the terms of the GNU General Public
+ * License v2, or at your option any later version.
+ */
+
+/*
+ * This is a small version of xargs for use in the ELKS project.
+ * It is not fully functional, and may not be the most efficient
+ * implementation for larger systems. It minimises memory usage and
+ * code size.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define MAX_ARGS 20
+#define MAX_IARGS 10
+#define MAX_CHARS 255
+
+#define DEFAULT_CMD "/bin/echo"
+
+int max_args = MAX_ARGS;
+int max_chars = MAX_CHARS;     /* Not yet implemented */
+
+char * progname;
+
+/* Command to run if none specified */
+char * default_cmd = DEFAULT_CMD;
+
+/* New arguments for programs */
+int nargc;
+char * nargv[MAX_ARGS + MAX_IARGS + 2];
+
+/*
+ *
+ * usage()
+ *
+ * Display usage information.
+ *
+ */
+
+void usage(char ** argv)
+{
+       fprintf(stderr, "%s [-n max-args] [-s max-chars] [command [initial-arguments]]\n", argv[0]);
+       exit(1);
+}
+
+/*
+ *
+ * do_args()
+ *
+ * Interpret command switches from the command line.
+ *
+ * int argc;           As passed to main().
+ * char ** argv;       As passed to main().
+ *
+ * RETURN              Num of arguments interpreted.
+ *
+ */
+
+
+int do_args(int argc, char ** argv)
+{
+       int i = 1, j, k;
+
+       while(i < argc && argv[i][0] == '-') {
+               k = 0;
+               for(j = 1; j < strlen(argv[i]); j++) {
+                       switch (argv[i][j]) {
+                               case 'n':
+                                       k++;
+                                       if ((i + k) < argc) {
+                                               max_args = atoi(argv[i+k]);
+                                       }
+                                       break;
+                               case 's':
+                                       k++;
+                                       if ((i + k) < argc) {
+                                               max_chars = atoi(argv[i+k]);
+                                       }
+                                       break;
+                               default:
+                                       usage(argv);
+                       }
+               }
+               i += k;
+               i++;
+       }
+       if (max_args > MAX_ARGS) {
+               max_args = MAX_ARGS;
+       }
+       if (max_chars > MAX_CHARS) {
+               max_chars = MAX_CHARS;
+       }
+       return i;
+}
+
+/*
+ *
+ * build_cmd()
+ *
+ * Build the initial portion of the argv array to be used to run
+ * commands from the command line arguments given for xargs.
+ *
+ * int argc;           Number of arguments left.
+ * char ** argv;       Pointer to the first item in main()'s argv for us.
+ *
+ */
+
+void build_cmd(int argc, char ** argv)
+{
+       int i;
+
+       if (argc > (MAX_IARGS + MAX_ARGS - max_args)) {
+               fprintf(stderr, "%s: Too many initial arguments.\n", progname);
+               exit(1);
+       }
+       for(i = 0; i < argc; i++) {
+               nargv[i] = argv[i];
+       }
+       nargc += argc;
+}
+
+#define BSIZE 64
+#define out_of_mem() { perror("malloc"); exit(1); }
+
+/*
+ * next_token()
+ *
+ * Read standard in and get the next argument.
+ * Returns NULL on end of file.
+ *
+ */
+
+char * next_token(void)
+{
+       int size = BSIZE;
+       int tail = 0;
+       char * buf = malloc(BSIZE);
+
+       if (buf == NULL) {
+               out_of_mem();
+       }
+       for(;;) {
+               int inp = fgetc(stdin);
+               switch (inp) {
+                       case EOF:
+                               if (tail != 0) {
+                                       buf[tail] = '\0';
+                               } else {
+                                       free(buf);
+                                       buf = NULL;
+                               }
+                               return buf;
+                               break;
+                       case ' ':
+                       case '\t':
+                       case '\n':
+                               if (tail != 0) {
+                                       buf[tail] = '\0';
+                                       return buf;
+                               }
+                               break;
+                       default:
+                               buf[tail++] = inp;
+                               break;
+               }
+               if (tail > size) {
+                       size += BSIZE;
+                       buf = realloc(buf, size);
+                       if (buf == NULL) {
+                               out_of_mem();
+                       }
+               }
+                       
+       }
+}
+
+/*
+ *
+ * run()
+ *
+ * Fork, exec and wait for the commant to complete.
+ *
+ * Parameters are as for execvp.
+ *
+ * We use vfork as this is a good saving under elks.
+ *
+ */
+
+void run(char * argv0, char ** argv)
+{
+       int pid;
+       
+       pid = fork();
+       switch (pid) {
+               case -1:
+                       perror("fork");
+                       exit(1);
+                       break;
+               case 0:
+                       break;
+               default:
+                       wait(NULL);
+                       return;
+       }
+       execvp(argv0, argv);
+       perror("argv0");
+       exit(1);
+}
+
+int main(int argc, char ** argv)
+{
+       int num_args;
+       int new_argc;
+       char * tok = NULL;
+
+       progname = argv[0];
+       num_args = do_args(argc, argv);
+
+       if (num_args >= argc) {
+               build_cmd(1, &default_cmd);
+       } else {
+               build_cmd(argc - num_args, &argv[num_args]);
+       }
+
+       do {
+               int i;
+
+               new_argc = nargc;
+               while(new_argc < (nargc + max_args) &&
+                    (tok = next_token()) != NULL) {
+                       nargv[new_argc++] = tok;
+               }
+               nargv[new_argc] = NULL;
+               if (nargc != new_argc) {
+                       run(nargv[0], nargv);
+               }
+               for(i = nargc; i < new_argc; i++) {
+                       free(nargv[i]);
+               }
+       } while (tok != NULL);
+
+       exit(0);
+}