home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
editor
/
beav
/
basic.c
next >
Wrap
C/C++ Source or Header
|
1994-01-30
|
12KB
|
553 lines
/*
* Basic cursor motion commands.
* The routines in this file are the basic
* command functions for moving the cursor around on
* the screen, setting mark, and swapping dot with
* mark. Only moves between lines, which might make the
* current buffer framing bad, are hard.
*/
#include "def.h"
bool move_ptr ();
bool forwchar ();
bool wind_on_dot ();
bool backline ();
extern char MSG_mark_set[];
extern char MSG_no_mark[];
extern char MSG_go_b_n[];
extern char MSG_bad_num[];
#if RUNCHK
extern char ERR_bas_1[];
#endif
extern char MSG_lX[];
extern char MSG_lO[];
extern char MSG_lD[];
extern bool rplc_mode;
/* pvr
* Move cursor backwards. Do the
* right thing if the count is less than
* 0. Error if you try to move back from
* the beginning of the buffer.
*/
bool
backchar (f, n, k)
register int f, n, k;
{
if (n < 0)
return (forwchar (f, -n, KRANDOM));
while (n--)
{
if (curwp->w_unit_offset == 0)
{
if (!move_ptr (curwp, -(long) R_B_PER_U (curwp),
TRUE, TRUE, TRUE))
return (FALSE);
/* step to previous unit */
curwp->w_unit_offset = R_CHR_PER_U (curwp) - 1;
/* if before first line in window then move window */
wind_on_dot (curwp);
}
else
curwp->w_unit_offset--;
}
curwp->w_flag |= WFMODE; /* update mode line */
return (TRUE);
}
/* pvr
* Move cursor forwards. Do the
* right thing if the count is less than
* 0. Error if you try to move forward
* from the end of the buffer.
*/
bool
forwchar (f, n, k)
register int f, n, k;
{
if (n < 0)
return (backchar (f, -n, KRANDOM));
curwp->w_flag |= WFMODE; /* update mode line */
while (n--)
{
if (curwp->w_unit_offset >= (R_CHR_PER_U (curwp) - 1))
{
/* move to the mext unit */
curwp->w_unit_offset = 0;
if (!move_ptr (curwp, (long) R_B_PER_U (curwp),
TRUE, TRUE, TRUE))
{
/* I am at the the end of the buffer */
return (FALSE);
}
/* if after the last line in window then move window */
wind_on_dot (curwp);
}
else if /* if at last byte of buffer then do not step */
(DOT_POS (curwp) < BUF_SIZE (curwp))
curwp->w_unit_offset++; /* step within unit */
}
return (TRUE);
}
/* pvr
* This function moves the specified pointer by the ammount specified
* in 'len'. Move the dot pointer is 'dot' is true, else move
* the window pointer. Do the fix up if 'fix' is TRUE.
* This is a relative move if 'rel' is TRUE, else it is an
* absolute move.
*/
bool
move_ptr (wp, len, dot, fix, rel)
WINDOW *wp;
long len;
bool dot, fix, rel;
{
A32 cur_pos, dest_pos, fix_val, last_pos;
long rel_pos;
A32 last_fixed_pos, align;
LINE **line;
int *l_off;
char shift;
bool no_limit;
no_limit = TRUE;
if (dot)
{ /* move dot position */
l_off = (int *) &wp->w_doto;
line = &wp->w_dotp;
align = R_SIZE (wp); /* bytes -1 in a unit */
}
else
{ /* move window position */
l_off = (int *) &wp->w_loff;
line = &wp->w_linep;
align = R_ALIGN (wp) - 1; /* interval of bytes to align window */
}
/* get the current position in the buffer */
cur_pos = (*line)->l_file_offset + *l_off;
if (rel)
{
rel_pos = len;
dest_pos = len + cur_pos; /* destination position */
}
else
{
rel_pos = len - cur_pos;/* relative move amount */
dest_pos = len; /* destination position */
}
if (fix)
{
shift = wp->w_disp_shift;
/* limit at begining */
if ((long) dest_pos < (long) shift)
{
rel_pos = shift - cur_pos;
no_limit = FALSE;
}
else
{
/* calculate fixed up destination position */
fix_val = dest_pos &= ~align;
fix_val += shift;
/* calculate the last position in the buffer */
last_pos = BUF_SIZE (wp);
if (last_pos < (last_fixed_pos = (last_pos & ~align) + shift))
last_pos = last_fixed_pos - align - 1;
/* if we are going to limit at the end of the buffer */
if (last_pos < fix_val)
{
fix_val = last_pos;
no_limit = FALSE;
}
rel_pos = fix_val - cur_pos;
}
}
while (TRUE)
{
if (rel_pos < 0) /* move backward through buffer */
{
/* current line? */
if (*l_off + rel_pos >= 0)
{
*l_off += (short) rel_pos;
return (no_limit);
}
/* are we at the first line */
if ((*line)->l_bp->l_size != 0)
{ /* no, so step back */
rel_pos += *l_off;
(*line) = (*line)->l_bp; /* move back one line */
*l_off = (*line)->l_used;
}
else
{ /* yes, limit at the begining */
*l_off = 0;
return (FALSE);
}
}
else
/* move forward through buffer */
{
/* is in current line? */
if (((A32) (*l_off) + rel_pos) < ((A32) ((*line)->l_used)))
{
*l_off += (short) rel_pos;
return (no_limit);
}
if ((*line)->l_fp->l_size != 0)
{
rel_pos -= (*line)->l_used - *l_off;
*l_off = 0;
(*line) = (*line)->l_fp; /* move forward one line */
}
else
{
*l_off = (*line)->l_used; /* at last line so limit it */
return (FALSE);
}
}
}
}
/* pvr
* Move the window so that the dot is within it's
* area. Return TRUE if window was moved.
*/
bool
wind_on_dot (wp)
WINDOW *wp;
{
long diff, incr;
A32 d_offs, w_start, bytes, align;
/* number of bytes in a row */
bytes = R_BYTES (wp);
/* number of bytes to align on */
align = R_ALIGN (wp);
/* offset of window from start of the buffer */
w_start = WIND_POS (wp);
/* offset of dot from start of the buffer */
d_offs = DOT_POS (wp);
/* calculate the amount to move that is 1/3 of the window */
incr = bytes * wp->w_ntrows / 3;
/* if dot is before first line in window */
if ((diff = (d_offs - w_start)) < 0) /* diff used later */
{
move_ptr (wp, diff - incr, FALSE, TRUE, TRUE);
wp->w_flag |= WFHARD;
return (TRUE);
}
/* if dot is after the last line in window */
if (0 < (diff -= (wp->w_ntrows * bytes - 1)))
{
if (align != 1)
diff = (diff & ~(align - 1)) + align;
move_ptr (wp, diff + incr, FALSE, TRUE, TRUE);
wp->w_flag |= WFHARD;
return (TRUE);
}
/* is window aligned? */
if (w_start != ((w_start & ~(align - 1)) + wp->w_disp_shift))
{ /* if no then move into alignment */
move_ptr (wp, 0L, FALSE, TRUE, TRUE);
wp->w_flag |= WFHARD;
return (TRUE);
}
return (FALSE);
}
/* pvr
* Go to the beginning of the
* buffer. Setting WFHARD is conservative,
* but almost always the case.
*/
bool
gotobob ()
{
move_ptr (curwp, 0L, TRUE, TRUE, FALSE); /* move dot */
move_ptr (curwp, 0L, FALSE, TRUE, FALSE); /* move window */
curwp->w_unit_offset = 0;
curwp->w_flag |= WFHARD;
return (TRUE);
}
/* pvr
* Go to the end of the buffer.
* Setting WFHARD is conservative, but
* almost always the case.
* Dot is one byte past the end of the buffer.
*/
bool
gotoeob ()
{
move_ptr (curwp, BUF_SIZE (curwp), TRUE, TRUE, FALSE); /* move dot */
curwp->w_unit_offset = 0;
wind_on_dot (curwp);
return (TRUE);
}
/* pvr
* Move forward by full lines.
* If the number of lines to move is less
* than zero, call the backward line function to
* actually do it. The last command controls how
* the goal column is set.
*/
bool
forwline (f, n, k)
int f, n, k;
{
if (n < 0)
return (backline (f, -n, KRANDOM));
if (rplc_mode)
{
next_pat ();
}
else
{
/* move dot */
if (!move_ptr (curwp, (long) R_BYTES (curwp) * n,
TRUE, TRUE, TRUE))
curwp->w_unit_offset = 0;
wind_on_dot (curwp);
curwp->w_flag |= WFMODE;/* update mode line */
}
return (TRUE);
}
/* pvr
* This function is like "forwline", but
* goes backwards. The scheme is exactly the same.
* Check for arguments that are less than zero and
* call your alternate. Figure out the new line and
* call "movedot" to perform the motion.
*/
bool
backline (f, n, k)
int f, n, k;
{
if (n < 0)
return (forwline (f, -n, KRANDOM));
if (rplc_mode)
{
next_pat ();
}
else
{
if (!move_ptr (curwp, -((long) (R_BYTES (curwp) * n)),
TRUE, TRUE, TRUE))
curwp->w_unit_offset = 0;
/* is dot before the top of window? */
wind_on_dot (curwp);
curwp->w_flag |= WFMODE;/* update mode line */
}
return (TRUE);
}
/* pvr
* Scroll forward by a specified number
* of lines, or by a full page if no argument.
* (KRW) Added cursor (dot) weighting to force cursor
* to same position on new page.
*/
bool
forwpage (f, n, k)
int f, n, k;
{
long mov_lines;
if (rplc_mode)
next_pat ();
else
{
if (curwp->w_ntrows <= 2)
mov_lines = 2;
else
mov_lines = curwp->w_ntrows - 2;
/* check if last line is already displayed */
if (WIND_POS (curwp) + (R_BYTES (curwp) * curwp->w_ntrows) <
curwp->w_bufp->b_linep->l_bp->l_file_offset +
curwp->w_bufp->b_linep->l_bp->l_used)
{
move_ptr (curwp, (long) (R_BYTES (curwp) * mov_lines),
FALSE, TRUE, TRUE);
}
/* move dot by same amount */
if (!move_ptr (curwp, (long) (R_BYTES (curwp) * mov_lines),
TRUE, TRUE, TRUE))
curwp->w_unit_offset = 0;
curwp->w_flag |= WFHARD;
}
return (TRUE);
}
/* pvr
* This command is like "forwpage",
* but it goes backwards.
*/
bool
backpage (f, n, k)
int f, n, k;
{
long mov_lines;
if (rplc_mode)
next_pat ();
else
{
if (curwp->w_ntrows <= 2)
mov_lines = 2;
else
mov_lines = curwp->w_ntrows - 2;
/* move window */
move_ptr (curwp, -(long) (R_BYTES (curwp) * mov_lines),
FALSE, TRUE, TRUE);
/* move dot by same amount */
if (!move_ptr (curwp, -(long) (R_BYTES (curwp) * mov_lines),
TRUE, TRUE, TRUE))
curwp->w_unit_offset = 0;
curwp->w_flag |= WFHARD;
}
return (TRUE);
}
/*
* Set the mark in the current window
* to the value of dot. A message is written to
* the echo line unless we are running in a keyboard
* macro, when it would be silly.
*/
bool
setmark ()
{
if (curbp == blistp) /* jam - hack to do goto/kill */
pickone ();
else
{
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
if (kbdmop == NULL)
{
writ_echo (MSG_mark_set);
}
}
return (TRUE);
}
/* pvr
* Swap the values of "dot" and "mark" in
* the current window. This is pretty easy, because
* all of the hard work gets done by the standard routine
* that moves the mark about. The only possible
* error is "no mark".
*/
bool
swapmark ()
{
register short odoto;
register LINE *odotp;
if (curwp->w_markp == NULL)
{
writ_echo (MSG_no_mark);
return (FALSE);
}
odotp = curwp->w_dotp;
curwp->w_dotp = curwp->w_markp;
curwp->w_markp = odotp;
odoto = curwp->w_doto;
curwp->w_doto = curwp->w_marko;
curwp->w_marko = odoto;
wind_on_dot (curwp);
curwp->w_flag |= WFMODE; /* update mode line */
return (TRUE);
}
/* pvr
* Go to a specific byte position in buffer.
* If an argument is present, then
* it is the byte number, else prompt for a byte number
* to use.
*/
bool
gotoline (f, n, k)
int f, n, k;
{
A32 index;
register int s;
char buf[32];
if (f == FALSE)
{
if ((s = ereply (MSG_go_b_n, buf, sizeof (buf), 0) != TRUE))
return (s);
switch (R_TYPE (curwp))
{
case TEXT:
case ASCII:
case EBCDIC:
case BINARY:
case HEX:
sscanf (buf, MSG_lX, &index);
break;
case OCTAL:
sscanf (buf, MSG_lO, &index);
break;
case DECIMAL:
#if FLOAT_DISP
case FLOAT:
#endif
sscanf (buf, MSG_lD, &index);
break;
#if RUNCHK
default:
writ_echo (ERR_bas_1);
break;
#endif
}
}
if (n <= 0)
{
writ_echo (MSG_bad_num);
return (FALSE);
}
move_ptr (curwp, index, TRUE, TRUE, FALSE);
curwp->w_unit_offset = 0;
curwp->w_flag |= WFMODE; /* update mode line */
wind_on_dot (curwp);
return (TRUE);
}