/*++ Copyright (c) 1996 Microsoft Corporation Module Name: applyinf.cxx Abstract: Merge HTML documents & localizable string .inf file Author: Philippe Choquier ( Phillich ) 15-may-1996 --*/ #include #include #include #include #include typedef struct _SUBST_NODE { LPSTR pszName; LPSTR pszValue; } SUBST_NODE; #define MAX_NODES 8192 #define MAX_SIZE_NAME 256 #define MAX_SIZE_VALUE 8192 #define INF_SEEK_FIRST_CHAR_NAME 0 #define INF_SEEK_NAME 1 #define INF_SEEK_END_NAME 2 #define INF_SEEK_STR 3 #define INF_SEEK_END_STR 4 #define INF_SEEK_EOL 5 #define HT_SEEK_NAME 0 #define HT_SEEK_END_NAME 1 SUBST_NODE aNodes[MAX_NODES]; int cNodes = 0; char achName[MAX_SIZE_NAME]; char achValue[MAX_SIZE_VALUE]; extern "C" int __cdecl QsortStrCmp( const void *pA, const void *pB ) /*++ Routine Description: Compare two SUBST_NODE structures base on their pszName field Arguments: pA - ptr to 1st struct pB - ptr to 2nd struct Returns: -1 if *pA < *pB, 0 if *pA == *pB, 1 if *pA > *pB based on strcmp of their pszName field --*/ { return strcmp( ((SUBST_NODE*)pA)->pszName, ((SUBST_NODE*)pB)->pszName ); } BOOL ParseINF( LPSTR pszInf ) /*++ Routine Description: Parse the .inf file for localizable string substitutions Arguments: pszInf - name of .inf file Returns: TRUE if success, FALSE if error --*/ { BOOL fSt = TRUE; int ch; FILE *inf; if ( ( inf = fopen(pszInf, "r") ) == NULL ) { return FALSE; } int iName = 0; int iValue = 0; BOOL fEsc; int iState = INF_SEEK_FIRST_CHAR_NAME; for ( ; (ch = fgetc( inf )) != EOF ; ) { if ( ch == '\\' ) { if ( (ch = fgetc( inf )) == EOF ) { break; } if ( ch == '\n' ) { continue; } if ( ch == 'n' ) { ch = '\n'; } fEsc = TRUE; } else { fEsc = FALSE; } switch ( iState ) { case INF_SEEK_FIRST_CHAR_NAME: if ( !fEsc && ch == '#' ) { iState = INF_SEEK_EOL; break; } iState = INF_SEEK_NAME; // fall-through case INF_SEEK_NAME: if ( !fEsc && ch == '^' ) { iState = INF_SEEK_END_NAME; } break; case INF_SEEK_END_NAME: if ( !fEsc && ch == '^' ) { iState = INF_SEEK_STR; } else { achName[ iName++ ] = (char)ch; } break; case INF_SEEK_STR: if ( !fEsc && ch == '"' ) { iState = INF_SEEK_END_STR; } break; case INF_SEEK_END_STR: // handle "" as a single quote if ( !fEsc && ch == '"' ) { if ( (ch = fgetc( inf )) == EOF ) { break; } if ( ch == '"' ) { fEsc = TRUE; } else { ungetc( ch, inf ); ch = '"'; } } // skip new lines char in stream if ( !fEsc && ch == '\n' ) { break; } if ( !fEsc && ch == '"' ) { achName[ iName ] = '\0'; achValue[ iValue ] = '\0'; aNodes[ cNodes ].pszName = _strdup( achName ); aNodes[ cNodes ].pszValue = _strdup( achValue ); ++cNodes; iState = INF_SEEK_FIRST_CHAR_NAME; iName = 0; iValue = 0; } else { achValue[ iValue++ ] = (char)ch; } break; case INF_SEEK_EOL: if ( !fEsc && ch == '\n' ) { iState = INF_SEEK_FIRST_CHAR_NAME; } break; } } qsort( aNodes, cNodes, sizeof(SUBST_NODE), QsortStrCmp ); fclose( inf ); return fSt; } BOOL ParseHTML( LPSTR pszIn, LPSTR pszOut ) /*++ Routine Description: Parse a HTML document and generate an output document based on a previously parsed .inf susbtitution file Arguments: pszIn - name of input HTML document pszOut - name of created localized HTML document Returns: TRUE if success, FALSE if error --*/ { BOOL fSt = TRUE; int ch; FILE *in; FILE *out; if ( ( in = fopen(pszIn, "r") ) == NULL ) { return FALSE; } if ( ( out = fopen(pszOut, "w") ) == NULL ) { fclose( in ); return FALSE; } int iName = 0; BOOL fEsc; int iState = HT_SEEK_NAME; for ( ; (ch = fgetc( in )) != EOF ; ) { if ( ch == '\\' ) { if ( (ch = fgetc( in )) == EOF ) { break; } if ( ch == '\n' ) { continue; } fEsc = TRUE; } else { fEsc = FALSE; } switch ( iState ) { case HT_SEEK_NAME: if ( !fEsc && ch == '^' ) { iState = HT_SEEK_END_NAME; } else { fputc( ch, out ); } break; case HT_SEEK_END_NAME: if ( !fEsc && ch == '^' ) { SUBST_NODE snSeek; SUBST_NODE *pN; snSeek.pszName = achName; achName[ iName ] = '\0'; if ( (pN = (SUBST_NODE*)bsearch( &snSeek, aNodes, cNodes, sizeof(SUBST_NODE), QsortStrCmp )) != NULL ) { fputs( pN->pszValue, out ); } else { fprintf( stdout, "Can't find reference to %s in %s\n", achName, pszIn ); fflush( stdout ); } iState = HT_SEEK_NAME; iName = 0; } else { achName[ iName++ ] = (char)ch; } break; } } fclose( in ); fclose( out ); return fSt; } BOOL BreakPath( LPSTR pOut, LPSTR pExt, BOOL *pfIsExt ) /*++ Routine Description: Move a file extension from a file path to an extension buffer Arguments: pOut - file path updated to remove file extension pExt - buffer for file extension pfIsExt - set to TRUE if file extension present Returns: TRUE if success, FALSE if error --*/ { // if ends with '\\' is directory // else extract extension LPSTR pL = pOut + strlen(pOut); LPSTR pE = NULL; if ( pL[-1] == '\\' ) { *pfIsExt = FALSE; return TRUE; } while ( pL > pOut && pL[-1] != '\\' ) { if ( pL[-1] == '.' && pE == NULL ) { pE = pL; } --pL; } if ( pL == pOut ) { return FALSE; } *pL = '\0'; strcpy( pExt, pE ); *pfIsExt = TRUE; return TRUE; } void Usage( ) /*++ Routine Description: Display usage for this utility Arguments: None Returns: Nothing --*/ { fprintf( stdout, "\n" "Usage: applyinf [source_file] [target_directory] [inf_file]\n" " source_file : can contains wild card characters\n" " target_directory : can contains a new extension to be\n" " used, e.g. *.out\n" " inf_file : name of the .inf files containing replacement strings\n" "\n" ); } BOOL Combine( LPSTR pOut, LPSTR pExt, BOOL fIsExt, LPSTR pFileName ) /*++ Routine Description: Combine file name & extension to a new file name Arguments: pOut - output filename pExt - contains file extension if fIsExt is TRUE fIsExt - TRUE if pExt contains file extension pFileName - filename to be combined with extension to generare pOut Returns: TRUE if success, FALSE if error --*/ { LPSTR pL = pFileName + strlen(pFileName); if ( fIsExt ) { while ( pL > pFileName && pL[-1] != '.' ) --pL; if ( pL == pFileName ) { // no ext in filename memcpy( pOut, pFileName, strlen(pFileName) ); pOut += strlen(pFileName ); } else { memcpy( pOut, pFileName, DIFF(pL - pFileName) - 1 ); pOut += pL - pFileName - 1; } *pOut ++ = '.'; strcpy( pOut, pExt ); } else { strcpy( pOut, pFileName ); } return TRUE; } int __cdecl main( int argc, char *argv[] ) /*++ Routine Description: Entry point of this utility, parse command line Arguments: argc - nbr of command line parameters argv - ptr to command line parameters Returns: 0 if success, else error code --*/ { char achIn[MAX_PATH]=""; char achOut[MAX_PATH]=""; char achInf[MAX_PATH]=""; char achExt[MAX_PATH]; BOOL fIsExt; WIN32_FIND_DATA fdIn; HANDLE hF; int arg; int iN = 0; LPSTR pLastS; LPSTR pOut; for ( arg = 1 ; arg < argc ; ++arg ) { if ( argv[arg][0] == '-' ) { switch( argv[arg][1] ) { case 'z': default: ; } } else { switch ( iN ) { case 0: strcpy( achIn, argv[arg] ); break; case 1: strcpy( achOut, argv[arg] ); break; case 2: strcpy( achInf, argv[arg] ); break; } ++iN; } } if ( achIn[0] == '\0' ) { fprintf( stdout, "No source directory specified\n" ); fflush( stdout ); Usage(); return 3; } if ( achOut[0] == '\0' ) { fprintf( stdout, "No target directory specified\n" ); fflush( stdout ); Usage(); return 3; } if ( achInf[0] == '\0' ) { fprintf( stdout, "No INF file specified\n" ); fflush( stdout ); Usage(); return 3; } for ( pLastS = achIn + strlen(achIn) ; pLastS > achIn ; --pLastS ) { if ( pLastS[-1] == '\\' ) { break; } } if ( pLastS == achIn ) { fprintf( stdout, "Invalid source directory : %s\n", achIn ); fflush( stdout ); return 5; } if ( !BreakPath( achOut, achExt, &fIsExt ) ) { fprintf( stdout, "Invalid target directory : %s\n", achOut ); fflush( stdout ); return 6; } pOut = achOut + strlen( achOut ); if ( !ParseINF( achInf ) ) { fprintf( stdout, "Can't parse INF file %s\n", achInf ); fflush( stdout ); return 1; } // applyinf srcdir trgdirandext inffile // e.g. applyinf c:\nt\*.htr c:\drop\*.htm html.inf if ( (hF = FindFirstFile( achIn, &fdIn )) != INVALID_HANDLE_VALUE ) { do { strcpy( pLastS, fdIn.cFileName ); Combine( pOut, achExt, fIsExt, fdIn.cFileName ); if ( !ParseHTML( achIn, achOut) ) { fprintf( stdout, "Can't generate %s from %s\n", achOut, achIn ); fflush( stdout ); return 2; } else { fprintf( stdout, "Parsed %s to %s\n", achIn, achOut ); fflush( stdout ); } } while ( FindNextFile( hF, &fdIn ) ); FindClose( hF ); } else { fprintf( stdout, "No file found in %s", achIn ); fflush( stdout ); return 4; } return 0; }