summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2003-12-27 14:36:26 +0000
committerJim Meyering <jim@meyering.net>2003-12-27 14:36:26 +0000
commitfdb08248b8a7671a404fa222d3e0e4122b20140e (patch)
tree6a0797be807e9a142d756c2fc493d450e17dde5d /src
parent064ca9ef3c384f3f7a812b9f2c2f6396530fcfe3 (diff)
downloadcoreutils-fdb08248b8a7671a404fa222d3e0e4122b20140e.tar.xz
Include "quote.h".
(min, max): Remove definitions. Make a few function parameters and corresponding locals `const'. Use bool for boolean variables. Use size_t (not int) for all counters and related index variables. (prjoin): Remove now-useless assertion. (string_to_join_field): New function. (main): Accept join fields as large as SIZE_MAX. (keycmp): Rename `min' to MIN and max to MAX.
Diffstat (limited to 'src')
-rw-r--r--src/join.c181
1 files changed, 96 insertions, 85 deletions
diff --git a/src/join.c b/src/join.c
index c079c31d1..4330db86b 100644
--- a/src/join.c
+++ b/src/join.c
@@ -29,6 +29,7 @@
#include "hard-locale.h"
#include "linebuffer.h"
#include "memcasecmp.h"
+#include "quote.h"
#include "xmemcoll.h"
#include "xstrtol.h"
@@ -39,12 +40,6 @@
#define join system_join
-/* Undefine, to avoid warning about redefinition on some systems. */
-#undef min
-#undef max
-#define min(A, B) ((A) < (B) ? (A) : (B))
-#define max(A, B) ((A) > (B) ? (A) : (B))
-
/* An element of the list identifying which fields to print for each
output line. */
struct outlist
@@ -54,7 +49,7 @@ struct outlist
int file;
/* Field index (zero-based), specified only when FILE is 1 or 2. */
- int field;
+ size_t field;
struct outlist *next;
};
@@ -70,8 +65,8 @@ struct field
struct line
{
struct linebuffer buf; /* The line itself. */
- int nfields; /* Number of elements in `fields'. */
- int nfields_allocated; /* Number of elements in `fields'. */
+ size_t nfields; /* Number of elements in `fields'. */
+ size_t nfields_allocated; /* Number of elements allocated for `fields'. */
struct field *fields;
};
@@ -91,16 +86,16 @@ char *program_name;
static int hard_LC_COLLATE;
/* If nonzero, print unpairable lines in file 1 or 2. */
-static int print_unpairables_1, print_unpairables_2;
+static bool print_unpairables_1, print_unpairables_2;
/* If nonzero, print pairable lines. */
-static int print_pairables;
+static bool print_pairables;
/* Empty output field filler. */
static char *empty_filler;
/* Field to join on. */
-static int join_field_1, join_field_2;
+static size_t join_field_1, join_field_2;
/* List of fields to print. */
static struct outlist outlist_head;
@@ -130,7 +125,7 @@ static struct option const longopts[] =
static struct line uni_blank;
/* If nonzero, ignore case when comparing join fields. */
-static int ignore_case;
+static bool ignore_case;
void
usage (int status)
@@ -202,7 +197,7 @@ ADD_FIELD (struct line *line, const unsigned char *field, size_t len)
static void
xfields (struct line *line)
{
- int i;
+ size_t i;
unsigned char *ptr0 = (unsigned char *) line->buf.buffer;
unsigned char *ptr;
unsigned char *lim;
@@ -310,7 +305,7 @@ getseq (FILE *fp, struct seq *seq)
static void
delseq (struct seq *seq)
{
- int i;
+ size_t i;
for (i = 0; i < seq->count; i++)
if (seq->lines[i].buf.buffer)
freeline (&seq->lines[i]);
@@ -322,12 +317,13 @@ delseq (struct seq *seq)
Report an error and exit if the comparison fails. */
static int
-keycmp (struct line *line1, struct line *line2)
+keycmp (struct line const *line1, struct line const *line2)
{
/* Start of field to compare in each file. */
const unsigned char *beg1, *beg2;
- size_t len1, len2; /* Length of fields to compare. */
+ size_t len1;
+ size_t len2; /* Length of fields to compare. */
int diff;
if (join_field_1 < line1->nfields)
@@ -364,13 +360,13 @@ keycmp (struct line *line1, struct line *line2)
{
/* FIXME: ignore_case does not work with NLS (in particular,
with multibyte chars). */
- diff = memcasecmp (beg1, beg2, min (len1, len2));
+ diff = memcasecmp (beg1, beg2, MIN (len1, len2));
}
else
{
if (HAVE_SETLOCALE && hard_LC_COLLATE)
return xmemcoll ((char *) beg1, len1, (char *) beg2, len2);
- diff = memcmp (beg1, beg2, min (len1, len2));
+ diff = memcmp (beg1, beg2, MIN (len1, len2));
}
if (diff)
@@ -382,7 +378,7 @@ keycmp (struct line *line1, struct line *line2)
`empty_filler' if it is nonempty. */
static void
-prfield (int n, struct line *line)
+prfield (size_t n, struct line const *line)
{
size_t len;
@@ -401,7 +397,7 @@ prfield (int n, struct line *line)
/* Print the join of LINE1 and LINE2. */
static void
-prjoin (struct line *line1, struct line *line2)
+prjoin (struct line const *line1, struct line const *line2)
{
const struct outlist *outlist;
@@ -413,8 +409,8 @@ prjoin (struct line *line1, struct line *line2)
o = outlist;
while (1)
{
- int field;
- struct line *line;
+ size_t field;
+ struct line const *line;
if (o->file == 0)
{
@@ -432,7 +428,6 @@ prjoin (struct line *line1, struct line *line2)
else
{
line = (o->file == 1 ? line1 : line2);
- assert (o->field >= 0);
field = o->field;
}
prfield (field, line);
@@ -445,11 +440,11 @@ prjoin (struct line *line1, struct line *line2)
}
else
{
- int i;
+ size_t i;
if (line1 == &uni_blank)
{
- struct line *t;
+ struct line const *t;
t = line1;
line1 = line2;
line2 = t;
@@ -487,7 +482,8 @@ join (FILE *fp1, FILE *fp2)
{
struct seq seq1, seq2;
struct line line;
- int diff, i, j, eof1, eof2;
+ int diff;
+ bool eof1, eof2;
/* Read the first line of each file. */
initseq (&seq1);
@@ -497,6 +493,7 @@ join (FILE *fp1, FILE *fp2)
while (seq1.count && seq2.count)
{
+ size_t i;
diff = keycmp (&seq1.lines[0], &seq2.lines[0]);
if (diff < 0)
{
@@ -519,11 +516,11 @@ join (FILE *fp1, FILE *fp2)
/* Keep reading lines from file1 as long as they continue to
match the current line from file2. */
- eof1 = 0;
+ eof1 = false;
do
if (!getseq (fp1, &seq1))
{
- eof1 = 1;
+ eof1 = true;
++seq1.count;
break;
}
@@ -531,11 +528,11 @@ join (FILE *fp1, FILE *fp2)
/* Keep reading lines from file2 as long as they continue to
match the current line from file1. */
- eof2 = 0;
+ eof2 = false;
do
if (!getseq (fp2, &seq2))
{
- eof2 = 1;
+ eof2 = true;
++seq2.count;
break;
}
@@ -544,8 +541,11 @@ join (FILE *fp1, FILE *fp2)
if (print_pairables)
{
for (i = 0; i < seq1.count - 1; ++i)
- for (j = 0; j < seq2.count - 1; ++j)
- prjoin (&seq1.lines[i], &seq2.lines[j]);
+ {
+ size_t j;
+ for (j = 0; j < seq2.count - 1; ++j)
+ prjoin (&seq1.lines[i], &seq2.lines[j]);
+ }
}
for (i = 0; i < seq1.count - 1; ++i)
@@ -598,12 +598,12 @@ join (FILE *fp1, FILE *fp2)
/* Add a field spec for field FIELD of file FILE to `outlist'. */
static void
-add_field (int file, int field)
+add_field (int file, size_t field)
{
struct outlist *o;
assert (file == 0 || file == 1 || file == 2);
- assert (file == 0 ? field < 0 : field >= 0);
+ assert (file != 0 || field == 0);
o = xmalloc (sizeof *o);
o->file = file;
@@ -615,15 +615,42 @@ add_field (int file, int field)
outlist_end = o;
}
+/* Convert a string of decimal digits, STR (the 1-based join field number),
+ to an integral value. Upon successful conversion, return one less
+ (the zero-based field number). If it cannot be converted, give a
+ diagnostic and exit. */
+
+size_t
+string_to_join_field (char const *str, char const *err_msg_fmt)
+{
+ size_t result;
+ uintmax_t val;
+
+ strtol_error s_err = xstrtoumax (str, NULL, 10, &val, "");
+ if (s_err == LONGINT_OVERFLOW || SIZE_MAX < val)
+ {
+ error (EXIT_FAILURE, 0,
+ _("value %s is so large that it is not representable"),
+ quote (str));
+ }
+
+ if (s_err != LONGINT_OK || val == 0)
+ error (EXIT_FAILURE, 0, err_msg_fmt, quote (str));
+
+ result = val - 1;
+
+ return result;
+}
+
/* Convert a single field specifier string, S, to a *FILE_INDEX, *FIELD_INDEX
pair. In S, the field index string is 1-based; *FIELD_INDEX is zero-based.
- If S is valid, return zero. Otherwise, give a diagnostic, don't update
- *FILE_INDEX or *FIELD_INDEX, and return nonzero. */
+ If S is valid, return false. Otherwise, give a diagnostic, don't update
+ *FILE_INDEX or *FIELD_INDEX, and return true. */
-static int
-decode_field_spec (const char *s, int *file_index, int *field_index)
+static bool
+decode_field_spec (const char *s, int *file_index, size_t *field_index)
{
- int invalid = 1;
+ bool invalid = true;
/* The first character must be 0, 1, or 2. */
switch (s[0])
@@ -632,9 +659,10 @@ decode_field_spec (const char *s, int *file_index, int *field_index)
if (s[1] == '\0')
{
*file_index = 0;
- /* Give *field_index an invalid value. */
- *field_index = -1;
- invalid = 0;
+ /* Give *field_index a value that won't affect things,
+ e.g. in `uni_blank.nfields = MAX (...'. */
+ *field_index = 0;
+ invalid = false;
}
else
{
@@ -647,21 +675,10 @@ decode_field_spec (const char *s, int *file_index, int *field_index)
case '2':
if (s[1] == '.' && s[2] != '\0')
{
- strtol_error s_err;
- long int tmp_long;
-
- s_err = xstrtol (s + 2, NULL, 10, &tmp_long, "");
- if (s_err != LONGINT_OK || tmp_long <= 0 || tmp_long > INT_MAX)
- {
- error (0, 0, _("invalid field number: `%s'"), s + 2);
- }
- else
- {
- *file_index = s[0] - '0';
- /* Convert to a zero-based index. */
- *field_index = (int) tmp_long - 1;
- invalid = 0;
- }
+ *field_index
+ = string_to_join_field (s + 2, _("invalid field number: %s"));
+ *file_index = s[0] - '0';
+ invalid = false;
}
break;
@@ -687,8 +704,9 @@ add_field_list (const char *c_str)
p = str;
do
{
- int invalid;
- int file_index, field_index;
+ bool invalid;
+ int file_index;
+ size_t field_index;
char *spec_item = p;
p = strpbrk (p, ", \t");
@@ -698,7 +716,7 @@ add_field_list (const char *c_str)
if (invalid)
return 1;
add_field (file_index, field_index);
- uni_blank.nfields = max (uni_blank.nfields, field_index);
+ uni_blank.nfields = MAX (uni_blank.nfields, field_index);
}
while (p);
return 0;
@@ -707,16 +725,16 @@ add_field_list (const char *c_str)
/* Create a blank line with COUNT fields separated by tabs. */
static void
-make_blank (struct line *blank, int count)
+make_blank (struct line *blank, size_t count)
{
- int i;
+ size_t i;
unsigned char *buffer;
struct field *fields;
blank->nfields = count;
blank->buf.size = blank->buf.length = count + 1;
blank->buf.buffer = xmalloc (blank->buf.size);
buffer = (unsigned char *) blank->buf.buffer;
- blank->fields = fields = xmalloc (count * sizeof *fields);
+ blank->fields = fields = xnmalloc (count, sizeof *fields);
for (i = 0; i < count; i++)
{
buffer[i] = '\t';
@@ -747,7 +765,7 @@ main (int argc, char **argv)
uni_blank.nfields = 1;
nfiles = 0;
- print_pairables = 1;
+ print_pairables = true;
while ((optc = getopt_long_only (argc, argv, "-a:e:i1:2:o:t:v:", longopts,
NULL)) != -1)
@@ -760,7 +778,7 @@ main (int argc, char **argv)
break;
case 'v':
- print_pairables = 0;
+ print_pairables = false;
/* Fall through. */
case 'a':
@@ -768,9 +786,9 @@ main (int argc, char **argv)
|| (val != 1 && val != 2))
error (EXIT_FAILURE, 0, _("invalid field number: `%s'"), optarg);
if (val == 1)
- print_unpairables_1 = 1;
+ print_unpairables_1 = true;
else
- print_unpairables_2 = 1;
+ print_unpairables_2 = true;
break;
case 'e':
@@ -778,32 +796,25 @@ main (int argc, char **argv)
break;
case 'i':
- ignore_case = 1;
+ ignore_case = true;
break;
case '1':
- if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK
- || val <= 0 || val > INT_MAX)
- {
- error (EXIT_FAILURE, 0,
- _("invalid field number for file 1: `%s'"), optarg);
- }
- join_field_1 = (int) val - 1;
+ join_field_1 =
+ string_to_join_field (optarg,
+ _("invalid field number for file 1: `%s'"));
break;
case '2':
- if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK
- || val <= 0 || val > INT_MAX)
- error (EXIT_FAILURE, 0,
- _("invalid field number for file 2: `%s'"), optarg);
- join_field_2 = (int) val - 1;
+ join_field_2 =
+ string_to_join_field (optarg,
+ _("invalid field number for file 2: `%s'"));
break;
case 'j':
- if (xstrtol (optarg, NULL, 10, &val, "") != LONGINT_OK
- || val <= 0 || val > INT_MAX)
- error (EXIT_FAILURE, 0, _("invalid field number: `%s'"), optarg);
- join_field_1 = join_field_2 = (int) val - 1;
+ join_field_1 = join_field_2 =
+ string_to_join_field (optarg,
+ _("invalid field number: `%s'"));
break;
case 'o':