home *** CD-ROM | disk | FTP | other *** search
Wrap
/* 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-file FILE-NAME STRING Writes STRING to file FILE-NAME. ::end:: */ { FILE *fh; VALUE res = sym_nil; DECLARE1(file, STRINGP); DECLARE2(str, STRINGP); fh = fopen(VSTR(file), "w"); if(fh) { int len = STRING_LEN(str); if(fwrite(VSTR(str), 1, len, fh) != len) res = cmd_signal(sym_file_error, list_2(lookup_errno(), file)); else res = sym_t; fclose(fh); } else res = cmd_signal(sym_file_error, list_2(lookup_errno(), file)); return(res); } _PR VALUE cmd_read_file(VALUE file); DEFUN("read-file", cmd_read_file, subr_read_file, (VALUE file), V_Subr1, DOC_read_file) /* ::doc:read_file:: read-file FILE-NAME Return the contents of file FILE-NAME. ::end:: */ { DECLARE1(file, STRINGP); return(read_file(VSTR(file))); } _PR VALUE cmd_read_file_from_to(VALUE file, VALUE offset, VALUE ch); DEFUN("read-file-from-to", cmd_read_file_from_to, subr_read_file_from_to, (VALUE file, VALUE offset, VALUE ch), V_Subr3, DOC_read_file_from_to) /* ::doc:read_file_from_to:: read-file-from-to FILENAME OFFSET CHAR ::end:: */ { FILE *fh; VALUE str = NULL; DECLARE1(file, STRINGP); DECLARE2(offset, NUMBERP); DECLARE3(ch, CHARP); if((fh = fopen(VSTR(file), "r")) && !fseek(fh, VNUM(offset), 0 /*SEEK_SET*/)) { int buflen = 128, i = 0, c; u_char *buf = str_alloc(buflen); if(buf) { while(((c = getc(fh)) != VCHAR(ch)) && (c != EOF)) { if(i >= buflen) { u_char *newbuf; int newbuflen = buflen * 2; if(!(newbuf = str_alloc(newbuflen))) goto error; memcpy(newbuf, buf, i); str_free(buf); buf = newbuf; buflen = newbuflen; } buf[i++] = c; } str = string_dupn(buf, i); error: str_free(buf); } fclose(fh); } else return(cmd_signal(sym_file_error, list_2(MKSTR("Can't open file"), file))); return(str); } _PR VALUE cmd_write_clip(VALUE unit, VALUE str); DEFUN("write-clip", cmd_write_clip, subr_write_clip, (VALUE unit, VALUE str), V_Subr2, DOC_write_clip) /* ::doc:write_clip:: write-clip UNIT STRING Writes STRING to unit UNIT of the standard clipboard. ::end:: */ { DECLARE1(unit, NUMBERP); DECLARE2(str, STRINGP); if(write_clip(VNUM(unit), VSTR(str), STRING_LEN(str))) return(sym_t); return(sym_nil); } _PR VALUE cmd_read_clip(VALUE unit); DEFUN("read-clip", cmd_read_clip, subr_read_clip, (VALUE unit), V_Subr1, DOC_read_clip) /* ::doc:read_clip:: read-clip UNIT Returns the string which unit UNIT of the clipboard holds. ::end:: */ { DECLARE1(unit, NUMBERP); return(read_clip(VNUM(unit))); } bool file_exists2(u_char *s1, u_char *s2) { u_char buf[256]; stpcpy(stpcpy(buf, s1), s2); return(file_exists(buf)); } bool file_exists3(u_char *s1, u_char *s2, u_char *s3) { u_char buf[256]; stpcpy(stpcpy(stpcpy(buf, s1), s2), s3); return(file_exists(buf)); } VALUE signal_file_error(VALUE cdr) { VALUE data = cmd_cons(lookup_errno(), sym_nil); if(cdr) { if(CONSP(cdr) || NILP(cdr)) VCDR(data) = cdr; else VCDR(data) = cmd_cons(cdr, sym_nil); } return(cmd_signal(sym_file_error, data)); } void io_init(void) { ADD_SUBR(subr_read_buffer); ADD_SUBR(subr_write_buffer); ADD_SUBR(subr_write_buffer_area); ADD_SUBR(subr_cd); ADD_SUBR(subr_write_file); ADD_SUBR(subr_read_file); ADD_SUBR(subr_read_file_from_to); ADD_SUBR(subr_write_clip); ADD_SUBR(subr_read_clip); }