static void my_fgets80(char *buf80) { fflush_all(); if (!fgets(buf80, 80, stdin)) { bb_perror_msg_and_die("can't read standard input"); } }
static void die_if_nologin(void) { FILE *fp; int c; int empty = 1; fp = fopen_for_read("/etc/nologin"); if (!fp) /* assuming it does not exist */ return; while ((c = getc(fp)) != EOF) { if (c == '\n') bb_putchar('\r'); bb_putchar(c); empty = 0; } if (empty) puts("\r\nSystem closed for routine maintenance\r"); fclose(fp); fflush_all(); /* Users say that they do need this prior to exit: */ tcdrain(STDOUT_FILENO); exit(EXIT_FAILURE); }
static void confirm_or_abort(void) { fprintf(stderr, "Continue? [y/N] "); fflush_all(); if (!bb_ask_confirmation()) bb_error_msg_and_die("aborting"); }
static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) { printf("\rErasing %u Kibyte @ %x - %2u%% complete.", (unsigned)meminfo->erasesize / 1024, erase->start, (unsigned) ((unsigned long long) erase->start * 100 / meminfo->size) ); fflush_all(); }
/* Die with an error message if we can't copy an entire FILE* to stdout, * then close that file. */ void FAST_FUNC xprint_and_close_file(FILE *file) { fflush_all(); // copyfd outputs error messages for us. if (bb_copyfd_eof(fileno(file), STDOUT_FILENO) == -1) xfunc_die(); fclose(file); }
void FAST_FUNC print_login_prompt(void) { char *hostname = safe_gethostname(); fputs(hostname, stdout); fputs(LOGIN, stdout); fflush_all(); free(hostname); }
/* Code size is approximately the same, but currently it's the only user * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) { int strerr_len, msgeol_len; struct iovec iov[3]; #define used (iov[2].iov_len) #define msgv (iov[2].iov_base) #define msgc ((char*)(iov[2].iov_base)) #define msgptr (&(iov[2].iov_base)) if (!logmode) return; if (!s) /* nomsg[_and_die] uses NULL fmt */ s = ""; /* some libc don't like printf(NULL) */ /* Prevent "derefing type-punned ptr will break aliasing rules" */ used = vasprintf((char**)(void*)msgptr, s, p); if (used < 0) return; /* This is ugly and costs +60 bytes compared to multiple * fprintf's, but is guaranteed to do a single write. * This is needed for e.g. httpd logging, when multiple * children can produce log messages simultaneously. */ strerr_len = strerr ? strlen(strerr) : 0; msgeol_len = strlen(msg_eol); /* +3 is for ": " before strerr and for terminating NUL */ msgv = xrealloc(msgv, used + strerr_len + msgeol_len + 3); if (strerr) { msgc[used++] = ':'; msgc[used++] = ' '; strcpy(msgc + used, strerr); used += strerr_len; } strcpy(msgc + used, msg_eol); used += msgeol_len; if (logmode & LOGMODE_STDIO) { iov[0].iov_base = (char*)applet_name; iov[0].iov_len = strlen(applet_name); iov[1].iov_base = (char*)": "; iov[1].iov_len = 2; /*iov[2].iov_base = msgc;*/ /*iov[2].iov_len = used;*/ fflush_all(); writev(STDERR_FILENO, iov, 3); } # if ENABLE_FEATURE_SYSLOG if (logmode & LOGMODE_SYSLOG) { syslog(LOG_ERR, "%s", msgc); } # endif free(msgc); }
int length_main(int argc, char **argv) { if ((argc != 2) || (**(++argv) == '-')) { bb_show_usage(); } printf("%u\n", (unsigned)strlen(*argv)); return fflush_all(); }
// file coreutils/dirname.c line 29 signed int __main(signed int argc, char **argv) { char *return_value_single_argv$1; return_value_single_argv$1=single_argv(argv); char *return_value_dirname$2; return_value_dirname$2=dirname(return_value_single_argv$1); puts(return_value_dirname$2); signed int return_value_fflush_all$3; return_value_fflush_all$3=fflush_all(); return return_value_fflush_all$3; }
static void motd(void) { int fd; fd = open(bb_path_motd_file, O_RDONLY); if (fd >= 0) { fflush_all(); bb_copyfd_eof(fd, STDOUT_FILENO); close(fd); } }
static void alarm_handler(int sig UNUSED_PARAM) { /* This is the escape hatch! Poor serial line users and the like * arrive here when their connection is broken. * We don't want to block here */ ndelay_on(1); printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT); fflush_all(); /* unix API is brain damaged regarding O_NONBLOCK, * we should undo it, or else we can affect other processes */ ndelay_off(1); _exit(EXIT_SUCCESS); }
/* Read a line from fp. If the first non-whitespace char is 'y' or 'Y', * return 1. Otherwise return 0. */ int FAST_FUNC bb_ask_y_confirmation_FILE(FILE *fp) { char first = 0; int c; fflush_all(); while (((c = fgetc(fp)) != EOF) && (c != '\n')) { if (first == 0 && !isblank(c)) { first = c|0x20; } } return first == 'y'; }
static void progress(int mode, uoff_t count, uoff_t total) { uoff_t percent; if (!option_mask32) //if (!(option_mask32 & OPT_v)) return; percent = count * 100; if (total) percent = (unsigned) (percent / total); printf("\r%s: %"OFF_FMT"u/%"OFF_FMT"u (%u%%) ", (mode < 0) ? "Erasing block" : ((mode == 0) ? "Writing kb" : "Verifying kb"), count, total, (unsigned)percent); fflush_all(); }
char* FAST_FUNC send_mail_command(const char *fmt, const char *param) { char *msg; if (timeout) alarm(timeout); msg = (char*)fmt; if (fmt) { msg = xasprintf(fmt, param); if (verbose) bb_error_msg("send:'%s'", msg); printf("%s\r\n", msg); } fflush_all(); return msg; }
/* Prompt the user for a response, and * if user responds affirmatively, return true; * otherwise, return false. Uses "/dev/tty", not stdin. */ static int xargs_ask_confirmation(void) { FILE *tty_stream; int c, savec; #if !ENABLE_PLATFORM_MINGW32 tty_stream = xfopen_for_read(CURRENT_TTY); #endif fputs(" ?...", stderr); fflush_all(); #if !ENABLE_PLATFORM_MINGW32 c = savec = getc(tty_stream); while (c != EOF && c != '\n') c = getc(tty_stream); fclose(tty_stream); #else c = savec = getche(); while (c != EOF && c != '\r') c = getche(); fputs("\n", stderr); fflush_all(); #endif return (savec == 'y' || savec == 'Y'); }
void FAST_FUNC bb_info_msg(const char *s, ...) { #ifdef THIS_ONE_DOESNT_DO_SINGLE_WRITE va_list p; /* va_copy is used because it is not portable * to use va_list p twice */ va_list p2; va_start(p, s); va_copy(p2, p); if (logmode & LOGMODE_STDIO) { vprintf(s, p); fputs(msg_eol, stdout); } # if ENABLE_FEATURE_SYSLOG if (logmode & LOGMODE_SYSLOG) vsyslog(LOG_INFO, s, p2); # endif va_end(p2); va_end(p); #else int used; char *msg; va_list p; if (logmode == 0) return; va_start(p, s); used = vasprintf(&msg, s, p); va_end(p); if (used < 0) return; # if ENABLE_FEATURE_SYSLOG if (logmode & LOGMODE_SYSLOG) syslog(LOG_INFO, "%s", msg); # endif if (logmode & LOGMODE_STDIO) { fflush_all(); /* used = strlen(msg); - must be true already */ msg[used++] = '\n'; full_write(STDOUT_FILENO, msg, used); } free(msg); #endif }
/* * Write the specified lines out to the specified file. * Returns TRUE if successful, or FALSE on an error with a message output. */ static int writeLines(const char *file, int num1, int num2) { LINE *lp; int fd, lineCount, charCount; if (bad_nums(num1, num2, "write")) return FALSE; lineCount = 0; charCount = 0; fd = creat(file, 0666); if (fd < 0) { bb_simple_perror_msg(file); return FALSE; } printf("\"%s\", ", file); fflush_all(); lp = findLine(num1); if (lp == NULL) { close(fd); return FALSE; } while (num1++ <= num2) { if (full_write(fd, lp->data, lp->len) != lp->len) { bb_simple_perror_msg(file); close(fd); return FALSE; } charCount += lp->len; lineCount++; lp = lp->next; } if (close(fd) < 0) { bb_simple_perror_msg(file); return FALSE; } printf("%d lines, %d chars\n", lineCount, charCount); return TRUE; }
// file coreutils/hostid.c line 33 signed int __main(signed int argc, char **argv) { if(!(argv == ((char **)NULL))) (void)0; else /* assertion !(argv == ((char **)((void*)0))) */ __VERIFIER_error(); if(!(*(1l + argv) == ((char *)NULL))) bb_show_usage(); signed long int return_value_gethostid$1; return_value_gethostid$1=gethostid(); printf("%08x\n", (unsigned int)return_value_gethostid$1); signed int return_value_fflush_all$2; return_value_fflush_all$2=fflush_all(); return return_value_fflush_all$2; }
void FAST_FUNC print_login_prompt(void) { char buf[MAXHOSTNAMELEN+1]; /* Login Prompt by BrainSlayer */ FILE *fp = fopen ("/tmp/loginprompt", "rb"); if (fp) { int d; while ((d=getc(fp))!=EOF) { putc (d, stdout); } fclose (fp); } fprintf(stdout,"\n"); char *hostname = safe_gethostname(); fputs(hostname, stdout); fputs(LOGIN, stdout); fflush_all(); free(hostname); }
/* This does a fork/exec in one call, using vfork(). Returns PID of new child, * -1 for failure. Runs argv[0], searching path if that has no / in it. */ pid_t FAST_FUNC spawn(char **argv) { /* Compiler should not optimize stores here */ volatile int failed; pid_t pid; fflush_all(); /* Be nice to nommu machines. */ failed = 0; pid = vfork(); if (pid < 0) /* error */ return pid; if (!pid) { /* child */ /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */ BB_EXECVP(argv[0], argv); /* We are (maybe) sharing a stack with blocked parent, * let parent know we failed and then exit to unblock parent * (but don't run atexit() stuff, which would screw up parent.) */ failed = errno; /* mount, for example, does not want the message */ /*bb_perror_msg("can't execute '%s'", argv[0]);*/ _exit(111); } /* parent */ /* Unfortunately, this is not reliable: according to standards * vfork() can be equivalent to fork() and we won't see value * of 'failed'. * Interested party can wait on pid and learn exit code. * If 111 - then it (most probably) failed to exec */ if (failed) { safe_waitpid(pid, NULL, 0); /* prevent zombie */ errno = failed; return -1; } return pid; }
/* Reset terminal input to normal */ static void set_tty_cooked(void) { fflush_all(); tcsetattr(kbd_fd, TCSANOW, &term_orig); }
void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) { char *msg, *msg1; int applet_len, strerr_len, msgeol_len, used; if (!logmode) return; if (!s) /* nomsg[_and_die] uses NULL fmt */ s = ""; /* some libc don't like printf(NULL) */ used = vasprintf(&msg, s, p); if (used < 0) return; /* This is ugly and costs +60 bytes compared to multiple * fprintf's, but is guaranteed to do a single write. * This is needed for e.g. httpd logging, when multiple * children can produce log messages simultaneously. */ applet_len = strlen(applet_name) + 2; /* "applet: " */ strerr_len = strerr ? strlen(strerr) : 0; msgeol_len = strlen(msg_eol); /* can't use xrealloc: it calls error_msg on failure, * that may result in a recursion */ /* +3 is for ": " before strerr and for terminating NUL */ msg1 = realloc(msg, applet_len + used + strerr_len + msgeol_len + 3); if (!msg1) { msg[used++] = '\n'; /* overwrites NUL */ applet_len = 0; } else { msg = msg1; /* TODO: maybe use writev instead of memmoving? Need full_writev? */ memmove(msg + applet_len, msg, used); used += applet_len; strcpy(msg, applet_name); msg[applet_len - 2] = ':'; msg[applet_len - 1] = ' '; if (strerr) { if (s[0]) { /* not perror_nomsg? */ msg[used++] = ':'; msg[used++] = ' '; } strcpy(&msg[used], strerr); used += strerr_len; } strcpy(&msg[used], msg_eol); used += msgeol_len; } if (logmode & LOGMODE_STDIO) { fflush_all(); full_write(STDERR_FILENO, msg, used); } #if ENABLE_FEATURE_SYSLOG if (logmode & LOGMODE_SYSLOG) { syslog(LOG_ERR, "%s", msg + applet_len); } #endif free(msg); }
void FAST_FUNC print_login_issue(const char *issue_file, const char *tty) { FILE *fp; int c; char buf[256+1]; const char *outbuf; time_t t; struct utsname uts; time(&t); uname(&uts); puts("\r"); /* start a new line */ fp = fopen_for_read(issue_file); if (!fp) return; while ((c = fgetc(fp)) != EOF) { outbuf = buf; buf[0] = c; buf[1] = '\0'; if (c == '\n') { buf[1] = '\r'; buf[2] = '\0'; } if (c == '\\' || c == '%') { c = fgetc(fp); switch (c) { //From getty manpage (* - supported by us) //======================================== //4 or 4{interface} // Insert the IPv4 address of the network interface (example: \4{eth0}). // If the interface argument is not specified, then select the first // fully configured (UP, non-LOOPBACK, RUNNING) interface. //6 or 6{interface} -- The same as \4 but for IPv6. //b -- Insert the baudrate of the current line. //*d -- Insert the current date. //*t -- Insert the current time. //e or e{name} // Translate the human-readable name to an escape sequence and insert it // (for example: \e{red}Alert text.\e{reset}). If the name argument // is not specified, then insert \033. The currently supported names are: // black, blink, blue, bold, brown, cyan, darkgray, gray, green, halfbright, // lightblue, lightcyan, lightgray, lightgreen, lightmagenta, lightred, // magenta, red, reset, reverse, and yellow. Unknown names are ignored. //*s // Insert the system name (the name of the operating system - `uname -s`) //*S or S{VARIABLE} // Insert the VARIABLE data from /etc/os-release. // If the VARIABLE argument is not specified, use PRETTY_NAME. // If PRETTY_NAME is not in /etc/os-release, \S is the same as \s. //*l -- Insert the name of the current tty line. //*m -- Insert the architecture identifier of the machine: `uname -m`. //*n -- Insert the nodename of the machine: `uname -n`. //*o -- Insert the NIS domainname of the machine. Same as `hostname -d'. //*O -- Insert the DNS domainname of the machine. //*r -- Insert the release number of the OS: `uname -r`. //u -- Insert the number of current users logged in. //U -- Insert the string "1 user" or "N users" (current users logged in). //*v -- Insert the version of the OS, e.g. the build-date etc: `uname -v`. //We also implement: //*D -- same as \O "DNS domainname" //*h -- same as \n "nodename" case 'S': /* minimal implementation, not reading /etc/os-release */ /*FALLTHROUGH*/ case 's': outbuf = uts.sysname; break; case 'n': case 'h': outbuf = uts.nodename; break; case 'r': outbuf = uts.release; break; case 'v': outbuf = uts.version; break; case 'm': outbuf = uts.machine; break; /* The field domainname of struct utsname is Linux specific. */ #if defined(__linux__) case 'D': case 'o': case 'O': outbuf = uts.domainname; break; #endif case 'd': strftime(buf, sizeof(buf), fmtstr_d, localtime(&t)); break; case 't': strftime_HHMMSS(buf, sizeof(buf), &t); break; case 'l': outbuf = tty; break; default: buf[0] = c; } } fputs(outbuf, stdout); } fclose(fp); fflush_all(); }
/* Dump all but word data. */ static void dump_data(int bus_fd, int mode, unsigned first, unsigned last, int *block, int blen) { int i, j, res; puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f" " 0123456789abcdef"); for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) { if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen) break; if (i/16 < first/16) continue; if (i/16 > last/16) break; printf("%02x: ", i); for (j = 0; j < 16; j++) { fflush_all(); /* Skip unwanted registers */ if (i+j < first || i+j > last) { printf(" "); if (mode == I2C_SMBUS_WORD_DATA) { printf(" "); j++; } continue; } switch (mode) { case I2C_SMBUS_BYTE_DATA: res = i2c_smbus_read_byte_data(bus_fd, i+j); block[i+j] = res; break; case I2C_SMBUS_WORD_DATA: res = i2c_smbus_read_word_data(bus_fd, i+j); if (res < 0) { block[i+j] = res; block[i+j+1] = res; } else { block[i+j] = res & 0xff; block[i+j+1] = res >> 8; } break; case I2C_SMBUS_BYTE: res = i2c_smbus_read_byte(bus_fd); block[i+j] = res; break; default: res = block[i+j]; } if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen) { printf(" "); } else if (res < 0) { printf("XX "); if (mode == I2C_SMBUS_WORD_DATA) printf("XX "); } else { printf("%02x ", block[i+j]); if (mode == I2C_SMBUS_WORD_DATA) printf("%02x ", block[i+j+1]); } if (mode == I2C_SMBUS_WORD_DATA) j++; } printf(" "); for (j = 0; j < 16; j++) { if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen) break; /* Skip unwanted registers */ if (i+j < first || i+j > last) { bb_putchar(' '); continue; } res = block[i+j]; if (res < 0) { bb_putchar('X'); } else if (res == 0x00 || res == 0xff) { bb_putchar('.'); } else if (res < 32 || res >= 127) { bb_putchar('?'); } else { bb_putchar(res); } } bb_putchar('\n'); } }
/* * Read lines from a file at the specified line number. * Returns TRUE if the file was successfully read. */ static int readLines(const char *file, int num) { int fd, cc; int len, lineCount, charCount; char *cp; if ((num < 1) || (num > lastNum + 1)) { bb_error_msg("bad line for read"); return FALSE; } fd = open(file, 0); if (fd < 0) { bb_simple_perror_msg(file); return FALSE; } bufPtr = bufBase; bufUsed = 0; lineCount = 0; charCount = 0; cc = 0; printf("\"%s\", ", file); fflush_all(); do { cp = memchr(bufPtr, '\n', bufUsed); if (cp) { len = (cp - bufPtr) + 1; if (!insertLine(num, bufPtr, len)) { close(fd); return FALSE; } bufPtr += len; bufUsed -= len; charCount += len; lineCount++; num++; continue; } if (bufPtr != bufBase) { memcpy(bufBase, bufPtr, bufUsed); bufPtr = bufBase + bufUsed; } if (bufUsed >= bufSize) { len = (bufSize * 3) / 2; cp = xrealloc(bufBase, len); bufBase = cp; bufPtr = bufBase + bufUsed; bufSize = len; } cc = safe_read(fd, bufPtr, bufSize - bufUsed); bufUsed += cc; bufPtr = bufBase; } while (cc > 0); if (cc < 0) { bb_simple_perror_msg(file); close(fd); return FALSE; } if (bufUsed) { if (!insertLine(num, bufPtr, bufUsed)) { close(fd); return -1; } lineCount++; charCount += bufUsed; } close(fd); printf("%d lines%s, %d chars\n", lineCount, (bufUsed ? " (incomplete)" : ""), charCount); return TRUE; }
char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) { /* Was static char[BIGNUM] */ enum { sizeof_passwd = 128 }; static char *passwd; char *ret; int i; struct sigaction sa, oldsa; struct termios tio, oldtio; tcgetattr(fd, &oldtio); tcflush(fd, TCIFLUSH); tio = oldtio; #ifndef IUCLC # define IUCLC 0 #endif tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); tcsetattr(fd, TCSANOW, &tio); memset(&sa, 0, sizeof(sa)); /* sa.sa_flags = 0; - no SA_RESTART! */ /* SIGINT and SIGALRM will interrupt reads below */ sa.sa_handler = askpass_timeout; sigaction(SIGINT, &sa, &oldsa); if (timeout) { sigaction_set(SIGALRM, &sa); alarm(timeout); } fputs(prompt, stdout); fflush_all(); if (!passwd) passwd = xmalloc(sizeof_passwd); ret = passwd; i = 0; while (1) { int r = read(fd, &ret[i], 1); if (r < 0) { /* read is interrupted by timeout or ^C */ ret = NULL; break; } if (r == 0 /* EOF */ || ret[i] == '\r' || ret[i] == '\n' /* EOL */ || ++i == sizeof_passwd-1 /* line limit */ ) { ret[i] = '\0'; break; } } if (timeout) { alarm(0); } sigaction_set(SIGINT, &oldsa); tcsetattr(fd, TCSANOW, &oldtio); bb_putchar('\n'); fflush_all(); return ret; }
static int getch_nowait(void) { int rd; struct pollfd pfd[2]; pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; pfd[1].fd = kbd_fd; pfd[1].events = POLLIN; again: tcsetattr(kbd_fd, TCSANOW, &term_less); /* NB: select/poll returns whenever read will not block. Therefore: * if eof is reached, select/poll will return immediately * because read will immediately return 0 bytes. * Even if select/poll says that input is available, read CAN block * (switch fd into O_NONBLOCK'ed mode to avoid it) */ rd = 1; /* Are we interested in stdin? */ //TODO: reuse code for determining this if (!(option_mask32 & FLAG_S) ? !(max_fline > cur_fline + max_displayed_line) : !(max_fline >= cur_fline && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line) ) { if (eof_error > 0) /* did NOT reach eof yet */ rd = 0; /* yes, we are interested in stdin */ } /* Position cursor if line input is done */ if (less_gets_pos >= 0) move_cursor(max_displayed_line + 2, less_gets_pos + 1); fflush_all(); if (kbd_input[0] == 0) { /* if nothing is buffered */ #if ENABLE_FEATURE_LESS_WINCH while (1) { int r; /* NB: SIGWINCH interrupts poll() */ r = poll(pfd + rd, 2 - rd, -1); if (/*r < 0 && errno == EINTR &&*/ winch_counter) return '\\'; /* anything which has no defined function */ if (r) break; } #else safe_poll(pfd + rd, 2 - rd, -1); #endif } /* We have kbd_fd in O_NONBLOCK mode, read inside read_key() * would not block even if there is no input available */ rd = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); if (rd == -1) { if (errno == EAGAIN) { /* No keyboard input available. Since poll() did return, * we should have input on stdin */ read_lines(); buffer_fill_and_print(); goto again; } /* EOF/error (ssh session got killed etc) */ less_exit(0); } set_tty_cooked(); return rd; }
int seq_main(int argc, char **argv) { enum { OPT_w = (1 << 0), OPT_s = (1 << 1), }; double first, last, increment, v; unsigned n; unsigned width; unsigned frac_part; const char *sep, *opt_s = "\n"; unsigned opt; #if ENABLE_LOCALE_SUPPORT /* Undo busybox.c: on input, we want to use dot * as fractional separator, regardless of current locale */ setlocale(LC_NUMERIC, "C"); #endif opt = getopt32(argv, "+ws:", &opt_s); argc -= optind; argv += optind; first = increment = 1; errno = 0; switch (argc) { char *pp; case 3: increment = strtod(argv[1], &pp); errno |= *pp; case 2: first = strtod(argv[0], &pp); errno |= *pp; case 1: last = strtod(argv[argc-1], &pp); if (!errno && *pp == '\0') break; default: bb_show_usage(); } #if ENABLE_LOCALE_SUPPORT setlocale(LC_NUMERIC, ""); #endif /* Last checked to be compatible with: coreutils-6.10 */ width = 0; frac_part = 0; while (1) { char *dot = strchrnul(*argv, '.'); int w = (dot - *argv); int f = strlen(dot); if (width < w) width = w; argv++; if (!*argv) break; /* Why do the above _before_ frac check below? * Try "seq 1 2.0" and "seq 1.0 2.0": * coreutils never pay attention to the number * of fractional digits in last arg. */ if (frac_part < f) frac_part = f; } if (frac_part) { frac_part--; if (frac_part) width += frac_part + 1; } if (!(opt & OPT_w)) width = 0; sep = ""; v = first; n = 0; while (increment >= 0 ? v <= last : v >= last) { if (printf("%s%0*.*f", sep, width, frac_part, v) < 0) break; /* I/O error, bail out (yes, this really happens) */ sep = opt_s; /* v += increment; - would accumulate floating point errors */ n++; v = first + n * increment; } if (n) /* if while loop executed at least once */ bb_putchar('\n'); return fflush_all(); }
//TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL" //string. hush naturally has it, and ash has setvareq(). //Here we can simply store "VAR=" at buffer start and store read data directly //after "=", then pass buffer to setvar() to consume. const char* FAST_FUNC shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), char **argv, const char *ifs, int read_flags, const char *opt_n, const char *opt_p, const char *opt_t, const char *opt_u ) { unsigned end_ms; /* -t TIMEOUT */ int fd; /* -u FD */ int nchars; /* -n NUM */ char **pp; char *buffer; struct termios tty, old_tty; const char *retval; int bufpos; /* need to be able to hold -1 */ int startword; smallint backslash; pp = argv; while (*pp) { if (!is_well_formed_var_name(*pp, '\0')) { /* Mimic bash message */ bb_error_msg("read: '%s': not a valid identifier", *pp); return (const char *)(uintptr_t)1; } pp++; } nchars = 0; /* if != 0, -n is in effect */ if (opt_n) { nchars = bb_strtou(opt_n, NULL, 10); if (nchars < 0 || errno) return "invalid count"; /* note: "-n 0": off (bash 3.2 does this too) */ } end_ms = 0; if (opt_t) { end_ms = bb_strtou(opt_t, NULL, 10); if (errno || end_ms > UINT_MAX / 2048) return "invalid timeout"; end_ms *= 1000; #if 0 /* even bash has no -t N.NNN support */ ts.tv_sec = bb_strtou(opt_t, &p, 10); ts.tv_usec = 0; /* EINVAL means number is ok, but not terminated by NUL */ if (*p == '.' && errno == EINVAL) { char *p2; if (*++p) { int scale; ts.tv_usec = bb_strtou(p, &p2, 10); if (errno) return "invalid timeout"; scale = p2 - p; /* normalize to usec */ if (scale > 6) return "invalid timeout"; while (scale++ < 6) ts.tv_usec *= 10; } } else if (ts.tv_sec < 0 || errno) { return "invalid timeout"; } if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */ return "invalid timeout"; } #endif /* if 0 */ } fd = STDIN_FILENO; if (opt_u) { fd = bb_strtou(opt_u, NULL, 10); if (fd < 0 || errno) return "invalid file descriptor"; } if (opt_p && isatty(fd)) { fputs(opt_p, stderr); fflush_all(); } if (ifs == NULL) ifs = defifs; if (nchars || (read_flags & BUILTIN_READ_SILENT)) { tcgetattr(fd, &tty); old_tty = tty; if (nchars) { tty.c_lflag &= ~ICANON; tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; } if (read_flags & BUILTIN_READ_SILENT) { tty.c_lflag &= ~(ECHO | ECHOK | ECHONL); } /* This forces execution of "restoring" tcgetattr later */ read_flags |= BUILTIN_READ_SILENT; /* if tcgetattr failed, tcsetattr will fail too. * Ignoring, it's harmless. */ tcsetattr(fd, TCSANOW, &tty); } retval = (const char *)(uintptr_t)0; startword = 1; backslash = 0; if (end_ms) /* NB: end_ms stays nonzero: */ end_ms = ((unsigned)monotonic_ms() + end_ms) | 1; buffer = NULL; bufpos = 0; do { char c; if (end_ms) { int timeout; struct pollfd pfd[1]; pfd[0].fd = fd; pfd[0].events = POLLIN; timeout = end_ms - (unsigned)monotonic_ms(); if (timeout <= 0 /* already late? */ || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */ ) { /* timed out! */ retval = (const char *)(uintptr_t)1; goto ret; } } if ((bufpos & 0xff) == 0) buffer = xrealloc(buffer, bufpos + 0x100); if (nonblock_safe_read(fd, &buffer[bufpos], 1) != 1) { retval = (const char *)(uintptr_t)1; break; } c = buffer[bufpos]; if (c == '\0') continue; if (backslash) { backslash = 0; if (c != '\n') goto put; continue; } if (!(read_flags & BUILTIN_READ_RAW) && c == '\\') { backslash = 1; continue; } if (c == '\n') break; /* $IFS splitting. NOT done if we run "read" * without variable names (bash compat). * Thus, "read" and "read REPLY" are not the same. */ if (argv[0]) { /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ const char *is_ifs = strchr(ifs, c); if (startword && is_ifs) { if (isspace(c)) continue; /* it is a non-space ifs char */ startword--; if (startword == 1) /* first one? */ continue; /* yes, it is not next word yet */ } startword = 0; if (argv[1] != NULL && is_ifs) { buffer[bufpos] = '\0'; bufpos = 0; setvar(*argv, buffer); argv++; /* can we skip one non-space ifs char? (2: yes) */ startword = isspace(c) ? 2 : 1; continue; } } put: bufpos++; } while (--nchars); if (argv[0]) { /* Remove trailing space $IFS chars */ while (--bufpos >= 0 && isspace(buffer[bufpos]) && strchr(ifs, buffer[bufpos]) != NULL) continue; buffer[bufpos + 1] = '\0'; /* Use the remainder as a value for the next variable */ setvar(*argv, buffer); /* Set the rest to "" */ while (*++argv) setvar(*argv, ""); } else { /* Note: no $IFS removal */ buffer[bufpos] = '\0'; setvar("REPLY", buffer); } ret: free(buffer); if (read_flags & BUILTIN_READ_SILENT) tcsetattr(fd, TCSANOW, &old_tty); return retval; }
int more_main(int argc UNUSED_PARAM, char **argv) { int c = c; /* for compiler */ int lines; int input = 0; int spaces = 0; int please_display_more_prompt; struct stat st; FILE *file; FILE *cin; int len; unsigned terminal_width; unsigned terminal_height; INIT_G(); argv++; /* Another popular pager, most, detects when stdout * is not a tty and turns into cat. This makes sense. */ if (!isatty(STDOUT_FILENO)) return bb_cat(argv); cin = fopen_for_read(CURRENT_TTY); if (!cin) return bb_cat(argv); if (ENABLE_FEATURE_USE_TERMIOS) { cin_fileno = fileno(cin); getTermSettings(cin_fileno, &initial_settings); new_settings = initial_settings; new_settings.c_lflag &= ~(ICANON | ECHO); new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; setTermSettings(cin_fileno, &new_settings); bb_signals(0 + (1 << SIGINT) + (1 << SIGQUIT) + (1 << SIGTERM) , gotsig); } do { file = stdin; if (*argv) { file = fopen_or_warn(*argv, "r"); if (!file) continue; } st.st_size = 0; fstat(fileno(file), &st); please_display_more_prompt = 0; /* never returns w, h <= 1 */ get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height); terminal_height -= 1; len = 0; lines = 0; while (spaces || (c = getc(file)) != EOF) { int wrap; if (spaces) spaces--; loop_top: if (input != 'r' && please_display_more_prompt) { len = printf("--More-- "); if (st.st_size != 0) { uoff_t d = (uoff_t)st.st_size / 100; if (d == 0) d = 1; len += printf("(%u%% of %"OFF_FMT"u bytes)", (int) ((uoff_t)ftello(file) / d), st.st_size); } fflush_all(); /* * We've just displayed the "--More--" prompt, so now we need * to get input from the user. */ for (;;) { input = getc(cin); input = tolower(input); if (!ENABLE_FEATURE_USE_TERMIOS) printf("\033[A"); /* cursor up */ /* Erase the last message */ printf("\r%*s\r", len, ""); /* Due to various multibyte escape * sequences, it's not ok to accept * any input as a command to scroll * the screen. We only allow known * commands, else we show help msg. */ if (input == ' ' || input == '\n' || input == 'q' || input == 'r') break; len = printf("(Enter:next line Space:next page Q:quit R:show the rest)"); } len = 0; lines = 0; please_display_more_prompt = 0; if (input == 'q') goto end; /* The user may have resized the terminal. * Re-read the dimensions. */ if (ENABLE_FEATURE_USE_TERMIOS) { get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height); terminal_height -= 1; } } /* Crudely convert tabs into spaces, which are * a bajillion times easier to deal with. */ if (c == '\t') { spaces = ((unsigned)~len) % CONVERTED_TAB_SIZE; c = ' '; } /* * There are two input streams to worry about here: * * c : the character we are reading from the file being "mored" * input: a character received from the keyboard * * If we hit a newline in the _file_ stream, we want to test and * see if any characters have been hit in the _input_ stream. This * allows the user to quit while in the middle of a file. */ wrap = (++len > terminal_width); if (c == '\n' || wrap) { /* Then outputting this character * will move us to a new line. */ if (++lines >= terminal_height || input == '\n') please_display_more_prompt = 1; len = 0; } if (c != '\n' && wrap) { /* Then outputting this will also put a character on * the beginning of that new line. Thus we first want to * display the prompt (if any), so we skip the putchar() * and go back to the top of the loop, without reading * a new character. */ putchar('\n'); goto loop_top; } /* My small mind cannot fathom backspaces and UTF-8 */ putchar(c); die_if_ferror_stdout(); /* if tty was destroyed (closed xterm, etc) */ } fclose(file); fflush_all(); } while (*argv && *++argv); end: setTermSettings(cin_fileno, &initial_settings); return 0; }