home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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"
-
- bool ldelnewline_p ();
- void l_fix_up ();
- bool kinsert ();
-
-
- extern char MSG_cnt_alloc[];
- extern char MSG_too_m_k[];
- #if RUNCHK
- extern char ERR_no_alloc[];
- extern char ERR_db_dalloc[];
- extern char ERR_lock[];
- extern char ERR_lock_del[];
- #endif
- #include "lintfunc.dec"
-
- #ifndef KBLOCK
- #define KBLOCK 256 /* Kill buffer block size. */
- #endif
-
- char *kbufp = NULL; /* Kill buffer data. */
- int kused = 0; /* # of bytes used in KB. */
- int ksize = 0; /* # of bytes allocated in KB. */
-
- extern LINE *cur_pat;
- extern LINE *cur_mask;
- extern bool read_pat_mode;
-
- /*
- * This routine allocates a block
- * of memory large enough to hold a LINE
- * containing "used" characters. The block is
- * always rounded up a bit. 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 (used)
- register int used;
- {
- register LINE * lp;
- char buf[80], buf1[50];
- #if RUNCHK
- if (read_pat_mode)
- printf (ERR_no_alloc);
- #endif
-
- if ((lp = (LINE *) malloc (sizeof (LINE) + used)) == NULL)
- {
- sprintf (buf1, MSG_cnt_alloc, R_POS_FMT(curwp));
- sprintf (buf, buf1, (A32)used);
- writ_echo (buf);
- curbp -> b_flag |= BFBAD;/* may be trashed */
- curwp -> w_flag |= WFMODE;
- update ();
- return (NULL);
- }
- lp -> l_size = used;
- lp -> l_used = used;
- 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;
- }
- }
-
-
- /*
- * 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)
- {
- register char *cp1;
- register char *cp2;
- register LINE * lp1;
- register LINE * lp2;
- register LINE * lp3;
- 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 */
- if ((lp2 = lalloc (n + NBLOCK)) == NULL)/* Allocate new line */
- return (FALSE);
- lp2 -> l_used = n; /* set to correct size */
- lp3 = lp1 -> l_bp; /* Previous line */
- lp3 -> l_fp = lp2; /* Link in */
- lp2 -> l_fp = lp1;
- lp1 -> l_bp = lp2;
- lp2 -> l_bp = lp3;
- for (i = 0; i < n; ++i)
- lp2 -> l_text[i] = c;
- curwp -> w_dotp = lp2;
- curwp -> w_doto = n;
- lp2 -> l_file_offset = lp1 -> l_file_offset + lp1 -> l_used;
- l_fix_up (lp2); /* re-adjust file offsets */
- return (TRUE);
- }
-
- doto = curwp -> w_doto; /* Save for later. */
- if (lp1 -> l_used + n > lp1 -> l_size)
- {
- /* Hard: reallocate */
- if ((lp2 = lalloc (lp1 -> l_used + n + NBLOCK)) == NULL)
- return (FALSE);
- lp2 -> l_used = lp1 -> l_used + n; /* set to correct size */
- cp1 = &lp1 -> l_text[0];
- cp2 = &lp2 -> l_text[0];
- while (cp1 != &lp1 -> l_text[doto])
- *cp2++ = *cp1++;
- cp2 += n;
- while (cp1 != &lp1 -> l_text[lp1 -> l_used])
- *cp2++ = *cp1++;
- lp1 -> l_bp -> l_fp = lp2;
- lp2 -> l_fp = lp1 -> l_fp;
- lp1 -> l_fp -> l_bp = lp2;
- lp2 -> l_bp = lp1 -> l_bp;
- lp2 -> l_file_offset = lp1 -> l_file_offset;
- free ((char *) lp1);
- }
- 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;
- wp = wheadp; /* Update windows */
- while (wp != NULL)
- {
- if (wp -> w_linep == lp1)
- {
- wp -> w_linep = lp2;
- }
-
- if (wp -> w_dotp == lp1)
- {
- wp -> w_dotp = lp2;
- if (wp == curwp || wp -> w_doto > doto)
- wp -> w_doto += n;
- }
-
- if (wp -> w_markp == lp1)
- {
- wp -> w_markp = lp2;
- if (wp -> w_marko > doto)
- wp -> w_marko += n;
- }
-
- wp = wp -> w_wndp;
- }
- l_fix_up (curwp -> w_dotp); /* 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, kflag)
- {
- register char *cp1;
- register char *cp2;
- register LINE * dotp;
- register short doto, l_size, prev_size;
- register WINDOW * wp;
-
- #if RUNCHK
- /* check that buffer size can be changed */
- if (curbp -> b_flag & BFSLOCK)
- {
- writ_echo (ERR_lock_del);
- return (FALSE);
- }
- #endif
-
- doto = curwp -> w_doto;
-
- lchange (WFMOVE);
-
- prev_size = 0;
- while (((l_size = curwp -> w_dotp -> l_used) - doto) < n)
- {
- /* break out when there are no more lines to delete */
- if (l_size == prev_size)
- break;
- /* Must merge the two lines. */
- if (ldelnewline_p () == FALSE)
- return (FALSE);
- prev_size = l_size;
- }
-
- dotp = curwp -> w_dotp;
-
- /* if at the end of the buffer then delete nothing */
- if (doto >= dotp -> l_used)
- {
- l_fix_up (dotp); /* re-adjust file offsets */
- return (TRUE);
- }
- cp1 = &dotp -> l_text[doto];/* Scrunch text. */
- cp2 = cp1 + n;
-
- /* put stuff to delete into the kill buffer */
- if (kflag != FALSE)
- {
- /* Kill? */
- while (cp1 != cp2)
- {
- if (kinsert (*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;
- wp = wheadp; /* Fix windows */
- while (wp != NULL)
- {
- if (wp -> w_dotp == dotp && wp -> w_doto >= doto)
- {
- wp -> w_doto -= n;
- if (wp -> w_doto < doto)
- wp -> w_doto = doto;
- }
-
- if (wp -> w_markp == dotp && wp -> w_marko >= doto)
- {
- wp -> w_marko -= n;
- if (wp -> w_marko < doto)
- wp -> w_marko = doto;
- }
-
- wp = wp -> w_wndp;
- }
- l_fix_up (curwp -> w_dotp); /* re-adjust file offsets */
- return (TRUE);
- }
-
-
- /*
- * Delete a newline. Join the current line
- * with the next line. Always allocate some extra space, if this
- * line was edited ones then it will probably be again. It will
- * go faster the second time. If the next line is the magic
- * header line always return TRUE; merging the last line
- * with the header line can be thought of as always being a
- * successful operation, even if nothing is done, and this makes
- * the kill buffer work "right". Easy cases can be done by
- * shuffling data around. Hard cases require that lines be moved
- * about in memory. Return FALSE on error and TRUE if all
- * looks ok. Called by "ldelete" only.
- */
- bool ldelnewline_p ()
- {
-
- register char *cp1;
- register char *cp2;
- register LINE * lp1;
- register LINE * lp2;
- register LINE * lp3;
- register WINDOW * wp;
-
- lp1 = curwp -> w_dotp;
- lp2 = lp1 -> l_fp;
- if (lp2 == curbp -> b_linep)
- {
- /* At the buffer end. */
- if (lp1 -> l_used == 0) /* Blank line. */
- lfree (lp1);
- return (TRUE);
- }
-
- /* will next line fit in current line? */
- if (lp2 -> l_used <= lp1 -> l_size - lp1 -> l_used)
- {
-
- cp1 = &lp1 -> l_text[lp1 -> l_used];
- cp2 = &lp2 -> l_text[0];
- while (cp2 != &lp2 -> l_text[lp2 -> l_used])
- *cp1++ = *cp2++;
- wp = wheadp;
- while (wp != NULL)
- {
-
- if (wp -> w_linep == lp2)
- {
- wp -> w_linep = lp1;
- wp -> w_loff += lp1 -> l_used;
- }
-
- if (wp -> w_dotp == lp2)
- {
- wp -> w_dotp = lp1;
- wp -> w_doto += lp1 -> l_used;
- }
-
- if (wp -> w_markp == lp2)
- {
- wp -> w_markp = lp1;
- wp -> w_marko += lp1 -> l_used;
- }
-
- wp = wp -> w_wndp;
- }
-
- lp1 -> l_used += lp2 -> l_used;
- lp1 -> l_fp = lp2 -> l_fp;
- lp2 -> l_fp -> l_bp = lp1;
- free ((char *) lp2);
- return (TRUE);
- }
-
- /* lines too big so allocate a new one */
- if ((lp3 = lalloc (lp1 -> l_used + lp2 -> l_used + NBLOCK)) == NULL)
- return (FALSE);
- lp3 -> l_used = lp1 -> l_used + lp2 -> l_used; /* set to correct size */
- cp1 = &lp1 -> l_text[0];
- cp2 = &lp3 -> l_text[0];
- while (cp1 != &lp1 -> l_text[lp1 -> l_used])
- *cp2++ = *cp1++;
- cp1 = &lp2 -> l_text[0];
- while (cp1 != &lp2 -> l_text[lp2 -> l_used])
- *cp2++ = *cp1++;
- lp1 -> l_bp -> l_fp = lp3;
- lp3 -> l_fp = lp2 -> l_fp;
- lp2 -> l_fp -> l_bp = lp3;
- lp3 -> l_bp = lp1 -> l_bp;
- lp3 -> l_file_offset = lp1 -> l_file_offset;
- wp = wheadp;
- while (wp != NULL)
- {
-
- if (wp -> w_linep == lp1 || wp -> w_linep == lp2)
- {
- wp -> w_linep = lp3;
- if (wp -> w_linep == lp2)
- wp -> w_loff += lp1 -> l_used;
- }
-
- if (wp -> w_dotp == lp1)
- wp -> w_dotp = lp3;
- else
- if (wp -> w_dotp == lp2)
- {
- wp -> w_dotp = lp3;
- wp -> w_doto += lp1 -> l_used;
- }
-
- if (wp -> w_markp == lp1)
- wp -> w_markp = lp3;
- else
- if (wp -> w_markp == lp2)
- {
- wp -> w_markp = lp3;
- wp -> w_marko += lp1 -> l_used;
- }
-
- wp = wp -> w_wndp;
- }
-
- free ((char *) lp1);
- free ((char *) lp2);
- return (TRUE);
- }
-
- /*
- * Replace character at dot position.
- */
- bool 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 LINE *dotp; /* pointer to line structure */
- register int doto; /* offset into line */
- 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.
- */
- doto = curwp -> w_doto;
- rlen = rstr -> l_used;
- if (plen > rlen)
- {
- ldelete (plen - rlen, FALSE);
- }
- else if (plen < rlen)
- {
- if (linsert (rlen - plen, ' ') == FALSE)
- return (FALSE);
- }
- curwp -> w_doto = doto;
- dotp = curwp -> w_dotp; /* save dot line for later */
-
- /* 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);
- }
- curwp -> w_doto = doto;
- curwp -> w_dotp = dotp;
- lchange (WFHARD);
- return (TRUE);
- }
-
-
- /*
- * Delete all of the text
- * saved in the kill buffer. Called by commands
- * when a new kill context is being created. The kill
- * buffer array is released, just in case the buffer has
- * grown to immense size. No errors.
- */
- void kdelete ()
- {
- if (kbufp != NULL)
- {
- free ((char *) kbufp);
- kbufp = NULL;
- kused = 0;
- ksize = 0;
- }
- }
-
- /*
- * Insert a character to the kill buffer,
- * enlarging the buffer if there isn't any room. Always
- * grow the buffer in chunks, on the assumption that if you
- * put something in the kill buffer you are going to put
- * more stuff there too later. Return TRUE if all is
- * well, and FALSE on errors. Print a message on
- * errors.
- */
- bool kinsert (c)
- {
- register char *nbufp;
- register int i;
-
- if (kused == ksize)
- {
- if ((nbufp = malloc (ksize + KBLOCK)) == NULL)
- {
- writ_echo (MSG_too_m_k);
- return (FALSE);
- }
- for (i = 0; i < ksize; ++i)
- nbufp[i] = kbufp[i];
- if (kbufp != NULL)
- free ((char *) kbufp);
- kbufp = nbufp;
- ksize += KBLOCK;
- }
- kbufp[kused++] = c;
- return (TRUE);
- }
-
-
- /*
- * This function gets characters from
- * the kill buffer. If the character index "n" is
- * off the end, it returns "-1". This lets the caller
- * just scan along until it gets a "-1" back.
- */
- char kremove (n)
- {
- if (n >= kused)
- return (-1);
- return (kbufp[n] & 0xFF);
- }
-
- /*
- * 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;
- LINE * end_line;
-
- end_line = curwp -> w_bufp -> b_linep;/* header line */
-
- if (line == NULL)
- line = end_line -> l_fp;/* point to first line */
-
- offset = line -> l_file_offset;/* starting offset */
- offset += line -> l_used;
- while ((line = line -> l_fp) != end_line)
- {
- line -> l_file_offset = offset;
- offset += line -> l_used;
- }
- }
-
-
-
-