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 >
Wrap
C/C++ Source or Header
|
1994-04-19
|
25KB
|
1,089 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 . ??): (w), to end of string
* (buffer . pos): (rw), from buffer, pos is advanced
* (buffer . t): (w), end of buffer
* function-name: (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>
_PR int streamgetc(VALUE);
_PR int streamungetc(VALUE, int);
_PR int streamputc(VALUE, int);
_PR int streamputs(VALUE, u_char *, int);
_PR u_char escstreamchar(VALUE, int *);
_PR void streamputcntl(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
posgetc(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
posputc(TX *tx, POS *pos, int c)
{
int rc = EOF;
if(!readonly(tx) && padpos(tx, pos))
{
u_char tmps[2];
tmps[0] = (u_char)c;
tmps[1] = 0;
if(iscntrl(c))
{
if(insertstring(tx, tmps, tx->tx_TabSize, pos))
rc = 1;
}
else
{
POS start = *pos;
if(insertstrn(tx, tmps, 1, pos))
{
flaginsertion(tx, &start, pos);
rc = 1;
}
}
}
return(rc);
}
static int
posputs(TX *tx, POS *pos, u_char *buf)
{
int rc = EOF;
if(!readonly(tx) && padpos(tx, pos))
{
if(insertstring(tx, buf, tx->tx_TabSize, pos))
rc = strlen(buf);
}
return(rc);
}
int
streamgetc(VALUE stream)
{
int c = EOF;
if(NILP(stream) && !(stream = cmd_symbol_value(sym_standard_input)))
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 = posgetc(VMARK(stream)->mk_File.tx, &VPOS(VMARK(stream)->mk_Pos));
break;
case V_TX:
c = posgetc(VTX(stream), gettxcurspos(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) = newnumber(VNUM(res) + 1);
else
c = EOF;
break;
}
else if(BUFFERP(res) && POSP(VCDR(stream)))
{
c = posgetc(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 = GCinhibit;
GCinhibit = TRUE;
if((res = calllisp0(stream)) && NUMBERP(res))
c = VNUM(res);
GCinhibit = oldgci;
break;
#ifdef HAVE_UNIX
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 POSUNGETC(p,tx) \
if(--((p)->pos_Col) < 0) \
{ \
(p)->pos_Line--; \
(p)->pos_Col = (tx)->tx_Lines[(p)->pos_Line].ln_Strlen - 1; \
}
int
streamungetc(VALUE stream, int c)
{
int rc = FALSE;
if(NILP(stream) && !(stream = cmd_symbol_value(sym_standard_input)))
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);
POSUNGETC(pos, VMARK(stream)->mk_File.tx)
rc = TRUE;
break;
case V_TX:
pos = gettxcurspos(VTX(stream));
POSUNGETC(pos, VTX(stream))
rc = TRUE;
break;
case V_Cons:
tmp = VCAR(stream);
if(NUMBERP(tmp) && STRINGP(VCDR(stream)))
{
VCAR(stream) = newnumber(VNUM(tmp) - 1);
rc = TRUE;
break;
}
else if(BUFFERP(tmp) && POSP(VCDR(stream)))
{
POSUNGETC(&VPOS(VCDR(stream)), VTX(tmp));
rc = TRUE;
break;
}
/* FALL THROUGH */
case V_Symbol:
tmp = newnumber(c);
oldgci = GCinhibit;
GCinhibit = TRUE;
if((tmp = calllisp1(stream, tmp)) && !NILP(tmp))
rc = TRUE;
GCinhibit = oldgci;
break;
}
return(rc);
}
int
streamputc(VALUE stream, int c)
{
int rc = 0;
if(NILP(stream) && !(stream = cmd_symbol_value(sym_standard_output)))
return(rc);
switch(VTYPE(stream))
{
VALUE args, res, new;
int len;
u_char tmps[2];
POS pos;
int oldgci;
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 = posputc(VMARK(stream)->mk_File.tx, &pos, c);
}
break;
case V_TX:
pos = *(gettxcurspos(VTX(stream)));
rc = posputc(VTX(stream), &pos, c);
break;
case V_Cons:
args = VCAR(stream);
if(STRINGP(args))
{
len = strlen(VSTR(args));
new = valstralloc(len + 2);
if(new)
{
memcpy(VSTR(new), VSTR(args), len);
VSTR(new)[len] = (u_char)c;
VSTR(new)[len+1] = 0;
VCAR(stream) = new;
rc = 1;
}
break;
}
else if(BUFFERP(args))
{
if(POSP(VCDR(stream)))
rc = posputc(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 = posputc(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(CurrVW->vw_NonStdTitle)
{
VW *vw = CurrVW;
u_char *s;
len = strlen(vw->vw_LastTitle);
s = mystrdupn(vw->vw_LastTitle, len + 1);
if(s)
{
s[len] = c;
s[len + 1] = 0;
mystrfree(vw->vw_LastTitle);
vw->vw_LastTitle = s;
vw->vw_Flags |= VWFF_REFRESH_STATUS;
}
}
else
{
tmps[0] = (u_char)c;
tmps[1] = 0;
settitle(tmps);
}
rc = 1;
}
else
{
oldgci = GCinhibit;
GCinhibit = TRUE;
if((res = calllisp1(stream, newnumber(c))) && !NILP(res))
rc = 1;
GCinhibit = oldgci;
}
break;
#ifdef HAVE_UNIX
case V_Process:
tmps[0] = (u_char)c;
tmps[1] = 0;
rc = writetoproc(stream, tmps);
break;
#endif
default:
cmd_signal(sym_invalid_stream, LIST_1(stream));
}
return(rc);
}
int
streamputs(VALUE stream, u_char *buf, int is