Esempio n. 1
0
	timeptr->tm_yday = 0;
    }
}

/* strptime: roken */
//extern "C"
char *
//strptime (const char *buf, const char *format, struct tm *timeptr)
_DEFUN (strptime, (buf, format, timeptr),
	_CONST char *buf _AND
	_CONST char *format _AND
	struct tm *timeptr)
{
    char c;

    struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale ();
    for (; (c = *format) != '\0'; ++format) {
	char *s;
	int ret;

	if (isspace (c)) {
	    while (isspace (*buf))
		++buf;
	} else if (c == '%' && format[1] != '\0') {
	    c = *++format;
	    if (c == 'E' || c == 'O')
		c = *++format;
	    switch (c) {
	    case 'A' :
		ret = match_string (&buf, _ctloc (weekday));
		if (ret < 0)
Esempio n. 2
0
char *
nl_langinfo_l(nl_item item, locale_t loc)
{
   char *ret, *cs;
   const char *s;
   FIX_LOCALE(loc);

   switch (item) {
	case CODESET:
		s = XLOCALE_CTYPE(loc)->runes->__encoding;
		if (strcmp(s, "EUC-CN") == 0)
			ret = "eucCN";
		else if (strcmp(s, "EUC-JP") == 0)
			ret = "eucJP";
		else if (strcmp(s, "EUC-KR") == 0)
			ret = "eucKR";
		else if (strcmp(s, "EUC-TW") == 0)
			ret = "eucTW";
		else if (strcmp(s, "BIG5") == 0)
			ret = "Big5";
		else if (strcmp(s, "MSKanji") == 0)
			ret = "SJIS";
		else if (strcmp(s, "NONE") == 0)
			ret = "POSIX";
		else if (strncmp(s, "NONE:", 5) == 0)
			ret = (char *)(s + 5);
		else
			ret = (char *)s;
		break;
	case D_T_FMT:
		ret = (char *) __get_current_time_locale(loc)->c_fmt;
		break;
	case D_FMT:
		ret = (char *) __get_current_time_locale(loc)->x_fmt;
		break;
	case T_FMT:
		ret = (char *) __get_current_time_locale(loc)->X_fmt;
		break;
	case T_FMT_AMPM:
		ret = (char *) __get_current_time_locale(loc)->ampm_fmt;
		break;
	case AM_STR:
		ret = (char *) __get_current_time_locale(loc)->am;
		break;
	case PM_STR:
		ret = (char *) __get_current_time_locale(loc)->pm;
		break;
	case DAY_1: case DAY_2: case DAY_3:
	case DAY_4: case DAY_5: case DAY_6: case DAY_7:
		ret = (char*) __get_current_time_locale(loc)->weekday[_REL(DAY_1)];
		break;
	case ABDAY_1: case ABDAY_2: case ABDAY_3:
	case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
		ret = (char*) __get_current_time_locale(loc)->wday[_REL(ABDAY_1)];
		break;
	case MON_1: case MON_2: case MON_3: case MON_4:
	case MON_5: case MON_6: case MON_7: case MON_8:
	case MON_9: case MON_10: case MON_11: case MON_12:
		ret = (char*) __get_current_time_locale(loc)->month[_REL(MON_1)];
		break;
	case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
	case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
	case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
		ret = (char*) __get_current_time_locale(loc)->mon[_REL(ABMON_1)];
		break;
	case ALTMON_1: case ALTMON_2: case ALTMON_3: case ALTMON_4:
	case ALTMON_5: case ALTMON_6: case ALTMON_7: case ALTMON_8:
	case ALTMON_9: case ALTMON_10: case ALTMON_11: case ALTMON_12:
		ret = (char*)
		    __get_current_time_locale(loc)->alt_month[_REL(ALTMON_1)];
		break;
	case ERA:
		/* XXX: need to be implemented  */
		ret = "";
		break;
	case ERA_D_FMT:
		/* XXX: need to be implemented  */
		ret = "";
		break;
	case ERA_D_T_FMT:
		/* XXX: need to be implemented  */
		ret = "";
		break;
	case ERA_T_FMT:
		/* XXX: need to be implemented  */
		ret = "";
		break;
	case ALT_DIGITS:
		/* XXX: need to be implemented  */
		ret = "";
		break;
	case RADIXCHAR:
		ret = (char*) __get_current_numeric_locale(loc)->decimal_point;
		break;
	case THOUSEP:
		ret = (char*) __get_current_numeric_locale(loc)->thousands_sep;
		break;
	case YESEXPR:
		ret = (char*) __get_current_messages_locale(loc)->yesexpr;
		break;
	case NOEXPR:
		ret = (char*) __get_current_messages_locale(loc)->noexpr;
		break;
	/*
	 * YESSTR and NOSTR items marked with LEGACY are available, but not
	 * recomended by SUSv2 to be used in portable applications since
	 * they're subject to remove in future specification editions.
	 */
	case YESSTR:            /* LEGACY  */
		ret = (char*) __get_current_messages_locale(loc)->yesstr;
		break;
	case NOSTR:             /* LEGACY  */
		ret = (char*) __get_current_messages_locale(loc)->nostr;
		break;
	/*
	 * SUSv2 special formatted currency string 
	 */
	case CRNCYSTR:
		ret = "";
		cs = (char*) __get_current_monetary_locale(loc)->currency_symbol;
		if (*cs != '\0') {
			char pos = localeconv_l(loc)->p_cs_precedes;

			if (pos == localeconv_l(loc)->n_cs_precedes) {
				char psn = '\0';

				if (pos == CHAR_MAX) {
					if (strcmp(cs, __get_current_monetary_locale(loc)->mon_decimal_point) == 0)
						psn = '.';
				} else
					psn = pos ? '-' : '+';
				if (psn != '\0') {
					int clen = strlen(cs);

					if ((loc->csym = reallocf(loc->csym, clen + 2)) != NULL) {
						*loc->csym = psn;
						strcpy(loc->csym + 1, cs);
						ret = loc->csym;
					}
				}
			}
		}
		break;
	case D_MD_ORDER:        /* FreeBSD local extension */
		ret = (char *) __get_current_time_locale(loc)->md_order;
		break;
	default:
		ret = "";
   }
   return (ret);
}
Esempio n. 3
0
static char *
_fmt(const char *format, const struct tm *t, char *pt,
     const char *ptlim)
{
    int Ealternative, Oalternative, PadIndex;
#ifdef __ORCAC__
#define tptr (&_C_time_locale)
#else
    struct lc_time_T *tptr = __get_current_time_locale(__get_locale());
#endif

    for ( ; *format; ++format) {
        if (*format == '%') {
            Ealternative = 0;
            Oalternative = 0;
            PadIndex	 = PAD_DEFAULT;
label:
            switch (*++format) {
            case '\0':
                --format;
                break;
            case 'A':
                pt = _add((t->tm_wday < 0 || t->tm_wday >= DAYSPERWEEK) ?
                          "?" : tptr->weekday[t->tm_wday],
                          pt, ptlim);
                continue;
            case 'a':
                pt = _add((t->tm_wday < 0 || t->tm_wday >= DAYSPERWEEK) ?
                          "?" : tptr->wday[t->tm_wday],
                          pt, ptlim);
                continue;
            case 'B':
                pt = _add((t->tm_mon < 0 ||
                           t->tm_mon >= MONSPERYEAR) ?
                          "?" : (Oalternative ? tptr->alt_month :
                                 tptr->month)[t->tm_mon],
                          pt, ptlim);
                continue;

                continue;
            case 'b':
            case 'h':
                pt = _add((t->tm_mon < 0 || t->tm_mon >= MONSPERYEAR) ?
                          "?" : tptr->mon[t->tm_mon],
                          pt, ptlim);
                continue;
            case 'C':
                /*
                 * %C used to do a...
                 *	_fmt("%a %b %e %X %Y", t);
                 * ...whereas now POSIX 1003.2 calls for
                 * something completely different.
                 * (ado, 1993-05-24)
                 */
                pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
                            pt, ptlim);
                continue;
            case 'c':
                pt = _fmt(tptr->c_fmt, t, pt, ptlim);
                continue;
            case 'D':
                pt = _fmt("%m/%d/%y", t, pt, ptlim);
                continue;
            case 'd':
                pt = _conv(t->tm_mday,
                           fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex],
                           pt, ptlim);
                continue;
            case 'E':
                if (Ealternative || Oalternative)
                    break;
                Ealternative++;
                goto label;
            case 'O':
                /*
                 * C99 locale modifiers.
                 * The sequences
                 *	%Ec %EC %Ex %EX %Ey %EY
                 *	%Od %oe %OH %OI %Om %OM
                 *	%OS %Ou %OU %OV %Ow %OW %Oy
                 * are supposed to provide alternate
                 * representations.
                 *
                 * FreeBSD extension
                 *      %OB
                 */
                if (Ealternative || Oalternative)
                    break;
                Oalternative++;
                goto label;
            case 'e':
                pt = _conv(t->tm_mday,
                           fmt_padding[PAD_FMT_SDAYOFMONTH][PadIndex],
                           pt, ptlim);
                continue;
            case 'F':
                pt = _fmt("%Y-%m-%d", t, pt, ptlim);
                continue;
            case 'H':
                pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex],
                           pt, ptlim);
                continue;
            case 'I':
                pt = _conv((t->tm_hour % 12) ?
                           (t->tm_hour % 12) : 12,
                           fmt_padding[PAD_FMT_HMS][PadIndex],
                           pt, ptlim);
                continue;
            case 'j':
                pt = _conv(t->tm_yday + 1,
                           fmt_padding[PAD_FMT_DAYOFYEAR][PadIndex],
                           pt, ptlim);
                continue;
            case 'k':
                /*
                 * This used to be...
                 *	_conv(t->tm_hour % 12 ?
                 *		t->tm_hour % 12 : 12, 2, ' ');
                 * ...and has been changed to the below to
                 * match SunOS 4.1.1 and Arnold Robbins'
                 * strftime version 3.0. That is, "%k" and
                 * "%l" have been swapped.
                 * (ado, 1993-05-24)
                 */
                pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_SHMS][PadIndex],
                           pt, ptlim);
                continue;
#ifdef KITCHEN_SINK
            case 'K':
                /*
                ** After all this time, still unclaimed!
                */
                pt = _add("kitchen sink", pt, ptlim);
                continue;
#endif /* defined KITCHEN_SINK */
            case 'l':
                /*
                 * This used to be...
                 *	_conv(t->tm_hour, 2, ' ');
                 * ...and has been changed to the below to
                 * match SunOS 4.1.1 and Arnold Robbin's
                 * strftime version 3.0. That is, "%k" and
                 * "%l" have been swapped.
                 * (ado, 1993-05-24)
                 */
                pt = _conv((t->tm_hour % 12) ?
                           (t->tm_hour % 12) : 12,
                           fmt_padding[PAD_FMT_SHMS][PadIndex],
                           pt, ptlim);
                continue;
            case 'M':
                pt = _conv(t->tm_min, fmt_padding[PAD_FMT_HMS][PadIndex],
                           pt, ptlim);
                continue;
            case 'm':
                pt = _conv(t->tm_mon + 1,
                           fmt_padding[PAD_FMT_MONTH][PadIndex],
                           pt, ptlim);
                continue;
            case 'n':
                pt = _add("\n", pt, ptlim);
                continue;
            case 'p':
                pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
                          tptr->pm : tptr->am,
                          pt, ptlim);
                continue;
            case 'R':
                pt = _fmt("%H:%M", t, pt, ptlim);
                continue;
            case 'r':
                pt = _fmt(tptr->ampm_fmt, t, pt, ptlim);
                continue;
            case 'S':
                pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex],
                           pt, ptlim);
                continue;
            case 's':
                pt = _secs(t, pt, ptlim);
                continue;
            case 'T':
                pt = _fmt("%H:%M:%S", t, pt, ptlim);
                continue;
            case 't':
                pt = _add("\t", pt, ptlim);
                continue;
            case 'U':
                pt = _conv((t->tm_yday + DAYSPERWEEK -
                            t->tm_wday) / DAYSPERWEEK,
                           fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
                           pt, ptlim);
                continue;
            case 'u':
                /*
                 * From Arnold Robbins' strftime version 3.0:
                 * "ISO 8601: Weekday as a decimal number
                 * [1 (Monday) - 7]"
                 * (ado, 1993-05-24)
                 */
                pt = _conv((t->tm_wday == 0) ?
                           DAYSPERWEEK : t->tm_wday,
                           "%d", pt, ptlim);
                continue;
            case 'V':	/* ISO 8601 week number */
            case 'G':	/* ISO 8601 year (four digits) */
            case 'g':	/* ISO 8601 year (two digits) */
                /*
                 * From Arnold Robbins' strftime version 3.0: "the week number of the
                 * year (the first Monday as the first day of week 1) as a decimal number
                 * (01-53)."
                 * (ado, 1993-05-24)
                 *
                 * From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
                 * "Week 01 of a year is per definition the first week which has the
                 * Thursday in this year, which is equivalent to the week which contains
                 * the fourth day of January. In other words, the first week of a new year
                 * is the week which has the majority of its days in the new year. Week 01
                 * might also contain days from the previous year and the week before week
                 * 01 of a year is the last week (52 or 53) of the previous year even if
                 * it contains days from the new year. A week starts with Monday (day 1)
                 * and ends with Sunday (day 7). For example, the first week of the year
                 * 1997 lasts from 1996-12-30 to 1997-01-05..."
                 * (ado, 1996-01-02)
                 */
            {
                int	year;
                int	base;
                int	yday;
                int	wday;
                int	w;

                year = t->tm_year;
                base = TM_YEAR_BASE;
                yday = t->tm_yday;
                wday = t->tm_wday;
                for ( ; ; ) {
                    int	len;
                    int	bot;
                    int	top;

                    len = isleap_sum(year, base) ?
                          DAYSPERLYEAR :
                          DAYSPERNYEAR;
                    /*
                     * What yday (-3 ... 3) does
                     * the ISO year begin on?
                     */
                    bot = ((yday + 11 - wday) %
                           DAYSPERWEEK) - 3;
                    /*
                     * What yday does the NEXT
                     * ISO year begin on?
                     */
                    top = bot -
                          (len % DAYSPERWEEK);
                    if (top < -3)
                        top += DAYSPERWEEK;
                    top += len;
                    if (yday >= top) {
                        ++base;
                        w = 1;
                        break;
                    }
                    if (yday >= bot) {
                        w = 1 + ((yday - bot) /
                                 DAYSPERWEEK);
                        break;
                    }
                    --base;
                    yday += isleap_sum(year, base) ?
                            DAYSPERLYEAR :
                            DAYSPERNYEAR;
                }
#ifdef XPG4_1994_04_09
                if ((w == 52 &&
                        t->tm_mon == TM_JANUARY) ||
                        (w == 1 &&
                         t->tm_mon == TM_DECEMBER))
                    w = 53;
#endif /* defined XPG4_1994_04_09 */
                if (*format == 'V')
                    pt = _conv(w, fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
                               pt, ptlim);
                else if (*format == 'g') {
                    pt = _yconv(year, base, 0, 1,
                                pt, ptlim);
                } else	pt = _yconv(year, base, 1, 1,
                                        pt, ptlim);
            }
            continue;
            case 'v':
                /*
                 * From Arnold Robbins' strftime version 3.0:
                 * "date as dd-bbb-YYYY"
                 * (ado, 1993-05-24)
                 */
                pt = _fmt("%e-%b-%Y", t, pt, ptlim);
                continue;
            case 'W':
                pt = _conv((t->tm_yday + DAYSPERWEEK -
                            (t->tm_wday ?
                             (t->tm_wday - 1) :
                             (DAYSPERWEEK - 1))) / DAYSPERWEEK,
                           fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
                           pt, ptlim);
                continue;
            case 'w':
                pt = _conv(t->tm_wday, "%d", pt, ptlim);
                continue;
            case 'X':
                pt = _fmt(tptr->X_fmt, t, pt, ptlim);
                continue;
            case 'x':
                pt = _fmt(tptr->x_fmt, t, pt, ptlim);
                continue;
            case 'y':
                pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
                            pt, ptlim);
                continue;
            case 'Y':
                pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
                            pt, ptlim);
                continue;
            case 'Z':
