home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Borland Programmer's Resource
/
Borland_Programmers_Resource_CD_1995.iso
/
utils
/
resc
/
input.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-18
|
35KB
|
1,044 lines
/*
*
* Input procedures.
*
*/
#include "resconv.h"
#include "extdef.h"
#include <stdio.h>
typedef struct SrcFile {
HANDLE fnum; /* file handle */
long size; /* file size */
long total_read; /* total bytes read from file */
uchar ptr buffer; /* input data buffer */
long bytes; /* # bytes in data buffer */
long bytes_read; /* # bytes read from buffer */
} SrcFile;
#define max_src_files 10
SrcFile srcTable [max_src_files]; /* source file table */
long src_entries; /* # entries in source file table */
SrcFile ptr srcFile; /* the current source file element */
typedef struct Token {
ushort token; /* token type */
long value; /* if numeric token */
uchar ptr string; /* if string, constant, or filename token */
} Token;
static Token token; /* the current token */
static Token putToken; /* the put back token */
static uchar putChar; /* the put back character */
extern ushort cLineCurrent; /* the current line number */
static uchar ptr pszComment = NULL; /* the current comment line. */
static ushort iComment = 0; /* current place in comment string. */
void debug_ptoken()
{
switch(token.token)
{
case tok_numeric:
printf( "Numeric Token (%d)\n", token.value);
break;
case tok_string:
printf( "Numeric Token (%s)\n", token.string);
break;
case tok_constant:
printf( "Constant Token (%d)\n", token.value);
break;
case tok_undefined:
printf( "Undef Token\n");
break;
case tok_keyword:
printf( "Keyword Token\n");
break;
case tok_filename:
printf( "File Name Token (%s)\n", token.string);
break;
case tok_comma:
printf( "COMMA Token\n");
break;
case tok_bitor:
printf( "BITOR Token\n");
break;
case tok_plus:
printf( "PLUS Token\n");
break;
case tok_pound_sign:
printf( "POUND Token\n");
break;
case tok_eof:
printf( "EOF Token\n");
break;
}
}
/**************************************************************************
* *
* READ_DATA *
* *
* This procedure is called to read some data from a file. *
* *
**************************************************************************/
static flag read_data (SrcFile ptr src)
{
ushort error;
DWORD read;
/* Read the data, and die if we get an error. */
src->bytes = MIN ((long) max_buffer_bytes, src->size - src->total_read);
error = ReadFile (src->fnum, src->buffer, src->bytes, &read, NULL);
if ((error == FALSE) || (ushort) src->bytes != read) {
printf ("I/O error %d while reading from data file.\n", GetLastError());
close_destination_file ();
terminate_input ();
exit(1);
}
/* Success is ours. */
src->bytes_read = 0L;
src->total_read += src->bytes;
return TRUE;
}
/***********************************************************************
* *
* PUT_CHAR *
* *
* This procedure puts a character back into the input stream. *
* *
***********************************************************************/
void put_char (uchar ch)
{
/* If we already have a put back character, there's a logic error. */
if (putChar)
report_error (err_full_put_char_buffer, 0, "put_char");
/* Save the character. */
putChar = ch;
}
/***********************************************************************
* *
* GET_CHAR *
* *
* This procedure gets the next character from the input stream. *
* *
***********************************************************************/
uchar get_char (void)
{
uchar ch; /* character */
/* If there is a put back character, return it. */
if (putChar) {
ch = putChar;
putChar = 0;
return ch;
}
/* Make sure we have a current source file element */
if (srcFile == NULL)
report_error (err_no_source_file, 0, "get_char");
/*
* While there are still entries in the source file table, try to
* get a character from a source file.
*/
while (src_entries > 0) {
/*
* See if there are more characters in the file buffer.
*/
if (srcFile->bytes > srcFile->bytes_read)
return (srcFile->buffer [srcFile->bytes_read++]);
/*
* If there are more bytes in the file to be read, read into the buffer.
*/
if (srcFile->size > srcFile->total_read) {
read_data (srcFile);
return (srcFile->buffer [srcFile->bytes_read++]);
}
/*
* We reached the end of the current source file, so delete it from
* the table and get the next entry.
*/
CloseHandle(srcFile->fnum);
--src_entries;
if (src_entries > 0)
srcFile = &srcTable [src_entries - 1];
else
srcFile = NULL;
}
/* Couldn't find anything to return so we must be at the EOF. */
return char_eof;
}
/***********************************************************************
* *
* ALPHA *
* *
* This procedure checks to see if a character is an alpha character. *
* *
***********************************************************************/
static flag alpha (uchar ch)
{
return (ch >= 'A' && ch <= 'Z'
||
ch >= 'a' && ch <= 'z');
}
/***********************************************************************
* *
* NUMERIC *
* *
* This procedure checks to see if a character is a numeric character.*
* *
***********************************************************************/
static flag numeric (uchar ch)
{
return (ch >= '0' && ch <= '9');
}
/***********************************************************************
* *
* WHITE_SPACE *
* *
* This procedure checks if a character is white space. *
* *
***********************************************************************/
static flag white_space (uchar ch)
{
/* Switch on the character and return the result. */
switch (ch) {
case char_cr:
case char_lf:
case char_space:
case char_tab:
return TRUE;
break;
case char_eof:
default:
return FALSE;
break;
}
return FALSE;
}
/***********************************************************************
* *
* SKIP_COMMENT *
* *
* This procedure skips comment text. *
* *
***********************************************************************/
static void skip_comment (void)
{
uchar ch, last_ch;
/* See if the next character is a '*'. If so, handle it.
====================================================== */
if ((ch = get_char ()) == char_star) {
/* Make sure we have a comment buffer.
=================================== */
if (pszComment == NULL)
pszComment = _fmalloc (max_comment_size);
/* Start filling in the comment buffer.
==================================== */
iComment = 0;
if (pszComment) {
pszComment[0] = char_slash;
pszComment[1] = char_star;
iComment = 2;
}
/* Loop until we see a '/'. */
forever {
while ((ch = get_char ()) != char_slash && ch != char_eof) {
last_ch = ch;
if (ch == char_cr)
cLineCurrent++;
if (pszComment)
pszComment[iComment++] = ch;
}
if (pszComment && ch != char_eof)
pszComment[iComment++] = ch;
/* If we reached the end of the file, there was an error. */
if (ch == char_eof) {
iComment = 0;
report_error (err_unexpected_eof, 0, "skip_comment");
}
/* If the last character was a '*', this is the end of
the comment. Otherwise, continue.
=================================================== */
if (last_ch == char_star) {
if (pszComment)
pszComment[iComment] = 0;
return;
}
last_ch = ch;
}
return; // should never execute this line?
}
/* Handle the two slash comment format.
==================================== */
else if (ch == char_slash) {
/* Make sure we have a comment buffer.
=================================== */
if (pszComment == NULL)
pszComment = _fmalloc (max_comment_size);
/* Start filling in the comment buffer.
==================================== */
iComment = 0;
if (pszComment != NULL) {
pszComment[0] = char_slash;
pszComment[1] = char_slash;
iComment = 2;
}
/* Skip to first character on next line. */
while ((ch = get_char ()) != char_eof) {
if (pszComment)
pszComment[iComment++] = ch;
if (ch == char_lf) {
if (pszComment) {
iComment -= 2; // Don't keep the cr-lf.
pszComment[iComment] = 0;
}
return;
}
}
/* If we reach here, end-of-file. Put eof back. */
put_char(char_eof);
return;
}
/* Otherwise, unexpected slash character.
====================================== */
else
report_error (err_unexpected_comment_char, 0, "skip_comment");
return;
}
/***********************************************************************
* *
* SKIP_WHITE_SPACE *
* *
* This procedure skips white space characters including comments. *
* *
***********************************************************************/
static void skip_white_space (void)
{
uchar ch;
/* Loop forever getting characters until a non-white space char is found. */
forever {
ch = get_char ();
if (ch == char_cr)
cLineCurrent++;
if (ch == char_slash)
skip_comment ();
else if (not white_space (ch) || ch == char_eof) {
put_char (ch);
return;
}
}
}
/***********************************************************************
* *
* LEX_STRING *
* *
* This procedure gets a token that is a string. *
* *
***********************************************************************/
static void lex_string (void)
{
uchar ptr buffer; /* string buffer */
ushort i; /* loop counter */
uchar ch; /* character */
/* Get a buffer large enough to hold the maximum number of chars. */
buffer = _fmalloc (max_string_size);
for (i = 0; i < max_string_size; i++) {
/*
* Get a character and exit now if the EOF was reached.
*/
ch = get_char ();
if (ch == char_eof)
report_error (err_unexpected_eof, 0, "lex_string");
/*
* If it's not the delimiter quote put the glob in the buffer.
*/
if (ch == char_cr)
cLineCurrent++;
if (ch != char_quote_double)
buffer [i] = ch;
/*
* Else it's the delimiter quote but if it's not followed by another,
* this must be the end of the string.
*/
else {
ch = get_char ();
if (ch != char_quote_double) {
put_char (ch);
break;
}
buffer [i] = ch;
}
}
/* Make sure the string isn't too long. */
if (i >= max_string_size)
report_error (err_string_too_long, 0, "lex_string");
/* Save the string information in the current token. */
buffer [i] = '\0';
token.token = tok_string;
token.string = buffer;
}
/***********************************************************************
* *
* LEX_KEYWORD *
* *
* This procedure checks is a token is a keyword. *
* *
***********************************************************************/
flag lex_keyword (uchar ptr buffer)
{
ushort tok_id; /* token identifier */
ushort i; /* loop counter */
typedef struct {
ushort id; /* numeric ID */
uchar *text; /* text ID */
} KeywordTable;
static KeywordTable keyword_table [] = {
tok_acceltable , "ACCELTABLE",
tok_alt , "ALT",
tok_begin , "BEGIN",
tok_bitmap , "BITMAP",
tok_bs_autocheckbox , "BS_AUTOCHECKBOX",
tok_bs_autoradiobutton , "BS_AUTORADIOBUTTON",
tok_bs_checkbox , "BS_CHECKBOX",
tok_bs_default , "BS_DEFAULT",
tok_bs_help , "BS_HELP",
tok_bs_nopointerfocus , "BS_NOPOINTERFOCUS",
tok_bs_pushbutton , "BS_PUSHBUTTON",
tok_bs_radiobutton , "BS_RADIOBUTTON",
tok_cbs_dropdown , "CBS_DROPDOWN",
tok_cbs_dropdownlist , "CBS_DROPDOWNLIST",
tok_cbs_simple , "CBS_SIMPLE",
tok_char , "CHAR",
tok_control , "CONTROL",
tok_dialog , "DIALOG",
tok_discardable , "DISCARDABLE",
tok_dlgtemplate , "DLGTEMPLATE",
tok_dt_bottom , "DT_BOTTOM",
tok_dt_center , "DT_CENTER",
tok_dt_left , "DT_LEFT",
tok_dt_mnemonic , "DT_MNEMONIC",
tok_dt_right , "DT_RIGHT",
tok_dt_top , "DT_TOP",
tok_dt_vcenter , "DT_VCENTER",
tok_dt_wordbreak , "DT_WORDBREAK",
tok_end , "END",
tok_es_autoscroll , "ES_AUTOSCROLL",
tok_es_center , "ES_CENTER",
tok_es_left , "ES_LEFT",
tok_es_margin , "ES_MARGIN",
tok_es_right , "ES_RIGHT",
tok_fcf_sysmenu , "FCF_SYSMENU",
tok_fcf_titlebar , "FCF_TITLEBAR",
tok_fixed , "FIXED",
tok_frame , "FRAME",
tok_fs_border , "FS_BORDER",
tok_fs_dlgborder , "FS_DLGBORDER",
tok_fs_mousealign , "FS_MOUSEALIGN",
tok_fs_nobytealign , "FS_NOBYTEALIGN",
tok_icon , "ICON",
tok_include , "INCLUDE",
tok_loadoncall , "LOADONCALL",
tok_ls_horzscroll , "LS_HORZSCROLL",
tok_ls_multiplesel , "LS_MULTIPLESEL",
tok_menu , "MENU",
tok_menuitem , "MENUITEM",
tok_mia_disabled , "MIA_DISABLED",
tok_mis_bitmap , "MIS_BITMAP",
tok_mis_break , "MIS_BREAK",
tok_mis_ownerdraw , "MIS_OWNERDRAW",
tok_mis_text , "MIS_TEXT",
tok_moveable , "MOVEABLE",
tok_pointer , "POINTER",
tok_preload , "PRELOAD",
tok_rcinclude , "RCINCLUDE",
tok_resource , "RESOURCE",
tok_sbs_horz , "SBS_HORZ",
tok_sbs_vert , "SBS_VERT",
tok_separator , "SEPARATOR",
tok_shift , "SHIFT",
tok_stringtable , "STRINGTABLE",
tok_ss_fgndframe , "SS_FGNDFRAME",
tok_ss_groupbox , "SS_GROUPBOX",
tok_ss_halftoneframe , "SS_HALFTONEFRAME",
tok_ss_text , "SS_TEXT",
tok_submenu , "SUBMENU",
tok_virtualkey , "VIRTUALKEY",
wc_button , "WC_BUTTON",
wc_combobox , "WC_COMBOBOX",
wc_entryfield , "WC_ENTRYFIELD",
wc_listbox , "WC_LISTBOX",
wc_scrollbar , "WC_SCROLLBAR",
wc_static , "WC_STATIC",
tok_ws_clipsiblings , "WS_CLIPSIBLINGS",
tok_ws_group , "WS_GROUP",
tok_ws_savebits , "WS_SAVEBITS",
tok_ws_tabstop , "WS_TABSTOP",
tok_ws_visible , "WS_VISIBLE",
tok_dt_halftone , "DT_HALFTONE",
tok_fcf_nobytealign , "FCF_NOBYTEALIGN",
tok_dlginclude , "DLGINCLUDE",
tok_ls_ownerdraw , "LS_OWNERDRAW",
wc_mle , "WC_MLE",
tok_mls_vscroll , "MLS_VSCROLL",
tok_mls_wordwrap , "MLS_WORDWRAP",
tok_helptable , "HELPTABLE",
tok_helpsubtable , "HELPSUBTABLE",
tok_mls_border , "MLS_BORDER",
tok_syscommand , "SYSCOMMAND",
tok_mis_syscommand , "MIS_SYSCOMMAND",
tok_mis_submenu , "MIS_SUBMENU",
tok_ss_icon , "SS_ICON",
tok_did_ok , "DID_OK",
tok_did_cancel , "DID_CANCEL",
tok_fs_icon , "FS_ICON",
tok_begin , "{",
tok_end , "}",
tok_mia_checked , "MIA_CHECKED",
tok_fcf_dlgborder , "FCF_DLGBORDER",
tok_mis_separator , "MIS_SEPARATOR",
tok_ltext , "LTEXT",
tok_rtext , "RTEXT",
tok_ctext , "CTEXT",
tok_radiobutton , "RADIOBUTTON",
tok_autoradiobutton , "AUTORADIOBUTTON",
tok_checkbox , "CHECKBOX",
tok_autocheckbox , "AUTOCHECKBOX",
tok_pushbutton , "PUSHBUTTON",
tok_defpushbutton , "DEFPUSHBUTTON",
tok_listbox , "LISTBOX",
tok_groupbox , "GROUPBOX",
tok_entryfield , "ENTRYFIELD",
tok_fcf_minbutton , "FCF_MINBUTTON",
tok_fcf_icon , "FCF_ICON",
tok_mis_breakseparator , "MIS_BREAKSEPARATOR",
tok_mis_buttonseparator , "MIS_BUTTONSEPARATOR",
0 , "",
};
/* Search the keyword table for a match. */
tok_id = 0;
for (i = 0; tok_id == 0 && keyword_table [i].id != 0; i++) {
if (equal_ignoring_case (buffer, keyword_table [i].text))
tok_id = keyword_table [i].id;
}
// Printf error message for unsupported items
if (tok_id == tok_mis_bitmap) {
printf(" BITMAP menu are not supported by RESCONV. \n\r Define them as text menu and then use Windows ModifyMenu in your program\n\r");
}
/* Update the current token structure and return. */
if (tok_id == 0) {
return FALSE;
}
else {
token.token = tok_id;
return (TRUE);
}
}
/***********************************************************************
* *
* LEX_ALPHA *
* *
* This procedure gets a token that starts with an alpha character. *
* *
***********************************************************************/
static void lex_alpha (uchar ch)
{
uchar ptr buffer; /* string buffer */
ushort i; /* loop counter */
/* Fill the buffer with the alpha/numeric characters. */
buffer = _fmalloc (max_identifier_size + 1);
buffer [0] = ch;
for (i = 1; i <= max_identifier_size; i++) {
ch = get_char ();
if (white_space (ch) || ch == char_comma || ch == char_pipe) {
put_char (ch);
break;
}
buffer [i] = ch;
}
/* See if the identifier is longer than allowable. */
if (i > max_identifier_size)
report_error (err_identifier_too_long, 0, "lex_alpha");
/* See if this is a keyword. */
buffer [i] = '\0';
if (lex_keyword (buffer)) {
_ffree (buffer);
return;
}
/* Save the string as a constant. */
token.string = buffer;
token.token = tok_constant;
}
/***********************************************************************
* *
* LEX_NUMERIC *
* *
* This procedure gets a token that starts with a numeric character. *
* *
***********************************************************************/
static void lex_numeric (uchar ch, flag sign)
{
uchar buffer [40]; /* value buffer */
uchar ptr sp; /* string pointer */
long value; /* numeric value */
ushort i; /* loop counter */
/* Build a buffer of characters until a non-numeric character is found. */
sp = buffer;
if (sign)
*sp++ = '-';
*sp++ = ch;
for (i = 0; i < ucharsizeof (buffer); i++) {
if (!numeric (ch = get_char ())) {
put_char (ch);
break;
}
*sp++ = ch;
}
/* Make sure the number isn't too many characters. */
if (i >= ucharsizeof (buffer))
report_error (err_value_too_big, 0, "lex_numeric");
/* First check to see if this is an integer. */
*sp = '\0';
value = atol (buffer);
token.token = tok_numeric;
token.value = value;
}
/***********************************************************************
* *
* LEX_SPECIAL *
* *
* This procedure gets a token that starts with a special character. *
* *
***********************************************************************/
static void lex_special (uchar ch)
{
ushort tok;
/* Switch on the character to determine the token type. */
switch (ch) {
case char_quote_double:
lex_string ();
return;
break;
case char_minus:
if (numeric (ch = get_char ()))
lex_numeric (ch, TRUE);
else
report_error (err_invalid_syntax, 0, "lex_special");
return;
break;
case char_plus:
tok = tok_plus;
break;
case char_comma:
tok = tok_comma;
break;
case char_pipe:
tok = tok_bitor;
break;
case char_bracket_begin:
tok = tok_begin;
break;
case char_bracket_end:
tok = tok_end;
break;
case char_less_than:
case char_back_slash:
case char_dot:
/*
* This must be a file name.
*/
lex_alpha (ch);
return;
break;
case char_pound_sign:
tok = tok_pound_sign;
break;
case char_eof:
tok = tok_eof;
break;
default:
report_error (err_invalid_character, 0, "lex_special");
return;
break;
}
/* Update the current token structure and return. */
token.token = tok;
}
/***********************************************************************
* *
* GET_TOKEN *
* *
* This procedure gets the next token from the input string. *
* *
***********************************************************************/
ushort get_token (void)
{
uchar ch; /* a character */
uchar buffer [max_identifier_size + 1];
ushort index;
/* If a token has been put back, just get that one.
================================================ */
if (putToken.token != tok_undefined) {
token = putToken;
putToken.token = tok_undefined;
if (is_debug_on)
debug_ptoken();
return token.token;
}
/* Skip any white space and clean up the current token.
==================================================== */
skip_white_space ();
if (token.string)
_ffree (token.string);
token.token = 0;
token.value = 0L;
token.string = NULL;
/* Get a character and see if it's alphabetic, numeric, or special.
It's not a cr, which would have been eaten in skip_white_space.
================================================================ */
forever {
ch = get_char ();
if (alpha (ch))
lex_alpha (ch);
else if (numeric (ch))
lex_numeric (ch, FALSE);
else
lex_special (ch);
/* Return the token type, unless it's a pound sign.
================================================ */
if (token.token != tok_pound_sign) {
if (is_debug_on)
debug_ptoken();
return token.token;
}
/* If it is a pound sign, see if it is an include token.
===================================================== */
index = 0;
while ((ch = get_char()) && !white_space (ch) && index < max_identifier_size)
buffer [index++] = ch;
if (index >= max_identifier_size)
report_error (err_string_too_long, 0, "get_token");
buffer [index] = '\0';
put_char (ch);
if (equal_ignoring_case (buffer, "include")) {
token.token = tok_include;
if (is_debug_on)
debug_ptoken();
return token.token;
}
output_control_line (buffer);
skip_white_space ();
}
}
/***********************************************************************
* *
* PUT_TOKEN *
* *
* This procedure puts a token into the pending token buffer. *
* *
***********************************************************************/
void put_token (void)
{
/* If there is currently a put back token, there's a logic error. */
if (putToken.token != tok_undefined)
report_error (err_full_put_token_buffer, 0, "put_token");
/* Save the current token in the put back token structure. */
putToken = token;
}
/***********************************************************************
* *
* CURRENT_TOKEN_STRING *
* *
* This procedure returns the current token string. *
* *
***********************************************************************/
void ptr current_token_string (void)
{
return (void ptr)token.string;
}
/***********************************************************************
* *
* CURRENT_TOKEN_VALUE *
* *
* This procedure returns the current token value. *
* *
***********************************************************************/
long current_token_value (void)
{
return token.value;
}
/**************************************************************************
* *
* OPEN_SOURCE_FILE *
* *
* This procedure opens a source file and adds an entry to the Source *
* File table. *
* *
**************************************************************************/
flag open_source_file (uchar ptr src_fname)
{
HANDLE fnum; /* file handle */
/* Open the source file. */
fnum = CreateFile(src_fname, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fnum == NULL)
{
printf ("Unable to open: %s, error %ld\n", src_fname, GetLastError());
close_destination_file ();
terminate_input ();
exit(1);
}
/* Initialize a source file structure and insert the entry in the table. */
srcFile = &srcTable [src_entries];
srcFile->fnum = fnum;
srcFile->size = GetFileSize(fnum, NULL);
srcFile->total_read = 0L;
srcFile->buffer = _fmalloc (max_buffer_bytes);
src_entries++;
/* Read some data into the data buffer. */
return (read_data (srcFile));
}
/**************************************************************************
* *
* INITIALIZE_INPUT *
* *
* This procedure initializes the input system. *
* *
**************************************************************************/
void initialize_input (void)
{
src_entries = 0;
srcFile = NULL;
}
/**************************************************************************
* *
* TERMINATE_INPUT *
* *
* This procedure terminates the input system. *
* *
**************************************************************************/
void terminate_input (void)
{
SrcFile ptr src; /* source file element */
long i; /* loop counter */
for (i = 0L; i < src_entries; i++) {
src = &srcTable [i];
_ffree (src->buffer);
}
}
/***********************************************************************
* *
* GET_COMMENT_STRING *
* *
* This procedure returns the current comment string. *
* *
***********************************************************************/
void ptr get_comment_string (void)
{
if (pszComment == NULL || iComment == 0)
return NULL;
if (pszComment[0] == char_space)
return NULL;
return (void ptr) pszComment;
}
/***********************************************************************
* *
* CLEAR_COMMENT_STRING *
* *
* This procedure clears the comment string. *
* *
***********************************************************************/
void clear_comment_string (void)
{
if (pszComment != NULL)
pszComment[0] = 0;
iComment = 0;
}