ARPDAS_QNX6 1.0
tma_file.c
Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines