Windows NT 4.0 source code leak
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.

739 lines
15 KiB

4 years ago
  1. /*
  2. * mrc.c
  3. *
  4. * Makes RCDATA, #defines, and a table of keywords from a set of of tokens
  5. * given as input.
  6. *
  7. * Usage:
  8. * mrc <tokens> <header> <resource> <C table>
  9. *
  10. * <tokens> is the filename of the tokens file (.TOK) which lists out the
  11. * tokens and optionally, lines to put in the other files. The internal
  12. * format of the file is:
  13. *
  14. * goal: ( <BOL> sections <EOL> )*
  15. * sections: comment | seed | token | imbed
  16. * comment: '#' <text>
  17. * seed: 'TOKENS' short_int
  18. * token: C_string value <text>*
  19. * value: token_symbol | short_int | C_char_constant
  20. * imbed: 'IMBED_IN' dest <EOL> imbed_text <BOL> 'END_IMBED'
  21. * dest: '.H' | '.RC' | '.C'
  22. * imbed_text: ( <BOL> <text>* <EOL> )*
  23. * <BOL>: Beginning of line
  24. * <EOL>: End of line
  25. *
  26. * The seed, lets you specify the seed value for the values to be assigned
  27. * to each new token_symbol that is found. As a new token_symbol is found
  28. * it is written out directly to the .H file as a #define line.
  29. *
  30. * The imbedded text is written out the the corresponding .H, .RC, or .C
  31. * file. This makes it possible to maintain just one source file for all
  32. * the generated files. As each imbed is encountered, it is written out
  33. * to the appropriate file.
  34. *
  35. * When the end of the token file is reached, the set of tokens are sorted
  36. * by their corresponding string and then written out to the C file and RC
  37. * file.
  38. *
  39. * <header> is the filename of the header file (.H) which will hold
  40. * generated #defines which correspond to token_symbols and their assigned
  41. * values.
  42. *
  43. * <resource> is the filename of the resource file (.RC) which will hold
  44. * a relocatable binary image of the the token lookup table in a RCDATA
  45. * field. After any imbedded text, it will be written out as:
  46. *
  47. * KEYWORDS RCDATA
  48. * BEGIN
  49. * <binary image of a C long>, <binary image of a C short>, // 1
  50. * :
  51. * <binary image of a C long>, <binary image of a C short>, // n
  52. * <binary image of a long 0>, <binary image of a short 0>,
  53. * <null terminated string>, // 1
  54. * :
  55. * <null terminated string> // n
  56. * END
  57. *
  58. * The C shorts hold the token values. The longs hold offsets from the
  59. * beginning of the image, to the string for that token value. The long 0
  60. * and short 0 denote the end of the look up table and allows the code
  61. * that loads the image to find out how many entries there are in the
  62. * table.
  63. *
  64. * <C table> is the filename of the C file (.C) which will hold the
  65. * declaration a token lookup table. After any imbedded text, it will be
  66. * written out as:
  67. *
  68. * static KEYWORD rgKeyword[] =
  69. * {
  70. * { <C_string>, <token_value> }, // 1
  71. * :
  72. * { <C_string>, <token_value> }, // n
  73. * { NULL, 0 }
  74. * };
  75. *
  76. * Owner: Anthony Xavier V. Francisco
  77. *
  78. * CAVEAT: If the KEYWORD structure in _rtfpars.h is changed, this program
  79. * will be utterly useless and will have to updated accordingly.
  80. */
  81. #include <windows.h>
  82. // #include <ourtypes.h>
  83. #include <stdio.h>
  84. #include <stdarg.h>
  85. #include <stdlib.h>
  86. enum
  87. {
  88. eTOK,
  89. eH,
  90. eRC,
  91. eC
  92. };
  93. typedef SHORT TOKEN;
  94. typedef struct _keyword
  95. {
  96. CHAR *szKeyword;
  97. TOKEN token;
  98. } KEYWORD;
  99. FILE * file[4]; // Streams for input and output
  100. CHAR * szOpenMode[] = { "r", "w", "w", "w" }; // Stream opening modes
  101. TOKEN sNextToken = 0; // Value for next token
  102. // Table of token strings and their values
  103. KEYWORD rgToken[256];
  104. INT cToken = 0;
  105. // Table of strings and their token values
  106. KEYWORD rgKeyword[256];
  107. INT cKeyword = 0;
  108. // Buffer and pointer used to support MyMalloc()
  109. CHAR rgchBuffer[4096];
  110. CHAR * pchAvail = rgchBuffer;
  111. // A scratch pad string used to store temporary C constant string versions of
  112. // a C string.
  113. CHAR szScratch[128];
  114. /*
  115. * Error
  116. *
  117. * Purpose:
  118. * Print out error messages to stderr with free formatting capabilites
  119. *
  120. * Arguments:
  121. * szFmt printf format string
  122. * ... parameter corresponding to format string
  123. *
  124. * Returns:
  125. * None.
  126. */
  127. void Error( char * szFmt, ... )
  128. {
  129. va_list marker;
  130. va_start( marker, szFmt );
  131. vfprintf( stderr, szFmt, marker );
  132. va_end(marker);
  133. exit(-1);
  134. }
  135. /*
  136. * TrimCRLF
  137. *
  138. * Purpose:
  139. * Take away the trailing '\n' and '\r' from a string
  140. *
  141. * Arguments:
  142. * sz string to be trimmed
  143. *
  144. * Returns:
  145. * None.
  146. */
  147. void TrimCRLF( CHAR * sz )
  148. {
  149. INT nLen = strlen(sz);
  150. CHAR * pch = &sz[ nLen - 1 ];
  151. while ( nLen && *pch == '\n' || *pch == '\r' )
  152. {
  153. *pch-- = '\0';
  154. --nLen;
  155. }
  156. }
  157. /*
  158. * NSzACmp
  159. *
  160. * Purpose:
  161. * Compares two ASCII strings based on ASCII values
  162. *
  163. * Arguments:
  164. * szA1 Strings to be compared
  165. * szA2
  166. *
  167. * Returns:
  168. * < 0 szA1 < szA2
  169. * 0 szA1 = szA2
  170. * > 0 szA1 > szA2
  171. */
  172. INT NSzACmp( CHAR * szA1, CHAR * szA2 )
  173. {
  174. while ( *szA1 && ( *szA1 == *szA2 ) )
  175. {
  176. ++szA1;
  177. ++szA2;
  178. }
  179. return *szA1 - *szA2;
  180. }
  181. /*
  182. * PchGetNextWord
  183. *
  184. * Purpose:
  185. * Collects the group of characters delimitted by whitespace in a
  186. * string.
  187. *
  188. * Arguments:
  189. * szLine Pointer to the string where to look for a word
  190. * szString Where to put the word
  191. *
  192. * Returns:
  193. * Pointer to the character delimiting the end of the word found. If
  194. * none is found, szString will have a length of zero.
  195. *
  196. */
  197. CHAR * PchGetNextWord( CHAR * szLine, CHAR *szString )
  198. {
  199. while ( *szLine && isspace(*szLine) )
  200. szLine++;
  201. while ( *szLine && !isspace(*szLine) )
  202. *szString++ = *szLine++;
  203. *szString = '\0';
  204. return szLine;
  205. }
  206. /*
  207. * HandleImbed
  208. *
  209. * Purpose:
  210. * Takes care of copying lines to be imbedded into a generated file
  211. *
  212. * Arguments:
  213. * sz String containing the destination for the imbedded
  214. * lines.
  215. *
  216. * Returns:
  217. * None.
  218. */
  219. void HandleImbed( CHAR * sz )
  220. {
  221. CHAR szLine[128];
  222. CHAR szString[128];
  223. FILE * fileDest;
  224. if ( !NSzACmp( sz, ".H" ) )
  225. fileDest = file[eH];
  226. else if ( !NSzACmp( sz, ".RC" ) )
  227. fileDest = file[eRC];
  228. else if ( !NSzACmp( sz, ".C" ) )
  229. fileDest = file[eC];
  230. else
  231. Error( "Can't imbed into %s\n", sz );
  232. while ( fgets( szLine, sizeof(szLine), file[eTOK] ) )
  233. {
  234. TrimCRLF(szLine);
  235. PchGetNextWord( szLine, szString );
  236. if ( !NSzACmp( szString, "END_IMBED" ) )
  237. break;
  238. fprintf( fileDest, "%s\n", szLine );
  239. }
  240. }
  241. /*
  242. * TranslateQuoted
  243. *
  244. * Purpose:
  245. * Takes as C string constant declaration and makes it into a C string
  246. * with out the escape characters.
  247. *
  248. * Arguments:
  249. * szDest C string constant declaration to converted
  250. *
  251. * Returns:
  252. * None.
  253. */
  254. void TranslateQuoted( CHAR * szDest )
  255. {
  256. CHAR szSrc[128];
  257. CHAR * pch = &szSrc[1];
  258. // Go through the string until the end of string or matching quote
  259. strcpy( szSrc, szDest );
  260. while ( *pch && *pch != szSrc[0] )
  261. {
  262. switch (*pch)
  263. {
  264. case '\\':
  265. ++pch;
  266. switch(*pch)
  267. {
  268. case '\\':
  269. *szDest++ = '\\';
  270. break;
  271. case 'n':
  272. *szDest++ = '\n';
  273. break;
  274. case 'r':
  275. *szDest++ = '\r';
  276. break;
  277. case 't':
  278. *szDest++ = '\t';
  279. break;
  280. default:
  281. *szDest++ = *pch;
  282. break;
  283. }
  284. break;
  285. default:
  286. *szDest++ = *pch;
  287. break;
  288. }
  289. pch++;
  290. }
  291. *szDest = '\0';
  292. }
  293. /*
  294. * CompareKeywords
  295. *
  296. * Purpose:
  297. * Compares to KEYWORD structures to see if their keyword strings
  298. * match.
  299. *
  300. * Arguments:
  301. * pv1 Pointer to a keyword structure
  302. * pv2 Pointer to another keyword structure
  303. *
  304. * Returns:
  305. * 0 strings are the same
  306. * < 0 pv1's string is less than pv2's string
  307. * > 0 pv1's string is greater than pv2's string
  308. */
  309. int __cdecl CompareKeywords( void const * pv1, void const * pv2 )
  310. {
  311. KEYWORD * pk1 = ( KEYWORD * ) pv1;
  312. KEYWORD * pk2 = ( KEYWORD * ) pv2;
  313. return NSzACmp( pk1->szKeyword, pk2->szKeyword );
  314. }
  315. /*
  316. * MyMalloc
  317. *
  318. * Purpose:
  319. * Simulates malloc() by using a staticly allocated buffer.
  320. *
  321. * Arguments:
  322. * cb Number of bytes to allocate
  323. *
  324. * Returns:
  325. * Pointer to a set of allocated bytes.
  326. */
  327. CHAR * MyMalloc( INT cb )
  328. {
  329. CHAR * pch;
  330. pch = pchAvail;
  331. pchAvail += cb;
  332. if ( pchAvail - rgchBuffer > sizeof(rgchBuffer) )
  333. Error( "Not enough memory to satisfy %d byte request\n", cb );
  334. return pch;
  335. }
  336. /*
  337. * AddKeyword
  338. *
  339. * Purpose:
  340. * Stores a keyword string and it's corresponding value into a
  341. * KEYWORD structure. Space for the string is allocated.
  342. *
  343. * Arguments:
  344. * pkeyword Pointer to a keyword structure
  345. * szKeyword The string to be stored.
  346. * token The token value for this string
  347. *
  348. * Returns:
  349. * None.
  350. */
  351. void AddKeyword( KEYWORD * pk, CHAR * szKeyword, TOKEN token )
  352. {
  353. pk->token = token;
  354. pk->szKeyword = ( CHAR * ) MyMalloc( strlen(szKeyword) + 1 );
  355. if ( pk->szKeyword == NULL )
  356. Error( "Not enough memory to store %s\n", szKeyword );
  357. strcpy( pk->szKeyword, szKeyword );
  358. }
  359. /*
  360. * TokenLookup
  361. *
  362. * Purpose:
  363. * Lookup a token symbol in the rgToken table and return the value
  364. * of the token for it. If the token symbol can't be found, add it
  365. * to the table and assign the next available token value.
  366. *
  367. * Arguments:
  368. * sz The symbol to lookup
  369. *
  370. * Returns:
  371. * The token value for the symbol.
  372. */
  373. TOKEN TokenLookup( CHAR * sz )
  374. {
  375. KEYWORD * pk = rgToken;
  376. while ( pk->szKeyword && NSzACmp( pk->szKeyword, sz ) )
  377. pk++;
  378. if ( pk->szKeyword == NULL )
  379. {
  380. pk = &rgToken[cToken++];
  381. AddKeyword( pk, sz, sNextToken++ );
  382. fprintf( file[eH], "#define %s\t%d\n", sz, pk->token );
  383. }
  384. return pk->token;
  385. }
  386. /*
  387. * MakeByte
  388. *
  389. * Purpose:
  390. * Write out the representation of a byte for an RCDATA statement into
  391. * the RC file.
  392. *
  393. * Arguments:
  394. * b The byte value to be written out.
  395. *
  396. * Returns:
  397. * None.
  398. */
  399. void MakeByte( BYTE b )
  400. {
  401. fprintf( file[eRC], "\"\\%03o\"", b );
  402. }
  403. /*
  404. * MakeShort
  405. *
  406. * Purpose:
  407. * Write out the binary image of a short as a RCDATA statement into
  408. * the RC file.
  409. *
  410. * Arguments:
  411. * s The short value to be written out.
  412. *
  413. * Returns:
  414. * None.
  415. */
  416. void MakeShort( SHORT s )
  417. {
  418. BYTE * pb = ( BYTE * ) &s;
  419. INT i;
  420. for ( i = 0; i < sizeof(SHORT); i++ )
  421. {
  422. MakeByte(*pb++);
  423. if ( i + 1 < sizeof(SHORT) )
  424. fprintf( file[eRC], ", " );
  425. }
  426. }
  427. /*
  428. * MakeLong
  429. *
  430. * Purpose:
  431. * Write out the binary image of a long as a RCDATA statement into
  432. * the RC file.
  433. *
  434. * Arguments:
  435. * l The long value to be written out.
  436. *
  437. * Returns:
  438. * None.
  439. */
  440. void MakeLong( LONG l )
  441. {
  442. BYTE * pb = ( BYTE * ) &l;
  443. INT i;
  444. for ( i = 0; i < sizeof(LONG); i++ )
  445. {
  446. MakeByte(*pb++);
  447. if ( i + 1 < sizeof(LONG) )
  448. fprintf( file[eRC], ", " );
  449. }
  450. }
  451. /*
  452. * SzMakeQuoted
  453. *
  454. * Purpose:
  455. * Create the C constant string declaration version of a string and
  456. * return a pointer to it.
  457. * The created string is kept in a scratchpad which will be
  458. * overwritten each time this function is called.
  459. *
  460. * Arguments:
  461. * sz String to make a C constant string version of
  462. *
  463. * Returns:
  464. * Pointer to a scratchpad containing C constant string version of
  465. * sz
  466. */
  467. CHAR * SzMakeQuoted( CHAR * sz )
  468. {
  469. CHAR * pch = szScratch;
  470. *pch++ = '"';
  471. while (*sz)
  472. {
  473. switch (*sz)
  474. {
  475. case '\n':
  476. *pch++ = '\\';
  477. *pch++ = 'n';
  478. break;
  479. case '\r':
  480. *pch++ = '\\';
  481. *pch++ = 'r';
  482. break;
  483. case '\t':
  484. *pch++ = '\\';
  485. *pch++ = 't';
  486. break;
  487. case '\\':
  488. *pch++ = '\\';
  489. *pch++ = '\\';
  490. break;
  491. case '"':
  492. *pch++ = '\\';
  493. *pch++ = '"';
  494. break;
  495. default:
  496. if (isprint(*sz))
  497. *pch++ = *sz;
  498. else
  499. Error( "Don't know how to deal with ASCII %d\n", *sz );
  500. break;
  501. }
  502. sz++;
  503. }
  504. *pch++ = '"';
  505. *pch = '\0';
  506. return szScratch;
  507. }
  508. /*
  509. * GenerateTable
  510. *
  511. * Purpose:
  512. * Generates the C table and RCDATA tables
  513. *
  514. * Arguments:
  515. * None.
  516. *
  517. * Returns:
  518. * None.
  519. */
  520. void GenerateTable(void)
  521. {
  522. KEYWORD * pk;
  523. INT nOffset;
  524. // Sort the keywords
  525. qsort( rgKeyword, cKeyword, sizeof(KEYWORD), CompareKeywords );
  526. // Put the header for the C table
  527. fprintf( file[eC], "static KEYWORD rgKeyword[] =\n{\n" );
  528. // Put the header for the RCDATA
  529. fprintf( file[eRC], "TOKENS RCDATA\nBEGIN\n" );
  530. // Output our keyword table
  531. pk = rgKeyword;
  532. nOffset = sizeof(rgKeyword);
  533. while ( pk->szKeyword != NULL )
  534. {
  535. // Add the string and token to the C file
  536. fprintf( file[eC], "\t{ %s, %d },\n", SzMakeQuoted(pk->szKeyword),
  537. pk->token );
  538. // Add the table entry into the RC file
  539. MakeLong(nOffset);
  540. fprintf( file[eRC], ", " );
  541. MakeShort(pk->token);
  542. fprintf( file[eRC], ", /* %d, %d */\n", nOffset, pk->token );
  543. nOffset += strlen(pk->szKeyword) + 1;
  544. pk++;
  545. }
  546. // Put the NULL entry for the RCDATA
  547. MakeLong(0);
  548. fprintf( file[eRC], ", " );
  549. MakeShort(pk->token);
  550. fprintf( file[eRC], ", /* %d, %d */\n", 0, pk->token );
  551. // Put the NULL entry for the C table and end the table
  552. fprintf( file[eC], "\t{ NULL, 0 }\n};\n" );
  553. // Output our keyword strings
  554. pk = rgKeyword;
  555. while ( pk->szKeyword != NULL )
  556. {
  557. if ( isprint(*pk->szKeyword) )
  558. fprintf( file[eRC], "\"%s\\0\"", pk->szKeyword );
  559. else
  560. {
  561. MakeByte( *pk->szKeyword );
  562. fprintf( file[eRC], ", " );
  563. MakeByte(0);
  564. }
  565. pk++;
  566. if ( pk->szKeyword != NULL )
  567. fprintf( file[eRC],",");
  568. fprintf( file[eRC],"\n");
  569. }
  570. fprintf( file[eRC], "END\n\n" );
  571. }
  572. int __cdecl main( int argc, char * argv[] )
  573. {
  574. INT i;
  575. CHAR szLine[128];
  576. CHAR szString[128];
  577. CHAR szToken[128];
  578. CHAR *pchCurr;
  579. TOKEN token;
  580. // Verify we have enough parameters
  581. if ( argc != 5 )
  582. Error( "usage: %s tokens.TOK header.H resource.RC table.C\n", argv[0] );
  583. // Blank out our buffers
  584. memset( rgToken, 0, sizeof(rgToken) );
  585. memset( rgKeyword, 0, sizeof(rgKeyword) );
  586. memset( rgchBuffer, 0, sizeof(rgchBuffer) );
  587. // Open the files
  588. for ( i = eTOK; i <= eC; i++ )
  589. if ( ( file[i] = fopen( argv[ i + 1 ], szOpenMode[i] ) ) == NULL )
  590. {
  591. perror( argv[ i + 1 ] );
  592. return -1;
  593. }
  594. // Go through every line in the tokens file
  595. while ( fgets( szLine, sizeof(szLine), file[eTOK] ) )
  596. {
  597. TrimCRLF(szLine);
  598. // Skip blank lines
  599. if ( strlen(szLine) == 0 )
  600. continue;
  601. // Skip comments
  602. if ( szLine[0] == '#' )
  603. continue;
  604. // Get the first word
  605. pchCurr = PchGetNextWord( szLine, szString );
  606. // Do we want to imbed some text someplace ?
  607. if ( !NSzACmp( szString, "IMBED_IN" ) )
  608. {
  609. PchGetNextWord( pchCurr, szString );
  610. HandleImbed(szString);
  611. continue;
  612. }
  613. // Do we want to reset the lowest token value ?
  614. if ( !NSzACmp( szString, "TOKENS" ) )
  615. {
  616. PchGetNextWord( pchCurr, szString );
  617. sNextToken = atoi(szString);
  618. continue;
  619. }
  620. // Are we specifying a string on this line ?
  621. if ( szString[0] == '"' )
  622. {
  623. // Remove the quotes from the string
  624. TranslateQuoted(szString);
  625. // Get the next word to find out what token value should go with
  626. // this string
  627. PchGetNextWord( pchCurr, szToken );
  628. if ( szToken[0] == '\'' )
  629. {
  630. // We have a single character equivalent for this token.
  631. TranslateQuoted(szToken);
  632. token = *szToken;
  633. }
  634. else if ( isdigit(szToken[0]) )
  635. token = atoi(szToken);
  636. else
  637. token = TokenLookup(szToken);
  638. // Add the token and string pair to our table
  639. AddKeyword( &rgKeyword[cKeyword++], szString, token );
  640. }
  641. }
  642. // Generate the RC data for the RC file
  643. GenerateTable();
  644. // Close the files
  645. for ( i = eTOK; i <= eC; i++ )
  646. fclose(file[i]);
  647. return 0;
  648. }