static char Sccsid[] = "xed.c @(#)xed.c 1.1 10/1/82 Berkeley "; # /* * V7.15 81/09/16 14:22 Fixed bug causing bus errors occasionally * V7.14 81/09/10 21:50 -B dynamically allocated line buffer * V7.13 81/07/25 22:51 added -O and "long" pointers * * Editor * * Major additions beginning 77/04 * Conversion to version 7 79/12 * Conversion to VAX 80/11 * * Purdue University, Engineering Computer Network * * Tgi -- Room 337A * Electrical Engineering Dept * Purdue University * West Lafayette, Indiana * 47907 * 317/49-41592 */ #define XED /* enable powerful stuff */ #define V7 /* enable environment stuff for protocol */ /* * At the entry to a function (PDP-11) the following sequence * of instructions is executed: * func: jsr r5,csv * csv: mov r5,r0 * csv+2: mov sp,r5 * If a signal occurs between the first and second, or between the * second and third instructions, r5 will NOT contain a valid * stack address. Hence, when longjmp() attempts to validate * the environment pointer (r5) links, an instruction will be * fetched instead of a valid pointer, and will generally cause * one of "memory fault", "bus error", or "illegal instruction" * resulting in the loss of the editing session. * * Due to this wonderful feature of version 7 ingenuity, I have * reverted to using setexit/reset, since they are simpler and * do not assume that I do not know what I am doing. * * 80/11/10 V7.01 Tgi */ #ifndef pdp11 #include jmp_buf _env_rst; #define setexit() setjmp(_env_rst) #define reset() longjmp(_env_rst,1) #endif #include #include /* * Machine-dependent definitions */ #ifdef pdp11 # define BPB 8 /* bits per byte */ # define BPW (BPB*sizeof(int))/* bits per word */ # define BPWC 4 /* log2(BPW) */ # define BPWM 017 /* mask of BPWC bits */ typedef short block; typedef short charac; typedef short filedes; typedef short flag; typedef int (*func)(); typedef short linep; #endif #ifdef vax # define BPB 8 /* bits per byte */ # define BPW (BPB*sizeof(int))/* bits per word */ # define BPWC 5 /* log2(BPW) */ # define BPWM 037 /* mask of BPWC bits */ typedef long block; typedef int charac; typedef short filedes; typedef char flag; typedef int (*func)(); typedef long linep; /* NEW */ #endif /* * conditional compilation */ #ifdef XED # define AGAIN /* enable "o" "again" command */ # define ALLOC 1024 /* line buffer size */ # define APLMAP /* enable Apl character mapping */ # define DEBUG /* enable "du" command */ # define DUMB 0 /* enable command to disable spcl chars */ # define EOL /* enable special eol stuff */ # define EXTMARK /* extended "k" capability */ # define G_VFY /* enable verifying on "g" command */ # define HELP "/etc/xed.doc" # ifdef pdp11 /* only needed on 16-bit machines */ # define HUGE /* enable "huge" file stuff */ # endif # define PAGE /* enable proper line counting on ":" */ # define PARENS /* enable "b" suffix to count parentheses */ # define PIPE /* enable | command to pipe to process */ # define PROMPT ">" # define STRLEN /* enable string-length counting code */ # define TABS ((LBSIZE+sizeof(int)-1)/sizeof(int)) /* words for tab stops */ # define TTL "XED\tV7.15" /* #define TTL_NL 9 /* location of newline in TTL */ # define UNDO /* enable "u"ndo command */ # define USE /* enable "@" command */ # define XDEL /* enable undelete stuff */ # define YINT /* enable special interrupt processing */ #endif /* * stuff for EED, instead of XED */ #ifndef XED # define HELP "/etc/eed.doc" # define PROMPT "*" # define TTL "EED" #else # define EEDHELP "/etc/eed.doc" # define EEDPROMPT "*" # define EEDTTL "EED" #endif /* * stuff normally enabled */ #define CLEAR "\33:\33H\33J\32\14" /* HP-2640A, Lear ADM-3A */ #define CMDS "edsav" /* all commands written if exists */ #ifndef DUMB # define DUMB 1 /* enable command to disable spcl chars */ #endif /* * special stuff, occasionally enabled */ #define LOG "/a/tgi/etc/xed.log" /* feature use logging */ /* * data #defines */ #define BAK 4 /* file.bak - backup() */ #define BLKSIZE 512 /* disk block size (bytes) */ #define BS1 0100000 /* stty() */ #define CBACK 14 /* back-reference: \(blah\)more\1 */ #define CBRA 1 /* \( */ #define CCHR 2 /* literal character */ #define CCL 6 /* character class [x...y] */ #define CCOUNT (80-1) /* terminal width */ #define CDOL 10 /* ...$ */ #define CDOT 4 /* . */ #define CEOF 11 /* end of pattern */ #define CKET 12 /* \) */ #define EOF -1 /* end of file */ #define ESIZE 128 /* regular expression size */ #define FILE 0 /* no extension - backup() */ #define FNSIZE 64 /* max size of pathname to file */ #define GBSIZE 256 /* max global command length */ #define HUP 3 /* file.hup - backup() */ #define INT 2 /* file.int - backup() */ #define LBSIZE 512 /* max line length */ #define LMASK 077 /* mask for "locked" file */ #define LMODE (MODE&~LMASK) /* mode for "locked" file */ #define MODCNT 35 /* default mod count before auto-write */ #define MODE 0666 /* mode for normal files */ #define NBRA 9 /* number of \( \) pairs */ #define NCCL 8 /* not in character class: [^x...y] */ #define PAGSIZ 22 /* page size for ":" command */ #define READ 0 /* getblock: read function */ #define SIGBUS 10 /* Bus error */ #define SIGEMT 7 /* EMT trap */ #define SIGFPE 8 /* Floating Point Exception */ #define SIGHUP 1 /* Hangup signal */ #define SIGILL 4 /* Illegal instruction */ #define SIGINT 2 /* Interrupt signal */ #define SIGIOT 6 /* IOT trap */ #define SIGPIP 13 /* Broken pipe for ! stuff */ #define SIGQIT 3 /* Quit signal */ #define SIGSEGV 11 /* Memory fault */ #define SIGSYS 12 /* Bad system call */ #define SIGTRC 5 /* Trace/BPT for mail stuff */ #define SIGTRM 15 /* Termination */ #define STAR 1 /* * */ #define TABFILL '\t' /* fill character for tab expansion */ #define TMP 1 /* file.edt - backup() */ #define TRM 5 /* file.trm - backup() */ #define TTSIZE (512+4) /* terminal output buffer size */ #define WRITE 1 /* getblock: write function */ #define ever (;;) #define error errfunc #define ctrl(x) ((x)&037) #ifdef AGAIN char agbuf[GBSIZE], /* save area for "again" command */ *agp = 0; /* "again" command pointer */ flag agf = 0; /* "again" flag (executing the command) */ #endif #ifdef ALLOC int lbsize = LBSIZE;/* line buffer size */ #endif #ifdef APLMAP flag aplmap = 0; /* Apl character mapping */ #include "aplmap.h" /* apl ADM-3A char set mapping tables */ #endif #ifdef CKPT char *cfname = "/tmp/ce00000";/* filename for checkpoint */ int recovry = 0, /* non-zero to recover checkpointed session */ tfnum; /* index into tfname for "00000" string */ #endif #ifdef CLEAR char *clears = CLEAR;/* screen-clear sequence */ flag zflg = 0; /* if "stty bs1" not set */ /* bs1 displays ctrl-z as ^Z on tty */ #endif #ifdef CMDS filedes cmd = 0; /* file des for command-save file */ char cmdfil[] = CMDS;/* command-save file */ #endif #ifdef DEBUG flag tflg = 0; /* tracing flag */ #endif #ifdef DUMB flag dumbf = DUMB; /* 1 = disable special chars in patterns */ #endif #ifdef EOL charac eol = 0; /* "end-of-line" char for multiple commands */ /* per line */ flag prompt3 = 1; /* disable prompts for "eol" stuff */ #endif #ifdef G_VFY flag gaskf = 0; /* verify mode on global command */ #endif #ifdef HELP filedes doc = 0; /* "help" file descriptor */ char *help = HELP; /* "help" file name */ #endif #ifdef LOG char logfile[]= LOG; /* logging use of features */ filedes lfile = 0; /* logging file descriptor */ short logamp; /* since s/x/&/ may be done many times */ struct logstat { short l_uid; /* user id of caller */ char l_xed, /* 1 if xed, 0 if eed, 2 if apled */ l_inter; /* 1 if interactive */ /* command features */ short lc_shell, /* ! */ lc_pipe, /* | */ lc_piplus, /* |+ */ lc_piminus, /* |- */ lc_dpipe, /* || */ lc_pfrom, /* |< */ lc_pto, /* |> */ lc_at, /* @ */ lc_colon, /* : */ lc_star, /* * */ lc_clnminus, /* :- */ lc_comment, /* : stuff or * stuff */ lc_append, /* a */ lc_abort, /* abort */ lc_aspace, /* a line */ lc_aslash, /* a/string/ */ lc_browse, /* bN */ lc_change, /* c */ lc_cslash, /* c/s1/s2/ */ lc_copy, /* coNN */ lc_delete, /* d */ lc_depth, /* d=NN */ lc_directory, /* d path */ lc_edit, /* e file */ lc_eol, /* e=C */ lc_errmsg, /* eNN */ lc_exp, /* exp */ lc_eplus, /* e+ */ lc_eminus, /* e- */ lc_fshow, /* f */ lc_fset, /* f file */ lc_fillset, /* f=C */ lc_global, /* g/str/cmd */ lc_gvfy, /* g/str/vcmd */ lc_header, /* h */ lc_help, /* help */ lc_insert, /* i */ lc_islash, /* i/string/ */ lc_join, /* j */ lc_jglue, /* j/glue/ */ lc_klist, /* k */ lc_kset, /* kC */ lc_list, /* l */ lc_move, /* mNN */ lc_moove, /* moNN */ lc_magic, /* m */ lc_numbers, /* n */ lc_numinus, /* n- */ lc_numplus, /* n+ */ lc_o, /* o ^Q */ lc_print, /* p */ lc_pprint, /* pp */ lc_quit, /* q */ lc_qimm, /* qi */ lc_quote, /* q=C */ lc_read, /* r */ lc_substitute, /* s/s1/s2/ */ lc_stop, /* s */ lc_savecount, /* saNN */ lc_tablist, /* t */ lc_tabset, /* t,NN */ lc_tabchar, /* t=C */ lc_transfer, /* tNN */ lc_undo, /* u */ lc_vglobal, /* v/str/cmd */ lc_write, /* w */ lc_wonto, /* w> */ lc_wimm, /* wi */ lc_width, /* w=NN */ lc_xundelete, /* x */ lc_yintr, /* y */ lc_yminus, /* y- */ lc_yplus, /* y+ */ /* address features */ la_dot, /* . */ la_dotdot, /* .. */ la_dol, /* $ */ la_num, /* NN */ la_plus, /* + */ la_minus, /* - */ la_caret, /* ^ */ la_quote, /* 'a */ la_letter, /* A */ la_slash, /* /str/ */ la_query, /* ?str? */ la_equal, /* = */ /* pattern features */ lp_caret, /* ^ */ lp_dol, /* $ */ lp_dot, /* . */ lp_star, /* * */ lp_ccl, /* [ ] */ lp_nccl, /* [^ ] */ lp_paren, /* \( \) */ lp_digit, /* \1 \2 \3 ... */ /* substitution features */ lp_amp, /* & */ /* miscellaneous features */ lm_quote, /* ...q */ lm_bracket, /* ...b */ lm_overwrite; /* -O,wi */ /* resources */ long lt_start, /* starting time */ lt_end, /* elapsed time */ lt_usercpu, /* user cpu time */ lt_syscpu, /* system cpu time */ lt_kidscpu, /* total ! kids time */ lt_rlines, /* total lines read */ lt_wlines; /* total lines written */ } logstats; #endif #ifdef PAGE int ccount = CCOUNT;/* terminal width */ #endif #ifdef PARENS int parenc[3] = {0, 0, 0};/* parentheses counts */ flag parenf = 0; /* count parentheses and brackets */ #endif #ifdef PIPE filedes pfile = 0; /* "pipe" file descriptor */ char *pfname = "/tmp/ep00000";/* for "double-piping" */ flag piperr = 0, /* pipe error flag - shell() */ pno = -1, /* piping line numbering flag (default n-) */ strict = 1; /* strict exit status checking for | */ #endif #ifdef STRLEN charac quotec = '\0', /* quote character other than " or ' */ quotec2 = '\0'; /* closing quote */ int quotef = 0; /* length of strings within " or ' chars */ #endif #ifdef TABS charac tabfill = TABFILL,/* fill character */ tabc = 0; /* tab character - if 0 no tab processing */ int maxtab = -1, /* last column number with tab stop */ tabs[TABS]; /* each bit on = tab stop */ #endif #ifdef UNDO linep undo_oldp, /* original line pointer */ undo_newp; /* replacement line */ #endif #ifdef USE filedes alt = 0; /* alternate command input file */ char altfile[FNSIZE]; flag eflg2 = 0; /* another kludge */ #endif #ifdef XDEL linep deleted = 0; /* pointer to deleted line pointers */ int ndeleted = 0; /* number of lines */ #endif #ifdef YINT flag yflg = 0; /* page upon interrupt */ linep *yplus = 0; /* page from this line - if zero, from dot */ #endif /* * globals */ block iblock = -1, /* block number of input buffer */ oblock = -1; /* output buffer block number */ char *braelist[NBRA], /* bracket \( \) end list */ *braslist[NBRA], /* bracket \( \) start list */ dotbak[] = ".bak", dotedt[] = ".edt", /* "file saved" file */ dothup[] = ".hup", dotint[] = ".int", dottrm[] = ".trm", *dots[] = { dothup, dottrm, dotedt, dotint, 0 }, expbuf[ESIZE + 4], /* expression buffer */ file[FNSIZE], /* filename buffer */ #ifndef ALLOC genbuf[LBSIZE], /* generated line buffer */ #else *genbuf, /* generated line buffer pointer */ #endif ibuff[BLKSIZE], /* input tmpfile buffer */ line[TTSIZE + 4], /* terminal output buffer */ #ifndef ALLOC linebuf[LBSIZE], /* line buffer for getline()/putline() */ #else *linebuf, /* line buffer for getline()/putline() */ #endif no[] = "no ", null[] = "", /* "" */ obuff[BLKSIZE], /* output tmpfile buffer */ off[] = "off", on[] = "on", prcntu[] = "%u\n", /* %u */ quote_s[] = "s", /* "s" */ rhsbuf[LBSIZE / 2], /* right-hand-side expression buffer */ savedfile[FNSIZE], /* saved filename */ tempfile[FNSIZE], /* scratch area for filename */ *editor, /* argv[0] */ *e_prompt = PROMPT,/* editor command prompt */ *fmtlno = "%7u=",/* format for line-number output */ *globp, /* global command pointer */ *linp = line, /* line pointer */ *linebp, *loc1, /* start pointer of & string */ *loc2, /* end pointer of & string */ *locs, *nextip, *overfile, /* filename mode was changed on */ *tfname = "/tmp/e00000",/* "buffer" name */ *ver = TTL; /* ID message */ charac lastc = 0, /* peekc set to lastc on interrupt */ peekc = 0; /* one character pushback */ int brcount = 1, /* number of lines to output on "newline" */ col = 0, /* column counter for calculating line wraps */ line_num, /* integer for line number on output */ modcount = MODCNT,/* number of mods before auto-write */ overmode, /* mode of overridden file */ mods = 0, /* number of mods */ nbra = 0, /* count of currently defined \( \) pairs */ ninbuf, /* bytes in tmpfile input buffer */ nleft, /* bytes remaining in tmpfile output buffer */ num_reads = 0, /* indicator to aid text_modified-- */ /* first read isn't really a modify */ pcount = PAGSIZ-1,/* number of lines to display on ":" command */ s_cnt = 0, /* counter for "s/str1/str2/nn" */ s_tmp = 0, /* scratch var for same */ savf, /* counter for auto-write stuff */ text_modified = 0;/* flag--on if text was modified */ filedes fout = 1, /* putchar() writes on this fildes */ io = 0, /* file descriptor for "r", "w", "e" */ tfile = -1; /* file des for "buffer" */ flag aflg = 0, /* "apl mode" flag */ appflg = 0, /* append flag (if "w>file") */ badf = 0, /* bad read on temp file */ bflg = 0, /* "back-up" flag -- Generate back-up file */ bflg2 = 0, /* Secondary "back-up" flag */ circfl, /* reg expr started with ^ */ curt = 0, /* short error messages -- ie: '?' */ deltflg = 0, /* don't delete .edt file upon exit */ eflg = 0, /* echo input flag */ eof = 0, /* eof was last char typed */ fflg = 0, /* "create" flag */ globf2 = 0, /* kludge for -f */ #ifdef HUGE hugef = 0, /* -h is process huge file */ hugef2 = 0, /* getblock() conversion to huge */ #endif hupflag = 0, /* hangup signal has been caught */ ichanged, /* ibuf has been changed */ iflg = 0, /* file.int and exit on interrupt */ immflg = 0, /* immediate flag -- q and e */ io_w = 0, /* writing in progress */ listf = 0, /* list control chars explicitly */ noshell = 0, /* true if no ! command allowed */ over = 0, /* override permissions on write if possible */ pflag, /* print line after doing command */ pipef = 0, /* for talking to pipes */ prompt1 = 1, /* flag--enable or disable line-num prompts */ prompt2 = 1, /* flag--enable or disable ALL prompting */ reading = 0, /* waiting on tty read */ seekf = 0, /* no seek to EOF on error on fd 0 */ termflg = 0; /* if termination signal (15) occurred */ linep *addr1, /* lower line bound */ *addr2, /* upper line bound */ *dol, /* last line in file */ *dot, /* "current" line */ *dotdot, /* last different "dot" */ *endcore, /* current end of memory */ *fendcore, /* start of dynamic area */ *lastdot, /* last "dot" */ names['z' - 'a' + 1], /* "k" command markers */ #ifdef EXTMARK names2['z' - 'a' + 1], /* "k" command markers */ #endif *old_a1, /* previous address bounds */ *old_a2, tline, /* pointer to next available pos in tmpfile */ *zero; /* anchor line for all other lines */ /* * magic constants used in many places */ #ifdef pdp11 # define _1a ~0377 # define _2a 0400 # define _3a 0377 # define _4a 0774 # define _5a 255 # define _6a 077776 # define _1b ~0177 # define _2b 0200 # define _3b 0777 # define _4b 0774 # define _5b 511 # define _6b 077777 #endif #ifdef vax # define _1a ~0377 # define _2a 0400 # define _3a 077777777 # define _4a 0774 # define _5a 65535 # define _6a 077777776 #endif #ifdef HUGE int _1[] = { _1a, _1b }, /* tl &= _1; getline() */ _2[] = { _2a, _2b }, /* tl += _2; getline()... */ _3[] = { _3a, _3b }, /* bno = ... & _3; getblock() */ _4[] = { _4a, _4b }, /* off = ... & _4; getblock() */ _5[] = { _5a, _5b }, /* if (bno >= _5)... getblock() */ _6[] = { _6a, _6b }; /* tline += ... & _6; */ #else # define _1 _1a # define _2 _2a # define _3 _3a # define _4 _4a # define _5 _5a # define _6 _6a #endif /* * error messages * * (there are more than these) */ char *errtext[] = { /* 0 */ "syntax is k[a-z]", /* 1 */ "illegal command format", /* 2 */ "no command", /* 3 */ "no tab character", /* 4 */ "can't change filename", /* 5 */ "file name syntax", /* 6 */ "recursive \"@\" command", /* 7 */ "null file name illegal", /* 8 */ "unrecognized command", /* 9 */ "no tabs set", /* 10 */ "global command not allowed with huge file", /* 11 */ "file name too long", /* 12 */ "expanded line too long", /* 13 */ "no such line", /* 14 */ "can't fork", /* 15 */ "can't write to process", /* 16 */ "no lines", /* 17 */ "backup(FILE) error (?)", /* 18 */ "string not found", /* 19 */ " ' must be followed by [a-z]", /* 20 */ "address syntax error", /* 21 */ "lower address bound > upper one", /* 22 */ "address illegal here", /* 23 */ "non-existent line number", /* 24 */ "bottom of file reached", /* 25 */ "command syntax error", /* 26 */ "\"advance\" error (?)", /* 27 */ "null string illegal", /* 28 */ "destination not found", /* 29 */ "INTERRUPT!", /* 30 */ "line too long", /* 31 */ "missing destination address", /* 32 */ "I/O error--file not saved!", /* 33 */ "file overflows available memory", /* 34 */ "file too large (TMPERR)", /* 35 */ "I/O error on temp file (TMPERR)", /* 36 */ "open error on temp file (TMPERR)", /* 37 */ "recursive global command", /* 38 */ "global command list too long", /* 39 */ "substitute pattern not found", /* 40 */ "missing substring", /* 41 */ "string2 too long", /* 42 */ "substring too long", /* 43 */ "substituted string too long", /* 44 */ "too many \\(", /* 45 */ "unbalanced \\( \\)", /* 46 */ "\\n illegal", /* 47 */ "unimplemented feature", /* 48 */ "[nothing written]", /* 49 */ "pattern too complicated", /* 50 */ "can't create temp file (TMPERR)", /* 51 */ "bad directory", /* 52 */ "no ! allowed", /* 53 */ "can't read ", /* 54 */ "can't create ", /* 55 */ "%u line%s\n", /* 56 */ "[file saved]", /* 57 */ "\nHangup!\n", /* 58 */ "\nTerminated...\n", /* 59 */ "EOF illegal here", /* 60 */ "can't join to line 0", /* 61 */ "! not allowed with global command", /* 62 */ "no filename specified", /* 63 */ "not enough \\( \\) pairs", /* 64 */ "can't create pipe file (PIPERR)", /* 65 */ "open error on pipe file (PIPERR)", /* 66 */ "can't checkpoint", /* 67 */ "can't recover", }; #define NERR (sizeof errtext / sizeof errtext[0]) /* * ! error strings */ char *status[] = { /* 0 */ 0, /* 1 */ "hangup", /* 2 */ "interrupt", /* 3 */ "quit", /* 4 */ "illegal instruction", /* 5 */ "bpt", /* 6 */ "iot", /* 7 */ "emt", /* 8 */ "fpp", /* 9 */ "killed", /* 10 */ "bus error", /* 11 */ "memory fault", /* 12 */ "bad sys call", /* 13 */ "broken pipe", /* 14 */ "alarm", /* 15 */ "terminated", #ifdef pdp11 /* 16 */ "time limit", #else /* 16 */ 0, /* 17 */ "stopped", /* 18 */ "terminal stop", /* 19 */ "continue", /* 20 */ "child status changed", /* 21 */ "terminal input", /* 22 */ "terminal output", /* 23 */ "terminal input ready", /* 24 */ "cpu timelimit exceeded", /* 25 */ "filesize limit exceeded", #endif }; #define NSTR (sizeof status / sizeof status[0]) #define putsn(x) (puts2((x)),putchar('\n')) #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) /* * function declarations */ linep *findmark(); char *getblock(); long lseek(); func signal(); #ifndef CKPT int badsig(), #else int checkpoint(), #endif hangup(), mail(), onintr(), term(); /* * signals */ struct sigtab { int s_sig, s_func; } sigtab1[] = { #ifdef CKPT SIGILL, checkpoint, SIGIOT, checkpoint, SIGEMT, checkpoint, SIGFPE, checkpoint, SIGBUS, checkpoint, SIGSEGV, checkpoint, SIGSYS, checkpoint, #else SIGILL, badsig, SIGIOT, badsig, SIGEMT, badsig, SIGFPE, badsig, SIGBUS, badsig, SIGSEGV, badsig, SIGSYS, badsig, #endif 0, 0, }, sigtab2[] = { SIGTRC, mail, SIGHUP, hangup, SIGTRM, term, SIGINT, onintr, 0, 0, }; main(argc, argv) char **argv; { #ifdef CKPT extern checkpoint(); #else extern badsig(); #endif extern onintr(), hangup(), mail(), term(); #ifdef DEBUG #ifdef EXPDMP extern expdmp(); #endif #endif register n; register char *p1, *p2, *ep; func savint; signal(SIGQIT, 1); savint = signal(SIGINT, 1); ep = *argv; #ifdef XED p1 = ep; p2 = p1; while (*p1) if (*p1++ == '/' && *p1 && *p1 != '/') p2 = p1; p1 = p2; *argv = p2; n = 0; while (*p1) if (*p1++ == 'x') { /* xed .vs. eed */ ++n; break; } if (n == 0) { e_prompt = EEDPROMPT; ver = EEDTTL; help = EEDHELP; dumbf = 1; } #ifdef LOG logstats.l_xed = n; #endif #endif prompt2 = istty(0); #ifdef V7 if (getenv("_OVERWRITE_")) ++over; #endif while (--argc) if (**++argv == '-') { while (*++*argv) { switch (**argv) { case '!': /* no ! allowed */ noshell = 1; break; #ifdef APLMAP case 'A': /* apl char mapping */ aplmap = 1; errtext[29] = "G interrupt G"; p1 = ver; while (*p1) { if ('A' <= *p1 && *p1 <= 'Z') *p1 |= 040; ++p1; } #endif case 'a': /* apl mode */ aflg = 1; fmtlno = "[ %u ]\t"; #ifdef DUMB dumbf = 1; #endif #ifdef XED #ifdef TTL_NL ver[TTL_NL] = 0; #endif #endif break; case 'b': /* file.bak on entry */ bflg = 1; bflg2 = 1; break; #ifdef PAGE case 'c': /* crt depth in lines */ ++*argv; n = argnum(argv); if (n >= 0) pcount = n; break; #endif case 'd': /* don't delete .edt file */ deltflg = 1; break; case 'e': /* echo input commands */ eflg = 1; break; case 'f': /* create mode */ fflg = 1; break; #ifdef HUGE case 'h': /* edit "huge" file */ hugef = 1; break; #endif case 'i': /* file.int on interrupt */ iflg = 1; break; case 'k': /* kill verbose messages */ curt = 1; break; #ifdef EOL case 'l': /* set eol char to "x" */ if (*++*argv) eol = **argv; else --*argv; break; #endif case 'm': /* mod cnt for autosave */ ++*argv; n = argnum(argv); if (n >= 0) modcount = n; break; case 'n': /* no line num */ prompt1 = 0; break; case 'o': /* no seek to EOF on error */ seekf = 1; break; case 'p': /* force prompts for pipe */ pipef = 1; prompt2 = 1; break; case 'q': /* don't inhibit quits */ signal(SIGQIT, 0); break; #ifdef DUMB case 'r': /* spcl char meaning */ dumbf ^= 01; break; #endif case 's': /* silent mode */ prompt2 = 0; break; #ifdef TABS case 't': /* tab char */ if (*++*argv) tabc = **argv; else --*argv; break; #endif #ifdef TABS case 'v': /* tab fill char */ if (*++*argv) tabfill = **argv; else --*argv; break; #endif #ifdef PAGE case 'w': /* crt width */ ++*argv; n = argnum(argv); if (--n >= 2) ccount = n; break; #endif #ifdef YINT case 'y': /* page on interrupt */ yflg = 1; break; #endif #ifdef USE case '@': /* set "@" filename */ p2 = altfile; p1 = ++*argv; while (*p1 && p2 < &altfile[FNSIZE - 2]) *p2++ = *p1++; if (*p1) { p2 = altfile; putsn(errtext[11]); } *p2 = '\0'; *argv = &p1[-1]; break; #endif #ifdef ALLOC case 'B': /* line buffer size */ ++*argv; n = argnum(argv); if (n >= LBSIZE) lbsize = n; break; #endif #ifdef DEBUG case 'D': /* trace mode -- debug */ tflg = 1; break; #ifdef EXPDMP case 'Q': /* show pattern on quit */ signal(SIGQIT, expdmp); break; #endif #endif #ifdef XED case 'I': /* suppress ID message */ ver = 0; break; case 'P': /* prompt */ p1 = *argv; e_prompt = ++p1; while (*p1++); *argv = &p1[-2]; break; case 'L': /* line number prompt */ p1 = *argv; fmtlno = ++p1; while (*p1++); *argv = &p1[-2]; break; case 'C': /* screen-clear */ p1 = *argv; clears = ++p1; while (*p1++); *argv = &p1[-2]; break; #ifdef CKPT case 'R': /* recover */ ++*argv; if ((recovry = argnum(argv)) == 0) recovry = 1; break; #endif case 'O': /* over-ride write perm */ over ^= 01; break; case 'T': /* temp filename */ p1 = *argv; tfname = ++p1; #ifdef PIPE while (*p1) if (*p1++ == ':') { p1[-1] = '\0'; pfname = p1; #ifdef CKPT break; #endif } #endif #ifdef CKPT while (*p1) if (*p1++ == ':') { p1[-1] = '\0'; cfname = p1; } #endif *argv = &p1[-1]; break; #endif default: /* tabs stops/illegals */ if (!**argv || **argv == '-' #ifdef TABS || **argv == ',' #endif ) break; #ifdef TABS if (**argv < '0' || **argv > '9') { #endif printf("bad flag: -%c\n", **argv); exit(1); #ifdef TABS } n = argnum(argv); settab(n); #endif } } } else { p1 = *argv; p2 = savedfile; while (*p2++ = *p1++) if (p2 >= &savedfile[FNSIZE - 2]) { putsn(errtext[11]); exit(1); } globf2 = 1; if (fflg) globp = "a\n"; else globp = "r\n"; } #ifdef YINT if (iflg) yflg = 0; #endif #ifdef ALLOC linebuf = sbrk(lbsize); genbuf = sbrk(lbsize); #endif fendcore = sbrk(0); #ifdef CKPT if ((n = recovry) == 0) #endif n = getpid(); #ifdef PIPE tmpname(pfname, n); #endif #ifdef CKPT tmpname(cfname, n); #endif tmpname(tfname, n); /* MUST be last call to tmpname */ #ifdef LOG logstats.l_uid = getuid(); time(&logstats.lt_start); if (prompt2) ++logstats.l_inter; if (aflg) logstats.l_xed = 2; /* magic num for apled */ #endif #ifdef CKPT if (recovry) recover(); #endif editor = ep; if (prompt2) { #ifdef CMDS if ((cmd = open(cmdfil, 1)) > 0) lseek(cmd, 0L, 2); else cmd = 0; #endif if (ver) putsn(ver); /* XED V0.00 ... */ flush_buf(); } else modcount = 0; #ifdef CMDS if (cmd && *savedfile) { write(cmd, "e,", 2); p1 = savedfile; while (*p1++); write(cmd, savedfile, --p1 - savedfile); write(cmd, "\n", 1); } #endif signals(sigtab1); setexit(); if (((int)savint & 01) == 0) signals(sigtab2); #ifdef YINT else yflg = 0; #endif #ifdef CKPT if (!recovry) #endif init(); setexit(); cant: do { commands(0); } while (are_you_sure()); if (immflg == 0) { if (fflg) if (backup(FILE)) text_modified = 0; else goto cant; if (text_modified == 0) backup(-TMP); else if (modcount && eof) if (backup(TMP) && prompt2) if (!curt) putsn(errtext[56]); } delexit(0); } abort() { register char *p; register charac c; setnoaddr(); peekc = 0; p = "ort\n"; while (*p) if ((c = getchar()) != *p++) { peekc = c; errmsg(25); } #ifdef LOG ++logstats.lc_abort; #endif delexit(1); } linep * address() { register minus; register charac c; register linep *a1, *start; register n, relerr; minus = 0; a1 = 0; for ever { c = getchar(); if ('0' <= c && c <= '9') { peekc = c; n = getnum(); if (a1 == 0) { a1 = zero; n += aflg; #ifdef LOG if (!globp) ++logstats.la_num; #endif } if (minus < 0) n = -n; a1 += n; minus = 0; continue; } relerr = 0; if (a1 || minus) relerr++; switch (c) { case ' ': case '\t': continue; case '+': minus += brcount; if (a1 == 0) a1 = dot; #ifdef LOG if (!globp) ++logstats.la_plus; #endif continue; case '-': case '^': /* for upwards compatibility */ minus -= brcount; if (a1 == 0) a1 = dot; #ifdef LOG if (!globp) if (c == '^') ++logstats.la_caret; else ++logstats.la_minus; #endif continue; /* search: */ case '?': minus++; case '/': compile(c); if (a1 == 0) a1 = dot; if (a1 < zero) a1 = zero; if (a1 > dol) a1 = dol; start = a1; #ifdef LOG if (!globp) if (minus) ++logstats.la_query; else ++logstats.la_slash; #endif for ever { if (minus == 0) { if (++a1 > dol) a1 = zero; } else { if (--a1 < zero) a1 = dol; } if (execute(0, a1)) { minus = 0; relerr = 0; break; } if (a1 == start) errmsg(18); } break; case '$': a1 = dol; #ifdef LOG if (!globp) ++logstats.la_dol; #endif break; case '.': if ((peekc = getchar()) == '.') { peekc = 0; a1 = dotdot; #ifdef LOG if (!globp) ++logstats.la_dotdot; #endif } else { a1 = dot; #ifdef LOG if (!globp) ++logstats.la_dot; #endif } break; case '\'': if (((c = getchar()) | 040) < 'a' || (c | 040) > 'z') { peekc = c; errmsg(19); } c |= 040; #ifdef LOG if (!globp) ++logstats.la_quote; #endif casemark: #ifdef EXTMARK n = 3; if ((peekc = getchar()) == '^') { n = 1; peekc = 0; } else if (peekc == '$') { n = 2; if (names2[c - 'a'] == 0) n = 1; peekc = 0; } if (n & 01) if ((a1=findmark(names[c-'a'],0))==0) { a1 = dol; n = 0; } if (n > 1 && names2[c - 'a']) { if (n == 3) { if (addr1 || addr2) errmsg(20); addr1 = a1; } a1 = findmark(names2[c - 'a'], dol); if (n == 2) break; addr2 = a1; return(0); } #else a1 = findmark(names[c - 'a'], dol); #endif break; case '=': #ifdef LOG if (!globp) ++logstats.la_equal; #endif if ((peekc = getchar()) == '^') a1 = old_a1; else if (peekc == '$') a1 = old_a2; else { if (addr1 || addr2 || a1) errmsg(20); addr1 = old_a1; addr2 = old_a2; return(0); } peekc = 0; break; default: if ('A' <= c && c <= 'Z') { c |= 040; #ifdef LOG if (!globp) ++logstats.la_letter; #endif goto casemark; } peekc = c; if (a1 == 0) if (c == ',' || c == ';') if (dot + 1 > dol) return(dol); else return(dot + 1); else return(0); a1 += minus; if (a1 < zero) a1 = zero + (zero != dol); else if (a1 > dol) a1 = dol; return(a1); } if (relerr) errmsg(20); } } advance(alp, aep) { register char *lp, *ep, *curlp; register s_sav, i; lp = alp; ep = aep; for ever switch (*ep++) { case CCHR: if (*ep++ == *lp++) continue; return(0); case CDOT: if (*lp++) continue; return(0); case CDOL: if (*lp == 0) continue; return(0); case CEOF: loc2 = lp; if (--s_tmp > 0) return(0); return(1); case CCL: case NCCL: if (cclass(ep, *lp++, ep[-1] == CCL)) { ep += *ep; continue; } return(0); case CBRA: braslist[*ep++] = lp; continue; case CKET: braelist[*ep++] = lp; continue; case CBACK: if (braelist[i = *ep++] == 0) errmsg(63); if (backref(i, lp)) { lp += braelist[i] - braslist[i]; continue; } return(0); case CBACK | STAR: if (braelist[i = *ep++] == 0) errmsg(63); curlp = lp; while (backref(i, lp)) lp += braelist[i] - braslist[i]; while (lp >= curlp) { if (advance(lp, ep)) return(1); lp -= braelist[i] - braslist[i]; } continue; case CDOT | STAR: curlp = lp; while (*lp++); goto star; case CCHR | STAR: curlp = lp; while (*lp++ == *ep); ep++; goto star; case CCL | STAR: case NCCL | STAR: curlp = lp; while (cclass(ep, *lp++, ep[-1] == (CCL | STAR))); ep += *ep; /* goto star; */ star: s_sav = s_tmp; do { if (--lp == locs) break; if (advance(lp, ep)) return(1); s_tmp = s_sav; } while (lp > curlp); --s_tmp; return(0); default: errmsg(-26); } } linep * append(f, a, single, bkpf) func f; linep *a; { register linep *a1, *a2, *rdot; register nline, tl; nline = 0; dot = a; while ((*f)(single) == 0) { if (dol >= endcore) { if (sbrk(1024) == -1) errmsg(33); endcore = (int)endcore + 1024; } tl = putline(); nline++; a1 = ++dol; a2 = a1 + 1; rdot = ++dot; while (a1 > rdot) *--a2 = *--a1; *rdot = tl; if (bkpf) { mods++; backchk(); } if (single) break; } return(nline); } are_you_sure() { #ifdef USE if (alt) return(1); #endif if (!text_modified || fflg || immflg || zero == dol) return(0); return(yes_no(curt? "?forget" : "did you forget to save your text", 1, 1, 0)); } argnum(ap) char **ap; { register n; register char *p; p = *ap; n = 0; while ('0' <= *p && *p <= '9') n = n * 10 + *p++ - '0'; *ap = --p; return(n); } backchk() { if (modcount == 0) return; if (mods >= modcount) { mods = 0; #ifdef EOL if (backup(TMP) && prompt2 && prompt3) #endif #ifndef EOL if (backup(TMP) && prompt2) #endif if (!curt) putsn(errtext[56]); } } backref(an, alp) char *alp; { register n; register char *bp, *lp; n = an; bp = braslist[n]; lp = alp; while (*bp++ == *lp++) if (bp >= braelist[n]) return(1); return(0); } backup(af) { register char *p1, *p2, *t2; register linep *a1, *a2; register func savint, savhup; if (io) { putsn("******** backup: I/O in progress"); return(0); } flush_buf(); p1 = savedfile; t2 = p2 = file; while (*p2 = *p1++) if (*p2++ == '/') t2 = p2; if (p2 > t2 + 10) p2 = t2 + 10; if (af != FILE && p2 >= &file[FNSIZE - 6]) errmsg(11); switch (af < 0? -af : af) { case FILE: p1 = 0; break; case TMP: p1 = dotedt; break; case INT: p1 = dotint; break; case HUP: p1 = dothup; break; case BAK: p1 = dotbak; break; case TRM: p1 = dottrm; break; default: errmsg(-17); } if (p1) while (*p2++ = *p1++); if (af < 0) { if (deltflg) return(1); return(!unlink(file)); } if (dol == zero && !fflg) { if (af == FILE) if (curt) putsn("?48"); else putsn(errtext[48]); return(1); } if (dol == zero) return(1); if (!iflg) { savhup = signal(SIGHUP, 1); savint = signal(SIGINT, 1); } if (over && af == FILE) override(); io = create(file, (af == FILE? MODE : LMODE)); if (overfile) { chmod(overfile, overmode); overfile = 0; } if (io < 0) { io = 0; if (af != TMP) { if (curt) putsn("?54"); else { puts2(errtext[54]); putsn(file); } } if (!iflg) { signal(SIGHUP, savhup); signal(SIGINT, savint); } return(0); } io_w++; a1 = addr1; a2 = addr2; addr1 = zero + 1; addr2 = dol; putfile(); close(io); io = 0; io_w = 0; addr1 = a1; addr2 = a2; if (!iflg) { signal(SIGHUP, savhup); signal(SIGINT, savint); } return(1); } #ifndef CKPT badsig(an) { register n; if (n = backup(TMP)) putsn(errtext[56]); puts(" Fatal Signal: "); if (0 < an && an < NSTR && status[an]) putsn(status[an]); else printf("%d\n", an); flush_buf(); if (n) exit(1); error(); } #endif blkio(b, buf, iofcn) func iofcn; { lseek(tfile, 512L * b, 0); if ((*iofcn)(tfile, buf, BLKSIZE) != BLKSIZE) { badf++; errmsg(-35); } } cclass(aset, ac, af) char *aset; charac ac; { register char *set; register n; register charac c, m; set = aset; if ((c = ac) == 0) return(0); n = *set++; while (--n) if (set[1] == '-' && n > 2) { c = min(set[0], set[2]); m = max(set[0], set[2]); do { if (c == ac) return(af); } while (++c != m); set += 2; c = ac; } else if (*set++ == c) return(af); return(!af); } #ifdef CKPT checkpoint(asig) { extern etext; register filedes f; register char *p; register func savint, savqit; int n; savint = signal(SIGINT, 1); savqit = signal(SIGQIT, 1); p = &etext; /* won't work for -n, -i, or -z */ n = (char *)dol - p; n += sizeof (int); if ((f = create(cfname, LMODE)) < 0 || write(f, &n, sizeof n) != sizeof n) { n = 66; goto cerror; } #ifdef pdp11 /* 16 bit byte count only */ if (n < 0) { if (write(f, etext, 32256) != 32256) { n = 66; goto cerror; } n -= 32256; /* 63 blocks, since 64 is < 0 */ p += 32256; } #endif if (write(f, p, n) != n) n = 66; else n = 0; cerror: close(f); if (n) { signal(SIGINT, savint); signal(SIGQIT, savqit); recovry = 0; errmsg(n); } if (asig) { puts2(status[asig]); if (!curt) puts(": Fatal error"); } if (curt) puts2("?CKPT "); else { puts2("Editing session checkpointed to \""); puts2(cfname); puts("\".\nTo recover your work, type:"); if (editor && *editor) puts2(editor); else puts2("edit"); puts2(" -R"); } puts(&tfname[tfnum]); exit(1); } #endif chk() { register charac c; register char *p2, *p1, *t2, **p; register charac oldc; long t; struct stat s; if (*savedfile == '\0') return(0); t2 = p2 = file; p1 = savedfile; if (stat(p1, &s) >= 0) t = s.st_mtime; else t = 0L; while (*p2 = *p1++) if (*p2++ == '/') t2 = p2; if (p2 > t2 + 10) p2 = t2 + 10; if (p2 >= &file[FNSIZE - 6]) return(0); t2 = p2; p = dots; while (p1 = *p++) { p2 = t2; while (*p2++ = *p1++); if (stat(file, &s) >= 0 && s.st_mtime >= t) { if (curt) { puts2("?\""); puts2(file); puts2("\" "); } else { putsn("When you were last editing this file"); putsn("you did not exit the editor normally,"); puts2("leaving the file: \""); puts2(file); if (p1 == dotedt) { putsn("\".\nIt contains your file up to the last \"[file saved]\""); putsn("message. This file will be deleted if you do"); putsn("not read it into the editor now. If you read"); putsn("it, then decide not to use it, exit the editor"); putsn("with \"qi\"."); } else putsn("\"."); } return(yes_no(curt? "read" : "Do you wish to read it", 1, -1, 0)); } } return(0); } _cleanup() { flush_buf(); } #ifdef CLEAR clear() { register l, i; l = listf; listf = 0; puts2(clears); /* clear sequence */ flush_buf(); i = 5; while (--i >= 0) putchar(0); /* ADM-3A's need padding at 19.2 */ putchar('\n'); listf = l; } #endif commands(baseflg) { extern getfile(), gettty(); register linep *a1; register charac c; register char *p; register r, num; for ever { #ifdef AGAIN if (agp) { *agp++ = '\n'; *agp = '\0'; } agf = 0; agp = 0; #endif immflg = 0; #ifdef LOG if (logamp) { ++logstats.lp_amp; logamp = 0; } #endif if (!globp && (hupflag || termflg)) { if (hupflag) { backup(HUP); puts2(errtext[57]); } else { backup(TRM); puts2(errtext[58]); } delexit(1); } if (pflag) { pflag = 0; addr1 = addr2 = dot; goto print; } if (!globp) { #ifdef USE if (!alt) { #endif if (modcount) { if (text_modified > savf) mods++; savf = text_modified; backchk(); } #ifdef EOL #ifdef USE if (prompt2 && prompt3 && !eflg2) #endif #ifndef USE if (prompt2 && prompt3) #endif #endif #ifndef EOL #ifdef USE if (prompt2 && !eflg2) #endif #ifndef USE if (prompt2) #endif #endif { puts2(e_prompt); flush_buf(); } #ifdef USE } #endif } if (!globp) { if (dotdot > dol) dotdot = dol; if (dotdot < zero) dotdot = zero; if (dot != lastdot) { dotdot = lastdot; lastdot = dot; } } addr1 = 0; addr2 = 0; s_tmp = 0; s_cnt = 0; r = 1; do { addr1 = addr2; if ((a1 = address()) == 0) { c = getchar(); break; } addr2 = a1; if ((c = getchar()) == ';') { c = ','; dot = a1; } } while (c == ',' && --r >= 0); if (addr1 == 0) addr1 = addr2; if (!globp && !baseflg) { if (addr1) { old_a1 = addr1; old_a2 = addr2; } } line_num = (addr1? addr1 : dot) - zero; #ifdef AGAIN if (c == 'o' || c == ctrl('Q')) { /* again command "o" */ if (c != ctrl('Q') && (peekc = getchar()) != '\n') errmsg(1); if (c == ctrl('Q')) putchar(lastc = '\n'); if (*agbuf == 0) errmsg(2); agf++; agp = agbuf; c = *agp++; peekc = 0; #ifdef LOG ++logstats.lc_o; #endif } else if (baseflg == 0 && globp == 0) if (c != '\n') { agp = agbuf; *agp++ = c; /* first char not yet saved */ } #endif switch (c) { case 'a': if ((peekc = getchar()) == 'b') abort(); setdot(); #ifdef XED if (peekc != ' ' && peekc != '\n') { c = peekc; peekc = 0; if (tack(c, 1)) text_modified++; #ifdef LOG ++logstats.lc_aslash; #endif continue; } #endif line_num++; num = addr2; #ifdef LOG ++logstats.lc_append; #endif caseadd: if ((c = getchar()) == ' ') { r = 1; #ifdef LOG ++logstats.lc_aspace; #endif } else { #ifndef XED if (c != '\n') { peekc = c; newline(); } #endif r = 0; } if (append(gettty, num, r, 1)) text_modified++; continue; case 'b': setnoaddr(); white_space(); if ((brcount = setnum(1)) <= 0) brcount = 1; #ifdef LOG ++logstats.lc_browse; #endif continue; case 'c': if ((peekc = getchar()) == 'o') { /* co == t */ peekc = 0; #ifdef LOG ++logstats.lc_copy; #endif goto casecopy; } if (peekc != '\n') goto casesub; newline(); setdot(); nonzero(); delete(); text_modified++; #ifdef LOG ++logstats.lc_change; #endif append(gettty, addr1 - 1, 0, 0); continue; case 'd': #ifdef DEBUG /* *du Dump command (testing only) */ if ((peekc = getchar()) == 'u') { peekc = 0; dump(); continue; } #endif if ((peekc = getchar()) == ' ' || peekc == ',') { peekc = 0; white_space(); p = linebuf; if ((c = getchar()) == '\n') errmsg(51); do { *p++ = c; #ifndef ALLOC if (p >= &linebuf[LBSIZE - 2]) #else if (p >= &linebuf[lbsize - 2]) #endif errmsg(11); } while ((c = getchar()) >= 0 && c != '\n'); *p = 0; #ifdef LOG ++logstats.lc_directory; #endif if (chdir(linebuf) < 0) errmsg(51); continue; } #ifdef PAGE if (peekc == '=') { /* d= */ peekc = 0; setnoaddr(); pcount = setnum(PAGSIZ); #ifdef LOG ++logstats.lc_depth; #endif continue; } #endif newline(); setdot(); nonzero(); delete(); text_modified++; #ifdef LOG ++logstats.lc_delete; #endif continue; case 'e': eagain: if ((peekc = getchar()) != '\n') { #ifdef EOL if (peekc == '=') { /* e=c - set eol to 'c' */ peekc = 0; if (immflg) errmsg(8); setnoaddr(); eol = setchar(0); #ifdef LOG ++logstats.lc_eol; #endif continue; } #endif #ifdef TABS if (peekc == 'x') { peekc = 0; if (immflg) errmsg(8); if ((c = getchar()) != 'p') errmsg(8); newline(); if (!tabc) errmsg(3); if (maxtab < 0) errmsg(9); if (exp()) text_modified++; #ifdef LOG ++logstats.lc_exp; #endif continue; } #endif if ('0' <= peekc && peekc <= '9') { c = getnum(); newline(); if (0 <= c && c < NERR) printf("%3d: %s\n", c, errtext[c]); #ifdef LOG ++logstats.lc_errmsg; #endif continue; } if (peekc == '+' || peekc == '-') { c = peekc; peekc = 0; newline(); curt = c == '-'; #ifdef LOG if (curt) ++logstats.lc_eminus; else ++logstats.lc_eplus; #endif continue; } if (peekc == 'i') { peekc = 0; if (immflg) errmsg(8); immflg++; goto eagain; } setnoaddr(); if (fflg) errmsg(4); if (peekc != ' ' && peekc != ',') illfnm: errmsg(5); scopy(savedfile, tempfile); if (zero == dol || text_modified == 0) backup(-TMP); savedfile[0] = 0; filename(); if (text_modified && are_you_sure()) { scopy(tempfile, savedfile); error(); } peekc = '\n'; } else { setnoaddr(); if (text_modified) { r = peekc; peekc = 0; if (are_you_sure()) { peekc = r; error(); } peekc = r; } if (zero == dol || text_modified == 0) backup(-TMP); } if (init()) continue; #ifdef LOG ++logstats.lc_edit; #endif goto caseread; case 'f': setnoaddr(); #ifdef TABS if ((peekc = getchar()) == '=') { /* f=c fill char */ peekc = 0; tabfill = setchar(TABFILL); #ifdef LOG ++logstats.lc_fillset; #endif continue; } #endif if ((c = getchar()) != '\n') { if (fflg) errmsg(4); peekc = c; filename(); scopy(file, savedfile); #ifdef LOG ++logstats.lc_fset; #endif if (prompt2 == 0) continue; } #ifdef LOG else ++logstats.lc_fshow; #endif putsn(savedfile); continue; case 'g': global(1); continue; case 'h': #ifdef HELP if ((peekc = getchar()) == 'e') { /* he[lp] */ peekc = 0; setnoaddr(); skip_rest(); #ifdef LOG ++logstats.lc_help; #endif if ((doc = open(help, 0)) > 0) { while ((c = read(doc, linebuf, #ifndef ALLOC LBSIZE)) > 0) #else lbsize)) > 0) #endif write(1, linebuf, c); close(doc); } doc = 0; continue; } #endif if (zero != dol) { setdot(); nonzero(); } #ifdef LOG ++logstats.lc_header; #endif header(); continue; case 'i': setdot(); #ifdef XED if ((peekc = getchar()) != ' ' && peekc != '\n') { c = peekc; peekc = 0; if (tack(c, 0)) text_modified++; #ifdef LOG ++logstats.lc_islash; #endif continue; } #endif nonzero(); num = addr2 - 1; #ifdef LOG ++logstats.lc_insert; #endif goto caseadd; #ifdef XED case 'j': setdot(); nonzero(); join(); text_modified++; continue; #endif case 'k': if ((c = getchar()) == '\n') { setnoaddr(); #ifdef LOG ++logstats.lc_klist; #endif printmarks(); continue; } if ('A' <= c && c <= 'Z') c |= 040; if (c < 'a' || c > 'z') errmsg(0); newline(); setdot(); nonzero(); #ifdef HUGE r = hugef ^ 01; #else #define r 1 #endif #ifdef EXTMARK if (addr1 != addr2) { names[c - 'a'] = *addr1 | r; names2[c - 'a'] = *addr2 | r; } else { names[c - 'a'] = *addr2 | r; names2[c - 'a'] = 0; } #else names[c - 'a'] = *addr2 | r; #endif #ifdef LOG ++logstats.lc_kset; #endif continue; #ifndef HUGE #undef r #endif case 'm': #ifdef DUMB if ((peekc = getchar()) == '\n') { setnoaddr(); peekc = 0; dumbf ^= 01; #ifdef LOG ++logstats.lc_magic; #endif if (curt) putsn(dumbf? off : on); else { puts2("\"$&[^.*\\(\\)\" have "); if (dumbf) puts2(no); putsn("special meaning"); } continue; } #endif if ((peekc = getchar()) == 'o') { /* mo == m */ peekc = 0; #ifdef LOG ++logstats.lc_moove; #endif } #ifdef LOG else ++logstats.lc_move; #endif move(0); text_modified++; continue; case 'n': setnoaddr(); #ifdef PIPE if ((peekc = getchar()) == '+') { peekc = 0; newline(); pno = 1; #ifdef LOG ++logstats.lc_numplus; #endif continue; } if (peekc == '-') { peekc = 0; newline(); pno = -1; #ifdef LOG ++logstats.lc_numinus; #endif continue; } #endif newline(); prompt1 ^= 01; #ifdef LOG ++logstats.lc_numbers; #endif if (curt) putsn(prompt1? on : off); else { if (prompt1 == 0) puts2(no); putsn("line numbers"); } continue; case '\n': if (globp || addr2 > dol) continue; if (addr2 == 0) { addr1 = addr2 = dot + 1; if (addr2 <= dol) line_num++; if (brcount != 1) { addr2 = dot + brcount; if (addr1 > dol) continue; if (addr2 > dol) addr2 = dol; if (addr2 < zero) addr2 = zero; #ifdef CLEAR if (zflg && addr2 - addr1 > pcount / 2) clear(); #endif } } if (addr2 <= dol) { pflag = 0; goto print; } continue; case 'l': listf++; #ifdef LOG ++logstats.lc_list; #endif case 'p': if ((peekc = getchar()) == 'a') { peekc = 0; case ':': case '*': num = 0; if (c == ':' || c == '*') { if ((peekc = getchar()) == ' ' || peekc == '\t') { skip_rest(); /* comments */ #ifdef LOG ++logstats.lc_comment; #endif continue; } r = peekc; peekc = 0; #ifdef LOG if (r == '-' || r == '+') ++logstats.lc_clnminus; else if (c == '*') ++logstats.lc_star; else ++logstats.lc_colon; #endif while (r == '-' || r == '^' || r == '+') { if (r == '+') ++num; else --num; r = getchar(); } peekc = r; } #ifdef LOG else if (c != 'p') ++logstats.lc_print; #endif newline(); pflag = 0; if (addr1 == addr2) { if (num == -1 && c == ':') { if (addr2 == 0) addr2 = dot; addr1 = addr2 - pcount; if (addr1 <= zero) addr1 = zero + 1; #ifdef CLEAR if (zflg) clear(); #endif goto print; } num *= pcount; if (c == '*') num -= (pcount + 1) / 2; if (addr1 == 0) a1 = dot + (num? num : 1); else a1 = addr1 + num; if (a1 <= zero) a1 = zero + 1; addr1 = addr2 = a1; } nonzero(); if (addr1 == addr2 || addr2 > dol || addr2 <= zero) addr2 = dol; setdot(); #ifdef CLEAR if (zflg && addr2 - addr1 > pcount / 2) clear(); #endif #ifndef PAGE if (addr2 > addr1 + pcount) addr2 = addr1 + pcount; goto print; #else page(); listf = 0; #ifdef PARENS parenf = 0; #endif #ifdef STRLEN quotef = 0; #endif continue; #endif } else if (peekc == 'p' || peekc == 'l') { peekc = 0; addr1 = zero + 1; addr2 = dol; #ifdef LOG ++logstats.lc_pprint; #endif } newline(); pflag = 0; print: setdot(); nonzero(); a1 = addr1; #ifdef PARENS parenc[0] = 0; parenc[1] = 0; parenc[2] = 0; #endif do { col = 0; printlno(line_num = a1 - zero); puts(getline(*a1++)); } while (a1 <= addr2); dot = addr2; listf = 0; #ifdef PARENS parenf = 0; #endif #ifdef STRLEN quotef = 0; #endif continue; case 'q': if ((peekc = getchar()) == 'i') { /* qi - immediate */ peekc = 0; newline(); immflg++; #ifdef LOG ++logstats.lc_qimm; #endif return; } #ifdef STRLEN if (peekc == '=') { /* q=cc set quote chars */ peekc = 0; if ((c = getchar()) == '\\') c = getchar(); quotec = quotec2 = c; #ifdef LOG ++logstats.lc_quote; #endif if (c != '\n') { if ((c = getchar()) == '\\') c = getchar(); if (c == '\n') continue; quotec2 = c; } else { quotec = 0; quotec2 = 0; continue; } if (c != '\n') newline(); continue; } #endif setnoaddr(); if ((peekc = getchar()) != '\n') errmsg(25); peekc = 0; #ifdef LOG ++logstats.lc_quit; #endif return; case 'r': #ifdef LOG ++logstats.lc_read; #endif caseread: filename(); if ((io = open(file, 0)) < 0) { io = 0; lastc = '\n'; if (curt) errmsg(53); puts2(errtext[53]); putsn(file); error(); } setall(); ninbuf = 0; r = append(getfile, addr2, 0, 0); if (prompt2) printf((curt? prcntu : errtext[55]), r, (r == 1? null : quote_s)); close(io); io = 0; #ifdef LOG logstats.lt_rlines += r; #endif if (num_reads++ || fflg) { if (r) text_modified++; } /* else text_modified = 0; */ if ((c == 'e' && bflg == 1) || bflg2 == 1) { bflg2 = 0; backup(BAK); } continue; case 's': if (!globp && (peekc = getchar()) == '\n') { /* w;q */ setnoaddr(); #ifdef LOG ++logstats.lc_stop; #endif if (text_modified && !fflg) if (backup(FILE) == 0) error(); /* errmsg(10) */ peekc = text_modified = 0; #ifdef LOG logstats.lt_wlines += dol - zero; #endif return; } if (peekc == 'a') { /* sa - count before auto-save */ setnoaddr(); peekc = 0; modcount = setnum(MODCNT); mods = 0; #ifdef LOG ++logstats.lc_savecount; #endif continue; } casesub: setdot(); nonzero(); substitute(globp); text_modified++; #ifdef LOG if (c == 's') ++logstats.lc_substitute; else ++logstats.lc_cslash; #endif continue; case 't': #ifdef TABS if ((peekc = getchar()) == '=') { /* t=c tab char */ setnoaddr(); peekc = 0; tabc = setchar(0); #ifdef LOG ++logstats.lc_tabchar; #endif continue; } else if (peekc == ',') { /* t,nn set tabs */ setnoaddr(); #ifdef LOG ++logstats.lc_tabset; #endif while ((c = getchar()) == ',') { while ((c = getchar()) == ','); if ((c < '0' || c > '9') && c != '-') break; peekc = c; settab(getsnum()); } peekc = c; newline(); continue; } else if (peekc == '\n') { /* list tabs */ setnoaddr(); peekc = 0; #ifdef LOG ++logstats.lc_tablist; #endif listabs(); continue; } #endif #ifdef LOG ++logstats.lc_transfer; #endif casecopy: move(1); text_modified++; continue; #ifdef UNDO case 'u': setnoaddr(); newline(); undo(); #ifdef LOG ++logstats.lc_undo; #endif continue; #endif case 'v': global(0); continue; case 'w': #ifdef PAGE if ((peekc = getchar()) == '=') { /* w= */ peekc = 0; ccount = setnum(CCOUNT); #ifdef LOG ++logstats.lc_width; #endif continue; } #endif if ((peekc = getchar()) == 'i') { /* wi over-ride */ ++immflg; peekc = 0; #ifdef LOG ++logstats.lc_wimm; #endif } #ifdef LOG else ++logstats.lc_write; #endif filename(); #ifdef LOG if (appflg) { --logstats.lc_write; ++logstats.lc_wonto; } #endif if (globp) { setdot(); appflg++; } else setall(); if (dol == zero) { if (curt) putsn("?48"); else putsn(errtext[48]); if (!fflg || appflg) continue; } if (over || immflg) override(); if (appflg) io = open(file, 1); if (!appflg || io < 0) io = creat(file, MODE); if (overfile) { chmod(overfile, overmode); overfile = 0; } if (io < 0) { io = 0; if (curt) errmsg(54); puts2(errtext[54]); putsn(file); error(); } io_w++; if (appflg) lseek(io, 0L, 2); /* append onto file */ putfile(); close(io); io = 0; io_w = 0; if (addr1 == zero + 1 && addr2 == dol) text_modified = 0; #ifdef LOG logstats.lt_wlines += dol - zero; #endif continue; #ifdef USE case '@': setnoaddr(); if (alt) errmsg(6); if ((peekc = getchar()) == 'p') peekc = 0; else eflg2++; if ((peekc = getchar()) == '\n' && altfile[0]) { peekc = 0; goto altname; } if ((c = getchar()) != ' ' && c != '\t' && c != ',') errmsg(5); white_space(); if ((c = getchar()) == '\n') errmsg(7); p = altfile; *p++ = c; while ((c = getchar()) != '\n') { if (c < 0) errmsg(59); *p++ = c; } *p = '\0'; altname: #ifdef LOG ++logstats.lc_at; #endif if ((alt = open(altfile, 0)) < 0) { alt = 0; /* this MUST be 0 */ lastc = '\n'; if (curt) errmsg(53); puts2(errtext[53]); putsn(altfile); error(); } continue; #endif #ifdef DEBUG case '#': /* toggle debug flag */ if (addr1 != addr2 || addr1 != zero) goto illcmd; newline(); tflg ^= 01; continue; #ifdef XDEL case '`': setnoaddr(); newline(); if (ndeleted == 0) errmsg(16); printf("deleted = %o ndeleted = %d\n", deleted, ndeleted); { register n, *bp, nl; int tl; tl = deleted; bp = getblock(tl, READ); #ifdef HUGE tl &= _1[hugef]; #else tl &= _1; #endif nl = nleft / sizeof(linep); for (n = 0; n < ndeleted; n++) { printf("%7d: %6o\n", n + 1, *bp++); if (--nl <= 0) { #ifdef HUGE bp = getblock(tl += _2[hugef], READ); #else bp = getblock(tl += _2, READ); #endif nl = nleft / sizeof(linep); } } } continue; #endif #endif #ifdef XDEL case 'x': newline(); r = undelete(); #ifdef LOG ++logstats.lc_xundelete; #endif if (prompt2) printf((curt? prcntu : errtext[55]), r, (r == 1? null : quote_s)); text_modified++; continue; #endif #ifdef YINT case 'y': if ((c = getchar()) == '+') { setdot(); nonzero(); newline(); if (zero == dol) yplus = 0; else yplus = *addr2 | 01; yflg = 1; #ifdef LOG ++logstats.lc_yplus; #endif } else if (c == '-') { setnoaddr(); newline(); yflg = 0; #ifdef LOG ++logstats.lc_yminus; #endif } else { setnoaddr(); peekc = c; newline(); yflg = 1; yplus = 0; #ifdef LOG ++logstats.lc_yintr; #endif } continue; #endif #ifdef PIPE case '|': #ifndef XED if (globp) /* turkeys will be turkeys */ errmsg(61); #endif if (noshell) errmsg(52); if ((peekc = getchar()) == '+') { peekc = 0; newline(); setnoaddr(); strict++; #ifdef LOG ++logstats.lc_piplus; #endif continue; } else if (peekc == '-') { peekc = 0; newline(); setnoaddr(); strict = 0; #ifdef LOG ++logstats.lc_piminus; #endif continue; } setdot(); shell(); continue; #endif case '!': #ifndef XED if (globp) errmsg(61); #endif if (noshell) errmsg(52); setnoaddr(); shell(); continue; #ifdef CKPT case 'z': newline(); setnoaddr(); checkpoint(0); /* doesn't return */ #endif case EOF: #ifdef USE if (!baseflg && alt) { close(alt); alt = 0; eflg2 = 0; continue; } #endif return; } illcmd: errmsg(8); } /* nothing lasts "for ever" */ } compile(aeof) charac aeof; { register charac eof, c; register char *ep, *lastep, *bracketp; register cclcnt; char bracket[NBRA]; ep = expbuf; lastep = 0; eof = aeof; bracketp = bracket; if ((c = getchar()) == eof || c == '\n') { if (*ep == 0) errmsg(27); if (c == '\n') peekc = c; return; } circfl = 0; nbra = 0; if ( #ifdef DUMB !dumbf && #endif c == '^') { c = getchar(); circfl++; #ifdef LOG ++logstats.lp_caret; #endif } /* if (c == '*') { /* if first = *, then quote it */ /* *ep++ = CCHR; */ /* *ep++ = c; */ /* c = 0; */ /* } */ peekc = c; for ever { if (ep >= &expbuf[ESIZE - 2 - (bracketp - bracket) * 2]) break; c = getchar(); if (c == eof || c == '\n') { while (bracketp > bracket) { *ep++ = CKET; *ep++ = *--bracketp; } *ep++ = CEOF; if (c == '\n') { if (prompt2) pflag++; peekc = c; } return; } if (c != '*') lastep = ep; #ifdef DUMB if (dumbf && c >= 0) goto defchar; #endif switch (c) { case '\\': if ((c = getchar()) == '(') { if (nbra >= NBRA) { c = 44; goto cerror; } *bracketp++ = nbra; *ep++ = CBRA; *ep++ = nbra++; #ifdef LOG ++logstats.lp_paren; #endif continue; } if (c == ')') { if (bracketp <= bracket) { c = 45; goto cerror; } *ep++ = CKET; *ep++ = *--bracketp; continue; } if ('1' <= c && c < '1' + nbra) { *ep++ = CBACK; *ep++ = c - '1'; #ifdef LOG ++logstats.lp_digit; #endif continue; } if (c == '\n') { c = 46; goto cerror; } defchar: default: *ep++ = CCHR; *ep++ = c; continue; case '.': *ep++ = CDOT; #ifdef LOG ++logstats.lp_dot; #endif continue; case '*': if (lastep == 0 || *lastep == CBRA || *lastep == CKET) goto defchar; *lastep |= STAR; #ifdef LOG ++logstats.lp_star; #endif continue; case '$': if ((peekc = getchar()) != eof && peekc != '\n') goto defchar; *ep++ = CDOL; #ifdef LOG ++logstats.lp_dol; #endif continue; case '[': *ep++ = CCL; *ep++ = 0; cclcnt = 1; if ((c = getchar()) == '^') { c = getchar(); ep[-2] = NCCL; #ifdef LOG ++logstats.lp_nccl; #endif } #ifdef LOG else ++logstats.lp_ccl; #endif do { if (c == '\\') c = getchar(); if (c == '\n') { peekc = c; break; } if (c < 0) { c = 59; goto cerror; } *ep++ = c; cclcnt++; if (ep >= &expbuf[ESIZE - 2]) { c = 49; goto cerror; } } while ((c = getchar()) != ']'); lastep[1] = cclcnt; continue; case EOF: c = 59; goto cerror; } } c = 42; cerror: expbuf[0] = '\0'; nbra = 0; errmsg(c); } compsub() { register charac seof, c; register char *p; if ((seof = getchar()) == '\n') errmsg(40); compile(seof); p = rhsbuf; for ever { c = getchar(); if (c < 0) errmsg(59); if (c == '\\') c = getchar() | 0200; if (c == '\n') { *p = 0; peekc = 0; if (prompt2) pflag++; return(0); } if (c == seof) break; *p++ = c; if (p >= &rhsbuf[LBSIZE / 2 - 2]) errmsg(41); } *p = '\0'; p = 0; if ((peekc = getchar()) == 'g') { /* if in 'glob' */ peekc = 0; p = 1; } else if ('0' <= peekc && peekc <= '9') if ((s_cnt = getnum()) < 0) s_cnt = 0; newline(); return(p); } create(as, am) char *as; { register savmask; register func savint, savqit; register ret; if (am == LMODE) { savint = signal(SIGINT, 1); savqit = signal(SIGQIT, 1); savmask = umask(LMASK); } ret = creat(as, am); if (am == LMODE) { umask(savmask); signal(SIGINT, savint); signal(SIGQIT, savqit); } return(ret); } delete() { register linep *a1, *a2, *a3; a1 = addr1; a2 = addr2 + 1; #ifdef XDEL if (!globp) saveline(); #endif a3 = dol; dol -= a2 - a1; do { *a1++ = *a2++; } while (a2 <= a3); a1 = addr1; if (a1 > dol) a1 = dol; dot = a1; } delexit(aretcode) { #ifdef LOG #include struct tms t; #endif unlink(tfname); #ifdef LOG if ((io = open(LOG, 1)) >= 0) { time(&logstats.lt_end); times(&t); logstats.lt_usercpu = t.tms_utime; logstats.lt_syscpu = t.tms_stime; logstats.lt_kidscpu = t.tms_cutime + t.tms_cstime; lseek(io, 0L, 2); write(io, &logstats, sizeof logstats); } #endif exit(aretcode); } dosub() { register char *lp, *sp, *rp; register charac c; lp = linebuf; sp = genbuf; rp = rhsbuf; while (lp < loc1) *sp++ = *lp++; while (c = *rp++) { #ifdef DUMB if (!dumbf) #endif if (c == '&') { #ifdef LOG ++logamp; #endif sp = place(sp, loc1, loc2); continue; } else if (c < 0 && (c &= 0177) >= '1' && c < nbra + '1') { c -= '1'; sp = place(sp,braslist[c],braelist[c]); continue; } *sp++ = c & 0177; #ifndef ALLOC if (sp >= &genbuf[LBSIZE - 2]) #else if (sp >= &genbuf[lbsize - 2]) #endif errmsg(42); } lp = loc2; loc2 = sp + (linebuf - genbuf); while (*sp++ = *lp++) #ifndef ALLOC if (sp >= &genbuf[LBSIZE - 2]) #else if (sp >= &genbuf[lbsize - 2]) #endif errmsg(43); lp = linebuf; sp = genbuf; while (*lp++ = *sp++); } #ifdef DEBUG dump() { register linep *i; register b, o; setdot(); nonzero(); newline(); line_num = addr1 - zero; for (i = addr1; i <= addr2; i++) { #ifdef HUGE b = (*i >> (8 - hugef)) & _3[hugef]; o = (*i << (1 + hugef)) & _4[hugef]; #else b = (*i >> 8) & _3; o = (*i << 1) & _4; #endif printlno(line_num++); #ifdef pdp11 printf("%6o:%7o%6d/%d\n", i, *i, b, o); #else printf("%6o:%7o%6d/%d\n", i, *i&(unsigned)(unsigned short)-1, b, o); #endif } dot = addr2; } #endif echo(ch) charac ch; { #ifdef AGAIN static charac lastchar; #endif #ifdef USE if (eflg || alt && !eflg2) #endif #ifndef USE if (eflg) #endif write(2, &ch, 1); #ifdef AGAIN if (!agf && agp) { /* save current command for "again" */ if (agp >= &agbuf[GBSIZE - 2]) agp = agbuf[0] = 0; else *agp++ = ch; if (ch == '\n' && lastchar != '\\') agp = *agp = 0; } lastchar = ch; #endif return(ch); } errfunc() { if (io) { close(io); io = 0; io_w = 0; } if (overfile) { chmod(overfile, overmode); overfile = 0; } #ifdef HELP if (doc) { close(doc); doc = 0; } #endif #ifdef PIPE if (pfile) { close(pfile); unlink(pfname); pfile = 0; } #endif /* puts("?"); */ if (!seekf) lseek(0, 0L, 2); pflag = 0; listf = 0; #ifdef PARENS parenf = 0; #endif #ifdef STRLEN quotef = 0; #endif if (globp) { lastc = '\n'; globp = 0; } peekc = lastc; skip_rest(); eflg2 = 0; reset(); } errmsg(n) { extern errno; listf = 0; #ifdef PARENS parenf = 0; #endif #ifdef STRLEN quotef = 0; #endif col = 0; if (n < 0) { puts2("\7******** "); printf("%d ", errno); n = -n; } if (curt) printf("?%d\n", n); else if (0 <= n && n < NERR) putsn(errtext[n]); else printf("bad error number: %d\n", n); error(); } execute(gf, addr) linep *addr; { register char *p1, *p2; register charac c; if (gf) { if (circfl) return(0); p1 = linebuf; p2 = genbuf; while (*p1++ = *p2++); locs = p1 = loc2; } else { if (addr == zero) return(0); p1 = getline(*addr); locs = 0; } p2 = expbuf; c = NBRA; while (--c >= 0) { braslist[c] = 0; braelist[c] = 0; } if (circfl) { loc1 = p1; return(advance(p1, p2)); } /* fast check for first character */ if (*p2 == CCHR) { c = p2[1]; do { if (*p1 != c) continue; if (advance(p1, p2)) { loc1 = p1; return(1); } } while (*p1++); return(0); } /* regular algorithm */ do { if (advance(p1, p2)) { loc1 = p1; return(1); } } while (*p1++); return(0); } #ifdef TABS exp() { register n; register linep p, *a1; setdot(); nonzero(); n = 0; for (a1 = addr1; a1 <= addr2; a1++) { getline(*a1); if (expand()) { n++; p = *a1; *a1 = putline(); savemark(p, *a1); } } dot = addr2; return(n); } expand() { register char *p2; register charac c; register n; register char *p1; register cnt, i; register flag tabflg; p1 = linebuf; p2 = genbuf; while (*p2++ = *p1++); p2 = linebuf; p1 = genbuf; cnt = col = n = 0; while (c = *p1++) { if (c == tabc && col < maxtab) { n = col; c = tabfill; if (c == '\t') { n = col; tabflg = 0; while (n < maxtab) { if ((++n & 07) == 0) { *p2++ = c; tabflg++; if (p2 >= #ifndef ALLOC &linebuf[LBSIZE - 2] #else &linebuf[lbsize - 2] #endif || n >= TABS * BPW) goto experr; } if (tabs[n >> BPWC] >> (n & BPWM) & 01) if (*p1 == tabc && n < maxtab) { p1++; cnt++; } else break; } i = n; if (tabflg) n &= 07; else n -= col; col = i; while (n--) { *p2++ = ' '; #ifndef ALLOC if (p2 >= &linebuf[LBSIZE - 2]) #else if (p2 >= &linebuf[lbsize - 2]) #endif goto experr; } cnt++; continue; } do { *p2++ = c; #ifndef ALLOC if (p2 >= &linebuf[LBSIZE - 2] #else if (p2 >= &linebuf[lbsize - 2] #endif || n >= TABS * BPW) goto experr; n++; } while (!(tabs[n >> BPWC] >> (n & BPWM) & 01)); col = n; cnt++; continue; } else if ('\0' < c && c < ' ') { switch (c) { case '\b': col -= 2; break; case '\t': col += 7 - (col & 07); break; case '\r': col = -1; break; default: col--; } } if (c) { *p2++ = c; col++; #ifndef ALLOC if (p2 >= &linebuf[LBSIZE - 2] || #else if (p2 >= &linebuf[lbsize - 2] || #endif col >= TABS * BPW) experr: errmsg(12); } } *p2++ = 0; return(cnt); } #endif #ifdef DEBUG #ifdef EXPDMP expdmp() { register n; register char *ep, **p; register flag star; signal(SIGQIT, expdmp); ep = expbuf; putchar('"'); if (circfl) putchar('^'); while (*ep) { n = 0; star = 0; switch (*ep++) { case CCHR | STAR: star++; case CCHR: putchar(*ep++); break; case CDOT | STAR: star++; case CDOT: putchar('.'); break; case CDOL: putchar('$'); break; case CEOF: putchar('"'); goto done; case NCCL | STAR: star++; case NCCL: n++; goto ccl; case CCL | STAR: star++; case CCL: ccl: putchar('['); if (n) putchar('^'); n = *ep++; while (--n) putchar(*ep++); putchar(']'); break; case CBRA: putchar('\\'); putchar('('); ep++; break; case CKET: putchar('\\'); putchar(')'); ep++; break; case CBACK | STAR: star++; case CBACK: putchar('\\'); putchar(*ep++ + '1'); break; default: putchar('?'); break; } if (star) putchar('*'); } done: putchar('\n'); if (reading) reset(); } #endif #endif filename() { register char *p1, *p2; register charac c; appflg = 0; c = getchar(); if (c < 0) errmsg(59); if (c == '\n') { noname: if (savedfile[0] == 0) errmsg(62); scopy(savedfile, file); return; } if (c != ' ' && c != '\t' && c != ',' && c != '>') errmsg(5); if (c != ',') peekc = c; white_space(); if ((c = getchar()) == '>') { while ((c = getchar()) == '>'); appflg++; if (c == '\n') goto noname; peekc = c; white_space(); c = getchar(); } if (c == '\n') errmsg(7); p1 = file; do { *p1++ = c; if (p1 >= &file[FNSIZE - 2]) errmsg(11); } while ((c = getchar()) != '\n'); *p1++ = 0; if (savedfile[0] == 0) scopy(file, savedfile); } linep * findmark(alp, adflt) linep alp, *adflt; { register linep *a, v; #ifdef HUGE register i; i = hugef ^ 01; #endif v = alp; for (a = zero + 1; a <= dol; a++) if (v == (*a | #ifdef HUGE i #else 1 #endif )) return(a); return(adflt); } flush_buf() { register n; if (n = linp - line) { linp = line; write(fout, line, n); } } #ifdef G_VFY gask(a1) linep *a1; { register charac c; col = 0; printlno(line_num = a1 - zero); puts(linebuf); puts2("Ok? "); flush_buf(); if ((c = getchar()) < 0) { putchar('\n'); return(-1); } if (c == '\n') return(1); skip_rest(); return(c != 'n'); } #endif char * getblock(atl, iof) { extern read(), write(); register bno, off; register linep *a; #ifdef HUGE register flag c; register func savint; bno = (atl >> (8 - hugef)) & _3[hugef]; off = (atl << (1 + hugef)) & _4[hugef]; #else bno = (atl >> 8) & _3; off = (atl << 1) & _4; #endif if (bno >= #ifdef HUGE _5[hugef] #else _5 #endif ) { #ifdef HUGE if (!hugef && !globp) { /* let's try converting to huge */ if (!curt) { putsn("File too large for normal editing."); puts2("Conversion to \"huge\" mode disallows "); puts2("use of the global command."); } c = yes_no(curt? "?huge" : "Do you wish to convert", 1, 0, 0); if (c) { savint = signal(SIGINT, 1); for (a = zero + 1; a <= dol; a++) *a = ((unsigned)*a) >> 1; hugef++; hugef2++; /* conversion occurred */ atl = (atl >> 1) & _6[hugef]; #ifdef XDEL ndeleted = 0; /* useless pointers */ deleted = 0; #endif signal(SIGINT, savint); goto huger; } } #endif errmsg(34); } #ifdef HUGE huger: #endif nleft = BLKSIZE - off; if (bno == iblock && !badf) { ichanged |= iof; return(ibuff + off); } if (bno == oblock) return(obuff + off); if (iof == READ) { if (ichanged) { blkio(iblock, ibuff, write); ichanged = 0; } iblock = bno; blkio(bno, ibuff, read); return(ibuff + off); } if (oblock >= 0) blkio(oblock, obuff, write); oblock = bno; return(obuff + off); } charac getchar() { flush_buf(); eof = 0; if (lastc = peekc) { peekc = 0; return(lastc); } if (globp) { if (lastc = *globp++) { if (globf2 && *globp == 0) globp = globf2 = 0; return(lastc); } globp = 0; return(EOF); } #ifdef AGAIN if (agf #ifdef USE && !alt #endif ) { /* "again" stuff */ if (lastc = *agp++) return(lastc); agf = agp = 0; } #endif reading++; #ifdef USE if (read(alt, &lastc, 1) <= 0) { #endif #ifndef USE if (read(0, &lastc, 1) <= 0) { #endif reading = 0; eof++; return(lastc = EOF); } reading = 0; lastc &= 0177; #ifdef APLMAP if (aplmap && lastc > ' ') lastc = map_ascii[lastc - (' ' + 1)]; #endif #ifdef EOL if (lastc == '\n') prompt3 = 1; else if (eol && lastc == eol) { lastc = '\n'; prompt3 = 0; } #endif #ifdef CMDS if (cmd) write(cmd, &lastc, 1); #endif eof = 0; return(echo(lastc)); } getcopy() { if (addr1 > addr2) return(EOF); getline(*addr1++); return(0); } getfile() { register charac c; register char *lp, *fp; lp = linebuf; fp = nextip; do { if (--ninbuf < 0) { #ifndef ALLOC if ((ninbuf = read(io, genbuf, LBSIZE) - 1) < 0) #else if ((ninbuf = read(io, genbuf, lbsize) - 1) < 0) #endif if (lp == linebuf) return(EOF); else { lp++; break; } fp = genbuf; } #ifndef ALLOC if (lp >= &linebuf[LBSIZE - 2] && (*fp & 0177) != '\n') { #else if (lp >= &linebuf[lbsize - 2] && (*fp & 0177) != '\n') { #endif printf((curt? "?long%u\n" : "line %u in file too long\n"), dot - zero + 1); flush_buf(); lp++; ninbuf++; break; } if ((*lp++ = c = *fp++ & 0177) == 0) { lp--; continue; } } while (c != '\n'); *--lp = 0; nextip = fp; return(0); } getline(tl) { register char *bp, *lp; register nl; #ifdef DEBUG if (tflg) printf("getline:\t%o\n", tl); #endif lp = linebuf; bp = getblock(tl, READ); #ifdef HUGE if (hugef2) { hugef2 = 0; tl = (tl >> 1) & _6[hugef]; } tl &= _1[hugef]; #else tl &= _1; #endif nl = nleft; while (*lp++ = *bp++) if (--nl <= 0) { #ifdef HUGE bp = getblock(tl += _2[hugef], READ); #else bp = getblock(tl += _2, READ); #endif nl = nleft; } return(linebuf); } getnum() { register n; register charac c; n = 0; while ('0' <= (c = getchar()) && c <= '9') n = n * 10 + c - '0'; peekc = c; return(n); } getsnum() { register sign; if (sign = (peekc = getchar()) == '-') peekc = 0; return(sign? -getnum() : getnum()); } getsub() { register char *p1, *p2; p1 = linebuf; if ((p2 = linebp) == 0) return(EOF); while (*p1++ = *p2++); linebp = 0; return(0); } gettty(single) { register charac c; register char *p, *gf; #ifdef TABS int tabf; tabf = 0; #endif p = linebuf; gf = globp; #ifdef EOL if (prompt2 && prompt3 && !single) { #endif #ifndef EOL if (prompt2 && !single) { #endif printlno(line_num); flush_buf(); } line_num++; while ((c = getchar()) != '\n') { if (c < 0) { if (gf) peekc = c; else if (prompt2 && (prompt1 || !zflg)) putchar('\n'); if (p > linebuf) break; return(c); } if ((c &= 0177) == 0) continue; #ifdef TABS if (tabc && c == tabc) tabf++; #endif *p++ = c; #ifndef ALLOC if (p >= &linebuf[LBSIZE - 2]) #else if (p >= &linebuf[lbsize - 2]) #endif errmsg(30); } *p++ = 0; #ifdef TABS if (tabf) expand(); #endif if (!single && linebuf[0] == '.' && linebuf[1] == 0) return(EOF); return(0); } global(k) { register char *gp; register charac c; register linep *a1; register flag globpf; char globuf[GBSIZE]; #ifdef HUGE if (hugef) errmsg(10); #endif if (globp) errmsg(37); setall(); nonzero(); if ((c = getchar()) == '\n') peekc = c; compile(c); #ifdef G_VFY gaskf = 0; if ((peekc = getchar()) == 'v') { gaskf++; peekc = 0; } #endif globpf = pflag; if (peekc == '\n') globpf = 0; pflag = 0; gp = globuf; if ((peekc = getchar()) < 0) errmsg(59); if (peekc == '\n') { *gp++ = 'p'; peekc = 0; } else while ((c = getchar()) != '\n') { if (c == '\\') { c = getchar(); if (c != '\n') *gp++ = '\\'; } if (c < 0) errmsg(59); *gp++ = c; if (gp >= &globuf[GBSIZE - 2]) errmsg(38); } *gp++ = '\n'; *gp = 0; c = 0; #ifdef LOG #ifdef G_VFY if (gaskf) ++logstats.lc_gvfy; #endif if (k) ++logstats.lc_global; else ++logstats.lc_vglobal; #endif for (a1 = zero + 1; a1 <= dol; a1++) { *a1 &= ~01; s_tmp = 0; if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k) #ifdef G_VFY if (!gaskf || (c = gask(a1))) if (c < 0) addr2 = a1; else #endif *a1 |= 01; } for (a1 = zero + 1; a1 <= dol; a1++) if (*a1 & 01) { *a1 &= ~01; dot = a1; globp = globuf; pflag = globpf; commands(1); a1 = zero; } } hangup() { signal(SIGHUP, 1); if (reading) { backup(HUP); if (fout != 1) { flush_buf(); fout = 1; } puts2(errtext[57]); delexit(1); } hupflag++; } header() { register colnum, number; register flag lf; number = 0; if ((peekc = getchar()) != '\n') { white_space(); number = getnum(); } if (!number) number = ccount - (prompt1? 8 : 0); newline(); if (zero != dol) dot = addr2; lf = listf; listf = 0; if (prompt1) putchar('\t'); for (colnum = 0; colnum < number / 10; colnum++) printf("%10d", colnum + 1); putchar('\n'); if (prompt1) putchar('\t'); for (colnum = 1; colnum <= number; colnum++) #ifdef TABS if (colnum < (TABS << BPWC) && (tabs[(colnum - 1) >> BPWC] >> ((colnum - 1) & BPWM) & 01)) putchar('-'); else #endif putchar(colnum % 10 + '0'); putchar('\n'); listf = lf; } init() { register n; register char *p; if (tfile > 0) close(tfile); if (io) { close(io); io = 0; io_w = 0; } #ifdef HELP if (doc) { close(doc); doc = 0; } #endif #ifdef USE if (alt) { close(alt); alt = 0; eflg2 = 0; } #endif #ifdef PIPE if (pfile) { close(pfile); unlink(pfname); pfile = 0; } #endif tline = 0; #ifdef XDEL deleted = 0; ndeleted = 0; #endif num_reads = 0; text_modified = 0; #ifdef YINT yplus = 0; #endif #ifdef UNDO undo_oldp = 0; undo_newp = 0; #endif #ifdef V7 if (overfile) { chmod(overfile, overmode); overfile = 0; } #endif iblock = oblock = -1; badf = 0; ichanged = 0; if ((n = create(tfname, LMODE)) < 0) { putsn(errtext[50]); exit(1); } close(n); if ((tfile = open(tfname, 2)) < 0) { putsn(errtext[36]); exit(1); } addr1 = addr2 = dot = dotdot = lastdot = zero = dol = fendcore; endcore = fendcore - 2; brk(fendcore); n = 26; while (--n >= 0) { /* kill marks */ names[n] = 0; #ifdef EXTMARK names2[n] = 0; #endif } p = globp; globp = 0; if (chk()) { if ((io = open(file, 0)) < 0) { io = 0; lastc = '\n'; if (curt) putsn("?53"); else { puts2(errtext[53]); putsn(file); } flush_buf(); } else { n = append(getfile, addr1, 0, 0); if (prompt2) printf((curt? prcntu : errtext[55]), n, (n == 1? null : quote_s)); if (n) { num_reads++; text_modified++; } if (io) { close(io); io = 0; io_w = 0; } } return(1); } globp = p; return(0); } istty(fd) { register r; short buf[3]; /* naughty int's */ buf[2] = BS1; r = 0; if (gtty(fd, buf) >= 0) ++r; #ifdef CLEAR zflg = (buf[2] & BS1) == 0; #endif if (pipef #ifdef V7 || getenv("_NO_STDIO_BUF") #endif ) ++r; return(r); } #ifdef XED join() { register linep *a1; register char *p1, *p2; register charac c, ceof; setdot(); nonzero(); if (addr1 == addr2) --addr1; if (addr1 <= zero) errmsg(60); p2 = rhsbuf; if ((c = peekc = getchar()) < 0) errmsg(59); ceof = 0; if (peekc != '\n' && peekc != 'p' && peekc != 'l' #ifdef PARENS && peekc != 'b' #endif #ifdef STRLEN && peekc != 'q' #endif ) { ceof = peekc; peekc = 0; while ((c = getchar()) != ceof && c != '\n') { if (c < 0) errmsg(59); if (c == '\\') if ((c = getchar()) == '\n') errmsg(46); *p2++ = c; if (p2 >= &rhsbuf[LBSIZE / 2 - 2]) errmsg(42); } if (c != '\n') c = '\0'; else if (prompt2) pflag++; if (p2 != rhsbuf) *p2 = '\0'; if (*rhsbuf == 0) errmsg(27); #ifdef LOG ++logstats.lc_jglue; #endif } #ifdef LOG else ++logstats.lc_join; #endif peekc = c; newline(); p1 = rhsbuf; while (*p1) if (*p1++ == '\n') errmsg(46); p2 = genbuf; a1 = addr1; while (a1 <= addr2) { p1 = getline(*a1++); while (*p2++ = *p1++) #ifndef ALLOC if (p2 >= &genbuf[LBSIZE - 2]) #else if (p2 >= &genbuf[lbsize - 2]) #endif errmsg(12); --p2; if (ceof && a1 <= addr2) { p1 = rhsbuf; while (*p2++ = *p1++) #ifndef ALLOC if (p2 >= &genbuf[LBSIZE - 2]) #else if (p2 >= &genbuf[lbsize - 2]) #endif errmsg(12); --p2; } } *p2 = '\0'; p1 = genbuf; p2 = linebuf; while (*p2++ = *p1++); a1 = putline(); savemark(*addr1, a1); *addr1++ = a1; delete(); dot = --addr1; if (dot > dol) dot = dol; } #endif #ifdef TABS listabs() { register n; if (maxtab < 0) errmsg(9); n = next_tab(-1); printf("tabs: %d", n + 1); while ((n = next_tab(n)) >= 0) printf(",%d", n + 1); putchar('\n'); } #endif mail() { delexit(1); } move(cflag) { extern getcopy(); register linep *adt, *ad1, *ad2; setdot(); nonzero(); if ((adt = address()) == 0) errmsg(31); ad1 = addr1; ad2 = addr2; newline(); if (cflag) { ad1 = dol; append(getcopy, ad1++, 0, 0); ad2 = dol; } ad2++; if (adt < ad1) { dot = adt + (ad2 - ad1); if (++adt == ad1) return; reverse(adt, ad1); reverse(ad1, ad2); reverse(adt, ad2); } else if (adt >= ad2) { dot = adt++; reverse(ad1, ad2); reverse(ad2, adt); reverse(ad1, adt); } else errmsg(28); } newline() { register charac c; if ((c = getchar()) == '\n') return; if (c == 'p' || c == 'l' #ifdef PARENS || c == 'b' #endif #ifdef STRLEN || c == 'q' #endif ) { pflag++; if (c == 'l') listf++; #ifdef PARENS else if (c == 'b') parenf++; #endif #ifdef STRLEN else if (c == 'q') quotef++; #endif if (getchar() == '\n') return; } errmsg(25); } #ifdef TABS next_tab(acol) { register n; if ((n = acol) < maxtab) { do { n++; } while (!(tabs[n >> BPWC] >> (n & BPWM) & 01)); return(n); } return(-1); } #endif nonzero() { if (addr1 <= zero) errmsg(23); if (addr2 > dol) errmsg(24); } #ifdef PIPE oil_spilled() { if (!iflg) { signal(SIGINT, 1); signal(SIGQIT, 1); } signal(SIGPIP, 1); piperr++; } #endif onintr() { register char *p1, *p2; signal(SIGINT, onintr); #ifdef USE if (alt) { close(alt); alt = 0; eflg2 = 0; } #endif if (io) { if (curt) putsn("?intI/O"); else { puts2("\7Interrupted I/O!!!\7\nWarning: \""); puts2(file); if (io_w) { putsn("\" is probably truncated."); puts2("You should probably re-write it."); } else { putsn("\" was not read entirely."); puts2("If you write the buffer, "); puts2("part of the file may be lost."); } } flush_buf(); } #ifdef EOL prompt3 = 1; #endif if (fout != 1) { close(fout); fout = 1; } #ifdef YINT if (!globp && reading && yflg) { globp = ".:\n"; if (yplus) { dot = findmark(yplus, 0); } else globp++; peekc = 0; putchar('\n'); commands(1); reset(); } #endif if (iflg) { signal(SIGINT, 1); backup(INT); delexit(1); } putchar(lastc = '\n'); errmsg(29); } override() { struct stat s; if (access(file, 02) < 0) { if (stat(file, &s) >= 0 && (s.st_mode & S_IFMT) == S_IFREG) { overmode = s.st_mode & 07777; if (chmod(file, overmode) < 0) return; if (immflg == 0) { if (curt) { puts2("?\""); puts2(file); puts2("\" "); } else { puts2("The file \""); puts2(file); puts2("\" is write-protected."); } if (yes_no(curt? "override" : "Do you wish to over-ride the permission", 0, 1, 1)) return; } overfile = file; if (chmod(overfile, overmode | 0200) < 0) overfile = 0; else { putsn("[over-riding]"); #ifdef LOG ++logstats.lm_overwrite; #endif } } } } #ifdef PAGE page() { register cl, n; register char *p, *pp; register linep *a, *b; register l; a = addr1; if (addr2 != addr1) b = addr2; else b = dol; #ifdef PARENS parenc[0] = 0; parenc[1] = 0; parenc[2] = 0; #endif for (n = pcount; n >= 0 && a <= b; n--) { pp = p = getline(*a); cl = prompt1? 8 : 0; l = 0; while (*p) { if (*p < ' ' || *p > '~') switch (*p) { case '\b': if (listf) cl++; else { cl--; if (aflg #ifdef PARENS && !parenf #endif #ifdef STRLEN && !quotef #endif ) l++; } break; case '\t': if (listf) cl++; else cl += 8 - cl % 8; break; case '\r': if (listf) cl += 2; else cl = 0; break; case ctrl('L'): /* ADM-3A's */ if (listf) cl++; cl++; break; default: if (listf || zflg) cl += 2; } else cl++; #ifdef PARENS if (parenf && paren(*p)) l++; #endif #ifdef STRLEN /* if (quotef && (*p == '"' || *p == '\'')) */ if (quotef && (quotec? *p == quotec : *p == '"' || *p == '\'')) l++; #endif if (cl < 0) cl = 0; else if (cl > ccount) { cl = 0; if (--n < 0) goto done; } p++; } if (l) if (--n < 0) goto done; col = 0; printlno(line_num = a - zero); puts(pp); a++; } done: dot = a - 1; } #endif #ifdef PARENS paren(ac) { switch (ac) { case '(': return(1); case '[': return(2); case '{': return(3); case ')': return(-1); case ']': return(-2); case '}': return(-3); } return(0); } #endif place(asp, al1, al2) { register char *sp, *l1, *l2; sp = asp; l1 = al1; l2 = al2; while (l1 < l2) { *sp++ = *l1++; #ifndef ALLOC if (sp >= &genbuf[LBSIZE - 2]) #else if (sp >= &genbuf[lbsize - 2]) #endif errmsg(42); } return(sp); } /*VARARGS*/ printf(as, aarglist) char *as; { register *args, w; register char *q; register flag f; args = &aarglist; while (*as) { if (*as != '%') { putchar(*as++); continue; } if (*++as == '\0') return; w = 0; /* no default width */ f = 0; /* unsigned default */ while ('0' <= *as && *as <= '9') w = w * 10 + *as++ - '0'; if (*as == '\0') return; switch (*as++) { case 'c': /* char */ putchar(*args++); continue; case 'd': /* signed decimal */ f = 1; /* signed */ case 'u': /* unsigned decimal */ printfn(*args++, 10, f, w); continue; case 'o': /* unsigned octal */ printfn(*args++, 8, 0, w); continue; case 's': /* string */ q = *args++; while (*q) { putchar(*q++); --w; } while (--w > 0) putchar(' '); continue; default: putchar(as[-1]); continue; } } } printfn(an, ab, af, aw) { register w; register unsigned n; register char *p; char buf[(sizeof(int) != 2? 10 : 6) + 2]; w = aw; p = &buf[sizeof buf]; *--p = '\0'; n = an; if (af) if (an < 0) n = -an; else af = 0; do { *--p = n % ab + '0'; --w; } while (n /= ab); if (af) { *--p = '-'; --w; } while (--w >= 0) putchar(' '); while (*p) putchar(*p++); } printlno(an) { register flag l; if (prompt1) { l = listf; listf = 0; printf(fmtlno, an - aflg); col = 8; listf = l; } } printmarks() { register linep *a1; register charac c; register n, i; #ifdef HUGE i = hugef ^ 01; #endif for (c = 'a' - 'a'; c <= 'z' - 'a'; c++) { if (names[c] == 0) /* zap marks to deleted lines */ continue; n = 0; for (a1 = zero + 1; a1 <= dol; a1++) if (names[c] == (*a1 | #ifdef HUGE i #else 01 #endif )) { n++; printf("%c=%u", c + 'a', a1 - zero); #ifdef EXTMARK if (names2[c]) { for (a1++; a1 <= dol; a1++) if (names2[c] == (*a1 | 01)) { printf(",%u", a1 - zero); break; } } #endif putchar(' '); break; } if (n == 0) names[c] = 0; /* clear unknown marks */ } putchar('\n'); } putchar(ac) charac ac; { register char *lp; register charac c; lp = linp; c = ac; #ifdef APLMAP if (aplmap && fout == 1 && c > ' ') c = map_apl[c - (' ' + 1)]; #endif if (listf) { if (++col >= ccount - 1) { col = 1; if (c != '\n') { *lp++ = '\\'; *lp++ = '\n'; } } if (c == '\t') { c = '>'; goto esc; } if (c == '\b') { c = '<'; esc: *lp++ = '-'; *lp++ = '\b'; *lp++ = c; goto out; } if (c < ' ' && c != '\n' || c == 0177) { *lp++ = '^'; *lp++ = c ^ 0100; col++; goto out; } } *lp++ = c; out: if (lp >= &line[TTSIZE]) { linp = line; write(fout, line, lp - line); return; } linp = lp; } putfile() { register char *fp, *lp; register nib; register linep *a1; nib = BLKSIZE; fp = genbuf; a1 = addr1; do { lp = getline(*a1++); for ever { if (--nib < 0) { wte(io, genbuf, fp - genbuf); nib = BLKSIZE - 1; fp = genbuf; } if ((*fp++ = *lp++) == 0) { fp[-1] = '\n'; break; } } } while (a1 <= addr2); wte(io, genbuf, fp - genbuf); } putline() { register char *bp, *lp; register nl, tl; lp = linebuf; tl = tline; #ifdef DEBUG if (tflg) printf("putline:\t%o\n", tl); #endif bp = getblock(tl, WRITE); #ifdef HUGE if (hugef2) { hugef2 = 0; tl = tline = (tline >> 1) & _6[hugef]; } tl &= _1[hugef]; #else tl &= _1; #endif nl = nleft; while (*bp = *lp++) { if (*bp++ == '\n') { *--bp = 0; linebp = lp; break; } if (--nl <= 0) { #ifdef HUGE bp = getblock(tl += _2[hugef], WRITE); #else bp = getblock(tl += _2, WRITE); #endif nl = nleft; } } nl = tline; #ifdef HUGE tline += (((lp - linebuf) + 03) >> (1 + hugef)) & _6[hugef]; #else tline += (((lp - linebuf) + 03) >> 1) & _6; #endif return(nl); } #ifdef PARENS putparen(an) { register c; an %= 10 + 26 + 26; if (an < 0) an += 10 + 26 + 26; c = '0'; if (an > 9 + 26) c = 'a' - (10 + 26); else if (an > 9) c = 'A' - 10; putchar(c + an); } #endif puts(as) { register n; register flag ovp; register char *sp, *s; sp = as; ovp = 0; while (*sp) { if (aflg && #ifdef PARENS !parenf && #endif #ifdef STRLEN !quotef && #endif !listf && *sp == '\b') { ovp = 1; sp += 2; continue; } #ifdef PARENS if (!ovp && parenf && !listf && paren(*sp)) ovp = 1; #endif #ifdef STRLEN /* if (!ovp && quotef && !listf && (*sp == '"' || *sp == '\'')) */ if (!ovp && quotef && !listf && ( quotec? *sp == quotec : *sp == '"' || *sp == '\'')) ovp = 1; #endif putchar(*sp++); } sp = as; if (aflg && ovp && #ifdef PARENS !parenf && #endif #ifdef STRLEN !quotef && #endif !listf) { putchar('\n'); if (prompt1) putchar('\t'); for (; *sp; sp++) if (sp[1] == '\b' && sp[2]) { putchar(sp[2]); sp += 2; } else if (*sp == '\t') putchar('\t'); else if (*sp >= ' ') putchar(' '); ovp = 0; } #ifdef PARENS if (parenf && ovp && !listf) { putchar('\n'); if (prompt1) putchar('\t'); for (; *sp; sp++) if (n = paren(*sp)) { if (n < 0) { n = -n - 1; putparen(parenc[n]--); } else putparen(++parenc[--n]); } else if (*sp == '\t' || *sp >= ' ') putchar(*sp == '\t'? '\t' : ' '); ovp = 0; } #endif #ifdef STRLEN if (quotef && ovp && !listf) { s = null; n = 0; ovp = 0; putchar('\n'); if (prompt1) putchar('\t'); for (; *sp; sp++) { /* if (n == 0 && (*sp == '"' || *sp == '\'') || */ if (n == 0 && (quotec? *sp == (ovp? quotec : quotec2) : *sp == '"' || *sp == '\'') || *sp == n) { if (ovp) { ovp = 0; goto not; } if (n) n = 0; else { s = sp++; n = 0; while (*sp && *sp != *s) { if (*sp == '\\') { if ('0' <= *++sp && *sp <= '7') { if ('0' <= *++sp && *sp <= '7') if ('0' <= *++sp && *sp <= '7') sp++; } else sp++; } else sp++; n++; } sp = s; s = &"00000"[5]; do { *--s = n % 10 + '0'; } while (n /= 10); n = *sp; } } not: if (*s) putchar(*s++); else putchar(*sp == '\t'? '\t' : ' '); if (*sp == '\\') ovp ^= 01; } ovp = 0; } #endif putchar('\n'); } puts2(as) { register char *sp; sp = as; while (*sp) putchar(*sp++); } #ifdef CKPT recover() { extern etext; register filedes f; register char *p; register func savint, savqit; int n; savint = signal(SIGINT, 1); savqit = signal(SIGQIT, 1); if ((f = open(cfname, 0)) < 0 || read(f, &n, sizeof n) != sizeof n) { n = 67; goto cerror; } p = &etext; if (brk(p + n) == -1) { n = 67; goto cerror; } #ifdef pdp11 /* 16 bit byte count only */ if (n < 0) { if (read(f, p, 32256) != 32256) { n = 67; goto cerror; } n -= 32256; /* 63 blocks, since 64 is < 0 */ p += 32256; } #endif if (read(f, p, n) != n || (tfile = open(tfname, 2)) < 0) n = 67; else n = 0; recovry = 1; /* overwritten by reading data space */ cerror: if (n) { puts(errtext[n]); exit(1); } if (f > 0) close(f); /* * "initialize" special stuff to restore order */ globp = 0; io = 0; io_w = 0; #ifdef HELP doc = 0; #endif #ifdef USE alt = 0; #endif #ifdef AGAIN agf = 0; agp = 0; #endif #ifdef EOL prompt3 = 1; #endif #ifdef PIPE if (pfile) { unlink(pfname); pfile = 0; } #endif signal(SIGINT, savint); signal(SIGQIT, savqit); } #endif reverse(aa1, aa2) { register linep *a1, *a2, t; a1 = aa1; a2 = aa2; for ever { t = *--a2; if (a2 <= a1) return; *a2 = *a1; *a1++ = t; } } #ifdef XDEL saveline() { register linep *a1, *a2, *bp; register nl, tl; a1 = addr1; a2 = addr2; ndeleted = a2 - a1 + 1; tl = tline; #ifdef DEBUG if (tflg) printf("saveline:\t%o\n", tl); #endif bp = getblock(tl, WRITE); #ifdef HUGE if (hugef2) { hugef2 = 0; tl = (tl >> 1) & _6[hugef]; } tl &= _1[hugef]; #else tl &= _1; #endif nl = nleft / sizeof(linep); while (a1 <= a2) { *bp++ = *a1++; if (--nl <= 0) { #ifdef HUGE bp = getblock(tl += _2[hugef], WRITE); if (hugef2) { hugef2 = 0; tl = (tl >> 1) & _6[hugef]; } #else bp = getblock(tl += _2, WRITE); #endif nl = nleft / sizeof(linep); } } deleted = tline; #ifdef HUGE tline += ((a2 - addr1 + 1) << (1 - hugef)) & _6[hugef]; #else tline += ((a2 - addr1 + 1) << 1) & _6; #endif } #endif savemark(p1, p2) linep p1, p2; { register n; #ifdef HUGE register i; i = hugef ^ 01; p1 |= i; p2 |= i; #else p1 |= 01; p2 |= 01; #endif /* save "marks" on lines so marked */ for (n = 0; n <= 'z' - 'a'; n++) { if (names[n] == 0) /* zap marks to deleted lines */ continue; if (names[n] == p1) names[n] = p2; #ifdef EXTMARK if (names2[n] && names2[n] == p1) names2[n] = p2; #endif } #ifdef YINT /* don't lose "y+" line either */ if (yplus == p1) yplus = p2; #endif #ifdef UNDO /* and remember the line for "undo" */ undo_oldp = p1; undo_newp = p2; #endif } scopy(ass, ads) char *ass, *ads; { register char *p, *q; p = ass; q = ads; while (*q++ = *p++) ; return(ads); } setall() { if (addr2 == 0) { addr1 = zero + (zero != dol); addr2 = dol; } setdot(); } setchar(adflt) { register charac c; if ((c = getchar()) == '\\') c = getchar(); if (c < 0) errmsg(59); if (c == '\n') return(adflt); newline(); return(c); } setdot() { if (addr2 == 0) addr1 = addr2 = dot; if (addr1 > addr2) errmsg(21); } setnoaddr() { if (addr2) errmsg(22); } setnum(adflt) { register n; white_space(); n = adflt; if ('0' <= (peekc = getchar()) && peekc <= '9') n = getnum(); newline(); return(n); } #ifdef TABS settab(acs) { register *p, i, n; if (acs == 0) { maxtab = -1; n = TABS; p = tabs; while (--n >= 0) *p++ = 0; return; } i = 0; if (acs < 0) { acs = -acs; i++; } if (--acs < TABS * BPW) { p = &tabs[acs >> BPWC]; *p |= 01 << (n = acs & BPWM); if (i) { *p ^= 01 << n; if (acs == maxtab) { /* find new maxtab */ for (n = TABS - 1; n >= 0; --n) if (tabs[n >> BPWC] >> (n & BPWM) & 01) break; maxtab = n; } } else if (acs > maxtab) maxtab = acs; } } #endif shell() { #ifdef PIPE extern oil_spilled(); #endif register pid, wpid; register linep *a; register dp, df, nopipe, c, e, savint, savqit; register linep *dest; int retcode, p[2]; #ifdef PIPE dp = 0; df = 0; if (addr2) { #ifdef LOG ++logstats.lc_pipe; #endif dest = 0; nopipe = 0; if ((peekc = getchar()) == '|') { nonzero(); peekc = 0; dp++; df++; #ifdef LOG --logstats.lc_pipe; ++logstats.lc_dpipe; #endif } if ((peekc = getchar()) == '>') { nonzero(); #ifdef LOG --logstats.lc_pipe; ++logstats.lc_pto; #endif goto pi; } else if ((peekc = getchar()) == '<') { nopipe++; #ifdef LOG --logstats.lc_pipe; ++logstats.lc_pfrom; #endif pi: peekc = 0; dp++; dest = addr2; } if (dp && '0' <= (peekc = getchar()) && peekc <= '9') { c = getnum(); dest = zero + c; if (dest < zero) dest = zero + 1; if (dest > dol) dest = dol; } } #ifdef LOG else ++logstats.lc_shell; #endif piperr = 0; if (!iflg) if (addr2) { savint = signal(SIGINT, oil_spilled); savqit = signal(SIGQIT, oil_spilled); } else { #endif savint = signal(SIGINT, 1); savqit = signal(SIGQIT, 1); #ifdef PIPE } if (addr2 && pipe(p) < 0) { c = 15; errm: if (!iflg) { signal(SIGINT, savint); signal(SIGQIT, savqit); } if (c) errmsg(c); error(); } if (dp) { if ((pfile = create(pfname, LMODE)) < 0) { pfile = 0; c = 64; goto errm; } if ((io = open(pfname, 0)) < 0) { io = 0; c = 65; goto errm; } } #endif if ((pid = fork()) < 0) { #ifdef PIPE if (addr2) { close(p[0]); close(p[1]); } #endif c = 14; goto errm; } if (pid == 0) { /* kid */ if (!iflg) { /* kid */ signal(SIGHUP, 0); /* kid */ signal(SIGINT, 0); /* kid */ signal(SIGQIT, 0); /* kid */ } #ifdef PIPE /* kid */ if (addr2) { /* kid */ close(0); /* kid */ dup(p[0]); /* kid */ close(p[0]); /* kid */ close(p[1]); /* kid */ if (dp) { /* kid */ close(1); /* kid */ dup(pfile); /* kid */ close(pfile); /* kid */ } /* kid */ } #endif /* kid */ execl("/bin/sh", "!sh", "-t", 0); /* kid */ write(2, "No shell!\n", 10); /* kid */ exit(0177); } #ifdef CMDS if (cmd && !addr2) write(cmd, "\n", 7); #endif #ifdef PIPE if (addr2) { signal(SIGPIP, oil_spilled); close(p[0]); e = eflg2; eflg2++; fout = p[1]; while ((c = getchar()) >= 0 && c != '\n') putchar(c); putchar('\n'); if (!nopipe) { line_num = (a = addr1) - zero - aflg; do { if (pno >= 0) printlno(line_num++); puts(getline(*a++)); } while (a <= addr2 && !piperr); } flush_buf(); fout = 1; eflg2 = e; close(p[1]); if (!iflg) { signal(SIGINT, 1); signal(SIGQIT, 1); } } #endif while ((wpid = wait(&retcode)) != pid && wpid >= 0); #ifdef CMDS if (cmd) lseek(cmd, 0L, 2); #endif #ifdef PIPE if (addr2) signal(SIGPIP, 0); #endif if (c = retcode & 0177) { if (0 < c && c < NSTR && status[c]) puts2(status[c]); else printf("signal %d", c); if (retcode & 0200) puts2(" -- core dumped"); putchar(lastc = '\n'); c = 0; goto errm; } else if (df && strict && retcode >> 8) { printf("exit status %d\n", retcode >> 8); c = 0; goto errm; } #ifdef PIPE else if (addr2) { if (piperr) { putsn(status[SIGPIP]); c = 0; goto errm; } if (dp) { if (df) { c = addr2 != dol; delete(); if (dest == 0) dest = dot - c; } else if (dest == 0) dest = addr2; if (dest < zero) dest = zero; if (c = append(getfile, dest, 0, 0)) text_modified++; if (prompt2) printf((curt? prcntu : errtext[55]), c, (c == 1? null : quote_s)); close(io); io = 0; unlink(pfname); close(pfile); pfile = 0; } } #endif if (!iflg) { signal(SIGINT, savint); signal(SIGQIT, savqit); } if (!addr2) putsn("!"); #ifdef CLEAR istty(1); /* in case bs1 changed */ #endif } signals(ast) struct sigtab *ast; { register n; register struct sigtab *s; s = ast - 1; while (n = (++s)->s_sig) signal(n, s->s_func); } skip_rest() { register charac c; while ((c = getchar()) >= 0 && c != '\n'); } substitute(inglob) { extern getsub(); register linep *a1, p; register nl; register flag gsubf; gsubf = compsub(); /* 0 or 1 depending on 'g' */ for (a1 = addr1; a1 <= addr2; a1++) { s_tmp = s_cnt; if (execute(0, a1) == 0) continue; inglob |= 01; dosub(); if (gsubf) while (*loc2) { if (execute(1) == 0) break; dosub(); } p = *a1; *a1 = putline(); savemark(p, *a1); nl = append(getsub, a1, 0, 0); a1 += nl; addr2 += nl; } if (inglob == 0) errmsg(39); } #ifdef XED tack(aeof, aflag) char aeof; { register n; register char *p1, *p2; register linep *a; register charac c; nonzero(); setdot(); p1 = rhsbuf; /* i/TEXT screwed for long lines */ while ((c = getchar()) != aeof && c != '\n') { if (c == '\\') if ((c = getchar()) == '\n') break; if (c < 0) errmsg(59); *p1++ = c; if (p1 >= &rhsbuf[LBSIZE / 2 - 2]) errmsg(42); } if (*rhsbuf == 0) errmsg(27); if (c == '\n') { if (prompt2) pflag++; } else newline(); if (p1 != rhsbuf) *p1 = 0; else while (*p1) p1++; n = p1 - rhsbuf; for (a = addr1; a <= addr2; a++) { getline(*a); for (p2 = linebuf; *p2; p2++); #ifndef ALLOC if (p2 + n >= &linebuf[LBSIZE / 2 - 2]) #else if (p2 + n >= &linebuf[lbsize / 2 - 2]) #endif errmsg(30); if (aflag) { /* $ */ p1 = rhsbuf; while (*p2++ = *p1++); } else { /* ^ */ p1 = p2 + n; *p1 = *p2; while (p2 > linebuf) *--p1 = *--p2; p1 = linebuf; p2 = rhsbuf; while (*p2) *p1++ = *p2++; } p2 = *a; *a = putline(); savemark(p2, *a); } dot = addr2; return(addr2 - addr1 + 1); } #endif term() { signal(SIGTRM, 1); if (reading) { backup(TRM); if (fout != 1) { flush_buf(); fout = 1; } puts2(errtext[58]); delexit(1); } termflg++; } tmpname(as, an) char *as; { register unsigned n; register char *p, c; p = as; n = an; while (*p) p++; while (--p >= as) if ((c = *p) == '0' || (c | 040) == 'x') { *p = n % 10 + '0'; n /= 10; #ifdef CKPT tfnum = p - as; #endif } return(as); } #ifdef XDEL undelete() { register linep *a1, *a2, *bp; register tl, nl, num; if ((tl = deleted) == 0) errmsg(16); #ifdef DEBUG if (tflg) printf("undelete:\t%o\n", tl); #endif setdot(); a1 = dol + 1; a2 = a1 + ndeleted; bp = addr2 + 1; if (dol + ndeleted > endcore) { num = ((ndeleted * 2) + 1023) & ~01777; if (sbrk(num) == -1) errmsg(33); endcore = (int)endcore + num; } while (a1 > bp) *--a2 = *--a1; dol += ndeleted; a1 = addr2 + 1; a2 = a1 + ndeleted; bp = getblock(tl, READ); #ifdef HUGE tl &= _1[hugef]; #else tl &= _1; #endif nl = nleft / sizeof(linep); while (a1 < a2) { *a1++ = *bp++; if (--nl <= 0) { #ifdef HUGE bp = getblock(tl += _2[hugef], READ); #else bp = getblock(tl += _2, READ); #endif nl = nleft / sizeof(linep); } } dot = a2 - 1; return(ndeleted); } #endif #ifdef UNDO undo() { register linep *a, t, o; if (undo_newp == 0 || (a = findmark(undo_newp, 0)) == 0) errmsg(13); t = *a | #ifdef HUGE hugef ^ #endif 01; o = undo_oldp; savemark(*a, o); *a = o; undo_newp = o; undo_oldp = t; dot = a; if (text_modified == 0) text_modified++; } #endif white_space() { register charac c; while ((c = getchar()) == ' ' || c == '\t'); peekc = c; } wte(fd, buf, len) char buf[]; { if (write(fd, buf, len) != len) errmsg(-32); } /* * as a prompt string * ay yes response, !no response * ad default (\n) response, <0 means no default allowed * aef end-of-file response */ yes_no(as, ay, ad, aef) char *as; { register charac c, p; register n; register flag l; l = listf; listf = 0; p = peekc; peekc = 0; for ever { putchar('\n'); puts2(as); puts2("? "); for (n = 0; n < 5; n++) { flush_buf(); if ((c = getchar()) < 0) { putchar('\n'); n = aef; goto ret; } if (c != '\n') skip_rest(); else if (ad >= 0) { n = ad; goto ret; } if (c == 'y' || c == 'n') { n = ay; if (c != 'y') n ^= 01; goto ret; } puts2("yes or no? "); } } ret: listf = l; peekc = p; return(n); }