page@swan.ulowell.edu (Bob Page) (03/15/89)
Submitted-by: grwalter@watcgl.waterloo.edu (Fred Walter) Posting-number: Volume 89, Issue 42 Archive-name: editors/stevie35a.3 # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # charset.c # edit.c # help.c # main.c # misccmds.c # screen.c # This archive created: Tue Mar 14 14:41:34 1989 cat << \SHAR_EOF > charset.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" /* * This file shows how to display characters on the screen. This is approach * is something of an overkill. It's a remnant from the original code that * isn't worth messing with for now. TABS are special-cased depending on the * value of the "list" parameter. */ struct charinfo chars[] = { /* 0 */ 1, NUL, /* 1 */ 2, "^A", /* 2 */ 2, "^B", /* 3 */ 2, "^C", /* 4 */ 2, "^D", /* 5 */ 2, "^E", /* 6 */ 2, "^F", /* 7 */ 2, "^G", /* 8 */ 2, "^H", /* 9 */ 2, "^I", /* 10 */ 7, "[ERROR]", /* shouldn't happen */ /* 11 */ 2, "^K", /* 12 */ 2, "^L", /* 13 */ 2, "^M", /* 14 */ 2, "^N", /* 15 */ 2, "^O", /* 16 */ 2, "^P", /* 17 */ 2, "^Q", /* 18 */ 2, "^R", /* 19 */ 2, "^S", /* 20 */ 2, "^T", /* 21 */ 2, "^U", /* 22 */ 2, "^V", /* 23 */ 2, "^W", /* 24 */ 2, "^X", /* 25 */ 2, "^Y", /* 26 */ 2, "^Z", /* 27 */ 2, "^[", /* 28 */ 2, "^\\", /* 29 */ 2, "^]", /* 30 */ 2, "^^", /* 31 */ 2, "^_", /* 32 */ 1, " ", /* 33 */ 1, "!", /* 34 */ 1, "\"", /* 35 */ 1, "#", /* 36 */ 1, "$", /* 37 */ 1, "%", /* 38 */ 1, "&", /* 39 */ 1, "'", /* 40 */ 1, "(", /* 41 */ 1, ")", /* 42 */ 1, "*", /* 43 */ 1, "+", /* 44 */ 1, ",", /* 45 */ 1, "-", /* 46 */ 1, ".", /* 47 */ 1, "/", /* 48 */ 1, "0", /* 49 */ 1, "1", /* 50 */ 1, "2", /* 51 */ 1, "3", /* 52 */ 1, "4", /* 53 */ 1, "5", /* 54 */ 1, "6", /* 55 */ 1, "7", /* 56 */ 1, "8", /* 57 */ 1, "9", /* 58 */ 1, ":", /* 59 */ 1, ";", /* 60 */ 1, "<", /* 61 */ 1, "=", /* 62 */ 1, ">", /* 63 */ 1, "?", /* 64 */ 1, "@", /* 65 */ 1, "A", /* 66 */ 1, "B", /* 67 */ 1, "C", /* 68 */ 1, "D", /* 69 */ 1, "E", /* 70 */ 1, "F", /* 71 */ 1, "G", /* 72 */ 1, "H", /* 73 */ 1, "I", /* 74 */ 1, "J", /* 75 */ 1, "K", /* 76 */ 1, "L", /* 77 */ 1, "M", /* 78 */ 1, "N", /* 79 */ 1, "O", /* 80 */ 1, "P", /* 81 */ 1, "Q", /* 82 */ 1, "R", /* 83 */ 1, "S", /* 84 */ 1, "T", /* 85 */ 1, "U", /* 86 */ 1, "V", /* 87 */ 1, "W", /* 88 */ 1, "X", /* 89 */ 1, "Y", /* 90 */ 1, "Z", /* 91 */ 1, "[", /* 92 */ 1, "\\", /* 93 */ 1, "]", /* 94 */ 1, "^", /* 95 */ 1, "_", /* 96 */ 1, "`", /* 97 */ 1, "a", /* 98 */ 1, "b", /* 99 */ 1, "c", /* 100 */ 1, "d", /* 101 */ 1, "e", /* 102 */ 1, "f", /* 103 */ 1, "g", /* 104 */ 1, "h", /* 105 */ 1, "i", /* 106 */ 1, "j", /* 107 */ 1, "k", /* 108 */ 1, "l", /* 109 */ 1, "m", /* 110 */ 1, "n", /* 111 */ 1, "o", /* 112 */ 1, "p", /* 113 */ 1, "q", /* 114 */ 1, "r", /* 115 */ 1, "s", /* 116 */ 1, "t", /* 117 */ 1, "u", /* 118 */ 1, "v", /* 119 */ 1, "w", /* 120 */ 1, "x", /* 121 */ 1, "y", /* 122 */ 1, "z", /* 123 */ 1, "{", /* 124 */ 1, "|", /* 125 */ 1, "}", /* 126 */ 1, "~", /* 127 */ 2, "^?", /* 128 */ 5, "[128]", /* 129 */ 5, "[129]", /* 130 */ 5, "[130]", /* 131 */ 5, "[131]", /* 132 */ 5, "[132]", /* 133 */ 5, "[133]", /* 134 */ 5, "[134]", /* 135 */ 5, "[135]", /* 136 */ 5, "[136]", /* 137 */ 5, "[137]", /* 138 */ 5, "[138]", /* 139 */ 5, "[139]", /* 140 */ 5, "[140]", /* 141 */ 5, "[141]", /* 142 */ 5, "[142]", /* 143 */ 5, "[143]", /* 144 */ 5, "[144]", /* 145 */ 5, "[145]", /* 146 */ 5, "[146]", /* 147 */ 5, "[147]", /* 148 */ 5, "[148]", /* 149 */ 5, "[149]", /* 150 */ 5, "[150]", /* 151 */ 5, "[151]", /* 152 */ 5, "[152]", /* 153 */ 5, "[153]", /* 154 */ 5, "[154]", /* 155 */ 5, "[155]", /* 156 */ 5, "[156]", /* 157 */ 5, "[157]", /* 158 */ 5, "[158]", /* 159 */ 5, "[159]", #ifdef AMIGA /* 160 */ 1, "\240", /* 161 */ 1, "\241", /* 162 */ 1, "\242", /* 163 */ 1, "\243", /* 164 */ 1, "\244", /* 165 */ 1, "\245", /* 166 */ 1, "\246", /* 167 */ 1, "\247", /* 168 */ 1, "\250", /* 169 */ 1, "\251", /* 170 */ 1, "\252", /* 171 */ 1, "\253", /* 172 */ 1, "\254", /* 173 */ 1, "\255", /* 174 */ 1, "\256", /* 175 */ 1, "\257", /* 176 */ 1, "\260", /* 177 */ 1, "\261", /* 178 */ 1, "\262", /* 179 */ 1, "\263", /* 180 */ 1, "\264", /* 181 */ 1, "\265", /* 182 */ 1, "\266", /* 183 */ 1, "\267", /* 184 */ 1, "\270", /* 185 */ 1, "\271", /* 186 */ 1, "\272", /* 187 */ 1, "\273", /* 188 */ 1, "\274", /* 189 */ 1, "\275", /* 190 */ 1, "\276", /* 191 */ 1, "\277", /* 192 */ 1, "\300", /* 193 */ 1, "\301", /* 194 */ 1, "\302", /* 195 */ 1, "\303", /* 196 */ 1, "\304", /* 197 */ 1, "\305", /* 198 */ 1, "\306", /* 199 */ 1, "\307", /* 200 */ 1, "\310", /* 201 */ 1, "\311", /* 202 */ 1, "\312", /* 203 */ 1, "\313", /* 204 */ 1, "\314", /* 205 */ 1, "\315", /* 206 */ 1, "\316", /* 207 */ 1, "\317", /* 208 */ 1, "\320", /* 209 */ 1, "\321", /* 210 */ 1, "\322", /* 211 */ 1, "\323", /* 212 */ 1, "\324", /* 213 */ 1, "\325", /* 214 */ 1, "\326", /* 215 */ 1, "\327", /* 216 */ 1, "\330", /* 217 */ 1, "\331", /* 218 */ 1, "\332", /* 219 */ 1, "\333", /* 220 */ 1, "\334", /* 221 */ 1, "\335", /* 222 */ 1, "\336", /* 223 */ 1, "\337", /* 224 */ 1, "\340", /* 225 */ 1, "\341", /* 226 */ 1, "\342", /* 227 */ 1, "\343", /* 228 */ 1, "\344", /* 229 */ 1, "\345", /* 230 */ 1, "\346", /* 231 */ 1, "\347", /* 232 */ 1, "\350", /* 233 */ 1, "\351", /* 234 */ 1, "\352", /* 235 */ 1, "\353", /* 236 */ 1, "\354", /* 237 */ 1, "\355", /* 238 */ 1, "\356", /* 239 */ 1, "\357", /* 240 */ 1, "\360", /* 241 */ 1, "\361", /* 242 */ 1, "\362", /* 243 */ 1, "\363", /* 244 */ 1, "\364", /* 245 */ 1, "\365", /* 246 */ 1, "\366", /* 247 */ 1, "\367", /* 248 */ 1, "\370", /* 249 */ 1, "\371", /* 250 */ 1, "\372", /* 251 */ 1, "\373", /* 252 */ 1, "\374", /* 253 */ 1, "\375", /* 254 */ 1, "\376", /* 255 */ 1, "\377" #else /* 160 */ 5, "[160]", /* 161 */ 5, "[161]", /* 162 */ 5, "[162]", /* 163 */ 5, "[163]", /* 164 */ 5, "[164]", /* 165 */ 5, "[165]", /* 166 */ 5, "[166]", /* 167 */ 5, "[167]", /* 168 */ 5, "[168]", /* 169 */ 5, "[169]", /* 170 */ 5, "[170]", /* 171 */ 5, "[171]", /* 172 */ 5, "[172]", /* 173 */ 5, "[173]", /* 174 */ 5, "[174]", /* 175 */ 5, "[175]", /* 176 */ 5, "[176]", /* 177 */ 5, "[177]", /* 178 */ 5, "[178]", /* 179 */ 5, "[179]", /* 180 */ 5, "[180]", /* 181 */ 5, "[181]", /* 182 */ 5, "[182]", /* 183 */ 5, "[183]", /* 184 */ 5, "[184]", /* 185 */ 5, "[185]", /* 186 */ 5, "[186]", /* 187 */ 5, "[187]", /* 188 */ 5, "[188]", /* 189 */ 5, "[189]", /* 190 */ 5, "[190]", /* 191 */ 5, "[191]", /* 192 */ 5, "[192]", /* 193 */ 5, "[193]", /* 194 */ 5, "[194]", /* 195 */ 5, "[195]", /* 196 */ 5, "[196]", /* 197 */ 5, "[197]", /* 198 */ 5, "[198]", /* 199 */ 5, "[199]", /* 200 */ 5, "[200]", /* 201 */ 5, "[201]", /* 202 */ 5, "[202]", /* 203 */ 5, "[203]", /* 204 */ 5, "[204]", /* 205 */ 5, "[205]", /* 206 */ 5, "[206]", /* 207 */ 5, "[207]", /* 208 */ 5, "[208]", /* 209 */ 5, "[209]", /* 210 */ 5, "[210]", /* 211 */ 5, "[211]", /* 212 */ 5, "[212]", /* 213 */ 5, "[213]", /* 214 */ 5, "[214]", /* 215 */ 5, "[215]", /* 216 */ 5, "[216]", /* 217 */ 5, "[217]", /* 218 */ 5, "[218]", /* 219 */ 5, "[219]", /* 220 */ 5, "[220]", /* 221 */ 5, "[221]", /* 222 */ 5, "[222]", /* 223 */ 5, "[223]", /* 224 */ 5, "[224]", /* 225 */ 5, "[225]", /* 226 */ 5, "[226]", /* 227 */ 5, "[227]", /* 228 */ 5, "[228]", /* 229 */ 5, "[229]", /* 230 */ 5, "[230]", /* 231 */ 5, "[231]", /* 232 */ 5, "[232]", /* 233 */ 5, "[233]", /* 234 */ 5, "[234]", /* 235 */ 5, "[235]", /* 236 */ 5, "[236]", /* 237 */ 5, "[237]", /* 238 */ 5, "[238]", /* 239 */ 5, "[239]", /* 240 */ 5, "[240]", /* 241 */ 5, "[241]", /* 242 */ 5, "[242]", /* 243 */ 5, "[243]", /* 244 */ 5, "[244]", /* 245 */ 5, "[245]", /* 246 */ 5, "[246]", /* 247 */ 5, "[247]", /* 248 */ 5, "[248]", /* 249 */ 5, "[249]", /* 250 */ 5, "[250]", /* 251 */ 5, "[251]", /* 252 */ 5, "[252]", /* 253 */ 5, "[253]", /* 254 */ 5, "[254]", /* 255 */ 5, "[255]" #endif }; SHAR_EOF cat << \SHAR_EOF > edit.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" /* * This flag is used to make auto-indent work right on lines where only a * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and * reset when any other editting is done on the line. If an <ESC> or <RETURN> * is received, and did_ai is TRUE, the line is truncated. */ bool_t did_ai = FALSE; void edit() { char c; bool_t literal_next_flag = FALSE; Prenum = 0; /* position the display and the cursor at the top of the file. */ *Topchar = *Filemem; *Curschar = *Filemem; Cursrow = Curscol = 0; for (;;) { if (!RedrawingDisabled) { cursupdate(); /* Figure out where the cursor is based on * Curschar. */ if (MustRedrawLine) redrawline(); if (MustRedrawScreen) updateRealscreen(); windgoto(Cursrow, Curscol); } c = vgetc(); if (State == 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'); continue; } /* execute the command */ normal(c); Prenum = 0; } else { if (c == CTRL('V') && !literal_next_flag) { literal_next_flag = TRUE; outchar('^'); continue; } if (literal_next_flag) { literal_next_flag = FALSE; outchar('\b'); if (c != NL) { did_ai = FALSE; insertchar(c); continue; } } switch (c) { /* We're in insert mode */ case ESC: /* an escape ends input mode */ doESCkey: /* * If we just did an auto-indent, truncate the line, and put * the cursor back. */ if (did_ai) { Curschar->linep->s[0] = NUL; Curschar->index = 0; did_ai = FALSE; } set_want_col = TRUE; /* * The cursor should end up on the last inserted character. * This is an attempt to match the real 'vi', but it may not * be quite right yet. */ if (Curschar->index != 0) { if (gchar(Curschar) == NUL) dec(Curschar); else if (Insbuffptr != NULL) dec(Curschar); } State = NORMAL; msg(""); if (RedrawingDisabled) { updateNextscreen(NOT_VALID); /* Update LineSizes. */ cursupdate(); /* Update Topchar and Botchar. */ } if (!UndoInProgress) { int n; char *p; if (last_command == 'o') AppendToUndobuff(UNDO_SHIFTJ_STR); if (Insbuffptr != NULL) { if (last_command == 'O') AppendToUndobuff("0"); AppendToRedobuff(Insbuff); AppendToUndoUndobuff(Insbuff); n = 0; for (p = Insbuff; *p != NUL; p++) { if (*p == NL) { if (n) { AppendNumberToUndobuff(n); AppendToUndobuff("dl"); n = 0; } AppendToUndobuff(UNDO_SHIFTJ_STR); } else n++; } if (n) { AppendNumberToUndobuff(n); AppendToUndobuff("dl"); } } if (last_command == 'c') { AppendToUndobuff(mkstr(last_command_char)); AppendToUndobuff(Yankbuff); AppendToUndobuff(ESC_STR); } AppendToRedobuff(ESC_STR); AppendToUndoUndobuff(ESC_STR); if (last_command == 'O') AppendToUndobuff(UNDO_SHIFTJ_STR); } break; case CTRL('D'): /* * Control-D is treated as a backspace in insert mode to make * auto-indent easier. This isn't completely compatible with * vi, but it's a lot easier than doing it exactly right, and * the difference isn't very noticeable. */ case BS: /* can't backup past starting point */ if (Curschar->linep == Insstart->linep && Curschar->index <= Insstart->index) { beep(); break; } /* can't backup to a previous line */ if (Curschar->linep != Insstart->linep && Curschar->index <= 0) { beep(); break; } did_ai = FALSE; dec(Curschar); delchar(TRUE, FALSE); /* * It's a little strange to put backspaces into the redo * buffer, but it makes auto-indent a lot easier to deal * with. */ AppendToInsbuff(BS_STR); if (!RedrawingDisabled) { cursupdate(); updateline(); } break; case CR: case NL: AppendToInsbuff(NL_STR); if (!OpenForward(!RedrawingDisabled)) goto doESCkey; /* out of memory */ if (!RedrawingDisabled) windgoto(Cursrow, Curscol); break; default: did_ai = FALSE; insertchar(c); break; } } } } /* * Special characters in this context are those that need processing other * than the simple insertion that can be performed here. This includes ESC * which terminates the insert, and CR/NL which need special processing to * open up a new line. This routine tries to optimize insertions performed by * the "redo", "undo" or "put" commands, so it needs to know when it should * stop and defer processing to the "normal" mechanism. */ #define ISSPECIAL(c) ((c) == BS || (c) == NL || (c) == CR || (c) == ESC) void insertchar(c) char c; { if (anyinput()) { /* If there's any pending input, grab up to * MAX_COLUMNS at once. */ char p[MAX_COLUMNS + 1]; int i; p[0] = c; i = 1; c = vpeekc(); while (!ISSPECIAL(c) && anyinput() && (i < MAX_COLUMNS)) { p[i++] = vgetc(); c = vpeekc(); } p[i] = '\0'; insstr(p); AppendToInsbuff(p); } else { inschar(c); AppendToInsbuff(mkstr(c)); } if (!RedrawingDisabled) updateline(); } void getout(r) int r; { windgoto(Rows - 1, 0); putchar('\r'); putchar('\n'); windexit(r); } void scrolldown(nlines) int nlines; { register LPtr *p; register int done = 0; /* total # of physical lines done */ /* Scroll up 'nlines' lines. */ while (nlines--) { if ((p = prevline(Topchar)) == NULL) break; done += plines(p); *Topchar = *p; if (Curschar->linep == Botchar->linep->prev) *Curschar = *prevline(Curschar); } s_ins(0, done, Rows, Columns); } void scrollup(nlines) int nlines; { register LPtr *p; register int done = 0; /* total # of physical lines done */ register int pl; /* # of plines for the current line */ /* Scroll down 'nlines' lines. */ while (nlines--) { pl = plines(Topchar); if ((p = nextline(Topchar)) == NULL) break; done += pl; if (Curschar->linep == Topchar->linep) *Curschar = *p; *Topchar = *p; } s_del(0, done, Rows, Columns); } /* * oneright oneleft onedown oneup * * Move one char {right,left,down,up}. Return TRUE when sucessful, FALSE when * we hit a boundary (of a line, or the file). */ bool_t oneright() { set_want_col = TRUE; switch (inc(Curschar)) { case 0: return TRUE; case 1: dec(Curschar); /* crossed a line, so back up */ /* FALLTHROUGH */ case -1: return FALSE; } return FALSE; /* PARANOIA: should never reach here */ } bool_t oneleft() { set_want_col = TRUE; switch (dec(Curschar)) { case 0: return TRUE; case 1: inc(Curschar); /* crossed a line, so back up */ /* FALLTHROUGH */ case -1: return FALSE; } return FALSE; /* PARANOIA: should never reach here */ } void beginline(flag) bool_t flag; { while (oneleft()); if (flag) { while (isspace(gchar(Curschar)) && oneright()); } set_want_col = TRUE; } bool_t oneup(n) { LPtr p, *np; int k; 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 FALSE; } p = *np; } *Curschar = p; cursupdate(); /* make sure Topchar is valid */ /* try to advance to the column we want to be at */ *Curschar = *coladvance(&p, Curswant); return TRUE; } bool_t onedown(n) { LPtr 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 FALSE; } p = *np; } cursupdate(); /* make sure Topchar is valid */ /* try to advance to the column we want to be at */ *Curschar = *coladvance(&p, Curswant); return TRUE; } SHAR_EOF cat << \SHAR_EOF > help.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" extern char *Version; static int helprow; #ifdef HELP #ifdef MEGAMAX overlay "help" #endif static void longline(); bool_t help() { outstr(T_ED); windgoto(helprow = 0, 0); longline("\ Positioning within file\n\ =======================\n\ ^F Forward screenfull Worked on by:\n\ ^B Backward screenfull Tim Thompson\n"); longline("\ ^D scroll down half screen Tony Andrews\n\ ^U scroll up half screen G.R. (Fred) Walter\n"); longline("\ G Goto line (end default)\n\ ]] next function\n\ [[ previous function\n\ /re next occurence of regular expression 're'\n"); longline("\ ?re prior occurence of regular expression 're'\n\ n repeat last / or ?\n\ N reverse last / or ?\n\ % find matching (, ), {, }, [, or ]\n"); longline("\ \n\ Adjusting the screen\n\ ====================\n\ ^L Redraw the screen\n\ ^E scroll window down 1 line\n\ ^Y scroll window up 1 line\n"); longline("\ z<RETURN> redraw, current line at top\n\ z- ... at bottom\n\ z. ... at center\n"); windgoto(0, 32); longline(Version); #ifdef AMIGA longline(" "); longline(__DATE__); longline(" "); longline(__TIME__); #endif windgoto(helprow = Rows - 2, 47); longline("<Press space bar to continue>\n"); windgoto(helprow = Rows - 1, 47); longline("<Any other key will quit>"); if (vgetc() != ' ') return TRUE; outstr(T_ED); windgoto(helprow = 0, 0); longline("\ Character Positioning\n\ =====================\n\ ^ first non-white\n\ 0 beginning of line\n\ $ end of line\n\ h backward\n"); longline("\ l forward\n\ ^H same as h\n\ space same as l\n\ fx find 'x' forward\n"); longline("\ Fx find 'x' backward\n\ tx upto 'x' forward\n\ Tx upto 'x' backward\n\ ; Repeat last f, F, t, or T\n"); longline("\ , inverse of ;\n\ | to specified column\n\ % find matching (, ), {, }, [, or ]\n"); windgoto(helprow = Rows - 2, 47); longline("<Press space bar to continue>\n"); windgoto(helprow = Rows - 1, 47); longline("<Any other key will quit>"); if (vgetc() != ' ') return TRUE; outstr(T_ED); windgoto(helprow = 0, 0); longline("\ Line Positioning\n\ =====================\n\ H home window line\n\ L last window line\n\ M middle window line\n"); longline("\ + next line, at first non-white\n\ - previous line, at first non-white\n\ CR return, same as +\n\ j next line, same column\n\ k previous line, same column\n"); longline("\ \n\ Marking and Returning\n\ =====================\n\ `` previous context\n\ '' ... at first non-white in line\n"); longline("\ mx mark position with letter 'x'\n\ `x to mark 'x'\n\ 'x ... at first non-white in line\n"); windgoto(helprow = Rows - 2, 47); longline("<Press space bar to continue>\n"); windgoto(helprow = Rows - 1, 47); longline("<Any other key will quit>"); if (vgetc() != ' ') return TRUE; outstr(T_ED); windgoto(helprow = 0, 0); longline("\ Insert and Replace\n\ ==================\n\ a append after cursor\n\ i insert before cursor\n\ A append at end of line\n\ I insert before first non-blank\n"); longline("\ o open line below\n\ O open line above\n\ rx replace single char with 'x'\n\ R replace characters (not yet)\n\ ~ replace character under cursor with other case\n"); longline("\ \n\ Words, sentences, paragraphs\n\ ============================\n\ w word forward\n\ b back word\n\ e end of word\n\ ) to next sentence (not yet)\n\ } to next paragraph (not yet)\n"); longline("\ ( back sentence (not yet)\n\ { back paragraph (not yet)\n\ W blank delimited word\n\ B back W\n\ E to end of W"); windgoto(helprow = Rows - 2, 47); longline("<Press space bar to continue>\n"); windgoto(helprow = Rows - 1, 47); longline("<Any other key will quit>"); if (vgetc() != ' ') return TRUE; outstr(T_ED); windgoto(helprow = 0, 0); longline("\ Undo & Redo\n\ =============\n\ u undo last change\n\ U restore current line (not yet)\n\ . repeat last change\n"); longline("\ \n\ File manipulation\n\ =================\n"); longline("\ :w write back changes\n\ :wq write and quit\n\ :x write if modified, and quit\n\ :q quit\n\ :q! quit, discard changes\n\ :e name edit file 'name'\n"); longline("\ :e! reedit, discard changes\n\ :e # edit alternate file\n\ :w name write file 'name'\n"); longline("\ :n edit next file in arglist\n\ :n args specify new arglist (not yet)\n\ :rew rewind arglist\n\ :f show current file and lines\n"); longline("\ :f file change current file name\n\ :ta tag to tag file entry 'tag'\n\ ^] :ta, current word is tag"); windgoto(helprow = Rows - 2, 47); longline("<Press space bar to continue>\n"); windgoto(helprow = Rows - 1, 47); longline("<Any other key will quit>"); if (vgetc() != ' ') return TRUE; outstr(T_ED); windgoto(helprow = 0, 0); longline("\ Operators (double to affect lines)\n\ ==================================\n\ d delete\n\ c change\n"); longline("\ < left shift\n\ > right shift\n\ y yank to buffer\n"); longline("\n\ Yank and Put\n\ ============\n\ p put back text\n\ P put before\n\ Y yank lines"); windgoto(helprow = Rows - 2, 47); longline("<Press space bar to continue>\n"); windgoto(helprow = Rows - 1, 47); longline("<Any other key will quit>"); if (vgetc() != ' ') return TRUE; outstr(T_ED); windgoto(helprow = 0, 0); longline("\n\ Miscellaneous operations\n\ ========================\n\ C change rest of line\n\ D delete rest of line\n\ s substitute chars\n"); longline("\ S substitute lines (not yet)\n\ J join lines\n\ x delete characters\n\ X ... before cursor\n\ :[range]s/search/replace/[g]\n\ :[range]g/search[/p|/d]\n\ :[range]d delete range of lines\n"); windgoto(helprow = Rows - 1, 47); longline("<Press any key>"); vgetc(); return TRUE; } static void longline(p) char *p; { # ifdef AMIGA outstr(p); # else char *s; for (s = p; *s; s++) { if (*s == '\n') windgoto(++helprow, 0); else outchar(*s); } # endif } #else bool_t help() { msg("Sorry, help not configured"); return FALSE; } #endif SHAR_EOF cat << \SHAR_EOF > main.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" int Rows; /* Number of Rows and Columns */ int Columns; /* in the current window. */ char *Realscreen = NULL; /* What's currently on the screen, a * single array of size Rows*Columns. */ char *Nextscreen = NULL; /* What's to be put on the screen. */ int NumLineSizes = 0; /* # of active LineSizes */ LINE **LinePointers = NULL; /* Pointer to the line for LineSizes */ char *LineSizes = NULL; /* Size of a line (pline output) */ char *Filename = NULL;/* Current file name */ LPtr *Filemem; /* The contents of the file, as a single * array. */ LPtr *Filetop; /* Line 'above' the start of the file */ LPtr *Fileend; /* Pointer to the end of the file in Filemem. * (It points to the byte AFTER the last * byte.) */ LPtr *Topchar; /* Pointer to the byte in Filemem which is in * the upper left corner of the screen. */ LPtr *Botchar; /* Pointer to the byte in Filemem which is * just off the bottom of the screen. */ LPtr *Curschar; /* Pointer to byte in Filemem at which the * cursor is currently placed. */ int Curscol; /* Current position of cursor (column) */ int Cursrow; /* Current position of cursor (row) */ int Cursvcol; /* Current virtual column, the column number * of the file's actual line, as opposed to * the column number we're at on the screen. * This makes a difference on lines that span * more than one screen line. */ int Curswant = 0; /* The column we'd like to be at. This is * used try to stay in the same column * through up/down cursor motions. */ bool_t set_want_col; /* If set, then update Curswant the next time * through cursupdate() to the current * virtual column. */ int State = NORMAL; /* This is the current state of the command * interpreter. */ int Prenum = 0; /* The (optional) number before a command. */ LPtr *Insstart; /* This is where the latest insert/append * mode started. */ bool_t Changed = FALSE;/* Set to TRUE if something in the file has * been changed and not written out. */ char *IObuff; /* file reads are done, one line at a time, * into this buffer; as well as sprintf's */ char *Insbuffptr = NULL; char *Insbuff; /* Each insertion gets stuffed into this * buffer. */ char *Readbuffptr = NULL; char *Readbuff; /* Having this buffer allows STEVIE to easily * make itself do commands */ char *Redobuffptr = NULL; char *Redobuff; /* Each command should stuff characters into * this buffer that will re-execute itself. */ bool_t UndoInProgress = FALSE; /* Set to TRUE if undo'ing */ char *Undobuffptr = NULL; char *Undobuff; /* Each command should stuff characters into * this buffer that will undo its effects. */ char *UndoUndobuffptr = NULL; char *UndoUndobuff; /* Each command should stuff characters into * this buffer that will undo its undo. */ char *Yankbuffptr = NULL; char *Yankbuff; /* Yank buffer */ char last_command = NUL; /* last command */ char last_command_char = NUL; /* character needed to undo * last command */ bool_t RedrawingDisabled = FALSE; /* Set to TRUE if undo'ing or * put'ing */ bool_t MustRedrawLine = FALSE; /* Set to TRUE if we must redraw the * current line */ bool_t MustRedrawScreen = TRUE; /* Set to TRUE if we must * redraw the screen */ char **files; /* list of input files */ int numfiles; /* number of input files */ int curfile; /* number of the current file */ static void usage() { fprintf(stderr, "usage: stevie [file ...]\n"); fprintf(stderr, " stevie -t tag\n"); fprintf(stderr, " stevie +[num] file\n"); fprintf(stderr, " stevie +/pat file\n"); exit(1); } #ifdef AMIGA void #else int #endif main(argc, argv) int argc; char **argv; { char *initstr, *getenv(); /* init string from the environment */ char *tag = NULL; /* tag from command line */ char *pat = NULL; /* pattern from command line */ int line = -1; /* line number from command line */ int atoi(); #ifdef AMIGA /* * This won't be needed if you have a version of Lattice 4.01 without broken * break signal handling. */ (void) signal(SIGINT, SIG_IGN); #endif /* * Process the command line arguments. */ if (argc > 1) { switch (argv[1][0]) { case '-': /* -t tag */ if (argv[1][1] != 't') usage(); if (argv[2] == NULL) usage(); Filename = NULL; tag = argv[2]; numfiles = 1; break; case '+': /* +n or +/pat */ if (argv[1][1] == '/') { if (argv[2] == NULL) usage(); Filename = strsave(argv[2]); pat = &(argv[1][1]); numfiles = 1; } else if (isdigit(argv[1][1]) || argv[1][1] == NUL) { if (argv[2] == NULL) usage(); Filename = strsave(argv[2]); numfiles = 1; line = (isdigit(argv[1][1])) ? atoi(&(argv[1][1])) : 0; } else usage(); break; default: /* must be a file name */ Filename = strsave(argv[1]); files = &(argv[1]); numfiles = argc - 1; break; } } else { Filename = NULL; numfiles = 1; } curfile = 0; windinit(); /* * Allocate LPtr structures for all the various position pointers */ if ((Filemem = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Filetop = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Fileend = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Topchar = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Botchar = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Curschar = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Insstart = (LPtr *) alloc((unsigned) sizeof(LPtr))) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } /* * Allocate space for the many buffers */ if ((IObuff = alloc(IOSIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Insbuff = alloc(INSERT_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Readbuff = alloc(READSIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Redobuff = alloc(REDO_UNDO_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Undobuff = alloc(REDO_UNDO_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((UndoUndobuff = alloc(REDO_UNDO_SIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } if ((Yankbuff = alloc(YANKSIZE)) == NULL) { fprintf(stderr, "Can't allocate data structures\n"); windexit(0); } screenalloc(); filealloc(); /* Initialize Filemem, Filetop & Fileend */ screenclear(); if ((initstr = getenv("EXINIT")) != NULL) { char *lp, buf[128]; if ((lp = getenv("LINES")) != NULL) { sprintf(buf, "%s lines=%s", initstr, lp); readcmdline(':', buf); } else readcmdline(':', initstr); } if (Filename != NULL) { if (readfile(Filename, Filemem, FALSE)) filemess("[New File]"); } else msg("Empty Buffer"); setpcmark(); updateNextscreen(NOT_VALID); if (tag) { stuffReadbuff(":ta "); stuffReadbuff(tag); stuffReadbuff("\n"); } else if (pat) { stuffReadbuff(pat); stuffReadbuff("\n"); } else if (line >= 0) { if (line > 0) stuffnumReadbuff(line); stuffReadbuff("G"); } edit(); windexit(0); } void stuffReadbuff(s) char *s; { if (strlen(s) == 0) return; if (Readbuffptr == NULL) { if ((strlen(s) + 1) < READSIZE) { strcpy(Readbuff, s); Readbuffptr = Readbuff; return; } } else if ((strlen(Readbuff) + (strlen(s) + 1)) < READSIZE) { strcat(Readbuff, s); return; } emsg("Couldn't stuffReadbuff() - clearing Readbuff\n"); *Readbuff = NUL; Readbuffptr = NULL; } void stuffnumReadbuff(n) int n; { char buf[32]; sprintf(buf, "%d", n); stuffReadbuff(buf); } /* OPTRESULT */ char vgetc() { int c; /* * inchar() may map special keys by using stuffReadbuff(). If it does so, * it returns -1 so we know to loop here to get a real char. */ do { if (Readbuffptr != NULL) { char nextc = *Readbuffptr++; if (*Readbuffptr == NUL) { *Readbuff = NUL; Readbuffptr = NULL; } return (nextc); } c = inchar(); } while (c == -1); return (char) c; } char vpeekc() { if (Readbuffptr != NULL) return (*Readbuffptr); return (NUL); } SHAR_EOF cat << \SHAR_EOF > misccmds.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" extern int did_ai; /* * OpenForward * * Add a blank line below the current line. */ bool_t OpenForward(can_ai) int can_ai; { LINE *l; LPtr *next; char *s; /* string to be moved to new line, if any */ int newindex = 0; /* index of the cursor on the new * line */ /* * If we're in insert mode, we need to move the remainder of the current * line onto the new line. Otherwise the new line is left blank. */ if (State == INSERT) s = &Curschar->linep->s[Curschar->index]; else s = ""; if ((next = nextline(Curschar)) == NULL) /* open on last line */ next = Fileend; /* * By asking for as much space as the prior line had we make sure that * we'll have enough space for any auto-indenting. */ if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) { emsg("out of memory"); beep(); sleep(2); return (FALSE); } if (can_ai && P(P_AI)) { char *p; /* * Copy prior line, and truncate after white space */ strcpy(l->s, Curschar->linep->s); for (p = l->s; *p == ' ' || *p == TAB; p++); *p = NUL; newindex = p - l->s; AppendToInsbuff(l->s); if (*s != NUL) strcat(l->s, s); /* * If we just did an auto-indent, then we didn't type anything on the * prior line, and it should be truncated. */ if (did_ai) Curschar->linep->s[0] = NUL; did_ai = TRUE; } else if (*s != NUL) { strcpy(l->s, s); /* copy string to new line */ } if (State == INSERT) /* truncate current line at cursor */ *s = NUL; Curschar->linep->next = l; /* link neighbors to new line */ next->linep->prev = l; l->prev = Curschar->linep; /* link new line to neighbors */ l->next = next->linep; if (next == Fileend) { /* new line at end */ l->num = Curschar->linep->num + LINEINC; } else if ((l->prev->num) + 1 == l->next->num) { /* no gap, renumber */ renum(); } else { /* stick it in the middle */ long lnum; lnum = (l->prev->num + l->next->num) / 2; l->num = lnum; } if (!RedrawingDisabled) { /* * Get the cursor to the start of the line, so that 'Cursrow' gets * set to the right physical line number for the stuff that * follows... */ Curschar->index = 0; cursupdate(); /* * If we're doing an open on the last logical line, then go ahead and * scroll the screen up. Otherwise, just insert a blank line at the * right place. We use calls to plines() in case the cursor is * resting on a long line. */ if (Cursrow + plines(Curschar) == (Rows - 1)) scrollup(1); else s_ins(Cursrow + plines(Curschar), 1, Rows, Columns); } *Curschar = *nextline(Curschar); /* cursor moves down */ Curschar->index = newindex; if (!RedrawingDisabled) { /* because Botchar is now invalid */ updateNextscreen(VALID_TO_CURSCHAR); cursupdate(); /* update Cursrow before insert */ } CHANGED; return (TRUE); } /* * OpenBackward * * Add a blank line above the current line. */ bool_t OpenBackward(can_ai) int can_ai; { LINE *l; LINE *prev; int newindex = 0; /* index of the cursor on the new * line */ prev = Curschar->linep->prev; if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) { emsg("out of memory"); beep(); sleep(2); return (FALSE); } Curschar->linep->prev = l; /* link neighbors to new line */ prev->next = l; l->next = Curschar->linep; /* link new line to neighbors */ l->prev = prev; if (can_ai && P(P_AI)) { char *p; /* * Copy current line, and truncate after white space */ strcpy(l->s, Curschar->linep->s); for (p = l->s; *p == ' ' || *p == TAB; p++); *p = NUL; newindex = p - l->s; AppendToInsbuff(l->s); did_ai = TRUE; } Curschar->linep = Curschar->linep->prev; Curschar->index = newindex; if (prev == Filetop->linep) { /* new start of file */ Filemem->linep = l; renum(); } else if ((l->prev->num) + 1 == l->next->num) { /* no gap, renumber */ renum(); } else { /* stick it in the middle */ long lnum; lnum = (l->prev->num + l->next->num) / 2; l->num = lnum; } if (!RedrawingDisabled) { if (LINEOF(Curschar) < LINEOF(Topchar)) { Topchar->linep = Curschar->linep; updateNextscreen(NOT_VALID); } else { updateNextscreen(VALID_TO_CURSCHAR); } cursupdate(); /* update Cursrow before insert */ if (Cursrow != 0) s_ins(Cursrow, 1, Rows, Columns); /* insert a physical line */ } CHANGED; return (TRUE); } int cntllines(pbegin, pend) LPtr *pbegin, *pend; { register LINE *lp; register int lnum = 1; for (lp = pbegin->linep; lp != pend->linep; lp = lp->next) lnum++; return (lnum); } /* * plines(p) - return the number of physical screen lines taken by line 'p' */ int plines(p) LPtr *p; { register int col = 0; register char *s; if (p == NULL) { fprintf(stderr, "plines(p) : p == NULL ????"); return (0); } s = p->linep->s; if (*s == NUL) /* empty line */ return 1; for (; *s != NUL; s++) { if (*s == TAB && !P(P_LS)) col += P(P_TS) - (col % P(P_TS)); else col += chars[(unsigned) (*s & 0xff)].ch_size; } /* * If list mode is on, then the '$' at the end of the line takes up one * extra column. */ if (P(P_LS)) col += 1; /* * If 'number' mode is on, add another 8. */ if (P(P_NU)) col += 8; return ((col + (Columns - 1)) / Columns); } void fileinfo() { long l1, l2; char buf[MAX_COLUMNS + 1]; if (bufempty()) { msg("Buffer Empty"); return; } l1 = cntllines(Filemem, Curschar); l2 = cntllines(Filemem, Fileend) - 1; sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --", (Filename != NULL) ? Filename : "No File", Changed ? " [Modified]" : "", l1, l2, (l1 * 100) / l2); msg(buf); } /* * gotoline(n) - return a pointer to line 'n' * * Returns a pointer to the last line of the file if n is zero, or beyond the * end of the file. */ LPtr * gotoline(n) int n; { static LPtr l; l.index = 0; if (n == 0) l = *prevline(Fileend); else { LPtr *p; for (l = *Filemem; --n > 0; l = *p) if ((p = nextline(&l)) == NULL) break; } return &l; } void inschar(c) char c; { register char *p; register char *pend; /* make room for the new char. */ if (!canincrease(1)) return; p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1]; pend = &Curschar->linep->s[Curschar->index]; for (; p > pend; p--) *p = *(p - 1); *p = c; if (RedrawingDisabled) { Curschar->index++; return; } /* * If we're in insert mode and showmatch mode is set, then check for * right parens and braces. If there isn't a match, then beep. If there * is a match AND it's on the screen, then flash to it briefly. If it * isn't on the screen, don't do anything. */ if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) { LPtr *lpos, csave; if ((lpos = showmatch()) == NULL) /* no match, so beep */ beep(); else if (LINEOF(lpos) >= LINEOF(Topchar)) { updateNextscreen(VALID_TO_CURSCHAR); /* show the new char * first */ updateRealscreen(); csave = *Curschar; *Curschar = *lpos; /* move to matching char */ cursupdate(); windgoto(Cursrow, Curscol); delay(); /* brief pause */ *Curschar = csave; /* restore cursor position */ cursupdate(); } } inc(Curschar); CHANGED; } void insstr(s) register char *s; { register char *p; register char *pend; register int n = strlen(s); /* Move everything in the file over to make */ /* room for the new string. */ if (!canincrease(n)) return; p = &Curschar->linep->s[strlen(Curschar->linep->s) + n]; pend = &Curschar->linep->s[Curschar->index]; for (; p > pend; p--) *p = *(p - n); for (; n > 0; n--) { *p++ = *s++; Curschar->index++; } CHANGED; } bool_t delchar(fixpos, undo) bool_t fixpos; /* if TRUE fix the cursor position when done */ bool_t undo; /* if TRUE put char deleted into Undo buffer */ { int i; /* Check for degenerate case; there's nothing in the file. */ if (bufempty()) return FALSE; if (lineempty(Curschar)) /* can't do anything */ return FALSE; if (undo) AppendToUndobuff(mkstr(gchar(Curschar))); /* Delete the char. at Curschar by shifting everything in the line down. */ for (i = Curschar->index + 1; i < Curschar->linep->size; i++) Curschar->linep->s[i - 1] = Curschar->linep->s[i]; /* * If we just took off the last character of a non-blank line, we don't * want to end up positioned at the newline. */ if (fixpos) { if (gchar(Curschar) == NUL && Curschar->index > 0 && State != INSERT) Curschar->index--; } CHANGED; return TRUE; } void delline(nlines, can_update) int nlines; bool_t can_update; { register LINE *p; register LINE *q; int doscreen; /* if true, update the screen */ int num_plines = 0; doscreen = can_update; /* * There's no point in keeping the screen updated if we're deleting more * than a screen's worth of lines. */ if (nlines > (Rows - 1) && can_update) { doscreen = FALSE; /* flaky way to clear rest of screen */ s_del(Cursrow, Rows - 1, Rows, Columns); } while (nlines-- > 0) { if (bufempty()) /* nothing to delete */ break; if (buf1line()) { /* just clear the line */ Curschar->linep->s[0] = NUL; Curschar->index = 0; break; } p = Curschar->linep->prev; q = Curschar->linep->next; if (p == Filetop->linep) { /* first line of file so... */ Filemem->linep = q; /* adjust start of file */ Topchar->linep = q; /* and screen */ } p->next = q; q->prev = p; clrmark(Curschar->linep); /* clear marks for the line */ /* * Set up to delete the correct number of physical lines on the * screen */ if (doscreen) num_plines += plines(Curschar); /* * If deleting the top line on the screen, adjust Topchar */ if (Topchar->linep == Curschar->linep) Topchar->linep = q; free(Curschar->linep->s); free((char *) (Curschar->linep)); Curschar->linep = q; Curschar->index = 0; /* is this right? */ CHANGED; /* If we delete the last line in the file, back up */ if (Curschar->linep == Fileend->linep) { Curschar->linep = Curschar->linep->prev; /* and don't try to delete any more lines */ break; } } /* * Delete the correct number of physical lines on the screen */ if (doscreen && num_plines > 0) s_del(Cursrow, num_plines, Rows, Columns); } SHAR_EOF cat << \SHAR_EOF > screen.c /* * STEVIE - Simply Try this Editor for VI Enthusiasts * * Code Contributions By : Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ #include "stevie.h" /* * The following variable is set (in cursupdate) to the number of physical * lines taken by the line the cursor is on. We use this to avoid extra calls * to plines(). The optimized routines updateline() and redrawline() * make sure that the size of the cursor line hasn't changed. If so, lines below * the cursor will move up or down and we need to call the routines * updateNextscreen() and updateRealscreen() to examine the entire screen. */ static int Cline_size; /* size (in rows) of the cursor line */ static int Cline_row; /* starting row of the cursor line */ /* * updateline() - like updateNextscreen() but only for cursor line * * This determines whether or not we need to call updateNextscreen() to examine * the entire screen for changes. This occurs if the size of the cursor line * (in rows) hasn't changed. */ void updateline() { register int row; register int col; register char *screenp; register char c; LPtr memp; register char *nextrow; char extra[16]; char *p_extra; int n_extra; int n; bool_t eof; int lno; /* number of the line we're doing */ int coff; /* column offset */ MustRedrawLine = TRUE; coff = P(P_NU) ? 8 : 0; /* * This should be done more efficiently. */ if (P(P_NU)) lno = cntllines(Filemem, Curschar); screenp = Nextscreen + (Cline_row * Columns); memp = *Curschar; memp.index = 0; eof = FALSE; col = 0; row = Cline_row; p_extra = NULL; n_extra = 0; if (P(P_NU)) { strcpy(extra, mkline(lno)); p_extra = extra; n_extra = 8; } while (!eof) { /* Get the next character to put on the screen. */ /* * The 'extra' array contains the extra stuff that is inserted to * represent special characters (tabs, and other non-printable stuff. * The order in the 'extra' array is reversed. */ if (n_extra > 0) { c = *p_extra++; n_extra--; } else { c = gchar(&memp); if (inc(&memp) == -1) eof = TRUE; /* * when getting a character from the file, we may have to turn it * into something else on the way to putting it into * 'Nextscreen'. */ if (c == TAB && !P(P_LS)) { strcpy(extra, " "); p_extra = extra; /* tab amount depends on current column */ n_extra = ((P(P_TS) - 1) - (col - coff) % P(P_TS)); c = ' '; } else if (c == NUL && P(P_LS)) { extra[0] = NUL; p_extra = extra; n_extra = 1; c = '$'; } else if (c != NUL && (n = chars[c].ch_size) > 1) { p_extra = chars[c].ch_str; c = *p_extra++; n_extra = n - 1; } } if (c == NUL) { row++; /* get pointer to start of next row */ nextrow = Nextscreen + (row * Columns); /* blank out the rest of this row */ while (screenp < nextrow) *screenp++ = ' '; break; } if (col >= Columns) { row++; col = 0; } /* store the character in Nextscreen */ *screenp++ = c; col++; } if ((row - Cline_row) != Cline_size) { updateNextscreen(VALID_TO_CURSCHAR); } } /* * redrawline * * Like updateRealscreen() but only for the cursor line. */ void redrawline() { register char *np = Nextscreen + (Cline_row * Columns); register char *rp = Realscreen + (Cline_row * Columns); register char *endline; register int row, col; int gorow = -1, gocol = -1; if (RedrawingDisabled) return; if (!MustRedrawLine && !MustRedrawScreen) return; if (MustRedrawScreen) { msg("STEVIE internal error: redrawline called"); sleep(5); } endline = np + (Cline_size * Columns); row = Cline_row; col = 0; outstr(T_CI); /* disable cursor */ for (; np < endline; np++, rp++) { /* If desired screen (contents of Nextscreen) does not */ /* match what's really there, put it there. */ if (*np != *rp) { /* if we are positioned at the right place, */ /* we don't have to use windgoto(). */ if (gocol != col || gorow != row) { /* * If we're just off by one, don't send an entire esc. seq. * (this happens a lot!) */ if (gorow == row && gocol + 1 == col) { outchar(*(np - 1)); gocol++; } else windgoto(gorow = row, gocol = col); } outchar(*rp = *np); gocol++; } if (++col >= Columns) { col = 0; row++; } } outstr(T_CV); /* enable cursor again */ MustRedrawScreen = FALSE; } /* * prt_line() - print the given line */ void prt_line(s) char *s; { register int si = 0; register int c; register int col = 0; char extra[16]; int n_extra = 0; int n; for (;;) { if (n_extra > 0) c = extra[--n_extra]; else { c = s[si++]; if (c == TAB && !P(P_LS)) { strcpy(extra, " "); /* tab amount depends on current column */ n_extra = (P(P_TS) - 1) - col % P(P_TS); c = ' '; } else if (c == NUL && P(P_LS)) { extra[0] = NUL; n_extra = 1; c = '$'; } else if (c != NUL && (n = chars[c].ch_size) > 1) { char *p; n_extra = 0; p = chars[c].ch_str; /* copy 'ch-str'ing into 'extra' in reverse */ while (n > 1) extra[n_extra++] = p[--n]; c = p[0]; } } if (c == NUL) break; outchar(c); col++; } } void screenclear() { register char *rp; register char *np; register char *end; register int i; outstr(T_ED); /* clear the display */ rp = Realscreen; end = Realscreen + Rows * Columns; np = Nextscreen; /* blank out the stored screens */ while (rp != end) *rp++ = *np++ = ' '; /* clear screen info */ for (i = 0; i < Rows; i++) { LinePointers[i] = NULL; LineSizes[i] = '\0'; } NumLineSizes = 0; } void cursupdate() { LPtr *p; LPtr *pp; char c; int incr, nlines; int i; int didincr; if (bufempty()) { /* special case - file is empty */ *Topchar = *Filemem; *Curschar = *Filemem; for (i = 0; i < Rows; i++) LineSizes[i] = 0; } else if (LINEOF(Curschar) < LINEOF(Topchar)) { nlines = cntllines(Curschar, Topchar); /* * if the cursor is above the top of the screen, put it at the top of * the screen.. */ *Topchar = *Curschar; Topchar->index = 0; /* * ... 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) { p = Topchar; for (i = 0; i < Rows / 3; i += plines(p)) { pp = prevline(p); if (pp == NULL) break; p = pp; } *Topchar = *p; } else s_ins(0, nlines - 1, Rows, Columns); updateNextscreen(VALID); } else if (LINEOF(Curschar) >= LINEOF(Botchar)) { nlines = cntllines(Botchar, Curschar); /* * If the cursor is off the bottom of the screen, put it at the top * of the screen.. ... and back up */ if (nlines > Rows / 3) { p = Curschar; for (i = 0; i < (2 * Rows) / 3; i += plines(p)) { pp = prevline(p); if (pp == NULL) break; p = pp; } *Topchar = *p; } else { scrollup(nlines); } updateNextscreen(VALID); } Cursrow = Curscol = Cursvcol = i = 0; for (p = Topchar; p->linep != Curschar->linep; p = nextline(p)) Cursrow += LineSizes[i++]; if (P(P_NU)) Curscol = 8; Cline_row = Cursrow; if (i >= NumLineSizes) { /* Should only happen with a line that is too * long to fit on the last screen line. */ Cline_size = 0; } else { Cline_size = LineSizes[i]; for (i = 0; i <= Curschar->index; i++) { c = Curschar->linep->s[i]; /* A tab gets expanded, depending on the current column */ if (c == TAB && !P(P_LS)) incr = P(P_TS) - (Cursvcol % P(P_TS)); else incr = chars[c].ch_size; Curscol += incr; Cursvcol += incr; if (Curscol >= Columns) { Curscol -= Columns; Cursrow++; didincr = TRUE; } else didincr = FALSE; } if (didincr) Cursrow--; if (c == TAB && State == NORMAL && !P(P_LS)) { Curscol--; Cursvcol--; } else { Curscol -= incr; Cursvcol -= incr; } if (Curscol < 0) Curscol += Columns; } if (set_want_col) { Curswant = Cursvcol; set_want_col = FALSE; } } /* * The rest of the routines in this file perform screen manipulations. The * given operation is performed physically on the screen. The corresponding * change is also made to the internal screen image. In this way, the editor * anticipates the effect of editing changes on the appearance of the screen. * That way, when we call screenupdate a complete redraw isn't usually * necessary. Another advantage is that we can keep adding code to anticipate * screen changes, and in the meantime, everything still works. */ /* * s_ins(row, nlines, total_rows, columns) - insert 'nlines' lines at 'row' */ void s_ins(row, nlines, total_rows, columns) int row; int nlines; int total_rows; int columns; { register char *s; /* src for block copy */ register char *d; /* dest for block copy */ register char *e; /* end point for copy */ int i; if (nlines > (total_rows - 1 - row)) nlines = total_rows - 1 - row; if ((T_IL[0] == NUL) || RedrawingDisabled || nlines <= 0) return; /* * It "looks" better if we do all the inserts at once */ outstr(T_SC); /* save position */ if (T_IL_B[0] == NUL) { for (i = 0; i < nlines; i++) { windgoto(row, 0); outstr(T_IL); } } else { windgoto(row, 0); outstr(T_IL); if (nlines >= 10) outchar((char) (nlines / 10 + '0')); outchar((char) (nlines % 10 + '0')); outstr(T_IL_B); } windgoto(total_rows - 1, 0); /* delete any garbage that may have */ outstr(T_EL); /* been shifted to the bottom line */ outstr(T_RC); /* restore the cursor position */ /* * Now do a block move to update the internal screen image */ d = Realscreen + (columns * (total_rows - 1)) - 1; s = d - (columns * nlines); e = Realscreen + (columns * row); while (s >= e) *d-- = *s--; /* * Clear the inserted lines */ s = Realscreen + (row * columns); e = s + (nlines * columns); while (s < e) *s++ = ' '; } /* * s_del(row, nlines, total_rows, columns) - delete 'nlines' lines at 'row' */ void s_del(row, nlines, total_rows, columns) int row; int nlines; int total_rows; int columns; { register char *s; register char *d; register char *e; int i; if (nlines > (total_rows - 1 - row)) nlines = total_rows - 1 - row; if ((T_DL[0] == NUL) || RedrawingDisabled || nlines <= 0) return; outstr(T_SC); /* save position */ windgoto(total_rows - 1, 0); /* delete any garbage that */ outstr(T_EL); /* was on the status line */ /* delete the lines */ if (T_DL_B[0] == NUL) { for (i = 0; i < nlines; i++) { windgoto(row, 0); outstr(T_DL); /* delete a line */ } } else { windgoto(row, 0); outstr(T_DL); if (nlines >= 10) outchar((char) (nlines / 10 + '0')); outchar((char) (nlines % 10 + '0')); outstr(T_DL_B); } outstr(T_RC); /* restore position */ /* * do a block move to update the internal image */ d = Realscreen + (row * columns); s = d + (nlines * columns); e = Realscreen + ((total_rows - 1) * columns); while (s < e) *d++ = *s++; while (d < e) /* clear the lines at the bottom */ *d++ = ' '; } SHAR_EOF # End of shell archive exit 0 -- Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page Have five nice days.