From 317e6b778833b5dcd5dd195c0b677835a8024b2a Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 16 May 2005 07:33:16 +0000 Subject: [PATCH] Fix rest of PR 13054. Regularize string and buffer function names so that they make some kind of sense. --- src/ChangeLog | 38 ++- src/aggregate.c | 3 +- src/command.c | 6 +- src/compute.c | 2 +- src/count.c | 4 +- src/data-in.c | 4 +- src/data-list.c | 2 +- src/data-out.c | 486 ++++++++++++++++--------------------- src/descript.c | 2 +- src/dictionary.c | 8 +- src/expressions/evaluate.c | 2 +- src/expressions/parse.c | 4 +- src/file-handle.q | 2 +- src/file-type.c | 4 +- src/filename.c | 2 +- src/flip.c | 7 +- src/format.c | 2 +- src/format.def | 4 +- src/lexer.c | 6 +- src/matrix-data.c | 11 +- src/pfm-read.c | 10 +- src/recode.c | 12 +- src/sfm-write.c | 4 +- src/str.c | 123 ++++++---- src/str.h | 23 +- src/title.c | 2 +- src/val-labs.c | 2 +- src/vars-atr.c | 4 +- 28 files changed, 380 insertions(+), 399 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 38401f8d..9039838e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,39 @@ +Sun May 15 23:38:10 2005 Ben Pfaff + + 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 + + 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 * dfm-read.c: Fixed polarity of test in dfm-close-reader. Closes @@ -11,7 +47,7 @@ Tue May 10 20:08:18 2005 Ben Pfaff Tue May 10 19:56:35 2005 Ben Pfaff - 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 diff --git a/src/aggregate.c b/src/aggregate.c index 154256f5..7f34309c 100644 --- a/src/aggregate.c +++ b/src/aggregate.c @@ -491,8 +491,7 @@ parse_aggregate_functions (struct agr_proc *agr) || 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]; diff --git a/src/command.c b/src/command.c index 1e9fd570..31854467 100644 --- a/src/command.c +++ b/src/command.c @@ -343,14 +343,14 @@ conflicting_3char_prefixes (const char *a, const char *b) 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 @@ -392,7 +392,7 @@ cmd_match_words (const struct command *cmd, 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], diff --git a/src/compute.c b/src/compute.c index 24148fe6..256b6a7e 100644 --- a/src/compute.c +++ b/src/compute.c @@ -353,7 +353,7 @@ lvalue_parse (void) 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; diff --git a/src/count.c b/src/count.c index 82085d6f..e3220d79 100644 --- a/src/count.c +++ b/src/count.c @@ -158,7 +158,7 @@ cmd_count (void) } } 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 ('=')) @@ -349,7 +349,7 @@ parse_string_criteria (struct counting * c) 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 (','); diff --git a/src/data-in.c b/src/data-in.c index d17a2cf7..3a49fa23 100644 --- a/src/data-in.c +++ b/src/data-in.c @@ -468,7 +468,7 @@ parse_IB (struct data_in *i) 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 @@ -760,7 +760,7 @@ parse_enum (struct data_in *i, const char *what, 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; diff --git a/src/data-list.c b/src/data-list.c index 1e9deb80..a6a68dc6 100644 --- a/src/data-list.c +++ b/src/data-list.c @@ -879,7 +879,7 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last) 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++) diff --git a/src/data-out.c b/src/data-out.c index 4289490b..6439b607 100644 --- a/src/data-out.c +++ b/src/data-out.c @@ -35,11 +35,6 @@ #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 /* Public functions. */ @@ -48,7 +43,9 @@ static numeric_converter convert_F, convert_N, convert_E, convert_F_plus; 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; @@ -196,92 +193,11 @@ data_out (char *s, const struct fmt_spec *fp, const union value *v) 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); } /* Main conversion functions. */ @@ -295,21 +211,6 @@ static int try_CCx (char *s, const struct fmt_spec *fp, double v); #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]) @@ -369,7 +270,10 @@ convert_E (char *dst, const struct fmt_spec *fp, double number) /* 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) @@ -561,7 +465,7 @@ convert_IB (char *dst, const struct fmt_spec *fp, double number) } memcpy (dst, temp, fp->w); #ifndef WORDS_BIGENDIAN - mm_reverse (dst, fp->w); + buf_reverse (dst, fp->w); #endif return 1; @@ -625,7 +529,7 @@ convert_PIB (char *dst, const struct fmt_spec *fp, double number) ((unsigned char *) dst)[i] = floor (frac); } #ifndef WORDS_BIGENDIAN - mm_reverse (dst, fp->w); + buf_reverse (dst, fp->w); #endif return 1; @@ -852,7 +756,7 @@ convert_date (char *dst, const struct fmt_spec *fp, double number) if (buf[0] == 0) return 0; - st_bare_pad_copy (dst, buf, fp->w); + buf_copy_str_rpad (dst, fp->w, buf); return 1; } @@ -902,7 +806,7 @@ convert_time (char *dst, const struct fmt_spec *fp, double number) 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; } @@ -922,7 +826,7 @@ convert_WKDAY (char *dst, const struct fmt_spec *fp, double wkday) (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; } @@ -943,7 +847,7 @@ convert_MONTH (char *dst, const struct fmt_spec *fp, double month) 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; } @@ -1121,201 +1025,225 @@ try_CCx (char *dst, const struct fmt_spec *fp, double number) 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; } diff --git a/src/descript.c b/src/descript.c index 57782c57..ba33b263 100644 --- a/src/descript.c +++ b/src/descript.c @@ -482,7 +482,7 @@ generate_z_varname (struct dsc_proc *dsc, char *z_name, /* 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); diff --git a/src/dictionary.c b/src/dictionary.c index d4ff2256..0fd59e11 100644 --- a/src/dictionary.c +++ b/src/dictionary.c @@ -268,7 +268,7 @@ dict_create_var (struct dictionary *d, const char *name, int width) /* 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; @@ -395,7 +395,7 @@ dict_lookup_var (const struct dictionary *d, const char *name) 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); } @@ -569,7 +569,7 @@ dict_rename_var (struct dictionary *d, struct variable *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) @@ -970,7 +970,7 @@ dict_create_vector (struct dictionary *d, 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++) { diff --git a/src/expressions/evaluate.c b/src/expressions/evaluate.c index b7f665d4..16076816 100644 --- a/src/expressions/evaluate.c +++ b/src/expressions/evaluate.c @@ -102,7 +102,7 @@ expr_evaluate_str (struct expression *e, const struct ccase *c, int case_idx, 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); } #include "lexer.h" diff --git a/src/expressions/parse.c b/src/expressions/parse.c index 15efe00b..a7064e03 100644 --- a/src/expressions/parse.c +++ b/src/expressions/parse.c @@ -881,14 +881,14 @@ word_matches (const char **test, const char **name) 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; } diff --git a/src/file-handle.q b/src/file-handle.q index 688fbb89..3f09d194 100644 --- a/src/file-handle.q +++ b/src/file-handle.q @@ -116,7 +116,7 @@ cmd_file_handle (void) 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) diff --git a/src/file-type.c b/src/file-type.c index 6a706eec..b90ae184 100644 --- a/src/file-type.c +++ b/src/file-type.c @@ -450,8 +450,8 @@ cmd_record_type (void) 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 { diff --git a/src/filename.c b/src/filename.c index 4db36ade..3b25b99c 100644 --- a/src/filename.c +++ b/src/filename.c @@ -502,7 +502,7 @@ fn_dirname (const char *filename) 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) diff --git a/src/flip.c b/src/flip.c index 73e1e7cb..b352f1b2 100644 --- a/src/flip.c +++ b/src/flip.c @@ -204,7 +204,7 @@ make_new_var (char name[]) *cp = '_'; } *cp = '\0'; - st_uppercase (name); + str_uppercase (name); if (dict_create_var (default_dict, name, 0)) return 1; @@ -290,7 +290,8 @@ flip_sink_create (struct flip_pgm *flip) /* 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)); @@ -328,7 +329,7 @@ flip_sink_write (struct case_sink *sink, const struct ccase *c) { 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 diff --git a/src/format.c b/src/format.c index 9c6bbea4..87be7b08 100644 --- a/src/format.c +++ b/src/format.c @@ -59,7 +59,7 @@ parse_format_specifier_name (const char **cp, enum fmt_parse_flags flags) /* 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. */ diff --git a/src/format.def b/src/format.def index 4b8d0c9b..e6f1725b 100644 --- a/src/format.def +++ b/src/format.def @@ -26,8 +26,8 @@ DEFFMT (FMT_DOT, "DOT", 2, 1, 40, 1, 40, 0001, FMT_DOT, 32) 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) diff --git a/src/lexer.c b/src/lexer.c index 53b702c4..ff93e0d9 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -116,7 +116,7 @@ restore_token (void) 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; } @@ -358,7 +358,7 @@ lex_get (void) 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)); @@ -720,7 +720,7 @@ lex_put_back_id (const char *id) 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)); } /* Weird line processing functions. */ diff --git a/src/matrix-data.c b/src/matrix-data.c index 73d473d1..776dfa5b 100644 --- a/src/matrix-data.c +++ b/src/matrix-data.c @@ -1347,8 +1347,8 @@ dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp, 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); @@ -1369,10 +1369,9 @@ dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp, 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); } } diff --git a/src/pfm-read.c b/src/pfm-read.c index 766e2140..7967926e 100644 --- a/src/pfm-read.c +++ b/src/pfm-read.c @@ -448,8 +448,8 @@ read_version_data (struct pfm_reader *r, struct pfm_read_info *info) 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); } } @@ -523,7 +523,7 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) 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); @@ -605,7 +605,7 @@ parse_value (struct pfm_reader *r, struct variable *vv) { 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); @@ -699,7 +699,7 @@ pfm_read_case (struct pfm_reader *r, struct ccase *c) { 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); } } diff --git a/src/recode.c b/src/recode.c index a8574c99..90792afa 100644 --- a/src/recode.c +++ b/src/recode.c @@ -378,7 +378,7 @@ cmd_recode (void) /* 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; } @@ -463,7 +463,7 @@ parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width) 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 (); @@ -626,7 +626,7 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width) 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 (); } } @@ -811,9 +811,9 @@ recode_trns_proc (struct trns_header * t, struct ccase * c, 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); diff --git a/src/sfm-write.c b/src/sfm-write.c index 0c8ebf01..99dd47bd 100644 --- a/src/sfm-write.c +++ b/src/sfm-write.c @@ -333,7 +333,7 @@ write_header (struct sfm_writer *w, const struct dictionary *d) 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); @@ -418,7 +418,7 @@ write_variable (struct sfm_writer *w, struct variable *v) 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; diff --git a/src/str.c b/src/str.c index 0ad0e2f5..2a766520 100644 --- a/src/str.c +++ b/src/str.c @@ -77,7 +77,7 @@ nvsprintf (char *buf, const char *format, va_list args) /* 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; @@ -94,7 +94,7 @@ mm_reverse (void *p, size_t nbytes) /* 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; @@ -107,10 +107,10 @@ mm_find_reverse (const char *haystack, size_t haystack_len, /* 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) { @@ -128,7 +128,7 @@ mm_case_compare (const void *a_, const void *b_, size_t size) 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; @@ -157,84 +157,101 @@ st_compare_pad (const char *a, size_t a_len, const char *b, size_t b_len) } } -/* 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); diff --git a/src/str.h b/src/str.h index c53b2f46..7816acf2 100644 --- a/src/str.h +++ b/src/str.h @@ -118,17 +118,18 @@ long getdelim (char **lineptr, size_t * n, int delimiter, FILE * stream); /* 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 *); /* Fixed-length strings. */ struct fixed_string diff --git a/src/title.c b/src/title.c index e403841d..e8d95bf0 100644 --- a/src/title.c +++ b/src/title.c @@ -117,7 +117,7 @@ add_document_line (const char *line, int indent) 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); diff --git a/src/val-labs.c b/src/val-labs.c index 2fa02e64..3dc4254f 100644 --- a/src/val-labs.c +++ b/src/val-labs.c @@ -154,7 +154,7 @@ get_label (struct variable **vars, int var_cnt) 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 { diff --git a/src/vars-atr.c b/src/vars-atr.c index a1b8276f..356f51a4 100644 --- a/src/vars-atr.c +++ b/src/vars-atr.c @@ -346,8 +346,8 @@ var_set_short_name (struct variable *v, const char *short_name) 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. */ -- 2.30.2