home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 357_01 / cstar1.exe / SYS.C < prev    next >
C/C++ Source or Header  |  1991-06-18  |  15KB  |  776 lines

  1. /*
  2.     C* -- System Interface Module with IO redirection support.
  3.  
  4.     Source:  cppsys.c
  5.     Started: October 7, 1985
  6.     Version:
  7.         April 2, 1987
  8.         March 7, 1989
  9.  
  10.     PUBLIC DOMAIN SOFTWARE
  11.  
  12.     The CSTAR program was placed in    the public domain on June 15, 1991,
  13.     by its author and sole owner,
  14.  
  15.         Edward K. Ream
  16.         1617 Monroe Street
  17.         Madison, WI 53711
  18.         (608) 257-0802
  19.  
  20.     CSTAR may be used for any commercial or non-commercial purpose.
  21.  
  22.     See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
  23. */
  24. #include "cstar.h"
  25.  
  26. /* Define STANDARD_C if the Compiler uses the standard C library. */
  27. #define STANDARD_C 1
  28.  
  29. #ifdef MICRO_SOFT
  30. #include <fcntl.h>
  31. #include <sys\types.h>
  32. #include <sys\stat.h>
  33. #include <io.h>
  34. #endif
  35.  
  36. #ifdef TURBOC
  37. #include <fcntl.h>
  38. #include <sys\stat.h>
  39. #include <io.h>
  40. #include <dos.h>
  41. #endif
  42.  
  43. /*
  44.     Externally visible routines:
  45. */
  46. void    sysabort    (void);
  47. void    sysnext        (void);
  48. void    syspush        (int c);
  49. void    sysspush    (char *s);
  50. void    sysiclose    (void);
  51. bool    sysopen        (char * name);
  52. bool    syscreat    (char * name);
  53. void    sysoclose    (void);
  54. void    sysnlput    (void);
  55. void    syscput        (char c);
  56. void    syssput        (char * s);
  57. void    sysend        (void);
  58. void    sysinit        (void);
  59. int    syscsts        (void);
  60.  
  61. /*
  62.     Internal routines:
  63. */
  64. static void    sys_release    (void);
  65. static struct FN *
  66.         sys_new        (int buf_size);
  67. static void    sysnx1        (void);
  68. static void    sys_close    (register struct FN * fnp, int count);
  69. static void    raw_close    (int handle);
  70. static int    raw_creat    (char *name);
  71. static int    raw_open    (char *name);
  72. static int    raw_read    (int handle, char *buffer, int n);
  73. static void    raw_write    (int handle, char *buffer, int n);
  74.  
  75.  
  76. /*
  77.     Define the format of a file node.
  78.  
  79.     The node contains all information pertaining to the file.
  80.     The fil_name and f_line are used to update preprocessor globals.
  81.     The f_line field is not used for output files.
  82. */
  83. static struct FN {
  84.     struct FN * f_next;    /* pointer to next node        */
  85.     char *    fil_name;    /* file name            */
  86.     int    f_line;        /* line number            */
  87.     char *    f_buffer;    /* file buffer            */
  88.     int    f_bufsize;    /* size of file buffer: bytes    */
  89.     int    f_handle;    /* File handle.            */
  90.     char *  f_bufp;        /* pointer into file buffer    */
  91.     int    f_bufc;        /* characters in buffer        */
  92.     int    f_type;        /* INPUT, OUTPUT, EOF_STAT, CLOSED    */
  93.     int    f_lastc;    /* last character of previous level */
  94. };
  95. #define FN_SIZE (sizeof(struct FN))
  96.  
  97. static struct FN * in_list;    /* List of input nodes.        */
  98. static struct FN * outn_list;    /* List of output nodes.    */
  99.  
  100. /*
  101.     The following global variables are copies of the fields in FN.
  102.     Global variables are used as an efficiency measure.
  103. */
  104. static char * s_ip;        /* Copy of f_bufp for input file.    */
  105. static int    s_ic;        /* Copy of f_bufc for input file.    */
  106. static char * s_op;    /* Copy of f_bufp for output file.    */
  107. static int    s_oc;    /* Copy of f_bufc for output file.    */
  108.  
  109. #define CLOSED 1
  110. #define INPUT 2
  111. #define OUTPUT 3
  112. #define EOF_STAT 3
  113.     
  114. /*
  115.     You may tune the following constants:
  116.  
  117.     MAX_INLEVEL    the greatest allowed depth for nested #includes.
  118.     IBUF_SIZE    size of each input buffer in bytes.
  119.     OBUF_SIZE    size of the output buffer in bytes.
  120. */
  121. #define MAX_INLEVEL 20
  122. #define IBUF_SIZE 4096
  123. #define OBUF_SIZE 4096
  124.  
  125. /*
  126.     Close all files and exit.
  127.  
  128.     Do not call fatal() or sysabort() from inside
  129.     sysiclose(), sysoclose(), or sys_release().
  130. */
  131. void
  132. sysabort(void)
  133. {
  134.     SL_DISABLE();
  135.  
  136.     /* Close the output file. */
  137.     if (outn_list != NULL) {
  138.         sysoclose();
  139.     }
  140.  
  141.     /* Close all input files. */
  142.     while(in_list != NULL) {
  143.         sysiclose();
  144.     }
  145.     sysend();
  146.     exit(1);
  147. }        
  148.  
  149. /*
  150.     Remove one node from the input list.
  151. */
  152. static void
  153. sys_release(void)
  154. {
  155.     register struct FN * fnp;
  156.  
  157.     TICKB("sys_release");
  158.  
  159. #ifdef DEBUG
  160.     if (in_list == NULL) {
  161.         t_error("sys_release: can't happen");
  162.         exit(0);
  163.     }
  164. #endif
  165.  
  166.     /* Remove the node from the input list. */
  167.     fnp     = in_list;
  168.     in_list = fnp -> f_next;
  169.     fnp -> f_type = CLOSED;
  170.  
  171.     /* Deallocate the node. */
  172.     if (fnp -> f_buffer != NULL) {
  173.         mg_free(fnp -> f_buffer);
  174.     }
  175.     mg_free( (char *) fnp);
  176.  
  177.     /* Reset the global variables from the next node. */
  178.     if (in_list != NULL) {
  179.         fnp = in_list;
  180.         s_ic = fnp -> f_bufc;
  181.         s_ip = fnp -> f_bufp;
  182.     }
  183.     else {
  184.         s_ic = 0;
  185.     }
  186.  
  187.     TICKX("sys_release");
  188. }
  189.  
  190. /*
  191.     Allocate space for a new file node, file buffer and FCB.
  192.     Fill in all other fields to neutral values.
  193.     Return a pointer to the node.
  194. */
  195. static struct FN *
  196. sys_new(int buf_size)
  197. {
  198.     register struct FN * fnp;
  199.  
  200.     TRACEPB("sys_new", printf("(%d)\n", buf_size));
  201.  
  202.     fnp         = (struct FN *) mg_alloc(sizeof(struct FN));
  203.     fnp -> f_buffer     = (char *)     mg_alloc(buf_size);
  204.     fnp -> f_bufsize = buf_size;
  205.     fnp -> f_next    = NULL;
  206.     fnp -> fil_name    = NULL;
  207.     fnp -> f_bufp    = fnp -> f_buffer;
  208.     fnp -> f_bufc    = 0;
  209.     fnp -> f_type    = CLOSED;
  210.     fnp -> f_handle = -1;
  211.  
  212.     RETURN_PTR("sys_new", fnp);
  213. }
  214.  
  215. /*
  216.     ----- I N P U T    L O G I C -----
  217.  
  218.     Set the global variable ch to the next character from the input stream.
  219.     The next call to sysnext() will return another character.
  220.     This is the most often called routine in the whole program.
  221. */
  222. #define MAX_MTEXT 2000
  223.  
  224. static char    m_buffer [MAX_MTEXT];
  225. static char *    m_oldp;
  226. static int    m_oldc;
  227. static int    m_flag;
  228.  
  229. /* this portion of the routine ought to be a macro */
  230. void
  231. sysnext(void)
  232. {
  233.     SL_DISABLE();
  234.  
  235.     if (!s_ic) {
  236.         sysnx1();
  237.     }
  238.     else {
  239.         s_ic--;
  240.         ch = (unsigned char) *s_ip++;
  241.     }
  242. }
  243.  
  244. /* This fills ch when the buffer is empty */
  245. static void
  246. sysnx1(void)
  247. {
  248.     register int n;
  249.     register struct FN * fnp;
  250.  
  251.     TICKB("sysnx1");
  252.  
  253.     if (m_flag == TRUE) {
  254.         /* Close the macro buffer. */
  255.         m_flag = FALSE;
  256.  
  257.         /* Restart the previous buffer. */
  258.         s_ic = m_oldc;
  259.         s_ip = m_oldp;
  260.         if (s_ic) {
  261.             s_ic--;
  262.             ch = (unsigned char) *s_ip++;
  263.             RETURN_VOID("sysnx1");
  264.         }
  265.     }
  266.  
  267.     /* A file buffer is empty. */
  268.     fnp = in_list;
  269.     switch(fnp -> f_type) {
  270.  
  271.     case EOF_STAT:
  272.         ch = END_FILE;
  273.         RETURN_VOID("sysnx1");
  274.  
  275.     case INPUT:
  276.         n = raw_read(fnp->f_handle, fnp->f_buffer, IBUF_SIZE);
  277.         if (n > 0) {
  278.             s_ic  = n;
  279.             s_ip = fnp -> f_buffer;
  280.             s_ic--;
  281.             ch = (unsigned char) *s_ip++;
  282.             RETURN_VOID("sysnx1");
  283.         }
  284.         else {
  285.             fnp -> f_type = EOF_STAT;
  286.             ch = END_FILE;
  287.             RETURN_VOID("sysnx1");
  288.         }
  289.  
  290.     default:
  291.         TRACEP("sysnx1",
  292.             printf("in_list = %p, in_list -> f_type = %d\n",
  293.                 in_list, in_list -> f_type));
  294.         fatal("sysnext: can't happen");
  295.     }
  296.  
  297.     TICKX("sysnx1");
  298. }
  299.  
  300. /*
  301.     Push a character so that it will be returned next by sysnext.
  302.  
  303.     The current value of ch is NOT saved.
  304. */
  305. void
  306. syspush(int c)
  307. {
  308.     SL_DISABLE();
  309.  
  310.     if (m_flag == FALSE) {
  311.  
  312.         TRACEP("syspush", printf("start of macro expansion\n"));
  313.  
  314.         /* Begin to use the macro buffer. */
  315.         m_flag = TRUE;
  316.  
  317.         /* Save the old pointers. */
  318.         m_oldp = s_ip;
  319.         m_oldc = s_ic;
  320.  
  321.         /* Point into the macro buffer. */
  322.         s_ip = &m_buffer[MAX_MTEXT-1];
  323.         *s_ip = (char) c;
  324.         s_ic = 1;
  325.     }
  326.     else if (s_ic >= MAX_MTEXT) {
  327.         fatal("macro expansion too long.");
  328.     }
  329.     else {
  330.         *--s_ip = (char) c;
  331.         s_ic++;
  332.     }
  333. }
  334.     
  335. /*
  336.     Push a string so that it will be returned next by sysnext.
  337. */
  338. void
  339. sysspush(register char *s)
  340. {
  341.     register char *p;
  342.     register int count;
  343.  
  344.     SL_DISABLE();
  345.  
  346.     /* Push in reverse. */
  347.     count = str_len(s);
  348.     p  = s;
  349.     p += count;
  350.     p--;
  351.  
  352.     while(count-- > 0) {
  353.         syspush(*p--);
  354.     }
  355. }
  356.  
  357. /*
  358.     Close the current input file and pop back one level.
  359. */
  360. void
  361. sysiclose(void)
  362. {
  363.     register struct FN * fnp;
  364.  
  365. #ifdef DEBUG
  366.  
  367.     TICKB("sysiclose");
  368.  
  369.     if (t_inlevel < 0) {
  370.         t_error("sysiclose: bad t_inlevel");
  371.         exit(0);
  372.     }
  373. #endif
  374.  
  375.     /* Close the current input file. */
  376.     fnp = in_list;    
  377.     raw_close(fnp -> f_handle);
  378.  
  379.     /* Release the current node. */
  380.     sys_release();
  381.     if (t_inlevel > 0 && in_list == NULL) {
  382.         t_error("sysiclose: null in_list");
  383.         exit(0);
  384.     }
  385.  
  386.     /* Pop back one level. */
  387.     if (in_list != NULL) {
  388.         if (t_inlevel < 0) {
  389.             t_error("sysiclose: unexpected in_list");
  390.             exit(0);
  391.         }
  392.         fnp = in_list;
  393.         s_ic = fnp -> f_bufc;
  394.         s_ip = fnp -> f_bufp;
  395.         t_file = fnp -> fil_name;
  396.         t_line = fnp -> f_line;
  397.     }
  398.     t_inlevel--;
  399.  
  400.     if (t_inlevel == -1) {
  401.         ch = END_FILE;
  402.     }
  403.     else {
  404.         ch = (unsigned char) fnp -> f_lastc;
  405.     }
  406.         
  407.     TRACEPX("sysiclose", printf("returns: t_inlevel=%d\n", t_inlevel));
  408. }
  409.  
  410. /*
  411.     Open a file for input.
  412.     Return TRUE if all went well.
  413. */
  414. bool
  415. sysopen(char * name)
  416. {
  417.     struct FN * fnp;
  418.  
  419.     char * str_galloc();
  420.  
  421.     TRACEPB("sysopen", printf("(%s) t_inlevel: %d\n", name, t_inlevel));
  422.  
  423.     if (m_flag == TRUE) {
  424.         m_flag = FALSE;
  425.         t_error("macro expansion truncated following #include");
  426.     }
  427.  
  428.     /* Save information about the current level on the stack. */
  429.     if (t_inlevel != -1) {
  430.         if (in_list == NULL) {
  431.             fatal("sysopen: can't happen\n");
  432.         }
  433.         fnp = in_list;
  434.         fnp -> f_line = t_line;
  435.         fnp -> f_bufc = s_ic;
  436.         fnp -> f_bufp = s_ip;
  437.         fnp -> f_lastc = (int) ch;
  438.     }
  439.  
  440.     /* Enter a new level. */
  441.     if (t_inlevel >= MAX_INLEVEL) {
  442.         t_error("include files nested too deeply");
  443.         exit(0);
  444.     }
  445.     else {
  446.         t_inlevel++;
  447.     }
  448.  
  449.     /* Create a new file node and link to the front of the list. */
  450.     TRACEP("sysopen", printf("set up new file: call sys_new\n"));
  451.  
  452.     fnp = sys_new(IBUF_SIZE);
  453.     fnp -> f_next = in_list;
  454.     in_list = fnp;
  455.     fnp -> f_type = INPUT;
  456.  
  457.     /* Actually open the file. */
  458.     fnp -> f_handle = raw_open(name);
  459.     if (fnp -> f_handle == -1) {
  460.  
  461.         /* Deallocate the node. */
  462.         TRACEP("sysopen", printf("file open %s fails\n", name));
  463.         sys_release();
  464.         t_inlevel--;
  465.         RETURN_BOOL("sysopen", FALSE);
  466.     }
  467.  
  468.     /* Set the global variables. */
  469.     t_file = str_galloc(name);
  470.     t_line = 1;
  471.     fnp -> fil_name = t_file;
  472.  
  473.     /* Put the first character of the file into ch. */
  474.     s_ic = 0;
  475.     s_ip = fnp -> f_buffer;
  476.     sysnext();
  477.  
  478.     TRACEP("sysopen",
  479.         printf("new t_inlevel=%d, in_list=%p\n", t_inlevel, in_list));
  480.  
  481.     RETURN_BOOL("sysopen", TRUE);
  482. }
  483.     
  484. /*
  485.     Close a file opened with raw_open() or raw_creat().
  486. */
  487. static void
  488. raw_close(int handle)
  489. {
  490.     SL_DISABLE();
  491.  
  492. #ifdef STANDARD_C
  493.     close (handle);
  494. #endif
  495.  
  496. }
  497.  
  498. /*
  499.     Open the file for writing only.
  500.     Return -1 on error.
  501. */
  502. static int
  503. raw_creat(char *name)
  504. {
  505.     int h;
  506.  
  507. #ifdef STANDARD_C
  508.  
  509.     TRACEPB("raw_creat", printf("(%s)\n", name));
  510.  
  511.     chmod(name, S_IREAD | S_IWRITE);
  512.  
  513. #ifdef TURBOC
  514.     _fmode = O_BINARY;
  515. #endif /* TURBOC */
  516.  
  517.     RETURN_INT("raw_creat", creat(name, S_IREAD | S_IWRITE));
  518. #endif
  519.  
  520. }
  521.  
  522. /*
  523.     Open the file for reading only.
  524.     Return -1 on error.
  525. */
  526. static bool
  527. raw_open(register char *name)
  528. {
  529.  
  530. #ifdef STANDARD_C
  531.     TRACEPB("raw_open", printf("(%s)\n", name));
  532.  
  533.     RETURN_BOOL("raw_open", open(name, O_RDONLY | O_BINARY));
  534. #endif
  535.  
  536. }
  537.  
  538. /*
  539.     Read n bytes from the file fd into buffer[].
  540.  
  541.     Return the number of bytes read.
  542. */
  543. static int
  544. raw_read(int handle, char *buffer, int n)
  545. {
  546.  
  547. #ifdef STANDARD_C
  548.     TRACEPB("raw_read", printf("(%d, %s, %d)\n", handle, buffer, n));
  549.  
  550.     RETURN_INT("raw_read", read (handle, buffer, n));
  551. #endif
  552.  
  553. }
  554.  
  555. /*
  556.     Write n bytes from buffer[] to the file fd.
  557.  
  558.     Return the number of bytes written or -1 for error.
  559. */
  560. static void
  561. raw_write(int handle, char *buffer, int n)
  562. {
  563.     TRACEPB("raw_write", printf("(%d, %s, %d)\n", handle, buffer, n));
  564.  
  565. #ifdef STANDARD_C
  566.     (void) write (handle, buffer, n);    
  567. #endif
  568.  
  569.     TICKX("raw_write");
  570. }
  571.  
  572. /*
  573.     ----- OUTPUT LOGIC -----
  574. */
  575.  
  576. /*
  577.     Open a file for output.  Only one such file may be open at a time.
  578.  
  579.     Return TRUE if all went well.
  580. */
  581. bool
  582. syscreat(register char * name)
  583. {
  584.     register struct FN * fnp;
  585.  
  586.     TRACEPB("syscreat", printf("(%s)\n", name));
  587.  
  588.     fnp = outn_list;
  589.  
  590. #ifdef DEBUG
  591.     if (fnp == NULL || fnp -> f_type != CLOSED) {
  592.         fatal("syscreat:  can't happen");
  593.     }
  594. #endif
  595.     
  596.     /* Actually open the file. */
  597.     fnp -> f_handle = raw_creat(name);
  598.     if (fnp -> f_handle == -1) {
  599.         RETURN_BOOL("syscreat", FALSE);
  600.     }
  601.     fnp -> f_type = OUTPUT;
  602.  
  603.     /* The output buffer is empty. */
  604.     s_oc = 0;
  605.     s_op = fnp -> f_buffer;
  606.  
  607.     RETURN_BOOL("syscreat", TRUE);
  608. }
  609.  
  610. /*
  611.     Close the output file(s).
  612. */
  613. void
  614. sysoclose(void)
  615. {
  616.     register struct FN * fnp;
  617.  
  618.     TICKB("sysoclose");
  619.  
  620.     fnp = outn_list;
  621.     if (fnp != NULL && fnp -> f_type != CLOSED) {
  622.         syscput(END_FILE);
  623.         sys_close(fnp, s_oc);
  624.     }
  625.  
  626.     TICKX("sysoclose");
  627. }
  628.  
  629. static void
  630. sys_close(register struct FN * fnp, int count)
  631. {
  632.     TRACEPB("sys_close", printf("(%p, %d)\n", fnp, count));
  633.  
  634.     /* Finish writing the last sector(s). */
  635.     if (count) {
  636.         raw_write(fnp->f_handle, fnp->f_buffer, count);
  637.     }
  638.  
  639.     /* Close the file. */
  640.     raw_close(fnp -> f_handle);
  641.     fnp -> f_type = CLOSED;
  642.  
  643.     TICKX("sys_close");
  644. }
  645.  
  646. /*
  647.     Put a newline to the output file.
  648. */
  649. void
  650. sysnlput(void)
  651. {
  652.     struct FN * fnp;
  653.  
  654.     SL_DISABLE();
  655.  
  656.     *s_op++ = '\r';
  657.     s_oc++;
  658.     if (s_oc == OBUF_SIZE) {
  659.         fnp = outn_list;
  660.         raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
  661.         s_op = fnp -> f_buffer;
  662.         *s_op++ = '\n';
  663.         s_oc = 1;
  664.     }
  665.     else {
  666.         *s_op++ = '\n';
  667.         s_oc++;
  668.         if (s_oc == OBUF_SIZE) {
  669.             fnp = outn_list;
  670.             raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
  671.             s_oc = 0;
  672.             s_op = fnp -> f_buffer;
  673.         }
  674.     }
  675.  
  676.     /* Give user a chance to stop. */
  677.     (void) syscsts();
  678. }
  679.  
  680. /*
  681.     Put a non-newline to the output file.
  682.     This is the most called routine after sysnext().
  683. */
  684. void
  685. syscput(char c)
  686. {
  687.     struct FN * fnp;
  688.  
  689.     SL_DISABLE();
  690.  
  691. #ifdef DEBUG
  692.     if (c == '\n') {
  693.         printf("syscput: shouldn't happen\n");
  694.         sysnlput();
  695.         return;
  696.     }
  697. #endif
  698.  
  699.     *s_op++ = c;
  700.     s_oc++;
  701.     if (s_oc == OBUF_SIZE) {
  702.         fnp = outn_list;
  703.         raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
  704.         s_oc = 0;
  705.         s_op = fnp -> f_buffer;
  706.     }
  707. }
  708.  
  709. /*
  710.     Put one string to the output file.
  711. */
  712. void
  713. syssput(register char * s)
  714. {
  715.     SL_DISABLE();
  716.  
  717.     while (*s) {
  718.         syscput(*s++);
  719.     }
  720. }
  721.  
  722. /*
  723.     Shut down the system.  This routine is called just before doing an
  724.     exit(0).  Do any last minute things here.
  725. */
  726. void
  727. sysend(void)
  728. {
  729.     TICK("sysend");
  730. }
  731.  
  732. /*
  733.     Initialize the system module.  This routine is called just once before
  734.     any other calls to this module.  Do any initilizing here.
  735. */
  736. void
  737. sysinit(void)
  738. {
  739.     register struct FN * fnp;
  740.  
  741.     TICKB("sysinit");
  742.  
  743.     /* Portable part. */
  744.     t_inlevel = -1;
  745.     t_line = 0;
  746.     t_file = NULL;
  747.  
  748.     in_list = NULL;
  749.     m_flag = FALSE;
  750.     
  751.     /* Allocate node for output file. */
  752.     outn_list  = sys_new(OBUF_SIZE);
  753.  
  754.     TRACEPX("sysinit", printf("outn_list = %p\n", outn_list));
  755. }
  756.  
  757. /*
  758.     Return 0 if no character is ready from the keyboard.
  759.     Otherwise, return the character itself.
  760. */
  761. int
  762. syscsts(void)
  763. {
  764.     SL_DISABLE();
  765.  
  766. #ifdef STANDARD_C
  767.     if (kbhit()) {
  768.         return fgetchar() & 0x7f;
  769.     }
  770.     else {
  771.         return 0;
  772.     }
  773. #endif
  774.  
  775. }
  776.