home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
new
/
util
/
edit
/
jade
/
src
/
streams.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-04
|
31KB
|
1,345 lines
/* streams.c -- Lisp stream handling
Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
This file is part of Jade.
Jade is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Jade is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jade; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* These are the Lisp objects which are classed as streams:
FILE: [rw]
MARK: [rw] advance pos attribute of mark afterwards
BUFFER: [rw] from cursor pos
(NUMBER . STRING): [r] from the NUMBER'th char of STRING
(STRING . ACTUAL-LENGTH): [w] to after INDEX
(BUFFER . POS): [rw] from BUFFER, POS is advanced
(BUFFER . t): [w] end of BUFFER
FUNCTION: [rw] call FUNCTION, when reading FUNCTION is expected to
return the next character, when writing it is called with
one arg, either character or string.
PROCESS: [w] write to the stdin of the PROCESS if it's running
t: [w] display in status line */
#include "jade.h"
#include "jade_protos.h"
#include "regexp/regexp.h"
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#ifdef NEED_MEMORY_H
# include <memory.h>
#endif
_PR int stream_getc(VALUE);
_PR int stream_ungetc(VALUE, int);
_PR int stream_putc(VALUE, int);
_PR int stream_puts(VALUE, u_char *, int, bool);
_PR int stream_read_esc(VALUE, int *);
_PR void stream_put_cntl(VALUE, int);
_PR void file_sweep(void);
_PR int file_cmp(VALUE, VALUE);
_PR void file_prin(VALUE, VALUE);
_PR void streams_init(void);
_PR void streams_kill(void);
static int
pos_getc(TX *tx, POS *pos)
{
int c = EOF;
if(pos->pos_Line < tx->tx_NumLines)
{
LINE *ln = tx->tx_Lines + pos->pos_Line;
if(pos->pos_Col >= (ln->ln_Strlen - 1))
{
if(++pos->pos_Line == tx->tx_NumLines)
{
--pos->pos_Line;
return(EOF);
}
pos->pos_Col = 0;
return('\n');
}
c = ln->ln_Line[pos->pos_Col++];
}
return(c);
}
static int
pos_putc(TX *tx, POS *pos, int c)
{
int rc = EOF;
if(!read_only(tx) && pad_pos(tx, pos))
{
u_char tmps[2];
tmps[0] = (u_char)c;
tmps[1] = 0;
if(iscntrl(c))
{
if(insert_string(tx, tmps, 1, pos))
rc = 1;
}
else
{
POS start = *pos;
if(insert_str_n(tx, tmps, 1, pos))
{
undo_record_insertion(tx, &start, pos);
flag_insertion(tx, &start, pos);
rc = 1;
}
}
}
return(rc);
}
static int
pos_puts(TX *tx, POS *pos, u_char *buf, int bufLen)
{
int rc = EOF;
if(!read_only(tx) && pad_pos(tx, pos))
{
if(insert_string(tx, buf, bufLen, pos))
rc = bufLen;
}
return(rc);
}
int
stream_getc(VALUE stream)
{
int c = EOF;
if(NILP(stream)
&& !(stream = cmd_symbol_value(sym_standard_input, sym_nil)))
return(c);
switch(VTYPE(stream))
{
VALUE res;
int oldgci;
case V_File:
if(VFILE(stream)->lf_Name)
c = getc(VFILE(stream)->lf_File);
break;
case V_Mark:
if(!VMARK(stream)->mk_Resident)
cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Marks used as streams must be resident")));
else
c = pos_getc(VMARK(stream)->mk_File.tx,
&VPOS(VMARK(stream)->mk_Pos));
break;
case V_TX:
c = pos_getc(VTX(stream), get_tx_cursor(VTX(stream)));
break;
case V_Cons:
res = VCAR(stream);
if(NUMBERP(res) && STRINGP(VCDR(stream)))
{
c = (int)VSTR(VCDR(stream))[VNUM(res)];
if(c)
VCAR(stream) = make_number(VNUM(res) + 1);
else
c = EOF;
break;
}
else if(BUFFERP(res) && POSP(VCDR(stream)))
{
c = pos_getc(VTX(res), &VPOS(VCDR(stream)));
break;
}
else if(res != sym_lambda)
{
cmd_signal(sym_invalid_stream, LIST_1(stream));
break;
}
/* FALL THROUGH */
case V_Symbol:
oldgci = gc_inhibit;
gc_inhibit = TRUE;
if((res = call_lisp0(stream)) && NUMBERP(res))
c = VNUM(res);
gc_inhibit = oldgci;
break;
#ifdef HAVE_SUBPROCESSES
case V_Process:
cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Processes are not input streams")));
break;
#endif
default:
cmd_signal(sym_invalid_stream, LIST_1(stream));
}
return(c);
}
/* Puts back one character, it will be read next call to streamgetc on
this stream.
Note that some types of stream don't actually use c, they just rewind
pointers.
Never call this unless you *have* *successfully* read from the stream
previously. (few checks are performed here, I assume they were made in
streamgetc()). */
#define POS_UNGETC(p,tx) \
if(--((p)->pos_Col) < 0) \
{ \
(p)->pos_Line--; \
(p)->pos_Col = (tx)->tx_Lines[(p)->pos_Line].ln_Strlen - 1; \
}
int
stream_ungetc(VALUE stream, int c)
{
int rc = FALSE;
if(NILP(stream)
&& !(stream = cmd_symbol_value(sym_standard_input, sym_nil)))
return(rc);
switch(VTYPE(stream))
{
POS *pos;
VALUE tmp;
int oldgci;
case V_File:
if(ungetc(c, VFILE(stream)->lf_File) != EOF)
rc = TRUE;
break;
case V_Mark:
pos = &VPOS(VMARK(stream)->mk_Pos);
POS_UNGETC(pos, VMARK(stream)->mk_File.tx)
rc = TRUE;
break;
case V_TX:
pos = get_tx_cursor(VTX(stream));
POS_UNGETC(pos, VTX(stream))
rc = TRUE;
break;
case V_Cons:
tmp = VCAR(stream);
if(NUMBERP(tmp) && STRINGP(VCDR(stream)))
{
VCAR(stream) = make_number(VNUM(tmp) - 1);
rc = TRUE;
break;
}
else if(BUFFERP(tmp) && POSP(VCDR(stream)))
{
POS_UNGETC(&VPOS(VCDR(stream)), VTX(tmp));
rc = TRUE;
break;
}
/* FALL THROUGH */
case V_Symbol:
tmp = make_number(c);
oldgci = gc_inhibit;
gc_inhibit = TRUE;
if((tmp = call_lisp1(stream, tmp)) && !NILP(tmp))
rc = TRUE;
gc_inhibit = oldgci;
break;
}
return(rc);
}
int
stream_putc(VALUE stream, int c)
{
int rc = 0;
if(NILP(stream)
&& !(stream = cmd_symbol_value(sym_standard_output, sym_nil)))
return(rc);
switch(VTYPE(stream))
{
VALUE args, res, new;
int len;
u_char tmps[2];
POS pos;
case V_File:
if(VFILE(stream)->lf_Name)
{
if(putc(c, VFILE(stream)->lf_File) != EOF)
rc = 1;
}
break;
case V_Mark:
if(!VMARK(stream)->mk_Resident)
cmd_signal(sym_invalid_stream, list_2(stream, MKSTR("Marks used as streams must be resident")));
else
{
pos = VPOS(VMARK(stream)->mk_Pos);
rc = pos_putc(VMARK(stream)->mk_File.tx, &pos, c);
}
break;
case V_TX:
pos = *(get_tx_cursor(VTX(stream)));
rc = pos_putc(VTX(stream), &pos, c);
break;
case V_Cons:
args = VCAR(stream);
if(VTYPEP(args, V_DynamicString) && NUMBERP(VCDR(stream)))
{
int actuallen = VNUM(VCDR(stream));
len = STRING_LEN(args);
if(len + 1 >= actuallen)
{
int newlen = actuallen < 16 ? 32 : actuallen * 2;
new = make_string(newlen + 1);
if(!new)
break;
memcpy(VSTR(new), VSTR(args), len);
VCAR(stream) = new;
VCDR(stream) = make_number(newlen);
args = new;
}
VSTR(args)[len] = (u_char)c;
VSTR(args)[len+1] = 0;
set_string_len(args, len + 1);
rc = 1;
break;
}
else if(BUFFERP(args))
{
if(POSP(VCDR(stream)))
rc = pos_putc(VTX(args), &VPOS(VCDR(stream)), c);
else
{
pos.pos_Line = VTX(args)->tx_NumLines - 1;
pos.pos_Col = VTX(args)->tx_Lines[pos.pos_Line].ln_Strlen - 1;
rc = pos_putc(VTX(args), &pos, c);
}
break;
}
else if(args != sym_lambda)
{
cmd_signal(sym_invalid_stream, LIST_1(stream));
break;
}
/* FALL THROUGH */
case V_Symbol:
if(stream == sym_t)
{
if(curr_vw->vw_Flags & VWFF_MESSAGE)
{
VW *vw = curr_vw;
u_char *s;
s = str_dupn(vw->vw_Message, vw->vw_MessageLen + 1);
if(s)
{
s[vw->vw_MessageLen++] = c;
s[vw->vw_MessageLen] = 0;
str_free(vw->vw_Message);
vw->vw_Message = s;
vw->vw_Flags |= VWFF_MESSAGE | VWFF_REFRESH_STATUS;
}
}