1: static char Sccsid[] = "xed.c @(#)xed.c 1.1 10/1/82 Berkeley "; 2: # 3: 4: /* 5: * V7.15 81/09/16 14:22 Fixed bug causing bus errors occasionally 6: * V7.14 81/09/10 21:50 -B dynamically allocated line buffer 7: * V7.13 81/07/25 22:51 added -O and "long" pointers 8: * 9: * Editor 10: * 11: * Major additions beginning 77/04 12: * Conversion to version 7 79/12 13: * Conversion to VAX 80/11 14: * 15: * Purdue University, Engineering Computer Network 16: * 17: * Tgi -- Room 337A 18: * Electrical Engineering Dept 19: * Purdue University 20: * West Lafayette, Indiana 21: * 47907 22: * 317/49-41592 23: */ 24: 25: #define XED /* enable powerful stuff */ 26: #define V7 /* enable environment stuff for protocol */ 27: 28: /* 29: * At the entry to a function (PDP-11) the following sequence 30: * of instructions is executed: 31: * func: jsr r5,csv 32: * csv: mov r5,r0 33: * csv+2: mov sp,r5 34: * If a signal occurs between the first and second, or between the 35: * second and third instructions, r5 will NOT contain a valid 36: * stack address. Hence, when longjmp() attempts to validate 37: * the environment pointer (r5) links, an instruction will be 38: * fetched instead of a valid pointer, and will generally cause 39: * one of "memory fault", "bus error", or "illegal instruction" 40: * resulting in the loss of the editing session. 41: * 42: * Due to this wonderful feature of version 7 ingenuity, I have 43: * reverted to using setexit/reset, since they are simpler and 44: * do not assume that I do not know what I am doing. 45: * 46: * 80/11/10 V7.01 Tgi 47: */ 48: 49: #ifndef pdp11 50: #include <setjmp.h> 51: jmp_buf _env_rst; 52: #define setexit() setjmp(_env_rst) 53: #define reset() longjmp(_env_rst,1) 54: #endif 55: 56: #include <sys/types.h> 57: #include <sys/stat.h> 58: 59: /* 60: * Machine-dependent definitions 61: */ 62: 63: #ifdef pdp11 64: # define BPB 8 /* bits per byte */ 65: # define BPW (BPB*sizeof(int))/* bits per word */ 66: # define BPWC 4 /* log2(BPW) */ 67: # define BPWM 017 /* mask of BPWC bits */ 68: typedef short block; 69: typedef short charac; 70: typedef short filedes; 71: typedef short flag; 72: typedef int (*func)(); 73: typedef short linep; 74: #endif 75: 76: #ifdef vax 77: # define BPB 8 /* bits per byte */ 78: # define BPW (BPB*sizeof(int))/* bits per word */ 79: # define BPWC 5 /* log2(BPW) */ 80: # define BPWM 037 /* mask of BPWC bits */ 81: typedef long block; 82: typedef int charac; 83: typedef short filedes; 84: typedef char flag; 85: typedef int (*func)(); 86: typedef long linep; /* NEW */ 87: #endif 88: 89: /* 90: * conditional compilation 91: */ 92: 93: #ifdef XED 94: # define AGAIN /* enable "o" "again" command */ 95: # define ALLOC 1024 /* line buffer size */ 96: # define APLMAP /* enable Apl character mapping */ 97: # define DEBUG /* enable "du" command */ 98: # define DUMB 0 /* enable command to disable spcl chars */ 99: # define EOL /* enable special eol stuff */ 100: # define EXTMARK /* extended "k" capability */ 101: # define G_VFY /* enable verifying on "g" command */ 102: # define HELP "/etc/xed.doc" 103: # ifdef pdp11 /* only needed on 16-bit machines */ 104: # define HUGE /* enable "huge" file stuff */ 105: # endif 106: # define PAGE /* enable proper line counting on ":" */ 107: # define PARENS /* enable "b" suffix to count parentheses */ 108: # define PIPE /* enable | command to pipe to process */ 109: # define PROMPT ">" 110: # define STRLEN /* enable string-length counting code */ 111: # define TABS ((LBSIZE+sizeof(int)-1)/sizeof(int)) /* words for tab stops */ 112: # define TTL "XED\tV7.15" 113: /* #define TTL_NL 9 /* location of newline in TTL */ 114: # define UNDO /* enable "u"ndo command */ 115: # define USE /* enable "@" command */ 116: # define XDEL /* enable undelete stuff */ 117: # define YINT /* enable special interrupt processing */ 118: #endif 119: 120: /* 121: * stuff for EED, instead of XED 122: */ 123: 124: #ifndef XED 125: # define HELP "/etc/eed.doc" 126: # define PROMPT "*" 127: # define TTL "EED" 128: #else 129: # define EEDHELP "/etc/eed.doc" 130: # define EEDPROMPT "*" 131: # define EEDTTL "EED" 132: #endif 133: 134: /* 135: * stuff normally enabled 136: */ 137: 138: #define CLEAR "\33:\33H\33J\32\14" /* HP-2640A, Lear ADM-3A */ 139: #define CMDS "edsav" /* all commands written if exists */ 140: #ifndef DUMB 141: # define DUMB 1 /* enable command to disable spcl chars */ 142: #endif 143: 144: /* 145: * special stuff, occasionally enabled 146: */ 147: 148: #define LOG "/a/tgi/etc/xed.log" /* feature use logging */ 149: 150: /* 151: * data #defines 152: */ 153: 154: #define BAK 4 /* file.bak - backup() */ 155: #define BLKSIZE 512 /* disk block size (bytes) */ 156: #define BS1 0100000 /* stty() */ 157: #define CBACK 14 /* back-reference: \(blah\)more\1 */ 158: #define CBRA 1 /* \( */ 159: #define CCHR 2 /* literal character */ 160: #define CCL 6 /* character class [x...y] */ 161: #define CCOUNT (80-1) /* terminal width */ 162: #define CDOL 10 /* ...$ */ 163: #define CDOT 4 /* . */ 164: #define CEOF 11 /* end of pattern */ 165: #define CKET 12 /* \) */ 166: #define EOF -1 /* end of file */ 167: #define ESIZE 128 /* regular expression size */ 168: #define FILE 0 /* no extension - backup() */ 169: #define FNSIZE 64 /* max size of pathname to file */ 170: #define GBSIZE 256 /* max global command length */ 171: #define HUP 3 /* file.hup - backup() */ 172: #define INT 2 /* file.int - backup() */ 173: #define LBSIZE 512 /* max line length */ 174: #define LMASK 077 /* mask for "locked" file */ 175: #define LMODE (MODE&~LMASK) /* mode for "locked" file */ 176: #define MODCNT 35 /* default mod count before auto-write */ 177: #define MODE 0666 /* mode for normal files */ 178: #define NBRA 9 /* number of \( \) pairs */ 179: #define NCCL 8 /* not in character class: [^x...y] */ 180: #define PAGSIZ 22 /* page size for ":" command */ 181: #define READ 0 /* getblock: read function */ 182: #define SIGBUS 10 /* Bus error */ 183: #define SIGEMT 7 /* EMT trap */ 184: #define SIGFPE 8 /* Floating Point Exception */ 185: #define SIGHUP 1 /* Hangup signal */ 186: #define SIGILL 4 /* Illegal instruction */ 187: #define SIGINT 2 /* Interrupt signal */ 188: #define SIGIOT 6 /* IOT trap */ 189: #define SIGPIP 13 /* Broken pipe for ! stuff */ 190: #define SIGQIT 3 /* Quit signal */ 191: #define SIGSEGV 11 /* Memory fault */ 192: #define SIGSYS 12 /* Bad system call */ 193: #define SIGTRC 5 /* Trace/BPT for mail stuff */ 194: #define SIGTRM 15 /* Termination */ 195: #define STAR 1 /* * */ 196: #define TABFILL '\t' /* fill character for tab expansion */ 197: #define TMP 1 /* file.edt - backup() */ 198: #define TRM 5 /* file.trm - backup() */ 199: #define TTSIZE (512+4) /* terminal output buffer size */ 200: #define WRITE 1 /* getblock: write function */ 201: #define ever (;;) 202: 203: #define error errfunc 204: #define ctrl(x) ((x)&037) 205: 206: #ifdef AGAIN 207: char agbuf[GBSIZE], /* save area for "again" command */ 208: *agp = 0; /* "again" command pointer */ 209: flag agf = 0; /* "again" flag (executing the command) */ 210: #endif 211: 212: #ifdef ALLOC 213: int lbsize = LBSIZE;/* line buffer size */ 214: #endif 215: 216: #ifdef APLMAP 217: flag aplmap = 0; /* Apl character mapping */ 218: #include "aplmap.h" /* apl ADM-3A char set mapping tables */ 219: #endif 220: 221: #ifdef CKPT 222: char *cfname = "/tmp/ce00000";/* filename for checkpoint */ 223: int recovry = 0, /* non-zero to recover checkpointed session */ 224: tfnum; /* index into tfname for "00000" string */ 225: #endif 226: 227: #ifdef CLEAR 228: char *clears = CLEAR;/* screen-clear sequence */ 229: flag zflg = 0; /* if "stty bs1" not set */ 230: /* bs1 displays ctrl-z as ^Z on tty */ 231: #endif 232: 233: #ifdef CMDS 234: filedes cmd = 0; /* file des for command-save file */ 235: char cmdfil[] = CMDS;/* command-save file */ 236: #endif 237: 238: #ifdef DEBUG 239: flag tflg = 0; /* tracing flag */ 240: #endif 241: 242: #ifdef DUMB 243: flag dumbf = DUMB; /* 1 = disable special chars in patterns */ 244: #endif 245: 246: #ifdef EOL 247: charac eol = 0; /* "end-of-line" char for multiple commands */ 248: /* per line */ 249: flag prompt3 = 1; /* disable prompts for "eol" stuff */ 250: #endif 251: 252: #ifdef G_VFY 253: flag gaskf = 0; /* verify mode on global command */ 254: #endif 255: 256: #ifdef HELP 257: filedes doc = 0; /* "help" file descriptor */ 258: char *help = HELP; /* "help" file name */ 259: #endif 260: 261: #ifdef LOG 262: char logfile[]= LOG; /* logging use of features */ 263: filedes lfile = 0; /* logging file descriptor */ 264: short logamp; /* since s/x/&/ may be done many times */ 265: struct logstat { 266: short l_uid; /* user id of caller */ 267: char l_xed, /* 1 if xed, 0 if eed, 2 if apled */ 268: l_inter; /* 1 if interactive */ 269: /* command features */ 270: short lc_shell, /* ! */ 271: lc_pipe, /* | */ 272: lc_piplus, /* |+ */ 273: lc_piminus, /* |- */ 274: lc_dpipe, /* || */ 275: lc_pfrom, /* |< */ 276: lc_pto, /* |> */ 277: lc_at, /* @ */ 278: lc_colon, /* : */ 279: lc_star, /* * */ 280: lc_clnminus, /* :- */ 281: lc_comment, /* : stuff or * stuff */ 282: lc_append, /* a */ 283: lc_abort, /* abort */ 284: lc_aspace, /* a line */ 285: lc_aslash, /* a/string/ */ 286: lc_browse, /* bN */ 287: lc_change, /* c */ 288: lc_cslash, /* c/s1/s2/ */ 289: lc_copy, /* coNN */ 290: lc_delete, /* d */ 291: lc_depth, /* d=NN */ 292: lc_directory, /* d path */ 293: lc_edit, /* e file */ 294: lc_eol, /* e=C */ 295: lc_errmsg, /* eNN */ 296: lc_exp, /* exp */ 297: lc_eplus, /* e+ */ 298: lc_eminus, /* e- */ 299: lc_fshow, /* f */ 300: lc_fset, /* f file */ 301: lc_fillset, /* f=C */ 302: lc_global, /* g/str/cmd */ 303: lc_gvfy, /* g/str/vcmd */ 304: lc_header, /* h */ 305: lc_help, /* help */ 306: lc_insert, /* i */ 307: lc_islash, /* i/string/ */ 308: lc_join, /* j */ 309: lc_jglue, /* j/glue/ */ 310: lc_klist, /* k */ 311: lc_kset, /* kC */ 312: lc_list, /* l */ 313: lc_move, /* mNN */ 314: lc_moove, /* moNN */ 315: lc_magic, /* m */ 316: lc_numbers, /* n */ 317: lc_numinus, /* n- */ 318: lc_numplus, /* n+ */ 319: lc_o, /* o ^Q */ 320: lc_print, /* p */ 321: lc_pprint, /* pp */ 322: lc_quit, /* q */ 323: lc_qimm, /* qi */ 324: lc_quote, /* q=C */ 325: lc_read, /* r */ 326: lc_substitute, /* s/s1/s2/ */ 327: lc_stop, /* s */ 328: lc_savecount, /* saNN */ 329: lc_tablist, /* t */ 330: lc_tabset, /* t,NN */ 331: lc_tabchar, /* t=C */ 332: lc_transfer, /* tNN */ 333: lc_undo, /* u */ 334: lc_vglobal, /* v/str/cmd */ 335: lc_write, /* w */ 336: lc_wonto, /* w> */ 337: lc_wimm, /* wi */ 338: lc_width, /* w=NN */ 339: lc_xundelete, /* x */ 340: lc_yintr, /* y */ 341: lc_yminus, /* y- */ 342: lc_yplus, /* y+ */ 343: /* address features */ 344: la_dot, /* . */ 345: la_dotdot, /* .. */ 346: la_dol, /* $ */ 347: la_num, /* NN */ 348: la_plus, /* + */ 349: la_minus, /* - */ 350: la_caret, /* ^ */ 351: la_quote, /* 'a */ 352: la_letter, /* A */ 353: la_slash, /* /str/ */ 354: la_query, /* ?str? */ 355: la_equal, /* = */ 356: /* pattern features */ 357: lp_caret, /* ^ */ 358: lp_dol, /* $ */ 359: lp_dot, /* . */ 360: lp_star, /* * */ 361: lp_ccl, /* [ ] */ 362: lp_nccl, /* [^ ] */ 363: lp_paren, /* \( \) */ 364: lp_digit, /* \1 \2 \3 ... */ 365: /* substitution features */ 366: lp_amp, /* & */ 367: /* miscellaneous features */ 368: lm_quote, /* ...q */ 369: lm_bracket, /* ...b */ 370: lm_overwrite; /* -O,wi */ 371: /* resources */ 372: long lt_start, /* starting time */ 373: lt_end, /* elapsed time */ 374: lt_usercpu, /* user cpu time */ 375: lt_syscpu, /* system cpu time */ 376: lt_kidscpu, /* total ! kids time */ 377: lt_rlines, /* total lines read */ 378: lt_wlines; /* total lines written */ 379: } logstats; 380: #endif 381: 382: #ifdef PAGE 383: int ccount = CCOUNT;/* terminal width */ 384: #endif 385: 386: #ifdef PARENS 387: int parenc[3] = {0, 0, 0};/* parentheses counts */ 388: flag parenf = 0; /* count parentheses and brackets */ 389: #endif 390: 391: #ifdef PIPE 392: filedes pfile = 0; /* "pipe" file descriptor */ 393: char *pfname = "/tmp/ep00000";/* for "double-piping" */ 394: flag piperr = 0, /* pipe error flag - shell() */ 395: pno = -1, /* piping line numbering flag (default n-) */ 396: strict = 1; /* strict exit status checking for | */ 397: #endif 398: 399: #ifdef STRLEN 400: charac quotec = '\0', /* quote character other than " or ' */ 401: quotec2 = '\0'; /* closing quote */ 402: int quotef = 0; /* length of strings within " or ' chars */ 403: #endif 404: 405: #ifdef TABS 406: charac tabfill = TABFILL,/* fill character */ 407: tabc = 0; /* tab character - if 0 no tab processing */ 408: int maxtab = -1, /* last column number with tab stop */ 409: tabs[TABS]; /* each bit on = tab stop */ 410: #endif 411: 412: #ifdef UNDO 413: linep undo_oldp, /* original line pointer */ 414: undo_newp; /* replacement line */ 415: #endif 416: 417: #ifdef USE 418: filedes alt = 0; /* alternate command input file */ 419: char altfile[FNSIZE]; 420: flag eflg2 = 0; /* another kludge */ 421: #endif 422: 423: #ifdef XDEL 424: linep deleted = 0; /* pointer to deleted line pointers */ 425: int ndeleted = 0; /* number of lines */ 426: #endif 427: 428: #ifdef YINT 429: flag yflg = 0; /* page upon interrupt */ 430: linep *yplus = 0; /* page from this line - if zero, from dot */ 431: #endif 432: 433: /* 434: * globals 435: */ 436: 437: block iblock = -1, /* block number of input buffer */ 438: oblock = -1; /* output buffer block number */ 439: 440: char *braelist[NBRA], /* bracket \( \) end list */ 441: *braslist[NBRA], /* bracket \( \) start list */ 442: dotbak[] = ".bak", 443: dotedt[] = ".edt", /* "file saved" file */ 444: dothup[] = ".hup", 445: dotint[] = ".int", 446: dottrm[] = ".trm", 447: *dots[] = { dothup, dottrm, dotedt, dotint, 0 }, 448: expbuf[ESIZE + 4], /* expression buffer */ 449: file[FNSIZE], /* filename buffer */ 450: #ifndef ALLOC 451: genbuf[LBSIZE], /* generated line buffer */ 452: #else 453: *genbuf, /* generated line buffer pointer */ 454: #endif 455: ibuff[BLKSIZE], /* input tmpfile buffer */ 456: line[TTSIZE + 4], /* terminal output buffer */ 457: #ifndef ALLOC 458: linebuf[LBSIZE], /* line buffer for getline()/putline() */ 459: #else 460: *linebuf, /* line buffer for getline()/putline() */ 461: #endif 462: no[] = "no ", 463: null[] = "", /* "" */ 464: obuff[BLKSIZE], /* output tmpfile buffer */ 465: off[] = "off", 466: on[] = "on", 467: prcntu[] = "%u\n", /* %u */ 468: quote_s[] = "s", /* "s" */ 469: rhsbuf[LBSIZE / 2], /* right-hand-side expression buffer */ 470: savedfile[FNSIZE], /* saved filename */ 471: tempfile[FNSIZE], /* scratch area for filename */ 472: 473: *editor, /* argv[0] */ 474: *e_prompt = PROMPT,/* editor command prompt */ 475: *fmtlno = "%7u=",/* format for line-number output */ 476: *globp, /* global command pointer */ 477: *linp = line, /* line pointer */ 478: *linebp, 479: *loc1, /* start pointer of & string */ 480: *loc2, /* end pointer of & string */ 481: *locs, 482: *nextip, 483: *overfile, /* filename mode was changed on */ 484: *tfname = "/tmp/e00000",/* "buffer" name */ 485: *ver = TTL; /* ID message */ 486: 487: charac lastc = 0, /* peekc set to lastc on interrupt */ 488: peekc = 0; /* one character pushback */ 489: 490: int brcount = 1, /* number of lines to output on "newline" */ 491: col = 0, /* column counter for calculating line wraps */ 492: line_num, /* integer for line number on output */ 493: modcount = MODCNT,/* number of mods before auto-write */ 494: overmode, /* mode of overridden file */ 495: mods = 0, /* number of mods */ 496: nbra = 0, /* count of currently defined \( \) pairs */ 497: ninbuf, /* bytes in tmpfile input buffer */ 498: nleft, /* bytes remaining in tmpfile output buffer */ 499: num_reads = 0, /* indicator to aid text_modified-- */ 500: /* first read isn't really a modify */ 501: pcount = PAGSIZ-1,/* number of lines to display on ":" command */ 502: s_cnt = 0, /* counter for "s/str1/str2/nn" */ 503: s_tmp = 0, /* scratch var for same */ 504: savf, /* counter for auto-write stuff */ 505: text_modified = 0;/* flag--on if text was modified */ 506: 507: filedes fout = 1, /* putchar() writes on this fildes */ 508: io = 0, /* file descriptor for "r", "w", "e" */ 509: tfile = -1; /* file des for "buffer" */ 510: 511: flag aflg = 0, /* "apl mode" flag */ 512: appflg = 0, /* append flag (if "w>file") */ 513: badf = 0, /* bad read on temp file */ 514: bflg = 0, /* "back-up" flag -- Generate back-up file */ 515: bflg2 = 0, /* Secondary "back-up" flag */ 516: circfl, /* reg expr started with ^ */ 517: curt = 0, /* short error messages -- ie: '?' */ 518: deltflg = 0, /* don't delete .edt file upon exit */ 519: eflg = 0, /* echo input flag */ 520: eof = 0, /* eof was last char typed */ 521: fflg = 0, /* "create" flag */ 522: globf2 = 0, /* kludge for -f */ 523: #ifdef HUGE 524: hugef = 0, /* -h is process huge file */ 525: hugef2 = 0, /* getblock() conversion to huge */ 526: #endif 527: hupflag = 0, /* hangup signal has been caught */ 528: ichanged, /* ibuf has been changed */ 529: iflg = 0, /* file.int and exit on interrupt */ 530: immflg = 0, /* immediate flag -- q and e */ 531: io_w = 0, /* writing in progress */ 532: listf = 0, /* list control chars explicitly */ 533: noshell = 0, /* true if no ! command allowed */ 534: over = 0, /* override permissions on write if possible */ 535: pflag, /* print line after doing command */ 536: pipef = 0, /* for talking to pipes */ 537: prompt1 = 1, /* flag--enable or disable line-num prompts */ 538: prompt2 = 1, /* flag--enable or disable ALL prompting */ 539: reading = 0, /* waiting on tty read */ 540: seekf = 0, /* no seek to EOF on error on fd 0 */ 541: termflg = 0; /* if termination signal (15) occurred */ 542: 543: linep *addr1, /* lower line bound */ 544: *addr2, /* upper line bound */ 545: *dol, /* last line in file */ 546: *dot, /* "current" line */ 547: *dotdot, /* last different "dot" */ 548: *endcore, /* current end of memory */ 549: *fendcore, /* start of dynamic area */ 550: *lastdot, /* last "dot" */ 551: names['z' - 'a' + 1], /* "k" command markers */ 552: #ifdef EXTMARK 553: names2['z' - 'a' + 1], /* "k" command markers */ 554: #endif 555: *old_a1, /* previous address bounds */ 556: *old_a2, 557: tline, /* pointer to next available pos in tmpfile */ 558: *zero; /* anchor line for all other lines */ 559: 560: /* 561: * magic constants used in many places 562: */ 563: 564: #ifdef pdp11 565: # define _1a ~0377 566: # define _2a 0400 567: # define _3a 0377 568: # define _4a 0774 569: # define _5a 255 570: # define _6a 077776 571: # define _1b ~0177 572: # define _2b 0200 573: # define _3b 0777 574: # define _4b 0774 575: # define _5b 511 576: # define _6b 077777 577: #endif 578: 579: #ifdef vax 580: # define _1a ~0377 581: # define _2a 0400 582: # define _3a 077777777 583: # define _4a 0774 584: # define _5a 65535 585: # define _6a 077777776 586: #endif 587: 588: #ifdef HUGE 589: int _1[] = { _1a, _1b }, /* tl &= _1; getline() */ 590: _2[] = { _2a, _2b }, /* tl += _2; getline()... */ 591: _3[] = { _3a, _3b }, /* bno = ... & _3; getblock() */ 592: _4[] = { _4a, _4b }, /* off = ... & _4; getblock() */ 593: _5[] = { _5a, _5b }, /* if (bno >= _5)... getblock() */ 594: _6[] = { _6a, _6b }; /* tline += ... & _6; */ 595: #else 596: # define _1 _1a 597: # define _2 _2a 598: # define _3 _3a 599: # define _4 _4a 600: # define _5 _5a 601: # define _6 _6a 602: #endif 603: 604: /* 605: * error messages 606: * 607: * (there are more than these) 608: */ 609: 610: char *errtext[] = { 611: /* 0 */ "syntax is k[a-z]", 612: /* 1 */ "illegal command format", 613: /* 2 */ "no command", 614: /* 3 */ "no tab character", 615: /* 4 */ "can't change filename", 616: /* 5 */ "file name syntax", 617: /* 6 */ "recursive \"@\" command", 618: /* 7 */ "null file name illegal", 619: /* 8 */ "unrecognized command", 620: /* 9 */ "no tabs set", 621: /* 10 */ "global command not allowed with huge file", 622: /* 11 */ "file name too long", 623: /* 12 */ "expanded line too long", 624: /* 13 */ "no such line", 625: /* 14 */ "can't fork", 626: /* 15 */ "can't write to process", 627: /* 16 */ "no lines", 628: /* 17 */ "backup(FILE) error (?)", 629: /* 18 */ "string not found", 630: /* 19 */ " ' must be followed by [a-z]", 631: /* 20 */ "address syntax error", 632: /* 21 */ "lower address bound > upper one", 633: /* 22 */ "address illegal here", 634: /* 23 */ "non-existent line number", 635: /* 24 */ "bottom of file reached", 636: /* 25 */ "command syntax error", 637: /* 26 */ "\"advance\" error (?)", 638: /* 27 */ "null string illegal", 639: /* 28 */ "destination not found", 640: /* 29 */ "INTERRUPT!", 641: /* 30 */ "line too long", 642: /* 31 */ "missing destination address", 643: /* 32 */ "I/O error--file not saved!", 644: /* 33 */ "file overflows available memory", 645: /* 34 */ "file too large (TMPERR)", 646: /* 35 */ "I/O error on temp file (TMPERR)", 647: /* 36 */ "open error on temp file (TMPERR)", 648: /* 37 */ "recursive global command", 649: /* 38 */ "global command list too long", 650: /* 39 */ "substitute pattern not found", 651: /* 40 */ "missing substring", 652: /* 41 */ "string2 too long", 653: /* 42 */ "substring too long", 654: /* 43 */ "substituted string too long", 655: /* 44 */ "too many \\(", 656: /* 45 */ "unbalanced \\( \\)", 657: /* 46 */ "\\n illegal", 658: /* 47 */ "unimplemented feature", 659: /* 48 */ "[nothing written]", 660: /* 49 */ "pattern too complicated", 661: /* 50 */ "can't create temp file (TMPERR)", 662: /* 51 */ "bad directory", 663: /* 52 */ "no ! allowed", 664: /* 53 */ "can't read ", 665: /* 54 */ "can't create ", 666: /* 55 */ "%u line%s\n", 667: /* 56 */ "[file saved]", 668: /* 57 */ "\nHangup!\n", 669: /* 58 */ "\nTerminated...\n", 670: /* 59 */ "EOF illegal here", 671: /* 60 */ "can't join to line 0", 672: /* 61 */ "! not allowed with global command", 673: /* 62 */ "no filename specified", 674: /* 63 */ "not enough \\( \\) pairs", 675: /* 64 */ "can't create pipe file (PIPERR)", 676: /* 65 */ "open error on pipe file (PIPERR)", 677: /* 66 */ "can't checkpoint", 678: /* 67 */ "can't recover", 679: }; 680: #define NERR (sizeof errtext / sizeof errtext[0]) 681: 682: /* 683: * ! error strings 684: */ 685: 686: char *status[] = { 687: /* 0 */ 0, 688: /* 1 */ "hangup", 689: /* 2 */ "interrupt", 690: /* 3 */ "quit", 691: /* 4 */ "illegal instruction", 692: /* 5 */ "bpt", 693: /* 6 */ "iot", 694: /* 7 */ "emt", 695: /* 8 */ "fpp", 696: /* 9 */ "killed", 697: /* 10 */ "bus error", 698: /* 11 */ "memory fault", 699: /* 12 */ "bad sys call", 700: /* 13 */ "broken pipe", 701: /* 14 */ "alarm", 702: /* 15 */ "terminated", 703: #ifdef pdp11 704: /* 16 */ "time limit", 705: #else 706: /* 16 */ 0, 707: /* 17 */ "stopped", 708: /* 18 */ "terminal stop", 709: /* 19 */ "continue", 710: /* 20 */ "child status changed", 711: /* 21 */ "terminal input", 712: /* 22 */ "terminal output", 713: /* 23 */ "terminal input ready", 714: /* 24 */ "cpu timelimit exceeded", 715: /* 25 */ "filesize limit exceeded", 716: #endif 717: }; 718: #define NSTR (sizeof status / sizeof status[0]) 719: 720: #define putsn(x) (puts2((x)),putchar('\n')) 721: #define min(x,y) ((x)<(y)?(x):(y)) 722: #define max(x,y) ((x)>(y)?(x):(y)) 723: 724: /* 725: * function declarations 726: */ 727: 728: linep *findmark(); 729: char *getblock(); 730: long lseek(); 731: func signal(); 732: #ifndef CKPT 733: int badsig(), 734: #else 735: int checkpoint(), 736: #endif 737: hangup(), 738: mail(), 739: onintr(), 740: term(); 741: 742: /* 743: * signals 744: */ 745: 746: struct sigtab { 747: int s_sig, 748: s_func; 749: } sigtab1[] = { 750: #ifdef CKPT 751: SIGILL, checkpoint, 752: SIGIOT, checkpoint, 753: SIGEMT, checkpoint, 754: SIGFPE, checkpoint, 755: SIGBUS, checkpoint, 756: SIGSEGV, checkpoint, 757: SIGSYS, checkpoint, 758: #else 759: SIGILL, badsig, 760: SIGIOT, badsig, 761: SIGEMT, badsig, 762: SIGFPE, badsig, 763: SIGBUS, badsig, 764: SIGSEGV, badsig, 765: SIGSYS, badsig, 766: #endif 767: 0, 0, 768: }, sigtab2[] = { 769: SIGTRC, mail, 770: SIGHUP, hangup, 771: SIGTRM, term, 772: SIGINT, onintr, 773: 0, 0, 774: }; 775: 776: main(argc, argv) 777: char **argv; 778: { 779: #ifdef CKPT 780: extern checkpoint(); 781: #else 782: extern badsig(); 783: #endif 784: extern onintr(), hangup(), mail(), term(); 785: #ifdef DEBUG 786: #ifdef EXPDMP 787: extern expdmp(); 788: #endif 789: #endif 790: register n; 791: register char *p1, *p2, *ep; 792: func savint; 793: 794: signal(SIGQIT, 1); 795: savint = signal(SIGINT, 1); 796: ep = *argv; 797: #ifdef XED 798: p1 = ep; 799: p2 = p1; 800: while (*p1) 801: if (*p1++ == '/' && *p1 && *p1 != '/') 802: p2 = p1; 803: p1 = p2; 804: *argv = p2; 805: n = 0; 806: while (*p1) 807: if (*p1++ == 'x') { /* xed .vs. eed */ 808: ++n; 809: break; 810: } 811: if (n == 0) { 812: e_prompt = EEDPROMPT; 813: ver = EEDTTL; 814: help = EEDHELP; 815: dumbf = 1; 816: } 817: #ifdef LOG 818: logstats.l_xed = n; 819: #endif 820: #endif 821: prompt2 = istty(0); 822: #ifdef V7 823: if (getenv("_OVERWRITE_")) 824: ++over; 825: #endif 826: while (--argc) 827: if (**++argv == '-') { 828: while (*++*argv) { 829: switch (**argv) { 830: case '!': /* no ! allowed */ 831: noshell = 1; 832: break; 833: #ifdef APLMAP 834: case 'A': /* apl char mapping */ 835: aplmap = 1; 836: errtext[29] = "G interrupt G"; 837: p1 = ver; 838: while (*p1) { 839: if ('A' <= *p1 && *p1 <= 'Z') 840: *p1 |= 040; 841: ++p1; 842: } 843: #endif 844: case 'a': /* apl mode */ 845: aflg = 1; 846: fmtlno = "[ %u ]\t"; 847: #ifdef DUMB 848: dumbf = 1; 849: #endif 850: #ifdef XED 851: #ifdef TTL_NL 852: ver[TTL_NL] = 0; 853: #endif 854: #endif 855: break; 856: case 'b': /* file.bak on entry */ 857: bflg = 1; 858: bflg2 = 1; 859: break; 860: #ifdef PAGE 861: case 'c': /* crt depth in lines */ 862: ++*argv; 863: n = argnum(argv); 864: if (n >= 0) 865: pcount = n; 866: break; 867: #endif 868: case 'd': /* don't delete .edt file */ 869: deltflg = 1; 870: break; 871: case 'e': /* echo input commands */ 872: eflg = 1; 873: break; 874: case 'f': /* create mode */ 875: fflg = 1; 876: break; 877: #ifdef HUGE 878: case 'h': /* edit "huge" file */ 879: hugef = 1; 880: break; 881: #endif 882: case 'i': /* file.int on interrupt */ 883: iflg = 1; 884: break; 885: case 'k': /* kill verbose messages */ 886: curt = 1; 887: break; 888: #ifdef EOL 889: case 'l': /* set eol char to "x" */ 890: if (*++*argv) 891: eol = **argv; 892: else 893: --*argv; 894: break; 895: #endif 896: case 'm': /* mod cnt for autosave */ 897: ++*argv; 898: n = argnum(argv); 899: if (n >= 0) 900: modcount = n; 901: break; 902: case 'n': /* no line num */ 903: prompt1 = 0; 904: break; 905: case 'o': /* no seek to EOF on error */ 906: seekf = 1; 907: break; 908: case 'p': /* force prompts for pipe */ 909: pipef = 1; 910: prompt2 = 1; 911: break; 912: case 'q': /* don't inhibit quits */ 913: signal(SIGQIT, 0); 914: break; 915: #ifdef DUMB 916: case 'r': /* spcl char meaning */ 917: dumbf ^= 01; 918: break; 919: #endif 920: case 's': /* silent mode */ 921: prompt2 = 0; 922: break; 923: #ifdef TABS 924: case 't': /* tab char */ 925: if (*++*argv) 926: tabc = **argv; 927: else 928: --*argv; 929: break; 930: #endif 931: #ifdef TABS 932: case 'v': /* tab fill char */ 933: if (*++*argv) 934: tabfill = **argv; 935: else 936: --*argv; 937: break; 938: #endif 939: #ifdef PAGE 940: case 'w': /* crt width */ 941: ++*argv; 942: n = argnum(argv); 943: if (--n >= 2) 944: ccount = n; 945: break; 946: #endif 947: #ifdef YINT 948: case 'y': /* page on interrupt */ 949: yflg = 1; 950: break; 951: #endif 952: #ifdef USE 953: case '@': /* set "@" filename */ 954: p2 = altfile; 955: p1 = ++*argv; 956: while (*p1 && p2 < &altfile[FNSIZE - 2]) 957: *p2++ = *p1++; 958: if (*p1) { 959: p2 = altfile; 960: putsn(errtext[11]); 961: } 962: *p2 = '\0'; 963: *argv = &p1[-1]; 964: break; 965: #endif 966: #ifdef ALLOC 967: case 'B': /* line buffer size */ 968: ++*argv; 969: n = argnum(argv); 970: if (n >= LBSIZE) 971: lbsize = n; 972: break; 973: #endif 974: #ifdef DEBUG 975: case 'D': /* trace mode -- debug */ 976: tflg = 1; 977: break; 978: #ifdef EXPDMP 979: case 'Q': /* show pattern on quit */ 980: signal(SIGQIT, expdmp); 981: break; 982: #endif 983: #endif 984: #ifdef XED 985: case 'I': /* suppress ID message */ 986: ver = 0; 987: break; 988: case 'P': /* prompt */ 989: p1 = *argv; 990: e_prompt = ++p1; 991: while (*p1++); 992: *argv = &p1[-2]; 993: break; 994: case 'L': /* line number prompt */ 995: p1 = *argv; 996: fmtlno = ++p1; 997: while (*p1++); 998: *argv = &p1[-2]; 999: break; 1000: case 'C': /* screen-clear */ 1001: p1 = *argv; 1002: clears = ++p1; 1003: while (*p1++); 1004: *argv = &p1[-2]; 1005: break; 1006: #ifdef CKPT 1007: case 'R': /* recover */ 1008: ++*argv; 1009: if ((recovry = argnum(argv)) == 0) 1010: recovry = 1; 1011: break; 1012: #endif 1013: case 'O': /* over-ride write perm */ 1014: over ^= 01; 1015: break; 1016: case 'T': /* temp filename */ 1017: p1 = *argv; 1018: tfname = ++p1; 1019: #ifdef PIPE 1020: while (*p1) 1021: if (*p1++ == ':') { 1022: p1[-1] = '\0'; 1023: pfname = p1; 1024: #ifdef CKPT 1025: break; 1026: #endif 1027: } 1028: #endif 1029: #ifdef CKPT 1030: while (*p1) 1031: if (*p1++ == ':') { 1032: p1[-1] = '\0'; 1033: cfname = p1; 1034: } 1035: #endif 1036: *argv = &p1[-1]; 1037: break; 1038: #endif 1039: default: /* tabs stops/illegals */ 1040: if (!**argv || **argv == '-' 1041: #ifdef TABS 1042: || **argv == ',' 1043: #endif 1044: ) 1045: break; 1046: #ifdef TABS 1047: if (**argv < '0' || 1048: **argv > '9') { 1049: #endif 1050: printf("bad flag: -%c\n", 1051: **argv); 1052: exit(1); 1053: #ifdef TABS 1054: } 1055: n = argnum(argv); 1056: settab(n); 1057: #endif 1058: } 1059: } 1060: } else { 1061: p1 = *argv; 1062: p2 = savedfile; 1063: while (*p2++ = *p1++) 1064: if (p2 >= &savedfile[FNSIZE - 2]) { 1065: putsn(errtext[11]); 1066: exit(1); 1067: } 1068: globf2 = 1; 1069: if (fflg) 1070: globp = "a\n"; 1071: else 1072: globp = "r\n"; 1073: } 1074: 1075: 1076: #ifdef YINT 1077: if (iflg) 1078: yflg = 0; 1079: #endif 1080: #ifdef ALLOC 1081: linebuf = sbrk(lbsize); 1082: genbuf = sbrk(lbsize); 1083: #endif 1084: fendcore = sbrk(0); 1085: #ifdef CKPT 1086: if ((n = recovry) == 0) 1087: #endif 1088: n = getpid(); 1089: #ifdef PIPE 1090: tmpname(pfname, n); 1091: #endif 1092: #ifdef CKPT 1093: tmpname(cfname, n); 1094: #endif 1095: tmpname(tfname, n); /* MUST be last call to tmpname */ 1096: #ifdef LOG 1097: logstats.l_uid = getuid(); 1098: time(&logstats.lt_start); 1099: if (prompt2) 1100: ++logstats.l_inter; 1101: if (aflg) 1102: logstats.l_xed = 2; /* magic num for apled */ 1103: #endif 1104: #ifdef CKPT 1105: if (recovry) 1106: recover(); 1107: #endif 1108: editor = ep; 1109: if (prompt2) { 1110: #ifdef CMDS 1111: if ((cmd = open(cmdfil, 1)) > 0) 1112: lseek(cmd, 0L, 2); 1113: else 1114: cmd = 0; 1115: #endif 1116: if (ver) 1117: putsn(ver); /* XED V0.00 ... */ 1118: flush_buf(); 1119: } else 1120: modcount = 0; 1121: #ifdef CMDS 1122: if (cmd && *savedfile) { 1123: write(cmd, "e,", 2); 1124: p1 = savedfile; 1125: while (*p1++); 1126: write(cmd, savedfile, --p1 - savedfile); 1127: write(cmd, "\n", 1); 1128: } 1129: #endif 1130: signals(sigtab1); 1131: setexit(); 1132: if (((int)savint & 01) == 0) 1133: signals(sigtab2); 1134: #ifdef YINT 1135: else 1136: yflg = 0; 1137: #endif 1138: #ifdef CKPT 1139: if (!recovry) 1140: #endif 1141: init(); 1142: setexit(); 1143: cant: do { 1144: commands(0); 1145: } while (are_you_sure()); 1146: if (immflg == 0) { 1147: if (fflg) 1148: if (backup(FILE)) 1149: text_modified = 0; 1150: else 1151: goto cant; 1152: if (text_modified == 0) 1153: backup(-TMP); 1154: else if (modcount && eof) 1155: if (backup(TMP) && prompt2) 1156: if (!curt) 1157: putsn(errtext[56]); 1158: } 1159: delexit(0); 1160: } 1161: 1162: abort() { 1163: register char *p; 1164: register charac c; 1165: 1166: setnoaddr(); 1167: peekc = 0; 1168: p = "ort\n"; 1169: while (*p) 1170: if ((c = getchar()) != *p++) { 1171: peekc = c; 1172: errmsg(25); 1173: } 1174: #ifdef LOG 1175: ++logstats.lc_abort; 1176: #endif 1177: delexit(1); 1178: } 1179: 1180: linep * 1181: address() { 1182: register minus; 1183: register charac c; 1184: register linep *a1, *start; 1185: register n, relerr; 1186: 1187: minus = 0; 1188: a1 = 0; 1189: for ever { 1190: c = getchar(); 1191: if ('0' <= c && c <= '9') { 1192: peekc = c; 1193: n = getnum(); 1194: if (a1 == 0) { 1195: a1 = zero; 1196: n += aflg; 1197: #ifdef LOG 1198: if (!globp) 1199: ++logstats.la_num; 1200: #endif 1201: } 1202: if (minus < 0) 1203: n = -n; 1204: a1 += n; 1205: minus = 0; 1206: continue; 1207: } 1208: relerr = 0; 1209: if (a1 || minus) 1210: relerr++; 1211: switch (c) { 1212: case ' ': 1213: case '\t': 1214: continue; 1215: 1216: case '+': 1217: minus += brcount; 1218: if (a1 == 0) 1219: a1 = dot; 1220: #ifdef LOG 1221: if (!globp) 1222: ++logstats.la_plus; 1223: #endif 1224: continue; 1225: 1226: case '-': 1227: case '^': /* for upwards compatibility */ 1228: minus -= brcount; 1229: if (a1 == 0) 1230: a1 = dot; 1231: #ifdef LOG 1232: if (!globp) 1233: if (c == '^') 1234: ++logstats.la_caret; 1235: else 1236: ++logstats.la_minus; 1237: #endif 1238: continue; 1239: 1240: /* search: */ 1241: case '?': 1242: minus++; 1243: case '/': 1244: compile(c); 1245: if (a1 == 0) 1246: a1 = dot; 1247: if (a1 < zero) 1248: a1 = zero; 1249: if (a1 > dol) 1250: a1 = dol; 1251: start = a1; 1252: #ifdef LOG 1253: if (!globp) 1254: if (minus) 1255: ++logstats.la_query; 1256: else 1257: ++logstats.la_slash; 1258: #endif 1259: for ever { 1260: if (minus == 0) { 1261: if (++a1 > dol) 1262: a1 = zero; 1263: } else { 1264: if (--a1 < zero) 1265: a1 = dol; 1266: } 1267: if (execute(0, a1)) { 1268: minus = 0; 1269: relerr = 0; 1270: break; 1271: } 1272: if (a1\x00 x 74160