home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 355_01 / slk1.exe / SDEL / SDEL.C < prev   
C/C++ Source or Header  |  1991-06-09  |  30KB  |  1,633 lines

  1. /*
  2.     Sherlock delete program.
  3.  
  4.     source:  sdel.c
  5.     started: December 15, 1985
  6.     versions:
  7.         1.0:  July 21, 1988
  8.         1.0c: November 9, 1988 bug fix to sysnlput().
  9.         1.1:  February 16, 1989 support for SL_DISABLE.
  10.  
  11.  
  12.     PUBLIC DOMAIN SOFTWARE
  13.  
  14.     Sherlock, including the SPP, SDEL and SDIF programs, was placed in
  15.     the public domain on June 15, 1991, by its author,
  16.  
  17.         Edward K. Ream
  18.         166 North Prospect Ave.
  19.         Madison, WI 53705.
  20.         (608) 257-0802
  21.  
  22.     Sherlock may be used for any commercial or non-commercial purpose.
  23.  
  24.  
  25.     DISCLAIMER OF WARRANTIES
  26.  
  27.     Edward K. Ream (Ream) specifically disclaims all warranties,
  28.     expressed or implied, with respect to this computer software,
  29.     including but not limited to implied warranties of merchantability
  30.     and fitness for a particular purpose.  In no event shall Ream be
  31.     liable for any loss of profit or any commercial damage, including
  32.     but not limited to special, incidental consequential or other damages.
  33. */
  34.  
  35. /*
  36.     Define which compiler will be used.
  37.     This should be done on the compiler command line.
  38.  
  39.     TURBOC        use Turbo C compiler.
  40.     MICRO_SOFT    use version 4.0 of MicroSoft compiler on MS DOS.
  41. */
  42.  
  43. /*
  44.     Miscellaneous global constants.
  45. */
  46. #define ZERO    (0)
  47. #define TRUE    (1)
  48. #define FALSE    (0)
  49. #define END_FILE 0x1a
  50. #define ERROR    (-1)
  51. #define BAD_EXIT 1
  52. typedef int    bool;
  53.  
  54. /*
  55.     Include subsidiary header files.
  56.  
  57.     SL.H MUST be included even if SL.C is not linked in.
  58. */
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <ctype.h>
  62. #include <string.h>
  63. #include <process.h>
  64.  
  65. #include "sl.h"
  66.  
  67. #define str_eq(a,b) (strcmp(a,b)==0)
  68. #define ishex(c) ((c>='0'&&c<='9') || (c>='a'&&c<='f') || (c>='A'&&c<='F'))
  69. #define isid1(c) (isalpha(c) || c=='_')
  70. #define isid2(c) (isalpha(c) || isdigit(c) || c=='_')
  71.  
  72. #define SIGNON "SDEL v1.7: June 15, 1991"
  73.  
  74. #ifdef SHERLOCK
  75. #define USAGE1 "usage: SDEL in out [options] ++/--tracepoint\n\n"
  76. #else
  77. #define USAGE1 "usage: SDEL in out [options]\n\n"
  78. #endif
  79.  
  80. #define USAGE2 "-d   retain SL_DISABLE macros\n"
  81. #define USAGE3 "-f <file>   rename macros using a synonym file\n"
  82. #define USAGE4 "-i   remove #include \"sl.h\" lines\n"
  83. #define USAGE5 "-n   disallow nested comments\n"
  84. #define USAGE6 "-r   retain SL_NAME macros\n"
  85. #define USAGE7 "-t   allow trigraph translation\n"
  86. #define USAGE8 "-?   print version number and exit\n"
  87.  
  88.  
  89. /*
  90.     Spellings of special case macros.
  91. */
  92. char *    r_void    = "RETURN_VOID";
  93. char *    s_disable = "SL_DISABLE";     /* new in v1.1 */
  94. char *    s_name    = "SL_NAME";
  95.  
  96. /*
  97.     Spellings of all return macros, except RETURN_VOID.
  98. */
  99. char * rmn_tab [] = {
  100.  
  101.     "RETURN_BOOL",    "RETURN_CHAR",     "RETURN_DOUBLE",
  102.     "RETURN_FLOAT",    "RETURN_INT",     "RETURN_LONG",
  103.     "RETURN_PTR",    "RETURN_STRING", "RETURN_UINT",
  104.     "RETURN_ULONG",
  105.  
  106.     /* End of table flag. */
  107.     NULL
  108. };
  109.  
  110. /*
  111.     Spellings of all other macros.
  112. */
  113. char * mn_tab [] = {
  114.  
  115.     "SL_CLEAR",    "SL_DUMP",    "SL_INIT",
  116.     "SL_OFF",    "SL_ON",    "SL_PARSE",
  117.  
  118.     "STAT",        "STATB",    "STATX",
  119.     "TICK",        "TICKB",    "TICKN",    "TICKX",
  120.     "TRACE",    "TRACEB",    "TRACEN",    "TRACEX",
  121.     "TRACEP",    "TRACEPB",    "TRACEPN",    "TRACEPX",
  122.  
  123.     NULL
  124. };
  125.  
  126. /*
  127.     Forward declarations.
  128.  
  129.     These lines will need to be modified or deleted when using old K & R 
  130.     compilers.
  131. */
  132. void    delete        (void);
  133. void    out_all        (void);
  134. void    out_hnl        (void);
  135. void    out_lws        (void);
  136. void    do_arg        (void);
  137. void    do_comment    (void);
  138. void    do_id        (bool nl_flag, bool multiple_flag);
  139. void    do_pp        (void);
  140. void    do_string    (void);
  141. void    do_ws        (void);
  142. bool    is_return    (char * name);
  143. bool    is_sherlock    (char * name);
  144. void    get_id        (char * buffer);
  145. void    out_char    (int c);
  146. void    set_syn        (char * id1, char * id2);
  147. char *    str_alloc    (char * string);
  148. void    synonyms    (void);
  149.  
  150. void    sysabort    (void);
  151. void    syspb        (char c);
  152. void    sysnext        (void);
  153. void    s_fillbuf    (void);
  154. int    sysn1        (void);
  155. int    sysn2        (void);
  156. void    sysiclose    (void);
  157. int    sysopen        (char * name);
  158. int    syscreat    (char * name);
  159. void    sysoclose    (void);
  160. void    sysnlput    (void);
  161. void    syscput        (char);
  162. void    syssput        (char * s);
  163. void    sysinit        (void);
  164. void    syscsts        (void);
  165.  
  166. void    raw_close    (int);
  167. int    raw_creat    (char * name);
  168. int    raw_open    (char * name);
  169. int    raw_read    (int handle, char * buffer, int n);
  170. int    raw_write    (int handle, char * buffer, int n);
  171. int    syscstat    (void);
  172.  
  173. /* Global flags. */
  174. bool    disable_flag    = FALSE;    /* TRUE if retain SL_DISABLE    */
  175. bool    include_flag    = FALSE;    /* TRUE if remove #include "sl.h" */
  176. bool    name_flag    = FALSE;    /* TRUE if retain SL_NAME    */
  177. bool    nest_flag    = TRUE;
  178. bool    trigraph    = FALSE;
  179.  
  180. /* Global variables. */
  181. char *    file        = NULL;
  182. int    line        = 1;        /* Current line number.        */
  183. char    ch;                /* The NEXT character.         */
  184. char    last_ch        = '@';        /* Previous non-blank char.    */
  185. bool    skipping    = FALSE;    /* TRUE if skipping output.    */
  186. bool    delete_flag    = FALSE;    /* Newline deleted flag.    */
  187.  
  188. #define MAX_SYMBOL 1000
  189. char    symbol [MAX_SYMBOL];
  190. int    held_nl;            /* Number of held newlines.    */
  191.  
  192. char    lws [MAX_SYMBOL];        /* Leading white space.        */
  193. int    lws_count = 0;
  194.  
  195. char    tws [MAX_SYMBOL];        /* Trailing white space.    */
  196. int    tws_count = 0;
  197.  
  198. /* Main routine.  Process command-line arguments. */
  199. main(int argc, char ** argv)
  200. {
  201.     char *in = NULL, *out = NULL;
  202.     char *arg;
  203.     char *def;
  204.     char *p1;
  205.  
  206.     /* These two calls MUST come before any others. */
  207.     SL_INIT();
  208.     SL_PARSE(argc, argv, "++", "--");
  209.  
  210.     /* Allow user to abort. */
  211.     syscsts();
  212.  
  213.     TICKB("main");
  214.  
  215.     /* Always put out the sign on message. */
  216.     printf("%s\n", SIGNON);
  217.  
  218.     /* Make first test for correct command line. */
  219.     if (argc == 2 && str_eq(argv[1], "-?")) {
  220.         sysabort();
  221.     }
  222.     else if (argc < 3) {
  223.         printf("\n%s%s%s%s%s%s",
  224.             USAGE2, USAGE3, USAGE4, USAGE5,
  225.             USAGE6, USAGE7, USAGE8);
  226.         sysabort();
  227.     }
  228.  
  229.     /* Process all the arguments on the command line. */
  230.     argc--;
  231.     argv++;
  232.     while (argc-- > 0) {
  233.         arg = *argv++;
  234.  
  235.         if (str_eq(arg, "-d")) {
  236.             disable_flag = TRUE;
  237.         }
  238.         else if (str_eq(arg, "-f")) {
  239.             if (argc--) {
  240.                 arg = *argv++;
  241.                 file = arg;
  242.                 if (sysopen(arg) == FALSE) {
  243.                     printf("Can not open %s\n", arg);
  244.                     exit(BAD_EXIT);
  245.                 }
  246.                 synonyms();
  247.                 sysiclose();
  248.                 line = 1;
  249.             }
  250.             else {
  251.                 printf("Trailing -f\n");
  252.                 exit(BAD_EXIT);
  253.             }
  254.         }
  255.         else if (str_eq(arg, "-i")) {
  256.             /* Remove #include "sl.h" */
  257.             include_flag = TRUE;
  258.         }
  259.         else if (str_eq(arg, "-n")) {
  260.             /* Disallow nested comments. */
  261.             nest_flag = FALSE;
  262.         }
  263.         else if (str_eq(arg, "-t")) {
  264.             /* Allow trigraph translation. */
  265.             trigraph = TRUE;
  266.         }
  267.         else if (str_eq(arg, "-r")) {
  268.             /* Retain SL_NAME. */
  269.             name_flag = TRUE;
  270.         }
  271.         else if (str_eq(arg, "-?")) {
  272.             /* Ignore it. */
  273.             ;
  274.         }
  275.         else if (in == NULL) {
  276.             in = arg;
  277.         }
  278.         else if (out == NULL) {
  279.             out = arg;
  280.         }
  281.         else {
  282.             printf("Extra file argument: %s\n", arg);
  283.             exit(BAD_EXIT);
  284.         }
  285.     }
  286.  
  287.     /* Make sure that both file arguments were provided. */
  288.     if (in == NULL) {
  289.         printf("Missing input, output file arguments.\n");
  290.         sysabort();
  291.     }
  292.     else if (out == NULL) {
  293.         printf("Missing output file argument.\n");
  294.         sysabort();
  295.     }
  296.     else if (str_eq(in, out)) {
  297.         printf("Can not copy input file to output file.");
  298.         sysabort();
  299.     }
  300.  
  301.     if (sysopen(out)) {
  302.         printf("Output file: %s exists...\n", out);
  303.         sysabort();
  304.     }
  305.     if (syscreat(out) == FALSE) {
  306.         printf("Can not open %s\n", out);
  307.         sysabort();
  308.     }
  309.     if (sysopen(in) == FALSE) {
  310.         printf("Can not open %s\n", in);
  311.         sysabort();
  312.     }
  313.  
  314.     /* Copy the program, deleting all Sherlock macros. */
  315.     delete();
  316.  
  317.     /* Close the output file. */
  318.     sysoclose();
  319.  
  320.     TRACE("dump", sl_dump());
  321.     RETURN_VOID("main");
  322. }
  323.  
  324. /*
  325.     Delete all calls to Sherlock macros, with any leading white space.
  326. */
  327. #define EXTRA_CLOSE\
  328. "Warning:  Line %d,  '*/' seen outside a comment.\n"
  329.  
  330. void
  331. delete(void)
  332. {
  333.     int i;
  334.  
  335.     TICKB("delete");
  336.  
  337.     if (ch == '#') {
  338.         do_pp();
  339.     }
  340.     for(;;) {
  341.         if (ch == END_FILE) {
  342.             RETURN_VOID("delete");
  343.         }
  344.         else if (delete_flag) {
  345.             delete_flag = FALSE;
  346.             held_nl = 0;
  347.  
  348.             if (isalpha(ch) || ch == '_') {
  349.                 /* Leading id, multiple delete possible */
  350.                 do_id(TRUE, TRUE);
  351.             }
  352.             else if (ch == '#') {
  353.                 /* Allow preprocessor directives. */
  354.                 out_lws();
  355.                 do_pp();
  356.             }
  357.             else {
  358.                 out_lws();
  359.             }
  360.         }
  361.         else if (ch == '\n') {
  362.  
  363.             /* Allow user to abort here. */
  364.             syscsts();
  365.  
  366.             /*
  367.                 Count the number of newline and queue up
  368.                 the last leading white space.
  369.             */
  370.             skipping = TRUE;
  371.             
  372.             held_nl = 0;
  373.             for (;;) {
  374.                 if (ch == '\n') {
  375.                     line++;
  376.                     held_nl++;
  377.                     sysnext();
  378.                     lws_count = 0;
  379.                 }
  380.                 else if (ch == ' ' || ch == '\t') {
  381.                     lws[lws_count++] = ch;
  382.                     sysnext();
  383.                 }
  384.                 else {
  385.                     break;
  386.                 }
  387.             }
  388.             skipping = FALSE;
  389.                     
  390.             if (isalpha(ch) || ch == '_') {
  391.                 /* Leading id, no multiple delete */
  392.                 do_id(TRUE, FALSE);
  393.             }
  394.             else if (ch == '#') {
  395.                 out_hnl();
  396.  
  397.                 /* Allow preprocessor directives. */
  398.                 do_pp();
  399.             }
  400.             else {
  401.                 out_all();
  402.             }
  403.         }
  404.         else if (isalpha(ch) || ch == '_') {
  405.             /* non-leading id, no multiple line. */
  406.             do_id(FALSE, FALSE);
  407.             last_ch = 'a';
  408.         }
  409.         else if (ch == '"' || ch == '\'') {
  410.             do_string();
  411.             last_ch = '"';
  412.         }
  413.         else if (ch == '/') {
  414.             out_char(ch);
  415.             sysnext();
  416.             if (ch == '*') {
  417.                 out_char(ch);
  418.                 sysnext();
  419.                 do_comment();
  420.             }
  421.             else {
  422.                 last_ch = '/';
  423.             }
  424.         }
  425.         else if (ch == '*') {
  426.             out_char(ch);
  427.             sysnext();
  428.             if (ch == '/') {
  429.                 printf(EXTRA_CLOSE, line);
  430.                 out_char(ch);
  431.                 sysnext();
  432.             }
  433.             else {
  434.                 last_ch = '*';
  435.             }
  436.         }
  437.         else {
  438.             STAT("v_default");
  439.             last_ch = ch;
  440.             out_char(ch);
  441.             sysnext();
  442.         }
  443.     }
  444. }
  445.  
  446. /*  Output all queued white space and newlines. */
  447. void
  448. out_all(void)
  449. {
  450.     int i;
  451.  
  452.     out_hnl();
  453.     out_lws();
  454. }
  455.  
  456. /*  Output held newlines. */
  457. void
  458. out_hnl(void)
  459. {
  460.     int i;
  461.  
  462.     /* Output queued newlines. */
  463.     for (i = 0; i < held_nl; i++) {
  464.         sysnlput();
  465.     }
  466.     held_nl = 0;
  467. }
  468.  
  469. /* Output leading white space. */
  470. void
  471. out_lws(void)
  472. {
  473.     int i;
  474.  
  475.     /* Output leading white space. */
  476.     for (i = 0; i < lws_count; i++) {
  477.         out_char(lws [i]);
  478.     }
  479.     lws_count = 0;
  480. }
  481.  
  482. /*
  483.     Handle all remaining actual arguments to a Sherlock macro.
  484.     The macro should end with a right paren and a semicolon.
  485. */
  486. #define EOF_IN_MACRO\
  487. "Unexpected End of File inside a Sherlock macro starting at line: %d.\n"
  488. #define NEED_SEMI\
  489. "Semicolon expected after Sherlock macro starting at line %d.\n"
  490.  
  491. void
  492. do_arg(void)
  493. {
  494.     int level;
  495.     int start;
  496.  
  497.     TICKB("do_arg");
  498.     TRACE("v", syssput("<BEGIN ARG>"));
  499.  
  500.     level = 1;
  501.     start = line;
  502.  
  503.     for (;;) {
  504.         do_ws();
  505.         if (ch == END_FILE) {
  506.             printf(EOF_IN_MACRO, start);
  507.             RETURN_VOID("do_arg");
  508.         }
  509.         else if (ch == '(') {
  510.             level++;
  511.             out_char(ch);
  512.             sysnext();
  513.         }
  514.         else if (ch == ')') {
  515.             level--;
  516.             if (level == 0) {
  517.                 TRACE("v", syssput("<END ARG>"));
  518.                 RETURN_VOID("do_arg");
  519.             }
  520.             else {
  521.                 out_char(ch);
  522.                 sysnext();
  523.             }
  524.         }
  525.         else if (ch == '\n') {
  526.             line++;
  527.             if (!skipping) {
  528.                 sysnlput();
  529.             }
  530.             sysnext();
  531.         }
  532.         else if (ch == '"' || ch == '\'') {
  533.             do_string();
  534.         }
  535.         else {
  536.             out_char(ch);
  537.             sysnext();
  538.         }
  539.     }
  540. }
  541.  
  542. /*
  543.     Handle a comment, including the closing, but not opening delim.
  544. */
  545.  
  546. #define EOF_IN_COMMENT\
  547. "Unexpected End of File inside a comment starting at line: %d.\n"
  548. #define WARN_NESTED_COMMENT\
  549. "Line: %d, Warning: '/*' in comment ignored.\n"
  550.  
  551. void
  552. do_comment(void)
  553. {
  554.     int level;
  555.     int start;
  556.  
  557.     TICKB("do_comment");
  558.     TRACE("v", syssput("<BEGIN COMMENT>"));
  559.  
  560.     start = line;
  561.     level = 1;
  562.  
  563.     for (;;) {
  564.         if (ch == END_FILE) {
  565.             printf(EOF_IN_COMMENT, start);
  566.             RETURN_VOID("do_comment");
  567.         }
  568.         else if (ch == '/') {
  569.             out_char(ch);
  570.             sysnext();
  571.             if (ch == '*') {
  572.                 out_char(ch);
  573.                 sysnext();
  574.                 if (nest_flag) {
  575.                     level++;
  576.                 }
  577.                 else {
  578.                     printf(WARN_NESTED_COMMENT, line);
  579.                 }
  580.             }
  581.         }
  582.         else if (ch == '*') {
  583.             out_char(ch);
  584.             sysnext();
  585.             if (ch == '/') {
  586.                 out_char(ch);
  587.                 sysnext();
  588.                 level--;
  589.                 if (level == 0) {
  590.                     TRACE("v", syssput("<END COMMENT>"));
  591.                     RETURN_VOID("do_comment");
  592.                 }
  593.             }
  594.         }
  595.         else if (ch == '\n') {
  596.             line++;
  597.             if (!skipping) {
  598.                 sysnlput();
  599.             }
  600.             sysnext();
  601.         }
  602.         else {
  603.             out_char(ch);
  604.             sysnext();
  605.         }
  606.     }
  607. }
  608.  
  609. /*
  610.     Handle an identifier.
  611.     nl_flag:  True if the id is the first non-white space of the line.
  612. */
  613. #define NEED_OPEN\
  614. "Line %d: Open parenthesis expected after Sherlock macro.\n"
  615. #define NEED_NAME\
  616. "Line %d: Tracepoint name expected after Sherlock macro.\n"
  617. #define NEED_COMMA\
  618. "Line %d: Comma expected after tracepoint name in Sherlock macro.\n"
  619. #define EOF_IN_ARG\
  620. "Line %d: Unexpected End of File in Sherlock macro.\n"
  621.  
  622. void
  623. do_id(bool nl_flag, bool multiple_flag)
  624. {
  625.     int start;
  626.     int i;
  627.  
  628.     TICKB("do_id");
  629.  
  630.     /* Get the id into symbol[]. */
  631.     get_id(symbol);
  632.  
  633.     if (str_eq(symbol, r_void)) {
  634.         start = line;
  635.  
  636.         /* Output all queued newlines and leading white space. */
  637.         out_all();
  638.  
  639.         /* Translate RETURN_VOID to return */
  640.         syssput("return");
  641.  
  642.         skipping = TRUE;
  643.  
  644.         do_ws();
  645.         if (ch == '(') {
  646.             sysnext();
  647.         }
  648.         else {
  649.             printf(NEED_OPEN, line);
  650.         }
  651.         
  652.         do_arg();
  653.         if (ch == ')') {
  654.             /* Skip the trailing closing paren. */
  655.             sysnext();
  656.         }
  657.         do_ws();
  658.  
  659.         skipping = FALSE;
  660.  
  661.         if (ch == ';') {
  662.             out_char(ch);
  663.             sysnext();
  664.         }
  665.         else {
  666.             printf(NEED_SEMI, start);
  667.         }
  668.     }
  669.     else if (is_return(symbol)) {
  670.         start = line;
  671.  
  672.         /* Output queued newlines and leading white space. */
  673.         out_all();
  674.  
  675.         /* Translate RETURN_xxx to return */
  676.         syssput("return");
  677.  
  678.         do_ws();
  679.         if (ch == '(') {
  680.             sysnext();
  681.         }
  682.         else {
  683.             printf(NEED_OPEN, line);
  684.         }
  685.         
  686.         skipping = TRUE;
  687.  
  688.         /* We can't demand a string here.  An array is OK too. */
  689.         do_ws();
  690.  
  691.         while (ch != ',' && ch != END_FILE) {
  692.             sysnext();
  693.         }
  694.         if (ch == ',') {
  695.             sysnext();
  696.         }
  697.         else {
  698.             printf(EOF_IN_ARG, line);
  699.             RETURN_VOID("do_id");
  700.         }
  701.  
  702.         /* Copy the argument. */
  703.         skipping = FALSE;
  704.  
  705.         do_arg();
  706.         if (ch == ')') {
  707.             /* Skip the trailing closing paren. */
  708.             sysnext();
  709.         }
  710.         do_ws();
  711.         if (ch == ';') {
  712.             out_char(ch);
  713.             sysnext();
  714.         }
  715.         else {
  716.             printf(NEED_SEMI, start);
  717.         }
  718.     }
  719.     else if (is_sherlock(symbol)) {
  720.         start = line;
  721.  
  722.         /* Throw away all saved white space. */
  723.         if (nl_flag) {
  724.             held_nl = 0;
  725.             lws_count = 0;
  726.         }
  727.         else {
  728.             out_all();
  729.         }
  730.         skipping = TRUE;
  731.  
  732.         do_ws();
  733.         if (ch == '(') {
  734.             sysnext();
  735.         }
  736.         else {
  737.             printf(NEED_OPEN, line);
  738.         }
  739.         do_arg();
  740.         if (ch == ')') {
  741.             sysnext();
  742.         }
  743.         if (ch == ';') {
  744.             sysnext();
  745.         }
  746.         else {
  747.             printf(NEED_SEMI, start);
  748.         }
  749.  
  750.         skipping = FALSE;
  751.  
  752.         if (!nl_flag) {
  753.             RETURN_VOID("do_id");
  754.         }
  755.  
  756.         /* Save trailing white space. */
  757.         while (ch == ' ' || ch == '\t') {
  758.             tws [tws_count++] = ch;
  759.             sysnext();
  760.         }
  761.  
  762.         if (ch != '\n') {
  763.             /* Change everything to one newline. */
  764.             sysnlput();
  765.             for (i = 0; i < tws_count; i++) {
  766.                 out_char(tws[i]);
  767.             }
  768.             RETURN_VOID("do_id");
  769.         }
  770.  
  771.         /* Discard trailing white space. */
  772.         tws_count = 0;
  773.  
  774.         /* Indicate at least one newline was deleted. */
  775.         delete_flag = TRUE;
  776.  
  777.         /* Discard all newlines and all leading white space. */
  778.         while (ch == '\n') {
  779.             sysnext();
  780.             lws_count = 0;
  781.             while (ch == ' ' || ch == '\t') {
  782.                 lws[lws_count++] = ch;
  783.                 sysnext();
  784.             }
  785.         }
  786.  
  787.         /*
  788.             Let the main line handle the newline so that
  789.             leading white space will be handled properly.
  790.         */
  791.         if (!multiple_flag) {
  792.             if (ch != '}' && last_ch != '{') {
  793.                 sysnlput();
  794.                 sysnlput();
  795.             }
  796.             else {
  797.                 sysnlput();
  798.             }
  799.         }
  800.         skipping = FALSE;
  801.     }
  802.     else {
  803.         out_all();
  804.         syssput(symbol);
  805.     }
  806.     skipping = FALSE;
  807.     RETURN_VOID("do_id");
  808. }
  809.  
  810. /*
  811.     Handle a preprocessor directive.
  812. */
  813. void
  814. do_pp(void)
  815. {
  816.     int old_skipping;
  817.  
  818.     TICKB("do_pp");
  819.     TRACE("v", syssput("<BEGIN PP>"));
  820.  
  821.     old_skipping = skipping;
  822.     skipping = FALSE;
  823.  
  824.     for (;;) {
  825.         do_ws();
  826.         if (ch == END_FILE) {
  827.             skipping = old_skipping;
  828.  
  829.             TRACE("v", syssput("<END PP>"));
  830.             RETURN_VOID("do_pp");
  831.         }
  832.         else if (ch == '\\') {
  833.             out_char(ch);
  834.             sysnext();
  835.             if (ch == '\n') {
  836.                 line++;
  837.                 sysnlput();
  838.                 sysnext();
  839.             }
  840.         }
  841.         else if (ch == '\n') {
  842.             skipping = old_skipping;
  843.  
  844.             /*
  845.                 Let the main line handle the newline so
  846.                 consecutive directives will be recognized.
  847.             */
  848.             TRACE("v", syssput("<END PP>"));
  849.             RETURN_VOID("do_pp");
  850.         }
  851.         else if (ch == '"' || ch == '\'') {
  852.             do_string();
  853.         }
  854.         else {
  855.             out_char(ch);
  856.             sysnext();
  857.         }
  858.     }
  859. }
  860.  
  861. /*
  862.     Handle a string, including the opening and closing delimiters.
  863. */
  864. #define EOF_IN_STRING\
  865. "Unexpected End of File inside string starting at line: %d.\n"
  866. #define EOF_IN_CHAR\
  867. "Unexpected End of File inside character constant starting at line: %d.\n"
  868. #define RUN_ON_STRING\
  869. "Run on string:  newline in string starting at line %d.\n"
  870.  
  871. void
  872. do_string(void)
  873. {
  874.     int delim;
  875.     int start;
  876.     int i;
  877.  
  878.     TICKB("do_string");
  879.     TRACE("v", syssput("<START STRING>"));
  880.  
  881.     start = line;
  882.     delim = ch;
  883.  
  884.     out_char(ch);
  885.     sysnext();
  886.  
  887.     for (;;) {
  888.         if (ch == delim) {
  889.             out_char(ch);
  890.             sysnext();
  891.  
  892.             TRACE("v", syssput("<END STRING>"));
  893.             RETURN_VOID("do_string");
  894.         }
  895.         else if (ch == END_FILE) {
  896.  
  897.             if (ch == '"') {
  898.                 printf(EOF_IN_STRING, start);
  899.             }
  900.             else {
  901.                 printf(EOF_IN_CHAR, start);
  902.             }
  903.             RETURN_VOID("do_string");
  904.         }
  905.  
  906.         else if (ch == '\n') {
  907.             line++;
  908.             sysnext();
  909.             if (!skipping) {
  910.                 sysnlput();
  911.             }
  912.             printf(RUN_ON_STRING, start);
  913.             RETURN_VOID("do_string");
  914.         }
  915.         else if (ch == '\\') {
  916.             /* Escape sequence. */
  917.  
  918.             STAT("v_esc");
  919.  
  920.             out_char(ch);
  921.             sysnext();
  922.             if (ch == '\n') {
  923.                 /* Strings eat directives. */
  924.                 line++;
  925.                 sysnext();
  926.                 if (!skipping) {
  927.                     sysnlput();
  928.                 }
  929.             }
  930.             else if (ch == 'x') {
  931.                 /* 3-digit hex escape sequence. */
  932.                 out_char(ch);
  933.                 sysnext();
  934.                 for (i = 0; i < 3 && ishex(ch); i++) {
  935.                     out_char(ch);
  936.                     sysnext();
  937.                 }
  938.             }
  939.             else if (ch >= '0' && ch <= '9') {
  940.                 /* Octal escape sequence. */
  941.                 for (i = 0; i < 3 && ch >= '0' && ch <= '9'; i++) {
  942.                     out_char(ch);
  943.                     sysnext();
  944.                 }
  945.             }
  946.             else if (ch != END_FILE) {
  947.                 out_char(ch);
  948.                 sysnext();
  949.             }
  950.         }
  951.         else {
  952.             out_char(ch);
  953.             sysnext();
  954.         }
  955.     }
  956. }
  957.  
  958. /*
  959.     Handle white space, including comments.
  960. */
  961. void
  962. do_ws(void)
  963. {
  964.     TICKB("do_ws");
  965.  
  966.     for (;;) {
  967.         if (ch == ' ' || ch == '\t') {
  968.             out_char(ch);
  969.             sysnext();
  970.         }
  971.         else if (ch == '/') {
  972.             out_char(ch);
  973.             sysnext();
  974.             if (ch == '*') {
  975.                 do_comment();
  976.             }
  977.         }
  978.         else {
  979.             RETURN_VOID("do_ws");
  980.         }
  981.     }
  982. }
  983.  
  984. /*
  985.     Get an identifier from the input file into the buffer.
  986. */
  987. void
  988. get_id(char * buffer)
  989. {
  990.     int i;
  991.  
  992.     i = 0;
  993.     while (isid2(ch)) {
  994.         buffer[i++] = ch;
  995.         sysnext();
  996.     }
  997.     buffer[i] = '\0';
  998.  
  999.     TRACEP("get_id", printf("<%s>\n", buffer));
  1000. }
  1001.         
  1002. /* Return TRUE if name is a Sherlock RETURN_xxx macro except RETURN_VOID. */
  1003. bool
  1004. is_return(char * name)
  1005. {
  1006.     int i;
  1007.  
  1008.     TRACEP("is_return", printf("(%s)\n", name));
  1009.  
  1010.     for (i = 0;;i++) {
  1011.         if (rmn_tab[i] == NULL) {
  1012.             return FALSE;
  1013.         }
  1014.         else if (str_eq(rmn_tab[i], name)) {
  1015.             return TRUE;
  1016.         }
  1017.     }
  1018. }
  1019.  
  1020. /* Return TRUE if name is a Sherlock macro except RETURN_xxx. */
  1021. bool
  1022. is_sherlock(char * name)
  1023. {
  1024.     int i;
  1025.  
  1026.     TRACEP("is_sherlock", printf("(%s)\n", name));
  1027.  
  1028.     /* Special cases, but not r_void. */
  1029.     if (str_eq(s_disable, name)) {
  1030.         return !disable_flag;
  1031.     }
  1032.     else if (str_eq(s_name, name)) {
  1033.         return !name_flag;
  1034.     }
  1035.  
  1036.     /* All other macros. */
  1037.     for (i = 0;;i++) {
  1038.         if (mn_tab[i] == NULL) {
  1039.             return FALSE;
  1040.         }
  1041.         else if (str_eq(mn_tab[i], name)) {
  1042.             return TRUE;
  1043.         }
  1044.     }
  1045. }
  1046.  
  1047. void
  1048. out_char(int c)
  1049. {
  1050.     if (skipping) {
  1051.         return;
  1052.     }
  1053.     else if (trigraph) {
  1054.         switch (c) {
  1055.         case '#':    syssput("??=");    break;
  1056.         case '[':    syssput("??(");    break;
  1057.         case '\\':    syssput("??/");    break;
  1058.         case ']':    syssput("??)");    break;
  1059.         case '^':    syssput("??'");    break;
  1060.         case '{':    syssput("??<");    break;
  1061.         case '|':    syssput("??!");    break;
  1062.         case '}':    syssput("??>");    break;
  1063.         case '~':    syssput("??-");    break;
  1064.         default:
  1065.             syscput(c);
  1066.         }
  1067.     }
  1068.     else {
  1069.         syscput(c);
  1070.     }
  1071. }
  1072.  
  1073. /*
  1074.     Change the spelling of a Sherlock macro.
  1075. */
  1076. void
  1077. set_syn(char * id1, char * id2)
  1078. {
  1079.     int i;
  1080.  
  1081.     TRACEP("set_syn", printf("(%s, %s)\n", id1, id2));
  1082.  
  1083.     /* Special cases. */
  1084.     if (str_eq(id1, r_void)) {
  1085.         r_void = str_alloc(id2);
  1086.         return;
  1087.     }
  1088.     else if (str_eq(id1, s_disable)) {
  1089.         s_disable = str_alloc(id2);
  1090.         return;
  1091.     }
  1092.     else if    (str_eq(id1, s_name)) {
  1093.         s_name = str_alloc(id2);
  1094.         return;
  1095.     }
  1096.  
  1097.     /* All return macros except RETURN_VOID. */
  1098.     for (i = 0; rmn_tab[i] != NULL; i++) {
  1099.         if (str_eq(rmn_tab[i], id1)) {
  1100.             rmn_tab[i] = str_alloc(id2);
  1101.             return;
  1102.         }
  1103.     }
  1104.  
  1105.     /* All other Sherlock macros. */
  1106.     for (i = 0; mn_tab[i] != NULL; i++) {
  1107.         if (str_eq(mn_tab[i], id1)) {
  1108.             mn_tab[i] = str_alloc(id2);
  1109.             return;
  1110.         }
  1111.     }
  1112.     printf("Synonym entry for %s has no effect.\n", id1);
  1113. }
  1114.  
  1115. void
  1116. skip_bl(void)
  1117. {
  1118.     while (ch == ' ' || ch == '\t') {
  1119.         sysnext();
  1120.     }
  1121. }
  1122.  
  1123. /*
  1124.     Allocate memory big enough to hold the string,
  1125.     then copy the string to the allocated memory.
  1126. */
  1127. char *
  1128. str_alloc(char *s)
  1129. {
  1130.     char * p;
  1131.     int n;
  1132.  
  1133.     TRACEPB("str_alloc", printf("(%s)\n", s));
  1134.  
  1135.     n = strlen(s) + 1;
  1136.     p = malloc(n);
  1137.     strcpy(p, s);
  1138.  
  1139.     RETURN_PTR("str_alloc", p);
  1140. }
  1141.  
  1142. void
  1143. synonyms(void)
  1144. {
  1145.     char buffer1 [1000];
  1146.     char buffer2 [1000];
  1147.  
  1148.     skip_bl();
  1149.     for(;;) {
  1150.         if (ch == END_FILE) {
  1151.             return;
  1152.         }
  1153.         else if (isid1(ch)) {
  1154.             get_id(&buffer1[0]);
  1155.             skip_bl();
  1156.             if (isid1(ch)) {
  1157.                 get_id(&buffer2[0]);
  1158.                 set_syn(&buffer1[0], &buffer2[0]);
  1159.                 TRACEP("synonym",
  1160.                     printf("<%s> = <%s>\n",
  1161.                         buffer1, buffer2));
  1162.                 skip_bl();
  1163.                 if (ch == '\n') {
  1164.                     sysnext();
  1165.                     line++;
  1166.                     skip_bl();
  1167.                 }
  1168.                 else {
  1169.                     printf("%s: %d: Newline expected.\n",
  1170.                         file, line);
  1171.                     sysabort();
  1172.                 }
  1173.             }
  1174.             else {
  1175.                 printf("%s: %d: Synonym expected.\n",
  1176.                     file, line);
  1177.                 sysabort();
  1178.             }
  1179.         }
  1180.         else if (ch == ' ' || ch == '\t' || ch == '\n') {
  1181.             if (ch == '\n') {
  1182.                 line++;
  1183.             }
  1184.             sysnext();
  1185.         }
  1186.         else if (ch == '#') {
  1187.             while (ch != '\n' && ch != END_FILE) {
  1188.                 sysnext();
  1189.             }
  1190.         }
  1191.         else {
  1192.             printf("%s: %d: Identifier expected.\n",
  1193.                 file, line);
  1194.             sysabort();
  1195.         }
  1196.     }
  1197. }            
  1198.  
  1199. #ifdef MICRO_SOFT
  1200. #include <fcntl.h>
  1201. #include <sys\types.h>
  1202. #include <sys\stat.h>
  1203. #include <io.h>
  1204. #endif
  1205.  
  1206. #ifdef TURBOC
  1207. #include <fcntl.h>
  1208. #include <sys\stat.h>
  1209. #include <io.h>
  1210. #include <conio.h>
  1211. #endif
  1212.  
  1213. /*
  1214.     Variables used by system routines.
  1215. */
  1216. #define IBUF_SIZE 2048    /* Size of each input buffer. */
  1217. #define OBUF_SIZE 2048    /* Size of the output buffer. */
  1218.  
  1219. char *    s_ip = NULL;        /* input pointer.        */
  1220. int    s_ic = 0;            /* input count.            */
  1221. int    s_ih = 0;        /* input handle.        */
  1222. bool    s_eof = FALSE;        /* input EOF flag.        */
  1223. char    s_npb = -1;        /* Outer push-back.        */
  1224. char    s_pushback = -1;    /* Inner push-back char.    */
  1225.  
  1226. #define    MAX_LINE 1000
  1227. char     s_buf [MAX_LINE];        /* Line buffer.        */
  1228. char *    s_bufp = s_buf;            /* Line buffer pointer.    */
  1229.  
  1230. char *    s_op = NULL;        /* output pointer.    */
  1231. int    s_oc = ERROR;        /* output count.    */
  1232. int    s_oh = ERROR;        /* output handle.    */
  1233.  
  1234. char ibuffer [IBUF_SIZE];
  1235. char obuffer [OBUF_SIZE];
  1236.  
  1237. /*
  1238.     Close all files and exit.
  1239.  
  1240.     Do not call sysabort() from inside
  1241.     sysiclose(), sysoclose(), or sys_release().
  1242. */
  1243. void
  1244. sysabort(void)
  1245. {
  1246.     TICK("sysabort");
  1247.  
  1248.     sysoclose();
  1249.     sysiclose();
  1250.     exit(BAD_EXIT);
  1251. }        
  1252.  
  1253. /*
  1254.     ----- I N P U T    L O G I C -----
  1255.  
  1256.     Set the global variable ch to the next character from the input stream.
  1257. */
  1258.  
  1259. void
  1260. sysnext(void)
  1261. {
  1262.     if (s_npb != -1) {
  1263.         ch = s_npb;
  1264.         s_npb = -1;
  1265.         return;
  1266.     }
  1267.     else if (s_eof) {
  1268.         ch = END_FILE;
  1269.         return;
  1270.     }
  1271.     for (;;) {
  1272.         ch = *s_bufp++;
  1273.         if (ch == '\0') {
  1274.             s_fillbuf();
  1275.         }
  1276.         else if (ch == END_FILE) {
  1277.             s_eof = TRUE;
  1278.             return;
  1279.         }
  1280.         else {
  1281.             return;
  1282.         }
  1283.     }
  1284. }
  1285.  
  1286. /* Fill the line buffer and delete lines consisting of #include "sl.h". */
  1287. void
  1288. s_fillbuf(void)
  1289. {
  1290.     int c;
  1291.  
  1292.     for(s_bufp = s_buf; ;) {
  1293.         *s_bufp++ = c = sysn2();
  1294.         if (c == END_FILE || c == '\n') {
  1295.             break;
  1296.         }
  1297.     }
  1298.     *s_bufp = '\0';
  1299.     s_bufp = s_buf;
  1300.     if (include_flag && str_eq(s_bufp, "#include \"sl.h\"\n")) {
  1301.         line++;
  1302.         s_buf[0] = '\0';
  1303.     }
  1304. }
  1305.         
  1306. int
  1307. sysn2(void)
  1308. {
  1309.     int c;
  1310.  
  1311.     /* Delete all carriage returns.  Translate all trigraph sequences. */
  1312.     do {
  1313.         c = sysn1();
  1314.  
  1315.         if (trigraph && c == '?') {
  1316.             c = sysn1();
  1317.             if (c == '?') {
  1318.                 /* A trigraph sequence. */
  1319.                 c = sysn1();
  1320.                 switch (c) {
  1321.                 case '=':    c = '#';    break;
  1322.                 case '(':    c = '[';    break;
  1323.                 case '/':    c = '\\';    break;
  1324.                 case ')':    c = ']';    break;
  1325.                 case '\'':    c = '^';    break;
  1326.                 case '<':    c = '{';    break;
  1327.                 case '!':    c = '|';    break;
  1328.                 case '>':    c = '}';    break;
  1329.                 case '-':    c = '~';    break;
  1330.                 default:
  1331.  
  1332.             printf("line %d: unknown trigraph ignored: ??%c\n",
  1333.                 line, c);
  1334.                     c = '\r';
  1335.                 }
  1336.             }
  1337.             else {
  1338.                 s_pushback = c;
  1339.                 c = '?';
  1340.             }
  1341.         }
  1342.     }
  1343.     while (c == '\r');
  1344.     return c;
  1345. }
  1346.  
  1347. int
  1348. sysn1(void)
  1349. {
  1350.     int n;
  1351.     int c;
  1352.  
  1353.     if (s_pushback != -1) {
  1354.         c = s_pushback;
  1355.         s_pushback = -1;
  1356.         return c;
  1357.     }
  1358.     else if (s_ic > 0) {
  1359.         s_ic--;
  1360.         return *s_ip++;
  1361.     }
  1362.     else {
  1363.         n = raw_read(s_ih, ibuffer, IBUF_SIZE);
  1364.         if (n > 0) {
  1365.             s_ic = n;
  1366.             s_ip = ibuffer;
  1367.             s_ic--;
  1368.             return *s_ip++;
  1369.         }
  1370.         else {
  1371.             return END_FILE;
  1372.         }
  1373.     }
  1374. }
  1375.  
  1376. /*
  1377.     Close the current input file.
  1378. */
  1379. void
  1380. sysiclose(void)
  1381. {
  1382.     TICK("sysiclose");
  1383.  
  1384.     /* Close the current input file. */
  1385.     if (s_ih != ERROR) {
  1386.         raw_close(s_ih);
  1387.     }
  1388.  
  1389.     ch = END_FILE;
  1390. }
  1391.  
  1392. /*
  1393.     Open a file for input.
  1394.     Return TRUE if all went well.
  1395. */
  1396. bool
  1397. sysopen(char * name)
  1398. {
  1399.     TRACEP("sysopen", printf("(%s)\n", name));
  1400.  
  1401.     /* Actually open the file. */
  1402.     s_ih = raw_open(name);
  1403.     if (s_ih == ERROR) {
  1404.         return FALSE;
  1405.     }
  1406.     else {
  1407.         s_eof = FALSE;
  1408.         s_ic = 0;
  1409.         s_ip = ibuffer;
  1410.         *s_bufp = '\0';
  1411.         sysnext();
  1412.         return TRUE;
  1413.     }
  1414. }
  1415.  
  1416. /*
  1417.     Close a file opened with raw_open() or raw_creat().
  1418. */
  1419. static void
  1420. raw_close(int handle)
  1421. {
  1422.     TRACEP("raw_close", printf("(%d)\n", handle));
  1423.  
  1424.     close (handle);
  1425. }
  1426.  
  1427. /*
  1428.     Open the file for writing only.
  1429.     Return a handle (int) or ERROR.
  1430. */
  1431. static int
  1432. raw_creat(char * name)
  1433. {
  1434.  
  1435.     TRACEP("raw_creat", printf("(%s)\n", name));
  1436.  
  1437. #ifdef MICRO_SOFT
  1438.     chmod(name, S_IREAD | S_IWRITE);
  1439.     return creat(name, S_IREAD | S_IWRITE);
  1440. #endif
  1441.  
  1442. #ifdef TURBOC
  1443.     chmod(name, S_IREAD | S_IWRITE);
  1444.     return creat(name, S_IREAD | S_IWRITE);
  1445. #endif
  1446.  
  1447. }
  1448.  
  1449. /*
  1450.     Open the file for reading only.
  1451.     Return a handle (int) or ERROR.
  1452. */
  1453. static int
  1454. raw_open(char * name)
  1455. {
  1456.     TRACEP("raw_open", printf("(%s)\n", name));
  1457.  
  1458.     return open(name, O_RDONLY | O_BINARY);
  1459. }
  1460.  
  1461. /*
  1462.     Read n bytes from the file described by handle into buffer[].
  1463.     Return the number of bytes read.
  1464. */
  1465. static int
  1466. raw_read(int handle, char * buffer, int n)
  1467. {
  1468.     int result;
  1469.  
  1470.     TRACEP("raw_read", printf("(handle: %d, buffer: %p, n: %d)\n",
  1471.         handle, buffer, n));
  1472.         
  1473.     result = read (handle, buffer, n);
  1474.     TRACEP("raw_read", printf("returns %d\n", result));
  1475.     return result;
  1476. }
  1477.  
  1478. /*
  1479.     Write n bytes from buffer[] to the file described by handle.
  1480.     Return the number of bytes written.
  1481. */
  1482. static int
  1483. raw_write(int handle, char * buffer, int n)
  1484. {
  1485.     TRACEP("raw_write", printf("(handle: %d, buffer: %p, n: %d)\n",
  1486.         handle, buffer, n));
  1487.         
  1488.     return write (handle, buffer, n);    
  1489. }
  1490.  
  1491.  
  1492. /*
  1493.     ----- OUTPUT LOGIC -----
  1494. */
  1495.  
  1496. /*
  1497.     Open a file for output.  Only one such file may be open at a time.
  1498.  
  1499.     Return TRUE if all went well.
  1500. */
  1501. bool
  1502. syscreat(char * name)
  1503. {
  1504.     TRACEP("syscreat", printf("(%s)\n", name));
  1505.  
  1506.     /* Actually open the file. */
  1507.     s_oh = raw_creat(name);
  1508.     if (s_oh == ERROR) {
  1509.         return FALSE;
  1510.     }
  1511.     else {
  1512.         /* The output buffer is empty. */
  1513.         s_oc = 0;
  1514.         s_op = obuffer;
  1515.         return TRUE;
  1516.     }
  1517. }
  1518.  
  1519. /*
  1520.     Close the output file(s).
  1521. */
  1522. void
  1523. sysoclose(void)
  1524. {
  1525.     TICK("sysoclose");
  1526.  
  1527.     if (s_oh != ERROR) {
  1528.         syscput(END_FILE);
  1529.         raw_write(s_oh, obuffer, s_oc);
  1530.         raw_close(s_oh);
  1531.         s_oh = ERROR;
  1532.     }
  1533. }
  1534.  
  1535. /*
  1536.     Put a newline to the output file.
  1537. */
  1538. void
  1539. sysnlput(void)
  1540. {
  1541.     STAT("sysnlput");
  1542.  
  1543.     /* syscput('\r'); bug fix: 11/9/88 */
  1544.     syscput('\n');
  1545.  
  1546.     /* Give user a chance to stop. */
  1547.     syscsts();
  1548. }
  1549.  
  1550. /*
  1551.     Put a non-newline to the output file.
  1552.     This is the most called routine after sysnext().
  1553. */
  1554. void
  1555. syscput(char c)
  1556. {
  1557.     TRACEP("syscput", printf("(%x = %c); s_oc=%d\n", c, c, s_oc));
  1558.  
  1559.     *s_op++ = c;
  1560.     s_oc++;
  1561.     if (s_oc == OBUF_SIZE) {
  1562.         if (raw_write(s_oh, obuffer, OBUF_SIZE) != OBUF_SIZE) {
  1563.             printf("Disk full\n");
  1564.             sysabort();
  1565.             return;
  1566.         }
  1567.         else {
  1568.             s_oc = 0;
  1569.             s_op = obuffer;
  1570.         }
  1571.     }
  1572. }
  1573.  
  1574. /*
  1575.     Put one string to the output file.
  1576. */
  1577. void
  1578. syssput(char *s)
  1579. {
  1580.     while (*s) {
  1581.         syscput(*s++);
  1582.     }
  1583. }
  1584.  
  1585. /*
  1586.     Return 0 if no character is ready from the keyboard.
  1587.     Otherwise, return the character itself.
  1588. */
  1589. static int
  1590. syscstat(void)
  1591. {
  1592.  
  1593. #ifdef MICRO_SOFT
  1594.     if (kbhit()) {
  1595.         return fgetchar() & 0x7f;
  1596.     }
  1597.     else {
  1598.         return 0;
  1599.     }
  1600. #endif
  1601.  
  1602. #ifdef TURBOC
  1603.     if (kbhit()) {
  1604.         return fgetchar() & 0x7f;
  1605.     }
  1606.     else {
  1607.         return 0;
  1608.     }
  1609. #endif
  1610.         
  1611.  
  1612. }
  1613.  
  1614. /*
  1615.     Get console status and pause if the user has hit control S.
  1616.     Abort if user has hit control C.
  1617. */
  1618.  
  1619. #define CONTROL_C 3
  1620.  
  1621. void
  1622. syscsts(void)
  1623. {
  1624.     int c;
  1625.  
  1626.     c = syscstat();
  1627.  
  1628.     if (c == CONTROL_C) {
  1629.         printf("\nCompilation aborted by operator.\n");
  1630.         sysabort();
  1631.     }
  1632. }
  1633.