home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Moscow ML 1.42 / src / !runtime / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-18  |  9.3 KB  |  421 lines  |  [TEXT/R*ch]

  1. /* Buffered input/output. */
  2.  
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <sys/types.h>
  6. #include "alloc.h"
  7. #include "fail.h"
  8. #include "io.h"
  9. #include "memory.h"
  10. #include "misc.h"
  11. #include "mlvalues.h"
  12. #include "signals.h"
  13. #include "sys.h"
  14. #ifdef HAS_UI
  15. #include "ui.h"
  16. #endif
  17.  
  18. /* Common functions. */
  19.  
  20. /* Improvement suggested by Doug Currie: 
  21.    memoize std_in, std_out and std_err.
  22.    Used also in function flush_stdouterr.
  23.  
  24.    As usual, std_channel[0] = stdin, 
  25.              std_channel[1] = stdout, 
  26.          std_channel[2] = stderr. 
  27. */
  28.  
  29. static struct channel *std_channel[3] = {NULL, NULL, NULL};
  30.  
  31. struct channel * open_descr(fd)
  32.      int fd;
  33. {
  34.   struct channel * channel;
  35.  
  36.   if( (unsigned)fd < 3 && std_channel[fd] != NULL )
  37.     return std_channel[fd];
  38.   channel = (struct channel *) stat_alloc(sizeof(struct channel));
  39.   channel->fd = fd;
  40.   channel->offset = 0;
  41.   channel->curr = channel->max = channel->buff;
  42.   channel->end = channel->buff + IO_BUFFER_SIZE;
  43.   if( (unsigned)fd < 3 )
  44.     std_channel[fd] = channel;
  45.   return channel;
  46. }               
  47.  
  48. value open_descriptor(fd)       /* ML */
  49.      value fd;
  50. {
  51.   return (value) open_descr(Int_val(fd));
  52. }
  53.  
  54. value channel_descriptor(channel)   /* ML */
  55.      struct channel * channel;
  56. {
  57.   return Val_long(channel->fd);
  58. }
  59.  
  60. value channel_size(channel)      /* ML */
  61.      struct channel * channel;
  62. {
  63.   long end;
  64.  
  65.   end = lseek(channel->fd, 0, 2);
  66.   if (end == -1) sys_error(NULL);
  67.   if (lseek(channel->fd, channel->offset, 0) != channel->offset) 
  68.     sys_error(NULL);
  69.   return Val_long(end);
  70. }
  71.  
  72. /* Output */
  73.  
  74. static void really_write(fd, p, n)
  75.      int fd;
  76.      char * p;
  77.      int n;
  78. {
  79.   int retcode;
  80.   while (n > 0) {
  81. #ifdef HAS_UI
  82.     retcode = ui_write(fd, p, n);
  83. #else
  84. #ifdef EINTR
  85.     do { retcode = write(fd, p, n); } while (retcode == -1 && errno == EINTR);
  86. #else
  87.     retcode = write(fd, p, n);
  88. #endif
  89. #endif
  90.     if (retcode == -1) sys_error(NULL);
  91.     p += retcode;
  92.     n -= retcode;
  93.   }
  94. }   
  95.  
  96. value flush(channel)            /* ML */
  97.      struct channel * channel;
  98. {
  99.   int n;
  100.   n = channel->max - channel->buff;
  101.   if (n > 0) {
  102.     really_write(channel->fd, channel->buff, n);
  103.     channel->offset += n;
  104.     channel->curr = channel->buff;
  105.     channel->max  = channel->buff;
  106.   }
  107.   return Atom(0);
  108. }
  109.  
  110. void flush_stdouterr(void)
  111. {
  112.   if (std_channel[1]) flush(std_channel[1]);
  113.   if (std_channel[2]) flush(std_channel[2]);
  114. }
  115.  
  116. value output_char(channel, ch)  /* ML */
  117.      struct channel * channel;
  118.      value ch;
  119. {
  120.   putch(channel, Long_val(ch));
  121.   return Atom(0);
  122. }
  123.  
  124. void putword(channel, w)
  125.      struct channel * channel;
  126.      uint32 w;
  127. {
  128.   putch(channel, w >> 24);
  129.   putch(channel, w >> 16);
  130.   putch(channel, w >> 8);
  131.   putch(channel, w);
  132. }
  133.  
  134. value output_int(channel, w)    /* ML */
  135.      struct channel * channel;
  136.      value w;
  137. {
  138.   putword(channel, Long_val(w));
  139.   return Atom(0);
  140. }
  141.  
  142. void putblock(channel, p, n)
  143.      struct channel * channel;
  144.      char * p;
  145.      unsigned n;
  146. {
  147.   unsigned m;
  148.  
  149.   m = channel->end - channel->curr;
  150.   if (channel->curr == channel->buff && n >= m) {
  151.     really_write(channel->fd, p, n);
  152.     channel->offset += n;
  153.   } else if (n <= m) {
  154.     bcopy(p, channel->curr, n);
  155.     channel->curr += n;
  156.     if (channel->curr > channel->max) channel->max = channel->curr;
  157.   } else {
  158.     bcopy(p, channel->curr, m);
  159.     p += m;
  160.     n -= m;
  161.     m = channel->end - channel->buff;
  162.     really_write(channel->fd, channel->buff, m);
  163.     channel->offset += m;
  164.     if (n <= m) {
  165.       bcopy(p, channel->buff, n);
  166.       channel->curr = channel->max = channel->buff + n;
  167.     } else {
  168.       really_write(channel->fd, p, n);
  169.       channel->offset += n;
  170.       channel->curr = channel->max = channel->buff;
  171.     }
  172.   }
  173. }
  174.  
  175. value output(channel, buff, start, length) /* ML */
  176.      value channel, buff, start, length;
  177. {
  178.   putblock((struct channel *) channel,
  179.            &Byte(buff, Long_val(start)),
  180.            (unsigned) Long_val(length));
  181.   return Atom(0);
  182. }
  183.  
  184. value seek_out(channel, pos)    /* ML */
  185.      struct channel * channel;
  186.      value pos;
  187. {
  188.   long dest;
  189.  
  190.   dest = Long_val(pos);
  191.   if (dest >= channel->offset &&
  192.       dest <= channel->offset + channel->max - channel->buff) {
  193.     channel->curr = channel->buff + dest - channel->offset;
  194.   } else {
  195.     flush(channel);
  196.     if (lseek(channel->fd, dest, 0) != dest) sys_error(NULL);
  197.     channel->offset = dest;
  198.   }
  199.   return Atom(0);
  200. }
  201.  
  202. value pos_out(channel)          /* ML */
  203.      struct channel * channel;
  204. {
  205.   return Val_long(channel->offset + channel->curr - channel->buff);
  206. }
  207.  
  208. value close_out(channel)     /* ML */
  209.      struct channel * channel;
  210. {
  211.   if ((unsigned)(channel->fd) >= 3) 
  212.     {
  213.       flush(channel);
  214.       close(channel->fd);
  215.       stat_free((char *) channel);
  216.     }
  217.   return Atom(0);
  218. }
  219.  
  220. /* Input */
  221.  
  222. static int really_read(fd, p, n)
  223.      int fd;
  224.      char * p;
  225.      unsigned n;
  226. {
  227.   int retcode;
  228.  
  229.   enter_blocking_section();
  230. #ifdef HAS_UI
  231.   retcode = ui_read(fd, p, n);
  232. #else
  233. #ifdef MSDOS
  234.   retcode = msdos_read(fd, p, n);
  235. #else
  236. #ifdef EINTR
  237.   do { retcode = read(fd, p, n); } while (retcode == -1 && errno == EINTR);
  238. #else
  239.   retcode = read(fd, p, n);
  240. #endif
  241. #endif
  242. #endif
  243.   leave_blocking_section();
  244.   if (retcode == -1) sys_error(NULL);
  245.   return retcode;
  246. }
  247.  
  248. unsigned char refill(channel)
  249.      struct channel * channel;
  250. {
  251.   int n;
  252.  
  253.   n = really_read(channel->fd, channel->buff, IO_BUFFER_SIZE);
  254.   if (n == 0) mlraise(Atom(END_OF_FILE_EXN));
  255.   channel->offset += n;
  256.   channel->max = channel->buff + n;
  257.   channel->curr = channel->buff + 1;
  258.   return (unsigned char)(channel->buff[0]);
  259. }
  260.  
  261. value input_char(channel)       /* ML */
  262.      struct channel * channel;
  263. {
  264.   unsigned char c;
  265.   c = getch(channel);
  266.   return Val_long(c);
  267. }
  268.  
  269. uint32 getword(channel)
  270.      struct channel * channel;
  271. {
  272.   int i;
  273.   uint32 res;
  274.  
  275.   res = 0;
  276.   for(i = 0; i < 4; i++) {
  277.     res = (res << 8) + getch(channel);
  278.   }
  279.   return res;
  280. }
  281.  
  282. value input_int(channel)        /* ML */
  283.      struct channel * channel;
  284. {
  285.   long i;
  286.   i = getword(channel);
  287. #ifdef SIXTYFOUR
  288.   i = (i << 32) >> 32;          /* Force sign extension */
  289. #endif
  290.   return Val_long(i);
  291. }
  292.  
  293. unsigned getblock(channel, p, n)
  294.      struct channel * channel;
  295.      char * p;
  296.      unsigned n;
  297. {
  298.   unsigned m, l;
  299.  
  300.   m = channel->max - channel->curr;
  301.   if (n <= m) {
  302.     bcopy(channel->curr, p, n);
  303.     channel->curr += n;
  304.     return n;
  305.   } else if (m > 0) {
  306.     bcopy(channel->curr, p, m);
  307.     channel->curr += m;
  308.     return m;
  309.   } else if (n < IO_BUFFER_SIZE) {
  310.     l = really_read(channel->fd, channel->buff, IO_BUFFER_SIZE);
  311.     channel->offset += l;
  312.     channel->max = channel->buff + l;
  313.     if (n > l) n = l;
  314.     bcopy(channel->buff, p, n);
  315.     channel->curr = channel->buff + n;
  316.     return n;
  317.   } else {
  318.     channel->curr = channel->buff;
  319.     channel->max = channel->buff;
  320.     l = really_read(channel->fd, p, n);
  321.     channel->offset += l;
  322.     return l;
  323.   }
  324. }
  325.  
  326. int really_getblock(chan, p, n)
  327.      struct channel * chan;
  328.      char * p;
  329.      unsigned long n;
  330. {
  331.   unsigned r;
  332.   while (n > 0) {
  333.     r = getblock(chan, p, (unsigned) n);
  334.     if (r == 0) return 0;
  335.     p += r;
  336.     n -= r;
  337.   }
  338.   return 1;
  339. }
  340.  
  341. value input(channel, buff, start, length) /* ML */
  342.      value channel, buff, start, length;
  343. {
  344.   return Val_long(getblock((struct channel *) channel,
  345.                            &Byte(buff, Long_val(start)),
  346.                            (unsigned) Long_val(length)));
  347. }
  348.  
  349. value seek_in(channel, pos)     /* ML */
  350.      struct channel * channel;
  351.      value pos;
  352. {
  353.   long dest;
  354.  
  355.   dest = Long_val(pos);
  356.   if (dest >= channel->offset - (channel->max - channel->buff) &&
  357.       dest <= channel->offset) {
  358.     channel->curr = channel->max - (channel->offset - dest);
  359.   } else {
  360.     if (lseek(channel->fd, dest, 0) != dest) sys_error(NULL);
  361.     channel->offset = dest;
  362.     channel->curr = channel->max = channel->buff;
  363.   }
  364.   return Atom(0);
  365. }
  366.  
  367. value pos_in(channel)           /* ML */
  368.      struct channel * channel;
  369. {
  370.   return Val_long(channel->offset - (channel->max - channel->curr));
  371. }
  372.  
  373. value close_in(channel)     /* ML */
  374.      struct channel * channel;
  375. {
  376.   close(channel->fd);
  377.   stat_free((char *) channel);
  378.   return Atom(0);
  379. }
  380.  
  381. value input_scan_line(channel)       /* ML */
  382.      struct channel * channel;
  383. {
  384.   char * p;
  385.   int n;
  386.  
  387.   p = channel->curr;
  388.   do {
  389.     if (p >= channel->max) {
  390.       /* No more characters available in the buffer */
  391.       if (channel->curr > channel->buff) {
  392.         /* Try to make some room in the buffer by shifting the unread
  393.            portion at the beginning */
  394.         bcopy(channel->curr, channel->buff, channel->max - channel->curr);
  395.         n = channel->curr - channel->buff;
  396.         channel->curr -= n;
  397.         channel->max -= n;
  398.         p -= n;
  399.       }
  400.       if (channel->max >= channel->end) {
  401.         /* Buffer is full, no room to read more characters from the input.
  402.            Return the number of characters in the buffer, with negative
  403.            sign to indicate that no newline was encountered. */
  404.         return Val_long(-(channel->max - channel->curr));
  405.       }
  406.       /* Fill the buffer as much as possible */
  407.       n = really_read(channel->fd, channel->max, channel->end - channel->max);
  408.       if (n == 0) {
  409.         /* End-of-file encountered. Return the number of characters in the
  410.            buffer, with negative sign since we haven't encountered 
  411.            a newline. */
  412.         return Val_long(-(channel->max - channel->curr));
  413.       }
  414.       channel->offset += n;
  415.       channel->max += n;
  416.     }
  417.   } while (*p++ != '\n');
  418.   /* Found a newline. Return the length of the line, newline included. */
  419.   return Val_long(p - channel->curr);
  420. }
  421.