Logo Search packages:      
Sourcecode: beav version File versions  Download package

line.c

/*
*       Text line handling.
* The functions in this file
* are a general set of line management
* utilities. They are the only routines that
* touch the text. They also touch the buffer
* and window structures, to make sure that the
* necessary updating gets done. There are routines
* in this file that handle the kill buffer too.
* It isn't here for any good reason.
*
* Note that this code only updates the dot and
* mark values in the window list. Since all the code
* acts on the current window, the buffer that we
* are editing must be being displayed, which means
* that "b_nwnd" is non zero, which means that the
* dot and mark values in the buffer headers are
* nonsense.
*/

#include    "def.h"

void l_fix_up ();

extern char MSG_cnt_alloc[];
#if RUNCHK
extern char ERR_no_alloc[];
extern char ERR_db_dalloc[];
extern char ERR_lock[];
extern char ERR_lock_del[];
#endif

extern LINE *cur_pat;
extern LINE *cur_mask;
extern bool read_pat_mode;
extern BUFFER sav_buf;

/*
* This routine allocates a block
* of memory large enough to hold a LINE
* containing "size" characters. Return a pointer
* to the new block, or NULL if there isn't
* any memory left. Print a message in the
* message line if no space.
*/
LINE *
lalloc (size)
    register int size;
{
    register LINE *lp;
    char buf[NCOL], buf1[NCOL];
#if RUNCHK
    if (read_pat_mode)
      printf (ERR_no_alloc);
#endif

    if ((lp = (LINE *) malloc (sizeof (LINE) + size)) == NULL)
    {
      sprintf (buf1, MSG_cnt_alloc, R_POS_FMT (curwp));
      sprintf (buf, buf1, (A32) size);
      err_echo (buf);
      curbp->b_flag |= BFBAD; /* may be trashed */
      curwp->w_flag |= WFMODE;
      update ();
      return (NULL);
    }
    lp->l_size = size;
    lp->l_used = 0;
    lp->l_file_offset = 0;    /* set resonable initial value */
    return (lp);
}

/*
* Delete line "lp". Fix all of the
* links that might point at it (they are
* moved to offset 0 of the next line.
* Unlink the line from whatever buffer it
* might be in. Release the memory. The
* buffers are updated too; the magic conditions
* described in the above comments don't hold
* here.
*/

void
lfree (lp)
    register LINE *lp;
{
    register BUFFER *bp;
    register WINDOW *wp;

#if RUNCHK
    if (read_pat_mode)
      printf (ERR_db_dalloc);
#endif

    wp = wheadp;
    while (wp != NULL)
    {
      if (wp->w_linep == lp)
      {
          wp->w_linep = lp->l_fp;
          wp->w_loff = 0;
      }

      if (wp->w_dotp == lp)
      {
          wp->w_dotp = lp->l_fp;
          wp->w_doto = 0;
      }

      if (wp->w_markp == lp)
      {
          wp->w_markp = lp->l_fp;
          wp->w_marko = 0;
      }

      wp = wp->w_wndp;
    }

    bp = bheadp;
    while (bp != NULL)
    {
      if (bp->b_nwnd == 0)
      {
          if (bp->b_dotp == lp)
          {
            bp->b_dotp = lp->l_fp;
            bp->b_doto = 0;
          }

          if (bp->b_markp == lp)
          {
            bp->b_markp = lp->l_fp;
            bp->b_marko = 0;
          }
      }
      bp = bp->b_bufp;
    }

    lp->l_bp->l_fp = lp->l_fp;
    lp->l_fp->l_bp = lp->l_bp;
    free ((char *) lp);
}

/*
* This routine gets called when
* a character is changed in place in the
* current buffer. It updates all of the required
* flags in the buffer and window system. The flag
* used is passed as an argument; if the buffer is being
* displayed in more than 1 window we change EDIT to
* HARD. Set MODE if the mode line needs to be
* updated (the "*" has to be set).
*/
void
lchange (flag)
    register int flag;
{
    register WINDOW *wp;

    if (curbp->b_nwnd != 1)   /* Ensure hard.     */
      flag = WFHARD;
    if ((curbp->b_flag & BFCHG) == 0)
    {
      /* First change, so     */
      flag |= WFMODE;         /* update mode lines.   */
      curbp->b_flag |= BFCHG;
    }

    wp = wheadp;
    while (wp != NULL)
    {
      if (wp->w_bufp == curbp)
          wp->w_flag |= flag;
      wp = wp->w_wndp;
    }
}

