home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / new / util / edit / jade / src / io.c < prev    next >
C/C++ Source or Header  |  1994-10-03  |  12KB  |  462 lines

  1. /* io.c -- Loading & saving files, etc...
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING.  If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <string.h>
  24.  
  25. #ifdef NEED_MEMORY_H
  26. # include <memory.h>
  27. #endif
  28.  
  29. #if defined( HAVE_UNIX )
  30. # include <unistd.h>
  31. #elif defined( HAVE_AMIGA )
  32.   /* my Amiga compiler has chdir() etc in <stdio.h> */
  33. #endif
  34.  
  35. _PR bool file_exists2(u_char *, u_char *);
  36. _PR bool file_exists3(u_char *, u_char *, u_char *);
  37. _PR VALUE signal_file_error(VALUE cdr);
  38. _PR void io_init(void);
  39.  
  40. /* Read a file into a tx structure, the line list should have been
  41.    killed.  */
  42. static bool
  43. read_tx(TX *tx, FILE *fh)
  44. {
  45. #define SIZESTEP  50    /* size at which line list grows by */
  46.     bool rc = FALSE;
  47.     u_char buf[BUFSIZ];
  48.     long len;
  49.     long linenum, allocedlines;
  50.     LINE *line;
  51. #ifdef HAVE_AMIGA
  52.     message("loading...");
  53. #endif
  54.     if(!resize_line_list(tx, SIZESTEP, 0))
  55.     goto abortmem;
  56.     allocedlines = SIZESTEP;
  57.     linenum = 0;
  58.     line = tx->tx_Lines;
  59.     while((len = fread(buf, 1, BUFSIZ, fh)) > 0)
  60.     {
  61.     u_char *new;
  62.     long newlen;
  63.     u_char *eol, *cur = buf;
  64.     while((eol = memchr(cur, '\n', (buf + len) - cur)))
  65.     {
  66.         if(line->ln_Strlen)
  67.         {
  68.         newlen = line->ln_Strlen + (eol - cur);
  69.         new = str_alloc(newlen);
  70.         memcpy(new, line->ln_Line, line->ln_Strlen);
  71.         memcpy(new + line->ln_Strlen - 1, cur, eol - cur);
  72.         new[newlen-1] = 0;
  73.         str_free(line->ln_Line);
  74.         line->ln_Line = new;
  75.         line->ln_Strlen = newlen;
  76.         }
  77.         else
  78.         {
  79.         newlen = eol - cur;
  80.         new = str_dupn(cur, newlen);
  81.         line->ln_Line = new;
  82.         line->ln_Strlen = newlen+1;
  83.         }
  84.         if(++linenum >= allocedlines)
  85.         {
  86.         if(!resize_line_list(tx, SIZESTEP, linenum))
  87.             goto abortmem;
  88.         allocedlines += SIZESTEP;
  89.         line = tx->tx_Lines + linenum;
  90.         }
  91.         else
  92.         line++;
  93.         cur = eol + 1;
  94.     }
  95.     if(cur < buf + len)
  96.     {
  97.             if(line->ln_Strlen)
  98.         {
  99.                 /* Only way we can get here is if there were *no* newlines in
  100.                    the chunk we just read. */
  101.         newlen = line->ln_Strlen + len;
  102.         new = str_alloc(newlen);
  103.         if(!new)
  104.             goto abortmem;
  105.         memcpy(new, line->ln_Line, line->ln_Strlen - 1);
  106.         memcpy(new + (line->ln_Strlen - 1), buf, len);
  107.         new[newlen-1] = 0;
  108.         str_free(line->ln_Line);
  109.         line->ln_Line = new;
  110.         line->ln_Strlen = newlen;
  111.         }
  112.             else
  113.         {
  114.         newlen = (buf + len) - cur;
  115.         line->ln_Line = str_alloc(newlen + 1);
  116.         if(!line->ln_Line)
  117.             goto abortmem;
  118.         memcpy(line->ln_Line, cur, newlen);
  119.         line->ln_Line[newlen] = 0;
  120.         line->ln_Strlen = newlen + 1;
  121.         }
  122.     }
  123.     }
  124.     if(line->ln_Strlen == 0)
  125.     {
  126.     line->ln_Line = str_dupn("", 0);
  127.     line->ln_Strlen = 1;
  128.     }
  129.     linenum++;
  130.     if(!resize_line_list(tx, linenum - allocedlines, linenum))
  131.     goto abortmem;
  132.     tx->tx_Changes++;
  133.     rc = TRUE;
  134. #ifdef HAVE_AMIGA
  135.     message("OK");
  136. #endif
  137.     if(0)
  138.     {
  139.     /* This only gets executed if we aborted while reading the file. */
  140. abortmem:
  141.     mem_error();
  142.     clear_line_list(tx);
  143.     }
  144.     tx->tx_Flags |= TXFF_REFRESH_ALL;
  145.     return(rc);
  146. }
  147.  
  148. _PR VALUE cmd_read_buffer(VALUE file, VALUE tx);
  149. DEFUN("read-buffer", cmd_read_buffer, subr_read_buffer, (VALUE file, VALUE tx), V_Subr2, DOC_read_buffer) /*
  150. ::doc:read_buffer::
  151. read-buffer FILE [BUFFER]
  152.  
  153. Overwrites the text in BUFFER with that from the file FILE.
  154. FILE is either a string naming the file to be opened or a Lisp file object
  155. (from `open') to be used.
  156. ::end:: */
  157. {
  158.     VALUE res = sym_nil;
  159.     FILE *fh;
  160.     bool closefh;
  161.     POS start, end;
  162.     if(FILEP(file) && VFILE(file)->lf_Name)
  163.     {
  164.     fh = VFILE(file)->lf_File;
  165.     closefh = FALSE;
  166.     }
  167.     else
  168.     {
  169.     DECLARE1(file, STRINGP);
  170.     if(!(fh = fopen(VSTR(file), "r")))
  171.         return(cmd_signal(sym_file_error, list_2(lookup_errno(), file)));
  172.     closefh = TRUE;
  173.     }
  174.     if(!BUFFERP(tx))
  175.     tx = VAL(curr_vw->vw_Tx);
  176.     start.pos_Col = start.pos_Line = 0;
  177.     end.pos_Line = VTX(tx)->tx_NumLines - 1;
  178.     end.pos_Col = VTX(tx)->tx_Lines[end.pos_Line].ln_Strlen - 1;
  179.     if(!(end.pos_Line == 0 && end.pos_Line == 0))
  180.     undo_record_deletion(VTX(tx), &start, &end);
  181.     kill_line_list(VTX(tx));
  182.     if(read_tx(VTX(tx), fh))
  183.     {
  184.     end.pos_Line = VTX(tx)->tx_NumLines - 1;
  185.     end.pos_Col = VTX(tx)->tx_Lines[end.pos_Line].ln_Strlen - 1;
  186.     undo_record_insertion(VTX(tx), &start, &end);
  187.     res = tx;
  188.     }
  189.     else
  190.     clear_line_list(VTX(tx));     /* hope for some mem left */
  191.     if(closefh)
  192.     fclose(fh);
  193.     reset_all_views(VTX(tx));
  194.     sys_reset_sleep_titles(VTX(tx));
  195.     return(res);
  196. }
  197.  
  198. _PR VALUE cmd_write_buffer(VALUE file, VALUE tx);
  199. DEFUN("write-buffer", cmd_write_buffer, subr_write_buffer, (VALUE file, VALUE tx), V_Subr2, DOC_write_buffer) /*
  200. ::doc:write_buffer::
  201. write-buffer [FILE-NAME] [BUFFER]
  202.  
  203. Saves the contents of BUFFER to file FILE-NAME.
  204. ::end:: */
  205. {
  206.     if(!BUFFERP(tx))
  207.     tx = VAL(curr_vw->vw_Tx);
  208.     if(!STRINGP(file))
  209.     file = VTX(tx)->tx_FileName;
  210.     if(file)
  211.     {
  212.     FILE *fh = fopen(VSTR(file), "w");
  213.     if(fh)
  214.     {
  215.         long i;
  216.         LINE *line = VTX(tx)->tx_Lines;
  217.         for(i = 0; i < VTX(tx)->tx_NumLines; i++, line++)
  218.         {
  219.         if(fwrite(line->ln_Line, 1, line->ln_Strlen - 1, fh)
  220.            != (line->ln_Strlen - 1))
  221.             goto error;
  222.         if(i != VTX(tx)->tx_NumLines - 1)
  223.             fputc('\n', fh);
  224.         }
  225.         fclose(fh);
  226.     }
  227.     else
  228. error:
  229.         return(cmd_signal(sym_file_error, list_2(lookup_errno(), file)));
  230.     return(file);
  231.     }
  232.     return(cmd_signal(sym_bad_arg, list_2(file, make_number(1))));
  233. }
  234.  
  235. _PR VALUE cmd_write_buffer_area(VALUE vstart, VALUE vend, VALUE file, VALUE tx);
  236. 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) /*
  237. ::doc:write_buffer_area::
  238. write-buffer-area START-POS END-POS [FILE-NAME] [BUFFER]
  239.  
  240. Writes the text between START-POS and END-POS in BUFFER to file
  241. FILE-NAME.
  242. ::end:: */
  243. {
  244.     POS start, end;
  245.     DECLARE1(vstart, POSP);
  246.     DECLARE2(vend, POSP);
  247.     if(!BUFFERP(tx))
  248.     tx = VAL(curr_vw->vw_Tx);
  249.     if(!STRINGP(file))
  250.     file = VTX(tx)->tx_FileName;
  251.     start = VPOS(vstart);
  252.     end = VPOS(vend);
  253.     if(!check_section(VTX(tx), &start, &end))
  254.     return(cmd_signal(sym_invalid_area, list_3(tx, vstart, vend)));
  255.     if(file)
  256.     {
  257.     FILE *fh = fopen(VSTR(file), "w");
  258.     if(fh)
  259.     {
  260.         LINE *line = VTX(tx)->tx_Lines + start.pos_Line;
  261.         while(start.pos_Line <= end.pos_Line)
  262.         {
  263.         int len = (((start.pos_Line == end.pos_Line)
  264.                 ? end.pos_Col : line->ln_Strlen)
  265.                - start.pos_Col - 1);
  266.         if(fwrite(line->ln_Line + start.pos_Col,
  267.               1, len, fh) != len) 
  268.             goto error;
  269.         if(start.pos_Line != end.pos_Line)
  270.             fputc('\n', fh);
  271.         start.pos_Line++;
  272.         start.pos_Col = 0;
  273.         line++;
  274.         }
  275.         fclose(fh);
  276.     }
  277.     else
  278. error:
  279.         return(cmd_signal(sym_file_error, list_2(lookup_errno(), file)));
  280.     return(file);
  281.     }
  282.     return(cmd_signal(sym_bad_arg, list_2(file, make_number(1))));
  283. }
  284.  
  285. _PR VALUE cmd_cd(VALUE dir);
  286. DEFUN("cd", cmd_cd, subr_cd, (VALUE dir), V_Subr1, DOC_cd) /*
  287. ::doc:cd::
  288. cd [DIRECTORY]
  289.  
  290. If DIRECTORY is given set the editor's current directory to it, else
  291. return the name of the current directory.
  292. ::end:: */
  293. {
  294.     VALUE res = sym_nil;
  295.     if(STRINGP(dir))
  296.     {
  297.     if(chdir(VSTR(dir)))
  298.         messagef("can't chdir to %s", VSTR(dir));
  299.     else
  300.         res = dir;
  301.     }
  302.     else
  303.     {
  304.     u_char buff[256];
  305.     if(getcwd(buff, 256))
  306.         res = string_dup(buff);
  307.     }
  308.     return(res);
  309. }
  310.  
  311. _PR VALUE cmd_write_file(VALUE file, VALUE str);
  312. DEFUN("write-file", cmd_write_file, subr_write_file, (VALUE file, VALUE str), V_Subr2, DOC_write_file) /*
  313. ::doc:write_file::
  314. write-