# 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: 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 ( to exit) a Append ( to exit) \n\ o Open line ( 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 #include #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 'edit.c' /* * STevie - ST editor for VI enthusiasts. ...Tim Thompson...twitch!tjt... */ #include #include #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= 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= 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 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 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 #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\ \n\ "); 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 ( to exit)\n"); longline("\ a Append ( to exit) \n\ o Open line ( to exit)\n\ \n\ \n\ "); 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\ "); 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 #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 #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 ) 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