in libs/libc/time/lib_localtime.c [1495:1895]
static int tzparse(FAR const char *name, FAR struct state_s *sp,
FAR struct state_s *basep)
{
FAR const char *stdname;
FAR const char *dstname;
size_t stdlen;
size_t dstlen;
size_t charcnt;
int_fast32_t stdoffset;
int_fast32_t dstoffset;
FAR char *cp;
int load_ok;
time_t atlo = TIME_T_MIN;
time_t leaplo = TIME_T_MIN;
stdname = name;
if (*name == '<')
{
name++;
stdname = name;
name = getqzname(name, '>');
if (*name != '>')
{
return -1;
}
stdlen = name - stdname;
name++;
}
else
{
name = getzname(name);
stdlen = name - stdname;
}
if (stdlen == 0)
{
return -1;
}
name = getoffset(name, &stdoffset);
if (name == NULL)
{
return -1;
}
charcnt = stdlen + 1;
if (sizeof(sp->chars) < charcnt)
{
return -1;
}
if (basep)
{
if (0 < basep->timecnt)
{
atlo = basep->ats[basep->timecnt - 1];
}
load_ok = -1;
sp->leapcnt = basep->leapcnt;
memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof(*sp->lsis));
}
else
{
load_ok = tzload(TZDEFRULES, sp, FALSE);
if (load_ok != 0)
{
sp->leapcnt = 0; /* so, we're off a little */
}
}
if (sp->leapcnt > 0)
{
leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
}
if (*name != '\0')
{
if (*name == '<')
{
dstname = ++name;
name = getqzname(name, '>');
if (*name != '>')
{
return -1;
}
dstlen = name - dstname;
name++;
}
else
{
dstname = name;
name = getzname(name);
dstlen = name - dstname; /* length of DST zone name */
}
if (dstlen == 0)
{
return -1;
}
charcnt += dstlen + 1;
if (sizeof(sp->chars) < charcnt)
{
return -1;
}
if (*name != '\0' && *name != ',' && *name != ';')
{
name = getoffset(name, &dstoffset);
if (name == NULL)
{
return -1;
}
}
else
{
dstoffset = stdoffset - SECSPERHOUR;
}
if (*name == '\0' && load_ok != 0)
{
name = TZDEFRULESTRING;
}
if (*name == ',' || *name == ';')
{
struct rule_s start;
struct rule_s end;
int year;
int yearlim;
int yearbeg;
int timecnt;
time_t janfirst;
int_fast32_t janoffset = 0;
++name;
if ((name = getrule(name, &start)) == NULL)
{
return -1;
}
if (*name++ != ',')
{
return -1;
}
if ((name = getrule(name, &end)) == NULL)
{
return -1;
}
if (*name != '\0')
{
return -1;
}
sp->typecnt = 2; /* standard time and DST */
/* Two transitions per year, from EPOCH_YEAR forward */
init_ttinfo(&sp->ttis[0], -stdoffset, FALSE, 0);
init_ttinfo(&sp->ttis[1], -dstoffset, TRUE, stdlen + 1);
sp->defaulttype = 0;
timecnt = 0;
janfirst = 0;
yearbeg = EPOCH_YEAR;
do
{
int_fast32_t yearsecs;
yearsecs = g_year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
yearbeg--;
if (increment_overflow_time(&janfirst, -yearsecs))
{
janoffset = -yearsecs;
break;
}
}
while (atlo < janfirst && (EPOCH_YEAR -
YEARSPERREPEAT / 2 < yearbeg));
while (true)
{
int_fast32_t yearsecs;
int yearbeg1 = yearbeg;
time_t janfirst1 = janfirst;
yearsecs = g_year_lengths[isleap(yearbeg)] * SECSPERDAY;
if (increment_overflow_time(&janfirst1, yearsecs) ||
increment_overflow(&yearbeg1, 1) || atlo <= janfirst1)
{
break;
}
yearbeg = yearbeg1;
janfirst = janfirst1;
}
yearlim = yearbeg;
if (increment_overflow(&yearlim, YEARSPERREPEAT + 1))
{
yearlim = INT_MAX;
}
for (year = yearbeg; year < yearlim; year++)
{
int_fast32_t
starttime = transtime(year, &start, stdoffset);
int_fast32_t
endtime = transtime(year, &end, dstoffset);
int_fast32_t
yearsecs = (g_year_lengths[isleap(year)] * SECSPERDAY);
int reversed = endtime < starttime;
if (reversed)
{
int_fast32_t swap = starttime;
starttime = endtime;
endtime = swap;
}
if (reversed ||
(starttime < endtime &&
(endtime - starttime < yearsecs)))
{
if (TZ_MAX_TIMES - 2 < timecnt)
{
break;
}
sp->ats[timecnt] = janfirst;
if (!increment_overflow_time(&sp->ats[timecnt],
janoffset + starttime) &&
atlo <= sp->ats[timecnt])
{
sp->types[timecnt++] = !reversed;
}
sp->ats[timecnt] = janfirst;
if (!increment_overflow_time(&sp->ats[timecnt],
janoffset + endtime) &&
atlo <= sp->ats[timecnt])
{
sp->types[timecnt++] = reversed;
}
}
if (endtime < leaplo)
{
yearlim = year;
if (increment_overflow(&yearlim, YEARSPERREPEAT + 1))
{
yearlim = INT_MAX;
}
}
if (increment_overflow_time(&janfirst, janoffset + yearsecs))
{
break;
}
janoffset = 0;
}
sp->timecnt = timecnt;
if (!timecnt)
{
sp->ttis[0] = sp->ttis[1];
sp->typecnt = 1; /* Perpetual DST. */
}
else if (YEARSPERREPEAT < year - yearbeg)
{
sp->goback = sp->goahead = TRUE;
}
}
else
{
int_fast32_t theirstdoffset;
int_fast32_t theirdstoffset;
int_fast32_t theiroffset;
int isdst;
int i;
int j;
if (*name != '\0')
{
return -1;
}
/* Initial value of theirstdoffset */
theirstdoffset = 0;
for (i = 0; i < sp->timecnt; ++i)
{
j = sp->types[i];
if (!sp->ttis[j].tt_isdst)
{
theirstdoffset = -sp->ttis[j].tt_utoff;
break;
}
}
theirdstoffset = 0;
for (i = 0; i < sp->timecnt; ++i)
{
j = sp->types[i];
if (!sp->ttis[j].tt_isdst)
{
theirdstoffset = -sp->ttis[j].tt_utoff;
break;
}
}
/* Initially we're assumed to be in standard time */
isdst = -1;
/* Now juggle transition times and types
* tracking offsets as you do.
*/
for (i = 0; i < sp->timecnt; ++i)
{
j = sp->types[i];
sp->types[i] = sp->ttis[j].tt_isdst;
if (sp->ttis[j].tt_ttisut)
{
/* No adjustment to transition time */
}
else
{
/* If daylight saving time is in
* effect, and the transition time was
* not specified as standard time, add
* the daylight saving time offset to
* the transition time; otherwise, add
* the standard time offset to the
* transition time.
*/
/* Transitions from DST to DDST
* will effectively disappear since
* POSIX provides for only one DST
* offset.
*/
if (isdst && !sp->ttis[j].tt_ttisstd)
{
sp->ats[i] += dstoffset - theirdstoffset;
}
else
{
sp->ats[i] += stdoffset - theirstdoffset;
}
}
theiroffset = -sp->ttis[j].tt_utoff;
if (sp->ttis[j].tt_isdst)
{
theirstdoffset = theiroffset;
}
else
{
theirdstoffset = theiroffset;
}
}
/* Finally, fill in ttis */
init_ttinfo(&sp->ttis[0], -stdoffset, FALSE, 0);
init_ttinfo(&sp->ttis[1], -dstoffset, TRUE, stdlen + 1);
sp->typecnt = 2;
sp->defaulttype = 0;
}
}
else
{
dstlen = 0;
sp->typecnt = 1; /* only standard time */
sp->timecnt = 0;
init_ttinfo(&sp->ttis[0], -stdoffset, FALSE, 0);
sp->defaulttype = 0;
}
sp->charcnt = charcnt;
cp = sp->chars;
memcpy(cp, stdname, stdlen);
cp += stdlen;
*cp++ = '\0';
if (dstlen != 0)
{
memcpy(cp, dstname, dstlen);
*(cp + dstlen) = '\0';
}
return 0;
}