Exemple #1
0
static void print_esc_string(char *str)
{
	for (; *str; str++) {
		if (*str == '\\') {
			str++;
			bb_putchar(bb_process_escape_sequence((const char **)&str));
		} else {
			bb_putchar(*str);
		}

	}
}
static size_t unescape(char *s, int *nocr)
{
	char *start = s;
	char *p = s;

	while (*s) {
		char c = *s;
		// do we need special processing?
		// standard escapes + \s for space and \N for \0
		// \c inhibits terminating \r for commands and is noop for expects
		if ('\\' == c) {
			c = *++s;
			if (c) {
#if ENABLE_FEATURE_CHAT_IMPLICIT_CR
				if ('c' == c) {
					*nocr = 1;
					goto next;
				}
#endif
				if ('N' == c) {
					c = '\0';
				} else if ('s' == c) {
					c = ' ';
#if ENABLE_FEATURE_CHAT_NOFAIL
				// unescape leading dash only
				// TODO: and only for expect, not command string
				} else if ('-' == c && (start + 1 == s)) {
					//c = '-';
#endif
				} else {
					c = bb_process_escape_sequence((const char **)&s);
					s--;
				}
			}
		// ^A becomes \001, ^B -- \002 and so on...
		} else if ('^' == c) {
			c = *++s-'@';
		}
		// put unescaped char
		*p++ = c;
#if ENABLE_FEATURE_CHAT_IMPLICIT_CR
 next:
#endif
		// next char
		s++;
	}
	*p = '\0';

	return p - start;
}
Exemple #3
0
static void parse_escape(char *word)
{
	char    *q, c;
	const char *p;

	if (!word)
		return;

	for (p = q = word; *p; q++) {
		c = *p++;
		if (c != '\\') {
			*q = c;
		} else {
			*q = bb_process_escape_sequence(&p);
		}
	}
	*q = 0;
}
/* supported constructs:
 *   Ranges,  e.g.,  [0-9]  ==>  0123456789
 *   Escapes, e.g.,  \a     ==>  Control-G
 */
