jimomura@lsuc.UUCP (Jim Omura) (05/04/86)
Error: Unrecognized entry. Choices are: all, alsop, backward, comment, copy, date, download, duew, first, forward, header, help, last, original, quit, reference, resign, say, search, skip, to, unclop, upload, withdraw, No more unread Hit <RETURN> for next R:sh scracttch ========== os.9/public.domain #81, from jimomura, 3719 chars, Sat Mar 22 18:53:05 1986 ---------- TITLE: 'microEMACS' part 12 'uefile2.c' /* * The routines in this file * handle the reading and writing of * disk files. All of details about the * reading and writing of the disk are * in "fileio.c". */ #include <stdio.h> #include "ueed.h" /* * Save the contents of the current * buffer in its associatd file. No nothing * if nothing has changed (this may be a bug, not a * feature). Error if there is no remembered file * name for the buffer. Bound to "C-X C-S". May * get called by "C-Z". */ filesave(f, n) { register WINDOW *wp; register int s; if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */ return (TRUE); if (curbp->b_fname[0] == 0) { /* Must have a name. */ mlwrite("No file name"); return (FALSE); } if ((s=writeout(curbp->b_fname)) == TRUE) { curbp->b_flag &= ~BFCHG; wp = wheadp; /* Update mode lines. */ while (wp != NULL) { if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; wp = wp->w_wndp; } } return (s); } /* * This function performs the details of file * writing. Uses the file management routines in the * "fileio.c" package. The number of lines written is * displayed. Sadly, it looks inside a LINE; provide * a macro for this. Most of the grief is error * checking of some sort. */ writeout(fn) char *fn; { register int s; register LINE *lp; register int nline; if ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */ return (FALSE); lp = lforw(curbp->b_linep); /* First line. */ nline = 0; /* Number of lines. */ while (lp != curbp->b_linep) { if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC) break; ++nline; lp = lforw(lp); } if (s == FIOSUC) { /* No write error. */ s = ffclose(); if (s == FIOSUC) { /* No close error. */ if (nline == 1) mlwrite("[Wrote 1 line]"); else mlwrite("[Wrote %d lines]", nline); } } else /* Ignore close error */ ffclose(); /* if a write error. */ if (s != FIOSUC) /* Some sort of error. */ return (FALSE); return (TRUE); } /* * The command allows the user * to modify the file name associated with * the current buffer. It is like the "f" command * in UNIX "ed". The operation is simple; just zap * the name in the BUFFER structure, and mark the windows * as needing an update. You can type a blank line at the * prompt if you wish. */ filename(f, n) { register WINDOW *wp; register int s; char fname[NFILEN]; if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT) return (s); if (s == FALSE) strcpy(curbp->b_fname, ""); else strcpy(curbp->b_fname, fname); wp = wheadp; /* Update mode lines. */ while (wp != NULL) { if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; wp = wp->w_wndp; } return (TRUE); } ========== os.9/public.domain #82, from jimomura, 2796 chars, Sat Mar 22 18:58:32 1986 ---------- TITLE: 'microEMACS' part 13 'uefileio.c' /* * The routines in this file read and write ASCII files from the disk. All of * the knowledge about files are here. A better message writing scheme should * be used. */ #include <stdio.h> #include "ueed.h" FILE *ffp; /* File pointer, all functions. */ /* * Open a file for reading. */ ffropen(fn) char *fn; { if ((ffp=fopen(fn, "r")) == NULL) return (FIOFNF); return (FIOSUC); } /* * Open a file for writing. Return TRUE if all is well, and FALSE on error * (cannot create). */ ffwopen(fn) char *fn; { #ifdef VMS register int fd; if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0 || (ffp=fdopen(fd, "w")) == NULL) { #else if ((ffp=fopen(fn, "w")) == NULL) { #endif mlwrite("Cannot open file for writing"); return (FIOERR); } return (FIOSUC); } /* * Close a file. Should look at the status in all systems. */ ffclose() { #ifdef V7 if (fclose(ffp) != FALSE) { mlwrite("Error closing file"); return(FIOERR); } return(FIOSUC); #endif fclose(ffp); return (FIOSUC); } /* * Write a line to the already opened file. The "buf" points to the buffer, * and the "nbuf" is its length, less the free newline. Return the status. * Check only at the newline. */ ffputline(buf, nbuf) char buf[]; { register int i; for (i = 0; i < nbuf; ++i) putc(buf[i]&0xFF, ffp); putc('\n', ffp); if (ferror(ffp)) { mlwrite("Write I/O error"); return (FIOERR); } return (FIOSUC); } /* * Read a line from a file, and store the bytes in the supplied buffer. The * "nbuf" is the length of the buffer. Complain about long lines and lines * at the end of the file that don't have a newline present. Check for I/O * errors too. Return status. */ ffgetline(buf, nbuf) register char buf[]; { register int c; register int i; i = 0; while ((c = fgetc(ffp)) != EOF && c != '\n') { if (i >= nbuf-1) { mlwrite("File has long line"); return (FIOERR); } buf[i++] = c; } if (c == EOF) { if (ferror(ffp)) { mlwrite("File read error"); return (FIOERR); } if (i != 0) { mlwrite("File has funny line at EOF"); return (FIOERR); } return (FIOEOF); } buf[i] = 0; return (FIOSUC); } ========== os.9/public.domain #83, from jimomura, 7847 chars, Sat Mar 22 19:09:48 1986 ---------- TITLE: 'microEMACS' part 14 'ueline1.c' /* * The functions in this file are a general set of line management utilities. * They are the only routines that touch the text. They also touch the buffer * and window structures, to make sure that the necessary updating gets done. * There are routines in this file that handle the kill buffer too. It isn't * here for any good reason. * * Note that this code only updates the dot and mark values in the window list. * Since all the code acts on the current window, the buffer that we are * editing must be being displayed, which means that "b_nwnd" is non zero, * which means that the dot and mark values in the buffer headers are nonsense. */ #include <stdio.h> #include "ueed.h" #define NBLOCK 16 /* Line block chunk size */ #define KBLOCK 256 /* Kill buffer block size */ char *kbufp = NULL; /* Kill buffer data */ int kused = 0; /* # of bytes used in KB */ int ksize = 0; /* # of bytes allocated in KB */ /* * This routine allocates a block of memory large enough to hold a LINE * containing "used" characters. The block is always rounded up a bit. Return * a pointer to the new block, or NULL if there isn't any memory left. Print a * message in the message line if no space. */ LINE *lalloc(used) register int used; { register LINE *lp; register int size; size = (used+NBLOCK-1) & ~(NBLOCK-1); if (size == 0) /* Assume that an empty */ size = NBLOCK; /* line is for type-in. */ if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) { mlwrite("Cannot allocate %d bytes", size); return (NULL); } lp->l_size = size; lp->l_used = used; return (lp); } /* * Delete line "lp". Fix all of the links that might point at it (they are * moved to offset 0 of the next line. Unlink the line from whatever buffer it * might be in. Release the memory. The buffers are updated too; the magic * conditions described in the above comments don't hold here. */ lfree(lp) register LINE *lp; { register BUFFER *bp; register WINDOW *wp; wp = wheadp; while (wp != NULL) { if (wp->w_linep == lp) wp->w_linep = lp->l_fp; if (wp->w_dotp == lp) { wp->w_dotp = lp->l_fp; wp->w_doto = 0; } if (wp->w_markp == lp) { wp->w_markp = lp->l_fp; wp->w_marko = 0; } wp = wp->w_wndp; } bp = bheadp; while (bp != NULL) { if (bp->b_nwnd == 0) { if (bp->b_dotp == lp) { bp->b_dotp = lp->l_fp; bp->b_doto = 0; } if (bp->b_markp == lp) { bp->b_markp = lp->l_fp; bp->b_marko = 0; } } bp = bp->b_bufp; } lp->l_bp->l_fp = lp->l_fp; lp->l_fp->l_bp = lp->l_bp; free((char *) lp); } /* * This routine gets called when a character is changed in place in the current * buffer. It updates all of the required flags in the buffer and window * system. The flag used is passed as an argument; if the buffer is being * displayed in more than 1 window we change EDIT t HARD. Set MODE if the * mode line needs to be updated (the "*" has to be set). */ lchange(flag) register int flag; { register WINDOW *wp; if (curbp->b_nwnd != 1) /* Ensure hard. */ flag = WFHARD; if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */ flag |= WFMODE; /* update mode lines. */ curbp->b_flag |= BFCHG; } wp = wheadp; while (wp != NULL) { if (wp->w_bufp == curbp) wp->w_flag |= flag; wp = wp->w_wndp; } } /* * Insert "n" copies of the character "c" at the current location of dot. In * the easy case all that happens is the text is stored in the line. In the * hard case, the line has to be reallocated. When the window list is updated, * take special care; I screwed it up once. You always update dot in the * current window. You update mark, and a dot in another window, if it is * greater than the place where you did the insert. Return TRUE if all is * well, and FALSE on errors. */ linsert(n, c) { register char *cp1; register char *cp2; register LINE *lp1; register LINE *lp2; register LINE *lp3; register int doto; register int i; register WINDOW *wp; lchange(WFEDIT); lp1 = curwp->w_dotp; /* Current line */ if (lp1 == curbp->b_linep) { /* At the end: special */ if (curwp->w_doto != 0) { mlwrite("bug: linsert"); return (FALSE); } if ((lp2=lalloc(n)) == NULL) /* Allocate new line */ return (FALSE); lp3 = lp1->l_bp; /* Previous line */ lp3->l_fp = lp2; /* Link in */ lp2->l_fp = lp1; lp1->l_bp = lp2; lp2->l_bp = lp3; for (i=0; i<n; ++i) lp2->l_text[i] = c; curwp->w_dotp = lp2; curwp->w_doto = n; return (TRUE); } doto = curwp->w_doto; /* Save for later. */ if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */ if ((lp2=lalloc(lp1->l_used+n)) == NULL) return (FALSE); cp1 = &lp1->l_text[0]; cp2 = &lp2->l_text[0]; while (cp1 != &lp1->l_text[doto]) *cp2++ = *cp1++; cp2 += n; while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++; lp1->l_bp->l_fp = lp2; lp2->l_fp = lp1->l_fp; lp1->l_fp->l_bp = lp2; lp2->l_bp = lp1->l_bp; free((char *) lp1); } else { /* Easy: in place */ lp2 = lp1; /* Pretend new line */ lp2->l_used += n; cp2 = &lp1->l_text[lp1->l_used]; cp1 = cp2-n; while (cp1 != &lp1->l_text[doto]) *--cp2 = *--cp1; } for (i=0; i<n; ++i) /* Add the characters */ lp2->l_text[doto+i] = c; wp = wheadp; /* Update windows */ while (wp != NULL) { if (wp->w_linep == lp1) wp->w_linep = lp2; if (wp->w_dotp == lp1) { wp->w_dotp = lp2; if (wp==curwp || wp->w_doto>doto) wp->w_doto += n; } if (wp->w_markp == lp1) { wp->w_markp = lp2; if (wp->w_marko > doto) wp->w_marko += n; } wp = wp->w_wndp; } return (TRUE); } ========== os.9/public.domain #84, from jimomura, 10631 chars, Sat Mar 22 19:25:11 1986 ---------- TITLE: 'microEMACS' part 15 'ueline2.c' /* * The functions in this file are a general set of line management utilities. * They are the only routines that touch the text. They also touch the buffer * and window structures, to make sure that the necessary updating gets done. * There are routines in this file that handle the kill buffer too. It i sn't * here for any good reason. * * Note that this code only updates the dot and mark values in the window list. * Since all the code acts on the current window, the buffer that we are * editing must be being displayed, which means that "b_nwnd" is non zero, * which means that the dot and mark values in the buffer headers are nonsense. */ #include <stdio.h> #include "ueed.h" #define NBLOCK 16 /* Line block chunk size */ #define KBLOCK 256 /* Kill buffer block size */ extern char *kbufp; /* Kill buffer data */ extern int kused; /* # of bytes used in KB */ extern int ksize; /* # of bytes allocated in KB */ /* * Insert a newline into the buffer at the current location of dot in the * current window. The funny ass-backwards way it does things is not a botch; * it just makes the last line in the file not a special case. Return TRUE if * everything works out and FALSE on error (memory allocation failure). The * update of dot and mark is a bit easier then in the above case, because the * split forces more updating. */ lnewline() { register char *cp1; register char *cp2; register LINE *lp1; register LINE *lp2; register int doto; register WINDOW *wp; lchange(WFHARD); lp1 = curwp->w_dotp; /* Get the address and */ doto = curwp->w_doto; /* offset of "." */ if ((lp2=lalloc(doto)) == NULL) /* New first half line */ return (FALSE); cp1 = &lp1->l_text[0]; /* Shuffle text around */ cp2 = &lp2->l_text[0]; while (cp1 != &lp1->l_text[doto]) *cp2++ = *cp1++; cp2 = &lp1->l_text[0]; while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++; lp1->l_used -= doto; lp2->l_bp = lp1->l_bp; lp1->l_bp = lp2; lp2->l_bp->l_fp = lp2; lp2->l_fp = lp1; wp = wheadp; /* Windows */ while (wp != NULL) { if (wp->w_linep == lp1) wp->w_linep = lp2; if (wp->w_dotp == lp1) { if (wp->w_doto < doto) wp->w_dotp = lp2; else wp->w_doto -= doto; } if (wp->w_markp == lp1) { if (wp->w_marko < doto) wp->w_markp = lp2; else wp->w_marko -= doto; } wp = wp->w_wndp; } return (TRUE); } /* * This function deletes "n" bytes, starting at dot. It understands how do deal * with end of lines, etc. It returns TRUE if all of the characters were * deleted, and FALSE if they were not (because dot ran into the end of the * buffer. The "kflag" is TRUE if the text should be put in the kill buffer. */ ldelete(n, kflag) { register char *cp1; register char *cp2; register LINE *dotp; register int doto; register int chunk; register WINDOW *wp; while (n != 0) { dotp = curwp->w_dotp; doto = curwp->w_doto; if (dotp == curbp->b_linep) /* Hit end of buffer. */ return (FALSE); chunk = dotp->l_used-doto; /* Size of chunk. */ if (chunk > n) chunk = n; if (chunk == 0) { /* End of line, merge. */ lchange(WFHARD); if (ldelnewline() == FALSE || (kflag!=FALSE && kinsert('\n')==FALSE)) return (FALSE); --n; continue; } lchange(WFEDIT); cp1 = &dotp->l_text[doto]; /* Scrunch text. */ cp2 = cp1 + chunk; if (kflag != FALSE) { /* Kill? */ while (cp1 != cp2) { if (kinsert(*cp1) == FALSE) return (FALSE); ++cp1; } cp1 = &dotp->l_text[doto]; } while (cp2 != &dotp->l_text[dotp->l_used]) *cp1++ = *cp2++; dotp->l_used -= chunk; wp = wheadp; /* Fix windows */ while (wp != NULL) { if (wp->w_dotp==dotp && wp->w_doto>=doto) { wp->w_doto -= chunk; if (wp->w_doto < doto) wp->w_doto = doto; } if (wp->w_markp==dotp && wp->w_marko>=doto) { wp->w_marko -= chunk; if (wp->w_marko < doto) wp->w_marko = doto; } wp = wp->w_wndp; } n -= chunk; } return (TRUE); } /* * Delete a newline. Join the current line with the next line. If the next line * is the magic header line always return TRUE; merging the last line with the * header line can be thought of as always being a successful operation, even * if nothing is done, and this makes the kill buffer work "right". Easy cases * can be done by shuffling data around. Hard cases require that lines be moved * about in memory. Return FALSE on error and TRUE if all looks ok. Called by * "ldelete" only. */ ldelnewline() { register char *cp1; register char *cp2; register LINE *lp1; register LINE *lp2; register LINE *lp3; register WINDOW *wp; lp1 = curwp->w_dotp; lp2 = lp1->l_fp; if (lp2 == curbp->b_linep) { /* At the buffer end. */ if (lp1->l_used == 0) /* Blank line. */ lfree(lp1); return (TRUE); } if (lp2->l_used <= lp1->l_size-lp1->l_used) { cp1 = &lp1->l_text[lp1->l_used]; cp2 = &lp2->l_text[0]; while (cp2 != &lp2->l_text[lp2->l_used]) *cp1++ = *cp2++; wp = wheadp; while (wp != NULL) { if (wp->w_linep == lp2) wp->w_linep = lp1; if (wp->w_dotp == lp2) { wp->w_dotp = lp1; wp->w_doto += lp1->l_used; } if (wp->w_markp == lp2) { wp->w_markp = lp1; wp->w_marko += lp1->l_used; } wp = wp->w_wndp; } lp1->l_used += lp2->l_used; lp1->l_fp = lp2->l_fp; lp2->l_fp->l_bp = lp1; free((char *) lp2); return (TRUE); } if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL) return (FALSE); cp1 = &lp1->l_text[0]; cp2 = &lp3->l_text[0]; while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++; cp1 = &lp2->l_text[0]; while (cp1 != &lp2->l_text[lp2->l_used]) *cp2++ = *cp1++; lp1->l_bp->l_fp = lp3; lp3->l_fp = lp2->l_fp; lp2->l_fp->l_bp = lp3; lp3->l_bp = lp1->l_bp; wp = wheadp; while (wp != NULL) { if (wp->w_linep==lp1 || wp->w_linep==lp2) wp->w_linep = lp3; if (wp->w_dotp == lp1) wp->w_dotp = lp3; else if (wp->w_dotp == lp2) { wp->w_dotp = lp3; wp->w_doto += lp1->l_used; } if (wp->w_markp == lp1) wp->w_markp = lp3; else if (wp->w_markp == lp2) { wp->w_markp = lp3; wp->w_marko += lp1->l_used; } wp = wp->w_wndp; } free((char *) lp1); free((char *) lp2); return (TRUE); } /* * Delete all of the text saved in the kill buffer. Called by commands when a * new kill context is being created. The kill buffer array is released, just * in case the buffer has grown to immense size. No errors. */ kdelete() { if (kbufp != NULL) { free((char *) kbufp); kbufp = NULL; kused = 0; ksize = 0; } } /* * Insert a character to the kill buffer, enlarging the buffer if there isn't * any room. Always grow the buffer in chunks, on the assumption that if you * put something in the kill buffer you are going to put more stuff there too * later. Return TRUE if all is well, and FALSE on errors. */ kinsert(c) { register char *nbufp; register int i; if (kused == ksize) { if ((nbufp=malloc(ksize+KBLOCK)) == NULL) return (FALSE); for (i=0; i<ksize; ++i) nbufp[i] = kbufp[i]; if (kbufp != NULL) free((char *) kbufp); kbufp = nbufp; ksize += KBLOCK; } kbufp[kused++] = c; return (TRUE); } /* * This function gets characters from the kill buffer. If the character index * "n" is off the end, it returns "-1". This lets the caller just scan along * until it gets a "-1" back. */ kremove(n) { if (n >= kused) return (-1); else return (kbufp[n] & 0xFF); } ========== os.9/public.domain #85, from jimomura, 2886 chars, Sat Mar 22 19:30:20 1986 ---------- TITLE: 'microEMACS' part 16 'uemacs.doc' MicroEMACS control sequences for 6809 OS9 version For Os9/68000 consult the source code. Note: For the Color Computer /TERM version, the <esc> key is <clear> and <break> keys together. <ctrl> is the <clear> key. del is the <<-> key. The window commands have been deleted. Therefore, there is only one window. <ctrl-@> Set Mark at current position. <ctrl-A> Move cursor to beginning of line. <ctrl-B> Move cursor BACK one character. <ctrl-C> Push to a new interactive command shell. <ctrl-D> DELETE current current character. <ctrl-E> Move cursor to END of line. <ctrl-F> Move cursor FORWARD one character. <ctrl-G> Abort any command. (shades of Teco). <ctrl-H> (backspace) delete previous character. <ctrl-K> KILL (delete) to end of line. <ctrl-L> Redisplay screen. <ctrl-N> Move cursor to NEXT line. <ctrl-O> OPEN a new line. <ctrl-P> Move to PREVIOUS line. <ctrl-Q> QUOTE the next character (insert the next character typed). <ctrl-R> REVERSE Search. <ctrl-S> Forward SEARCH. <ctrl-T> TRANSPOSE characters. <ctrl-U> Enter repeat count for next command. <ctrl-V> VIEW the next screen (scroll up one screen). <ctrl-W> Kill region (all text between cursor and last mark set). <ctrl-Y> YANK (undelete) last text killed (deleted). <ctrl-Z> Save file in current buffer and exit. <ctrl-X>= Show buffer statistics: X=cc Y=ll CH=$$ .=loc (nn% of total chars) <ctrl-X>( Begin keyboard Macro. <ctrl-X>) End keyboard Macro. <ctrl-X>E EXECUTE keyboard macro. <ctrl-X><ctrl-C> Exit without saving buffers. <ctrl-X><ctrl-N> Scroll current window up by repeat count lines. <ctrl-X><ctrl-P> Scroll current window down by repeat count lines. <ctrl-X><ctrl-R> READ file into current buffer. <ctrl-X><ctrl-S> SAVE (write) current buffer into its file. <ctrl-X><ctrl-W> WRITE buffer to file. <ctrl-X><ctrl-U> UPPERCASE region between cursor and mark. <ctrl-X><ctrl-L> LOWERCASE region between cursor and mark. <ctrl-X><ctrl-X> Swap cursor and mark positions. <del> delete previous character. <esc>. Set Mark at current position. <esc>! Move current line to repeat count lines from top of window. <esc>> Move cursor to end of buffer. <esc>< Move cursor to beginning of buffer. <esc>B Move cursor BACK one word. <esc>C CAPITALIZE (Capitalize) word. <esc>D DELETE next word. <esc><del> DELETE previous word. <esc>F Move cursor FORWARD one word. <esc>L LOWERCASE (lowercase) next word. <esc>U UPPERCASE (UPPERCASE) next word. <esc>V VIEW the previous screen (scroll down one screen). -- James Omura, Barrister & Solicitor, Toronto ihnp4!utzoo!lsuc!jimomura Byte Information eXchange: jimomura (416) 652-3880