windows-nt/Source/XPSP1/NT/sdktools/hivepp/p0io.c
2020-09-26 16:20:57 +08:00

620 lines
21 KiB
C

/************************************************************************/
/* */
/* RCPP - Resource Compiler Pre-Processor for NT system */
/* */
/* P0IO.C - Input/Output for Preprocessor */
/* */
/* 27-Nov-90 w-BrianM Update for NT from PM SDK RCPP */
/* */
/************************************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "rcpptype.h"
#include "rcppdecl.h"
#include "rcppext.h"
#include "p0defs.h"
#include "charmap.h"
#include "rcunicod.h"
/************************************************************************/
/* Local Function Prototypes */
/************************************************************************/
ptext_t esc_sequence(ptext_t, ptext_t);
#define TEXT_TYPE ptext_t
/*** ASSUME : the trailing marker byte is only 1 character. ***/
#define PUSHBACK_BYTES 1
#define TRAILING_BYTES 1
#define EXTRA_BYTES (PUSHBACK_BYTES + TRAILING_BYTES)
/*
** here are some defines for the new handling of io buffers.
** the buffer itself is 6k plus some extra bytes.
** the main source file uses all 6k.
** the first level of include files will use 4k starting 2k from the beginning.
** the 2nd level - n level will use 2k starting 4k from the beginning.
** this implies that some special handling may be necessary when we get
** overlapping buffers. (unless the source file itself is < 2k
** all the include files are < 2k and they do not nest more than 2 deep.)
** first, the source file is read into the buffer (6k at a time).
** at the first include file, (if the source from the parent file
** is more than 2k chars) . . .
** if the Current_char ptr is not pointing above the 2k boundary
** (which is the beginning of the buffer for the include file)
** then we pretend we've read in only 2k into the buffer and
** place the terminator at the end of the parents 2k buffer.
** else we pretend we've used up all chars in the parents buffer
** so the next read for the parent will be the terminator, and
** the buffer will get filled in the usual manner.
** (if we're in a macro, the picture is slightly different in that we have
** to update the 'real' source file pointer in the macro structure.)
**
** the first nested include file is handled in a similar manner. (except
** it starts up 4k away from the start.)
**
** any further nesting will keep overlaying the upper 2k part.
*/
#define ONE_K (1024)
#define TWO_K (ONE_K * 2)
#define FOUR_K (ONE_K * 4)
#define SIX_K (ONE_K * 6)
#define IO_BLOCK (TWO_K + EXTRA_BYTES)
int vfCurrFileType = DFT_FILE_IS_UNKNOWN; //- Added for 16-bit file support.
char InputBuffer[IO_BLOCK * 3];
//- Added to input 16-bit files. 8-2-91 David Marsyla.
WCHAR wchInputBuffer[IO_BLOCK * 3];
extern expansion_t Macro_expansion[];
typedef struct s_filelist filelist_t;
static struct s_filelist { /* list of input files (nested) */
int fl_bufsiz;/* bytes to read into the buffer */
FILE * fl_file; /* FILE id */
long fl_lineno; /* line number when file was pushed */
PUCHAR fl_name; /* previous file text name */
ptext_t fl_currc; /* ptr into our buffer for current c */
TEXT_TYPE fl_buffer; /* type of buffer */
WCHAR *fl_pwchBuffer; //- Added for 16-bit file support.
//- pointer to identical wide char buffer.
int fl_numread; /* # of bytes read into buffer */
int fl_fFileType; //- Added for 16-bit file support.
//- return from DetermineFileType.
long fl_totalread;
} Fstack[LIMIT_NESTED_INCLUDES];
static FILE *Fp = NULL;
int Findex = -1;
/************************************************************************
* NEWINPUT - A new input file is to be opened, saving the old.
*
* ARGUMENTS
* char *newname - the name of the file
*
* RETURNS - none
*
* SIDE EFFECTS
* - causes input stream to be switched
* - Linenumber is reset to 1
* - storage is allocated for the newname
* - Filename is set to the new name
*
* DESCRIPTION
* The file is opened, and if successful, the current input stream is saved
* and the stream is switched to the new file. If the newname is NULL,
* then stdin is taken as the new input.
*
* AUTHOR - Ralph Ryan, Sept. 9, 1982
*
* MODIFICATIONS - none
*
************************************************************************/
int newinput (char *newname, int m_open)
{
filelist_t *pF;
TEXT_TYPE p;
WCHAR *pwch;
if ( newname == NULL ) {
Fp = stdin;
} else if ((Fp = fopen(newname, "rb")) == NULL) {
if (m_open == MUST_OPEN) {
Msg_Temp = GET_MSG (1013);
SET_MSG (Msg_Text, Msg_Temp, newname);
fatal(1013);
}
return (FALSE);
}
/* now push it onto the file stack */
++Findex;
if (Findex >= LIMIT_NESTED_INCLUDES) {
Msg_Temp = GET_MSG (1014);
SET_MSG (Msg_Text, Msg_Temp);
fatal(1014);
}
pF = &Fstack[Findex];
if (Findex == 0) {
p = &InputBuffer[(IO_BLOCK * 0) + PUSHBACK_BYTES];
pwch = &wchInputBuffer[(IO_BLOCK * 0) + PUSHBACK_BYTES];
pF->fl_bufsiz = SIX_K;
} else {
filelist_t *pPrevF;
pPrevF = pF - 1;
if (Findex == 1) { /* first level include */
p = &InputBuffer[(IO_BLOCK * 1) + PUSHBACK_BYTES];
pwch = &wchInputBuffer[(IO_BLOCK * 1) + PUSHBACK_BYTES];
pF->fl_bufsiz = FOUR_K;
} else { /* (Findex > 1) */
/* nested includes . . . */
p = &InputBuffer[(IO_BLOCK * 2) + PUSHBACK_BYTES];
pwch = &wchInputBuffer[(IO_BLOCK * 2) + PUSHBACK_BYTES];
pF->fl_bufsiz = TWO_K;
}
if ((pPrevF->fl_numread > TWO_K) || (Findex > 2)) {
/*
** the parent file has read something into the upper section
** or this is a nested include at least 3 deep.
** the child will overwrite some parent info. we must take this
** into account for the parent to reread when the time comes.
** we also must stick in the eos char into the parents buffer.
** (this latter is the useless thing in deeply nested
** includes since we overwrite the thing we just put in. we'll
** handle this later when we fpop the child.)
*/
TEXT_TYPE pCurrC;
long seek_posn;
seek_posn = pPrevF->fl_totalread;
if ( Macro_depth != 0 ) {
/*
** in a macro, the 'current char' we want is kept as the
** first thing in the macro structure.
*/
pCurrC = (TEXT_TYPE)Macro_expansion[1].exp_string;
} else {
pCurrC = (TEXT_TYPE)Current_char;
}
if (pCurrC >= p) {
/*
** p is the start of the child section.
** current char is past it. ie, we've already read some
** from the upper section.
** current char - p = # of characters used in upper section.
** numread = 0 implies there are no chars left from the parent.
** since, this is really the 'end' of the parent's buffer,
** we'll have to update the info so that the next read from the
** parent (after the child is finished) will be the terminator
** and we want the io_eob handler to refill the buffer.
** we reset the parent's cur char ptr to the beginning of its
** buffer, and put the terminator there.
*/
seek_posn += (long)(pCurrC - pPrevF->fl_buffer);
pPrevF->fl_totalread += (long)(pCurrC - pPrevF->fl_buffer);
pPrevF->fl_numread = 0;
if ( Macro_depth != 0 ) {
Macro_expansion[1].exp_string = pPrevF->fl_buffer;
} else {
Current_char = pPrevF->fl_buffer;
}
*(pPrevF->fl_buffer) = EOS_CHAR;
*(pPrevF->fl_pwchBuffer) = EOS_CHAR;
} else {
/*
** the upper section has not been read from yet,
** but it has been read into.
** 'p' is pointing to the start of the child's buffer.
** we add the terminator to the new end of the parent's buffer.
*/
seek_posn += TWO_K;
pPrevF->fl_numread = TWO_K;
*(pPrevF->fl_buffer + TWO_K) = EOS_CHAR;
*(pPrevF->fl_pwchBuffer + TWO_K) = EOS_CHAR;
}
if (pPrevF->fl_fFileType == DFT_FILE_IS_8_BIT) {
if (fseek(pPrevF->fl_file, seek_posn, SEEK_SET) == -1)
return FALSE;
} else {
if (fseek(pPrevF->fl_file, seek_posn * sizeof (WCHAR), SEEK_SET) == -1)
return FALSE;
}
}
}
pF->fl_currc = Current_char;/* previous file's current char */
pF->fl_lineno = Linenumber; /* previous file's line number */
pF->fl_file = Fp; /* the new file descriptor */
pF->fl_buffer = p;
pF->fl_pwchBuffer = pwch;
pF->fl_numread = 0;
pF->fl_totalread = 0;
//- Added to support 16-bit files.
//- 8-2-91 David Marsyla.
pF->fl_fFileType = DetermineFileType (Fp);
//- The file type is unknown, warn them and then take a stab at an
//- 8-bit file. 8-2-91 David Marsyla.
if (pF->fl_fFileType == DFT_FILE_IS_UNKNOWN) {
Msg_Temp = GET_MSG (4413);
SET_MSG (Msg_Text, Msg_Temp, newname);
warning (4413);
pF->fl_fFileType = DFT_FILE_IS_8_BIT;
}
vfCurrFileType = pF->fl_fFileType;
Current_char = (ptext_t)p;
io_eob(); /* fill the buffer */
/*
* Note that include filenames will live the entire compiland. This
* puts the burden on the user with MANY include files. Any other
* scheme takes space out of static data.
* Notice also, that we save the previous filename in the new file's
* fl_name.
*/
pF->fl_name = pstrdup(Filename);
strncpy(Filebuff,newname,sizeof(Filebuff));
Linenumber = 0; /* do_newline() will increment to the first line */
if (Eflag) {
emit_line();
fwrite("\n", 1, 1, OUTPUTFILE); /* this line is inserted */
}
do_newline(); /* a new file may have preproc cmd as first line */
return (TRUE);
}
/************************************************************************
* FPOP - pop to a previous level of input stream
*
* ARGUMENTS - none
*
* RETURNS
* TRUE if successful, FALSE if the stack is empty
*
* SIDE EFFECTS
* - Linenumber is restored to the old files line number
* - Filename is reset to the old filename
* - frees storage allocated for filename
*
* DESCRIPTION
* Pop the top of the file stack, restoring the previous input stream.
*
* AUTHOR - Ralph Ryan, Sept. 9, 1982
*
* MODIFICATIONS - none
*
************************************************************************/
UCHAR fpop(void)
{
int Old_line;
if (Findex == -1) { /* no files left */
return (FALSE);
}
fclose(Fp);
strappend(Filebuff,Fstack[Findex].fl_name);
Old_line = Linenumber;
Linenumber = (int)Fstack[Findex].fl_lineno;
Current_char = Fstack[Findex].fl_currc;
if (--Findex < 0) { /* popped the last file */
Linenumber = Old_line;
return (FALSE);
}
Fp = Fstack[Findex].fl_file;
vfCurrFileType = Fstack[Findex].fl_fFileType;
if (Findex >= 2) { /* popped off a deeply nested include */
io_eob();
}
if (Eflag) {
emit_line();
}
return (TRUE);
}
/************************************************************************
** nested_include : searches the parentage list of the currently
** open files on the stack when a new include file is found.
** Input : ptr to include file name.
** Output : TRUE if the file was found, FALSE if not.
*************************************************************************/
int nested_include(void)
{
PUCHAR p_tmp1;
PUCHAR p_file;
PUCHAR p_slash;
int tos;
tos = Findex;
p_file = Filename; /* always start with the current file */
for (;;) {
p_tmp1 = p_file;
p_slash = NULL;
while (*p_tmp1) { /* pt to end of filename, find trailing slash */
if (CHARMAP(*p_tmp1) == LX_LEADBYTE) {
p_tmp1++;
} else if (strchr(Path_chars, *p_tmp1)) {
p_slash = p_tmp1;
}
p_tmp1++;
}
if (p_slash) {
p_tmp1 = Reuse_1;
while (p_file <= p_slash) { /* we want the trailing '/' */
*p_tmp1++ = *p_file++; /* copy the parent directory */
}
p_file = yylval.yy_string.str_ptr;
while ((*p_tmp1++ = *p_file++)!=0) { /*append include file name */
; /* NULL */
}
} else {
SET_MSG(Reuse_1,"%s",yylval.yy_string.str_ptr);
}
if (newinput(Reuse_1,MAY_OPEN)) {
return (TRUE);
}
if (tos <= 0) {
break;
}
p_file = Fstack[tos--].fl_name;
}
return (FALSE);
}
/************************************************************************/
/* esc_sequence() */
/************************************************************************/
ptext_t esc_sequence(ptext_t dest, ptext_t name)
{
*dest = '"';
while ((*++dest = *name) != 0) {
switch ( CHARMAP(*name) ) {
case LX_EOS:
*++dest = '\\';
break;
case LX_LEADBYTE:
*++dest = *++name;
break;
}
name++;
}
*dest++ = '"'; /* overwrite null */
return ( dest );
}
/************************************************************************/
/* emit_line() */
/************************************************************************/
void emit_line(void)
{
char linebuf[16];
ptext_t p;
SET_MSG(linebuf, "#line %d ", Linenumber+1);
fwrite(linebuf, strlen(linebuf), 1, OUTPUTFILE);
p = esc_sequence(Reuse_1, Filename);
fwrite(Reuse_1, (size_t)(p - Reuse_1), 1, OUTPUTFILE);
}
//-
//- wchCheckWideChar - This functions was added to support 16-bit input files.
//- It is the equivalent of CHECKCH() but it locates the current position
//- in the wide character buffer and then returns the stored character.
//- 8-2-91 David Marsyla.
//-
unsigned short wchCheckWideChar (void)
{
WCHAR *pwch;
TEXT_TYPE p;
//- Get pointers to both buffers.
pwch = Fstack[Findex].fl_pwchBuffer;
p = Fstack[Findex].fl_buffer;
//- Find the equivalent offset from the beginning of the pwch buffer.
pwch += (Current_char - (ptext_t)p);
return (*pwch);
}
/************************************************************************
** io_eob : handle getting the next block from a file.
** return TRUE if this is the real end of the buffer, FALSE if we have
** more to do.
************************************************************************/
int io_eob(void)
{
int n;
TEXT_TYPE p;
WCHAR *pwch;
p = Fstack[Findex].fl_buffer;
pwch = Fstack[Findex].fl_pwchBuffer;
if ((Current_char - (ptext_t)p) < Fstack[Findex].fl_numread) {
/*
** haven't used all the chars from the buffer yet.
** (some clown has a null/cntl z embedded in his source file.)
*/
if (PREVCH() == CONTROL_Z) { /* imbedded control z, real eof */
UNGETCH();
return (TRUE);
}
return (FALSE);
}
Current_char = p;
//-
//- The following section was added to support 16-bit resource files.
//- It will just convert them to 8-bit files that the Resource Compiler
//- can read. Here is the basic strategy used. An 8-bit file is
//- read into the normal buffer and should be processed the old way.
//- A 16-bit file is read into a wide character buffer identical to the
//- normal 8-bit one. The entire contents are then copied to the 8-bit
//- buffer and processed normally. The one exception to this is when
//- a string literal is encountered. We then return to the 16-bit buffer
//- to read the characters. These characters are written as backslashed
//- escape characters inside an 8-bit string. (ex. "\x004c\x523f").
//- I'll be the first person to admit that this is an ugly solution, but
//- hey, we're Microsoft :-). 8-2-91 David Marsyla.
//-
if (Fstack[Findex].fl_fFileType == DFT_FILE_IS_8_BIT) {
n = fread (p, sizeof (char), Fstack[Findex].fl_bufsiz, Fp);
} else {
n = fread (pwch, sizeof (WCHAR), Fstack[Findex].fl_bufsiz, Fp);
//-
//- If the file is in reversed format, swap the bytes.
//-
if (Fstack[Findex].fl_fFileType == DFT_FILE_IS_16_BIT_REV && n > 0) {
WCHAR *pwchT = pwch;
BYTE jLowNibble;
BYTE jHighNibble;
INT cNumWords = n;
while (cNumWords--) {
jLowNibble = (BYTE)(*pwchT & 0xFF);
jHighNibble = (BYTE)((*pwchT >> 8) & 0xFF);
*pwchT++ = (WCHAR)(jHighNibble | (jLowNibble << 8));
}
}
//-
//- The following block will copy the 16-bit buffer to the 8-bit
//- buffer. It does this by truncating the 16-bit character. This
//- will cause information loss but we will keep the 16-bit buffer
//- around for when we need to look at any string literals.
//-
if (n > 0) {
char *pchT = p;
WCHAR *pwchT = pwch;
INT cNumWords = n;
while (cNumWords--) {
*pchT++ = (char)*pwchT++;
}
}
}
/*
** the total read counts the total read *and* used.
*/
Fstack[Findex].fl_totalread += Fstack[Findex].fl_numread;
Fstack[Findex].fl_numread = n;
if (n != 0) { /* we read something */
*(p + n) = EOS_CHAR; /* sentinal at the end */
*(pwch + n) = EOS_CHAR; /* sentinal at the end */
return (FALSE); /* more to do */
}
*p = EOS_CHAR; /* read no chars */
*pwch = EOS_CHAR; /* read no chars */
return (TRUE); /* real end of buffer */
}
/************************************************************************
** p0_init : inits for prepocessing.
** Input : ptr to file name to use as input.
** ptr to LIST containing predefined values.
** ( -D's from cmd line )
**
** Note : if "newinput" cannot open the file,
** it gives a fatal msg and exits.
**
************************************************************************/
void p0_init(char *p_fname, char *p_outname, LIST *p_defns)
{
REG char *p_dstr;
REG char *p_eq;
int ntop;
CHARMAP(LX_FORMALMARK) = LX_MACFORMAL;
CHARMAP(LX_FORMALSTR) = LX_STRFORMAL;
CHARMAP(LX_FORMALCHAR) = LX_CHARFORMAL;
CHARMAP(LX_NOEXPANDMARK) = LX_NOEXPAND;
if (EXTENSION) {
/*
** '$' is an identifier character under extensions.
*/
CHARMAP('$') = LX_ID;
CONTMAP('$') = LXC_ID;
}
for (ntop = p_defns->li_top; ntop < MAXLIST; ++ntop) {
p_dstr = p_defns->li_defns[ntop];
p_eq = Reuse_1;
while ((*p_eq = *p_dstr++) != 0) { /* copy the name to Reuse_1 */
if (CHARMAP(*p_eq) == LX_LEADBYTE) {
*++p_eq = *p_dstr++;
} else if (*p_eq == '=') { /* we're told what the value is */
break;
}
p_eq++;
}
if (*p_eq == '=') {
char *p_tmp;
char *last_space = NULL;
*p_eq = '\0'; /* null the = */
for (p_tmp = p_dstr; *p_tmp; p_tmp++) { /* find the end of it */
if (CHARMAP(*p_tmp) == LX_LEADBYTE) {
p_tmp++;
last_space = NULL;
} else if (isspace(*p_tmp)) {
if (last_space == NULL) {
last_space = p_tmp;
}
} else {
last_space = NULL;
}
}
if (last_space != NULL) {
*last_space = '\0';
}
Reuse_1_hash = local_c_hash(Reuse_1);
Reuse_1_length = strlen(Reuse_1) + 1;
if ( *p_dstr ) { /* non-empty string */
definstall(p_dstr, (strlen(p_dstr) + 2), FROM_COMMAND);
} else {
definstall((char *)0, 0, 0);
}
} else {
Reuse_1_hash = local_c_hash(Reuse_1);
Reuse_1_length = strlen(Reuse_1) + 1;
definstall("1\000", 3, FROM_COMMAND); /* value of string is 1 */
}
}
if ((OUTPUTFILE = fopen (p_outname, "w+")) == NULL) {
Msg_Temp = GET_MSG (1023);
SET_MSG (Msg_Text, Msg_Temp);
fatal (1023);
}
newinput(p_fname,MUST_OPEN);
}