#define __xnumtoint xnumtoimax
#define __xdectoint_t intmax_t
#define __xstrtol xstrtoimax
-#define __xdectoint_signed 1
#include "xdectoint.c"
#include <errno.h>
#include <inttypes.h>
-#include <stddef.h>
#include <stdlib.h>
#include <error.h>
#include <xstrtol.h>
/* Parse numeric string N_STR of base BASE, and return the value.
- Exit on parse error or if MIN or MAX are exceeded.
+ The value is between MIN and MAX.
Strings can have multiplicative SUFFIXES if specified.
- ERR is printed along with N_STR on error. */
+ On a parse error or out-of-range number, diagnose with N_STR and ERR, and
+ exit with status ERR_EXIT if nonzero, EXIT_FAILURE otherwise.
+ However, if FLAGS & XTOINT_MIN_QUIET, do not diagnose or exit
+ for too-low numbers; return MIN and set errno instead.
+ Similarly for XTOINT_MAX_QUIET and too-high numbers and MAX.
+ The errno value and diagnostic for out-of-range values depend on
+ whether FLAGS & XTOINT_MIN_RANGE and FLAGS & XTOINT_MAX_RANGE are set. */
__xdectoint_t
__xnumtoint (char const *n_str, int base, __xdectoint_t min, __xdectoint_t max,
- char const *suffixes, char const *err, int err_exit)
+ char const *suffixes, char const *err, int err_exit,
+ int flags)
{
- strtol_error s_err;
+ __xdectoint_t tnum, r;
+ strtol_error s_err = __xstrtol (n_str, nullptr, base, &tnum, suffixes);
- __xdectoint_t tnum;
- s_err = __xstrtol (n_str, nullptr, base, &tnum, suffixes);
+ /* Errno value to report if there is an overflow. */
+ int overflow_errno;
- if (s_err == LONGINT_OK)
+ if (tnum < min)
{
- if (tnum < min || max < tnum)
- {
- s_err = LONGINT_OVERFLOW;
- /* Use have the INT range as a heuristic to distinguish
- type overflow rather than other min/max limits. */
- if (tnum > INT_MAX / 2)
- errno = EOVERFLOW;
-#if __xdectoint_signed
- else if (tnum < INT_MIN / 2)
- errno = EOVERFLOW;
-#endif
- else
- errno = ERANGE;
- }
+ r = min;
+ overflow_errno = flags & XTOINT_MIN_RANGE ? ERANGE : EOVERFLOW;
+ if (s_err == LONGINT_OK)
+ s_err = LONGINT_OVERFLOW;
}
- else if (s_err == LONGINT_OVERFLOW)
- errno = EOVERFLOW;
- else if (s_err == LONGINT_INVALID_SUFFIX_CHAR_WITH_OVERFLOW)
- errno = 0; /* Don't show ERANGE errors for invalid numbers. */
-
- if (s_err != LONGINT_OK)
+ else if (max < tnum)
{
- /* EINVAL error message is redundant in this context. */
- error (err_exit ? err_exit : EXIT_FAILURE, errno == EINVAL ? 0 : errno,
- "%s: %s", err, quote (n_str));
- unreachable ();
+ r = max;
+ overflow_errno = flags & XTOINT_MAX_RANGE ? ERANGE : EOVERFLOW;
+ if (s_err == LONGINT_OK)
+ s_err = LONGINT_OVERFLOW;
}
+ else
+ {
+ r = tnum;
+ overflow_errno = EOVERFLOW;
+ }
+
+ int e = s_err == LONGINT_OVERFLOW ? overflow_errno : 0;
+
+ if (! (s_err == LONGINT_OK
+ || (s_err == LONGINT_OVERFLOW
+ && flags & (tnum < 0 ? XTOINT_MIN_QUIET : XTOINT_MAX_QUIET))))
+ error (err_exit ? err_exit : EXIT_FAILURE, e, "%s: %s", err, quote (n_str));
- return tnum;
+ errno = e;
+ return r;
}
/* Parse decimal string N_STR, and return the value.
__xdectoint (char const *n_str, __xdectoint_t min, __xdectoint_t max,
char const *suffixes, char const *err, int err_exit)
{
- return __xnumtoint (n_str, 10, min, max, suffixes, err, err_exit);
+ return __xnumtoint (n_str, 10, min, max, suffixes, err, err_exit, 0);
}
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef XDECTOINT_H_
-# define XDECTOINT_H_ 1
+#define XDECTOINT_H_ 1
-# include <inttypes.h>
+#include <inttypes.h>
-# define _DECLARE_XDECTOINT(name, type) \
+/* Flags for xnumtoimax and xnumtoumax. They can be ORed togethar. */
+enum
+ {
+ /* If the number is less than MIN, do not diagnose the problem;
+ instead, return MIN and set errno to EOVERFLOW or ERANGE. */
+ XTOINT_MIN_QUIET = 1 << 0,
+
+ /* Likewise for the MAX argument. */
+ XTOINT_MAX_QUIET = 1 << 1,
+
+ /* The MIN argument is imposed by the caller, not by the type of
+ the result. This causes the function to use ERANGE rather
+ than EOVERFLOW behavior when issuing diagnostics or setting errno. */
+ XTOINT_MIN_RANGE = 1 << 2,
+
+ /* Likewise for the MAX argument. */
+ XTOINT_MAX_RANGE = 1 << 3
+ };
+
+#define _DECLARE_XDECTOINT(name, type) \
type name (char const *n_str, type min, type max, \
char const *suffixes, char const *err, int err_exit) \
_GL_ATTRIBUTE_NONNULL ((1, 5));
-# define _DECLARE_XNUMTOINT(name, type) \
+#define _DECLARE_XNUMTOINT(name, type) \
type name (char const *n_str, int base, type min, type max, \
- char const *suffixes, char const *err, int err_exit) \
+ char const *suffixes, char const *err, int err_exit, int flags) \
_GL_ATTRIBUTE_NONNULL ((1, 6));
_DECLARE_XDECTOINT (xdectoimax, intmax_t)
#define __xnumtoint xnumtoumax
#define __xdectoint_t uintmax_t
#define __xstrtol xstrtoumax
-#define __xdectoint_signed 0
#include "xdectoint.c"
{
/* Limit max_width to MAXCHARS / 2; otherwise, the resulting
output can be quite ugly. */
- max_width = xdectoumax (max_width_option, 0, MAXCHARS / 2, "",
- _("invalid width"), 0);
+ max_width = xnumtoumax (max_width_option, 10, 0, MAXCHARS / 2, "",
+ _("invalid width"), 0, XTOINT_MAX_RANGE);
}
if (goal_width_option)
}
FALLTHROUGH;
case 'w': /* Line width. */
- width = xdectoumax (optarg, 1, SIZE_MAX - TAB_WIDTH - 1, "",
- _("invalid number of columns"), 0);
+ width = xnumtoumax (optarg, 10, 1, SIZE_MAX - TAB_WIDTH - 1, "",
+ _("invalid number of columns"), 0,
+ XTOINT_MIN_RANGE | XTOINT_MAX_RANGE);
break;
case_GETOPT_HELP_CHAR;
case 'T':
tabsize_opt = xnumtoumax (optarg, 0, 0, MIN (PTRDIFF_MAX, SIZE_MAX),
- "", _("invalid tab size"), LS_FAILURE);
+ "", _("invalid tab size"), LS_FAILURE, 0);
break;
case 'U':
reset_numbers = false;
break;
case 'l':
- blank_join = xdectoimax (optarg, 1, INTMAX_MAX, "",
- _("invalid line number of blank lines"), 0);
+ blank_join = xnumtoimax (optarg, 10, 1, INTMAX_MAX, "",
+ _("invalid line number of blank lines"),
+ 0, XTOINT_MIN_RANGE);
break;
case 's':
separator_str = optarg;
break;
case 'w':
- lineno_width = xdectoimax (optarg, 1, INT_MAX, "",
- _("invalid line number field width"), 0);
+ lineno_width = xnumtoimax (optarg, 10, 1, INT_MAX, "",
+ _("invalid line number field width"),
+ 0, XTOINT_MIN_RANGE);
break;
case 'n':
if (STREQ (optarg, "ln"))
static void print_header (void);
static void pad_across_to (int position);
static void add_line_number (COLUMN *p);
-static void getoptnum (char const *n_str, int min, int *num,
- char const *errfmt);
+static int getoptnum (char const *n_str, int min, char const *errfmt);
static void getoptarg (char *arg, char switch_char, char *character,
int *number);
static void print_files (int number_of_files, char **av);
static void
parse_column_count (char const *s)
{
- getoptnum (s, 1, &columns, _("invalid number of columns"));
+ columns = getoptnum (s, 1, _("invalid number of columns"));
explicit_columns = true;
}
join_lines = true;
break;
case 'l':
- getoptnum (optarg, 1, &lines_per_page,
- _("'-l PAGE_LENGTH' invalid number of lines"));
+ lines_per_page
+ = getoptnum (optarg, 1,
+ _("'-l PAGE_LENGTH' invalid number of lines"));
break;
case 'm':
parallel_files = true;
break;
case 'N':
skip_count = false;
- getoptnum (optarg, INT_MIN, &start_line_num,
- _("'-N NUMBER' invalid starting line number"));
+ start_line_num
+ = getoptnum (optarg, INT_MIN,
+ _("'-N NUMBER' invalid starting line number"));
break;
case 'o':
- getoptnum (optarg, 0, &chars_per_margin,
- _("'-o MARGIN' invalid line offset"));
+ chars_per_margin = getoptnum (optarg, 0,
+ _("'-o MARGIN' invalid line offset"));
break;
case 'r':
ignore_failed_opens = true;
old_options = true;
old_w = true;
{
- int tmp_cpl;
- getoptnum (optarg, 1, &tmp_cpl,
- _("'-w PAGE_WIDTH' invalid number of characters"));
+ int tmp_cpl
+ = getoptnum (optarg, 1,
+ _("'-w PAGE_WIDTH' invalid number of characters"));
if (! truncate_lines)
chars_per_line = tmp_cpl;
}
case 'W':
old_w = false; /* dominates -w */
truncate_lines = true;
- getoptnum (optarg, 1, &chars_per_line,
- _("'-W PAGE_WIDTH' invalid number of characters"));
+ chars_per_line
+ = getoptnum (optarg, 1,
+ _("'-W PAGE_WIDTH' invalid number of characters"));
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
/* Parse numeric arguments, ensuring MIN <= number <= INT_MAX. */
-static void
-getoptnum (char const *n_str, int min, int *num, char const *err)
+static int
+getoptnum (char const *n_str, int min, char const *err)
{
- intmax_t tnum = xdectoimax (n_str, min, INT_MAX, "", err, 0);
- *num = tnum;
+ return xnumtoimax (n_str, 10, min, INT_MAX, "", err, 0,
+ min <= 0 ? 0 : XTOINT_MIN_RANGE);
}
/* Parse options of the form -scNNN.
case 's':
flags.size = xnumtoumax (optarg, 0, 0, OFF_T_MAX, "cbBkKMGTPEZYRQ0",
- _("invalid file size"), 0);
+ _("invalid file size"), 0, 0);
break;
case 'v':
break;
case IO_BLKSIZE_OPTION:
- in_blk_size = xdectoumax (optarg, 1,
+ in_blk_size = xnumtoumax (optarg, 10, 1,
MIN (SYS_BUFSIZE_MAX,
MIN (IDX_MAX, SIZE_MAX) - 1),
- multipliers, _("invalid IO block size"), 0);
+ multipliers, _("invalid IO block size"),
+ 0, XTOINT_MIN_RANGE);
break;
case VERBOSE_OPTION:
static bool set_mode (struct mode_info const *info, bool reversed,
struct termios *mode);
static bool eq_mode (struct termios *mode1, struct termios *mode2);
-static unsigned long int integer_arg (char const *s, unsigned long int max);
+static uintmax_t integer_arg (char const *s, uintmax_t max);
static speed_t string_to_baud (char const *arg);
static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
static void display_all (struct termios *mode, char const *device_name);
#ifdef HAVE_C_LINE
else if (STREQ (arg, "line"))
{
- unsigned long int value;
check_argument (arg);
++k;
- mode->c_line = value = integer_arg (settings[k], ULONG_MAX);
- if (mode->c_line != value)
- error (0, 0, _("invalid line discipline %s"),
+ uintmax_t value = integer_arg (settings[k], UINTMAX_MAX);
+ if (ckd_add (&mode->c_line, value, 0))
+ error (0, EOVERFLOW, _("invalid line discipline %s"),
quote (settings[k]));
*require_set_attr = true;
}
but allowing octal and hex numbers as in C. Reject values
larger than MAXVAL. */
-static unsigned long int
-integer_arg (char const *s, unsigned long int maxval)
+static uintmax_t
+integer_arg (char const *s, uintmax_t maxval)
{
- return xnumtoumax (s, 0, 0, maxval, "bB", _("invalid integer argument"), 0);
+ return xnumtoumax (s, 0, 0, maxval, "bB", _("invalid integer argument"),
+ 0, 0);
}