ustel@well.UUCP (Mark Hargrove) (02/11/88)
Comp.sources.misc: Volume 2, Issue 51 Submitted-By: "Mark Hargrove" <ustel@well.UUCP> Archive-Name: accell-text/Part2 #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./fileio.c` then echo "writing ./fileio.c" cat > ./fileio.c << '\Rogue\Monster\' /* * Name: MicroEMACS * System V file I/O */ #include "def.h" # ifndef F_OK # define F_OK 0 # define X_OK 1 # define W_OK 2 # define R_OK 4 # endif /* * Move bytes, overlaps OK (daveb). * * Doesn't really belong here, but it's system specific since it * is in assembler in some C libraries. */ bcopy( from, to, cnt ) char *from; char *to; int cnt; { if ( from == to ) return; if( from > to ) { while( cnt-- ) *to++ = *from++; } else { to += cnt; from += cnt; while( cnt-- ) *--to = *--from; } } static FILE *ffp; /* * 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; { if ((ffp=fopen(fn, "w")) == NULL) { ewprintf("Cannot open file for writing"); return (FIOERR); } return (FIOSUC); } /* * Close a file. * Should look at the status. */ ffclose() { (VOID) 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) register char buf[]; { register int i; for (i=0; i<nbuf; ++i) putc(buf[i]&0xFF, ffp); putc('\n', ffp); if (ferror(ffp) != FALSE) { ewprintf("Write I/O error"); return (FIOERR); } return (FIOSUC); } /* * Read a line from a file, and store the bytes * in the supplied buffer. Stop on end of file or end of * line. Don't get upset by files that don't have an end of * line on the last line; this seem to be common on CP/M-86 and * MS-DOS (the suspected culprit is VAX/VMS kermit, but this * has not been confirmed. If this is sufficiently researched * it may be possible to pull this kludge). Delete any CR * followed by an LF. This is mainly for runoff documents, * both on VMS and on Ultrix (they get copied over from * VMS systems with DECnet). */ ffgetline(buf, nbuf) register char buf[]; { register int c; register int i; i = 0; for (;;) { c = getc(ffp); if (c == '\r') { /* Delete any non-stray */ c = getc(ffp); /* carriage returns. */ if (c != '\n') { if (i >= nbuf-1) { ewprintf("File has long line"); return (FIOERR); } buf[i++] = '\r'; } } if (c==EOF || c=='\n') /* End of line. */ break; if (i >= nbuf-1) { ewprintf("File has long line"); return (FIOERR); } buf[i++] = c; } if (c == EOF) { /* End of file. */ if (ferror(ffp) != FALSE) { ewprintf("File read error"); return (FIOERR); } if (i == 0) /* Don't get upset if */ return (FIOEOF); /* no newline at EOF. */ } buf[i] = 0; return (FIOSUC); } #if BACKUP /* * Rename the file "fname" into a backup * copy. On Unix the backup has the same name as the * original file, with a "~" on the end; this seems to * be newest of the new-speak. The error handling is * all in "file.c". The "unlink" is perhaps not the * right thing here; I don't care that much as * I don't enable backups myself. */ fbackupfile(fname) char *fname; { register char *nname; if ((nname=malloc(strlen(fname)+1+1)) == NULL) return (ABORT); (void) strcpy(nname, fname); (void) strcat(nname, "~"); (void) unlink(nname); /* Ignore errors. */ /* no rename on System V, so do it dangerous way. */ if ( link(fname, nname) < 0 || unlink(fname) < 0 ) { free(nname); return (FALSE); } free(nname); return (TRUE); } #endif /* * The string "fn" is a file name. * Perform any required case adjustments. All sustems * we deal with so far have case insensitive file systems. * We zap everything to lower case. The problem we are trying * to solve is getting 2 buffers holding the same file if * you visit one of them with the "caps lock" key down. * On UNIX file names are dual case, so we leave * everything alone. */ /*ARGSUSED*/ adjustcase(fn) register char *fn; { #if 0 register int c; while ((c = *fn) != 0) { if (c>='A' && c<='Z') *fn = c + 'a' - 'A'; ++fn; } #endif } #ifdef STARTUP #include <sys/types.h> #include <sys/file.h> /* * find the users startup file, and return it's name. Check for * $HOME/.mg then for $HOME/.emacs, then give up. */ char * startupfile() { register char *file; static char home[NFILEN]; char *getenv(); if ( (file = getenv("HOME")) == NULL || strlen(file)+7 >= NFILEN - 1 ) return NULL; (VOID) strcpy(home, file); file = &(home[strlen(home)]); *file++ = '/'; (VOID) strcpy(file, ".mg"); if (access(home, F_OK ) == 0) return home; (VOID) strcpy(file, ".emacs"); if (access(home, F_OK) == 0) return home; return NULL; } #endif \Rogue\Monster\ else echo "will not over write ./fileio.c" fi if `test ! -s ./kbd.c` then echo "writing ./kbd.c" cat > ./kbd.c << '\Rogue\Monster\' /* * Terminal independent keyboard handling. */ #include "def.h" static mapin(); #ifdef DPROMPT #define PROMPTL 80 char prompt[PROMPTL], *promptp; #endif /* * All input from the user (should!) go through * getkey. Quotep is true to get raw keys, false to * get 11-bit code keys. * Getkey is responsible for putting keystrokes away * for macros. It also takes keystrokes out of the macro, * though other input routines will can also do this. * Read in a key, doing the terminal * independent prefix handling. The terminal specific * "getkbd" routine gets the first swing, and may return * one of the special codes used by the special keys * on the keyboard. The "getkbd" routine returns the * C0 controls as received; this routine moves them to * the right spot in 11 bit code. * If the KPROMPT bit in the flags is set and DPROMPT is * defined, do delayed prompting. (dprompt routine is * in sys/???/ttyio.c) */ KEY getkey(f) register int f; { register KEY c; KEY keychar(); int getkbd(), ttgetc(); if (kbdmop != NULL) return *kbdmop++; #ifdef DPROMPT if(!(f&KPROMPT)) prompt[0] = '\0'; #endif c = (KEY) mapin(getkbd); #ifdef DPROMPT if(f&KPROMPT) { if(promptp > prompt) *(promptp-1) = ' '; if(promptp >= &prompt[PROMPTL-8]) f &= ~KPROMPT; /* must have a lot of prefixes.... */ } #endif if ((f&KQUOTE) == 0) { #ifdef DO_METAKEY if ((c & ~KCHAR) == KCTRL) /* Function key */ c = ((char) c) & KCHAR;/* remove wrapping */ else if ((c >= 0x80) && (c <= 0xFF)) { /* real meta key */ c = ((char) c) & 0x7f; /* Get the key and mode map it */ if ((mode&MFLOW) != 0) if (c == CCHR('^')) c = CCHR('Q'); else if (c == CCHR('\\')) c = CCHR('S'); if ((mode&MBSMAP) != 0) if (c == CCHR('H')) c = 0x7f; else if (c == 0x7f) c = CCHR('H'); c = KMETA | keychar(c & ~0x80, TRUE); } #endif #ifdef DPROMPT if(f&KPROMPT) { keyname(promptp, (c<=0x1F && c>=0x00)?KCTRL|(c+'@'):c); strcat(promptp, "-"); } #endif if (c == METACH) /* M- */ c = KMETA | keychar(mapin(ttgetc), TRUE); else if (c == CTRLCH) /* C- */ c = KCTRL | keychar(mapin(ttgetc), TRUE); else if (c == CTMECH) /* C-M- */ c = KCTRL | KMETA | keychar(mapin(ttgetc), TRUE); else if (c<=0x1F && c>=0x00) /* Relocate control. */ c = KCTRL | (c+'@'); if (c == (KCTRL|'X')) /* C-X */ c = KCTLX | keychar(mapin(ttgetc), TRUE); } if ((f&KNOMAC) == 0 && kbdmip != NULL) { if (kbdmip+1 > &kbdm[NKBDM-3]) { /* macro overflow */ (VOID) ctrlg(FALSE, 0, KRANDOM); ewprintf("Keyboard macro overflow"); ttflush(); return (KCTRL|'G'); /* ^G it for us */ } *kbdmip++ = c; } #ifdef DPROMPT if(f&KPROMPT) { keyname(promptp, c); promptp += strlen(promptp); *promptp++ = '-'; *promptp = '\0'; } #endif return (c); } /* * go get a key, and run it through whatever mapping the modes * specify. */ static mapin(get) int (*get)(); { register int c; #ifdef DPROMPT if(prompt[0]!='\0' && ttwait()) { ewprintf("%s", prompt); /* avoid problems with % */ update(); /* put the cursor back */ epresf = KPROMPT; } #endif c = (*get)(); if ((mode&MFLOW) != 0) { while (c == CCHR('S') || c == CCHR('Q')) c = (*get)(); if (c == CCHR('^')) c = CCHR('Q'); else if (c == CCHR('\\')) c = CCHR('S'); } if ((mode&MBSMAP) != 0) if (c == CCHR('H')) c = 0x7f; else if (c == 0x7f) c = CCHR('H'); return c; } /* * Transform a key code into a name, * using a table for the special keys and combination * of some hard code and some general processing for * the rest. None of this code is terminal specific any * more. This makes adding keys easier. */ VOID keyname(cp, k) register char *cp; register int k; { register char *np; register int c; char nbuf[3]; static char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; if ((k&KCTLX) != 0) { /* C-X prefix. */ *cp++ = 'C'; *cp++ = '-'; *cp++ = 'x'; *cp++ = ' '; } if ((k&KMETA) != 0) { /* Add M- mark. */ *cp++ = 'E'; *cp++ = 'S'; *cp++ = 'C'; *cp++ = ' '; } if ((k&KCHAR)>=KFIRST && (k&KCHAR)<=KLAST) { if ((np=keystrings[(k&KCHAR)-KFIRST]) != NULL) { if ((k&KCTRL) != 0) { *cp++ = 'C'; *cp++ = '-'; } (VOID) strcpy(cp, np); return; } } c = k & ~(KMETA|KCTLX); if (c == (KCTRL|'I')) /* Some specials. */ np = "TAB"; else if (c == (KCTRL|'M')) np = "RET"; else if (c == (KCTRL|'J')) np = "LFD"; else if (c == ' ') np = "SPC"; else if (c == 0x7F) np = "DEL"; else if (c == (KCTRL|'[')) np = "ESC"; else { if ((k&KCTRL) != 0) { /* Add C- mark. */ *cp++ = 'C'; *cp++ = '-'; } if ((k&(KCTRL|KMETA|KCTLX)) != 0 && ISUPPER(k&KCHAR) != FALSE) k = TOLOWER(k&KCHAR); np = &nbuf[0]; if (((k&KCHAR)>=0x20 && (k&KCHAR)<=0x7E) || ((k&KCHAR)>=0xA0 && (k&KCHAR)<=0xFE)) { nbuf[0] = k&KCHAR; /* Graphic. */ nbuf[1] = 0; } else { /* Non graphic. */ nbuf[0] = hex[(k>>4)&0x0F]; nbuf[1] = hex[k&0x0F]; nbuf[2] = 0; } } (VOID) strcpy(cp, np); } /* * turn a key into an internal char. */ KEY keychar(c, f) register int c, f; { if (f == TRUE && ISLOWER(c) != FALSE) c = TOUPPER(c); else if (c>=0x00 && c<=0x1F) /* Relocate control. */ c = (KCTRL|(c+'@')); return (KEY) c; } \Rogue\Monster\ else echo "will not over write ./kbd.c" fi if `test ! -s ./line.c` then echo "writing ./line.c" cat > ./line.c << '\Rogue\Monster\' /* * Text line handling. * 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 "def.h" #define NBLOCK 16 /* Line block chunk size */ #ifndef KBLOCK #define KBLOCK 256 /* Kill buffer block size. */ #endif static char *kbufp = NULL; /* Kill buffer data. */ static RSIZE kused = 0; /* # of bytes used in KB. */ static RSIZE ksize = 0; /* # of bytes allocated in KB. */ static RSIZE kstart = 0; /* # of first used byte in KB. */ char *malloc(); /* * 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 RSIZE used; { register LINE *lp; register int size; /*NOSTRICT*/ size = (NBLOCK-1+used) & ~(NBLOCK-1); if (size == 0) /* Assume that an empty */ size = NBLOCK; /* line is for type-in. */ /*NOSTRICT*/ if ((lp=(LINE *)malloc(sizeof(LINE)+size)) == NULL) { ewprintf("Can't get %d bytes", sizeof(LINE) + size); return (NULL); } lp->l_size = size; /*NOSTRICT*/ 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. */ VOID 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 to * HARD. Set MODE if the mode line needs to be * updated (the "*" has to be set). * Modified by Walter Bright to reduce update times. */ VOID lchange(flag) register int flag; { register WINDOW *wp; 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; if (wp != curwp) wp->w_flag |= WFHARD; } 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. * * Added 11-1-87 by s.k.henry: overstrike mode for text insertion. * Not too hard, mostly just modifies the meaning of 'n'. */ linsert(n, c) RSIZE n; { register char *cp1; register char *cp2; register LINE *lp1; LINE *lp2; LINE *lp3; register int doto; register RSIZE i; WINDOW *wp; #ifndef max #define max(a,b) ((a) > (b)) ? (a) : (b) #endif lchange(WFEDIT); lp1 = curwp->w_dotp; /* Current line */ if (lp1 == curbp->b_linep) /* At the end: special */ { if (curwp->w_doto != 0) { ewprintf("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; 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->w_markp == lp1) wp->w_markp = lp2; wp = wp->w_wndp; } /*NOSTRICT*/ curwp->w_doto = n; return (TRUE); } doto = curwp->w_doto; /* Save for later. */ #define INS_MODE ((mode & MOVRSTK) == 0) #define OVR_MODE ((mode & MOVRSTK) == MOVRSTK) /*NOSTRICT*/ if ((OVR_MODE && (doto+n > lp1->l_size)) || (INS_MODE && (lp1->l_used+n > lp1->l_size))) { /* Hard: reallocate */ if ((lp2=lalloc((RSIZE) (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++; if (INS_MODE) { /*NOSTRICT*/ 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 */ if (INS_MODE) { /*NOSTRICT*/ lp2->l_used += n; cp2 = &lp1->l_text[lp1->l_used]; cp1 = cp2-n; while (cp1 != &lp1->l_text[doto]) *--cp2 = *--cp1; } else { /*NOSTRICT*/ lp2->l_used = max( (doto+n), (lp2->l_used)); } } 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) /*NOSTRICT*/ wp->w_doto += n; } if (wp->w_markp == lp1) { wp->w_markp = lp2; if (wp->w_marko > doto) /*NOSTRICT*/ wp->w_marko += n; } wp = wp->w_wndp; } return (TRUE); } /* * 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; LINE *lp2; register int doto; WINDOW *wp; lchange(WFHARD); lp1 = curwp->w_dotp; /* Get the address and */ doto = curwp->w_doto; /* offset of "." */ if ((lp2=lalloc((RSIZE) 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" indicates either no insertion, * or direction of insertion into the kill buffer. */ ldelete(n, kflag) RSIZE n; { register char *cp1; register char *cp2; register LINE *dotp; register int doto; register RSIZE chunk; WINDOW *wp; /* * HACK - doesn't matter, and fixes back-over-nl bug for empty * kill buffers. */ if (kused == kstart) kflag = KFORW; 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!=KNONE && kinsert('\n', kflag)==FALSE)) return (FALSE); --n; continue; } lchange(WFEDIT); cp1 = &dotp->l_text[doto]; /* Scrunch text. */ cp2 = cp1 + chunk; if (kflag == KFORW) { while (ksize - kused < chunk) if (kgrow(FALSE) == FALSE) return FALSE; bcopy(cp1, &(kbufp[kused]), (int) chunk); kused += chunk; } else if (kflag == KBACK) { while (kstart < chunk) if (kgrow(TRUE) == FALSE) return FALSE; bcopy(cp1, &(kbufp[kstart-chunk]), (int) chunk); kstart -= chunk; } else if (kflag != KNONE) panic("broken ldelete call"); while (cp2 != &dotp->l_text[dotp->l_used]) *cp1++ = *cp2++; dotp->l_used -= (int) chunk; wp = wheadp; /* Fix windows */ while (wp != NULL) { if (wp->w_dotp==dotp && wp->w_doto>=doto) { /*NOSTRICT*/ wp->w_doto -= chunk; if (wp->w_doto < doto) wp->w_doto = doto; } if (wp->w_markp==dotp && wp->w_marko>=doto) { /*NOSTRICT*/ 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. */ ldelnewline() { register char *cp1; register char *cp2; register LINE *lp1; LINE *lp2; LINE *lp3; 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((RSIZE) (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); } /* * Replace plen characters before dot with argument string. * Control-J characters in st are interpreted as newlines. * There is a casehack disable flag (normally it likes to match * case of replacement to what was there). */ lreplace(plen, st, f) register RSIZE plen; /* length to remove */ char *st; /* replacement string */ int f; /* case hack disable */ { register RSIZE rlen; /* replacement length */ register int rtype; /* capitalization */ register int c; /* used for random characters */ register int doto; /* offset into line */ /* * Find the capitalization of the word that was found. * f says use exact case of replacement string (same thing that * happens with lowercase found), so bypass check. */ /*NOSTRICT*/ (VOID) backchar(TRUE, (int) plen, KRANDOM); rtype = _L; c = lgetc(curwp->w_dotp, curwp->w_doto); if (ISUPPER(c)!=FALSE && f==FALSE) { rtype = _U|_L; if (curwp->w_doto+1 < llength(curwp->w_dotp)) { c = lgetc(curwp->w_dotp, curwp->w_doto+1); if (ISUPPER(c) != FALSE) { rtype = _U; } } } /* * make the string lengths match (either pad the line * so that it will fit, or scrunch out the excess). * be careful with dot's offset. */ rlen = strlen(st); doto = curwp->w_doto; if (plen > rlen) (VOID) ldelete((RSIZE) (plen-rlen), KNONE); else if (plen < rlen) { if (linsert((RSIZE) (rlen-plen), ' ') == FALSE) return (FALSE); } curwp->w_doto = doto; /* * do the replacement: If was capital, then place first * char as if upper, and subsequent chars as if lower. * If inserting upper, check replacement for case. */ while ((c = *st++&0xff) != '\0') { if ((rtype&_U)!=0 && ISLOWER(c)!=0) c = TOUPPER(c); if (rtype == (_U|_L)) rtype = _L; if (c == SEOL) { if (curwp->w_doto == llength(curwp->w_dotp)) (VOID) forwchar(FALSE, 1, KRANDOM); else { if (ldelete((RSIZE) 1, KNONE) != FALSE) (VOID) lnewline(); } } else if (curwp->w_dotp == curbp->b_linep) { (VOID) linsert((RSIZE) 1, c); } else if (curwp->w_doto == llength(curwp->w_dotp)) { if (ldelete((RSIZE) 1, KNONE) != FALSE) (VOID) linsert((RSIZE) 1, c); } else lputc(curwp->w_dotp, curwp->w_doto++, c); } lchange(WFHARD); 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. */ VOID kdelete() { if (kbufp != NULL) { free((char *) kbufp); kbufp = NULL; kstart = kused = 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. Print a message on * errors. Dir says whether to put it at back or front. */ kinsert(c, dir) { if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE) return FALSE; if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE) return FALSE; if (dir == KFORW) kbufp[kused++] = c; else if (dir == KBACK) kbufp[--kstart] = c; else panic("broken kinsert call"); /* Oh shit! */ return (TRUE); } /* * kgrow - just get more kill buffer for the callee. back is true if * we are trying to get space at the beginning of the kill buffer. */ kgrow(back) { register int nstart; register char *nbufp; if ((nbufp=malloc((int)(ksize+KBLOCK))) == NULL) { ewprintf("Can't get %ld bytes", (long)(ksize+KBLOCK)); return (FALSE); } nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4) ; bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int) (kused-kstart)); if (kbufp != NULL) free((char *) kbufp); kbufp = nbufp; ksize += KBLOCK; kused = kused - kstart + nstart; kstart = nstart; 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 < 0 || n + kstart >= kused) return (-1); return (kbufp[n + kstart] & 0xFF); } \Rogue\Monster\ else echo "will not over write ./line.c" fi if `test ! -s ./main.c` then echo "writing ./main.c" cat > ./main.c << '\Rogue\Monster\' /* * Mainline, macro commands. */ #include "def.h" int thisflag; /* Flags, this command */ int lastflag; /* Flags, last command */ int curgoal; /* Goal column */ BUFFER *curbp; /* Current buffer */ WINDOW *curwp; /* Current window */ BUFFER *bheadp; /* BUFFER listhead */ WINDOW *wheadp = (WINDOW *)NULL; /* WINDOW listhead */ KEY kbdm[NKBDM] = {(KCTLX|')')}; /* Macro */ KEY *kbdmip; /* Input for above */ KEY *kbdmop; /* Output for above */ char pat[NPAT]; /* Pattern */ #ifdef HASH SYMBOL *symbol[NSHASH]; /* Symbol table listhead. */ #else /* should really be a *symbol, but don't want to break the hash code yet */ SYMBOL *symbol[1] = {(SYMBOL *)NULL}; #endif SYMBOL *binding[NKEYS]; /* Key bindings. */ #ifdef DPROMPT extern char prompt[], *promptp; /* delayed prompting */ #endif VOID edinit(); VOID main(argc, argv) int argc; char *argv[]; { register KEY c; register int f; register int n; register int mflag; #ifdef STARTUP char *sfile, *startupfile(); #endif char bname[NBUFN]; #ifdef SYSINIT SYSINIT; /* system dependent. */ #endif vtinit(); /* Virtual terminal. */ edinit(); /* Buffers, windows. */ keymapinit(); /* Symbols, bindings. */ /* doing update() before reading files causes the error messages from * the file I/O show up on the screen. (and also an extra display * of the mode line if there are files specified on the command line.) */ update(); #ifdef STARTUP /* User startup file. */ if ((sfile = startupfile()) != NULL) (VOID) load(sfile); #endif while (--argc > 0) { adjustcase(*++argv); makename(bname, *argv); curbp = bfind(bname, TRUE); (VOID) showbuffer(curbp, curwp, 0); (VOID) readin(*argv); } lastflag = 0; /* Fake last flags. */ loop: #ifdef DPROMPT *(promptp = prompt) = '\0'; if(epresf == KPROMPT) eerase(); #endif update(); /* Fix up the screen. */ c = getkey(KPROMPT); if (epresf == TRUE) { eerase(); update(); } f = FALSE; n = 1; if (((KMETA|'0') <= c && c <= (KMETA|'9')) || c == (KMETA|'-')) { f = TRUE; c = c & ~KMETA; } else if (c == (KCTRL|'U')) { f = TRUE; n = 4; while ((c=getkey(KNOMAC | KPROMPT)) == (KCTRL|'U')) n *= 4; } if (f == TRUE) { if ((c>='0' && c<='9') || c=='-') { if (c == '-') { n = 0; mflag = TRUE; } else { n = ((int) c) - '0'; mflag = FALSE; } while ((c=getkey(KNOMAC | KPROMPT))>='0' && c<='9') n = 10*n + ((int) c) - '0'; if (mflag != FALSE) n = -n; } } if (kbdmip != NULL) { /* Terminate macros. */ if (c!=(KCTLX|')') && kbdmip>&kbdm[NKBDM-6]) { (VOID) ctrlg(FALSE, 0, KRANDOM); goto loop; } if (f != FALSE) { kbdmip[-1] = (KEY) (KCTRL|'U');/* overwrite ESC */ *kbdmip++ = (KEY) n; *kbdmip++ = (KEY) c; } } switch (execute(c, f, n)) { /* Do it. */ case TRUE: break; case ABORT: ewprintf("Quit"); /* and fall through */ case FALSE: default: ttbeep(); if (kbdmip != NULL) { kbdm[0] = (KEY) (KCTLX|')'); kbdmip = NULL; } } goto loop; } /* * Command execution. Look up the binding in the the * binding array, and do what it says. Return a very bad status * if there is no binding, or if the symbol has a type that * is not usable (there is no way to get this into a symbol table * entry now). Also fiddle with the flags. */ execute(c, f, n) KEY c; { register SYMBOL *sp; register int status; if ((sp=binding[c]) != NULL) { thisflag = 0; status = (*sp->s_funcp)(f, n, c); lastflag = thisflag; return (status); } lastflag = 0; return (FALSE); } /* * Initialize all of the buffers * and windows. The buffer name is passed down as * an argument, because the main routine may have been * told to read in a file by default, and we want the * buffer name to be right. */ VOID edinit() { register BUFFER *bp; register WINDOW *wp; bheadp = NULL; bp = bfind("*scratch*", TRUE); /* Text buffer. */ wp = (WINDOW *)malloc(sizeof(WINDOW)); /* Initial window. */ if (bp==NULL || wp==NULL) panic("edinit"); curbp = bp; /* Current ones. */ wheadp = wp; curwp = wp; wp->w_wndp = NULL; /* Initialize window. */ wp->w_bufp = bp; bp->b_nwnd = 1; /* Displayed. */ wp->w_linep = bp->b_linep; wp->w_dotp = bp->b_linep; wp->w_doto = 0; wp->w_markp = NULL; wp->w_marko = 0; wp->w_toprow = 0; wp->w_ntrows = nrow-2; /* 2 = mode, echo. */ wp->w_force = 0; wp->w_flag = WFMODE|WFHARD; /* Full. */ } /* * Quit command. If an argument, always * quit. Otherwise confirm if a buffer has been * changed and not written out. Normally bound * to "C-X C-C". */ /*ARGSUSED*/ quit(f, n, k) { register int s; if (f == FALSE) { if ((s = anycb(FALSE)) == ABORT) return ABORT; if (s == FALSE || eyesno("The text is modified, really exit") == TRUE) { vttidy(); exit(GOOD); } } else { vttidy(); exit(GOOD); } return TRUE; } /* * User abort. Should be called by any input routine that sees a C-g * to abort whatever C-g is aborting these days. Currently does * nothing. */ /*ARGSUSED*/ ctrlg(f, n, k) { return (ABORT); } \Rogue\Monster\ else echo "will not over write ./main.c" fi if `test ! -s ./match.c` then echo "writing ./match.c" cat > ./match.c << '\Rogue\Monster\' /* * Name: MicroEMACS * Limited parenthesis matching routines * Version: Gnu30 * Last edit: 13-Jul-86 * Created: 19-May-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic * * The hacks in this file implement automatic matching * of (), [], {}, and other characters. It would be * better to have a full-blown syntax table, but there's * enough overhead in the editor as it is. * * Since I often edit Scribe code, I've made it possible to * blink arbitrary characters -- just bind delimiter characters * to "blink-matching-paren-hack" */ #include "def.h" #ifndef TINY static int balance(); static displaymatch(); /* Balance table. When balance() encounters a character * that is to be matched, it first searches this table * for a balancing left-side character. If the character * is not in the table, the character is balanced by itself. * This is to allow delimiters in Scribe documents to be matched. */ static struct balance { char left, right; } bal[] = { { '(', ')' }, { '[', ']' }, { '{', '}' }, { '<', '>' }, { '\0','\0'} }; /* * Fake the GNU "blink-matching-paren" variable. * If the argument exists, nonzero means show, * zero means don't. If it doesn't exist, * pretend it's nonzero. */ blinkparen(f, n, k) { register char *command; register SYMBOL *sp; if (f == FALSE) n = 1; command = (n == 0) ? "self-insert-command" : "blink-matching-paren-hack"; if ((sp=symlookup(command)) == NULL) { ewprintf("blinkparen: no binding for %s",command); return (FALSE); } binding[(KEY) ')'] = sp; /* rebind paren */ return (TRUE); } /* * Self-insert character, then show matching character, * if any. Bound to "blink-matching-paren-command". */ showmatch(f, n, k) { register int i, s; if (k == KRANDOM) return(FALSE); for (i = 0; i < n; i++) { if ((s = selfinsert(f, 1, k)) != TRUE) return(s); if (balance(k) != TRUE) /* unbalanced -- warn user */ ttbeep(); } return (TRUE); } /* * Search for and display a matching character. * * This routine does the real work of searching backward * for a balancing character. If such a balancing character * is found, it uses displaymatch() to display the match. */ static balance(k) int k; { register LINE *clp; register int cbo; int c; int i; int rbal, lbal; int depth; rbal = k & KCHAR; if ((k&KCTRL)!=0 && rbal>='@' && rbal<='_') /* ASCII-ify. */ rbal -= '@'; /* See if there is a matching character -- default to the same */ lbal = rbal; for (i = 0; bal[i].right != '\0'; i++) if (bal[i].right == rbal) { lbal = bal[i].left; break; } /* Move behind the inserted character. We are always guaranteed */ /* that there is at least one character on the line, since one was */ /* just self-inserted by blinkparen. */ clp = curwp->w_dotp; cbo = curwp->w_doto - 1; depth = 0; /* init nesting depth */ for (;;) { if (cbo == 0) { /* beginning of line */ clp = lback(clp); if (clp == curbp->b_linep) return (FALSE); cbo = llength(clp)+1; } if (--cbo == llength(clp)) /* end of line */ c = '\n'; else c = lgetc(clp,cbo); /* somewhere in middle */ /* Check for a matching character. If still in a nested */ /* level, pop out of it and continue search. This check */ /* is done before the nesting check so single-character */ /* matches will work too. */ if (c == lbal) { if (depth == 0) { displaymatch(clp,cbo); return (TRUE); } else depth--; } /* Check for another level of nesting. */ if (c == rbal) depth++; } /*NOTREACHED*/ } /* * Display matching character. * Matching characters that are not in the current window * are displayed in the echo line. If in the current * window, move dot to the matching character, * sit there a while, then move back. */ static displaymatch(clp, cbo) register LINE *clp; register int cbo; { register LINE *tlp; register int tbo; register int cp; register int bufo; register int c; int inwindow; char buf[NLINE]; /* Figure out if matching char is in current window by */ /* searching from the top of the window to dot. */ inwindow = FALSE; for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp)) if (tlp == clp) inwindow = TRUE; if (inwindow == TRUE) { tlp = curwp->w_dotp; /* save current position */ tbo = curwp->w_doto; curwp->w_dotp = clp; /* move to new position */ curwp->w_doto = cbo; curwp->w_flag |= WFMOVE; update(); /* show match */ sleep(1); /* wait a bit */ curwp->w_dotp = tlp; /* return to old position */ curwp->w_doto = tbo; curwp->w_flag |= WFMOVE; update(); } else { /* match not in this window so display line in echo area */ bufo = 0; for (cp = 0; cp < llength(clp); cp++) { /* expand tabs */ c = lgetc(clp,cp); if ( #ifdef NOTAB (mode&MNOTAB) || #endif c != '\t') if(ISCTRL(c)) { buf[bufo++] = '^'; buf[bufo++] = c ^ 0x40; } else buf[bufo++] = c; else do { buf[bufo++] = ' '; } while (bufo & 7); } buf[bufo++] = '\0'; ewprintf("Matches %s",buf); } return (TRUE); } #endif \Rogue\Monster\ else echo "will not over write ./match.c" fi if `test ! -s ./newlog.c` then echo "writing ./newlog.c" cat > ./newlog.c << '\Rogue\Monster\' /************************************************************************* * * newlog - set up a header for a new log entry * **************************************************************************/ #ifdef MISLOG #include "def.h" #include <stdio.h> #include <pwd.h> #include <time.h> int newlog( f, n, k) int f, n, k; { FILE *fp, *fopen(); struct passwd *pw_entry, *getpwnam(); char *fs_file, basename[80], author[80], date[80], *getlogin(), *asctime(), *login_name, buf[80], *tmpnam(); struct tm *timenow, *localtime(); long clock, time(); int n; login_name = getlogin(); pw_entry = getpwnam(login_name); strcpy(author, pw_entry->pw_gecos); clock = time((long *) 0); timenow = localtime(&clock); fs_file = tmpnam(); fp = fopen(fs_file, "w"); sprintf(date, "%s", asctime(timenow)); fprintf(fp, "----------------------------------------------------------------------\n"); date[strlen(date) - 1] = '\0'; fprintf(fp, "%s %s\n\n", date, author); fclose(fp); gotoeob( FALSE, 0, 0); insertfile( fs_file, (char *)0); unlink( fs_file); gotoeob( FALSE, 0, 0); return TRUE; } #endif \Rogue\Monster\ else echo "will not over write ./newlog.c" fi if `test ! -s ./paragraph.c` then echo "writing ./paragraph.c" cat > ./paragraph.c << '\Rogue\Monster\' /* * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6 * and GNU-ified by mwm@ucbvax. Several bug fixes by blarson@usc-oberon. */ #include "def.h" static int fillcol = 70 ; #define MAXWORD 256 /* * go back to the begining of the current paragraph * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> * combination to delimit the begining of a paragraph */ /*ARGSUSED*/ gotobop(f, n, k) { register int suc; /* success of last backchar */ if (n < 0) /* the other way...*/ return(gotoeop(f, -n, KRANDOM)); while (n-- > 0) { /* for each one asked for */ /* first scan back until we are in a word */ suc = backchar(FALSE, 1, KRANDOM); while (!inword() && suc) suc = backchar(FALSE, 1, KRANDOM); curwp->w_doto = 0; /* and go to the B-O-Line */ /* and scan back until we hit a <NL><SP> <NL><TAB> or <NL><NL> */ while (lback(curwp->w_dotp) != curbp->b_linep) if (llength(lback(curwp->w_dotp)) && lgetc(curwp->w_dotp,0) != ' ' && lgetc(curwp->w_dotp,0) != '\t') curwp->w_dotp = lback(curwp->w_dotp); else break; } curwp->w_flag |= WFMOVE; /* force screen update */ return TRUE; } /* * go forword to the end of the current paragraph * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> * combination to delimit the begining of a paragraph */ /*ARGSUSED*/ gotoeop(f, n, k) { register int suc; /* success of last backchar */ if (n < 0) /* the other way...*/ return(gotobop(f, -n, KRANDOM)); while (n-- > 0) { /* for each one asked for */ /* Find the first word on/after the current line */ curwp->w_doto = 0; suc = forwchar(FALSE, 1, KRANDOM); while (!inword() && suc) suc = forwchar(FALSE, 1, KRANDOM); curwp->w_doto = 0; if (curwp->w_dotp == curbp->b_linep) break; /* check for eob */ curwp->w_dotp = lforw(curwp->w_dotp); /* and scan forword until we hit a <NL><SP> or ... */ while (curwp->w_dotp != curbp->b_linep) { if (llength(curwp->w_dotp) && lgetc(curwp->w_dotp,0) != ' ' && lgetc(curwp->w_dotp,0) != '\t') curwp->w_dotp = lforw(curwp->w_dotp); else break; } } curwp->w_flag |= WFMOVE; /* force screen update */ return TRUE; } /* * Fill the current paragraph according to the current * fill column */ /*ARGSUSED*/ fillpara(f, n, k) { register int c; /* current char durring scan */ register int wordlen; /* length of current word */ register int clength; /* position on line during fill */ register int i; /* index during word copy */ register int eopflag; /* Are we at the End-Of-Paragraph? */ int firstflag; /* first word? (needs no space) */ int newlength; /* tentative new line length */ int eolflag; /* was at end of line */ LINE *eopline; /* pointer to line just past EOP */ char wbuf[MAXWORD]; /* buffer for current word */ int old_mode; /* saved mode value */ /* save the mode and put into insert mode for duration of fill */ old_mode = mode; mode &= !MOVRSTK; /* record the pointer to the line just past the EOP */ (VOID) gotoeop(FALSE, 1, KRANDOM); eopline = curwp->w_dotp; /* and back top the begining of the paragraph */ (VOID) gotobop(FALSE, 1, KRANDOM); /* initialize various info */ i = TRUE; while (i == TRUE && !inword()) i = forwchar(FALSE, 1, KRANDOM); clength = curwp->w_doto; wordlen = 0; /* scan through lines, filling words */ firstflag = TRUE; eopflag = FALSE; while (!eopflag) { /* get the next character in the paragraph */ if (eolflag=(curwp->w_doto == llength(curwp->w_dotp))) { c = ' '; if (lforw(curwp->w_dotp) == eopline) eopflag = TRUE; } else c = lgetc(curwp->w_dotp, curwp->w_doto); /* and then delete it */ if (ldelete((RSIZE) 1, KNONE) == FALSE) { mode = old_mode; return FALSE ; } /* if not a separator, just add it in */ if (c != ' ' && c != '\t') { if (wordlen < MAXWORD - 1) wbuf[wordlen++] = c; else { /* You loose chars beyond MAXWORD if the word * is to long. I'm to lazy to fix it now; it * just silently truncated the word before, so * I get to feel smug. */ ewprintf("Word too long!"); } } else if (wordlen) { /* calculate tenatitive new length with word added */ newlength = clength + 1 + wordlen; /* if at end of line or at doublespace and previous * character was one of '.','?','!' doublespace here. */ if((eolflag || curwp->w_doto==llength(curwp->w_dotp) || (c=lgetc(curwp->w_dotp,curwp->w_doto))==' ' || c=='\t') && ISEOSP(wbuf[wordlen-1]) && wordlen<MAXWORD-1) wbuf[wordlen++] = ' '; /* at a word break with a word waiting */ if (newlength <= fillcol) { /* add word to current line */ if (!firstflag) { (VOID) linsert((RSIZE) 1, ' '); ++clength; } firstflag = FALSE; } else { if(curwp->w_doto > 0 && lgetc(curwp->w_dotp,curwp->w_doto-1)==' ') { curwp->w_doto -= 1; (VOID) ldelete((RSIZE) 1, KNONE); } /* start a new line */ (VOID) lnewline(); clength = 0; } /* and add the word in in either case */ for (i=0; i<wordlen; i++) { (VOID) linsert((RSIZE) 1, wbuf[i]); ++clength; } wordlen = 0; } } /* and add a last newline for the end of our new paragraph */ (VOID) lnewline(); /* we realy should wind up where we started, (which is hard to keep * track of) but I think the end of the last line is better than the * begining of the blank line. */ (VOID) backchar(FALSE, 1, KRANDOM); mode = old_mode; return TRUE; } /* delete n paragraphs starting with the current one */ /*ARGSUSED*/ killpara(f, n, k) { register int status; /* returned status of functions */ while (n--) { /* for each paragraph to delete */ /* mark out the end and begining of the para to delete */ (VOID) gotoeop(FALSE, 1, KRANDOM); /* set the mark here */ curwp->w_markp = curwp->w_dotp; curwp->w_marko = curwp->w_doto; /* go to the begining of the paragraph */ (VOID) gotobop(FALSE, 1, KRANDOM); curwp->w_doto = 0; /* force us to the begining of line */ /* and delete it */ if ((status = killregion(FALSE, 1, KRANDOM)) != TRUE) return(status); /* and clean up the 2 extra lines */ (VOID) ldelete((RSIZE) 1, KFORW); } return(TRUE); } /* * check to see if we're past fillcol, and if so, * justify this line. As a last step, justify the line. */ /*ARGSUSED*/ fillword(f, n, k) { register char c; register int col, i, nce; for (i = col = 0; col <= fillcol; ++i, ++col) { if (i == curwp->w_doto) return selfinsert(f, n, k) ; c = lgetc(curwp->w_dotp, i); if ( #ifdef NOTAB !(mode&MNOTAB) && #endif c == '\t') col |= 0x07; else if (ISCTRL(c) != FALSE) ++col; } if (curwp->w_doto != llength(curwp->w_dotp)) { (VOID) selfinsert(f, n, k); nce = llength(curwp->w_dotp) - curwp->w_doto; } else nce = 0; curwp->w_doto = i; if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t') do { (VOID) backchar(FALSE, 1, KRANDOM); } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t' && curwp->w_doto > 0); if (curwp->w_doto == 0) do { (VOID) forwchar(FALSE, 1, KRANDOM); } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t' && curwp->w_doto < llength(curwp->w_dotp)); (VOID) delwhite(FALSE, 1, KRANDOM); (VOID) lnewline(); curwp->w_doto = llength(curwp->w_dotp) - nce; curwp->w_flag |= WFMOVE; if (nce == 0 && curwp->w_doto != 0) return fillword(f, n, k); return TRUE; } /* Set fill column to n. */ /*ARGSUSED*/ setfillcol(f, n, k) { extern int getcolpos() ; fillcol = ((f == FALSE) ? getcolpos() : n); if (kbdmop == NULL) ewprintf("Fill column set to %d", fillcol); return(TRUE); } \Rogue\Monster\ else echo "will not over write ./paragraph.c" fi if `test ! -s ./prefix.c` then echo "writing ./prefix.c" cat > ./prefix.c << '\Rogue\Monster\' /* * This code is a kludge for the two prefix sequences from GNU (well, * the two I want) that uemacs doesn't have. Rather than quadruple the table * space for keys, plus have to test for them everywhere, I'll just kludge * it with functions that are bound to those keys. Later, maybe I'll do * prefixes right. */ #include "def.h" #ifndef TINY /*ARGSUSED*/ ctlx4hack(f, n, k) { register KEY c; if ((c = getkey(KPROMPT)) == 'b' || c == 'B') return poptobuffer(f, n, KRANDOM); if (c == 'f' || c == (KCTRL|'F') || c == 'F') return poptofile(f, n, KRANDOM); if (c == (KCTRL|'G') || c == (KCTLX|KCTRL|'G') || c == (KMETA|KCTRL|'G')) { (VOID) ctrlg(FALSE, 1, KRANDOM); return ABORT; } return FALSE; } /*ARGSUSED*/ help(f, n, k) { register KEY c; c = getkey(KPROMPT); while (c == (KCTRL|'H')) { ewprintf("B C: "); c = getkey(0); } if (c == 'b' || c == 'B') return wallchart(f, n, KRANDOM); if (c == 'c' || c == 'C') return desckey(f, n, KRANDOM); if (c == (KCTRL|'G') || c == (KCTLX|KCTRL|'G') || c == (KMETA|KCTRL|'G')) { (VOID) ctrlg(FALSE, 1, KRANDOM); return ABORT; } return FALSE; } #endif \Rogue\Monster\ else echo "will not over write ./prefix.c" fi if `test ! -s ./random.c` then echo "writing ./random.c" cat > ./random.c << '\Rogue\Monster\' /* * Assorted commands. * The file contains the command * processors for a large assortment of unrelated * commands. The only thing they have in common is * that they are all command processors. */ #include "def.h" /* * Display a bunch of useful information about * the current location of dot. The character under the * cursor (in octal), the current line, row, and column, and * approximate position of the cursor in the file (as a percentage) * is displayed. The column position assumes an infinite position * display; it does not truncate just because the screen does. * This is normally bound to "C-X =". */ /*ARGSUSED*/ showcpos(f, n, k) { register LINE *clp; register long nchar; long cchar; register int nline, row; int cline, cbyte; /* Current line/char/byte */ int ratio; KEY keychar(); clp = lforw(curbp->b_linep); /* Collect the data. */ nchar = 0; nline = 0; for (;;) { ++nline; /* Count this line */ if (clp == curwp->w_dotp) { cline = nline; /* Mark line */ cchar = nchar + curwp->w_doto; if (curwp->w_doto == llength(clp)) cbyte = '\n'; else cbyte = lgetc(clp, curwp->w_doto); } nchar += llength(clp) + 1; /* Now count the chars */ if (clp == curbp->b_linep) break ; clp = lforw(clp); } row = curwp->w_toprow; /* Determine row. */ clp = curwp->w_linep; while (clp!=curbp->b_linep && clp!=curwp->w_dotp) { ++row; clp = lforw(clp); } ++row; /* Convert to origin 1. */ /*NOSTRICT*/ /* nchar can't be zero (because of the "bonus" \n at end of file) */ ratio = (100L*cchar) / nchar; ewprintf("Char: %c (0%o) point=%ld(%d%%) line=%d row=%d col=%d", (int) keychar(cbyte, FALSE), cbyte, cchar, ratio, cline, row, getcolpos()); return (TRUE); } getcolpos() { register int col, i, c; col = 0; /* Determine column. */ for (i=0; i<curwp->w_doto; ++i) { c = lgetc(curwp->w_dotp, i); if ( #ifdef NOTAB !(mode & MNOTAB) && #endif c == '\t') col |= 0x07; else if (ISCTRL(c) != FALSE) ++col; ++col; } return col + 1; /* Convert to origin 1. */ } /* * Ordinary text characters are bound to this function, * which inserts them into the buffer. Characters marked as control * characters (using the CTRL flag) may be remapped to their ASCII * equivalent. This makes TAB (C-I) work right, and also makes the * world look reasonable if a control character is bound to this * this routine by hand. Any META or CTLX flags on the character * are discarded. This is the only routine that actually looks * the the "k" argument. */ /*ARGSUSED*/ selfinsert(f, n, k) { register int c; if (n < 0) return (FALSE); if (n == 0) return (TRUE); c = k & KCHAR; if ((k&KCTRL)!=0 && c>='@' && c<='_') /* ASCII-ify. */ c -= '@'; return (linsert((RSIZE) n, c)); } /* * Open up some blank space. The basic plan * is to insert a bunch of newlines, and then back * up over them. Everything is done by the subcommand * procerssors. They even handle the looping. Normally * this is bound to "C-O". */ /*ARGSUSED*/ openline(f, n, k) { register int i; register int s; if (n < 0) return (FALSE); if (n == 0) return (TRUE); gotobol( FALSE, 0, KRANDOM); i = n; /* Insert newlines. */ do { s = lnewline(); } while (s==TRUE && --i); if (s == TRUE) /* Then back up overtop */ s = backchar(f, n, KRANDOM); /* of them all. */ return (s); } /* * Insert a newline. * If you are at the end of the line and the * next line is a blank line, just move into the * blank line. This makes "C-O" and "C-X C-O" work * nicely, and reduces the ammount of screen * update that has to be done. This would not be * as critical if screen update were a lot * more efficient. */ /*ARGSUSED*/ newline(f, n, k) { register LINE *lp; register int s; if (n < 0) return (FALSE); while (n--) { lp = curwp->w_dotp; if (llength(lp) == curwp->w_doto && lp != curbp->b_linep && llength(lforw(lp)) == 0) { if ((s=forwchar(FALSE, 1, KRANDOM)) != TRUE) return (s); } else if ((s=lnewline()) != TRUE) return (s); } return (TRUE); } /* * Delete any whitespace around dot. */ /*ARGSUSED*/ delwhite(f, n, k) { register int col, c, s; col = curwp->w_doto; while ((c = lgetc(curwp->w_dotp, col)) == ' ' || c == '\t') ++col; do if ((s = backchar(FALSE, 1, KRANDOM)) == FALSE) break; while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t') ; if (s == TRUE) (VOID) forwchar(FALSE, 1, KRANDOM); (VOID) ldelete((RSIZE)(col - curwp->w_doto), KNONE); return (TRUE); } /* * Delete forward. This is real * easy, because the basic delete routine does * all of the work. Watches for negative arguments, * and does the right thing. If any argument is * present, it kills rather than deletes, to prevent * loss of text if typed with a big argument. * Normally bound to "C-D". */ /*ARGSUSED*/ forwdel(f, n, k) { if (n < 0) return (backdel(f, -n, KRANDOM)); if (f != FALSE) { /* Really a kill. */ if ((lastflag&CFKILL) == 0) kdelete(); thisflag |= CFKILL; } return (ldelete((RSIZE) n, f ? KFORW : KNONE)); } /* * Delete backwards. This is quite easy too, * because it's all done with other functions. Just * move the cursor back, and delete forwards. * Like delete forward, this actually does a kill * if presented with an argument. */ /*ARGSUSED*/ backdel(f, n, k) { register int s; if (n < 0) return (forwdel(f, -n, KRANDOM)); if (f != FALSE) { /* Really a kill. */ if ((lastflag&CFKILL) == 0) kdelete(); thisflag |= CFKILL; } if ((s=backchar(f, n, KRANDOM)) == TRUE) s = ldelete((RSIZE) n, f ? KFORW : KNONE); return (s); } /* * Kill line. If called without an argument, * it kills from dot to the end of the line, unless it * is at the end of the line, when it kills the newline. * If called with an argument of 0, it kills from the * start of the line to dot. If called with a positive * argument, it kills from dot forward over that number * of newlines. If called with a negative argument it * kills any text before dot on the current line, * then it kills back abs(arg) lines. */ /*ARGSUSED*/ killline(f, n, k) { register RSIZE chunk; register LINE *nextp; register int i, c; if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */ kdelete(); /* last wasn't a kill. */ thisflag |= CFKILL; if (f == FALSE) { for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i) if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t') break; if (i == llength(curwp->w_dotp)) chunk = llength(curwp->w_dotp)-curwp->w_doto + 1; else { chunk = llength(curwp->w_dotp)-curwp->w_doto; if (chunk == 0) chunk = 1; } } else if (n > 0) { chunk = llength(curwp->w_dotp)-curwp->w_doto+1; nextp = lforw(curwp->w_dotp); i = n; while (--i) { if (nextp == curbp->b_linep) break; chunk += llength(nextp)+1; nextp = lforw(nextp); } } else { /* n <= 0 */ chunk = curwp->w_doto; curwp->w_doto = 0; i = n; while (i++) { if (lback(curwp->w_dotp) == curbp->b_linep) break; curwp->w_dotp = lback(curwp->w_dotp); curwp->w_flag |= WFMOVE; chunk += llength(curwp->w_dotp)+1; } } /* * KFORW here is a bug. Should be KBACK/KFORW, but we need to * rewrite the ldelete code (later)? */ return (ldelete(chunk, KFORW)); } /* * Commands to toggle the five modes. Without an argument, sets the * mode on, with an argument, sets the mode off. */ /*ARGSUSED*/ bsmapmode(f, n, k) { if ((mode&MBSMAP) != MBSMAP) mode |= MBSMAP; else mode &= ~MBSMAP; upmodes((BUFFER *) NULL); return TRUE; } /*ARGSUSED*/ flowmode(f, n, k) { if ((mode&MFLOW) != MFLOW) mode |= MFLOW; else mode &= ~MFLOW; upmodes((BUFFER *) NULL); return TRUE; } /*ARGSUSED*/ fillmode(f, n, k) { if ((mode&MFILL) != MFILL) { mode |= MFILL; if ((binding[' '] = symlookup("insert-with-wrap")) == NULL) panic("no insert-with-wrap in fillmode"); } else { mode &= ~MFILL; if ((binding[' '] = symlookup("self-insert-command")) == NULL) panic("no self-insert-command in fillmode"); } upmodes((BUFFER *) NULL); return TRUE; } #ifdef NOTAB space_tabpos(f, n, k) int f, n; { int stat; if(n<0) return FALSE; if(n==0) return TRUE; return linsert(((RSIZE)n<<3) - (curwp->w_doto & 7), ' '); } notabmode(f, n, k) { if((mode&MNOTAB) != MNOTAB) { mode |= MNOTAB; if ((binding[KCTRL|'I'] = symlookup("space-to-tabstop")) == NULL) panic("no space-to-tabstop in notabmode"); } else { mode &= ~ MNOTAB; if ((binding[KCTRL|'I'] = symlookup("self-insert-command")) == NULL) panic("no self-insert-command in notabmode"); } upmodes((BUFFER *) NULL); return TRUE; } #endif /* * This function toggles the state of the * insert/overstrike flag. The editor will come up in * one mode or the other, and can be changed by this * function. No argument or 0 will toggle the value, >0 will * set to insert mode, <0 will set to overstrike. */ /*ARGSUSED*/ insovrmode( f, n, k) { if (f == FALSE || n == 0) { if ((mode & MOVRSTK) == MOVRSTK) mode &= ~MOVRSTK; else mode |= MOVRSTK; } else if (n > 0) mode &= ~MOVRSTK; else mode |= MOVRSTK; upmodes((BUFFER *) NULL); return TRUE; } /* * Yank text back from the kill buffer. This * is really easy. All of the work is done by the * standard insert routines. All you do is run the loop, * and check for errors. The blank * lines are inserted with a call to "newline" * instead of a call to "lnewline" so that the magic * stuff that happens when you type a carriage * return also happens when a carriage return is * yanked back from the kill buffer. * An attempt has been made to fix the cosmetic bug * associated with a yank when dot is on the top line of * the window (nothing moves, because all of the new * text landed off screen). */ /*ARGSUSED*/ yank(f, n, k) { register int c; register int i; register LINE *lp; register int nline; if (n < 0) return (FALSE); nline = 0; /* Newline counting. */ while (n--) { isetmark(); /* mark around last yank */ i = 0; while ((c=kremove(i)) >= 0) { if (c == '\n') { if (newline(FALSE, 1, KRANDOM) == FALSE) return (FALSE); ++nline; } else { if (linsert((RSIZE) 1, c) == FALSE) return (FALSE); } ++i; } } lp = curwp->w_linep; /* Cosmetic adjustment */ if (curwp->w_dotp == lp) { /* if offscreen insert. */ while (nline-- && lback(lp)!=curbp->b_linep) lp = lback(lp); curwp->w_linep = lp; /* Adjust framing. */ curwp->w_flag |= WFHARD; } return (TRUE); } \Rogue\Monster\ else echo "will not over write ./random.c" fi echo "Finished archive 2 of 5" exit -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Mark A. Hargrove U.S. TeleCenters Voice: 408-496-1800 Santa Clara, CA uucp : {dual, hoptoad, hplabs, portal, ptsfa}!well!ustel