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 = -1,22 };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[] = "/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 = "/fd/1";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(L'\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(L'\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(L'\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(L'?');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(L'\n');691 lastc = '\n';692 error1(Q);693 notejmp(a, savej, 0);694 }695 if(strcmp(s, "hangup") == 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 return 0;762 }764 int765 gettty(void)766 {767 int rc;769 rc = gety();770 if(rc)771 return rc;772 if(linebuf[0] == '.' && linebuf[1] == 0)773 return EOF;774 return 0;775 }777 int778 getfile(void)779 {780 int c;781 Rune *lp;783 lp = linebuf;784 do {785 c = Bgetrune(&iobuf);786 if(c < 0) {787 if(lp > linebuf) {788 putst("'\\n' appended");789 c = '\n';790 } else791 return EOF;792 }793 if(lp >= &linebuf[LBSIZE]) {794 lastc = '\n';795 error(Q);796 }797 *lp++ = c;798 count++;799 } while(c != '\n');800 lp[-1] = 0;801 return 0;802 }804 void805 putfile(void)806 {807 int *a1;808 Rune *lp;809 long c;811 a1 = addr1;812 do {813 lp = getline(*a1++);814 for(;;) {815 count++;816 c = *lp++;817 if(c == 0) {818 if(Bputrune(&iobuf, '\n') < 0)819 error(Q);820 break;821 }822 if(Bputrune(&iobuf, c) < 0)823 error(Q);824 }825 } while(a1 <= addr2);826 if(Bflush(&iobuf) < 0)827 error(Q);828 }830 int831 append(int (*f)(void), int *a)832 {833 int *a1, *a2, *rdot, nline, tl;835 nline = 0;836 dot = a;837 while((*f)() == 0) {838 if((dol-zero) >= nlall) {839 nlall += 512;840 a1 = realloc(zero, (nlall+5)*sizeof(int*));841 if(a1 == 0) {842 error("MEM?");843 rescue();844 }845 tl = a1 - zero; /* relocate pointers */846 zero += tl;847 addr1 += tl;848 addr2 += tl;849 dol += tl;850 dot += tl;851 }852 tl = putline();853 nline++;854 a1 = ++dol;855 a2 = a1+1;856 rdot = ++dot;857 while(a1 > rdot)858 *--a2 = *--a1;859 *rdot = tl;860 }861 return nline;862 }864 void865 add(int i)866 {867 if(i && (given || dol > zero)) {868 addr1--;869 addr2--;870 }871 squeeze(0);872 newline();873 append(gettty, addr2);874 }876 void877 browse(void)878 {879 int forward, n;880 static int bformat, bnum; /* 0 */882 forward = 1;883 peekc = getchr();884 if(peekc != '\n'){885 if(peekc == '-' || peekc == '+') {886 if(peekc == '-')887 forward = 0;888 getchr();889 }890 n = getnum();891 if(n > 0)892 bpagesize = n;893 }894 newline();895 if(pflag) {896 bformat = listf;897 bnum = listn;898 } else {899 listf = bformat;900 listn = bnum;901 }902 if(forward) {903 addr1 = addr2;904 addr2 += bpagesize;905 if(addr2 > dol)906 addr2 = dol;907 } else {908 addr1 = addr2-bpagesize;909 if(addr1 <= zero)910 addr1 = zero+1;911 }912 printcom();913 }915 void916 callunix(void)917 {918 int c, pid;919 Rune rune;920 char buf[512];921 char *p;923 setnoaddr();924 p = buf;925 while((c=getchr()) != EOF && c != '\n')926 if(p < &buf[sizeof(buf) - 6]) {927 rune = c;928 p += runetochar(p, &rune);929 }930 *p = 0;931 pid = fork();932 if(pid == 0) {933 execlp("rc", "rc", "-c", buf, 0);934 sysfatal("exec failed: %r");935 exits("execl failed");936 }937 waiting = 1;938 while(waitpid() != pid)939 ;940 waiting = 0;941 if(vflag)942 putst("!");943 }945 void946 quit(void)947 {948 if(vflag && fchange && dol!=zero) {949 fchange = 0;950 error(Q);951 }952 remove(tfname);953 exits(0);954 }956 void957 onquit(int sig)958 {959 USED(sig);960 quit();961 }963 void964 rdelete(int *ad1, int *ad2)965 {966 int *a1, *a2, *a3;968 a1 = ad1;969 a2 = ad2+1;970 a3 = dol;971 dol -= a2 - a1;972 do {973 *a1++ = *a2++;974 } while(a2 <= a3);975 a1 = ad1;976 if(a1 > dol)977 a1 = dol;978 dot = a1;979 fchange = 1;980 }982 void983 gdelete(void)984 {985 int *a1, *a2, *a3;987 a3 = dol;988 for(a1=zero; (*a1&01)==0; a1++)989 if(a1>=a3)990 return;991 for(a2=a1+1; a2<=a3;) {992 if(*a2 & 01) {993 a2++;994 dot = a1;995 } else996 *a1++ = *a2++;997 }998 dol = a1-1;999 if(dot > dol)1000 dot = dol;1001 fchange = 1;1002 }1004 Rune*1005 getline(int tl)1006 {1007 Rune *lp, *bp;1008 int nl;1010 lp = linebuf;1011 bp = getblock(tl, OREAD);1012 nl = nleft;1013 tl &= ~((BLKSIZE/2) - 1);1014 while(*lp++ = *bp++) {1015 nl -= sizeof(Rune);1016 if(nl == 0) {1017 bp = getblock(tl += BLKSIZE/2, OREAD);1018 nl = nleft;1019 }1020 }1021 return linebuf;1022 }1024 int1025 putline(void)1026 {1027 Rune *lp, *bp;1028 int nl, tl;1030 fchange = 1;1031 lp = linebuf;1032 tl = tline;1033 bp = getblock(tl, OWRITE);1034 nl = nleft;1035 tl &= ~((BLKSIZE/2)-1);1036 while(*bp = *lp++) {1037 if(*bp++ == '\n') {1038 bp[-1] = 0;1039 linebp = lp;1040 break;1041 }1042 nl -= sizeof(Rune);1043 if(nl == 0) {1044 tl += BLKSIZE/2;1045 bp = getblock(tl, OWRITE);1046 nl = nleft;1047 }1048 }1049 nl = tline;1050 tline += ((lp-linebuf) + 03) & 077776;1051 return nl;1052 }1054 void1055 blkio(int b, uchar *buf, int isread)1056 {1057 int n;1059 seek(tfile, b*BLKSIZE, 0);1060 if(isread)1061 n = read(tfile, buf, BLKSIZE);1062 else1063 n = write(tfile, buf, BLKSIZE);1064 if(n != BLKSIZE)1065 error(T);1066 }1068 Rune*1069 getblock(int atl, int iof)1070 {1071 int bno, off;1073 static uchar ibuff[BLKSIZE];1074 static uchar obuff[BLKSIZE];1076 bno = atl / (BLKSIZE/2);1077 off = (atl<<1) & (BLKSIZE-1) & ~03;1078 if(bno >= NBLK) {1079 lastc = '\n';1080 error(T);1081 }1082 nleft = BLKSIZE - off;1083 if(bno == iblock) {1084 ichanged |= iof;1085 return (Rune*)(ibuff+off);1086 }1087 if(bno == oblock)1088 return (Rune*)(obuff+off);1089 if(iof == OREAD) {1090 if(ichanged)1091 blkio(iblock, ibuff, 0);1092 ichanged = 0;1093 iblock = bno;1094 blkio(bno, ibuff, 1);1095 return (Rune*)(ibuff+off);1096 }1097 if(oblock >= 0)1098 blkio(oblock, obuff, 0);1099 oblock = bno;1100 return (Rune*)(obuff+off);1101 }1103 void1104 init(void)1105 {1106 int *markp;1108 close(tfile);1109 tline = 2;1110 for(markp = names; markp < &names[26]; )1111 *markp++ = 0;1112 subnewa = 0;1113 anymarks = 0;1114 iblock = -1;1115 oblock = -1;1116 ichanged = 0;1117 if((tfile = create(tfname, ORDWR, 0600)) < 0){1118 error1(T);1119 exits(0);1120 }1121 dot = dol = zero;1122 }1124 void1125 global(int k)1126 {1127 Rune *gp, globuf[GBSIZE];1128 int c, *a1;1130 if(globp)1131 error(Q);1132 setwide();1133 squeeze(dol > zero);1134 c = getchr();1135 if(c == '\n')1136 error(Q);1137 compile(c);1138 gp = globuf;1139 while((c=getchr()) != '\n') {1140 if(c == EOF)1141 error(Q);1142 if(c == '\\') {1143 c = getchr();1144 if(c != '\n')1145 *gp++ = '\\';1146 }1147 *gp++ = c;1148 if(gp >= &globuf[GBSIZE-2])1149 error(Q);1150 }1151 if(gp == globuf)1152 *gp++ = 'p';1153 *gp++ = '\n';1154 *gp = 0;1155 for(a1=zero; a1<=dol; a1++) {1156 *a1 &= ~01;1157 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)1158 *a1 |= 01;1159 }1161 /*1162 * Special case: g/.../d (avoid n^2 algorithm)1163 */1164 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {1165 gdelete();1166 return;1167 }1168 for(a1=zero; a1<=dol; a1++) {1169 if(*a1 & 01) {1170 *a1 &= ~01;1171 dot = a1;1172 globp = globuf;1173 commands();1174 a1 = zero;1175 }1176 }1177 }1179 void1180 join(void)1181 {1182 Rune *gp, *lp;1183 int *a1;1185 nonzero();1186 gp = genbuf;1187 for(a1=addr1; a1<=addr2; a1++) {1188 lp = getline(*a1);1189 while(*gp = *lp++)1190 if(gp++ >= &genbuf[LBSIZE-2])1191 error(Q);1192 }1193 lp = linebuf;1194 gp = genbuf;1195 while(*lp++ = *gp++)1196 ;1197 *addr1 = putline();1198 if(addr1 < addr2)1199 rdelete(addr1+1, addr2);1200 dot = addr1;1201 }1203 void1204 substitute(int inglob)1205 {1206 int *mp, *a1, nl, gsubf, n;1208 n = getnum(); /* OK even if n==0 */1209 gsubf = compsub();1210 for(a1 = addr1; a1 <= addr2; a1++) {1211 if(match(a1)){1212 int *ozero;1213 int m = n;1215 do {1216 int span = loc2-loc1;1218 if(--m <= 0) {1219 dosub();1220 if(!gsubf)1221 break;1222 if(span == 0) { /* null RE match */1223 if(*loc2 == 0)1224 break;1225 loc2++;1226 }1227 }1228 } while(match(0));1229 if(m <= 0) {1230 inglob |= 01;1231 subnewa = putline();1232 *a1 &= ~01;1233 if(anymarks) {1234 for(mp=names; mp<&names[26]; mp++)1235 if(*mp == *a1)1236 *mp = subnewa;1237 }1238 subolda = *a1;1239 *a1 = subnewa;1240 ozero = zero;1241 nl = append(getsub, a1);1242 addr2 += nl;1243 nl += zero-ozero;1244 a1 += nl;1245 }1246 }1247 }1248 if(inglob == 0)1249 error(Q);1250 }1252 int1253 compsub(void)1254 {1255 int seof, c;1256 Rune *p;1258 seof = getchr();1259 if(seof == '\n' || seof == ' ')1260 error(Q);1261 compile(seof);1262 p = rhsbuf;1263 for(;;) {1264 c = getchr();1265 if(c == '\\') {1266 c = getchr();1267 *p++ = ESCFLG;1268 if(p >= &rhsbuf[LBSIZE/2])1269 error(Q);1270 } else1271 if(c == '\n' && (!globp || !globp[0])) {1272 peekc = c;1273 pflag++;1274 break;1275 } else1276 if(c == seof)1277 break;1278 *p++ = c;1279 if(p >= &rhsbuf[LBSIZE/2])1280 error(Q);1281 }1282 *p = 0;1283 peekc = getchr();1284 if(peekc == 'g') {1285 peekc = 0;1286 newline();1287 return 1;1288 }1289 newline();1290 return 0;1291 }1293 int1294 getsub(void)1295 {1296 Rune *p1, *p2;1298 p1 = linebuf;1299 if((p2 = linebp) == 0)1300 return EOF;1301 while(*p1++ = *p2++)1302 ;1303 linebp = 0;1304 return 0;1305 }1307 void1308 dosub(void)1309 {1310 Rune *lp, *sp, *rp;1311 int c, n;1313 lp = linebuf;1314 sp = genbuf;1315 rp = rhsbuf;1316 while(lp < loc1)1317 *sp++ = *lp++;1318 while(c = *rp++) {1319 if(c == '&'){1320 sp = place(sp, loc1, loc2);1321 continue;1322 }1323 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {1324 n = c-'0';1325 if(subexp[n].s.rsp && subexp[n].e.rep) {1326 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);1327 continue;1328 }1329 error(Q);1330 }1331 *sp++ = c;1332 if(sp >= &genbuf[LBSIZE])1333 error(Q);1334 }1335 lp = loc2;1336 loc2 = sp - genbuf + linebuf;1337 while(*sp++ = *lp++)1338 if(sp >= &genbuf[LBSIZE])1339 error(Q);1340 lp = linebuf;1341 sp = genbuf;1342 while(*lp++ = *sp++)1343 ;1344 }1346 Rune*1347 place(Rune *sp, Rune *l1, Rune *l2)1348 {1350 while(l1 < l2) {1351 *sp++ = *l1++;1352 if(sp >= &genbuf[LBSIZE])1353 error(Q);1354 }1355 return sp;1356 }1358 void1359 move(int cflag)1360 {1361 int *adt, *ad1, *ad2;1363 nonzero();1364 if((adt = address())==0) /* address() guarantees addr is in range */1365 error(Q);1366 newline();1367 if(cflag) {1368 int *ozero, delta;1369 ad1 = dol;1370 ozero = zero;1371 append(getcopy, ad1++);1372 ad2 = dol;1373 delta = zero - ozero;1374 ad1 += delta;1375 adt += delta;1376 } else {1377 ad2 = addr2;1378 for(ad1 = addr1; ad1 <= ad2;)1379 *ad1++ &= ~01;1380 ad1 = addr1;1381 }1382 ad2++;1383 if(adt<ad1) {1384 dot = adt + (ad2-ad1);1385 if((++adt)==ad1)1386 return;1387 reverse(adt, ad1);1388 reverse(ad1, ad2);1389 reverse(adt, ad2);1390 } else1391 if(adt >= ad2) {1392 dot = adt++;1393 reverse(ad1, ad2);1394 reverse(ad2, adt);1395 reverse(ad1, adt);1396 } else1397 error(Q);1398 fchange = 1;1399 }1401 void1402 reverse(int *a1, int *a2)1403 {1404 int t;1406 for(;;) {1407 t = *--a2;1408 if(a2 <= a1)1409 return;1410 *a2 = *a1;1411 *a1++ = t;1412 }1413 }1415 int1416 getcopy(void)1417 {1418 if(addr1 > addr2)1419 return EOF;1420 getline(*addr1++);1421 return 0;1422 }1424 void1425 compile(int eof)1426 {1427 Rune c;1428 char *ep;1429 char expbuf[ESIZE];1431 if((c = getchr()) == '\n') {1432 peekc = c;1433 c = eof;1434 }1435 if(c == eof) {1436 if(!pattern)1437 error(Q);1438 return;1439 }1440 if(pattern) {1441 free(pattern);1442 pattern = 0;1443 }1444 ep = expbuf;1445 do {1446 if(c == '\\') {1447 if(ep >= expbuf+sizeof(expbuf)) {1448 error(Q);1449 return;1450 }1451 ep += runetochar(ep, &c);1452 if((c = getchr()) == '\n') {1453 error(Q);1454 return;1455 }1456 }1457 if(ep >= expbuf+sizeof(expbuf)) {1458 error(Q);1459 return;1460 }1461 ep += runetochar(ep, &c);1462 } while((c = getchr()) != eof && c != '\n');1463 if(c == '\n')1464 peekc = c;1465 *ep = 0;1466 pattern = regcomp(expbuf);1467 }1469 int1470 match(int *addr)1471 {1472 if(!pattern)1473 return 0;1474 if(addr){1475 if(addr == zero)1476 return 0;1477 subexp[0].s.rsp = getline(*addr);1478 } else1479 subexp[0].s.rsp = loc2;1480 subexp[0].e.rep = 0;1481 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {1482 loc1 = subexp[0].s.rsp;1483 loc2 = subexp[0].e.rep;1484 return 1;1485 }1486 loc1 = loc2 = 0;1487 return 0;1489 }1491 void1492 putd(void)1493 {1494 int r;1496 r = count%10;1497 count /= 10;1498 if(count)1499 putd();1500 putchr(r + L'0');1501 }1503 void1504 putst(char *sp)1505 {1506 Rune r;1508 col = 0;1509 for(;;) {1510 sp += chartorune(&r, sp);1511 if(r == 0)1512 break;1513 putchr(r);1514 }1515 putchr(L'\n');1516 }1518 void1519 putshst(Rune *sp)1520 {1521 col = 0;1522 while(*sp)1523 putchr(*sp++);1524 putchr(L'\n');1525 }1527 void1528 putchr(int ac)1529 {1530 char *lp;1531 int c;1532 Rune rune;1534 lp = linp;1535 c = ac;1536 if(listf) {1537 if(c == '\n') {1538 if(linp != line && linp[-1] == ' ') {1539 *lp++ = '\\';1540 *lp++ = 'n';1541 }1542 } else {1543 if(col > (72-6-2)) {1544 col = 8;1545 *lp++ = '\\';1546 *lp++ = '\n';1547 *lp++ = '\t';1548 }1549 col++;1550 if(c=='\b' || c=='\t' || c=='\\') {1551 *lp++ = '\\';1552 if(c == '\b')1553 c = 'b';1554 else1555 if(c == '\t')1556 c = 't';1557 col++;1558 } else1559 if(c<' ' || c>='\177') {1560 *lp++ = '\\';1561 *lp++ = 'x';1562 *lp++ = hex[c>>12];1563 *lp++ = hex[c>>8&0xF];1564 *lp++ = hex[c>>4&0xF];1565 c = hex[c&0xF];1566 col += 5;1567 }1568 }1569 }1571 rune = c;1572 lp += runetochar(lp, &rune);1574 if(c == '\n' || lp >= &line[sizeof(line)-5]) {1575 linp = line;1576 write(oflag? 2: 1, line, lp-line);1577 return;1578 }1579 linp = lp;1580 }1582 char*1583 mktemp(char *as)1584 {1585 char *s;1586 unsigned pid;1587 int i;1589 pid = getpid();1590 s = as;1591 while(*s++)1592 ;1593 s--;1594 while(*--s == 'X') {1595 *s = pid % 10 + '0';1596 pid /= 10;1597 }1598 s++;1599 i = 'a';1600 while(access(as, 0) != -1) {1601 if(i == 'z')1602 return "/";1603 *s = i++;1604 }1605 return as;1606 }1608 void1609 regerror(char *s)1610 {1611 USED(s);1612 error(Q);1613 }