1 /* 2 * lib/krb5/krb/deltat.y 3 * 4 * Copyright 1999 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 * 26 * 27 * krb5_string_to_deltat() 28 */ 29 30 /* For a clean, thread-safe interface, we must use the "pure parser" 31 facility of GNU Bison. Unfortunately, standard YACC has no such 32 option. */ 33 34 /* N.B.: For simplicity in dealing with the distribution, the 35 Makefile.in listing for deltat.c does *not* normally list this 36 file. If you change this file, tweak the Makefile so it'll rebuild 37 deltat.c, or do it manually. */ 38 %{ 39 40 /* 41 * GCC optimizer will detect a variable used without being set in a YYERROR 42 * path. As this is generated code, suppress the complaint. 43 */ 44 #ifdef __GNUC__ 45 #pragma GCC diagnostic push 46 #pragma GCC diagnostic ignored "-Wuninitialized" 47 #endif 48 49 #include "k5-int.h" 50 #include <ctype.h> 51 52 struct param { 53 krb5_int32 delta; 54 char *p; 55 }; 56 57 #define MAX_TIME KRB5_INT32_MAX 58 #define MIN_TIME KRB5_INT32_MIN 59 60 #define DAY (24 * 3600) 61 #define HOUR 3600 62 63 #define MAX_DAY (MAX_TIME / DAY) 64 #define MIN_DAY (MIN_TIME / DAY) 65 #define MAX_HOUR (MAX_TIME / HOUR) 66 #define MIN_HOUR (MIN_TIME / HOUR) 67 #define MAX_MIN (MAX_TIME / 60) 68 #define MIN_MIN (MIN_TIME / 60) 69 70 /* An explanation of the tests being performed. 71 We do not want to overflow a 32 bit integer with out manipulations, 72 even for testing for overflow. Therefore we rely on the following: 73 74 The lex parser will not return a number > MAX_TIME (which is out 32 75 bit limit). 76 77 Therefore, seconds (s) will require 78 MIN_TIME < s < MAX_TIME 79 80 For subsequent tests, the logic is as follows: 81 82 If A < MAX_TIME and B < MAX_TIME 83 84 If we want to test if A+B < MAX_TIME, there are two cases 85 if (A > 0) 86 then A + B < MAX_TIME if B < MAX_TIME - A 87 else A + B < MAX_TIME always. 88 89 if we want to test if MIN_TIME < A + B 90 if A > 0 - then nothing to test 91 otherwise, we test if MIN_TIME - A < B. 92 93 We of course are testing for: 94 MIN_TIME < A + B < MAX_TIME 95 */ 96 97 98 #define DAY_NOT_OK(d) (d) > MAX_DAY || (d) < MIN_DAY 99 #define HOUR_NOT_OK(h) (h) > MAX_HOUR || (h) < MIN_HOUR 100 #define MIN_NOT_OK(m) (m) > MAX_MIN || (m) < MIN_MIN 101 #define SUM_OK(a, b) (((a) > 0) ? ( (b) <= MAX_TIME - (a)) : (MIN_TIME - (a) <= (b))) 102 #define DO_SUM(res, a, b) if (!SUM_OK((a), (b))) YYERROR; \ 103 res = (a) + (b) 104 105 106 #define OUT_D tmv->delta 107 #define DO(D,H,M,S) \ 108 { \ 109 /* Overflow testing - this does not handle negative values well.. */ \ 110 if (DAY_NOT_OK(D) || HOUR_NOT_OK(H) || MIN_NOT_OK(M)) YYERROR; \ 111 OUT_D = D * DAY; \ 112 DO_SUM(OUT_D, OUT_D, H * HOUR); \ 113 DO_SUM(OUT_D, OUT_D, M * 60); \ 114 DO_SUM(OUT_D, OUT_D, S); \ 115 } 116 117 static int mylex(int *intp, struct param *tmv); 118 #undef yylex 119 #define yylex(U, P) mylex (&(U)->val, (P)) 120 121 #undef yyerror 122 #define yyerror(tmv, msg) 123 124 static int yyparse(struct param *); 125 126 %} 127 128 %union {int val;} 129 %parse-param {struct param *tmv} 130 %lex-param {struct param *tmv} 131 %define api.pure 132 133 %token <val> tok_NUM tok_LONGNUM tok_OVERFLOW 134 %token '-' ':' 'd' 'h' 'm' 's' tok_WS 135 136 %type <val> num opt_hms opt_ms opt_s wsnum posnum 137 138 %start start 139 140 %% 141 142 start: deltat; 143 posnum: tok_NUM | tok_LONGNUM ; 144 num: posnum | '-' posnum { $$ = - $2; } ; 145 ws: /* nothing */ | tok_WS ; 146 wsnum: ws num { $$ = $2; } 147 | ws tok_OVERFLOW { YYERROR; }; 148 deltat: 149 wsnum 'd' opt_hms { DO ($1, 0, 0, $3); } 150 | wsnum 'h' opt_ms { DO ( 0, $1, 0, $3); } 151 | wsnum 'm' opt_s { DO ( 0, 0, $1, $3); } 152 | wsnum 's' { DO ( 0, 0, 0, $1); } 153 | wsnum '-' tok_NUM ':' tok_NUM ':' tok_NUM { DO ($1, $3, $5, $7); } 154 | wsnum ':' tok_NUM ':' tok_NUM { DO ( 0, $1, $3, $5); } 155 | wsnum ':' tok_NUM { DO ( 0, $1, $3, 0); } 156 | wsnum { DO ( 0, 0, 0, $1); } 157 /* default to 's' */ 158 ; 159 160 opt_hms: 161 opt_ms 162 | wsnum 'h' opt_ms { if (HOUR_NOT_OK($1)) YYERROR; 163 DO_SUM($$, $1 * 3600, $3); }; 164 opt_ms: 165 opt_s 166 | wsnum 'm' opt_s { if (MIN_NOT_OK($1)) YYERROR; 167 DO_SUM($$, $1 * 60, $3); }; 168 opt_s: 169 ws { $$ = 0; } 170 | wsnum 's' ; 171 172 %% 173 174 #ifdef __GNUC__ 175 #pragma GCC diagnostic pop 176 #endif 177 178 static int 179 mylex(int *intp, struct param *tmv) 180 { 181 int num, c; 182 #define P (tmv->p) 183 char *orig_p = P; 184 185 #ifdef isascii 186 if (!isascii (*P)) 187 return 0; 188 #endif 189 switch (c = *P++) { 190 case '-': 191 case ':': 192 case 'd': 193 case 'h': 194 case 'm': 195 case 's': 196 return c; 197 case '0': 198 case '1': 199 case '2': 200 case '3': 201 case '4': 202 case '5': 203 case '6': 204 case '7': 205 case '8': 206 case '9': 207 /* XXX assumes ASCII */ 208 num = c - '0'; 209 while (isdigit ((int) *P)) { 210 if (num > MAX_TIME / 10) 211 return tok_OVERFLOW; 212 num *= 10; 213 if (num > MAX_TIME - (*P - '0')) 214 return tok_OVERFLOW; 215 num += *P++ - '0'; 216 } 217 *intp = num; 218 return (P - orig_p > 2) ? tok_LONGNUM : tok_NUM; 219 case ' ': 220 case '\t': 221 case '\n': 222 while (isspace ((int) *P)) 223 P++; 224 return tok_WS; 225 default: 226 return YYEOF; 227 } 228 } 229 230 krb5_error_code KRB5_CALLCONV 231 krb5_string_to_deltat(char *string, krb5_deltat *deltatp) 232 { 233 struct param p; 234 p.delta = 0; 235 p.p = string; 236 if (yyparse (&p)) 237 return KRB5_DELTAT_BADFORMAT; 238 *deltatp = p.delta; 239 return 0; 240 } 241