1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010 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/legacy-encoding.h"
41 #include "libpspp/misc.h"
42 #include "libpspp/str.h"
46 #include "gl/c-ctype.h"
47 #include "gl/c-strtod.h"
48 #include "gl/minmax.h"
49 #include "gl/xalloc.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. */
60 union value *output; /* Destination. */
61 int width; /* Output width. */
64 typedef char *data_in_parser_func (struct data_in *);
65 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
66 static data_in_parser_func parse_##METHOD;
69 static void default_result (struct data_in *);
70 static bool trim_spaces_and_check_missing (struct data_in *);
72 static int hexit_value (int c);
74 /* Parses the characters in INPUT, which are encoded in the given
75 INPUT_ENCODING, according to FORMAT.
77 Stores the parsed representation in OUTPUT, which the caller must have
78 initialized with the given WIDTH (0 for a numeric field, otherwise the
79 string width). If FORMAT is FMT_A, then OUTPUT_ENCODING must specify the
80 correct encoding for OUTPUT (normally obtained via dict_get_encoding()). */
82 data_in (struct substring input, const char *input_encoding,
84 union value *output, int width, const char *output_encoding)
86 static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
88 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) parse_##METHOD,
94 enum fmt_category cat;
95 const char *dest_encoding;
99 assert ((width != 0) == fmt_is_string (format));
106 if (ss_is_empty (input))
112 cat = fmt_get_category (format);
113 if (cat & (FMT_CAT_BASIC | FMT_CAT_HEXADECIMAL
114 | FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT))
116 /* We're going to parse these into numbers. For this purpose we want to
117 deal with them in the local "C" encoding. Any character not in that
118 encoding wouldn't be valid anyhow. */
119 dest_encoding = LEGACY_NATIVE;
121 else if (cat & (FMT_CAT_BINARY | FMT_CAT_LEGACY))
123 /* Don't recode these binary formats at all, since they are not text. */
124 dest_encoding = NULL;
128 assert (cat == FMT_CAT_STRING);
129 if (format == FMT_AHEX)
131 /* We want the hex digits in the local "C" encoding, even though the
132 result may not be in that encoding. */
133 dest_encoding = LEGACY_NATIVE;
137 /* Use the final output encoding. */
138 dest_encoding = output_encoding;
142 if (dest_encoding != NULL)
144 i.input = recode_substring_pool (dest_encoding, input_encoding, input,
154 error = handlers[i.format] (&i);
164 data_in_msg (struct substring input, const char *input_encoding,
165 enum fmt_type format,
166 union value *output, int width, const char *output_encoding)
168 char *error = data_in (input, input_encoding, format,
169 output, width, output_encoding);
172 msg (SW,_("Data is not valid as format %s: %s"),
173 fmt_name (format), error);
182 number_has_implied_decimals (const char *s, enum fmt_type type)
184 int decimal = settings_get_style (type)->decimal;
185 bool got_digit = false;
190 case '0': case '1': case '2': case '3': case '4':
191 case '5': case '6': case '7': case '8': case '9':
200 case 'e': case 'E': case 'd': case 'D':
220 has_implied_decimals (struct substring input, const char *input_encoding,
221 enum fmt_type format)
248 s = recode_string (LEGACY_NATIVE, input_encoding,
249 ss_data (input), ss_length (input));
250 retval = (format == FMT_Z
251 ? strchr (s, '.') == NULL
252 : number_has_implied_decimals (s, format));
258 /* In some cases, when no decimal point is explicitly included in numeric
259 input, its position is implied by the number of decimal places in the input
260 format. In such a case, this function may be called just after data_in().
261 Its arguments are a subset of that function's arguments plus D, the number
262 of decimal places associated with FORMAT.
264 If it is appropriate, this function modifies the numeric value in OUTPUT. */
266 data_in_imply_decimals (struct substring input, const char *input_encoding,
267 enum fmt_type format, int d, union value *output)
269 if (d > 0 && output->f != SYSMIS
270 && has_implied_decimals (input, input_encoding, format))
271 output->f /= pow (10., d);
274 /* Format parsers. */
276 /* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
278 parse_number (struct data_in *i)
280 const struct fmt_number_style *style =
281 settings_get_style (i->format);
285 bool explicit_decimals = false;
289 if (fmt_get_category (i->format) == FMT_CAT_CUSTOM)
291 style = settings_get_style (FMT_F);
294 /* Trim spaces and check for missing value representation. */
295 if (trim_spaces_and_check_missing (i))
298 ds_init_empty (&tmp);
299 ds_extend (&tmp, 64);
301 /* Prefix character may precede sign. */
302 if (!ss_is_empty (style->prefix))
304 ss_match_byte (&i->input, ss_first (style->prefix));
305 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
309 if (ss_match_byte (&i->input, '-'))
311 ds_put_byte (&tmp, '-');
312 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
316 ss_match_byte (&i->input, '+');
317 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
320 /* Prefix character may follow sign. */
321 if (!ss_is_empty (style->prefix))
323 ss_match_byte (&i->input, ss_first (style->prefix));
324 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
327 /* Digits before decimal point. */
328 while (c_isdigit (ss_first (i->input)))
330 ds_put_byte (&tmp, ss_get_byte (&i->input));
331 if (style->grouping != 0)
332 ss_match_byte (&i->input, style->grouping);
335 /* Decimal point and following digits. */
336 if (ss_match_byte (&i->input, style->decimal))
338 explicit_decimals = true;
339 ds_put_byte (&tmp, '.');
340 while (c_isdigit (ss_first (i->input)))
341 ds_put_byte (&tmp, ss_get_byte (&i->input));
345 if (!ds_is_empty (&tmp)
346 && !ss_is_empty (i->input)
347 && strchr ("eEdD-+", ss_first (i->input)))
349 explicit_decimals = true;
350 ds_put_byte (&tmp, 'e');
352 if (strchr ("eEdD", ss_first (i->input)))
354 ss_advance (&i->input, 1);
355 ss_match_byte (&i->input, ' ');
358 if (ss_first (i->input) == '-' || ss_first (i->input) == '+')
360 if (ss_get_byte (&i->input) == '-')
361 ds_put_byte (&tmp, '-');
362 ss_match_byte (&i->input, ' ');
365 while (c_isdigit (ss_first (i->input)))
366 ds_put_byte (&tmp, ss_get_byte (&i->input));
369 /* Suffix character. */
370 if (!ss_is_empty (style->suffix))
371 ss_match_byte (&i->input, ss_first (style->suffix));
373 if (!ss_is_empty (i->input))
376 if (ds_is_empty (&tmp))
377 error = xstrdup (_("Field contents are not numeric."));
379 error = xstrdup (_("Number followed by garbage."));
384 /* Let c_strtod() do the conversion. */
387 i->output->f = c_strtod (ds_cstr (&tmp), &tail);
392 return xstrdup (_("Invalid numeric syntax."));
394 else if (errno == ERANGE)
396 if (fabs (i->output->f) > 1)
398 i->output->f = SYSMIS;
400 return xstrdup (_("Too-large number set to system-missing."));
406 return xstrdup (_("Too-small number set to zero."));
416 /* Parses N format. */
418 parse_N (struct data_in *i)
423 while ((c = ss_get_byte (&i->input)) != EOF)
426 return xstrdup (_("All characters in field must be digits."));
427 i->output->f = i->output->f * 10.0 + (c - '0');
433 /* Parses PIBHEX format. */
435 parse_PIBHEX (struct data_in *i)
442 while ((c = ss_get_byte (&i->input)) != EOF)
445 return xstrdup (_("Unrecognized character in field."));
446 n = n * 16.0 + hexit_value (c);
453 /* Parses RBHEX format. */
455 parse_RBHEX (struct data_in *i)
460 memset (&d, 0, sizeof d);
461 for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
463 int hi = ss_get_byte (&i->input);
464 int lo = ss_get_byte (&i->input);
466 return xstrdup (_("Field must have even length."));
467 else if (!c_isxdigit (hi) || !c_isxdigit (lo))
468 return xstrdup (_("Field must contain only hex digits."));
469 ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
477 /* Digits for Z format. */
478 static const char z_digits[] = "0123456789{ABCDEFGHI}JKLMNOPQR";
480 /* Returns true if C is a Z format digit, false otherwise. */
484 return c > 0 && strchr (z_digits, c) != NULL;
487 /* Returns the (absolute value of the) value of C as a Z format
490 z_digit_value (int c)
492 assert (is_z_digit (c));
493 return (strchr (z_digits, c) - z_digits) % 10;
496 /* Returns true if Z format digit C represents a negative value,
499 is_negative_z_digit (int c)
501 assert (is_z_digit (c));
502 return (strchr (z_digits, c) - z_digits) >= 20;
505 /* Parses Z format. */
507 parse_Z (struct data_in *i)
513 bool got_dot = false;
514 bool got_final_digit = false;
516 /* Trim spaces and check for missing value representation. */
517 if (trim_spaces_and_check_missing (i))
520 ds_init_empty (&tmp);
521 ds_extend (&tmp, 64);
523 ds_put_byte (&tmp, '+');
524 while (!ss_is_empty (i->input))
526 int c = ss_get_byte (&i->input);
527 if (c_isdigit (c) && !got_final_digit)
528 ds_put_byte (&tmp, c);
529 else if (is_z_digit (c) && !got_final_digit)
531 ds_put_byte (&tmp, z_digit_value (c) + '0');
532 if (is_negative_z_digit (c))
533 ds_data (&tmp)[0] = '-';
534 got_final_digit = true;
536 else if (c == '.' && !got_dot)
538 ds_put_byte (&tmp, '.');
544 return xstrdup (_("Invalid zoned decimal syntax."));
548 if (!ss_is_empty (i->input))
552 if (ds_length (&tmp) == 1)
553 error = xstrdup (_("Field contents are not numeric."));
555 error = xstrdup (_("Number followed by garbage."));
561 /* Let c_strtod() do the conversion. */
564 i->output->f = c_strtod (ds_cstr (&tmp), NULL);
567 if (fabs (i->output->f) > 1)
569 i->output->f = SYSMIS;
571 return xstrdup (_("Too-large number set to system-missing."));
577 return xstrdup (_("Too-small number set to zero."));
587 /* Parses IB format. */
589 parse_IB (struct data_in *i)
595 bytes = MIN (8, ss_length (i->input));
596 value = integer_get (settings_get_input_integer_format (), ss_data (i->input), bytes);
598 sign_bit = UINT64_C(1) << (8 * bytes - 1);
599 if (!(value & sign_bit))
600 i->output->f = value;
603 /* Sign-extend to full 64 bits. */
604 value -= sign_bit << 1;
605 i->output->f = -(double) -value;
611 /* Parses PIB format. */
613 parse_PIB (struct data_in *i)
615 i->output->f = integer_get (settings_get_input_integer_format (), ss_data (i->input),
616 MIN (8, ss_length (i->input)));
621 /* Consumes the first character of S. Stores its high 4 bits in
622 HIGH_NIBBLE and its low 4 bits in LOW_NIBBLE. */
624 get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
626 int c = ss_get_byte (s);
628 *high_nibble = (c >> 4) & 15;
629 *low_nibble = c & 15;
632 /* Parses P format. */
634 parse_P (struct data_in *i)
636 int high_nibble, low_nibble;
640 while (ss_length (i->input) > 1)
642 get_nibbles (&i->input, &high_nibble, &low_nibble);
643 if (high_nibble > 9 || low_nibble > 9)
644 return xstrdup (_("Invalid syntax for P field."));
645 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
648 get_nibbles (&i->input, &high_nibble, &low_nibble);
650 return xstrdup (_("Invalid syntax for P field."));
651 i->output->f = (10 * i->output->f) + high_nibble;
653 i->output->f = (10 * i->output->f) + low_nibble;
654 else if (low_nibble == 0xb || low_nibble == 0xd)
655 i->output->f = -i->output->f;
660 /* Parses PK format. */
662 parse_PK (struct data_in *i)
665 while (!ss_is_empty (i->input))
667 int high_nibble, low_nibble;
669 get_nibbles (&i->input, &high_nibble, &low_nibble);
670 if (high_nibble > 9 || low_nibble > 9)
672 i->output->f = SYSMIS;
675 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
681 /* Parses RB format. */
683 parse_RB (struct data_in *i)
685 enum float_format ff = settings_get_input_float_format ();
686 size_t size = float_get_size (ff);
687 if (ss_length (i->input) >= size)
688 float_convert (ff, ss_data (i->input),
689 FLOAT_NATIVE_DOUBLE, &i->output->f);
691 i->output->f = SYSMIS;
696 /* Parses A format. */
698 parse_A (struct data_in *i)
700 /* This is equivalent to buf_copy_rpad, except that we posibly
701 do a character set recoding in the middle. */
702 uint8_t *dst = value_str_rw (i->output, i->width);
703 size_t dst_size = i->width;
704 const char *src = ss_data (i->input);
705 size_t src_size = ss_length (i->input);
707 memcpy (dst, src, MIN (src_size, dst_size));
709 if (dst_size > src_size)
710 memset (&dst[src_size], ' ', dst_size - src_size);
715 /* Parses AHEX format. */
717 parse_AHEX (struct data_in *i)
719 uint8_t *s = value_str_rw (i->output, i->width);
724 int hi = ss_get_byte (&i->input);
725 int lo = ss_get_byte (&i->input);
729 return xstrdup (_("Field must have even length."));
731 if (!c_isxdigit (hi) || !c_isxdigit (lo))
732 return xstrdup (_("Field must contain only hex digits."));
735 s[j] = hexit_value (hi) * 16 + hexit_value (lo);
738 memset (&s[j], ' ', i->width - j);
743 /* Date & time format components. */
745 /* Sign of a time value. */
748 SIGN_NO_TIME, /* No time yet encountered. */
749 SIGN_POSITIVE, /* Positive time. */
750 SIGN_NEGATIVE /* Negative time. */
753 /* Parses a signed decimal integer from at most the first
754 MAX_DIGITS characters in I, storing the result into *RESULT.
755 Returns true if successful, false if no integer was
757 static char * WARN_UNUSED_RESULT
758 parse_int (struct data_in *i, long *result, size_t max_digits)
760 struct substring head = ss_head (i->input, max_digits);
761 size_t n = ss_get_long (&head, result);
764 ss_advance (&i->input, n);
768 return xstrdup (_("Syntax error in date field."));
771 /* Parses a date integer between 1 and 31 from I, storing it into
773 Returns true if successful, false if no date was present. */
775 parse_day (struct data_in *i, long *day)
777 char *error = parse_int (i, day, SIZE_MAX);
780 if (*day >= 1 && *day <= 31)
783 return xasprintf (_("Day (%ld) must be between 1 and 31."), *day);
786 /* Parses an integer from the beginning of I.
787 Adds SECONDS_PER_UNIT times the absolute value of the integer
789 If *TIME_SIGN is SIGN_NO_TIME, allows a sign to precede the
790 time and sets *TIME_SIGN. Otherwise, does not allow a sign.
791 Returns true if successful, false if no integer was present. */
793 parse_time_units (struct data_in *i, double seconds_per_unit,
794 enum time_sign *time_sign, double *time)
800 if (*time_sign == SIGN_NO_TIME)
802 if (ss_match_byte (&i->input, '-'))
803 *time_sign = SIGN_NEGATIVE;
806 ss_match_byte (&i->input, '+');
807 *time_sign = SIGN_POSITIVE;
810 error = parse_int (i, &units, SIZE_MAX);
814 return xstrdup (_("Syntax error in date field."));
815 *time += units * seconds_per_unit;
819 /* Parses a data delimiter from the beginning of I.
820 Returns true if successful, false if no delimiter was
823 parse_date_delimiter (struct data_in *i)
825 if (ss_ltrim (&i->input, ss_cstr ("-/.," CC_SPACES)))
828 return xstrdup (_("Delimiter expected between fields in date."));
831 /* Parses spaces at the beginning of I. */
833 parse_spaces (struct data_in *i)
835 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
838 static struct substring
839 parse_name_token (struct data_in *i)
841 struct substring token;
842 ss_get_bytes (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
846 /* Reads a name from I and sets *OUTPUT to the value associated
847 with that name. If ALLOW_SUFFIXES is true, then names that
848 begin with one of the names are accepted; otherwise, only
849 exact matches (except for case) are allowed.
850 Returns true if successful, false otherwise. */
852 match_name (struct substring token, const char *const *names, long *output)
856 for (i = 1; *names != NULL; i++)
857 if (ss_equals_case (ss_cstr (*names++), token))
866 /* Parses a month name or number from the beginning of I,
867 storing the month (in range 1...12) into *MONTH.
868 Returns true if successful, false if no month was present. */
870 parse_month (struct data_in *i, long *month)
872 if (c_isdigit (ss_first (i->input)))
874 char *error = parse_int (i, month, SIZE_MAX);
877 if (*month >= 1 && *month <= 12)
882 static const char *const english_names[] =
884 "jan", "feb", "mar", "apr", "may", "jun",
885 "jul", "aug", "sep", "oct", "nov", "dec",
889 static const char *const roman_names[] =
891 "i", "ii", "iii", "iv", "v", "vi",
892 "vii", "viii", "ix", "x", "xi", "xii",
896 struct substring token = parse_name_token (i);
897 if (match_name (ss_head (token, 3), english_names, month)
898 || match_name (ss_head (token, 4), roman_names, month))
902 return xstrdup (_("Unrecognized month format. Months may be specified "
903 "as Arabic or Roman numerals or as at least 3 letters "
904 "of their English names."));
907 /* Parses a year of at most MAX_DIGITS from the beginning of I,
908 storing a "4-digit" year into *YEAR. */
910 parse_year (struct data_in *i, long *year, size_t max_digits)
912 char *error = parse_int (i, year, max_digits);
916 if (*year >= 0 && *year <= 99)
918 int epoch = settings_get_epoch ();
919 int epoch_century = ROUND_DOWN (epoch, 100);
920 int epoch_offset = epoch - epoch_century;
921 if (*year >= epoch_offset)
922 *year += epoch_century;
924 *year += epoch_century + 100;
926 if (*year >= 1582 || *year <= 19999)
929 return xasprintf (_("Year (%ld) must be between 1582 and 19999."), *year);
932 /* Returns true if input in I has been exhausted,
935 parse_trailer (struct data_in *i)
937 if (ss_is_empty (i->input))
940 return xasprintf (_("Trailing garbage `%.*s' following date."),
941 (int) ss_length (i->input), ss_data (i->input));
944 /* Parses a 3-digit Julian day-of-year value from I into *YDAY.
945 Returns true if successful, false on failure. */
947 parse_yday (struct data_in *i, long *yday)
949 struct substring num_s;
952 ss_get_bytes (&i->input, 3, &num_s);
953 if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
954 return xstrdup (_("Julian day must have exactly three digits."));
955 else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
956 return xasprintf (_("Julian day (%ld) must be between 1 and 366."), num);
962 /* Parses a quarter-of-year integer between 1 and 4 from I.
963 Stores the corresponding month into *MONTH.
964 Returns true if successful, false if no quarter was present. */
966 parse_quarter (struct data_in *i, long int *month)
971 error = parse_int (i, &quarter, SIZE_MAX);
974 if (quarter >= 1 && quarter <= 4)
976 *month = (quarter - 1) * 3 + 1;
980 return xasprintf (_("Quarter (%ld) must be between 1 and 4."), quarter);
983 /* Parses a week-of-year integer between 1 and 53 from I,
984 Stores the corresponding year-of-day into *YDAY.
985 Returns true if successful, false if no week was present. */
987 parse_week (struct data_in *i, long int *yday)
992 error = parse_int (i, &week, SIZE_MAX);
995 if (week >= 1 && week <= 53)
997 *yday = (week - 1) * 7 + 1;
1001 return xasprintf (_("Week (%ld) must be between 1 and 53."), week);
1004 /* Parses a time delimiter from the beginning of I.
1005 Returns true if successful, false if no delimiter was
1008 parse_time_delimiter (struct data_in *i)
1010 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
1013 return xstrdup (_("Delimiter expected between fields in time."));
1016 /* Parses minutes and optional seconds from the beginning of I.
1017 The time is converted into seconds, which are added to
1019 Returns true if successful, false if an error was found. */
1021 parse_minute_second (struct data_in *i, double *time)
1028 /* Parse minutes. */
1029 error = parse_int (i, &minute, SIZE_MAX);
1032 if (minute < 0 || minute > 59)
1033 return xasprintf (_("Minute (%ld) must be between 0 and 59."), minute);
1034 *time += 60. * minute;
1036 /* Check for seconds. */
1037 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) == 0
1038 || !c_isdigit (ss_first (i->input)))
1041 /* Parse seconds. */
1043 while (c_isdigit (ss_first (i->input)))
1044 *cp++ = ss_get_byte (&i->input);
1045 if (ss_match_byte (&i->input, settings_get_decimal_char (FMT_F)))
1047 while (c_isdigit (ss_first (i->input)))
1048 *cp++ = ss_get_byte (&i->input);
1051 *time += strtod (buf, NULL);
1056 /* Parses a weekday name from the beginning of I,
1057 storing a value of 1=Sunday...7=Saturday into *WEEKDAY.
1058 Returns true if successful, false if an error was found. */
1060 parse_weekday (struct data_in *i, long *weekday)
1062 static const char *const weekday_names[] =
1064 "su", "mo", "tu", "we", "th", "fr", "sa",
1068 struct substring token = parse_name_token (i);
1069 bool ok = match_name (ss_head (token, 2), weekday_names, weekday);
1071 return xstrdup (_("Unrecognized weekday name. At least the first two "
1072 "letters of an English weekday name must be "
1077 /* Date & time formats. */
1079 /* Parses WKDAY format. */
1081 parse_WKDAY (struct data_in *i)
1086 if (trim_spaces_and_check_missing (i))
1089 error = parse_weekday (i, &weekday);
1091 error = parse_trailer (i);
1093 i->output->f = weekday;
1097 /* Parses MONTH format. */
1099 parse_MONTH (struct data_in *i)
1104 if (trim_spaces_and_check_missing (i))
1107 error = parse_month (i, &month);
1109 error = parse_trailer (i);
1111 i->output->f = month;
1115 /* Parses DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, KWYR,
1116 DATETIME, TIME and DTIME formats. */
1118 parse_date (struct data_in *i)
1120 long int year = INT_MIN;
1124 double time = 0, date = 0;
1125 enum time_sign time_sign = SIGN_NO_TIME;
1127 const char *template = fmt_date_template (i->format);
1128 size_t template_width = strlen (template);
1131 if (trim_spaces_and_check_missing (i))
1134 while (*template != '\0')
1136 unsigned char ch = *template;
1139 while (template[count] == ch)
1146 error = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
1149 error = parse_month (i, &month);
1154 if (!c_isalpha (*template))
1155 max_digits = SIZE_MAX;
1158 if (ss_length (i->input) >= template_width + 2)
1163 error = parse_year (i, &year, max_digits);
1167 error = parse_quarter (i, &month);
1170 error = parse_week (i, &yday);
1173 error = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
1176 error = parse_time_units (i, 60. * 60., &time_sign, &time);
1179 error = parse_minute_second (i, &time);
1185 error = parse_date_delimiter (i);
1188 error = parse_time_delimiter (i);
1194 assert (count == 1);
1195 if (!ss_match_byte (&i->input, c_toupper (ch))
1196 && !ss_match_byte (&i->input, c_tolower (ch)))
1197 error = xasprintf (_("`%c' expected in date field."), ch);
1205 error = parse_trailer (i);
1209 if (year != INT_MIN)
1214 ofs = calendar_gregorian_to_offset (year, month, day, &error);
1217 date = (yday - 1 + ofs) * 60. * 60. * 24.;
1221 i->output->f = date + (time_sign == SIGN_NEGATIVE ? -time : time);
1226 /* Utility functions. */
1228 /* Sets the default result for I.
1229 For a numeric format, this is the value set on SET BLANKS
1230 (typically system-missing); for a string format, it is all
1233 default_result (struct data_in *i)
1235 if (fmt_is_string (i->format))
1236 memset (value_str_rw (i->output, i->width), ' ', i->width);
1238 i->output->f = settings_get_blanks ();
1241 /* Trims leading and trailing spaces from I.
1242 If the result is empty, or a single period character, then
1243 sets the default result and returns true; otherwise, returns
1246 trim_spaces_and_check_missing (struct data_in *i)
1248 ss_trim (&i->input, ss_cstr (" "));
1249 if (ss_is_empty (i->input) || ss_equals (i->input, ss_cstr (".")))
1257 /* Returns the integer value of hex digit C. */
1261 const char s[] = "0123456789abcdef";
1262 const char *cp = strchr (s, c_tolower ((unsigned char) c));
1264 assert (cp != NULL);