/*
 *  Break the line "dotp" in two at the position "doto."
 */

LINE *
l_break_in_two (lp, lo, extra)
    register LINE *lp;
    register LPOS lo, extra;
{
    register LINE *new_lp;
    register D8 *cp1;
    register D8 *cp2;
    LPOS cnt, i;

    i = 0;
    cnt = lp->l_used - lo;
    if ((new_lp = lalloc (cnt + extra)) == NULL)
      return (NULL);

    cp1 = &lp->l_text[lo];    /* starting location, source */
    cp2 = &new_lp->l_text[0]; /* starting location, destination */

    /* kill bytes in the current line */
    while (i++ < cnt)
    {
      *cp2++ = *cp1++;
    }
    lp->l_used -= cnt;
    new_lp->l_used = cnt;
    new_lp->l_file_offset = new_lp->l_file_offset + lo;

    /* insert into chain */
    new_lp->l_fp = lp->l_fp;
    lp->l_fp = new_lp;
    new_lp->l_bp = lp;
    new_lp->l_fp->l_bp = new_lp;
    return (new_lp);
}

/*
* Insert "n" copies of the character "c"
* at the current location of dot. In the easy case
* all that happens is the text is stored in the line.
* Always allocate some extra space in line so that edit
* will be faster next time but will save space in the general case.
* In the hard case, the line has to be reallocated.
* When the window list is updated, take special
* care; I screwed it up once. You always update dot
* in the current window. You update mark, and a
* dot in another window, if it is greater than
* the place where you did the insert. Return TRUE
* if all is well, and FALSE on errors.
*/
bool
linsert (n, c)
    uchar c;
    int n;
{
    register D8 *cp1;
    register D8 *cp2;
    register LINE *lp1;
    register LINE *lp2;
    register short doto;
    register int i;
    register WINDOW *wp;

#if RUNCHK
    /* check that buffer size can be changed */
    if (curbp->b_flag & BFSLOCK)
    {
      writ_echo (ERR_lock);
      return (FALSE);
    }
#endif

    lchange (WFMOVE);
    lp1 = curwp->w_dotp;      /* Current line     */
    if (lp1 == curbp->b_linep)
    {
      /* At the end: special  */
      /* break the current line at the end */
      if ((lp2 = l_break_in_two (lp1, lp1->l_used, (LPOS) n + NBLOCK)) == NULL)
          return (FALSE);
      for (i = 0; i < n; ++i) /* Add the characters   */
          lp2->l_text[i] = c;
      lp2->l_used = n;
      curwp->w_dotp = lp2;
      curwp->w_doto = n;
      return (TRUE);
    }

    doto = curwp->w_doto;     /* Save for later.  */
    if (lp1->l_used + n > lp1->l_size)
    {
      /* break the current line and let the normal insert do it */
      if ((lp2 = l_break_in_two (lp1, doto, (LPOS) n + NBLOCK)) == NULL)
          return (FALSE);
      lp1->l_text[doto] = c;
      lp1->l_used++;
      curwp->w_doto++;
      if (curwp->w_doto >= lp1->l_used)
      {
          curwp->w_dotp = lp2;
          curwp->w_doto = 0;
      }
      if (n > 1)
          return (linsert (n - 1, c));    /* handle the rest in normal maner */
    }
    else
    {
      /* Easy: in place   */
      lp2 = lp1;        /* Pretend new line */
      lp2->l_used += n;
      cp2 = &lp1->l_text[lp1->l_used];
      cp1 = cp2 - n;
      while (cp1 != &lp1->l_text[doto])
          *--cp2 = *--cp1;
      for (i = 0; i < n; ++i) /* Add the characters   */
          lp2->l_text[doto + i] = c;
      move_ptr (curwp, (A32) n, TRUE, TRUE, TRUE);
    }

    wp = wheadp;        /* Update windows   */
    while (wp != NULL)
    {
      if ((wp->w_linep == lp1) && (wp->w_loff >= lp1->l_used))
      {
          wp->w_linep = lp2;
          wp->w_loff -= lp1->l_used;
      }

      /* move dot to next line but not to head line */
      if ((wp->w_dotp == lp1) && (wp->w_doto >= lp1->l_used) &&
          (wp->w_dotp->l_fp->l_size != 0))
      {
          wp->w_dotp = lp2;
          wp->w_doto -= (lp1->l_used - 1);
      }

      if ((wp->w_markp == lp1) && (wp->w_marko >= lp1->l_used))
      {
          wp->w_markp = lp2;
          wp->w_marko -= (lp1->l_used - 1);
      }

      wp = wp->w_wndp;
    }
    l_fix_up (lp1);           /* re-adjust file offsets */
    return (TRUE);
}

