/* $OpenBSD: word.c,v 1.14 2006/05/28 23:30:16 kjell Exp $ */
/* This file is in the public domain. */
/*
* Word mode commands.
* The routines in this file implement commands that work word at a time.
* There are all sorts of word mode commands.
*/
#include "def.h"
RSIZE countfword(void);
/*
* Move the cursor backward by "n" words. All of the details of motion are
* performed by the "backchar" and "forwchar" routines.
*/
/* ARGSUSED */
int
backword(int f, int n)
{
if (n < 0)
return (forwword(f | FFRAND, -n));
if (backchar(FFRAND, 1) == FALSE)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (backchar(FFRAND, 1) == FALSE)
return (TRUE);
}
while (inword() != FALSE) {
if (backchar(FFRAND, 1) == FALSE)
return (TRUE);
}
}
return (forwchar(FFRAND, 1));
}
/*
* Move the cursor forward by the specified number of words. All of the
* motion is done by "forwchar".
*/
/* ARGSUSED */
int
forwword(int f, int n)
{
if (n < 0)
return (backword(f | FFRAND, -n));
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
while (inword() != FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move,
* convert any characters to upper case.
*/
/* ARGSUSED */
int
upperword(int f, int n)
{
int c;
RSIZE size;
if (curbp->b_flag & BFREADONLY) {
ewprintf("Buffer is read-only");
return (FALSE);
}
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
size = countfword();
undo_add_change(curwp->w_dotp, curwp->w_doto, size);
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISLOWER(c) != FALSE) {
c = TOUPPER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFFULL);
}
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert characters to lower case.
*/
/* ARGSUSED */
int
lowerword(int f, int n)
{
int c;
RSIZE size;
if (curbp->b_flag & BFREADONLY) {
ewprintf("Buffer is read-only");
return (FALSE);
}
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
size = countfword();
undo_add_change(curwp->w_dotp, curwp->w_doto, size);
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISUPPER(c) != FALSE) {
c = TOLOWER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFFULL);
}
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert the first character of the word to upper case, and subsequent
* characters to lower case. Error if you try to move past the end of the
* buffer.
*/
/* ARGSUSED */
int
capword(int f, int n)
{
int c;
RSIZE size;
if (curbp->b_flag & BFREADONLY) {
ewprintf("Buffer is read-only");
return (FALSE);
}
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
size = countfword();
undo_add_change(curwp->w_dotp, curwp->w_doto, size);
if (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISLOWER(c) != FALSE) {
c = TOUPPER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFFULL);
}
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISUPPER(c) != FALSE) {
c = TOLOWER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFFULL);
}
if (forwchar(FFRAND, 1) == FALSE)
return (TRUE);
}
}
}
return (TRUE);
}
/*
* Count characters in word, from current position
*/
RSIZE
countfword()
{
RSIZE size;
struct line *dotp;
int doto;
dotp = curwp->w_dotp;
doto = curwp->w_doto;
size = 0;
while (inword() != FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
/* hit the end of the buffer */
goto out;
++size;
}
out:
curwp->w_dotp = dotp;
curwp->w_doto = doto;
return (size);
}
/*
* Kill forward by "n" words.
*/
/* ARGSUSED */
int
delfword(int f, int n)
{
RSIZE size;
struct line *dotp;
int doto;
if (curbp->b_flag & BFREADONLY) {
ewprintf("Buffer is read-only");
return (FALSE);
}
if (n < 0)
return (FALSE);
/* purge kill buffer */
if ((lastflag & CFKILL) == 0)
kdelete();
thisflag |= CFKILL;
dotp = curwp->w_dotp;
doto = curwp->w_doto;
size = 0;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
/* hit the end of the buffer */
goto out;
++size;
}
while (inword() != FALSE) {
if (forwchar(FFRAND, 1) == FALSE)
/* hit the end of the buffer */
goto out;
++size;
}
}
out:
curwp->w_dotp = dotp;
curwp->w_doto = doto;
return (ldelete(size, KFORW));
}
/*
* Kill backwards by "n" words. The rules for success and failure are now
* different, to prevent strange behavior at the start of the buffer. The
* command only fails if something goes wrong with the actual delete of the
* characters. It is successful even if no characters are deleted, or if you
* say delete 5 words, and there are only 4 words left. I considered making
* the first call to "backchar" special, but decided that that would just be
* weird. Normally this is bound to "M-Rubout" and to "M-Backspace".
*/
/* ARGSUSED */
int
delbword(int f, int n)
{
RSIZE size;
if (curbp->b_flag & BFREADONLY) {
ewprintf("Buffer is read-only");
return (FALSE);
}
if (n < 0)
return (FALSE);
/* purge kill buffer */
if ((lastflag & CFKILL) == 0)
kdelete();
thisflag |= CFKILL;
if (backchar(FFRAND, 1) == FALSE)
/* hit buffer start */
return (TRUE);
/* one deleted */
size = 1;
while (n--) {
while (inword() == FALSE) {
if (backchar(FFRAND, 1) == FALSE)
/* hit buffer start */
goto out;
++size;
}
while (inword() != FALSE) {
if (backchar(FFRAND, 1) == FALSE)
/* hit buffer start */
goto out;
++size;
}
}
if (forwchar(FFRAND, 1) == FALSE)
return (FALSE);
/* undo assumed delete */
--size;
out:
return (ldelete(size, KBACK));
}
/*
* Return TRUE if the character at dot is a character that is considered to be
* part of a word. The word character list is hard coded. Should be settable.
*/
int
inword(void)
{
/* can't use lgetc in ISWORD due to bug in OSK cpp */
return (curwp->w_doto != llength(curwp->w_dotp) &&
ISWORD(curwp->w_dotp->l_text[curwp->w_doto]));
}