home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / jade-3.0.lha / Jade / src / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-19  |  13.1 KB  |  550 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. #if defined( HAVE_UNIX )
  26. # include <unistd.h>
  27. #elif defined( HAVE_AMIGA )
  28.   /* my Amiga compiler has chdir() etc in <stdio.h> */
  29. #endif
  30.  
  31. _PR bool readtx(TX *, FILE *, long, long *);
  32. _PR bool writeline(u_char *, long, FILE *, TX *, long);
  33. _PR bool fileexists2(u_char *, u_char *);
  34. _PR bool fileexists3(u_char *, u_char *, u_char *);
  35. _PR VALUE signalfileerror(VALUE cdr);
  36. _PR void io_init(void);
  37.  
  38. /* bytes to copy instead of tabs */
  39. _PR   const u_char Spaces[];
  40. _PR   const u_char Tabs[];
  41. const u_char Spaces[] = "                                                "
  42.             "                                                "
  43.             "                                                ";
  44. 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";
  45.  
  46. /*
  47.  * read a file into a tx structure, the line list should have been
  48.  * killed.
  49.  * I'm going to have to speed this up somehow.
  50.  * hopefully now loads lines of any length (upto max of 32768)
  51.  *
  52.  * codePos is an array of 3 LONGs to hold the position of the code
  53.  * section to execute, it is filled in as follows,
  54.  *  codePos[0]    start column
  55.  *       [1]    start line
  56.  *       [2]    end line
  57.  * It should initially hold -1s to check for no code section.
  58.  */
  59. #define SIZESTEP  50    /* size at which line list grows by */
  60. #define BUFFSTART 128
  61. bool
  62. readtx(TX *tx, FILE *fh, long diskTab, long *codePos)
  63. {
  64.     bool rc = FALSE;
  65.     long bufflen = BUFFSTART;
  66.     u_char *buff = mystralloc(bufflen);
  67.     if(buff)
  68.     {
  69.     long c, i = 0;
  70.     long linenum = 0, allocedlines = 0;
  71.     u_char *newstr;
  72.     LINE *line;
  73. #ifdef HAVE_AMIGA
  74.     settitle("loading...");
  75. #endif
  76.     while((c = fgetc(fh)) != EOF)
  77.     {
  78.         if(i >= bufflen)
  79.         {
  80.         u_char *newbuff;
  81.         newbuff = mystralloc(bufflen * 2);
  82.         if(!newbuff)
  83.             goto abortmem;
  84.         memcpy(newbuff, buff, i);
  85.         mystrfree(buff);
  86.         buff = newbuff;
  87.         bufflen *= 2;
  88.         }
  89.         if(c == '\n')
  90.         {
  91.         if(linenum >= allocedlines)
  92.         {
  93.             if(!resizelinelist(tx, SIZESTEP, linenum))
  94.             goto abortmem;
  95.             allocedlines += SIZESTEP;
  96.         }
  97.         if(!(newstr = mystralloc(i + 1)))
  98.             goto abortmem;
  99.         memcpy(newstr, buff, i);
  100.         newstr[i] = 0;
  101.         line = tx->tx_Lines + linenum;
  102.         line->ln_Strlen = i + 1;
  103.         line->ln_Line = newstr;
  104.         i = 0;
  105.         /*
  106.          * check for code section
  107.          */
  108.         if(codePos[1] < 0)
  109.         {
  110.             u_char *s = strstr(newstr, "::jade" "-code::");
  111.             if(s)
  112.             {
  113.             codePos[0] = s - newstr;
  114.             codePos[1] = linenum;
  115.             }
  116.         }
  117.         else if(codePos[2] < 0)
  118.         {
  119.             if(strstr(newstr, "::end::"))
  120.             codePos[2] = linenum;
  121.         }
  122.         linenum++;
  123.         }
  124.         else if(c == '\t')
  125.         {
  126.         int numspaces = diskTab - (i % diskTab);
  127.         if(i + numspaces >= bufflen)
  128.         {
  129.             u_char *newbuff = mystralloc(bufflen * 2);
  130.             if(!newbuff)
  131.             goto abortmem;
  132.             memcpy(newbuff, buff, i);
  133.             mystrfree(buff);
  134.             buff = newbuff;
  135.             bufflen *= 2;
  136.         }
  137.         strncpy(buff + i, Spaces, numspaces);
  138.         i += numspaces;
  139.         }
  140.         else
  141.         buff[i++] = c;
  142.     }
  143.     if(!resizelinelist(tx, linenum - allocedlines + 1, linenum))
  144.         goto abortmem;
  145.     if(!(newstr = mystralloc(i + 1)))
  146.         goto abortmem;
  147.     memcpy(newstr, buff, i);
  148.     newstr[i] = 0;
  149.     line = tx->tx_Lines + linenum;
  150.     line->ln_Strlen = i + 1;
  151.     line->ln_Line = newstr;
  152.     if((codePos[1] >= 0) && (codePos[2] < 0))
  153.         codePos[2] = linenum;
  154.     tx->tx_Changes++;
  155.     rc = TRUE;
  156. #ifdef HAVE_AMIGA
  157.     settitle("OK");
  158. #endif
  159.     /* This block only gets executed if we aborted while
  160.      * reading the file.
  161.      */
  162.     if(0)
  163.     {
  164. abortmem:
  165.         settitle(NoMemMsg);
  166. #if 0
  167. abort:
  168. #endif
  169.         clearlinelist(tx);
  170.     }
  171.     mystrfree(buff);
  172.     }
  173.     else
  174.     settitle(NoMemMsg);
  175.     tx->tx_Flags |= TXFF_REFRESH_ALL;
  176.     return(rc);
  177. }
  178.  
  179. _PR VALUE cmd_read_buffer(VALUE file, VALUE tx);
  180. DEFUN("read-buffer", cmd_read_buffer, subr_read_buffer, (VALUE file, VALUE tx), V_Subr2, DOC_read_buffer) /*
  181. ::doc:read_buffer::
  182. (read-buffer FILE [BUFFER])
  183. Overwrites the text in BUFFER with that from the file FILE.
  184. FILE is either a string naming the file to be opened or a Lisp file object
  185. (from `open') to be used.
  186. ::end:: */
  187. {
  188.     long codepos[3];
  189.     VALUE res = sym_nil;
  190.     FILE *fh;
  191.     bool closefh;
  192.     if(FILEP(file) && VFILE(file)->lf_Name)
  193.     {
  194.     fh = VFILE(file)->lf_File;
  195.     closefh = FALSE;
  196.     }
  197.     else
  198.     {
  199.     DECLARE1(file, STRINGP);
  200.     if(!(fh = fopen(VSTR(file), "r")))
  201.         return(cmd_signal(sym_file_error, list_2(geterrstring(), file)));
  202.     closefh = TRUE;
  203.     }
  204.     if(!BUFFERP(tx))
  205.     tx = CurrVW->vw_Tx;
  206.     killlinelist(VTX(tx));
  207.     codepos[1] = codepos[2] = -1;
  208.     if(readtx(VTX(tx), fh, VTX(tx)->tx_DiskTab, codepos))
  209.     res = tx;
  210.     else
  211.     clearlinelist(VTX(tx));     /* hope for some mem left */
  212.     if(closefh)
  213.     fclose(fh);
  214.     resetallviews(VTX(tx));
  215.     resetslptxtitles(VTX(tx));
  216.     if(codepos[2] > 0)
  217.     execfilecode(VTX(tx), codepos);
  218.     return(res);
  219. }
  220.  
  221. _PR VALUE cmd_write_buffer(VALUE file, VALUE tx);
  222. DEFUN("write-buffer", cmd_write_buffer, subr_write_buffer, (VALUE file, VALUE tx), V_Subr2, DOC_write_buffer) /*
  223. ::doc:write_buffer::
  224. (write-buffer [FILE-NAME] [BUFFER])
  225. Saves the contents of BUFFER to file FILE-NAME.
  226. ::end:: */
  227. {
  228.     if(!BUFFERP(tx))
  229.     tx = CurrVW->vw_Tx;
  230.     if(!STRINGP(file))
  231.     file = VTX(tx)->tx_FileName;
  232.     if(file)
  233.     {
  234.     FILE *fh = fopen(VSTR(file), "w");
  235.     if(fh)
  236.     {
  237.         long i;
  238.         LINE *line = VTX(tx)->tx_Lines;
  239.         for(i = 0; i < VTX(tx)->tx_NumLines; i++, line++)
  240.         {
  241.         if(!writeline(line->ln_Line, line->ln_Strlen - 1, fh, VTX(tx), 0))
  242.             goto error;
  243.         if(i != VTX(tx)->tx_NumLines - 1)
  244.             fputc('\n', fh);
  245.         }
  246.         fclose(fh);
  247.     }
  248.     else
  249. error:
  250.         return(cmd_signal(sym_file_error, list_2(geterrstring(), file)));
  251.     return(file);
  252.     }
  253.     return(cmd_signal(sym_bad_arg, list_2(file, newnumber(1))));
  254. }
  255.  
  256. _PR VALUE cmd_write_buffer_area(VALUE vstart, VALUE vend, VALUE file, VALUE tx);
  257. 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) /*
  258. ::doc:write_buffer_area::
  259. (write-buffer-area START-POS END-POS [FILE-NAME] [BUFFER])
  260. Writes the text between START-POS and END-POS in BUFFER to file
  261. FILE-NAME.
  262. ::end:: */
  263. {
  264.     POS start, end;
  265.     DECLARE1(vstart, POSP);
  266.     DECLARE2(vend, POSP);
  267.     if(!BUFFERP(tx))
  268.     tx = CurrVW->vw_Tx;
  269.     if(!STRINGP(file))
  270.     file = VTX(tx)->tx_FileName;
  271.     start = VPOS(vstart);
  272.     end = VPOS(vend);
  273.     if(!checksect(tx, &start, &end))
  274.     return(cmd_signal(sym_invalid_area, list_3(tx, vstart, vend)));
  275.     if(file)
  276.     {
  277.     FILE *fh = fopen(VSTR(file), "w");
  278.     if(fh)
  279.     {
  280.         LINE *line = VTX(tx)->tx_Lines + start.pos_Line;
  281.         while(start.pos_Line <= end.pos_Line)
  282.         {
  283.         if(!writeline(line->ln_Line,
  284.                   (start.pos_Line == end.pos_Line)
  285.                 ? end.pos_Col : line->ln_Strlen - 1,
  286.                   fh, tx, start.pos_Col))
  287.             goto error;
  288.         if(start.pos_Line != end.pos_Line)
  289.             fputc('\n', fh);
  290.         start.pos_Line++;
  291.         start.pos_Col = 0;
  292.         line++;
  293.         }
  294.         fclose(fh);
  295.     }
  296.     else
  297. error:
  298.         return(cmd_signal(sym_file_error, list_2(geterrstring(), file)));
  299.     return(file);
  300.     }
  301.     return(cmd_signal(sym_bad_arg, list_2(file, newnumber(1))));
  302. }
  303.  
  304. _PR VALUE cmd_cd(VALUE dir);
  305. DEFUN("cd", cmd_cd, subr_cd, (VALUE dir), V_Subr1, DOC_cd) /*
  306. ::doc:cd::
  307. (cd [DIRECTORY])
  308. If DIRECTORY is given set the editor's current directory to it, else
  309. return the name of the current directory.
  310. ::end:: */
  311. {
  312.     VALUE res = sym_nil;
  313.     if(STRINGP(dir))
  314.     {
  315.     if(chdir(VSTR(dir)))
  316.         settitlefmt("can't chdir to %s", VSTR(dir));
  317.     else
  318.         res = dir;
  319.     }
  320.     else
  321.     {
  322.     u_char buff[256];
  323.     if(getcwd(buff, 256))
  324.         res = valstrdup(buff);
  325.     }
  326.     return(res);
  327. }
  328.  
  329. _PR VALUE cmd_write_file(VALUE file, VALUE str);
  330. DEFUN("write-file", cmd_write_file, subr_write_file, (VALUE file, VALUE str), V_Subr2, DOC_write_file) /*
  331. ::doc:write_file::
  332. (write-file FILE-NAME STRING)
  333. Writes STRING to file FILE-NAME.
  334. ::end:: */
  335. {
  336.     FILE *fh;
  337.     VALUE res = sym_nil;
  338.     DECLARE1(file, STRINGP);
  339.     DECLARE2(str, STRINGP);
  340.     fh = fopen(VSTR(file), "w");
  341.     if(fh)
  342.     {
  343.     if(fputs(VSTR(str), fh) == EOF)
  344.         res = cmd_signal(sym_file_error, list_2(geterrstring(), file));
  345.     else
  346.         res = sym_t;
  347.     fclose(fh);
  348.     }
  349.     else
  350.     res = cmd_signal(sym_file_error, list_2(geterrstring(), file));
  351.     return(res);
  352. }
  353.  
  354. _PR VALUE cmd_read_file(VALUE file);
  355. DEFUN("read-file", cmd_read_file, subr_read_file, (VALUE file), V_Subr1, DOC_read_file) /*
  356. ::doc:read_file::
  357. (read-file FILE-NAME)
  358. Return the contents of file FILE-NAME.
  359. ::end:: */
  360. {
  361.     DECLARE1(file, STRINGP);
  362.     return(valsquirrelfile(VSTR(file)));
  363. }
  364.  
  365. _PR VALUE cmd_read_file_from_to(VALUE file, VALUE offset, VALUE ch);
  366. 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) /*
  367. ::doc:read_file_from_to::
  368. (read-file-from-to FILENAME OFFSET CHAR)
  369. ::end:: */
  370. {
  371.     FILE *fh;
  372.     VALUE str = NULL;
  373.     DECLARE1(file, STRINGP);
  374.     DECLARE2(offset, NUMBERP);
  375.     DECLARE3(ch, CHARP);
  376.     if((fh = fopen(VSTR(file), "r")) && !fseek(fh, VNUM(offset), 0 /*SEEK_SET*/))
  377.     {
  378.     int buflen = 128, i = 0, c;
  379.     u_char *buf = mystralloc(buflen);
  380.     if(buf)
  381.     {
  382.         while(((c = getc(fh)) != VCHAR(ch)) && (c != EOF))
  383.         {
  384.         if(i >= buflen)
  385.         {
  386.             u_char *newbuf;
  387.             int newbuflen = buflen * 2;
  388.             if(!(newbuf = mystralloc(newbuflen)))
  389.             goto error;
  390.             memcpy(newbuf, buf, i);
  391.             mystrfree(buf);
  392.             buf = newbuf;
  393.             buflen = newbuflen;
  394.         }
  395.         buf[i++] = c;
  396.         }
  397.         str = valstrdupn(buf, i);
  398. error:
  399.         mystrfree(buf);
  400.     }
  401.     fclose(fh);
  402.     }
  403.     else
  404.     return(cmd_signal(sym_file_error, list_2(MKSTR("Can't open file"), file)));
  405.     return(str);
  406. }
  407.  
  408. _PR VALUE cmd_write_clip(VALUE unit, VALUE str);
  409. DEFUN("write-clip", cmd_write_clip, subr_write_clip, (VALUE unit, VALUE str), V_Subr2, DOC_write_clip) /*
  410. ::doc:write_clip::
  411. (write-clip UNIT STRING)
  412. Writes STRING to unit UNIT of the standard clipboard.
  413. ::end:: */
  414. {
  415.     DECLARE1(unit, NUMBERP);
  416.     DECLARE2(str, STRINGP);
  417.     if(writeclip(VNUM(unit), VSTR(str), strlen(VSTR(str))))
  418.     return(sym_t);
  419.     return(sym_nil);
  420. }
  421.  
  422. _PR VALUE cmd_read_clip(VALUE unit);
  423. DEFUN("read-clip", cmd_read_clip, subr_read_clip, (VALUE unit), V_Subr1, DOC_read_clip) /*
  424. ::doc:read_clip::
  425. (read-clip UNIT)
  426. Returns the string which unit UNIT of the clipboard holds.
  427. ::end:: */
  428. {
  429.     DECLARE1(unit, NUMBERP);
  430.     return(readclip(VNUM(unit)));
  431. }
  432.  
  433. /*
  434.  * Writes out a line of text,
  435.  * if SaveTabs == 1 leading spaces will be changed to tabs,
  436.  * if SaveTabs == 2 all spaces (except after quotes) are made into tabs and
  437.  * trailing spaces are discarded.
  438.  */
  439. bool
  440. writeline(u_char *line, long len, FILE *fh, TX *tx, long i)
  441. {
  442.     if(tx->tx_SaveTabs)
  443.     {
  444.     long lastchg = i;
  445.     bool inspc = FALSE;
  446.     bool nodo = FALSE;
  447.     long disktab = tx->tx_DiskTab;
  448.     u_char c;
  449.     for( ; (i <= len) && (c = line[i]); i++)
  450.     {
  451.         if(!nodo)
  452.         {
  453.         if(c == ' ')
  454.         {
  455.             if(!inspc)
  456.             {
  457.             if(fwrite(line + lastchg, 1, i - lastchg, fh) != i - lastchg)
  458.                 goto error;
  459.             lastchg = i;
  460.             inspc = TRUE;
  461.             }
  462.         }
  463.         else
  464.         {
  465.             if(inspc)
  466.             {
  467.             int numtabs, numspcs;
  468.             if(lastchg == i - 1)
  469.             {
  470.                 numtabs = 0;
  471.                 numspcs = 1;
  472.             }
  473.             else
  474.             {
  475.                 numtabs = (i - (lastchg - (lastchg % disktab))) / disktab;
  476.                 numspcs = i % disktab;
  477.                 if(numspcs > i - lastchg)
  478.                 numspcs = i - lastchg;
  479.             }
  480.             if(fwrite(Tabs, 1, numtabs, fh) != numtabs)
  481.                 goto error;
  482.             if(fwrite(Spaces, 1, numspcs, fh) != numspcs)
  483.                 goto error;
  484.             lastchg = i;
  485.             inspc = FALSE;
  486.             }
  487.             if((c == '"') || (c == '\'') || (c == '`') || (tx->tx_SaveTabs == 1))
  488.             nodo = TRUE;
  489.         }
  490.         }
  491.     }
  492.     if((!inspc) || nodo)
  493.     {
  494.         if(fwrite(line + lastchg, 1, i - lastchg, fh) != i - lastchg)
  495.         goto error;
  496.     }
  497.     return(TRUE);
  498.     }
  499.     else
  500.     {
  501.     if(fwrite(line + i, 1, len - i, fh) == (len - i))
  502.         return(TRUE);
  503.     }
  504. error:
  505.     return(FALSE);
  506. }
  507.  
  508. bool
  509. fileexists2(u_char *s1, u_char *s2)
  510. {
  511.     u_char buf[256];
  512.     stpcpy(stpcpy(buf, s1), s2);
  513.     return(fileexists(buf));
  514. }
  515. bool
  516. fileexists3(u_char *s1, u_char *s2, u_char *s3)
  517. {
  518.     u_char buf[256];
  519.     stpcpy(stpcpy(stpcpy(buf, s1), s2), s3);
  520.     return(fileexists(buf));
  521. }
  522.  
  523. VALUE
  524. signalfileerror(VALUE cdr)
  525. {
  526.     VALUE data = cmd_cons(geterrstring, sym_nil);
  527.     if(cdr)
  528.     {
  529.     if(CONSP(cdr))
  530.         VCDR(data) = cdr;
  531.     else
  532.         VCDR(data) = cmd_cons(cdr, sym_nil);
  533.     }
  534.     return(cmd_signal(sym_file_error, data));
  535. }
  536.  
  537. void
  538. io_init(void)
  539. {
  540.     ADD_SUBR(subr_read_buffer);
  541.     ADD_SUBR(subr_write_buffer);
  542.     ADD_SUBR(subr_write_buffer_area);
  543.     ADD_SUBR(subr_cd);
  544.     ADD_SUBR(subr_write_file);
  545.     ADD_SUBR(subr_read_file);
  546.     ADD_SUBR(subr_read_file_from_to);
  547.     ADD_SUBR(subr_write_clip);
  548.     ADD_SUBR(subr_read_clip);
  549. }
  550.