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