Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A mini-vi for the ST (part 1 of 2)

225 views
Skip to first unread message

Tim Thompson

unread,
Jun 28, 1987, 2:21:33 PM6/28/87
to

# Enclosed is (part 1 of) the source for a mini-VI which I wrote when I
# first got the ST, to make things easier for my own development. Although
# it is somewhat minimal in capabilities, it does have a fairly good
# implementation of the 'u' (undo) and '.' (repeat) commands. I have
# much more interesting things to work on these days, so I am unlikely
# to provide any support (hence my posting of the source). It has worked
# well for 6 months, and since no alternatives have appeared on the net
# (other than VIX, which is too different for me), I figure it might be
# useful. See the README below for more info.
# ...Tim Thompson...ihnp4!twitch!tjt...
#
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# README
# Makefile
# cmdline.c
# edit.c
# help.c
# hexchars.c
# linefunc.c
# This archive created: Sun Jun 28 13:18:36 1987
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
STEVIE - ST Editor for VI Enthusiasts ...Tim Thompson...twitch!tjt...
=====================================

The STEVIE editor is a fairly accurate (in the small subset of commands
it chooses to implement) version of the VI editor. It was written
at a time when alternatives (ie. VIX) were not available. To VI users,
STEVIE should provide a much more familiar environment than VIX, but has
nowhere near the capabilities (or speed), in general.

Features/Limitations
====================

- The "." (repeat last operation) and "u" (undo last insertion or
deletion) commands are available, and will repeat/undo almost
anything.

- The commands implemented in STEVIE happen to be the subset of
VI commands used by its author (suprise!). A fair number of
additional (positioning and substitution) commands should be
easy to add. Regular expressions and global substitutions
are not implemented.

- STEVIE is limited to editing files < 64K. The source code has no
built-in limitations, but the file is kept in memory as a single
contiguous stream of bytes. This implies various limitations,
among them the fact that operations such as insert and delete will
slow down (by a LOT, in the current implementation) as the file
being edited grows larger. The slowness could be eliminated by
some reworking, which I'm unmotiviated to do, since I rarely edit
files larger than 16K. Scrolling in general is also unnecessarily
slow. Reading/writing files is also slow.

- Known glitches/annoyances: <control-d> scrolling works strangely.
Long (>80 chars) lines are usually handled okay, but strange
(positional) things sometime happen at the bottom of the screen.
Backspacing at the beginning of a line, in insert mode, isn't handled
correctly. Undoing insertions at the end of a line are sometimes
off by a character. The :r command does not work very well.
A final line that does not end in '\n' is troublesome.

- There is some support in the editor for displaying and editing binary
files. Giving a '-b' option tells the editor that you are intentionally
editing a binary file. Unprintable characters are displayed in a
[xxx] format, where xxx is either octal or hex (if you use the -x
option). The binary editing support is mostly an untested hack
(although it was one of the original goals of the editor, so the
support for it was not unplanned). If it works, fine; I'm not
claiming that it does.

- Although STEVIE has been used with no problems for several months,
it no doubt contains bugs that will surface when used by others.
Cautious initial use is recommended.

Commands
========

