%{
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
#include "k5-int.h"
#include <ctype.h>
struct param {
krb5_int32 delta;
char *p;
};
#define MAX_TIME KRB5_INT32_MAX
#define MIN_TIME KRB5_INT32_MIN
#define DAY (24 * 3600)
#define HOUR 3600
#define MAX_DAY (MAX_TIME / DAY)
#define MIN_DAY (MIN_TIME / DAY)
#define MAX_HOUR (MAX_TIME / HOUR)
#define MIN_HOUR (MIN_TIME / HOUR)
#define MAX_MIN (MAX_TIME / 60)
#define MIN_MIN (MIN_TIME / 60)
#define DAY_NOT_OK(d) (d) > MAX_DAY || (d) < MIN_DAY
#define HOUR_NOT_OK(h) (h) > MAX_HOUR || (h) < MIN_HOUR
#define MIN_NOT_OK(m) (m) > MAX_MIN || (m) < MIN_MIN
#define SUM_OK(a, b) (((a) > 0) ? ( (b) <= MAX_TIME - (a)) : (MIN_TIME - (a) <= (b)))
#define DO_SUM(res, a, b) if (!SUM_OK((a), (b))) YYERROR; \
res = (a) + (b)
#define OUT_D tmv->delta
#define DO(D,H,M,S) \
{ \
\
if (DAY_NOT_OK(D) || HOUR_NOT_OK(H) || MIN_NOT_OK(M)) YYERROR; \
OUT_D = D * DAY; \
DO_SUM(OUT_D, OUT_D, H * HOUR); \
DO_SUM(OUT_D, OUT_D, M * 60); \
DO_SUM(OUT_D, OUT_D, S); \
}
static int mylex(int *intp, struct param *tmv);
#undef yylex
#define yylex(U, P) mylex (&(U)->val, (P))
#undef yyerror
#define yyerror(tmv, msg)
static int yyparse(struct param *);
%}
%union {int val;}
%parse-param {struct param *tmv}
%lex-param {struct param *tmv}
%define api.pure
%token <val> tok_NUM tok_LONGNUM tok_OVERFLOW
%token '-' ':' 'd' 'h' 'm' 's' tok_WS
%type <val> num opt_hms opt_ms opt_s wsnum posnum
%start start
%%
start: deltat;
posnum: tok_NUM | tok_LONGNUM ;
num: posnum | '-' posnum { $$ = - $2; } ;
ws: | tok_WS ;
wsnum: ws num { $$ = $2; }
| ws tok_OVERFLOW { YYERROR; };
deltat:
wsnum 'd' opt_hms { DO ($1, 0, 0, $3); }
| wsnum 'h' opt_ms { DO ( 0, $1, 0, $3); }
| wsnum 'm' opt_s { DO ( 0, 0, $1, $3); }
| wsnum 's' { DO ( 0, 0, 0, $1); }
| wsnum '-' tok_NUM ':' tok_NUM ':' tok_NUM { DO ($1, $3, $5, $7); }
| wsnum ':' tok_NUM ':' tok_NUM { DO ( 0, $1, $3, $5); }
| wsnum ':' tok_NUM { DO ( 0, $1, $3, 0); }
| wsnum { DO ( 0, 0, 0, $1); }
;
opt_hms:
opt_ms
| wsnum 'h' opt_ms { if (HOUR_NOT_OK($1)) YYERROR;
DO_SUM($$, $1 * 3600, $3); };
opt_ms:
opt_s
| wsnum 'm' opt_s { if (MIN_NOT_OK($1)) YYERROR;
DO_SUM($$, $1 * 60, $3); };
opt_s:
ws { $$ = 0; }
| wsnum 's' ;
%%
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
static int
mylex(int *intp, struct param *tmv)
{
int num, c;
#define P (tmv->p)
char *orig_p = P;
#ifdef isascii
if (!isascii (*P))
return 0;
#endif
switch (c = *P++) {
case '-':
case ':':
case 'd':
case 'h':
case 'm':
case 's':
return c;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
num = c - '0';
while (isdigit ((int) *P)) {
if (num > MAX_TIME / 10)
return tok_OVERFLOW;
num *= 10;
if (num > MAX_TIME - (*P - '0'))
return tok_OVERFLOW;
num += *P++ - '0';
}
*intp = num;
return (P - orig_p > 2) ? tok_LONGNUM : tok_NUM;
case ' ':
case '\t':
case '\n':
while (isspace ((int) *P))
P++;
return tok_WS;
default:
return YYEOF;
}
}
krb5_error_code KRB5_CALLCONV
krb5_string_to_deltat(char *string, krb5_deltat *deltatp)
{
struct param p;
p.delta = 0;
p.p = string;
if (yyparse (&p))
return KRB5_DELTAT_BADFORMAT;
*deltatp = p.delta;
return 0;
}