xprintf
xprintf-posix
xreadlink
+ xdectoint
xstrtod
xstrtoimax
xstrtol
_src = (false|lbracket|ls-(dir|ls|vdir)|tac-pipe|uname-(arch|uname))
exclude_file_name_regexp--sc_require_config_h_first = \
- (^lib/buffer-lcm\.c|src/$(_src)\.c)$$
+ (^lib/buffer-lcm\.c|gl/lib/xdecto.max\.c|src/$(_src)\.c)$$
exclude_file_name_regexp--sc_require_config_h = \
$(exclude_file_name_regexp--sc_require_config_h_first)
--- /dev/null
+#define __xdectoint xdectoimax
+#define __xnumtoint xnumtoimax
+#define __xdectoint_t intmax_t
+#define __xstrtol xstrtoimax
+#define __xdectoint_signed 1
+#include "xdectoint.c"
--- /dev/null
+/* Convert decimal strings with bounds checking and exit on error.
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "xdectoint.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "error.h"
+#include "quote.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.
+ Strings can have multiplicative SUFFIXES if specified.
+ ERR is printed along with N_STR on error. */
+
+__xdectoint_t
+__xnumtoint (const char *n_str, int base, __xdectoint_t min, __xdectoint_t max,
+ const char *suffixes, const char *err, int err_exit)
+{
+ strtol_error s_err;
+
+ __xdectoint_t tnum;
+ s_err = __xstrtol (n_str, NULL, base, &tnum, suffixes);
+
+ if (s_err == LONGINT_OK)
+ {
+ 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;
+ }
+ }
+ 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)
+ {
+ error (err_exit ? err_exit : EXIT_FAILURE, errno,
+ "%s: %s", err, quote (n_str));
+ }
+
+ return tnum;
+}
+
+/* Parse decimal string N_STR, and return the value.
+ Exit on parse error or if MIN or MAX are exceeded.
+ Strings can have multiplicative SUFFIXES if specified.
+ ERR is printed along with N_STR on error. */
+
+__xdectoint_t
+__xdectoint (const char *n_str, __xdectoint_t min, __xdectoint_t max,
+ const char *suffixes, const char *err, int err_exit)
+{
+ return __xnumtoint (n_str, 10, min, max, suffixes, err, err_exit);
+}
--- /dev/null
+/* Convert decimal strings with bounds checking and exit on error.
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef XDECTOINT_H_
+# define XDECTOINT_H_ 1
+
+# include <inttypes.h>
+
+# define _DECLARE_XDECTOINT(name, type) \
+ type name (const char *n_str, type min, type max, \
+ const char *suffixes, const char *err, int err_exit);
+# define _DECLARE_XNUMTOINT(name, type) \
+ type name (const char *n_str, int base, type min, type max, \
+ const char *suffixes, const char *err, int err_exit);
+
+_DECLARE_XDECTOINT (xdectoimax, intmax_t)
+_DECLARE_XDECTOINT (xdectoumax, uintmax_t)
+
+_DECLARE_XNUMTOINT (xnumtoimax, intmax_t)
+_DECLARE_XNUMTOINT (xnumtoumax, uintmax_t)
+
+#endif /* not XDECTOINT_H_ */
--- /dev/null
+#define __xdectoint xdectoumax
+#define __xnumtoint xnumtoumax
+#define __xdectoint_t uintmax_t
+#define __xstrtol xstrtoumax
+#define __xdectoint_signed 0
+#include "xdectoint.c"
--- /dev/null
+Description:
+Convert decimal string to '[u]intmax_t', with bounds checking and exit on error
+
+Files:
+lib/xdectoint.h
+lib/xdectoint.c
+lib/xdectoimax.c
+lib/xdectoumax.c
+
+Depends-on:
+error
+errno
+quote
+xstrtoimax
+xstrtoumax
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += xdectoimax.c xdectoumax.c
+
+Include:
+"xdectoint.h"
+
+License:
+GPL
+
+Maintainer:
+all
#include "quote.h"
#include "safe-read.h"
#include "stdio--.h"
+#include "xdectoint.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no 'g' prefix). */
main (int argc, char **argv)
{
int optc;
- unsigned long int val;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
break;
case 'n':
- if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK
- || MIN (INT_MAX, SIZE_MAX) < val)
- error (EXIT_FAILURE, 0, _("%s: invalid number"), optarg);
- digits = val;
+ digits = xdectoimax (optarg, 0, MIN (INT_MAX, SIZE_MAX), "",
+ _("invalid number"), 0);
break;
case 's':
if (invalid != LONGINT_OK)
error (EXIT_FAILURE, invalid == LONGINT_OVERFLOW ? EOVERFLOW : 0,
- _("invalid number %s"), quote (val));
+ "%s: %s", _("invalid number"), quote (val));
}
}
#include "error.h"
#include "fadvise.h"
#include "quote.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "fmt"
{
/* Limit max_width to MAXCHARS / 2; otherwise, the resulting
output can be quite ugly. */
- unsigned long int tmp;
- if (! (xstrtoul (max_width_option, NULL, 10, &tmp, "") == LONGINT_OK
- && tmp <= MAXCHARS / 2))
- error (EXIT_FAILURE, 0, _("invalid width: %s"),
- quote (max_width_option));
- max_width = tmp;
+ max_width = xdectoumax (max_width_option, 0, MAXCHARS / 2, "",
+ _("invalid width"), 0);
}
if (goal_width_option)
{
/* Limit goal_width to max_width. */
- unsigned long int tmp;
- if (! (xstrtoul (goal_width_option, NULL, 10, &tmp, "") == LONGINT_OK
- && tmp <= max_width))
- error (EXIT_FAILURE, 0, _("invalid width: %s"),
- quote (goal_width_option));
- goal_width = tmp;
+ goal_width = xdectoumax (goal_width_option, 0, max_width, "",
+ _("invalid width"), 0);
if (max_width_option == NULL)
max_width = goal_width + 10;
}
#include "system.h"
#include "error.h"
#include "fadvise.h"
-#include "quote.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
#define TAB_WIDTH 8
}
/* Fall through. */
case 'w': /* Line width. */
- {
- unsigned long int tmp_ulong;
- if (! (xstrtoul (optarg, NULL, 10, &tmp_ulong, "") == LONGINT_OK
- && 0 < tmp_ulong && tmp_ulong < SIZE_MAX - TAB_WIDTH))
- error (EXIT_FAILURE, 0,
- _("invalid number of columns: %s"), quote (optarg));
- width = tmp_ulong;
- }
+ width = xdectoumax (optarg, 1, SIZE_MAX - TAB_WIDTH - 1, "",
+ _("invalid number of columns"), 0);
break;
case_GETOPT_HELP_CHAR;
#include "safe-read.h"
#include "stat-size.h"
#include "xfreopen.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "head"
return ok;
}
-/* Convert a string of decimal digits, N_STRING, with an optional suffinx
+/* Convert a string of decimal digits, N_STRING, with an optional suffix
to an integral value. Upon successful conversion,
return that value. If it cannot be converted, give a diagnostic and exit.
COUNT_LINES indicates whether N_STRING is a number of bytes or a number
static uintmax_t
string_to_integer (bool count_lines, const char *n_string)
{
- strtol_error s_err;
- uintmax_t n;
-
- s_err = xstrtoumax (n_string, NULL, 10, &n, "bkKmMGTPEZY0");
-
- if (s_err == LONGINT_OVERFLOW)
- {
- error (EXIT_FAILURE, 0,
- _("%s: %s is so large that it is not representable"), n_string,
- count_lines ? _("number of lines") : _("number of bytes"));
- }
-
- if (s_err != LONGINT_OK)
- {
- error (EXIT_FAILURE, 0, "%s: %s", n_string,
- (count_lines
- ? _("invalid number of lines")
- : _("invalid number of bytes")));
- }
-
- return n;
+ return xdectoumax (n_string, 0, UINTMAX_MAX, "bkKmMGTPEZY0",
+ count_lines ? _("invalid number of lines")
+ : _("invalid number of bytes"), 0);
}
int
if ( ! count_lines && elide_from_end && OFF_T_MAX < n_units)
{
char umax_buf[INT_BUFSIZE_BOUND (n_units)];
- error (EXIT_FAILURE, 0, _("%s: number of bytes is too large"),
- umaxtostr (n_units, umax_buf));
+ error (EXIT_FAILURE, EOVERFLOW, "%s: %s", _("invalid number of bytes"),
+ quote (umaxtostr (n_units, umax_buf)));
}
file_list = (optind < argc
#include "stat-size.h"
#include "stat-time.h"
#include "strftime.h"
+#include "xdectoint.h"
#include "xstrtol.h"
#include "areadlink.h"
#include "mbsalign.h"
break;
case 'w':
- {
- unsigned long int tmp_ulong;
- if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK
- || ! (0 < tmp_ulong && tmp_ulong <= SIZE_MAX))
- error (LS_FAILURE, 0, _("invalid line width: %s"),
- quotearg (optarg));
- line_length = tmp_ulong;
- break;
- }
+ line_length = xnumtoumax (optarg, 0, 1, SIZE_MAX, "",
+ _("invalid line width"), LS_FAILURE);
+ break;
case 'x':
format = horizontal;
break;
case 'T':
- {
- unsigned long int tmp_ulong;
- if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK
- || SIZE_MAX < tmp_ulong)
- error (LS_FAILURE, 0, _("invalid tab size: %s"),
- quotearg (optarg));
- tabsize = tmp_ulong;
- break;
- }
+ tabsize = xnumtoumax (optarg, 0, 0, SIZE_MAX, "",
+ _("invalid tab size"), LS_FAILURE);
+ break;
case 'U':
sort_type = sort_none;
#include "fadvise.h"
#include "linebuffer.h"
#include "quote.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "nl"
}
break;
case 'v':
- if (xstrtoimax (optarg, NULL, 10, &starting_line_number, "")
- != LONGINT_OK)
- {
- error (0, 0, _("invalid starting line number: %s"),
- quote (optarg));
- ok = false;
- }
+ starting_line_number = xdectoimax (optarg, INTMAX_MIN, INTMAX_MAX, "",
+ _("invalid starting line number"),
+ 0);
break;
case 'i':
- if (! (xstrtoimax (optarg, NULL, 10, &page_incr, "") == LONGINT_OK
- && 0 < page_incr))
- {
- error (0, 0, _("invalid line number increment: %s"),
- quote (optarg));
- ok = false;
- }
+ page_incr = xdectoimax (optarg, 1, INTMAX_MAX, "",
+ _("invalid line number increment"), 0);
break;
case 'p':
reset_numbers = false;
break;
case 'l':
- if (! (xstrtoimax (optarg, NULL, 10, &blank_join, "") == LONGINT_OK
- && 0 < blank_join))
- {
- error (0, 0, _("invalid number of blank lines: %s"),
- quote (optarg));
- ok = false;
- }
+ blank_join = xdectoimax (optarg, 1, INTMAX_MAX, "",
+ _("invalid line number of blank lines"), 0);
break;
case 's':
separator_str = optarg;
break;
case 'w':
- {
- long int tmp_long;
- if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
- || tmp_long <= 0 || tmp_long > INT_MAX)
- {
- error (0, 0, _("invalid line number field width: %s"),
- quote (optarg));
- ok = false;
- }
- else
- {
- lineno_width = tmp_long;
- }
- }
+ lineno_width = xdectoimax (optarg, 1, INT_MAX, "",
+ _("invalid line number field width"), 0);
break;
case 'n':
if (STREQ (optarg, "ln"))
#include "error.h"
#include "nproc.h"
#include "quote.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "nproc"
break;
case IGNORE_OPTION:
- if (xstrtoul (optarg, NULL, 10, &ignore, "") != LONGINT_OK)
- {
- error (0, 0, _("%s: invalid number to ignore"), optarg);
- usage (EXIT_FAILURE);
- }
+ ignore = xdectoumax (optarg, 0, ULONG_MAX, "", _("invalid number"),0);
break;
default:
#include "stdio--.h"
#include "strftime.h"
#include "xstrtol.h"
+#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "pr"
static void print_header (void);
static void pad_across_to (int position);
static void add_line_number (COLUMN *p);
+static void getoptnum (const char *n_str, int min, int *num,
+ const char *errfmt);
static void getoptarg (char *arg, char switch_char, char *character,
int *number);
static void print_files (int number_of_files, char **av);
/* Parse column count string S, and if it's valid (1 or larger and
within range of the type of 'columns') set the global variables
- columns and explicit_columns and return true.
- Otherwise, exit with a diagnostic. */
+ columns and explicit_columns. Otherwise, exit with a diagnostic. */
+
static void
parse_column_count (char const *s)
{
- long int tmp_long;
- if (xstrtol (s, NULL, 10, &tmp_long, "") != LONGINT_OK
- || !(1 <= tmp_long && tmp_long <= INT_MAX))
- error (EXIT_FAILURE, 0,
- _("invalid number of columns: %s"), quote (s));
-
- columns = tmp_long;
+ getoptnum (s, 1, &columns, _("invalid number of columns"));
explicit_columns = true;
}
join_lines = true;
break;
case 'l':
- {
- long int tmp_long;
- if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
- || tmp_long <= 0 || tmp_long > INT_MAX)
- {
- error (EXIT_FAILURE, 0,
- _("'-l PAGE_LENGTH' invalid number of lines: %s"),
- quote (optarg));
- }
- lines_per_page = tmp_long;
- break;
- }
+ getoptnum (optarg, 1, &lines_per_page,
+ _("'-l PAGE_LENGTH' invalid number of lines"));
+ break;
case 'm':
parallel_files = true;
storing_columns = false;
break;
case 'N':
skip_count = false;
- {
- long int tmp_long;
- if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
- || tmp_long > INT_MAX)
- {
- error (EXIT_FAILURE, 0,
- _("'-N NUMBER' invalid starting line number: %s"),
- quote (optarg));
- }
- start_line_num = tmp_long;
- break;
- }
+ getoptnum (optarg, INT_MIN, &start_line_num,
+ _("'-N NUMBER' invalid starting line number"));
+ break;
case 'o':
- {
- long int tmp_long;
- if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
- || tmp_long < 0 || tmp_long > INT_MAX)
- error (EXIT_FAILURE, 0,
- _("'-o MARGIN' invalid line offset: %s"), quote (optarg));
- chars_per_margin = tmp_long;
- break;
- }
+ getoptnum (optarg, 0, &chars_per_margin,
+ _("'-o MARGIN' invalid line offset"));
+ break;
case 'r':
ignore_failed_opens = true;
break;
old_options = true;
old_w = true;
{
- long int tmp_long;
- if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
- || tmp_long <= 0 || tmp_long > INT_MAX)
- error (EXIT_FAILURE, 0,
- _("'-w PAGE_WIDTH' invalid number of characters: %s"),
- quote (optarg));
- if (!truncate_lines)
- chars_per_line = tmp_long;
- break;
+ int tmp_cpl;
+ getoptnum (optarg, 1, &tmp_cpl,
+ _("'-w PAGE_WIDTH' invalid number of characters"));
+ if (! truncate_lines)
+ chars_per_line = tmp_cpl;
}
+ break;
case 'W':
old_w = false; /* dominates -w */
truncate_lines = true;
- {
- long int tmp_long;
- if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
- || tmp_long <= 0 || tmp_long > INT_MAX)
- error (EXIT_FAILURE, 0,
- _("'-W PAGE_WIDTH' invalid number of characters: %s"),
- quote (optarg));
- chars_per_line = tmp_long;
- break;
- }
+ getoptnum (optarg, 1, &chars_per_line,
+ _("'-W PAGE_WIDTH' invalid number of characters"));
+ break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
return failed_opens ? EXIT_FAILURE : EXIT_SUCCESS;
}
+/* Parse numeric arguments, ensuring MIN <= number <= INT_MAX. */
+
+static void
+getoptnum (const char *n_str, int min, int *num, const char *err)
+{
+ intmax_t tnum = xdectoimax (n_str, min, INT_MAX, "", err, 0);
+ *num = tnum;
+}
+
/* Parse options of the form -scNNN.
Example: -nck, where 'n' is the option, c is the optional number
{
long int tmp_long;
if (xstrtol (arg, NULL, 10, &tmp_long, "") != LONGINT_OK
- || tmp_long <= 0 || tmp_long > INT_MAX)
+ || tmp_long <= 0 || INT_MAX < tmp_long)
{
- error (0, 0,
+ error (0, INT_MAX < tmp_long ? EOVERFLOW : errno,
_("'-%c' extra characters or invalid number in the argument: %s"),
switch_char, quote (arg));
usage (EXIT_FAILURE);
#include "system.h"
#include "argmatch.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
#include "error.h"
#include "fcntl--.h"
#include "human.h"
break;
case 'n':
- {
- uintmax_t tmp;
- if (xstrtoumax (optarg, NULL, 10, &tmp, NULL) != LONGINT_OK
- || MIN (ULONG_MAX, SIZE_MAX / sizeof (int)) <= tmp)
- {
- error (EXIT_FAILURE, 0, _("%s: invalid number of passes"),
- quotearg_colon (optarg));
- }
- flags.n_iterations = tmp;
- }
+ flags.n_iterations = xdectoumax (optarg, 0,
+ MIN (ULONG_MAX,
+ SIZE_MAX / sizeof (int)), "",
+ _("invalid number of passes"), 0);
break;
case RANDOM_SOURCE_OPTION:
break;
case 's':
- {
- uintmax_t tmp;
- if ((xstrtoumax (optarg, NULL, 0, &tmp, "cbBkKMGTPEZY0")
- != LONGINT_OK)
- || OFF_T_MAX < tmp)
- {
- error (EXIT_FAILURE, 0, _("%s: invalid file size"),
- quotearg_colon (optarg));
- }
- flags.size = tmp;
- }
+ flags.size = xnumtoumax (optarg, 0, 0, OFF_T_MAX, "cbBkKMGTPEZY0",
+ _("invalid file size"), 0);
break;
case 'v':
#include "randperm.h"
#include "read-file.h"
#include "stdio--.h"
+#include "xdectoint.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no 'g' prefix). */
case 'i':
{
- unsigned long int argval = 0;
char *p = strchr (optarg, '-');
char const *hi_optarg = optarg;
bool invalid = !p;
if (p)
{
*p = '\0';
- invalid = ((xstrtoul (optarg, NULL, 10, &argval, NULL)
- != LONGINT_OK)
- || SIZE_MAX < argval);
+ lo_input = xdectoumax (optarg, 0, SIZE_MAX, "",
+ _("invalid input range"), 0);
*p = '-';
- lo_input = argval;
hi_optarg = p + 1;
}
- invalid |= ((xstrtoul (hi_optarg, NULL, 10, &argval, NULL)
- != LONGINT_OK)
- || SIZE_MAX < argval);
- hi_input = argval;
+ hi_input = xdectoumax (hi_optarg, 0, SIZE_MAX, "",
+ _("invalid input range"), 0);
+
n_lines = hi_input - lo_input + 1;
invalid |= ((lo_input <= hi_input) == (n_lines == 0));
if (invalid)
- error (EXIT_FAILURE, 0, _("invalid input range %s"),
+ error (EXIT_FAILURE, errno, "%s: %s", _("invalid input range"),
quote (optarg));
}
break;
if (e == LONGINT_OK)
head_lines = MIN (head_lines, argval);
else if (e != LONGINT_OVERFLOW)
- error (EXIT_FAILURE, 0, _("invalid line count %s"),
+ error (EXIT_FAILURE, 0, _("invalid line count: %s"),
quote (optarg));
}
break;
#include "safe-read.h"
#include "sig2str.h"
#include "xfreopen.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "split"
} \
while (0)
+
/* Parse K/N syntax of chunk options. */
static void
parse_chunk (uintmax_t *k_units, uintmax_t *n_units, char *slash)
{
- *slash = '\0';
- if (xstrtoumax (slash + 1, NULL, 10, n_units, "") != LONGINT_OK
- || *n_units == 0)
- error (EXIT_FAILURE, 0, _("%s: invalid number of chunks"), slash + 1);
- if (slash != optarg /* a leading number is specified. */
- && (xstrtoumax (optarg, NULL, 10, k_units, "") != LONGINT_OK
- || *k_units == 0 || *n_units < *k_units))
- error (EXIT_FAILURE, 0, _("%s: invalid chunk number"), optarg);
+ *n_units = xdectoumax (slash + 1, 1, UINTMAX_MAX, "",
+ _("invalid number of chunks"), 0);
+ if (slash != optarg) /* a leading number is specified. */
+ {
+ *slash = '\0';
+ *k_units = xdectoumax (optarg, 1, *n_units, "",
+ _("invalid chunk number"), 0);
+ }
}
size_t in_blk_size = 0; /* optimal block size of input file device */
size_t page_size = getpagesize ();
uintmax_t k_units = 0;
- uintmax_t n_units;
+ uintmax_t n_units = 0;
static char const multipliers[] = "bEGKkMmPTYZ0";
int c;
switch (c)
{
case 'a':
- {
- unsigned long tmp;
- if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK
- || SIZE_MAX / sizeof (size_t) < tmp)
- {
- error (0, 0, _("%s: invalid suffix length"), optarg);
- usage (EXIT_FAILURE);
- }
- suffix_length = tmp;
- }
+ suffix_length = xdectoumax (optarg, 0, SIZE_MAX / sizeof (size_t),
+ "", _("invalid suffix length"), 0);
break;
case ADDITIONAL_SUFFIX_OPTION:
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_bytes;
- if (xstrtoumax (optarg, NULL, 10, &n_units, multipliers) != LONGINT_OK
- || n_units == 0)
- {
- error (0, 0, _("%s: invalid number of bytes"), optarg);
- usage (EXIT_FAILURE);
- }
- /* If input is a pipe, we could get more data than is possible
- to write to a single file, so indicate that immediately
- rather than having possibly future invocations fail. */
- if (OFF_T_MAX < n_units)
- error (EXIT_FAILURE, EFBIG,
- _("%s: invalid number of bytes"), optarg);
-
+ /* Limit to OFF_T_MAX, becaue if input is a pipe, we could get more
+ data than is possible to write to a single file, so indicate that
+ immediately rather than having possibly future invocations fail. */
+ n_units = xdectoumax (optarg, 1, OFF_T_MAX, multipliers,
+ _("invalid number of bytes"), 0);
break;
case 'l':
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_lines;
- if (xstrtoumax (optarg, NULL, 10, &n_units, "") != LONGINT_OK
- || n_units == 0)
- {
- error (0, 0, _("%s: invalid number of lines"), optarg);
- usage (EXIT_FAILURE);
- }
+ n_units = xdectoumax (optarg, 1, UINTMAX_MAX, "",
+ _("invalid number of lines"), 0);
break;
case 'C':
if (split_type != type_undef)
FAIL_ONLY_ONE_WAY ();
split_type = type_byteslines;
- if (xstrtoumax (optarg, NULL, 10, &n_units, multipliers) != LONGINT_OK
- || n_units == 0 || SIZE_MAX < n_units)
- {
- error (0, 0, _("%s: invalid number of bytes"), optarg);
- usage (EXIT_FAILURE);
- }
- if (OFF_T_MAX < n_units)
- error (EXIT_FAILURE, EFBIG,
- _("%s: invalid number of bytes"), optarg);
+ n_units = xdectoumax (optarg, 1, MIN (SIZE_MAX, OFF_T_MAX),
+ multipliers, _("invalid number of bytes"), 0);
break;
case 'n':
split_type = type_chunk_bytes;
if ((slash = strchr (optarg, '/')))
parse_chunk (&k_units, &n_units, slash);
- else if (xstrtoumax (optarg, NULL, 10, &n_units, "") != LONGINT_OK
- || n_units == 0)
- error (EXIT_FAILURE, 0, _("%s: invalid number of chunks"), optarg);
+ else
+ n_units = xdectoumax (optarg, 1, UINTMAX_MAX, "",
+ _("invalid number of chunks"), 0);
break;
case 'u':
break;
case IO_BLKSIZE_OPTION:
- {
- uintmax_t tmp_blk_size;
- if (xstrtoumax (optarg, NULL, 10, &tmp_blk_size,
- multipliers) != LONGINT_OK
- || tmp_blk_size == 0 || SIZE_MAX - page_size < tmp_blk_size)
- error (0, 0, _("%s: invalid IO block size"), optarg);
- else
- in_blk_size = tmp_blk_size;
- }
+ in_blk_size = xdectoumax (optarg, 1, SIZE_MAX - page_size,
+ multipliers, _("invalid IO block size"), 0);
break;
case VERBOSE_OPTION:
if (n_units == 0)
{
- error (0, 0, _("%s: invalid number of lines"), "0");
+ error (0, 0, "%s: %s", _("invalid number of lines"), quote ("0"));
usage (EXIT_FAILURE);
}
if (OFF_T_MAX < n_units)
{
char buffer[INT_BUFSIZE_BOUND (uintmax_t)];
- error (EXIT_FAILURE, EFBIG, _("%s: invalid number of chunks"),
- umaxtostr (n_units, buffer));
+ error (EXIT_FAILURE, EOVERFLOW, "%s: %s",
+ _("invalid number of chunks"),
+ quote (umaxtostr (n_units, buffer)));
}
/* increase file_size to n_units here, so that we still process
any input data, and create empty files for the rest. */
{
uintmax_t tmp_size;
enum strtol_error e = xstrtoumax (str, NULL, 10, &tmp_size, "EGkKMPTYZ0");
- if (e == LONGINT_OK && tmp_size > SIZE_MAX)
+ if (e == LONGINT_OK && SIZE_MAX < tmp_size)
e = LONGINT_OVERFLOW;
if (e == LONGINT_OK)
return 0;
}
- errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : 0);
+ errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : errno);
return -1;
}
#include "error.h"
#include "fd-reopen.h"
#include "quote.h"
+#include "xdectoint.h"
#include "xstrtol.h"
/* The official name of this program (e.g., no 'g' prefix). */
static unsigned long int
integer_arg (const char *s, unsigned long int maxval)
{
- unsigned long int value;
- if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
- {
- error (0, 0, _("invalid integer argument %s"), quote (s));
- usage (EXIT_FAILURE);
- }
- return value;
+ return xnumtoumax (s, 0, 0, maxval, "bB", _("invalid integer argument"), 0);
}
#include "stat-time.h"
#include "xfreopen.h"
#include "xnanosleep.h"
+#include "xdectoint.h"
#include "xstrtol.h"
#include "xstrtod.h"
else if ((xstrtoumax (n_string, NULL, 10, n_units, "b")
& ~LONGINT_INVALID_SUFFIX_CHAR)
!= LONGINT_OK)
- error (EXIT_FAILURE, 0, _("number in %s is too large"), quote (argv[1]));
+ {
+ error (EXIT_FAILURE, errno, "%s: %s", _("invalid number"),
+ quote (argv[1]));
+ }
/* Set globals. */
from_start = t_from_start;
else if (*optarg == '-')
++optarg;
- {
- strtol_error s_err;
- s_err = xstrtoumax (optarg, NULL, 10, n_units, "bkKmMGTPEZY0");
- if (s_err != LONGINT_OK)
- {
- error (EXIT_FAILURE, 0, "%s: %s", optarg,
- (c == 'n'
- ? _("invalid number of lines")
- : _("invalid number of bytes")));
- }
- }
+ *n_units = xdectoumax (optarg, 0, UINTMAX_MAX, "bkKmMGTPEZY0",
+ count_lines
+ ? _("invalid number of lines")
+ : _("invalid number of bytes"), 0);
break;
case 'f':
case MAX_UNCHANGED_STATS_OPTION:
/* --max-unchanged-stats=N */
- if (xstrtoumax (optarg, NULL, 10,
- &max_n_unchanged_stats_between_opens,
- "")
- != LONGINT_OK)
- {
- error (EXIT_FAILURE, 0,
- _("%s: invalid maximum number of unchanged stats between opens"),
- optarg);
- }
+ max_n_unchanged_stats_between_opens =
+ xdectoumax (optarg, 0, UINTMAX_MAX, "",
+ _("invalid maximum number of unchanged stats between opens"), 0);
break;
case DISABLE_INOTIFY_OPTION:
break;
case PID_OPTION:
- {
- strtol_error s_err;
- unsigned long int tmp_ulong;
- s_err = xstrtoul (optarg, NULL, 10, &tmp_ulong, "");
- if (s_err != LONGINT_OK || tmp_ulong > PID_T_MAX)
- {
- error (EXIT_FAILURE, 0, _("%s: invalid PID"), optarg);
- }
- pid = tmp_ulong;
- }
+ pid = xdectoumax (optarg, 0, PID_T_MAX, "", _("invalid PID"), 0);
break;
case PRESUME_INPUT_PIPE_OPTION:
double s;
if (! (xstrtod (optarg, NULL, &s, c_strtod) && 0 <= s))
error (EXIT_FAILURE, 0,
- _("%s: invalid number of seconds"), optarg);
+ _("invalid number of seconds: %s"), quote (optarg));
*sleep_interval = s;
}
break;
#include "error.h"
#include "quote.h"
#include "stat-size.h"
-#include "xstrtol.h"
+#include "xdectoint.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "truncate"
typedef enum
{ rm_abs = 0, rm_rel, rm_min, rm_max, rm_rdn, rm_rup } rel_mode_t;
-/* Set size to the value of STR, interpreted as a decimal integer,
- optionally multiplied by various values.
- Return -1 on error, 0 on success.
-
- This supports dd BLOCK size suffixes + lowercase g,t,m for bsd compat
- Note we don't support dd's b=512, c=1, w=2 or 21x512MiB formats. */
-static int
-parse_len (char const *str, off_t *size)
-{
- enum strtol_error e;
- intmax_t tmp_size;
- e = xstrtoimax (str, NULL, 10, &tmp_size, "EgGkKmMPtTYZ0");
- if (e == LONGINT_OK
- && !(OFF_T_MIN <= tmp_size && tmp_size <= OFF_T_MAX))
- e = LONGINT_OVERFLOW;
-
- if (e == LONGINT_OK)
- {
- errno = 0;
- *size = tmp_size;
- return 0;
- }
-
- errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : 0);
- return -1;
-}
-
void
usage (int status)
{
}
rel_mode = rm_rel;
}
- if (parse_len (optarg, &size) == -1)
- error (EXIT_FAILURE, errno, _("invalid number %s"),
- quote (optarg));
+ /* Support dd BLOCK size suffixes + lowercase g,t,m for bsd compat.
+ Note we don't support dd's b=512, c=1, w=2 or 21x512MiB formats. */
+ size = xdectoimax (optarg, OFF_T_MIN, OFF_T_MAX, "EgGkKmMPtTYZ0",
+ _("Invalid number"), 0);
/* Rounding to multiple of 0 is nonsensical */
if ((rel_mode == rm_rup || rel_mode == rm_rdn) && size == 0)
error (EXIT_FAILURE, 0, _("division by zero"));
{IN=> "ça\nçb\n"},
{OUT=>"ça b\n"}],
['wide-1', '-w 32768',
- {ERR => "fmt: invalid width: '32768'\n"}, {EXIT => 1}],
+ {ERR => "fmt: invalid width: '32768'"}, {EXIT => 1},
+ {ERR_SUBST => 's/:[^:]*$//'}],
['wide-2', '-w 2147483647',
- {ERR => "fmt: invalid width: '2147483647'\n"}, {EXIT => 1}],
+ {ERR => "fmt: invalid width: '2147483647'"}, {EXIT => 1},
+ {ERR_SUBST => 's/:[^:]*$//'}],
['bad-suffix', '-72x', {IN=> ''},
{ERR => "fmt: invalid width: '72x'\n"}, {EXIT => 1}],
['no-file', 'no-such-file',
tests/misc/sha384sum.pl \
tests/misc/sha512sum.pl \
tests/misc/shred-exact.sh \
- tests/misc/shred-negative.sh \
tests/misc/shred-passes.sh \
tests/misc/shred-remove.sh \
+ tests/misc/shred-size.sh \
tests/misc/shuf.sh \
tests/misc/shuf-reservoir.sh \
tests/misc/sort.pl \
tests/ls/file-type.sh \
tests/ls/follow-slink.sh \
tests/ls/getxattr-speedup.sh \
+ tests/ls/hex-option.sh \
tests/ls/infloop.sh \
tests/ls/inode.sh \
tests/ls/m-option.sh \
#!/bin/sh
-# Exercise shred -s-3 FILE
+# accept hex/oct numbers to -w and -T
# Copyright (C) 2014 Free Software Foundation, Inc.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
-print_ver_ shred
+print_ver_ ls
-echo 'shred: -2: invalid file size' > exp || framework_failure_
-echo 1234 > f || framework_failure_
-
-shred -s-2 f 2>err && fail=1
-compare exp err || fail=1
+ls -x -T0x10 -w010 || fail=1
Exit $fail
--- /dev/null
+#!/bin/sh
+# Exercise shred --size
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# 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 3 of the License, or
+# (at your option) any later version.
+
+# 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.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ shred
+
+# Negative size
+echo "shred: invalid file size: '-2'" > exp || framework_failure_
+echo 1234 > f || framework_failure_
+shred -s-2 f 2>err && fail=1
+compare exp err || fail=1
+
+# Octal/Hex
+shred -s010 f || fail=1
+test $(stat --printf=%s f) = 8 || fail=1
+shred -s0x10 f || fail=1
+test $(stat --printf=%s f) = 16 || fail=1
+
+Exit $fail
7 rows_1 1_1
8 columns_80 1_80
9 rows_30 30_80
+10 rows_0x1E 30_80
+11 rows_036 30_80
NA LAST NA
'
set $tests
use strict;
my $prog = 'tail';
-my $normalize_filename = {ERR_SUBST => 's/^$prog: .*?:/$prog: -:/'};
+my $normalize_strerror = 's/:[^:]*$//';
# Turn off localization of executable's output.
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
"$prog: cannot open '+cl' for reading: No such file or directory\n"],
['err-2', '-cl', '', '', 1,
- "$prog: l: invalid number of bytes\n"],
+ "$prog: invalid number of bytes: 'l'\n"],
['err-3', '+2cz', '', '', 1,
"$prog: cannot open '+2cz' for reading: No such file or directory\n"],
# the diagnostic: 'tail: 99999999999999999999: invalid number of bytes'
# on all systems... probably, for now, maybe.
['err-5', '-c99999999999999999999', '', '', 1,
- "$prog: 99999999999999999999: invalid number of bytes\n"],
+ "$prog: invalid number of bytes: '99999999999999999999'", $normalize_strerror],
['err-6', '-c --', '', '', 1,
- "$prog: -: invalid number of bytes\n", $normalize_filename],
+ "$prog: invalid number of bytes: '-'\n"],
# Same as -n 10
['minus-1', '-', '', '', 0],
foreach my $t (@tv)
{
- my ($test_name, $flags, $in, $exp, $ret, $err_msg) = @$t;
+ my ($test_name, $flags, $in, $exp, $ret, $err_msg, $err_sub) = @$t;
my $e = [$test_name, $flags, {IN=>$in}, {OUT=>$exp}];
$ret
- and push @$e, {EXIT=>$ret}, {ERR=>$err_msg};
+ and push @$e, {EXIT=>$ret}, {ERR=>$err_msg}, {ERR_SUBST=>$err_sub};
$test_name =~ /^(obs-plus-|minus-)/
and push @$e, {ENV=>'_POSIX2_VERSION=199209'};
['col-long', '-W3 -t -1 --columns=2', "a\nb\nc\n", "a c\nb\n", 0],
# Make sure these fail.
['col-0', '-0', '', '', 1,
- "$prog: invalid number of columns: '0'\n"],
+ "$prog: invalid number of columns: '0'",
+ 's/:[^:]*$//'],
['col-inval', '-'.'9'x100, '', '', 1,
- "$prog: invalid number of columns: '". ('9'x100) ."'\n"],
+ "$prog: invalid number of columns: '". ('9'x100) ."'",
+ 's/:[^:]*$//'],
# Before coreutils-5.3.1, --pages=1:-1 would be treated like
# --pages=1:18446744073709551615.
my @Tests;
foreach my $t (@tv)
{
- my ($test_name, $flags, $in, $exp, $ret, $err_msg) = @$t;
+ my ($test_name, $flags, $in, $exp, $ret, $err_msg, $err_sub) = @$t;
my $new_ent = [$test_name, $common_option_prefix, $flags];
if (!ref $in)
{
}
}
$ret
- and push @$new_ent, {EXIT=>$ret}, {ERR=>$err_msg};
+ and push @$new_ent, {EXIT=>$ret}, {ERR=>$err_msg}, {ERR_SUBST=>$err_sub};
push @Tests, $new_ent;
}
print_ver_ split
# invalid number of chunks
-echo 'split: 1o: invalid number of chunks' > exp
+echo "split: invalid number of chunks: '1o'" > exp
split -n l/1o 2>err && fail=1
compare exp err || fail=1
printf "%s" "$lines" | tr '~' '\n' > in || framework_failure_
-echo 'split: 16: invalid chunk number' > exp
-split -n l/16/15 in 2>err && fail=1
+echo "split: invalid chunk number: '16'" > exp
+split -n l/16/15 in 2>err.t && fail=1
+sed 's/:[^:]*$//' < err.t > err || framework_failure_
compare exp err || fail=1
printf '%s' "\