1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
34 #include "identifier.h"
38 #include <libpspp/assertion.h>
39 #include <libpspp/compiler.h>
40 #include <libpspp/integer-format.h>
41 #include <libpspp/magic.h>
42 #include <libpspp/message.h>
43 #include <libpspp/misc.h>
44 #include <libpspp/str.h>
52 #define _(msgid) gettext (msgid)
54 /* Information about parsing one data field. */
57 struct substring input; /* Source. */
58 enum fmt_type format; /* Input format. */
59 int implied_decimals; /* Number of implied decimal places. */
61 union value *output; /* Destination. */
62 int width; /* Output width. */
64 int first_column; /* First column of field; 0 if inapplicable. */
65 int last_column; /* Last column. */
68 /* Integer format used for IB and PIB input. */
69 static enum integer_format input_integer_format = INTEGER_NATIVE;
71 /* Floating-point format used for RB and RBHEX input. */
72 static enum float_format input_float_format = FLOAT_NATIVE_DOUBLE;
74 typedef bool data_in_parser_func (struct data_in *);
75 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
76 static data_in_parser_func parse_##METHOD;
79 static void vdata_warning (const struct data_in *, const char *, va_list)
81 static void data_warning (const struct data_in *, const char *, ...)
84 static void apply_implied_decimals (struct data_in *);
85 static void default_result (struct data_in *);
86 static bool trim_spaces_and_check_missing (struct data_in *);
88 static int hexit_value (int c);
90 /* Parses the characters in INPUT according to FORMAT. Stores
91 the parsed representation in OUTPUT, which has the given WIDTH
92 (0 for a numeric field, otherwise the string width).
94 If no decimal point is included in a numeric format, then
95 IMPLIED_DECIMALS decimal places are implied. Specify 0 if no
96 decimal places should be implied.
98 If FIRST_COLUMN is nonzero, then it should be the 1-based
99 column number of the first character in INPUT, used in error
102 data_in (struct substring input,
103 enum fmt_type format, int implied_decimals,
104 int first_column, union value *output, int width)
106 static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
108 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) parse_##METHOD,
109 #include "format.def"
115 assert ((width != 0) == fmt_is_string (format));
119 i.implied_decimals = implied_decimals;
124 i.first_column = first_column;
125 i.last_column = first_column + ss_length (input) - 1;
127 if (!ss_is_empty (i.input))
129 ok = handlers[i.format] (&i);
142 /* Returns the integer format used for IB and PIB input. */
144 data_in_get_integer_format (void)
146 return input_integer_format;
149 /* Sets the integer format used for IB and PIB input to
152 data_in_set_integer_format (enum integer_format format)
154 input_integer_format = format;
157 /* Returns the floating-point format used for RB and RBHEX
160 data_in_get_float_format (void)
162 return input_float_format;
165 /* Sets the floating-point format used for RB and RBHEX input to
168 data_in_set_float_format (enum float_format format)
170 input_float_format = format;
173 /* Format parsers. */
175 /* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
177 parse_number (struct data_in *i)
179 const struct fmt_number_style *style = fmt_get_style (i->format);
183 bool explicit_decimals = false;
187 assert (fmt_get_category (i->format) != FMT_CAT_CUSTOM);
189 /* Trim spaces and check for missing value representation. */
190 if (trim_spaces_and_check_missing (i))
193 ds_init_empty (&tmp);
194 ds_extend (&tmp, 64);
196 /* Prefix character may precede sign. */
197 if (!ss_is_empty (style->prefix))
199 ss_match_char (&i->input, ss_first (style->prefix));
200 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
204 if (ss_match_char (&i->input, '-'))
206 ds_put_char (&tmp, '-');
207 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
211 ss_match_char (&i->input, '+');
212 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
215 /* Prefix character may follow sign. */
216 if (!ss_is_empty (style->prefix))
218 ss_match_char (&i->input, ss_first (style->prefix));
219 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
222 /* Digits before decimal point. */
223 while (c_isdigit (ss_first (i->input)))
225 ds_put_char (&tmp, ss_get_char (&i->input));
226 if (style->grouping != 0)
227 ss_match_char (&i->input, style->grouping);
230 /* Decimal point and following digits. */
231 if (ss_match_char (&i->input, style->decimal))
233 explicit_decimals = true;
234 ds_put_char (&tmp, '.');
235 while (c_isdigit (ss_first (i->input)))
236 ds_put_char (&tmp, ss_get_char (&i->input));
240 if (!ds_is_empty (&tmp)
241 && !ss_is_empty (i->input)
242 && strchr ("eEdD-+", ss_first (i->input)))
244 explicit_decimals = true;
245 ds_put_char (&tmp, 'e');
247 if (strchr ("eEdD", ss_first (i->input)))
249 ss_advance (&i->input, 1);
250 ss_match_char (&i->input, ' ');
253 if (ss_first (i->input) == '-' || ss_first (i->input) == '+')
255 if (ss_get_char (&i->input) == '-')
256 ds_put_char (&tmp, '-');
257 ss_match_char (&i->input, ' ');
260 while (c_isdigit (ss_first (i->input)))
261 ds_put_char (&tmp, ss_get_char (&i->input));
264 /* Suffix character. */
265 if (!ss_is_empty (style->suffix))
266 ss_match_char (&i->input, ss_first (style->suffix));
268 if (!ss_is_empty (i->input))
270 if (ds_is_empty (&tmp))
271 data_warning (i, _("Field contents are not numeric."));
273 data_warning (i, _("Number followed by garbage."));
278 /* Let strtod() do the conversion. */
281 i->output->f = strtod (ds_cstr (&tmp), &tail);
284 data_warning (i, _("Invalid numeric syntax."));
289 else if (errno == ERANGE)
291 if (fabs (i->output->f) > 1)
293 data_warning (i, _("Too-large number set to system-missing."));
294 i->output->f = SYSMIS;
298 data_warning (i, _("Too-small number set to zero."));
305 if (!explicit_decimals)
306 apply_implied_decimals (i);
313 /* Parses N format. */
315 parse_N (struct data_in *i)
320 while ((c = ss_get_char (&i->input)) != EOF)
324 data_warning (i, _("All characters in field must be digits."));
327 i->output->f = i->output->f * 10.0 + (c - '0');
330 apply_implied_decimals (i);
334 /* Parses PIBHEX format. */
336 parse_PIBHEX (struct data_in *i)
343 while ((c = ss_get_char (&i->input)) != EOF)
347 data_warning (i, _("Unrecognized character in field."));
350 n = n * 16.0 + hexit_value (c);
357 /* Parses RBHEX format. */
359 parse_RBHEX (struct data_in *i)
364 memset (&d, 0, sizeof d);
365 for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
367 int hi = ss_get_char (&i->input);
368 int lo = ss_get_char (&i->input);
371 data_warning (i, _("Field must have even length."));
374 else if (!c_isxdigit (hi) || !c_isxdigit (lo))
376 data_warning (i, _("Field must contain only hex digits."));
379 ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
387 /* Digits for Z format. */
388 static const char z_digits[] = "0123456789{ABCDEFGHI}JKLMNOPQR";
390 /* Returns true if C is a Z format digit, false otherwise. */
394 return c > 0 && strchr (z_digits, c) != NULL;
397 /* Returns the (absolute value of the) value of C as a Z format
400 z_digit_value (int c)
402 assert (is_z_digit (c));
403 return (strchr (z_digits, c) - z_digits) % 10;
406 /* Returns true if Z format digit C represents a negative value,
409 is_negative_z_digit (int c)
411 assert (is_z_digit (c));
412 return (strchr (z_digits, c) - z_digits) >= 20;
415 /* Parses Z format. */
417 parse_Z (struct data_in *i)
423 bool got_dot = false;
424 bool got_final_digit = false;
426 /* Trim spaces and check for missing value representation. */
427 if (trim_spaces_and_check_missing (i))
430 ds_init_empty (&tmp);
431 ds_extend (&tmp, 64);
433 ds_put_char (&tmp, '+');
434 while (!ss_is_empty (i->input))
436 int c = ss_get_char (&i->input);
437 if (c_isdigit (c) && !got_final_digit)
438 ds_put_char (&tmp, c);
439 else if (is_z_digit (c) && !got_final_digit)
441 ds_put_char (&tmp, z_digit_value (c) + '0');
442 if (is_negative_z_digit (c))
443 ds_data (&tmp)[0] = '-';
444 got_final_digit = true;
446 else if (c == '.' && !got_dot)
448 ds_put_char (&tmp, '.');
458 if (!ss_is_empty (i->input))
460 if (ds_length (&tmp) == 1)
461 data_warning (i, _("Field contents are not numeric."));
463 data_warning (i, _("Number followed by garbage."));
468 /* Let strtod() do the conversion. */
471 i->output->f = strtod (ds_cstr (&tmp), NULL);
474 if (fabs (i->output->f) > 1)
476 data_warning (i, _("Too-large number set to system-missing."));
477 i->output->f = SYSMIS;
481 data_warning (i, _("Too-small number set to zero."));
489 apply_implied_decimals (i);
496 /* Parses IB format. */
498 parse_IB (struct data_in *i)
504 bytes = MIN (8, ss_length (i->input));
505 value = integer_get (input_integer_format, ss_data (i->input), bytes);
507 sign_bit = UINT64_C(1) << (8 * bytes - 1);
508 if (!(value & sign_bit))
509 i->output->f = value;
512 /* Sign-extend to full 64 bits. */
513 value -= sign_bit << 1;
514 i->output->f = -(double) -value;
517 apply_implied_decimals (i);
522 /* Parses PIB format. */
524 parse_PIB (struct data_in *i)
526 i->output->f = integer_get (input_integer_format, ss_data (i->input),
527 MIN (8, ss_length (i->input)));
529 apply_implied_decimals (i);
534 /* Consumes the first character of S. Stores its high 4 bits in
535 HIGH_NIBBLE and its low 4 bits in LOW_NIBBLE. */
537 get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
539 int c = ss_get_char (s);
541 *high_nibble = (c >> 4) & 15;
542 *low_nibble = c & 15;
545 /* Parses P format. */
547 parse_P (struct data_in *i)
549 int high_nibble, low_nibble;
553 while (ss_length (i->input) > 1)
555 get_nibbles (&i->input, &high_nibble, &low_nibble);
556 if (high_nibble > 9 || low_nibble > 9)
558 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
561 get_nibbles (&i->input, &high_nibble, &low_nibble);
564 i->output->f = (10 * i->output->f) + high_nibble;
566 i->output->f = (10 * i->output->f) + low_nibble;
567 else if (low_nibble == 0xb || low_nibble == 0xd)
568 i->output->f = -i->output->f;
570 apply_implied_decimals (i);
575 /* Parses PK format. */
577 parse_PK (struct data_in *i)
580 while (!ss_is_empty (i->input))
582 int high_nibble, low_nibble;
584 get_nibbles (&i->input, &high_nibble, &low_nibble);
585 if (high_nibble > 9 || low_nibble > 9)
587 i->output->f = SYSMIS;
590 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
593 apply_implied_decimals (i);
598 /* Parses RB format. */
600 parse_RB (struct data_in *i)
602 size_t size = float_get_size (input_float_format);
603 if (ss_length (i->input) >= size)
604 float_convert (input_float_format, ss_data (i->input),
605 FLOAT_NATIVE_DOUBLE, &i->output->f);
607 i->output->f = SYSMIS;
612 /* Parses A format. */
614 parse_A (struct data_in *i)
616 buf_copy_rpad (i->output->s, i->width,
617 ss_data (i->input), ss_length (i->input));
621 /* Parses AHEX format. */
623 parse_AHEX (struct data_in *i)
629 int hi = ss_get_char (&i->input);
630 int lo = ss_get_char (&i->input);
635 data_warning (i, _("Field must have even length."));
639 if (!c_isxdigit (hi) || !c_isxdigit (lo))
641 data_warning (i, _("Field must contain only hex digits."));
646 i->output->s[j] = hexit_value (hi) * 16 + hexit_value (lo);
649 memset (i->output->s + j, ' ', i->width - j);
654 /* Date & time format components. */
656 /* Sign of a time value. */
659 SIGN_NO_TIME, /* No time yet encountered. */
660 SIGN_POSITIVE, /* Positive time. */
661 SIGN_NEGATIVE /* Negative time. */
664 /* Parses a signed decimal integer from at most the first
665 MAX_DIGITS characters in I, storing the result into *RESULT.
666 Returns true if successful, false if no integer was
669 parse_int (struct data_in *i, long *result, size_t max_digits)
671 struct substring head = ss_head (i->input, max_digits);
672 size_t n = ss_get_long (&head, result);
675 ss_advance (&i->input, n);
680 data_warning (i, _("Syntax error in date field."));
685 /* Parses a date integer between 1 and 31 from I, storing it into
687 Returns true if successful, false if no date was present. */
689 parse_day (struct data_in *i, long *day)
691 if (!parse_int (i, day, SIZE_MAX))
693 if (*day >= 1 && *day <= 31)
696 data_warning (i, _("Day (%ld) must be between 1 and 31."), *day);
700 /* Parses an integer from the beginning of I.
701 Adds SECONDS_PER_UNIT times the absolute value of the integer
703 If *TIME_SIGN is SIGN_NO_TIME, allows a sign to precede the
704 time and sets *TIME_SIGN. Otherwise, does not allow a sign.
705 Returns true if successful, false if no integer was present. */
707 parse_time_units (struct data_in *i, double seconds_per_unit,
708 enum time_sign *time_sign, double *time)
713 if (*time_sign == SIGN_NO_TIME)
715 if (ss_match_char (&i->input, '-'))
716 *time_sign = SIGN_NEGATIVE;
719 ss_match_char (&i->input, '+');
720 *time_sign = SIGN_POSITIVE;
723 if (!parse_int (i, &units, SIZE_MAX))
727 data_warning (i, _("Syntax error in date field."));
730 *time += units * seconds_per_unit;
734 /* Parses a data delimiter from the beginning of I.
735 Returns true if successful, false if no delimiter was
738 parse_date_delimiter (struct data_in *i)
740 if (ss_ltrim (&i->input, ss_cstr ("-/.," CC_SPACES)))
743 data_warning (i, _("Delimiter expected between fields in date."));
747 /* Parses spaces at the beginning of I. */
749 parse_spaces (struct data_in *i)
751 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
754 static struct substring
755 parse_name_token (struct data_in *i)
757 struct substring token;
758 ss_get_chars (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
762 /* Reads a name from I and sets *OUTPUT to the value associated
763 with that name. If ALLOW_SUFFIXES is true, then names that
764 begin with one of the names are accepted; otherwise, only
765 exact matches (except for case) are allowed.
766 Returns true if successful, false otherwise. */
768 match_name (struct substring token, const char **names, long *output)
772 for (i = 1; *names != NULL; i++)
773 if (ss_equals_case (ss_cstr (*names++), token))
782 /* Parses a month name or number from the beginning of I,
783 storing the month (in range 1...12) into *MONTH.
784 Returns true if successful, false if no month was present. */
786 parse_month (struct data_in *i, long *month)
788 if (c_isdigit (ss_first (i->input)))
790 if (!parse_int (i, month, SIZE_MAX))
792 if (*month >= 1 && *month <= 12)
797 static const char *english_names[] =
799 "jan", "feb", "mar", "apr", "may", "jun",
800 "jul", "aug", "sep", "oct", "nov", "dec",
804 static const char *roman_names[] =
806 "i", "ii", "iii", "iv", "v", "vi",
807 "vii", "viii", "ix", "x", "xi", "xii",
811 struct substring token = parse_name_token (i);
812 if (match_name (ss_head (token, 3), english_names, month)
813 || match_name (ss_head (token, 4), roman_names, month))
817 data_warning (i, _("Unrecognized month format. Months may be specified "
818 "as Arabic or Roman numerals or as at least 3 letters "
819 "of their English names."));
823 /* Parses a year of at most MAX_DIGITS from the beginning of I,
824 storing a "4-digit" year into *YEAR. */
826 parse_year (struct data_in *i, long *year, size_t max_digits)
828 if (!parse_int (i, year, max_digits))
831 if (*year >= 0 && *year <= 99)
833 int epoch = get_epoch ();
834 int epoch_century = ROUND_DOWN (epoch, 100);
835 int epoch_offset = epoch - epoch_century;
836 if (*year >= epoch_offset)
837 *year += epoch_century;
839 *year += epoch_century + 100;
841 if (*year >= 1582 || *year <= 19999)
844 data_warning (i, _("Year (%ld) must be between 1582 and 19999."), *year);
848 /* Returns true if input in I has been exhausted,
851 parse_trailer (struct data_in *i)
853 if (ss_is_empty (i->input))
856 data_warning (i, _("Trailing garbage \"%.*s\" following date."),
857 (int) ss_length (i->input), ss_data (i->input));
861 /* Parses a 3-digit Julian day-of-year value from I into *YDAY.
862 Returns true if successful, false on failure. */
864 parse_yday (struct data_in *i, long *yday)
866 struct substring num_s;
869 ss_get_chars (&i->input, 3, &num_s);
870 if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
872 data_warning (i, _("Julian day must have exactly three digits."));
875 else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
877 data_warning (i, _("Julian day (%ld) must be between 1 and 366."), num);
885 /* Parses a quarter-of-year integer between 1 and 4 from I.
886 Stores the corresponding month into *MONTH.
887 Returns true if successful, false if no quarter was present. */
889 parse_quarter (struct data_in *i, long int *month)
893 if (!parse_int (i, &quarter, SIZE_MAX))
895 if (quarter >= 1 && quarter <= 4)
897 *month = (quarter - 1) * 3 + 1;
901 data_warning (i, _("Quarter (%ld) must be between 1 and 4."), quarter);
905 /* Parses a week-of-year integer between 1 and 53 from I,
906 Stores the corresponding year-of-day into *YDAY.
907 Returns true if successful, false if no week was present. */
909 parse_week (struct data_in *i, long int *yday)
913 if (!parse_int (i, &week, SIZE_MAX))
915 if (week >= 1 && week <= 53)
917 *yday = (week - 1) * 7 + 1;
921 data_warning (i, _("Week (%ld) must be between 1 and 53."), week);
925 /* Parses a time delimiter from the beginning of I.
926 Returns true if successful, false if no delimiter was
929 parse_time_delimiter (struct data_in *i)
931 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
934 data_warning (i, _("Delimiter expected between fields in time."));
938 /* Parses minutes and optional seconds from the beginning of I.
939 The time is converted into seconds, which are added to
941 Returns true if successful, false if an error was found. */
943 parse_minute_second (struct data_in *i, double *time)
950 if (!parse_int (i, &minute, SIZE_MAX))
952 if (minute < 0 || minute > 59)
954 data_warning (i, _("Minute (%ld) must be between 0 and 59."), minute);
957 *time += 60. * minute;
959 /* Check for seconds. */
960 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) == 0
961 || !c_isdigit (ss_first (i->input)))
966 while (c_isdigit (ss_first (i->input)))
967 *cp++ = ss_get_char (&i->input);
968 if (ss_match_char (&i->input, fmt_decimal_char (FMT_F)))
970 while (c_isdigit (ss_first (i->input)))
971 *cp++ = ss_get_char (&i->input);
974 *time += strtod (buf, NULL);
979 /* Parses a weekday name from the beginning of I,
980 storing a value of 1=Sunday...7=Saturday into *WEEKDAY.
981 Returns true if successful, false if an error was found. */
983 parse_weekday (struct data_in *i, long *weekday)
985 static const char *weekday_names[] =
987 "su", "mo", "tu", "we", "th", "fr", "sa",
991 struct substring token = parse_name_token (i);
992 bool ok = match_name (ss_head (token, 2), weekday_names, weekday);
994 data_warning (i, _("Unrecognized weekday name. At least the first two "
995 "letters of an English weekday name must be "
1000 /* Date & time formats. */
1002 /* Helper function for passing to
1003 calendar_gregorian_to_offset. */
1005 calendar_error (void *i_, const char *format, ...)
1007 struct data_in *i = i_;
1010 va_start (args, format);
1011 vdata_warning (i, format, args);
1015 /* Parses WKDAY format. */
1017 parse_WKDAY (struct data_in *i)
1021 if (trim_spaces_and_check_missing (i))
1024 if (!parse_weekday (i, &weekday)
1025 || !parse_trailer (i))
1028 i->output->f = weekday;
1032 /* Parses MONTH format. */
1034 parse_MONTH (struct data_in *i)
1038 if (trim_spaces_and_check_missing (i))
1041 if (!parse_month (i, &month)
1042 || !parse_trailer (i))
1045 i->output->f = month;
1049 /* Parses DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, KWYR,
1050 DATETIME, TIME and DTIME formats. */
1052 parse_date (struct data_in *i)
1054 long int year = INT_MIN;
1058 double time = 0, date = 0;
1059 enum time_sign time_sign = SIGN_NO_TIME;
1061 const char *template = fmt_date_template (i->format);
1062 size_t template_width = strlen (template);
1064 if (trim_spaces_and_check_missing (i))
1067 while (*template != '\0')
1069 unsigned char ch = *template;
1073 while (template[count] == ch)
1081 ok = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
1084 ok = parse_month (i, &month);
1089 if (!c_isalpha (*template))
1090 max_digits = SIZE_MAX;
1093 if (ss_length (i->input) >= template_width + 2)
1098 ok = parse_year (i, &year, max_digits);
1102 ok = parse_quarter (i, &month);
1105 ok = parse_week (i, &yday);
1108 ok = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
1111 ok = parse_time_units (i, 60. * 60., &time_sign, &time);
1114 ok = parse_minute_second (i, &time);
1120 ok = parse_date_delimiter (i);
1123 ok = parse_time_delimiter (i);
1128 assert (count == 1);
1129 if (!ss_match_char (&i->input, c_toupper (ch))
1130 && !ss_match_char (&i->input, c_tolower (ch)))
1132 data_warning (i, _("`%c' expected in date field."), ch);
1140 if (!parse_trailer (i))
1143 if (year != INT_MIN)
1145 double ofs = calendar_gregorian_to_offset (year, month, day,
1149 date = (yday - 1 + ofs) * 60. * 60. * 24.;
1153 i->output->f = date + (time_sign == SIGN_NEGATIVE ? -time : time);
1158 /* Utility functions. */
1160 /* Outputs FORMAT with the given ARGS as a warning for input
1163 vdata_warning (const struct data_in *i, const char *format, va_list args)
1168 ds_init_empty (&text);
1169 ds_put_char (&text, '(');
1170 if (i->first_column != 0)
1172 if (i->first_column == i->last_column)
1173 ds_put_format (&text, _("column %d"), i->first_column);
1175 ds_put_format (&text, _("columns %d-%d"),
1176 i->first_column, i->last_column);
1177 ds_put_cstr (&text, ", ");
1179 ds_put_format (&text, _("%s field) "), fmt_name (i->format));
1180 ds_put_vformat (&text, format, args);
1182 m.category = MSG_DATA;
1183 m.severity = MSG_WARNING;
1184 m.text = ds_cstr (&text);
1189 /* Outputs FORMAT with the given ARGS as a warning for input
1192 data_warning (const struct data_in *i, const char *format, ...)
1196 va_start (args, format);
1197 vdata_warning (i, format, args);
1201 /* Apply implied decimal places to output. */
1203 apply_implied_decimals (struct data_in *i)
1205 if (i->implied_decimals > 0)
1206 i->output->f /= pow (10., i->implied_decimals);
1209 /* Sets the default result for I.
1210 For a numeric format, this is the value set on SET BLANKS
1211 (typically system-missing); for a string format, it is all
1214 default_result (struct data_in *i)
1216 if (fmt_is_string (i->format))
1217 memset (i->output->s, ' ', i->width);
1219 i->output->f = get_blanks ();
1222 /* Trims leading and trailing spaces from I.
1223 If the result is empty, or a single period character, then
1224 sets the default result and returns true; otherwise, returns
1227 trim_spaces_and_check_missing (struct data_in *i)
1229 ss_trim (&i->input, ss_cstr (" "));
1230 if (ss_is_empty (i->input) || ss_equals (i->input, ss_cstr (".")))
1238 /* Returns the integer value of hex digit C. */
1242 const char s[] = "0123456789abcdef";
1243 const char *cp = strchr (s, c_tolower ((unsigned char) c));
1245 assert (cp != NULL);