+/* Argument tokenizer. */
+char *
+argsep(char **sp) {
+ int single_quoted = 0, double_quoted = 0;
+ char *arg, *cp, *next;
+
+ if (*sp == NULL)
+ return NULL;
+
+ /* Eat and move characters until end of argument is found. */
+ for (arg = next = cp = *sp; *cp != '\0'; ++cp) {
+ if (!double_quoted && *cp == '\'') {
+ /* Eat single-quote. */
+ single_quoted = !single_quoted;
+ } else if (!single_quoted && *cp == '"') {
+ /* Eat double-quote. */
+ double_quoted = !double_quoted;
+ } else if (!single_quoted && *cp == '\\' && *(cp + 1) == '"') {
+ /* Eat backslash; copy escaped character to arg. */
+ *next++ = *(++cp);
+ } else if (!single_quoted && !double_quoted && *cp == '\\' &&
+ (*(cp + 1) == '\'' || *(cp + 1) == ' ')) {
+ /* Eat backslash; move escaped character. */
+ *next++ = *(++cp);
+ } else if (!single_quoted && !double_quoted &&
+ (*cp == ' ' || *cp == '\t')) {
+ /* Terminate argument. */
+ *next++ = '\0';
+ /* Point sp to beginning of next argument. */
+ *sp = ++cp;
+ break;
+ } else {
+ /* Move regular character. */
+ *next++ = *cp;
+ }
+ }
+
+ /* Terminate argument if end of string. */
+ if (*cp == '\0') {
+ *next = '\0';
+ *sp = NULL;
+ }
+
+ return arg;
+}
+