src/utils.c: Support more powerful duration strings
Add support for "1d23h42m"-like duration strings to parse_duration(). Also, switch to using a deterministic finite automaton to parse duration strings, as things tend to get unclear. Signed-off-by: Lukas Fleischer <calcurse@cryptocrack.de>
This commit is contained in:
parent
a7489b916e
commit
4ff3bb9d4f
117
src/utils.c
117
src/utils.c
@ -696,50 +696,127 @@ parse_time (const char *string, unsigned *hour, unsigned *minute)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts a duration string into minutes. Both "hh:mm" (e.g. "23:42") and
|
* Converts a duration string into minutes.
|
||||||
* "mmm" (e.g. "100") formats are accepted. Short forms like "23:" (23:00) or
|
*
|
||||||
* ":45" (0:45) are allowed as well.
|
* Allowed formats (noted as regular expressions):
|
||||||
|
*
|
||||||
|
* - \d*:\d*
|
||||||
|
* - (\d*m|\d*h(|\d*m)|\d*d(|\d*m|\d*h(|\d*m)))
|
||||||
|
* - \d+
|
||||||
|
*
|
||||||
|
* "\d" is used as a placeholder for "(0|1|2|3|4|5|6|7|8|9)".
|
||||||
|
*
|
||||||
|
* Note that this function performs an additional range check on each token to
|
||||||
|
* ensure we do not accept semantically invalid strings such as "42:23".
|
||||||
*
|
*
|
||||||
* Returns 1 on success and 0 on failure.
|
* Returns 1 on success and 0 on failure.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
parse_duration (const char *string, unsigned *duration)
|
parse_duration (const char *string, unsigned *duration)
|
||||||
{
|
{
|
||||||
|
enum {
|
||||||
|
STATE_INITIAL,
|
||||||
|
STATE_HHMM_MM,
|
||||||
|
STATE_DDHHMM_HH,
|
||||||
|
STATE_DDHHMM_MM,
|
||||||
|
STATE_DONE
|
||||||
|
} state = STATE_INITIAL;
|
||||||
|
|
||||||
const char *p;
|
const char *p;
|
||||||
unsigned in[2] = {0, 0}, n = 0;
|
unsigned in = 0;
|
||||||
|
unsigned dur = 0;
|
||||||
|
|
||||||
if (!string || *string == '\0')
|
if (!string || *string == '\0')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* parse string into in[], read up to two integers */
|
/* parse string using a simple state machine */
|
||||||
for (p = string; *p; p++)
|
for (p = string; *p; p++)
|
||||||
{
|
{
|
||||||
|
if ((*p >= '0') && (*p <= '9'))
|
||||||
|
{
|
||||||
|
if (state == STATE_DONE)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
in = in * 10 + (int)(*p - '0');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case STATE_INITIAL:
|
||||||
if (*p == ':')
|
if (*p == ':')
|
||||||
{
|
{
|
||||||
if ((++n) > 1)
|
dur += in * HOURINMIN;
|
||||||
return 0;
|
state = STATE_HHMM_MM;
|
||||||
|
}
|
||||||
|
else if (*p == 'd')
|
||||||
|
{
|
||||||
|
dur += in * DAYINMIN;
|
||||||
|
state = STATE_DDHHMM_HH;
|
||||||
|
}
|
||||||
|
else if (*p == 'h')
|
||||||
|
{
|
||||||
|
if (in >= DAYINHOURS)
|
||||||
|
return 0;
|
||||||
|
dur += in * HOURINMIN;
|
||||||
|
state = STATE_DDHHMM_MM;
|
||||||
|
}
|
||||||
|
else if (*p == 'm')
|
||||||
|
{
|
||||||
|
if (in >= HOURINMIN)
|
||||||
|
return 0;
|
||||||
|
dur += in;
|
||||||
|
state = STATE_DONE;
|
||||||
}
|
}
|
||||||
else if ((*p >= '0') && (*p <= '9'))
|
|
||||||
in[n] = in[n] * 10 + (int)(*p - '0');
|
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
break;
|
||||||
|
case STATE_DDHHMM_HH:
|
||||||
|
if (*p == 'h')
|
||||||
|
{
|
||||||
|
if (in >= DAYINHOURS)
|
||||||
|
return 0;
|
||||||
|
dur += in * HOURINMIN;
|
||||||
|
state = STATE_DDHHMM_MM;
|
||||||
|
}
|
||||||
|
else if (*p == 'm')
|
||||||
|
{
|
||||||
|
if (in >= HOURINMIN)
|
||||||
|
return 0;
|
||||||
|
dur += in;
|
||||||
|
state = STATE_DONE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case STATE_DDHHMM_MM:
|
||||||
|
if (*p == 'm')
|
||||||
|
{
|
||||||
|
if (in >= HOURINMIN)
|
||||||
|
return 0;
|
||||||
|
dur += in;
|
||||||
|
state = STATE_DONE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case STATE_HHMM_MM:
|
||||||
|
case STATE_DONE:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0)
|
in = 0;
|
||||||
{
|
|
||||||
if (in[0] > 999)
|
|
||||||
return 0;
|
|
||||||
*duration = in[0];
|
|
||||||
}
|
}
|
||||||
else if (n == 1)
|
|
||||||
{
|
|
||||||
if (in[0] > DAYINHOURS || in[1] >= HOURINMIN)
|
|
||||||
return 0;
|
|
||||||
*duration = in[0] * HOURINMIN + in[1];
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if ((state == STATE_HHMM_MM && in >= HOURINMIN) ||
|
||||||
|
((state == STATE_DDHHMM_HH || state == STATE_DDHHMM_MM) && in > 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
dur += in;
|
||||||
|
*duration = dur;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user