Blob
1 /*2 * Editor3 */4 #include <u.h>5 #include <libc.h>6 #include <bio.h>7 #include <regexp.h>9 enum10 {11 FNSIZE = 128, /* file name */12 LBSIZE = 4096, /* max line size */13 BLKSIZE = 4096, /* block size in temp file */14 NBLK = 8191, /* max size of temp file */15 ESIZE = 256, /* max size of reg exp */16 GBSIZE = 256, /* max size of global command */17 MAXSUB = 9, /* max number of sub reg exp */18 ESCFLG = 0xFFFF, /* escape Rune - user defined code */19 EOF = -1,20 };22 void (*oldhup)(int);23 void (*oldquit)(int);24 int* addr1;25 int* addr2;26 int anymarks;27 int col;28 long count;29 int* dol;30 int* dot;31 int fchange;32 char file[FNSIZE];33 Rune genbuf[LBSIZE];34 int given;35 Rune* globp;36 int iblock;37 int ichanged;38 int io;39 Biobuf iobuf;40 int lastc;41 char line[70];42 Rune* linebp;43 Rune linebuf[LBSIZE];44 int listf;45 int listn;46 Rune* loc1;47 Rune* loc2;48 int names[26];49 int nleft;50 int oblock;51 int oflag;52 Reprog *pattern;53 int peekc;54 int pflag;55 int rescuing;56 Rune rhsbuf[LBSIZE/2];57 char savedfile[FNSIZE];58 jmp_buf savej;59 int subnewa;60 int subolda;61 Resub subexp[MAXSUB];62 char* tfname;63 int tline;64 int waiting;65 int wrapp;66 int* zero;68 char Q[] = "";69 char T[] = "TMP";70 char WRERR[] = "WRITE ERROR";71 int bpagesize = 20;72 char hex[] = "0123456789abcdef";73 char* linp = line;74 ulong nlall = 128;75 int tfile = -1;76 int vflag = 1;78 void add(int);79 int* address(void);80 int append(int(*)(void), int*);81 void browse(void);82 void callunix(void);83 void commands(void);84 void compile(int);85 int compsub(void);86 void dosub(void);87 void error(char*);88 int match(int*);89 void exfile(int);90 void filename(int);91 Rune* getblock(int, int);92 int getchr(void);93 int getcopy(void);94 int getfile(void);95 Rune* getline(int);96 int getnum(void);97 int getsub(void);98 int gettty(void);99 void global(int);100 void init(void);101 void join(void);102 void move(int);103 void newline(void);104 void nonzero(void);105 void notifyf(void*, char*);106 Rune* place(Rune*, Rune*, Rune*);107 void printcom(void);108 void putchr(int);109 void putd(void);110 void putfile(void);111 int putline(void);112 void putshst(Rune*);113 void putst(char*);114 void quit(void);115 void rdelete(int*, int*);116 void regerror(char *);117 void reverse(int*, int*);118 void setnoaddr(void);119 void setwide(void);120 void squeeze(int);121 void substitute(int);123 Rune La[] = { 'a', 0 };124 Rune Lr[] = { 'r', 0 };126 char tmp[] = "/tmp/eXXXXX";128 void129 main(int argc, char *argv[])130 {131 char *p1, *p2;133 notify(notifyf);134 ARGBEGIN {135 case 'o':136 oflag = 1;137 vflag = 0;138 break;139 } ARGEND141 USED(argc);142 if(*argv && (strcmp(*argv, "-") == 0)) {143 argv++;144 vflag = 0;145 }146 if(oflag) {147 p1 = "/fd/1";148 p2 = savedfile;149 while(*p2++ = *p1++)150 ;151 globp = La;152 } else153 if(*argv) {154 p1 = *argv;155 p2 = savedfile;156 while(*p2++ = *p1++)157 if(p2 >= &savedfile[sizeof(savedfile)])158 p2--;159 globp = Lr;160 }161 zero = malloc((nlall+5)*sizeof(int*));162 tfname = mktemp(tmp);163 init();164 setjmp(savej);165 commands();166 quit();167 }169 void170 commands(void)171 {172 int *a1, c, temp;173 char lastsep;174 Dir *d;176 for(;;) {177 if(pflag) {178 pflag = 0;179 addr1 = addr2 = dot;180 printcom();181 }182 c = '\n';183 for(addr1 = 0;;) {184 lastsep = c;185 a1 = address();186 c = getchr();187 if(c != ',' && c != ';')188 break;189 if(lastsep == ',')190 error(Q);191 if(a1 == 0) {192 a1 = zero+1;193 if(a1 > dol)194 a1--;195 }196 addr1 = a1;197 if(c == ';')198 dot = a1;199 }200 if(lastsep != '\n' && a1 == 0)201 a1 = dol;202 if((addr2=a1) == 0) {203 given = 0;204 addr2 = dot;205 } else206 given = 1;207 if(addr1 == 0)208 addr1 = addr2;209 switch(c) {211 case 'a':212 add(0);213 continue;215 case 'b':216 nonzero();217 browse();218 continue;220 case 'c':221 nonzero();222 newline();223 rdelete(addr1, addr2);224 append(gettty, addr1-1);225 continue;227 case 'd':228 nonzero();229 newline();230 rdelete(addr1, addr2);231 continue;233 case 'E':234 fchange = 0;235 c = 'e';236 case 'e':237 setnoaddr();238 if(vflag && fchange) {239 fchange = 0;240 error(Q);241 }242 filename(c);243 init();244 addr2 = zero;245 goto caseread;247 case 'f':248 setnoaddr();249 filename(c);250 putst(savedfile);251 continue;253 case 'g':254 global(1);255 continue;257 case 'i':258 add(-1);259 continue;262 case 'j':263 if(!given)264 addr2++;265 newline();266 join();267 continue;269 case 'k':270 nonzero();271 c = getchr();272 if(c < 'a' || c > 'z')273 error(Q);274 newline();275 names[c-'a'] = *addr2 & ~01;276 anymarks |= 01;277 continue;279 case 'm':280 move(0);281 continue;283 case 'n':284 listn++;285 newline();286 printcom();287 continue;289 case '\n':290 if(a1==0) {291 a1 = dot+1;292 addr2 = a1;293 addr1 = a1;294 }295 if(lastsep==';')296 addr1 = a1;297 printcom();298 continue;300 case 'l':301 listf++;302 case 'p':303 case 'P':304 newline();305 printcom();306 continue;308 case 'Q':309 fchange = 0;310 case 'q':311 setnoaddr();312 newline();313 quit();315 case 'r':316 filename(c);317 caseread:318 if((io=open(file, OREAD)) < 0) {319 lastc = '\n';320 error(file);321 }322 if((d = dirfstat(io)) != nil){323 if(d->mode & DMAPPEND)324 print("warning: %s is append only\n", file);325 free(d);326 }327 Binit(&iobuf, io, OREAD);328 setwide();329 squeeze(0);330 c = zero != dol;331 append(getfile, addr2);332 exfile(OREAD);334 fchange = c;335 continue;337 case 's':338 nonzero();339 substitute(globp != 0);340 continue;342 case 't':343 move(1);344 continue;346 case 'u':347 nonzero();348 newline();349 if((*addr2&~01) != subnewa)350 error(Q);351 *addr2 = subolda;352 dot = addr2;353 continue;355 case 'v':356 global(0);357 continue;359 case 'W':360 wrapp++;361 case 'w':362 setwide();363 squeeze(dol>zero);364 temp = getchr();365 if(temp != 'q' && temp != 'Q') {366 peekc = temp;367 temp = 0;368 }369 filename(c);370 if(!wrapp ||371 ((io = open(file, OWRITE)) == -1) ||372 ((seek(io, 0L, 2)) == -1))373 if((io = create(file, OWRITE, 0666)) < 0)374 error(file);375 Binit(&iobuf, io, OWRITE);376 wrapp = 0;377 if(dol > zero)378 putfile();379 exfile(OWRITE);380 if(addr1<=zero+1 && addr2==dol)381 fchange = 0;382 if(temp == 'Q')383 fchange = 0;384 if(temp)385 quit();386 continue;388 case '=':389 setwide();390 squeeze(0);391 newline();392 count = addr2 - zero;393 putd();394 putchr(L'\n');395 continue;397 case '!':398 callunix();399 continue;401 case EOF:402 return;404 }405 error(Q);406 }407 }409 void410 printcom(void)411 {412 int *a1;414 nonzero();415 a1 = addr1;416 do {417 if(listn) {418 count = a1-zero;419 putd();420 putchr(L'\t');421 }422 putshst(getline(*a1++));423 } while(a1 <= addr2);424 dot = addr2;425 listf = 0;426 listn = 0;427 pflag = 0;428 }430 int*431 address(void)432 {433 int sign, *a, opcnt, nextopand, *b, c;435 nextopand = -1;436 sign = 1;437 opcnt = 0;438 a = dot;439 do {440 do {441 c = getchr();442 } while(c == ' ' || c == '\t');443 if(c >= '0' && c <= '9') {444 peekc = c;445 if(!opcnt)446 a = zero;447 a += sign*getnum();448 } else449 switch(c) {450 case '$':451 a = dol;452 case '.':453 if(opcnt)454 error(Q);455 break;456 case '\'':457 c = getchr();458 if(opcnt || c < 'a' || c > 'z')459 error(Q);460 a = zero;461 do {462 a++;463 } while(a <= dol && names[c-'a'] != (*a & ~01));464 break;465 case '?':466 sign = -sign;467 case '/':468 compile(c);469 b = a;470 for(;;) {471 a += sign;472 if(a <= zero)473 a = dol;474 if(a > dol)475 a = zero;476 if(match(a))477 break;478 if(a == b)479 error(Q);480 }481 break;482 default:483 if(nextopand == opcnt) {484 a += sign;485 if(a < zero || dol < a)486 continue; /* error(Q); */487 }488 if(c != '+' && c != '-' && c != '^') {489 peekc = c;490 if(opcnt == 0)491 a = 0;492 return a;493 }494 sign = 1;495 if(c != '+')496 sign = -sign;497 nextopand = ++opcnt;498 continue;499 }500 sign = 1;501 opcnt++;502 } while(zero <= a && a <= dol);503 error(Q);504 return 0;505 }507 int508 getnum(void)509 {510 int r, c;512 r = 0;513 for(;;) {514 c = getchr();515 if(c < '0' || c > '9')516 break;517 r = r*10 + (c-'0');518 }519 peekc = c;520 return r;521 }523 void524 setwide(void)525 {526 if(!given) {527 addr1 = zero + (dol>zero);528 addr2 = dol;529 }530 }532 void533 setnoaddr(void)534 {535 if(given)536 error(Q);537 }539 void540 nonzero(void)541 {542 squeeze(1);543 }545 void546 squeeze(int i)547 {548 if(addr1 < zero+i || addr2 > dol || addr1 > addr2)549 error(Q);550 }552 void553 newline(void)554 {555 int c;557 c = getchr();558 if(c == '\n' || c == EOF)559 return;560 if(c == 'p' || c == 'l' || c == 'n') {561 pflag++;562 if(c == 'l')563 listf++;564 else565 if(c == 'n')566 listn++;567 c = getchr();568 if(c == '\n')569 return;570 }571 error(Q);572 }574 void575 filename(int comm)576 {577 char *p1, *p2;578 Rune rune;579 int c;581 count = 0;582 c = getchr();583 if(c == '\n' || c == EOF) {584 p1 = savedfile;585 if(*p1 == 0 && comm != 'f')586 error(Q);587 p2 = file;588 while(*p2++ = *p1++)589 ;590 return;591 }592 if(c != ' ')593 error(Q);594 while((c=getchr()) == ' ')595 ;596 if(c == '\n')597 error(Q);598 p1 = file;599 do {600 if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)601 error(Q);602 rune = c;603 p1 += runetochar(p1, &rune);604 } while((c=getchr()) != '\n');605 *p1 = 0;606 if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {607 p1 = savedfile;608 p2 = file;609 while(*p1++ = *p2++)610 ;611 }612 }614 void615 exfile(int om)616 {618 if(om == OWRITE)619 if(Bflush(&iobuf) < 0)620 error(Q);621 close(io);622 io = -1;623 if(vflag) {624 putd();625 putchr(L'\n');626 }627 }629 void630 error1(char *s)631 {632 int c;634 wrapp = 0;635 listf = 0;636 listn = 0;637 count = 0;638 seek(0, 0, 2);639 pflag = 0;640 if(globp)641 lastc = '\n';642 globp = 0;643 peekc = lastc;644 if(lastc)645 for(;;) {646 c = getchr();647 if(c == '\n' || c == EOF)648 break;649 }650 if(io > 0) {651 close(io);652 io = -1;653 }654 putchr(L'?');655 putst(s);656 }658 void659 error(char *s)660 {661 error1(s);662 longjmp(savej, 1);663 }665 void666 rescue(void)667 {668 rescuing = 1;669 if(dol > zero) {670 addr1 = zero+1;671 addr2 = dol;672 io = create("ed.hup", OWRITE, 0666);673 if(io > 0){674 Binit(&iobuf, io, OWRITE);675 putfile();676 }677 }678 fchange = 0;679 quit();680 }682 void683 notifyf(void *a, char *s)684 {685 if(strcmp(s, "interrupt") == 0){686 if(rescuing || waiting)687 noted(NCONT);688 putchr(L'\n');689 lastc = '\n';690 error1(Q);691 notejmp(a, savej, 0);692 }693 if(strcmp(s, "hangup") == 0){694 if(rescuing)695 noted(NDFLT);696 rescue();697 }698 fprint(2, "ed: note: %s\n", s);699 abort();700 }702 int703 getchr(void)704 {705 char s[UTFmax];706 int i;707 Rune r;709 if(lastc = peekc) {710 peekc = 0;711 return lastc;712 }713 if(globp) {714 if((lastc=*globp++) != 0)715 return lastc;716 globp = 0;717 return EOF;718 }719 for(i=0;;) {720 if(read(0, s+i, 1) <= 0)721 return lastc = EOF;722 i++;723 if(fullrune(s, i))724 break;726 }727 chartorune(&r, s);728 lastc = r;729 return lastc;730 }732 int733 gety(void)734 {735 int c;736 Rune *gf, *p;738 p = linebuf;739 gf = globp;740 for(;;) {741 c = getchr();742 if(c == '\n') {743 *p = 0;744 return 0;745 }746 if(c == EOF) {747 if(gf)748 peekc = c;749 return c;750 }751 if(c == 0)752 continue;753 *p++ = c;754 if(p >= &linebuf[LBSIZE-2])755 error(Q);756 }757 return 0;758 }760 int761 gettty(void)762 {763 int rc;765 rc = gety();766 if(rc)767 return rc;768 if(linebuf[0] == '.' && linebuf[1] == 0)769 return EOF;770 return 0;771 }773 int774 getfile(void)775 {776 int c;777 Rune *lp;779 lp = linebuf;780 do {781 c = Bgetrune(&iobuf);782 if(c < 0) {783 if(lp > linebuf) {784 putst("'\\n' appended");785 c = '\n';786 } else787 return EOF;788 }789 if(lp >= &linebuf[LBSIZE]) {790 lastc = '\n';791 error(Q);792 }793 *lp++ = c;794 count++;795 } while(c != '\n');796 lp[-1] = 0;797 return 0;798 }800 void801 putfile(void)802 {803 int *a1;804 Rune *lp;805 long c;807 a1 = addr1;808 do {809 lp = getline(*a1++);810 for(;;) {811 count++;812 c = *lp++;813 if(c == 0) {814 if(Bputrune(&iobuf, '\n') < 0)815 error(Q);816 break;817 }818 if(Bputrune(&iobuf, c) < 0)819 error(Q);820 }821 } while(a1 <= addr2);822 if(Bflush(&iobuf) < 0)823 error(Q);824 }826 int827 append(int (*f)(void), int *a)828 {829 int *a1, *a2, *rdot, nline, tl;831 nline = 0;832 dot = a;833 while((*f)() == 0) {834 if((dol-zero) >= nlall) {835 nlall += 512;836 a1 = realloc(zero, (nlall+5)*sizeof(int*));837 if(a1 == 0) {838 error("MEM?");839 rescue();840 }841 tl = a1 - zero; /* relocate pointers */842 zero += tl;843 addr1 += tl;844 addr2 += tl;845 dol += tl;846 dot += tl;847 }848 tl = putline();849 nline++;850 a1 = ++dol;851 a2 = a1+1;852 rdot = ++dot;853 while(a1 > rdot)854 *--a2 = *--a1;855 *rdot = tl;856 }857 return nline;858 }860 void861 add(int i)862 {863 if(i && (given || dol > zero)) {864 addr1--;865 addr2--;866 }867 squeeze(0);868 newline();869 append(gettty, addr2);870 }872 void873 browse(void)874 {875 int forward, n;876 static int bformat, bnum; /* 0 */878 forward = 1;879 peekc = getchr();880 if(peekc != '\n'){881 if(peekc == '-' || peekc == '+') {882 if(peekc == '-')883 forward = 0;884 getchr();885 }886 n = getnum();887 if(n > 0)888 bpagesize = n;889 }890 newline();891 if(pflag) {892 bformat = listf;893 bnum = listn;894 } else {895 listf = bformat;896 listn = bnum;897 }898 if(forward) {899 addr1 = addr2;900 addr2 += bpagesize;901 if(addr2 > dol)902 addr2 = dol;903 } else {904 addr1 = addr2-bpagesize;905 if(addr1 <= zero)906 addr1 = zero+1;907 }908 printcom();909 }911 void912 callunix(void)913 {914 int c, pid;915 Rune rune;916 char buf[512];917 char *p;919 setnoaddr();920 p = buf;921 while((c=getchr()) != EOF && c != '\n')922 if(p < &buf[sizeof(buf) - 6]) {923 rune = c;924 p += runetochar(p, &rune);925 }926 *p = 0;927 pid = fork();928 if(pid == 0) {929 execl("/bin/rc", "rc", "-c", buf, 0);930 exits("execl failed");931 }932 waiting = 1;933 while(waitpid() != pid)934 ;935 waiting = 0;936 if(vflag)937 putst("!");938 }940 void941 quit(void)942 {943 if(vflag && fchange && dol!=zero) {944 fchange = 0;945 error(Q);946 }947 remove(tfname);948 exits(0);949 }951 void952 onquit(int sig)953 {954 USED(sig);955 quit();956 }958 void959 rdelete(int *ad1, int *ad2)960 {961 int *a1, *a2, *a3;963 a1 = ad1;964 a2 = ad2+1;965 a3 = dol;966 dol -= a2 - a1;967 do {968 *a1++ = *a2++;969 } while(a2 <= a3);970 a1 = ad1;971 if(a1 > dol)972 a1 = dol;973 dot = a1;974 fchange = 1;975 }977 void978 gdelete(void)979 {980 int *a1, *a2, *a3;982 a3 = dol;983 for(a1=zero; (*a1&01)==0; a1++)984 if(a1>=a3)985 return;986 for(a2=a1+1; a2<=a3;) {987 if(*a2 & 01) {988 a2++;989 dot = a1;990 } else991 *a1++ = *a2++;992 }993 dol = a1-1;994 if(dot > dol)995 dot = dol;996 fchange = 1;997 }999 Rune*1000 getline(int tl)1001 {1002 Rune *lp, *bp;1003 int nl;1005 lp = linebuf;1006 bp = getblock(tl, OREAD);1007 nl = nleft;1008 tl &= ~((BLKSIZE/2) - 1);1009 while(*lp++ = *bp++) {1010 nl -= sizeof(Rune);1011 if(nl == 0) {1012 bp = getblock(tl += BLKSIZE/2, OREAD);1013 nl = nleft;1014 }1015 }1016 return linebuf;1017 }1019 int1020 putline(void)1021 {1022 Rune *lp, *bp;1023 int nl, tl;1025 fchange = 1;1026 lp = linebuf;1027 tl = tline;1028 bp = getblock(tl, OWRITE);1029 nl = nleft;1030 tl &= ~((BLKSIZE/2)-1);1031 while(*bp = *lp++) {1032 if(*bp++ == '\n') {1033 bp[-1] = 0;1034 linebp = lp;1035 break;1036 }1037 nl -= sizeof(Rune);1038 if(nl == 0) {1039 tl += BLKSIZE/2;1040 bp = getblock(tl, OWRITE);1041 nl = nleft;1042 }1043 }1044 nl = tline;1045 tline += ((lp-linebuf) + 03) & 077776;1046 return nl;1047 }1049 void1050 blkio(int b, uchar *buf, int isread)1051 {1052 int n;1054 seek(tfile, b*BLKSIZE, 0);1055 if(isread)1056 n = read(tfile, buf, BLKSIZE);1057 else1058 n = write(tfile, buf, BLKSIZE);1059 if(n != BLKSIZE)1060 error(T);1061 }1063 Rune*1064 getblock(int atl, int iof)1065 {1066 int bno, off;1068 static uchar ibuff[BLKSIZE];1069 static uchar obuff[BLKSIZE];1071 bno = atl / (BLKSIZE/2);1072 off = (atl<<1) & (BLKSIZE-1) & ~03;1073 if(bno >= NBLK) {1074 lastc = '\n';1075 error(T);1076 }1077 nleft = BLKSIZE - off;1078 if(bno == iblock) {1079 ichanged |= iof;1080 return (Rune*)(ibuff+off);1081 }1082 if(bno == oblock)1083 return (Rune*)(obuff+off);1084 if(iof == OREAD) {1085 if(ichanged)1086 blkio(iblock, ibuff, 0);1087 ichanged = 0;1088 iblock = bno;1089 blkio(bno, ibuff, 1);1090 return (Rune*)(ibuff+off);1091 }1092 if(oblock >= 0)1093 blkio(oblock, obuff, 0);1094 oblock = bno;1095 return (Rune*)(obuff+off);1096 }1098 void1099 init(void)1100 {1101 int *markp;1103 close(tfile);1104 tline = 2;1105 for(markp = names; markp < &names[26]; )1106 *markp++ = 0;1107 subnewa = 0;1108 anymarks = 0;1109 iblock = -1;1110 oblock = -1;1111 ichanged = 0;1112 if((tfile = create(tfname, ORDWR, 0600)) < 0){1113 error1(T);1114 exits(0);1115 }1116 dot = dol = zero;1117 }1119 void1120 global(int k)1121 {1122 Rune *gp, globuf[GBSIZE];1123 int c, *a1;1125 if(globp)1126 error(Q);1127 setwide();1128 squeeze(dol > zero);1129 c = getchr();1130 if(c == '\n')1131 error(Q);1132 compile(c);1133 gp = globuf;1134 while((c=getchr()) != '\n') {1135 if(c == EOF)1136 error(Q);1137 if(c == '\\') {1138 c = getchr();1139 if(c != '\n')1140 *gp++ = '\\';1141 }1142 *gp++ = c;1143 if(gp >= &globuf[GBSIZE-2])1144 error(Q);1145 }1146 if(gp == globuf)1147 *gp++ = 'p';1148 *gp++ = '\n';1149 *gp = 0;1150 for(a1=zero; a1<=dol; a1++) {1151 *a1 &= ~01;1152 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)1153 *a1 |= 01;1154 }1156 /*1157 * Special case: g/.../d (avoid n^2 algorithm)1158 */1159 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {1160 gdelete();1161 return;1162 }1163 for(a1=zero; a1<=dol; a1++) {1164 if(*a1 & 01) {1165 *a1 &= ~01;1166 dot = a1;1167 globp = globuf;1168 commands();1169 a1 = zero;1170 }1171 }1172 }1174 void1175 join(void)1176 {1177 Rune *gp, *lp;1178 int *a1;1180 nonzero();1181 gp = genbuf;1182 for(a1=addr1; a1<=addr2; a1++) {1183 lp = getline(*a1);1184 while(*gp = *lp++)1185 if(gp++ >= &genbuf[LBSIZE-2])1186 error(Q);1187 }1188 lp = linebuf;1189 gp = genbuf;1190 while(*lp++ = *gp++)1191 ;1192 *addr1 = putline();1193 if(addr1 < addr2)1194 rdelete(addr1+1, addr2);1195 dot = addr1;1196 }1198 void1199 substitute(int inglob)1200 {1201 int *mp, *a1, nl, gsubf, n;1203 n = getnum(); /* OK even if n==0 */1204 gsubf = compsub();1205 for(a1 = addr1; a1 <= addr2; a1++) {1206 if(match(a1)){1207 int *ozero;1208 int m = n;1210 do {1211 int span = loc2-loc1;1213 if(--m <= 0) {1214 dosub();1215 if(!gsubf)1216 break;1217 if(span == 0) { /* null RE match */1218 if(*loc2 == 0)1219 break;1220 loc2++;1221 }1222 }1223 } while(match(0));1224 if(m <= 0) {1225 inglob |= 01;1226 subnewa = putline();1227 *a1 &= ~01;1228 if(anymarks) {1229 for(mp=names; mp<&names[26]; mp++)1230 if(*mp == *a1)1231 *mp = subnewa;1232 }1233 subolda = *a1;1234 *a1 = subnewa;1235 ozero = zero;1236 nl = append(getsub, a1);1237 addr2 += nl;1238 nl += zero-ozero;1239 a1 += nl;1240 }1241 }1242 }1243 if(inglob == 0)1244 error(Q);1245 }1247 int1248 compsub(void)1249 {1250 int seof, c;1251 Rune *p;1253 seof = getchr();1254 if(seof == '\n' || seof == ' ')1255 error(Q);1256 compile(seof);1257 p = rhsbuf;1258 for(;;) {1259 c = getchr();1260 if(c == '\\') {1261 c = getchr();1262 *p++ = ESCFLG;1263 if(p >= &rhsbuf[LBSIZE/2])1264 error(Q);1265 } else1266 if(c == '\n' && (!globp || !globp[0])) {1267 peekc = c;1268 pflag++;1269 break;1270 } else1271 if(c == seof)1272 break;1273 *p++ = c;1274 if(p >= &rhsbuf[LBSIZE/2])1275 error(Q);1276 }1277 *p = 0;1278 peekc = getchr();1279 if(peekc == 'g') {1280 peekc = 0;1281 newline();1282 return 1;1283 }1284 newline();1285 return 0;1286 }1288 int1289 getsub(void)1290 {1291 Rune *p1, *p2;1293 p1 = linebuf;1294 if((p2 = linebp) == 0)1295 return EOF;1296 while(*p1++ = *p2++)1297 ;1298 linebp = 0;1299 return 0;1300 }1302 void1303 dosub(void)1304 {1305 Rune *lp, *sp, *rp;1306 int c, n;1308 lp = linebuf;1309 sp = genbuf;1310 rp = rhsbuf;1311 while(lp < loc1)1312 *sp++ = *lp++;1313 while(c = *rp++) {1314 if(c == '&'){1315 sp = place(sp, loc1, loc2);1316 continue;1317 }1318 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {1319 n = c-'0';1320 if(subexp[n].s.rsp && subexp[n].e.rep) {1321 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);1322 continue;1323 }1324 error(Q);1325 }1326 *sp++ = c;1327 if(sp >= &genbuf[LBSIZE])1328 error(Q);1329 }1330 lp = loc2;1331 loc2 = sp - genbuf + linebuf;1332 while(*sp++ = *lp++)1333 if(sp >= &genbuf[LBSIZE])1334 error(Q);1335 lp = linebuf;1336 sp = genbuf;1337 while(*lp++ = *sp++)1338 ;1339 }1341 Rune*1342 place(Rune *sp, Rune *l1, Rune *l2)1343 {1345 while(l1 < l2) {1346 *sp++ = *l1++;1347 if(sp >= &genbuf[LBSIZE])1348 error(Q);1349 }1350 return sp;1351 }1353 void1354 move(int cflag)1355 {1356 int *adt, *ad1, *ad2;1358 nonzero();1359 if((adt = address())==0) /* address() guarantees addr is in range */1360 error(Q);1361 newline();1362 if(cflag) {1363 int *ozero, delta;1364 ad1 = dol;1365 ozero = zero;1366 append(getcopy, ad1++);1367 ad2 = dol;1368 delta = zero - ozero;1369 ad1 += delta;1370 adt += delta;1371 } else {1372 ad2 = addr2;1373 for(ad1 = addr1; ad1 <= ad2;)1374 *ad1++ &= ~01;1375 ad1 = addr1;1376 }1377 ad2++;1378 if(adt<ad1) {1379 dot = adt + (ad2-ad1);1380 if((++adt)==ad1)1381 return;1382 reverse(adt, ad1);1383 reverse(ad1, ad2);1384 reverse(adt, ad2);1385 } else1386 if(adt >= ad2) {1387 dot = adt++;1388 reverse(ad1, ad2);1389 reverse(ad2, adt);1390 reverse(ad1, adt);1391 } else1392 error(Q);1393 fchange = 1;1394 }1396 void1397 reverse(int *a1, int *a2)1398 {1399 int t;1401 for(;;) {1402 t = *--a2;1403 if(a2 <= a1)1404 return;1405 *a2 = *a1;1406 *a1++ = t;1407 }1408 }1410 int1411 getcopy(void)1412 {1413 if(addr1 > addr2)1414 return EOF;1415 getline(*addr1++);1416 return 0;1417 }1419 void1420 compile(int eof)1421 {1422 Rune c;1423 char *ep;1424 char expbuf[ESIZE];1426 if((c = getchr()) == '\n') {1427 peekc = c;1428 c = eof;1429 }1430 if(c == eof) {1431 if(!pattern)1432 error(Q);1433 return;1434 }1435 if(pattern) {1436 free(pattern);1437 pattern = 0;1438 }1439 ep = expbuf;1440 do {1441 if(c == '\\') {1442 if(ep >= expbuf+sizeof(expbuf)) {1443 error(Q);1444 return;1445 }1446 ep += runetochar(ep, &c);1447 if((c = getchr()) == '\n') {1448 error(Q);1449 return;1450 }1451 }1452 if(ep >= expbuf+sizeof(expbuf)) {1453 error(Q);1454 return;1455 }1456 ep += runetochar(ep, &c);1457 } while((c = getchr()) != eof && c != '\n');1458 if(c == '\n')1459 peekc = c;1460 *ep = 0;1461 pattern = regcomp(expbuf);1462 }1464 int1465 match(int *addr)1466 {1467 if(!pattern)1468 return 0;1469 if(addr){1470 if(addr == zero)1471 return 0;1472 subexp[0].s.rsp = getline(*addr);1473 } else1474 subexp[0].s.rsp = loc2;1475 subexp[0].e.rep = 0;1476 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {1477 loc1 = subexp[0].s.rsp;1478 loc2 = subexp[0].e.rep;1479 return 1;1480 }1481 loc1 = loc2 = 0;1482 return 0;1484 }1486 void1487 putd(void)1488 {1489 int r;1491 r = count%10;1492 count /= 10;1493 if(count)1494 putd();1495 putchr(r + L'0');1496 }1498 void1499 putst(char *sp)1500 {1501 Rune r;1503 col = 0;1504 for(;;) {1505 sp += chartorune(&r, sp);1506 if(r == 0)1507 break;1508 putchr(r);1509 }1510 putchr(L'\n');1511 }1513 void1514 putshst(Rune *sp)1515 {1516 col = 0;1517 while(*sp)1518 putchr(*sp++);1519 putchr(L'\n');1520 }1522 void1523 putchr(int ac)1524 {1525 char *lp;1526 int c;1527 Rune rune;1529 lp = linp;1530 c = ac;1531 if(listf) {1532 if(c == '\n') {1533 if(linp != line && linp[-1] == ' ') {1534 *lp++ = '\\';1535 *lp++ = 'n';1536 }1537 } else {1538 if(col > (72-6-2)) {1539 col = 8;1540 *lp++ = '\\';1541 *lp++ = '\n';1542 *lp++ = '\t';1543 }1544 col++;1545 if(c=='\b' || c=='\t' || c=='\\') {1546 *lp++ = '\\';1547 if(c == '\b')1548 c = 'b';1549 else1550 if(c == '\t')1551 c = 't';1552 col++;1553 } else1554 if(c<' ' || c>='\177') {1555 *lp++ = '\\';1556 *lp++ = 'x';1557 *lp++ = hex[c>>12];1558 *lp++ = hex[c>>8&0xF];1559 *lp++ = hex[c>>4&0xF];1560 c = hex[c&0xF];1561 col += 5;1562 }1563 }1564 }1566 rune = c;1567 lp += runetochar(lp, &rune);1569 if(c == '\n' || lp >= &line[sizeof(line)-5]) {1570 linp = line;1571 write(oflag? 2: 1, line, lp-line);1572 return;1573 }1574 linp = lp;1575 }1577 char*1578 mktemp(char *as)1579 {1580 char *s;1581 unsigned pid;1582 int i;1584 pid = getpid();1585 s = as;1586 while(*s++)1587 ;1588 s--;1589 while(*--s == 'X') {1590 *s = pid % 10 + '0';1591 pid /= 10;1592 }1593 s++;1594 i = 'a';1595 while(access(as, 0) != -1) {1596 if(i == 'z')1597 return "/";1598 *s = i++;1599 }1600 return as;1601 }1603 void1604 regerror(char *s)1605 {1606 USED(s);1607 error(Q);1608 }