/*
 *
 *  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;
}