/*
* This function deletes n_bytes,
* starting at dot. It understands how to deal
* with end of lines, etc. It returns TRUE if all
* of the characters were deleted, and FALSE if
* they were not (because dot ran into the end of
* the buffer). The "kflag" is TRUE if the text
* should be put in the kill buffer.
*/
bool
ldelete (n_bytes, kflag)
    A32 n_bytes;
    int kflag;
{
    register LINE *dotp, *lp, *lp_prev, *lp_next;
    register LPOS doto, l_cnt;
    register WINDOW *wp;
    D8 *cp1, *cp2;
    D32 dot_pos;
    uint n_byt;

#if RUNCHK
    /* check that buffer size can be changed */
    if (curbp->b_flag & BFSLOCK)
    {
      writ_echo (ERR_lock_del);
      return (FALSE);
    }
#endif
    lchange (WFMOVE);
    doto = curwp->w_doto;
    dotp = curwp->w_dotp;
    lp_prev = dotp->l_bp;
    dot_pos = DOT_POS (curwp);

    /* if at the end of the buffer then delete nothing */
    if (dot_pos >= BUF_SIZE (curwp))
    {
      l_fix_up (dotp);  /* re-adjust file offsets */
      return (TRUE);
    }

    /* save dot and mark positions for later restore */
    wp = wheadp;
    while (wp != NULL)
    {
      wp->w_dot_temp = DOT_POS (wp);
      if (wp->w_markp != NULL)/* mark may not be set */
          wp->w_mark_temp = MARK_POS (wp);
      wp->w_wind_temp = WIND_POS (wp);
      wp = wp->w_wndp;
    }

    /* is delete wholy within one line? */
    if ((doto + n_bytes) <= dotp->l_used)
    {
      cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
      cp2 = cp1 + n_bytes;

      /* put stuff to delete into the kill buffer */
      if (kflag != FALSE)
      {
          /* Kill?        */
          while (cp1 != cp2)
          {
            if (b_append_c (&sav_buf, *cp1) == FALSE)
                return (FALSE);
            ++cp1;
          }
          cp1 = &dotp->l_text[doto];
      }
      /* kill bytes in the current line */
      while (cp2 < &dotp->l_text[dotp->l_used])
          *cp1++ = *cp2++;

      dotp->l_used -= n_bytes;
    }
    else
    {                   /* wholesale delete by moving lines to save buffer */
      if (doto != 0)
      {
          if ((lp = l_break_in_two (dotp, doto, 0)) == NULL)
            return (FALSE);
      }
      else
          lp = dotp;

      n_byt = n_bytes;
      /* now handle whole lines if necessary */
      while (n_byt > 0)
      {
          lp_next = lp->l_fp;

          if (n_byt < lp->l_used)
          {
            /* get last piece of a line */
            lp_next = l_break_in_two (lp, n_byt, 0);
          }
          n_byt -= lp->l_used;
          if (kflag)
          {
            /* remove form linked list */
            lp->l_bp->l_fp = lp->l_fp;
            lp->l_fp->l_bp = lp->l_bp;
            /* append it to the save buffer */
            b_append_l (&sav_buf, lp);
          }
          else
            /* if we don't want it, free it */
            lfree (lp);
          lp = lp_next;
      }
    }
    l_fix_up (lp_prev);       /* re-adjust file offsets */

    /* adjust dot and marks in other windows */
    /* this should be ok because the save buffer dosn't disturb l_file_offset */
    wp = wheadp;        /* Fix windows      */
    while (wp != NULL)
    {
      if (curbp == wp->w_bufp)
      {
          A32 temp;

          /* if dot is before delete position, do nothing */
          if (dot_pos <= (temp = wp->w_dot_temp))
          {
            /* step back to the previous line */
            wp->w_doto = 0;
            wp->w_dotp = lp_prev;

            /* if dot is in deleted range, set to dot position */
            if (temp > dot_pos + n_bytes)
                /* if after deleted range, move back deleted ammount */
                move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
            else
                /* if in the deleted range, move to curwp dot position */
                move_ptr (wp, dot_pos, TRUE, TRUE, FALSE);
          }
          /* mark may not be set in some windows */
          if (wp->w_markp != NULL)
          {
            /* do the same for mark */
            if (dot_pos <= (temp = wp->w_mark_temp))
            {
                /* if in or after the deleted range, move to curwp dot position */
                wp->w_marko = curwp->w_doto;
                wp->w_markp = curwp->w_dotp;

                /* if mark after deleted range */
                if (temp > dot_pos + n_bytes)
                {
                  /* if after deleted range, move back deleted ammount */
                  /* move dot then swap with mark to produce result */
                  move_ptr (wp, temp - n_bytes, TRUE, TRUE, FALSE);
                  lp_next = wp->w_dotp;
                  wp->w_dotp = wp->w_markp;
                  wp->w_markp = lp_next;
                  l_cnt = wp->w_doto;
                  wp->w_doto = wp->w_marko;
                  wp->w_marko = l_cnt;
                }
            }
          }
          /* if window position is before delete position, do nothing */
          if (dot_pos <= (temp = wp->w_wind_temp))
          {
            /* set window position to dot position */
            wp->w_loff = 0;
            wp->w_linep = wp->w_dotp;
            wind_on_dot (wp);
          }
      }
      wp = wp->w_wndp;
    }
    /* update buffer display */
    if ((blistp->b_nwnd != 0) &&
      (blistp->b_type == BTLIST))
      listbuffers ();
    return (TRUE);
}

