X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=libbb%2Fxfuncs.c;h=8ef305ba08e2b1d4301ae92941bb29b23f2f6807;hb=96c45b0e0bda5bf47c03682c8fcbeae7ade89386;hp=8784b5058a2da686c425cc6d594a8f127b35c644;hpb=cb81e6484d1f50ec2761f6294722407b14add525;p=oweals%2Fbusybox.git diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 8784b5058..8ef305ba0 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -2,195 +2,290 @@ /* * Utility routines. * - * Copyright (C) 1999-2003 by Erik Andersen + * Copyright (C) 1999-2004 by Erik Andersen + * Copyright (C) 2006 Rob Landley + * Copyright (C) 2006 Denys Vlasenko * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Licensed under GPL version 2, see file LICENSE in this tarball for details. + */ + +/* We need to have separate xfuncs.c and xfuncs_printf.c because + * with current linkers, even with section garbage collection, + * if *.o module references any of XXXprintf functions, you pull in + * entire printf machinery. Even if you do not use the function + * which uses XXXprintf. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * xfuncs.c contains functions (not necessarily xfuncs) + * which do not pull in printf, directly or indirectly. + * xfunc_printf.c contains those which do. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * TODO: move xmalloc() and xatonum() here. */ -#include -#include -#include -#include -#include -#include -#include #include "libbb.h" - -#ifndef DMALLOC -#ifdef L_xmalloc -extern void *xmalloc(size_t size) +/* Turn on nonblocking I/O on a fd */ +int FAST_FUNC ndelay_on(int fd) { - void *ptr = malloc(size); - if (ptr == NULL && size != 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); - return ptr; + return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK); } -#endif -#ifdef L_xrealloc -extern void *xrealloc(void *ptr, size_t size) +int FAST_FUNC ndelay_off(int fd) { - ptr = realloc(ptr, size); - if (ptr == NULL && size != 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); - return ptr; + return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK); } -#endif -#ifdef L_xcalloc -extern void *xcalloc(size_t nmemb, size_t size) +int FAST_FUNC close_on_exec_on(int fd) { - void *ptr = calloc(nmemb, size); - if (ptr == NULL && nmemb != 0 && size != 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); - return ptr; + return fcntl(fd, F_SETFD, FD_CLOEXEC); } -#endif -#endif /* DMALLOC */ - -#ifdef L_xstrdup -extern char * bb_xstrdup (const char *s) { - char *t; - - if (s == NULL) - return NULL; - t = strdup (s); +/* Convert unsigned long long value into compact 4-char + * representation. Examples: "1234", "1.2k", " 27M", "123T" + * String is not terminated (buf[4] is untouched) */ +void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) +{ + const char *fmt; + char c; + unsigned v, u, idx = 0; - if (t == NULL) - bb_error_msg_and_die(bb_msg_memory_exhausted); + if (ul > 9999) { // do not scale if 9999 or less + ul *= 10; + do { + ul /= 1024; + idx++; + } while (ul >= 10000); + } + v = ul; // ullong divisions are expensive, avoid them - return t; + fmt = " 123456789"; + u = v / 10; + v = v % 10; + if (!idx) { + // 9999 or less: use "1234" format + // u is value/10, v is last digit + c = buf[0] = " 123456789"[u/100]; + if (c != ' ') fmt = "0123456789"; + c = buf[1] = fmt[u/10%10]; + if (c != ' ') fmt = "0123456789"; + buf[2] = fmt[u%10]; + buf[3] = "0123456789"[v]; + } else { + // u is value, v is 1/10ths (allows for 9.2M format) + if (u >= 10) { + // value is >= 10: use "123M', " 12M" formats + c = buf[0] = " 123456789"[u/100]; + if (c != ' ') fmt = "0123456789"; + v = u % 10; + u = u / 10; + buf[1] = fmt[u%10]; + } else { + // value is < 10: use "9.2M" format + buf[0] = "0123456789"[u]; + buf[1] = '.'; + } + buf[2] = "0123456789"[v]; + buf[3] = scale[idx]; /* typically scale = " kmgt..." */ + } } -#endif -#ifdef L_xstrndup -extern char * bb_xstrndup (const char *s, int n) { - char *t; +/* Convert unsigned long long value into compact 5-char representation. + * String is not terminated (buf[5] is untouched) */ +void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) +{ + const char *fmt; + char c; + unsigned v, u, idx = 0; - if (s == NULL) - bb_error_msg_and_die("bb_xstrndup bug"); + if (ul > 99999) { // do not scale if 99999 or less + ul *= 10; + do { + ul /= 1024; + idx++; + } while (ul >= 100000); + } + v = ul; // ullong divisions are expensive, avoid them - t = xmalloc(++n); - - return safe_strncpy(t,s,n); + fmt = " 123456789"; + u = v / 10; + v = v % 10; + if (!idx) { + // 99999 or less: use "12345" format + // u is value/10, v is last digit + c = buf[0] = " 123456789"[u/1000]; + if (c != ' ') fmt = "0123456789"; + c = buf[1] = fmt[u/100%10]; + if (c != ' ') fmt = "0123456789"; + c = buf[2] = fmt[u/10%10]; + if (c != ' ') fmt = "0123456789"; + buf[3] = fmt[u%10]; + buf[4] = "0123456789"[v]; + } else { + // value has been scaled into 0..9999.9 range + // u is value, v is 1/10ths (allows for 92.1M format) + if (u >= 100) { + // value is >= 100: use "1234M', " 123M" formats + c = buf[0] = " 123456789"[u/1000]; + if (c != ' ') fmt = "0123456789"; + c = buf[1] = fmt[u/100%10]; + if (c != ' ') fmt = "0123456789"; + v = u % 10; + u = u / 10; + buf[2] = fmt[u%10]; + } else { + // value is < 100: use "92.1M" format + c = buf[0] = " 123456789"[u/10]; + if (c != ' ') fmt = "0123456789"; + buf[1] = fmt[u%10]; + buf[2] = '.'; + } + buf[3] = "0123456789"[v]; + buf[4] = scale[idx]; /* typically scale = " kmgt..." */ + } } -#endif -#ifdef L_xfopen -FILE *bb_xfopen(const char *path, const char *mode) -{ - FILE *fp; - if ((fp = fopen(path, mode)) == NULL) - bb_perror_msg_and_die("%s", path); - return fp; -} -#endif -#ifdef L_xopen -extern int bb_xopen(const char *pathname, int flags) +// Convert unsigned integer to ascii, writing into supplied buffer. +// A truncated result contains the first few digits of the result ala strncpy. +// Returns a pointer past last generated digit, does _not_ store NUL. +void BUG_sizeof_unsigned_not_4(void); +char* FAST_FUNC utoa_to_buf(unsigned n, char *buf, unsigned buflen) { - int ret; - - ret = open(pathname, flags, 0777); - if (ret == -1) { - bb_perror_msg_and_die("%s", pathname); + unsigned i, out, res; + if (sizeof(unsigned) != 4) + BUG_sizeof_unsigned_not_4(); + if (buflen) { + out = 0; + for (i = 1000000000; i; i /= 10) { + res = n / i; + if (res || out || i == 1) { + if (!--buflen) break; + out++; + n -= res*i; + *buf++ = '0' + res; + } + } } - return ret; + return buf; } -#endif -#ifdef L_xread -extern ssize_t bb_xread(int fd, void *buf, size_t count) +/* Convert signed integer to ascii, like utoa_to_buf() */ +char* FAST_FUNC itoa_to_buf(int n, char *buf, unsigned buflen) { - ssize_t size; - - size = read(fd, buf, count); - if (size == -1) { - bb_perror_msg_and_die("Read error"); + if (buflen && n < 0) { + n = -n; + *buf++ = '-'; + buflen--; } - return(size); + return utoa_to_buf((unsigned)n, buf, buflen); } -#endif -#ifdef L_xread_all -extern void bb_xread_all(int fd, void *buf, size_t count) +// The following two functions use a static buffer, so calling either one a +// second time will overwrite previous results. +// +// The largest 32 bit integer is -2 billion plus null terminator, or 12 bytes. +// It so happens that sizeof(int) * 3 is enough for 32+ bits. +// (sizeof(int) * 3 + 2 is correct for any width, even 8-bit) + +static char local_buf[sizeof(int) * 3]; + +// Convert unsigned integer to ascii using a static buffer (returned). +char* FAST_FUNC utoa(unsigned n) { - ssize_t size; + *(utoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; - while (count) { - if ((size = bb_xread(fd, buf, count)) == 0) { /* EOF */ - bb_error_msg_and_die("Short read"); - } - count -= size; - } - return; + return local_buf; } -#endif -#ifdef L_xread_char -extern unsigned char bb_xread_char(int fd) +/* Convert signed integer to ascii using a static buffer (returned). */ +char* FAST_FUNC itoa(int n) { - char tmp; - - bb_xread_all(fd, &tmp, 1); + *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0'; - return(tmp); + return local_buf; } -#endif -#ifdef L_xferror -extern void bb_xferror(FILE *fp, const char *fn) +/* Emit a string of hex representation of bytes */ +char* FAST_FUNC bin2hex(char *p, const char *cp, int count) { - if (ferror(fp)) { - bb_error_msg_and_die("%s", fn); + while (count) { + unsigned char c = *cp++; + /* put lowercase hex digits */ + *p++ = 0x20 | bb_hexdigits_upcase[c >> 4]; + *p++ = 0x20 | bb_hexdigits_upcase[c & 0xf]; + count--; } + return p; } -#endif -#ifdef L_xferror_stdout -extern void bb_xferror_stdout(void) +/* Return how long the file at fd is, if there's any way to determine it. */ +#ifdef UNUSED +off_t FAST_FUNC fdlength(int fd) { - bb_xferror(stdout, bb_msg_standard_output); + off_t bottom = 0, top = 0, pos; + long size; + + // If the ioctl works for this, return it. + + if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512; + + // FIXME: explain why lseek(SEEK_END) is not used here! + + // If not, do a binary search for the last location we can read. (Some + // block devices don't do BLKGETSIZE right.) + + do { + char temp; + + pos = bottom + (top - bottom) / 2; + + // If we can read from the current location, it's bigger. + + if (lseek(fd, pos, SEEK_SET)>=0 && safe_read(fd, &temp, 1)==1) { + if (bottom == top) bottom = top = (top+1) * 2; + else bottom = pos; + + // If we can't, it's smaller. + + } else { + if (bottom == top) { + if (!top) return 0; + bottom = top/2; + } + else top = pos; + } + } while (bottom + 1 != top); + + return pos + 1; } #endif -#ifdef L_xfflush_stdout -extern void bb_xfflush_stdout(void) +/* It is perfectly ok to pass in a NULL for either width or for + * height, in which case that value will not be set. */ +int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) { - if (fflush(stdout)) { - bb_perror_msg_and_die(bb_msg_standard_output); + struct winsize win = { 0, 0, 0, 0 }; + int ret = ioctl(fd, TIOCGWINSZ, &win); + + if (height) { + if (!win.ws_row) { + char *s = getenv("LINES"); + if (s) win.ws_row = atoi(s); + } + if (win.ws_row <= 1 || win.ws_row >= 30000) + win.ws_row = 24; + *height = (int) win.ws_row; } -} -#endif -#ifdef L_strlen -/* Stupid gcc always includes its own builtin strlen()... */ -#undef strlen -size_t bb_strlen(const char *string) -{ - return(strlen(string)); -} -#endif + if (width) { + if (!win.ws_col) { + char *s = getenv("COLUMNS"); + if (s) win.ws_col = atoi(s); + } + if (win.ws_col <= 1 || win.ws_col >= 30000) + win.ws_col = 80; + *width = (int) win.ws_col; + } -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ + return ret; +}