static unsigned int expand(const char *arg, register unsigned char *buffer)
{
	unsigned char *buffer_start = buffer;
	int i, ac;

	while (*arg) {
		if (*arg == '\\') {
			arg++;
			*buffer++ = bb_process_escape_sequence(&arg);
		} else if (*(arg+1) == '-') {
			ac = *(arg+2);
			if(ac == 0) {
				*buffer++ = *arg++;
				continue;
			}
			i = *arg;
			while (i <= ac)
				*buffer++ = i++;
			arg += 3; /* Skip the assumed a-z */
		} else if (*arg == '[') {
			arg++;
			i = *arg++;
			if (*arg++ != '-') {
				*buffer++ = '[';
				arg -= 2;
				continue;
			}
			ac = *arg++;
			while (i <= ac)
				*buffer++ = i++;
			arg++;				/* Skip the assumed ']' */
		} else
			*buffer++ = *arg++;
	}

	return (buffer - buffer_start);
}
Exemple #5
0
int bb_echo(int ATTRIBUTE_UNUSED argc, char **argv)
{
#ifndef CONFIG_FEATURE_FANCY_ECHO
#define eflag '\\'
	arg = *++argv;
#else
	const char *p;
	int nflag = 1;
	int eflag = 0;

	while (*++argv && (**argv == '-')) {
		/* If it appears that we are handling options, then make sure
		 * that all of the options specified are actually valid.
		 * Otherwise, the string should just be echoed.
		 */

		if (!*(p = *argv + 1)) {	/* A single '-', so echo it. */
			goto just_echo;
		}

		do {
			if (strrchr("neE", *p) == 0) {
				goto just_echo;
			}
		} while (*++p);

		/* All of the options in this arg are valid, so handle them. */
		p = *argv + 1;
		do {
			if (*p == 'n') {
				nflag = 0;
			} else if (*p == 'e') {
				eflag = '\\';
			} else {
				eflag = 0;
			}
		} while (*++p);
	}

just_echo:
#endif
	while (*argv) {
		register int c;

		while ((c = *(*argv)++)) {
			if (c == eflag) {	/* Check for escape seq. */
				if (**argv == 'c') {
					/* '\c' means cancel newline and
					 * ignore all subsequent chars. */
					return 0;
				}
#ifndef CONFIG_FEATURE_FANCY_ECHO
				/* SUSv3 specifies that octal escapes must begin with '0'. */
				if (((unsigned int)(**argv - '1')) >= 7)
#endif
				{
					/* Since SUSv3 mandates a first digit of 0, 4-digit octals
					* of the form \0### are accepted. */
					if ((**argv == '0') && (((unsigned int)(argv[0][1] - '0')) < 8)) {
						(*argv)++;
					}
					/* bb_process_escape_sequence can handle nul correctly */
					c = bb_process_escape_sequence((const char **) argv);
				}
			}
			putchar(c);
		}

		if (*++argv) {
			putchar(' ');
		}
	}

#ifdef CONFIG_FEATURE_FANCY_ECHO
	if (nflag) {
		putchar('\n');
	}
#else
	putchar('\n');
#endif
	return 0;
}
Exemple #6
0
static void parse_prompt(const char *prmt_ptr)
{
	int prmt_len = 0;
	size_t cur_prmt_len = 0;
	char flg_not_length = '[';
	char *prmt_mem_ptr = xzalloc(1);
	char *pwd_buf = xrealloc_getcwd_or_warn(NULL);
	char buf2[PATH_MAX + 1];
	char buf[2];
	char c;
	char *pbuf;

	cmdedit_prmt_len = 0;

	if (!pwd_buf) {
		pwd_buf = (char *)bb_msg_unknown;
	}

	while (*prmt_ptr) {
		pbuf = buf;
		pbuf[1] = 0;
		c = *prmt_ptr++;
		if (c == '\\') {
			const char *cp = prmt_ptr;
			int l;

			c = bb_process_escape_sequence(&prmt_ptr);
			if (prmt_ptr == cp) {
				if (*cp == 0)
					break;
				c = *prmt_ptr++;
				switch (c) {
#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
				case 'u':
					pbuf = user_buf ? user_buf : (char*)"";
					break;
#endif
				case 'h':
					pbuf = hostname_buf;
					if (!pbuf) {
						pbuf = xzalloc(256);
						if (gethostname(pbuf, 255) < 0) {
							strcpy(pbuf, "?");
						} else {
							char *s = strchr(pbuf, '.');
							if (s)
								*s = '\0';
						}
						hostname_buf = pbuf;
					}
					break;
				case '$':
					c = (geteuid() == 0 ? '#' : '$');
					break;
#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
				case 'w':
					pbuf = pwd_buf;
					l = strlen(home_pwd_buf);
					if (l != 0
					 && strncmp(home_pwd_buf, pbuf, l) == 0
					 && (pbuf[l]=='/' || pbuf[l]=='\0')
					 && strlen(pwd_buf+l)<PATH_MAX
					) {
						pbuf = buf2;
						*pbuf = '~';
						strcpy(pbuf+1, pwd_buf+l);
					}
					break;
#endif
				case 'W':
					pbuf = pwd_buf;
					cp = strrchr(pbuf, '/');
					if (cp != NULL && cp != pbuf)
						pbuf += (cp-pbuf) + 1;
					break;
				case '!':
					pbuf = buf2;
					snprintf(buf2, sizeof(buf2), "%d", num_ok_lines);
					break;
				case 'e': case 'E':     /* \e \E = \033 */
					c = '\033';
					break;
				case 'x': case 'X':
					for (l = 0; l < 3;) {
						int h;
						buf2[l++] = *prmt_ptr;
						buf2[l] = 0;
						h = strtol(buf2, &pbuf, 16);
						if (h > UCHAR_MAX || (pbuf - buf2) < l) {
							l--;
							break;
						}
						prmt_ptr++;
					}
					buf2[l] = 0;
					c = (char)strtol(buf2, NULL, 16);
					if (c == 0)
						c = '?';
					pbuf = buf;
					break;
				case '[': case ']':
					if (c == flg_not_length) {
						flg_not_length = flg_not_length == '[' ? ']' : '[';
						continue;
					}
					break;
				}
			}
		}
		if (pbuf == buf)
			*pbuf = c;
		cur_prmt_len = strlen(pbuf);
		prmt_len += cur_prmt_len;
		if (flg_not_length != ']')
			cmdedit_prmt_len += cur_prmt_len;
		prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf);
	}
	if (pwd_buf != (char *)bb_msg_unknown)
		free(pwd_buf);
	cmdedit_prompt = prmt_mem_ptr;
	put_prompt();
}
Exemple #7
0
static int print_formatted(char *format, int argc, char **argv)
{
	int save_argc = argc;   /* Preserve original value.  */
	char *f;                /* Pointer into 'format'.  */
	char *direc_start;      /* Start of % directive.  */
	size_t direc_length;    /* Length of % directive.  */
	int field_width;        /* Arg to first '*', or -1 if none.  */
	int precision;          /* Arg to second '*', or -1 if none.  */

	for (f = format; *f; ++f) {
		switch (*f) {
		case '%':
			direc_start = f++;
			direc_length = 1;
			field_width = precision = -1;
			if (*f == '%') {
				bb_putchar('%');
				break;
			}
			if (*f == 'b') {
				if (argc > 0) {
					print_esc_string(*argv);
					++argv;
					--argc;
				}
				break;
			}
			if (strchr("-+ #", *f)) {
				++f;
				++direc_length;
			}
			if (*f == '*') {
				++f;
				++direc_length;
				if (argc > 0) {
					field_width = my_xstrtoul(*argv);
					++argv;
					--argc;
				} else
					field_width = 0;
			} else {
				while (isdigit(*f)) {
					++f;
					++direc_length;
				}
			}
			if (*f == '.') {
				++f;
				++direc_length;
				if (*f == '*') {
					++f;
					++direc_length;
					if (argc > 0) {
						precision = my_xstrtoul(*argv);
						++argv;
						--argc;
					} else
						precision = 0;
				} else
					while (isdigit(*f)) {
						++f;
						++direc_length;
					}
			}
			if (*f == 'l' || *f == 'L' || *f == 'h') {
				++f;
				++direc_length;
			}
			/*
			if (!strchr ("diouxXfeEgGcs", *f))
			fprintf(stderr, "%%%c: invalid directive", *f);
			*/
			++direc_length;
			if (argc > 0) {
				print_direc(direc_start, direc_length, field_width,
							precision, *argv);
				++argv;
				--argc;
			} else
				print_direc(direc_start, direc_length, field_width,
							precision, "");
			break;
		case '\\':
			if (*++f == 'c')
				exit(0);
			bb_putchar(bb_process_escape_sequence((const char **)&f));
			f--;
			break;
		default:
			bb_putchar(*f);
		}
	}

	return save_argc - argc;
}
Exemple #8
0
int echo_main(int argc UNUSED_PARAM, char **argv)
{
	char **pp;
	const char *arg;
	char *out;
	char *buffer;
	unsigned buflen;
#if !ENABLE_FEATURE_FANCY_ECHO
	enum {
		eflag = '\\',
		nflag = 1,  /* 1 -- print '\n' */
	};

	argv++;
#else
	char nflag = 1;
	char eflag = 0;

	while ((arg = *++argv) != NULL) {
		char n, e;

		if (arg[0] != '-')
			break; /* not an option arg, echo it */

		/* If it appears that we are handling options, then make sure
		 * that all of the options specified are actually valid.
		 * Otherwise, the string should just be echoed.
		 */
		arg++;
		n = nflag;
		e = eflag;
		do {
			if (*arg == 'n')
				n = 0;
			else if (*arg == 'e')
				e = '\\';
			else if (*arg != 'E') {
				/* "-ccc" arg with one of c's invalid, echo it */
				/* arg consisting from just "-" also handled here */
				goto just_echo;
			}
		} while (*++arg);
		nflag = n;
		eflag = e;
	}
 just_echo:
#endif

	buflen = 0;
	pp = argv;
	while ((arg = *pp) != NULL) {
		buflen += strlen(arg) + 1;
		pp++;
	}
	out = buffer = xmalloc(buflen + 1); /* +1 is needed for "no args" case */

	while ((arg = *argv) != NULL) {
		int c;

		if (!eflag) {
			/* optimization for very common case */
			out = stpcpy(out, arg);
		} else
		while ((c = *arg++) != '\0') {
			if (c == eflag) {
				/* This is an "\x" sequence */

				if (*arg == 'c') {
					/* "\c" means cancel newline and
					 * ignore all subsequent chars. */
					goto do_write;
				}
				/* Since SUSv3 mandates a first digit of 0, 4-digit octals
				* of the form \0### are accepted. */
				if (*arg == '0') {
					if ((unsigned char)(arg[1] - '0') < 8) {
						/* 2nd char is 0..7: skip leading '0' */
						arg++;
					}
				}
				/* bb_process_escape_sequence handles NUL correctly
				 * ("...\" case). */
				{
					/* optimization: don't force arg to be on-stack,
					 * use another variable for that. ~30 bytes win */
					const char *z = arg;
					c = bb_process_escape_sequence(&z);
					arg = z;
				}
			}
			*out++ = c;
		}

		if (!*++argv)
			break;
		*out++ = ' ';
	}

	if (nflag) {
		*out++ = '\n';
	}

 do_write:
	/* Careful to error out on partial writes too (think ENOSPC!) */
	errno = 0;
	/*r =*/ full_write(STDOUT_FILENO, buffer, out - buffer);
	free(buffer);
	if (/*WRONG:r < 0*/ errno) {
		bb_perror_msg(bb_msg_write_error);
		return 1;
	}
	return 0;
}
Exemple #9
0
int echo_main(int argc, char **argv)
{
	struct iovec io[argc];
	struct iovec *cur_io = io;
	char *arg;
	char *p;
#if !ENABLE_FEATURE_FANCY_ECHO
	enum {
		eflag = '\\',
		nflag = 1,  /* 1 -- print '\n' */
	};
	arg = *++argv;
	if (!arg)
		goto newline_ret;
#else
	char nflag = 1;
	char eflag = 0;

	while (1) {
		arg = *++argv;
		if (!arg)
			goto newline_ret;
		if (*arg != '-')
			break;

		/* If it appears that we are handling options, then make sure
		 * that all of the options specified are actually valid.
		 * Otherwise, the string should just be echoed.
		 */
		p = arg + 1;
		if (!*p)	/* A single '-', so echo it. */
			goto just_echo;

		do {
			if (!strchr("neE", *p))
				goto just_echo;
		} while (*++p);

		/* All of the options in this arg are valid, so handle them. */
		p = arg + 1;
		do {
			if (*p == 'n')
				nflag = 0;
			if (*p == 'e')
				eflag = '\\';
		} while (*++p);
	}
 just_echo:
#endif

	while (1) {
		/* arg is already == *argv and isn't NULL */
		int c;

		cur_io->iov_base = p = arg;

		if (!eflag) {
			/* optimization for very common case */
			p += strlen(arg);
		} else while ((c = *arg++)) {
			if (c == eflag) {
				/* This is an "\x" sequence */

				if (*arg == 'c') {
					/* "\c" means cancel newline and
					 * ignore all subsequent chars. */
					cur_io->iov_len = p - (char*)cur_io->iov_base;
					cur_io++;
					goto ret;
				}
				/* Since SUSv3 mandates a first digit of 0, 4-digit octals
				* of the form \0### are accepted. */
				if (*arg == '0' && (unsigned char)(arg[1] - '0') < 8) {
					arg++;
				}
				/* bb_process_escape_sequence can handle nul correctly */
				c = bb_process_escape_sequence( (void*) &arg);
			}
			*p++ = c;
		}

		arg = *++argv;
		if (arg)
			*p++ = ' ';
		cur_io->iov_len = p - (char*)cur_io->iov_base;
		cur_io++;
		if (!arg)
			break;
	}

 newline_ret:
	if (nflag) {
		cur_io->iov_base = (char*)"\n";
		cur_io->iov_len = 1;
		cur_io++;
	}
 ret:
	/* TODO: implement and use full_writev? */
	return writev(1, io, (cur_io - io)) >= 0;
}
Exemple #10
0
int echo_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
        int newfd = 0;
	const char *arg;