/*
*   Replace character at dot position.
*/
void
lreplace (n, c)
    int n;
    char c;
{
    lchange (WFEDIT);
    while (n--)
    {
      DOT_CHAR (curwp) = c & 0xff;
      move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
    }
}

/*
* Replace plen characters before dot with argument string.
*/
bool
lrepl_str (plen, rstr, mstr)

    register int plen;        /* length to remove     */
    register LINE *rstr;      /* replace string       */
    register LINE *mstr;      /* mask string       */
{
    register int i;           /* used for random characters   */
    register A32 dot_pos;     /* dot offset into buffer     */
    register int rlen;        /* rplace string length */
    register char c;          /* temp storage for char */
    register char mask;       /* temp storage for mask */

    /*
  * make the string lengths match (either pad the line
  * so that it will fit, or scrunch out the excess).
  * be careful with dot's offset.
  */
    /* get offset from begining of buffer */
    dot_pos = DOT_POS (curwp);
    rlen = rstr->l_used;
    if (plen > rlen)
    {
      ldelete ((A32) (plen - rlen), FALSE);
    }
    else if (plen < rlen)
    {
      if (linsert (rlen - plen, ' ') == FALSE)
          return (FALSE);
    }
    /* must use move_ptr because delete may advance to next line */
    move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);

    /* do the replacement. */
    for (i = 0; i < rlen; i++)
    {
      c = DOT_CHAR (curwp);
      mask = mstr->l_text[i];
      DOT_CHAR (curwp) = (c & mask) | (rstr->l_text[i] & ~mask);
      move_ptr (curwp, 1L, TRUE, FALSE, TRUE);
    }
    move_ptr (curwp, dot_pos, TRUE, FALSE, FALSE);
    lchange (WFHARD);
    return (TRUE);
}

/*
*   Line fixup.
*   This fixes the 'l_file_offset' variable in
*   each line structure.
*   This is necessary after every change in the size
*   of the buffer.
*/
void
l_fix_up (line)

    LINE *line;               /* points to buffer header line */

{
    long offset;

    offset = line->l_file_offset;   /* starting offset */
    offset += line->l_used;
    for (;;)
    {
      line = line->l_fp;
      if (line->l_size == 0)
          return;
      line->l_file_offset = offset;
      offset += line->l_used;
    }
}

Generated by  Doxygen 1.6.0   Back to index