home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / may94 / util / edit / jade.lha / Jade / src / streams.c < prev    next >
C/C++ Source or Header  |  1994-04-19  |  25KB  |  1,089 lines

  1. /* streams.c -- Lisp stream handling
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4. This file is part of Jade.
  5.  
  6. Jade is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. Jade is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with Jade; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * These are the Lisp objects which are classed as streams:
  22.  *
  23.  * file: (rw)
  24.  * mark: (rw), advance pos attribute of mark afterwards
  25.  * buffer: (rw), from cursor pos
  26.  * (number . string): (r), from the number'th char of string
  27.  * (string . ??): (w), to end of string
  28.  * (buffer . pos): (rw), from buffer, pos is advanced
  29.  * (buffer . t): (w), end of buffer
  30.  * function-name: (rw), call function, when reading function is expected to
  31.  *          return the next character, when writing it is called with
  32.  *          one arg, either character or string.
  33.  * process: (w), write to the stdin of the process if it's running
  34.  * t: (w), display in status line
  35.  */
  36.  
  37. #include "jade.h"
  38. #include "jade_protos.h"
  39. #include "regexp/regexp.h"
  40.  
  41. #include <string.h>
  42. #include <fcntl.h>
  43. #include <ctype.h>
  44. #include <stdlib.h>
  45.  
  46. _PR int streamgetc(VALUE);
  47. _PR int streamungetc(VALUE, int);
  48. _PR int streamputc(VALUE, int);
  49. _PR int streamputs(VALUE, u_char *, int);
  50. _PR u_char escstreamchar(VALUE, int *);
  51. _PR void streamputcntl(VALUE, int);
  52.  
  53. _PR void file_sweep(void);
  54. _PR int    file_cmp(VALUE, VALUE);
  55. _PR void file_prin(VALUE, VALUE);
  56.  
  57. _PR void streams_init(void);
  58. _PR void streams_kill(void);
  59.  
  60. static int
  61. posgetc(TX *tx, POS *pos)
  62. {
  63.     int c = EOF;
  64.     if(pos->pos_Line < tx->tx_NumLines)
  65.     {
  66.     LINE *ln = tx->tx_Lines + pos->pos_Line;
  67.     if(pos->pos_Col >= (ln->ln_Strlen - 1))
  68.     {
  69.         if(++pos->pos_Line == tx->tx_NumLines)
  70.         {
  71.         --pos->pos_Line;
  72.         return(EOF);
  73.         }
  74.         pos->pos_Col = 0;
  75.         return('\n');
  76.     }
  77.     c = ln->ln_Line[pos->pos_Col++];
  78.     }
  79.     return(c);
  80. }
  81. static int
  82. posputc(TX *tx, POS *pos, int c)
  83. {
  84.     int rc = EOF;
  85.     if(!readonly(tx) && padpos(tx, pos))
  86.     {
  87.     u_char tmps[2];
  88.     tmps[0] = (u_char)c;
  89.     tmps[1] = 0;
  90.     if(iscntrl(c))
  91.     {
  92.         if(insertstring(tx, tmps, tx->tx_TabSize, pos))
  93.         rc = 1;
  94.     }
  95.     else
  96.     {
  97.         POS start = *pos;
  98.         if(insertstrn(tx, tmps, 1, pos))
  99.         {
  100.         flaginsertion(tx, &start, pos);
  101.         rc = 1;
  102.         }
  103.     }
  104.     }
  105.     return(rc);
  106. }
  107. static int
  108. posputs(TX *tx, POS *pos, u_char *buf)
  109. {
  110.     int rc = EOF;
  111.     if(!readonly(tx) && padpos(tx, pos))
  112.     {
  113.     if(insertstring(tx, buf, tx->tx_TabSize, pos))
  114.         rc = strlen(buf);
  115.     }
  116.     return(rc);
  117. }
  118.  
  119. int
  120. streamgetc(VALUE stream)
  121. {
  122.     int c = EOF;
  123.     if(NILP(stream) && !(stream = cmd_symbol_value(sym_standard_input)))
  124.     return(c);
  125.     switch(VTYPE(stream))
  126.     {
  127.     VALUE res;
  128.     int oldgci;
  129.     case V_File:
  130.     if(VFILE(stream)->lf_Name)
  131.         c = getc(VFILE(stream)->lf_File);
  132.     break;
  133.     case V_Mark:
  134.     if(!VMARK(stream)->mk_Resident)
  135.         cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Marks used as streams must be resident")));
  136.     else
  137.         c = posgetc(VMARK(stream)->mk_File.tx, &VPOS(VMARK(stream)->mk_Pos));
  138.     break;
  139.     case V_TX:
  140.     c = posgetc(VTX(stream), gettxcurspos(VTX(stream)));
  141.     break;
  142.     case V_Cons:
  143.     res = VCAR(stream);
  144.     if(NUMBERP(res) && STRINGP(VCDR(stream)))
  145.     {
  146.         c = (int)VSTR(VCDR(stream))[VNUM(res)];
  147.         if(c)
  148.         VCAR(stream) = newnumber(VNUM(res) + 1);
  149.         else
  150.         c = EOF;
  151.         break;
  152.     }
  153.     else if(BUFFERP(res) && POSP(VCDR(stream)))
  154.     {
  155.         c = posgetc(VTX(res), &VPOS(VCDR(stream)));
  156.         break;
  157.     }
  158.     else if(res != sym_lambda)
  159.     {
  160.         cmd_signal(sym_invalid_stream, LIST_1(stream));
  161.         break;
  162.     }
  163.     /* FALL THROUGH */
  164.     case V_Symbol:
  165.     oldgci = GCinhibit;
  166.     GCinhibit = TRUE;
  167.     if((res = calllisp0(stream)) && NUMBERP(res))
  168.         c = VNUM(res);
  169.     GCinhibit = oldgci;
  170.     break;
  171. #ifdef HAVE_UNIX
  172.     case V_Process:
  173.     cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Processes are not input streams")));
  174.     break;
  175. #endif
  176.     default:
  177.     cmd_signal(sym_invalid_stream, LIST_1(stream));
  178.     }
  179.     return(c);
  180. }
  181.  
  182. /*
  183.  * Puts back one character, it will be read next call to streamgetc on
  184.  * this stream.
  185.  * Note that some types of stream don't actually use c, they just rewind
  186.  * pointers.
  187.  * Never call this unless you *have* *successfully* read from the stream
  188.  * previously. (few checks are performed here, I assume they were made in
  189.  * streamgetc()).
  190.  */
  191. #define POSUNGETC(p,tx) \
  192.     if(--((p)->pos_Col) < 0) \
  193.     { \
  194.     (p)->pos_Line--; \
  195.     (p)->pos_Col = (tx)->tx_Lines[(p)->pos_Line].ln_Strlen - 1; \
  196.     }
  197. int
  198. streamungetc(VALUE stream, int c)
  199. {
  200.     int rc = FALSE;
  201.     if(NILP(stream) && !(stream = cmd_symbol_value(sym_standard_input)))
  202.     return(rc);
  203.     switch(VTYPE(stream))
  204.     {
  205.     POS *pos;
  206.     VALUE tmp;
  207.     int oldgci;
  208.     case V_File:
  209.     if(ungetc(c, VFILE(stream)->lf_File) != EOF)
  210.         rc = TRUE;
  211.     break;
  212.     case V_Mark:
  213.     pos = &VPOS(VMARK(stream)->mk_Pos);
  214.     POSUNGETC(pos, VMARK(stream)->mk_File.tx)
  215.     rc = TRUE;
  216.     break;
  217.     case V_TX:
  218.     pos = gettxcurspos(VTX(stream));
  219.     POSUNGETC(pos, VTX(stream))
  220.     rc = TRUE;
  221.     break;
  222.     case V_Cons:
  223.     tmp = VCAR(stream);
  224.     if(NUMBERP(tmp) && STRINGP(VCDR(stream)))
  225.     {
  226.         VCAR(stream) = newnumber(VNUM(tmp) - 1);
  227.         rc = TRUE;
  228.         break;
  229.     }
  230.     else if(BUFFERP(tmp) && POSP(VCDR(stream)))
  231.     {
  232.         POSUNGETC(&VPOS(VCDR(stream)), VTX(tmp));
  233.         rc = TRUE;
  234.         break;
  235.     }
  236.     /* FALL THROUGH */
  237.     case V_Symbol:
  238.     tmp = newnumber(c);
  239.     oldgci = GCinhibit;
  240.     GCinhibit = TRUE;
  241.     if((tmp = calllisp1(stream, tmp)) && !NILP(tmp))
  242.         rc = TRUE;
  243.     GCinhibit = oldgci;
  244.     break;
  245.     }
  246.     return(rc);
  247. }
  248.  
  249. int
  250. streamputc(VALUE stream, int c)
  251. {
  252.     int rc = 0;
  253.     if(NILP(stream) && !(stream = cmd_symbol_value(sym_standard_output)))
  254.     return(rc);
  255.     switch(VTYPE(stream))
  256.     {
  257.     VALUE args, res, new;
  258.     int len;
  259.     u_char tmps[2];
  260.     POS pos;
  261.     int oldgci;
  262.     case V_File:
  263.     if(VFILE(stream)->lf_Name)
  264.     {
  265.         if(putc(c, VFILE(stream)->lf_File) != EOF)
  266.         rc = 1;
  267.     }
  268.     break;
  269.     case V_Mark:
  270.     if(!VMARK(stream)->mk_Resident)
  271.         cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Marks used as streams must be resident")));
  272.     else
  273.     {
  274.         pos = VPOS(VMARK(stream)->mk_Pos);
  275.         rc = posputc(VMARK(stream)->mk_File.tx, &pos, c);
  276.     }
  277.     break;
  278.     case V_TX:
  279.     pos = *(gettxcurspos(VTX(stream)));
  280.     rc = posputc(VTX(stream), &pos, c);
  281.     break;
  282.     case V_Cons:
  283.     args = VCAR(stream);
  284.     if(STRINGP(args))
  285.     {
  286.         len = strlen(VSTR(args));
  287.         new = valstralloc(len + 2);
  288.         if(new)
  289.         {
  290.         memcpy(VSTR(new), VSTR(args), len);
  291.         VSTR(new)[len] = (u_char)c;
  292.         VSTR(new)[len+1] = 0;
  293.         VCAR(stream) = new;
  294.         rc = 1;
  295.         }
  296.         break;
  297.     }
  298.     else if(BUFFERP(args))
  299.     {
  300.         if(POSP(VCDR(stream)))
  301.         rc = posputc(VTX(args), &VPOS(VCDR(stream)), c);
  302.         else
  303.         {
  304.         pos.pos_Line = VTX(args)->tx_NumLines - 1;
  305.         pos.pos_Col = VTX(args)->tx_Lines[pos.pos_Line].ln_Strlen - 1;
  306.         rc = posputc(VTX(args), &pos, c);
  307.         }
  308.         break;
  309.     }
  310.     else if(args != sym_lambda)
  311.     {
  312.         cmd_signal(sym_invalid_stream, LIST_1(stream));
  313.         break;
  314.     }
  315.     /* FALL THROUGH */
  316.     case V_Symbol:
  317.     if(stream == sym_t)
  318.     {
  319.         if(CurrVW->vw_NonStdTitle)
  320.         {
  321.         VW *vw = CurrVW;
  322.         u_char *s;
  323.         len = strlen(vw->vw_LastTitle);
  324.         s = mystrdupn(vw->vw_LastTitle, len + 1);
  325.         if(s)
  326.         {
  327.             s[len] = c;
  328.             s[len + 1] = 0;
  329.             mystrfree(vw->vw_LastTitle);
  330.             vw->vw_LastTitle = s;
  331.             vw->vw_Flags |= VWFF_REFRESH_STATUS;
  332.         }
  333.         }
  334.         else
  335.         {
  336.         tmps[0] = (u_char)c;
  337.         tmps[1] = 0;
  338.         settitle(tmps);
  339.         }
  340.         rc = 1;
  341.     }
  342.     else
  343.     {
  344.         oldgci = GCinhibit;
  345.         GCinhibit = TRUE;
  346.         if((res = calllisp1(stream, newnumber(c))) && !NILP(res))
  347.         rc = 1;
  348.         GCinhibit = oldgci;
  349.     }
  350.     break;
  351. #ifdef HAVE_UNIX
  352.     case V_Process:
  353.     tmps[0] = (u_char)c;
  354.     tmps[1] = 0;
  355.     rc = writetoproc(stream, tmps);
  356.     break;
  357. #endif
  358.     default:
  359.     cmd_signal(sym_invalid_stream, LIST_1(stream));
  360.     }
  361.     return(rc);
  362. }
  363.  
  364. int
  365. streamputs(VALUE stream, u_char *buf, int is