ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

infcore.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:    .inf file parser
00003  * LICENSE:    GPL - See COPYING in the top level directory
00004  * PROGRAMMER: Royce Mitchell III
00005  *             Eric Kohl
00006  *             Ge van Geldorp <gvg@reactos.org>
00007  */
00008 
00009 /* INCLUDES *****************************************************************/
00010 
00011 #include "inflib.h"
00012 
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 #define CONTROL_Z  '\x1a'
00017 #define MAX_SECTION_NAME_LEN  255
00018 #define MAX_FIELD_LEN         511  /* larger fields get silently truncated */
00019 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
00020 #define MAX_STRING_LEN        (MAX_INF_STRING_LENGTH+1)
00021 
00022 
00023 /* parser definitions */
00024 
00025 enum parser_state
00026 {
00027   LINE_START,      /* at beginning of a line */
00028   SECTION_NAME,    /* parsing a section name */
00029   KEY_NAME,        /* parsing a key name */
00030   VALUE_NAME,      /* parsing a value name */
00031   EOL_BACKSLASH,   /* backslash at end of line */
00032   QUOTES,          /* inside quotes */
00033   LEADING_SPACES,  /* leading spaces */
00034   TRAILING_SPACES, /* trailing spaces */
00035   COMMENT,         /* inside a comment */
00036   NB_PARSER_STATES
00037 };
00038 
00039 struct parser
00040 {
00041   const CHAR        *start;       /* start position of item being parsed */
00042   const CHAR        *end;         /* end of buffer */
00043   PINFCACHE         file;         /* file being built */
00044   enum parser_state state;        /* current parser state */
00045   enum parser_state stack[4];     /* state stack */
00046   int               stack_pos;    /* current pos in stack */
00047 
00048   PINFCACHESECTION cur_section;   /* pointer to the section being parsed*/
00049   PINFCACHELINE    line;          /* current line */
00050   unsigned int     line_pos;      /* current line position in file */
00051   INFSTATUS        error;         /* error code */
00052   unsigned int     token_len;     /* current token len */
00053   TCHAR token[MAX_FIELD_LEN+1];   /* current token */
00054 };
00055 
00056 typedef const CHAR * (*parser_state_func)( struct parser *parser, const CHAR *pos );
00057 
00058 /* parser state machine functions */
00059 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos );
00060 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos );
00061 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos );
00062 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos );
00063 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos );
00064 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos );
00065 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos );
00066 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos );
00067 static const CHAR *comment_state( struct parser *parser, const CHAR *pos );
00068 
00069 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
00070 {
00071   line_start_state,      /* LINE_START */
00072   section_name_state,    /* SECTION_NAME */
00073   key_name_state,        /* KEY_NAME */
00074   value_name_state,      /* VALUE_NAME */
00075   eol_backslash_state,   /* EOL_BACKSLASH */
00076   quotes_state,          /* QUOTES */
00077   leading_spaces_state,  /* LEADING_SPACES */
00078   trailing_spaces_state, /* TRAILING_SPACES */
00079   comment_state          /* COMMENT */
00080 };
00081 
00082 
00083 /* PRIVATE FUNCTIONS ********************************************************/
00084 
00085 static PINFCACHELINE
00086 InfpFreeLine (PINFCACHELINE Line)
00087 {
00088   PINFCACHELINE Next;
00089   PINFCACHEFIELD Field;
00090 
00091   if (Line == NULL)
00092     {
00093       return NULL;
00094     }
00095 
00096   Next = Line->Next;
00097   if (Line->Key != NULL)
00098     {
00099       FREE (Line->Key);
00100       Line->Key = NULL;
00101     }
00102 
00103   /* Remove data fields */
00104   while (Line->FirstField != NULL)
00105     {
00106       Field = Line->FirstField->Next;
00107       FREE (Line->FirstField);
00108       Line->FirstField = Field;
00109     }
00110   Line->LastField = NULL;
00111 
00112   FREE (Line);
00113 
00114   return Next;
00115 }
00116 
00117 
00118 PINFCACHESECTION
00119 InfpFreeSection (PINFCACHESECTION Section)
00120 {
00121   PINFCACHESECTION Next;
00122 
00123   if (Section == NULL)
00124     {
00125       return NULL;
00126     }
00127 
00128   /* Release all keys */
00129   Next = Section->Next;
00130   while (Section->FirstLine != NULL)
00131     {
00132       Section->FirstLine = InfpFreeLine (Section->FirstLine);
00133     }
00134   Section->LastLine = NULL;
00135 
00136   FREE (Section);
00137 
00138   return Next;
00139 }
00140 
00141 
00142 PINFCACHESECTION
00143 InfpFindSection(PINFCACHE Cache,
00144                 PCTSTR Name)
00145 {
00146   PINFCACHESECTION Section = NULL;
00147 
00148   if (Cache == NULL || Name == NULL)
00149     {
00150       return NULL;
00151     }
00152 
00153   /* iterate through list of sections */
00154   Section = Cache->FirstSection;
00155   while (Section != NULL)
00156     {
00157       if (_tcsicmp (Section->Name, Name) == 0)
00158         {
00159           return Section;
00160         }
00161 
00162       /* get the next section*/
00163       Section = Section->Next;
00164     }
00165 
00166   return NULL;
00167 }
00168 
00169 
00170 PINFCACHESECTION
00171 InfpAddSection(PINFCACHE Cache,
00172                PCTSTR Name)
00173 {
00174   PINFCACHESECTION Section = NULL;
00175   ULONG Size;
00176 
00177   if (Cache == NULL || Name == NULL)
00178     {
00179       DPRINT("Invalid parameter\n");
00180       return NULL;
00181     }
00182 
00183   /* Allocate and initialize the new section */
00184   Size = (ULONG)FIELD_OFFSET(INFCACHESECTION,
00185                              Name[_tcslen (Name) + 1]);
00186   Section = (PINFCACHESECTION)MALLOC (Size);
00187   if (Section == NULL)
00188     {
00189       DPRINT("MALLOC() failed\n");
00190       return NULL;
00191     }
00192   ZEROMEMORY (Section,
00193               Size);
00194 
00195   /* Copy section name */
00196   _tcscpy (Section->Name, Name);
00197 
00198   /* Append section */
00199   if (Cache->FirstSection == NULL)
00200     {
00201       Cache->FirstSection = Section;
00202       Cache->LastSection = Section;
00203     }
00204   else
00205     {
00206       Cache->LastSection->Next = Section;
00207       Section->Prev = Cache->LastSection;
00208       Cache->LastSection = Section;
00209     }
00210 
00211   return Section;
00212 }
00213 
00214 
00215 PINFCACHELINE
00216 InfpAddLine(PINFCACHESECTION Section)
00217 {
00218   PINFCACHELINE Line;
00219 
00220   if (Section == NULL)
00221     {
00222       DPRINT("Invalid parameter\n");
00223       return NULL;
00224     }
00225 
00226   Line = (PINFCACHELINE)MALLOC (sizeof(INFCACHELINE));
00227   if (Line == NULL)
00228     {
00229       DPRINT("MALLOC() failed\n");
00230       return NULL;
00231     }
00232   ZEROMEMORY(Line,
00233              sizeof(INFCACHELINE));
00234 
00235   /* Append line */
00236   if (Section->FirstLine == NULL)
00237     {
00238       Section->FirstLine = Line;
00239       Section->LastLine = Line;
00240     }
00241   else
00242     {
00243       Section->LastLine->Next = Line;
00244       Line->Prev = Section->LastLine;
00245       Section->LastLine = Line;
00246     }
00247   Section->LineCount++;
00248 
00249   return Line;
00250 }
00251 
00252 
00253 PVOID
00254 InfpAddKeyToLine(PINFCACHELINE Line,
00255                  PCTSTR Key)
00256 {
00257   if (Line == NULL)
00258     {
00259       DPRINT1("Invalid Line\n");
00260       return NULL;
00261     }
00262 
00263   if (Line->Key != NULL)
00264     {
00265       DPRINT1("Line already has a key\n");
00266       return NULL;
00267     }
00268 
00269   Line->Key = (PTCHAR)MALLOC((_tcslen(Key) + 1) * sizeof(TCHAR));
00270   if (Line->Key == NULL)
00271     {
00272       DPRINT1("MALLOC() failed\n");
00273       return NULL;
00274     }
00275 
00276   _tcscpy(Line->Key, Key);
00277 
00278   return (PVOID)Line->Key;
00279 }
00280 
00281 
00282 PVOID
00283 InfpAddFieldToLine(PINFCACHELINE Line,
00284                    PCTSTR Data)
00285 {
00286   PINFCACHEFIELD Field;
00287   ULONG Size;
00288 
00289   Size = (ULONG)FIELD_OFFSET(INFCACHEFIELD,
00290                              Data[_tcslen(Data) + 1]);
00291   Field = (PINFCACHEFIELD)MALLOC(Size);
00292   if (Field == NULL)
00293     {
00294       DPRINT1("MALLOC() failed\n");
00295       return NULL;
00296     }
00297   ZEROMEMORY (Field,
00298               Size);
00299   _tcscpy (Field->Data, Data);
00300 
00301   /* Append key */
00302   if (Line->FirstField == NULL)
00303     {
00304       Line->FirstField = Field;
00305       Line->LastField = Field;
00306     }
00307   else
00308     {
00309       Line->LastField->Next = Field;
00310       Field->Prev = Line->LastField;
00311       Line->LastField = Field;
00312     }
00313   Line->FieldCount++;
00314 
00315   return (PVOID)Field;
00316 }
00317 
00318 
00319 PINFCACHELINE
00320 InfpFindKeyLine(PINFCACHESECTION Section,
00321                 PCTSTR Key)
00322 {
00323   PINFCACHELINE Line;
00324 
00325   Line = Section->FirstLine;
00326   while (Line != NULL)
00327     {
00328       if (Line->Key != NULL && _tcsicmp (Line->Key, Key) == 0)
00329         {
00330           return Line;
00331         }
00332 
00333       Line = Line->Next;
00334     }
00335 
00336   return NULL;
00337 }
00338 
00339 
00340 /* push the current state on the parser stack */
00341 __inline static void push_state( struct parser *parser, enum parser_state state )
00342 {
00343 //  assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) );
00344   parser->stack[parser->stack_pos++] = state;
00345 }
00346 
00347 
00348 /* pop the current state */
00349 __inline static void pop_state( struct parser *parser )
00350 {
00351 //  assert( parser->stack_pos );
00352   parser->state = parser->stack[--parser->stack_pos];
00353 }
00354 
00355 
00356 /* set the parser state and return the previous one */
00357 __inline static enum parser_state set_state( struct parser *parser, enum parser_state state )
00358 {
00359   enum parser_state ret = parser->state;
00360   parser->state = state;
00361   return ret;
00362 }
00363 
00364 
00365 /* check if the pointer points to an end of file */
00366 __inline static int is_eof( struct parser *parser, const CHAR *ptr )
00367 {
00368   return (ptr >= parser->end || *ptr == CONTROL_Z);
00369 }
00370 
00371 
00372 /* check if the pointer points to an end of line */
00373 __inline static int is_eol( struct parser *parser, const CHAR *ptr )
00374 {
00375   return (ptr >= parser->end ||
00376           *ptr == CONTROL_Z ||
00377           *ptr == '\n' ||
00378           (*ptr == '\r' && *(ptr + 1) == '\n'));
00379 }
00380 
00381 
00382 /* push data from current token start up to pos into the current token */
00383 static int push_token( struct parser *parser, const CHAR *pos )
00384 {
00385   UINT len = (UINT)(pos - parser->start);
00386   const CHAR *src = parser->start;
00387   TCHAR *dst = parser->token + parser->token_len;
00388 
00389   if (len > MAX_FIELD_LEN - parser->token_len)
00390     len = MAX_FIELD_LEN - parser->token_len;
00391 
00392   parser->token_len += len;
00393   for ( ; len > 0; len--, dst++, src++)
00394   {
00395     if (*src)
00396     {
00397       *dst = *src;
00398     }
00399     else
00400     {
00401       *dst = _T(' ');
00402     }
00403   }
00404 
00405   *dst = 0;
00406   parser->start = pos;
00407 
00408   return 0;
00409 }
00410 
00411 
00412 
00413 /* add a section with the current token as name */
00414 static PVOID add_section_from_token( struct parser *parser )
00415 {
00416   PINFCACHESECTION Section;
00417 
00418   if (parser->token_len > MAX_SECTION_NAME_LEN)
00419     {
00420       parser->error = INF_STATUS_SECTION_NAME_TOO_LONG;
00421       return NULL;
00422     }
00423 
00424   Section = InfpFindSection(parser->file,
00425                             parser->token);
00426   if (Section == NULL)
00427     {
00428       /* need to create a new one */
00429       Section= InfpAddSection(parser->file,
00430                               parser->token);
00431       if (Section == NULL)
00432         {
00433           parser->error = INF_STATUS_NOT_ENOUGH_MEMORY;
00434           return NULL;
00435         }
00436     }
00437 
00438   parser->token_len = 0;
00439   parser->cur_section = Section;
00440 
00441   return (PVOID)Section;
00442 }
00443 
00444 
00445 /* add a field containing the current token to the current line */
00446 static struct field *add_field_from_token( struct parser *parser, int is_key )
00447 {
00448   PVOID field;
00449 
00450   if (!parser->line)  /* need to start a new line */
00451     {
00452       if (parser->cur_section == NULL)  /* got a line before the first section */
00453         {
00454           parser->error = INF_STATUS_WRONG_INF_STYLE;
00455           return NULL;
00456         }
00457 
00458       parser->line = InfpAddLine(parser->cur_section);
00459       if (parser->line == NULL)
00460         goto error;
00461     }
00462   else
00463     {
00464 //      assert(!is_key);
00465     }
00466 
00467   if (is_key)
00468     {
00469       field = InfpAddKeyToLine(parser->line, parser->token);
00470     }
00471   else
00472     {
00473       field = InfpAddFieldToLine(parser->line, parser->token);
00474     }
00475 
00476   if (field != NULL)
00477     {
00478       parser->token_len = 0;
00479       return field;
00480     }
00481 
00482 error:
00483   parser->error = INF_STATUS_NOT_ENOUGH_MEMORY;
00484   return NULL;
00485 }
00486 
00487 
00488 /* close the current line and prepare for parsing a new one */
00489 static void close_current_line( struct parser *parser )
00490 {
00491   parser->line = NULL;
00492 }
00493 
00494 
00495 
00496 /* handler for parser LINE_START state */
00497 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos )
00498 {
00499   const CHAR *p;
00500 
00501   for (p = pos; !is_eof( parser, p ); p++)
00502     {
00503       switch(*p)
00504         {
00505           case '\r':
00506             continue;
00507 
00508           case '\n':
00509             parser->line_pos++;
00510             close_current_line( parser );
00511             break;
00512 
00513           case ';':
00514             push_state( parser, LINE_START );
00515             set_state( parser, COMMENT );
00516             return p + 1;
00517 
00518           case '[':
00519             parser->start = p + 1;
00520             set_state( parser, SECTION_NAME );
00521             return p + 1;
00522 
00523           default:
00524             if (!isspace(*p))
00525               {
00526                 parser->start = p;
00527                 set_state( parser, KEY_NAME );
00528                 return p;
00529               }
00530             break;
00531         }
00532     }
00533   close_current_line( parser );
00534   return NULL;
00535 }
00536 
00537 
00538 /* handler for parser SECTION_NAME state */
00539 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos )
00540 {
00541   const CHAR *p;
00542 
00543   for (p = pos; !is_eol( parser, p ); p++)
00544     {
00545       if (*p == ']')
00546         {
00547           push_token( parser, p );
00548           if (add_section_from_token( parser ) == NULL)
00549             return NULL;
00550           push_state( parser, LINE_START );
00551           set_state( parser, COMMENT );  /* ignore everything else on the line */
00552           return p + 1;
00553         }
00554     }
00555   parser->error = INF_STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */
00556   return NULL;
00557 }
00558 
00559 
00560 /* handler for parser KEY_NAME state */
00561 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos )
00562 {
00563     const CHAR *p, *token_end = parser->start;
00564 
00565     for (p = pos; !is_eol( parser, p ); p++)
00566     {
00567         if (*p == ',') break;
00568         switch(*p)
00569         {
00570 
00571          case '=':
00572             push_token( parser, token_end );
00573             if (!add_field_from_token( parser, 1 )) return NULL;
00574             parser->start = p + 1;
00575             push_state( parser, VALUE_NAME );
00576             set_state( parser, LEADING_SPACES );
00577             return p + 1;
00578         case ';':
00579             push_token( parser, token_end );
00580             if (!add_field_from_token( parser, 0 )) return NULL;
00581             push_state( parser, LINE_START );
00582             set_state( parser, COMMENT );
00583             return p + 1;
00584         case '"':
00585             push_token( parser, token_end );
00586             parser->start = p + 1;
00587             push_state( parser, KEY_NAME );
00588             set_state( parser, QUOTES );
00589             return p + 1;
00590         case '\\':
00591             push_token( parser, token_end );
00592             parser->start = p;
00593             push_state( parser, KEY_NAME );
00594             set_state( parser, EOL_BACKSLASH );
00595             return p;
00596         default:
00597             if (!isspace(*p)) token_end = p + 1;
00598             else
00599             {
00600                 push_token( parser, p );
00601                 push_state( parser, KEY_NAME );
00602                 set_state( parser, TRAILING_SPACES );
00603                 return p;
00604             }
00605             break;
00606         }
00607     }
00608     push_token( parser, token_end );
00609     set_state( parser, VALUE_NAME );
00610     return p;
00611 }
00612 
00613 
00614 /* handler for parser VALUE_NAME state */
00615 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos )
00616 {
00617     const CHAR *p, *token_end = parser->start;
00618 
00619     for (p = pos; !is_eol( parser, p ); p++)
00620     {
00621         switch(*p)
00622         {
00623         case ';':
00624             push_token( parser, token_end );
00625             if (!add_field_from_token( parser, 0 )) return NULL;
00626             push_state( parser, LINE_START );
00627             set_state( parser, COMMENT );
00628             return p + 1;
00629         case ',':
00630             push_token( parser, token_end );
00631             if (!add_field_from_token( parser, 0 )) return NULL;
00632             parser->start = p + 1;
00633             push_state( parser, VALUE_NAME );
00634             set_state( parser, LEADING_SPACES );
00635             return p + 1;
00636         case '"':
00637             push_token( parser, token_end );
00638             parser->start = p + 1;
00639             push_state( parser, VALUE_NAME );
00640             set_state( parser, QUOTES );
00641             return p + 1;
00642         case '\\':
00643             push_token( parser, token_end );
00644             parser->start = p;
00645             push_state( parser, VALUE_NAME );
00646             set_state( parser, EOL_BACKSLASH );
00647             return p;
00648         default:
00649             if (!isspace(*p)) token_end = p + 1;
00650             else
00651             {
00652                 push_token( parser, p );
00653                 push_state( parser, VALUE_NAME );
00654                 set_state( parser, TRAILING_SPACES );
00655                 return p;
00656             }
00657             break;
00658         }
00659     }
00660     push_token( parser, token_end );
00661     if (!add_field_from_token( parser, 0 )) return NULL;
00662     set_state( parser, LINE_START );
00663     return p;
00664 }
00665 
00666 
00667 /* handler for parser EOL_BACKSLASH state */
00668 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos )
00669 {
00670   const CHAR *p;
00671 
00672   for (p = pos; !is_eof( parser, p ); p++)
00673     {
00674       switch(*p)
00675         {
00676           case '\r':
00677             continue;
00678 
00679           case '\n':
00680             parser->line_pos++;
00681             parser->start = p + 1;
00682             set_state( parser, LEADING_SPACES );
00683             return p + 1;
00684 
00685           case '\\':
00686             continue;
00687 
00688           case ';':
00689             push_state( parser, EOL_BACKSLASH );
00690             set_state( parser, COMMENT );
00691             return p + 1;
00692 
00693           default:
00694             if (isspace(*p))
00695               continue;
00696             push_token( parser, p );
00697             pop_state( parser );
00698             return p;
00699         }
00700     }
00701   parser->start = p;
00702   pop_state( parser );
00703 
00704   return p;
00705 }
00706 
00707 
00708 /* handler for parser QUOTES state */
00709 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos )
00710 {
00711   const CHAR *p, *token_end = parser->start;
00712 
00713   for (p = pos; !is_eol( parser, p ); p++)
00714     {
00715       if (*p == '"')
00716         {
00717           if (p+1 < parser->end && p[1] == '"')  /* double quotes */
00718             {
00719               push_token( parser, p + 1 );
00720               parser->start = token_end = p + 2;
00721               p++;
00722             }
00723           else  /* end of quotes */
00724             {
00725               push_token( parser, p );
00726               parser->start = p + 1;
00727               pop_state( parser );
00728               return p + 1;
00729             }
00730         }
00731     }
00732   push_token( parser, p );
00733   pop_state( parser );
00734   return p;
00735 }
00736 
00737 
00738 /* handler for parser LEADING_SPACES state */
00739 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos )
00740 {
00741   const CHAR *p;
00742 
00743   for (p = pos; !is_eol( parser, p ); p++)
00744     {
00745       if (*p == '\\')
00746         {
00747           parser->start = p;
00748           set_state( parser, EOL_BACKSLASH );
00749           return p;
00750         }
00751       if (!isspace(*p))
00752         break;
00753     }
00754   parser->start = p;
00755   pop_state( parser );
00756   return p;
00757 }
00758 
00759 
00760 /* handler for parser TRAILING_SPACES state */
00761 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos )
00762 {
00763   const CHAR *p;
00764 
00765   for (p = pos; !is_eol( parser, p ); p++)
00766     {
00767       if (*p == '\\')
00768         {
00769           set_state( parser, EOL_BACKSLASH );
00770           return p;
00771         }
00772       if (!isspace(*p))
00773         break;
00774     }
00775   pop_state( parser );
00776   return p;
00777 }
00778 
00779 
00780 /* handler for parser COMMENT state */
00781 static const CHAR *comment_state( struct parser *parser, const CHAR *pos )
00782 {
00783   const CHAR *p = pos;
00784 
00785   while (!is_eol( parser, p ))
00786      p++;
00787   pop_state( parser );
00788   return p;
00789 }
00790 
00791 
00792 /* parse a complete buffer */
00793 INFSTATUS
00794 InfpParseBuffer (PINFCACHE file,
00795                  const CHAR *buffer,
00796                  const CHAR *end,
00797                  PULONG error_line)
00798 {
00799   struct parser parser;
00800   const CHAR *pos = buffer;
00801 
00802   parser.start       = buffer;
00803   parser.end         = end;
00804   parser.file        = file;
00805   parser.line        = NULL;
00806   parser.state       = LINE_START;
00807   parser.stack_pos   = 0;
00808   parser.cur_section = NULL;
00809   parser.line_pos    = 1;
00810   parser.error       = 0;
00811   parser.token_len   = 0;
00812 
00813   /* parser main loop */
00814   while (pos)
00815     pos = (parser_funcs[parser.state])(&parser, pos);
00816 
00817   if (parser.error)
00818     {
00819       if (error_line)
00820         *error_line = parser.line_pos;
00821       return parser.error;
00822     }
00823 
00824   /* find the [strings] section */
00825   file->StringsSection = InfpFindSection(file,
00826                                          _T("Strings"));
00827 
00828   return INF_STATUS_SUCCESS;
00829 }
00830 
00831 /* EOF */

Generated on Sun May 27 2012 04:36:14 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.