#ifdef TM_ZONE
                if (t->TM_ZONE != NULL)
                    pt = _add(t->TM_ZONE, pt, ptlim);
                else
#endif /* defined TM_ZONE */
                    if (t->tm_isdst >= 0)
                        pt = _add(tzname[t->tm_isdst != 0],
                                  pt, ptlim);
                /*
                 * C99 says that %Z must be replaced by the
                 * empty string if the time zone is not
                 * determinable.
                 */
                continue;
            case 'z':
            {
                int		diff;
                char const *	sign;

                if (t->tm_isdst < 0)
                    continue;
#ifdef TM_GMTOFF
                diff = t->TM_GMTOFF;
#else /* !defined TM_GMTOFF */
                /*
                 * C99 says that the UTC offset must
                 * be computed by looking only at
                 * tm_isdst. This requirement is
                 * incorrect, since it means the code
                 * must rely on magic (in this case
                 * altzone and timezone), and the
                 * magic might not have the correct
                 * offset. Doing things correctly is
                 * tricky and requires disobeying C99;
                 * see GNU C strftime for details.
                 * For now, punt and conform to the
                 * standard, even though it's incorrect.
                 *
                 * C99 says that %z must be replaced by the
                 * empty string if the time zone is not
                 * determinable, so output nothing if the
                 * appropriate variables are not available.
                 */
                if (t->tm_isdst == 0)
#ifdef USG_COMPAT
                    diff = -timezone;
#else /* !defined USG_COMPAT */
                    continue;
#endif /* !defined USG_COMPAT */
                else
#ifdef ALTZONE
                    diff = -altzone;
#else /* !defined ALTZONE */
                    continue;
#endif /* !defined ALTZONE */
#endif /* !defined TM_GMTOFF */
                if (diff < 0) {
                    sign = "-";
                    diff = -diff;
                } else
                    sign = "+";
                pt = _add(sign, pt, ptlim);
                diff /= SECSPERMIN;
                diff = (diff / MINSPERHOUR) * 100 +
                       (diff % MINSPERHOUR);
                pt = _conv(diff,
                           fmt_padding[PAD_FMT_YEAR][PadIndex],
                           pt, ptlim);
            }
            continue;
            case '+':
                pt = _fmt(tptr->date_fmt, t, pt, ptlim);
                continue;
            case '-':
                if (PadIndex != PAD_DEFAULT)
                    break;
                PadIndex = PAD_LESS;
                goto label;
            case '_':
                if (PadIndex != PAD_DEFAULT)
                    break;
                PadIndex = PAD_SPACE;
                goto label;
            case '0':
                if (PadIndex != PAD_DEFAULT)
                    break;
                PadIndex = PAD_ZERO;
                goto label;
            case '%':
            /*
             * X311J/88-090 (4.12.3.5): if conversion char is
             * undefined, behavior is undefined. Print out the
             * character itself as printf(3) also does.
             */
            default:
                break;
            }
        }
