home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / programs / text / jed / src / jed.lha / edit.c < prev    next >
C/C++ Source or Header  |  1993-01-08  |  25KB  |  1,092 lines

  1.  
  2. /*
  3.  * EDIT.C
  4.  * (c) 1992 J.Harper
  5.  */
  6.  
  7. #include "jed.h"
  8. #include "jed_protos.h"
  9.  
  10. Prototype   BOOL    clearlinelist    (TX *);
  11. Prototype   VOID    killlinelist    (TX *);
  12. Prototype   VOID    killsomelines    (TX *, LONG, LONG);
  13. Prototype   LINE *  resizelinelist    (TX *, LONG, LONG);
  14. Prototype   BOOL    stuffline        (STRPTR, LONG);
  15. Prototype   BOOL    insertstr        (STRPTR);
  16. Prototype   BOOL    insertstrn        (STRPTR, WORD);
  17. Prototype   BOOL    insertstring    (STRPTR, LONG);
  18. Prototype   BOOL    insertsection    (STRPTR);
  19. Prototype   BOOL    deletechars        (WORD);
  20. Prototype   BOOL    deletelines        (LONG);
  21. Prototype   BOOL    deletesection    (POS *);
  22. Prototype   BOOL    splitline        (VOID);
  23. Prototype   BOOL    joinlines        (VOID);
  24. Prototype   BOOL    wrapline        (VOID);
  25. Prototype   BOOL    padcursor        (VOID);
  26. Prototype   VOID    orderpos        (POS *, POS *);
  27. Prototype   BOOL    getsection        (STRPTR, POS *);
  28. Prototype   LONG    sectionlength    (POS *, POS *);
  29. Prototype   VOID    copysection        (POS *, POS *, STRPTR);
  30. Prototype   BOOL    posinblock        (WORD, LONG);
  31. Prototype   BOOL    cursinblock        (VOID);
  32. Prototype   BOOL    pageinblock        (VOID);
  33. Prototype   WORD    lineinblock        (LONG);
  34. Prototype   VOID    orderblock        (VOID);
  35. Prototype   VOID    setblockrefresh    (VOID);
  36. Prototype   LONG    offset        (VOID);
  37. Prototype   LONG    size        (VOID);
  38.  
  39. #define allocll(n)   AllocVec(sizeof(LINE) * (n), 0L)
  40. #define freell(l)    FreeVec(l)
  41.  
  42. /*
  43.  * This macro copies a line list (or part of one).
  44.  * d = destination
  45.  * s = source
  46.  * n = number of LINE's to copy.
  47.  */
  48. #define movll(d,s,n) CopyMemQuick((ULONG *)(s), (ULONG *)(d), (n) << 3)
  49.  
  50. /*
  51.  * Makes file empty (null string in first line)
  52.  */
  53. BOOL
  54. clearlinelist(TX *tx)
  55. {
  56.     if(tx->tx_Lines)
  57.     killlinelist(tx);
  58.     if(tx->tx_Lines = allocll(1));
  59.     {
  60.     if(tx->tx_Lines[0].ln_Line = savestring(""))
  61.         tx->tx_Lines[0].ln_Strlen = 1;
  62.     else
  63.         tx->tx_Lines[0].ln_Strlen = 0;
  64.     tx->tx_NumLines = 1;
  65.     return(TRUE);
  66.     }
  67.     return(FALSE);
  68. }
  69.  
  70. /*
  71.  * deallocates all lines and their list
  72.  */
  73. VOID
  74. killlinelist(TX *tx)
  75. {
  76.     if(tx->tx_Lines)
  77.     {
  78.     LINE *line;
  79.     LONG i;
  80.     for(i = 0, line = tx->tx_Lines; i < tx->tx_NumLines; i++, line++)
  81.     {
  82.         if(line->ln_Strlen)
  83.         FreeVec(line->ln_Line);
  84.     }
  85.     freell(tx->tx_Lines);
  86.     tx->tx_Lines = NULL;
  87.     tx->tx_NumLines = 0;
  88.     }
  89.     killmarklist(tx);
  90. }
  91.  
  92. /*
  93.  * deallocates some lines (but not the list)
  94.  */
  95. VOID
  96. killsomelines(TX *tx, LONG start, LONG number)
  97. {
  98.     LINE *line = tx->tx_Lines + start;
  99.     LONG i;
  100.  
  101.     for(i = 0; i < number; i++, line++)
  102.     {
  103.     if(line->ln_Strlen)
  104.     {
  105.         FreeVec(line->ln_Line);
  106.         line->ln_Strlen = 0;
  107.         line->ln_Line = NULL;
  108.     }
  109.     }
  110. }
  111.  
  112. /*
  113.  * Creates blank entries or removes existing lines starting from line 'where'
  114.  * 'change' is the number of lines to insert, negative numbers mean delete
  115.  * that number of lines starting at the cursor line.
  116.  * If lines are deleted the actual text is also deleted.
  117.  */
  118. LINE *
  119. resizelinelist(TX *tx, LONG change, LONG where)
  120. {
  121.     LINE *newlines;
  122.     LONG newsize = tx->tx_NumLines + change;
  123.  
  124.     if((newsize >= 0) && (newlines = allocll(newsize)))
  125.     {
  126.     if(tx->tx_Lines)
  127.     {
  128.         if(change > 0)
  129.         {
  130.         movll(newlines, tx->tx_Lines, where);
  131.         movll(newlines + where + change, tx->tx_Lines + where, tx->tx_NumLines - where);
  132.         }
  133.         else
  134.         {
  135.         movll(newlines, tx->tx_Lines, where);
  136.         movll(newlines + where, tx->tx_Lines + where - change, tx->tx_NumLines - where + change);
  137.         killsomelines(tx, where, -change);
  138.         }
  139.         freell(tx->tx_Lines);
  140.     }
  141.     if(change > 0)
  142.         bzero(newlines + where, change * sizeof(LINE));
  143.     tx->tx_Lines = newlines;
  144.     tx->tx_NumLines = newsize;
  145.     return(newlines);
  146.     }
  147.     return(FALSE);
  148. }
  149.  
  150. /*
  151.  * Pastes a line into the current view at line num.
  152.  * a LINE should have been made if it is wanted.
  153.  * text is not copied, it should have been AllocVec()'ed (or savestring()'ed)
  154.  */
  155. BOOL
  156. stuffline(STRPTR text, LONG lineNum)
  157. {
  158.     LINE *line = CurrVW->vw_Tx->tx_Lines + lineNum;
  159.  
  160.     if(line->ln_Strlen)
  161.     FreeVec(line->ln_Line);
  162.  
  163.     line->ln_Strlen = strlen(text) + 1;
  164.     line->ln_Line = text;
  165.     return(TRUE);
  166. }
  167.  
  168. /*
  169.  * Inserts a string into the current line at the cursor pos
  170.  */
  171. BOOL
  172. insertstr(STRPTR text)
  173. {
  174.     return(insertstrn(text, strlen(text)));
  175. }
  176.  
  177. BOOL
  178. insertstrn(STRPTR text, WORD textLen)
  179. {
  180.     VW *vw = CurrVW;
  181.     TX *tx = vw->vw_Tx;
  182.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  183.     STRPTR newline;
  184.  
  185.     if(newline = AllocVec(textLen + line->ln_Strlen, 0L))
  186.     {
  187.     if(line->ln_Strlen)
  188.     {
  189.         memcpy(newline, line->ln_Line, vw->vw_CursorPos.pos_Col);
  190.         memcpy(newline + vw->vw_CursorPos.pos_Col, text, textLen);
  191.         strcpy(newline + vw->vw_CursorPos.pos_Col + textLen, line->ln_Line + vw->vw_CursorPos.pos_Col);
  192.     }
  193.     else
  194.     {
  195.         memcpy(newline, text, textLen);
  196.         newline[textLen] = 0;
  197.     }
  198.     stuffline(newline, vw->vw_CursorPos.pos_Line);
  199.     keepposaddx(textLen);
  200.     return(TRUE);
  201.     }
  202.     return(FALSE);
  203. }
  204.  
  205. /*
  206.  * Inserts a null teminated string, this routine acts on any '\n' or '\t'
  207.  * characters that it finds.
  208.  * I expect that this routine will be incredibly slow.
  209.  */
  210. BOOL
  211. insertstring(STRPTR text, LONG tabSize)
  212. {
  213.     STRPTR buff = AllocVec(1024, 0L);
  214.     if(buff)
  215.     {
  216.     VW *vw = CurrVW;
  217.     STRPTR str = text;
  218.     setrefresh(RFF_LINEFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
  219.     while(*str)
  220.     {
  221.         UBYTE c;
  222.         LONG i = 0;
  223.         WORD startx = vw->vw_CursorPos.pos_Col;
  224.  
  225.         while((c = *str++) && (c != '\n') && (i < 1024))
  226.         {
  227.         if(c == '\t')
  228.         {
  229.             WORD numspc = tabSize - ((i + startx) % tabSize);
  230.             memcpy(buff + i, Spaces, numspc);
  231.             i += numspc;
  232.         }
  233.         else
  234.             buff[i++] = c;
  235.         }
  236.         buff[i] = 0;
  237.         if(c == '\n')
  238.         {
  239.         vw->vw_RefreshType |= RFF_ALLFROM;
  240.         if(vw->vw_CursorPos.pos_Col)
  241.         {
  242.             if(!insertstrn(buff, i))
  243.             goto abort;
  244.             if(!splitline())
  245.             goto abort;
  246.         }
  247.         else
  248.         {
  249.             STRPTR copy;
  250.             if(!resizelinelist(vw->vw_Tx, +1, vw->vw_CursorPos.pos_Line))
  251.             goto abort;
  252.             if(!(copy = savestring(buff)))
  253.             goto abort;
  254.             stuffline(copy, vw->vw_CursorPos.pos_Line);
  255.             keepposaddy(+1);
  256.         }
  257.         startx = 0;
  258.         }
  259.         else
  260.         {
  261.         str--;
  262.         if(!insertstrn(buff, i))
  263.         {
  264. abort:
  265.             settitle(NoMemMsg);
  266.             FreeVec(buff);
  267.             return(FALSE);
  268.         }
  269.         }
  270.     }
  271.     FreeVec(buff);
  272.     return(TRUE);
  273.     }
  274.     settitle(NoMemMsg);
  275.     return(FALSE);
  276. }
  277.  
  278. /*
  279.  * Inserts a section from the text file into the current cursor position.
  280.  * You can't insert into the text that is to be inserted.
  281.  * Works out if the copied text is to be inserted before the cursor (if so
  282.  * all line numbers have to recalculated after each line is inserted).
  283.  */
  284. BOOL
  285. insertsection(STRPTR sectType)
  286. {
  287.     VW *vw = CurrVW;
  288.     TX *tx = vw->vw_Tx;
  289.     POS endpos, temp;
  290.     POS startpos = vw->vw_CursorPos;
  291.  
  292.     if(getsection(sectType, &endpos))
  293.     {
  294.     BOOL copyback = FALSE;
  295.  
  296.     /* If some of the next code seems totally weird it's because the
  297.      * startpos and vw_CursorPos are actually swapped with each other
  298.      * for this part :-)
  299.      */
  300.     if(!(
  301.         ((startpos.pos_Line < vw->vw_CursorPos.pos_Line) || (startpos.pos_Line > endpos.pos_Line)) ||
  302.         ((startpos.pos_Line == vw->vw_CursorPos.pos_Line) && (startpos.pos_Col < vw->vw_CursorPos.pos_Col)) ||
  303.         ((startpos.pos_Line == endpos.pos_Line) && (startpos.pos_Col >= endpos.pos_Col))
  304.     )){
  305.         settitle("error: can't insert into self");
  306.         vw->vw_CursorPos = startpos;
  307.         return(FALSE);
  308.     }
  309.  
  310.     /* They're switched back here.
  311.      */
  312.     temp = vw->vw_CursorPos;
  313.     vw->vw_CursorPos = startpos;
  314.     startpos = temp;
  315.  
  316.     /* Test if we're copying to a line behind where we're copying from,
  317.      * this would really screw up the copy if not accounted for!
  318.      */
  319.     if(vw->vw_CursorPos.pos_Line < startpos.pos_Line)
  320.         copyback = TRUE;
  321.  
  322.     if(startpos.pos_Line == endpos.pos_Line)
  323.     {
  324.         setrefresh(RFF_LINEFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
  325.         return(insertstrn(tx->tx_Lines[startpos.pos_Line].ln_Line + startpos.pos_Col, endpos.pos_Col - startpos.pos_Col));
  326.     }
  327.     else
  328.     {
  329.         LONG middle;
  330.         setrefresh(RFF_ALLFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
  331.         if(startpos.pos_Col || vw->vw_CursorPos.pos_Col)
  332.         {
  333.         LINE *sline = tx->tx_Lines + startpos.pos_Line;
  334.         if(!insertstrn(sline->ln_Line + startpos.pos_Col, sline->ln_Strlen - startpos.pos_Col - 1))
  335.             goto abort;
  336.         if(!splitline())
  337.             goto abort;
  338.         if(copyback)
  339.         {
  340.             endpos.pos_Line++;
  341.             startpos.pos_Line += 2;
  342.         }
  343.         else
  344.             startpos.pos_Line++;
  345.         }
  346.         middle = endpos.pos_Line - startpos.pos_Line;
  347.         if(!resizelinelist(vw->vw_Tx, middle, vw->vw_CursorPos.pos_Line))
  348.         goto abort;
  349.         if(copyback)
  350.         {
  351.         endpos.pos_Line += middle;
  352.         startpos.pos_Line += middle;
  353.         }
  354.         while(startpos.pos_Line < endpos.pos_Line)
  355.         {
  356.         LINE *sline = tx->tx_Lines + startpos.pos_Line;
  357.         LINE *dline = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  358.         STRPTR copy = savestring(sline->ln_Line);
  359.         if(!copy)
  360.             goto abort;
  361.         dline->ln_Line = copy;
  362.         dline->ln_Strlen = sline->ln_Strlen;
  363.         keepposaddy(+1);
  364.         startpos.pos_Line++;
  365.         }
  366.         if(endpos.pos_Col)
  367.         {
  368.         if(!insertstrn(tx->tx_Lines[endpos.pos_Line].ln_Line, endpos.pos_Col))
  369.         {
  370. abort:
  371.             settitle(NoMemMsg);
  372.             return(FALSE);
  373.         }
  374.         }
  375.     }
  376.     return(TRUE);
  377.     }
  378.     return(FALSE);
  379. }
  380.  
  381. /*
  382.  * Deletes some text from the cursor pos (this line only)
  383.  */
  384. BOOL
  385. deletechars(WORD size)
  386. {
  387.     VW *vw = CurrVW;
  388.     TX *tx = vw->vw_Tx;
  389.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  390.  
  391.     if(line->ln_Strlen)
  392.     {
  393.     STRPTR newline;
  394.  
  395.     if(size >= line->ln_Strlen)
  396.         size = line->ln_Strlen - 1;
  397.  
  398.     if(newline = AllocVec(line->ln_Strlen - size, 0L))
  399.     {
  400.         strncpy(newline, line->ln_Line, vw->vw_CursorPos.pos_Col);
  401.         strcpy(newline + vw->vw_CursorPos.pos_Col, line->ln_Line + vw->vw_CursorPos.pos_Col + size);
  402.         FreeVec(line->ln_Line);
  403.         line->ln_Strlen -= size;
  404.         line->ln_Line = newline;
  405.  
  406.         keeppossubx(size);
  407.         return(TRUE);
  408.     }
  409.     return(FALSE);
  410.     }
  411.     return(TRUE);
  412. }
  413.  
  414. /*
  415.  * deletes some lines from the cursor pos
  416.  */
  417. BOOL
  418. deletelines(LONG size)
  419. {
  420.     VW *vw = CurrVW;
  421.     BOOL rc;
  422.     rc = (BOOL)resizelinelist(vw->vw_Tx, -size, vw->vw_CursorPos.pos_Line);
  423.     keeppossuby(size);
  424.     return(rc);
  425. }
  426.  
  427. /*
  428.  * Deletes from the cursor to endPos
  429.  * sets refresh flags and resync*()'s text but doesn't call refresh().
  430.  */
  431. BOOL
  432. deletesection(POS *endPos)
  433. {
  434.     VW *vw = CurrVW;
  435.     TX *tx = vw->vw_Tx;
  436.     POS oldcurs = vw->vw_CursorPos;
  437.     if(endPos->pos_Line == vw->vw_CursorPos.pos_Line)
  438.     {
  439.     deletechars(endPos->pos_Col - vw->vw_CursorPos.pos_Col);
  440.     setrefresh(RFF_LINEFROM, oldcurs.pos_Col, oldcurs.pos_Line);
  441.     resyncx();
  442.     }
  443.     else
  444.     {
  445.     LONG middle;
  446.     BOOL joinflag = FALSE;
  447.  
  448.     if(vw->vw_CursorPos.pos_Col)
  449.     {
  450.         WORD start = tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen - vw->vw_CursorPos.pos_Col - 1;
  451.         if(start)
  452.         deletechars(start);
  453.         vw->vw_CursorPos.pos_Col = 0;
  454.         vw->vw_CursorPos.pos_Line++;
  455.         joinflag = TRUE;
  456.     }
  457.     if(middle = endPos->pos_Line - vw->vw_CursorPos.pos_Line)
  458.     {
  459.         deletelines(middle);
  460.         endPos->pos_Line -= middle;
  461.     }
  462.     if(endPos->pos_Col)
  463.         deletechars(endPos->pos_Col);
  464.     if(joinflag && vw->vw_CursorPos.pos_Line)
  465.     {
  466.         vw->vw_CursorPos.pos_Line--;
  467.         vw->vw_CursorPos.pos_Col = tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen - 1;
  468.         joinlines();
  469.     }
  470.     setrefresh(RFF_ALLFROM, oldcurs.pos_Col, oldcurs.pos_Line);
  471.     resyncxy();
  472.     }
  473.     return(TRUE);
  474. }
  475.  
  476. /*
  477.  * splits the line into two at the cursor pos
  478.  */
  479. BOOL
  480. splitline(VOID)
  481. {
  482.     VW *vw = CurrVW;
  483.     TX *tx = vw->vw_Tx;
  484.  
  485.     if(resizelinelist(tx, +1, vw->vw_CursorPos.pos_Line + 1))
  486.     {
  487.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  488.     STRPTR newline1;
  489.     if(newline1 = savestringn(line->ln_Line, vw->vw_CursorPos.pos_Col))
  490.     {
  491.         STRPTR newline2;
  492.         if(newline2 = savestring(line->ln_Line + vw->vw_CursorPos.pos_Col))
  493.         {
  494.         stuffline(newline1, vw->vw_CursorPos.pos_Line);
  495.         stuffline(newline2, vw->vw_CursorPos.pos_Line + 1);
  496.         keeppossplity();
  497.         return(TRUE);
  498.         }
  499.         freestring(newline1);
  500.     }
  501.     }
  502.     settitle(NoMemMsg);
  503.     return(FALSE);
  504. }
  505.  
  506. /*
  507.  * joins the current line to the line below it.
  508.  */
  509. BOOL
  510. joinlines(VOID)
  511. {
  512.     VW *vw = CurrVW;
  513.     TX *tx = vw->vw_Tx;
  514.  
  515.     if((vw->vw_CursorPos.pos_Line + 1) < tx->tx_NumLines)
  516.     {
  517.     LINE *line1 = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  518.     LINE *line2 = line1 + 1;
  519.     STRPTR newstr;
  520.  
  521.     if(newstr = AllocVec(line1->ln_Strlen + line2->ln_Strlen - 1, 0L))
  522.     {
  523.         stpcpy(stpcpy(newstr, line1->ln_Line), line2->ln_Line);
  524.         resizelinelist(tx, -1, vw->vw_CursorPos.pos_Line);
  525.         stuffline(newstr, vw->vw_CursorPos.pos_Line);
  526.         keepposjoiny();
  527.         return(TRUE);
  528.     }
  529.     settitle(NoMemMsg);
  530.     }
  531.     return(FALSE);
  532. }
  533.  
  534. /*
  535.  * Does a 'wordwrap'
  536.  */
  537. BOOL
  538. wrapline(VOID)
  539. {
  540.     VW *vw = CurrVW;
  541.     TX *tx = vw->vw_Tx;
  542.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  543.     STRPTR txt = line->ln_Line + vw->vw_CursorPos.pos_Col;
  544.  
  545.     while(!isspace(*txt--))
  546.     {
  547.     if(txt == line->ln_Line - 1)
  548.         return(FALSE);
  549.     }
  550.     txt++;
  551.     vw->vw_CursorPos.pos_Col = txt - line->ln_Line;
  552.     setrefresh(RFF_ALLFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
  553.  
  554.     if(resizelinelist(tx, +1, vw->vw_CursorPos.pos_Line + 1))
  555.     {
  556.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  557.     STRPTR newline1;
  558.     if(newline1 = savestringn(line->ln_Line, vw->vw_CursorPos.pos_Col))
  559.     {
  560.         STRPTR newline2;
  561.         LONG newlen = line->ln_Strlen - vw->vw_CursorPos.pos_Col - 1;
  562.         LONG indlen = 0;
  563.         LONG movlen = vw->vw_Prefs.prf_RightMargin - vw->vw_CursorPos.pos_Col - 1;
  564.         if(vw->vw_Prefs.prf_AutoIndent)
  565.         {
  566.         STRPTR spc = line->ln_Line;
  567.         while(isspace(*spc++))
  568.             indlen++;
  569.         }
  570.         else
  571.         indlen = vw->vw_Prefs.prf_LeftMargin;
  572.         movlen += indlen;
  573.         if(newline2 = AllocVec(newlen + indlen + 1, 0L))
  574.         {
  575.         STRPTR spc = newline2;
  576.         while(indlen--)
  577.             *spc++ = ' ';
  578.         memcpy(spc, line->ln_Line + vw->vw_CursorPos.pos_Col + 1, newlen);
  579.  
  580.         stuffline(newline1, vw->vw_CursorPos.pos_Line);
  581.         stuffline(newline2, vw->vw_CursorPos.pos_Line + 1);
  582.  
  583.         /* This next bit isn't too satisfactory.
  584.          */
  585.         keeppossubx(line->ln_Strlen - vw->vw_CursorPos.pos_Col - 1);
  586.         keeppossplity();
  587.         if(movlen > 0)
  588.             keepposaddx(movlen);
  589.         else
  590.             keeppossubx(-movlen);
  591.  
  592.         return(TRUE);
  593.         }
  594.         freestring(newline1);
  595.     }
  596.     }
  597.     settitle(NoMemMsg);
  598.     return(FALSE);
  599. }
  600.  
  601. /*
  602.  * Inserts spaces from end of line to cursor position (for free-form editing)
  603.  */
  604. BOOL
  605. padcursor(VOID)
  606. {
  607.     VW *vw = CurrVW;
  608.     TX *tx = vw->vw_Tx;
  609.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  610.  
  611.     if(vw->vw_LineUndo.line != vw->vw_CursorPos.pos_Line)
  612.     {
  613.     freestring(vw->vw_LineUndo.text);
  614.     vw->vw_LineUndo.text = savestring(line->ln_Line);
  615.     vw->vw_LineUndo.line = vw->vw_CursorPos.pos_Line;
  616.     vw->vw_LineUndo.changes = tx->tx_Changes;
  617.     }
  618.     if(line->ln_Strlen < (vw->vw_CursorPos.pos_Col + 1))
  619.     {
  620.     STRPTR newline;
  621.     if(newline = AllocVec(vw->vw_CursorPos.pos_Col + 1, 0L))
  622.     {
  623.         WORD i;
  624.         strcpy(newline, line->ln_Line);
  625.         for(i = line->ln_Strlen - 1; i < vw->vw_CursorPos.pos_Col; i++)
  626.         newline[i] = ' ';
  627.         newline[i] = 0;
  628.         stuffline(newline, vw->vw_CursorPos.pos_Line);
  629.         return(TRUE);
  630.     }
  631.     settitle(NoMemMsg);
  632.     vw->vw_CursorPos.pos_Col = line->ln_Strlen - 1;
  633.     return(FALSE);
  634.     }
  635.     return(TRUE);
  636. }
  637.  
  638. /*
  639.  * if end is before start then swap the two
  640.  */
  641. VOID
  642. orderpos(POS *start, POS *end)
  643. {
  644.     if
  645.     (
  646.     ((start->pos_Line == end->pos_Line) && (start->pos_Col > end->pos_Col)) ||
  647.     (start->pos_Line > end->pos_Line)
  648.     )
  649.     {
  650.     POS temp;
  651.     temp = *start;
  652.     *start = *end;
  653.     *end = temp;
  654.     }
  655. }
  656.  
  657. /*
  658.  * cursor is set to start of section, end to end (end is exclusive)
  659.  * types,
  660.  *  b            - marked Block
  661.  *  c            - char under Cursor
  662.  *  f            - whole File
  663.  *  l            - Line
  664.  *  p            - Previous character
  665.  *  n            - Next character
  666.  *  w            - word
  667.  *  el            - to EoL
  668.  *  sl            - to SoL
  669.  *  ef            - to EoF
  670.  *  sf            - to SoF
  671.  *  mX            - to mark X
  672.  */
  673. BOOL
  674. getsection(STRPTR type, POS *end)
  675. {
  676.     VW *vw = CurrVW;
  677.     TX *tx = vw->vw_Tx;
  678.     BOOL rc = TRUE;
  679.  
  680.     switch(tolower(*type++))
  681.     {
  682.     case 'b':
  683.         if(!vw->vw_BlockStatus)
  684.         {
  685.         vw->vw_CursorPos = vw->vw_Block[0];
  686.         *end = vw->vw_Block[1];
  687.         vw->vw_BlockStatus = -1;
  688.         setblockrefresh();
  689.         }
  690.         else
  691.         rc = FALSE;
  692.         break;
  693.     case 'c':
  694.         end->pos_Col = vw->vw_CursorPos.pos_Col + 1;
  695.         end->pos_Line = vw->vw_CursorPos.pos_Line;
  696.         if(end->pos_Col >= tx->tx_Lines[end->pos_Line].ln_Strlen)
  697.         {
  698.         end->pos_Col = 0;
  699.         if(++end->pos_Line >= tx->tx_NumLines)
  700.             rc = FALSE;
  701.         }
  702.         break;
  703.     case 'f':
  704.         vw->vw_CursorPos.pos_Col = vw->vw_CursorPos.pos_Line = 0;
  705.         end->pos_Col = tx->tx_Lines[tx->tx_NumLines - 1].ln_Strlen - 1;
  706.         end->pos_Line = tx->tx_NumLines - 1;
  707.         break;
  708.     case 'l':
  709.         vw->vw_CursorPos.pos_Col = 0;
  710.         end->pos_Col = 0;
  711.         end->pos_Line = vw->vw_CursorPos.pos_Line + 1;
  712.         if(end->pos_Line >= tx->tx_NumLines)
  713.         {
  714.         end->pos_Line--;
  715.         end->pos_Col = tx->tx_Lines[end->pos_Line].ln_Strlen - 1;
  716.         }
  717.         break;
  718.     case 'p':
  719.         end->pos_Col = vw->vw_CursorPos.pos_Col--;
  720.         end->pos_Line = vw->vw_CursorPos.pos_Line;
  721.         if(vw->vw_CursorPos.pos_Col < 0)
  722.         {
  723.         if(--vw->vw_CursorPos.pos_Line < 0)
  724.         {
  725.             vw->vw_CursorPos.pos_Col++;
  726.             vw->vw_CursorPos.pos_Line++;
  727.             return(FALSE);
  728.         }
  729.         vw->vw_CursorPos.pos_Col = tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen - 1;
  730.         }
  731.         break;
  732.     case 'n':
  733.         if(++vw->vw_CursorPos.pos_Col > tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen - 1)
  734.         {
  735.         if(++vw->vw_CursorPos.pos_Line >= tx->tx_NumLines)
  736.         {
  737.             vw->vw_CursorPos.pos_Col--;
  738.             vw->vw_CursorPos.pos_Line--;
  739.             return(FALSE);
  740.         }
  741.         vw->vw_CursorPos.pos_Col = 0;
  742.         }
  743.         end->pos_Col = vw->vw_CursorPos.pos_Col + 1;
  744.         end->pos_Line = vw->vw_CursorPos.pos_Line;
  745.         if(end->pos_Col > tx->tx_Lines[end->pos_Line].ln_Strlen - 1)
  746.         {
  747.         if(++end->pos_Line >= tx->tx_NumLines)
  748.             return(FALSE);
  749.         end->pos_Col = 0;
  750.         }
  751.         break;
  752.     case 'w':
  753.         if(vw->vw_CursorPos.pos_Col < tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen)
  754.         {
  755.         STRPTR line = tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Line;
  756.         STRPTR word = line + vw->vw_CursorPos.pos_Col;
  757.         while(isalnum(*word--))
  758.             ;
  759.         word += 2;
  760.         vw->vw_CursorPos.pos_Col = word - line;
  761.         end->pos_Col = stpalnum(word) - line;
  762.         end->pos_Line = vw->vw_CursorPos.pos_Line;
  763.         rc = TRUE;
  764.         }
  765.         else
  766.         rc = FALSE;
  767.         break;
  768.     case 'e':
  769.         switch(tolower(*type++))
  770.         {
  771.         case 'f':
  772.             end->pos_Col = tx->tx_Lines[tx->tx_NumLines - 1].ln_Strlen - 1;
  773.             end->pos_Line = tx->tx_NumLines - 1;
  774.             break;
  775.         case 'l':
  776.             end->pos_Col = tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen - 1;
  777.             end->pos_Line = vw->vw_CursorPos.pos_Line;
  778.             break;
  779.         default:
  780.             rc = FALSE;
  781.         }
  782.         break;
  783.     case 's':
  784.         switch(tolower(*type++))
  785.         {
  786.         case 'f':
  787.             *end = vw->vw_CursorPos;
  788.             vw->vw_CursorPos.pos_Col = vw->vw_CursorPos.pos_Line = 0;
  789.             break;
  790.         case 'l':
  791.             *end = vw->vw_CursorPos;
  792.             vw->vw_CursorPos.pos_Col = 0;
  793.             break;
  794.         default:
  795.             rc = FALSE;
  796.         }
  797.         break;
  798.     case 'm':
  799.         APTR dummy;
  800.         MARK *mk;
  801.         WORD mknum = strtol(type, &dummy, 0);
  802.         for(mk = (MARK *)tx->tx_Marks.mlh_Head; mk->mk_Node.mln_Succ; mk = (MARK *)mk->mk_Node.mln_Succ)
  803.         {
  804.         if(mk->mk_Index == mknum)
  805.             break;
  806.         }
  807.         if(mk->mk_Node.mln_Succ)
  808.         {
  809.         *end = mk->mk_Pos;
  810.         if(end->pos_Line >= tx->tx_NumLines)
  811.             end->pos_Line = tx->tx_NumLines - 1;
  812.         if(end->pos_Col >= tx->tx_Lines[end->pos_Line].ln_Strlen)
  813.             end->pos_Col = tx->tx_Lines[end->pos_Line].ln_Strlen - 1;
  814.         orderpos(&vw->vw_CursorPos, end);
  815.         }
  816.         else
  817.         {
  818.         settitlefmt("error: mark %ld is not set", mknum);
  819.         rc = FALSE;
  820.         }
  821.         break;
  822.     default:
  823.         settitle("error: invalid section specification");
  824.         rc = FALSE;
  825.         break;
  826.     }
  827.     return(rc);
  828. }
  829.  
  830. /*
  831.  * Returns the number of bytes needed to store a section, doesn't include
  832.  * a zero terminator but does include all newline chars.
  833.  */
  834. LONG
  835. sectionlength(POS *startPos, POS *endPos)
  836. {
  837.     LONG linenum = startPos->pos_Line;
  838.     LINE *line = CurrVW->vw_Tx->tx_Lines + linenum;
  839.     LONG length;
  840.  
  841.     if(startPos->pos_Line == endPos->pos_Line)
  842.     length = endPos->pos_Col - startPos->pos_Col;
  843.     else
  844.     {
  845.     length = line->ln_Strlen - startPos->pos_Col;
  846.     linenum++;
  847.     line++;
  848.     while(linenum < endPos->pos_Line)
  849.     {
  850.         length += line->ln_Strlen;
  851.         linenum++;
  852.         line++;
  853.     }
  854.     length += endPos->pos_Col;
  855.     }
  856.     return(length);
  857. }
  858.  
  859. /*
  860.  * Copies a section to a buffer.
  861.  * end of copy does NOT have a zero appended to it.
  862.  */
  863. VOID
  864. copysection(POS *startPos, POS *endPos, STRPTR buff)
  865. {
  866.     LONG linenum = startPos->pos_Line;
  867.     LINE *line = CurrVW->vw_Tx->tx_Lines + linenum;
  868.     LONG copylen;
  869.  
  870.     if(startPos->pos_Line == endPos->pos_Line)
  871.     {
  872.     copylen = endPos->pos_Col - startPos->pos_Col;
  873.     memcpy(buff, line->ln_Line + startPos->pos_Col, copylen);
  874.     buff[copylen] = 0;
  875.     }
  876.     else
  877.     {
  878.     copylen = line->ln_Strlen - startPos->pos_Col - 1;
  879.     memcpy(buff, line->ln_Line + startPos->pos_Col, copylen);
  880.     buff[copylen] = '\n';
  881.     buff += copylen + 1;
  882.     linenum++;
  883.     line++;
  884.     while(linenum < endPos->pos_Line)
  885.     {
  886.         copylen = line->ln_Strlen - 1;
  887.         memcpy(buff, line->ln_Line, copylen);
  888.         buff[copylen] = '\n';
  889.         buff += copylen + 1;
  890.         linenum++;
  891.         line++;
  892.     }
  893.     memcpy(buff, line->ln_Line, endPos->pos_Col);
  894.     }
  895. }
  896.  
  897. /*
  898.  * returns TRUE if the specified position is inside a block
  899.  */
  900. BOOL
  901. posinblock(WORD col, LONG line)
  902. {
  903.     VW *vw = CurrVW;
  904.     if
  905.     (
  906.     (vw->vw_BlockStatus) ||
  907.     (line < vw->vw_Block[0].pos_Line) ||
  908.     ((line == vw->vw_Block[0].pos_Line) && (col < vw->vw_Block[0].pos_Col))
  909.     )
  910.     return(FALSE);
  911.     if
  912.     (
  913.     (line < vw->vw_Block[1].pos_Line) ||
  914.     ((line == vw->vw_Block[1].pos_Line) && (col < vw->vw_Block[1].pos_Col))
  915.     )
  916.     return(TRUE);
  917.     return(FALSE);
  918. }
  919.  
  920. BOOL
  921. cursinblock(VOID)
  922. {
  923.     VW *vw = CurrVW;
  924.     return(posinblock(vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line));
  925. }
  926.  
  927.  
  928. BOOL
  929. pageinblock(VOID)
  930. {
  931.     VW *vw = CurrVW;
  932.     if
  933.     (
  934.     (vw->vw_BlockStatus) ||
  935.     (vw->vw_Block[1].pos_Line < vw->vw_StartLine) ||
  936.     (vw->vw_Block[0].pos_Line >= vw->vw_StartLine + vw->vw_MaxY)
  937.     )
  938.     return(FALSE);
  939.     return(TRUE);
  940. }
  941.  
  942. /*
  943.  * these returns,
  944.  *
  945.  *    0   line not in block
  946.  *    1   whole line in block
  947.  *    2   start of line in block
  948.  *    3   end of line in block
  949.  *    4   middle of line in block
  950.  *
  951.  * note:
  952.  *  this isn't very intelligent (but it works :-).
  953.  */
  954. WORD
  955. lineinblock(LONG line)
  956. {
  957.     VW *vw = CurrVW;
  958.     BOOL startin = FALSE;
  959.     BOOL endin = FALSE;
  960.  
  961.     if
  962.     (
  963.     (vw->vw_BlockStatus) ||
  964.     (line < vw->vw_Block[0].pos_Line) ||
  965.     (line > vw->vw_Block[1].pos_Line)
  966.     )
  967.     return(0);
  968.  
  969.     if(line == vw->vw_Block[1].pos_Line)
  970.     startin = TRUE;
  971.     if(line == vw->vw_Block[0].pos_Line)
  972.     endin = TRUE;
  973.  
  974.     if(startin)
  975.     {
  976.     if(endin)
  977.         return(4);
  978.     return(2);
  979.     }
  980.     if(endin)
  981.     return(3);
  982.     return(1);
  983. }
  984.  
  985. /*
  986.  * makes sure that the marked block is valid
  987.  */
  988. VOID
  989. orderblock(VOID)
  990. {
  991.     VW *vw = CurrVW;
  992.     LINE *fline = vw->vw_Tx->tx_Lines;
  993.     if(!vw->vw_BlockStatus)
  994.     {
  995.     if(vw->vw_Block[0].pos_Col >= fline[vw->vw_Block[0].pos_Line].ln_Strlen)
  996.         vw->vw_Block[0].pos_Col = fline[vw->vw_Block[0].pos_Line].ln_Strlen - 1;
  997.     if(vw->vw_Block[1].pos_Col >= fline[vw->vw_Block[1].pos_Line].ln_Strlen)
  998.         vw->vw_Block[1].pos_Col = fline[vw->vw_Block[1].pos_Line].ln_Strlen - 1;
  999.  
  1000.     if(vw->vw_Block[0].pos_Line > vw->vw_Block[1].pos_Line)
  1001.     {
  1002.         POS temp = vw->vw_Block[1];
  1003.         vw->vw_Block[1] = vw->vw_Block[0];
  1004.         vw->vw_Block[0] = temp;
  1005.     }
  1006.     else if(vw->vw_Block[0].pos_Line == vw->vw_Block[1].pos_Line)
  1007.     {
  1008.         if(vw->vw_Block[0].pos_Col > vw->vw_Block[1].pos_Col)
  1009.         {
  1010.         POS temp = vw->vw_Block[1];
  1011.         vw->vw_Block[1] = vw->vw_Block[0];
  1012.         vw->vw_Block[0] = temp;
  1013.         }
  1014.     }
  1015.     }
  1016. }
  1017.  
  1018. /*
  1019.  * Set up the refresh flags to refresh the block in the most efficient manner.
  1020.  * To make it better I'll have to add a refresh type which allows you to say
  1021.  * where to stop drawing.
  1022.  */
  1023. VOID
  1024. setblockrefresh(VOID)
  1025. {
  1026.     VW *vw = CurrVW;
  1027.     LONG endline = vw->vw_StartLine + vw->vw_MaxY;
  1028.     WORD refx;
  1029.     LONG refy;
  1030.  
  1031.     if((vw->vw_Block[0].pos_Line > endline) || (vw->vw_Block[1].pos_Line < vw->vw_StartLine))
  1032.     return;
  1033.  
  1034.     if(vw->vw_Block[0].pos_Line < vw->vw_StartLine)
  1035.     {
  1036.     refy= vw->vw_StartLine;
  1037.     refx = 0;
  1038.     }
  1039.     else
  1040.     {
  1041.     refy = vw->vw_Block[0].pos_Line;
  1042.     refx = vw->vw_Block[0].pos_Col;
  1043.     }
  1044.     if(vw->vw_Block[0].pos_Line == vw->vw_Block[1].pos_Line)
  1045.     setrefresh(RFF_LINEFROM, refx, refy);
  1046.     else
  1047.     setrefresh(RFF_ALLFROM, refx, refy);
  1048. }
  1049.  
  1050. /*
  1051.  * Returns the number of bytes from the start of the file that the cursor
  1052.  * is.
  1053.  */
  1054. LONG
  1055. offset(VOID)
  1056. {
  1057.     VW *vw = CurrVW;
  1058.     LINE *line = vw->vw_Tx->tx_Lines;
  1059.     LONG linenum = 0;
  1060.     LONG off = 0;
  1061.  
  1062.     while(linenum < vw->vw_CursorPos.pos_Line)
  1063.     {
  1064.     off += line->ln_Strlen;
  1065.     line++;
  1066.     linenum++;
  1067.     }
  1068.     off += vw->vw_CursorPos.pos_Col;
  1069.     return(off);
  1070. }
  1071.  
  1072. /*
  1073.  * Returns the number of bytes in the file
  1074.  */
  1075. LONG
  1076. size(VOID)
  1077. {
  1078.     TX *tx = CurrVW->vw_Tx;
  1079.     LINE *line = tx->tx_Lines;
  1080.     LONG linenum = 0;
  1081.     LONG size = 0;
  1082.  
  1083.     while(linenum < tx->tx_NumLines)
  1084.     {
  1085.     size += line->ln_Strlen;
  1086.     line++;
  1087.     linenum++;
  1088.     }
  1089.     return(size);
  1090. }
  1091.  
  1092.