📄 utils.c
字号:
return p;}/* N, a byte quantity, is converted to a human-readable abberviated form a la sizes printed by `ls -lh'. The result is written to a static buffer, a pointer to which is returned. Unlike `with_thousand_seps', this approximates to the nearest unit. Quoting GNU libit: "Most people visually process strings of 3-4 digits effectively, but longer strings of digits are more prone to misinterpretation. Hence, converting to an abbreviated form usually improves readability." This intentionally uses kilobyte (KB), megabyte (MB), etc. in their original computer-related meaning of "powers of 1024". We don't use the "*bibyte" names invented in 1998, and seldom used in practice. Wikipedia's entry on "binary prefix" discusses this in some detail. */char *human_readable (HR_NUMTYPE n){ /* These suffixes are compatible with those of GNU `ls -lh'. */ static char powers[] = { 'K', /* kilobyte, 2^10 bytes */ 'M', /* megabyte, 2^20 bytes */ 'G', /* gigabyte, 2^30 bytes */ 'T', /* terabyte, 2^40 bytes */ 'P', /* petabyte, 2^50 bytes */ 'E', /* exabyte, 2^60 bytes */ }; static char buf[8]; int i; /* If the quantity is smaller than 1K, just print it. */ if (n < 1024) { snprintf (buf, sizeof (buf), "%d", (int) n); return buf; } /* Loop over powers, dividing N with 1024 in each iteration. This works unchanged for all sizes of wgint, while still avoiding non-portable `long double' arithmetic. */ for (i = 0; i < countof (powers); i++) { /* At each iteration N is greater than the *subsequent* power. That way N/1024.0 produces a decimal number in the units of *this* power. */ if ((n / 1024) < 1024 || i == countof (powers) - 1) { double val = n / 1024.0; /* Print values smaller than 10 with one decimal digits, and others without any decimals. */ snprintf (buf, sizeof (buf), "%.*f%c", val < 10 ? 1 : 0, val, powers[i]); return buf; } n /= 1024; } return NULL; /* unreached */}/* Count the digits in the provided number. Used to allocate space when printing numbers. */intnumdigit (wgint number){ int cnt = 1; if (number < 0) ++cnt; /* accomodate '-' */ while ((number /= 10) != 0) ++cnt; return cnt;}#define PR(mask) *p++ = n / (mask) + '0'/* DIGITS_<D> is used to print a D-digit number and should be called with mask==10^(D-1). It prints n/mask (the first digit), reducing n to n%mask (the remaining digits), and calling DIGITS_<D-1>. Recursively this continues until DIGITS_1 is invoked. */#define DIGITS_1(mask) PR (mask)#define DIGITS_2(mask) PR (mask), n %= (mask), DIGITS_1 ((mask) / 10)#define DIGITS_3(mask) PR (mask), n %= (mask), DIGITS_2 ((mask) / 10)#define DIGITS_4(mask) PR (mask), n %= (mask), DIGITS_3 ((mask) / 10)#define DIGITS_5(mask) PR (mask), n %= (mask), DIGITS_4 ((mask) / 10)#define DIGITS_6(mask) PR (mask), n %= (mask), DIGITS_5 ((mask) / 10)#define DIGITS_7(mask) PR (mask), n %= (mask), DIGITS_6 ((mask) / 10)#define DIGITS_8(mask) PR (mask), n %= (mask), DIGITS_7 ((mask) / 10)#define DIGITS_9(mask) PR (mask), n %= (mask), DIGITS_8 ((mask) / 10)#define DIGITS_10(mask) PR (mask), n %= (mask), DIGITS_9 ((mask) / 10)/* DIGITS_<11-20> are only used on machines with 64-bit wgints. */#define DIGITS_11(mask) PR (mask), n %= (mask), DIGITS_10 ((mask) / 10)#define DIGITS_12(mask) PR (mask), n %= (mask), DIGITS_11 ((mask) / 10)#define DIGITS_13(mask) PR (mask), n %= (mask), DIGITS_12 ((mask) / 10)#define DIGITS_14(mask) PR (mask), n %= (mask), DIGITS_13 ((mask) / 10)#define DIGITS_15(mask) PR (mask), n %= (mask), DIGITS_14 ((mask) / 10)#define DIGITS_16(mask) PR (mask), n %= (mask), DIGITS_15 ((mask) / 10)#define DIGITS_17(mask) PR (mask), n %= (mask), DIGITS_16 ((mask) / 10)#define DIGITS_18(mask) PR (mask), n %= (mask), DIGITS_17 ((mask) / 10)#define DIGITS_19(mask) PR (mask), n %= (mask), DIGITS_18 ((mask) / 10)/* Shorthand for casting to wgint. */#define W wgint/* Print NUMBER to BUFFER in base 10. This is equivalent to `sprintf(buffer, "%lld", (long long) number)', only typically much faster and portable to machines without long long. The speedup may make a difference in programs that frequently convert numbers to strings. Some implementations of sprintf, particularly the one in some versions of GNU libc, have been known to be quite slow when converting integers to strings. Return the pointer to the location where the terminating zero was printed. (Equivalent to calling buffer+strlen(buffer) after the function is done.) BUFFER should be large enough to accept as many bytes as you expect the number to take up. On machines with 64-bit wgints the maximum needed size is 24 bytes. That includes the digits needed for the largest 64-bit number, the `-' sign in case it's negative, and the terminating '\0'. */char *number_to_string (char *buffer, wgint number){ char *p = buffer; wgint n = number; int last_digit_char = 0;#if (SIZEOF_WGINT != 4) && (SIZEOF_WGINT != 8) /* We are running in a very strange environment. Leave the correct printing to sprintf. */ p += sprintf (buf, "%j", (intmax_t) (n));#else /* (SIZEOF_WGINT == 4) || (SIZEOF_WGINT == 8) */ if (n < 0) { if (n < -WGINT_MAX) { /* n = -n would overflow because -n would evaluate to a wgint value larger than WGINT_MAX. Need to make n smaller and handle the last digit separately. */ int last_digit = n % 10; /* The sign of n%10 is implementation-defined. */ if (last_digit < 0) last_digit_char = '0' - last_digit; else last_digit_char = '0' + last_digit; /* After n is made smaller, -n will not overflow. */ n /= 10; } *p++ = '-'; n = -n; } /* Use the DIGITS_ macro appropriate for N's number of digits. That way printing any N is fully open-coded without a loop or jump. (Also see description of DIGITS_*.) */ if (n < 10) DIGITS_1 (1); else if (n < 100) DIGITS_2 (10); else if (n < 1000) DIGITS_3 (100); else if (n < 10000) DIGITS_4 (1000); else if (n < 100000) DIGITS_5 (10000); else if (n < 1000000) DIGITS_6 (100000); else if (n < 10000000) DIGITS_7 (1000000); else if (n < 100000000) DIGITS_8 (10000000); else if (n < 1000000000) DIGITS_9 (100000000);#if SIZEOF_WGINT == 4 /* wgint is 32 bits wide: no number has more than 10 digits. */ else DIGITS_10 (1000000000);#else /* wgint is 64 bits wide: handle numbers with 9-19 decimal digits. Constants are constructed by compile-time multiplication to avoid dealing with different notations for 64-bit constants (nL/nLL/nI64, depending on the compiler and architecture). */ else if (n < 10*(W)1000000000) DIGITS_10 (1000000000); else if (n < 100*(W)1000000000) DIGITS_11 (10*(W)1000000000); else if (n < 1000*(W)1000000000) DIGITS_12 (100*(W)1000000000); else if (n < 10000*(W)1000000000) DIGITS_13 (1000*(W)1000000000); else if (n < 100000*(W)1000000000) DIGITS_14 (10000*(W)1000000000); else if (n < 1000000*(W)1000000000) DIGITS_15 (100000*(W)1000000000); else if (n < 10000000*(W)1000000000) DIGITS_16 (1000000*(W)1000000000); else if (n < 100000000*(W)1000000000) DIGITS_17 (10000000*(W)1000000000); else if (n < 1000000000*(W)1000000000) DIGITS_18 (100000000*(W)1000000000); else DIGITS_19 (1000000000*(W)1000000000);#endif if (last_digit_char) *p++ = last_digit_char; *p = '\0';#endif /* (SIZEOF_WGINT == 4) || (SIZEOF_WGINT == 8) */ return p;}#undef PR#undef W#undef SPRINTF_WGINT#undef DIGITS_1#undef DIGITS_2#undef DIGITS_3#undef DIGITS_4#undef DIGITS_5#undef DIGITS_6#undef DIGITS_7#undef DIGITS_8#undef DIGITS_9#undef DIGITS_10#undef DIGITS_11#undef DIGITS_12#undef DIGITS_13#undef DIGITS_14#undef DIGITS_15#undef DIGITS_16#undef DIGITS_17#undef DIGITS_18#undef DIGITS_19#define RING_SIZE 3/* Print NUMBER to a statically allocated string and return a pointer to the printed representation. This function is intended to be used in conjunction with printf. It is hard to portably print wgint values: a) you cannot use printf("%ld", number) because wgint can be long long on 32-bit machines with LFS. b) you cannot use printf("%lld", number) because NUMBER could be long on 32-bit machines without LFS, or on 64-bit machines, which do not require LFS. Also, Windows doesn't support %lld. c) you cannot use printf("%j", (int_max_t) number) because not all versions of printf support "%j", the most notable being the one on Windows. d) you cannot #define WGINT_FMT to the appropriate format and use printf(WGINT_FMT, number) because that would break translations for user-visible messages, such as printf("Downloaded: %d bytes\n", number). What you should use instead is printf("%s", number_to_static_string (number)). CAVEAT: since the function returns pointers to static data, you must be careful to copy its result before calling it again. However, to make it more useful with printf, the function maintains an internal ring of static buffers to return. That way things like printf("%s %s", number_to_static_string (num1), number_to_static_string (num2)) work as expected. Three buffers are currently used, which means that "%s %s %s" will work, but "%s %s %s %s" won't. If you need to print more than three wgints, bump the RING_SIZE (or rethink your message.) */char *number_to_static_string (wgint number){ static char ring[RING_SIZE][24]; static int ringpos; char *buf = ring[ringpos]; number_to_string (buf, number); ringpos = (ringpos + 1) % RING_SIZE; return buf;}/* Determine the width of the terminal we're running on. If that's not possible, return 0. */intdetermine_screen_width (void){ /* If there's a way to get the terminal size using POSIX tcgetattr(), somebody please tell me. */#ifdef TIOCGWINSZ int fd; struct winsize wsz; if (opt.lfilename != NULL) return 0; fd = fileno (stderr); if (ioctl (fd, TIOCGWINSZ, &wsz) < 0) return 0; /* most likely ENOTTY */ return wsz.ws_col;#elif defined(WINDOWS) CONSOLE_SCREEN_BUFFER_INFO csbi; if (!GetConsoleScreenBufferInfo (GetStdHandle (STD_ERROR_HANDLE), &csbi)) return 0; return csbi.dwSize.X;#else /* neither TIOCGWINSZ nor WINDOWS */ return 0;#endif /* neither TIOCGWINSZ nor WINDOWS */}/* Whether the rnd system (either rand or [dl]rand48) has been seeded. */static int rnd_seeded;/* Return a random number between 0 and MAX-1, inclusive. If the system does not support lrand48 and MAX is greater than the value of RAND_MAX+1 on the system, the returned value will be in the range [0, RAND_MAX]. This may be fixed in a future release. The random number generator is seeded automatically the first time it is called. This uses lrand48 where available, rand elsewhere. DO NOT use it for cryptography. It is only meant to be used in situations where quality of the random numbers returned doesn't really matter. */intrandom_number (int max){#ifdef HAVE_DRAND48 if (!rnd_seeded) { srand48 ((long) time (NULL) ^ (long) getpid ()); rnd_seeded = 1; } return lrand48 () % max;#else /* not HAVE_DRAND48 */ double bounded; int rnd; if (!rnd_seeded) { srand ((unsigned) time (NULL) ^ (unsigned) getpid ()); rnd_seeded = 1; } rnd = rand (); /* Like rand() % max, but uses the high-order bits for better randomness on architectures where rand() is implemented using a simple congruential generator. */ bounded = (double) max * rnd / (RAND_MAX + 1.0); return (int) bounded;#endif /* not HAVE_DRAND48 */}/* Return a random uniformly distributed floating point number in the [0, 1) range. Uses drand48 where available, and a really lame kludge elsewhere. */doublerandom_float (void){#ifdef HAVE_DRAND48 if (!rnd_seeded) { srand48 ((long) time (NULL) ^ (long) getpid ()); rnd_seeded = 1; } return drand48 ();#else /* not HAVE_DRAND48 */ return ( random_number (10000) / 10000.0 + random_number (10000) / (10000.0 * 10000.0) + random_number (10000) / (10000.0 * 10000.0 * 10000.0) + random_number (10000) / (10000.0 * 10000.0 * 10000.0 * 10000.0));#endif /* not HAVE_DRAND48 */}/* Implementation of run_with_timeout, a generic timeout-forcing routine for systems with Unix-like signal handling. */#ifdef USE_SIGNAL_TIMEOUT# ifdef HAVE_SIGSETJMP# define SETJMP(env) sigsetjmp (env, 1)static sigjmp_buf run_with_timeout_env;static voidabort_run_with_timeout (int sig){ assert (sig == SIGALRM); siglongjmp (run_with_timeout_env, -1);}# else /* not HAVE_SIGSETJMP */# define SETJMP(env) setjmp (env)static jmp_buf run_with_timeout_env;static voidabort_run_with_timeout (int sig){ assert (sig == SIGALRM); /* We don't have siglongjmp to preserve the set of blocked signals; if we longjumped out of the handler at this point, SIGALRM would remain blocked. We must unblock it manually. */ int mask = siggetmask (); mask &= ~sigmask (SIGALRM); sigsetmask (mask); /* Now it's safe to longjump. */ longjmp (run_with_timeout_env, -1);}# endif /* not HAVE_SIGSETJMP *//* Arrange for SIGALRM to be delivered in TIMEOUT seconds. This uses setitimer where available, alarm otherwise. TIMEOUT should be non-zero. If the timeout value is so small that it would be rounded to zero, it is rounded to the least legal value instead (1us for setitimer, 1s for alarm). That ensures that SIGALRM will be delivered in all cases. */static voidalarm_set (double timeout){#ifdef ITIMER_REAL /* Use the modern itimer interface. */ struct itimerval itv; xzero (itv); itv.it_value.tv_sec = (long) timeout; itv.it_value.tv_usec = 1000000 * (timeout - (long)timeout); if (itv.it_value.tv_sec == 0 && itv.it_value.tv_usec == 0) /* Ensure that we wait for at least the minimum interval. Specifying zero would mean "wait forever". */ itv.it_value.tv_usec = 1; setitimer (ITIMER_REAL, &itv, NULL);#else /* not ITIMER_REAL */ /* Use the old alarm() interface. */ int secs = (int) timeout; if (secs == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -