1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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, see <http://www.gnu.org/licenses/>. */
33 #include "identifier.h"
37 #include "dictionary.h"
39 #include <libpspp/assertion.h>
40 #include <libpspp/legacy-encoding.h>
41 #include <libpspp/i18n.h>
42 #include <libpspp/compiler.h>
43 #include <libpspp/integer-format.h>
44 #include <libpspp/message.h>
45 #include <libpspp/misc.h>
46 #include <libpspp/str.h>
53 #define _(msgid) gettext (msgid)
55 /* Information about parsing one data field. */
58 const char *src_enc; /* Encoding of source. */
59 struct substring input; /* Source. */
60 enum fmt_type format; /* Input format. */
61 int implied_decimals; /* Number of implied decimal places. */
63 union value *output; /* Destination. */
64 int width; /* Output width. */
66 int first_column; /* First column of field; 0 if inapplicable. */
67 int last_column; /* Last column. */
72 typedef bool data_in_parser_func (struct data_in *);
73 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
74 static data_in_parser_func parse_##METHOD;
77 static void vdata_warning (const struct data_in *, const char *, va_list)
79 static void data_warning (const struct data_in *, const char *, ...)
82 static void apply_implied_decimals (struct data_in *);
83 static void default_result (struct data_in *);
84 static bool trim_spaces_and_check_missing (struct data_in *);
86 static int hexit_value (int c);
88 /* Parses the characters in INPUT, which are encoded in the given
89 ENCODING, according to FORMAT. Stores the parsed
90 representation in OUTPUT, which the caller must have
91 initialized with the given WIDTH (0 for a numeric field,
92 otherwise the string width).
93 Iff FORMAT is a string format, then DICT must be a pointer
94 to the dictionary associated with OUTPUT. Otherwise, DICT
97 If no decimal point is included in a numeric format, then
98 IMPLIED_DECIMALS decimal places are implied. Specify 0 if no
99 decimal places should be implied.
101 If FIRST_COLUMN and LAST_COLUMN are nonzero, then they should
102 be the 1-based column number of the first and
103 one-past-the-last-character in INPUT, for use in error
104 messages. (LAST_COLUMN cannot always be calculated from
105 FIRST_COLUMN plus the length of the input because of the
106 possibility of escaped quotes in strings, etc.) */
108 data_in (struct substring input, const char *encoding,
109 enum fmt_type format, int implied_decimals,
110 int first_column, int last_column,
111 const struct dictionary *dict,
112 union value *output, int width)
114 static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
116 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) parse_##METHOD,
117 #include "format.def"
125 assert ((width != 0) == fmt_is_string (format));
128 i.implied_decimals = implied_decimals;
133 i.first_column = first_column;
134 i.last_column = last_column;
135 i.src_enc = encoding;
137 if (ss_is_empty (input))
143 if (fmt_get_category (format) & ( FMT_CAT_BINARY | FMT_CAT_HEXADECIMAL | FMT_CAT_LEGACY))
149 const char *dest_encoding;
153 assert (0 == (fmt_get_category (format) & (FMT_CAT_BINARY | FMT_CAT_STRING)));
154 dest_encoding = LEGACY_NATIVE;
157 dest_encoding = dict_get_encoding (dict);
159 s = recode_string (dest_encoding, i.src_enc, ss_data (input), ss_length (input));
160 i.input = ss_cstr (s);
163 ok = handlers[i.format] (&i);
172 /* Format parsers. */
174 /* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
176 parse_number (struct data_in *i)
178 const struct fmt_number_style *style =
179 settings_get_style (i->format);
183 bool explicit_decimals = false;
187 if (fmt_get_category (i->format) == FMT_CAT_CUSTOM)
189 style = settings_get_style (FMT_F);
192 /* Trim spaces and check for missing value representation. */
193 if (trim_spaces_and_check_missing (i))
196 ds_init_empty (&tmp);
197 ds_extend (&tmp, 64);
199 /* Prefix character may precede sign. */
200 if (!ss_is_empty (style->prefix))
202 ss_match_char (&i->input, ss_first (style->prefix));
203 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
207 if (ss_match_char (&i->input, '-'))
209 ds_put_char (&tmp, '-');
210 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
214 ss_match_char (&i->input, '+');
215 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
218 /* Prefix character may follow sign. */
219 if (!ss_is_empty (style->prefix))
221 ss_match_char (&i->input, ss_first (style->prefix));
222 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
225 /* Digits before decimal point. */
226 while (c_isdigit (ss_first (i->input)))
228 ds_put_char (&tmp, ss_get_char (&i->input));
229 if (style->grouping != 0)
230 ss_match_char (&i->input, style->grouping);
233 /* Decimal point and following digits. */
234 if (ss_match_char (&i->input, style->decimal))
236 explicit_decimals = true;
237 ds_put_char (&tmp, '.');
238 while (c_isdigit (ss_first (i->input)))
239 ds_put_char (&tmp, ss_get_char (&i->input));
243 if (!ds_is_empty (&tmp)
244 && !ss_is_empty (i->input)
245 && strchr ("eEdD-+", ss_first (i->input)))
247 explicit_decimals = true;
248 ds_put_char (&tmp, 'e');
250 if (strchr ("eEdD", ss_first (i->input)))
252 ss_advance (&i->input, 1);
253 ss_match_char (&i->input, ' ');
256 if (ss_first (i->input) == '-' || ss_first (i->input) == '+')
258 if (ss_get_char (&i->input) == '-')
259 ds_put_char (&tmp, '-');
260 ss_match_char (&i->input, ' ');
263 while (c_isdigit (ss_first (i->input)))
264 ds_put_char (&tmp, ss_get_char (&i->input));
267 /* Suffix character. */
268 if (!ss_is_empty (style->suffix))
269 ss_match_char (&i->input, ss_first (style->suffix));
271 if (!ss_is_empty (i->input))
273 if (ds_is_empty (&tmp))
274 data_warning (i, _("Field contents are not numeric."));
276 data_warning (i, _("Number followed by garbage."));
281 /* Let c_strtod() do the conversion. */
284 i->output->f = c_strtod (ds_cstr (&tmp), &tail);
287 data_warning (i, _("Invalid numeric syntax."));
292 else if (errno == ERANGE)
294 if (fabs (i->output->f) > 1)
296 data_warning (i, _("Too-large number set to system-missing."));
297 i->output->f = SYSMIS;
301 data_warning (i, _("Too-small number set to zero."));
308 if (!explicit_decimals)
309 apply_implied_decimals (i);
316 /* Parses N format. */
318 parse_N (struct data_in *i)
323 while ((c = ss_get_char (&i->input)) != EOF)
327 data_warning (i, _("All characters in field must be digits."));
330 i->output->f = i->output->f * 10.0 + (c - '0');
333 apply_implied_decimals (i);
337 /* Parses PIBHEX format. */
339 parse_PIBHEX (struct data_in *i)
346 while ((c = ss_get_char (&i->input)) != EOF)
350 data_warning (i, _("Unrecognized character in field."));
353 n = n * 16.0 + hexit_value (c);
360 /* Parses RBHEX format. */
362 parse_RBHEX (struct data_in *i)
367 memset (&d, 0, sizeof d);
368 for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
370 int hi = ss_get_char (&i->input);
371 int lo = ss_get_char (&i->input);
374 data_warning (i, _("Field must have even length."));
377 else if (!c_isxdigit (hi) || !c_isxdigit (lo))
379 data_warning (i, _("Field must contain only hex digits."));
382 ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
390 /* Digits for Z format. */
391 static const char z_digits[] = "0123456789{ABCDEFGHI}JKLMNOPQR";
393 /* Returns true if C is a Z format digit, false otherwise. */
397 return c > 0 && strchr (z_digits, c) != NULL;
400 /* Returns the (absolute value of the) value of C as a Z format
403 z_digit_value (int c)
405 assert (is_z_digit (c));
406 return (strchr (z_digits, c) - z_digits) % 10;
409 /* Returns true if Z format digit C represents a negative value,
412 is_negative_z_digit (int c)
414 assert (is_z_digit (c));
415 return (strchr (z_digits, c) - z_digits) >= 20;
418 /* Parses Z format. */
420 parse_Z (struct data_in *i)
426 bool got_dot = false;
427 bool got_final_digit = false;
429 /* Trim spaces and check for missing value representation. */
430 if (trim_spaces_and_check_missing (i))
433 ds_init_empty (&tmp);
434 ds_extend (&tmp, 64);
436 ds_put_char (&tmp, '+');
437 while (!ss_is_empty (i->input))
439 int c = ss_get_char (&i->input);
440 if (c_isdigit (c) && !got_final_digit)
441 ds_put_char (&tmp, c);
442 else if (is_z_digit (c) && !got_final_digit)
444 ds_put_char (&tmp, z_digit_value (c) + '0');
445 if (is_negative_z_digit (c))
446 ds_data (&tmp)[0] = '-';
447 got_final_digit = true;
449 else if (c == '.' && !got_dot)
451 ds_put_char (&tmp, '.');
461 if (!ss_is_empty (i->input))
463 if (ds_length (&tmp) == 1)
464 data_warning (i, _("Field contents are not numeric."));
466 data_warning (i, _("Number followed by garbage."));
471 /* Let c_strtod() do the conversion. */
474 i->output->f = c_strtod (ds_cstr (&tmp), NULL);
477 if (fabs (i->output->f) > 1)
479 data_warning (i, _("Too-large number set to system-missing."));
480 i->output->f = SYSMIS;
484 data_warning (i, _("Too-small number set to zero."));
492 apply_implied_decimals (i);
499 /* Parses IB format. */
501 parse_IB (struct data_in *i)
507 bytes = MIN (8, ss_length (i->input));
508 value = integer_get (settings_get_input_integer_format (), ss_data (i->input), bytes);
510 sign_bit = UINT64_C(1) << (8 * bytes - 1);
511 if (!(value & sign_bit))
512 i->output->f = value;
515 /* Sign-extend to full 64 bits. */
516 value -= sign_bit << 1;
517 i->output->f = -(double) -value;
520 apply_implied_decimals (i);
525 /* Parses PIB format. */
527 parse_PIB (struct data_in *i)
529 i->output->f = integer_get (settings_get_input_integer_format (), ss_data (i->input),
530 MIN (8, ss_length (i->input)));
532 apply_implied_decimals (i);
537 /* Consumes the first character of S. Stores its high 4 bits in
538 HIGH_NIBBLE and its low 4 bits in LOW_NIBBLE. */
540 get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
542 int c = ss_get_char (s);
544 *high_nibble = (c >> 4) & 15;
545 *low_nibble = c & 15;
548 /* Parses P format. */
550 parse_P (struct data_in *i)
552 int high_nibble, low_nibble;
556 while (ss_length (i->input) > 1)
558 get_nibbles (&i->input, &high_nibble, &low_nibble);
559 if (high_nibble > 9 || low_nibble > 9)
561 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
564 get_nibbles (&i->input, &high_nibble, &low_nibble);
567 i->output->f = (10 * i->output->f) + high_nibble;
569 i->output->f = (10 * i->output->f) + low_nibble;
570 else if (low_nibble == 0xb || low_nibble == 0xd)
571 i->output->f = -i->output->f;
573 apply_implied_decimals (i);
578 /* Parses PK format. */
580 parse_PK (struct data_in *i)
583 while (!ss_is_empty (i->input))
585 int high_nibble, low_nibble;
587 get_nibbles (&i->input, &high_nibble, &low_nibble);
588 if (high_nibble > 9 || low_nibble > 9)
590 i->output->f = SYSMIS;
593 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
596 apply_implied_decimals (i);
601 /* Parses RB format. */
603 parse_RB (struct data_in *i)
605 enum float_format ff = settings_get_input_float_format ();
606 size_t size = float_get_size (ff);
607 if (ss_length (i->input) >= size)
608 float_convert (ff, ss_data (i->input),
609 FLOAT_NATIVE_DOUBLE, &i->output->f);
611 i->output->f = SYSMIS;
616 /* Parses A format. */
618 parse_A (struct data_in *i)
620 /* This is equivalent to buf_copy_rpad, except that we posibly
621 do a character set recoding in the middle. */
622 uint8_t *dst = value_str_rw (i->output, i->width);
623 size_t dst_size = i->width;
624 const char *src = ss_data (i->input);
625 size_t src_size = ss_length (i->input);
627 memcpy (dst, src, MIN (src_size, dst_size));
629 if (dst_size > src_size)
630 memset (&dst[src_size], ' ', dst_size - src_size);
635 /* Parses AHEX format. */
637 parse_AHEX (struct data_in *i)
639 uint8_t *s = value_str_rw (i->output, i->width);
644 int hi = ss_get_char (&i->input);
645 int lo = ss_get_char (&i->input);
650 data_warning (i, _("Field must have even length."));
654 if (0 != strcmp (i->src_enc, LEGACY_NATIVE))
656 hi = legacy_to_native (i->src_enc, hi);
657 lo = legacy_to_native (i->src_enc, lo);
659 if (!c_isxdigit (hi) || !c_isxdigit (lo))
661 data_warning (i, _("Field must contain only hex digits."));
666 s[j] = hexit_value (hi) * 16 + hexit_value (lo);
669 memset (&s[j], ' ', i->width - j);
674 /* Date & time format components. */
676 /* Sign of a time value. */
679 SIGN_NO_TIME, /* No time yet encountered. */
680 SIGN_POSITIVE, /* Positive time. */
681 SIGN_NEGATIVE /* Negative time. */
684 /* Parses a signed decimal integer from at most the first
685 MAX_DIGITS characters in I, storing the result into *RESULT.
686 Returns true if successful, false if no integer was
689 parse_int (struct data_in *i, long *result, size_t max_digits)
691 struct substring head = ss_head (i->input, max_digits);
692 size_t n = ss_get_long (&head, result);
695 ss_advance (&i->input, n);
700 data_warning (i, _("Syntax error in date field."));
705 /* Parses a date integer between 1 and 31 from I, storing it into
707 Returns true if successful, false if no date was present. */
709 parse_day (struct data_in *i, long *day)
711 if (!parse_int (i, day, SIZE_MAX))
713 if (*day >= 1 && *day <= 31)
716 data_warning (i, _("Day (%ld) must be between 1 and 31."), *day);
720 /* Parses an integer from the beginning of I.
721 Adds SECONDS_PER_UNIT times the absolute value of the integer
723 If *TIME_SIGN is SIGN_NO_TIME, allows a sign to precede the
724 time and sets *TIME_SIGN. Otherwise, does not allow a sign.
725 Returns true if successful, false if no integer was present. */
727 parse_time_units (struct data_in *i, double seconds_per_unit,
728 enum time_sign *time_sign, double *time)
733 if (*time_sign == SIGN_NO_TIME)
735 if (ss_match_char (&i->input, '-'))
736 *time_sign = SIGN_NEGATIVE;
739 ss_match_char (&i->input, '+');
740 *time_sign = SIGN_POSITIVE;
743 if (!parse_int (i, &units, SIZE_MAX))
747 data_warning (i, _("Syntax error in date field."));
750 *time += units * seconds_per_unit;
754 /* Parses a data delimiter from the beginning of I.
755 Returns true if successful, false if no delimiter was
758 parse_date_delimiter (struct data_in *i)
760 if (ss_ltrim (&i->input, ss_cstr ("-/.," CC_SPACES)))
763 data_warning (i, _("Delimiter expected between fields in date."));
767 /* Parses spaces at the beginning of I. */
769 parse_spaces (struct data_in *i)
771 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
774 static struct substring
775 parse_name_token (struct data_in *i)
777 struct substring token;
778 ss_get_chars (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
782 /* Reads a name from I and sets *OUTPUT to the value associated
783 with that name. If ALLOW_SUFFIXES is true, then names that
784 begin with one of the names are accepted; otherwise, only
785 exact matches (except for case) are allowed.
786 Returns true if successful, false otherwise. */
788 match_name (struct substring token, const char *const *names, long *output)
792 for (i = 1; *names != NULL; i++)
793 if (ss_equals_case (ss_cstr (*names++), token))
802 /* Parses a month name or number from the beginning of I,
803 storing the month (in range 1...12) into *MONTH.
804 Returns true if successful, false if no month was present. */
806 parse_month (struct data_in *i, long *month)
808 if (c_isdigit (ss_first (i->input)))
810 if (!parse_int (i, month, SIZE_MAX))
812 if (*month >= 1 && *month <= 12)
817 static const char *const english_names[] =
819 "jan", "feb", "mar", "apr", "may", "jun",
820 "jul", "aug", "sep", "oct", "nov", "dec",
824 static const char *const roman_names[] =
826 "i", "ii", "iii", "iv", "v", "vi",
827 "vii", "viii", "ix", "x", "xi", "xii",
831 struct substring token = parse_name_token (i);
832 if (match_name (ss_head (token, 3), english_names, month)
833 || match_name (ss_head (token, 4), roman_names, month))
837 data_warning (i, _("Unrecognized month format. Months may be specified "
838 "as Arabic or Roman numerals or as at least 3 letters "
839 "of their English names."));
843 /* Parses a year of at most MAX_DIGITS from the beginning of I,
844 storing a "4-digit" year into *YEAR. */
846 parse_year (struct data_in *i, long *year, size_t max_digits)
848 if (!parse_int (i, year, max_digits))
851 if (*year >= 0 && *year <= 99)
853 int epoch = settings_get_epoch ();
854 int epoch_century = ROUND_DOWN (epoch, 100);
855 int epoch_offset = epoch - epoch_century;
856 if (*year >= epoch_offset)
857 *year += epoch_century;
859 *year += epoch_century + 100;
861 if (*year >= 1582 || *year <= 19999)
864 data_warning (i, _("Year (%ld) must be between 1582 and 19999."), *year);
868 /* Returns true if input in I has been exhausted,
871 parse_trailer (struct data_in *i)
873 if (ss_is_empty (i->input))
876 data_warning (i, _("Trailing garbage \"%.*s\" following date."),
877 (int) ss_length (i->input), ss_data (i->input));
881 /* Parses a 3-digit Julian day-of-year value from I into *YDAY.
882 Returns true if successful, false on failure. */
884 parse_yday (struct data_in *i, long *yday)
886 struct substring num_s;
889 ss_get_chars (&i->input, 3, &num_s);
890 if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
892 data_warning (i, _("Julian day must have exactly three digits."));
895 else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
897 data_warning (i, _("Julian day (%ld) must be between 1 and 366."), num);
905 /* Parses a quarter-of-year integer between 1 and 4 from I.
906 Stores the corresponding month into *MONTH.
907 Returns true if successful, false if no quarter was present. */
909 parse_quarter (struct data_in *i, long int *month)
913 if (!parse_int (i, &quarter, SIZE_MAX))
915 if (quarter >= 1 && quarter <= 4)
917 *month = (quarter - 1) * 3 + 1;
921 data_warning (i, _("Quarter (%ld) must be between 1 and 4."), quarter);
925 /* Parses a week-of-year integer between 1 and 53 from I,
926 Stores the corresponding year-of-day into *YDAY.
927 Returns true if successful, false if no week was present. */
929 parse_week (struct data_in *i, long int *yday)
933 if (!parse_int (i, &week, SIZE_MAX))
935 if (week >= 1 && week <= 53)
937 *yday = (week - 1) * 7 + 1;
941 data_warning (i, _("Week (%ld) must be between 1 and 53."), week);
945 /* Parses a time delimiter from the beginning of I.
946 Returns true if successful, false if no delimiter was
949 parse_time_delimiter (struct data_in *i)
951 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
954 data_warning (i, _("Delimiter expected between fields in time."));
958 /* Parses minutes and optional seconds from the beginning of I.
959 The time is converted into seconds, which are added to
961 Returns true if successful, false if an error was found. */
963 parse_minute_second (struct data_in *i, double *time)
970 if (!parse_int (i, &minute, SIZE_MAX))
972 if (minute < 0 || minute > 59)
974 data_warning (i, _("Minute (%ld) must be between 0 and 59."), minute);
977 *time += 60. * minute;
979 /* Check for seconds. */
980 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) == 0
981 || !c_isdigit (ss_first (i->input)))
986 while (c_isdigit (ss_first (i->input)))
987 *cp++ = ss_get_char (&i->input);
988 if (ss_match_char (&i->input, settings_get_decimal_char (FMT_F)))
990 while (c_isdigit (ss_first (i->input)))
991 *cp++ = ss_get_char (&i->input);
994 *time += strtod (buf, NULL);
999 /* Parses a weekday name from the beginning of I,
1000 storing a value of 1=Sunday...7=Saturday into *WEEKDAY.
1001 Returns true if successful, false if an error was found. */
1003 parse_weekday (struct data_in *i, long *weekday)
1005 static const char *const weekday_names[] =
1007 "su", "mo", "tu", "we", "th", "fr", "sa",
1011 struct substring token = parse_name_token (i);
1012 bool ok = match_name (ss_head (token, 2), weekday_names, weekday);
1014 data_warning (i, _("Unrecognized weekday name. At least the first two "
1015 "letters of an English weekday name must be "
1020 /* Date & time formats. */
1022 /* Helper function for passing to
1023 calendar_gregorian_to_offset. */
1025 calendar_error (void *i_, const char *format, ...)
1027 struct data_in *i = i_;
1030 va_start (args, format);
1031 vdata_warning (i, format, args);
1035 /* Parses WKDAY format. */
1037 parse_WKDAY (struct data_in *i)
1041 if (trim_spaces_and_check_missing (i))
1044 if (!parse_weekday (i, &weekday)
1045 || !parse_trailer (i))
1048 i->output->f = weekday;
1052 /* Parses MONTH format. */
1054 parse_MONTH (struct data_in *i)
1058 if (trim_spaces_and_check_missing (i))
1061 if (!parse_month (i, &month)
1062 || !parse_trailer (i))
1065 i->output->f = month;
1069 /* Parses DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, KWYR,
1070 DATETIME, TIME and DTIME formats. */
1072 parse_date (struct data_in *i)
1074 long int year = INT_MIN;
1078 double time = 0, date = 0;
1079 enum time_sign time_sign = SIGN_NO_TIME;
1081 const char *template = fmt_date_template (i->format);
1082 size_t template_width = strlen (template);
1084 if (trim_spaces_and_check_missing (i))
1087 while (*template != '\0')
1089 unsigned char ch = *template;
1093 while (template[count] == ch)
1101 ok = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
1104 ok = parse_month (i, &month);
1109 if (!c_isalpha (*template))
1110 max_digits = SIZE_MAX;
1113 if (ss_length (i->input) >= template_width + 2)
1118 ok = parse_year (i, &year, max_digits);
1122 ok = parse_quarter (i, &month);
1125 ok = parse_week (i, &yday);
1128 ok = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
1131 ok = parse_time_units (i, 60. * 60., &time_sign, &time);
1134 ok = parse_minute_second (i, &time);
1140 ok = parse_date_delimiter (i);
1143 ok = parse_time_delimiter (i);
1148 assert (count == 1);
1149 if (!ss_match_char (&i->input, c_toupper (ch))
1150 && !ss_match_char (&i->input, c_tolower (ch)))
1152 data_warning (i, _("`%c' expected in date field."), ch);
1160 if (!parse_trailer (i))
1163 if (year != INT_MIN)
1165 double ofs = calendar_gregorian_to_offset (year, month, day,
1169 date = (yday - 1 + ofs) * 60. * 60. * 24.;
1173 i->output->f = date + (time_sign == SIGN_NEGATIVE ? -time : time);
1178 /* Utility functions. */
1180 /* Outputs FORMAT with the given ARGS as a warning for input
1183 vdata_warning (const struct data_in *i, const char *format, va_list args)
1188 ds_init_empty (&text);
1189 ds_put_char (&text, '(');
1190 if (i->first_column != 0)
1192 if (i->first_column == i->last_column - 1)
1193 ds_put_format (&text, _("column %d"), i->first_column);
1195 ds_put_format (&text, _("columns %d-%d"),
1196 i->first_column, i->last_column - 1);
1197 ds_put_cstr (&text, ", ");
1199 ds_put_format (&text, _("%s field) "), fmt_name (i->format));
1200 ds_put_vformat (&text, format, args);
1202 m.category = MSG_C_DATA;
1203 m.severity = MSG_S_WARNING;
1204 m.text = ds_cstr (&text);
1205 m.where.file_name = NULL;
1206 m.where.line_number = -1;
1211 /* Outputs FORMAT with the given ARGS as a warning for input
1214 data_warning (const struct data_in *i, const char *format, ...)
1218 va_start (args, format);
1219 vdata_warning (i, format, args);
1223 /* Apply implied decimal places to output. */
1225 apply_implied_decimals (struct data_in *i)
1227 if (i->implied_decimals > 0)
1228 i->output->f /= pow (10., i->implied_decimals);
1231 /* Sets the default result for I.
1232 For a numeric format, this is the value set on SET BLANKS
1233 (typically system-missing); for a string format, it is all
1236 default_result (struct data_in *i)
1238 if (fmt_is_string (i->format))
1239 memset (value_str_rw (i->output, i->width), ' ', i->width);
1241 i->output->f = settings_get_blanks ();
1244 /* Trims leading and trailing spaces from I.
1245 If the result is empty, or a single period character, then
1246 sets the default result and returns true; otherwise, returns
1249 trim_spaces_and_check_missing (struct data_in *i)
1251 ss_trim (&i->input, ss_cstr (" "));
1252 if (ss_is_empty (i->input) || ss_equals (i->input, ss_cstr (".")))
1260 /* Returns the integer value of hex digit C. */
1264 const char s[] = "0123456789abcdef";
1265 const char *cp = strchr (s, c_tolower ((unsigned char) c));
1267 assert (cp != NULL);