home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / new / util / edit / jade / src / streams.c < prev    next >
C/C++ Source or Header  |  1994-10-04  |  31KB  |  1,345 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. /* These are the Lisp objects which are classed as streams:
  21.    FILE: [rw]
  22.    MARK: [rw] advance pos attribute of mark afterwards
  23.    BUFFER: [rw] from cursor pos
  24.    (NUMBER . STRING): [r] from the NUMBER'th char of STRING
  25.    (STRING . ACTUAL-LENGTH): [w] to after INDEX
  26.    (BUFFER . POS): [rw] from BUFFER, POS is advanced
  27.    (BUFFER . t): [w] end of BUFFER
  28.    FUNCTION: [rw] call FUNCTION, when reading FUNCTION is expected to
  29.             return the next character, when writing it is called with
  30.             one arg, either character or string.
  31.    PROCESS: [w] write to the stdin of the PROCESS if it's running
  32.    t: [w] display in status line  */
  33.  
  34. #include "jade.h"
  35. #include "jade_protos.h"
  36. #include "regexp/regexp.h"
  37.  
  38. #include <string.h>
  39. #include <fcntl.h>
  40. #include <ctype.h>
  41. #include <stdlib.h>
  42.  
  43. #ifdef NEED_MEMORY_H
  44. # include <memory.h>
  45. #endif
  46.  
  47. _PR int stream_getc(VALUE);
  48. _PR int stream_ungetc(VALUE, int);
  49. _PR int stream_putc(VALUE, int);
  50. _PR int stream_puts(VALUE, u_char *, int, bool);
  51. _PR int stream_read_esc(VALUE, int *);
  52. _PR void stream_put_cntl(VALUE, int);
  53.  
  54. _PR void file_sweep(void);
  55. _PR int file_cmp(VALUE, VALUE);
  56. _PR void file_prin(VALUE, VALUE);
  57.  
  58. _PR void streams_init(void);
  59. _PR void streams_kill(void);
  60.  
  61. static int
  62. pos_getc(TX *tx, POS *pos)
  63. {
  64.     int c = EOF;
  65.     if(pos->pos_Line < tx->tx_NumLines)
  66.     {
  67.     LINE *ln = tx->tx_Lines + pos->pos_Line;
  68.     if(pos->pos_Col >= (ln->ln_Strlen - 1))
  69.     {
  70.         if(++pos->pos_Line == tx->tx_NumLines)
  71.         {
  72.         --pos->pos_Line;
  73.         return(EOF);
  74.         }
  75.         pos->pos_Col = 0;
  76.         return('\n');
  77.     }
  78.     c = ln->ln_Line[pos->pos_Col++];
  79.     }
  80.     return(c);
  81. }
  82.  
  83. static int
  84. pos_putc(TX *tx, POS *pos, int c)
  85. {
  86.     int rc = EOF;
  87.     if(!read_only(tx) && pad_pos(tx, pos))
  88.     {
  89.     u_char tmps[2];
  90.     tmps[0] = (u_char)c;
  91.     tmps[1] = 0;
  92.     if(iscntrl(c))
  93.     {
  94.         if(insert_string(tx, tmps, 1, pos))
  95.         rc = 1;
  96.     }
  97.     else
  98.     {
  99.         POS start = *pos;
  100.         if(insert_str_n(tx, tmps, 1, pos))
  101.         {
  102.         undo_record_insertion(tx, &start, pos);
  103.         flag_insertion(tx, &start, pos);
  104.         rc = 1;
  105.         }
  106.     }
  107.     }
  108.     return(rc);
  109. }
  110.  
  111. static int
  112. pos_puts(TX *tx, POS *pos, u_char *buf, int bufLen)
  113. {
  114.     int rc = EOF;
  115.     if(!read_only(tx) && pad_pos(tx, pos))
  116.     {
  117.     if(insert_string(tx, buf, bufLen, pos))
  118.         rc = bufLen;
  119.     }
  120.     return(rc);
  121. }
  122.  
  123. int
  124. stream_getc(VALUE stream)
  125. {
  126.     int c = EOF;
  127.     if(NILP(stream)
  128.        && !(stream = cmd_symbol_value(sym_standard_input, sym_nil)))
  129.     return(c);
  130.     switch(VTYPE(stream))
  131.     {
  132.     VALUE res;
  133.     int oldgci;
  134.  
  135.     case V_File:
  136.     if(VFILE(stream)->lf_Name)
  137.         c = getc(VFILE(stream)->lf_File);
  138.     break;
  139.  
  140.     case V_Mark:
  141.     if(!VMARK(stream)->mk_Resident)
  142.         cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Marks used as streams must be resident")));
  143.     else
  144.         c = pos_getc(VMARK(stream)->mk_File.tx,
  145.              &VPOS(VMARK(stream)->mk_Pos));
  146.     break;
  147.  
  148.     case V_TX:
  149.     c = pos_getc(VTX(stream), get_tx_cursor(VTX(stream)));
  150.     break;
  151.  
  152.     case V_Cons:
  153.     res = VCAR(stream);
  154.     if(NUMBERP(res) && STRINGP(VCDR(stream)))
  155.     {
  156.         c = (int)VSTR(VCDR(stream))[VNUM(res)];
  157.         if(c)
  158.         VCAR(stream) = make_number(VNUM(res) + 1);
  159.         else
  160.         c = EOF;
  161.         break;
  162.     }
  163.     else if(BUFFERP(res) && POSP(VCDR(stream)))
  164.     {
  165.         c = pos_getc(VTX(res), &VPOS(VCDR(stream)));
  166.         break;
  167.     }
  168.     else if(res != sym_lambda)
  169.     {
  170.         cmd_signal(sym_invalid_stream, LIST_1(stream));
  171.         break;
  172.     }
  173.     /* FALL THROUGH */
  174.  
  175.     case V_Symbol:
  176.     oldgci = gc_inhibit;
  177.     gc_inhibit = TRUE;
  178.     if((res = call_lisp0(stream)) && NUMBERP(res))
  179.         c = VNUM(res);
  180.     gc_inhibit = oldgci;
  181.     break;
  182.  
  183. #ifdef HAVE_SUBPROCESSES
  184.     case V_Process:
  185.     cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Processes are not input streams")));
  186.     break;
  187. #endif
  188.  
  189.     default:
  190.     cmd_signal(sym_invalid_stream, LIST_1(stream));
  191.     }
  192.     return(c);
  193. }
  194.  
  195. /* Puts back one character, it will be read next call to streamgetc on
  196.    this stream.
  197.    Note that some types of stream don't actually use c, they just rewind
  198.    pointers.
  199.    Never call this unless you *have* *successfully* read from the stream
  200.    previously. (few checks are performed here, I assume they were made in
  201.    streamgetc()).  */
  202. #define POS_UNGETC(p,tx) \
  203.     if(--((p)->pos_Col) < 0) \
  204.     { \
  205.     (p)->pos_Line--; \
  206.     (p)->pos_Col = (tx)->tx_Lines[(p)->pos_Line].ln_Strlen - 1; \
  207.     }
  208. int
  209. stream_ungetc(VALUE stream, int c)
  210. {
  211.     int rc = FALSE;
  212.     if(NILP(stream)
  213.        && !(stream = cmd_symbol_value(sym_standard_input, sym_nil)))
  214.     return(rc);
  215.     switch(VTYPE(stream))
  216.     {
  217.     POS *pos;
  218.     VALUE tmp;
  219.     int oldgci;
  220.  
  221.     case V_File:
  222.     if(ungetc(c, VFILE(stream)->lf_File) != EOF)
  223.         rc = TRUE;
  224.     break;
  225.  
  226.     case V_Mark:
  227.     pos = &VPOS(VMARK(stream)->mk_Pos);
  228.     POS_UNGETC(pos, VMARK(stream)->mk_File.tx)
  229.     rc = TRUE;
  230.     break;
  231.  
  232.     case V_TX:
  233.     pos = get_tx_cursor(VTX(stream));
  234.     POS_UNGETC(pos, VTX(stream))
  235.     rc = TRUE;
  236.     break;
  237.  
  238.     case V_Cons:
  239.     tmp = VCAR(stream);
  240.     if(NUMBERP(tmp) && STRINGP(VCDR(stream)))
  241.     {
  242.         VCAR(stream) = make_number(VNUM(tmp) - 1);
  243.         rc = TRUE;
  244.         break;
  245.     }
  246.     else if(BUFFERP(tmp) && POSP(VCDR(stream)))
  247.     {
  248.         POS_UNGETC(&VPOS(VCDR(stream)), VTX(tmp));
  249.         rc = TRUE;
  250.         break;
  251.     }
  252.     /* FALL THROUGH */
  253.  
  254.     case V_Symbol:
  255.     tmp = make_number(c);
  256.     oldgci = gc_inhibit;
  257.     gc_inhibit = TRUE;
  258.     if((tmp = call_lisp1(stream, tmp)) && !NILP(tmp))
  259.         rc = TRUE;
  260.     gc_inhibit = oldgci;
  261.     break;
  262.     }
  263.     return(rc);
  264. }
  265.  
  266. int
  267. stream_putc(VALUE stream, int c)
  268. {
  269.     int rc = 0;
  270.     if(NILP(stream)
  271.        && !(stream = cmd_symbol_value(sym_standard_output, sym_nil)))
  272.     return(rc);
  273.     switch(VTYPE(stream))
  274.     {
  275.     VALUE args, res, new;
  276.     int len;
  277.     u_char tmps[2];
  278.     POS pos;
  279.  
  280.     case V_File:
  281.     if(VFILE(stream)->lf_Name)
  282.     {
  283.         if(putc(c, VFILE(stream)->lf_File) != EOF)
  284.         rc = 1;
  285.     }
  286.     break;
  287.  
  288.     case V_Mark:
  289.     if(!VMARK(stream)->mk_Resident)
  290.         cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Marks used as streams must be resident")));
  291.     else
  292.     {
  293.         pos = VPOS(VMARK(stream)->mk_Pos);
  294.         rc = pos_putc(VMARK(stream)->mk_File.tx, &pos, c);
  295.     }
  296.     break;
  297.  
  298.     case V_TX:
  299.     pos = *(get_tx_cursor(VTX(stream)));
  300.     rc = pos_putc(VTX(stream), &pos, c);
  301.     break;
  302.  
  303.     case V_Cons:
  304.     args = VCAR(stream);
  305.     if(VTYPEP(args, V_DynamicString) && NUMBERP(VCDR(stream)))
  306.     {
  307.         int actuallen = VNUM(VCDR(stream));
  308.         len = STRING_LEN(args);
  309.         if(len + 1 >= actuallen)
  310.         {
  311.         int newlen = actuallen < 16 ? 32 : actuallen * 2;
  312.         new = make_string(newlen + 1);
  313.         if(!new)
  314.             break;
  315.         memcpy(VSTR(new), VSTR(args), len);
  316.         VCAR(stream) = new;
  317.         VCDR(stream) = make_number(newlen);
  318.         args = new;
  319.         }
  320.         VSTR(args)[len] = (u_char)c;
  321.         VSTR(args)[len+1] = 0;
  322.         set_string_len(args, len + 1);
  323.         rc = 1;
  324.         break;
  325.     }
  326.     else if(BUFFERP(args))
  327.     {
  328.         if(POSP(VCDR(stream)))
  329.         rc = pos_putc(VTX(args), &VPOS(VCDR(stream)), c);
  330.         else
  331.         {
  332.         pos.pos_Line = VTX(args)->tx_NumLines - 1;
  333.         pos.pos_Col = VTX(args)->tx_Lines[pos.pos_Line].ln_Strlen - 1;
  334.         rc = pos_putc(VTX(args), &pos, c);
  335.         }
  336.         break;
  337.     }
  338.     else if(args != sym_lambda)
  339.     {
  340.         cmd_signal(sym_invalid_stream, LIST_1(stream));
  341.         break;
  342.     }
  343.     /* FALL THROUGH */
  344.  
  345.     case V_Symbol:
  346.     if(stream == sym_t)
  347.     {
  348.         if(curr_vw->vw_Flags & VWFF_MESSAGE)
  349.         {
  350.         VW *vw = curr_vw;
  351.         u_char *s;
  352.         s = str_dupn(vw->vw_Message, vw->vw_MessageLen + 1);
  353.         if(s)
  354.         {
  355.             s[vw->vw_MessageLen++] = c;
  356.             s[vw->vw_MessageLen] = 0;
  357.             str_free(vw->vw_Message);
  358.             vw->vw_Message = s;
  359.             vw->vw_Flags |= VWFF_MESSAGE | VWFF_REFRESH_STATUS;
  360.         }
  361.         }
  362.