#if !ENABLE_FEATURE_FANCY_ECHO
	enum {
		eflag = '\\',
		nflag = 1,  /* 1 -- print '\n' */
	};

	/* We must check that stdout is not closed.
	 * The reason for this is highly non-obvious.
	 * echo_main is used from shell. Shell must correctly handle "echo foo"
	 * if stdout is closed. With stdio, output gets shoveled into
	 * stdout buffer, and even fflush cannot clear it out. It seems that
	 * even if libc receives EBADF on write attempts, it feels determined
	 * to output data no matter what. So it will try later,
	 * and possibly will clobber future output. Not good. */
	/*if (dup2(1, 1) != 1)
	  return -1;*/
	/* atisu: using dup2() did not work on windows */ 
	newfd = dup(STDOUT_FILENO);
	if (newfd == -1){
	  if (getenv("GIT_TRACE")) {
	    fprintf(stderr, "command 'echo' returns without doing anything\n");  
	  }
          return -1;
	}
	close(newfd);
	
	arg = *++argv;
	if (!arg)
		goto newline_ret;
#else
	const char *p;
	char nflag = 1;
	char eflag = 0;


	/* We must check that stdout is not closed. */
	/*if (_dup2(1, 1) != 1)
	  return -1;*/
	/* atisu: using dup2() did not work on windows */ 
	newfd = dup(STDOUT_FILENO);
	if (newfd == -1){
	  if (getenv("GIT_TRACE")) {
	    fprintf(stderr, "command 'echo' returns without doing anything\n");  
	  }
          return -1;
	}
	close(newfd);
	while (1) {
		arg = *++argv;
		if (!arg)
			goto newline_ret;
		if (*arg != '-')
			break;

		/* If it appears that we are handling options, then make sure
		 * that all of the options specified are actually valid.
		 * Otherwise, the string should just be echoed.
		 */
		p = arg + 1;
		if (!*p)	/* A single '-', so echo it. */
			goto just_echo;

		do {
			if (!strrchr("neE", *p))
				goto just_echo;
		} while (*++p);

		/* All of the options in this arg are valid, so handle them. */
		p = arg + 1;
		do {
			if (*p == 'n')
				nflag = 0;
			if (*p == 'e')
				eflag = '\\';
		} while (*++p);
	}
 just_echo:
