📄 utils.c
字号:
}/* Free the pointers in a NULL-terminated vector of pointers, then free the pointer itself. */voidfree_vec (char **vec){ if (vec) { char **p = vec; while (*p) xfree (*p++); xfree (vec); }}/* Append vector V2 to vector V1. The function frees V2 and reallocates V1 (thus you may not use the contents of neither pointer after the call). If V1 is NULL, V2 is returned. */char **merge_vecs (char **v1, char **v2){ int i, j; if (!v1) return v2; if (!v2) return v1; if (!*v2) { /* To avoid j == 0 */ xfree (v2); return v1; } /* Count v1. */ for (i = 0; v1[i]; i++); /* Count v2. */ for (j = 0; v2[j]; j++); /* Reallocate v1. */ v1 = (char **)xrealloc (v1, (i + j + 1) * sizeof (char **)); memcpy (v1 + i, v2, (j + 1) * sizeof (char *)); xfree (v2); return v1;}/* Append a freshly allocated copy of STR to VEC. If VEC is NULL, it is allocated as needed. Return the new value of the vector. */char **vec_append (char **vec, const char *str){ int cnt; /* count of vector elements, including the one we're about to append */ if (vec != NULL) { for (cnt = 0; vec[cnt]; cnt++) ; ++cnt; } else cnt = 1; /* Reallocate the array to fit the new element and the NULL. */ vec = xrealloc (vec, (cnt + 1) * sizeof (char *)); /* Append a copy of STR to the vector. */ vec[cnt - 1] = xstrdup (str); vec[cnt] = NULL; return vec;}/* Sometimes it's useful to create "sets" of strings, i.e. special hash tables where you want to store strings as keys and merely query for their existence. Here is a set of utility routines that makes that transparent. */voidstring_set_add (struct hash_table *ht, const char *s){ /* First check whether the set element already exists. If it does, do nothing so that we don't have to free() the old element and then strdup() a new one. */ if (hash_table_contains (ht, s)) return; /* We use "1" as value. It provides us a useful and clear arbitrary value, and it consumes no memory -- the pointers to the same string "1" will be shared by all the key-value pairs in all `set' hash tables. */ hash_table_put (ht, xstrdup (s), "1");}/* Synonym for hash_table_contains... */intstring_set_contains (struct hash_table *ht, const char *s){ return hash_table_contains (ht, s);}static intstring_set_to_array_mapper (void *key, void *value_ignored, void *arg){ char ***arrayptr = (char ***) arg; *(*arrayptr)++ = (char *) key; return 0;}/* Convert the specified string set to array. ARRAY should be large enough to hold hash_table_count(ht) char pointers. */void string_set_to_array (struct hash_table *ht, char **array){ hash_table_map (ht, string_set_to_array_mapper, &array);}static intstring_set_free_mapper (void *key, void *value_ignored, void *arg_ignored){ xfree (key); return 0;}voidstring_set_free (struct hash_table *ht){ hash_table_map (ht, string_set_free_mapper, NULL); hash_table_destroy (ht);}static intfree_keys_and_values_mapper (void *key, void *value, void *arg_ignored){ xfree (key); xfree (value); return 0;}/* Another utility function: call free() on all keys and values of HT. */voidfree_keys_and_values (struct hash_table *ht){ hash_table_map (ht, free_keys_and_values_mapper, NULL);}static voidget_grouping_data (const char **sep, const char **grouping){ static const char *cached_sep; static const char *cached_grouping; static int initialized; if (!initialized) { /* If locale.h is present and defines LC_NUMERIC, assume C89 struct lconv with "thousand_sep" and "grouping" members. */#ifdef LC_NUMERIC /* Get the grouping info from the locale. */ struct lconv *lconv; const char *oldlocale = setlocale (LC_NUMERIC, NULL); /* Temporarily switch to the current locale */ setlocale (LC_NUMERIC, ""); lconv = localeconv (); cached_sep = xstrdup (lconv->thousands_sep); cached_grouping = xstrdup (lconv->grouping); /* Restore the locale to previous setting. */ setlocale (LC_NUMERIC, oldlocale); if (!*cached_sep)#endif /* Force separator for locales that specify no separators ("C", "hr", and probably many more.) */ cached_sep = ",", cached_grouping = "\x03"; initialized = 1; } *sep = cached_sep; *grouping = cached_grouping;}/* Add thousand separators to a number already in string form. Used by with_thousand_seps and with_thousand_seps_sum. */char *add_thousand_seps (const char *repr){ static char outbuf[48]; char *p = outbuf + sizeof outbuf; const char *in = strchr (repr, '\0'); const char *instart = repr + (*repr == '-'); /* don't group sign */ /* Info received from locale */ const char *grouping, *sep; int seplen; /* State information */ int i = 0, groupsize; const char *atgroup; /* Initialize grouping data. */ get_grouping_data (&sep, &grouping); seplen = strlen (sep); atgroup = grouping; groupsize = *atgroup++; /* Write the number into the buffer, backwards, inserting the separators as necessary. */ *--p = '\0'; while (1) { *--p = *--in; if (in == instart) break; /* Prepend SEP to every groupsize'd digit and get new groupsize. */ if (++i == groupsize) { if (seplen == 1) *--p = *sep; else memcpy (p -= seplen, sep, seplen); i = 0; if (*atgroup) groupsize = *atgroup++; } } if (*repr == '-') *--p = '-'; return p;}/* Return a printed representation of N with thousand separators. This should respect locale settings, with the exception of the "C" locale which mandates no separator, but we use one anyway. Unfortunately, we cannot use %'d (in fact it would be %'j) to get the separators because it's too non-portable, and it's hard to test for this feature at configure time. Besides, it wouldn't work in the "C" locale, which many Unix users still work in. */char *with_thousand_seps (wgint l){ char inbuf[24]; /* Print the number into the buffer. */ number_to_string (inbuf, l); return add_thousand_seps (inbuf);}/* When SUM_SIZE_INT is wgint, with_thousand_seps_large is #defined to with_thousand_seps. The function below is used on non-LFS systems where SUM_SIZE_INT typedeffed to double. */#ifndef with_thousand_seps_sumchar *with_thousand_seps_sum (SUM_SIZE_INT l){ char inbuf[32]; snprintf (inbuf, sizeof (inbuf), "%.0f", l); return add_thousand_seps (inbuf);}#endif /* not with_thousand_seps_sum *//* 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 science meaning of "powers of 1024". Powers of 1000 would be useless since Wget already displays sizes with thousand separators. We don't use the "*bibyte" names invented in 1998, and seldom used in practice. Wikipedia's entry on kilobyte discusses this in some detail. */char *human_readable (wgint 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 >> 10) < 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 >>= 10; } 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)/* SPRINTF_WGINT is used by number_to_string to handle pathological cases and to portably support strange sizes of wgint. Ideally this would just use "%j" and intmax_t, but many systems don't support it, so it's used only if nothing else works. */#if SIZEOF_LONG >= SIZEOF_WGINT# define SPRINTF_WGINT(buf, n) sprintf (buf, "%ld", (long) (n))#else# if SIZEOF_LONG_LONG >= SIZEOF_WGINT# define SPRINTF_WGINT(buf, n) sprintf (buf, "%lld", (long long) (n))# else# ifdef WINDOWS# define SPRINTF_WGINT(buf, n) sprintf (buf, "%I64d", (__int64) (n))# else# define SPRINTF_WGINT(buf, n) sprintf (buf, "%j", (intmax_t) (n))# endif# endif#endif/* 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 GNU libc, have been known to be extremely 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 big enough to accept as many bytes as you expect the number to take up. On machines with 64-bit longs 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;#if (SIZEOF_WGINT != 4) && (SIZEOF_WGINT != 8) /* We are running in a strange or misconfigured environment. Let sprintf cope with it. */ SPRINTF_WGINT (buffer, n); p += strlen (buffer);#else /* (SIZEOF_WGINT == 4) || (SIZEOF_WGINT == 8) */ if (n < 0) { if (n < -WGINT_MAX) { /* -n would overflow. Have sprintf deal with this. */ SPRINTF_WGINT (buffer, n); p += strlen (buffer); return p; } *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 more than 9 decimal digits. Constants are constructed by compile-time multiplication to avoid dealing with different notations for 64-bit constants (nnnL, nnnLL, and nnnI64, depending on the compiler). */ 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 *p = '\0';#endif /* (SIZEOF_WGINT == 4) || (SIZEOF_WGINT == 8) */ return p;}#undef PR#undef W#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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -