Blob
1 /*2 * Editor3 */4 #include <u.h>5 #include <libc.h>6 #include <bio.h>7 #include <regexp.h>9 #undef EOF /* stdio? */11 enum12 {13 FNSIZE = 128, /* file name */14 LBSIZE = 4096, /* max line size */15 BLKSIZE = 4096, /* block size in temp file */16 NBLK = 8191, /* max size of temp file */17 ESIZE = 256, /* max size of reg exp */18 GBSIZE = 256, /* max size of global command */19 MAXSUB = 9, /* max number of sub reg exp */20 ESCFLG = 0xFFFF, /* escape Rune - user defined code */21 EOF = -122 };24 void (*oldhup)(int);25 void (*oldquit)(int);26 int* addr1;27 int* addr2;28 int anymarks;29 int col;30 long count;31 int* dol;32 int* dot;33 int fchange;34 char file[FNSIZE];35 Rune genbuf[LBSIZE];36 int given;37 Rune* globp;38 int iblock;39 int ichanged;40 int io;41 Biobuf iobuf;42 int lastc;43 char line[70];44 Rune* linebp;45 Rune linebuf[LBSIZE];46 int listf;47 int listn;48 Rune* loc1;49 Rune* loc2;50 int names[26];51 int nleft;52 int oblock;53 int oflag;54 Reprog *pattern;55 int peekc;56 int pflag;57 int rescuing;58 Rune rhsbuf[LBSIZE/2];59 char savedfile[FNSIZE];60 jmp_buf savej;61 int subnewa;62 int subolda;63 Resub subexp[MAXSUB];64 char* tfname;65 int tline;66 int waiting;67 int wrapp;68 int* zero;70 char Q[] = "";71 char T[] = "TMP";72 char WRERR[] = "WRITE ERROR";73 int bpagesize = 20;74 char hex[] = "0123456789abcdef";75 char* linp = line;76 ulong nlall = 128;77 int tfile = -1;78 int vflag = 1;80 void add(int);81 int* address(void);82 int append(int(*)(void), int*);83 void browse(void);84 void callunix(void);85 void commands(void);86 void compile(int);87 int compsub(void);88 void dosub(void);89 void error(char*);90 int match(int*);91 void exfile(int);92 void filename(int);93 Rune* getblock(int, int);94 int getchr(void);95 int getcopy(void);96 int getfile(void);97 Rune* getline(int);98 int getnum(void);99 int getsub(void);100 int gettty(void);101 void global(int);102 void init(void);103 void join(void);104 void move(int);105 void newline(void);106 void nonzero(void);107 void notifyf(void*, char*);108 Rune* place(Rune*, Rune*, Rune*);109 void printcom(void);110 void putchr(int);111 void putd(void);112 void putfile(void);113 int putline(void);114 void putshst(Rune*);115 void putst(char*);116 void quit(void);117 void rdelete(int*, int*);118 void regerror(char *);119 void reverse(int*, int*);120 void setnoaddr(void);121 void setwide(void);122 void squeeze(int);123 void substitute(int);125 Rune La[] = { 'a', 0 };126 Rune Lr[] = { 'r', 0 };128 char tmp[] = "/var/tmp/eXXXXX";130 void131 main(int argc, char *argv[])132 {133 char *p1, *p2;135 notify(notifyf);136 ARGBEGIN {137 case 'o':138 oflag = 1;139 vflag = 0;140 break;141 } ARGEND143 USED(argc);144 if(*argv && (strcmp(*argv, "-") == 0)) {145 argv++;146 vflag = 0;147 }148 if(oflag) {149 p1 = "/dev/stdout";150 p2 = savedfile;151 while(*p2++ = *p1++)152 ;153 globp = La;154 } else155 if(*argv) {156 p1 = *argv;157 p2 = savedfile;158 while(*p2++ = *p1++)159 if(p2 >= &savedfile[sizeof(savedfile)])160 p2--;161 globp = Lr;162 }163 zero = malloc((nlall+5)*sizeof(int*));164 tfname = mktemp(tmp);165 init();166 setjmp(savej);167 commands();168 quit();169 }171 void172 commands(void)173 {174 int *a1, c, temp;175 char lastsep;176 Dir *d;178 for(;;) {179 if(pflag) {180 pflag = 0;181 addr1 = addr2 = dot;182 printcom();183 }184 c = '\n';185 for(addr1 = 0;;) {186 lastsep = c;187 a1 = address();188 c = getchr();189 if(c != ',' && c != ';')190 break;191 if(lastsep == ',')192 error(Q);193 if(a1 == 0) {194 a1 = zero+1;195 if(a1 > dol)196 a1--;197 }198 addr1 = a1;199 if(c == ';')200 dot = a1;201 }202 if(lastsep != '\n' && a1 == 0)203 a1 = dol;204 if((addr2=a1) == 0) {205 given = 0;206 addr2 = dot;207 } else208 given = 1;209 if(addr1 == 0)210 addr1 = addr2;211 switch(c) {213 case 'a':214 add(0);215 continue;217 case 'b':218 nonzero();219 browse();220 continue;222 case 'c':223 nonzero();224 newline();225 rdelete(addr1, addr2);226 append(gettty, addr1-1);227 continue;229 case 'd':230 nonzero();231 newline();232 rdelete(addr1, addr2);233 continue;235 case 'E':236 fchange = 0;237 c = 'e';238 case 'e':239 setnoaddr();240 if(vflag && fchange) {241 fchange = 0;242 error(Q);243 }244 filename(c);245 init();246 addr2 = zero;247 goto caseread;249 case 'f':250 setnoaddr();251 filename(c);252 putst(savedfile);253 continue;255 case 'g':256 global(1);257 continue;259 case 'i':260 add(-1);261 continue;264 case 'j':265 if(!given)266 addr2++;267 newline();268 join();269 continue;271 case 'k':272 nonzero();273 c = getchr();274 if(c < 'a' || c > 'z')275 error(Q);276 newline();277 names[c-'a'] = *addr2 & ~01;278 anymarks |= 01;279 continue;281 case 'm':282 move(0);283 continue;285 case 'n':286 listn++;287 newline();288 printcom();289 continue;291 case '\n':292 if(a1==0) {293 a1 = dot+1;294 addr2 = a1;295 addr1 = a1;296 }297 if(lastsep==';')298 addr1 = a1;299 printcom();300 continue;302 case 'l':303 listf++;304 case 'p':305 case 'P':306 newline();307 printcom();308 continue;310 case 'Q':311 fchange = 0;312 case 'q':313 setnoaddr();314 newline();315 quit();317 case 'r':318 filename(c);319 caseread:320 if((io=open(file, OREAD)) < 0) {321 lastc = '\n';322 error(file);323 }324 if((d = dirfstat(io)) != nil){325 if(d->mode & DMAPPEND)326 print("warning: %s is append only\n", file);327 free(d);328 }329 Binit(&iobuf, io, OREAD);330 setwide();331 squeeze(0);332 c = zero != dol;333 append(getfile, addr2);334 exfile(OREAD);336 fchange = c;337 continue;339 case 's':340 nonzero();341 substitute(globp != 0);342 continue;344 case 't':345 move(1);346 continue;348 case 'u':349 nonzero();350 newline();351 if((*addr2&~01) != subnewa)352 error(Q);353 *addr2 = subolda;354 dot = addr2;355 continue;357 case 'v':358 global(0);359 continue;361 case 'W':362 wrapp++;363 case 'w':364 setwide();365 squeeze(dol>zero);366 temp = getchr();367 if(temp != 'q' && temp != 'Q') {368 peekc = temp;369 temp = 0;370 }371 filename(c);372 if(!wrapp ||373 ((io = open(file, OWRITE)) == -1) ||374 ((seek(io, 0L, 2)) == -1))375 if((io = create(file, OWRITE, 0666)) < 0)376 error(file);377 Binit(&iobuf, io, OWRITE);378 wrapp = 0;379 if(dol > zero)380 putfile();381 exfile(OWRITE);382 if(addr1<=zero+1 && addr2==dol)383 fchange = 0;384 if(temp == 'Q')385 fchange = 0;386 if(temp)387 quit();388 continue;390 case '=':391 setwide();392 squeeze(0);393 newline();394 count = addr2 - zero;395 putd();396 putchr('\n');397 continue;399 case '!':400 callunix();401 continue;403 case EOF:404 return;406 }407 error(Q);408 }409 }411 void412 printcom(void)413 {414 int *a1;416 nonzero();417 a1 = addr1;418 do {419 if(listn) {420 count = a1-zero;421 putd();422 putchr('\t');423 }424 putshst(getline(*a1++));425 } while(a1 <= addr2);426 dot = addr2;427 listf = 0;428 listn = 0;429 pflag = 0;430 }432 int*433 address(void)434 {435 int sign, *a, opcnt, nextopand, *b, c;437 nextopand = -1;438 sign = 1;439 opcnt = 0;440 a = dot;441 do {442 do {443 c = getchr();444 } while(c == ' ' || c == '\t');445 if(c >= '0' && c <= '9') {446 peekc = c;447 if(!opcnt)448 a = zero;449 a += sign*getnum();450 } else451 switch(c) {452 case '$':453 a = dol;454 case '.':455 if(opcnt)456 error(Q);457 break;458 case '\'':459 c = getchr();460 if(opcnt || c < 'a' || c > 'z')461 error(Q);462 a = zero;463 do {464 a++;465 } while(a <= dol && names[c-'a'] != (*a & ~01));466 break;467 case '?':468 sign = -sign;469 case '/':470 compile(c);471 b = a;472 for(;;) {473 a += sign;474 if(a <= zero)475 a = dol;476 if(a > dol)477 a = zero;478 if(match(a))479 break;480 if(a == b)481 error(Q);482 }483 break;484 default:485 if(nextopand == opcnt) {486 a += sign;487 if(a < zero || dol < a)488 continue; /* error(Q); */489 }490 if(c != '+' && c != '-' && c != '^') {491 peekc = c;492 if(opcnt == 0)493 a = 0;494 return a;495 }496 sign = 1;497 if(c != '+')498 sign = -sign;499 nextopand = ++opcnt;500 continue;501 }502 sign = 1;503 opcnt++;504 } while(zero <= a && a <= dol);505 error(Q);506 return 0;507 }509 int510 getnum(void)511 {512 int r, c;514 r = 0;515 for(;;) {516 c = getchr();517 if(c < '0' || c > '9')518 break;519 r = r*10 + (c-'0');520 }521 peekc = c;522 return r;523 }525 void526 setwide(void)527 {528 if(!given) {529 addr1 = zero + (dol>zero);530 addr2 = dol;531 }532 }534 void535 setnoaddr(void)536 {537 if(given)538 error(Q);539 }541 void542 nonzero(void)543 {544 squeeze(1);545 }547 void548 squeeze(int i)549 {550 if(addr1 < zero+i || addr2 > dol || addr1 > addr2)551 error(Q);552 }554 void555 newline(void)556 {557 int c;559 c = getchr();560 if(c == '\n' || c == EOF)561 return;562 if(c == 'p' || c == 'l' || c == 'n') {563 pflag++;564 if(c == 'l')565 listf++;566 else567 if(c == 'n')568 listn++;569 c = getchr();570 if(c == '\n')571 return;572 }573 error(Q);574 }576 void577 filename(int comm)578 {579 char *p1, *p2;580 Rune rune;581 int c;583 count = 0;584 c = getchr();585 if(c == '\n' || c == EOF) {586 p1 = savedfile;587 if(*p1 == 0 && comm != 'f')588 error(Q);589 p2 = file;590 while(*p2++ = *p1++)591 ;592 return;593 }594 if(c != ' ')595 error(Q);596 while((c=getchr()) == ' ')597 ;598 if(c == '\n')599 error(Q);600 p1 = file;601 do {602 if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)603 error(Q);604 rune = c;605 p1 += runetochar(p1, &rune);606 } while((c=getchr()) != '\n');607 *p1 = 0;608 if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {609 p1 = savedfile;610 p2 = file;611 while(*p1++ = *p2++)612 ;613 }614 }616 void617 exfile(int om)618 {620 if(om == OWRITE)621 if(Bflush(&iobuf) < 0)622 error(Q);623 close(io);624 io = -1;625 if(vflag) {626 putd();627 putchr('\n');628 }629 }631 void632 error1(char *s)633 {634 int c;636 wrapp = 0;637 listf = 0;638 listn = 0;639 count = 0;640 seek(0, 0, 2);641 pflag = 0;642 if(globp)643 lastc = '\n';644 globp = 0;645 peekc = lastc;646 if(lastc)647 for(;;) {648 c = getchr();649 if(c == '\n' || c == EOF)650 break;651 }652 if(io > 0) {653 close(io);654 io = -1;655 }656 putchr('?');657 putst(s);658 }660 void661 error(char *s)662 {663 error1(s);664 longjmp(savej, 1);665 }667 void668 rescue(void)669 {670 rescuing = 1;671 if(dol > zero) {672 addr1 = zero+1;673 addr2 = dol;674 io = create("ed.hup", OWRITE, 0666);675 if(io > 0){676 Binit(&iobuf, io, OWRITE);677 putfile();678 }679 }680 fchange = 0;681 quit();682 }684 void685 notifyf(void *a, char *s)686 {687 if(strcmp(s, "interrupt") == 0){688 if(rescuing || waiting)689 noted(NCONT);690 putchr('\n');691 lastc = '\n';692 error1(Q);693 notejmp(a, savej, 0);694 }695 if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){696 if(rescuing)697 noted(NDFLT);698 rescue();699 }700 if(strstr(s, "child"))701 noted(NCONT);702 fprint(2, "ed: note: %s\n", s);703 abort();704 }706 int707 getchr(void)708 {709 char s[UTFmax];710 int i;711 Rune r;713 if(lastc = peekc) {714 peekc = 0;715 return lastc;716 }717 if(globp) {718 if((lastc=*globp++) != 0)719 return lastc;720 globp = 0;721 return EOF;722 }723 for(i=0;;) {724 if(read(0, s+i, 1) <= 0)725 return lastc = EOF;726 i++;727 if(fullrune(s, i))728 break;730 }731 chartorune(&r, s);732 lastc = r;733 return lastc;734 }736 int737 gety(void)738 {739 int c;740 Rune *gf, *p;742 p = linebuf;743 gf = globp;744 for(;;) {745 c = getchr();746 if(c == '\n') {747 *p = 0;748 return 0;749 }750 if(c == EOF) {751 if(gf)752 peekc = c;753 return c;754 }755 if(c == 0)756 continue;757 *p++ = c;758 if(p >= &linebuf[LBSIZE-2])759 error(Q);760 }761 }763 int764 gettty(void)765 {766 int rc;768 rc = gety();769 if(rc)770 return rc;771 if(linebuf[0] == '.' && linebuf[1] == 0)772 return EOF;773 return 0;774 }776 int777 getfile(void)778 {779 int c;780 Rune *lp;782 lp = linebuf;783 do {784 c = Bgetrune(&iobuf);785 if(c < 0) {786 if(lp > linebuf) {787 putst("'\\n' appended");788 c = '\n';789 } else790 return EOF;791 }792 if(lp >= &linebuf[LBSIZE]) {793 lastc = '\n';794 error(Q);795 }796 *lp++ = c;797 count++;798 } while(c != '\n');799 lp[-1] = 0;800 return 0;801 }803 void804 putfile(void)805 {806 int *a1;807 Rune *lp;808 long c;810 a1 = addr1;811 do {812 lp = getline(*a1++);813 for(;;) {814 count++;815 c = *lp++;816 if(c == 0) {817 if(Bputrune(&iobuf, '\n') < 0)818 error(Q);819 break;820 }821 if(Bputrune(&iobuf, c) < 0)822 error(Q);823 }824 } while(a1 <= addr2);825 if(Bflush(&iobuf) < 0)826 error(Q);827 }829 int830 append(int (*f)(void), int *a)831 {832 int *a1, *a2, *rdot, nline, tl;834 nline = 0;835 dot = a;836 while((*f)() == 0) {837 if((dol-zero) >= nlall) {838 nlall += 512;839 a1 = realloc(zero, (nlall+5)*sizeof(int*));840 if(a1 == 0) {841 error("MEM?");842 rescue();843 }844 tl = a1 - zero; /* relocate pointers */845 zero += tl;846 addr1 += tl;847 addr2 += tl;848 dol += tl;849 dot += tl;850 }851 tl = putline();852 nline++;853 a1 = ++dol;854 a2 = a1+1;855 rdot = ++dot;856 while(a1 > rdot)857 *--a2 = *--a1;858 *rdot = tl;859 }860 return nline;861 }863 void864 add(int i)865 {866 if(i && (given || dol > zero)) {867 addr1--;868 addr2--;869 }870 squeeze(0);871 newline();872 append(gettty, addr2);873 }875 void876 browse(void)877 {878 int forward, n;879 static int bformat, bnum; /* 0 */881 forward = 1;882 peekc = getchr();883 if(peekc != '\n'){884 if(peekc == '-' || peekc == '+') {885 if(peekc == '-')886 forward = 0;887 getchr();888 }889 n = getnum();890 if(n > 0)891 bpagesize = n;892 }893 newline();894 if(pflag) {895 bformat = listf;896 bnum = listn;897 } else {898 listf = bformat;899 listn = bnum;900 }901 if(forward) {902 addr1 = addr2;903 addr2 += bpagesize;904 if(addr2 > dol)905 addr2 = dol;906 } else {907 addr1 = addr2-bpagesize;908 if(addr1 <= zero)909 addr1 = zero+1;910 }911 printcom();912 }914 void915 callunix(void)916 {917 int c, pid;918 Rune rune;919 char buf[512];920 char *p;922 setnoaddr();923 p = buf;924 while((c=getchr()) != EOF && c != '\n')925 if(p < &buf[sizeof(buf) - 6]) {926 rune = c;927 p += runetochar(p, &rune);928 }929 *p = 0;930 pid = fork();931 if(pid == 0) {932 execlp("rc", "rc", "-c", buf, (char*)0);933 sysfatal("exec failed: %r");934 exits("execl failed");935 }936 waiting = 1;937 while(waitpid() != pid)938 ;939 waiting = 0;940 if(vflag)941 putst("!");942 }944 void945 quit(void)946 {947 if(vflag && fchange && dol!=zero) {948 fchange = 0;949 error(Q);950 }951 remove(tfname);952 exits(0);953 }955 void956 onquit(int sig)957 {958 USED(sig);959 quit();960 }962 void963 rdelete(int *ad1, int *ad2)964 {965 int *a1, *a2, *a3;967 a1 = ad1;968 a2 = ad2+1;969 a3 = dol;970 dol -= a2 - a1;971 do {972 *a1++ = *a2++;973 } while(a2 <= a3);974 a1 = ad1;975 if(a1 > dol)976 a1 = dol;977 dot = a1;978 fchange = 1;979 }981 void982 gdelete(void)983 {984 int *a1, *a2, *a3;986 a3 = dol;987 for(a1=zero; (*a1&01)==0; a1++)988 if(a1>=a3)989 return;990 for(a2=a1+1; a2<=a3;) {991 if(*a2 & 01) {992 a2++;993 dot = a1;994 } else995 *a1++ = *a2++;996 }997 dol = a1-1;998 if(dot > dol)999 dot = dol;1000 fchange = 1;1001 }1003 Rune*1004 getline(int tl)1005 {1006 Rune *lp, *bp;1007 int nl;1009 lp = linebuf;1010 bp = getblock(tl, OREAD);1011 nl = nleft;1012 tl &= ~((BLKSIZE/2) - 1);1013 while(*lp++ = *bp++) {1014 nl -= sizeof(Rune);1015 if(nl == 0) {1016 bp = getblock(tl += BLKSIZE/2, OREAD);1017 nl = nleft;1018 }1019 }1020 return linebuf;1021 }1023 int1024 putline(void)1025 {1026 Rune *lp, *bp;1027 int nl, tl;1029 fchange = 1;1030 lp = linebuf;1031 tl = tline;1032 bp = getblock(tl, OWRITE);1033 nl = nleft;1034 tl &= ~((BLKSIZE/2)-1);1035 while(*bp = *lp++) {1036 if(*bp++ == '\n') {1037 bp[-1] = 0;1038 linebp = lp;1039 break;1040 }1041 nl -= sizeof(Rune);1042 if(nl == 0) {1043 tl += BLKSIZE/2;1044 bp = getblock(tl, OWRITE);1045 nl = nleft;1046 }1047 }1048 nl = tline;1049 tline += ((lp-linebuf) + 03) & 077776;1050 return nl;1051 }1053 void1054 blkio(int b, uchar *buf, int isread)1055 {1056 int n;1058 seek(tfile, b*BLKSIZE, 0);1059 if(isread)1060 n = read(tfile, buf, BLKSIZE);1061 else1062 n = write(tfile, buf, BLKSIZE);1063 if(n != BLKSIZE)1064 error(T);1065 }1067 Rune*1068 getblock(int atl, int iof)1069 {1070 int bno, off;1072 static uchar ibuff[BLKSIZE];1073 static uchar obuff[BLKSIZE];1075 bno = atl / (BLKSIZE/2);1076 off = (atl<<1) & (BLKSIZE-1) & ~03;1077 if(bno >= NBLK) {1078 lastc = '\n';1079 error(T);1080 }1081 nleft = BLKSIZE - off;1082 if(bno == iblock) {1083 ichanged |= iof;1084 return (Rune*)(ibuff+off);1085 }1086 if(bno == oblock)1087 return (Rune*)(obuff+off);1088 if(iof == OREAD) {1089 if(ichanged)1090 blkio(iblock, ibuff, 0);1091 ichanged = 0;1092 iblock = bno;1093 blkio(bno, ibuff, 1);1094 return (Rune*)(ibuff+off);1095 }1096 if(oblock >= 0)1097 blkio(oblock, obuff, 0);1098 oblock = bno;1099 return (Rune*)(obuff+off);1100 }1102 void1103 init(void)1104 {1105 int *markp;1107 close(tfile);1108 tline = 2;1109 for(markp = names; markp < &names[26]; )1110 *markp++ = 0;1111 subnewa = 0;1112 anymarks = 0;1113 iblock = -1;1114 oblock = -1;1115 ichanged = 0;1116 if((tfile = create(tfname, ORDWR, 0600)) < 0){1117 error1(T);1118 exits(0);1119 }1120 dot = dol = zero;1121 }1123 void1124 global(int k)1125 {1126 Rune *gp, globuf[GBSIZE];1127 int c, *a1;1129 if(globp)1130 error(Q);1131 setwide();1132 squeeze(dol > zero);1133 c = getchr();1134 if(c == '\n')1135 error(Q);1136 compile(c);1137 gp = globuf;1138 while((c=getchr()) != '\n') {1139 if(c == EOF)1140 error(Q);1141 if(c == '\\') {1142 c = getchr();1143 if(c != '\n')1144 *gp++ = '\\';1145 }1146 *gp++ = c;1147 if(gp >= &globuf[GBSIZE-2])1148 error(Q);1149 }1150 if(gp == globuf)1151 *gp++ = 'p';1152 *gp++ = '\n';1153 *gp = 0;1154 for(a1=zero; a1<=dol; a1++) {1155 *a1 &= ~01;1156 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)1157 *a1 |= 01;1158 }1160 /*1161 * Special case: g/.../d (avoid n^2 algorithm)1162 */1163 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {1164 gdelete();1165 return;1166 }1167 for(a1=zero; a1<=dol; a1++) {1168 if(*a1 & 01) {1169 *a1 &= ~01;1170 dot = a1;1171 globp = globuf;1172 commands();1173 a1 = zero;1174 }1175 }1176 }1178 void1179 join(void)1180 {1181 Rune *gp, *lp;1182 int *a1;1184 nonzero();1185 gp = genbuf;1186 for(a1=addr1; a1<=addr2; a1++) {1187 lp = getline(*a1);1188 while(*gp = *lp++)1189 if(gp++ >= &genbuf[LBSIZE-2])1190 error(Q);1191 }1192 lp = linebuf;1193 gp = genbuf;1194 while(*lp++ = *gp++)1195 ;1196 *addr1 = putline();1197 if(addr1 < addr2)1198 rdelete(addr1+1, addr2);1199 dot = addr1;1200 }1202 void1203 substitute(int inglob)1204 {1205 int *mp, *a1, nl, gsubf, n;1207 n = getnum(); /* OK even if n==0 */1208 gsubf = compsub();1209 for(a1 = addr1; a1 <= addr2; a1++) {1210 if(match(a1)){1211 int *ozero;1212 int m = n;1214 do {1215 int span = loc2-loc1;1217 if(--m <= 0) {1218 dosub();1219 if(!gsubf)1220 break;1221 if(span == 0) { /* null RE match */1222 if(*loc2 == 0)1223 break;1224 loc2++;1225 }1226 }1227 } while(match(0));1228 if(m <= 0) {1229 inglob |= 01;1230 subnewa = putline();1231 *a1 &= ~01;1232 if(anymarks) {1233 for(mp=names; mp<&names[26]; mp++)1234 if(*mp == *a1)1235 *mp = subnewa;1236 }1237 subolda = *a1;1238 *a1 = subnewa;1239 ozero = zero;1240 nl = append(getsub, a1);1241 addr2 += nl;1242 nl += zero-ozero;1243 a1 += nl;1244 }1245 }1246 }1247 if(inglob == 0)1248 error(Q);1249 }1251 int1252 compsub(void)1253 {1254 int seof, c;1255 Rune *p;1257 seof = getchr();1258 if(seof == '\n' || seof == ' ')1259 error(Q);1260 compile(seof);1261 p = rhsbuf;1262 for(;;) {1263 c = getchr();1264 if(c == '\\') {1265 c = getchr();1266 *p++ = ESCFLG;1267 if(p >= &rhsbuf[LBSIZE/2])1268 error(Q);1269 } else1270 if(c == '\n' && (!globp || !globp[0])) {1271 peekc = c;1272 pflag++;1273 break;1274 } else1275 if(c == seof)1276 break;1277 *p++ = c;1278 if(p >= &rhsbuf[LBSIZE/2])1279 error(Q);1280 }1281 *p = 0;1282 peekc = getchr();1283 if(peekc == 'g') {1284 peekc = 0;1285 newline();1286 return 1;1287 }1288 newline();1289 return 0;1290 }1292 int1293 getsub(void)1294 {1295 Rune *p1, *p2;1297 p1 = linebuf;1298 if((p2 = linebp) == 0)1299 return EOF;1300 while(*p1++ = *p2++)1301 ;1302 linebp = 0;1303 return 0;1304 }1306 void1307 dosub(void)1308 {1309 Rune *lp, *sp, *rp;1310 int c, n;1312 lp = linebuf;1313 sp = genbuf;1314 rp = rhsbuf;1315 while(lp < loc1)1316 *sp++ = *lp++;1317 while(c = *rp++) {1318 if(c == '&'){1319 sp = place(sp, loc1, loc2);1320 continue;1321 }1322 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {1323 n = c-'0';1324 if(subexp[n].s.rsp && subexp[n].e.rep) {1325 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);1326 continue;1327 }1328 error(Q);1329 }1330 *sp++ = c;1331 if(sp >= &genbuf[LBSIZE])1332 error(Q);1333 }1334 lp = loc2;1335 loc2 = sp - genbuf + linebuf;1336 while(*sp++ = *lp++)1337 if(sp >= &genbuf[LBSIZE])1338 error(Q);1339 lp = linebuf;1340 sp = genbuf;1341 while(*lp++ = *sp++)1342 ;1343 }1345 Rune*1346 place(Rune *sp, Rune *l1, Rune *l2)1347 {1349 while(l1 < l2) {1350 *sp++ = *l1++;1351 if(sp >= &genbuf[LBSIZE])1352 error(Q);1353 }1354 return sp;1355 }1357 void1358 move(int cflag)1359 {1360 int *adt, *ad1, *ad2;1362 nonzero();1363 if((adt = address())==0) /* address() guarantees addr is in range */1364 error(Q);1365 newline();1366 if(cflag) {1367 int *ozero, delta;1368 ad1 = dol;1369 ozero = zero;1370 append(getcopy, ad1++);1371 ad2 = dol;1372 delta = zero - ozero;1373 ad1 += delta;1374 adt += delta;1375 } else {1376 ad2 = addr2;1377 for(ad1 = addr1; ad1 <= ad2;)1378 *ad1++ &= ~01;1379 ad1 = addr1;1380 }1381 ad2++;1382 if(adt<ad1) {1383 dot = adt + (ad2-ad1);1384 if((++adt)==ad1)1385 return;1386 reverse(adt, ad1);1387 reverse(ad1, ad2);1388 reverse(adt, ad2);1389 } else1390 if(adt >= ad2) {1391 dot = adt++;1392 reverse(ad1, ad2);1393 reverse(ad2, adt);1394 reverse(ad1, adt);1395 } else1396 error(Q);1397 fchange = 1;1398 }1400 void1401 reverse(int *a1, int *a2)1402 {1403 int t;1405 for(;;) {1406 t = *--a2;1407 if(a2 <= a1)1408 return;1409 *a2 = *a1;1410 *a1++ = t;1411 }1412 }1414 int1415 getcopy(void)1416 {1417 if(addr1 > addr2)1418 return EOF;1419 getline(*addr1++);1420 return 0;1421 }1423 void1424 compile(int eof)1425 {1426 Rune c;1427 char *ep;1428 char expbuf[ESIZE];1430 if((c = getchr()) == '\n') {1431 peekc = c;1432 c = eof;1433 }1434 if(c == eof) {1435 if(!pattern)1436 error(Q);1437 return;1438 }1439 if(pattern) {1440 free(pattern);1441 pattern = 0;1442 }1443 ep = expbuf;1444 do {1445 if(c == '\\') {1446 if(ep >= expbuf+sizeof(expbuf)) {1447 error(Q);1448 return;1449 }1450 ep += runetochar(ep, &c);1451 if((c = getchr()) == '\n') {1452 error(Q);1453 return;1454 }1455 }1456 if(ep >= expbuf+sizeof(expbuf)) {1457 error(Q);1458 return;1459 }1460 ep += runetochar(ep, &c);1461 } while((c = getchr()) != eof && c != '\n');1462 if(c == '\n')1463 peekc = c;1464 *ep = 0;1465 pattern = regcomp(expbuf);1466 }1468 int1469 match(int *addr)1470 {1471 if(!pattern)1472 return 0;1473 if(addr){1474 if(addr == zero)1475 return 0;1476 subexp[0].s.rsp = getline(*addr);1477 } else1478 subexp[0].s.rsp = loc2;1479 subexp[0].e.rep = 0;1480 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {1481 loc1 = subexp[0].s.rsp;1482 loc2 = subexp[0].e.rep;1483 return 1;1484 }1485 loc1 = loc2 = 0;1486 return 0;1488 }1490 void1491 putd(void)1492 {1493 int r;1495 r = count%10;1496 count /= 10;1497 if(count)1498 putd();1499 putchr(r + '0');1500 }1502 void1503 putst(char *sp)1504 {1505 Rune r;1507 col = 0;1508 for(;;) {1509 sp += chartorune(&r, sp);1510 if(r == 0)1511 break;1512 putchr(r);1513 }1514 putchr('\n');1515 }1517 void1518 putshst(Rune *sp)1519 {1520 col = 0;1521 while(*sp)1522 putchr(*sp++);1523 putchr('\n');1524 }1526 void1527 putchr(int ac)1528 {1529 char *lp;1530 int c;1531 Rune rune;1533 lp = linp;1534 c = ac;1535 if(listf) {1536 if(c == '\n') {1537 if(linp != line && linp[-1] == ' ') {1538 *lp++ = '\\';1539 *lp++ = 'n';1540 }1541 } else {1542 if(col > (72-6-2)) {1543 col = 8;1544 *lp++ = '\\';1545 *lp++ = '\n';1546 *lp++ = '\t';1547 }1548 col++;1549 if(c=='\b' || c=='\t' || c=='\\') {1550 *lp++ = '\\';1551 if(c == '\b')1552 c = 'b';1553 else1554 if(c == '\t')1555 c = 't';1556 col++;1557 } else1558 if(c<' ' || c>='\177') {1559 *lp++ = '\\';1560 *lp++ = 'x';1561 *lp++ = hex[c>>12];1562 *lp++ = hex[c>>8&0xF];1563 *lp++ = hex[c>>4&0xF];1564 c = hex[c&0xF];1565 col += 5;1566 }1567 }1568 }1570 rune = c;1571 lp += runetochar(lp, &rune);1573 if(c == '\n' || lp >= &line[sizeof(line)-5]) {1574 linp = line;1575 write(oflag? 2: 1, line, lp-line);1576 return;1577 }1578 linp = lp;1579 }1581 char*1582 mktemp(char *as)1583 {1584 char *s;1585 unsigned pid;1586 int i;1588 pid = getpid();1589 s = as;1590 while(*s++)1591 ;1592 s--;1593 while(*--s == 'X') {1594 *s = pid % 10 + '0';1595 pid /= 10;1596 }1597 s++;1598 i = 'a';1599 while(access(as, 0) != -1) {1600 if(i == 'z')1601 return "/";1602 *s = i++;1603 }1604 return as;1605 }1607 void1608 regerror(char *s)1609 {1610 USED(s);1611 error(Q);1612 }