Leaked source code of windows server 2003
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.

619 lines
22 KiB

  1. /************************************************************************/
  2. /* */
  3. /* RCPP - Resource Compiler Pre-Processor for NT system */
  4. /* */
  5. /* P0IO.C - Input/Output for Preprocessor */
  6. /* */
  7. /* 27-Nov-90 w-BrianM Update for NT from PM SDK RCPP */
  8. /* */
  9. /************************************************************************/
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include "rcpptype.h"
  14. #include "rcppdecl.h"
  15. #include "rcppext.h"
  16. #include "p0defs.h"
  17. #include "charmap.h"
  18. #include "rcunicod.h"
  19. /************************************************************************/
  20. /* Local Function Prototypes */
  21. /************************************************************************/
  22. ptext_t esc_sequence(ptext_t, ptext_t);
  23. #define TEXT_TYPE ptext_t
  24. /*** ASSUME : the trailing marker byte is only 1 character. ***/
  25. #define PUSHBACK_BYTES 1
  26. #define TRAILING_BYTES 1
  27. #define EXTRA_BYTES (PUSHBACK_BYTES + TRAILING_BYTES)
  28. /*
  29. ** here are some defines for the new handling of io buffers.
  30. ** the buffer itself is 6k plus some extra bytes.
  31. ** the main source file uses all 6k.
  32. ** the first level of include files will use 4k starting 2k from the beginning.
  33. ** the 2nd level - n level will use 2k starting 4k from the beginning.
  34. ** this implies that some special handling may be necessary when we get
  35. ** overlapping buffers. (unless the source file itself is < 2k
  36. ** all the include files are < 2k and they do not nest more than 2 deep.)
  37. ** first, the source file is read into the buffer (6k at a time).
  38. ** at the first include file, (if the source from the parent file
  39. ** is more than 2k chars) . . .
  40. ** if the Current_char ptr is not pointing above the 2k boundary
  41. ** (which is the beginning of the buffer for the include file)
  42. ** then we pretend we've read in only 2k into the buffer and
  43. ** place the terminator at the end of the parents 2k buffer.
  44. ** else we pretend we've used up all chars in the parents buffer
  45. ** so the next read for the parent will be the terminator, and
  46. ** the buffer will get filled in the usual manner.
  47. ** (if we're in a macro, the picture is slightly different in that we have
  48. ** to update the 'real' source file pointer in the macro structure.)
  49. **
  50. ** the first nested include file is handled in a similar manner. (except
  51. ** it starts up 4k away from the start.)
  52. **
  53. ** any further nesting will keep overlaying the upper 2k part.
  54. */
  55. #define ONE_K (1024)
  56. #define TWO_K (ONE_K * 2)
  57. #define FOUR_K (ONE_K * 4)
  58. #define SIX_K (ONE_K * 6)
  59. #define IO_BLOCK (TWO_K + EXTRA_BYTES)
  60. int vfCurrFileType = DFT_FILE_IS_UNKNOWN; //- Added for 16-bit file support.
  61. char InputBuffer[IO_BLOCK * 3];
  62. //- Added to input 16-bit files. 8-2-91 David Marsyla.
  63. WCHAR wchInputBuffer[IO_BLOCK * 3];
  64. extern expansion_t Macro_expansion[];
  65. typedef struct s_filelist filelist_t;
  66. static struct s_filelist { /* list of input files (nested) */
  67. int fl_bufsiz;/* bytes to read into the buffer */
  68. FILE * fl_file; /* FILE id */
  69. long fl_lineno; /* line number when file was pushed */
  70. PUCHAR fl_name; /* previous file text name */
  71. ptext_t fl_currc; /* ptr into our buffer for current c */
  72. TEXT_TYPE fl_buffer; /* type of buffer */
  73. WCHAR *fl_pwchBuffer; //- Added for 16-bit file support.
  74. //- pointer to identical wide char buffer.
  75. int fl_numread; /* # of bytes read into buffer */
  76. int fl_fFileType; //- Added for 16-bit file support.
  77. //- return from DetermineFileType.
  78. long fl_totalread;
  79. } Fstack[LIMIT_NESTED_INCLUDES];
  80. static FILE *Fp = NULL;
  81. int Findex = -1;
  82. /************************************************************************
  83. * NEWINPUT - A new input file is to be opened, saving the old.
  84. *
  85. * ARGUMENTS
  86. * char *newname - the name of the file
  87. *
  88. * RETURNS - none
  89. *
  90. * SIDE EFFECTS
  91. * - causes input stream to be switched
  92. * - Linenumber is reset to 1
  93. * - storage is allocated for the newname
  94. * - Filename is set to the new name
  95. *
  96. * DESCRIPTION
  97. * The file is opened, and if successful, the current input stream is saved
  98. * and the stream is switched to the new file. If the newname is NULL,
  99. * then stdin is taken as the new input.
  100. *
  101. * AUTHOR - Ralph Ryan, Sept. 9, 1982
  102. *
  103. * MODIFICATIONS - none
  104. *
  105. ************************************************************************/
  106. int newinput (char *newname, int m_open)
  107. {
  108. filelist_t *pF;
  109. TEXT_TYPE p;
  110. WCHAR *pwch;
  111. if ( newname == NULL ) {
  112. Fp = stdin;
  113. } else if ((Fp = fopen(newname, "rb")) == NULL) {
  114. if (m_open == MUST_OPEN) {
  115. Msg_Temp = GET_MSG (1013);
  116. SET_MSG (Msg_Text, Msg_Temp, newname);
  117. fatal(1013);
  118. }
  119. return (FALSE);
  120. }
  121. /* now push it onto the file stack */
  122. ++Findex;
  123. if (Findex >= LIMIT_NESTED_INCLUDES) {
  124. Msg_Temp = GET_MSG (1014);
  125. SET_MSG (Msg_Text, Msg_Temp);
  126. fatal(1014);
  127. }
  128. pF = &Fstack[Findex];
  129. if (Findex == 0) {
  130. p = &InputBuffer[(IO_BLOCK * 0) + PUSHBACK_BYTES];
  131. pwch = &wchInputBuffer[(IO_BLOCK * 0) + PUSHBACK_BYTES];
  132. pF->fl_bufsiz = SIX_K;
  133. } else {
  134. filelist_t *pPrevF;
  135. pPrevF = pF - 1;
  136. if (Findex == 1) { /* first level include */
  137. p = &InputBuffer[(IO_BLOCK * 1) + PUSHBACK_BYTES];
  138. pwch = &wchInputBuffer[(IO_BLOCK * 1) + PUSHBACK_BYTES];
  139. pF->fl_bufsiz = FOUR_K;
  140. } else { /* (Findex > 1) */
  141. /* nested includes . . . */
  142. p = &InputBuffer[(IO_BLOCK * 2) + PUSHBACK_BYTES];
  143. pwch = &wchInputBuffer[(IO_BLOCK * 2) + PUSHBACK_BYTES];
  144. pF->fl_bufsiz = TWO_K;
  145. }
  146. if ((pPrevF->fl_numread > TWO_K) || (Findex > 2)) {
  147. /*
  148. ** the parent file has read something into the upper section
  149. ** or this is a nested include at least 3 deep.
  150. ** the child will overwrite some parent info. we must take this
  151. ** into account for the parent to reread when the time comes.
  152. ** we also must stick in the eos char into the parents buffer.
  153. ** (this latter is the useless thing in deeply nested
  154. ** includes since we overwrite the thing we just put in. we'll
  155. ** handle this later when we fpop the child.)
  156. */
  157. TEXT_TYPE pCurrC;
  158. long seek_posn;
  159. seek_posn = pPrevF->fl_totalread;
  160. if ( Macro_depth != 0 ) {
  161. /*
  162. ** in a macro, the 'current char' we want is kept as the
  163. ** first thing in the macro structure.
  164. */
  165. pCurrC = (TEXT_TYPE)Macro_expansion[1].exp_string;
  166. } else {
  167. pCurrC = (TEXT_TYPE)Current_char;
  168. }
  169. if (pCurrC >= p) {
  170. /*
  171. ** p is the start of the child section.
  172. ** current char is past it. ie, we've already read some
  173. ** from the upper section.
  174. ** current char - p = # of characters used in upper section.
  175. ** numread = 0 implies there are no chars left from the parent.
  176. ** since, this is really the 'end' of the parent's buffer,
  177. ** we'll have to update the info so that the next read from the
  178. ** parent (after the child is finished) will be the terminator
  179. ** and we want the io_eob handler to refill the buffer.
  180. ** we reset the parent's cur char ptr to the beginning of its
  181. ** buffer, and put the terminator there.
  182. */
  183. seek_posn += (long)(pCurrC - pPrevF->fl_buffer);
  184. pPrevF->fl_totalread += (long)(pCurrC - pPrevF->fl_buffer);
  185. pPrevF->fl_numread = 0;
  186. if ( Macro_depth != 0 ) {
  187. Macro_expansion[1].exp_string = pPrevF->fl_buffer;
  188. } else {
  189. Current_char = pPrevF->fl_buffer;
  190. }
  191. *(pPrevF->fl_buffer) = EOS_CHAR;
  192. *(pPrevF->fl_pwchBuffer) = EOS_CHAR;
  193. } else {
  194. /*
  195. ** the upper section has not been read from yet,
  196. ** but it has been read into.
  197. ** 'p' is pointing to the start of the child's buffer.
  198. ** we add the terminator to the new end of the parent's buffer.
  199. */
  200. seek_posn += TWO_K;
  201. pPrevF->fl_numread = TWO_K;
  202. *(pPrevF->fl_buffer + TWO_K) = EOS_CHAR;
  203. *(pPrevF->fl_pwchBuffer + TWO_K) = EOS_CHAR;
  204. }
  205. if (pPrevF->fl_fFileType == DFT_FILE_IS_8_BIT) {
  206. if (fseek(pPrevF->fl_file, seek_posn, SEEK_SET) == -1)
  207. return FALSE;
  208. } else {
  209. if (fseek(pPrevF->fl_file, seek_posn * sizeof (WCHAR), SEEK_SET) == -1)
  210. return FALSE;
  211. }
  212. }
  213. }
  214. pF->fl_currc = Current_char;/* previous file's current char */
  215. pF->fl_lineno = Linenumber; /* previous file's line number */
  216. pF->fl_file = Fp; /* the new file descriptor */
  217. pF->fl_buffer = p;
  218. pF->fl_pwchBuffer = pwch;
  219. pF->fl_numread = 0;
  220. pF->fl_totalread = 0;
  221. //- Added to support 16-bit files.
  222. //- 8-2-91 David Marsyla.
  223. pF->fl_fFileType = DetermineFileType (Fp);
  224. //- The file type is unknown, warn them and then take a stab at an
  225. //- 8-bit file. 8-2-91 David Marsyla.
  226. if (pF->fl_fFileType == DFT_FILE_IS_UNKNOWN) {
  227. Msg_Temp = GET_MSG (4413);
  228. SET_MSG (Msg_Text, Msg_Temp, newname);
  229. warning (4413);
  230. pF->fl_fFileType = DFT_FILE_IS_8_BIT;
  231. }
  232. vfCurrFileType = pF->fl_fFileType;
  233. Current_char = (ptext_t)p;
  234. io_eob(); /* fill the buffer */
  235. /*
  236. * Note that include filenames will live the entire compiland. This
  237. * puts the burden on the user with MANY include files. Any other
  238. * scheme takes space out of static data.
  239. * Notice also, that we save the previous filename in the new file's
  240. * fl_name.
  241. */
  242. pF->fl_name = pstrdup(Filename);
  243. strncpy(Filebuff,newname,sizeof(Filebuff));
  244. Linenumber = 0; /* do_newline() will increment to the first line */
  245. if (Eflag) {
  246. emit_line();
  247. fwrite("\n", 1, 1, OUTPUTFILE); /* this line is inserted */
  248. }
  249. do_newline(); /* a new file may have preproc cmd as first line */
  250. return (TRUE);
  251. }
  252. /************************************************************************
  253. * FPOP - pop to a previous level of input stream
  254. *
  255. * ARGUMENTS - none
  256. *
  257. * RETURNS
  258. * TRUE if successful, FALSE if the stack is empty
  259. *
  260. * SIDE EFFECTS
  261. * - Linenumber is restored to the old files line number
  262. * - Filename is reset to the old filename
  263. * - frees storage allocated for filename
  264. *
  265. * DESCRIPTION
  266. * Pop the top of the file stack, restoring the previous input stream.
  267. *
  268. * AUTHOR - Ralph Ryan, Sept. 9, 1982
  269. *
  270. * MODIFICATIONS - none
  271. *
  272. ************************************************************************/
  273. UCHAR fpop(void)
  274. {
  275. int Old_line;
  276. if (Findex == -1) { /* no files left */
  277. return (FALSE);
  278. }
  279. fclose(Fp);
  280. strappend(Filebuff,Fstack[Findex].fl_name);
  281. Old_line = Linenumber;
  282. Linenumber = (int)Fstack[Findex].fl_lineno;
  283. Current_char = Fstack[Findex].fl_currc;
  284. if (--Findex < 0) { /* popped the last file */
  285. Linenumber = Old_line;
  286. return (FALSE);
  287. }
  288. Fp = Fstack[Findex].fl_file;
  289. vfCurrFileType = Fstack[Findex].fl_fFileType;
  290. if (Findex >= 2) { /* popped off a deeply nested include */
  291. io_eob();
  292. }
  293. if (Eflag) {
  294. emit_line();
  295. }
  296. return (TRUE);
  297. }
  298. /************************************************************************
  299. ** nested_include : searches the parentage list of the currently
  300. ** open files on the stack when a new include file is found.
  301. ** Input : ptr to include file name.
  302. ** Output : TRUE if the file was found, FALSE if not.
  303. *************************************************************************/
  304. int nested_include(void)
  305. {
  306. PUCHAR p_tmp1;
  307. PUCHAR p_file;
  308. PUCHAR p_slash;
  309. int tos;
  310. tos = Findex;
  311. p_file = Filename; /* always start with the current file */
  312. for (;;) {
  313. p_tmp1 = p_file;
  314. p_slash = NULL;
  315. while (*p_tmp1) { /* pt to end of filename, find trailing slash */
  316. if (CHARMAP(*p_tmp1) == LX_LEADBYTE) {
  317. p_tmp1++;
  318. } else if (strchr(Path_chars, *p_tmp1)) {
  319. p_slash = p_tmp1;
  320. }
  321. p_tmp1++;
  322. }
  323. if (p_slash) {
  324. p_tmp1 = Reuse_1;
  325. while (p_file <= p_slash) { /* we want the trailing '/' */
  326. *p_tmp1++ = *p_file++; /* copy the parent directory */
  327. }
  328. p_file = yylval.yy_string.str_ptr;
  329. while ((*p_tmp1++ = *p_file++)!=0) { /*append include file name */
  330. ; /* NULL */
  331. }
  332. } else {
  333. SET_MSG(Reuse_1,"%s",yylval.yy_string.str_ptr);
  334. }
  335. if (newinput(Reuse_1,MAY_OPEN)) {
  336. return (TRUE);
  337. }
  338. if (tos <= 0) {
  339. break;
  340. }
  341. p_file = Fstack[tos--].fl_name;
  342. }
  343. return (FALSE);
  344. }
  345. /************************************************************************/
  346. /* esc_sequence() */
  347. /************************************************************************/
  348. ptext_t esc_sequence(ptext_t dest, ptext_t name)
  349. {
  350. *dest = '"';
  351. while ((*++dest = *name) != 0) {
  352. switch ( CHARMAP(*name) ) {
  353. case LX_EOS:
  354. *++dest = '\\';
  355. break;
  356. case LX_LEADBYTE:
  357. *++dest = *++name;
  358. break;
  359. }
  360. name++;
  361. }
  362. *dest++ = '"'; /* overwrite null */
  363. return ( dest );
  364. }
  365. /************************************************************************/
  366. /* emit_line() */
  367. /************************************************************************/
  368. void emit_line(void)
  369. {
  370. char linebuf[16];
  371. ptext_t p;
  372. SET_MSG(linebuf, "#line %d ", Linenumber+1);
  373. fwrite(linebuf, strlen(linebuf), 1, OUTPUTFILE);
  374. p = esc_sequence(Reuse_1, Filename);
  375. fwrite(Reuse_1, (size_t)(p - Reuse_1), 1, OUTPUTFILE);
  376. }
  377. //-
  378. //- wchCheckWideChar - This functions was added to support 16-bit input files.
  379. //- It is the equivalent of CHECKCH() but it locates the current position
  380. //- in the wide character buffer and then returns the stored character.
  381. //- 8-2-91 David Marsyla.
  382. //-
  383. unsigned short wchCheckWideChar (void)
  384. {
  385. WCHAR *pwch;
  386. TEXT_TYPE p;
  387. //- Get pointers to both buffers.
  388. pwch = Fstack[Findex].fl_pwchBuffer;
  389. p = Fstack[Findex].fl_buffer;
  390. //- Find the equivalent offset from the beginning of the pwch buffer.
  391. pwch += (Current_char - (ptext_t)p);
  392. return (*pwch);
  393. }
  394. /************************************************************************
  395. ** io_eob : handle getting the next block from a file.
  396. ** return TRUE if this is the real end of the buffer, FALSE if we have
  397. ** more to do.
  398. ************************************************************************/
  399. int io_eob(void)
  400. {
  401. int n;
  402. TEXT_TYPE p;
  403. WCHAR *pwch;
  404. p = Fstack[Findex].fl_buffer;
  405. pwch = Fstack[Findex].fl_pwchBuffer;
  406. if ((Current_char - (ptext_t)p) < Fstack[Findex].fl_numread) {
  407. /*
  408. ** haven't used all the chars from the buffer yet.
  409. ** (some clown has a null/cntl z embedded in his source file.)
  410. */
  411. if (PREVCH() == CONTROL_Z) { /* imbedded control z, real eof */
  412. UNGETCH();
  413. return (TRUE);
  414. }
  415. return (FALSE);
  416. }
  417. Current_char = p;
  418. //-
  419. //- The following section was added to support 16-bit resource files.
  420. //- It will just convert them to 8-bit files that the Resource Compiler
  421. //- can read. Here is the basic strategy used. An 8-bit file is
  422. //- read into the normal buffer and should be processed the old way.
  423. //- A 16-bit file is read into a wide character buffer identical to the
  424. //- normal 8-bit one. The entire contents are then copied to the 8-bit
  425. //- buffer and processed normally. The one exception to this is when
  426. //- a string literal is encountered. We then return to the 16-bit buffer
  427. //- to read the characters. These characters are written as backslashed
  428. //- escape characters inside an 8-bit string. (ex. "\x004c\x523f").
  429. //- I'll be the first person to admit that this is an ugly solution, but
  430. //- hey, we're Microsoft :-). 8-2-91 David Marsyla.
  431. //-
  432. if (Fstack[Findex].fl_fFileType == DFT_FILE_IS_8_BIT) {
  433. n = fread (p, sizeof (char), Fstack[Findex].fl_bufsiz, Fp);
  434. } else {
  435. n = fread (pwch, sizeof (WCHAR), Fstack[Findex].fl_bufsiz, Fp);
  436. //-
  437. //- If the file is in reversed format, swap the bytes.
  438. //-
  439. if (Fstack[Findex].fl_fFileType == DFT_FILE_IS_16_BIT_REV && n > 0) {
  440. WCHAR *pwchT = pwch;
  441. BYTE jLowNibble;
  442. BYTE jHighNibble;
  443. INT cNumWords = n;
  444. while (cNumWords--) {
  445. jLowNibble = (BYTE)(*pwchT & 0xFF);
  446. jHighNibble = (BYTE)((*pwchT >> 8) & 0xFF);
  447. *pwchT++ = (WCHAR)(jHighNibble | (jLowNibble << 8));
  448. }
  449. }
  450. //-
  451. //- The following block will copy the 16-bit buffer to the 8-bit
  452. //- buffer. It does this by truncating the 16-bit character. This
  453. //- will cause information loss but we will keep the 16-bit buffer
  454. //- around for when we need to look at any string literals.
  455. //-
  456. if (n > 0) {
  457. char *pchT = p;
  458. WCHAR *pwchT = pwch;
  459. INT cNumWords = n;
  460. while (cNumWords--) {
  461. *pchT++ = (char)*pwchT++;
  462. }
  463. }
  464. }
  465. /*
  466. ** the total read counts the total read *and* used.
  467. */
  468. Fstack[Findex].fl_totalread += Fstack[Findex].fl_numread;
  469. Fstack[Findex].fl_numread = n;
  470. if (n != 0) { /* we read something */
  471. *(p + n) = EOS_CHAR; /* sentinal at the end */
  472. *(pwch + n) = EOS_CHAR; /* sentinal at the end */
  473. return (FALSE); /* more to do */
  474. }
  475. *p = EOS_CHAR; /* read no chars */
  476. *pwch = EOS_CHAR; /* read no chars */
  477. return (TRUE); /* real end of buffer */
  478. }
  479. /************************************************************************
  480. ** p0_init : inits for prepocessing.
  481. ** Input : ptr to file name to use as input.
  482. ** ptr to LIST containing predefined values.
  483. ** ( -D's from cmd line )
  484. **
  485. ** Note : if "newinput" cannot open the file,
  486. ** it gives a fatal msg and exits.
  487. **
  488. ************************************************************************/
  489. void p0_init(char *p_fname, char *p_outname, LIST *p_defns)
  490. {
  491. REG char *p_dstr;
  492. REG char *p_eq;
  493. int ntop;
  494. CHARMAP(LX_FORMALMARK) = LX_MACFORMAL;
  495. CHARMAP(LX_FORMALSTR) = LX_STRFORMAL;
  496. CHARMAP(LX_FORMALCHAR) = LX_CHARFORMAL;
  497. CHARMAP(LX_NOEXPANDMARK) = LX_NOEXPAND;
  498. if (EXTENSION) {
  499. /*
  500. ** '$' is an identifier character under extensions.
  501. */
  502. CHARMAP('$') = LX_ID;
  503. CONTMAP('$') = LXC_ID;
  504. }
  505. for (ntop = p_defns->li_top; ntop < MAXLIST; ++ntop) {
  506. p_dstr = p_defns->li_defns[ntop];
  507. p_eq = Reuse_1;
  508. while ((*p_eq = *p_dstr++) != 0) { /* copy the name to Reuse_1 */
  509. if (CHARMAP(*p_eq) == LX_LEADBYTE) {
  510. *++p_eq = *p_dstr++;
  511. } else if (*p_eq == '=') { /* we're told what the value is */
  512. break;
  513. }
  514. p_eq++;
  515. }
  516. if (*p_eq == '=') {
  517. char *p_tmp;
  518. char *last_space = NULL;
  519. *p_eq = '\0'; /* null the = */
  520. for (p_tmp = p_dstr; *p_tmp; p_tmp++) { /* find the end of it */
  521. if (CHARMAP(*p_tmp) == LX_LEADBYTE) {
  522. p_tmp++;
  523. last_space = NULL;
  524. } else if (isspace(*p_tmp)) {
  525. if (last_space == NULL) {
  526. last_space = p_tmp;
  527. }
  528. } else {
  529. last_space = NULL;
  530. }
  531. }
  532. if (last_space != NULL) {
  533. *last_space = '\0';
  534. }
  535. Reuse_1_hash = local_c_hash(Reuse_1);
  536. Reuse_1_length = strlen(Reuse_1) + 1;
  537. if ( *p_dstr ) { /* non-empty string */
  538. definstall(p_dstr, (strlen(p_dstr) + 2), FROM_COMMAND);
  539. } else {
  540. definstall((char *)0, 0, 0);
  541. }
  542. } else {
  543. Reuse_1_hash = local_c_hash(Reuse_1);
  544. Reuse_1_length = strlen(Reuse_1) + 1;
  545. definstall("1\000", 3, FROM_COMMAND); /* value of string is 1 */
  546. }
  547. }
  548. if ((OUTPUTFILE = fopen (p_outname, "w+")) == NULL) {
  549. Msg_Temp = GET_MSG (1023);
  550. SET_MSG (Msg_Text, Msg_Temp);
  551. fatal (1023);
  552. }
  553. newinput(p_fname,MUST_OPEN);
  554. }