- char *in_from_stdin = NULL;
- char *args = NULL;
- char *cmd_to_be_executed = NULL;
- char traceflag = 0;
- int len_args=10, len_cmd_to_be_executed, opt;
- pid_t pid;
- int wpid, status;
-
- /* Note that we do not use getopt here, since
- * we only want to interpret initial options,
- * not options passed to commands */
- while (--argc && **(++argv) == '-') {
- while (*++(*argv)) {
- switch (**argv) {
- case 't':
- traceflag=1;
- break;
- default:
- fatalError(xargs_usage);
+ /* Grow by 256 elements at once */
+ if (!(G.idx & 0xff)) { /* G.idx == N*256 */
+ /* Enlarge, make G.args[(N+1)*256 - 1] last valid idx */
+ G.args = xrealloc(G.args, sizeof(G.args[0]) * (G.idx + 0x100));
+ }
+ G.args[G.idx++] = s;
+}
+
+/* process[0]_stdin:
+ * Read characters into buf[n_max_chars+1], and when parameter delimiter
+ * is seen, store the address of a new parameter to args[].
+ * If reading discovers that last chars do not form the complete
+ * parameter, the pointer to the first such "tail character" is returned.
+ * (buf has extra byte at the end to accomodate terminating NUL
+ * of "tail characters" string).
+ * Otherwise, the returned pointer points to NUL byte.
+ * On entry, buf[] may contain some "seed chars" which are to become
+ * the beginning of the first parameter.
+ */
+
+#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
+static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
+{
+#define NORM 0
+#define QUOTE 1
+#define BACKSLASH 2
+#define SPACE 4
+ char q = '\0'; /* quote char */
+ char state = NORM;
+ char *s = buf; /* start of the word */
+ char *p = s + strlen(buf); /* end of the word */
+
+ buf += n_max_chars; /* past buffer's end */
+
+ /* "goto ret" is used instead of "break" to make control flow
+ * more obvious: */
+
+ while (1) {
+ int c = getchar();
+ if (c == EOF) {
+ if (p != s)
+ goto close_word;
+ goto ret;
+ }
+ if (state == BACKSLASH) {
+ state = NORM;
+ goto set;
+ }
+ if (state == QUOTE) {
+ if (c != q)
+ goto set;
+ q = '\0';
+ state = NORM;
+ } else { /* if (state == NORM) */
+ if (ISSPACE(c)) {
+ if (p != s) {
+ close_word:
+ state = SPACE;
+ c = '\0';
+ goto set;
+ }
+ } else {
+ if (c == '\\') {
+ state = BACKSLASH;
+ } else if (c == '\'' || c == '"') {
+ q = c;
+ state = QUOTE;
+ } else {
+ set:
+ *p++ = c;
+ }
+ }
+ }
+ if (state == SPACE) { /* word's delimiter or EOF detected */
+ if (q) {
+ bb_error_msg_and_die("unmatched %s quote",
+ q == '\'' ? "single" : "double");
+ }
+ /* A full word is loaded */
+ if (G.eof_str) {
+ if (strcmp(s, G.eof_str) == 0) {
+ while (getchar() != EOF)
+ continue;
+ p = s;
+ goto ret;
+ }
+ }
+ store_param(s);
+ dbg_msg("args[]:'%s'", s);
+ s = p;
+ n_max_arg--;
+ if (n_max_arg == 0) {
+ goto ret;
+ }
+ state = NORM;
+ }
+ if (p == buf) {
+ goto ret;
+ }
+ }
+ ret:
+ *p = '\0';
+ /* store_param(NULL) - caller will do it */
+ dbg_msg("return:'%s'", s);
+ return s;
+}
+#else
+/* The variant does not support single quotes, double quotes or backslash */
+static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
+{
+ char *s = buf; /* start of the word */
+ char *p = s + strlen(buf); /* end of the word */
+
+ buf += n_max_chars; /* past buffer's end */
+
+ while (1) {
+ int c = getchar();
+ if (c == EOF) {
+ if (p == s)
+ goto ret;
+ }
+ if (c == EOF || ISSPACE(c)) {
+ if (p == s)
+ continue;
+ c = EOF;
+ }
+ *p++ = (c == EOF ? '\0' : c);
+ if (c == EOF) { /* word's delimiter or EOF detected */
+ /* A full word is loaded */
+ if (G.eof_str) {
+ if (strcmp(s, G.eof_str) == 0) {
+ while (getchar() != EOF)
+ continue;
+ p = s;
+ goto ret;
+ }