home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / FILE / BEAV132S.ZIP / LINE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-08  |  14.3 KB  |  594 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. uchar   c;
  233. {
  234.     register D8    *cp1;
  235.     register D8    *cp2;
  236.     register    LINE * lp1;
  237.     register    LINE * lp2;
  238.     register short  doto;
  239.     register int    i;
  240.     register    WINDOW * wp;
  241.  
  242. #if RUNCHK
  243.     /* check that buffer size can be changed */
  244.     if (curbp -> b_flag & BFSLOCK)
  245.     {
  246.         writ_echo (ERR_lock);
  247.         return (FALSE);
  248.     }
  249. #endif
  250.  
  251.     lchange (WFMOVE);
  252.     lp1 = curwp -> w_dotp;      /* Current line     */
  253.     if (lp1 == curbp -> b_linep)
  254.     {
  255.         /* At the end: special  */
  256.         /* break the current line at the end */
  257.         if ((lp2 = l_break_in_two (lp1, lp1 -> l_used, (LPOS)n + NBLOCK)) == NULL)
  258.             return (FALSE);
  259.         for (i = 0; i < n; ++i)     /* Add the characters   */
  260.             lp2 -> l_text[i] = c;
  261.         lp2 -> l_used = n;
  262.         curwp -> w_dotp = lp2;
  263.         curwp -> w_doto = n;
  264.         return (TRUE);
  265.     }
  266.  
  267.     doto = curwp -> w_doto;     /* Save for later.  */
  268.     if (lp1 -> l_used + n > lp1 -> l_size)
  269.     {
  270.         /* break the current line and let the normal insert do it */
  271.         if ((lp2 = l_break_in_two (lp1, doto, (LPOS)n + NBLOCK)) == NULL)
  272.             return (FALSE);
  273.         lp1 -> l_text[doto] = c;
  274.         lp1 -> l_used++;
  275.         curwp -> w_doto++;
  276.         if (curwp -> w_doto >= lp1 -> l_used)
  277.         {
  278.             curwp -> w_dotp = lp2;
  279.             curwp -> w_doto = 0;
  280.         }
  281.         if (n > 1)
  282.             return (linsert (n - 1, c));    /* handle the rest in normal maner */
  283.     }
  284.     else
  285.     {
  286.         /* Easy: in place   */
  287.         lp2 = lp1;              /* Pretend new line */
  288.         lp2 -> l_used += n;
  289.         cp2 = &lp1 -> l_text[lp1 -> l_used];
  290.         cp1 = cp2 - n;
  291.         while (cp1 != &lp1 -> l_text[doto])
  292.             *--cp2 = *--cp1;
  293.         for (i = 0; i < n; ++i)     /* Add the characters   */
  294.             lp2 -> l_text[doto + i] = c;
  295.         move_ptr (curwp, (A32)n, TRUE, TRUE, TRUE);
  296.     }
  297.  
  298.     wp = wheadp;                /* Update windows   */
  299.     while (wp != NULL)
  300.     {
  301.         if ((wp -> w_linep == lp1) && (wp -> w_loff >= lp1 -> l_used))
  302.         {
  303.             wp -> w_linep = lp2;
  304.             wp -> w_loff -= lp1 -> l_used;
  305.         }
  306.  
  307.         /* move dot to next line but not to head line */
  308.         if ((wp -> w_dotp == lp1) && (wp -> w_doto >= lp1 -> l_used) &&
  309.             (wp -> w_dotp -> l_fp -> l_size != 0))
  310.         {
  311.             wp -> w_dotp = lp2;
  312.             wp -> w_doto -= (lp1 -> l_used - 1);
  313.         }
  314.  
  315.         if ((wp -> w_markp == lp1) && (wp -> w_marko >= lp1 -> l_used))
  316.         {
  317.             wp -> w_markp = lp2;
  318.             wp -> w_marko -= (lp1 -> l_used - 1);
  319.         }
  320.  
  321.         wp = wp -> w_wndp;
  322.     }
  323.     l_fix_up (lp1);   /* re-adjust file offsets */
  324.     return (TRUE);
  325. }
  326.  
  327. /*
  328. * This function deletes n_bytes,
  329. * starting at dot. It understands how to deal
  330. * with end of lines, etc. It returns TRUE if all
  331. * of the characters were deleted, and FALSE if
  332. * they were not (because dot ran into the end of
  333. * the buffer). The "kflag" is TRUE if the text
  334. * should be put in the kill buffer.
  335. */
  336. bool ldelete (n_bytes, kflag)
  337. A32    n_bytes;
  338. {
  339.     register LINE  *dotp, *lp, *lp_prev, *lp_next;
  340.     register LPOS  doto, l_cnt;
  341.     register WINDOW *wp;
  342.     D8       *cp1, *cp2;
  343.     D32      n_byt, dot_pos;
  344.  
  345. #if RUNCHK
  346.     /* check that buffer size can be changed */
  347.     if (curbp -> b_flag & BFSLOCK)
  348.     {
  349.         writ_echo (ERR_lock_del);
  350.         return (FALSE);
  351.     }
  352. #endif
  353.     lchange (WFMOVE);
  354.     doto = curwp -> w_doto;
  355.     dotp = curwp -> w_dotp;
  356.     lp_prev = dotp -> l_bp;
  357.     dot_pos = DOT_POS(curwp);
  358.  
  359.     /* if at the end of the buffer then delete nothing */
  360.     if (dot_pos >= BUF_SIZE(curwp))
  361.     {
  362.         l_fix_up (dotp);    /* re-adjust file offsets */
  363.         return (TRUE);
  364.     }
  365.  
  366.     /* save dot and mark positions for later restore */
  367.     wp = wheadp;
  368.     while (wp != NULL)
  369.     {
  370.         wp->w_dot_temp = DOT_POS (wp);
  371.         if (wp->w_markp != NULL)  /* mark may not be set */
  372.             wp->w_mark_temp = MARK_POS (wp);
  373.         wp->w_wind_temp = WIND_POS (wp);
  374.         wp = wp -> w_wndp;
  375.     }
  376.  
  377.     /* is delete wholy within one line? */
  378.     if ((doto + n_bytes) < dotp -> l_used)
  379.     {
  380.         cp1 = &dotp -> l_text[doto];/* Scrunch text.    */
  381.         cp2 = cp1 + n_bytes;
  382.  
  383.         /* put stuff to delete into the kill buffer */
  384.         if (kflag != FALSE)
  385.         {
  386.             /* Kill?        */
  387.             while (cp1 != cp2)
  388.             {
  389.                 if (b_append_c (&sav_buf, *cp1) == FALSE)
  390.                     return (FALSE);
  391.                 ++cp1;
  392.             }
  393.             cp1 = &dotp -> l_text[doto];
  394.         }
  395.         /* kill bytes in the current line */
  396.         while (cp2 < &dotp -> l_text[dotp -> l_used])
  397.             *cp1++ = *cp2++;
  398.  
  399.         dotp -> l_used -= n_bytes;
  400.     }
  401.     else
  402.     {   /* wholesale delete by moving lines to save buffer */
  403.         if (doto != 0)
  404.         {
  405.             if ((lp = l_break_in_two (dotp, doto, 0l)) == NULL)
  406.                 return (FALSE);
  407.         }
  408.         else
  409.             lp = dotp;
  410.  
  411.         n_byt = n_bytes;
  412.         /* now handle whole lines if necessary */
  413.         while (n_byt > 0)
  414.         {
  415.             lp_next = lp -> l_fp;
  416.  
  417.             if (n_byt < lp -> l_used)
  418.             {
  419.                 /* get last piece of a line */
  420.                 lp_next = l_break_in_two (lp, n_byt, 0l);
  421.             }
  422.             n_byt -= lp -> l_used;
  423.             if (kflag)
  424.             {
  425.                 /* remove form linked list */
  426.                 lp -> l_bp -> l_fp = lp -> l_fp;
  427.                 lp -> l_fp -> l_bp = lp -> l_bp;
  428.                 /* append it to the save buffer */
  429.                 b_append_l (&sav_buf, lp);
  430.             }
  431.             else
  432.                 /* if we don't want it, free it */
  433.                 lfree (lp);
  434.             lp = lp_next;
  435.         }
  436.     }
  437.     l_fix_up (lp_prev);    /* re-adjust file offsets */
  438.  
  439.     /* adjust dot and marks in other windows */
  440.     /* this should be ok because the save buffer dosn't disturb l_file_offset */
  441.     wp = wheadp;            /* Fix windows      */
  442.     while (wp != NULL)
  443.     {
  444.         if (curbp == wp -> w_bufp)
  445.         {
  446.             A32    temp;
  447.  
  448.             /* if dot is before delete position, do nothing */
  449.             if (dot_pos <= (temp = wp -> w_dot_temp))
  450.             {
  451.                 /* step back to the previous line */
  452.                 wp -> w_doto = 0;
  453.                 wp -> w_dotp = lp_prev;
  454.  
  455.                 /* if dot is in deleted range, set to dot position */
  456.                 if (temp > dot_pos + n_bytes)
  457.                     /* if after deleted range, move back deleted ammount */
  458.                     move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
  459.                 else
  460.                     /* if in the deleted range, move to curwp dot position */
  461.                     move_ptr (wp, dot_pos, TRUE, TRUE, FALSE);
  462.             }
  463.             /* mark may not be set in some windows */
  464.             if (wp -> w_markp != NULL)
  465.             {
  466.                 /* do the same for mark */
  467.                 if (dot_pos <= (temp = wp->w_mark_temp))
  468.                 {
  469.                     /* if in or after the deleted range, move to curwp dot position */
  470.                     wp -> w_marko = curwp -> w_doto;
  471.                     wp -> w_markp = curwp -> w_dotp;
  472.  
  473.                     /* if mark after deleted range */
  474.                     if (temp > dot_pos + n_bytes)
  475.                     {
  476.                         /* if after deleted range, move back deleted ammount */
  477.                         /* move dot then swap with mark to produce result */
  478.                         move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
  479.                         lp_next = wp -> w_dotp;
  480.                         wp -> w_dotp = wp -> w_markp;
  481.                         wp -> w_markp = lp_next;
  482.                         l_cnt = wp -> w_doto;
  483.                         wp -> w_doto = wp -> w_marko;
  484.                         wp -> w_marko = l_cnt;
  485.                     }
  486.                 }
  487.             }
  488.             /* if window position is before delete position, do nothing */
  489.             if (dot_pos <= (temp = wp -> w_wind_temp))
  490.             {
  491.                 /* set window position to dot position */
  492.                 wp -> w_loff = 0;
  493.                 wp -> w_linep = wp -> w_dotp;
  494.                 wind_on_dot (wp);
  495.             }
  496.         }
  497.         wp = wp -> w_wndp;
  498.     }
  499.     /* update buffer display */
  500.     if ((blistp -> b_nwnd != 0) &&
  501.         (blistp -> b_type == BTLIST))
  502.         listbuffers ();
  503.     return (TRUE);
  504. }
  505. /*
  506. *   Replace character at dot position.
  507. */
  508. void    lreplace (n, c)
  509. int     n;
  510. char    c;
  511. {
  512.     lchange (WFEDIT);
  513.     while (n--)
  514.     {
  515.         DOT_CHAR(curwp) = c & 0xff;
  516.         move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
  517.     }
  518. }
  519.  
  520. /*
  521. * Replace plen characters before dot with argument string.
  522. */
  523. bool lrepl_str (plen, rstr, mstr)
  524.  
  525. register int    plen;           /* length to remove     */
  526. register LINE   *rstr;          /* replace string       */
  527. register LINE   *mstr;          /* mask string       */
  528. {
  529.     register    int    i;       /* used for random characters   */
  530.     register    LINE   *dotp;   /* pointer to line structure */
  531.     register    int    doto;    /* offset into line     */
  532.     register    int     rlen;   /* rplace string length */
  533.     register    char    c;      /* temp storage for char */
  534.     register    char    mask;   /* temp storage for mask */
  535.  
  536.     /* 
  537.   * make the string lengths match (either pad the line
  538.   * so that it will fit, or scrunch out the excess).
  539.   * be careful with dot's offset.
  540.   */
  541.     doto = curwp -> w_doto;
  542.     rlen = rstr -> l_used;
  543.     if (plen > rlen)
  544.     {
  545.         ldelete ((A32)(plen - rlen), FALSE);
  546.     }
  547.     else if (plen < rlen)
  548.     {
  549.         if (linsert (rlen - plen, ' ') == FALSE)
  550.             return (FALSE);
  551.     }
  552.     curwp -> w_doto = doto;
  553.     dotp = curwp -> w_dotp;     /* save dot line for later */
  554.  
  555.     /* do the replacement. */
  556.     for (i = 0; i < rlen; i++)
  557.     {
  558.         c = DOT_CHAR(curwp);
  559.         mask = mstr -> l_text[i];
  560.         DOT_CHAR(curwp) = (c & mask) | (rstr -> l_text[i] & ~mask);
  561.         move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
  562.     }
  563.     curwp -> w_doto = doto;
  564.     curwp -> w_dotp = dotp;
  565.     lchange (WFHARD);
  566.     return (TRUE);
  567. }
  568.  
  569. /*
  570. *   Line fixup.
  571. *   This fixes the 'l_file_offset' variable in
  572. *   each line structure.
  573. *   This is necessary after every change in the size
  574. *   of the buffer.
  575. */
  576. void l_fix_up (line)
  577.  
  578. LINE * line;                    /* points to buffer header line */
  579.  
  580. {
  581.     long    offset;
  582.  
  583.     offset = line -> l_file_offset;/* starting offset */
  584.     offset += line -> l_used;
  585.     for (;;)
  586.     {
  587.         line = line -> l_fp;
  588.         if (line -> l_size == 0)
  589.             return;
  590.         line -> l_file_offset = offset;
  591.         offset += line -> l_used;
  592.     }
  593. }
  594.