home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
new
/
util
/
edit
/
jade
/
src
/
io.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-03
|
12KB
|
462 lines
/* io.c -- Loading & saving files, etc...
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. */
#include "jade.h"
#include "jade_protos.h"
#include <string.h>
#ifdef NEED_MEMORY_H
# include <memory.h>
#endif
#if defined( HAVE_UNIX )
# include <unistd.h>
#elif defined( HAVE_AMIGA )
/* my Amiga compiler has chdir() etc in <stdio.h> */
#endif
_PR bool file_exists2(u_char *, u_char *);
_PR bool file_exists3(u_char *, u_char *, u_char *);
_PR VALUE signal_file_error(VALUE cdr);
_PR void io_init(void);
/* Read a file into a tx structure, the line list should have been
killed. */
static bool
read_tx(TX *tx, FILE *fh)
{
#define SIZESTEP 50 /* size at which line list grows by */
bool rc = FALSE;
u_char buf[BUFSIZ];
long len;
long linenum, allocedlines;
LINE *line;
#ifdef HAVE_AMIGA
message("loading...");
#endif
if(!resize_line_list(tx, SIZESTEP, 0))
goto abortmem;
allocedlines = SIZESTEP;
linenum = 0;
line = tx->tx_Lines;
while((len = fread(buf, 1, BUFSIZ, fh)) > 0)
{
u_char *new;
long newlen;
u_char *eol, *cur = buf;
while((eol = memchr(cur, '\n', (buf + len) - cur)))
{
if(line->ln_Strlen)
{
newlen = line->ln_Strlen + (eol - cur);
new = str_alloc(newlen);
memcpy(new, line->ln_Line, line->ln_Strlen);
memcpy(new + line->ln_Strlen - 1, cur, eol - cur);
new[newlen-1] = 0;
str_free(line->ln_Line);
line->ln_Line = new;
line->ln_Strlen = newlen;
}
else
{
newlen = eol - cur;
new = str_dupn(cur, newlen);
line->ln_Line = new;
line->ln_Strlen = newlen+1;
}
if(++linenum >= allocedlines)
{
if(!resize_line_list(tx, SIZESTEP, linenum))
goto abortmem;
allocedlines += SIZESTEP;
line = tx->tx_Lines + linenum;
}
else
line++;
cur = eol + 1;
}
if(cur < buf + len)
{
if(line->ln_Strlen)
{
/* Only way we can get here is if there were *no* newlines in
the chunk we just read. */
newlen = line->ln_Strlen + len;
new = str_alloc(newlen);
if(!new)
goto abortmem;
memcpy(new, line->ln_Line, line->ln_Strlen - 1);
memcpy(new + (line->ln_Strlen - 1), buf, len);
new[newlen-1] = 0;
str_free(line->ln_Line);
line->ln_Line = new;
line->ln_Strlen = newlen;
}
else
{
newlen = (buf + len) - cur;
line->ln_Line = str_alloc(newlen + 1);
if(!line->ln_Line)
goto abortmem;
memcpy(line->ln_Line, cur, newlen);
line->ln_Line[newlen] = 0;
line->ln_Strlen = newlen + 1;
}
}
}
if(line->ln_Strlen == 0)
{
line->ln_Line = str_dupn("", 0);
line->ln_Strlen = 1;
}
linenum++;
if(!resize_line_list(tx, linenum - allocedlines, linenum))
goto abortmem;
tx->tx_Changes++;
rc = TRUE;
#ifdef HAVE_AMIGA
message("OK");
#endif
if(0)
{
/* This only gets executed if we aborted while reading the file. */
abortmem:
mem_error();
clear_line_list(tx);
}
tx->tx_Flags |= TXFF_REFRESH_ALL;
return(rc);
}
_PR VALUE cmd_read_buffer(VALUE file, VALUE tx);
DEFUN("read-buffer", cmd_read_buffer, subr_read_buffer, (VALUE file, VALUE tx), V_Subr2, DOC_read_buffer) /*
::doc:read_buffer::
read-buffer FILE [BUFFER]
Overwrites the text in BUFFER with that from the file FILE.
FILE is either a string naming the file to be opened or a Lisp file object
(from `open') to be used.
::end:: */
{
VALUE res = sym_nil;
FILE *fh;
bool closefh;
POS start, end;
if(FILEP(file) && VFILE(file)->lf_Name)
{
fh = VFILE(file)->lf_File;
closefh = FALSE;
}
else
{
DECLARE1(file, STRINGP);
if(!(fh = fopen(VSTR(file), "r")))
return(cmd_signal(sym_file_error, list_2(lookup_errno(), file)));
closefh = TRUE;
}
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
start.pos_Col = start.pos_Line = 0;
end.pos_Line = VTX(tx)->tx_NumLines - 1;
end.pos_Col = VTX(tx)->tx_Lines[end.pos_Line].ln_Strlen - 1;
if(!(end.pos_Line == 0 && end.pos_Line == 0))
undo_record_deletion(VTX(tx), &start, &end);
kill_line_list(VTX(tx));
if(read_tx(VTX(tx), fh))
{
end.pos_Line = VTX(tx)->tx_NumLines - 1;
end.pos_Col = VTX(tx)->tx_Lines[end.pos_Line].ln_Strlen - 1;
undo_record_insertion(VTX(tx), &start, &end);
res = tx;
}
else
clear_line_list(VTX(tx)); /* hope for some mem left */
if(closefh)
fclose(fh);
reset_all_views(VTX(tx));
sys_reset_sleep_titles(VTX(tx));
return(res);
}
_PR VALUE cmd_write_buffer(VALUE file, VALUE tx);
DEFUN("write-buffer", cmd_write_buffer, subr_write_buffer, (VALUE file, VALUE tx), V_Subr2, DOC_write_buffer) /*
::doc:write_buffer::
write-buffer [FILE-NAME] [BUFFER]
Saves the contents of BUFFER to file FILE-NAME.
::end:: */
{
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(!STRINGP(file))
file = VTX(tx)->tx_FileName;
if(file)
{
FILE *fh = fopen(VSTR(file), "w");
if(fh)
{
long i;
LINE *line = VTX(tx)->tx_Lines;
for(i = 0; i < VTX(tx)->tx_NumLines; i++, line++)
{
if(fwrite(line->ln_Line, 1, line->ln_Strlen - 1, fh)
!= (line->ln_Strlen - 1))
goto error;
if(i != VTX(tx)->tx_NumLines - 1)
fputc('\n', fh);
}
fclose(fh);
}
else
error:
return(cmd_signal(sym_file_error, list_2(lookup_errno(), file)));
return(file);
}
return(cmd_signal(sym_bad_arg, list_2(file, make_number(1))));
}
_PR VALUE cmd_write_buffer_area(VALUE vstart, VALUE vend, VALUE file, VALUE tx);
DEFUN("write-buffer-area", cmd_write_buffer_area, subr_write_buffer_area, (VALUE vstart, VALUE vend, VALUE file, VALUE tx), V_Subr4, DOC_write_buffer_area) /*
::doc:write_buffer_area::
write-buffer-area START-POS END-POS [FILE-NAME] [BUFFER]
Writes the text between START-POS and END-POS in BUFFER to file
FILE-NAME.
::end:: */
{
POS start, end;
DECLARE1(vstart, POSP);
DECLARE2(vend, POSP);
if(!BUFFERP(tx))
tx = VAL(curr_vw->vw_Tx);
if(!STRINGP(file))
file = VTX(tx)->tx_FileName;
start = VPOS(vstart);
end = VPOS(vend);
if(!check_section(VTX(tx), &start, &end))
return(cmd_signal(sym_invalid_area, list_3(tx, vstart, vend)));
if(file)
{
FILE *fh = fopen(VSTR(file), "w");
if(fh)
{
LINE *line = VTX(tx)->tx_Lines + start.pos_Line;
while(start.pos_Line <= end.pos_Line)
{
int len = (((start.pos_Line == end.pos_Line)
? end.pos_Col : line->ln_Strlen)
- start.pos_Col - 1);
if(fwrite(line->ln_Line + start.pos_Col,
1, len, fh) != len)
goto error;
if(start.pos_Line != end.pos_Line)
fputc('\n', fh);
start.pos_Line++;
start.pos_Col = 0;
line++;
}
fclose(fh);
}
else
error:
return(cmd_signal(sym_file_error, list_2(lookup_errno(), file)));
return(file);
}
return(cmd_signal(sym_bad_arg, list_2(file, make_number(1))));
}
_PR VALUE cmd_cd(VALUE dir);
DEFUN("cd", cmd_cd, subr_cd, (VALUE dir), V_Subr1, DOC_cd) /*
::doc:cd::
cd [DIRECTORY]
If DIRECTORY is given set the editor's current directory to it, else
return the name of the current directory.
::end:: */
{
VALUE res = sym_nil;
if(STRINGP(dir))
{
if(chdir(VSTR(dir)))
messagef("can't chdir to %s", VSTR(dir));
else
res = dir;
}
else
{
u_char buff[256];
if(getcwd(buff, 256))
res = string_dup(buff);
}
return(res);
}
_PR VALUE cmd_write_file(VALUE file, VALUE str);
DEFUN("write-file", cmd_write_file, subr_write_file, (VALUE file, VALUE str), V_Subr2, DOC_write_file) /*
::doc:write_file::
write-