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> #if defined( HAVE_UNIX ) # include <unistd.h> #elif defined( HAVE_AMIGA ) /* my Amiga compiler has chdir() etc in <stdio.h> */ #endif _PR bool readtx(TX *, FILE *, long, long *); _PR bool writeline(u_char *, long, FILE *, TX *, long); _PR bool fileexists2(u_char *, u_char *); _PR bool fileexists3(u_char *, u_char *, u_char *); _PR VALUE signalfileerror(VALUE cdr); _PR void io_init(void); /* bytes to copy instead of tabs */ _PR const u_char Spaces[]; _PR const u_char Tabs[]; const u_char Spaces[] = " " " " " "; const u_char Tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; /* * read a file into a tx structure, the line list should have been * killed. * I'm going to have to speed this up somehow. * hopefully now loads lines of any length (upto max of 32768) * * codePos is an array of 3 LONGs to hold the position of the code * section to execute, it is filled in as follows, * codePos[0] start column * [1] start line * [2] end line * It should initially hold -1s to check for no code section. */ #define SIZESTEP 50 /* size at which line list grows by */ #define BUFFSTART 128 bool readtx(TX *tx, FILE *fh, long diskTab, long *codePos) { bool rc = FALSE; long bufflen = BUFFSTART; u_char *buff = mystralloc(bufflen); if(buff) { long c, i = 0; long linenum = 0, allocedlines = 0; u_char *newstr; LINE *line; #ifdef HAVE_AMIGA settitle("loading..."); #endif while((c = fgetc(fh)) != EOF) { if(i >= bufflen) { u_char *newbuff; newbuff = mystralloc(bufflen * 2); if(!newbuff) goto abortmem; memcpy(newbuff, buff, i); mystrfree(buff); buff = newbuff; bufflen *= 2; } if(c == '\n') { if(linenum >= allocedlines) { if(!resizelinelist(tx, SIZESTEP, linenum)) goto abortmem; allocedlines += SIZESTEP; } if(!(newstr = mystralloc(i + 1))) goto abortmem; memcpy(newstr, buff, i); newstr[i] = 0; line = tx->tx_Lines + linenum; line->ln_Strlen = i + 1; line->ln_Line = newstr; i = 0; /* * check for code section */ if(codePos[1] < 0) { u_char *s = strstr(newstr, "::jade" "-code::"); if(s) { codePos[0] = s - newstr; codePos[1] = linenum; } } else if(codePos[2] < 0) { if(strstr(newstr, "::end::")) codePos[2] = linenum; } linenum++; } else if(c == '\t') { int numspaces = diskTab - (i % diskTab); if(i + numspaces >= bufflen) { u_char *newbuff = mystralloc(bufflen * 2); if(!newbuff) goto abortmem; memcpy(newbuff, buff, i); mystrfree(buff); buff = newbuff; bufflen *= 2; } strncpy(buff + i, Spaces, numspaces); i += numspaces; } else buff[i++] = c; } if(!resizelinelist(tx, linenum - allocedlines + 1, linenum)) goto abortmem; if(!(newstr = mystralloc(i + 1))) goto abortmem; memcpy(newstr, buff, i); newstr[i] = 0; line = tx->tx_Lines + linenum; line->ln_Strlen = i + 1; line->ln_Line = newstr; if((codePos[1] >= 0) && (codePos[2] < 0)) codePos[2] = linenum; tx->tx_Changes++; rc = TRUE; #ifdef HAVE_AMIGA settitle("OK"); #endif /* This block only gets executed if we aborted while * reading the file. */ if(0) { abortmem: settitle(NoMemMsg); #if 0 abort: #endif clearlinelist(tx); } mystrfree(buff); } else settitle(NoMemMsg); 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:: */ { long codepos[3]; VALUE res = sym_nil; FILE *fh; bool closefh; 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(geterrstring(), file))); closefh = TRUE; } if(!BUFFERP(tx)) tx = CurrVW->vw_Tx; killlinelist(VTX(tx)); codepos[1] = codepos[2] = -1; if(readtx(VTX(tx), fh, VTX(tx)->tx_DiskTab, codepos)) res = tx; else clearlinelist(VTX(tx)); /* hope for some mem left */ if(closefh) fclose(fh); resetallviews(VTX(tx)); resetslptxtitles(VTX(tx)); if(codepos[2] > 0) execfilecode(VTX(tx), codepos); 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 = CurrVW->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(!writeline(line->ln_Line, line->ln_Strlen - 1, fh, VTX(tx), 0)) goto error; if(i != VTX(tx)->tx_NumLines - 1) fputc('\n', fh); } fclose(fh); } else error: return(cmd_signal(sym_file_error, list_2(geterrstring(), file))); return(file); } return(cmd_signal(sym_bad_arg, list_2(file, newnumber(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 = CurrVW->vw_Tx; if(!STRINGP(file)) file = VTX(tx)->tx_FileName; start = VPOS(vstart); end = VPOS(vend); if(!checksect(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) { if(!writeline(line->ln_Line, (start.pos_Line == end.pos_Line) ? end.pos_Col : line->ln_Strlen - 1, fh, tx, start.pos_Col)) 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(geterrstring(), file))); return(file); } return(cmd_signal(sym_bad_arg, list_2(file, newnumber(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))) settitlefmt("can't chdir to %s", VSTR(dir)); else res = dir; } else { u_char buff[256]; if(getcwd(buff, 256)) res = valstrdup(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) { if(fputs(VSTR(str), fh) == EOF) res = cmd_signal(sym_file_error, list_2(geterrstring(), file)); else res = sym_t; fclose(fh); } else res = cmd_signal(sym_file_error, list_2(geterrstring(), 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(valsquirrelfile(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 = mystralloc(buflen); if(buf) { while(((c = getc(fh)) != VCHAR(ch)) && (c != EOF)) { if(i >= buflen) { u_char *newbuf; int newbuflen = buflen * 2; if(!(newbuf = mystralloc(newbuflen))) goto error; memcpy(newbuf, buf, i); mystrfree(buf); buf = newbuf; buflen = newbuflen; } buf[i++] = c; } str = valstrdupn(buf, i); error: mystrfree(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(writeclip(VNUM(unit), VSTR(str), strlen(VSTR(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(readclip(VNUM(unit))); } /* * Writes out a line of text, * if SaveTabs == 1 leading spaces will be changed to tabs, * if SaveTabs == 2 all spaces (except after quotes) are made into tabs and * trailing spaces are discarded. */ bool writeline(u_char *line, long len, FILE *fh, TX *tx, long i) { if(tx->tx_SaveTabs) { long lastchg = i; bool inspc = FALSE; bool nodo = FALSE; long disktab = tx->tx_DiskTab; u_char c; for( ; (i <= len) && (c = line[i]); i++) { if(!nodo) { if(c == ' ') { if(!inspc) { if(fwrite(line + lastchg, 1, i - lastchg, fh) != i - lastchg) goto error; lastchg = i; inspc = TRUE; } } else { if(inspc) { int numtabs, numspcs; if(lastchg == i - 1) { numtabs = 0; numspcs = 1; } else { numtabs = (i - (lastchg - (lastchg % disktab))) / disktab; numspcs = i % disktab; if(numspcs > i - lastchg) numspcs = i - lastchg; } if(fwrite(Tabs, 1, numtabs, fh) != numtabs) goto error; if(fwrite(Spaces, 1, numspcs, fh) != numspcs) goto error; lastchg = i; inspc = FALSE; } if((c == '"') || (c == '\'') || (c == '`') || (tx->tx_SaveTabs == 1)) nodo = TRUE; } } } if((!inspc) || nodo) { if(fwrite(line + lastchg, 1, i - lastchg, fh) != i - lastchg) goto error; } return(TRUE); } else { if(fwrite(line + i, 1, len - i, fh) == (len - i)) return(TRUE); } error: return(FALSE); } bool fileexists2(u_char *s1, u_char *s2) { u_char buf[256]; stpcpy(stpcpy(buf, s1), s2); return(fileexists(buf)); } bool fileexists3(u_char *s1, u_char *s2, u_char *s3) { u_char buf[256]; stpcpy(stpcpy(stpcpy(buf, s1), s2), s3); return(fileexists(buf)); } VALUE signalfileerror(VALUE cdr) { VALUE data = cmd_cons(geterrstring, sym_nil); if(cdr) { if(CONSP(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); }