home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / beav1402.zip / line.c < prev    next >
Text File  |  1993-04-16  |  15KB  |  603 lines

  1. /*
  2. *       Text line handling.
  3. * The functions in this file
  4. * are a general set of line management
  5. * utilities. They are the only routines that
  6. * touch the text. They also touch the buffer
  7. * and window structures, to make sure that the
  8. * necessary updating gets done. There are routines
  9. * in this file that handle the kill buffer too.
  10. * It isn't here for any good reason.
  11. *
  12. * Note that this code only updates the dot and
  13. * mark values in the window list. Since all the code
  14. * acts on the current window, the buffer that we
  15. * are editing must be being displayed, which means
  16. * that "b_nwnd" is non zero, which means that the
  17. * dot and mark values in the buffer headers are
  18. * nonsense.
  19. */
  20.  
  21. #include    "def.h"
  22.  
  23. void l_fix_up ();
  24.  
  25. extern char MSG_cnt_alloc[];
  26. #if RUNCHK
  27. extern char ERR_no_alloc[];
  28. extern char ERR_db_dalloc[];
  29. extern char ERR_lock[];
  30. extern char ERR_lock_del[];
  31. #endif
  32.  
  33. extern LINE *cur_pat;
  34. extern LINE *cur_mask;
  35. extern bool read_pat_mode;
  36. extern BUFFER sav_buf;
  37.  
  38. /*
  39. * This routine allocates a block
  40. * of memory large enough to hold a LINE
  41. * containing "size" characters. Return a pointer
  42. * to the new block, or NULL if there isn't
  43. * any memory left. Print a message in the
  44. * message line if no space.
  45. */
  46. LINE *
  47. lalloc (size)
  48.     register int size;
  49. {
  50.     register LINE *lp;
  51.     char buf[NCOL], buf1[NCOL];
  52. #if RUNCHK
  53.     if (read_pat_mode)
  54.     printf (ERR_no_alloc);
  55. #endif
  56.  
  57.     if ((lp = (LINE *) malloc (sizeof (LINE) + size)) == NULL)
  58.     {
  59.     sprintf (buf1, MSG_cnt_alloc, R_POS_FMT (curwp));
  60.     sprintf (buf, buf1, (A32) size);
  61.     err_echo (buf);
  62.     curbp->b_flag |= BFBAD;    /* may be trashed */
  63.     curwp->w_flag |= WFMODE;
  64.     update ();
  65.     return (NULL);
  66.     }
  67.     lp->l_size = size;
  68.     lp->l_used = 0;
  69.     lp->l_file_offset = 0;    /* set resonable initial value */
  70.     return (lp);
  71. }
  72.  
  73. /*
  74. * Delete line "lp". Fix all of the
  75. * links that might point at it (they are
  76. * moved to offset 0 of the next line.
  77. * Unlink the line from whatever buffer it
  78. * might be in. Release the memory. The
  79. * buffers are updated too; the magic conditions
  80. * described in the above comments don't hold
  81. * here.
  82. */
  83.  
  84. void
  85. lfree (lp)
  86.     register LINE *lp;
  87. {
  88.     register BUFFER *bp;
  89.     register WINDOW *wp;
  90.  
  91. #if RUNCHK
  92.     if (read_pat_mode)
  93.     printf (ERR_db_dalloc);
  94. #endif
  95.  
  96.     wp = wheadp;
  97.     while (wp != NULL)
  98.     {
  99.     if (wp->w_linep == lp)
  100.     {
  101.         wp->w_linep = lp->l_fp;
  102.         wp->w_loff = 0;
  103.     }
  104.  
  105.     if (wp->w_dotp == lp)
  106.     {
  107.         wp->w_dotp = lp->l_fp;
  108.         wp->w_doto = 0;
  109.     }
  110.  
  111.     if (wp->w_markp == lp)
  112.     {
  113.         wp->w_markp = lp->l_fp;
  114.         wp->w_marko = 0;
  115.     }
  116.  
  117.     wp = wp->w_wndp;
  118.     }
  119.  
  120.     bp = bheadp;
  121.     while (bp != NULL)
  122.     {
  123.     if (bp->b_nwnd == 0)
  124.     {
  125.         if (bp->b_dotp == lp)
  126.         {
  127.         bp->b_dotp = lp->l_fp;
  128.         bp->b_doto = 0;
  129.         }
  130.  
  131.         if (bp->b_markp == lp)
  132.         {
  133.         bp->b_markp = lp->l_fp;
  134.         bp->b_marko = 0;
  135.         }
  136.     }
  137.     bp = bp->b_bufp;
  138.     }
  139.  
  140.     lp->l_bp->l_fp = lp->l_fp;
  141.     lp->l_fp->l_bp = lp->l_bp;
  142.     free ((char *) lp);
  143. }
  144.  
  145. /*
  146. * This routine gets called when
  147. * a character is changed in place in the
  148. * current buffer. It updates all of the required
  149. * flags in the buffer and window system. The flag
  150. * used is passed as an argument; if the buffer is being
  151. * displayed in more than 1 window we change EDIT to
  152. * HARD. Set MODE if the mode line needs to be
  153. * updated (the "*" has to be set).
  154. */
  155. void
  156. lchange (flag)
  157.     register int flag;
  158. {
  159.     register WINDOW *wp;
  160.  
  161.     if (curbp->b_nwnd != 1)    /* Ensure hard.     */
  162.     flag = WFHARD;
  163.     if ((curbp->b_flag & BFCHG) == 0)
  164.     {
  165.     /* First change, so     */
  166.     flag |= WFMODE;        /* update mode lines.   */
  167.     curbp->b_flag |= BFCHG;
  168.     }
  169.  
  170.     wp = wheadp;
  171.     while (wp != NULL)
  172.     {
  173.     if (wp->w_bufp == curbp)
  174.         wp->w_flag |= flag;
  175.     wp = wp->w_wndp;
  176.     }
  177. }
  178.  
  179. /*
  180.  *  Break the line "dotp" in two at the position "doto."
  181.  */
  182.  
  183. LINE *
  184. l_break_in_two (lp, lo, extra)
  185.     register LINE *lp;
  186.     register LPOS lo, extra;
  187. {
  188.     register LINE *new_lp;
  189.     register D8 *cp1;
  190.     register D8 *cp2;
  191.     LPOS cnt, i;
  192.  
  193.     i = 0;
  194.     cnt = lp->l_used - lo;
  195.     if ((new_lp = lalloc (cnt + extra)) == NULL)
  196.     return (NULL);
  197.  
  198.     cp1 = &lp->l_text[lo];    /* starting location, source */
  199.     cp2 = &new_lp->l_text[0];    /* starting location, destination */
  200.  
  201.     /* kill bytes in the current line */
  202.     while (i++ < cnt)
  203.     {
  204.     *cp2++ = *cp1++;
  205.     }
  206.     lp->l_used -= cnt;
  207.     new_lp->l_used = cnt;
  208.     new_lp->l_file_offset = new_lp->l_file_offset + lo;
  209.  
  210.     /* insert into chain */
  211.     new_lp->l_fp = lp->l_fp;
  212.     lp->l_fp = new_lp;
  213.     new_lp->l_bp = lp;
  214.     new_lp->l_fp->l_bp = new_lp;
  215.     return (new_lp);
  216. }
  217.  
  218. /*
  219. * Insert "n" copies of the character "c"
  220. * at the current location of dot. In the easy case
  221. * all that happens is the text is stored in the line.
  222. * Always allocate some extra space in line so that edit
  223. * will be faster next time but will save space in the general case.
  224. * In the hard case, the line has to be reallocated.
  225. * When the window list is updated, take special
  226. * care; I screwed it up once. You always update dot
  227. * in the current window. You update mark, and a
  228. * dot in another window, if it is greater than
  229. * the place where you did the insert. Return TRUE
  230. * if all is well, and FALSE on errors.
  231. */
  232. bool
  233. linsert (n, c)
  234.     uchar c;
  235.     int n;
  236. {
  237.     register D8 *cp1;
  238.     register D8 *cp2;
  239.     register LINE *lp1;
  240.     register LINE *lp2;
  241.     register short doto;
  242.     register int i;
  243.     register WINDOW *wp;
  244.  
  245. #if RUNCHK
  246.     /* check that buffer size can be changed */
  247.     if (curbp->b_flag & BFSLOCK)
  248.     {
  249.     writ_echo (ERR_lock);
  250.     return (FALSE);
  251.     }
  252. #endif
  253.  
  254.     lchange (WFMOVE);
  255.     lp1 = curwp->w_dotp;    /* Current line     */
  256.     if (lp1 == curbp->b_linep)
  257.     {
  258.     /* At the end: special  */
  259.     /* break the current line at the end */
  260.     if ((lp2 = l_break_in_two (lp1, lp1->l_used, (LPOS) n + NBLOCK)) == NULL)
  261.         return (FALSE);
  262.     for (i = 0; i < n; ++i)    /* Add the characters   */
  263.         lp2->l_text[i] = c;
  264.     lp2->l_used = n;
  265.     curwp->w_dotp = lp2;
  266.     curwp->w_doto = n;
  267.     return (TRUE);
  268.     }
  269.  
  270.     doto = curwp->w_doto;    /* Save for later.  */
  271.     if (lp1->l_used + n > lp1->l_size)
  272.     {
  273.     /* break the current line and let the normal insert do it */
  274.     if ((lp2 = l_break_in_two (lp1, doto, (LPOS) n + NBLOCK)) == NULL)
  275.         return (FALSE);
  276.     lp1->l_text[doto] = c;
  277.     lp1->l_used++;
  278.     curwp->w_doto++;
  279.     if (curwp->w_doto >= lp1->l_used)
  280.     {
  281.         curwp->w_dotp = lp2;
  282.         curwp->w_doto = 0;
  283.     }
  284.     if (n > 1)
  285.         return (linsert (n - 1, c));    /* handle the rest in normal maner */
  286.     }
  287.     else
  288.     {
  289.     /* Easy: in place   */
  290.     lp2 = lp1;        /* Pretend new line */
  291.     lp2->l_used += n;
  292.     cp2 = &lp1->l_text[lp1->l_used];
  293.     cp1 = cp2 - n;
  294.     while (cp1 != &lp1->l_text[doto])
  295.         *--cp2 = *--cp1;
  296.     for (i = 0; i < n; ++i)    /* Add the characters   */
  297.         lp2->l_text[doto + i] = c;
  298.     move_ptr (curwp, (A32) n, TRUE, TRUE, TRUE);
  299.     }
  300.  
  301.     wp = wheadp;        /* Update windows   */
  302.     while (wp != NULL)
  303.     {
  304.     if ((wp->w_linep == lp1) && (wp->w_loff >= lp1->l_used))
  305.     {
  306.         wp->w_linep = lp2;
  307.         wp->w_loff -= lp1->l_used;
  308.     }
  309.  
  310.     /* move dot to next line but not to head line */
  311.     if ((wp->w_dotp == lp1) && (wp->w_doto >= lp1->l_used) &&
  312.         (wp->w_dotp->l_fp->l_size != 0))
  313.     {
  314.         wp->w_dotp = lp2;
  315.         wp->w_doto -= (lp1->l_used - 1);
  316.     }
  317.  
  318.     if ((wp->w_markp == lp1) && (wp->w_marko >= lp1->l_used))
  319.     {
  320.         wp->w_markp = lp2;
  321.         wp->w_marko -= (lp1->l_used - 1);
  322.     }
  323.  
  324.     wp = wp->w_wndp;
  325.     }
  326.     l_fix_up (lp1);        /* re-adjust file offsets */
  327.     return (TRUE);
  328. }
  329.  
  330. /*
  331. * This function deletes n_bytes,
  332. * starting at dot. It understands how to deal
  333. * with end of lines, etc. It returns TRUE if all
  334. * of the characters were deleted, and FALSE if
  335. * they were not (because dot ran into the end of
  336. * the buffer). The "kflag" is TRUE if the text
  337. * should be put in the kill buffer.
  338. */
  339. bool
  340. ldelete (n_bytes, kflag)
  341.     A32 n_bytes;
  342.     int kflag;
  343. {
  344.     register LINE *dotp, *lp, *lp_prev, *lp_next;
  345.     register LPOS doto, l_cnt;
  346.     register WINDOW *wp;
  347.     D8 *cp1, *cp2;
  348.     D32 dot_pos;
  349.     uint n_byt;
  350.  
  351. #if RUNCHK
  352.     /* check that buffer size can be changed */
  353.     if (curbp->b_flag & BFSLOCK)
  354.     {
  355.     writ_echo (ERR_lock_del);
  356.     return (FALSE);
  357.     }
  358. #endif
  359.     lchange (WFMOVE);
  360.     doto = curwp->w_doto;
  361.     dotp = curwp->w_dotp;
  362.     lp_prev = dotp->l_bp;
  363.     dot_pos = DOT_POS (curwp);
  364.  
  365.     /* if at the end of the buffer then delete nothing */
  366.     if (dot_pos >= BUF_SIZE (curwp))
  367.     {
  368.     l_fix_up (dotp);    /* re-adjust file offsets */
  369.     return (TRUE);
  370.     }
  371.  
  372.     /* save dot and mark positions for later restore */
  373.     wp = wheadp;
  374.     while (wp != NULL)
  375.     {
  376.     wp->w_dot_temp = DOT_POS (wp);
  377.     if (wp->w_markp != NULL)/* mark may not be set */
  378.         wp->w_mark_temp = MARK_POS (wp);
  379.     wp->w_wind_temp = WIND_POS (wp);
  380.     wp = wp->w_wndp;
  381.     }
  382.  
  383.     /* is delete wholy within one line? */
  384.     if ((doto + n_bytes) <= dotp->l_used)
  385.     {
  386.     cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  387.     cp2 = cp1 + n_bytes;
  388.  
  389.     /* put stuff to delete into the kill buffer */
  390.     if (kflag != FALSE)
  391.     {
  392.         /* Kill?        */
  393.         while (cp1 != cp2)
  394.         {
  395.         if (b_append_c (&sav_buf, *cp1) == FALSE)
  396.             return (FALSE);
  397.         ++cp1;
  398.         }
  399.         cp1 = &dotp->l_text[doto];
  400.     }
  401.     /* kill bytes in the current line */
  402.     while (cp2 < &dotp->l_text[dotp->l_used])
  403.         *cp1++ = *cp2++;
  404.  
  405.     dotp->l_used -= n_bytes;
  406.     }
  407.     else
  408.     {                /* wholesale delete by moving lines to save buffer */
  409.     if (doto != 0)
  410.     {
  411.         if ((lp = l_break_in_two (dotp, doto, 0)) == NULL)
  412.         return (FALSE);
  413.     }
  414.     else
  415.         lp = dotp;
  416.  
  417.     n_byt = n_bytes;
  418.     /* now handle whole lines if necessary */
  419.     while (n_byt > 0)
  420.     {
  421.         lp_next = lp->l_fp;
  422.  
  423.         if (n_byt < lp->l_used)
  424.         {
  425.         /* get last piece of a line */
  426.         lp_next = l_break_in_two (lp, n_byt, 0);
  427.         }
  428.         n_byt -= lp->l_used;
  429.         if (kflag)
  430.         {
  431.         /* remove form linked list */
  432.         lp->l_bp->l_fp = lp->l_fp;
  433.         lp->l_fp->l_bp = lp->l_bp;
  434.         /* append it to the save buffer */
  435.         b_append_l (&sav_buf, lp);
  436.         }
  437.         else
  438.         /* if we don't want it, free it */
  439.         lfree (lp);
  440.         lp = lp_next;
  441.     }
  442.     }
  443.     l_fix_up (lp_prev);        /* re-adjust file offsets */
  444.  
  445.     /* adjust dot and marks in other windows */
  446.     /* this should be ok because the save buffer dosn't disturb l_file_offset */
  447.     wp = wheadp;        /* Fix windows      */
  448.     while (wp != NULL)
  449.     {
  450.     if (curbp == wp->w_bufp)
  451.     {
  452.         A32 temp;
  453.  
  454.         /* if dot is before delete position, do nothing */
  455.         if (dot_pos <= (temp = wp->w_dot_temp))
  456.         {
  457.         /* step back to the previous line */
  458.         wp->w_doto = 0;
  459.         wp->w_dotp = lp_prev;
  460.  
  461.         /* if dot is in deleted range, set to dot position */
  462.         if (temp > dot_pos + n_bytes)
  463.             /* if after deleted range, move back deleted ammount */
  464.             move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
  465.         else
  466.             /* if in the deleted range, move to curwp dot position */
  467.             move_ptr (wp, dot_pos, TRUE, TRUE, FALSE);
  468.         }
  469.         /* mark may not be set in some windows */
  470.         if (wp->w_markp != NULL)
  471.         {
  472.         /* do the same for mark */
  473.         if (dot_pos <= (temp = wp->w_mark_temp))
  474.         {
  475.             /* if in or after the deleted range, move to curwp dot position */
  476.             wp->w_marko = curwp->w_doto;
  477.             wp->w_markp = curwp->w_dotp;
  478.  
  479.             /* if mark after deleted range */
  480.             if (temp > dot_pos + n_bytes)
  481.             {
  482.             /* if after deleted range, move back deleted ammount */
  483.             /* move dot then swap with mark to produce result */
  484.             move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
  485.             lp_next = wp->w_dotp;
  486.             wp->w_dotp = wp->w_markp;
  487.             wp->w_markp = lp_next;
  488.             l_cnt = wp->w_doto;
  489.             wp->w_doto = wp->w_marko;
  490.             wp->w_marko = l_cnt;
  491.             }
  492.         }
  493.         }
  494.         /* if window position is before delete position, do nothing */
  495.         if (dot_pos <= (temp = wp->w_wind_temp))
  496.         {
  497.         /* set window position to dot position */
  498.         wp->w_loff = 0;
  499.         wp->w_linep = wp->w_dotp;
  500.         wind_on_dot (wp);
  501.         }
  502.     }
  503.     wp = wp->w_wndp;
  504.     }
  505.     /* update buffer display */
  506.     if ((blistp->b_nwnd != 0) &&
  507.     (blistp->b_type == BTLIST))
  508.     listbuffers ();
  509.     return (TRUE);
  510. }
  511.  
  512. /*
  513. *   Replace character at dot position.
  514. */
  515. void
  516. lreplace (n, c)
  517.     int n;
  518.     char c;
  519. {
  520.     lchange (WFEDIT);
  521.     while (n--)
  522.     {
  523.     DOT_CHAR (curwp) = c & 0xff;
  524.     move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
  525.     }
  526. }
  527.  
  528. /*
  529. * Replace plen characters before dot with argument string.
  530. */
  531. bool
  532. lrepl_str (plen, rstr, mstr)
  533.  
  534.     register int plen;        /* length to remove     */
  535.     register LINE *rstr;    /* replace string       */
  536.     register LINE *mstr;    /* mask string       */
  537. {
  538.     register int i;        /* used for random characters   */
  539.     register A32 dot_pos;    /* dot offset into buffer     */
  540.     register int rlen;        /* rplace string length */
  541.     register char c;        /* temp storage for char */
  542.     register char mask;        /* temp storage for mask */
  543.  
  544.     /*
  545.   * make the string lengths match (either pad the line
  546.   * so that it will fit, or scrunch out the excess).
  547.   * be careful with dot's offset.
  548.   */
  549.     /* get offset from begining of buffer */
  550.     dot_pos = DOT_POS (curwp);
  551.     rlen = rstr->l_used;
  552.     if (plen > rlen)
  553.     {
  554.     ldelete ((A32) (plen - rlen), FALSE);
  555.     }
  556.     else if (plen < rlen)
  557.     {
  558.     if (linsert (rlen - plen, ' ') == FALSE)
  559.         return (FALSE);
  560.     }
  561.     /* must use move_ptr because delete may advance to next line */
  562.     move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);
  563.  
  564.     /* do the replacement. */
  565.     for (i = 0; i < rlen; i++)
  566.     {
  567.     c = DOT_CHAR (curwp);
  568.     mask = mstr->l_text[i];
  569.     DOT_CHAR (curwp) = (c & mask) | (rstr->l_text[i] & ~mask);
  570.     move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
  571.     }
  572.     move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);
  573.     lchange (WFHARD);
  574.     return (TRUE);
  575. }
  576.  
  577. /*
  578. *   Line fixup.
  579. *   This fixes the 'l_file_offset' variable in
  580. *   each line structure.
  581. *   This is necessary after every change in the size
  582. *   of the buffer.
  583. */
  584. void
  585. l_fix_up (line)
  586.  
  587.     LINE *line;            /* points to buffer header line */
  588.  
  589. {
  590.     long offset;
  591.  
  592.     offset = line->l_file_offset;    /* starting offset */
  593.     offset += line->l_used;
  594.     for (;;)
  595.     {
  596.     line = line->l_fp;
  597.     if (line->l_size == 0)
  598.         return;
  599.     line->l_file_offset = offset;
  600.     offset += line->l_used;
  601.     }
  602. }
  603.