Some commands can make use of a numeric prefix, indicated in
the summary below as [#].

Cursor movement commands
========================
control-l Redraw screen
control-d Cursor down 1/2 screen
control-u Cursor up 1/2 screen
control-f Cursor forward 1 screen
control-b Cursor back 1 screen
control-g Give info on file

h Cursor left 1 char
j Cursor down 1 char
k Cursor up 1 char
l Cursor right 1 char
$ Cursor to end of line
^ -or- 0 Cursor to beginning of line
b Cursor back 1 word
w Cursor forward 1 word\n\
[#]G Goto line # (or last line if no #)

Modification commands
=====================
x Delete 1 char
dw Delete 1 word
D Delete rest of line
[#]dd Delete 1 (or #) lines
C Change rest of line
cw Change word
cc Change line
r Replace single character
[#]yy Yank 1 (or #) lines
p Insert last yanked or deleted line(s)
P below (p) or above (P) current line
J Join current and next line
[#]<< Shift line left 1 (or #) tabs
[#]>> Shift line right 1 (or #) tabs
i Enter Insert mode (<ESC> to exit)
a Append (<ESC> to exit) \n\
o Open line (<ESC> to exit)\n\

Miscellaneous
=============
. Repeat last operation. The works for most (but not all)
commands, including insertions.
u Undo last insert or delete. This works for most
operations, although there are undoubtedly some for
which it will not.
/str/ Search for 'str' (NO REGULAR EXPRESSIONS)
?str? Search backward for 'str'
n Repeat previous search
:.= Print current line number
:$= Print number of lines in file
H Help - a quick summary of commands

File manipulation
=================
:w Write file
:wq Write and quit
:e {file} Edit a new file
:e! Re-read current file
:f Print file into (current line and total # of lines)
:f {file} Change current file name
:q Quit
:q! Quit (no save)


SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
CFLAGS = -DTCAP # or UNIXPC or ATARI

OBJ = main.o edit.o linefunc.o normal.o \
cmdline.o hexchars.o misccmds.o help.o

default : stevie

stevie : $(OBJ) tcapwind.o
cc $(OBJ) tcapwind.o -lcurses -ltermcap -o stevie

s4vi : $(OBJ) unixpcwind.o
cc $(OBJ) unixpcwind.o -ltam -ltermcap -o s4vi

tcapwind.o : window.c
cc -c $(CFLAGS) window.c
mv window.o tcapwind.o

unixpcwind.o : window.c
cc -c $(CFLAGS) window.c
mv window.o unixpcwind.o

clean :
rm -f *.o stevie s4vi
SHAR_EOF
fi # end of overwriting check
if test -f 'cmdline.c'
then
echo shar: will not over-write existing file "'cmdline.c'"
else
cat << \SHAR_EOF > 'cmdline.c'
/*
* STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt...
*/

#include <stdio.h>
#include <ctype.h>
#include "stevie.h"

readcmdline(firstc)
int firstc; /* either ':', '/', or '?' */
{
int c;
char buff[100];
char *p, *q, *cmd, *arg;

gotocmd(1,1,firstc);
p = buff;
if ( firstc != ':' )
*p++ = firstc;
/* collect the command string, handling '\b' and @ */
for ( ; ; ) {
c = vgetc();
if ( c=='\n'||c=='\r'||c==EOF )
break;
if ( c=='\b' ) {
if ( p > buff ) {
p--;
/* I know this is gross, but it has the */
/* advantage of relying only on 'gotocmd' */
gotocmd(1,0,firstc==':'?':':0);
for ( q=buff; q<p; q++ )
windputc(*q);
windrefresh();
}
continue;
}
if ( c=='@' ) {
p = buff;
gotocmd(1,1,firstc);
continue;
}
windputc(c);
windrefresh();
*p++ = c;
}
*p = '\0';

/* skip any initial white space */
for ( cmd = buff; isspace(*cmd); cmd++ )
;

/* search commands */
c = *cmd;
if ( c == '/' || c == '?' ) {
cmd++;
if ( *cmd == c ) {
/* the command was '//' or '??' */
repsearch();
return;
}
/* If there is a matching '/' or '?' at the end, toss it */
p = strchr(cmd,'\0');
if ( *(--p) == c )
*p = '\0';
dosearch(c=='/'?FORWARD:BACKWARD,cmd);
return;
}

/* isolate the command and find any argument */
for ( p=cmd; *p!='\0' && ! isspace(*p); p++ )
;
if ( *p == '\0' )
arg = NULL;
else {
*p = '\0';
while ( *(++p) != '\0' && isspace(*p) )
;
arg = p;
if ( *arg == '\0' )
arg = NULL;
}
if ( strcmp(cmd,"q!")==0 )
getout();
if ( strcmp(cmd,"q")==0 ) {
if ( Changed )
message("File not written out. Use 'q!' to override.");
else
getout();
return;
}
if ( strcmp(cmd,"w")==0 ) {
if ( arg == NULL ) {
writeit(Filename);
UNCHANGED;
}
else
writeit(arg);
return;
}
if ( strcmp(cmd,"wq")==0 ) {
if ( writeit(Filename) )
getout();
return;
}
if ( strcmp(cmd,"f")==0 && arg==NULL ) {
fileinfo();
return;
}
if ( strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0 ) {
if ( cmd[1]!='!' && Changed ) {
message("File not written out. Use 'e!' to override.");
}
else {
if ( arg != NULL )
Filename = strsave(arg);
/* clear mem and read file */
Fileend = Topchar = Curschar = Filemem;
UNCHANGED;
p = nextline(Curschar);
readfile(Filename,Fileend,0);
updatescreen();
}
return;
}
if ( strcmp(cmd,"f") == 0 ) {
Filename = strsave(arg);
filemess("");
return;
}
if ( strcmp(cmd,"r") == 0 || strcmp(cmd,".r") == 0 ) {
char *pp;
if ( arg == NULL ) {
badcmd();
return;
}
/* find the beginning of the next line and */
/* read file in there */
pp = nextline(Curschar);
readfile(arg,pp,1);
updatescreen();
CHANGED;
return;
}
if ( strcmp(cmd,".=")==0 ) {
char messbuff[80];
sprintf(messbuff,"line %d character %d",
cntlines(Filemem,Curschar),
1+(int)(Curschar-Filemem));
message(messbuff);
return;
}
if ( strcmp(cmd,"$=")==0 ) {
char messbuff[8];
sprintf(messbuff,"%d",
cntlines(Filemem,Fileend)-1);
message(messbuff);
return;
}
if ( strcmp(cmd,"set")==0 ) {
if ( arg == NULL )
badcmd();
else if ( strcmp(arg,"oct")==0 ) {
octchars();
updatescreen();
}
else if ( strcmp(arg,"hex")==0 ) {
hexchars();
updatescreen();
}
else if ( strcmp(arg,"dec")==0 ) {
decchars();
updatescreen();
}
else
badcmd();
return;
}
badcmd();
}

badcmd()
{
message("Unrecognized command");
}

gotocmd(clr,fresh,firstc)
{
int n;

windgoto(Rows-1,0);
if ( clr ) {
/* clear the line */
for ( n=0; n<(Columns-1); n++ )
windputc(' ');
windgoto(Rows-1,0);
}
if ( firstc )
windputc(firstc);
if ( fresh )
windrefresh();
}

message(s)
char *s;
{
static char *lastmess = NULL;
char *p;

if ( lastmess!=NULL ) {
if ( strcmp(lastmess,s)==0 )
return;
free(lastmess);
}
gotocmd(1,1,0);
/* take off any trailing newline */
if ( (p=strchr(s,'\0'))!=NULL && *p=='\n' )
*p = '\0';
windstr(s);
lastmess = strsave(s);
}

writeit(fname)
char *fname;
{
FILE *f;
char buff[128];
char *p;
int n;

#ifdef ATARI
if ( (f=fopen(fname,Binary?"bw":"w")) == NULL ) {
#else
if ( (f=fopen(fname,"w")) == NULL ) {
#endif
message("Unable to open file!");
return(0);
}
for ( n=0,p=Filemem; p<Fileend; p++,n++ )
putc(*p,f);
fclose(f);
sprintf(buff,"\"%s\" %d characters",fname,n);
message(buff);
UNCHANGED;
return(1);
}

filemess(s)
char *s;
{
char buff[128];
sprintf(buff,"\"%s\" %s",Filename,s);
message(buff);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'edit.c'
then
echo shar: will not over-write existing file "'edit.c'"
else
cat << \SHAR_EOF > 'edit.c'
/*
* STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt...
*/

#include <stdio.h>
#include <ctype.h>
#include "stevie.h"

edit()
{
int c, c1, c2;
char *p, *q;

Prenum = 0;

/* position the display and the cursor at the top of the file. */
Topchar = Filemem;
Curschar = Filemem;
Cursrow = Curscol = 0;

for ( ;; ) {
/* Figure out where the cursor is based on Curschar. */
cursupdate();
if ( State == INSERT )
message("Insert Mode");
/* printf("Curschar=(%d,%d) row/col=(%d,%d)",
Curschar,*Curschar,Cursrow,Curscol); */
windgoto(Cursrow,Curscol);
windrefresh();
c = vgetc();
if ( State != INSERT )
message("");
switch(State) {
case NORMAL:
/* We're in the normal (non-insert) mode. */

/* Pick up any leading digits and compute 'Prenum' */
if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){
Prenum = Prenum*10 + (c-'0');
break;
}
/* execute the command */
normal(c);
Prenum = 0;
break;
case INSERT:
/* We're in insert mode. */
switch(c){
case '\033': /* an ESCape ends input mode */

/* If we're past the end of the file, (which should */
/* only happen when we're editing a new file or a */
/* file that doesn't have a newline at the end of */
/* the line), add a newline automatically. */
if ( Curschar >= Fileend ) {
insertchar('\n');
Curschar--;
}

/* Don't end up on a '\n' if you can help it. */
if ( Curschar>Filemem && *Curschar=='\n'
&& *(Curschar-1)!='\n' ) {
Curschar--;
}
State = NORMAL;
message("");
Uncurschar = Insstart;
Undelchars = Ninsert;
/* Undobuff[0] = '\0'; */
/* construct the Redo buffer */
p=Redobuff;
q=Insbuff;
while ( q<Insptr )
*p++ = *q++;
*p++ = '\033';
*p = '\0';
updatescreen();
break;
case '\b':
if ( Curschar <= Insstart )
beep();
else {
int wasnewline = 0;
if ( *Curschar == '\n' )
wasnewline=1;
Curschar--;
delchar();
Insptr--;
Ninsert--;
if ( wasnewline )
Curschar++;
cursupdate();
updatescreen();
}
break;
case '\030': /* control-x */
{ int wasnewline = 0; char *p1;
p1 = Curschar;
if ( *Curschar == '\n' )
wasnewline = 1;
inschar('[');
inschar('x');
cursupdate();
updatescreen();
c1 = gethexchar();
inschar(c1);
cursupdate();
updatescreen();
c2 = gethexchar();
Curschar = p1;
delchar();
delchar();
delchar();
c = 16*hextoint(c1)+hextoint(c2);
if(Debug)printf("(c=%d)",c);
if ( wasnewline )
Curschar++;
inschar(c);
Ninsert++;
*Insptr++ = c;
updatescreen();
break;
}
case '\017':
break;
case '\r':
c = '\n';
/* This is SUPPOSED to fall down into 'default' */
default:
insertchar(c);
break;
}
break;
}
}
}

insertchar(c)
int c;
{
char *p;

if ( ! anyinput() ) {
inschar(c);
*Insptr++ = c;
Ninsert++;
}
else {
/* If there's any pending input, grab */
/* it all at once. */
p = Insptr;
*Insptr++ = c;
Ninsert++;
while ( (c=vpeekc()) != '\033' ) {
c = vgetc();
*Insptr++ = c;
Ninsert++;
}
*Insptr = '\0';
insstr(p);
}
updatescreen();
}

gethexchar()
{
int c;

for ( ;; ) {
windgoto(Cursrow,Curscol);
windrefresh();
c = vgetc();
if ( hextoint(c) >= 0 )
break;
message("Expecting a hexidecimal character (0-9 or a-f)");
beep();
sleep(1);
}
return(c);
}

getout()
{
windgoto(Rows-1,0);
windrefresh();
putchar('\r');
putchar('\n');
windexit(0);
}

cursupdate()
{
char *p;
int inc, c, nlines;

/* special case: file is completely empty */
if ( Fileend == Filemem ) {
Topchar = Curschar = Filemem;
}
else if ( Curschar < Topchar ) {
nlines = cntlines(Curschar,Topchar);
/* if the cursor is above the top of */
/* the screen, put it at the top of the screen.. */
Topchar = Curschar;
/* ... and, if we weren't very close to begin with, */
/* we scroll so that the line is close to the middle. */
if ( nlines > Rows/3 )
scrolldown(Rows/3);
else {
/* make sure we have the current line completely */
/* on the screen, by setting Topchar to the */
/* beginning of the current line (in a strange way). */
if ( (p=prevline(Topchar))!=NULL &&
(p=nextline(p))!=NULL ) {
Topchar = p;
}
}
updatescreen();
}
else if ( Curschar >= Botchar && Curschar < Fileend ) {
nlines = cntlines(Botchar,Curschar);
/* If the cursor is off the bottom of the screen, */
/* put it at the top of the screen.. */
Topchar = Curschar;
/* ... and back up */
if ( nlines > Rows/3 )
scrolldown((2*Rows)/3);
else
scrolldown(Rows-2);
updatescreen();
}

Cursrow = Curscol = Cursvcol = 0;
for ( p=Topchar; p<Curschar; p++ ) {
c = *p;
if ( c == '\n' ) {
Cursrow++;
Curscol = Cursvcol = 0;
continue;
}
/* A tab gets expanded, depending on the current column */
if ( c == '\t' )
inc = (8 - (Curscol)%8);
else
inc = chars[(unsigned)(c & 0xff)].ch_size;
Curscol += inc;
Cursvcol += inc;
if ( Curscol >= Columns ) {
Curscol -= Columns;
Cursrow++;
}
}
}

scrolldown(nlines)
int nlines;
{
int n;
char *p;

/* Scroll up 'nlines' lines. */
for ( n=nlines; n>0; n-- ) {
if ( (p=prevline(Topchar)) == NULL )
break;
Topchar = p;
}
}

/*
* oneright
* oneleft
* onedown
* oneup
*
* Move one char {right,left,down,up}. Return 1 when
* sucessful, 0 when we hit a boundary (of a line, or the file).
*/

oneright()
{
char *p;

p = Curschar;
if ( (*p++)=='\n' || p>=Fileend || *p == '\n' )
return(0);
Curschar++;
return(1);
}

oneleft()
{
char *p;

p = Curschar;
if ( *p=='\n' || p==Filemem || *(p-1) == '\n' )
return(0);
Curschar--;
return(1);
}

beginline()
{
while ( oneleft() )
;
}

oneup(n)
{
char *p, *np;
int savevcol, k;

savevcol = Cursvcol;
p = Curschar;
for ( k=0; k<n; k++ ) {
/* Look for the previous line */
if ( (np=prevline(p)) == NULL ) {
/* If we've at least backed up a little .. */
if ( k > 0 )
break; /* to update the cursor, etc. */
else
return(0);
}
p = np;
}
Curschar = p;
/* This makes sure Topchar gets updated so the complete line */
/* is one the screen. */
cursupdate();
/* try to advance to the same (virtual) column */
/* that we were at before. */
Curschar = coladvance(p,savevcol);
return(1);
}

onedown(n)
{
char *p, *np;
int k;

p = Curschar;
for ( k=0; k<n; k++ ) {
/* Look for the next line */
if ( (np=nextline(p)) == NULL ) {
if ( k > 0 )
break;
else
return(0);
}
p = np;
}
/* try to advance to the same (virtual) column */
/* that we were at before. */
Curschar = coladvance(p,Cursvcol);
return(1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'help.c'
then
echo shar: will not over-write existing file "'help.c'"
else
cat << \SHAR_EOF > 'help.c'
/*
* STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt...
*/

#include <ctype.h>
#include "stevie.h"

static int helprow;

help()
{
windclear();
windgoto(helprow=0,0);
longline("\
\n\
Cursor movement commands\n\
========================\n\
control-l Redraw screen\n\
control-d Cursor down 1/2 screen\n\
control-u Cursor up 1/2 screen\n\
control-f Cursor forward 1 screen\n");
longline("\
control-b Cursor back 1 screen\n\
control-g Give info on file\n\
\n\
h Cursor left 1 char\n\
j Cursor down 1 char\n\
k Cursor up 1 char\n");
longline("\
l Cursor right 1 char\n\
$ Cursor to end of line\n\
^ -or- 0 Cursor to beginning of line\n\
b Cursor back 1 word\n");
longline("\
w Cursor forward 1 word\n\
[#]G Goto line # (or last line if no #)\n\
\n\
<Press space bar to continue>\n\
<Any other key will quit>");
windrefresh();
if ( vgetc() != ' ' )
return;
windclear();
windgoto(helprow=0,0);
longline("\
\n\
Modification commands\n\
=====================\n\
x Delete 1 char\n\
dw Delete 1 word\n\
D Delete rest of line\n\
[#]dd Delete 1 (or #) lines\n\
C Change rest of line\n");
longline("\
cw Change word\n\
cc Change line\n\
r Replace single character\n\
[#]yy Yank 1 (or #) lines\n\
p Insert last yanked or deleted line(s)\n");
longline("\
P below (p) or above (P) current line\n\
J Join current and next line\n\
[#]<< Shift line left 1 (or #) tabs\n\
[#]>> Shift line right 1 (or #) tabs\n\
i Enter Insert mode (<ESC> to exit)\n");
longline("\
a Append (<ESC> to exit) \n\
o Open line (<ESC> to exit)\n\
\n\
<Press space bar to continue>\n\
<Any other key will quit>");
windrefresh();
if ( vgetc() != ' ' )
return;
windclear();
windgoto(helprow=0,0);
longline("\
\n\
Miscellaneous\n\
=============\n\
. Repeat last insert or delete\n\
u Undo last insert or delete\n\
/str/ Search for 'str'\n\
?str? Search backward for 'str'\n");
longline(" n Repeat previous search\n\
:.= Print current line number\n\
:$= Print number of lines in file\n\
H Help\n\
\n\
File manipulation\n\
=================\n");
longline("\
:w Write file\n\
:wq Write and quit\n\
:e {file} Edit a new file\n\
:e! Re-read current file\n\
:f Print file into (current line and total # of lines)\n");
longline("\
:f {file} Change current file name\n\
:q Quit\n\
:q! Quit (no save)\n\
\n\
<Press any key>");
windrefresh();
vgetc();
}

longline(p)
char *p;
{
char *s;

for ( s=p; *s; s++ ) {
if ( *s == '\n' )
windgoto(++helprow,0);
else
windputc(*s);
}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'hexchars.c'
then
echo shar: will not over-write existing file "'hexchars.c'"
else
cat << \SHAR_EOF > 'hexchars.c'
/*
* STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt...
*/

#include <stdio.h>
#include "stevie.h"

/*
* This stuff is used to provide readable interpretations of unprintable
* characters. The 'xxx' in each is replaced with either hex, octal, or
* decimal numbers, depending on what command-line argument is given.
*/

struct charinfo chars[] = {
/* 000 */ 5, "[xxx]",
/* 001 */ 5, "[xxx]",
/* 002 */ 5, "[xxx]",
/* 003 */ 5, "[xxx]",
/* 004 */ 5, "[xxx]",
/* 005 */ 5, "[xxx]",
/* 006 */ 5, "[xxx]",
/* 007 */ 5, "[xxx]",
/* 010 */ 5, "[xxx]",
/* 011 */ 5, "[xxx]",
/* 012 */ 1, NULL,
/* 013 */ 5, "[xxx]",
/* 014 */ 5, "[xxx]",
/* 015 */ 5, "[xxx]",
/* 016 */ 5, "[xxx]",
/* 017 */ 5, "[xxx]",
/* 020 */ 5, "[xxx]",
/* 021 */ 5, "[xxx]",
/* 022 */ 5, "[xxx]",
/* 023 */ 5, "[xxx]",
/* 024 */ 5, "[xxx]",
/* 025 */ 5, "[xxx]",
/* 026 */ 5, "[xxx]",
/* 027 */ 5, "[xxx]",
/* 030 */ 5, "[xxx]",
/* 031 */ 5, "[xxx]",
/* 032 */ 5, "[xxx]",
/* 033 */ 5, "[xxx]",
/* 034 */ 5, "[xxx]",
/* 035 */ 5, "[xxx]",
/* 036 */ 5, "[xxx]",
/* 037 */ 5, "[xxx]",
/* 040 */ 1, NULL,
/* 041 */ 1, NULL,
/* 042 */ 1, NULL,
/* 043 */ 1, NULL,
/* 044 */ 1, NULL,
/* 045 */ 1, NULL,
/* 046 */ 1, NULL,
/* 047 */ 1, NULL,
/* 050 */ 1, NULL,
/* 051 */ 1, NULL,
/* 052 */ 1, NULL,
/* 053 */ 1, NULL,
/* 054 */ 1, NULL,
/* 055 */ 1, NULL,
/* 056 */ 1, NULL,
/* 057 */ 1, NULL,
/* 060 */ 1, NULL,
/* 061 */ 1, NULL,
/* 062 */ 1, NULL,
/* 063 */ 1, NULL,
/* 064 */ 1, NULL,
/* 065 */ 1, NULL,
/* 066 */ 1, NULL,
/* 067 */ 1, NULL,
/* 070 */ 1, NULL,
/* 071 */ 1, NULL,
/* 072 */ 1, NULL,
/* 073 */ 1, NULL,
/* 074 */ 1, NULL,
/* 075 */ 1, NULL,
/* 076 */ 1, NULL,
/* 077 */ 1, NULL,
/* 100 */ 1, NULL,
/* 101 */ 1, NULL,
/* 102 */ 1, NULL,
/* 103 */ 1, NULL,
/* 104 */ 1, NULL,
/* 105 */ 1, NULL,
/* 106 */ 1, NULL,
/* 107 */ 1, NULL,
/* 110 */ 1, NULL,
/* 111 */ 1, NULL,
/* 112 */ 1, NULL,
/* 113 */ 1, NULL,
/* 114 */ 1, NULL,
/* 115 */ 1, NULL,
/* 116 */ 1, NULL,
/* 117 */ 1, NULL,
/* 120 */ 1, NULL,
/* 121 */ 1, NULL,
/* 122 */ 1, NULL,
/* 123 */ 1, NULL,
/* 124 */ 1, NULL,
/* 125 */ 1, NULL,
/* 126 */ 1, NULL,
/* 127 */ 1, NULL,
/* 130 */ 1, NULL,
/* 131 */ 1, NULL,
/* 132 */ 1, NULL,
/* 133 */ 1, NULL,
/* 134 */ 1, NULL,
/* 135 */ 1, NULL,
/* 136 */ 1, NULL,
/* 137 */ 1, NULL,
/* 140 */ 1, NULL,
/* 141 */ 1, NULL,
/* 142 */ 1, NULL,
/* 143 */ 1, NULL,
/* 144 */ 1, NULL,
/* 145 */ 1, NULL,
/* 146 */ 1, NULL,
/* 147 */ 1, NULL,
/* 150 */ 1, NULL,
/* 151 */ 1, NULL,
/* 152 */ 1, NULL,
/* 153 */ 1, NULL,
/* 154 */ 1, NULL,
/* 155 */ 1, NULL,
/* 156 */ 1, NULL,
/* 157 */ 1, NULL,
/* 160 */ 1, NULL,
/* 161 */ 1, NULL,
/* 162 */ 1, NULL,
/* 163 */ 1, NULL,
/* 164 */ 1, NULL,
/* 165 */ 1, NULL,
/* 166 */ 1, NULL,
/* 167 */ 1, NULL,
/* 170 */ 1, NULL,
/* 171 */ 1, NULL,
/* 172 */ 1, NULL,
/* 173 */ 1, NULL,
/* 174 */ 1, NULL,
/* 175 */ 1, NULL,
/* 176 */ 1, NULL,
/* 177 */ 5, "[xxx]",
/* 200 */ 5, "[xxx]",
/* 201 */ 5, "[xxx]",
/* 202 */ 5, "[xxx]",
/* 203 */ 5, "[xxx]",
/* 204 */ 5, "[xxx]",
/* 205 */ 5, "[xxx]",
/* 206 */ 5, "[xxx]",
/* 207 */ 5, "[xxx]",
/* 210 */ 5, "[xxx]",
/* 211 */ 5, "[xxx]",
/* 212 */ 5, "[xxx]",
/* 213 */ 5, "[xxx]",
/* 214 */ 5, "[xxx]",
/* 215 */ 5, "[xxx]",
/* 216 */ 5, "[xxx]",
/* 217 */ 5, "[xxx]",
/* 220 */ 5, "[xxx]",
/* 221 */ 5, "[xxx]",
/* 222 */ 5, "[xxx]",
/* 223 */ 5, "[xxx]",
/* 224 */ 5, "[xxx]",
/* 225 */ 5, "[xxx]",
/* 226 */ 5, "[xxx]",
/* 227 */ 5, "[xxx]",
/* 230 */ 5, "[xxx]",
/* 231 */ 5, "[xxx]",
/* 232 */ 5, "[xxx]",
/* 233 */ 5, "[xxx]",
/* 234 */ 5, "[xxx]",
/* 235 */ 5, "[xxx]",
/* 236 */ 5, "[xxx]",
/* 237 */ 5, "[xxx]",
/* 240 */ 5, "[xxx]",
/* 241 */ 5, "[xxx]",
/* 242 */ 5, "[xxx]",
/* 243 */ 5, "[xxx]",
/* 244 */ 5, "[xxx]",
/* 245 */ 5, "[xxx]",
/* 246 */ 5, "[xxx]",
/* 247 */ 5, "[xxx]",
/* 250 */ 5, "[xxx]",
/* 251 */ 5, "[xxx]",
/* 252 */ 5, "[xxx]",
/* 253 */ 5, "[xxx]",
/* 254 */ 5, "[xxx]",
/* 255 */ 5, "[xxx]",
/* 256 */ 5, "[xxx]",
/* 257 */ 5, "[xxx]",
/* 260 */ 5, "[xxx]",
/* 261 */ 5, "[xxx]",
/* 262 */ 5, "[xxx]",
/* 263 */ 5, "[xxx]",
/* 264 */ 5, "[xxx]",
/* 265 */ 5, "[xxx]",
/* 266 */ 5, "[xxx]",
/* 267 */ 5, "[xxx]",
/* 270 */ 5, "[xxx]",
/* 271 */ 5, "[xxx]",
/* 272 */ 5, "[xxx]",
/* 273 */ 5, "[xxx]",
/* 274 */ 5, "[xxx]",
/* 275 */ 5, "[xxx]",
/* 276 */ 5, "[xxx]",
/* 277 */ 5, "[xxx]",
/* 300 */ 5, "[xxx]",
/* 301 */ 5, "[xxx]",
/* 302 */ 5, "[xxx]",
/* 303 */ 5, "[xxx]",
/* 304 */ 5, "[xxx]",
/* 305 */ 5, "[xxx]",
/* 306 */ 5, "[xxx]",
/* 307 */ 5, "[xxx]",
/* 310 */ 5, "[xxx]",
/* 311 */ 5, "[xxx]",
/* 312 */ 5, "[xxx]",
/* 313 */ 5, "[xxx]",
/* 314 */ 5, "[xxx]",
/* 315 */ 5, "[xxx]",
/* 316 */ 5, "[xxx]",
/* 317 */ 5, "[xxx]",
/* 320 */ 5, "[xxx]",
/* 321 */ 5, "[xxx]",
/* 322 */ 5, "[xxx]",
/* 323 */ 5, "[xxx]",
/* 324 */ 5, "[xxx]",
/* 325 */ 5, "[xxx]",
/* 326 */ 5, "[xxx]",
/* 327 */ 5, "[xxx]",
/* 330 */ 5, "[xxx]",
/* 331 */ 5, "[xxx]",
/* 332 */ 5, "[xxx]",
/* 333 */ 5, "[xxx]",
/* 334 */ 5, "[xxx]",
/* 335 */ 5, "[xxx]",
/* 336 */ 5, "[xxx]",
/* 337 */ 5, "[xxx]",
/* 340 */ 5, "[xxx]",
/* 341 */ 5, "[xxx]",
/* 342 */ 5, "[xxx]",
/* 343 */ 5, "[xxx]",
/* 344 */ 5, "[xxx]",
/* 345 */ 5, "[xxx]",
/* 346 */ 5, "[xxx]",
/* 347 */ 5, "[xxx]",
/* 350 */ 5, "[xxx]",
/* 351 */ 5, "[xxx]",
/* 352 */ 5, "[xxx]",
/* 353 */ 5, "[xxx]",
/* 354 */ 5, "[xxx]",
/* 355 */ 5, "[xxx]",
/* 356 */ 5, "[xxx]",
/* 357 */ 5, "[xxx]",
/* 360 */ 5, "[xxx]",
/* 361 */ 5, "[xxx]",
/* 362 */ 5, "[xxx]",
/* 363 */ 5, "[xxx]",
/* 364 */ 5, "[xxx]",
/* 365 */ 5, "[xxx]",
/* 366 */ 5, "[xxx]",
/* 367 */ 5, "[xxx]",
/* 370 */ 5, "[xxx]",
/* 371 */ 5, "[xxx]",
/* 372 */ 5, "[xxx]",
/* 373 */ 5, "[xxx]",
/* 374 */ 5, "[xxx]",
/* 375 */ 5, "[xxx]",
/* 376 */ 5, "[xxx]",
/* 377 */ 5, "[xxx]",
};

/*
* octchars()
*
* Convert the charinfo strings to octal.
*/
octchars()
{
char *p;
int n;

for ( n=0; n<256; n++ ) {
p = chars[n].ch_str;
if ( p==NULL || *p != '[' )
continue;
sprintf(++p,"%03o]",n);
}
}

/*
* hexchars()
*
* Convert the charinfo strings to hex.
*/
hexchars()
{
char *p;
int n;

for ( n=0; n<256; n++ ) {
p = chars[n].ch_str;
if ( p==NULL || *p != '[' )
continue;
sprintf(++p,"x%02X]",n);
}
}

/*
* decchars()
*
* Convert the charinfo strings to decimal.
*/
decchars()
{
char *p;
int n;

for ( n=0; n<256; n++ ) {
p = chars[n].ch_str;
if ( p==NULL || *p != '[' )
continue;
sprintf(++p,"%3d]",n);
}
}

hextoint(c)
int c;
{
if ( c>='0' && c<='9' )
return(c-'0');
if ( c>='a' && c<='f' )
return(10+c-'a');
if ( c>='A' && c<='F' )
return(10+c-'A');
return(-1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'linefunc.c'
then
echo shar: will not over-write existing file "'linefunc.c'"
else
cat << \SHAR_EOF > 'linefunc.c'
/*
* STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt...
*/

#include <stdio.h>
#include "stevie.h"

/*
* nextline(curr)
*
* Return a pointer to the beginning of the next line after the
* 'curr' char. Return NULL if there is no next line.
*/

char *
nextline(curr)
char *curr;
{
while ( curr<Fileend ) {
if ( *curr++ == '\n' )
break;
}
if ( curr >= Fileend )
return(NULL);
return(curr);
}

/*
* prevline(curr)
*
* Return a pointer to the beginning of the previous line before the
* 'curr' char. Return NULL if there is no previous line.
*/

char *
prevline(curr)
char *curr;
{
int nnl = 0;

/* If we are currently positioned on a '\n', */
/* we are on a blank line. Adjust accordingly. */
if ( *curr == '\n' )
nnl = -1;
while ( curr>Filemem ) {
/* look for the 2nd previous newline */
if ( *curr == '\n' ) {
nnl++;
if ( nnl == 2)
break;
}
curr--;
}
if ( curr <= Filemem ) {
/* If we found 1 newline, we found the first line */
if ( nnl == 1 )
return(Filemem);
else
return(NULL);
}
/* return the first char of the previous line */
return(++curr);
}

/*
* coladvance(p,col)
*
* Try to advance to the specified column, starting at p.
*/

char *
coladvance(p,col)
char *p;
int col;
{
int c, inc;

/* If we're on a blank ('\n' only) line, we can't do anything */
if ( *p == '\n' )
return(p);
/* try to advance to the specified column */
for ( c=0; col-- > 0; c++ ) {
/* Count a tab for what it's worth */
if ( *p == '\t' ) {
inc = (7 - c%8);
col -= inc;
c += inc;
}
p++;
/* Don't go past the end of */
/* the file or the line. */
if ( p==Fileend || *p=='\n' ) {
p--;
break;
}
}
return(p);
}
char *strcpy(), *malloc();

#define NULL 0

char *
alloc(size)
unsigned size;
{
char *p; /* pointer to new storage space */

p = malloc(size);
if ( p == (char *)NULL ) { /* if there is no more room... */
message("alloc() is unable to find memory!");
}
return(p);
}

char *
strsave(string)
char *string;
{
return(strcpy(alloc((unsigned)(strlen(string)+1)),string));
}

#define NULL 0

static char *laststr = NULL;
static int lastdir;

char *
ssearch(dir,str)
int dir; /* FORWARD or BACKWARD */
char *str;
{
if ( laststr != NULL )
free(laststr);
laststr = strsave(str);
lastdir = dir;
if ( dir == BACKWARD )
return(bcksearch(str));
else
return(fwdsearch(str));
}

dosearch(dir,str)
int dir;
char *str;
{
char *p;

if ( (p=ssearch(dir,str)) == NULL )
message("Pattern not found");
else {
char *savep;

cursupdate();
/* if we're backing up, we make sure the line we're on */
/* is on the screen. */
Curschar = savep = p;
/* get to the beginning of the line */
beginline();
if ( Curschar < Topchar )
Topchar = Curschar;
Curschar = savep;
cursupdate();
updatescreen();
}
}


repsearch()
{
if ( laststr == NULL )
beep();
else {
dosearch(lastdir,laststr);
}
}

char *
fwdsearch(str)
char *str;
{
register char *sofar = str;
register char *infile = Curschar+1;
int leng = strlen(str);
char *stopit;

/* search forward to the end of the file */
for ( ; infile < Fileend && *sofar != '\0' ; infile++ ) {
if ( *infile == *sofar )
sofar++;
else
sofar = str;
}
if ( *sofar == '\0' )
return(infile-strlen(str));
/* search from the beginning of the file to Curschar */
infile = Filemem;
sofar = str;
stopit = Curschar + leng;
for ( ; infile <= stopit && *sofar != '\0' ; infile++ ) {
if ( *infile == *sofar )
sofar++;
else
sofar = str;
}
if ( *sofar == '\0' )
return(infile-leng);
else
return(NULL);
}

char *
bcksearch(str)
char *str;
{
int leng = strlen(str);
char *infile = Curschar+1;
char *endofstr, *sofar, *stopit;

/* make sure str isn't empty before getting pointer to */
/* its last character. */
if ( leng == 0 )
return(NULL);
endofstr = &str[leng-1];
sofar = endofstr;
/* search backward to the beginning of the file */
for ( ; infile >= Filemem && sofar >= str ; infile-- ) {
if ( *infile == *sofar )
sofar--;
else
sofar = endofstr;
}
if ( sofar < str )
return(++infile);

/* search backward from the end of the file */
sofar = endofstr;
infile = Fileend-1;
stopit = Curschar - leng;
for ( ; infile >= stopit && sofar >= str ; infile-- ) {
if ( *infile == *sofar )
sofar--;
else
sofar = endofstr;
}
if ( sofar < str )
return(++infile);
else
return(NULL);
}
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0

0 new messages