#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'stevie/edit.c' <<'END_OF_FILE' X/* $Header: /nw/tony/src/stevie/src/RCS/edit.c,v 1.11 89/08/02 19:57:12 tony Exp $ X * X * The main edit loop as well as some other simple cursor movement routines. X */ X X#include "stevie.h" X X/* X * This flag is used to make auto-indent work right on lines where only X * a or is typed. It is set when an auto-indent is done, X * and reset when any other editting is done on the line. If an X * or is received, and did_ai is TRUE, the line is truncated. X */ Xbool_t did_ai = FALSE; X Xvoid Xedit() X{ X extern bool_t need_redraw; X int c; X register char *p, *q; X X Prenum = 0; X X /* position the display and the cursor at the top of the file. */ X *Topchar = *Filemem; X *Curschar = *Filemem; X Cursrow = Curscol = 0; X X do_mlines(); /* check for mode lines before starting */ X X updatescreen(); X X for ( ;; ) { X X /* Figure out where the cursor is based on Curschar. */ X cursupdate(); X X if (need_redraw && !anyinput()) { X updatescreen(); X need_redraw = FALSE; X } X X if (!anyinput()) X windgoto(Cursrow,Curscol); X X X c = vgetc(); X X if (State == NORMAL) { X X /* We're in the normal (non-insert) mode. */ X X /* Pick up any leading digits and compute 'Prenum'. Could be X special code K_UARROW etc. so check ascii first. */ X if ( isascii(c) && isdigit(c) && (Prenum>0 || c!='0') ){ X Prenum = Prenum*10 + (c-'0'); X continue; X } X /* execute the command */ X normal(c); X Prenum = 0; X X } else { X X /* X * Insert or Replace mode. X */ X switch (c) { X X case ESC: /* an escape ends input mode */ X X /* X * If we just did an auto-indent, truncate the X * line, and put the cursor back. X */ X if (did_ai) { X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X did_ai = FALSE; X } X X set_want_col = TRUE; X X /* Don't end up on a '\n' if you can help it. */ X if (gchar(Curschar) == NUL && Curschar->index != 0) X dec(Curschar); X X /* X * The cursor should end up on the last inserted X * character. This is an attempt to match the real X * 'vi', but it may not be quite right yet. X */ X if (Curschar->index != 0 && !endofline(Curschar)) X dec(Curschar); X X State = NORMAL; X msg(""); X X /* construct the Redo buffer */ X p=Redobuff; X q=Insbuff; X while ( q < Insptr ) X *p++ = *q++; X *p++ = ESC; X *p = NUL; X updatescreen(); X break; X X case CTRL('D'): X /* X * Control-D is treated as a backspace in insert X * mode to make auto-indent easier. This isn't X * completely compatible with vi, but it's a lot X * easier than doing it exactly right, and the X * difference isn't very noticeable. X */ X case BS: X /* can't backup past starting point */ X if (Curschar->linep == Insstart->linep && X Curschar->index <= Insstart->index) { X beep(); X break; X } X X /* can't backup to a previous line */ X if (Curschar->linep != Insstart->linep && X Curschar->index <= 0) { X beep(); X break; X } X X did_ai = FALSE; X dec(Curschar); X if (State == INSERT) X delchar(TRUE); X /* X * It's a little strange to put backspaces into X * the redo buffer, but it makes auto-indent a X * lot easier to deal with. X */ X *Insptr++ = BS; X Ninsert++; X cursupdate(); X updateline(); X break; X X case CR: X case NL: X if (State == REPLACE) /* DMT added, 12/89 */ X delchar(FALSE); X *Insptr++ = NL; X Ninsert++; X opencmd(FORWARD, TRUE); /* open a new line */ X break; X X default: X did_ai = FALSE; X insertchar(c); X break; X } X } X } X} X Xvoid Xinsertchar(c) Xint c; X{ X inschar(c); X *Insptr++ = c; X Ninsert++; X /* X * The following kludge avoids overflowing the statically X * allocated insert buffer. Just dump the user back into X * command mode, and print a message. X */ X if (Insptr+10 >= &Insbuff[1024]) { X stuffin(mkstr(ESC)); X emsg("No buffer space - returning to command mode"); X sleep(2); X } X updateline(); X} X Xvoid Xgetout() X{ X windgoto(Rows-1,0); X putchar('\r'); X putchar('\n'); X windexit(0); X} X Xvoid Xscrolldown(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X X /* Scroll up 'nlines' lines. */ X while (nlines--) { X if ((p = prevline(Topchar)) == NULL) X break; X done += plines(p); X *Topchar = *p; X /* X * If the cursor is on the bottom line, we need to X * make sure it gets moved up the appropriate number X * of lines so it stays on the screen. X */ X if (Curschar->linep == Botchar->linep->prev) { X int i = 0; X while (i < done) { X i += plines(Curschar); X *Curschar = *prevline(Curschar); X } X } X } X s_ins(0, done); X} X Xvoid Xscrollup(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X register int pl; /* # of plines for the current line */ X X /* Scroll down 'nlines' lines. */ X while (nlines--) { X pl = plines(Topchar); X if ((p = nextline(Topchar)) == NULL) X break; X done += pl; X if (Curschar->linep == Topchar->linep) X *Curschar = *p; X *Topchar = *p; X X } X s_del(0, done); X} X X/* X * oneright X * oneleft X * onedown X * oneup X * X * Move one char {right,left,down,up}. Return TRUE when X * sucessful, FALSE when we hit a boundary (of a line, or the file). X */ X Xbool_t Xoneright() X{ X set_want_col = TRUE; X X switch (inc(Curschar)) { X X case 0: X return TRUE; X X case 1: X dec(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ X} X Xbool_t Xoneleft() X{ X set_want_col = TRUE; X X switch (dec(Curschar)) { X X case 0: X return TRUE; X X case 1: X inc(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ X} X Xvoid Xbeginline(flag) Xbool_t flag; X{ X while ( oneleft() ) X ; X if (flag) { X while (isspace(gchar(Curschar)) && oneright()) X ; X } X set_want_col = TRUE; X} X Xbool_t Xoneup(n) Xint n; X{ X LPTR p, *np; X register int k; X X p = *Curschar; X for ( k=0; k 0 ) X break; /* to update the cursor, etc. */ X else X return FALSE; X } X p = *np; X } X *Curschar = p; X /* This makes sure Topchar gets updated so the complete line */ X /* is one the screen. */ X cursupdate(); X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} X Xbool_t Xonedown(n) Xint n; X{ X LPTR p, *np; X register int k; X X p = *Curschar; X for ( k=0; k 0 ) X break; X else X return FALSE; X } X p = *np; X } X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} END_OF_FILE if test 6635 -ne `wc -c <'stevie/edit.c'`; then echo shar: \"'stevie/edit.c'\" unpacked with wrong size! fi # end of 'stevie/edit.c' fi if test -f 'stevie/minix.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie/minix.c'\" else echo shar: Extracting \"'stevie/minix.c'\" \(4836 characters\) sed "s/^X//" >'stevie/minix.c' <<'END_OF_FILE' X/* $Header: /nw/tony/src/stevie/src/RCS/minix.c,v 1.5 89/07/11 21:24:18 tony Exp $ X * X * System-dependent routines for Minix-ST X */ X X#include "stevie.h" X#include X#include X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X char c; X X flushbuf(); /* flush any pending output */ X X while (read(0, &c, 1) != 1) X ; X X got_int = FALSE; X return c; X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xvoid Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xregister char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X Xvoid Xoutstr(s) Xregister char *s; X{ X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X if ( P(P_VB) ) X vbeep(); X else X outone('\007'); X} X X/* X * remove(file) - remove a file X */ Xvoid Xremove(file) Xchar *file; X{ X unlink(file); X} X X/* X * rename(of, nf) - rename existing file 'of' to 'nf' X */ Xvoid Xrename(of, nf) Xchar *of, *nf; X{ X unlink(nf); X link(of, nf); X unlink(of); X} X Xvoid Xpause() X{ X sleep (1); X} X Xstatic struct sgttyb ostate; X X/* X * Go into cbreak mode X */ Xvoid Xset_tty() X{ X struct sgttyb nstate; X X ioctl(0, TIOCGETP, &ostate); X nstate = ostate; X nstate.sg_flags &= ~(XTABS|ECHO); X nstate.sg_flags |= CBREAK; X ioctl(0, TIOCSETP, &nstate); X} X X/* X * Restore original terminal modes X */ Xvoid Xreset_tty() X{ X ioctl(0, TIOCSETP, &ostate); X} X Xvoid Xsig() X{ X signal(SIGINT, sig); X signal(SIGQUIT, sig); X X got_int = TRUE; X} X Xvoid Xwindinit() X{ X#ifdef TERMCAP X if (t_init() != 1) { X exit(1); X } X#else X Columns = 80; X P(P_LI) = Rows = 25; X#endif X /* X * The code here makes sure that there isn't a window during which X * we could get interrupted and exit with the tty in a weird state. X */ X signal(SIGINT, sig); X signal(SIGQUIT, sig); X X set_tty(); X X if (got_int) X windexit(0); X} X Xvoid Xwindexit(r) Xint r; X{ X reset_tty(); X exit(r); X} X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X#ifdef TERMCAP X char *tgoto(); X#else X r += 1; X c += 1; X#endif X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X#ifdef TERMCAP X outstr(tgoto(T_CM, c, r)); X#else X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X#endif X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X return fopen(fname, mode); X} X Xchar * Xstrchr(s, c) Xchar *s; Xchar c; X{ X char *index(); X X return index(s, c); X} X Xchar * Xfixname(s) Xchar *s; X{ X return s; X} X X/* X * doshell() - run a command or an interactive shell X */ Xvoid Xdoshell(cmd) Xchar *cmd; X{ X char *cp, *getenv(); X char cline[128]; X X outstr("\r\n"); X flushbuf(); X X if (cmd == NULL) { X if ((cmd = getenv("SHELL")) == NULL) X cmd = "/bin/sh"; X sprintf(cline, "%s -i", cmd); X cmd = cline; X } X X reset_tty(); X system(cmd); X set_tty(); X X wait_return(); X} X X/* X * FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT! X * X * The next couple of functions do system-specific stuff. X * They currently do nothing; I'm not familiar enough with X * system-specific programming on this system. X * If you fill it in for your system, please post the results X * and share with the rest of us. X */ X X Xsetcolor (c) X/* X * Set the color to c, using the local system convention for numbering X * colors or video attributes. X * X * If you implement this, remember to note the original color in X * windinit(), before you do any setcolor() commands, and X * do a setcolor() back to the original as part of windexit(). X */ X int c: X{ X} X X Xsetrows (r) X/* X * Set the number of lines to r, if possible. Otherwise X * "do the right thing". Return the number of lines actually set. X * X * If you implement this, remember to note the original number of rows X * in windinit(), before you do any setrows() commands, and X * do a setrows() back to the original as part of windexit(). X */ X int r; X{ X /* Since we do nothing, just return the current number of lines */ X return ( P(P_LI) ); X} X X Xvbeep () X/* X * Do a "visual bell". This generally consists of flashing the screen X * once in inverse video. X */ X{ X int color, revco; X X color = P( P_CO ); /* get current color */ X revco = reverse_color (color); /* system-specific */ X setcolor (revco); X flushbuf (); X pause (); X setcolor (color); X windgoto (Cursrow, Curscol); X flushbuf (); X} X Xreverse_color (co) X/* X * Returns the inverse video attribute or color of co. X * The existing code below is VERY simple-minded. X * Replace it with proper code for your system. X */ X int co; X{ X if (co) return (0); X else return (1); X} X X X/********** End of do-it-yourself kit **********************/ X END_OF_FILE if test 4836 -ne `wc -c <'stevie/minix.c'`; then echo shar: \"'stevie/minix.c'\" unpacked with wrong size! fi # end of 'stevie/minix.c' fi if test -f 'stevie/os2.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie/os2.c'\" else echo shar: Extracting \"'stevie/os2.c'\" \(7126 characters\) sed "s/^X//" >'stevie/os2.c' <<'END_OF_FILE' X/* $Header: /nw/tony/src/stevie/src/RCS/os2.c,v 1.7 89/08/07 05:49:19 tony Exp $ X * X * OS/2 System-dependent routines. X */ X X#define INCL_BASE X#include X#include X#include "stevie.h" X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X register int c; X X got_int = FALSE; X X for (;;beep()) { /* loop until we get a valid character */ X X flushbuf(); /* flush any pending output */ X X switch (c = getch()) { X case 0x1e: X return K_CCIRCM; X case 0: /* special key */ X if (State != NORMAL) { X c = getch(); /* throw away next char */ X continue; /* and loop for another char */ X } X switch (c = getch()) { X case 0x50: X return K_DARROW; X case 0x48: X return K_UARROW; X case 0x4b: X return K_LARROW; X case 0x4d: X return K_RARROW; X case 0x52: X return K_INSERT; X case 0x47: /* Home key */ X stuffin("1G"); X return -1; X case 0x4f: /* End key */ X stuffin("G"); X return -1; X case 0x51: /* PgDn key */ X stuffin(mkstr(CTRL('F'))); X return -1; X case 0x49: /* PgUp key */ X stuffin(mkstr(CTRL('B'))); X return -1; X case 0x52: /* insert key */ X return K_INSERT; X case 0x53: /* delete key */ X stuffin("x"); X return -1; X /* X * Hard-code some useful function key macros. X */ X case 0x3b: /* F1 */ X stuffin(":help\n"); X return -1; X case 0x3c: /* F2 */ X stuffin(":n\n"); X return -1; X case 0x55: /* SF2 */ X stuffin(":n!\n"); X return -1; X case 0x3d: /* F3 */ X stuffin(":N\n"); X return -1; X case 0x56: /* SF3 */ X stuffin(":N!\n"); X return -1; X case 0x3e: /* F4 */ X stuffin(":e #\n"); X return -1; X case 0x57: /* SF4 */ X stuffin(":e! #\n"); X return -1; X case 0x3f: /* F5 */ X stuffin(":rew\n"); X return -1; X case 0x58: /* SF5 */ X stuffin(":rew!\n"); X return -1; X case 0x40: /* F6 */ X stuffin("]]"); X return -1; X case 0x59: /* SF6 */ X stuffin("[["); X return -1; X case 0x42: /* F8 - Set up global substitute */ X stuffin(":1,$s/"); X return -1; X case 0x43: /* F9 - declare C variable */ X stuffin("yyp!!cdecl\n"); X return -1; X case 0x5C: /* SF9 - explain C declaration */ X stuffin("yyp^iexplain \033!!cdecl\n"); X return -1; X case 0x44: /* F10 - save & quit */ X stuffin(":x\n"); X return -1; X case 0x5D: /* F10 - quit without saving */ X stuffin(":q!\n"); X return -1; X default: X break; X } X break; X X default: X return c; X } X } X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xvoid Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xregister char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X Xstatic char cell[2] = { 0, 7 }; X X/* X * outstr(s) - write a string to the console X * X * We implement insert/delete line escape sequences here. This is kind X * of a kludge, but at least it's localized to a single point. X */ Xvoid Xoutstr(s) Xregister char *s; X{ X if (strcmp(s, T_DL) == 0) { /* delete line */ X int r, c; X X flushbuf(); X VioGetCurPos(&r, &c, 0); X VioScrollUp(r, 0, 100, 100, 1, cell, 0); X return; X } X if (strcmp(s, T_IL) == 0) { /* insert line */ X int r, c; X X flushbuf(); X VioGetCurPos(&r, &c, 0); X VioScrollDn(r, 0, 100, 100, 1, cell, 0); X return; X } X X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X in ( P(P_VB) ) X vbeep(); X else X outone('\007'); X} X Xsleep(n) Xint n; X{ X DosSleep(1000L * n); X} X Xvoid Xpause() X{ X flushbuf(); X DosSleep(300L); X} X Xvoid Xsig() X{ X signal(SIGINT, sig); X X got_int = TRUE; X} X Xvoid Xwindinit() X{ X Columns = 80; X P(P_LI) = Rows = 25; X X signal(SIGINT, sig); X} X Xvoid Xwindexit(r) Xint r; X{ X flushbuf(); X exit(r); X} X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X r += 1; X c += 1; X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X FILE *fopen(); X char modestr[16]; X X sprintf(modestr, "%sb", mode); X return fopen(fname, modestr); X} X X#define PSIZE 128 X X/* X * fixname(s) - fix up a dos name X * X * Takes a name like: X * X * \x\y\z\base.ext X * X * and trims 'base' to 8 characters, and 'ext' to 3. X */ Xchar * Xfixname(s) Xchar *s; X{ X char *strchr(), *strrchr(); X static char f[PSIZE]; X char base[32]; X char ext[32]; X char *p; X int i; X X strcpy(f, s); X X for (i=0; i < PSIZE ;i++) X if (f[i] == '/') X f[i] = '\\'; X X /* X * Split the name into directory, base, extension. X */ X if ((p = strrchr(f, '\\')) != NULL) { X strcpy(base, p+1); X p[1] = '\0'; X } else { X strcpy(base, f); X f[0] = '\0'; X } X X if ((p = strchr(base, '.')) != NULL) { X strcpy(ext, p+1); X *p = '\0'; X } else X ext[0] = '\0'; X X /* X * Trim the base name if necessary. X */ X if (strlen(base) > 8) X base[8] = '\0'; X X if (strlen(ext) > 3) X ext[3] = '\0'; X X /* X * Paste it all back together X */ X strcat(f, base); X strcat(f, "."); X strcat(f, ext); X X return f; X} X Xvoid Xdoshell(cmd) Xchar *cmd; X{ X if (cmd == NULL) X cmd = "cmd.exe"; X X system(cmd); X wait_return(); X} X X/* X * FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT! X * X * The next couple of functions do system-specific stuff. X * They currently do nothing; I'm not familiar enough with X * system-specific programming on this system. X * If you fill it in for your system, please post the results X * and share with the rest of us. X */ X X Xsetcolor (c) X/* X * Set the color to c, using the local system convention for numbering X * colors or video attributes. X * X * If you implement this, remember to note the original color in X * windinit(), before you do any setcolor() commands, and X * do a setcolor() back to the original as part of windexit(). X */ X int c: X{ X} X X Xsetrows (r) X/* X * Set the number of lines to r, if possible. Otherwise X * "do the right thing". Return the number of lines actually set. X * X * If you implement this, remember to note the original number of rows X * in windinit(), before you do any setrows() commands, and X * do a setrows() back to the original as part of windexit(). X */ X int r; X{ X /* Since we do nothing, just return the current number of lines */ X return ( P(P_LI) ); X} X X Xvbeep () X/* X * Do a "visual bell". This generally consists of flashing the screen X * once in inverse video. X */ X{ X int color, revco; X X color = P( P_CO ); /* get current color */ X revco = reverse_color (color); /* system-specific */ X setcolor (revco); X flushbuf (); X pause (); X setcolor (color); X windgoto (Cursrow, Curscol); X flushbuf (); X} X Xreverse_color (co) X/* X * Returns the inverse video attribute or color of co. X * The existing code below is VERY simple-minded. X * Replace it with proper code for your system. X */ X int co; X{ X if (co) return (0); X else return (1); X} X X X/********** End of do-it-yourself kit **********************/ X END_OF_FILE if test 7126 -ne `wc -c <'stevie/os2.c'`; then echo shar: \"'stevie/os2.c'\" unpacked with wrong size! fi # end of 'stevie/os2.c' fi if test -f 'stevie/tagcmd.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie/tagcmd.c'\" else echo shar: Extracting \"'stevie/tagcmd.c'\" \(5019 characters\) sed "s/^X//" >'stevie/tagcmd.c' <<'END_OF_FILE' X/* #Header: /????? X * X * Routines to implement tags, and, especially, tag stacking. X * Added by Dave Tutelman - 12/89. X * The dotag() routine is a modification of the posted X * version by Tony Andrews. X * The untag() routine is new. X */ X X#include "stevie.h" X X#define LSIZE 256 /* max. size of a line in the tags file */ X X#ifdef TAGSTACK X/* We build a stack of file records, on which we push info about X * current file when dotag() is called. X */ X#define TAGSTACKSIZE 12 /* how many tag calls can we stack? */ Xstatic struct filerecord { X char *name; /* file name pointer */ X int linenum; /* line number when we left */ X} tagstack [TAGSTACKSIZE]; Xstatic int stackindex = 0; /* here's how we keep track */ X#endif X Xextern char **files; Xextern int curfile; Xstatic void pushtags(), poptags(); X X X/* X * dotag(tag, force) - goto tag. If force=TRUE, dump pending changes. X */ Xvoid Xdotag(tag, force) Xchar *tag; Xbool_t force; X{ X FILE *tp, *fopen(); X char lbuf[LSIZE]; /* line buffer */ X char pbuf[LSIZE]; /* search pattern buffer */ X register char *fname, *str; X register char *p; X X if ((tp = fopen("tags", "r")) == NULL) { X emsg("Can't open tags file"); X return; X } X X while (fgets(lbuf, LSIZE, tp) != NULL) { X X if ((fname = strchr(lbuf, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *fname++ = '\0'; X if ((str = strchr(fname, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *str++ = '\0'; X X if (strcmp(lbuf, tag) == 0) { X X /* X * Scan through the search string. If we see a magic X * char, we have to quote it. This lets us use "real" X * implementations of ctags. X */ X p = pbuf; X *p++ = *str++; /* copy the '/' or '?' */ X *p++ = *str++; /* copy the '^' */ X X for (; *str != NUL ;str++) { X if (*str == '\\') { X *p++ = *str++; X *p++ = *str; X } else if (strchr("/?", *str) != NULL) { X if (str[1] != '\n') { X *p++ = '\\'; X *p++ = *str; X } else X *p++ = *str; X } else if (strchr("^()*.", *str) != NULL) { X *p++ = '\\'; X *p++ = *str; X } else X *p++ = *str; X } X *p = NUL; X X#ifdef TAGSTACK X /* Push current position onto stack, unless this X * is a startup call using '-t' option. */ X if (Filename!=NULL && *Filename!='\0') X pushtags (); X#endif X X /* X * This looks out of order, but by calling stuffin() X * before doecmd() we keep an extra screen update X * from occuring. This stuffins() have no effect X * until we get back to the main loop, anyway. X */ X X stuffin(pbuf); /* str has \n at end */ X stuffin("\007"); /* CTRL('g') */ X X if (doecmd(fname, force)) { X fclose(tp); X return; X } else { X#ifdef TAGSTACK X poptags (); /* cancel stack entry */ X#endif X stuffin(NULL); /* clear the input */ X } X } X } X emsg("tag not found"); X fclose(tp); X} X X/* X * dountag (spec) - undo the last ':ta' command, popping the tag stack. X * spec is the appended character, giving specifics: X * '!' dump pending changes. X * 'e' came from K_CCIRCM "shortcut". do :e# if stack empty. X * ' ' do normal untag. X * else bad command. X */ X Xvoid Xdountag (spec) X char spec; X{ X#ifndef TAGSTACK X badcmd(); /* complain & return */ X} X#else X X char force=0, shortcut=0; X char *newfile; X char buf [LSIZE]; X X switch (spec) { X case '!': X force++; X break; X case 'e': X shortcut++; X break; X case ' ': X case '\n': X case '\r': X case '\0': X break; X default: X badcmd(); X return; X } X X /* Check the stack. If empty, don't pop */ X if (!stackindex) { X if (shortcut) /* just edit altfile */ X stuffin(":e #\n"); X else X emsg("Tags stack empty"); X return; X } X X /* Get the top of the stack, and do the implied edit. X * If it succeeds, switch; if not, back off */ X newfile = tagstack [stackindex-1].name; X if (doecmd (newfile, force)) { X sprintf (buf, "%dG:f\n", tagstack [stackindex-1].linenum); X stuffin(buf); X poptags (); X return; X } X else X stuffin(NULL); X} X X/* X * pushtags () - push the current state onto the tagstack. X */ X Xstatic void Xpushtags () X{ X int i; X X /* If stack full, throw away oldest and push the rest. X * This is clearly the best and most transparent way to behave, X * much preferable to either complaining or losing new entry. X */ X if (stackindex >= TAGSTACKSIZE) { X for (i=0; i'stevie/undo.c' <<'END_OF_FILE' X/* $Header: /nw/tony/src/stevie/src/RCS/undo.c,v 1.7 89/08/06 09:51:06 tony Exp $ X * X * Undo facility X * X * The routines in this file comprise a general undo facility for use X * throughout the rest of the editor. The routine u_save() is called X * before each edit operation to save the current contents of the lines X * to be editted. Later, u_undo() can be called to return those lines X * to their original state. The routine u_clear() should be called X * whenever a new file is going to be editted to clear the undo buffer. X */ X X#include "stevie.h" X X/* X * The next two variables mark the boundaries of the changed section X * of the file. Lines BETWEEN the lower and upper bounds are changed X * and originally contained the lines pointed to by u_lines. To undo X * the last change, insert the lines in u_lines between the lower and X * upper bounds. X */ Xstatic LINE *u_lbound = NULL; /* line just prior to first changed line */ Xstatic LINE *u_ubound = NULL; /* line just after the last changed line */ X Xstatic LINE *u_lline = NULL; /* bounds of the saved lines */ Xstatic LINE *u_uline = NULL; X Xstatic int u_col; Xstatic bool_t u_valid = FALSE; /* is the undo buffer valid */ X X/* X * Local forward declarations X */ Xstatic LINE *copyline(); Xstatic void u_lsave(); Xstatic void u_lfree(); X X/* X * u_save(l, u) - save the current contents of part of the file X * X * The lines between 'l' and 'u' are about to be changed. This routine X * saves their current contents into the undo buffer. The range l to u X * is not inclusive because when we do an open, for example, there aren't X * any lines in between. If no lines are to be saved, then l->next == u. X */ Xvoid Xu_save(l, u) XLINE *l, *u; X{ X LINE *nl; /* copy of the current line */ X X /* X * If l or u is null, there's an error. We don't return an X * indication to the caller. They should find the problem X * while trying to perform whatever edit is being requested X * (e.g. a join on the last line). X */ X if (l == NULL || u == NULL) X return; X X u_clear(); /* clear the buffer, first */ X X u_lsave(l, u); /* save to the "line undo" buffer, if needed */ X X u_lbound = l; X u_ubound = u; X X if (l->next != u) { /* there are lines in the middle */ X l = l->next; X u = u->prev; X X u_lline = nl = copyline(l); /* copy the first line */ X while (l != u) { X nl->next = copyline(l->next); X nl->next->prev = nl; X l = l->next; X nl = nl->next; X } X u_uline = nl; X } else X u_lline = u_uline = NULL; X X u_valid = TRUE; X u_col = Cursvcol; X} X X/* X * u_saveline() - save the current line in the undo buffer X */ Xvoid Xu_saveline() X{ X u_save(Curschar->linep->prev, Curschar->linep->next); X} X X/* X * u_undo() - effect an 'undo' operation X * X * The last edit is undone by restoring the modified section of the file X * to its original state. The lines we're going to trash are copied to X * the undo buffer so that even an 'undo' can be undone. Rings the bell X * if the undo buffer is empty. X */ Xvoid Xu_undo() X{ X LINE *tl, *tu; X X if (!u_valid) { X beep(); X return; X } X X /* X * Get the first line of the thing we're undoing on the screen. X */ X Curschar->linep = u_lbound->next; X Curschar->index = 0; /* for now */ X if (Curschar->linep == Fileend->linep) X Curschar->linep = Curschar->linep->prev; X cursupdate(); X X /* X * Save pointers to what's in the file now. X */ X if (u_lbound->next != u_ubound) { /* there are lines to get */ X tl = u_lbound->next; X tu = u_ubound->prev; X tl->prev = NULL; X tu->next = NULL; X } else X tl = tu = NULL; /* no lines between bounds */ X X /* X * Link the undo buffer into the right place in the file. X */ X if (u_lline != NULL) { /* there are lines in the undo buf */ X X /* X * If the top line of the screen is being undone, we need to X * fix up Topchar to point to the new line that will be there. X */ X if (u_lbound->next == Topchar->linep) X Topchar->linep = u_lline; X X u_lbound->next = u_lline; X u_lline->prev = u_lbound; X u_ubound->prev = u_uline; X u_uline->next = u_ubound; X } else { /* no lines... link the bounds */ X if (u_lbound->next == Topchar->linep) X Topchar->linep = u_ubound; X if (u_lbound == Filetop->linep) X Topchar->linep = u_ubound; X X u_lbound->next = u_ubound; X u_ubound->prev = u_lbound; X } X X /* X * If we swapped the top line, patch up Filemem appropriately. X */ X if (u_lbound == Filetop->linep) X Filemem->linep = Filetop->linep->next; X X /* X * Now save the old stuff in the undo buffer. X */ X u_lline = tl; X u_uline = tu; X X renum(); /* have to renumber everything */ X X /* X * Put the cursor on the first line of the 'undo' region. X */ X Curschar->linep = u_lbound->next; X Curschar->index = 0; X if (Curschar->linep == Fileend->linep) X Curschar->linep = Curschar->linep->prev; X *Curschar = *coladvance(Curschar, u_col); X cursupdate(); X updatescreen(); /* now show the change */ X X u_lfree(); /* clear the "line undo" buffer */ X} X X/* X * u_clear() - clear the undo buffer X * X * This routine is called to clear the undo buffer at times when the X * pointers are about to become invalid, such as when a new file is X * about to be editted. X */ Xvoid Xu_clear() X{ X LINE *l, *nextl; X X if (!u_valid) /* nothing to do */ X return; X X for (l = u_lline; l != NULL ;l = nextl) { X nextl = l->next; X free(l->s); X free((char *)l); X } X X u_lbound = u_ubound = u_lline = u_uline = NULL; X u_valid = FALSE; X} X X/* X * The following functions and data implement the "line undo" feature X * performed by the 'U' command. X */ X Xstatic LINE *u_line; /* pointer to the line we last saved */ Xstatic LINE *u_lcopy = NULL; /* local copy of the original line */ X X/* X * u_lfree() - free the line save buffer X */ Xstatic void Xu_lfree() X{ X if (u_lcopy != NULL) { X free(u_lcopy->s); X free((char *)u_lcopy); X u_lcopy = NULL; X } X u_line = NULL; X} X X/* X * u_lsave() - save the current line if necessary X */ Xstatic void Xu_lsave(l, u) XLINE *l, *u; X{ X X if (l->next != u->prev) { /* not changing exactly one line */ X u_lfree(); X return; X } X X if (l->next == u_line) /* more edits on the same line */ X return; X X u_lfree(); X u_line = l->next; X u_lcopy = copyline(l->next); X} X X/* X * u_lundo() - undo the current line (the 'U' command) X */ Xvoid Xu_lundo() X{ X if (u_lcopy != NULL) { X free(Curschar->linep->s); X Curschar->linep->s = u_lcopy->s; X Curschar->linep->size = u_lcopy->size; X free((char *)u_lcopy); X } else X beep(); X Curschar->index = 0; X X cursupdate(); X updatescreen(); /* now show the change */ X X u_lcopy = NULL; /* can't undo this kind of undo */ X u_line = NULL; X} X X/* X * u_lcheck() - clear the "line undo" buffer if we've moved to a new line X */ Xvoid Xu_lcheck() X{ X if (Curschar->linep != u_line) X u_lfree(); X} X X/* X * copyline(l) - copy the given line, and return a pointer to the copy X */ Xstatic LINE * Xcopyline(l) XLINE *l; X{ X LINE *nl; /* the new line */ X X nl = newline(strlen(l->s)); X strcpy(nl->s, l->s); X X return nl; X} END_OF_FILE if test 6821 -ne `wc -c <'stevie/undo.c'`; then echo shar: \"'stevie/undo.c'\" unpacked with wrong size! fi # end of 'stevie/undo.c' fi echo shar: End of archive 4 \(of 13\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 13 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0