/* EMACS_MODES: c, !fill */ #include "emacs_io.h" #include "emacs_gb.h" #include "emacs_cmds.h" #include <signal.h> #ifdef ux3 #include <fcntl.h> #endif /* lext -- extend line up to position if necessary */ lext(line,col) /* Keywords: picture-mode movement insertion */ { mvc (line,col); if (column<col) insertc(col-column,' '); } dput(c) /* Keywords: insertion modes:10 overwrite-mode */ { if (NODEL) insertc(1,c); else put(c); } /* move forward COUNT characters */ /* Keywords: movement commands forwards character-at-a-time picture-mode:20 */ forw(count) register int count; { register int retval; if (PICMODE) { if (count>0) { lext(curln,count+column); return(1); } else { column += count; if (column<0) { beep(); column=0; return(0); } else return(1); } } if (count < 0) { retval = findb(-count); } else { retval = findf(count); } if (retval == 0) beep(); /* couldn't go all the way */ move(kline,kcol); return(retval); } /* backward COUNT characters */ back(count) /* Keywords: movement commands forwards character-at-a-time */ register int count; { forw(-count); /* do it this way */ } /* move to previous line, same collumn */ upl (count) /* Keywords: commands backwards:30 upward-movement movement text-lines */ register int count; { if (curln-count < 1) { if (count == 1) { beep(); return(0); } else curln = 1; } else curln -= count; if (PICMODE) lext(curln,column); else mvc(curln,column); return(1); } /* move down one line, same column */ downl (count) /* Keywords: commands forwards:30 downward-movement movement text-lines */ register int count; { register int retval; if (((curln += count) > nlines)&& (PICMODE == 0)) { curln = nlines+NLRUN; beep(); retval = 0; } else retval = 1; if (PICMODE) lext(curln,column); else mvc(curln,column); return(retval); } /* abort EMACS */ int aborts = 0; eabort(sig) int sig; { /* Keywords: internal-errors unix-interface commands */ if (sig){ signal(sig,SIG_DFL); /* Prevent looping */ } signal (SIGIOT,SIG_DFL); cook(); if (aborts>3) exit(-1); aborts++; #ifdef MINFILES rmtemp(); #endif #ifdef PC rmtemp(); exit(-1); #else #ifdef bsd sigsetmask(0); /* ARGH, set mask to allow abort! */ #endif abort(); exit(-1); #endif PC } /* exit EMACS */ quit() { /* Keywords: commands exit-processing user-interface:20 unix-interface:30 */ clear(); cook(); statout(); #ifdef MINFILES rmtemp(); /* flush temp files */ #endif #ifdef PC rmtemp(); #else flushproc(); #endif exit(0); } /* exit EMACS gracefully */ gquit() /* Keywords: commands exit-processing user-interface:20 unix-interface:30 macro-hooks:10 */ { if (hooks[Exit_Emacs_Hook]) if (hook(Exit_Emacs_Hook) == 0) return; if(bclean()== 0)quit(); } /* kill line */ /* if the count is one, and if there is text on the line beyond column, * only that text is killed * if count is one, and column is at end of line, the end of line is killed */ /* if count is greater than one, the next count lines (and their end of * lines) are killed */ /* all killed text is put into the kill stack */ ekill (count) register int count; /* Keywords: commands deletion killstack:10 text-lines */ { register int l; int opic,onodel; if (numarg == 0) { if ((l=leng(curln)) > column) { return(delc(l-column)); } } opic = PICMODE; onodel =NODEL; PICMODE=NODEL=0; /* Allow line kills! */ kline = curln+count; kcol = 0; l= tkill(); PICMODE=opic; NODEL=onodel; return(l); } /* goto beginning of current line */ begin() /* Keywords: text-lines commands movement backwards */ { move(curln,0); } /* goto end of line */ endl() /* Keywords: text-lines commands movement backwards */ { mvc (curln,10000); /* mvc will adjust line length */ } mquote(arg) int arg; /* Keywords: quoting commands insertion */ { quote(arg,0200); } rquote(arg) int arg; /* Keywords: quoting commands insertion */ { quote(arg,0); } /* insert the next character, whatever it is */ /* note that newlines inserted ths way act just like unquoted newlines */ quote(count,metf) register int metf; register int count; { /* Keywords: quoting commands insertion */ register int c; while(count--) { if ((VERBOSE)&& (MOREIN == 0)) prompt1("%d ^Q: ",count+1); c = getchar(); c = c | metf; insertc(1,c); if (VERBOSE && (MOREIN == 0)) { unprompt(); } disup(); } } /* numchar -- convert argument to a character to insert */ numchar(count) /* Keywords: quoting commands insertion argument-processing */ register int count; { insertc(1,count); /* insert the count */ } /* deletes count characters going forward */ fdel(count) /* Keywords: commands deletion forwards character-at-a-time */ { IGNORE(findf(count)); return(tkill()); } /* deletes count characters going backward */ bdel(count) register int count; /* Keywords: commands deletion backwards character-at-a-time */ { IGNORE(findb(count)); return(tkill()); } /* file write command */ int fright(arg) int arg; { register char *np; /* Keywords: files commands buffers:20 filenames:10 writing */ if ((np = expenv(getname("Write file? "))) != NULL) { return(wout(np,arg)); } return(0); } /* fred -- read a file */ fred(arg) int arg; { /* Keywords: files commands buffers:20 filenames:10 reading */ register char *np; if ((np = expenv(getname("Read File? "))) != NULL) { return(readin(np,arg)); } else return(0); } /* forward words -- leaves kline, kcol at spot that is count words *forward */ wordf(count) register int count; { kmark(); /* Keywords: commands:10 forwards movement:50 deletion:50 word-oriented-commands */ while (count--) { if (skipf(WRDSEP) || skipf(WRDCHR)) { return; } } } /* skips kline, kcol forward until a character without type bit on is * found */ skipf(bit) register int bit; /* Keywords: forwards sentence-commands word-oriented-commands movement:20 commands:10 */ { while (bits[*klptr] & bit) { if (mfk()) return(1); } return(0); } /* move forward count words */ mfwrd(count) /* Keywords: commands forwards movement word-oriented-commands */ register int count; { wordf(count); move(kline,kcol); } /* kill next count words */ kfwrd(count) /* Keywords: commands forwards deletion word-oriented-commands */ register int count; { wordf(count); return(tkill()); } /* skip kline, kcol back until a character without type bit is found */ skipb(bit) register int bit; /* Keywords: sentence-commands word-oriented-commands movement:20 backwards commands:10 */ { do { if (mbk()) return(1); } while (bits[*klptr] &bit); return(0); } /* backward count words, leaves pointer in kline, kcol */ wordb(count) register int count; /* Keywords: commands:10 backwards movement:10 deletion:20 word-oriented-commands */ { kmark(); while (count--) { if ((skipb(WRDSEP) || skipb(WRDCHR))) { return; } } IGNORE(mfk()); } /* move back count words */ mbwrd(count) register int count; /* Keywords: commands backwards movement word-oriented-commands */ { wordb(count); move(kline,kcol); } /* kill back count words */ kbwrd(count) register int count; /* Keywords: commands backwards deletion word-oriented-commands */ { wordb(count); return(tkill()); } /* kmark -- set kline,kcol and klptr */ kmark() /* Keywords: commands:5 movement:50 deletion:50 character-at-a-time:20 word-oriented-commands:20 sentence-commands:20 */ { kline = curln; kcol = column; klptr = mkline(kline)+kcol; } /* move kline,kcol forward one */ mfk() /* Keywords: commands:5 movement:50 deletion:50 character-at-a-time:20 word-oriented-commands:20 sentence-commands:20 forwards */ { if ((*klptr++)!=EOL ) { ++kcol; return(0); } if (kline<nlines) { ++kline; klptr = mkline(kline); kcol=0; return(0); } return(1); } /* move kline, kcol back one character */ mbk() /* Keywords: commands:5 movement:50 deletion:50 character-at-a-time:20 word-oriented-commands:20 sentence-commands:20 backwards */ { if ((kcol--)>0) { klptr--; return(0); } if (kline>1) { --kline; kcol = leng(kline); klptr = mkline(kline) + kcol; return(0); } kcol = 0; return(1); } /* forward to end of sentence */ /* leaves resulting pointer in kline, kcol */ fsent () /* Keywords: commands:10 forwards movement:40 sentence-commands */ { kmark(); while (mfk() == 0) { if ((bits[*klptr] & SENTE) && (bits[klptr[1]]&WHITE)) { return(1); } } return(0); } /* back one sentence, leaves pointer in kline, kcol */ bsent() /* Keywords: commands:10 backwards movement:40 sentence-commands */ { kmark(); IGNORE(skipb(WRDSEP)); while (mbk() == 0) { if (kcol == 0) { if (kline>1) { if (bits[*mkline(kline-1)] & SENTE) return(1); } } if ((bits[*klptr] & SENTE) && (bits[klptr[1]] & WHITE)) { IGNORE(skipf(WRDCHR)); IGNORE(skipf(WRDSEP)); return(1); } } return(0); } /* move back count sentences */ ssent(count) register int count; /* Keywords: commands backwards movement sentence-commands */ { while (count--) { if(bsent()) move(kline,kcol); } } /* move forward count sentences */ esent(count) register int count; /* Keywords: commands forwards movement sentence-commands */ { while (count--) { if (fsent() == 0) break; move(kline,kcol+1); } } /* move to top of file */ top() /* Keywords: files:20 buffers:20 movement upward-movement commands */ { move(1,0); } /* move to end of file */ bot() /* Keywords: files:20 buffers:20 movement downward-movement commands */ { mvc(nlines,10000); } /* new line handler */ /* First, finishes off comment on the current line (if any) */ /* Next, if the current buffer has a sub-process, the line is sent to the sub-process */ /* Then, if the next line is non-empty, it creates an empty next line */ /* next, the next line is tab adjusted (if in C mode ) */ /* now, any text on the current line beyond the current position, it is * moved to the end of the next line */ /* finally, the pointer is moved to the (tab adjusted) start of the next * line */ /* if count > 1, then count-1 blank lines will be inserted in between * the current line and the 'next' line */ nl(count) /* Keywords: commands C-mode:30 insertion text-lines comments:50 shell-escape:10 */ register int count; { if (RARE == 0) { if (comln == curln) putin(" */"); #ifndef PC if (curbf == procbuf){ MARK *mp; mp = markptr(curbf); if ((mp->markl == curln) && (mp->markc <= column)) { /* If this is the last line on which output was done from */ /* the sub-process, then send from mark and re-mark */ sendproc (clptr+mp->markc, column+1-mp->markc); mp->markl = curln+1; mp->markc = 0; } else { sendproc(clptr,column+1); } } #endif } comln = 0; if ((count != 1) || (NLINS) || (isblank(curln+1)==0) || (clptr[column] != EOL)) { openl(count); } if (TABMD&& (RARE == 0)) tabjust(curln+count); else move(curln+count,0); } /* sets mark at current position */ mark(mnumb) /* Keywords: marking regions commands */ { MARK *markp; markp = markptr(mnumb); markp->markl = curln; markp->markc = column; } /* returns mark pointer */ MARK *markptr(mnumb) register int mnumb; /* Keywords: commands:10 marking:50 regions deletion:50 movement:50 */ { if (mnumb >= NMARKS) { error(WARN,44); mnumb = curbf; } if ((mnumb == 1) && (numarg == 0)) mnumb = curbf; return(&marks[mnumb]); } /* kills text between current position and mark position */ mkill(mnumb) int mnumb; /* Keywords: commands deletion regions */ { register MARK *markp; markp = markptr(mnumb); kline = markp->markl; if (kline < 1) kline = 1; if (kline > nlines) kline = nlines; kcol = leng(kline); if (markp->markc < kcol) kcol = markp->markc; if (PICMODE) { /* This pain is to get the * mark to work in picture * mode so that everything * up to and including the * marked position is killed */ if (kcol > column) { kcol++; } else { forw(1); } } return(tkill()); } /* retrieves text from the kill stack and inserts it (count times ) */ int yline; int ycol; yank(count) /* Keywords: regions commands insertion killstack retrieval popping:10 */ register int count; { register int result; register int unp; unp = unstart(); mark(curbf); while (count--) { result = retrv(); } unend(unp); yline = curln; ycol = column; /* Save, so we know when not to re-yank */ return(result); } /* kills the marked region, removes the top item from the kill stack, * and then inserts the next area from the kill stack */ reyank(count) /* yank again */ register int count; /* Keywords: regions commands insertion killstack retrieval deletion popping:10 */ { register int unp; if ((curln != yline) || (column != ycol)) { error (WARN,84); /* Prevent some nastyness */ return; } kbapp = 0; unp = unstart(); mkill(curbf); /* flush last insertion */ kpop(); /* first pop the mkill */ kpop(); /* now pop that last insertion */ yank(count); unend(unp); } /* search subroutine */ /* searches forward or backward for a string, starting at the * given position. If the string is found, 1 is returned, and the start * of the match is left in kline, kcol. Return of 0 indicates no match */ /* Keywords: searching */ srch(sline,scol,sp,direct) int sline; int scol; char *sp; int direct; { register char *lp; register char *cp; register int l; int c; lp = sp; while (c = *lp) *lp++ = casem[c&0177]; /* map string to allowed case */ lp = mkline(sline)+scol; while (1) { cp = sp; l = sline; while (*cp) { if ((c = casem[(*lp++)&0177]) != *cp++) goto again; if (c == EOL) { if (l == nlines) { if (direct>0) return(0); goto again; } ++l; lp = mkline(l); } } kline = sline; kcol = scol; return(1); again: if (brkflg) brkit(); lp = mkline(sline)+scol; if (direct>0) { do { if (*lp++ !=EOL) scol++; else { if (sline == nlines) return(0); sline++; scol = 0; lp = mkline(sline); } } while (casem[*lp&0177] != *sp); } else { do { if (--scol<0) { if (sline == 1) return(0); scol = leng(--sline); lp = mkline(sline)+scol; } else lp--; } while (casem[*lp&0177] != *sp); } } } fisrch(arg) int arg; /* Keywords: searching commands forwards key-bindings:10 */ { return(isrch(1,arg)); } risrch(arg) int arg; /* Keywords: searching commands backwards key-bindings:10 */ { return(isrch(-1,arg)); } /* incremental search command (either direction) */ isrch(d,arg) int d; int arg; /* Keywords: commands:80 searching user-interface:60 key-bindings:50 */ { int oldln; int oldcol; register char *ilp; register int c; int lx; int ly; int nd; int missed; char sst[40]; char *xp; ilp = sst; missed = 0; lx = oldln = curln; ly = oldcol = column; if (infrn < 0) { /* if in a macro */ xp = getname(NULL); /* search argument */ ilp = mstrcpy(ilp,xp); } while (1) { *ilp = 0; if (missed == 0) { psrch(d,sst); /* prompt */ if (infrn == 0) mflush(stdout); if (srch(curln,column,sst,d) == NULL) { move(lx,ly); if (infrn >= 0) { beep(); prompt1("Failing Search: %s", sst); } missed = 1; } else { move(lx = kline,ly = kcol); if (ilp!=sst)strcpy (presst,sst); missed = 0; } } if (infrn < 0) return(missed == 0); /* macro invocation */ disup(); if ((missed == 0) && (incnt == 0)) { psrch(d,sst); /* restore prompt */ mgo(nln,ncol); /* goback to display position */ } c = getchar(); if ((c == CTRLH)||(c == RUBOUT)) { if (ilp!=sst) ilp--; missed=0; move (oldln,oldcol); continue; /* next loop */ } if (c == CTRLG) { move (oldln,oldcol); unprompt(); beep(); return(0); } if (srch_nl?((c == '\n') || (c == '\r')) : (c == ESC)) { goout: unprompt(); return(missed == 0); } if (nd=issrch(c)) { if (nd == d) { if (ilp == sst) { ilp = mstrcpy(sst,presst); continue; } else { if (missed) { beep(); continue; } forw(d); } } else { missed=0; d = nd; } continue; } if (isquote(c)) { c = getchar(); /* skip all other processing */ } else { if (c == CTRLM) c = '\n'; if ((c < 040) && (c != '\n')) { ungetch(c); goto goout; } } if (missed) { beep(); continue; } *ilp++ = c; } } /* psrch -- print search prompt */ psrch(dir,sstp) register int dir; char *sstp; /* Keywords: mode-line prompting searching */ { if (dir>0) prompt1("Search: %s",sstp); else prompt1("Reverse Search: %s",sstp); } /* handle a separator character in auto fill mode */ /* if fill mode is on, and the current position is beyond FILLCOL, a * newline is inserted before the last word. Otherwise, just insert the * character at the current position */ afsep(count,chr) int count; int chr; /* Keywords: commands:40 modes:30 text-filling comments:20 C-mode:10 */ { register int cc; int newcol; int oldcol; char lbuf[MAXEL]; /* KLUDGE! */ register char *p1; register char *p2; /* whitespace characters in a macro expansion must be quoted to be * self-inserting. The following checks for non-zero character * count, input from macro, and a whitespace character to be * inserted. Under these conditions, no inserting is done. */ if (count && (infrn < 0)&& (WHITE&bits[chr])) return(1); if (FILLMD && (RARE == 0)) { insertc(count,chr); oldcol = column; cc = leng(curln) - column; mline=0; findpos(clptr,column); if (mline || (mcol>FILLCOL)|| (column > FILLCOL)) { again: newcol = column; do { column--; } while ((column) && (((bits[clptr[column]] & WHITE) == 0) || (clptr[column+1] == '.') || (clptr[column+1] == '\''))); mline=0; findpos(clptr,column); if (mline || (mcol>FILLCOL)|| (column > FILLCOL)) goto again; /* Now then, do the work. We are sitting at the right column to break the line */ /* First, save the rest of the line. Then, kill it, then, do a newline, */ /* now, bring it back */ if (column == 0) column = newcol; /* 1 word line */ if (column == oldcol) return(1); /* Do absolutely nothing */ p1 = clptr+column+1; /* Eat the whitespace character */ p2 = lbuf; while ((*p2++= *p1++)!=EOL); /* copy line */ sputl(curln,column,curln); /* Flag line is bad! */ clptr[column]=EOL; /* truncate line */ if (comln == curln) { comln = -1; nl(1); cment(1); *(clptr+column-3)=' '; } else nl(1); p1 = lbuf; while (*p1 != EOL) put(*p1++); /* restore line */ forw(-cc); /* go back to right place. */ } return(1); } insertc(count,chr); return(1); } /* unix escape */ char *shell = "sh"; /* name of shell processor */ ux(arg) int arg; { /* Keywords: commands buffers:20 unix-interface shell-escape */ register char *sp; if (SAVEMD) fsave(0); do { sp = (getname("command line? ")); } while (sp && (unx(sp,(arg != 1))== 0)); return(cstatus); } #ifndef PC char * nvmatch(s1, s2) register char *s1, *s2; /* Keywords: unix-interface shell-escape environment-variables */ { while(*s1 == *s2++) if(*s1++ == '=') return(s2); if(*s1 == '\0' && *(s2-1) == '=') return(s2); return(NULL); } /* Environment fixer-upper, adds definition of filename to the * environment and returns a pointer to it. */ extern char **environ; char ** fixenv(defp) register char *defp; /* Keywords: unix-interface shell-escape environment-variables */ { register char **xp; register char **yp; int envd = 0; xp =((char **) &bbuf[0][0]); /* Overlay screen */ yp = environ; while (*xp = *yp++) { if (nvmatch(defp,*xp++)) { xp[-1] = defp; envd=1; } } if (envd==0) { *xp++ = defp; *xp = NULL; } xp =((char **) &bbuf[0][0]); /* Overlay screen */ return(xp); } #endif /* general unix escape -- */ /* flag = 0 means just run it */ /* flag = 1 means run and feed it the buffer */ /* flag = 2 means run and replace .exec with the result */ /* flag = 3 means run and append result to .exec */ /* flag = 4 means run and bring results back in fnbuf */ /* flag = 5 means run and hook up input and output pipes */ /* flag = 6 means run it and hook up output to splfile, leave input in splfile */ /* flag = 7 means run it and hook up input from splfile, leave output in splfile */ #define UNEEDSIN 1 #define UNEEDSOUT 2 #define UDOTEXEC 4 #define UNOSCREEN 8 #define URETBUF 16 #define UPROCESS 32 #define USENDBUF 64 #define UREADBUF 128 #define UINITBUF 256 #define USPLIN 512 #define USPLOUT 1024 int unxflags[8] = { 0, UNEEDSIN+USENDBUF, UNEEDSOUT+UDOTEXEC+UREADBUF+UINITBUF, UNEEDSOUT+UDOTEXEC+UREADBUF, UNEEDSOUT+UNOSCREEN+URETBUF, UNEEDSIN+UNEEDSOUT+UNOSCREEN+UPROCESS, UNEEDSIN+USPLOUT+UNOSCREEN, UNEEDSOUT+USPLIN+UNOSCREEN }; unx(cmd,flag) /* Keywords: commands:80 buffers:10 files:10 environment-variables:20 unix-interface shell-escape dired:10 sub-processes:40 encryption:20 */ register char *cmd; register int flag; { #ifdef PC return(1); /* Don't do this, just exit */ #else struct pipes { int rdpipe; int wrpipe; } piped1,piped2; FILE tinbuf[1]; FILE *infile; int (*istat)(); int (*qstat)(); register int i; int c; int obuf; int pid; char **evp; char *obname; char evbuf[256]; char *myshell; if (*cmd == 0) return(1); /* Don't even bother with null commands */ obname=fname(); cstatus = -1; /* start off bad */ flag = unxflags[flag]; /* Translate to bit-coded value */ if ((flag & UPROCESS) && procpid) flushproc(); /* Zap old process */ if (flag&UDOTEXEC) { /* if .exec in the business */ obuf = curbf; if (chgbuf(".exec") == 0) return(0); } if ((USILENT == 0) && ((flag&UNOSCREEN) == 0)) { clear(); putout("%s",cmd); istat = signal(SIGINT, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); cook(); } if (flag & UNEEDSIN) { if (pipe(&piped1)) { error (WARN,errno,cmd); goto done; } } if (flag & UNEEDSOUT) { if (pipe (&piped2)) { error (WARN,errno,cmd); if (flag & UNEEDSIN) { close(piped1.rdpipe); close(piped1.wrpipe); } goto done; } } if ((pid = fork()) == 0) { /* child process */ if (flag &UNEEDSIN) { close(0); dup(piped1.rdpipe); } else if (flag & USPLIN) { close(0); dup(splfile); } else if ((USILENT)|| (flag & URETBUF)) { close(0); open("/dev/null",0); } if (flag &UNEEDSOUT) { /* if writing to .exec */ close(1); dup(piped2.wrpipe); } else if (flag & USPLOUT) { close(1); dup(splfile); } else if (USILENT) { /* silent, throw away output */ close(1); open("/dev/null",2); } signal(SIGINT, SIG_DFL); signal(SIGQUIT,SIG_DFL); xclose(2); /* close all irrelavent files */ dup(1); /* restore stderr */ myshell = getenv("SHELL"); if ((myshell == NULL)|| (*myshell == '\0')) myshell = "/bin/sh"; umask(mymask); /* Restore user's umask */ seprintf(evbuf,"filename=%s",obname); evp = fixenv(evbuf); /* Add filename definition */ if (streq(cmd,shell)) execl(myshell,shell,"-i",0,evp); execle(myshell, shell, "-c", cmd, 0,evp); execle("/bin/sh",shell, "-c", cmd, 0,evp); _exit(127); } /* parent process (the one that remains EMACS) */ if (pid== -1) { error(WARN,73,cmd); goto done; } if (flag &UPROCESS) { close (piped1.rdpipe); close (piped2.wrpipe); inproc = piped2.rdpipe; outproc = piped1.wrpipe; #ifdef ux3 fcntl(inproc,F_SETFL,O_NDELAY); /* Turn on non-blocking I/O */ ioset(1); /* Set timeout on terminal short */ #endif procbuf = curbf; procpid = pid; return(1); } if (flag & USPLIN) { close(splfile); splfile = piped2.rdpipe; close(piped2.wrpipe); return(1); } if (flag & USPLOUT) { close(splfile); splfile = piped1.wrpipe; close(piped1.rdpipe); return(1); } if (flag&USENDBUF) { /* if sending the buffer */ close(piped1.rdpipe); infile = fdopen(tinbuf,piped1.wrpipe,"w"); for (i = 1; i <=nlines; i++) { cmd = mkline(i); while ((c = *cmd++) != EOL) { putc(c,infile); } if (i != nlines) putc(EOL,infile); } mclose(infile); } if (flag&(UREADBUF|URETBUF)) { /* if writing */ close(piped2.wrpipe); infile = fdopen(tinbuf,piped2.rdpipe,"r"); if (flag&UINITBUF) bufinit(); else if (flag&UREADBUF) { bot(); /* append */ if (column != 0) nl(1); putin(cmd); nl(2); } if (flag&URETBUF) { cmd = fnbuf; i = 127; while (i--) { c = getc(infile); if ((c=='\0')||(c == '\n')||(c==' ')||(c=='\t')|| (c == EOF)) break; *cmd++ = c; } *cmd = 0; /* EOS */ mclose(infile); } else { i = ((flag & UINITBUF) != 0); readsub(infile,i,cmd,1-(USILENT|NOECHO)); chbuf(obuf); } } /* wait for child to finish */ /* must wait for child else it becomes a <defunct> process */ while ((i = wait(&cstatus)) != pid && i != -1); if (flag&URETBUF) return(cstatus); /* child is now done, go back to normal EMACS */ mailcnt = 0; done: if ((USILENT == 0) && ((flag&UNOSCREEN) == 0)) { uncook(); signal(SIGINT, istat); signal(SIGQUIT, qstat); junked++; } return(contin()); #endif } bux(arg) int arg; /* Keywords: commands buffers unix-interface shell-escape */ { register char *sp; register int flag; if (SAVEMD) fsave(0); if (arg == 0) flag = 5; else if (arg == 1) flag = 2; else flag = 3; do { sp = (getname("command line? ")); } while (sp && (unx(sp,flag)== 0)); return(cstatus); } /* query replace */ /* prompts for strings and does conditional replacement */ qrep(gflag) int gflag; /* Keywords: commands query-replace */ { iqrep(0,gflag); /* no regular expressions */ } rqrep(gflag) int gflag; /* Keywords: commands query-replace regular-expressions */ { iqrep(1,gflag); /* regular expression version */ } iqrep(regular,gflag) int regular; int gflag; /* Keywords: query-replace regular-expressions:20 user-interface key-bindings:20 commands:10 */ { char sstring[128]; int dir = 1; register char *sp; int bsflag = 0; int ask = 1; int show = 1; int l = 1; int stop = 0; int upt; register int c; int oldln; int oldcol; if((sp = getname("From? "))== NULL) return; if (*sp == NULL) sp = presst; strcpy(sstring,sp); if ((sp = getname("To? ")) == NULL) return; if (!streq(sp,"%")) strcpy(rstring,sp); /* Copy over return string unless it is a single % */ oldln = curln; oldcol = column; upt = unstart(); while (1) { if (regular) { if (rgsrch(curln,column,sstring,0,dir)== 0) break; } else { if (srch(curln,column,sstring,dir)== 0) break; } dir = 1; if ((l == 0) && (curln == kline) && (column == kcol)) { error(WARN,72,sstring,rstring); goto rdone; } prompt1("From %s To %s",sstring,rstring); strcpy(presst,sstring); /* save successful search */ move(kline,kcol); if (show) { disup(); } if (ask){ c = getchar(); donttime=0; } else c = 'y'; switch(c) { case '.': stop = 1; /* stop after this one */ goto rep_it; /* make this replacement. */ case ESC: sp = getname("Replace with: "); if (sp) { strcpy(rstring,sp); goto rep_it; } case CTRLG: beep(); done: unprompt(); /* wipe out help message */ unend(upt); return; case '<': move (oldln,oldcol); /* return to last replacement */ goto done; case 'R': show = 0; case 'r': ask = 0; /* do rest */ NOBEL++; /* Inhibit ding on zero length deletes */ /* fall through to do this one too */ case ' ': case 'y': case 'Y': rep_it: kbapp = 0; oldln = curln; oldcol = column; if (regular) { l = (loc2-column); } else { l = (lng(sstring)); } fdel(l); for (sp = rstring; *sp; sp++) { switch(*sp) { case '\\': if (!bsflag) { bsflag = 1; continue; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': if (bsflag && regular && regrep(*sp-'1')) { bsflag = 0; continue; /* \number style replace */ } /* fall through to default treatment of numbers */ default: dput(*sp); bsflag = 0; break; case '&': if (bsflag) { dput(*sp); bsflag = 0; continue; } else { yank(1); unpop(1); } } } unins(oldln,oldcol); /* Make an undo entry */ kpop(); /* clean up our stack */ if (stop) goto done; if (show) { disup(); /* before next search */ mflush(stdout); } break; case CTRLH: case RUBOUT: case 'n': case 'N': forw(1); break; case 'p': case 'b': dir = -1; forw(-1); break; default: beep(); case '?': donttime=1; /* Avoid time mode */ prompt3("Query replace -- 'y' to replace, 'n' to skip, ^G to quit,'R' or 'r' for rest"); } if (gflag>1) move(kline+1,0); /* only do first one */ } rdone: prompt1("Replace Done"); if (ask==0) NOBEL--; /* Re-enable warning on 0 length deletes */ unend(upt); } /* length of a string */ lng(sp) char *sp; /* Keywords: string-handling length */ { register char *spo; spo = sp; while(*spo++); return(spo-sp-1); } /* capitalize next count characters */ capnxt(count) register int count; /* Keywords: commands character-at-a-time forwards capitalization */ { register int c; int oldover; while (count--) { c = (clptr[column]); if ((c >= 'a') && (c <= 'z')) { oldover=OVERW; OVERW=1; insertc(1,c-040); OVERW=oldover; } else if (forw(1)==0) break; /* check for EOF */ } } /* lowercase next count characters */ lownxt(count) register int count; /* Keywords: commands character-at-a-time forwards capitalization */ { register int c; int oldover; while (count--) { c = (clptr[column]); if ((c >= 'A') && (c <= 'Z')) { oldover=OVERW; OVERW=1; insertc(1,c+040); OVERW=oldover; } else if (forw(1)==0) break; /* check for EOF */ } } /* capitalize first character of the next word */ capwrd(count) register int count; /* Keywords: commands word-oriented-commands forwards capitalization */ { while (count--) { kmark(); IGNORE(skipf(WRDSEP)); move(kline,kcol); /* to next word */ capnxt(1); mfwrd(1); } } /* exchange current position and the marked position */ exch(mnumb) /* Keywords: commands regions marking movement */ { register int x; register int y; register MARK *markp; markp = markptr(mnumb); x = markp->markl; if (x < 1) x = 1; y = markp->markc; if ((x == curln) && (y == column)) { return(0); } if (x > nlines) x = nlines; mark(mnumb); mvc(x,y); return(1); } /* exchange next two chacters in the buffer and move forward one */ xpose(count) register int count; /* Keywords: commands forwards movement:10 transposition */ { int oldnodel,oldpic; register int undp; oldnodel=NODEL; oldpic=PICMODE; NODEL=0; PICMODE=0; kbapp = 0; undp = unstart(); fdel(1); forw(count); yank(1); unend(undp); kpop(); forw(-1); NODEL=oldnodel; PICMODE=oldpic; } /* changes a mode parameter. Mode parameters are of three types, * string, boolean, or integer. * Integer modes set from the count argument, boolean modes turn on if * count is one, off otherwise, and string modes prompt for new value * chmode returns the previous value of the mode set */ chmode(count) register int count; /* Keywords: modes commands assignment */ { register char *mp; if ((mp=getname("Mode? ")) != NULL) { if (*mp == '\0') { modisp(numarg); return(0); } return(setmode(mp,count,1)); } return(0); } char *MDHEAD = "EMACS_MODES:"; bfmodes() /* set modes from buffer */ /* Keywords: modes buffers file-modes assignment:10 */ { register char *cp; register char *cp1; char mdbuf[20]; int onoff; kline = 11; if (kline > nlines) kline = nlines; while ((kline > 0) && srch(kline,leng(kline),MDHEAD,-1)) { /* if modes set */ for (cp = mkline(kline)+kcol+12; *cp != EOL;) { cp1 = mdbuf; while ((*cp != EOL) && (*cp != '!') && ((bits[*cp] & WRDCHR) == 0)) cp++; if (*cp == '!') { onoff = 0; cp++; } else onoff = 1; while (bits[*cp] & WRDCHR) { *cp1++ = *cp++; } if (*cp == '=') { cp++; cp = nscan(cp,&onoff); } *cp1 = 0; if (mdbuf[0]) setmode(mdbuf,onoff,0); /* Set up mode */ } kline--; } } setmode(mp,count,fudge) register char *mp; int count; int fudge; /* Keywords: modes macro-programming:10 assignment time-handling:20 display-format:10 */ { register int i; extern char cbuf[]; int retval; int mfield; for (i = 0; i < NMODES; i++) { if (streq(mdata[i].modename,mp)) { retval = *mdata[i].modeloc; /* old value */ switch(mdata[i].modetype) { case ONOFF: if (fudge && (count != 1)) count = 0; *mdata[i].modeloc = count; break; case INT: *mdata[i].modeloc = count; break; } if ((mfield = mdata[i].moderset)&DSIZE) { SCRNLIN = SCRLINES+4; setsize(); } /* customize the behavior of ^H in word commands */ if (mfield|CTYPE) { if (BACKP) { bits[CTRLH] = bits['_'] = WRDCHR; ctype[CTRLH] = BACKSP; } else { bits[CTRLH] = bits['_'] = WRDSEP; ctype[CTRLH] = CONTRL; } if (NOTABS) ctype[CTRLI] = CONTRL; else ctype[CTRLI] = TAB; if (bit8) metal = 0; else metal = 2; } if (mfield & CSE) { if (NOCASE) count = 'a'-'A'; else count = 0; for (i = 'A'; i <= 'Z'; i++) { casem[i] = i+count; } } if (timemd == 0) *cbuf = 0; /* Nullify current time */ if (mfield&DISPLAY) { fclear(); /* force re-display */ if (PICMODE==0) hcol=0; } return(retval); } } IGNORE(error (WARN,45,mp)); return(0); } modval(mp) char *mp; /* Keywords: commands macro-programming modes */ { register int i; for (i = 0; i < NMODES; i++) if (streq(mdata[i].modename,mp)) return(*mdata[i].modeloc); return(0); } /* display all active modes. Values displayed for integer and string * modes, all on boolean modes are displayed */ modisp(arg) register int arg; /* Keywords: informational-displays modes commands user-interface */ { register int i; char *mp; if ((arg < 0) && (mp = getname("Mode? "))) return(modval(mp)); mtop(); for (i = 0; i < NMODES; i++) { switch(mdata[i].modetype) { case ONOFF: if (*mdata[i].modeloc) putout("%s mode is on",mdata[i].modename); else if (arg) putout ("%s mode is off",mdata[i].modename); break; case INT: putout("%s = %d",mdata[i].modename,*mdata[i].modeloc); break; } } putout (endput); return(contin()); } /* compare two strings */ streq(cp,cp1) register char *cp; register char *cp1; /* Keywords: string-handling comparison */ { while (*cp) if (*cp++ != *cp1++) return(0); if (*cp1) return(0); return(1); } char * mstrcpy(cp,cp1) /* Keywords: assignment string-handling */ register char *cp; register char *cp1; { while (*cp++ = *cp1++); return(cp-1); } /* push the marked region onto the kill stack without killing it */ pickup(mnumb) /* Keywords: regions commands killstack stacking */ { register MARK *markp; markp = markptr(mnumb); if ((markp->markl < curln) || ((markp->markl == curln) && (markp->markc < column))) { killstk(markp->markl,markp->markc,curln,column); } else { killstk(curln,column,markp->markl,markp->markc); } } /* go to beginning of count line */ absgoto(count) register int count; /* Keywords: commands movement text-lines */ { move((count<nlines)?count:nlines, 0); } /* begin a C coment. comment begins in COMCOL, if current position is * not column 0, otherwise begins in column 0. the next newline will end * the coment */ cment() /* Keywords: C-mode commands comments */ { if (column) { disup(); if (mcol<comcol) { while (mcol<comcol) { put(' '); disup(); } } else { put (' '); } } putin ("\057* "); /* it's a slash, for stupid compilers! */ comln = curln; } /* adjust the indentation of the current line to be consistent with that * in the last line. */ tabjust(lno) register int lno; /* Keywords: insertion C-mode commands:10 */ { register int lln; register int tabno; char *llp; int c; tabno = 0; for (lln = lno-1; lln > 0; lln--) { llp = mkline(lln); while (llp[tabno] == ' ') ++tabno; if ((llp[tabno]!= EOL) && (llp[tabno+1] != '*')) { while ((c = llp[tabno])!=EOL) { switch(c) { case '{': ++tabno; break; default: ++llp; } } goto tabout; } tabno = 0; } tabout: move(lno,0); while ((c = clptr[column]) == ' ') { tabno--; column++; } if ((c == '}') && tabno) tabno--; if (tabno) { if (tabno>0) tabc(tabno,' '); else { bdel(-tabno); kpop(); unpop(1); } } else { sputl(curln,column,curln); move(curln,column); } } /* } handler, re-sets the indentation back one level */ cbrak(count,brace) register int count; register int brace; /* Keywords: C-mode insertion commands */ { if (TABMD &&(RARE == 0) && column && (*(clptr+column-1) == ' ')){ bdel(1); kpop(); unpop(1); }; insertc(count,brace); } /* returns 1 if next line contains no non blank (or tab) characters */ isblank(line) register int line; /* Keywords: commands:10 line-representation:50 */ { register char *lp; if ((line <= nlines) && (ptrs[line] == 0)) return(1); lp = mkline(line); while (*lp!=EOL) { if ((bits[*lp++] & WHITE) == 0) return(0); } return(1); } /* change working dir */ cwd() /* Keywords: commands directories unix-interface */ { #ifndef PC char *np; np = expenv(getname("Directory? ")); if (np) { if (SAVEMD) fsave(0); if (*np == 0) np = getenv("HOME"); /* null means home */ if(chdir(np)) { IGNORE(error(WARN,errno,np)); return(0); } return(1); } return(0); #endif PC } stats() { /* Keywords: commands informational-displays statistics */ #ifdef COMPRESS extern long coutc; #endif mtop(); putout ("%d chars from terminal",ninch); putout ("%D calls to mputc",nmput); putout ("%D chars written by mputc",noutc); #ifdef COMPRESS putout ("%D chars after compression",coutc); #endif putout ("%d terminal writes", ntwrite); putout ("%d calls to makeline",nmkline); putout ("%d buffer reads",nbread); putout ("%d file writes",nbwrite); putout ("%d file seeks", nbseek); putout ("%d characters of buffer left", (NBLOCK*BLEN)-macptr); IGNORE(contin()); } uline(count) /* Keywords: word-oriented-commands commands underlining */ register int count; { while (count--) { kmark(); IGNORE(skipf(WRDSEP)); /* skip to begginning of word */ move(kline,kcol); while (bits[*klptr] & WRDCHR) { put('_'); put(CTRLH); forw(1); } } } infile(fn) /* Keywords: commands:40 files keyboard-macros:10 command-line-processing:10 command-files */ register char *fn; { if (pushin(expenv(fn))) { edit(1); inpop(); return(1); } else return(0); } inpsh(arg) int arg; { register char *fp; /* Keywords: commands files keyboard-macros:10 command-files */ if (fp=getname("Input file? ")) { if (infile(fp)==0 ) { if (arg > 0) IGNORE(error(WARN,errno,fp)); return(0); } } return(1); } /* send the contents of the buffer as mail */ /* mtch -- see if current line matches header */ mtch(cp) register char *cp; /* Keywords: mail-processing string-handling:20 comparison:40 */ { register char *cl; cl = clptr; while (*cp) if (*cp++ != *cl++) return(0); return(1); } mailit() /* Keywords: mail-processing unix-interface commands */ { char cmdbuf[256]; register char *mp; register char *mp1; int mailstat; char *mailcom; #ifdef POSTHACK char *s; register int c; extern char *strrchr(); #endif mailstat = 0; #ifndef PC #ifdef bsd #define DEFMAIL "/usr/lib/sendmail -t" #else #define DEFMAIL "mail" #endif if ((mailcom=getenv("MAILER"))==NULL) mailcom=DEFMAIL; mp = mstrcpy(cmdbuf,mailcom); #ifdef POSTHACK /* find the start of the mail command name */ if ((s = strrchr(mailcom, '/')) != NULL) { ++s; } else { s = mailcom; } /* if this is post or Berkeley mail */ if (streq(s, "post") || streq(s, "Mail")) { top(); while (curln < 10 && *clptr != EOL) { /* if there is a subject line in the message */ if (mtch("Subject: ")) { /* add -s 'subject' to the mail command */ strcpy(mp, " -s '"); mp += 5; mp1 = clptr + 9; /* skip "Subject: " */ while ((c = *mp1) != EOL) { if (c == '\'') { /* ' becomes '\'' */ *mp++ = '\''; *mp++ = '\\'; *mp++ = '\''; *mp++ = '\''; } else { *mp++ = c; } ++mp1; } *mp++ = '\''; *mp = 0; break; } move(curln+1,0); } } /* get the list of addressees */ #endif top(); while (curln < 10 && *clptr != EOL) { if (mtch("TO: ") || mtch("To: ") || mtch("CC: ") || mtch("Cc: ")) { if (clptr[1] == 'O') clptr[1] = 'o'; if (clptr[1] == 'C') clptr[1] = 'c'; column = 3; if (((mp-cmdbuf)+leng(curln)-column) > 250) { mailstat += unx(cmdbuf,1); /* partial list */ mp = mstrcpy(cmdbuf,mailcom); move(curln,column); } mp1 = clptr+column; while (*mp1 != EOL) *mp++ = *mp1++; /* copy mailing list */ *mp = 0; } move(curln+1,0); } mp1 = cmdbuf+4; while (*mp1) if (*mp1++ != ' ') { /* Check for non-null destination list */ mailstat += unx(cmdbuf,1); /* send to mail command */ return(mailstat == 0); } IGNORE(error (WARN,46)); #endif return(0); } /* contin -- ask user to continue */ contin() { /* Keywords: informational-displays:20 user-interface:10 prompting:40 */ register int c; if (infrn < 0) return(1); /* continue always in a macro */ prompt1("Continue?"); c = getchar(); prompt1(""); if ((c == 'y') || (c == ' ') || (c == '\n') || (c == '\015')) return(1); if ('n' == c) return(0); if (c == CTRLZ) { gquit(); return(1); } ungetch(c); return(0); } /* buffer length and current position */ /* If invoked from tty, prints buffer status info on the terminal. If */ /* invoked from a macro, returns a value dependent on its argument */ #define VLIN 0 /* return line number */ #define VCOL 1 /* return column number */ #define VDLIN 2 /* display line */ #define VDCOL 3 /* display column */ #define VMINLN 4 /* First file line on screen */ #define VMAXLN 5 /* ditto last */ #define VWTOP 6 /* First screen line of window */ #define VWBOT 7 /* ditto last */ buflng(arg) int arg; { /* Keywords: commands macro-programming:40 buffers statistics */ long flng; long fpos; char xbuf[128]; extern int minln; extern int maxln; register int i; if (infrn < 0) { /* If from macro, return useful info */ switch(arg) { case VCOL: return(column); case VLIN: return(curln); case VDCOL: case VDLIN: if (findline(curln) == 0) return(-1); mline=nln; if (findpos(clptr,column) == 0) return(-1); if (arg == VDLIN) return(nln-wbase); else return(mcol); case VMINLN: return(minln); case VMAXLN: return(maxln); case VWTOP: return(wbase); case VWBOT: return(SCRLINES-1); } } flng = 0L; for (i = 1; i <= nlines; i++) { if (i != 1) flng++; /* linefeed from last line */ if (i == curln) fpos = flng + column; flng += leng(i); } clptr=mkline(curln); seprintf(xbuf,"next char: %o, line: %d/%d: pos: %D/%D column: %d", clptr[column],curln,nlines-1,fpos,flng,column); prompt1(xbuf); return(0); } filler(arg) /* Keywords: regions:50 text-filling commands */ int arg; { register int i; register char *cp; register int j; int unp; unp = unstart(); if (arg != 1) { /* fill region only */ register MARK *markp; markp = markptr(curbf); if ((i = markp->markl) > curln) fillreg(curln,i,1); else fillreg(i,curln,1); } else { undel(); killstk(1,0,nlines,0); kpop(); for (i = 1; i < nlines;i++ ) { cp = mkline(i); if ((*cp != '.') && (*cp != '\'') && (*cp != EOL)) { j = i; while (i < nlines) { cp = mkline(i); if ((*cp == '.') || (*cp == '\'') || (*cp == EOL)) break; i++; } fillreg(j,i,0); i = curln+1; } } unins(1,0); } unend(unp); } fillreg(i,j,u) register int i; register int j; int u; { /* Keywords: commands:10 text-filling regions:20 undo:10 */ int onlin,ofill; onlin = NLINS; ofill = FILLMD; FILLMD = NLINS = 1; /* Turn on "rigid_newline" mode */ move(i,0); if (u) { /* Make an undo record for this region */ undel(); killstk(i,0,j,0); kpop(); } while (curln < j) { endl(); do { i = curln; afsep(0,0);/* Note that we don't really put anything in */ if (i != curln) j++; } while (i != curln); if (curln < j-1) { fdel(1); kpop(); unpop(1); while ((clptr[column] == ' ') || (clptr[column] == ' ')) { fdel(1); kpop(); unpop(1); } put(' '); j--; } else break; } if (u) { move(j,0); unins(i,0); /* Make a second undo record */ } NLINS = onlin; FILLMD = ofill; } /* macro the region */ macro(arg) int arg; { /* Keywords: key-bindings memory-allocation:10 parsing symbol-handling commands macro-hooks:20 */ register int mychar; register int balance; register int machr; int oldpic; int compos; int hookp; int hash,ename; #ifdef u370 int beepbeep(); #else extern int beep(); #endif oldpic=PICMODE; PICMODE=0; bot(); back(2); if (clptr[column] != CTRLZ) { /* File does not end in ^Z, Try to catch a potential disaster */ error(WARN,80,fname()); PICMODE=oldpic; return(0); } if (arg != 1) { for (mychar = 0; mychar < NCHARS; mychar++) { if (map_it[mychar] > ISIZE) { map_it[mychar] = 0; } if (mychar < NMAC) machash[mychar] = 0; if (mychar < NHOOKS) hooks[mychar] = 0; } macptr = 0; fbkno = 0; } top(); while (curln<nlines) { balance = 0; machr = clptr[column]&0377; if (machr == ESC) machr = (clptr[++column]&0377)+0200; if (machr == CTRLX) { machr = (clptr[++column]&0377)+0400; } if (machr == CTRLZ) { hookp = (clptr[++column]&0377); if (hookp > NHOOKS) { hookp = 0; /* Just ignore the bad ones */ --column; } } forw(1); if (macptr == 0) pshchr(0); /* Can't use the first location! */ compos = macptr; pshchr(0); /* Leave room for linkage chain */ pshchr(0); hash = 0; ename = 1; if (clptr[column] == CTRLBACK) { /* if comment */ pshchr(0); ++column; while (clptr[column] != EOL) { if ((clptr[column] == ' ')||(clptr[column] == ' ')) ename = 0; if (ename) hash += clptr[column]; pshchr(clptr[column++]); } pshchr(0); forw(1); /* skip newline */ } hash %= NMAC; bbuf[0][compos] = machash[hash]; bbuf[0][compos+1] = machash[hash]>>8; machash[hash] = compos; if (machr == CTRLZ) hooks[hookp] = macptr; /* Define hook */ else { /* Define character command */ map_it[machr] = macptr+ISIZE; } while (curln < nlines) { mychar = clptr[column]&0377; if (column == 0) { while ((mychar==' ') || (mychar==' ')) { column++; mychar = clptr[column]&0377; } } if (mychar != CTRLBACK) { if (mychar == MTA({)) balance++; else if (mychar == MTA(})) balance--; pshchr(mychar); forw(1); if ((mychar == CTRLZ) && (clptr[column] == EOL)) { if (balance) { error(WARN,47,curln); } goto macdone; /* end of macro definition */ } } else { move(curln+1,0); /* skip comment */ } } error (WARN,48); pshchr(CTRLG); /* escape from bad macro */ macdone: forw(1); /* on to next macro */ } PICMODE=oldpic; if (hooks[Load_Macro_Hook]) { hook(Load_Macro_Hook); hooks[Load_Macro_Hook] = 0; } return(1); } ldmac(arg) int arg; /* Keywords: commands files reading macro-programming:20 */ { register int oldbuf; register int tmpbuf; char *obname; int oldbin; int err; if (arg>0) err = 1; else { err = 0; arg = 1; } obname = fname(); /* Old file name */ oldbuf = curbf; chgbuf("..."); /* temporary buffer */ strcpy(fname(),obname); /* Restore file name */ #ifdef PC oldbin = BINMODE; BINMODE = 1; #endif PC if (fred(err)) { /* read file */ macro(arg); err = 1; } else { err = 0; } #ifdef PC BINMODE=oldbin; #endif PC tmpbuf = curbf; chbuf(oldbuf); klbfr(tmpbuf); /* kill temp buffer */ return(err); } /* macro programming commands */ /* these commands perform various utility functions for macro commands */ bfchr() /* get a character from the buffer */ { /* Keywords: macro-programming quoting character-at-a-time buffers:40 */ return(clptr[column]&0377); /* Trim sign bits! */ } litchr() /* literal character */ { /* Keywords: macro-programming quoting */ return(getchar()); } compar(ctype) /* general comparison */ /* comparison type definitions (pecular arangement for convenient */ /* specification via ^U */ #define CLE 0 /* <= */ #define CEQ 1 /* = */ #define CLS 2 /* < */ #define CGT 3 /* > */ #define CNE 4 /* != */ #define CGE 5 /* >= */ #define COR 6 /* OR */ #define CAND 7 /* AND */ #define CNOT 8 /* NOT */ #define CFALSE 9 /* FALSE */ #define CTRUE 10 /* TRUE */ #define CPLUS 11 /* arg1 + arg2 */ #define CMINUS 12 /* arg1 - arg2 */ #define CTIMES 13 /* arg1 * arg2 */ #define CDIV 14 /* arg1 / arg2 */ #define CREM 15 /* arg1 % arg2 */ #define CDTOS 16 /* arg1 convert to string on kill stack */ #define CSTOD 17 /* convert ks to decimal and return */ #define CBAND 18 /* Bitwise and */ #define CBOR 19 /* Bitwise or */ #define CXOR 20 /* Bitwise xor */ #define CUNGET 21 /* Unget character */ #define CPENDING 22 /* number of characters pending */ /* Keywords: macro-programming arithmetic:50 comparison:50 */ register int ctype; { register int r1; register int r2; char *sp; char sbuf[20]; int res; if (ctype == CFALSE) return(0); if (ctype == CTRUE) return(1); if (ctype == CSTOD) { sp = getname("Number?"); nscan(sp,&res); return(res); } if (ctype == CPENDING) { ttfill(); /* Read any pending tty input */ return(ttcnt); } r1 = edit(0); /* first arg */ if (ctype == CNOT) return(r1 == 0); if (ctype == CDTOS) { seprintf(sbuf,"%d",r1); stkstr(sbuf); return(r1); } if (ctype == CUNGET) { pushin(0); /* Force to tty */ ungetch(r1); inpop(); return(1); } r2 = edit(0); /* second arg */ switch(ctype) { case CLE: return(r1<=r2); case CEQ: return(r1==r2); case CLS: return(r1<r2); case CGT: return(r1>r2); case CNE: return(r1!=r2); case CGE: return(r1>=r2); case CAND: return(r1 && r2); case COR: return(r1 || r2); case CPLUS: return(r1+r2); case CMINUS: return(r1-r2); case CTIMES: return (r1*r2); case CDIV: if (r2) return(r1/r2); else return(0); case CREM: if (r2) return(r1%r2); else return(0); case CBAND: return(r1&r2); case CBOR: return(r1|r2); case CXOR: return (r1^r2); default:return(0); } } pscan(lev) /* parenthesis scan */ /* Keywords: macro-programming parsing control-flow:50 */ register int lev; /* returns when lev+paren level = 0 */ { register int c; register int ctlx; ctlx = 0; while (lev) { c = Mgetchar(); if (c == CTRLX) { ctlx++; continue; } if (!ctlx && ((c == (CTRLQ)) || (c == MTA(q)) || (c == (CTRLQ+META)))) { c = Mgetchar(); continue; } ctlx = 0; if (c == MTA({)) lev++; else if (c == MTA(})) lev--; } } cond() /* conditional execute */ /* Keywords: control-flow parsing :5 conditionals macro-programming */ { register int c; MACEXIT; /* Only in a macro */ if ((c = Mgetchar()) != MTA({)) { /* must be M-{ */ return(error(NORM,49)); } while ((c = Mgetchar()) != MTA(})) { while ((c != MTA({)) && (c !=MTA(}))) c = Mgetchar(); if (c == MTA(})) return(0); /* failed */ if (edit(0)) { c = edit(1); /* scan command */ pscan(1); /* skip to end of cond */ return(c); } else pscan(1); /* skip to end of block */ } return(0); /* cond failed */ } /* macro case statement: syntax is ^x!M-{<expr> * M-{<char><sequence>M-} * ... * M-} */ mcase() /* Keywords: cases parsing:5 control-flow macro-programming */ { register int cchar; register int c; MACEXIT; while ((cchar =Mgetchar()) != MTA({)); cchar = edit(0); /* match expression */ while ((c = Mgetchar()) != MTA(})) { while ((c != MTA({)) && (c !=MTA(}))) c = Mgetchar(); if (c == MTA(})) return(0); /* failed */ c = Mgetchar(); if ((c == cchar) || (c == 0377)) { c = edit(1); /* scan command */ pscan(1); /* skip to end of case */ return(c); } else pscan(1); /* skip to end of block */ } return(0); /* case failed */ } /* mbegin -- begin block in macro */ mbegin() /* Keywords: macro-programming parsing:20 control-flow */ { return(edit(1)); /* push command */ } /* iteration handler */ iter() { /* Keywords: macro-programming control-flow parsing:10 loops */ register int c; register char *savptr; MACEXIT; while ((c =Mgetchar()) != MTA({)) { if ((c != ' ') && (c != ' ') && (c != EOL)) { return(error (NORM,50)); } } savptr = inget(); while (edit(0)) { /* test condition */ c = edit(1); /* execute body */ inset(savptr); /* backup */ } pscan(1); /* skip body */ return(c); } /* gparam -- get a parameter and push into the kill stack */ /* with an argument of 1, it takes the parameter in line, with */ /* other arguments, it takes the parameter from the tty, prompting with */ /* the in line parameter4 */ gparam(arg) /* get a parameter */ int arg; /* with 1 arg, from macro text, else from tty */ /* Keywords: macro-programming string-handling:20 string-variables:50 filenames:10 prompting:40 reading:20 killstack:20 */ { char pbuf[128]; register char *pb; register int pbch; MACEXIT; for (pb = pbuf;;) { *pb++ = pbch = Mgetchar(); if (pbch == CTRLQ){ --pb; *pb++ = Mgetchar(); } if ((pbch == EOL)|| (pbch==CTRLZ)) break; if (pb>=(pbuf+128)) pb--; /* Truncate pb */ } *(--pb) = 0; /* pickup prompt message */ return(gpm(arg,pbuf)); /* pickup up parameter */ } /* gkarm -- like gparm, except input is from the kill stack. */ gkarm(arg) /* Keywords: macro-programming string-handling:20 string-variables:50 filenames:10 prompting:40 reading:20 killstack:20 */ int arg; { char *pb; pb = getname(""); /* pick up parameter */ return(gpm(arg,pb)); } gpm(arg,pbuf) register int arg; register char *pbuf; /* Keywords: macro-programming string-handling:20 string-variables:50 filenames:10 prompting:40 reading:20 killstack:20 */ { register char *pb; char pmpt[128]; int pbch; if (arg == 3) { eprintf("%s",pbuf); /* Raw print, shouldn't mung screen */ return(1); } if (arg != 1) { pushin(NULL); if (arg <= 0) { /* single character */ prompt1("%s",pbuf); if (arg < 0) { mgo(nln,ncol); pbch = getchar(); unprompt(); } inpop(); return(pbch); } strcpy(pmpt,pbuf); /* In case prompt is in pbuf already */ pb = getname(pmpt); if (pb == NULL) pb = ""; inpop(); } else pb = pbuf; stkstr(pb); return(lng(pb)); } char * maclook(mp) char *mp; /* Keywords: macro-programming:20 symbol-handling macro-invocation global-variables:50 */ { int hash,ohash; register char *mp1,*mp2; /* now look up macro name */ mp1 = mp; hash = 0; while (*mp1) hash += *mp1++; hash = hash %NMAC; ohash = hash; hash = machash[hash]; while (hash) { for (mp1=mp,mp2= &bbuf[0][hash+3]; *mp1++ == *mp2++; ) { if ((*mp1 == 0) && ((*mp2 == 0)||(*mp2 == ' ')|| (*mp2 == ' '))) { while (*mp2++); return(mp2); } } hash = (bbuf[0][hash]&0377) + (bbuf[0][hash+1] <<8); } return(NULL); } /* macro call by name */ macex(arg,ivchar) int arg; int ivchar; /* Keywords: macro-invocation macro-programming modes:10 reading:40 */ { char mbuf[100]; register char *mp1; register char *mp3; register int c; mp1 = mbuf; if (infrn < 0) { while ((c = Mgetchar()) != EOL) *mp1++ = c; *mp1 = 0; mp3 = mbuf; } else { mp3 = getname ("Macro name? "); } if (mp3 == NULL) return(0); /* aborted */ if (mp1 = maclook(mp3)) { run: return(xmac(mp1-bbuf[0],arg,ivchar)); } else { if (AUTOLOAD && (infrn < 0)) { /* Autoload mode, If an undefined macro is called from a macro, it */ /* tries to load it from a standard library */ char buf[128]; #ifdef PC seprintf (buf,"%s",mp3); #else seprintf(buf,"~EMACS/macros/%s",mp3); #endif stkstr(buf); if (ldmac(-1) &&(mp1 = maclook(mp3))) { loaded: prompt(ECHOL,"Autoloaded %s",buf); goto run; } #ifdef PC seprintf(buf,"c:%s",mp3); #else seprintf(buf,"$EMACS_LIB/%s",mp3); #endif stkstr(buf); if (ldmac(-1) && (mp1 = maclook(mp3))) goto loaded; } error (WARN,51,mp3); return(NULL); } } hook(hookp) int hookp; /* Keywords: macro-programming macro-invoction:50 macro-hooks */ { register int oldhook; int result; char xfnbuf[FNLEN]; strcpy(xfnbuf,fnbuf); /* Preserve temp buffer, in case it's wiped by the macro */ oldhook = hooks[hookp]; hooks[hookp] = 0; /* Prevent recursion */ result = xmac (oldhook,0,0); hooks[hookp] = oldhook; strcpy(fnbuf,xfnbuf); return(result); } /* xmac -- execute a macro */ xmac(macp,arg,ivchar) register int macp; register int arg; int ivchar; { /* Keywords: macro-programming macro-invocation local-variables:60 argument-processing:20 */ int mvars[NMVAR]; /* macro variables */ int *omarg; /* old pointer to mvars */ omarg = marg; marg = mvars; mvars[1]=arg; /* record macro argument */ mvars[0] = ivchar; /* invoking character */ pshmac(macp); if (etrace) putout("Entering macro: %s",hmap(macp)); arg = edit(1); if (etrace) putout ("Exiting macro: %s",hmap(macp)); marg = omarg; inpop(); return(arg); } /* setvar -- set a local variable */ setvar(arg) register int arg; { /* Keywords: assignment macro-programming local-variables */ register int oldvar; if ((arg <NMVAR) && (arg >=0)) { oldvar = marg[arg]; marg[arg] = edit(0); /* set new value */ return(oldvar); } else { beep(); return(0); } } /* getsharg -- get argument from shell command line */ /* with argument of 1, gets one argument and pops. */ /* with other argument, returns argument but does not pop */ /* Value returned is 1 unless there are no more command line options. */ getsharg(arg) int arg; { /* Keywords: argument-processing:10 command-line-processing macro-programming */ extern char **sharg; extern int nsharg; if (nsharg) { stkstr(*sharg); if (arg==1) { nsharg--; sharg++; } return(1); } return(0); } /* string operations */ /* compares same argument conventions as other comparisons */ #define CAPP 7 /* Arg 2 appended to arg1 */ #define CINDEX 8 /* index of arg 2 in arg1 */ #define SBINARY 8 #define CSUBSTR 9 /* string indexed by next 2 commands */ #define CLENGTH 10 /* String length */ #define SUNARY 10 #define CPTR 11 #define CSTRING 12 #define CPRINTF 13 /* formatted I/O */ cmpst(arg) register int arg; /* Keywords: macro-programming comparison string-variables string-handling:30 conversions:20 */ { char buf[256]; register char *bp1; register char *bp2; char *bp3; int i,j; if (arg <= SUNARY)bp1 = getname(""); /* get first string */ if (arg <= SBINARY) { strcpy(buf,bp1); bp1 = buf; bp2 = getname(""); } if (arg <= CGE) { while ((*bp1 == *bp2) && *bp1) { bp1++; bp2++; } } switch (arg) { case CLE: return(*bp1<=*bp2); case CEQ: return(*bp1==*bp2); case CLS: return(*bp1<*bp2); case CGT: return(*bp1>*bp2); case CNE: return(*bp1!=*bp2); case CGE: return(*bp1>=*bp2); case CAPP: strcpy(bp2+lng(bp2),bp1); stkstr(bp2); return(1); case CINDEX: i = 0; bp3 = bp2; while (*(bp2=bp3+i)) { bp1 = buf; while (*bp1++ == *bp2++) { if (*bp1 == 0) return(i); } i++; } return(-1); case CSUBSTR: i = edit(0); j = edit(0); bp1[j]=0; stkstr(bp1+i); return(1); case CLENGTH: return(lng(bp1)); case CPTR: return(kgptr()); case CSTRING: i = edit(0); kput(i); return(1); case CPRINTF: /* Printf like formatting. */ { int pts[20],len; char buf2[256]; bp1=bp2=getname(""); /* Format string */ /* First, collect all of the parameters */ i = 0; while(*bp1) { if (bp1[0] == '%') { if (bp1[1] == '%') bp1++; else pts[i++] = kgptr(); /* Collect one */ } bp1++; } strcpy(buf2,bp2); bp2 = buf2; bp1 = buf; while (*bp2) { if (*bp2 == '%') { bp2 = nscan(bp2+1,&j); if (*bp2 == '%') { *bp1++ = *bp2++; continue; } kput(pts[--i]); bp3 = getname(""); /* get the param */ len = lng(bp3); switch(*bp2++) { case 'l': bp1 = mstrcpy(bp1,bp3); j = j-len; if (j>0) while (j--) *bp1++ = ' '; break; case 'r': j = j-len; if (j>0) while (j--) *bp1++ = ' '; bp1 = mstrcpy(bp1,bp3); break; case 'c': len = (j-len); if (len>= 0) { j = len/2; len = len-j; while (j--) *bp1++ = ' '; } bp1 = mstrcpy(bp1,bp3); if (len> 0) while (len--) *bp1++ = ' '; break; } } else *bp1++ = *bp2++; } *bp1 = 0; stkstr(buf); return(1); } default: return(0); } } /* Global variable -- global variables are dynamically bound by * names. They are 2 or 4 bytes long and always stored in order of * lsB first. */ glob(arg) int arg; { /* Keywords: global-variables assignment:50 macro-programming */ int size; char *name; char *where; int hash; if (name= getname ("Global variable name? ")) { if ((where = maclook(name)) == NULL) { if (arg == 0) return(0); where = name; hash = 0; while (*where) hash += *where++; hash = hash %NMAC; pshchr(machash[hash]); pshchr(machash[hash]>>8); machash[hash] = macptr-2; where = name; pshchr(0); while (*where) pshchr(*where++); pshchr(0); for (size=0; size<sizeof(size); size++) pshchr(0); where = maclook(name); } switch(arg) { case 0: return(1); break; case 1: hash = 0; for (size=0; size<sizeof(size); size++) { hash+= ((*where++)&0377) << (size*8); } return(hash); case 2: hash = edit(0); for (size=0; size<sizeof(size); size++) { *where++ = hash; hash = hash >>8; } break; } } return(0); } /* envexp -- expand environment variables in a string */ /* expansion takes place in the caller's string buffer */ /* pointer is returned for convenience only */ char *pwpath = "/etc/passwd"; char * expenv(str) register char *str; /* Keywords: environment-variables unix-interface user-interface:20 shell-escape:10 */ { char strtemp[128]; char vartemp [64]; register char *cp1; char *cp2; register int c; int oc; if (str == NULL) return(NULL); cp1 = strtemp; cp2 = str; while (*cp1++ = *str) { if ((*str== '`')||(*str=='*')||(*str=='{')||(*str=='[')||((*str++)=='?')) { seprintf(strtemp,"exec echo %s",cp2); unx(strtemp,4); /* expand through the shell */ return(fnbuf); } } cp1 = strtemp; str = fnbuf; /* always copy back into file name */ while (c = *cp1++) { if ((c == '$') || (c == '~')) { /* Environment variable or `logdir` */ oc = c; cp2 = vartemp; while (bits[c=((*cp1++)&0377)]&WRDCHR) { *cp2++ = c; } cp1--; /* backspace pointer */ *cp2 = 0; if (oc == '$') { cp2 = getenv(vartemp); /* environment variable */ } else { #ifndef PC /* Home Directory */ if (*vartemp == 0) { cp2 = getenv("HOME"); /* Bare ~ means home */ } else if (streq(vartemp,"EMACS")) { cp2 = em_dir; } else if (streq(vartemp,"exptools") && (cp2 = getenv("TOOLS")) && *cp2) { ; } else { FILE pwfile[1]; FILE *pwptr; char *vp; cp2 = NULL; pwptr = xopen(pwfile,pwpath,"r"); if (pwptr) { while ((c = getc(pwptr))!= EOF) { if (c == '\n') { vp = vartemp; /* Try to match the specified user ID */ while (*vp++ == (c = getc(pwptr))); if ((vp[-1] == 0) && (c == ':')) { /* Found it, now skip 4 colons, and copy next field into vartemp; */ c = 0; while (c < 4) if (getc(pwptr) == ':') c++; cp2 = vartemp; while ((c = getc(pwptr)) != ':') *cp2++=c; *cp2++=0; cp2=vartemp; break; /* Break out of password scan */ } } } mclose(pwptr); } else error(WARN,errno,pwpath); } #endif PC } if (cp2 != NULL) { str = mstrcpy(str,cp2); } else { *str++ = oc; str = mstrcpy(str,vartemp); } } else { *str++ = c; } } *str++ = 0; return(fnbuf); } /* * envget takes a string and expands it into the string * stored in the shell variable by the same name. * If the shell variable did not exist, then envget * returns NULL. */ envget() /* Keywords: commands environment-variables */ { char * ptr; if (ptr = getenv(getname("Environment variable: "))) { stkstr(ptr); return(1); } else { stkstr(""); return(0); } } stopjob () { char x; clear(); cook(); #if (defined (bsd) || defined (v8)) kill(mypid,SIGSTOP); #else eprintf ("Type ^Z to suspend emacs and <return> to continue"); read(0,&x,1); #endif uncook(); clear(); } #ifdef u370 beepbeep() { extern int beep(); } #endif