Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!rutgers!sri-spam!ames!ptsfa!ihnp4!inuxc!iuvax!isrnix!mr From: mr@isrnix.UUCP (a.k.a regoli@silver.bacs.indiana.edu) Newsgroups: comp.sys.ibm.pc Subject: Repost: EMACS 3.8L Source (Part 5 of 9) Message-ID: <873@isrnix.UUCP> Date: Fri, 31-Jul-87 15:26:48 EDT Article-I.D.: isrnix.873 Posted: Fri Jul 31 15:26:48 1987 Date-Received: Sun, 2-Aug-87 09:43:16 EDT Sender: mr@isrnix.UUCP Organization: indiana university, bloomington Lines: 2216 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # ibmpc.c # input.c # isearch.c # line.c # lock.c # This archive created: Fri Jul 31 13:54:30 1987 # By: michael regoli (indiana university, bloomington) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'ibmpc.c'" '(0 character)' if test -f 'ibmpc.c' then echo shar: "will not over-write existing file 'ibmpc.c'" else cat << \SHAR_EOF > 'ibmpc.c' /* * The routines in this file provide support for the IBM-PC and other * compatible terminals. It goes directly to the graphics RAM to do * screen output. It compiles into nothing if not an IBM-PC driver * Supported monitor cards include CGA, MONO and EGA. */ #define termdef 1 /* don't define "term" external */ #include #include "estruct.h" #include "edef.h" #if IBMPC #define NROW 43 /* Max Screen size. */ #define NCOL 80 /* Edit if you want to. */ #define MARGIN 8 /* size of minimim margin and */ #define SCRSIZ 64 /* scroll size for extended lines */ #define NPAUSE 200 /* # times thru update to pause */ #define BEL 0x07 /* BEL character. */ #define ESC 0x1B /* ESC character. */ #define SPACE 32 /* space character */ #define SCADC 0xb8000000L /* CGA address of screen RAM */ #define SCADM 0xb0000000L /* MONO address of screen RAM */ #define SCADE 0xb8000000L /* EGA address of screen RAM */ #define MONOCRSR 0x0B0D /* monochrome cursor */ #define CGACRSR 0x0607 /* CGA cursor */ #define EGACRSR 0x0709 /* EGA cursor */ #define CDCGA 0 /* color graphics card */ #define CDMONO 1 /* monochrome text card */ #define CDEGA 2 /* EGA color adapter */ #define CDSENSE 9 /* detect the card type */ #define NDRIVE 3 /* number of screen drivers */ int dtype = -1; /* current display type */ char drvname[][8] = { /* screen resolution names */ "CGA", "MONO", "EGA" }; long scadd; /* address of screen ram */ int *scptr[NROW]; /* pointer to screen lines */ int sline[NCOL]; /* screen line image */ int egaexist = FALSE; /* is an EGA card available? */ extern union REGS rg; /* cpu register for use of DOS calls */ extern int ttopen(); /* Forward references. */ extern int ttgetc(); extern int ttputc(); extern int ttflush(); extern int ttclose(); extern int ibmmove(); extern int ibmeeol(); extern int ibmeeop(); extern int ibmbeep(); extern int ibmopen(); extern int ibmrev(); extern int ibmcres(); extern int ibmclose(); extern int ibmputc(); extern int ibmkopen(); extern int ibmkclose(); #if COLOR extern int ibmfcol(); extern int ibmbcol(); int cfcolor = -1; /* current forground color */ int cbcolor = -1; /* current background color */ int ctrans[] = /* ansi to ibm color translation table */ {0, 4, 2, 6, 1, 5, 3, 7}; #endif /* * Standard terminal interface dispatch table. Most of the fields point into * "termio" code. */ TERM term = { NROW-1, NROW-1, NCOL, NCOL, MARGIN, SCRSIZ, NPAUSE, ibmopen, ibmclose, ibmkopen, ibmkclose, ttgetc, ibmputc, ttflush, ibmmove, ibmeeol, ibmeeop, ibmbeep, ibmrev, ibmcres #if COLOR , ibmfcol, ibmbcol #endif }; extern union REGS rg; #if COLOR ibmfcol(color) /* set the current output color */ int color; /* color to set */ { cfcolor = ctrans[color]; } ibmbcol(color) /* set the current background color */ int color; /* color to set */ { cbcolor = ctrans[color]; } #endif ibmmove(row, col) { rg.h.ah = 2; /* set cursor position function code */ rg.h.dl = col; rg.h.dh = row; rg.h.bh = 0; /* set screen page number */ int86(0x10, &rg, &rg); } ibmeeol() /* erase to the end of the line */ { int attr; /* attribute byte mask to place in RAM */ int *lnptr; /* pointer to the destination line */ int i; int ccol; /* current column cursor lives */ int crow; /* row */ /* find the current cursor position */ rg.h.ah = 3; /* read cursor position function code */ rg.h.bh = 0; /* current video page */ int86(0x10, &rg, &rg); ccol = rg.h.dl; /* record current column */ crow = rg.h.dh; /* and row */ /* build the attribute byte and setup the screen pointer */ #if COLOR if (dtype != CDMONO) attr = (((cbcolor & 15) << 4) | (cfcolor & 15)) << 8; else attr = 0x0700; #else attr = 0x0700; #endif lnptr = &sline[0]; for (i=0; i < term.t_ncol; i++) *lnptr++ = SPACE | attr; if (flickcode && (dtype == CDCGA)) { /* wait for vertical retrace to be off */ while ((inp(0x3da) & 8)) ; /* and to be back on */ while ((inp(0x3da) & 8) == 0) ; } /* and send the string out */ movmem(&sline[0], scptr[crow]+ccol, (term.t_ncol-ccol)*2); } ibmputc(ch) /* put a character at the current position in the current colors */ int ch; { rg.h.ah = 14; /* write char to screen with current attrs */ rg.h.al = ch; #if COLOR if (dtype != CDMONO) rg.h.bl = cfcolor; else rg.h.bl = 0x07; #else rg.h.bl = 0x07; #endif int86(0x10, &rg, &rg); } ibmeeop() { int attr; /* attribute to fill screen with */ rg.h.ah = 6; /* scroll page up function code */ rg.h.al = 0; /* # lines to scroll (clear it) */ rg.x.cx = 0; /* upper left corner of scroll */ rg.x.dx = (term.t_nrow << 8) | (term.t_ncol - 1); /* lower right corner of scroll */ #if COLOR if (dtype != CDMONO) attr = ((ctrans[gbcolor] & 15) << 4) | (ctrans[gfcolor] & 15); else attr = 0; #else attr = 0; #endif rg.h.bh = attr; int86(0x10, &rg, &rg); } ibmrev(state) /* change reverse video state */ int state; /* TRUE = reverse, FALSE = normal */ { /* This never gets used under the IBM-PC driver */ } ibmcres(res) /* change screen resolution */ char *res; /* resolution to change to */ { int i; /* index */ for (i = 0; i < NDRIVE; i++) if (strcmp(res, drvname[i]) == 0) { scinit(i); return(TRUE); } return(FALSE); } spal() /* reset the pallette registers */ { /* nothin here now..... */ } ibmbeep() { #if MWC86 putcnb(BEL); #else bdos(6, BEL, 0); #endif } ibmopen() { scinit(CDSENSE); revexist = TRUE; ttopen(); } ibmclose() { #if COLOR ibmfcol(7); ibmbcol(0); #endif /* if we had the EGA open... close it */ if (dtype == CDEGA) egaclose(); ttclose(); } ibmkopen() /* open the keyboard */ { } ibmkclose() /* close the keyboard */ { } scinit(type) /* initialize the screen head pointers */ int type; /* type of adapter to init for */ { union { long laddr; /* long form of address */ int *paddr; /* pointer form of address */ } addr; int i; /* if asked...find out what display is connected */ if (type == CDSENSE) type = getboard(); /* if we have nothing to do....don't do it */ if (dtype == type) return(TRUE); /* if we try to switch to EGA and there is none, don't */ if (type == CDEGA && egaexist != TRUE) return(FALSE); /* if we had the EGA open... close it */ if (dtype == CDEGA) egaclose(); /* and set up the various parameters as needed */ switch (type) { case CDMONO: /* Monochrome adapter */ scadd = SCADM; newsize(TRUE, 25); break; case CDCGA: /* Color graphics adapter */ scadd = SCADC; newsize(TRUE, 25); break; case CDEGA: /* Enhanced graphics adapter */ scadd = SCADE; egaopen(); newsize(TRUE, 43); break; } /* reset the $sres environment variable */ strcpy(sres, drvname[type]); dtype = type; /* initialize the screen pointer array */ for (i = 0; i < NROW; i++) { addr.laddr = scadd + (long)(NCOL * i * 2); scptr[i] = addr.paddr; } } /* getboard: Determine which type of display board is attached. Current known types include: CDMONO Monochrome graphics adapter CDCGA Color Graphics Adapter CDEGA Extended graphics Adapter */ /* getbaord: Detect the current display adapter if MONO set to MONO CGA set to CGA EGAexist = FALSE EGA set to CGA EGAexist = TRUE */ int getboard() { int type; /* board type to return */ type = CDCGA; int86(0x11, &rg, &rg); if ((((rg.x.ax >> 4) & 3) == 3)) type = CDMONO; /* test if EGA present */ rg.x.ax = 0x1200; rg.x.bx = 0xff10; int86(0x10,&rg, &rg); /* If EGA, bh=0-1 and bl=0-3 */ egaexist = !(rg.x.bx & 0xfefc); /* Yes, it's EGA */ return(type); } egaopen() /* init the computer to work with the EGA */ { /* put the beast into EGA 43 row mode */ rg.x.ax = 3; int86(16, &rg, &rg); rg.h.ah = 17; /* set char. generator function code */ rg.h.al = 18; /* to 8 by 8 double dot ROM */ rg.h.bl = 0; /* block 0 */ int86(16, &rg, &rg); rg.h.ah = 18; /* alternate select function code */ rg.h.al = 0; /* clear AL for no good reason */ rg.h.bl = 32; /* alt. print screen routine */ int86(16, &rg, &rg); rg.h.ah = 1; /* set cursor size function code */ rg.x.cx = 0x0607; /* turn cursor on code */ int86(0x10, &rg, &rg); outp(0x3d4, 10); /* video bios bug patch */ outp(0x3d5, 6); } egaclose() { /* put the beast into 80 column mode */ rg.x.ax = 3; int86(16, &rg, &rg); } scwrite(row, outstr, forg, bacg) /* write a line out*/ int row; /* row of screen to place outstr on */ char *outstr; /* string to write out (must be term.t_ncol long) */ int forg; /* forground color of string to write */ int bacg; /* background color */ { int attr; /* attribute byte mask to place in RAM */ int *lnptr; /* pointer to the destination line */ int i; /* build the attribute byte and setup the screen pointer */ #if COLOR if (dtype != CDMONO) attr = (((ctrans[bacg] & 15) << 4) | (ctrans[forg] & 15)) << 8; else attr = (((bacg & 15) << 4) | (forg & 15)) << 8; #else attr = (((bacg & 15) << 4) | (forg & 15)) << 8; #endif lnptr = &sline[0]; for (i=0; i 'input.c' /* INPUT: Various input routines for MicroEMACS 3.7 written by Daniel Lawrence 5/9/86 */ #include #include "estruct.h" #include "edef.h" /* * Ask a yes or no question in the message line. Return either TRUE, FALSE, or * ABORT. The ABORT status is returned if the user bumps out of the question * with a ^G. Used any time a confirmation is required. */ mlyesno(prompt) char *prompt; { char c; /* input character */ char buf[NPAT]; /* prompt to user */ for (;;) { /* build and prompt the user */ strcpy(buf, prompt); strcat(buf, " [y/n]? "); mlwrite(buf); /* get the responce */ c = tgetc(); if (c == ectoc(abortc)) /* Bail out! */ return(ABORT); if (c=='y' || c=='Y') return(TRUE); if (c=='n' || c=='N') return(FALSE); } } /* * Write a prompt into the message line, then read back a response. Keep * track of the physical position of the cursor. If we are in a keyboard * macro throw the prompt away, and return the remembered response. This * lets macros run at full speed. The reply is always terminated by a carriage * return. Handle erase, kill, and abort keys. */ mlreply(prompt, buf, nbuf) char *prompt; char *buf; { return(nextarg(prompt, buf, nbuf, ctoec('\n'))); } mlreplyt(prompt, buf, nbuf, eolchar) char *prompt; char *buf; int eolchar; { return(nextarg(prompt, buf, nbuf, eolchar)); } /* ectoc: expanded character to character colapse the CTRL and SPEC flags back into an ascii code */ ectoc(c) int c; { if (c & CTRL) c = c & ~(CTRL | 0x40); if (c & SPEC) c= c & 255; return(c); } /* ctoec: character to extended character pull out the CTRL and SPEC prefixes (if possible) */ ctoec(c) int c; { if (c>=0x00 && c<=0x1F) c = CTRL | (c+'@'); return (c); } /* get a command name from the command line. Command completion means that pressing a will attempt to complete an unfinished command name if it is unique. */ int (*getname())() { #if ST520 & LATTICE #define register #endif register int cpos; /* current column on screen output */ register int c; register char *sp; /* pointer to string for output */ register NBIND *ffp; /* first ptr to entry in name binding table */ register NBIND *cffp; /* current ptr to entry in name binding table */ register NBIND *lffp; /* last ptr to entry in name binding table */ char buf[NSTRING]; /* buffer to hold tentative command name */ int (*fncmatch())(); /* starting at the beginning of the string buffer */ cpos = 0; /* if we are executing a command line get the next arg and match it */ if (clexec) { if (macarg(buf) != TRUE) return(FALSE); return(fncmatch(&buf[0])); } /* build a name string from the keyboard */ while (TRUE) { c = tgetc(); /* if we are at the end, just match it */ if (c == 0x0d) { buf[cpos] = 0; /* and match it off */ return(fncmatch(&buf[0])); } else if (c == ectoc(abortc)) { /* Bell, abort */ ctrlg(FALSE, 0); TTflush(); return( (int (*)()) NULL); } else if (c == 0x7F || c == 0x08) { /* rubout/erase */ if (cpos != 0) { TTputc('\b'); TTputc(' '); TTputc('\b'); --ttcol; --cpos; TTflush(); } } else if (c == 0x15) { /* C-U, kill */ while (cpos != 0) { TTputc('\b'); TTputc(' '); TTputc('\b'); --cpos; --ttcol; } TTflush(); } else if (c == ' ') { /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ /* attempt a completion */ buf[cpos] = 0; /* terminate it for us */ ffp = &names[0]; /* scan for matches */ while (ffp->n_func != NULL) { if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) { /* a possible match! More than one? */ if ((ffp + 1)->n_func == NULL || (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) { /* no...we match, print it */ sp = ffp->n_name + cpos; while (*sp) TTputc(*sp++); TTflush(); return(ffp->n_func); } else { /* << << << << << << << << << << << << << << << << << */ /* try for a partial match against the list */ /* first scan down until we no longer match the current input */ lffp = (ffp + 1); while ((lffp+1)->n_func != NULL) { if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0) break; ++lffp; } /* and now, attempt to partial complete the string, char at a time */ while (TRUE) { /* add the next char in */ buf[cpos] = ffp->n_name[cpos]; /* scan through the candidates */ cffp = ffp + 1; while (cffp <= lffp) { if (cffp->n_name[cpos] != buf[cpos]) goto onward; ++cffp; } /* add the character */ TTputc(buf[cpos++]); } /* << << << << << << << << << << << << << << << << << */ } } ++ffp; } /* no match.....beep and onward */ TTbeep(); onward:; TTflush(); /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ } else { if (cpos < NSTRING-1 && c > ' ') { buf[cpos++] = c; TTputc(c); } ++ttcol; TTflush(); } } } /* tgetc: Get a key from the terminal driver, resolve any keyboard macro action */ int tgetc() { int c; /* fetched character */ /* if we are playing a keyboard macro back, */ if (kbdmode == PLAY) { /* if there is some left... */ if (kbdptr < kbdend) return((int)*kbdptr++); /* at the end of last repitition? */ if (--kbdrep < 1) { kbdmode = STOP; #if VISMAC == 0 /* force a screen update after all is done */ update(FALSE); #endif } else { /* reset the macro to the begining for the next rep */ kbdptr = &kbdm[0]; return((int)*kbdptr++); } } /* fetch a character from the terminal driver */ c = TTgetc(); /* record it for $lastkey */ lastkey = c; /* save it if we need to */ if (kbdmode == RECORD) { *kbdptr++ = c; kbdend = kbdptr; /* don't overrun the buffer */ if (kbdptr == &kbdm[NKBDM - 1]) { kbdmode = STOP; TTbeep(); } } /* and finally give the char back */ return(c); } /* GET1KEY: Get one keystroke. The only prefixs legal here are the SPEC and CTRL prefixes. */ get1key() { int c; #if AMIGA int d; #endif /* get a keystroke */ c = tgetc(); #if MSDOS | ST520 if (c == 0) { /* Apply SPEC prefix */ c = tgetc(); if (c>=0x00 && c<=0x1F) /* control key? */ c = CTRL | (c+'@'); return(SPEC | c); } #endif #if AMIGA /* apply SPEC prefix */ if ((unsigned)c == 155) { c = tgetc(); /* first try to see if it is a cursor key */ if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T') return(SPEC | c); /* next, a 2 char sequence */ d = tgetc(); if (d == '~') return(SPEC | c); /* decode a 3 char sequence */ c = d + 32; /* if a shifted function key, eat the tilde */ if (d >= '0' && d <= '9') d = tgetc(); return(SPEC | c); } #endif #if WANGPC if (c == 0x1F) { /* Apply SPEC prefix */ c = tgetc(); return(SPEC | c); } #endif if (c>=0x00 && c<=0x1F) /* C0 control -> C- */ c = CTRL | (c+'@'); return (c); } /* GETCMD: Get a command from the keyboard. Process all applicable prefix keys */ getcmd() { int c; /* fetched keystroke */ /* get initial character */ c = get1key(); /* process META prefix */ if (c == metac) { c = get1key(); if (islower(c)) /* Force to upper */ c ^= DIFCASE; if (c>=0x00 && c<=0x1F) /* control key */ c = CTRL | (c+'@'); return(META | c); } /* process CTLX prefix */ if (c == ctlxc) { c = get1key(); if (c>='a' && c<='z') /* Force to upper */ c -= 0x20; if (c>=0x00 && c<=0x1F) /* control key */ c = CTRL | (c+'@'); return(CTLX | c); } /* otherwise, just return it */ return(c); } /* A more generalized prompt/reply function allowing the caller to specify the proper terminator. If the terminator is not a return ('\n') it will echo as "" */ getstring(prompt, buf, nbuf, eolchar) char *prompt; char *buf; int eolchar; { register int cpos; /* current character position in string */ register int c; register int quotef; /* are we quoting the next char? */ cpos = 0; quotef = FALSE; /* prompt the user for the input string */ mlwrite(prompt); for (;;) { /* get a character from the user */ c = get1key(); /* If it is a , change it to a */ if (c == (CTRL | 0x4d)) c = CTRL | 0x40 | '\n'; /* if they hit the line terminate, wrap it up */ if (c == eolchar && quotef == FALSE) { buf[cpos++] = 0; /* clear the message line */ mlwrite(""); TTflush(); /* if we default the buffer, return FALSE */ if (buf[0] == 0) return(FALSE); return(TRUE); } /* change from command form back to character form */ c = ectoc(c); if (c == ectoc(abortc) && quotef == FALSE) { /* Abort the input? */ ctrlg(FALSE, 0); TTflush(); return(ABORT); } else if ((c==0x7F || c==0x08) && quotef==FALSE) { /* rubout/erase */ if (cpos != 0) { outstring("\b \b"); --ttcol; if (buf[--cpos] < 0x20) { outstring("\b \b"); --ttcol; } if (buf[cpos] == '\n') { outstring("\b\b \b\b"); ttcol -= 2; } TTflush(); } } else if (c == 0x15 && quotef == FALSE) { /* C-U, kill */ while (cpos != 0) { outstring("\b \b"); --ttcol; if (buf[--cpos] < 0x20) { outstring("\b \b"); --ttcol; } } TTflush(); } else if (c == quotec && quotef == FALSE) { quotef = TRUE; } else { quotef = FALSE; if (cpos < nbuf-1) { buf[cpos++] = c; if ((c < ' ') && (c != '\n')) { outstring("^"); ++ttcol; c ^= 0x40; } if (c != '\n') { if (disinp) TTputc(c); } else { /* put out for */ outstring(""); ttcol += 3; } ++ttcol; TTflush(); } } } } outstring(s) /* output a string of characters */ char *s; /* string to output */ { if (disinp) while (*s) TTputc(*s++); } SHAR_EOF chmod +x 'input.c' fi echo shar: "extracting 'isearch.c'" '(0 character)' if test -f 'isearch.c' then echo shar: "will not over-write existing file 'isearch.c'" else cat << \SHAR_EOF > 'isearch.c' /* * The functions in this file implement commands that perform incremental * searches in the forward and backward directions. This "ISearch" command * is intended to emulate the same command from the original EMACS * implementation (ITS). Contains references to routines internal to * SEARCH.C. * * REVISION HISTORY: * * D. R. Banks 9-May-86 * - added ITS EMACSlike ISearch * * John M. Gamble 5-Oct-86 * - Made iterative search use search.c's scanner() routine. * This allowed the elimination of bakscan(). * - Put isearch constants into estruct.h * - Eliminated the passing of 'status' to scanmore() and * checknext(), since there were no circumstances where * it ever equalled FALSE. */ #include #include "estruct.h" #include "edef.h" #if ISRCH extern int scanner(); /* Handy search routine */ extern int eq(); /* Compare chars, match case */ /* A couple of "own" variables for re-eat */ int (*saved_get_char)(); /* Get character routine */ int eaten_char = -1; /* Re-eaten char */ /* A couple more "own" variables for the command string */ int cmd_buff[CMDBUFLEN]; /* Save the command args here */ int cmd_offset; /* Current offset into command buff */ int cmd_reexecute = -1; /* > 0 if re-executing command */ /* * Subroutine to do incremental reverse search. It actually uses the * same code as the normal incremental search, as both can go both ways. */ int risearch(f, n) { LINE *curline; /* Current line on entry */ int curoff; /* Current offset on entry */ /* remember the initial . on entry: */ curline = curwp->w_dotp; /* Save the current line pointer */ curoff = curwp->w_doto; /* Save the current offset */ /* Make sure the search doesn't match where we already are: */ backchar(TRUE, 1); /* Back up a character */ if (!(isearch(f, -n))) /* Call ISearch backwards */ { /* If error in search: */ curwp->w_dotp = curline; /* Reset the line pointer */ curwp->w_doto = curoff; /* and the offset to original value */ curwp->w_flag |= WFMOVE; /* Say we've moved */ update(FALSE); /* And force an update */ mlwrite ("[search failed]"); /* Say we died */ } else mlerase (); /* If happy, just erase the cmd line */ } /* Again, but for the forward direction */ int fisearch(f, n) { LINE *curline; /* Current line on entry */ int curoff; /* Current offset on entry */ /* remember the initial . on entry: */ curline = curwp->w_dotp; /* Save the current line pointer */ curoff = curwp->w_doto; /* Save the current offset */ /* do the search */ if (!(isearch(f, n))) /* Call ISearch forwards */ { /* If error in search: */ curwp->w_dotp = curline; /* Reset the line pointer */ curwp->w_doto = curoff; /* and the offset to original value */ curwp->w_flag |= WFMOVE; /* Say we've moved */ update(FALSE); /* And force an update */ mlwrite ("[search failed]"); /* Say we died */ } else mlerase (); /* If happy, just erase the cmd line */ } /* * Subroutine to do an incremental search. In general, this works similarly * to the older micro-emacs search function, except that the search happens * as each character is typed, with the screen and cursor updated with each * new search character. * * While searching forward, each successive character will leave the cursor * at the end of the entire matched string. Typing a Control-S or Control-X * will cause the next occurrence of the string to be searched for (where the * next occurrence does NOT overlap the current occurrence). A Control-R will * change to a backwards search, META will terminate the search and Control-G * will abort the search. Rubout will back up to the previous match of the * string, or if the starting point is reached first, it will delete the * last character from the search string. * * While searching backward, each successive character will leave the cursor * at the beginning of the matched string. Typing a Control-R will search * backward for the next occurrence of the string. Control-S or Control-X * will revert the search to the forward direction. In general, the reverse * incremental search is just like the forward incremental search inverted. * * In all cases, if the search fails, the user will be feeped, and the search * will stall until the pattern string is edited back into something that * exists (or until the search is aborted). */ isearch(f, n) { int status; /* Search status */ int col; /* prompt column */ register int cpos; /* character number in search string */ register int c; /* current input character */ register int expc; /* function expanded input char */ char pat_save[NPAT]; /* Saved copy of the old pattern str */ LINE *curline; /* Current line on entry */ int curoff; /* Current offset on entry */ int init_direction; /* The initial search direction */ /* Initialize starting conditions */ cmd_reexecute = -1; /* We're not re-executing (yet?) */ cmd_offset = 0; /* Start at the beginning of the buff */ cmd_buff[0] = '\0'; /* Init the command buffer */ strncpy (pat_save, pat, NPAT); /* Save the old pattern string */ curline = curwp->w_dotp; /* Save the current line pointer */ curoff = curwp->w_doto; /* Save the current offset */ init_direction = n; /* Save the initial search direction */ /* This is a good place to start a re-execution: */ start_over: /* ask the user for the text of a pattern */ col = promptpattern("ISearch: "); /* Prompt, remember the col */ cpos = 0; /* Start afresh */ status = TRUE; /* Assume everything's cool */ /* Get the first character in the pattern. If we get an initial Control-S or Control-R, re-use the old search string and find the first occurrence */ c = ectoc(expc = get_char()); /* Get the first character */ if ((c == IS_FORWARD) || (c == IS_REVERSE) || (c == IS_VMSFORW)) /* Reuse old search string? */ { for (cpos = 0; pat[cpos] != 0; cpos++) /* Yup, find the length */ col = echochar(pat[cpos],col); /* and re-echo the string */ if (c == IS_REVERSE) { /* forward search? */ n = -1; /* No, search in reverse */ backchar (TRUE, 1); /* Be defensive about EOB */ } else n = 1; /* Yes, search forward */ status = scanmore(pat, n); /* Do the search */ c = ectoc(expc = get_char()); /* Get another character */ } /* Top of the per character loop */ for (;;) /* ISearch per character loop */ { /* Check for special characters first: */ /* Most cases here change the search */ if (expc == metac) /* Want to quit searching? */ return (TRUE); /* Quit searching now */ switch (c) /* dispatch on the input char */ { case IS_ABORT: /* If abort search request */ return(FALSE); /* Quit searching again */ case IS_REVERSE: /* If backward search */ case IS_FORWARD: /* If forward search */ case IS_VMSFORW: /* of either flavor */ if (c == IS_REVERSE) /* If reverse search */ n = -1; /* Set the reverse direction */ else /* Otherwise, */ n = 1; /* go forward */ status = scanmore(pat, n); /* Start the search again */ c = ectoc(expc = get_char()); /* Get the next char */ continue; /* Go continue with the search*/ case IS_NEWLINE: /* Carriage return */ c = '\n'; /* Make it a new line */ break; /* Make sure we use it */ case IS_QUOTE: /* Quote character */ case IS_VMSQUOTE: /* of either variety */ c = ectoc(expc = get_char()); /* Get the next char */ case IS_TAB: /* Generically allowed */ case '\n': /* controlled characters */ break; /* Make sure we use it */ case IS_BACKSP: /* If a backspace: */ case IS_RUBOUT: /* or if a Rubout: */ if (cmd_offset <= 1) /* Anything to delete? */ return (TRUE); /* No, just exit */ --cmd_offset; /* Back up over the Rubout */ cmd_buff[--cmd_offset] = '\0'; /* Yes, delete last char */ curwp->w_dotp = curline; /* Reset the line pointer */ curwp->w_doto = curoff; /* and the offset */ n = init_direction; /* Reset the search direction */ strncpy (pat, pat_save, NPAT); /* Restore the old search str */ cmd_reexecute = 0; /* Start the whole mess over */ goto start_over; /* Let it take care of itself */ /* Presumably a quasi-normal character comes here */ default: /* All other chars */ if (c < ' ') /* Is it printable? */ { /* Nope. */ reeat (c); /* Re-eat the char */ return (TRUE); /* And return the last status */ } } /* Switch */ /* I guess we got something to search for, so search for it */ pat[cpos++] = c; /* put the char in the buffer */ if (cpos >= NPAT) /* too many chars in string? */ { /* Yup. Complain about it */ mlwrite("? Search string too long"); return(TRUE); /* Return an error */ } pat[cpos] = 0; /* null terminate the buffer */ col = echochar(c,col); /* Echo the character */ if (!status) { /* If we lost last time */ TTputc(BELL); /* Feep again */ TTflush(); /* see that the feep feeps */ } else /* Otherwise, we must have won*/ if (!(status = checknext(c, pat, n))) /* See if match */ status = scanmore(pat, n); /* or find the next match */ c = ectoc(expc = get_char()); /* Get the next char */ } /* for {;;} */ } /* * Trivial routine to insure that the next character in the search string is * still true to whatever we're pointing to in the buffer. This routine will * not attempt to move the "point" if the match fails, although it will * implicitly move the "point" if we're forward searching, and find a match, * since that's the way forward isearch works. * * If the compare fails, we return FALSE and assume the caller will call * scanmore or something. */ int checknext (chr, patrn, dir) /* Check next character in search string */ char chr; /* Next char to look for */ char *patrn; /* The entire search string (incl chr) */ int dir; /* Search direction */ { register LINE *curline; /* current line during scan */ register int curoff; /* position within current line */ register int buffchar; /* character at current position */ int status; /* how well things go */ /* setup the local scan pointer to current "." */ curline = curwp->w_dotp; /* Get the current line structure */ curoff = curwp->w_doto; /* Get the offset within that line */ if (dir > 0) /* If searching forward */ { if (curoff == llength(curline)) /* If at end of line */ { curline = lforw(curline); /* Skip to the next line */ if (curline == curbp->b_linep) return (FALSE); /* Abort if at end of buffer */ curoff = 0; /* Start at the beginning of the line */ buffchar = '\n'; /* And say the next char is NL */ } else buffchar = lgetc(curline, curoff++); /* Get the next char */ if (status = eq(buffchar, chr)) /* Is it what we're looking for? */ { curwp->w_dotp = curline; /* Yes, set the buffer's point */ curwp->w_doto = curoff; /* to the matched character */ curwp->w_flag |= WFMOVE; /* Say that we've moved */ } return (status); /* And return the status */ } else /* Else, if reverse search: */ return (match_pat (patrn)); /* See if we're in the right place */ } /* * This hack will search for the next occurrence of in the buffer, either * forward or backward. It is called with the status of the prior search * attempt, so that it knows not to bother if it didn't work last time. If * we can't find any more matches, "point" is left where it was before. If * we do find a match, "point" will be at the end of the matched string for * forward searches and at the beginning of the matched string for reverse * searches. */ int scanmore(patrn, dir) /* search forward or back for a pattern */ char *patrn; /* string to scan for */ int dir; /* direction to search */ { int sts; /* search status */ if (dir < 0) /* reverse search? */ { rvstrcpy(tap, patrn); /* Put reversed string in tap */ sts = scanner(tap, REVERSE, PTBEG); } else sts = scanner(patrn, FORWARD, PTEND); /* Nope. Go forward */ if (!sts) { TTputc(BELL); /* Feep if search fails */ TTflush(); /* see that the feep feeps */ } return(sts); /* else, don't even try */ } /* * The following is a worker subroutine used by the reverse search. It * compares the pattern string with the characters at "." for equality. If * any characters mismatch, it will return FALSE. * * This isn't used for forward searches, because forward searches leave "." * at the end of the search string (instead of in front), so all that needs to * be done is match the last char input. */ int match_pat (patrn) /* See if the pattern string matches string at "." */ char *patrn; /* String to match to buffer */ { register int i; /* Generic loop index/offset */ register int buffchar; /* character at current position */ register LINE *curline; /* current line during scan */ register int curoff; /* position within current line */ /* setup the local scan pointer to current "." */ curline = curwp->w_dotp; /* Get the current line structure */ curoff = curwp->w_doto; /* Get the offset within that line */ /* top of per character compare loop: */ for (i = 0; i < strlen(patrn); i++) /* Loop for all characters in patrn */ { if (curoff == llength(curline)) /* If at end of line */ { curline = lforw(curline); /* Skip to the next line */ curoff = 0; /* Start at the beginning of the line */ if (curline == curbp->b_linep) return (FALSE); /* Abort if at end of buffer */ buffchar = '\n'; /* And say the next char is NL */ } else buffchar = lgetc(curline, curoff++); /* Get the next char */ if (!eq(buffchar, patrn[i])) /* Is it what we're looking for? */ return (FALSE); /* Nope, just punt it then */ } return (TRUE); /* Everything matched? Let's celebrate*/ } /* Routine to prompt for I-Search string. */ int promptpattern(prompt) char *prompt; { char tpat[NPAT+20]; strcpy(tpat, prompt); /* copy prompt to output string */ strcat(tpat, " ["); /* build new prompt string */ expandp(pat, &tpat[strlen(tpat)], NPAT/2); /* add old pattern */ strcat(tpat, "]: "); /* check to see if we are executing a command line */ if (!clexec) { mlwrite(tpat); } return(strlen(tpat)); } /* routine to echo i-search characters */ int echochar(c,col) int c; /* character to be echoed */ int col; /* column to be echoed in */ { movecursor(term.t_nrow,col); /* Position the cursor */ if ((c < ' ') || (c == 0x7F)) /* Control character? */ { switch (c) /* Yes, dispatch special cases*/ { case '\n': /* Newline */ TTputc('<'); TTputc('N'); TTputc('L'); TTputc('>'); col += 3; break; case '\t': /* Tab */ TTputc('<'); TTputc('T'); TTputc('A'); TTputc('B'); TTputc('>'); col += 4; break; case 0x7F: /* Rubout: */ TTputc('^'); /* Output a funny looking */ TTputc('?'); /* indication of Rubout */ col++; /* Count the extra char */ break; default: /* Vanilla control char */ TTputc('^'); /* Yes, output prefix */ TTputc(c+0x40); /* Make it "^X" */ col++; /* Count this char */ } } else TTputc(c); /* Otherwise, output raw char */ TTflush(); /* Flush the output */ return(++col); /* return the new column no */ } /* * Routine to get the next character from the input stream. If we're reading * from the real terminal, force a screen update before we get the char. * Otherwise, we must be re-executing the command string, so just return the * next character. */ int get_char () { int c; /* A place to get a character */ /* See if we're re-executing: */ if (cmd_reexecute >= 0) /* Is there an offset? */ if ((c = cmd_buff[cmd_reexecute++]) != 0) return (c); /* Yes, return any character */ /* We're not re-executing (or aren't any more). Try for a real char */ cmd_reexecute = -1; /* Say we're in real mode again */ update(FALSE); /* Pretty up the screen */ if (cmd_offset >= CMDBUFLEN-1) /* If we're getting too big ... */ { mlwrite ("? command too long"); /* Complain loudly and bitterly */ return (metac); /* And force a quit */ } c = get1key(); /* Get the next character */ cmd_buff[cmd_offset++] = c; /* Save the char for next time */ cmd_buff[cmd_offset] = '\0';/* And terminate the buffer */ return (c); /* Return the character */ } /* * Hacky routine to re-eat a character. This will save the character to be * re-eaten by redirecting the input call to a routine here. Hack, etc. */ /* Come here on the next term.t_getchar call: */ int uneat() { int c; term.t_getchar = saved_get_char; /* restore the routine address */ c = eaten_char; /* Get the re-eaten char */ eaten_char = -1; /* Clear the old char */ return(c); /* and return the last char */ } int reeat(c) int c; { if (eaten_char != -1) /* If we've already been here */ return/*(NULL)*/; /* Don't do it again */ eaten_char = c; /* Else, save the char for later */ saved_get_char = term.t_getchar; /* Save the char get routine */ term.t_getchar = uneat; /* Replace it with ours */ } #else isearch() { } #endif SHAR_EOF chmod +x 'isearch.c' fi echo shar: "extracting 'line.c'" '(0 character)' if test -f 'line.c' then echo shar: "will not over-write existing file 'line.c'" else cat << \SHAR_EOF > 'line.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 #include "estruct.h" #include "edef.h" KILL *ykbuf; /* ptr to current kill buffer chunk being yanked */ int ykboff; /* offset into that chunk */ /* * 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; char *malloc(); 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; } } insspace(f, n) /* insert spaces forward into text */ int f, n; /* default flag and numeric argument */ { linsert(n, ' '); backchar(f, n); } /* * 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; if (curbp->b_mode&MDVIEW) /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ 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; il_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; il_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); } /* * 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; if (curbp->b_mode&MDVIEW) /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ 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) long n; /* # of chars to delete */ int kflag; /* put killed text in kill buffer flag */ { register char *cp1; register char *cp2; register LINE *dotp; register int doto; register int chunk; register WINDOW *wp; if (curbp->b_mode&MDVIEW) /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ 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; if (curbp->b_mode&MDVIEW) /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ 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() { KILL *kp; /* ptr to scan kill buffer chunk list */ if (kbufh != NULL) { /* first, delete all the chunks */ kbufp = kbufh; while (kbufp != NULL) { kp = kbufp->d_next; free(kbufp); kbufp = kp; } /* and reset all the kill buffer pointers */ kbufh = kbufp = NULL; kused = KBLOCK; } } /* * Insert a character to the kill buffer, allocating new chunks as needed. * Return TRUE if all is well, and FALSE on errors. */ kinsert(c) int c; /* character to insert in the kill buffer */ { KILL *nchunk; /* ptr to newly malloced chunk */ /* check to see if we need a new chunk */ if (kused >= KBLOCK) { if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL) return(FALSE); if (kbufh == NULL) /* set head ptr if first time */ kbufh = nchunk; if (kbufp != NULL) /* point the current to this new one */ kbufp->d_next = nchunk; kbufp = nchunk; kbufp->d_next = NULL; kused = 0; } /* and now insert the character */ kbufp->d_chunk[kused++] = c; 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. Bound to "C-Y". */ yank(f, n) { register int c; register int i; register char *sp; /* pointer into string to insert */ KILL *kp; /* pointer into kill buffer */ if (curbp->b_mode&MDVIEW) /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ if (n < 0) return (FALSE); /* make sure there is something to yank */ if (kbufh == NULL) return(TRUE); /* not an error, just nothing */ /* for each time.... */ while (n--) { kp = kbufh; while (kp != NULL) { if (kp->d_next == NULL) i = kused; else i = KBLOCK; sp = kp->d_chunk; while (i--) { if ((c = *sp++) == '\n') { if (lnewline() == FALSE) return (FALSE); } else { if (linsert(1, c) == FALSE) return (FALSE); } } kp = kp->d_next; } } return (TRUE); } SHAR_EOF chmod +x 'line.c' fi echo shar: "extracting 'lock.c'" '(0 character)' if test -f 'lock.c' then echo shar: "will not over-write existing file 'lock.c'" else cat << \SHAR_EOF > 'lock.c' /* LOCK: File locking command routines for MicroEMACS written by Daniel Lawrence */ #include #include "estruct.h" #include "edef.h" #if FILOCK #if BSD #include extern int sys_nerr; /* number of system error messages defined */ extern char *sys_errlist[]; /* list of message texts */ extern int errno; /* current error */ char *lname[NLOCKS]; /* names of all locked files */ int numlocks; /* # of current locks active */ /* lockchk: check a file for locking and add it to the list */ lockchk(fname) char *fname; /* file to check for a lock */ { register int i; /* loop indexes */ register int status; /* return status */ char *undolock(); /* check to see if that file is already locked here */ if (numlocks > 0) for (i=0; i < numlocks; ++i) if (strcmp(fname, lname[i]) == 0) return(TRUE); /* if we have a full locking table, bitch and leave */ if (numlocks == NLOCKS) { mlwrite("LOCK ERROR: Lock table full"); return(ABORT); } /* next, try to lock it */ status = lock(fname); if (status == ABORT) /* file is locked, no override */ return(ABORT); if (status == FALSE) /* locked, overriden, dont add to table */ return(TRUE); /* we have now locked it, add it to our table */ lname[++numlocks - 1] = (char *)malloc(strlen(fname) + 1); if (lname[numlocks - 1] == NULL) { /* malloc failure */ undolock(fname); /* free the lock */ mlwrite("Cannot lock, out of memory"); --numlocks; return(ABORT); } /* everthing is cool, add it to the table */ strcpy(lname[numlocks-1], fname); return(TRUE); } /* lockrel: release all the file locks so others may edit */ lockrel() { register int i; /* loop index */ register int status; /* status of locks */ register int s; /* status of one unlock */ status = TRUE; if (numlocks > 0) for (i=0; i < numlocks; ++i) { if ((s = unlock(lname[i])) != TRUE) status = s; free(lname[i]); } numlocks = 0; return(status); } /* lock: Check and lock a file from access by others returns TRUE = files was not locked and now is FALSE = file was locked and overridden ABORT = file was locked, abort command */ lock(fname) char *fname; /* file name to lock */ { register char *locker; /* lock error message */ register int status; /* return status */ char msg[NSTRING]; /* message string */ char *dolock(); /* attempt to lock the file */ locker = dolock(fname); if (locker == NULL) /* we win */ return(TRUE); /* file failed...abort */ if (strncmp(locker, "LOCK", 4) == 0) { lckerror(locker); return(ABORT); } /* someone else has it....override? */ strcpy(msg, "File in use by "); strcat(msg, locker); strcat(msg, ", overide?"); status = mlyesno(msg); /* ask them */ if (status == TRUE) return(FALSE); else return(ABORT); } /* unlock: Unlock a file this only warns the user if it fails */ unlock(fname) char *fname; /* file to unlock */ { register char *locker; /* undolock return string */ char *undolock(); /* unclock and return */ locker = undolock(fname); if (locker == NULL) return(TRUE); /* report the error and come back */ lckerror(locker); return(FALSE); } lckerror(errstr) /* report a lock error */ char *errstr; /* lock error string to print out */ { char obuf[NSTRING]; /* output buffer for error message */ strcpy(obuf, errstr); strcat(obuf, " - "); if (errno < sys_nerr) strcat(obuf, sys_errlist[errno]); else strcat(obuf, "[can not get system error message]"); mlwrite(obuf); } #endif #else lckhello() /* dummy function */ { } #endif SHAR_EOF chmod +x 'lock.c' fi exit 0 # End of shell archive