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; }
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); }
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; }
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(); }
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; }
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; }
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; }
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); }
/* 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); }
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); }
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); }