+/* NEGATIVE is nonzero if VALUE was negative before being cast to
+ uintmax_t; its original bitpattern can be deduced from VALSIZE, its
+ original size before casting. Convert VALUE to external form,
+ using SUBSTITUTE (...) if VALUE won't fit. Output to buffer WHERE
+ with size SIZE. TYPE is the kind of value being output (useful for
+ diagnostics). Prefer the POSIX format of SIZE - 1 octal digits
+ (with leading zero digits), followed by '\0'. If this won't work,
+ and if GNU format is allowed, use '+' or '-' followed by SIZE - 1
+ base-64 digits. If neither format works, use SUBSTITUTE (...)
+ instead. Pass to SUBSTITUTE the address of an 0-or-1 flag
+ recording whether the substitute value is negative. */
+
+static void
+to_chars (int negative, uintmax_t value, size_t valsize,
+ uintmax_t (*substitute) PARAMS ((int *)),
+ char *where, size_t size, const char *type)
+{
+ uintmax_t v = negative ? -value : value;
+
+ if (! negative && v <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
+ {
+ where[size - 1] = '\0';
+ to_base (v, LG_8, base_8_digits, where, size - 1);
+ }
+ else if (v <= MAX_VAL_WITH_DIGITS (size - 1, LG_64)
+ && archive_format == GNU_FORMAT)
+ {
+ where[0] = negative ? '-' : '+';
+ to_base (v, LG_64, base_64_digits, where + 1, size - 1);
+ }
+ else if (negative
+ && archive_format != GNU_FORMAT
+ && valsize * CHAR_BIT <= (size - 1) * LG_8)
+ {
+ where[size - 1] = '\0';
+ to_base (value & MAX_VAL_WITH_DIGITS (valsize * CHAR_BIT, 1),
+ LG_8, base_8_digits, where, size - 1);
+ }
+ else
+ {
+ uintmax_t maxval = (archive_format == GNU_FORMAT
+ ? MAX_VAL_WITH_DIGITS (size - 1, LG_64)
+ : MAX_VAL_WITH_DIGITS (size - 1, LG_8));
+ char buf1[UINTMAX_STRSIZE_BOUND + 1];
+ char buf2[UINTMAX_STRSIZE_BOUND + 1];
+ char buf3[UINTMAX_STRSIZE_BOUND + 1];
+ char *value_string = STRINGIFY_BIGINT (v, buf1 + 1);
+ char *maxval_string = STRINGIFY_BIGINT (maxval, buf2 + 1);
+ char const *minval_string =
+ (archive_format == GNU_FORMAT
+ ? "0"
+ : (maxval_string[-1] = '-', maxval_string - 1));
+ if (negative)
+ *--value_string = '-';
+ if (substitute)
+ {
+ int negsub;
+ uintmax_t sub = substitute (&negsub) & maxval;
+ uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? -sub : sub;
+ char *sub_string = STRINGIFY_BIGINT (s, buf3 + 1);
+ if (negsub)
+ *--sub_string = '-';
+ WARN ((0, 0, _("%s value %s out of range %s..%s; substituting %s"),
+ type, value_string, minval_string, maxval_string,
+ sub_string));
+ to_chars (negsub, s, valsize, NULL, where, size, type);
+ }
+ else
+ ERROR ((0, 0, _("%s value %s out of range %s..%s"),
+ type, value_string, minval_string, maxval_string));
+ }
+}
+
+static uintmax_t
+gid_substitute (int *negative)
+{
+ gid_t r;
+#ifdef GID_NOBODY
+ r = GID_NOBODY;
+#else
+ static gid_t gid_nobody;
+ if (!gid_nobody && !gname_to_gid ("nobody", &gid_nobody))
+ gid_nobody = -2;
+ r = gid_nobody;
+#endif
+ *negative = r < 0;
+ return r;
+}