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 fprint(2, "ed: note: %s\n", s);701 abort();702 }704 int705 getchr(void)706 {707 char s[UTFmax];708 int i;709 Rune r;711 if(lastc = peekc) {712 peekc = 0;713 return lastc;714 }715 if(globp) {716 if((lastc=*globp++) != 0)717 return lastc;718 globp = 0;719 return EOF;720 }721 for(i=0;;) {722 if(read(0, s+i, 1) <= 0)723 return lastc = EOF;724 i++;725 if(fullrune(s, i))726 break;728 }729 chartorune(&r, s);730 lastc = r;731 return lastc;732 }734 int735 gety(void)736 {737 int c;738 Rune *gf, *p;740 p = linebuf;741 gf = globp;742 for(;;) {743 c = getchr();744 if(c == '\n') {745 *p = 0;746 return 0;747 }748 if(c == EOF) {749 if(gf)750 peekc = c;751 return c;752 }753 if(c == 0)754 continue;755 *p++ = c;756 if(p >= &linebuf[LBSIZE-2])757 error(Q);758 }759 return 0;760 }762 int763 gettty(void)764 {765 int rc;767 rc = gety();768 if(rc)769 return rc;770 if(linebuf[0] == '.' && linebuf[1] == 0)771 return EOF;772 return 0;773 }775 int776 getfile(void)777 {778 int c;779 Rune *lp;781 lp = linebuf;782 do {783 c = Bgetrune(&iobuf);784 if(c < 0) {785 if(lp > linebuf) {786 putst("'\\n' appended");787 c = '\n';788 } else789 return EOF;790 }791 if(lp >= &linebuf[LBSIZE]) {792 lastc = '\n';793 error(Q);794 }795 *lp++ = c;796 count++;797 } while(c != '\n');798 lp[-1] = 0;799 return 0;800 }802 void803 putfile(void)804 {805 int *a1;806 Rune *lp;807 long c;809 a1 = addr1;810 do {811 lp = getline(*a1++);812 for(;;) {813 count++;814 c = *lp++;815 if(c == 0) {816 if(Bputrune(&iobuf, '\n') < 0)817 error(Q);818 break;819 }820 if(Bputrune(&iobuf, c) < 0)821 error(Q);822 }823 } while(a1 <= addr2);824 if(Bflush(&iobuf) < 0)825 error(Q);826 }828 int829 append(int (*f)(void), int *a)830 {831 int *a1, *a2, *rdot, nline, tl;833 nline = 0;834 dot = a;835 while((*f)() == 0) {836 if((dol-zero) >= nlall) {837 nlall += 512;838 a1 = realloc(zero, (nlall+5)*sizeof(int*));839 if(a1 == 0) {840 error("MEM?");841 rescue();842 }843 tl = a1 - zero; /* relocate pointers */844 zero += tl;845 addr1 += tl;846 addr2 += tl;847 dol += tl;848 dot += tl;849 }850 tl = putline();851 nline++;852 a1 = ++dol;853 a2 = a1+1;854 rdot = ++dot;855 while(a1 > rdot)856 *--a2 = *--a1;857 *rdot = tl;858 }859 return nline;860 }862 void863 add(int i)864 {865 if(i && (given || dol > zero)) {866 addr1--;867 addr2--;868 }869 squeeze(0);870 newline();871 append(gettty, addr2);872 }874 void875 browse(void)876 {877 int forward, n;878 static int bformat, bnum; /* 0 */880 forward = 1;881 peekc = getchr();882 if(peekc != '\n'){883 if(peekc == '-' || peekc == '+') {884 if(peekc == '-')885 forward = 0;886 getchr();887 }888 n = getnum();889 if(n > 0)890 bpagesize = n;891 }892 newline();893 if(pflag) {894 bformat = listf;895 bnum = listn;896 } else {897 listf = bformat;898 listn = bnum;899 }900 if(forward) {901 addr1 = addr2;902 addr2 += bpagesize;903 if(addr2 > dol)904 addr2 = dol;905 } else {906 addr1 = addr2-bpagesize;907 if(addr1 <= zero)908 addr1 = zero+1;909 }910 printcom();911 }913 void914 callunix(void)915 {916 int c, pid;917 Rune rune;918 char buf[512];919 char *p;921 setnoaddr();922 p = buf;923 while((c=getchr()) != EOF && c != '\n')924 if(p < &buf[sizeof(buf) - 6]) {925 rune = c;926 p += runetochar(p, &rune);927 }928 *p = 0;929 pid = fork();930 if(pid == 0) {931 execl("/bin/rc", "rc", "-c", buf, 0);932 exits("execl failed");933 }934 waiting = 1;935 while(waitpid() != pid)936 ;937 waiting = 0;938 if(vflag)939 putst("!");940 }942 void943 quit(void)944 {945 if(vflag && fchange && dol!=zero) {946 fchange = 0;947 error(Q);948 }949 remove(tfname);950 exits(0);951 }953 void954 onquit(int sig)955 {956 USED(sig);957 quit();958 }960 void961 rdelete(int *ad1, int *ad2)962 {963 int *a1, *a2, *a3;965 a1 = ad1;966 a2 = ad2+1;967 a3 = dol;968 dol -= a2 - a1;969 do {970 *a1++ = *a2++;971 } while(a2 <= a3);972 a1 = ad1;973 if(a1 > dol)974 a1 = dol;975 dot = a1;976 fchange = 1;977 }979 void980 gdelete(void)981 {982 int *a1, *a2, *a3;984 a3 = dol;985 for(a1=zero; (*a1&01)==0; a1++)986 if(a1>=a3)987 return;988 for(a2=a1+1; a2<=a3;) {989 if(*a2 & 01) {990 a2++;991 dot = a1;992 } else993 *a1++ = *a2++;994 }995 dol = a1-1;996 if(dot > dol)997 dot = dol;998 fchange = 1;999 }1001 Rune*1002 getline(int tl)1003 {1004 Rune *lp, *bp;1005 int nl;1007 lp = linebuf;1008 bp = getblock(tl, OREAD);1009 nl = nleft;1010 tl &= ~((BLKSIZE/2) - 1);1011 while(*lp++ = *bp++) {1012 nl -= sizeof(Rune);1013 if(nl == 0) {1014 bp = getblock(tl += BLKSIZE/2, OREAD);1015 nl = nleft;1016 }1017 }1018 return linebuf;1019 }1021 int1022 putline(void)1023 {1024 Rune *lp, *bp;1025 int nl, tl;1027 fchange = 1;1028 lp = linebuf;1029 tl = tline;1030 bp = getblock(tl, OWRITE);1031 nl = nleft;1032 tl &= ~((BLKSIZE/2)-1);1033 while(*bp = *lp++) {1034 if(*bp++ == '\n') {1035 bp[-1] = 0;1036 linebp = lp;1037 break;1038 }1039 nl -= sizeof(Rune);1040 if(nl == 0) {1041 tl += BLKSIZE/2;1042 bp = getblock(tl, OWRITE);1043 nl = nleft;1044 }1045 }1046 nl = tline;1047 tline += ((lp-linebuf) + 03) & 077776;1048 return nl;1049 }1051 void1052 blkio(int b, uchar *buf, int isread)1053 {1054 int n;1056 seek(tfile, b*BLKSIZE, 0);1057 if(isread)1058 n = read(tfile, buf, BLKSIZE);1059 else1060 n = write(tfile, buf, BLKSIZE);1061 if(n != BLKSIZE)1062 error(T);1063 }1065 Rune*1066 getblock(int atl, int iof)1067 {1068 int bno, off;1070 static uchar ibuff[BLKSIZE];1071 static uchar obuff[BLKSIZE];1073 bno = atl / (BLKSIZE/2);1074 off = (atl<<1) & (BLKSIZE-1) & ~03;1075 if(bno >= NBLK) {1076 lastc = '\n';1077 error(T);1078 }1079 nleft = BLKSIZE - off;1080 if(bno == iblock) {1081 ichanged |= iof;1082 return (Rune*)(ibuff+off);1083 }1084 if(bno == oblock)1085 return (Rune*)(obuff+off);1086 if(iof == OREAD) {1087 if(ichanged)1088 blkio(iblock, ibuff, 0);1089 ichanged = 0;1090 iblock = bno;1091 blkio(bno, ibuff, 1);1092 return (Rune*)(ibuff+off);1093 }1094 if(oblock >= 0)1095 blkio(oblock, obuff, 0);1096 oblock = bno;1097 return (Rune*)(obuff+off);1098 }1100 void1101 init(void)1102 {1103 int *markp;1105 close(tfile);1106 tline = 2;1107 for(markp = names; markp < &names[26]; )1108 *markp++ = 0;1109 subnewa = 0;1110 anymarks = 0;1111 iblock = -1;1112 oblock = -1;1113 ichanged = 0;1114 if((tfile = create(tfname, ORDWR, 0600)) < 0){1115 error1(T);1116 exits(0);1117 }1118 dot = dol = zero;1119 }1121 void1122 global(int k)1123 {1124 Rune *gp, globuf[GBSIZE];1125 int c, *a1;1127 if(globp)1128 error(Q);1129 setwide();1130 squeeze(dol > zero);1131 c = getchr();1132 if(c == '\n')1133 error(Q);1134 compile(c);1135 gp = globuf;1136 while((c=getchr()) != '\n') {1137 if(c == EOF)1138 error(Q);1139 if(c == '\\') {1140 c = getchr();1141 if(c != '\n')1142 *gp++ = '\\';1143 }1144 *gp++ = c;1145 if(gp >= &globuf[GBSIZE-2])1146 error(Q);1147 }1148 if(gp == globuf)1149 *gp++ = 'p';1150 *gp++ = '\n';1151 *gp = 0;1152 for(a1=zero; a1<=dol; a1++) {1153 *a1 &= ~01;1154 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)1155 *a1 |= 01;1156 }1158 /*1159 * Special case: g/.../d (avoid n^2 algorithm)1160 */1161 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {1162 gdelete();1163 return;1164 }1165 for(a1=zero; a1<=dol; a1++) {1166 if(*a1 & 01) {1167 *a1 &= ~01;1168 dot = a1;1169 globp = globuf;1170 commands();1171 a1 = zero;1172 }1173 }1174 }1176 void1177 join(void)1178 {1179 Rune *gp, *lp;1180 int *a1;1182 nonzero();1183 gp = genbuf;1184 for(a1=addr1; a1<=addr2; a1++) {1185 lp = getline(*a1);1186 while(*gp = *lp++)1187 if(gp++ >= &genbuf[LBSIZE-2])1188 error(Q);1189 }1190 lp = linebuf;1191 gp = genbuf;1192 while(*lp++ = *gp++)1193 ;1194 *addr1 = putline();1195 if(addr1 < addr2)1196 rdelete(addr1+1, addr2);1197 dot = addr1;1198 }1200 void1201 substitute(int inglob)1202 {1203 int *mp, *a1, nl, gsubf, n;1205 n = getnum(); /* OK even if n==0 */1206 gsubf = compsub();1207 for(a1 = addr1; a1 <= addr2; a1++) {1208 if(match(a1)){1209 int *ozero;1210 int m = n;1212 do {1213 int span = loc2-loc1;1215 if(--m <= 0) {1216 dosub();1217 if(!gsubf)1218 break;1219 if(span == 0) { /* null RE match */1220 if(*loc2 == 0)1221 break;1222 loc2++;1223 }1224 }1225 } while(match(0));1226 if(m <= 0) {1227 inglob |= 01;1228 subnewa = putline();1229 *a1 &= ~01;1230 if(anymarks) {1231 for(mp=names; mp<&names[26]; mp++)1232 if(*mp == *a1)1233 *mp = subnewa;1234 }1235 subolda = *a1;1236 *a1 = subnewa;1237 ozero = zero;1238 nl = append(getsub, a1);1239 addr2 += nl;1240 nl += zero-ozero;1241 a1 += nl;1242 }1243 }1244 }1245 if(inglob == 0)1246 error(Q);1247 }1249 int1250 compsub(void)1251 {1252 int seof, c;1253 Rune *p;1255 seof = getchr();1256 if(seof == '\n' || seof == ' ')1257 error(Q);1258 compile(seof);1259 p = rhsbuf;1260 for(;;) {1261 c = getchr();1262 if(c == '\\') {1263 c = getchr();1264 *p++ = ESCFLG;1265 if(p >= &rhsbuf[LBSIZE/2])1266 error(Q);1267 } else1268 if(c == '\n' && (!globp || !globp[0])) {1269 peekc = c;1270 pflag++;1271 break;1272 } else1273 if(c == seof)1274 break;1275 *p++ = c;1276 if(p >= &rhsbuf[LBSIZE/2])1277 error(Q);1278 }1279 *p = 0;1280 peekc = getchr();1281 if(peekc == 'g') {1282 peekc = 0;1283 newline();1284 return 1;1285 }1286 newline();1287 return 0;1288 }1290 int1291 getsub(void)1292 {1293 Rune *p1, *p2;1295 p1 = linebuf;1296 if((p2 = linebp) == 0)1297 return EOF;1298 while(*p1++ = *p2++)1299 ;1300 linebp = 0;1301 return 0;1302 }1304 void1305 dosub(void)1306 {1307 Rune *lp, *sp, *rp;1308 int c, n;1310 lp = linebuf;1311 sp = genbuf;1312 rp = rhsbuf;1313 while(lp < loc1)1314 *sp++ = *lp++;1315 while(c = *rp++) {1316 if(c == '&'){1317 sp = place(sp, loc1, loc2);1318 continue;1319 }1320 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {1321 n = c-'0';1322 if(subexp[n].s.rsp && subexp[n].e.rep) {1323 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);1324 continue;1325 }1326 error(Q);1327 }1328 *sp++ = c;1329 if(sp >= &genbuf[LBSIZE])1330 error(Q);1331 }1332 lp = loc2;1333 loc2 = sp - genbuf + linebuf;1334 while(*sp++ = *lp++)1335 if(sp >= &genbuf[LBSIZE])1336 error(Q);1337 lp = linebuf;1338 sp = genbuf;1339 while(*lp++ = *sp++)1340 ;1341 }1343 Rune*1344 place(Rune *sp, Rune *l1, Rune *l2)1345 {1347 while(l1 < l2) {1348 *sp++ = *l1++;1349 if(sp >= &genbuf[LBSIZE])1350 error(Q);1351 }1352 return sp;1353 }1355 void1356 move(int cflag)1357 {1358 int *adt, *ad1, *ad2;1360 nonzero();1361 if((adt = address())==0) /* address() guarantees addr is in range */1362 error(Q);1363 newline();1364 if(cflag) {1365 int *ozero, delta;1366 ad1 = dol;1367 ozero = zero;1368 append(getcopy, ad1++);1369 ad2 = dol;1370 delta = zero - ozero;1371 ad1 += delta;1372 adt += delta;1373 } else {1374 ad2 = addr2;1375 for(ad1 = addr1; ad1 <= ad2;)1376 *ad1++ &= ~01;1377 ad1 = addr1;1378 }1379 ad2++;1380 if(adt<ad1) {1381 dot = adt + (ad2-ad1);1382 if((++adt)==ad1)1383 return;1384 reverse(adt, ad1);1385 reverse(ad1, ad2);1386 reverse(adt, ad2);1387 } else1388 if(adt >= ad2) {1389 dot = adt++;1390 reverse(ad1, ad2);1391 reverse(ad2, adt);1392 reverse(ad1, adt);1393 } else1394 error(Q);1395 fchange = 1;1396 }1398 void1399 reverse(int *a1, int *a2)1400 {1401 int t;1403 for(;;) {1404 t = *--a2;1405 if(a2 <= a1)1406 return;1407 *a2 = *a1;1408 *a1++ = t;1409 }1410 }1412 int1413 getcopy(void)1414 {1415 if(addr1 > addr2)1416 return EOF;1417 getline(*addr1++);1418 return 0;1419 }1421 void1422 compile(int eof)1423 {1424 Rune c;1425 char *ep;1426 char expbuf[ESIZE];1428 if((c = getchr()) == '\n') {1429 peekc = c;1430 c = eof;1431 }1432 if(c == eof) {1433 if(!pattern)1434 error(Q);1435 return;1436 }1437 if(pattern) {1438 free(pattern);1439 pattern = 0;1440 }1441 ep = expbuf;1442 do {1443 if(c == '\\') {1444 if(ep >= expbuf+sizeof(expbuf)) {1445 error(Q);1446 return;1447 }1448 ep += runetochar(ep, &c);1449 if((c = getchr()) == '\n') {1450 error(Q);1451 return;1452 }1453 }1454 if(ep >= expbuf+sizeof(expbuf)) {1455 error(Q);1456 return;1457 }1458 ep += runetochar(ep, &c);1459 } while((c = getchr()) != eof && c != '\n');1460 if(c == '\n')1461 peekc = c;1462 *ep = 0;1463 pattern = regcomp(expbuf);1464 }1466 int1467 match(int *addr)1468 {1469 if(!pattern)1470 return 0;1471 if(addr){1472 if(addr == zero)1473 return 0;1474 subexp[0].s.rsp = getline(*addr);1475 } else1476 subexp[0].s.rsp = loc2;1477 subexp[0].e.rep = 0;1478 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {1479 loc1 = subexp[0].s.rsp;1480 loc2 = subexp[0].e.rep;1481 return 1;1482 }1483 loc1 = loc2 = 0;1484 return 0;1486 }1488 void1489 putd(void)1490 {1491 int r;1493 r = count%10;1494 count /= 10;1495 if(count)1496 putd();1497 putchr(r + L'0');1498 }1500 void1501 putst(char *sp)1502 {1503 Rune r;1505 col = 0;1506 for(;;) {1507 sp += chartorune(&r, sp);1508 if(r == 0)1509 break;1510 putchr(r);1511 }1512 putchr(L'\n');1513 }1515 void1516 putshst(Rune *sp)1517 {1518 col = 0;1519 while(*sp)1520 putchr(*sp++);1521 putchr(L'\n');1522 }1524 void1525 putchr(int ac)1526 {1527 char *lp;1528 int c;1529 Rune rune;1531 lp = linp;1532 c = ac;1533 if(listf) {1534 if(c == '\n') {1535 if(linp != line && linp[-1] == ' ') {1536 *lp++ = '\\';1537 *lp++ = 'n';1538 }1539 } else {1540 if(col > (72-6-2)) {1541 col = 8;1542 *lp++ = '\\';1543 *lp++ = '\n';1544 *lp++ = '\t';1545 }1546 col++;1547 if(c=='\b' || c=='\t' || c=='\\') {1548 *lp++ = '\\';1549 if(c == '\b')1550 c = 'b';1551 else1552 if(c == '\t')1553 c = 't';1554 col++;1555 } else1556 if(c<' ' || c>='\177') {1557 *lp++ = '\\';1558 *lp++ = 'x';1559 *lp++ = hex[c>>12];1560 *lp++ = hex[c>>8&0xF];1561 *lp++ = hex[c>>4&0xF];1562 c = hex[c&0xF];1563 col += 5;1564 }1565 }1566 }1568 rune = c;1569 lp += runetochar(lp, &rune);1571 if(c == '\n' || lp >= &line[sizeof(line)-5]) {1572 linp = line;1573 write(oflag? 2: 1, line, lp-line);1574 return;1575 }1576 linp = lp;1577 }1579 char*1580 mktemp(char *as)1581 {1582 char *s;1583 unsigned pid;1584 int i;1586 pid = getpid();1587 s = as;1588 while(*s++)1589 ;1590 s--;1591 while(*--s == 'X') {1592 *s = pid % 10 + '0';1593 pid /= 10;1594 }1595 s++;1596 i = 'a';1597 while(access(as, 0) != -1) {1598 if(i == 'z')1599 return "/";1600 *s = i++;1601 }1602 return as;1603 }1605 void1606 regerror(char *s)1607 {1608 USED(s);1609 error(Q);1610 }