+Sun May 15 23:38:10 2005 Ben Pfaff <blp@gnu.org>
+
+ Fix rest of PR 13054.
+
+ * format.def: FMT_A should allow 255-character output. FMT_AHEX
+ should allow 510-character input and output.
+
+ * data-out.c: (num_to_string) Get rid of NEW_STYLE option.
+ (convert_E) Handle non-finite values.
+ (try_F) Rewrite.
+ (format_and_round) New function.
+ (convert_infinite) New function used by try_F() and convert_E().
+
+Sun May 15 23:36:55 2005 Ben Pfaff <blp@gnu.org>
+
+ Regularize string and buffer function names so that they make some
+ kind of sense.
+
+ * str.c: (mm_reverse) Rename buf_reverse(). Update all
+ references.
+ (mm_find_reverse) Rename buf_find_reverse(). Update all
+ references.
+ (mm_case_compare) Rename buf_compare_case(). Update all
+ references.
+ (st_compare_pad) Rename buf_compare_rpad(). Update all
+ references.
+ (str_compare_rpad) New function.
+ (st_bare_pad_copy) Rename buf_copy_str_rpad(). Update all
+ references.
+ (buf_copy_str_lpad) New function.
+ (st_bare_pad_len_copy) Rename buf_copy_rpad(). Update all
+ references.
+ (st_pad_copy) Rename str_copy_rpad(). Update all references.
+ (st_trim_copy) Rename str_copy_trunc(). Update all references.
+ (st_uppercase) Renamed str_uppercase(). Update all references.
+
Sat May 14 08:22:26 WST 2005 John Darrington <john@darrington.wattle.id.au>
* dfm-read.c: Fixed polarity of test in dfm-close-reader. Closes
Tue May 10 19:56:35 2005 Ben Pfaff <blp@gnu.org>
- Fix PR 13054.
+ Start to fix PR 13054.
* format.c: (check_input_specifier) Improve error message.
(check_input_specifier) Check F, COMMA, and DOLLAR formats for
|| func_index == FIN || func_index == FOUT)
&& ((src[0]->type == NUMERIC && arg[0].f > arg[1].f)
|| (src[0]->type == ALPHA
- && st_compare_pad (arg[0].c, strlen (arg[0].c),
- arg[1].c, strlen (arg[1].c)) > 0)))
+ && str_compare_rpad (arg[0].c, arg[1].c) > 0)))
{
union value t = arg[0];
arg[0] = arg[1];
assert (aw != NULL && bw != NULL);
/* Words that are the same don't conflict. */
- if (aw_len == bw_len && !mm_case_compare (aw, bw, aw_len))
+ if (aw_len == bw_len && !buf_compare_case (aw, bw, aw_len))
return 0;
/* Words that are otherwise the same in the first three letters
do conflict. */
return ((aw_len > 3 && bw_len > 3)
|| (aw_len == 3 && bw_len > 3)
- || (bw_len == 3 && aw_len > 3)) && !mm_case_compare (aw, bw, 3);
+ || (bw_len == 3 && aw_len > 3)) && !buf_compare_case (aw, bw, 3);
}
/* Returns nonzero if CMD can be confused with another command
word != NULL && word_idx < word_cnt;
word = find_word (word + word_len, &word_len), word_idx++)
if (word_len != strlen (words[word_idx])
- || mm_case_compare (word, words[word_idx], word_len))
+ || buf_compare_case (word, words[word_idx], word_len))
{
size_t match_chars = match_strings (word, word_len,
words[word_idx],
else
{
/* Variable name. */
- st_trim_copy (lvalue->var_name, tokid, sizeof lvalue->var_name);
+ str_copy_trunc (lvalue->var_name, sizeof lvalue->var_name, tokid);
lex_get ();
}
return lvalue;
}
}
else
- st_trim_copy (cnt->n, tokid, sizeof cnt->n);
+ str_copy_trunc (cnt->n, sizeof cnt->n, tokid);
lex_get ();
if (!lex_force_match ('='))
cur = &c->crit.s[n++];
cur->type = CNT_SINGLE;
cur->s = malloc (len + 1);
- st_pad_copy (cur->s, ds_c_str (&tokstr), len + 1);
+ str_copy_rpad (cur->s, len + 1, ds_c_str (&tokstr));
lex_get ();
lex_match (',');
p = i->s;
#else
memcpy (buf, i->s, i->e - i->s);
- mm_reverse (buf, i->e - i->s);
+ buf_reverse (buf, i->e - i->s);
p = buf;
#endif
if ((ep->can_abbreviate
&& lex_id_match_len (ep->name, strlen (ep->name), name, length))
|| (!ep->can_abbreviate && length == strlen (ep->name)
- && !mm_case_compare (name, ep->name, length)))
+ && !buf_compare_case (name, ep->name, length)))
{
*output = ep->value;
return true;
spec->input = input;
spec->v = v;
spec->fv = v->fv;
- st_trim_copy (spec->name, v->name, sizeof spec->name);
+ str_copy_trunc (spec->name, sizeof spec->name, v->name);
append_var_spec (first, last, spec);
}
for (i = 0; i < name_cnt; i++)
#include "var.h"
#include "debug-print.h"
-
-/* In older versions, numbers got their trailing zeros stripped.
- Newer versions leave them on when there's room. Comment this next
- line out for retro styling. */
-#define NEW_STYLE 1
\f
/* Public functions. */
static numeric_converter convert_Z, convert_IB, convert_P, convert_PIB;
static numeric_converter convert_PIBHEX, convert_PK, convert_RB;
static numeric_converter convert_RBHEX, convert_CCx, convert_date;
-static numeric_converter convert_time, convert_WKDAY, convert_MONTH, try_F;
+static numeric_converter convert_time, convert_WKDAY, convert_MONTH;
+
+static numeric_converter try_F, convert_infinite;
typedef int string_converter (char *, const struct fmt_spec *, const char *);
static string_converter convert_A, convert_AHEX;
void
num_to_string (double v, char *s, int w, int d)
{
- /* Dummy to pass to convert_F. */
struct fmt_spec f;
-
-#if !NEW_STYLE
- /* Pointer to `.' in S. */
- char *decp;
-
- /* Pointer to `E' in S. */
- char *expp;
-
- /* Number of characters to delete. */
- int n = 0;
-#endif
-
+ f.type = FMT_F;
f.w = w;
f.d = d;
-
- /* Cut out the jokers. */
- if (!finite (v))
- {
- char temp[9];
- int len;
-
- if (isnan (v))
- {
- memcpy (temp, "NaN", 3);
- len = 3;
- }
- else if (isinf (v))
- {
- memcpy (temp, "+Infinity", 9);
- if (v < 0)
- temp[0] = '-';
- len = 9;
- }
- else
- {
- memcpy (temp, _("Unknown"), 7);
- len = 7;
- }
- if (w > len)
- {
- int pad = w - len;
- memset (s, ' ', pad);
- s += pad;
- w -= pad;
- }
- memcpy (s, temp, w);
- return;
- }
-
- try_F (s, &f, v);
-
-#if !NEW_STYLE
- decp = memchr (s, set_decimal, w);
- if (!decp)
- return;
-
- /* If there's an `E' we can only delete 0s before the E. */
- expp = memchr (s, 'E', w);
- if (expp)
- {
- while (expp[-n - 1] == '0')
- n++;
- if (expp[-n - 1] == set_decimal)
- n++;
- memmove (&s[n], s, expp - s - n);
- memset (s, ' ', n);
- return;
- }
-
- /* Otherwise delete all trailing 0s. */
- n++;
- while (s[w - n] == '0')
- n++;
- if (s[w - n] != set_decimal)
- {
- /* Avoid stripping `.0' to `'. */
- if (w == n || !isdigit ((unsigned char) s[w - n - 1]))
- n -= 2;
- }
- else
- n--;
- memmove (&s[n], s, w - n);
- memset (s, ' ', n);
-#endif
+ convert_F (s, &f, v);
}
\f
/* Main conversion functions. */
#error Write your own floating-point output routines.
#endif
-/* PORTME:
-
- Some of the routines in this file are likely very specific to
- base-2 representation of floating-point numbers, most notably the
- routines that use frexp() or ldexp(). These attempt to extract
- individual digits by setting the base-2 exponent and
- multiplying/dividing by powers of 2. In base-2 numeration systems,
- this just nudges the exponent up or down, but in base-10 floating
- point, such multiplications/division can cause catastrophic loss of
- precision.
-
- The author has never personally used a machine that didn't use
- binary floating point formats, so he is unwilling, and perhaps
- unable, to code around this "problem". */
-
/* Converts a number between 0 and 15 inclusive to a `hexit'
[0-9A-F]. */
#define MAKE_HEXIT(X) ("0123456789ABCDEF"[X])
/* Ranged number of decimal places. */
int d;
- /* Check that the format is width enough.
+ if (!finite (number))
+ return convert_infinite (dst, fp, number);
+
+ /* Check that the format is wide enough.
Although PSPP generally checks this, convert_E() can be called as
a fallback from other formats which do not check. */
if (fp->w < 6)
}
memcpy (dst, temp, fp->w);
#ifndef WORDS_BIGENDIAN
- mm_reverse (dst, fp->w);
+ buf_reverse (dst, fp->w);
#endif
return 1;
((unsigned char *) dst)[i] = floor (frac);
}
#ifndef WORDS_BIGENDIAN
- mm_reverse (dst, fp->w);
+ buf_reverse (dst, fp->w);
#endif
return 1;
if (buf[0] == 0)
return 0;
- st_bare_pad_copy (dst, buf, fp->w);
+ buf_copy_str_rpad (dst, fp->w, buf);
return 1;
}
cp = spprintf (cp, ":%0*.*f", w, d, fmod (time, 60.));
}
- st_bare_pad_copy (dst, temp_buf, fp->w);
+ buf_copy_str_rpad (dst, fp->w, temp_buf);
return 1;
}
(double) wkday);
return 0;
}
- st_bare_pad_copy (dst, weekdays[(int) wkday - 1], fp->w);
+ buf_copy_str_rpad (dst, fp->w, weekdays[(int) wkday - 1]);
return 1;
}
return 0;
}
- st_bare_pad_copy (dst, months[(int) month - 1], fp->w);
+ buf_copy_str_rpad (dst, fp->w, months[(int) month - 1]);
return 1;
}
return 1;
}
-/* This routine relies on the underlying implementation of sprintf:
-
- If the number has a magnitude 1e40 or greater, then we needn't
- bother with it, since it's guaranteed to need processing in
- scientific notation.
-
- Otherwise, do a binary search for the base-10 magnitude of the
- thing. log10() is not accurate enough, and the alternatives are
- frightful. Besides, we never need as many as 6 (pairs of)
- comparisons. The algorithm used for searching is Knuth's Algorithm
- 6.2.1C (Uniform binary search).
+static int
+format_and_round (char *dst, double number, const struct fmt_spec *fp,
+ int decimals);
- DON'T CHANGE ANYTHING HERE UNLESS YOU'VE THOUGHT ABOUT IT FOR A
- LONG TIME! The rest of the program is heavily dependent on
- specific properties of this routine's output. LOG ALL CHANGES! */
+/* Tries to format NUMBER into DST as the F format specified in
+ *FP. Return true if successful, false on failure. */
static int
try_F (char *dst, const struct fmt_spec *fp, double number)
{
- /* This is the DELTA array from Knuth.
- DELTA[j] = floor((40+2**(j-1))/(2**j)). */
- static const int delta[8] =
- {
- 0, (40 + 1) / 2, (40 + 2) / 4, (40 + 4) / 8, (40 + 8) / 16,
- (40 + 16) / 32, (40 + 32) / 64, (40 + 64) / 128,
- };
+ assert (fp->w <= 40);
+ if (finite (number))
+ {
+ if (fabs (number) < power10[fp->w])
+ {
+ /* The value may fit in the field. */
+ if (fp->d == 0)
+ {
+ /* There are no decimal places, so there's no way
+ that the value can be shortened. Either it fits
+ or it doesn't. */
+ char buf[40];
+ sprintf (buf, "%*.0f", fp->w, number);
+ if (strlen (buf) <= fp->w)
+ {
+ buf_copy_str_lpad (dst, fp->w, buf);
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ /* First try to format it with 2 extra decimal
+ places. This gives us a good chance of not
+ needing even more decimal places, but it also
+ avoids wasting too much time formatting more
+ decimal places on the first try. */
+ int result = format_and_round (dst, number, fp, fp->d + 2);
+ if (result >= 0)
+ return result;
+
+ /* 2 extra decimal places weren't enough to
+ correctly round. Try again with the maximum
+ number of places. */
+ return format_and_round (dst, number, fp, LDBL_DIG + 1);
+ }
+ }
+ else
+ {
+ /* The value is too big to fit in the field. */
+ return false;
+ }
+ }
+ else
+ return convert_infinite (dst, fp, number);
+}
- /* The number of digits in floor(number), including sign. This
- is `i' from Knuth. */
- int n_int = (40 + 1) / 2;
+/* Tries to compose NUMBER into DST in format FP by first
+ formatting it with DECIMALS decimal places, then rounding off
+ to as many decimal places will fit or the number specified in
+ FP, whichever is fewer.
- /* Used to step through delta[]. This is `j' from Knuth. */
- int j = 2;
+ Returns 1 if conversion succeeds, 0 if this try at conversion
+ failed and so will any other tries (because the integer part
+ of the number is too long), or -1 if this try failed but
+ another with higher DECIMALS might succeed (because we'd be
+ able to properly round). */
+static int
+format_and_round (char *dst, double number, const struct fmt_spec *fp,
+ int decimals)
+{
+ /* Number of characters before the decimal point,
+ which includes digits and possibly a minus sign. */
+ int predot_chars;
- /* Magnitude of number. This is `K' from Knuth. */
- double mag;
+ /* Number of digits in the output fraction,
+ which may be smaller than fp->d if there's not enough room. */
+ int fraction_digits;
- /* Number of characters for the fractional part, including the
- decimal point. */
- int n_dec;
+ /* Points to last digit that will remain in the fraction after
+ rounding. */
+ char *final_frac_dig;
- /* Pointer into buf used for formatting. */
- char *cp;
+ /* Round up? */
+ bool round_up;
+
+ char buf[128];
+
+ assert (decimals > fp->d);
+ if (decimals > LDBL_DIG)
+ decimals = LDBL_DIG + 1;
- /* Used to count characters formatted by nsprintf(). */
- int n;
+ sprintf (buf, "%.*f", decimals, number);
- /* Temporary buffer. */
- char buf[128];
+ if (!memcmp (buf, "0.", 2))
+ memmove (buf, buf + 1, strlen (buf));
+ else if (!memcmp (buf, "-0.", 3))
+ memmove (buf + 1, buf + 2, strlen (buf + 1));
- /* First check for infinities and NaNs. 12/13/96. */
- if (!finite (number))
+ predot_chars = strcspn (buf, ".");
+ if (predot_chars > fp->w)
{
- n = nsprintf (buf, "%f", number);
- if (n > fp->w)
- memset (buf, '*', fp->w);
- else if (n < fp->w)
- {
- memmove (&buf[fp->w - n], buf, n);
- memset (buf, ' ', fp->w - n);
- }
+ /* Can't possibly fit. */
+ return 0;
+ }
+ else if (predot_chars == fp->w)
+ {
+ /* Exact fit for integer part and sign. */
memcpy (dst, buf, fp->w);
return 1;
}
+ else if (predot_chars + 1 == fp->w)
+ {
+ /* There's room for the decimal point, but not for any
+ digits of the fraction.
+ Right-justify the integer part and sign. */
+ dst[0] = ' ';
+ memcpy (dst + 1, buf, fp->w);
+ return 1;
+ }
- /* Then check for radically out-of-range values. */
- mag = fabs (number);
- if (mag >= power10[fp->w])
- return 0;
+ /* It looks like we have room for at least one digit of the
+ fraction. Figure out how many. */
+ fraction_digits = fp->w - predot_chars - 1;
+ if (fraction_digits > fp->d)
+ fraction_digits = fp->d;
+ final_frac_dig = buf + predot_chars + fraction_digits;
- if (mag < 1.0)
+ /* Decide rounding direction and truncate string. */
+ if (final_frac_dig[1] == '5'
+ && strspn (final_frac_dig + 2, "0") == strlen (final_frac_dig + 2))
{
- n_int = 0;
-
- /* Avoid printing `-.000'. 7/6/96. */
- if (mag < EPSILON)
- number = 0.0;
+ /* Exactly 1/2. */
+ if (decimals <= LDBL_DIG)
+ {
+ /* Don't have enough fractional digits to know which way to
+ round. We can format with more decimal places, so go
+ around again. */
+ return -1;
+ }
+ else
+ {
+ /* We used up all our fractional digits and still don't
+ know. Round to even. */
+ round_up = (final_frac_dig[0] - '0') % 2 != 0;
+ }
}
else
- /* Now perform a `uniform binary search' based on the tables
- power10[] and delta[]. After this step, nint is the number of
- digits in floor(number), including any sign. */
- for (;;)
- {
- if (mag >= power10[n_int])
- {
- assert (delta[j]);
- n_int += delta[j++];
- }
- else if (mag < power10[n_int - 1])
- {
- assert (delta[j]);
- n_int -= delta[j++];
- }
- else
- break;
- }
-
- /* If we have any decimal places, then there is a decimal point,
- too. */
- n_dec = fp->d;
- if (n_dec)
- n_dec++;
+ round_up = final_frac_dig[1] >= '5';
+ final_frac_dig[1] = '\0';
- /* 1/10/96: If there aren't any digits at all, add one. This occurs
- only when fabs(number) < 1.0. */
- if (n_int + n_dec == 0)
- n_int++;
+ /* Do rounding. */
+ if (round_up)
+ {
+ char *cp = final_frac_dig;
+ for (;;)
+ {
+ if (*cp >= '0' && *cp <= '8')
+ {
+ (*cp)++;
+ break;
+ }
+ else if (*cp == '9')
+ *cp = '0';
+ else
+ assert (*cp == '.');
+
+ if (cp == buf || *--cp == '-')
+ {
+ size_t length;
+
+ /* Tried to go past the leftmost digit. Insert a 1. */
+ memmove (cp + 1, cp, strlen (cp) + 1);
+ *cp = '1';
+
+ length = strlen (buf);
+ if (length > fp->w)
+ {
+ /* Inserting the `1' overflowed our space.
+ Drop a decimal place. */
+ buf[--length] = '\0';
+
+ /* If that was the last decimal place, drop the
+ decimal point too. */
+ if (buf[length - 1] == '.')
+ buf[length - 1] = '\0';
+ }
+
+ break;
+ }
+ }
+ }
- /* Give space for a minus sign. Moved 1/10/96. */
- if (number < 0)
- n_int++;
+ buf_copy_str_lpad (dst, fp->w, buf);
+ return 1;
+}
- /* Normally we only go through the loop once; occasionally twice.
- Three times or more indicates a very serious bug somewhere. */
- for (;;)
+/* Formats non-finite NUMBER into DST according to the width
+ given in FP. */
+static int
+convert_infinite (char *dst, const struct fmt_spec *fp, double number)
+{
+ assert (!finite (number));
+
+ if (fp->w >= 3)
{
- /* Check out the total length of the string. */
- cp = buf;
- if (n_int + n_dec > fp->w)
- {
- /* The string is too long. Let's see what can be done. */
- if (n_int <= fp->w)
- /* If we can, just reduce the number of decimal places. */
- n_dec = fp->w - n_int;
- else
- return 0;
- }
- else if (n_int + n_dec < fp->w)
- {
- /* The string is too short. Left-pad with spaces. */
- int n_spaces = fp->w - n_int - n_dec;
- memset (cp, ' ', n_spaces);
- cp += n_spaces;
- }
+ const char *s;
- /* Finally, format the number. */
- if (n_dec)
- n = nsprintf (cp, "%.*f", n_dec - 1, number);
+ if (isnan (number))
+ s = "NaN";
+ else if (isinf (number))
+ s = number > 0 ? "+Infinity" : "-Infinity";
else
- n = nsprintf (cp, "%.0f", number);
+ s = "Unknown";
- /* If number is positive and its magnitude is less than
- 1... */
- if (n_int == 0)
- {
- if (*cp == '0')
- {
- /* The value rounds to `.###'. */
- memmove (cp, &cp[1], n - 1);
- n--;
- }
- else
- {
- /* The value rounds to `1.###'. */
- n_int = 1;
- continue;
- }
- }
- /* Else if number is negative and its magnitude is less
- than 1... */
- else if (number < 0 && n_int == 1)
- {
- if (cp[1] == '0')
- {
- /* The value rounds to `-.###'. */
- memmove (&cp[1], &cp[2], n - 2);
- n--;
- }
- else
- {
- /* The value rounds to `-1.###'. */
- n_int = 2;
- continue;
- }
- }
-
- /* Check for a correct number of digits & decimal places & stuff.
- This is just a desperation check. Hopefully it won't fail too
- often, because then we have to run through the whole loop again:
- sprintf() is not a fast operation with floating-points! */
- if (n == n_int + n_dec)
- {
- /* Convert periods `.' to commas `,' for our foreign friends. */
- if ((get_decimal() == ',' && fp->type != FMT_DOT)
- || (get_decimal() == '.' && fp->type == FMT_DOT))
- {
- cp = strchr (cp, '.');
- if (cp)
- *cp = ',';
- }
-
- memcpy (dst, buf, fp->w);
- return 1;
- }
-
- n_int = n - n_dec; /* FIXME? Need an idiot check on resulting n_int? */
+ buf_copy_str_lpad (dst, fp->w, s);
}
+ else
+ memset (dst, '*', fp->w);
+
+ return true;
}
/* Try a name based on the original variable name. */
name[0] = 'Z';
- st_trim_copy (name + 1, var_name, sizeof name - 1);
+ str_copy_trunc (name + 1, sizeof name - 1, var_name);
if (try_name (dsc, name))
{
strcpy (z_name, name);
/* Allocate and initialize variable. */
v = xmalloc (sizeof *v);
- st_trim_copy (v->name, name, sizeof v->name);
+ str_copy_trunc (v->name, sizeof v->name, name);
v->type = width == 0 ? NUMERIC : ALPHA;
v->width = width;
v->fv = d->next_value_idx;
assert (d != NULL);
assert (name != NULL);
- st_trim_copy (v.name, name, sizeof v.name);
+ str_copy_trunc (v.name, sizeof v.name, name);
return hsh_find (d->name_tab, &v);
}
|| dict_lookup_var (d, new_name) == NULL);
hsh_force_delete (d->name_tab, v);
- st_trim_copy (v->name, new_name, sizeof v->name);
+ str_copy_trunc (v->name, sizeof v->name, new_name);
hsh_force_insert (d->name_tab, v);
if (get_algorithm () == ENHANCED)
d->vector = xrealloc (d->vector, (d->vector_cnt + 1) * sizeof *d->vector);
vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector);
vector->idx = d->vector_cnt++;
- st_trim_copy (vector->name, name, sizeof vector->name);
+ str_copy_trunc (vector->name, sizeof vector->name, name);
vector->var = xmalloc (cnt * sizeof *var);
for (i = 0; i < cnt; i++)
{
assert (e->type == OP_string);
assert ((dst == NULL) == (dst_size == 0));
expr_evaluate (e, c, case_idx, &s);
- st_bare_pad_len_copy (dst, s.string, dst_size, s.length);
+ buf_copy_rpad (dst, dst_size, s.string, s.length);
}
\f
#include "lexer.h"
size_t name_len = strcspn (*name, ".");
if (test_len == name_len)
{
- if (mm_case_compare (*test, *name, test_len))
+ if (buf_compare_case (*test, *name, test_len))
return false;
}
else if (test_len < 3 || test_len > name_len)
return false;
else
{
- if (mm_case_compare (*test, *name, test_len))
+ if (buf_compare_case (*test, *name, test_len))
return false;
}
if (!lex_force_id ())
return CMD_FAILURE;
- st_trim_copy (handle_name, tokid, sizeof handle_name);
+ str_copy_trunc (handle_name, sizeof handle_name, tokid);
handle = get_handle_with_name (handle_name);
if (handle != NULL)
if (!lex_force_string ())
goto error;
rct->v[rct->nv].c = xmalloc (fty->record.nc + 1);
- st_bare_pad_copy (rct->v[rct->nv].c, ds_c_str (&tokstr),
- fty->record.nc + 1);
+ buf_copy_str_rpad (rct->v[rct->nv].c, fty->record.nc + 1,
+ ds_c_str (&tokstr));
}
else
{
if (len == 1 && filename[0] == '/')
p = filename + 1;
else if (len && filename[len - 1] == DIR_SEPARATOR)
- p = mm_find_reverse (filename, len - 1, filename + len - 1, 1);
+ p = buf_find_reverse (filename, len - 1, filename + len - 1, 1);
else
p = strrchr (filename, DIR_SEPARATOR);
if (p == NULL)
*cp = '_';
}
*cp = '\0';
- st_uppercase (name);
+ str_uppercase (name);
if (dict_create_var (default_dict, name, 0))
return 1;
/* Write variable names as first case. */
for (i = 0; i < flip->var_cnt; i++)
- st_bare_pad_copy (info->output_buf[i].s, flip->var[i]->name, MAX_SHORT_STRING);
+ buf_copy_str_rpad (info->output_buf[i].s, MAX_SHORT_STRING,
+ flip->var[i]->name);
if (fwrite (info->output_buf, sizeof *info->output_buf,
flip->var_cnt, flip->file) != (size_t) flip->var_cnt)
msg (FE, _("Error writing FLIP file: %s."), strerror (errno));
{
char name[INT_DIGITS + 2];
sprintf (name, "V%d", (int) f);
- st_trim_copy (v->name, name, sizeof v->name);
+ str_copy_trunc (v->name, sizeof v->name, name);
}
}
else
/* Find format. */
for (idx = 0; idx < FMT_NUMBER_OF_FORMATS; idx++)
if (strlen (formats[idx].name) == ep - sp
- && !mm_case_compare (formats[idx].name, sp, ep - sp))
+ && !buf_compare_case (formats[idx].name, sp, ep - sp))
break;
/* Check format. */
DEFFMT (FMT_DOLLAR, "DOLLAR", 2, 1, 40, 2, 40, 0001, FMT_DOLLAR, 4)
DEFFMT (FMT_PCT, "PCT", 2, 1, 40, 2, 40, 0001, FMT_PCT, 31)
DEFFMT (FMT_Z, "Z", 2, 1, 40, 1, 40, 0011, FMT_F, 15)
-DEFFMT (FMT_A, "A", 1, 1, 255, 1, 254, 0004, FMT_A, 1)
-DEFFMT (FMT_AHEX, "AHEX", 1, 2, 254, 2, 510, 0006, FMT_A, 2)
+DEFFMT (FMT_A, "A", 1, 1, 255, 1, 255, 0004, FMT_A, 1)
+DEFFMT (FMT_AHEX, "AHEX", 1, 2, 510, 2, 510, 0006, FMT_A, 2)
DEFFMT (FMT_IB, "IB", 2, 1, 8, 1, 8, 0010, FMT_F, 6)
DEFFMT (FMT_P, "P", 2, 1, 16, 1, 16, 0011, FMT_F, 8)
DEFFMT (FMT_PIB, "PIB", 2, 1, 8, 1, 8, 0010, FMT_F, 9)
assert (put_token != 0);
token = put_token;
ds_replace (&tokstr, ds_c_str (&put_tokstr));
- st_trim_copy (tokid, ds_c_str (&tokstr), sizeof tokid);
+ str_copy_trunc (tokid, sizeof tokid, ds_c_str (&tokstr));
tokval = put_tokval;
put_token = 0;
}
ds_putc (&tokstr, *prog++);
/* Copy tokstr to tokid, possibly truncating it.*/
- st_trim_copy (tokid, ds_c_str (&tokstr), sizeof tokid);
+ str_copy_trunc (tokid, sizeof tokid, ds_c_str (&tokstr));
/* Determine token type. */
token = lex_id_to_token (ds_c_str (&tokstr), ds_length (&tokstr));
save_token ();
token = T_ID;
ds_replace (&tokstr, id);
- st_trim_copy (tokid, ds_c_str (&tokstr), sizeof tokid);
+ str_copy_trunc (tokid, sizeof tokid, ds_c_str (&tokstr));
}
\f
/* Weird line processing functions. */
int type = content_type[content];
{
- st_bare_pad_copy (case_data_rw (c, mx->rowtype_->fv)->s,
- content_names[content], 8);
+ buf_copy_str_rpad (case_data_rw (c, mx->rowtype_->fv)->s, 8,
+ content_names[content]);
if (type != 1)
memset (case_data_rw (c, mx->varname_->fv)->s, ' ', 8);
cp++;
}
if (type == 1)
- st_bare_pad_copy (case_data_rw (c, mx->varname_->fv)->s,
- dict_get_var (default_dict,
- mx->first_continuous + i)->name,
- 8);
+ buf_copy_str_rpad (case_data_rw (c, mx->varname_->fv)->s, 8,
+ dict_get_var (default_dict,
+ mx->first_continuous + i)->name);
write_case (wc_data);
}
}
info->creation_time[8] = 0;
/* Product. */
- st_trim_copy (info->product, product, sizeof info->product);
- st_trim_copy (info->subproduct, subproduct, sizeof info->subproduct);
+ str_copy_trunc (info->product, sizeof info->product, product);
+ str_copy_trunc (info->subproduct, sizeof info->subproduct, subproduct);
}
}
if (!var_is_valid_name (name, false) || *name == '#' || *name == '$')
error (r, _("position %d: Invalid variable name `%s'."), name);
- st_uppercase (name);
+ str_uppercase (name);
if (width < 0 || width > 255)
error (r, "Bad width %d for variable %s.", width, name);
{
char string[256];
read_string (r, string);
- st_bare_pad_copy (v.s, string, 8);
+ buf_copy_str_rpad (v.s, 8, string);
}
else
v.f = read_float (r);
{
char string[256];
read_string (r, string);
- st_bare_pad_copy (case_data_rw (c, idx)->s, string, width);
+ buf_copy_str_rpad (case_data_rw (c, idx)->s, width, string);
idx += DIV_RND_UP (width, MAX_SHORT_STRING);
}
}
/* The NULL is only really necessary for the
debugging code. */
char *repl = xmalloc (max_dst_width + 1);
- st_pad_copy (repl, cp->t.c, max_dst_width + 1);
+ str_copy_rpad (repl, max_dst_width + 1, cp->t.c);
free (cp->t.c);
cp->t.c = repl;
}
if (toklen > max)
max = toklen;
v->c = xmalloc (max + 1);
- st_pad_copy (v->c, ds_c_str (&tokstr), max + 1);
+ str_copy_rpad (v->c, max + 1, ds_c_str (&tokstr));
flags = RCD_DEST_STRING;
*max_dst_width = max;
lex_get ();
if (!lex_force_string ())
return 0;
c->f1.c = xmalloc (max_src_width + 1);
- st_pad_copy (c->f1.c, ds_c_str (&tokstr), max_src_width + 1);
+ str_copy_rpad (c->f1.c, max_src_width + 1, ds_c_str (&tokstr));
lex_get ();
}
}
if (val == NULL)
{
if (v->dest->fv != v->src->fv)
- st_bare_pad_len_copy (case_data_rw (c, v->dest->fv)->s,
- case_str (c, v->src->fv),
- v->dest->width, v->src->width);
+ buf_copy_rpad (case_data_rw (c, v->dest->fv)->s,
+ v->dest->width,
+ case_str (c, v->src->fv), v->src->width);
}
else
memcpy (case_data_rw (c, v->dest->fv)->s, cp->t.c, v->dest->width);
if (label == NULL)
label = "";
- st_bare_pad_copy (hdr.file_label, label, sizeof hdr.file_label);
+ buf_copy_str_rpad (hdr.file_label, sizeof hdr.file_label, label);
}
memset (hdr.padding, 0, sizeof hdr.padding);
sv.n_missing_values = nm;
write_format_spec (&v->print, &sv.print);
write_format_spec (&v->write, &sv.write);
- st_bare_pad_copy (sv.name, v->short_name, sizeof sv.name);
+ buf_copy_str_rpad (sv.name, sizeof sv.name, v->short_name);
if (!buf_write (w, &sv, sizeof sv))
return 0;
/* Reverses the order of NBYTES bytes at address P, thus converting
between little- and big-endian byte orders. */
void
-mm_reverse (void *p, size_t nbytes)
+buf_reverse (char *p, size_t nbytes)
{
unsigned char *h = p, *t = &h[nbytes - 1];
unsigned char temp;
/* Finds the last NEEDLE of length NEEDLE_LEN in a HAYSTACK of length
HAYSTACK_LEN. Returns a pointer to the needle found. */
char *
-mm_find_reverse (const char *haystack, size_t haystack_len,
+buf_find_reverse (const char *haystack, size_t haystack_len,
const char *needle, size_t needle_len)
{
int i;
/* Compares the SIZE bytes in A to those in B, disregarding case,
and returns a strcmp()-type result. */
int
-mm_case_compare (const void *a_, const void *b_, size_t size)
+buf_compare_case (const char *a_, const char *b_, size_t size)
{
- const unsigned char *a = a_;
- const unsigned char *b = b_;
+ const unsigned char *a = (unsigned char *) a_;
+ const unsigned char *b = (unsigned char *) b_;
while (size-- > 0)
{
string is considered to be padded with spaces to the length of
the longer. */
int
-st_compare_pad (const char *a, size_t a_len, const char *b, size_t b_len)
+buf_compare_rpad (const char *a, size_t a_len, const char *b, size_t b_len)
{
size_t min_len;
int result;
}
}
-/* Copies SRC to DEST, truncating to N characters or right-padding
- with spaces to N characters as necessary. Does not append a null
- character. SRC must be null-terminated. */
-void
-st_bare_pad_copy (char *dest, const char *src, size_t n)
+/* Compares strin A to string B. The shorter string is
+ considered to be padded with spaces to the length of the
+ longer. */
+int
+str_compare_rpad (const char *a, const char *b)
{
- size_t len;
+ return buf_compare_rpad (a, strlen (a), b, strlen (b));
+}
- len = strlen (src);
- if (len >= n)
- memcpy (dest, src, n);
+/* Copies string SRC to buffer DST, of size DST_SIZE bytes.
+ DST is truncated to DST_SIZE bytes or padded on the right with
+ spaces as needed. */
+void
+buf_copy_str_rpad (char *dst, size_t dst_size, const char *src)
+{
+ size_t src_len = strlen (src);
+ if (src_len >= dst_size)
+ memcpy (dst, src, dst_size);
else
{
- memcpy (dest, src, len);
- memset (&dest[len], ' ', n - len);
+ memcpy (dst, src, src_len);
+ memset (&dst[src_len], ' ', dst_size - src_len);
}
}
-/* Copies SRC to DEST, truncating SRC to N characters or right-padding
- with spaces to N characters if necessary. Does not append a null
- character. SRC must be LEN characters long but does not need to be
- null-terminated. */
+/* Copies string SRC to buffer DST, of size DST_SIZE bytes.
+ DST is truncated to DST_SIZE bytes or padded on the left with
+ spaces as needed. */
void
-st_bare_pad_len_copy (char *dest, const char *src, size_t n, size_t len)
+buf_copy_str_lpad (char *dst, size_t dst_size, const char *src)
{
- if (len >= n)
- memmove (dest, src, n);
+ size_t src_len = strlen (src);
+ if (src_len >= dst_size)
+ memcpy (dst, src, dst_size);
else
{
- memmove (dest, src, len);
- memset (&dest[len], ' ', n - len);
+ size_t pad_cnt = dst_size - src_len;
+ memset (&dst[0], ' ', pad_cnt);
+ memcpy (dst + pad_cnt, src, src_len);
}
}
-/* Copies SRC to DEST, truncating SRC to N-1 characters or
- right-padding with spaces to N-1 characters if necessary. Always
- appends a null character. */
+/* Copies buffer SRC, of SRC_SIZE bytes, to DST, of DST_SIZE bytes.
+ DST is truncated to DST_SIZE bytes or padded on the right with
+ spaces as needed. */
void
-st_pad_copy (char *dest, const char *src, size_t n)
+buf_copy_rpad (char *dst, size_t dst_size,
+ const char *src, size_t src_size)
{
- size_t len;
-
- len = strlen (src);
- if (len == n - 1)
- strcpy (dest, src);
- else if (len < n - 1)
+ if (src_size >= dst_size)
+ memmove (dst, src, dst_size);
+ else
{
- memcpy (dest, src, len);
- memset (&dest[len], ' ', n - 1 - len);
- dest[n - 1] = 0;
+ memmove (dst, src, src_size);
+ memset (&dst[src_size], ' ', dst_size - src_size);
}
- else
+}
+
+/* Copies string SRC to string DST, which is in a buffer DST_SIZE
+ bytes long.
+ Truncates DST to DST_SIZE - 1 characters or right-pads with
+ spaces to DST_SIZE - 1 characters if necessary. */
+void
+str_copy_rpad (char *dst, size_t dst_size, const char *src)
+{
+ size_t src_len = strlen (src);
+ if (src_len < dst_size - 1)
{
- memcpy (dest, src, n - 1);
- dest[n - 1] = 0;
+ memcpy (dst, src, src_len);
+ memset (&dst[src_len], ' ', dst_size - 1 - src_len);
}
+ else
+ memcpy (dst, src, dst_size - 1);
+ dst[dst_size - 1] = 0;
}
-/* Copies SRC to DST, truncating DST to N-1 characters if
- necessary. Always appends a null character. */
+/* Copies SRC to DST, which is in a buffer DST_SIZE bytes long.
+ Truncates DST to DST_SIZE - 1 characters, if necessary. */
void
-st_trim_copy (char *dst, const char *src, size_t n)
+str_copy_trunc (char *dst, size_t dst_size, const char *src)
{
- size_t len = strlen (src);
- assert (n > 0);
- if (len + 1 < n)
- memcpy (dst, src, len + 1);
+ size_t src_len = strlen (src);
+ assert (dst_size > 0);
+ if (src_len + 1 < dst_size)
+ memcpy (dst, src, src_len + 1);
else
{
- memcpy (dst, src, n - 1);
- dst[n - 1] = '\0';
+ memcpy (dst, src, dst_size - 1);
+ dst[dst_size - 1] = '\0';
}
}
-
/* Converts each character in S to uppercase. */
void
-st_uppercase (char *s)
+str_uppercase (char *s)
{
for (; *s != '\0'; s++)
*s = toupper ((unsigned char) *s);
\f
/* Miscellaneous. */
-void mm_reverse (void *, size_t);
-char *mm_find_reverse (const char *, size_t, const char *, size_t);
-int mm_case_compare (const void *, const void *, size_t);
-
-int st_compare_pad (const char *, size_t, const char *, size_t);
-char *st_spaces (int);
-void st_bare_pad_copy (char *dest, const char *src, size_t n);
-void st_bare_pad_len_copy (char *dest, const char *src, size_t n, size_t len);
-void st_pad_copy (char *dest, const char *src, size_t n);
-void st_trim_copy (char *dest, const char *src, size_t n);
-void st_uppercase (char *);
+void buf_reverse (char *, size_t);
+char *buf_find_reverse (const char *, size_t, const char *, size_t);
+int buf_compare_case (const char *, const char *, size_t);
+int buf_compare_rpad (const char *, size_t, const char *, size_t);
+void buf_copy_rpad (char *, size_t, const char *, size_t);
+void buf_copy_str_lpad (char *, size_t, const char *);
+void buf_copy_str_rpad (char *, size_t, const char *);
+
+int str_compare_rpad (const char *, const char *);
+void str_copy_rpad (char *, size_t, const char *);
+void str_copy_trunc (char *, size_t, const char *);
+void str_uppercase (char *);
\f
/* Fixed-length strings. */
struct fixed_string
memcpy (new_documents, old_documents, old_len);
memset (new_documents + old_len, ' ', indent);
- st_bare_pad_copy (new_documents + old_len + indent, line, 80 - indent);
+ buf_copy_str_rpad (new_documents + old_len + indent, 80 - indent, line);
new_documents[old_len + 80] = '\0';
dict_set_documents (default_dict, new_documents);
lex_error (_("expecting string"));
return 0;
}
- st_bare_pad_copy (value.s, ds_c_str (&tokstr), MAX_SHORT_STRING);
+ buf_copy_str_rpad (value.s, MAX_SHORT_STRING, ds_c_str (&tokstr));
}
else
{
assert (v != NULL);
assert (short_name[0] == '\0' || var_is_valid_name (short_name, false));
- st_trim_copy (v->short_name, short_name, sizeof v->short_name);
- st_uppercase (v->short_name);
+ str_copy_trunc (v->short_name, sizeof v->short_name, short_name);
+ str_uppercase (v->short_name);
}
/* Clears V's short name. */