Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

648 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. applyinf.cxx
  5. Abstract:
  6. Merge HTML documents & localizable string .inf file
  7. Author:
  8. Philippe Choquier ( Phillich ) 15-may-1996
  9. --*/
  10. #include <windows.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <iis64.h>
  15. typedef struct _SUBST_NODE {
  16. LPSTR pszName;
  17. LPSTR pszValue;
  18. } SUBST_NODE;
  19. #define MAX_NODES 8192
  20. #define MAX_SIZE_NAME 256
  21. #define MAX_SIZE_VALUE 8192
  22. #define INF_SEEK_FIRST_CHAR_NAME 0
  23. #define INF_SEEK_NAME 1
  24. #define INF_SEEK_END_NAME 2
  25. #define INF_SEEK_STR 3
  26. #define INF_SEEK_END_STR 4
  27. #define INF_SEEK_EOL 5
  28. #define HT_SEEK_NAME 0
  29. #define HT_SEEK_END_NAME 1
  30. SUBST_NODE aNodes[MAX_NODES];
  31. int cNodes = 0;
  32. char achName[MAX_SIZE_NAME];
  33. char achValue[MAX_SIZE_VALUE];
  34. extern "C" int __cdecl
  35. QsortStrCmp(
  36. const void *pA,
  37. const void *pB )
  38. /*++
  39. Routine Description:
  40. Compare two SUBST_NODE structures base on their pszName field
  41. Arguments:
  42. pA - ptr to 1st struct
  43. pB - ptr to 2nd struct
  44. Returns:
  45. -1 if *pA < *pB, 0 if *pA == *pB, 1 if *pA > *pB
  46. based on strcmp of their pszName field
  47. --*/
  48. {
  49. return strcmp( ((SUBST_NODE*)pA)->pszName, ((SUBST_NODE*)pB)->pszName );
  50. }
  51. BOOL
  52. ParseINF(
  53. LPSTR pszInf
  54. )
  55. /*++
  56. Routine Description:
  57. Parse the .inf file for localizable string substitutions
  58. Arguments:
  59. pszInf - name of .inf file
  60. Returns:
  61. TRUE if success, FALSE if error
  62. --*/
  63. {
  64. BOOL fSt = TRUE;
  65. int ch;
  66. FILE *inf;
  67. if ( ( inf = fopen(pszInf, "r") ) == NULL )
  68. {
  69. return FALSE;
  70. }
  71. int iName = 0;
  72. int iValue = 0;
  73. BOOL fEsc;
  74. int iState = INF_SEEK_FIRST_CHAR_NAME;
  75. for ( ; (ch = fgetc( inf )) != EOF ; )
  76. {
  77. if ( ch == '\\' )
  78. {
  79. if ( (ch = fgetc( inf )) == EOF )
  80. {
  81. break;
  82. }
  83. if ( ch == '\n' )
  84. {
  85. continue;
  86. }
  87. if ( ch == 'n' )
  88. {
  89. ch = '\n';
  90. }
  91. fEsc = TRUE;
  92. }
  93. else
  94. {
  95. fEsc = FALSE;
  96. }
  97. switch ( iState )
  98. {
  99. case INF_SEEK_FIRST_CHAR_NAME:
  100. if ( !fEsc && ch == '#' )
  101. {
  102. iState = INF_SEEK_EOL;
  103. break;
  104. }
  105. iState = INF_SEEK_NAME;
  106. // fall-through
  107. case INF_SEEK_NAME:
  108. if ( !fEsc && ch == '^' )
  109. {
  110. iState = INF_SEEK_END_NAME;
  111. }
  112. break;
  113. case INF_SEEK_END_NAME:
  114. if ( !fEsc && ch == '^' )
  115. {
  116. iState = INF_SEEK_STR;
  117. }
  118. else
  119. {
  120. achName[ iName++ ] = (char)ch;
  121. }
  122. break;
  123. case INF_SEEK_STR:
  124. if ( !fEsc && ch == '"' )
  125. {
  126. iState = INF_SEEK_END_STR;
  127. }
  128. break;
  129. case INF_SEEK_END_STR:
  130. // handle "" as a single quote
  131. if ( !fEsc && ch == '"' )
  132. {
  133. if ( (ch = fgetc( inf )) == EOF )
  134. {
  135. break;
  136. }
  137. if ( ch == '"' )
  138. {
  139. fEsc = TRUE;
  140. }
  141. else
  142. {
  143. ungetc( ch, inf );
  144. ch = '"';
  145. }
  146. }
  147. // skip new lines char in stream
  148. if ( !fEsc && ch == '\n' )
  149. {
  150. break;
  151. }
  152. if ( !fEsc && ch == '"' )
  153. {
  154. achName[ iName ] = '\0';
  155. achValue[ iValue ] = '\0';
  156. aNodes[ cNodes ].pszName = _strdup( achName );
  157. aNodes[ cNodes ].pszValue = _strdup( achValue );
  158. ++cNodes;
  159. iState = INF_SEEK_FIRST_CHAR_NAME;
  160. iName = 0;
  161. iValue = 0;
  162. }
  163. else
  164. {
  165. achValue[ iValue++ ] = (char)ch;
  166. }
  167. break;
  168. case INF_SEEK_EOL:
  169. if ( !fEsc && ch == '\n' )
  170. {
  171. iState = INF_SEEK_FIRST_CHAR_NAME;
  172. }
  173. break;
  174. }
  175. }
  176. qsort( aNodes, cNodes, sizeof(SUBST_NODE), QsortStrCmp );
  177. fclose( inf );
  178. return fSt;
  179. }
  180. BOOL
  181. ParseHTML(
  182. LPSTR pszIn,
  183. LPSTR pszOut
  184. )
  185. /*++
  186. Routine Description:
  187. Parse a HTML document and generate an output document
  188. based on a previously parsed .inf susbtitution file
  189. Arguments:
  190. pszIn - name of input HTML document
  191. pszOut - name of created localized HTML document
  192. Returns:
  193. TRUE if success, FALSE if error
  194. --*/
  195. {
  196. BOOL fSt = TRUE;
  197. int ch;
  198. FILE *in;
  199. FILE *out;
  200. if ( ( in = fopen(pszIn, "r") ) == NULL )
  201. {
  202. return FALSE;
  203. }
  204. if ( ( out = fopen(pszOut, "w") ) == NULL )
  205. {
  206. fclose( in );
  207. return FALSE;
  208. }
  209. int iName = 0;
  210. BOOL fEsc;
  211. int iState = HT_SEEK_NAME;
  212. for ( ; (ch = fgetc( in )) != EOF ; )
  213. {
  214. if ( ch == '\\' )
  215. {
  216. if ( (ch = fgetc( in )) == EOF )
  217. {
  218. break;
  219. }
  220. if ( ch == '\n' )
  221. {
  222. continue;
  223. }
  224. fEsc = TRUE;
  225. }
  226. else
  227. {
  228. fEsc = FALSE;
  229. }
  230. switch ( iState )
  231. {
  232. case HT_SEEK_NAME:
  233. if ( !fEsc && ch == '^' )
  234. {
  235. iState = HT_SEEK_END_NAME;
  236. }
  237. else
  238. {
  239. fputc( ch, out );
  240. }
  241. break;
  242. case HT_SEEK_END_NAME:
  243. if ( !fEsc && ch == '^' )
  244. {
  245. SUBST_NODE snSeek;
  246. SUBST_NODE *pN;
  247. snSeek.pszName = achName;
  248. achName[ iName ] = '\0';
  249. if ( (pN = (SUBST_NODE*)bsearch( &snSeek,
  250. aNodes,
  251. cNodes,
  252. sizeof(SUBST_NODE),
  253. QsortStrCmp ))
  254. != NULL )
  255. {
  256. fputs( pN->pszValue, out );
  257. }
  258. else
  259. {
  260. fprintf( stdout, "Can't find reference to %s in %s\n",
  261. achName,
  262. pszIn );
  263. fflush( stdout );
  264. }
  265. iState = HT_SEEK_NAME;
  266. iName = 0;
  267. }
  268. else
  269. {
  270. achName[ iName++ ] = (char)ch;
  271. }
  272. break;
  273. }
  274. }
  275. fclose( in );
  276. fclose( out );
  277. return fSt;
  278. }
  279. BOOL
  280. BreakPath(
  281. LPSTR pOut,
  282. LPSTR pExt,
  283. BOOL *pfIsExt
  284. )
  285. /*++
  286. Routine Description:
  287. Move a file extension from a file path to an extension buffer
  288. Arguments:
  289. pOut - file path updated to remove file extension
  290. pExt - buffer for file extension
  291. pfIsExt - set to TRUE if file extension present
  292. Returns:
  293. TRUE if success, FALSE if error
  294. --*/
  295. {
  296. // if ends with '\\' is directory
  297. // else extract extension
  298. LPSTR pL = pOut + strlen(pOut);
  299. LPSTR pE = NULL;
  300. if ( pL[-1] == '\\' )
  301. {
  302. *pfIsExt = FALSE;
  303. return TRUE;
  304. }
  305. while ( pL > pOut && pL[-1] != '\\' )
  306. {
  307. if ( pL[-1] == '.' && pE == NULL )
  308. {
  309. pE = pL;
  310. }
  311. --pL;
  312. }
  313. if ( pL == pOut )
  314. {
  315. return FALSE;
  316. }
  317. *pL = '\0';
  318. strcpy( pExt, pE );
  319. *pfIsExt = TRUE;
  320. return TRUE;
  321. }
  322. void
  323. Usage(
  324. )
  325. /*++
  326. Routine Description:
  327. Display usage for this utility
  328. Arguments:
  329. None
  330. Returns:
  331. Nothing
  332. --*/
  333. {
  334. fprintf( stdout,
  335. "\n"
  336. "Usage: applyinf [source_file] [target_directory] [inf_file]\n"
  337. " source_file : can contains wild card characters\n"
  338. " target_directory : can contains a new extension to be\n"
  339. " used, e.g. *.out\n"
  340. " inf_file : name of the .inf files containing replacement strings\n"
  341. "\n" );
  342. }
  343. BOOL
  344. Combine(
  345. LPSTR pOut,
  346. LPSTR pExt,
  347. BOOL fIsExt,
  348. LPSTR pFileName
  349. )
  350. /*++
  351. Routine Description:
  352. Combine file name & extension to a new file name
  353. Arguments:
  354. pOut - output filename
  355. pExt - contains file extension if fIsExt is TRUE
  356. fIsExt - TRUE if pExt contains file extension
  357. pFileName - filename to be combined with extension to generare pOut
  358. Returns:
  359. TRUE if success, FALSE if error
  360. --*/
  361. {
  362. LPSTR pL = pFileName + strlen(pFileName);
  363. if ( fIsExt )
  364. {
  365. while ( pL > pFileName && pL[-1] != '.' )
  366. --pL;
  367. if ( pL == pFileName )
  368. {
  369. // no ext in filename
  370. memcpy( pOut, pFileName, strlen(pFileName) );
  371. pOut += strlen(pFileName );
  372. }
  373. else
  374. {
  375. memcpy( pOut, pFileName, DIFF(pL - pFileName) - 1 );
  376. pOut += pL - pFileName - 1;
  377. }
  378. *pOut ++ = '.';
  379. strcpy( pOut, pExt );
  380. }
  381. else
  382. {
  383. strcpy( pOut, pFileName );
  384. }
  385. return TRUE;
  386. }
  387. int __cdecl
  388. main(
  389. int argc,
  390. char *argv[]
  391. )
  392. /*++
  393. Routine Description:
  394. Entry point of this utility, parse command line
  395. Arguments:
  396. argc - nbr of command line parameters
  397. argv - ptr to command line parameters
  398. Returns:
  399. 0 if success, else error code
  400. --*/
  401. {
  402. char achIn[MAX_PATH]="";
  403. char achOut[MAX_PATH]="";
  404. char achInf[MAX_PATH]="";
  405. char achExt[MAX_PATH];
  406. BOOL fIsExt;
  407. WIN32_FIND_DATA fdIn;
  408. HANDLE hF;
  409. int arg;
  410. int iN = 0;
  411. LPSTR pLastS;
  412. LPSTR pOut;
  413. for ( arg = 1 ; arg < argc ; ++arg )
  414. {
  415. if ( argv[arg][0] == '-' )
  416. {
  417. switch( argv[arg][1] )
  418. {
  419. case 'z':
  420. default:
  421. ;
  422. }
  423. }
  424. else
  425. {
  426. switch ( iN )
  427. {
  428. case 0:
  429. strcpy( achIn, argv[arg] );
  430. break;
  431. case 1:
  432. strcpy( achOut, argv[arg] );
  433. break;
  434. case 2:
  435. strcpy( achInf, argv[arg] );
  436. break;
  437. }
  438. ++iN;
  439. }
  440. }
  441. if ( achIn[0] == '\0' )
  442. {
  443. fprintf( stdout, "No source directory specified\n" );
  444. fflush( stdout );
  445. Usage();
  446. return 3;
  447. }
  448. if ( achOut[0] == '\0' )
  449. {
  450. fprintf( stdout, "No target directory specified\n" );
  451. fflush( stdout );
  452. Usage();
  453. return 3;
  454. }
  455. if ( achInf[0] == '\0' )
  456. {
  457. fprintf( stdout, "No INF file specified\n" );
  458. fflush( stdout );
  459. Usage();
  460. return 3;
  461. }
  462. for ( pLastS = achIn + strlen(achIn) ; pLastS > achIn ; --pLastS )
  463. {
  464. if ( pLastS[-1] == '\\' )
  465. {
  466. break;
  467. }
  468. }
  469. if ( pLastS == achIn )
  470. {
  471. fprintf( stdout, "Invalid source directory : %s\n", achIn );
  472. fflush( stdout );
  473. return 5;
  474. }
  475. if ( !BreakPath( achOut, achExt, &fIsExt ) )
  476. {
  477. fprintf( stdout, "Invalid target directory : %s\n", achOut );
  478. fflush( stdout );
  479. return 6;
  480. }
  481. pOut = achOut + strlen( achOut );
  482. if ( !ParseINF( achInf ) )
  483. {
  484. fprintf( stdout, "Can't parse INF file %s\n", achInf );
  485. fflush( stdout );
  486. return 1;
  487. }
  488. // applyinf srcdir trgdirandext inffile
  489. // e.g. applyinf c:\nt\*.htr c:\drop\*.htm html.inf
  490. if ( (hF = FindFirstFile( achIn, &fdIn )) != INVALID_HANDLE_VALUE )
  491. {
  492. do {
  493. strcpy( pLastS, fdIn.cFileName );
  494. Combine( pOut, achExt, fIsExt, fdIn.cFileName );
  495. if ( !ParseHTML( achIn, achOut) )
  496. {
  497. fprintf( stdout, "Can't generate %s from %s\n", achOut, achIn );
  498. fflush( stdout );
  499. return 2;
  500. }
  501. else
  502. {
  503. fprintf( stdout, "Parsed %s to %s\n", achIn, achOut );
  504. fflush( stdout );
  505. }
  506. } while ( FindNextFile( hF, &fdIn ) );
  507. FindClose( hF );
  508. }
  509. else
  510. {
  511. fprintf( stdout, "No file found in %s", achIn );
  512. fflush( stdout );
  513. return 4;
  514. }
  515. return 0;
  516. }