ARPDAS_QNX6 1.0
|
00001 /* This file provides the file input support for TMCALGO R2 */ 00002 #include <malloc.h> 00003 #include <string.h> 00004 #include <ctype.h> 00005 #include <assert.h> 00006 #include <sys/types.h> 00007 #include <sys/stat.h> 00008 #include "nortlib.h" 00009 #include "tma.h" 00010 #include "cmdalgo.h" 00011 char rcsid_tma_file_c[] = 00012 "$Header: /cvsroot/arp-das/QNX6/tmlib/src/tma_file.c,v 1.2 2009/11/18 20:46:18 ntallen Exp $"; 00013 00014 static const char *yy_filename; 00015 static int yy_lineno; 00016 static char *yy_text; 00017 static long int yy_val; 00018 00019 static void synt_err( char *txt ) { 00020 nl_error( 2, "%s:%d %s", yy_filename, yy_lineno, txt ); 00021 } 00022 00023 #define TK_NUMBER 256 00024 #define TK_TMCCMD 257 00025 #define TK_QSTR 258 00026 #define KW_VALIDATE 259 00027 #define TK_NAME 260 00028 #define TK_EOF 261 00029 #define TK_ERR 262 00030 #define KW_AND 263 00031 #define KW_OR 264 00032 #define KW_HOLD 265 00033 #define KW_ELSE 266 00034 #define KW_RESUME 267 00035 00036 static int lexbufsize; 00037 static int lexbufpos; 00038 00039 static int buffer_char( char c ) { 00040 if ( lexbufpos >= lexbufsize ) { 00041 if ( lexbufsize == 0 ) lexbufsize = 128; 00042 else lexbufsize *= 2; 00043 yy_text = realloc( yy_text, lexbufsize ); 00044 if ( yy_text == 0 ) { 00045 synt_err( "Out of memory reading tma file" ); 00046 return 1; 00047 } 00048 } 00049 yy_text[ lexbufpos++ ] = c; 00050 return 0; 00051 } 00052 00053 #define BEGIN_BUFFER lexbufpos = 0 00054 #define BUFFER_CHAR(c) if ( buffer_char( c ) ) return TK_ERR 00055 #define END_BUFFER BUFFER_CHAR(0) 00056 00057 /* yylex() recognizes the following tokens 00058 [ \t]* nothing 00059 [\n] increment yy_lineno 00060 "#.*$" nothing 00061 TK_NUMBER [0-9]+ 00062 TK_TMCCMD ">.*$" 00063 TK_QSTR "..." 00064 KW_VALIDATE 00065 TK_NAME [A-Z_][A-Z_0-9]* 00066 TK_EOF EOF 00067 ':' 00068 ';' 00069 '+' 00070 */ 00071 static int yyunlexed = 0; 00072 static void yyunlex( int token ) { 00073 if ( yyunlexed ) 00074 nl_error( 4, "Cannot yyunlex two tokens" ); 00075 yyunlexed = token; 00076 } 00077 00078 static int yylex( FILE *fp ) { 00079 int c; 00080 00081 if ( yyunlexed ) { 00082 c = yyunlexed; 00083 yyunlexed = 0; 00084 return c; 00085 } 00086 for (;;) { 00087 switch ( c = getc(fp) ) { 00088 case EOF: return TK_EOF; 00089 case '\n': yy_lineno++; break; 00090 case ':': return ':'; 00091 case ';': return ';'; 00092 case '+': return '+'; 00093 case '#': 00094 for (;;) { 00095 c = getc( fp ); 00096 if ( c == '\n' ) { 00097 ungetc( c, fp ); 00098 break; 00099 } else if ( c == EOF ) break; 00100 } 00101 break; 00102 case '>': 00103 BEGIN_BUFFER; 00104 BUFFER_CHAR( c ); 00105 for (;;) { 00106 c = getc(fp); 00107 if ( c != ' ' && c != '\t' ) break; 00108 } 00109 while ( c != '\n' && c != EOF ) { 00110 BUFFER_CHAR( c ); 00111 c = getc(fp); 00112 } 00113 BUFFER_CHAR( '\n' ); 00114 END_BUFFER; 00115 if ( c == '\n' ) ungetc( c, fp ); 00116 return TK_TMCCMD; 00117 case '"': 00118 BEGIN_BUFFER; 00119 BUFFER_CHAR( c ); 00120 for (;;) { 00121 c = getc(fp); 00122 if ( c == '"' ) break; 00123 else if ( c == '\\' ) c = getc(fp); 00124 if ( c == '\n' || c == EOF ) { 00125 synt_err( "Runaway quote" ); 00126 return TK_ERR; 00127 } 00128 BUFFER_CHAR( c ); 00129 } 00130 END_BUFFER; 00131 return TK_QSTR; 00132 default: 00133 if ( isspace( c ) ) break; 00134 else if ( isdigit(c) ) { 00135 yy_val = 0; 00136 do { 00137 yy_val = yy_val*10 + c - '0'; 00138 c = getc(fp); 00139 } while ( isdigit(c) ); 00140 ungetc( c, fp ); 00141 return TK_NUMBER; 00142 } else if ( isalpha(c) || c == '_' ) { 00143 BEGIN_BUFFER; 00144 do { 00145 BUFFER_CHAR(c); c = getc(fp); 00146 } while( isalnum(c) || c == '_' ); 00147 ungetc( c, fp ); 00148 END_BUFFER; 00149 if ( stricmp( yy_text, "validate" ) == 0 ) 00150 return KW_VALIDATE; 00151 else if ( stricmp( yy_text, "and" ) == 0 ) 00152 return KW_AND; 00153 else if ( stricmp( yy_text, "or" ) == 0 ) 00154 return KW_OR; 00155 else if ( stricmp( yy_text, "hold" ) == 0 ) 00156 return KW_HOLD; 00157 else if ( stricmp( yy_text, "else" ) == 0 ) 00158 return KW_ELSE; 00159 else if ( stricmp( yy_text, "resume" ) == 0 ) 00160 return KW_RESUME; 00161 return TK_NAME; 00162 } else { 00163 synt_err( "syntax error" ); 00164 return TK_ERR; 00165 } 00166 } 00167 } 00168 } 00169 00170 typedef struct command_st { 00171 char *cmd; 00172 struct command_st *next; 00173 } command_t; 00174 00175 static int tma_strdup( command_t **ptr, const char *str, command_t *next ) { 00176 command_t *cmdl; 00177 cmdl = malloc( sizeof(command_t) ); 00178 if ( cmdl != 0 ) { 00179 cmdl->cmd = strdup( str ); 00180 if ( cmdl->cmd != 0 ) { 00181 cmdl->next = next; 00182 *ptr = cmdl; 00183 return 0; 00184 } 00185 free( cmdl ); 00186 } 00187 while ( next != 0 ) { 00188 cmdl = next; 00189 next = next->next; 00190 if ( cmdl->cmd ) free(cmdl->cmd); 00191 free(cmdl); 00192 } 00193 synt_err( "Out of memory reading tma file" ); 00194 return 1; 00195 } 00196 00197 static slurp_val *find_slurp( const char *statename ) { 00198 int i; 00199 if (statename[0] == '_') statename++; 00200 for ( i = 0; slurp_vals[i].state != 0; i++ ) { 00201 if ( strcmp( statename, slurp_vals[i].state ) == 0 ) { 00202 return &slurp_vals[i]; 00203 } 00204 } 00205 return NULL; 00206 } 00207 00208 static long int last_time; 00209 /* returns non-zero on error. dt=-1 and cmd = NULL on EOF. 00210 otherwise cmd is assigned a newly allocated string. 00211 Checks ">" command syntax, validate validity, 00212 time monotonicity. Supports '>', '"' and Validate 00213 commands plus # comments 00214 timecommand : timespec command 00215 : command 00216 timespec : delta time 00217 delta : 00218 : '+' 00219 time : TK_NUMBER 00220 : time ':' TK_NUMBER 00221 command : TK_TMCCMD 00222 : TK_QSTR ';' 00223 : KW_VALIDATE TK_NAME ';' 00224 : KW_HOLD [ KW_AND KW_VALIDATE TK_NAME ] 00225 ';' | KW_OR TK_NUMBER ( ';' | KW_ELSE command ) 00226 : KW_RESUME TK_NAME ';' 00227 */ 00228 00229 /* returns non-zero on error (and EOF is an error!) */ 00230 static int read_a_cmd( FILE *fp, command_t **cmdl, const char *mycase ) { 00231 slurp_val *sv; 00232 int token; 00233 00234 token = yylex(fp); 00235 switch ( token ) { 00236 case TK_TMCCMD: 00237 { int oldresp = set_response( 1 ); 00238 int rv; 00239 if ( yy_text[1] == '_' ) 00240 rv = ci_sendcmd( yy_text+2, 1 ); 00241 else rv = ci_sendcmd( yy_text+1, 1 ); 00242 set_response( oldresp ); 00243 if ( rv >= CMDREP_SYNERR ) { 00244 synt_err( "Syntax Error reported by command server" ); 00245 return 1; 00246 } 00247 } 00248 return tma_strdup( cmdl, yy_text, NULL ); 00249 case TK_QSTR: 00250 if ( tma_strdup( cmdl, yy_text, NULL ) == 0 ) { 00251 if ( yylex(fp) == ';' ) return 0; 00252 synt_err( "Semicolon required after quoted string" ); 00253 } 00254 return 1; 00255 case KW_VALIDATE: 00256 token = yylex( fp ); 00257 if ( token != TK_NAME ) { 00258 synt_err( "Expected State Name after validate" ); 00259 return 1; 00260 } 00261 sv = find_slurp( yy_text ); 00262 if ( sv == NULL ) synt_err( "Unknown state in validate" ); 00263 else if ( yylex(fp) != ';' ) 00264 synt_err( "Expected ';' after validate <state>" ); 00265 else return tma_strdup( cmdl, sv->cmdstr, NULL ); 00266 return 1; 00267 case KW_HOLD: 00268 token = yylex(fp); 00269 { int valcase = 0; 00270 long int timeout = -1; 00271 command_t *cmd_else = NULL; 00272 00273 if ( token == KW_AND ) { 00274 if ( yylex(fp) != KW_VALIDATE ) { 00275 synt_err( "Expected Validate after AND" ); 00276 return 1; 00277 } 00278 if ( yylex(fp) != TK_NAME ) { 00279 synt_err( "Expected state name after AND VALIDATE" ); 00280 return 1; 00281 } 00282 sv = find_slurp( yy_text ); 00283 if ( sv == NULL ) { 00284 synt_err( "Unknown state in Hold and Validate" ); 00285 return 1; 00286 } 00287 if ( sscanf( sv->cmdstr+1, "%d", &valcase ) != 1 ) { 00288 synt_err( "Error scanning valcase" ); 00289 return 1; 00290 } 00291 token = yylex(fp); 00292 } 00293 if ( token != ';' ) { 00294 if ( token == KW_OR ) { 00295 if ( yylex(fp) == TK_NUMBER ) { 00296 timeout = yy_val; 00297 token = yylex(fp); 00298 if ( token == KW_ELSE ) { 00299 if ( read_a_cmd( fp, &cmd_else, mycase ) ) 00300 return 1; 00301 } else if ( token != ';' ) { 00302 synt_err( "Expected ';' or ELSE after OR <number>" ); 00303 return 1; 00304 } 00305 } else { 00306 synt_err( "Expected a NUMBER after OR" ); 00307 return 1; 00308 } 00309 } else { 00310 synt_err( "Expected OR or ';' after HOLD" ); 00311 return 1; 00312 } 00313 } 00314 { int n_skip = 1; 00315 command_t *cl; 00316 char buf[80]; 00317 00318 for ( cl = cmd_else; cl != 0; cl = cl->next ) n_skip++; 00319 sprintf( buf, "?%d,%ld,%d,%s", n_skip, timeout, 00320 valcase, mycase ); 00321 return tma_strdup( cmdl, buf, cmd_else ); 00322 } 00323 } 00324 case KW_RESUME: 00325 if ( yylex(fp) != TK_NAME ) 00326 synt_err( "Expecting state name after RESUME" ); 00327 else { 00328 sv = find_slurp( yy_text ); 00329 if ( sv == NULL ) 00330 synt_err( "Unknown state after RESUME" ); 00331 else { 00332 char const * s; 00333 for ( s = sv->cmdstr; *s; s++ ) { 00334 if ( *s == 'R' ) 00335 return tma_strdup( cmdl, s, NULL ); 00336 } 00337 synt_err( "Resume code not found" ); 00338 } 00339 } 00340 return 1; 00341 default: 00342 synt_err( "Expected Command" ); 00343 return 1; 00344 } 00345 } 00346 00347 static int read_a_tcmd( FILE *fp, const char *mycase, 00348 long int *dtp, command_t **cmdl ) { 00349 int token; 00350 int delta = 0; 00351 long int dt = 0; 00352 00353 *cmdl = NULL; 00354 token = yylex( fp ); 00355 switch ( token ) { 00356 case '+': 00357 delta = 1; 00358 token = yylex( fp ); 00359 if ( token != TK_NUMBER ) { 00360 synt_err( "Expected Number after +" ); 00361 return 1; 00362 } 00363 case TK_NUMBER: 00364 for (;;) { 00365 dt = dt * 60 + yy_val; 00366 token = yylex( fp ); 00367 if ( token != ':' ) break; 00368 token = yylex( fp ); 00369 if ( token != TK_NUMBER ) { 00370 synt_err( "Expected Number after :" ); 00371 return 1; 00372 } 00373 } 00374 if ( delta ) last_time += dt; 00375 else if ( last_time > dt ) { 00376 synt_err( "Specified absolute time earlier than previous time" ); 00377 return 1; 00378 } else last_time = dt; 00379 break; 00380 case TK_EOF: 00381 *dtp = -1; 00382 return 0; 00383 default: 00384 break; 00385 } 00386 *dtp = last_time; 00387 yyunlex(token); 00388 return read_a_cmd( fp, cmdl, mycase ); 00389 } 00390 00391 static void free_tmacmds( tma_ifile *spec ) { 00392 tma_state *cmd; 00393 00394 assert( spec->cmds != 0 ); 00395 for ( cmd = spec->cmds; cmd->cmd != 0; cmd++ ) 00396 free( (char *)(cmd->cmd) ); 00397 free( spec->cmds ); 00398 spec->cmds = NULL; 00399 } 00400 00401 /* for read_tmafile() I need to build an array of tma_state's 00402 with pointers to a bunch of strings. I'll use the obvious 00403 approach of malloc/realloc on the tma_state array and simply use 00404 malloc/free on the strings. Returns 0 on success. 00405 */ 00406 static int read_tmafile( tma_ifile *spec, FILE *fp ) { 00407 int max_cmds = 32, n_cmds = 0; 00408 slurp_val *sv; 00409 const char *mycase; 00410 00411 spec->cmds = malloc( max_cmds * sizeof( tma_state ) ); 00412 if ( spec->cmds == 0 ) { 00413 nl_error( 2, "Out of memory reading tma file" ); 00414 return 1; 00415 } 00416 sv = find_slurp( spec->statename ); 00417 if ( sv == NULL ) { 00418 nl_error( 2, "State name '%s' not found in slurp_vals", 00419 spec->statename ); 00420 free_tmacmds( spec ); 00421 return 1; 00422 } 00423 mycase = sv->cmdstr + 1; 00424 yy_lineno = 1; 00425 yy_filename = spec->filename; 00426 last_time = 0; 00427 for (;;) { 00428 command_t *cmdl, *old_cmdl; 00429 long int dt; 00430 00431 spec->cmds[n_cmds].dt = -1; 00432 spec->cmds[n_cmds].cmd = NULL; 00433 if ( read_a_tcmd( fp, mycase, &dt, &cmdl ) ) { 00434 /* Syntax or other error */ 00435 free_tmacmds( spec ); 00436 return 1; 00437 } 00438 if ( cmdl == 0 ) break; /* EOF */ 00439 while ( cmdl != NULL ) { 00440 spec->cmds[n_cmds].dt = dt; 00441 spec->cmds[n_cmds].cmd = cmdl->cmd; 00442 if ( ++n_cmds == max_cmds ) { 00443 tma_state *ncmds; 00444 max_cmds *= 2; 00445 ncmds = realloc( spec->cmds, max_cmds * sizeof( tma_state ) ); 00446 if ( ncmds == 0 ) { 00447 if ( cmdl->cmd != 0 ) { 00448 free(cmdl->cmd); 00449 spec->cmds[n_cmds-1].cmd = NULL; 00450 } 00451 free_tmacmds( spec ); 00452 nl_error( 2, "Out of memory reading tma file" ); 00453 return 1; 00454 } else spec->cmds = ncmds; 00455 } 00456 old_cmdl = cmdl; 00457 cmdl = cmdl->next; 00458 free( old_cmdl ); 00459 } 00460 } 00461 return 0; 00462 } 00463 00464 void tma_read_file( tma_ifile *ifilespec ) { 00465 FILE *fp; 00466 tma_state *cmds; 00467 long int modtime = 0; 00468 struct stat buf; 00469 00470 assert( ifilespec != 0 && ifilespec->filename != 0 ); 00471 assert( ifilespec->statename != 0 ); 00472 /* check modtime of the file. If newer, free cmds */ 00473 if ( stat( ifilespec->filename, &buf ) == -1 ) 00474 modtime = -1; 00475 else modtime = buf.st_mtime; 00476 if ( modtime != ifilespec->modtime && ifilespec->cmds != 0 ) 00477 free_tmacmds( ifilespec ); 00478 if ( modtime != ifilespec->modtime && ifilespec->cmds == 0 ) { 00479 fp = fopen( ifilespec->filename, "r" ); 00480 if ( fp == 0 ) { 00481 nl_error( 1, "Unable to open algo file %s for state %s", 00482 ifilespec->filename, ifilespec->statename ); 00483 } else { 00484 nl_error( -2, "Reading algo file %s", ifilespec->filename ); 00485 read_tmafile( ifilespec, fp ); 00486 fclose( fp ); 00487 } 00488 ifilespec->modtime = modtime; 00489 } 00490 cmds = ifilespec->cmds; 00491 if ( cmds == 0 ) cmds = ifilespec->def_cmds; 00492 tma_init_state( ifilespec->partno, cmds, ifilespec->statename ); 00493 }