#endif
	while (1) {
		/* arg is already == *argv and isn't NULL */
		int c;

		if (!eflag) {
			/* optimization for very common case */
			fputs(arg, stdout);
		} else while ((c = *arg++)) {
			if (c == eflag) {	/* Check for escape seq. */
				if (*arg == 'c') {
					/* '\c' means cancel newline and
					 * ignore all subsequent chars. */
					goto ret;
				}
#if !ENABLE_FEATURE_FANCY_ECHO
				/* SUSv3 specifies that octal escapes must begin with '0'. */
				if ( (((unsigned char)*arg) - '1') >= 7)
#endif
				{
					/* Since SUSv3 mandates a first digit of 0, 4-digit octals
					* of the form \0### are accepted. */
					if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) {
						arg++;
					}
					/* bb_process_escape_sequence can handle nul correctly */
					c = bb_process_escape_sequence(&arg);
				}
			}
			bb_putchar(c);
		}

		arg = *++argv;
		if (!arg)
			break;
		bb_putchar(' ');
	}

 newline_ret:
	if (nflag) {
		bb_putchar('\n');
	}
 ret:
	return fflush(stdout);
}
Exemple #11
0
/* supported constructs:
 *   Ranges,  e.g.,  [0-9]  ==>  0123456789
 *   Escapes, e.g.,  \a     ==>  Control-G
 *	 Character classes, e.g. [:upper:] ==> A ... Z
 */