Esempio n. 4
0
static char*
_strptime(const char* buf, const char* fmt, struct tm* tm, int* GMTp) {
    char    c;
    const char* ptr;
    int i,
        len;
    int Ealternative, Oalternative;
    struct lc_time_T* tptr = __get_current_time_locale();
    ptr = fmt;

    while (*ptr != 0) {
        if (*buf == 0) {
            break;
        }

        c = *ptr++;

        if (c != '%') {
            if (isspace((unsigned char)c))
                while (*buf != 0 && isspace((unsigned char)*buf)) {
                    buf++;
                }
            else if (c != *buf++) {
                return 0;
            }

            continue;
        }

        Ealternative = 0;
        Oalternative = 0;
    label:
        c = *ptr++;

        switch (c) {
        case 0:
        case '%':
            if (*buf++ != '%') {
                return 0;
            }

            break;

        case '+':
            buf = _strptime(buf, tptr->date_fmt, tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'C':
            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            /* XXX This will break for 3-digit centuries. */
            len = 2;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (i < 19) {
                return 0;
            }

            tm->tm_year = i * 100 - 1900;
            break;

        case 'c':
            buf = _strptime(buf, tptr->c_fmt, tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'D':
            buf = _strptime(buf, "%m/%d/%y", tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'E':
            if (Ealternative || Oalternative) {
                break;
            }

            Ealternative++;
            goto label;

        case 'O':
            if (Ealternative || Oalternative) {
                break;
            }

            Oalternative++;
            goto label;

        case 'F':
            buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'R':
            buf = _strptime(buf, "%H:%M", tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'r':
            buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'T':
            buf = _strptime(buf, "%H:%M:%S", tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'X':
            buf = _strptime(buf, tptr->X_fmt, tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'x':
            buf = _strptime(buf, tptr->x_fmt, tm, GMTp);

            if (buf == 0) {
                return 0;
            }

            break;

        case 'j':
            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            len = 3;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (i < 1 || i > 366) {
                return 0;
            }

            tm->tm_yday = i - 1;
            break;

        case 'M':
        case 'S':
            if (*buf == 0 || isspace((unsigned char)*buf)) {
                break;
            }

            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            len = 2;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (c == 'M') {
                if (i > 59) {
                    return 0;
                }

                tm->tm_min = i;
            } else {
                if (i > 60) {
                    return 0;
                }

                tm->tm_sec = i;
            }

            if (*buf != 0 && isspace((unsigned char)*buf))
                while (*ptr != 0 && !isspace((unsigned char)*ptr)) {
                    ptr++;
                }

            break;

        case 'H':
        case 'I':
        case 'k':
        case 'l':

            /*
             * Of these, %l is the only specifier explicitly
             * documented as not being zero-padded.  However,
             * there is no harm in allowing zero-padding.
             *
             * XXX The %l specifier may gobble one too many
             * digits if used incorrectly.
             */
            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            len = 2;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (c == 'H' || c == 'k') {
                if (i > 23) {
                    return 0;
                }
            } else if (i > 12) {
                return 0;
            }

            tm->tm_hour = i;

            if (*buf != 0 && isspace((unsigned char)*buf))
                while (*ptr != 0 && !isspace((unsigned char)*ptr)) {
                    ptr++;
                }

            break;

        case 'p':
            /*
             * XXX This is bogus if parsed before hour-related
             * specifiers.
             */
            len = strlen(tptr->am);

            if (strncasecmp(buf, tptr->am, len) == 0) {
                if (tm->tm_hour > 12) {
                    return 0;
                }

                if (tm->tm_hour == 12) {
                    tm->tm_hour = 0;
                }

                buf += len;
                break;
            }

            len = strlen(tptr->pm);

            if (strncasecmp(buf, tptr->pm, len) == 0) {
                if (tm->tm_hour > 12) {
                    return 0;
                }

                if (tm->tm_hour != 12) {
                    tm->tm_hour += 12;
                }

                buf += len;
                break;
            }

            return 0;

        case 'A':
        case 'a':
            for (i = 0; i < asizeof(tptr->weekday); i++) {
                len = strlen(tptr->weekday[i]);

                if (strncasecmp(buf, tptr->weekday[i],
                                len) == 0) {
                    break;
                }

                len = strlen(tptr->wday[i]);

                if (strncasecmp(buf, tptr->wday[i],
                                len) == 0) {
                    break;
                }
            }

            if (i == asizeof(tptr->weekday)) {
                return 0;
            }

            tm->tm_wday = i;
            buf += len;
            break;

        case 'U':
        case 'W':

            /*
             * XXX This is bogus, as we can not assume any valid
             * information present in the tm structure at this
             * point to calculate a real value, so just check the
             * range for now.
             */
            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            len = 2;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (i > 53) {
                return 0;
            }

            if (*buf != 0 && isspace((unsigned char)*buf))
                while (*ptr != 0 && !isspace((unsigned char)*ptr)) {
                    ptr++;
                }

            break;

        case 'w':
            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            i = *buf - '0';

            if (i > 6) {
                return 0;
            }

            tm->tm_wday = i;

            if (*buf != 0 && isspace((unsigned char)*buf))
                while (*ptr != 0 && !isspace((unsigned char)*ptr)) {
                    ptr++;
                }

            break;

        case 'd':
        case 'e':

            /*
             * The %e specifier is explicitly documented as not
             * being zero-padded but there is no harm in allowing
             * such padding.
             *
             * XXX The %e specifier may gobble one too many
             * digits if used incorrectly.
             */
            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            len = 2;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (i > 31) {
                return 0;
            }

            tm->tm_mday = i;

            if (*buf != 0 && isspace((unsigned char)*buf))
                while (*ptr != 0 && !isspace((unsigned char)*ptr)) {
                    ptr++;
                }

            break;

        case 'B':
        case 'b':
        case 'h':
            for (i = 0; i < asizeof(tptr->month); i++) {
                if (Oalternative) {
                    if (c == 'B') {
                        len = strlen(tptr->alt_month[i]);

                        if (strncasecmp(buf,
                                        tptr->alt_month[i],
                                        len) == 0) {
                            break;
                        }
                    }
                } else {
                    len = strlen(tptr->month[i]);

                    if (strncasecmp(buf, tptr->month[i],
                                    len) == 0) {
                        break;
                    }

                    len = strlen(tptr->mon[i]);

                    if (strncasecmp(buf, tptr->mon[i],
                                    len) == 0) {
                        break;
                    }
                }
            }

            if (i == asizeof(tptr->month)) {
                return 0;
            }

            tm->tm_mon = i;
            buf += len;
            break;

        case 'm':
            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            len = 2;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (i < 1 || i > 12) {
                return 0;
            }

            tm->tm_mon = i - 1;

            if (*buf != 0 && isspace((unsigned char)*buf))
                while (*ptr != 0 && !isspace((unsigned char)*ptr)) {
                    ptr++;
                }

            break;

        case 's': {
                char* cp;
                int sverrno;
                long n;
                time_t t;
                sverrno = errno;
                errno = 0;
                n = strtol(buf, &cp, 10);

                if (errno == ERANGE || (long)(t = n) != n) {
                    errno = sverrno;
                    return 0;
                }

                errno = sverrno;
                buf = cp;
                gmtime_r(&t, tm);
                *GMTp = 1;
            }
            break;

        case 'Y':
        case 'y':
            if (*buf == 0 || isspace((unsigned char)*buf)) {
                break;
            }

            if (!isdigit((unsigned char)*buf)) {
                return 0;
            }

            len = (c == 'Y') ? 4 : 2;

            for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (c == 'Y') {
                i -= 1900;
            }

            if (c == 'y' && i < 69) {
                i += 100;
            }

            if (i < 0) {
                return 0;
            }

            tm->tm_year = i;

            if (*buf != 0 && isspace((unsigned char)*buf))
                while (*ptr != 0 && !isspace((unsigned char)*ptr)) {
                    ptr++;
                }

            break;

        case 'Z': {
                const char* cp;
                char* zonestr;

                for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {
                    /*empty*/
                }

                if (cp - buf) {
                    zonestr = alloca(cp - buf + 1);
                    strncpy(zonestr, buf, cp - buf);
                    zonestr[cp - buf] = '\0';
                    tzset();

                    if (0 == strcmp(zonestr, "GMT")) {
                        *GMTp = 1;
                    } else if (0 == strcmp(zonestr, tzname[0])) {
                        tm->tm_isdst = 0;
                    } else if (0 == strcmp(zonestr, tzname[1])) {
                        tm->tm_isdst = 1;
                    } else {
                        return 0;
                    }

                    buf += cp - buf;
                }
            }
            break;
        }
    }

    return (char*)buf;
}
Esempio n. 5
0
static char *
_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
          locale_t locale)
{
    char	c;
    const char *ptr;
    int	day_offset = -1, wday_offset;
    int week_offset;
    int	i, len;
    int flags;
    int Ealternative, Oalternative;
    const struct lc_time_T *tptr = __get_current_time_locale(locale);
    static int start_of_month[2][13] = {
        {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
        {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
    };

    flags = FLAG_NONE;

    ptr = fmt;
    while (*ptr != 0) {
        c = *ptr++;

        if (c != '%') {
            if (isspace_l((unsigned char)c, locale))
                while (*buf != 0 &&
                        isspace_l((unsigned char)*buf, locale))
                    buf++;
            else if (c != *buf++)
                return (NULL);
            continue;
        }

        Ealternative = 0;
        Oalternative = 0;
label:
        c = *ptr++;
        switch (c) {
        case '%':
            if (*buf++ != '%')
                return (NULL);
            break;

        case '+':
            buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
            break;

        case 'C':
            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            /* XXX This will break for 3-digit centuries. */
            len = 2;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }
            if (i < 19)
                return (NULL);

            tm->tm_year = i * 100 - TM_YEAR_BASE;
            flags |= FLAG_YEAR;

            break;

        case 'c':
            buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
            break;

        case 'D':
            buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
            break;

        case 'E':
            if (Ealternative || Oalternative)
                break;
            Ealternative++;
            goto label;

        case 'O':
            if (Ealternative || Oalternative)
                break;
            Oalternative++;
            goto label;

        case 'F':
            buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
            break;

        case 'R':
            buf = _strptime(buf, "%H:%M", tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            break;

        case 'r':
            buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            break;

        case 'T':
            buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            break;

        case 'X':
            buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            break;

        case 'x':
            buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);
            if (buf == NULL)
                return (NULL);
            flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
            break;

        case 'j':
            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            len = 3;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }
            if (i < 1 || i > 366)
                return (NULL);

            tm->tm_yday = i - 1;
            flags |= FLAG_YDAY;

            break;

        case 'M':
        case 'S':
            if (*buf == 0 ||
                    isspace_l((unsigned char)*buf, locale))
                break;

            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            len = 2;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }

            if (c == 'M') {
                if (i > 59)
                    return (NULL);
                tm->tm_min = i;
            } else {
                if (i > 60)
                    return (NULL);
                tm->tm_sec = i;
            }

            break;

        case 'H':
        case 'I':
        case 'k':
        case 'l':
            /*
             * Of these, %l is the only specifier explicitly
             * documented as not being zero-padded.  However,
             * there is no harm in allowing zero-padding.
             *
             * XXX The %l specifier may gobble one too many
             * digits if used incorrectly.
             */
            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            len = 2;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }
            if (c == 'H' || c == 'k') {
                if (i > 23)
                    return (NULL);
            } else if (i > 12)
                return (NULL);

            tm->tm_hour = i;

            break;

        case 'p':
            /*
             * XXX This is bogus if parsed before hour-related
             * specifiers.
             */
            len = strlen(tptr->am);
            if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {
                if (tm->tm_hour > 12)
                    return (NULL);
                if (tm->tm_hour == 12)
                    tm->tm_hour = 0;
                buf += len;
                break;
            }

            len = strlen(tptr->pm);
            if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {
                if (tm->tm_hour > 12)
                    return (NULL);
                if (tm->tm_hour != 12)
                    tm->tm_hour += 12;
                buf += len;
                break;
            }

            return (NULL);

        case 'A':
        case 'a':
            for (i = 0; i < asizeof(tptr->weekday); i++) {
                len = strlen(tptr->weekday[i]);
                if (strncasecmp_l(buf, tptr->weekday[i],
                                  len, locale) == 0)
                    break;
                len = strlen(tptr->wday[i]);
                if (strncasecmp_l(buf, tptr->wday[i],
                                  len, locale) == 0)
                    break;
            }
            if (i == asizeof(tptr->weekday))
                return (NULL);

            buf += len;
            tm->tm_wday = i;
            flags |= FLAG_WDAY;
            break;

        case 'U':
        case 'W':
            /*
             * XXX This is bogus, as we can not assume any valid
             * information present in the tm structure at this
             * point to calculate a real value, so just check the
             * range for now.
             */
            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            len = 2;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }
            if (i > 53)
                return (NULL);

            if (c == 'U')
                day_offset = TM_SUNDAY;
            else
                day_offset = TM_MONDAY;


            week_offset = i;

            break;

        case 'w':
            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            i = *buf - '0';
            buf++;
            if (i > 6)
                return (NULL);

            tm->tm_wday = i;
            flags |= FLAG_WDAY;

            break;

        case 'e':
            /*
             * With %e format, our strftime(3) adds a blank space
             * before single digits.
             */
            if (*buf != 0 &&
                    isspace_l((unsigned char)*buf, locale))
                buf++;
        /* FALLTHROUGH */
        case 'd':
            /*
             * The %e specifier was once explicitly documented as
             * not being zero-padded but was later changed to
             * equivalent to %d.  There is no harm in allowing
             * such padding.
             *
             * XXX The %e specifier may gobble one too many
             * digits if used incorrectly.
             */
            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            len = 2;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }
            if (i > 31)
                return (NULL);

            tm->tm_mday = i;
            flags |= FLAG_MDAY;

            break;

        case 'B':
        case 'b':
        case 'h':
            for (i = 0; i < asizeof(tptr->month); i++) {
                if (Oalternative) {
                    if (c == 'B') {
                        len = strlen(tptr->alt_month[i]);
                        if (strncasecmp_l(buf,
                                          tptr->alt_month[i],
                                          len, locale) == 0)
                            break;
                    }
                } else {
                    len = strlen(tptr->month[i]);
                    if (strncasecmp_l(buf, tptr->month[i],
                                      len, locale) == 0)
                        break;
                }
            }
            /*
             * Try the abbreviated month name if the full name
             * wasn't found and Oalternative was not requested.
             */
            if (i == asizeof(tptr->month) && !Oalternative) {
                for (i = 0; i < asizeof(tptr->month); i++) {
                    len = strlen(tptr->mon[i]);
                    if (strncasecmp_l(buf, tptr->mon[i],
                                      len, locale) == 0)
                        break;
                }
            }
            if (i == asizeof(tptr->month))
                return (NULL);

            tm->tm_mon = i;
            buf += len;
            flags |= FLAG_MONTH;

            break;

        case 'm':
            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            len = 2;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }
            if (i < 1 || i > 12)
                return (NULL);

            tm->tm_mon = i - 1;
            flags |= FLAG_MONTH;

            break;

        case 's':
        {
            char *cp;
            int sverrno;
            long n;
            time_t t;

            sverrno = errno;
            errno = 0;
            n = strtol_l(buf, &cp, 10, locale);
            if (errno == ERANGE || (long)(t = n) != n) {
                errno = sverrno;
                return (NULL);
            }
            errno = sverrno;
            buf = cp;
            if (gmtime_r(&t, tm) == NULL)
                return (NULL);
            *GMTp = 1;
            flags |= FLAG_YDAY | FLAG_WDAY | FLAG_MONTH |
                     FLAG_MDAY | FLAG_YEAR;
        }
        break;

        case 'Y':
        case 'y':
            if (*buf == 0 ||
                    isspace_l((unsigned char)*buf, locale))
                break;

            if (!isdigit_l((unsigned char)*buf, locale))
                return (NULL);

            len = (c == 'Y') ? 4 : 2;
            for (i = 0; len && *buf != 0 &&
                    isdigit_l((unsigned char)*buf, locale); buf++) {
                i *= 10;
                i += *buf - '0';
                len--;
            }
            if (c == 'Y')
                i -= TM_YEAR_BASE;
            if (c == 'y' && i < 69)
                i += 100;
            if (i < 0)
                return (NULL);

            tm->tm_year = i;
            flags |= FLAG_YEAR;

            break;

        case 'Z':
        {
            const char *cp;
            char *zonestr;

            for (cp = buf; *cp &&
                    isupper_l((unsigned char)*cp, locale); ++cp) {
                /*empty*/
            }
            if (cp - buf) {
                zonestr = alloca(cp - buf + 1);
                strncpy(zonestr, buf, cp - buf);
                zonestr[cp - buf] = '\0';
                tzset();
                if (0 == strcmp(zonestr, "GMT") ||
                        0 == strcmp(zonestr, "UTC")) {
                    *GMTp = 1;
                } else if (0 == strcmp(zonestr, tzname[0])) {
                    tm->tm_isdst = 0;
                } else if (0 == strcmp(zonestr, tzname[1])) {
                    tm->tm_isdst = 1;
                } else {
                    return (NULL);
                }
                buf += cp - buf;
            }
        }
        break;

        case 'z':
        {
            int sign = 1;
            len = 4;			/* RFC 822/ISO 8601 */

            if (*buf != '+') {
                if (*buf == '-')
                    sign = -1;
                else if (*buf == 'Z')	/* ISO 8601 Z (UTC) */
                    len = 0;
                else
                    return (NULL);
            }

            buf++;
            i = 0;
            for (; len > 0; len--) {
                if (isdigit_l((unsigned char)*buf, locale)) {
                    i *= 10;
                    i += *buf - '0';
                    buf++;
                } else if (*buf == ':' && len == 2) {
                    buf++;		/* ISO 8601 +hh:mm */
                    if (isdigit_l((unsigned char)*buf,
                                  locale)) {
                        i *= 10;
                        i += *buf - '0';
                        buf++;
                    } else {
                        return (NULL);
                    }
                } else if (len == 2) {
                    i *= 100;	/* ISO 8601 +hh */
                    break;
                } else {
                    return (NULL);
                }
            }

            tm->tm_hour -= sign * (i / 100);
            tm->tm_min  -= sign * (i % 100);
            *GMTp = 1;
        }
        break;

        case 'n':
        case 't':
            while (isspace_l((unsigned char)*buf, locale))
                buf++;
            break;

        default:
            return (NULL);
        }
    }

    if (!(flags & FLAG_YDAY) && (flags & FLAG_YEAR)) {
        if ((flags & (FLAG_MONTH | FLAG_MDAY)) ==
                (FLAG_MONTH | FLAG_MDAY)) {
            tm->tm_yday = start_of_month[isleap(tm->tm_year +
                                                TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1);
            flags |= FLAG_YDAY;
        } else if (day_offset != -1) {
            /* Set the date to the first Sunday (or Monday)
             * of the specified week of the year.
             */
            if (!(flags & FLAG_WDAY)) {
                tm->tm_wday = day_offset;
                flags |= FLAG_WDAY;
            }
            tm->tm_yday = (7 -
                           first_wday_of(tm->tm_year + TM_YEAR_BASE) +
                           day_offset) % 7 + (week_offset - 1 +
                                              (tm->tm_wday == 0 ? day_offset : 0)) * 7 +
                          tm->tm_wday - day_offset;
            flags |= FLAG_YDAY;
        }
    }

    if ((flags & (FLAG_YEAR | FLAG_YDAY)) == (FLAG_YEAR | FLAG_YDAY)) {
        if (!(flags & FLAG_MONTH)) {
            i = 0;
            while (tm->tm_yday >=
                    start_of_month[isleap(tm->tm_year +
                                          TM_YEAR_BASE)][i])
                i++;
            if (i > 12) {
                i = 1;
                tm->tm_yday -=
                    start_of_month[isleap(tm->tm_year +
                                          TM_YEAR_BASE)][12];
                tm->tm_year++;
            }
            tm->tm_mon = i - 1;
            flags |= FLAG_MONTH;
        }
        if (!(flags & FLAG_MDAY)) {
            tm->tm_mday = tm->tm_yday -
                          start_of_month[isleap(tm->tm_year + TM_YEAR_BASE)]
                          [tm->tm_mon] + 1;
            flags |= FLAG_MDAY;
        }
        if (!(flags & FLAG_WDAY)) {
            i = 0;
            wday_offset = first_wday_of(tm->tm_year);
            while (i++ <= tm->tm_yday) {
                if (wday_offset++ >= 6)
                    wday_offset = 0;
            }
            tm->tm_wday = wday_offset;
            flags |= FLAG_WDAY;
        }
    }

    return ((char *)buf);
}