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/sizeof(Rune)];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, d;834 nline = 0;835 dot = a;836 while((*f)() == 0) {837 if((dol-zero) >= nlall) {838 nlall += 512;839 a1 = realloc(zero, (nlall+50)*sizeof(int*));840 if(a1 == 0) {841 error("MEM?");842 rescue();843 }844 /* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */845 d = addr1 - zero;846 addr1 = a1 + d;847 d = addr2 - zero;848 addr2 = a1 + d;849 d = dol - zero;850 dol = a1 + d;851 d = dot - zero;852 dot = a1 + d;853 zero = a1;854 }855 d = putline();856 nline++;857 a1 = ++dol;858 a2 = a1+1;859 rdot = ++dot;860 while(a1 > rdot)861 *--a2 = *--a1;862 *rdot = d;863 }864 return nline;865 }867 void868 add(int i)869 {870 if(i && (given || dol > zero)) {871 addr1--;872 addr2--;873 }874 squeeze(0);875 newline();876 append(gettty, addr2);877 }879 void880 browse(void)881 {882 int forward, n;883 static int bformat, bnum; /* 0 */885 forward = 1;886 peekc = getchr();887 if(peekc != '\n'){888 if(peekc == '-' || peekc == '+') {889 if(peekc == '-')890 forward = 0;891 getchr();892 }893 n = getnum();894 if(n > 0)895 bpagesize = n;896 }897 newline();898 if(pflag) {899 bformat = listf;900 bnum = listn;901 } else {902 listf = bformat;903 listn = bnum;904 }905 if(forward) {906 addr1 = addr2;907 addr2 += bpagesize;908 if(addr2 > dol)909 addr2 = dol;910 } else {911 addr1 = addr2-bpagesize;912 if(addr1 <= zero)913 addr1 = zero+1;914 }915 printcom();916 }918 void919 callunix(void)920 {921 int c, pid;922 Rune rune;923 char buf[512];924 char *p;926 setnoaddr();927 p = buf;928 while((c=getchr()) != EOF && c != '\n')929 if(p < &buf[sizeof(buf) - 6]) {930 rune = c;931 p += runetochar(p, &rune);932 }933 *p = 0;934 pid = fork();935 if(pid == 0) {936 execlp("rc", "rc", "-c", buf, (char*)0);937 sysfatal("exec failed: %r");938 exits("execl failed");939 }940 waiting = 1;941 while(waitpid() != pid)942 ;943 waiting = 0;944 if(vflag)945 putst("!");946 }948 void949 quit(void)950 {951 if(vflag && fchange && dol!=zero) {952 fchange = 0;953 error(Q);954 }955 remove(tfname);956 exits(0);957 }959 void960 onquit(int sig)961 {962 USED(sig);963 quit();964 }966 void967 rdelete(int *ad1, int *ad2)968 {969 int *a1, *a2, *a3;971 a1 = ad1;972 a2 = ad2+1;973 a3 = dol;974 dol -= a2 - a1;975 do {976 *a1++ = *a2++;977 } while(a2 <= a3);978 a1 = ad1;979 if(a1 > dol)980 a1 = dol;981 dot = a1;982 fchange = 1;983 }985 void986 gdelete(void)987 {988 int *a1, *a2, *a3;990 a3 = dol;991 for(a1=zero; (*a1&01)==0; a1++)992 if(a1>=a3)993 return;994 for(a2=a1+1; a2<=a3;) {995 if(*a2 & 01) {996 a2++;997 dot = a1;998 } else999 *a1++ = *a2++;1000 }1001 dol = a1-1;1002 if(dot > dol)1003 dot = dol;1004 fchange = 1;1005 }1007 Rune*1008 getline(int tl)1009 {1010 Rune *lp, *bp;1011 int nl;1013 lp = linebuf;1014 bp = getblock(tl, OREAD);1015 nl = nleft;1016 tl &= ~((BLKSIZE/sizeof(Rune)) - 1);1017 while(*lp++ = *bp++) {1018 nl -= sizeof(Rune);1019 if(nl == 0) {1020 bp = getblock(tl += BLKSIZE/sizeof(Rune), OREAD);1021 nl = nleft;1022 }1023 }1024 return linebuf;1025 }1027 int1028 putline(void)1029 {1030 Rune *lp, *bp;1031 int nl, tl;1033 fchange = 1;1034 lp = linebuf;1035 tl = tline;1036 bp = getblock(tl, OWRITE);1037 nl = nleft;1038 tl &= ~((BLKSIZE/sizeof(Rune))-1);1039 while(*bp = *lp++) {1040 if(*bp++ == '\n') {1041 bp[-1] = 0;1042 linebp = lp;1043 break;1044 }1045 nl -= sizeof(Rune);1046 if(nl == 0) {1047 tl += BLKSIZE/sizeof(Rune);1048 bp = getblock(tl, OWRITE);1049 nl = nleft;1050 }1051 }1052 nl = tline;1053 tline += ((lp-linebuf) + 03) & 077776;1054 return nl;1055 }1057 void1058 blkio(int b, uchar *buf, int isread)1059 {1060 int n;1062 seek(tfile, b*BLKSIZE, 0);1063 if(isread)1064 n = read(tfile, buf, BLKSIZE);1065 else1066 n = write(tfile, buf, BLKSIZE);1067 if(n != BLKSIZE)1068 error(T);1069 }1071 Rune*1072 getblock(int atl, int iof)1073 {1074 int bno, off;1076 static uchar ibuff[BLKSIZE];1077 static uchar obuff[BLKSIZE];1079 bno = atl / (BLKSIZE/sizeof(Rune));1080 off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~03;1081 if(bno >= NBLK) {1082 lastc = '\n';1083 error(T);1084 }1085 nleft = BLKSIZE - off;1086 if(bno == iblock) {1087 ichanged |= iof;1088 return (Rune*)(ibuff+off);1089 }1090 if(bno == oblock)1091 return (Rune*)(obuff+off);1092 if(iof == OREAD) {1093 if(ichanged)1094 blkio(iblock, ibuff, 0);1095 ichanged = 0;1096 iblock = bno;1097 blkio(bno, ibuff, 1);1098 return (Rune*)(ibuff+off);1099 }1100 if(oblock >= 0)1101 blkio(oblock, obuff, 0);1102 oblock = bno;1103 return (Rune*)(obuff+off);1104 }1106 void1107 init(void)1108 {1109 int *markp;1111 close(tfile);1112 tline = 2;1113 for(markp = names; markp < &names[26]; )1114 *markp++ = 0;1115 subnewa = 0;1116 anymarks = 0;1117 iblock = -1;1118 oblock = -1;1119 ichanged = 0;1120 if((tfile = create(tfname, ORDWR, 0600)) < 0){1121 error1(T);1122 exits(0);1123 }1124 dot = dol = zero;1125 }1127 void1128 global(int k)1129 {1130 Rune *gp, globuf[GBSIZE];1131 int c, *a1;1133 if(globp)1134 error(Q);1135 setwide();1136 squeeze(dol > zero);1137 c = getchr();1138 if(c == '\n')1139 error(Q);1140 compile(c);1141 gp = globuf;1142 while((c=getchr()) != '\n') {1143 if(c == EOF)1144 error(Q);1145 if(c == '\\') {1146 c = getchr();1147 if(c != '\n')1148 *gp++ = '\\';1149 }1150 *gp++ = c;1151 if(gp >= &globuf[GBSIZE-2])1152 error(Q);1153 }1154 if(gp == globuf)1155 *gp++ = 'p';1156 *gp++ = '\n';1157 *gp = 0;1158 for(a1=zero; a1<=dol; a1++) {1159 *a1 &= ~01;1160 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)1161 *a1 |= 01;1162 }1164 /*1165 * Special case: g/.../d (avoid n^2 algorithm)1166 */1167 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {1168 gdelete();1169 return;1170 }1171 for(a1=zero; a1<=dol; a1++) {1172 if(*a1 & 01) {1173 *a1 &= ~01;1174 dot = a1;1175 globp = globuf;1176 commands();1177 a1 = zero;1178 }1179 }1180 }1182 void1183 join(void)1184 {1185 Rune *gp, *lp;1186 int *a1;1188 nonzero();1189 gp = genbuf;1190 for(a1=addr1; a1<=addr2; a1++) {1191 lp = getline(*a1);1192 while(*gp = *lp++)1193 if(gp++ >= &genbuf[LBSIZE-2])1194 error(Q);1195 }1196 lp = linebuf;1197 gp = genbuf;1198 while(*lp++ = *gp++)1199 ;1200 *addr1 = putline();1201 if(addr1 < addr2)1202 rdelete(addr1+1, addr2);1203 dot = addr1;1204 }1206 void1207 substitute(int inglob)1208 {1209 int *mp, *a1, nl, gsubf, n;1211 n = getnum(); /* OK even if n==0 */1212 gsubf = compsub();1213 for(a1 = addr1; a1 <= addr2; a1++) {1214 if(match(a1)){1215 int *ozero;1216 int m = n;1218 do {1219 int span = loc2-loc1;1221 if(--m <= 0) {1222 dosub();1223 if(!gsubf)1224 break;1225 if(span == 0) { /* null RE match */1226 if(*loc2 == 0)1227 break;1228 loc2++;1229 }1230 }1231 } while(match(0));1232 if(m <= 0) {1233 inglob |= 01;1234 subnewa = putline();1235 *a1 &= ~01;1236 if(anymarks) {1237 for(mp=names; mp<&names[26]; mp++)1238 if(*mp == *a1)1239 *mp = subnewa;1240 }1241 subolda = *a1;1242 *a1 = subnewa;1243 ozero = zero;1244 nl = append(getsub, a1);1245 addr2 += nl;1246 nl += zero-ozero;1247 a1 += nl;1248 }1249 }1250 }1251 if(inglob == 0)1252 error(Q);1253 }1255 int1256 compsub(void)1257 {1258 int seof, c;1259 Rune *p;1261 seof = getchr();1262 if(seof == '\n' || seof == ' ')1263 error(Q);1264 compile(seof);1265 p = rhsbuf;1266 for(;;) {1267 c = getchr();1268 if(c == '\\') {1269 c = getchr();1270 *p++ = ESCFLG;1271 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])1272 error(Q);1273 } else1274 if(c == '\n' && (!globp || !globp[0])) {1275 peekc = c;1276 pflag++;1277 break;1278 } else1279 if(c == seof)1280 break;1281 *p++ = c;1282 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])1283 error(Q);1284 }1285 *p = 0;1286 peekc = getchr();1287 if(peekc == 'g') {1288 peekc = 0;1289 newline();1290 return 1;1291 }1292 newline();1293 return 0;1294 }1296 int1297 getsub(void)1298 {1299 Rune *p1, *p2;1301 p1 = linebuf;1302 if((p2 = linebp) == 0)1303 return EOF;1304 while(*p1++ = *p2++)1305 ;1306 linebp = 0;1307 return 0;1308 }1310 void1311 dosub(void)1312 {1313 Rune *lp, *sp, *rp;1314 int c, n;1316 lp = linebuf;1317 sp = genbuf;1318 rp = rhsbuf;1319 while(lp < loc1)1320 *sp++ = *lp++;1321 while(c = *rp++) {1322 if(c == '&'){1323 sp = place(sp, loc1, loc2);1324 continue;1325 }1326 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {1327 n = c-'0';1328 if(subexp[n].s.rsp && subexp[n].e.rep) {1329 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);1330 continue;1331 }1332 error(Q);1333 }1334 *sp++ = c;1335 if(sp >= &genbuf[LBSIZE])1336 error(Q);1337 }1338 lp = loc2;1339 loc2 = sp - genbuf + linebuf;1340 while(*sp++ = *lp++)1341 if(sp >= &genbuf[LBSIZE])1342 error(Q);1343 lp = linebuf;1344 sp = genbuf;1345 while(*lp++ = *sp++)1346 ;1347 }1349 Rune*1350 place(Rune *sp, Rune *l1, Rune *l2)1351 {1353 while(l1 < l2) {1354 *sp++ = *l1++;1355 if(sp >= &genbuf[LBSIZE])1356 error(Q);1357 }1358 return sp;1359 }1361 void1362 move(int cflag)1363 {1364 int *adt, *ad1, *ad2;1366 nonzero();1367 if((adt = address())==0) /* address() guarantees addr is in range */1368 error(Q);1369 newline();1370 if(cflag) {1371 int *ozero, delta;1372 ad1 = dol;1373 ozero = zero;1374 append(getcopy, ad1++);1375 ad2 = dol;1376 delta = zero - ozero;1377 ad1 += delta;1378 adt += delta;1379 } else {1380 ad2 = addr2;1381 for(ad1 = addr1; ad1 <= ad2;)1382 *ad1++ &= ~01;1383 ad1 = addr1;1384 }1385 ad2++;1386 if(adt<ad1) {1387 dot = adt + (ad2-ad1);1388 if((++adt)==ad1)1389 return;1390 reverse(adt, ad1);1391 reverse(ad1, ad2);1392 reverse(adt, ad2);1393 } else1394 if(adt >= ad2) {1395 dot = adt++;1396 reverse(ad1, ad2);1397 reverse(ad2, adt);1398 reverse(ad1, adt);1399 } else1400 error(Q);1401 fchange = 1;1402 }1404 void1405 reverse(int *a1, int *a2)1406 {1407 int t;1409 for(;;) {1410 t = *--a2;1411 if(a2 <= a1)1412 return;1413 *a2 = *a1;1414 *a1++ = t;1415 }1416 }1418 int1419 getcopy(void)1420 {1421 if(addr1 > addr2)1422 return EOF;1423 getline(*addr1++);1424 return 0;1425 }1427 void1428 compile(int eof)1429 {1430 Rune c;1431 char *ep;1432 char expbuf[ESIZE];1434 if((c = getchr()) == '\n') {1435 peekc = c;1436 c = eof;1437 }1438 if(c == eof) {1439 if(!pattern)1440 error(Q);1441 return;1442 }1443 if(pattern) {1444 free(pattern);1445 pattern = 0;1446 }1447 ep = expbuf;1448 do {1449 if(c == '\\') {1450 if(ep >= expbuf+sizeof(expbuf)) {1451 error(Q);1452 return;1453 }1454 ep += runetochar(ep, &c);1455 if((c = getchr()) == '\n') {1456 error(Q);1457 return;1458 }1459 }1460 if(ep >= expbuf+sizeof(expbuf)) {1461 error(Q);1462 return;1463 }1464 ep += runetochar(ep, &c);1465 } while((c = getchr()) != eof && c != '\n');1466 if(c == '\n')1467 peekc = c;1468 *ep = 0;1469 pattern = regcomp(expbuf);1470 }1472 int1473 match(int *addr)1474 {1475 if(!pattern)1476 return 0;1477 if(addr){1478 if(addr == zero)1479 return 0;1480 subexp[0].s.rsp = getline(*addr);1481 } else1482 subexp[0].s.rsp = loc2;1483 subexp[0].e.rep = 0;1484 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {1485 loc1 = subexp[0].s.rsp;1486 loc2 = subexp[0].e.rep;1487 return 1;1488 }1489 loc1 = loc2 = 0;1490 return 0;1492 }1494 void1495 putd(void)1496 {1497 int r;1499 r = count%10;1500 count /= 10;1501 if(count)1502 putd();1503 putchr(r + '0');1504 }1506 void1507 putst(char *sp)1508 {1509 Rune r;1511 col = 0;1512 for(;;) {1513 sp += chartorune(&r, sp);1514 if(r == 0)1515 break;1516 putchr(r);1517 }1518 putchr('\n');1519 }1521 void1522 putshst(Rune *sp)1523 {1524 col = 0;1525 while(*sp)1526 putchr(*sp++);1527 putchr('\n');1528 }1530 void1531 putchr(int ac)1532 {1533 char *lp;1534 int c;1535 Rune rune;1537 lp = linp;1538 c = ac;1539 if(listf) {1540 if(c == '\n') {1541 if(linp != line && linp[-1] == ' ') {1542 *lp++ = '\\';1543 *lp++ = 'n';1544 }1545 } else {1546 if(col > (72-6-2)) {1547 col = 8;1548 *lp++ = '\\';1549 *lp++ = '\n';1550 *lp++ = '\t';1551 }1552 col++;1553 if(c=='\b' || c=='\t' || c=='\\') {1554 *lp++ = '\\';1555 if(c == '\b')1556 c = 'b';1557 else1558 if(c == '\t')1559 c = 't';1560 col++;1561 } else1562 if(c<' ' || c>='\177') {1563 *lp++ = '\\';1564 *lp++ = 'x';1565 *lp++ = hex[c>>12];1566 *lp++ = hex[c>>8&0xF];1567 *lp++ = hex[c>>4&0xF];1568 c = hex[c&0xF];1569 col += 5;1570 }1571 }1572 }1574 rune = c;1575 lp += runetochar(lp, &rune);1577 if(c == '\n' || lp >= &line[sizeof(line)-5]) {1578 linp = line;1579 write(oflag? 2: 1, line, lp-line);1580 return;1581 }1582 linp = lp;1583 }1585 char*1586 mktemp(char *as)1587 {1588 char *s;1589 unsigned pid;1590 int i;1592 pid = getpid();1593 s = as;1594 while(*s++)1595 ;1596 s--;1597 while(*--s == 'X') {1598 *s = pid % 10 + '0';1599 pid /= 10;1600 }1601 s++;1602 i = 'a';1603 while(access(as, 0) != -1) {1604 if(i == 'z')1605 return "/";1606 *s = i++;1607 }1608 return as;1609 }1611 void1612 regerror(char *s)1613 {1614 USED(s);1615 error(Q);1616 }