static unsigned int expand(const char *arg, char *buffer)
{
	char *buffer_start = buffer;
	unsigned i; /* XXX: FIXME: use unsigned char? */
	unsigned char ac;
#define CLO ":]"
	static const char * const classes[] = {
		"alpha"CLO, "alnum"CLO, "digit"CLO, "lower"CLO, "upper"CLO, "space"CLO,
		"blank"CLO, "punct"CLO, "cntrl"CLO, NULL
	};
#define CLASS_invalid 0 /* we increment the retval */
#define CLASS_alpha 1
#define CLASS_alnum 2
#define CLASS_digit 3
#define CLASS_lower 4
#define CLASS_upper 5
#define CLASS_space 6
#define CLASS_blank 7
#define CLASS_punct 8
#define CLASS_cntrl 9
//#define CLASS_xdigit 10
//#define CLASS_graph 11
//#define CLASS_print 12
	while (*arg) {
		if (*arg == '\\') {
			arg++;
			*buffer++ = bb_process_escape_sequence(&arg);
		} else if (*(arg+1) == '-') {
			ac = *(arg+2);
			if (ac == 0) {
				*buffer++ = *arg++;
				continue;
			}
			i = *arg;
			while (i <= ac)
				*buffer++ = i++;
			arg += 3; /* Skip the assumed a-z */
		} else if (*arg == '[') {
			arg++;
			i = *arg++;
			if (ENABLE_FEATURE_TR_CLASSES && i == ':') {
				smalluint j;
				{ /* not really pretty.. */
				char *tmp = xstrndup(arg, 7); // warning: xdigit needs 8, not 7
				j = index_in_str_array(classes, tmp) + 1;
				free(tmp);
				}
				if (j == CLASS_alnum || j == CLASS_digit) {
					for (i = '0'; i <= '9'; i++)
						*buffer++ = i;
				}
				if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_upper) {
					for (i = 'A'; i <= 'Z'; i++)
						*buffer++ = i;
				}
				if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_lower) {
					for (i = 'a'; i <= 'z'; i++)
						*buffer++ = i;
				}
				if (j == CLASS_space || j == CLASS_blank) {
					*buffer++ = '\t';
					if (j == CLASS_space) {
						*buffer++ = '\n';
						*buffer++ = '\v';
						*buffer++ = '\f';
						*buffer++ = '\r';
					}
					*buffer++ = ' ';
				}
				if (j == CLASS_punct || j == CLASS_cntrl) {
					for (i = 0; i <= ASCII; i++)
						if ((j == CLASS_punct &&
							 isprint(i) && (!isalnum(i)) && (!isspace(i))) ||
							(j == CLASS_cntrl && iscntrl(i)))
							*buffer++ = i;
				}
				if (j == CLASS_invalid) {
					*buffer++ = '[';
					*buffer++ = ':';
					continue;
				}
				break;
			}
			if (ENABLE_FEATURE_TR_EQUIV && i == '=') {
				*buffer++ = *arg;
				arg += 3;	/* Skip the closing =] */
				continue;
			}
			if (*arg++ != '-') {
				*buffer++ = '[';
				arg -= 2;
				continue;
			}
			ac = *arg++;
			while (i <= ac)
				*buffer++ = i++;
			arg++;	/* Skip the assumed ']' */
		} else
			*buffer++ = *arg++;
	}
	return (buffer - buffer_start);
}
Exemple #12
0
int echo_main(int argc UNUSED_PARAM, char **argv)
{
    const char *arg;
#if !ENABLE_FEATURE_FANCY_ECHO
    enum {
        eflag = '\\',
        nflag = 1,  /* 1 -- print '\n' */
    };

    /* We must check that stdout is not closed.
     * The reason for this is highly non-obvious.
     * echo_main is used from shell. Shell must correctly handle "echo foo"
     * if stdout is closed. With stdio, output gets shoveled into
     * stdout buffer, and even fflush cannot clear it out. It seems that
     * even if libc receives EBADF on write attempts, it feels determined
     * to output data no matter what. So it will try later,
     * and possibly will clobber future output. Not good. */
// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
    if (fcntl(1, F_GETFL) == -1)
        return 1; /* match coreutils 6.10 (sans error msg to stderr) */
    //if (dup2(1, 1) != 1) - old way
    //	return 1;

    arg = *++argv;
    if (!arg)
        goto newline_ret;
#else
    const char *p;
    char nflag = 1;
    char eflag = 0;

    /* We must check that stdout is not closed. */
    if (fcntl(1, F_GETFL) == -1)
        return 1;

    while (1) {
        arg = *++argv;
        if (!arg)
            goto newline_ret;
        if (*arg != '-')
            break;

        /* If it appears that we are handling options, then make sure
         * that all of the options specified are actually valid.
         * Otherwise, the string should just be echoed.
         */
        p = arg + 1;
        if (!*p)	/* A single '-', so echo it. */
            goto just_echo;

        do {
            if (!strrchr("neE", *p))
                goto just_echo;
        } while (*++p);

        /* All of the options in this arg are valid, so handle them. */
        p = arg + 1;
        do {
            if (*p == 'n')
                nflag = 0;
            if (*p == 'e')
                eflag = '\\';
        } while (*++p);
    }
just_echo:
#endif
    while (1) {
        /* arg is already == *argv and isn't NULL */
        int c;

        if (!eflag) {
            /* optimization for very common case */
            fputs(arg, stdout);
        } else while ((c = *arg++)) {
                if (c == eflag) {	/* Check for escape seq. */
                    if (*arg == 'c') {
                        /* '\c' means cancel newline and
                         * ignore all subsequent chars. */
                        goto ret;
                    }
#if !ENABLE_FEATURE_FANCY_ECHO
                    /* SUSv3 specifies that octal escapes must begin with '0'. */
                    if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */
#endif
                    {
                        /* Since SUSv3 mandates a first digit of 0, 4-digit octals
                        * of the form \0### are accepted. */
                        if (*arg == '0') {
                            /* NB: don't turn "...\0" into "...\" */
                            if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
                                arg++;
                            }
                        }
                        /* bb_process_escape_sequence handles NUL correctly
                         * ("...\" case). */
                        c = bb_process_escape_sequence(&arg);
                    }
                }
                bb_putchar(c);
            }

        arg = *++argv;
        if (!arg)
            break;
        bb_putchar(' ');
    }

