1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 "dictionary.h"
35 #include "identifier.h"
36 #include "libpspp/assertion.h"
37 #include "libpspp/compiler.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/integer-format.h"
40 #include "libpspp/misc.h"
41 #include "libpspp/str.h"
45 #include "gl/c-ctype.h"
46 #include "gl/c-strtod.h"
47 #include "gl/minmax.h"
48 #include "gl/xalloc.h"
51 #define _(msgid) gettext (msgid)
53 /* Information about parsing one data field. */
56 struct substring input; /* Source. */
57 enum fmt_type format; /* Input format. */
59 union value *output; /* Destination. */
60 int width; /* Output width. */
63 typedef char *data_in_parser_func (struct data_in *);
64 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
65 static data_in_parser_func parse_##METHOD;
68 static void default_result (struct data_in *);
69 static bool trim_spaces_and_check_missing (struct data_in *);
71 static int hexit_value (int c);
73 /* Parses the characters in INPUT, which are encoded in the given
74 INPUT_ENCODING, according to FORMAT.
76 Stores the parsed representation in OUTPUT, which the caller must have
77 initialized with the given WIDTH (0 for a numeric field, otherwise the
78 string width). If FORMAT is FMT_A, then OUTPUT_ENCODING must specify the
79 correct encoding for OUTPUT (normally obtained via dict_get_encoding()). */
81 data_in (struct substring input, const char *input_encoding,
83 union value *output, int width, const char *output_encoding)
85 static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
87 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) parse_##METHOD,
93 enum fmt_category cat;
94 const char *dest_encoding;
98 assert ((width != 0) == fmt_is_string (format));
105 if (ss_is_empty (input))
111 cat = fmt_get_category (format);
112 if (cat & (FMT_CAT_BASIC | FMT_CAT_HEXADECIMAL
113 | FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT))
115 /* We're going to parse these into numbers. For this purpose we want to
116 deal with them in the local "C" encoding. Any character not in that
117 encoding wouldn't be valid anyhow. */
118 dest_encoding = C_ENCODING;
120 else if (cat & (FMT_CAT_BINARY | FMT_CAT_LEGACY))
122 /* Don't recode these binary formats at all, since they are not text. */
123 dest_encoding = NULL;
127 assert (cat == FMT_CAT_STRING);
128 if (format == FMT_AHEX)
130 /* We want the hex digits in the local "C" encoding, even though the
131 result may not be in that encoding. */
132 dest_encoding = C_ENCODING;
136 /* Use the final output encoding. */
137 dest_encoding = output_encoding;
141 if (dest_encoding != NULL)
143 i.input = recode_substring_pool (dest_encoding, input_encoding, input,
153 error = handlers[i.format] (&i);
163 data_in_msg (struct substring input, const char *input_encoding,
164 enum fmt_type format,
165 union value *output, int width, const char *output_encoding)
167 char *error = data_in (input, input_encoding, format,
168 output, width, output_encoding);
171 msg (SW,_("Data is not valid as format %s: %s"),
172 fmt_name (format), error);
181 number_has_implied_decimals (const char *s, enum fmt_type type)
183 int decimal = settings_get_style (type)->decimal;
184 bool got_digit = false;
189 case '0': case '1': case '2': case '3': case '4':
190 case '5': case '6': case '7': case '8': case '9':
199 case 'e': case 'E': case 'd': case 'D':
219 has_implied_decimals (struct substring input, const char *input_encoding,
220 enum fmt_type format)
247 s = recode_string (C_ENCODING, input_encoding,
248 ss_data (input), ss_length (input));
249 retval = (format == FMT_Z
250 ? strchr (s, '.') == NULL
251 : number_has_implied_decimals (s, format));
257 /* In some cases, when no decimal point is explicitly included in numeric
258 input, its position is implied by the number of decimal places in the input
259 format. In such a case, this function may be called just after data_in().
260 Its arguments are a subset of that function's arguments plus D, the number
261 of decimal places associated with FORMAT.
263 If it is appropriate, this function modifies the numeric value in OUTPUT. */
265 data_in_imply_decimals (struct substring input, const char *input_encoding,
266 enum fmt_type format, int d, union value *output)
268 if (d > 0 && output->f != SYSMIS
269 && has_implied_decimals (input, input_encoding, format))
270 output->f /= pow (10., d);
273 /* Format parsers. */
275 /* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
277 parse_number (struct data_in *i)
279 const struct fmt_number_style *style =
280 settings_get_style (i->format);
284 bool explicit_decimals = false;
288 if (fmt_get_category (i->format) == FMT_CAT_CUSTOM)
290 style = settings_get_style (FMT_F);
293 /* Trim spaces and check for missing value representation. */
294 if (trim_spaces_and_check_missing (i))
297 ds_init_empty (&tmp);
298 ds_extend (&tmp, 64);
300 /* Prefix character may precede sign. */
301 if (style->prefix.s[0] != '\0')
303 ss_match_byte (&i->input, style->prefix.s[0]);
304 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
308 if (ss_match_byte (&i->input, '-'))
310 ds_put_byte (&tmp, '-');
311 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
315 ss_match_byte (&i->input, '+');
316 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
319 /* Prefix character may follow sign. */
320 if (style->prefix.s[0] != '\0')
322 ss_match_byte (&i->input, style->prefix.s[0]);
323 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
326 /* Digits before decimal point. */
327 while (c_isdigit (ss_first (i->input)))
329 ds_put_byte (&tmp, ss_get_byte (&i->input));
330 if (style->grouping != 0)
331 ss_match_byte (&i->input, style->grouping);
334 /* Decimal point and following digits. */
335 if (ss_match_byte (&i->input, style->decimal))
337 explicit_decimals = true;
338 ds_put_byte (&tmp, '.');
339 while (c_isdigit (ss_first (i->input)))
340 ds_put_byte (&tmp, ss_get_byte (&i->input));
344 if (!ds_is_empty (&tmp)
345 && !ss_is_empty (i->input)
346 && strchr ("eEdD-+", ss_first (i->input)))
348 explicit_decimals = true;
349 ds_put_byte (&tmp, 'e');
351 if (strchr ("eEdD", ss_first (i->input)))
353 ss_advance (&i->input, 1);
354 ss_match_byte (&i->input, ' ');
357 if (ss_first (i->input) == '-' || ss_first (i->input) == '+')
359 if (ss_get_byte (&i->input) == '-')
360 ds_put_byte (&tmp, '-');
361 ss_match_byte (&i->input, ' ');
364 while (c_isdigit (ss_first (i->input)))
365 ds_put_byte (&tmp, ss_get_byte (&i->input));
368 /* Suffix character. */
369 if (style->suffix.s[0] != '\0')
370 ss_match_byte (&i->input, style->suffix.s[0]);
372 if (!ss_is_empty (i->input))
375 if (ds_is_empty (&tmp))
376 error = xstrdup (_("Field contents are not numeric."));
378 error = xstrdup (_("Number followed by garbage."));
383 /* Let c_strtod() do the conversion. */
386 i->output->f = c_strtod (ds_cstr (&tmp), &tail);
391 return xstrdup (_("Invalid numeric syntax."));
393 else if (errno == ERANGE)
395 if (fabs (i->output->f) > 1)
397 i->output->f = SYSMIS;
399 return xstrdup (_("Too-large number set to system-missing."));
405 return xstrdup (_("Too-small number set to zero."));
415 /* Parses N format. */
417 parse_N (struct data_in *i)
422 while ((c = ss_get_byte (&i->input)) != EOF)
425 return xstrdup (_("All characters in field must be digits."));
426 i->output->f = i->output->f * 10.0 + (c - '0');
432 /* Parses PIBHEX format. */
434 parse_PIBHEX (struct data_in *i)
441 while ((c = ss_get_byte (&i->input)) != EOF)
444 return xstrdup (_("Unrecognized character in field."));
445 n = n * 16.0 + hexit_value (c);
452 /* Parses RBHEX format. */
454 parse_RBHEX (struct data_in *i)
459 memset (&d, 0, sizeof d);
460 for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
462 int hi = ss_get_byte (&i->input);
463 int lo = ss_get_byte (&i->input);
465 return xstrdup (_("Field must have even length."));
466 else if (!c_isxdigit (hi) || !c_isxdigit (lo))
467 return xstrdup (_("Field must contain only hex digits."));
468 ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
476 /* Digits for Z format. */
477 static const char z_digits[] = "0123456789{ABCDEFGHI}JKLMNOPQR";
479 /* Returns true if C is a Z format digit, false otherwise. */
483 return c > 0 && strchr (z_digits, c) != NULL;
486 /* Returns the (absolute value of the) value of C as a Z format
489 z_digit_value (int c)
491 assert (is_z_digit (c));
492 return (strchr (z_digits, c) - z_digits) % 10;
495 /* Returns true if Z format digit C represents a negative value,
498 is_negative_z_digit (int c)
500 assert (is_z_digit (c));
501 return (strchr (z_digits, c) - z_digits) >= 20;
504 /* Parses Z format. */
506 parse_Z (struct data_in *i)
512 bool got_dot = false;
513 bool got_final_digit = false;
515 /* Trim spaces and check for missing value representation. */
516 if (trim_spaces_and_check_missing (i))
519 ds_init_empty (&tmp);
520 ds_extend (&tmp, 64);
522 ds_put_byte (&tmp, '+');
523 while (!ss_is_empty (i->input))
525 int c = ss_get_byte (&i->input);
526 if (c_isdigit (c) && !got_final_digit)
527 ds_put_byte (&tmp, c);
528 else if (is_z_digit (c) && !got_final_digit)
530 ds_put_byte (&tmp, z_digit_value (c) + '0');
531 if (is_negative_z_digit (c))
532 ds_data (&tmp)[0] = '-';
533 got_final_digit = true;
535 else if (c == '.' && !got_dot)
537 ds_put_byte (&tmp, '.');
543 return xstrdup (_("Invalid zoned decimal syntax."));
547 if (!ss_is_empty (i->input))
551 if (ds_length (&tmp) == 1)
552 error = xstrdup (_("Field contents are not numeric."));
554 error = xstrdup (_("Number followed by garbage."));
560 /* Let c_strtod() do the conversion. */
563 i->output->f = c_strtod (ds_cstr (&tmp), NULL);
566 if (fabs (i->output->f) > 1)
568 i->output->f = SYSMIS;
570 return xstrdup (_("Too-large number set to system-missing."));
576 return xstrdup (_("Too-small number set to zero."));
586 /* Parses IB format. */
588 parse_IB (struct data_in *i)
594 bytes = MIN (8, ss_length (i->input));
595 value = integer_get (settings_get_input_integer_format (), ss_data (i->input), bytes);
597 sign_bit = UINT64_C(1) << (8 * bytes - 1);
598 if (!(value & sign_bit))
599 i->output->f = value;
602 /* Sign-extend to full 64 bits. */
603 value -= sign_bit << 1;
604 i->output->f = -(double) -value;
610 /* Parses PIB format. */
612 parse_PIB (struct data_in *i)
614 i->output->f = integer_get (settings_get_input_integer_format (), ss_data (i->input),
615 MIN (8, ss_length (i->input)));
620 /* Consumes the first character of S. Stores its high 4 bits in
621 HIGH_NIBBLE and its low 4 bits in LOW_NIBBLE. */
623 get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
625 int c = ss_get_byte (s);
627 *high_nibble = (c >> 4) & 15;
628 *low_nibble = c & 15;
631 /* Parses P format. */
633 parse_P (struct data_in *i)
635 int high_nibble, low_nibble;
639 while (ss_length (i->input) > 1)
641 get_nibbles (&i->input, &high_nibble, &low_nibble);
642 if (high_nibble > 9 || low_nibble > 9)
643 return xstrdup (_("Invalid syntax for P field."));
644 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
647 get_nibbles (&i->input, &high_nibble, &low_nibble);
649 return xstrdup (_("Invalid syntax for P field."));
650 i->output->f = (10 * i->output->f) + high_nibble;
652 i->output->f = (10 * i->output->f) + low_nibble;
653 else if (low_nibble == 0xb || low_nibble == 0xd)
654 i->output->f = -i->output->f;
659 /* Parses PK format. */
661 parse_PK (struct data_in *i)
664 while (!ss_is_empty (i->input))
666 int high_nibble, low_nibble;
668 get_nibbles (&i->input, &high_nibble, &low_nibble);
669 if (high_nibble > 9 || low_nibble > 9)
671 i->output->f = SYSMIS;
674 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
680 /* Parses RB format. */
682 parse_RB (struct data_in *i)
684 enum float_format ff = settings_get_input_float_format ();
685 size_t size = float_get_size (ff);
686 if (ss_length (i->input) >= size)
687 float_convert (ff, ss_data (i->input),
688 FLOAT_NATIVE_DOUBLE, &i->output->f);
690 i->output->f = SYSMIS;
695 /* Parses A format. */
697 parse_A (struct data_in *i)
699 /* This is equivalent to buf_copy_rpad, except that we posibly
700 do a character set recoding in the middle. */
701 uint8_t *dst = value_str_rw (i->output, i->width);
702 size_t dst_size = i->width;
703 const char *src = ss_data (i->input);
704 size_t src_size = ss_length (i->input);
706 memcpy (dst, src, MIN (src_size, dst_size));
708 if (dst_size > src_size)
709 memset (&dst[src_size], ' ', dst_size - src_size);
714 /* Parses AHEX format. */
716 parse_AHEX (struct data_in *i)
718 uint8_t *s = value_str_rw (i->output, i->width);
723 int hi = ss_get_byte (&i->input);
724 int lo = ss_get_byte (&i->input);
728 return xstrdup (_("Field must have even length."));
730 if (!c_isxdigit (hi) || !c_isxdigit (lo))
731 return xstrdup (_("Field must contain only hex digits."));
734 s[j] = hexit_value (hi) * 16 + hexit_value (lo);
737 memset (&s[j], ' ', i->width - j);
742 /* Date & time format components. */
744 /* Sign of a time value. */
747 SIGN_NO_TIME, /* No time yet encountered. */
748 SIGN_POSITIVE, /* Positive time. */
749 SIGN_NEGATIVE /* Negative time. */
752 /* Parses a signed decimal integer from at most the first
753 MAX_DIGITS characters in I, storing the result into *RESULT.
754 Returns true if successful, false if no integer was
756 static char * WARN_UNUSED_RESULT
757 parse_int (struct data_in *i, long *result, size_t max_digits)
759 struct substring head = ss_head (i->input, max_digits);
760 size_t n = ss_get_long (&head, result);
763 ss_advance (&i->input, n);
767 return xstrdup (_("Syntax error in date field."));
770 /* Parses a date integer between 1 and 31 from I, storing it into
772 Returns true if successful, false if no date was present. */
774 parse_day (struct data_in *i, long *day)
776 char *error = parse_int (i, day, SIZE_MAX);
779 if (*day >= 1 && *day <= 31)
782 return xasprintf (_("Day (%ld) must be between 1 and 31."), *day);
785 /* Parses an integer from the beginning of I.
786 Adds SECONDS_PER_UNIT times the absolute value of the integer
788 If *TIME_SIGN is SIGN_NO_TIME, allows a sign to precede the
789 time and sets *TIME_SIGN. Otherwise, does not allow a sign.
790 Returns true if successful, false if no integer was present. */
792 parse_time_units (struct data_in *i, double seconds_per_unit,
793 enum time_sign *time_sign, double *time)
799 if (*time_sign == SIGN_NO_TIME)
801 if (ss_match_byte (&i->input, '-'))
802 *time_sign = SIGN_NEGATIVE;
805 ss_match_byte (&i->input, '+');
806 *time_sign = SIGN_POSITIVE;
809 error = parse_int (i, &units, SIZE_MAX);
813 return xstrdup (_("Syntax error in date field."));
814 *time += units * seconds_per_unit;
818 /* Parses a data delimiter from the beginning of I.
819 Returns true if successful, false if no delimiter was
822 parse_date_delimiter (struct data_in *i)
824 if (ss_ltrim (&i->input, ss_cstr ("-/.," CC_SPACES)))
827 return xstrdup (_("Delimiter expected between fields in date."));
830 /* Parses spaces at the beginning of I. */
832 parse_spaces (struct data_in *i)
834 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
837 static struct substring
838 parse_name_token (struct data_in *i)
840 struct substring token;
841 ss_get_bytes (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
845 /* Reads a name from I and sets *OUTPUT to the value associated
846 with that name. If ALLOW_SUFFIXES is true, then names that
847 begin with one of the names are accepted; otherwise, only
848 exact matches (except for case) are allowed.
849 Returns true if successful, false otherwise. */
851 match_name (struct substring token, const char *const *names, long *output)
855 for (i = 1; *names != NULL; i++)
856 if (ss_equals_case (ss_cstr (*names++), token))
865 /* Parses a month name or number from the beginning of I,
866 storing the month (in range 1...12) into *MONTH.
867 Returns true if successful, false if no month was present. */
869 parse_month (struct data_in *i, long *month)
871 if (c_isdigit (ss_first (i->input)))
873 char *error = parse_int (i, month, SIZE_MAX);
876 if (*month >= 1 && *month <= 12)
881 static const char *const english_names[] =
883 "jan", "feb", "mar", "apr", "may", "jun",
884 "jul", "aug", "sep", "oct", "nov", "dec",
888 static const char *const roman_names[] =
890 "i", "ii", "iii", "iv", "v", "vi",
891 "vii", "viii", "ix", "x", "xi", "xii",
895 struct substring token = parse_name_token (i);
896 if (match_name (ss_head (token, 3), english_names, month)
897 || match_name (ss_head (token, 4), roman_names, month))
901 return xstrdup (_("Unrecognized month format. Months may be specified "
902 "as Arabic or Roman numerals or as at least 3 letters "
903 "of their English names."));
906 /* Parses a year of at most MAX_DIGITS from the beginning of I,
907 storing a "4-digit" year into *YEAR. */
909 parse_year (struct data_in *i, long *year, size_t max_digits)
911 char *error = parse_int (i, year, max_digits);
915 if (*year >= 0 && *year <= 99)
917 int epoch = settings_get_epoch ();
918 int epoch_century = ROUND_DOWN (epoch, 100);
919 int epoch_offset = epoch - epoch_century;
920 if (*year >= epoch_offset)
921 *year += epoch_century;
923 *year += epoch_century + 100;
925 if (*year >= 1582 || *year <= 19999)
928 return xasprintf (_("Year (%ld) must be between 1582 and 19999."), *year);
931 /* Returns true if input in I has been exhausted,
934 parse_trailer (struct data_in *i)
936 if (ss_is_empty (i->input))
939 return xasprintf (_("Trailing garbage `%.*s' following date."),
940 (int) ss_length (i->input), ss_data (i->input));
943 /* Parses a 3-digit Julian day-of-year value from I into *YDAY.
944 Returns true if successful, false on failure. */
946 parse_yday (struct data_in *i, long *yday)
948 struct substring num_s;
951 ss_get_bytes (&i->input, 3, &num_s);
952 if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
953 return xstrdup (_("Julian day must have exactly three digits."));
954 else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
955 return xasprintf (_("Julian day (%ld) must be between 1 and 366."), num);
961 /* Parses a quarter-of-year integer between 1 and 4 from I.
962 Stores the corresponding month into *MONTH.
963 Returns true if successful, false if no quarter was present. */
965 parse_quarter (struct data_in *i, long int *month)
970 error = parse_int (i, &quarter, SIZE_MAX);
973 if (quarter >= 1 && quarter <= 4)
975 *month = (quarter - 1) * 3 + 1;
979 return xasprintf (_("Quarter (%ld) must be between 1 and 4."), quarter);
982 /* Parses a week-of-year integer between 1 and 53 from I,
983 Stores the corresponding year-of-day into *YDAY.
984 Returns true if successful, false if no week was present. */
986 parse_week (struct data_in *i, long int *yday)
991 error = parse_int (i, &week, SIZE_MAX);
994 if (week >= 1 && week <= 53)
996 *yday = (week - 1) * 7 + 1;
1000 return xasprintf (_("Week (%ld) must be between 1 and 53."), week);
1003 /* Parses a time delimiter from the beginning of I.
1004 Returns true if successful, false if no delimiter was
1007 parse_time_delimiter (struct data_in *i)
1009 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
1012 return xstrdup (_("Delimiter expected between fields in time."));
1015 /* Parses minutes and optional seconds from the beginning of I.
1016 The time is converted into seconds, which are added to
1018 Returns true if successful, false if an error was found. */
1020 parse_minute_second (struct data_in *i, double *time)
1027 /* Parse minutes. */
1028 error = parse_int (i, &minute, SIZE_MAX);
1031 if (minute < 0 || minute > 59)
1032 return xasprintf (_("Minute (%ld) must be between 0 and 59."), minute);
1033 *time += 60. * minute;
1035 /* Check for seconds. */
1036 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) == 0
1037 || !c_isdigit (ss_first (i->input)))
1040 /* Parse seconds. */
1042 while (c_isdigit (ss_first (i->input)))
1043 *cp++ = ss_get_byte (&i->input);
1044 if (ss_match_byte (&i->input, settings_get_decimal_char (FMT_F)))
1046 while (c_isdigit (ss_first (i->input)))
1047 *cp++ = ss_get_byte (&i->input);
1050 *time += strtod (buf, NULL);
1055 /* Parses a weekday name from the beginning of I,
1056 storing a value of 1=Sunday...7=Saturday into *WEEKDAY.
1057 Returns true if successful, false if an error was found. */
1059 parse_weekday (struct data_in *i, long *weekday)
1061 static const char *const weekday_names[] =
1063 "su", "mo", "tu", "we", "th", "fr", "sa",
1067 struct substring token = parse_name_token (i);
1068 bool ok = match_name (ss_head (token, 2), weekday_names, weekday);
1070 return xstrdup (_("Unrecognized weekday name. At least the first two "
1071 "letters of an English weekday name must be "
1076 /* Date & time formats. */
1078 /* Parses WKDAY format. */
1080 parse_WKDAY (struct data_in *i)
1085 if (trim_spaces_and_check_missing (i))
1088 error = parse_weekday (i, &weekday);
1090 error = parse_trailer (i);
1092 i->output->f = weekday;
1096 /* Parses MONTH format. */
1098 parse_MONTH (struct data_in *i)
1103 if (trim_spaces_and_check_missing (i))
1106 error = parse_month (i, &month);
1108 error = parse_trailer (i);
1110 i->output->f = month;
1114 /* Parses DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, KWYR,
1115 DATETIME, TIME and DTIME formats. */
1117 parse_date (struct data_in *i)
1119 long int year = INT_MIN;
1123 double time = 0, date = 0;
1124 enum time_sign time_sign = SIGN_NO_TIME;
1126 const char *template = fmt_date_template (i->format);
1127 size_t template_width = strlen (template);
1130 if (trim_spaces_and_check_missing (i))
1133 while (*template != '\0')
1135 unsigned char ch = *template;
1138 while (template[count] == ch)
1145 error = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
1148 error = parse_month (i, &month);
1153 if (!c_isalpha (*template))
1154 max_digits = SIZE_MAX;
1157 if (ss_length (i->input) >= template_width + 2)
1162 error = parse_year (i, &year, max_digits);
1166 error = parse_quarter (i, &month);
1169 error = parse_week (i, &yday);
1172 error = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
1175 error = parse_time_units (i, 60. * 60., &time_sign, &time);
1178 error = parse_minute_second (i, &time);
1184 error = parse_date_delimiter (i);
1187 error = parse_time_delimiter (i);
1193 assert (count == 1);
1194 if (!ss_match_byte (&i->input, c_toupper (ch))
1195 && !ss_match_byte (&i->input, c_tolower (ch)))
1196 error = xasprintf (_("`%c' expected in date field."), ch);
1204 error = parse_trailer (i);
1208 if (year != INT_MIN)
1213 ofs = calendar_gregorian_to_offset (year, month, day, &error);
1216 date = (yday - 1 + ofs) * 60. * 60. * 24.;
1220 i->output->f = date + (time_sign == SIGN_NEGATIVE ? -time : time);
1225 /* Utility functions. */
1227 /* Sets the default result for I.
1228 For a numeric format, this is the value set on SET BLANKS
1229 (typically system-missing); for a string format, it is all
1232 default_result (struct data_in *i)
1234 if (fmt_is_string (i->format))
1235 memset (value_str_rw (i->output, i->width), ' ', i->width);
1237 i->output->f = settings_get_blanks ();
1240 /* Trims leading and trailing spaces from I.
1241 If the result is empty, or a single period character, then
1242 sets the default result and returns true; otherwise, returns
1245 trim_spaces_and_check_missing (struct data_in *i)
1247 ss_trim (&i->input, ss_cstr (" "));
1248 if (ss_is_empty (i->input) || ss_equals (i->input, ss_cstr (".")))
1256 /* Returns the integer value of hex digit C. */
1260 const char s[] = "0123456789abcdef";
1261 const char *cp = strchr (s, c_tolower ((unsigned char) c));
1263 assert (cp != NULL);