home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
CMDS
/
pvic_10a.lzh
/
SRCE
/
ops.c
< prev
next >
Wrap
Text File
|
1998-05-10
|
13KB
|
608 lines
/*
* Contains routines that implement the operators in vi. Everything in this
* file is called only from code in normal.c
*/
#include <stdio.h>
#include "pvic.h"
#include "locdefs.h"
/*
* do_shift - handle a shift operation
*/
void
do_shift(op, c1, c2, num)
int op;
char c1, c2;
int num;
{
void tabinout();
LPTR top, bot;
int nlines;
char opchar;
top = startop;
bot = *cursor_char;
if (lt(&bot, &top))
pswap(&top, &bot);
u_save(top.linep->prev, bot.linep->next);
nlines = cntllines(&top, &bot);
*cursor_char = top;
tabinout((op == LSHIFT), nlines);
/* construct Redo buff */
opchar = (op == LSHIFT) ? '<' : '>';
if (num != 0)
sprintf(redo_buffer, "%c%d%c%c", opchar, num, c1, c2);
else
sprintf(redo_buffer, "%c%c%c", opchar, c1, c2);
/*
* The cursor position afterward is the prior of the two positions.
*/
*cursor_char = top;
/*
* If we were on the last char of a line that got shifted left,
* then move left one so we aren't beyond the end of the line
*/
if (gchar(cursor_char) == '\0' && cursor_char->index > 0)
cursor_char->index--;
update_screen(0);
if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
show_message("%d lines %ced", nlines, opchar);
}
/*
* do_delete - handle a delete operation
*/
void
do_delete(c1, c2, num)
char c1, c2;
int num;
{
LPTR top, bot;
int nlines;
int botindex;
register int n;
/*
* Do a yank of whatever we're about to delete. If there's too much
* stuff to fit in the yank buffer, then get a confirmation before
* doing the delete. This is crude, but simple. And it avoids doing
* a delete of something we can't put back if we want.
*/
if (!do_yank()) {
msg("Yank buffer exceeded, press 'y' to delete anyway");
if (get_char_from_input_buffer() != 'y') {
msg("Delete aborted");
*cursor_char = startop;
return;
}
}
top = startop;
bot = *cursor_char;
if (lt(&bot, &top))
pswap(&top, &bot);
u_save(top.linep->prev, bot.linep->next);
/* Don't leave even the potential for orphan marks */
clear_mark (top.linep);
nlines = cntllines(&top, &bot);
*cursor_char = top;
update_cursor(0);
if (mtype == MLINE) {
delete_line(nlines, (1));
} else {
botindex = -1;
if (!mincl) {
botindex = bot.index; /* where it WAS */
if (bot.index != 0)
dec(&bot);
}
if (top.linep == bot.linep) { /* del. within line */
n = bot.index - top.index + 1;
while (n--)
if (!delete_char((1)))
break;
} else { /* del. between lines */
n = cursor_char->index;
while (cursor_char->index >= n)
if (!delete_char((1)))
break;
top = *cursor_char;
*cursor_char = *next_line(cursor_char);
delete_line(nlines-2, (1));
cursor_char->index = 0;
n = bot.index + 1;
while (n-- && botindex)
if (!delete_char((1)))
break;
*cursor_char = top;
(void) do_join((0));
one_right(); /* we got bumped left up above */
}
}
/* construct Redo buff */
if (num != 0)
sprintf(redo_buffer, "d%d%c%c", num, c1, c2);
else
sprintf(redo_buffer, "d%c%c", c1, c2);
if (mtype == MCHAR && nlines == 1)
update_line();
else
update_screen(0);
if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
show_message("%d fewer lines", nlines);
}
/*
* do_filter - handle a filter operation
*/
#define ITMP "viXXXXXX"
#define OTMP "voXXXXXX"
static char itmp[32];
static char otmp[32];
/*
* do_filter - filter lines through a command given by the user
*
* We use temp files and the system() routine here. This would normally
* be done using pipes on a UNIX machine, but this is more portable to
* the machines we usually run on. The system() routine needs to be able
* to deal with redirection somehow, and should handle things like looking
* at the PATH env. variable, and adding reasonable extensions to the
* command name given by the user. All reasonable versions of system()
* do this.
*/
void
do_filter(c1, c2, num)
char c1, c2;
int num;
{
char *mktemp();
static char *lastcmd = NULL;/* the last thing we did */
char *buff; /* cmd buffer from getcmdln() */
char cmdln[200]; /* filtering command line */
LPTR top, bot;
int nlines;
top = startop;
bot = *cursor_char;
buff = getcmdln('!');
if (buff == NULL) /* user backed out of the command prompt */
return;
if (*buff == '!') { /* use the 'last' command */
if (lastcmd == NULL) {
error_message("No previous command");
return;
}
buff = lastcmd;
}
/*
* Remember the current command
*/
if (lastcmd != NULL)
free(lastcmd);
lastcmd = strsave(buff);
if (lt(&bot, &top))
pswap(&top, &bot);
u_save(top.linep->prev, bot.linep->next);
nlines = cntllines(&top, &bot);
*cursor_char = top;
update_cursor(0);
/*
* 1. Form temp file names
* 2. Write the lines to a temp file
* 3. Run the filter command on the temp file
* 4. Read the output of the command into the buffer
* 5. Delete the original lines to be filtered
* 6. Remove the temp files
*/
itmp[0] = otmp[0] = '\0';
strcat(itmp, ITMP);
strcat(otmp, OTMP);
if (mktemp(itmp) == NULL || mktemp(otmp) == NULL) {
error_message("Can't get temp file names");
return;
}
if (!write_it(itmp, &top, &bot)) {
error_message("Can't create input temp file");
return;
}
sprintf(cmdln, "%s <%s >%s", buff, itmp, otmp);
local_deinit_terminal_io();
if (local_system(cmdln) != 0) {
local_init_terminal_io();
error_message("Filter command failed");
unlink(ITMP);
return;
}
else local_init_terminal_io();
if (read_file(otmp, &bot, (1))) {
error_message("Can't read filter output");
return;
}
delete_line(nlines, (1));
unlink(itmp);
unlink(otmp);
/* construct Redo buff */
if (num != 0)
sprintf(redo_buffer, "d%d%c%c", num, c1, c2);
else
sprintf(redo_buffer, "d%c%c", c1, c2);
update_screen(0);
if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
show_message("%d lines filtered", nlines);
}
/*
* do_change - handle a change operation
*/
void
do_change(c1, c2, num)
char c1, c2;
int num;
{
char sbuf[16];
int doappend; /* true if we should do append, not insert */
int at_eof; /* changing through the end of file */
LPTR top, bot;
top = startop;
bot = *cursor_char;
if (lt(&bot, &top))
pswap(&top, &bot);
doappend = end_of_line(&bot);
at_eof = (bot.linep->next == end_of_file->linep);
do_delete(c1, c2, num);
if (mtype == MLINE) {
/*
* If we made a change through the last line of the file,
* then the cursor got backed up, and we need to open a
* new line forward, otherwise we go backward.
*/
if (at_eof)
open_command(SEARCH_FORWARD, (0));
else
open_command(SEARCH_BACKWARD, (0));
} else {
if (doappend && !line_empty())
inc(cursor_char);
}
if (num)
sprintf(sbuf, "c%d%c%c", num, c1, c2);
else
sprintf(sbuf, "c%c%c", c1, c2);
do_start_insert(sbuf, mtype == MLINE);
}
#ifndef YBSIZE
#define YBSIZE 4096
#endif
static char ybuf[YBSIZE];
static int ybtype = MBAD;
int
do_yank()
{
LPTR top, bot;
char *yptr = ybuf;
char *ybend = &ybuf[YBSIZE-1];
int nlines;
top = startop;
bot = *cursor_char;
if (lt(&bot, &top))
pswap(&top, &bot);
nlines = cntllines(&top, &bot);
ybtype = mtype; /* set the yank buffer type */
if (mtype == MLINE) {
top.index = 0;
bot.index = strlen(bot.linep->s);
/*
* The following statement checks for the special case of
* yanking a blank line at the beginning of the file. If
* not handled right, we yank an extra char (a newline).
*/
if (dec(&bot) == -1) {
ybuf[0] = '\0';
if (operator == YANK)
*cursor_char = startop;
return (1);
}
} else {
if (!mincl) {
if (bot.index)
bot.index--;
else /* already first column */
bot = *( previous_char (&bot));
}
}
for (; ltoreq(&top, &bot) ;inc(&top)) {
*yptr = (gchar(&top) != '\0') ? gchar(&top) : '\n';
if (++yptr >= ybend) {
msg("Yank too big for buffer");
ybtype = MBAD;
return (0);
}
}
*yptr = '\0';
if (operator == YANK) { /* restore cursor_char if really doing yank */
*cursor_char = startop;
if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
show_message("%d lines yanked", nlines);
}
return (1);
}
/*
* do_put(dir)
*
* Put the yank buffer at the current location, using the direction given
* by 'dir'.
*/
void
do_put(dir)
int dir;
{
void inslines();
if (ybtype == MBAD) {
beep();
return;
}
u_save_line();
if (ybtype == MLINE)
inslines(cursor_char->linep, dir, ybuf);
else {
/*
* If we did a character-oriented yank, and the buffer
* contains multiple lines, the situation is more complex.
* For the moment, we punt, and pretend the user did a
* line-oriented yank. This doesn't actually happen that
* often.
*/
if (get_pointer_to_chr_in_string(ybuf, '\n') != NULL)
inslines(cursor_char->linep, dir, ybuf);
else {
char *s;
int len;
len = strlen(cursor_char->linep->s) + strlen(ybuf) + 1;
s = alloc((unsigned) len);
if (!s) return;
strcpy(s, cursor_char->linep->s);
if (dir == SEARCH_FORWARD)
cursor_char->index++;
strcpy(s + cursor_char->index, ybuf);
strcat(s, &cursor_char->linep->s[cursor_char->index]);
free(cursor_char->linep->s);
cursor_char->linep->s = s;
cursor_char->linep->size = len;
update_line();
}
}
CHANGED;
}
int
do_join(join_cmd)
int join_cmd; /* handling a real "join" command? */
{
int scol; /* save cursor column */
int size; /* size of the joined line */
if (next_line(cursor_char) == NULL) /* on last line */
return (0);
if (!can_increase(size = strlen(cursor_char->linep->next->s)))
return (0);
while (one_right()) /* to end of line */
;
strcat(cursor_char->linep->s, cursor_char->linep->next->s);
/*
* Delete the following line. To do this we move the cursor
* there briefly, and then move it back. Don't back up if the
* delete made us the last line.
*/
cursor_char->linep = cursor_char->linep->next;
scol = cursor_char->index;
if (next_line(cursor_char) != NULL) {
delete_line(1, (1));
cursor_char->linep = cursor_char->linep->prev;
} else
delete_line(1, (1));
cursor_char->index = scol;
if (join_cmd)
one_right(); /* go to first char. of joined line */
if (join_cmd && size != 0) {
/*
* Delete leading white space on the joined line
* and insert a single space.
*/
while (gchar(cursor_char) == ' ' || gchar(cursor_char) == CTRL_I)
delete_char((1));
inschar(' ');
}
return (1);
}
void
do_start_insert(initstr, startln)
char *initstr;
int startln; /* if set, insert point really at start of line */
{
register char *p, c;
*start_insert = *cursor_char;
if (startln)
start_insert->index = 0;
insert_n = 0;
insert_pointer = insert_buffer;
for (p=initstr; (c=(*p++))!='\0'; )
*insert_pointer++ = c;
if (*initstr == 'R')
current_status = STATUS_REPLACE;
else
current_status = STATUS_INSERT;
if (PARAMETER_VALUE(PARAMETER_SHOWMODE))
msg((current_status == STATUS_INSERT) ? "Insert mode" : "Replace mode");
}
/*
* tabinout(inout,num)
*
* If inout==0, add a tab to the begining of the next num lines.
* If inout==1, delete a tab from the beginning of the next num lines.
*/
static void
tabinout(inout, num)
int inout;
int num;
{
int ntodo = num;
LPTR *p;
begin_line((0));
while (ntodo-- > 0) {
begin_line((0));
if (inout == 0)
inschar(CTRL_I);
else {
if (gchar(cursor_char) == CTRL_I)
delete_char((1));
}
if ( ntodo > 0 ) {
if ((p = next_line(cursor_char)) != NULL)
*cursor_char = *p;
else
break;
}
}
}
/*
* inslines(lp, dir, buf)
*
* Inserts lines in the file from the given buffer. Lines are inserted
* before or after "lp" according to the given direction flag. Newlines
* in the buffer result in multiple lines being inserted. The cursor
* is left on the first of the inserted lines.
*/
static void
inslines(lp, dir, buf)
LINE *lp;
int dir;
char *buf;
{
register char *cp = buf;
register int len;
char *ep;
LINE *l, *nc = NULL;
if (dir == SEARCH_BACKWARD)
lp = lp->prev;
do {
if ((ep = get_pointer_to_chr_in_string(cp, '\n')) == NULL)
len = strlen(cp);
else
len = ep - cp;
l = newline(len);
if (len != 0)
strncpy(l->s, cp, len);
l->s[len] = '\0';
l->next = lp->next;
l->prev = lp;
lp->next->prev = l;
lp->next = l;
if (nc == NULL)
nc = l;
lp = lp->next;
cp = ep + 1;
} while (ep != NULL);
if (dir == SEARCH_BACKWARD) /* fix the top line in case we were there */
file_memory->linep = top_of_file->linep->next;
renum();
update_screen(0);
cursor_char->linep = nc;
cursor_char->index = 0;
}