newline_ret:
    if (nflag) {
        bb_putchar('\n');
    }
ret:
    return fflush(stdout);
}
Exemple #13
0
int main(int argc, char **argv)
{
	const char *arg;
	const char *p;
	char nflag = 1;
	char eflag = 0;

	/* We must check that stdout is not closed. */
	if (dup2(1, 1) != 1)
		return -1;

	while (1) {
		arg = *++argv;
		if (!arg)
			goto newline_ret;
		if (*arg != '-')
			break;

		/* If it appears that we are handling options, then make sure
		 * that all of the options specified are actually valid.
		 * Otherwise, the string should just be echoed.
		 */
		p = arg + 1;
		if (!*p)	/* A single '-', so echo it. */
			goto just_echo;

		do {
			if (!strrchr("neE", *p))
				goto just_echo;
		} while (*++p);

		/* All of the options in this arg are valid, so handle them. */
		p = arg + 1;
		do {
			if (*p == 'n')
				nflag = 0;
			if (*p == 'e')
				eflag = '\\';
		} while (*++p);
	}
 just_echo:
	while (1) {
		/* arg is already == *argv and isn't NULL */
		int c;

		if (!eflag) {
			/* optimization for very common case */
			fputs(arg, stdout);
		} else while ((c = *arg++)) {
			if (c == eflag) {	/* Check for escape seq. */
				if (*arg == 'c') {
					/* '\c' means cancel newline and
					 * ignore all subsequent chars. */
					goto ret;
				}
				{
					/* Since SUSv3 mandates a first digit of 0, 4-digit octals
					* of the form \0### are accepted. */
					if (*arg == '0') {
						/* NB: don't turn "...\0" into "...\" */
						if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
							arg++;
						}
					}
					/* bb_process_escape_sequence handles NUL correctly
					 * ("...\" case. */
					c = bb_process_escape_sequence(&arg);
				}
			}
			putchar(c);
		}

		arg = *++argv;
		if (!arg)
			break;
		putchar(' ');
	}

 newline_ret:
	if (nflag) {
		putchar('\n');
	}
 ret:
	return fflush(NULL);
}