home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / utils / resc / input.c < prev    next >
C/C++ Source or Header  |  1995-05-18  |  35KB  |  1,044 lines

  1. /*
  2.  *
  3.  *  Input procedures.
  4.  *
  5.  */
  6.  
  7. #include "resconv.h"
  8. #include "extdef.h"
  9.  
  10. #include <stdio.h>
  11.  
  12.  
  13. typedef struct SrcFile {
  14.     HANDLE      fnum;                   /* file handle */
  15.     long        size;                   /* file size */
  16.     long        total_read;             /* total bytes read from file */
  17.     uchar   ptr buffer;                 /* input data buffer */
  18.     long        bytes;                  /* # bytes in data buffer */
  19.     long        bytes_read;             /* # bytes read from buffer */
  20.     } SrcFile;
  21.  
  22. #define max_src_files        10
  23.  
  24. SrcFile     srcTable [max_src_files];    /* source file table */
  25. long        src_entries;                /* # entries in source file table */
  26. SrcFile ptr srcFile;                    /* the current source file element */
  27.  
  28.  
  29. typedef struct Token {
  30.     ushort      token;                  /* token type */
  31.     long        value;                  /* if numeric token */
  32.     uchar   ptr string;                 /* if string, constant, or filename token */
  33.     } Token;
  34.  
  35. static Token   token;                   /* the current token */
  36. static Token   putToken;                /* the put back token */
  37. static uchar   putChar;                 /* the put back character */
  38. extern ushort  cLineCurrent;        /* the current line number */
  39.  
  40. static uchar ptr pszComment = NULL;    /* the current comment line. */
  41. static ushort    iComment = 0;         /* current place in comment string. */
  42.  
  43. void debug_ptoken()
  44. {
  45.     switch(token.token)
  46.     {
  47.     case tok_numeric:
  48.         printf( "Numeric Token (%d)\n", token.value);
  49.         break;
  50.     case tok_string:
  51.         printf( "Numeric Token (%s)\n", token.string);
  52.         break;
  53.     case tok_constant:
  54.         printf( "Constant Token (%d)\n", token.value);
  55.         break;
  56.     case tok_undefined:
  57.         printf( "Undef Token\n");
  58.         break;
  59.     case tok_keyword:
  60.         printf( "Keyword Token\n");
  61.         break;
  62.     case tok_filename:
  63.         printf( "File Name Token (%s)\n", token.string);
  64.         break;
  65.     case tok_comma:
  66.         printf( "COMMA Token\n");
  67.         break;
  68.     case tok_bitor:
  69.         printf( "BITOR Token\n");
  70.         break;
  71.     case tok_plus:
  72.         printf( "PLUS Token\n");
  73.         break;
  74.     case tok_pound_sign:
  75.         printf( "POUND Token\n");
  76.         break;
  77.     case tok_eof:
  78.         printf( "EOF Token\n");
  79.         break;
  80.  
  81.  
  82.     }
  83. }
  84.  
  85. /**************************************************************************
  86.  *                                                                        *
  87.  *  READ_DATA                                                             *
  88.  *                                                                        *
  89.  *  This procedure is called to read some data from a file.               *
  90.  *                                                                        *
  91.  **************************************************************************/
  92.  
  93. static flag read_data (SrcFile ptr src)
  94. {
  95. ushort error;
  96. DWORD read;
  97.  
  98. /*  Read the data, and die if we get an error. */
  99.  
  100. src->bytes = MIN ((long) max_buffer_bytes, src->size - src->total_read);
  101.  
  102. error = ReadFile (src->fnum, src->buffer, src->bytes, &read, NULL);
  103. if ((error == FALSE) || (ushort) src->bytes != read) {
  104.     printf ("I/O error %d while reading from data file.\n", GetLastError());
  105.     close_destination_file ();
  106.     terminate_input ();
  107.     exit(1);
  108.     }
  109.  
  110. /*  Success is ours. */
  111.  
  112. src->bytes_read = 0L;
  113. src->total_read += src->bytes;
  114. return TRUE;
  115. }
  116.  
  117.  
  118. /***********************************************************************
  119.  *                                                                     *
  120.  *  PUT_CHAR                                                           *
  121.  *                                                                     *
  122.  *  This procedure puts a character back into the input stream.        *
  123.  *                                                                     *
  124.  ***********************************************************************/
  125.  
  126. void put_char (uchar ch)
  127. {
  128.  
  129. /*  If we already have a put back character, there's a logic error. */
  130.  
  131. if (putChar)
  132.     report_error (err_full_put_char_buffer, 0, "put_char");
  133.  
  134. /*  Save the character. */
  135.  
  136. putChar = ch;
  137. }
  138.  
  139.  
  140. /***********************************************************************
  141.  *                                                                     *
  142.  *  GET_CHAR                                                           *
  143.  *                                                                     *
  144.  *  This procedure gets the next character from the input stream.      *
  145.  *                                                                     *
  146.  ***********************************************************************/
  147.  
  148. uchar get_char (void)
  149. {
  150. uchar   ch;                                 /* character */
  151.  
  152. /*  If there is a put back character, return it. */
  153.  
  154. if (putChar) {
  155.     ch = putChar;
  156.     putChar = 0;
  157.     return ch;
  158.     }
  159.  
  160. /*  Make sure we have a current source file element */
  161.  
  162. if (srcFile == NULL)
  163.     report_error (err_no_source_file, 0, "get_char");
  164.  
  165. /*
  166.  *  While there are still entries in the source file table, try to
  167.  *  get a character from a source file.
  168.  */
  169.  
  170. while (src_entries > 0) {
  171.     /*
  172.      *  See if there are more characters in the file buffer.
  173.      */
  174.     if (srcFile->bytes > srcFile->bytes_read)
  175.         return (srcFile->buffer [srcFile->bytes_read++]);
  176.     /*
  177.      *  If there are more bytes in the file to be read, read into the buffer.
  178.      */
  179.     if (srcFile->size > srcFile->total_read) {
  180.         read_data (srcFile);
  181.         return (srcFile->buffer [srcFile->bytes_read++]);
  182.         }
  183.     /*
  184.      *  We reached the end of the current source file, so delete it from
  185.      *  the table and get the next entry.
  186.      */
  187.     CloseHandle(srcFile->fnum);
  188.     --src_entries;
  189.     if (src_entries > 0)
  190.     srcFile = &srcTable [src_entries - 1];
  191.     else
  192.     srcFile = NULL;
  193.     }
  194.  
  195. /*  Couldn't find anything to return so we must be at the EOF. */
  196.  
  197. return char_eof;
  198. }
  199.  
  200.  
  201. /***********************************************************************
  202.  *                                                                     *
  203.  *  ALPHA                                                              *
  204.  *                                                                     *
  205.  *  This procedure checks to see if a character is an alpha character. *
  206.  *                                                                     *
  207.  ***********************************************************************/
  208.  
  209. static flag alpha (uchar ch)
  210. {
  211. return (ch >= 'A' && ch <= 'Z'
  212.         ||
  213.         ch >= 'a' && ch <= 'z');
  214. }
  215.  
  216.  
  217. /***********************************************************************
  218.  *                                                                     *
  219.  *  NUMERIC                                                            *
  220.  *                                                                     *
  221.  *  This procedure checks to see if a character is a numeric character.*
  222.  *                                                                     *
  223.  ***********************************************************************/
  224.  
  225. static flag numeric (uchar ch)
  226. {
  227. return (ch >= '0' && ch <= '9');
  228. }
  229.  
  230.  
  231. /***********************************************************************
  232.  *                                                                     *
  233.  *  WHITE_SPACE                                                        *
  234.  *                                                                     *
  235.  *  This procedure checks if a character is white space.               *
  236.  *                                                                     *
  237.  ***********************************************************************/
  238.  
  239. static flag white_space (uchar ch)
  240. {
  241.  
  242. /*  Switch on the character and return the result. */
  243.  
  244. switch (ch) {
  245.     case char_cr:
  246.     case char_lf:
  247.     case char_space:
  248.     case char_tab:
  249.         return TRUE;
  250.         break;
  251.  
  252.     case char_eof:
  253.     default:
  254.         return FALSE;
  255.         break;
  256.     }
  257.  
  258. return FALSE;
  259. }
  260.  
  261.  
  262. /***********************************************************************
  263.  *                                                                     *
  264.  *  SKIP_COMMENT                                                       *
  265.  *                                                                     *
  266.  *  This procedure skips comment text.                                 *
  267.  *                                                                     *
  268.  ***********************************************************************/
  269.  
  270. static void skip_comment (void)
  271. {
  272.     uchar   ch, last_ch;
  273.  
  274. /*  See if the next character is a '*'.  If so, handle it.
  275.     ======================================================  */
  276.  
  277.     if ((ch = get_char ()) == char_star) {
  278.  
  279. /*      Make sure we have a comment buffer.
  280.         =================================== */
  281.  
  282.         if (pszComment == NULL)
  283.             pszComment = _fmalloc (max_comment_size);
  284.         
  285. /*      Start filling in the comment buffer.
  286.         ==================================== */
  287.  
  288.         iComment = 0;
  289.         if (pszComment) {
  290.             pszComment[0] = char_slash;
  291.             pszComment[1] = char_star;
  292.             iComment = 2;
  293.         }
  294.  
  295. /*      Loop until we see a '/'. */
  296.  
  297.         forever {
  298.             while ((ch = get_char ()) != char_slash && ch != char_eof) {
  299.                 last_ch = ch;
  300.                 if (ch == char_cr)
  301.                     cLineCurrent++;
  302.                 if (pszComment)
  303.                     pszComment[iComment++] = ch;
  304.             }
  305.             if (pszComment && ch != char_eof)
  306.                 pszComment[iComment++] = ch;
  307.  
  308. /*          If we reached the end of the file, there was an error.  */
  309.  
  310.             if (ch == char_eof) {
  311.                 iComment = 0;
  312.                 report_error (err_unexpected_eof, 0, "skip_comment");
  313.             }
  314.  
  315. /*          If the last character was a '*', this is the end of
  316.             the comment.  Otherwise, continue.
  317.             ===================================================  */
  318.  
  319.             if (last_ch == char_star) {
  320.                 if (pszComment)
  321.                     pszComment[iComment] = 0;
  322.                 return;
  323.             }
  324.             last_ch = ch;
  325.         }
  326.         return;  // should never execute this line?
  327.     }
  328.  
  329. /*  Handle the two slash comment format.
  330.     ====================================  */
  331.  
  332.     else if (ch == char_slash) {
  333.  
  334. /*      Make sure we have a comment buffer.
  335.         =================================== */
  336.  
  337.         if (pszComment == NULL)
  338.             pszComment = _fmalloc (max_comment_size);
  339.         
  340. /*      Start filling in the comment buffer.
  341.         ==================================== */
  342.  
  343.         iComment = 0;
  344.         if (pszComment != NULL) {
  345.             pszComment[0] = char_slash;
  346.             pszComment[1] = char_slash;
  347.             iComment = 2;
  348.         }
  349.  
  350. /*      Skip to first character on next line.  */
  351.  
  352.         while ((ch = get_char ()) != char_eof) {
  353.             if (pszComment)
  354.                 pszComment[iComment++] = ch;
  355.             if (ch == char_lf) {
  356.                 if (pszComment) {
  357.                     iComment -= 2;               // Don't keep the cr-lf.
  358.                     pszComment[iComment] = 0;  
  359.                 }
  360.                 return;
  361.             }
  362.         }
  363.  
  364. /*      If we reach here, end-of-file.  Put eof back.  */
  365.  
  366.         put_char(char_eof);
  367.         return;
  368.     }
  369.  
  370. /*  Otherwise, unexpected slash character.
  371.     ======================================  */
  372.  
  373.     else
  374.         report_error (err_unexpected_comment_char, 0, "skip_comment");
  375.     return;
  376. }
  377.  
  378.  
  379. /***********************************************************************
  380.  *                                                                     *
  381.  *  SKIP_WHITE_SPACE                                                   *
  382.  *                                                                     *
  383.  *  This procedure skips white space characters including comments.    *
  384.  *                                                                     *
  385.  ***********************************************************************/
  386.  
  387. static void skip_white_space (void)
  388. {
  389. uchar   ch;
  390.  
  391. /*  Loop forever getting characters until a non-white space char is found. */
  392.  
  393. forever {
  394.     ch = get_char ();
  395.     if (ch == char_cr)
  396.     cLineCurrent++;
  397.     if (ch == char_slash)
  398.         skip_comment ();
  399.     else if (not white_space (ch) || ch == char_eof) {
  400.         put_char (ch);
  401.         return;
  402.         }
  403.     }
  404. }
  405.  
  406.  
  407. /***********************************************************************
  408.  *                                                                     *
  409.  *  LEX_STRING                                                         *
  410.  *                                                                     *
  411.  *  This procedure gets a token that is a string.                      *
  412.  *                                                                     *
  413.  ***********************************************************************/
  414.  
  415. static void lex_string (void)
  416. {
  417. uchar   ptr buffer;                         /* string buffer */
  418. ushort      i;                              /* loop counter */
  419. uchar       ch;                             /* character */
  420.  
  421. /*  Get a buffer large enough to hold the maximum number of chars. */
  422.  
  423. buffer = _fmalloc (max_string_size);
  424.  
  425. for (i = 0; i < max_string_size; i++) {
  426.     /*
  427.      *  Get a character and exit now if the EOF was reached.
  428.      */
  429.     ch = get_char ();
  430.     if (ch == char_eof)
  431.         report_error (err_unexpected_eof, 0, "lex_string");
  432.     /*
  433.      *  If it's not the delimiter quote put the glob in the buffer.
  434.      */
  435.     if (ch == char_cr)
  436.     cLineCurrent++;
  437.     if (ch != char_quote_double)
  438.         buffer [i] = ch;
  439.     /*
  440.      *  Else it's the delimiter quote but if it's not followed by another,
  441.      *  this must be the end of the string.
  442.      */
  443.     else {
  444.         ch = get_char ();
  445.         if (ch != char_quote_double) {
  446.             put_char (ch);
  447.             break;
  448.             }
  449.         buffer [i] = ch;
  450.         }
  451.     }
  452.  
  453. /*  Make sure the string isn't too long. */
  454.  
  455. if (i >= max_string_size)
  456.     report_error (err_string_too_long, 0, "lex_string");
  457.  
  458. /*  Save the string information in the current token. */
  459.  
  460. buffer [i] = '\0';
  461. token.token  = tok_string;
  462. token.string = buffer;
  463. }
  464.  
  465.  
  466. /***********************************************************************
  467.  *                                                                     *
  468.  *  LEX_KEYWORD                                                        *
  469.  *                                                                     *
  470.  *  This procedure checks is a token is a keyword.                     *
  471.  *                                                                     *
  472.  ***********************************************************************/
  473.  
  474. flag lex_keyword (uchar ptr buffer)
  475. {
  476. ushort  tok_id;                             /* token identifier */
  477. ushort  i;                                  /* loop counter */
  478.  
  479. typedef struct {
  480.     ushort  id;                              /* numeric ID */
  481.     uchar  *text;                            /* text ID */
  482.     } KeywordTable;
  483.  
  484. static KeywordTable keyword_table [] = {
  485.     tok_acceltable              , "ACCELTABLE",
  486.     tok_alt                     , "ALT",
  487.     tok_begin                   , "BEGIN",
  488.     tok_bitmap                  , "BITMAP",
  489.     tok_bs_autocheckbox         , "BS_AUTOCHECKBOX",
  490.     tok_bs_autoradiobutton      , "BS_AUTORADIOBUTTON",
  491.     tok_bs_checkbox             , "BS_CHECKBOX",
  492.     tok_bs_default              , "BS_DEFAULT",
  493.     tok_bs_help                 , "BS_HELP",
  494.     tok_bs_nopointerfocus       , "BS_NOPOINTERFOCUS",
  495.     tok_bs_pushbutton           , "BS_PUSHBUTTON",
  496.     tok_bs_radiobutton          , "BS_RADIOBUTTON",
  497.     tok_cbs_dropdown            , "CBS_DROPDOWN",
  498.     tok_cbs_dropdownlist        , "CBS_DROPDOWNLIST",
  499.     tok_cbs_simple              , "CBS_SIMPLE",
  500.     tok_char                    , "CHAR",
  501.     tok_control                 , "CONTROL",
  502.     tok_dialog                  , "DIALOG",
  503.     tok_discardable             , "DISCARDABLE",
  504.     tok_dlgtemplate             , "DLGTEMPLATE",
  505.     tok_dt_bottom               , "DT_BOTTOM",
  506.     tok_dt_center               , "DT_CENTER",
  507.     tok_dt_left                 , "DT_LEFT",
  508.     tok_dt_mnemonic             , "DT_MNEMONIC",
  509.     tok_dt_right                , "DT_RIGHT",
  510.     tok_dt_top                  , "DT_TOP",
  511.     tok_dt_vcenter              , "DT_VCENTER",
  512.     tok_dt_wordbreak            , "DT_WORDBREAK",
  513.     tok_end                     , "END",
  514.     tok_es_autoscroll           , "ES_AUTOSCROLL",
  515.     tok_es_center               , "ES_CENTER",
  516.     tok_es_left                 , "ES_LEFT",
  517.     tok_es_margin               , "ES_MARGIN",
  518.     tok_es_right                , "ES_RIGHT",
  519.     tok_fcf_sysmenu             , "FCF_SYSMENU",
  520.     tok_fcf_titlebar            , "FCF_TITLEBAR",
  521.     tok_fixed                   , "FIXED",
  522.     tok_frame                   , "FRAME",
  523.     tok_fs_border               , "FS_BORDER",
  524.     tok_fs_dlgborder            , "FS_DLGBORDER",
  525.     tok_fs_mousealign           , "FS_MOUSEALIGN",
  526.     tok_fs_nobytealign          , "FS_NOBYTEALIGN",
  527.     tok_icon                    , "ICON",
  528.     tok_include                 , "INCLUDE",
  529.     tok_loadoncall              , "LOADONCALL",
  530.     tok_ls_horzscroll           , "LS_HORZSCROLL",
  531.     tok_ls_multiplesel          , "LS_MULTIPLESEL",
  532.     tok_menu                    , "MENU",
  533.     tok_menuitem                , "MENUITEM",
  534.     tok_mia_disabled            , "MIA_DISABLED",
  535.     tok_mis_bitmap              , "MIS_BITMAP",
  536.     tok_mis_break               , "MIS_BREAK",
  537.     tok_mis_ownerdraw           , "MIS_OWNERDRAW",
  538.     tok_mis_text                , "MIS_TEXT",
  539.     tok_moveable                , "MOVEABLE",
  540.     tok_pointer                 , "POINTER",
  541.     tok_preload                 , "PRELOAD",
  542.     tok_rcinclude               , "RCINCLUDE",
  543.     tok_resource                , "RESOURCE",
  544.     tok_sbs_horz                , "SBS_HORZ",
  545.     tok_sbs_vert                , "SBS_VERT",
  546.     tok_separator               , "SEPARATOR",
  547.     tok_shift                   , "SHIFT",
  548.     tok_stringtable             , "STRINGTABLE",
  549.     tok_ss_fgndframe            , "SS_FGNDFRAME",
  550.     tok_ss_groupbox             , "SS_GROUPBOX",
  551.     tok_ss_halftoneframe        , "SS_HALFTONEFRAME",
  552.     tok_ss_text                 , "SS_TEXT",
  553.     tok_submenu                 , "SUBMENU",
  554.     tok_virtualkey              , "VIRTUALKEY",
  555.     wc_button                   , "WC_BUTTON",
  556.     wc_combobox                 , "WC_COMBOBOX",
  557.     wc_entryfield               , "WC_ENTRYFIELD",
  558.     wc_listbox                  , "WC_LISTBOX",
  559.     wc_scrollbar                , "WC_SCROLLBAR",
  560.     wc_static                   , "WC_STATIC",
  561.     tok_ws_clipsiblings         , "WS_CLIPSIBLINGS",
  562.     tok_ws_group                , "WS_GROUP",
  563.     tok_ws_savebits             , "WS_SAVEBITS",
  564.     tok_ws_tabstop              , "WS_TABSTOP",
  565.     tok_ws_visible              , "WS_VISIBLE",
  566.     tok_dt_halftone        , "DT_HALFTONE",
  567.     tok_fcf_nobytealign     , "FCF_NOBYTEALIGN",
  568.     tok_dlginclude        , "DLGINCLUDE",
  569.     tok_ls_ownerdraw        , "LS_OWNERDRAW",
  570.     wc_mle            , "WC_MLE",
  571.     tok_mls_vscroll         , "MLS_VSCROLL",
  572.     tok_mls_wordwrap         , "MLS_WORDWRAP",
  573.     tok_helptable        , "HELPTABLE",
  574.     tok_helpsubtable        , "HELPSUBTABLE",
  575.     tok_mls_border        , "MLS_BORDER",
  576.     tok_syscommand        , "SYSCOMMAND",
  577.     tok_mis_syscommand        , "MIS_SYSCOMMAND",
  578.     tok_mis_submenu        , "MIS_SUBMENU",
  579.     tok_ss_icon         , "SS_ICON",
  580.     tok_did_ok            , "DID_OK",
  581.     tok_did_cancel        , "DID_CANCEL",
  582.     tok_fs_icon         , "FS_ICON",
  583.     tok_begin            , "{",
  584.     tok_end            , "}",
  585.     tok_mia_checked        , "MIA_CHECKED",
  586.     tok_fcf_dlgborder        , "FCF_DLGBORDER",
  587.     tok_mis_separator        , "MIS_SEPARATOR",
  588.     tok_ltext            , "LTEXT",
  589.     tok_rtext            , "RTEXT",
  590.     tok_ctext            , "CTEXT",
  591.     tok_radiobutton        , "RADIOBUTTON",
  592.     tok_autoradiobutton     , "AUTORADIOBUTTON",
  593.     tok_checkbox        , "CHECKBOX",
  594.     tok_autocheckbox        , "AUTOCHECKBOX",
  595.     tok_pushbutton        , "PUSHBUTTON",
  596.     tok_defpushbutton        , "DEFPUSHBUTTON",
  597.     tok_listbox         , "LISTBOX",
  598.     tok_groupbox        , "GROUPBOX",
  599.     tok_entryfield        , "ENTRYFIELD",
  600.     tok_fcf_minbutton        , "FCF_MINBUTTON",
  601.     tok_fcf_icon        , "FCF_ICON",
  602.     tok_mis_breakseparator    , "MIS_BREAKSEPARATOR",
  603.     tok_mis_buttonseparator    , "MIS_BUTTONSEPARATOR",
  604.     0                , "",
  605.     };
  606.  
  607. /*  Search the keyword table for a match. */
  608.  
  609. tok_id = 0;
  610. for (i = 0; tok_id == 0 && keyword_table [i].id != 0; i++) {
  611.     if (equal_ignoring_case (buffer, keyword_table [i].text))
  612.         tok_id = keyword_table [i].id;
  613.     }
  614.  
  615. // Printf error message for unsupported items
  616. if (tok_id == tok_mis_bitmap) {
  617.    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");
  618. }
  619.  
  620.  
  621.  
  622. /*  Update the current token structure and return. */
  623.  
  624. if (tok_id == 0) {
  625.     return FALSE;
  626. }
  627. else {
  628.     token.token = tok_id;
  629.     return (TRUE);
  630. }
  631.  
  632. }
  633.  
  634.  
  635. /***********************************************************************
  636.  *                                                                     *
  637.  *  LEX_ALPHA                                                          *
  638.  *                                                                     *
  639.  *  This procedure gets a token that starts with an alpha character.   *
  640.  *                                                                     *
  641.  ***********************************************************************/
  642.  
  643. static void lex_alpha (uchar ch)
  644. {
  645. uchar   ptr buffer;                         /* string buffer */
  646. ushort      i;                              /* loop counter */
  647.  
  648. /*  Fill the buffer with the alpha/numeric characters. */
  649.  
  650. buffer = _fmalloc (max_identifier_size + 1);
  651. buffer [0] = ch;
  652.  
  653. for (i = 1; i <= max_identifier_size; i++) {
  654.     ch = get_char ();
  655.     if (white_space (ch) || ch == char_comma || ch == char_pipe) {
  656.         put_char (ch);
  657.         break;
  658.         }
  659.     buffer [i] = ch;
  660.     }
  661.  
  662. /*  See if the identifier is longer than allowable. */
  663.  
  664. if (i > max_identifier_size)
  665.     report_error (err_identifier_too_long, 0, "lex_alpha");
  666.  
  667. /*  See if this is a keyword. */
  668.  
  669. buffer [i] = '\0';
  670. if (lex_keyword (buffer)) {
  671.     _ffree (buffer);
  672.     return;
  673.     }
  674.  
  675. /*  Save the string as a constant. */
  676.  
  677. token.string = buffer;
  678. token.token  = tok_constant;
  679. }
  680.  
  681.  
  682. /***********************************************************************
  683.  *                                                                     *
  684.  *  LEX_NUMERIC                                                        *
  685.  *                                                                     *
  686.  *  This procedure gets a token that starts with a numeric character.  *
  687.  *                                                                     *
  688.  ***********************************************************************/
  689.  
  690. static void lex_numeric (uchar ch, flag sign)
  691. {
  692. uchar       buffer [40];                    /* value buffer */
  693. uchar   ptr sp;                             /* string pointer */
  694. long        value;                          /* numeric value */
  695. ushort      i;                              /* loop counter */
  696.  
  697. /*  Build a buffer of characters until a non-numeric character is found. */
  698.  
  699. sp = buffer;
  700. if (sign)
  701.     *sp++ = '-';
  702. *sp++ = ch;
  703. for (i = 0; i < ucharsizeof (buffer); i++) {
  704.     if (!numeric (ch = get_char ())) {
  705.         put_char (ch);
  706.         break;
  707.         }
  708.     *sp++ = ch;
  709.     }
  710.  
  711. /*  Make sure the number isn't too many characters. */
  712.  
  713. if (i >= ucharsizeof (buffer))
  714.     report_error (err_value_too_big, 0, "lex_numeric");
  715.  
  716. /*  First check to see if this is an integer. */
  717.  
  718. *sp = '\0';
  719. value = atol (buffer);
  720. token.token = tok_numeric;
  721. token.value = value;
  722. }
  723.  
  724.  
  725. /***********************************************************************
  726.  *                                                                     *
  727.  *  LEX_SPECIAL                                                        *
  728.  *                                                                     *
  729.  *  This procedure gets a token that starts with a special character.  *
  730.  *                                                                     *
  731.  ***********************************************************************/
  732.  
  733. static void lex_special (uchar ch)
  734. {
  735. ushort      tok;
  736.  
  737. /*  Switch on the character to determine the token type. */
  738.  
  739. switch (ch) {
  740.     case char_quote_double:
  741.         lex_string ();
  742.         return;
  743.         break;
  744.  
  745.     case char_minus:
  746.         if (numeric (ch = get_char ()))
  747.             lex_numeric (ch, TRUE);
  748.         else
  749.             report_error (err_invalid_syntax, 0, "lex_special");
  750.         return;
  751.         break;
  752.  
  753.     case char_plus:
  754.         tok = tok_plus;
  755.         break;
  756.  
  757.     case char_comma:
  758.         tok = tok_comma;
  759.         break;
  760.  
  761.     case char_pipe:
  762.         tok = tok_bitor;
  763.         break;
  764.  
  765.     case char_bracket_begin:
  766.         tok = tok_begin;
  767.         break;
  768.  
  769.     case char_bracket_end:
  770.         tok = tok_end;
  771.         break;
  772.  
  773.     case char_less_than:
  774.     case char_back_slash:
  775.     case char_dot:
  776.         /*
  777.          *  This must be a file name.
  778.          */
  779.         lex_alpha (ch);
  780.         return;
  781.         break;
  782.  
  783.     case char_pound_sign:
  784.         tok = tok_pound_sign;
  785.         break;
  786.  
  787.     case char_eof:
  788.         tok = tok_eof;
  789.         break;
  790.  
  791.     default:
  792.         report_error (err_invalid_character, 0, "lex_special");
  793.         return;
  794.         break;
  795.     }
  796.  
  797.  
  798. /*  Update the current token structure and return. */
  799.  
  800. token.token = tok;
  801. }
  802.  
  803.  
  804. /***********************************************************************
  805.  *                                                                     *
  806.  *  GET_TOKEN                                                          *
  807.  *                                                                     *
  808.  *  This procedure gets the next token from the input string.          *
  809.  *                                                                     *
  810.  ***********************************************************************/
  811.  
  812. ushort get_token (void)
  813. {
  814.     uchar   ch;                                 /* a character */
  815.     uchar   buffer [max_identifier_size + 1];
  816.     ushort  index;
  817.  
  818. /*  If a token has been put back, just get that one.
  819.     ================================================ */
  820.  
  821.     if (putToken.token != tok_undefined) {
  822.         token = putToken;
  823.         putToken.token = tok_undefined;
  824.         if (is_debug_on)
  825.             debug_ptoken();
  826.         return token.token;
  827.     }
  828.  
  829. /*  Skip any white space and clean up the current token.
  830.     ==================================================== */
  831.  
  832.     skip_white_space ();
  833.     if (token.string)
  834.         _ffree (token.string);
  835.  
  836.     token.token = 0;
  837.     token.value = 0L;
  838.     token.string = NULL;
  839.  
  840. /*  Get a character and see if it's alphabetic, numeric, or special.
  841.     It's not a cr, which would have been eaten in skip_white_space.
  842.     ================================================================  */
  843.  
  844.     forever {
  845.         ch = get_char ();
  846.         if (alpha (ch))
  847.             lex_alpha (ch);
  848.         else if (numeric (ch))
  849.             lex_numeric (ch, FALSE);
  850.         else
  851.             lex_special (ch);
  852.  
  853. /*      Return the token type, unless it's a pound sign.
  854.         ================================================ */
  855.  
  856.         if (token.token != tok_pound_sign) {
  857.             if (is_debug_on)
  858.                 debug_ptoken();
  859.             return token.token;
  860.         }
  861.  
  862. /*      If it is a pound sign, see if it is an include token.
  863.         ===================================================== */
  864.  
  865.         index = 0;
  866.         while ((ch = get_char()) && !white_space (ch) && index < max_identifier_size)
  867.             buffer [index++] = ch;
  868.  
  869.         if (index >= max_identifier_size)
  870.             report_error (err_string_too_long, 0, "get_token");
  871.  
  872.         buffer [index] = '\0';
  873.         put_char (ch);
  874.         if (equal_ignoring_case (buffer, "include")) {
  875.             token.token = tok_include;
  876.             if (is_debug_on)
  877.                 debug_ptoken();
  878.             return token.token;
  879.         }
  880.  
  881.         output_control_line (buffer);
  882.         skip_white_space ();
  883.     }
  884. }
  885.  
  886.  
  887. /***********************************************************************
  888.  *                                                                     *
  889.  *  PUT_TOKEN                                                          *
  890.  *                                                                     *
  891.  *  This procedure puts a token into the pending token buffer.         *
  892.  *                                                                     *
  893.  ***********************************************************************/
  894.  
  895. void put_token (void)
  896. {
  897.  
  898. /*  If there is currently a put back token, there's a logic error. */
  899.  
  900. if (putToken.token != tok_undefined)
  901.     report_error (err_full_put_token_buffer, 0, "put_token");
  902.  
  903. /*  Save the current token in the put back token structure. */
  904.  
  905. putToken = token;
  906. }
  907.  
  908.  
  909. /***********************************************************************
  910.  *                                                                     *
  911.  *  CURRENT_TOKEN_STRING                                               *
  912.  *                                                                     *
  913.  *  This procedure returns the current token string.                   *
  914.  *                                                                     *
  915.  ***********************************************************************/
  916.  
  917. void ptr current_token_string (void)
  918. {
  919. return (void ptr)token.string;
  920. }
  921.  
  922.  
  923. /***********************************************************************
  924.  *                                                                     *
  925.  *  CURRENT_TOKEN_VALUE                                                *
  926.  *                                                                     *
  927.  *  This procedure returns the current token value.                    *
  928.  *                                                                     *
  929.  ***********************************************************************/
  930.  
  931. long current_token_value (void)
  932. {
  933. return token.value;
  934. }
  935.  
  936.  
  937. /**************************************************************************
  938.  *                                                                        *
  939.  *  OPEN_SOURCE_FILE                                                      *
  940.  *                                                                        *
  941.  *  This procedure opens a source file and adds an entry to the Source    *
  942.  *  File table.                                                           *
  943.  *                                                                        *
  944.  **************************************************************************/
  945.  
  946. flag open_source_file (uchar ptr src_fname)
  947. {
  948. HANDLE        fnum;                /* file handle */
  949.  
  950. /*  Open the source file. */
  951. fnum = CreateFile(src_fname, GENERIC_READ, FILE_SHARE_READ, 
  952.         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  953.  
  954. if (fnum == NULL)
  955. {
  956.     printf ("Unable to open: %s, error %ld\n", src_fname, GetLastError());
  957.     close_destination_file ();
  958.     terminate_input ();
  959.     exit(1);
  960. }
  961.  
  962.  
  963. /*  Initialize a source file structure and insert the entry in the table. */
  964.  
  965. srcFile = &srcTable [src_entries];
  966. srcFile->fnum = fnum;
  967. srcFile->size = GetFileSize(fnum, NULL);
  968. srcFile->total_read = 0L;
  969. srcFile->buffer = _fmalloc (max_buffer_bytes);
  970. src_entries++;
  971.  
  972. /*  Read some data into the data buffer. */
  973.  
  974. return (read_data (srcFile));
  975. }
  976.  
  977.  
  978. /**************************************************************************
  979.  *                                                                        *
  980.  *  INITIALIZE_INPUT                                                      *
  981.  *                                                                        *
  982.  *  This procedure initializes the input system.                          *
  983.  *                                                                        *
  984.  **************************************************************************/
  985.  
  986. void initialize_input (void)
  987. {
  988. src_entries = 0;
  989. srcFile = NULL;
  990. }
  991.  
  992.  
  993. /**************************************************************************
  994.  *                                                                        *
  995.  *  TERMINATE_INPUT                                                       *
  996.  *                                                                        *
  997.  *  This procedure terminates the input system.                           *
  998.  *                                                                        *
  999.  **************************************************************************/
  1000.  
  1001. void terminate_input (void)
  1002. {
  1003. SrcFile ptr src;                        /* source file element */
  1004. long        i;                /* loop counter */
  1005.  
  1006. for (i = 0L; i < src_entries; i++) {
  1007.     src = &srcTable [i];
  1008.     _ffree (src->buffer);
  1009.     }
  1010. }
  1011.  
  1012. /***********************************************************************
  1013.  *                                                                     *
  1014.  *  GET_COMMENT_STRING                                                 *
  1015.  *                                                                     *
  1016.  *  This procedure returns the current comment string.                 *
  1017.  *                                                                     *
  1018.  ***********************************************************************/
  1019. void ptr get_comment_string (void)
  1020. {
  1021.     if (pszComment == NULL || iComment == 0)
  1022.         return NULL;
  1023.  
  1024.     if (pszComment[0] == char_space)
  1025.         return NULL;
  1026.  
  1027.     return (void ptr) pszComment;
  1028. }
  1029.  
  1030. /***********************************************************************
  1031.  *                                                                     *
  1032.  *  CLEAR_COMMENT_STRING                                               *
  1033.  *                                                                     *
  1034.  *  This procedure clears the comment string.                          *
  1035.  *                                                                     *
  1036.  ***********************************************************************/
  1037. void clear_comment_string (void)
  1038. {
  1039.     if (pszComment != NULL)
  1040.         pszComment[0] = 0;
  1041.     iComment = 0;
  1042. }
  1043.  
  1044.