home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / may94 / util / edit / jade.lha / Jade / src / edit.c < prev    next >
C/C++ Source or Header  |  1994-04-19  |  22KB  |  981 lines

  1. /* edit.c -- Editing buffers
  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. #include <ctype.h>
  25.  
  26. _PR bool clearlinelist(TX *);
  27. _PR void killlinelist(TX *);
  28. _PR LINE *resizelinelist(TX *, long, long);
  29. _PR bool insertgap(TX *, long, const POS *);
  30. _PR bool insertstr(TX *, const u_char *, POS *);
  31. _PR bool insertstrn(TX *, const u_char *, long, POS *);
  32. _PR bool insertstring(TX *, const u_char *, long, POS *);
  33. _PR bool rectinsertstring(TX *, const u_char *, POS *);
  34. _PR bool deletechars(TX *, const POS *, long);
  35. _PR bool deletelines(TX *, long, long);
  36. _PR bool deletesection(TX *, POS *, POS *);
  37. _PR bool rectdeletesection(TX *, POS *, POS *);
  38. _PR bool splitline(TX *, POS *);
  39. static bool joinlines(TX *, POS *);
  40. _PR bool padpos(TX *, POS *);
  41. _PR bool padcursor(VW *);
  42. _PR void orderpos(POS *, POS *);
  43. _PR void orderrect(POS *, POS *, POS *, POS *);
  44. _PR bool checksect(TX *, POS *, POS *);
  45. _PR void checkpos(TX *, POS *);
  46. _PR bool checkline(TX *, POS *);
  47. _PR long sectionlength(TX *, POS *, POS *);
  48. _PR void copysection(TX *, POS *, POS *, u_char *);
  49. _PR long rectsectionlength(TX *, POS *, POS *);
  50. _PR void rectcopysection(TX *, POS *, POS *, u_char *);
  51. _PR bool colcopysect(TX *, long *, u_char *, long);
  52. _PR bool posinblock(VW *, long, long);
  53. _PR bool cursinblock(VW *);
  54. _PR bool pageinblock(VW *);
  55. _PR short lineinblock(VW *, long);
  56. _PR void orderblock(VW *);
  57. _PR void setblockrefresh(VW *);
  58. _PR bool readonly(TX *);
  59.  
  60. #define ALLOCLL(n)   mymalloc(sizeof(LINE) * (n))
  61. #define FREELL(l)    myfree(l)
  62.  
  63. /*
  64.  * This copies a line list (or part of one).
  65.  * d = destination
  66.  * s = source
  67.  * n = number of LINE's to copy.
  68.  */
  69. #define MOVLL(d,s,n) memcpy((d), (s), (n) * sizeof(LINE))
  70. /*
  71.  * void
  72.  * MOVLL(LINE *dst, LINE *src, long number)
  73.  * {
  74.  *     memcpy(dst, src, number * sizeof(LINE));
  75.  * }
  76.  */
  77.  
  78. /*
  79.  * Makes file empty (null string in first line)
  80.  */
  81. bool
  82. clearlinelist(TX *tx)
  83. {
  84.     if(tx->tx_Lines)
  85.     killlinelist(tx);
  86.     tx->tx_Lines = ALLOCLL(1);
  87.     if(tx->tx_Lines)
  88.     {
  89.     tx->tx_Lines[0].ln_Line = mystrdupn("", 0);
  90.     if(tx->tx_Lines[0].ln_Line)
  91.         tx->tx_Lines[0].ln_Strlen = 1;
  92.     else
  93.         tx->tx_Lines[0].ln_Strlen = 0;
  94.     tx->tx_NumLines = 1;
  95.     return(TRUE);
  96.     }
  97.     return(FALSE);
  98. }
  99.  
  100. /*
  101.  * deallocates all lines and their list
  102.  */
  103. void
  104. killlinelist(TX *tx)
  105. {
  106.     if(tx->tx_Lines)
  107.     {
  108.     LINE *line;
  109.     long i;
  110.     for(i = 0, line = tx->tx_Lines; i < tx->tx_NumLines; i++, line++)
  111.     {
  112.         if(line->ln_Strlen)
  113.         mystrfree(line->ln_Line);
  114.     }
  115.     FREELL(tx->tx_Lines);
  116.     tx->tx_Lines = NULL;
  117.     tx->tx_NumLines = 0;
  118.     }
  119. }
  120.  
  121. /*
  122.  * deallocates some lines (but not the list)
  123.  */
  124. static void
  125. killsomelines(TX *tx, long start, long number)
  126. {
  127.     LINE *line = tx->tx_Lines + start;
  128.     long i;
  129.     for(i = 0; i < number; i++, line++)
  130.     {
  131.     if(line->ln_Strlen)
  132.     {
  133.         mystrfree(line->ln_Line);
  134.         line->ln_Strlen = 0;
  135.         line->ln_Line = NULL;
  136.     }
  137.     }
  138. }
  139.  
  140. /*
  141.  * Creates blank entries or removes existing lines starting from line 'where'
  142.  * 'change' is the number of lines to insert, negative numbers mean delete
  143.  * that number of lines starting at the cursor line.
  144.  * If lines are deleted the actual text is also deleted.
  145.  * NOTE: You can't have a line list of zero lines.
  146.  */
  147. LINE *
  148. resizelinelist(TX *tx, long change, long where)
  149. {
  150.     LINE *newlines;
  151.     long newsize = tx->tx_NumLines + change;
  152.     if((newsize > 0) && (newlines = ALLOCLL(newsize)))
  153.     {
  154.     if(tx->tx_Lines)
  155.     {
  156.         if(change > 0)
  157.         {
  158.         MOVLL(newlines, tx->tx_Lines, where);
  159.         MOVLL(newlines + where + change, tx->tx_Lines + where, tx->tx_NumLines - where);
  160.         }
  161.         else
  162.         {
  163.         MOVLL(newlines, tx->tx_Lines, where);
  164.         MOVLL(newlines + where, tx->tx_Lines + where - change, tx->tx_NumLines - where + change);
  165.         killsomelines(tx, where, -change);
  166.         }
  167.         FREELL(tx->tx_Lines);
  168.     }
  169.     if(change > 0)
  170.         bzero(newlines + where, change * sizeof(LINE));
  171.     tx->tx_Lines = newlines;
  172.     tx->tx_NumLines = newsize;
  173.     return(newlines);
  174.     }
  175.     return(FALSE);
  176. }
  177.  
  178. #if 0
  179. /*
  180.  * Pastes a line into the current view at line num.
  181.  * a LINE should have been made if it is wanted.
  182.  * text is not copied, it should have been mymalloc()'ed (or savestring()'ed)
  183.  */
  184. bool
  185. stuffline(TX *tx, u_char *text, long lineNum)
  186. {
  187.     LINE *line = tx->tx_Lines + lineNum;
  188.     if(line->ln_Strlen)
  189.     mystrfree(line->ln_Line);
  190.     line->ln_Strlen = strlen(text) + 1;
  191.     line->ln_Line = text;
  192.     return(TRUE);
  193. }
  194. #endif
  195.  
  196. /*
  197.  * Inserts some `space' at pos. The gap will be filled with random garbage.
  198.  * pos is *not* altered.
  199.  */
  200. bool
  201. insertgap(TX *tx, long len, const POS *pos)
  202. {
  203.     LINE *line = tx->tx_Lines + pos->pos_Line;
  204.     u_char *newline = mystralloc(len + line->ln_Strlen);
  205.     if(newline)
  206.     {
  207.     if(line->ln_Strlen)
  208.     {
  209.         memcpy(newline, line->ln_Line, pos->pos_Col);
  210.         strcpy(newline + pos->pos_Col + len, line->ln_Line + pos->pos_Col);
  211.         mystrfree(line->ln_Line);
  212.     }
  213.     else
  214.         newline[len] = 0;
  215.     line->ln_Line = newline;
  216.     line->ln_Strlen += len;
  217.     keepposaddx(tx, len, pos->pos_Col, pos->pos_Line);
  218.     return(TRUE);
  219.     }
  220.     return(FALSE);
  221. }
  222.  
  223. /*
  224.  * Inserts a string into the current line at the cursor pos
  225.  *
  226.  * IMPORTANT: For any of the next functions which insert text the pos
  227.  * argument must not be one which will be fiddled with by the keeppos*()
  228.  * functions (specifically a direct pointer to vw_CursorPos).
  229.  */
  230. bool
  231. insertstr(TX *tx, const u_char *text, POS *pos)
  232. {
  233.     return(insertstrn(tx, text, strlen(text), pos));
  234. }
  235.  
  236. bool
  237. insertstrn(TX *tx, const u_char *text, long textLen, POS *pos)
  238. {
  239.     LINE *line = tx->tx_Lines + pos->pos_Line;
  240.     if(insertgap(tx, textLen, pos))
  241.     {
  242.     memcpy(line->ln_Line + pos->pos_Col, text, textLen);
  243.     pos->pos_Col += textLen;
  244.     return(TRUE);
  245.     }
  246.     return(FALSE);
  247. }
  248.  
  249. /*
  250.  * Inserts a null teminated string, this routine acts on any '\n' or '\t'
  251.  * characters that it finds.
  252.  * I expect that this routine will be incredibly slow.
  253.  */
  254. bool
  255. insertstring(TX *tx, const u_char *text, long tabSize, POS *pos)
  256. {
  257. #define INSERT_BUF_LEN 128
  258.     u_char *buff = mystralloc(INSERT_BUF_LEN);
  259.     if(buff)
  260.     {
  261.     const u_char *str = text;
  262.     POS orig = *pos;
  263.     while(*str)
  264.     {
  265.         u_char c;
  266.         long i = 0;
  267.         long startx = pos->pos_Col;
  268.         while((c = *str++) && (c != '\n') && (i < INSERT_BUF_LEN))
  269.         {
  270.         if(c == '\t')
  271.         {
  272.             int numspc = tabSize - ((i + startx) % tabSize);
  273.             memset(buff + i, ' ', numspc);
  274.             i += numspc;
  275.         }
  276.         else
  277.             buff[i++] = c;
  278.         }
  279.         buff[i] = 0;
  280.         if(c == '\n')
  281.         {
  282.         if(pos->pos_Col)
  283.         {
  284.             if(!insertstrn(tx, buff, i, pos))
  285.             goto abort;
  286.             if(!splitline(tx, pos))
  287.             goto abort;
  288.             pos->pos_Col = 0;
  289.         }
  290.         else
  291.         {
  292.             u_char *copy;
  293.             if(!resizelinelist(tx, +1, pos->pos_Line))
  294.             goto abort;
  295.             if(!(copy = mystrdupn(buff, i)))
  296.             goto abort;
  297.             tx->tx_Lines[pos->pos_Line].ln_Strlen = i + 1;
  298.             tx->tx_Lines[pos->pos_Line].ln_Line = copy;
  299.             keepposaddy(tx, +1, pos->pos_Line);
  300.         }
  301.         pos->pos_Line++;
  302.         startx = 0;
  303.         }
  304.         else
  305.         {
  306.         str--;
  307.         if(!insertstrn(tx, buff, i, pos))
  308.         {
  309. abort:
  310.             settitle(NoMemMsg);
  311.             mystrfree(buff);
  312.             return(FALSE);
  313.         }
  314.         }
  315.     }
  316.     flaginsertion(tx, &orig, pos);
  317.     mystrfree(buff);
  318.     return(TRUE);
  319.     }
  320.     settitle(NoMemMsg);
  321.     return(FALSE);
  322. }
  323.  
  324. /*
  325.  */
  326. bool
  327. rectinsertstring(TX *tx, const u_char *text, POS *pos)
  328. {
  329.     long col = pos->pos_Col;
  330.     LINE *line = tx->tx_Lines + pos->pos_Line;
  331.     long llen = 0;
  332.     POS orig;
  333.     while(*text && (pos->pos_Line < tx->tx_NumLines))
  334.     {
  335.     const u_char *tmp = text;
  336.     while(*tmp