home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 319_02 / sys.c < prev    next >
C/C++ Source or Header  |  1990-06-18  |  14KB  |  737 lines

  1. /*
  2.     CPP V5 -- system module.
  3.  
  4.     Source:  sys.c
  5.     Started: October 7, 1985
  6.     Version:
  7.         May 26, 1988
  8.         August 1, 1989
  9.             Stamp out the extra newline bug in sysnlput().
  10.  
  11.     Written by Edward K. Ream.
  12.     This software is in the public domain.
  13.  
  14.     See the read.me file for disclaimer and other information.
  15. */
  16.  
  17. #include "cpp.h"
  18.  
  19. #ifdef MICRO_SOFT
  20. #include <fcntl.h>
  21. #include <sys\types.h>
  22. #include <sys\stat.h>
  23. #include <io.h>
  24. #include <time.h>
  25. #endif
  26.  
  27. #ifdef TURBOC
  28. #include <fcntl.h>
  29. #include <sys\stat.h>
  30. #include <io.h>
  31. #include <conio.h>
  32. #include <time.h>
  33. #endif
  34.  
  35. /*
  36.     Define the format of a file node.
  37.     The node contains all information pertaining to the file.
  38.     The fil_name and f_line are used to update preprocessor globals.
  39. */
  40. typedef enum { NULL_STAT,
  41.     CLOSED_STAT, INPUT_STAT, OUTPUT_STAT, LOCAL_STAT, EOF_STAT
  42. } en_stat;
  43.  
  44. static struct FN {
  45.     struct FN * f_next;    /* pointer to next node        */
  46.     char *    fil_name;    /* file name            */
  47.     int    f_line;        /* line number            */
  48.     char *    f_buffer;    /* file buffer            */
  49.     int    f_bufsize;    /* size of file buffer: bytes    */
  50.     int    f_handle;    /* handle to file.        */
  51.     char *  f_bufp;        /* pointer into file buffer    */
  52.     int    f_bufc;        /* characters in buffer        */
  53.     en_stat    f_type;        /* status of file        */
  54.     int    f_lastc;    /* restart character        */
  55. };
  56. #define FN_SIZE (sizeof(struct FN))
  57.  
  58. static struct FN * in_list   = NULL;    /* List of input nodes.        */
  59. static struct FN * outn_list = NULL;    /* List of output nodes.    */
  60.  
  61. /*
  62.     The following global variables are copies of the fields in FN.
  63.     Global variables are used as an efficiency measure.
  64. */
  65. static char *    s_ip = NULL;    /* Copy of f_bufp for input file.    */
  66. static int    s_ic = 0;        /* Copy of f_bufc for input file.    */
  67. static char *    s_op = NULL;    /* Copy of f_bufp for output file.    */
  68. static int    s_oc = 0;    /* Copy of f_bufc for output file.    */
  69.  
  70. #define MAX_INLEVEL 20    /* Max depth of nested #includes.    */
  71. #define IBUF_SIZE 2048    /* Size of each input buffer.        */
  72. #define OBUF_SIZE 2048    /* Size of the output buffer.        */
  73.  
  74. /*
  75.     Define "pushed back" characters used by sysn1().
  76. */
  77. static int    push_back = -1;        /* Used by macro logic.        */
  78. static int    file_put_back = -1;    /* Used by non-macro logic.    */
  79.  
  80. /*
  81.     Define variables used by time and date routines.
  82. */
  83. static    long ltime;
  84. static    struct tm *newtime;
  85. static char time_buf [30];
  86. static char date_buf [30];
  87.  
  88. /*
  89.     Declare static functions in this module.
  90. */
  91. static void    raw_close    (int);
  92. static int    raw_creat    (char *);
  93. static int    raw_open    (char *);
  94. static int    raw_read    (int, char *, int);
  95. static int    raw_write    (int, char *, int);
  96. static int    syscstat    (void);
  97. static void    sysn1        (void);
  98. static struct FN *sys_new    (int);
  99. static void    sys_release    (void);
  100.  
  101. /*
  102.     Close a file opened with raw_open() or raw_creat().
  103. */
  104. static void
  105. raw_close(handle)
  106. int handle;
  107. {
  108.     TRACEP("raw_close", printf("(handle: %d)\n", handle));
  109.  
  110.     close (handle);
  111. }
  112.  
  113. /*
  114.     Open the file for writing only.
  115.     Return a handle (int) or ERROR.
  116. */
  117. static int
  118. raw_creat(name)
  119. char *name;
  120. {
  121.  
  122.     TRACEP("raw_creat", printf("(%s)\n", name));
  123.  
  124.     chmod(name, S_IREAD | S_IWRITE);
  125.     return creat(name, S_IREAD | S_IWRITE);
  126. }
  127.  
  128. /*
  129.     Open the file for reading only.
  130.     Return a handle (int) or ERROR.
  131. */
  132. static int
  133. raw_open(name)
  134. char *name;
  135. {
  136.     TRACEP("raw_open", printf("(%s)\n", name));
  137.  
  138.     return open(name, O_RDONLY | O_BINARY);
  139. }
  140.  
  141. /*
  142.     Read n bytes from the file described by handle into buffer[].
  143.     Return the number of bytes read.
  144. */
  145. static int
  146. raw_read(handle, buffer, n)
  147. int handle;
  148. char *buffer;
  149. int n;
  150. {
  151.     int result;
  152.  
  153.     TRACEP("raw_read", printf("(handle: %d, buffer: %lx, n: %d)\n",
  154.         handle, buffer, n));
  155.         
  156.     result = read (handle, buffer, n);
  157.  
  158.     TRACEP("raw_read", printf("returns %d\n", result));
  159.     return result;
  160. }
  161.  
  162. /*
  163.     Write n bytes from buffer[] to the file described by handle.
  164.     Return the number of bytes written.
  165. */
  166. static int
  167. raw_write(handle, buffer, n)
  168. int handle;
  169. char *buffer;
  170. int n;
  171. {
  172.     TRACEP("raw_write", printf("(handle: %dx, buffer: %lx, n: %d)\n",
  173.         handle, buffer, n));
  174.         
  175.     return write (handle, buffer, n);    
  176. }
  177.  
  178. /*
  179.     Close all files and exit.
  180.  
  181.     Do not call fatal() or sysabort() from inside
  182.     sysiclose(), sysoclose(), or sys_release().
  183. */
  184. void
  185. sysabort()
  186. {
  187.     /* Close the output file. */
  188.     if (outn_list != NULL) {
  189.         sysoclose();
  190.     }
  191.  
  192.     /* Close all input files. */
  193.     while(in_list != NULL) {
  194.         sysiclose();
  195.     }
  196.     sysend();
  197.     exit(BAD_EXIT);
  198. }        
  199.  
  200. /*
  201.     Put a non-newline to the output file.
  202.     This is the second most called routine after sysnext().
  203. */
  204. void
  205. syscput(c)
  206. char c;
  207. {
  208.     struct FN * fnp;
  209.  
  210.     *s_op++ = c;
  211.     s_oc++;
  212.     if (s_oc == OBUF_SIZE) {
  213.  
  214.         fnp = outn_list;
  215.         if (raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE) != 
  216.             OBUF_SIZE) {
  217.             error("Disk full.");
  218.             return;
  219.         }
  220.         
  221.         s_oc = 0;
  222.         s_op = fnp -> f_buffer;
  223.     }
  224. }
  225.  
  226. /*
  227.     Open a file for output.  Only one such file may be open at a time.
  228.  
  229.     Return TRUE if all went well.
  230. */
  231. bool
  232. syscreat(name)
  233. register char * name;
  234. {
  235.     register struct FN * fnp;
  236.     int handle;
  237.  
  238.     TRACEP("syscreat", printf("(%s)\n", name));
  239.  
  240.     fnp = outn_list;
  241.     if (fnp == NULL) {
  242.         /* Allocate node for output file. */
  243.         fnp = outn_list  = sys_new(OBUF_SIZE);
  244.     }
  245.     else if (fnp -> f_type != CLOSED_STAT) {
  246.         syserr("syscreat: Can't happen.");
  247.     }
  248.     
  249.     /* Actually open the file. */
  250.     handle = raw_creat(name);
  251.     if (handle == ERROR) {
  252.         return FALSE;
  253.     }
  254.     fnp -> f_handle = handle;
  255.     fnp -> f_type = OUTPUT_STAT;
  256.  
  257.     /* The output buffer is empty. */
  258.     s_oc = 0;
  259.     s_op = fnp -> f_buffer;
  260.  
  261.     return TRUE;
  262. }
  263.  
  264. /*
  265.     Return 0 if no character is ready from the keyboard.
  266.     Otherwise, return the character itself.
  267. */
  268. static int
  269. syscstat()
  270. {
  271.     if (kbhit()) {
  272.         return fgetchar() & 0x7f;
  273.     }
  274.     else {
  275.         return 0;
  276.     }
  277. }
  278.  
  279. /*
  280.     Get console status and pause if the user has hit control S.
  281.     Abort if user has hit control C.
  282. */
  283.  
  284. #define CONTROL_C 3
  285.  
  286. void
  287. syscsts()
  288. {
  289.     int c;
  290.  
  291.     c = syscstat();
  292.     if (c == CONTROL_C) {
  293.         printf("\nCompilation aborted by operator.\n");
  294.         sysabort();
  295.     }
  296. }
  297.  
  298. /*
  299.     Return the print string of the current date.
  300. */
  301. char *
  302. sysdate()
  303. {
  304.     char *p;
  305.  
  306.     time(<ime);    
  307.     newtime = localtime(<ime);
  308.     p = asctime(newtime);
  309.     if (strlen(p) != 25) {
  310.         return "";
  311.     }
  312.     else {
  313.         strcpy(date_buf, "\"");
  314.         p[11] = '\0';
  315.         strcat(date_buf, p);
  316.         p[24] = '\0';
  317.         strcat(date_buf, p + 20);
  318.         strcat(date_buf, "\"");
  319.  
  320.         TRACEPN("sysdate", printf("returns: %s\n", date_buf));
  321.         return date_buf;
  322.     }
  323. }
  324.  
  325. /*
  326.     Shut down the system.  This routine is called just before doing an
  327.     exit().  Do any last minute things here.
  328. */
  329. void
  330. sysend()
  331. {
  332.     TICK("sysend");
  333. }
  334.  
  335. /*
  336.     Push c back into the file input stream, not the macro input stream.
  337. */
  338. void
  339. sys_fpb(c)
  340. int c;
  341. {
  342.     file_put_back = c;
  343. }
  344.  
  345. /*
  346.     Close the current input file and pop back one level.
  347. */
  348. void
  349. sysiclose()
  350. {
  351.     register struct FN * fnp;
  352.  
  353.     TICK("sysiclose");
  354.  
  355. #ifdef DEBUG
  356.     if (t_inlevel < 0) {
  357.         syserr("sysiclose: Bad t_inlevel.");
  358.     }
  359. #endif
  360.  
  361.     /* Close the current input file. */
  362.     fnp = in_list;    
  363.     raw_close(fnp -> f_handle);
  364.  
  365.     /* Release the current node. */
  366.     sys_release();
  367.     if (t_inlevel > 0 && in_list == NULL) {
  368.         syserr("sysiclose: NULL in_list.");
  369.     }
  370.  
  371.     /* Pop back one level. */
  372.     if (in_list != NULL) {
  373.         if (t_inlevel < 0) {
  374.             syserr("sysiclose: Unexpected in_list.");
  375.         }
  376.         fnp = in_list;
  377.         s_ic = fnp -> f_bufc;
  378.         s_ip = fnp -> f_bufp;
  379.         t_file = fnp -> fil_name;
  380.         t_line = fnp -> f_line;
  381.     }
  382.     t_inlevel--;
  383.  
  384.     if (t_inlevel == -1) {
  385.         ch = END_FILE;
  386.         TRACEPN("sysiclose", printf("restarts. ch=END_FILE\n"));
  387.     }
  388.     else {
  389.         ch = (unsigned char) fnp -> f_lastc;
  390.         TRACEPN("sysiclose", printf("retarts. ch=lastc: %s\n",
  391.             pr_ch(ch)));
  392.     }
  393.         
  394.     TRACEP("sysiclose", printf("exit: t_inlevel=%d\n", t_inlevel));
  395. }
  396.  
  397. /*
  398.     Allocate space for a new file node and file buffer.
  399.     Fill in all other fields to neutral values.
  400. */
  401. static struct FN *
  402. sys_new(buf_size)
  403. int buf_size;
  404. {
  405.     register struct FN * fnp;
  406.  
  407.     TRACEP("sys_new", printf("(buf_size: %d)\n", buf_size));
  408.  
  409.     fnp         = (struct FN *) m_alloc(sizeof(struct FN));
  410.     fnp -> f_buffer     = (char *)      m_alloc(buf_size);
  411.     fnp -> f_bufsize = buf_size;
  412.  
  413.     fnp -> f_next    = NULL;
  414.     fnp -> fil_name    = NULL;
  415.     fnp -> f_bufp    = fnp -> f_buffer;
  416.     fnp -> f_bufc    = 0;
  417.     fnp -> f_type    = CLOSED_STAT;
  418.  
  419.     TRACEPN("sys_new", printf("returns %lx\n", fnp));
  420.     return fnp;
  421. }
  422.  
  423. /*
  424.     Set the global variable ch to the next character from the input stream.
  425.     This is the most often called routine in the whole program.
  426. */
  427. void
  428. sysnext()
  429. {
  430.     for(;;) {
  431.         sysn1();
  432.  
  433.         /* Intercept backslash newline combinations here. */
  434.         if (ch == '\\') {
  435.  
  436.             /* 3/3/89 */
  437.             sysn1();
  438.             while (ch == '\r') {
  439.                 sysn1();
  440.             }
  441.             
  442.             if (ch == '\n') {
  443.                 t_line++;
  444.                 continue;
  445.             }
  446.             else {
  447.                 push_back = ch;
  448.                 ch = '\\';
  449.                 return;
  450.             }
  451.         }
  452.         /* Filter out all carriage returns. */
  453.         else if (ch != '\r') {
  454.             return;
  455.         }
  456.     }
  457. }
  458.         
  459. static void
  460. sysn1()
  461. {
  462.     register int n;
  463.     register struct FN * fnp;
  464.  
  465.     /* Priority 1: A pushed back character. */
  466.     if (push_back != -1) {
  467.         ch = push_back;
  468.         TRACEP("sysnext", printf("pushback: %s\n", pr_ch(ch)));
  469.         push_back = -1;
  470.         return;
  471.     }
  472.  
  473.     /* Priority 2:  The rescan buffer. */
  474.     if (m_flag) {
  475.         ch = *p_rescan++;
  476.         if (ch) {
  477.             TRACEP("sysnext", printf("rescan ch: %s\n",
  478.                 pr_ch(ch)));
  479.             return;
  480.         }
  481.         m_flag = FALSE;
  482.  
  483.         /*
  484.             Priority 2A:  The trailing character.
  485.             This is NOT part of the rescan buffer.
  486.         */
  487.         if (file_put_back != -1) {
  488.             ch = file_put_back;
  489.             TRACEP("sysnext", printf("fpb ch: %s\n",
  490.                 pr_ch(ch)));
  491.             file_put_back = -1;
  492.             return;
  493.         }
  494.         /* FALL THROUGH. */
  495.     }
  496.  
  497.     /* Priority 3:  The current file. */
  498.     if (s_ic > 0) {
  499.         s_ic--;
  500.         ch = *s_ip++;
  501.         TRACEP("sysnext_v", printf("ch: %s\n", pr_ch(ch)));
  502.         return;
  503.     }
  504.  
  505.     /* A file or local buffer is empty. */
  506.     fnp = in_list;
  507.     switch(fnp -> f_type) {
  508.  
  509.     case EOF_STAT:
  510.         /* Continue returning END_FILE until the file is closed. */
  511.         ch = END_FILE;
  512.         return;
  513.  
  514.     case INPUT_STAT:
  515.         n = raw_read(fnp->f_handle, fnp->f_buffer, IBUF_SIZE);
  516.         if (n > 0) {
  517.             s_ic  = n;
  518.             s_ip = fnp -> f_buffer;
  519.             s_ic--;
  520.             ch = *s_ip++;
  521.         }
  522.         else {
  523.             fnp -> f_type = EOF_STAT;
  524.             ch = END_FILE;
  525.         }
  526.         return;
  527.  
  528.     default:
  529.         TRACEP("sysn1",
  530.             printf("in_list = %lx, in_list -> f_type = %d\n",
  531.                 in_list, in_list -> f_type));
  532.  
  533.         syserr("sysn1: Bad f_type field.");
  534.     }
  535. }
  536.  
  537. /*
  538.     Put a newline to the output file.
  539. */
  540. void
  541. sysnlput()
  542. {
  543.     STAT("sysnlput");
  544.  
  545.     /* 8/1/89 ----- file is open for text, not binary.
  546.     syscput('\r');
  547.     ----- */
  548.  
  549.     syscput('\n');
  550.  
  551.     /* Give user a chance to stop. */
  552.     syscsts();
  553. }
  554.  
  555. /*
  556.     Close the output file(s).
  557. */
  558. void
  559. sysoclose()
  560. {
  561.     register struct FN * fnp;
  562.  
  563.     TICK("sysoclose");
  564.  
  565.     fnp = outn_list;
  566.     if (fnp != NULL && fnp -> f_type != CLOSED_STAT) {
  567.         syscput(END_FILE);
  568.         raw_write(fnp -> f_handle, fnp -> f_buffer, s_oc);
  569.         raw_close(fnp -> f_handle);
  570.         fnp -> f_type = CLOSED_STAT;
  571.     }
  572. }
  573.  
  574. /*
  575.     Open a file for input.
  576.     Return TRUE if all went well.
  577. */
  578. bool
  579. sysopen(name)
  580. char *name;
  581. {
  582.     struct FN * fnp;
  583.     int handle;
  584.  
  585.     TRACEP("sysopen", printf("(%s); old t_inlevel = %d\n",
  586.         name, t_inlevel));
  587.  
  588.     if (m_flag == TRUE) {
  589.         m_flag = FALSE;
  590.         error("Macro expansion truncated following #include.");
  591.     }
  592.  
  593.     /* Save information about the current level on the stack. */
  594.     if (t_inlevel != -1) {
  595.         if (in_list == NULL) {
  596.             syserr("sysopen: Can't happen.");
  597.         }
  598.         fnp = in_list;
  599.         fnp -> f_line = t_line;
  600.         fnp -> f_bufc = s_ic;
  601.         fnp -> f_bufp = s_ip;
  602.         fnp -> f_lastc = (int) ch;
  603.     }
  604.  
  605.     /* Enter a new level. */
  606.     if (t_inlevel >= MAX_INLEVEL) {
  607.         fatal("include files nested too deeply");
  608.     }
  609.     else {
  610.         t_inlevel++;
  611.     }
  612.  
  613.     /* Create a new file node and link to the front of the list. */
  614.  
  615.     TRACEP("sysopen", printf("set up new file: call sys_new\n"));
  616.  
  617.     fnp          = sys_new(IBUF_SIZE);
  618.     fnp -> f_next = in_list;
  619.     fnp -> f_type = INPUT_STAT;
  620.     in_list       = fnp;
  621.  
  622.     /* Actually open the file. */
  623.  
  624.     handle = raw_open(name);
  625.     if (handle == ERROR) {
  626.  
  627.         /* Deallocate the node. */
  628.         TRACEP("sysopen", printf("file open %s fails\n", name));
  629.         sys_release();
  630.         t_inlevel--;
  631.         return FALSE;
  632.     }
  633.     else {
  634.         fnp -> f_handle = handle;
  635.     }
  636.  
  637.     /* Set the global variables. */
  638.     t_file = str_alloc(name);
  639.     t_line = 1;
  640.     fnp -> fil_name = t_file;
  641.  
  642.     /* Put the first character of the file into ch. */
  643.     s_ic = 0;
  644.     s_ip = fnp -> f_buffer;
  645.     sysnext();
  646.  
  647.     TRACEP("sysopen", printf("exit: t_inlevel=%d, in_list=%lx\n",
  648.                         t_inlevel, (long)in_list));
  649.     return TRUE;
  650. }
  651.  
  652. /*
  653.     Push back c so that sysnext() will return it next.
  654. */
  655. void
  656. syspushback(c)
  657. int c;
  658. {
  659.     push_back = c;
  660. }
  661.  
  662. /*
  663.     Remove one node from the input list.
  664. */
  665. static void
  666. sys_release()
  667. {
  668.     register struct FN * fnp;
  669.  
  670.     TICK("sys_release");
  671.  
  672. #ifdef DEBUG
  673.     if (in_list == NULL) {
  674.         syserr("sys_release: Can't happen.");
  675.     }
  676. #endif
  677.  
  678.     /* Remove the node from the input list. */
  679.     fnp     = in_list;
  680.     in_list = fnp -> f_next;
  681.     fnp -> f_type = CLOSED_STAT;
  682.  
  683.     /* Deallocate the node. */
  684.     if (fnp -> f_buffer != NULL) {
  685.         m_free(fnp -> f_buffer);
  686.     }
  687.     m_free(fnp);
  688.  
  689.     /* Reset the global variables from the next node. */
  690.     if (in_list == NULL) {
  691.         s_ic = 0;
  692.     }
  693.     else {
  694.         fnp = in_list;
  695.         s_ic = fnp -> f_bufc;
  696.         s_ip = fnp -> f_bufp;
  697.     }
  698. }
  699.  
  700. /*
  701.     Put one string to the output file.
  702. */
  703. void
  704. syssput(s)
  705. register char * s;
  706. {
  707.     TRACEP("syssput", printf("(%s)\n", s));
  708.  
  709.     while (*s) {
  710.         syscput(*s++);
  711.     }
  712. }
  713.  
  714. /*
  715.     Return a print string of the current time.
  716. */
  717. char *
  718. systime()
  719. {
  720.     char *p;
  721.  
  722.     time(<ime);    
  723.     newtime = localtime(<ime);
  724.     p = asctime(newtime);
  725.     if (strlen(p) != 25) {
  726.         return "\"\"";
  727.     }
  728.     else {
  729.         strcpy(time_buf, "\"");
  730.         *(p+19) = '\0';
  731.         strcat(time_buf, p+11);
  732.         strcat(time_buf, "\"");
  733.         TRACEPN("systime", printf("returns: %s\n", time_buf));
  734.         return time_buf;
  735.     }
  736. }
  737.