Blob
- Date:
- Message:
- ed: handle Unicode beyond the BMP correctly in list mode. List mode was constrained to the BMP. This change introduces the following new list mode convention, using Go string literal syntax: Non-printing ASCII characters display as \xhh. Non-ASCII characters in the BMP display as \uhhhh. Characters beyond the BMP display as \Uhhhhhhhh.
- Actions:
- History | Blame | Raw File
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 = 32767, /* 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 enum25 {26 LINELEN = 70, /* max number of glyphs in a display line */27 BELL = 6 /* A char could require up to BELL glyphs to display */28 };30 void (*oldhup)(int);31 void (*oldquit)(int);32 int* addr1;33 int* addr2;34 int anymarks;35 int col;36 long count;37 int* dol;38 int* dot;39 int fchange;40 char file[FNSIZE];41 Rune genbuf[LBSIZE];42 int given;43 Rune* globp;44 int iblock;45 int ichanged;46 int io;47 Biobuf iobuf;48 int lastc;49 char line[LINELEN];50 Rune* linebp;51 Rune linebuf[LBSIZE];52 int listf;53 int listn;54 Rune* loc1;55 Rune* loc2;56 int names[26];57 int nleft;58 int oblock;59 int oflag;60 Reprog *pattern;61 int peekc;62 int pflag;63 int rescuing;64 Rune rhsbuf[LBSIZE/sizeof(Rune)];65 char savedfile[FNSIZE];66 jmp_buf savej;67 int subnewa;68 int subolda;69 Resub subexp[MAXSUB];70 char* tfname;71 int tline;72 int waiting;73 int wrapp;74 int* zero;76 char Q[] = "";77 char T[] = "TMP";78 char WRERR[] = "WRITE ERROR";79 int bpagesize = 20;80 char hex[] = "0123456789abcdef";81 char* linp = line;82 ulong nlall = 128;83 int tfile = -1;84 int vflag = 1;86 void add(int);87 int* address(void);88 int append(int(*)(void), int*);89 void browse(void);90 void callunix(void);91 void commands(void);92 void compile(int);93 int compsub(void);94 void dosub(void);95 void error(char*);96 int match(int*);97 void exfile(int);98 void filename(int);99 Rune* getblock(int, int);100 int getchr(void);101 int getcopy(void);102 int getfile(void);103 Rune* getline(int);104 int getnum(void);105 int getsub(void);106 int gettty(void);107 void global(int);108 void init(void);109 void join(void);110 void move(int);111 void newline(void);112 void nonzero(void);113 void notifyf(void*, char*);114 Rune* place(Rune*, Rune*, Rune*);115 void printcom(void);116 void putchr(int);117 void putd(void);118 void putfile(void);119 int putline(void);120 void putshst(Rune*);121 void putst(char*);122 void quit(void);123 void rdelete(int*, int*);124 void regerror(char *);125 void reverse(int*, int*);126 void setnoaddr(void);127 void setwide(void);128 void squeeze(int);129 void substitute(int);131 Rune La[] = { 'a', 0 };132 Rune Lr[] = { 'r', 0 };134 char tmp[] = "/var/tmp/eXXXXX";136 void137 main(int argc, char *argv[])138 {139 char *p1, *p2;141 notify(notifyf);142 ARGBEGIN {143 case 'o':144 oflag = 1;145 vflag = 0;146 break;147 } ARGEND149 USED(argc);150 if(*argv && (strcmp(*argv, "-") == 0)) {151 argv++;152 vflag = 0;153 }154 if(oflag) {155 p1 = "/dev/stdout";156 p2 = savedfile;157 while(*p2++ = *p1++)158 ;159 globp = La;160 } else161 if(*argv) {162 p1 = *argv;163 p2 = savedfile;164 while(*p2++ = *p1++)165 if(p2 >= &savedfile[sizeof(savedfile)])166 p2--;167 globp = Lr;168 }169 zero = malloc((nlall+5)*sizeof(int*));170 tfname = mktemp(tmp);171 init();172 setjmp(savej);173 commands();174 quit();175 }177 void178 commands(void)179 {180 int *a1, c, temp;181 char lastsep;182 Dir *d;184 for(;;) {185 if(pflag) {186 pflag = 0;187 addr1 = addr2 = dot;188 printcom();189 }190 c = '\n';191 for(addr1 = 0;;) {192 lastsep = c;193 a1 = address();194 c = getchr();195 if(c != ',' && c != ';')196 break;197 if(lastsep == ',')198 error(Q);199 if(a1 == 0) {200 a1 = zero+1;201 if(a1 > dol)202 a1--;203 }204 addr1 = a1;205 if(c == ';')206 dot = a1;207 }208 if(lastsep != '\n' && a1 == 0)209 a1 = dol;210 if((addr2=a1) == 0) {211 given = 0;212 addr2 = dot;213 } else214 given = 1;215 if(addr1 == 0)216 addr1 = addr2;217 switch(c) {219 case 'a':220 add(0);221 continue;223 case 'b':224 nonzero();225 browse();226 continue;228 case 'c':229 nonzero();230 newline();231 rdelete(addr1, addr2);232 append(gettty, addr1-1);233 continue;235 case 'd':236 nonzero();237 newline();238 rdelete(addr1, addr2);239 continue;241 case 'E':242 fchange = 0;243 c = 'e';244 case 'e':245 setnoaddr();246 if(vflag && fchange) {247 fchange = 0;248 error(Q);249 }250 filename(c);251 init();252 addr2 = zero;253 goto caseread;255 case 'f':256 setnoaddr();257 filename(c);258 putst(savedfile);259 continue;261 case 'g':262 global(1);263 continue;265 case 'i':266 add(-1);267 continue;270 case 'j':271 if(!given)272 addr2++;273 newline();274 join();275 continue;277 case 'k':278 nonzero();279 c = getchr();280 if(c < 'a' || c > 'z')281 error(Q);282 newline();283 names[c-'a'] = *addr2 & ~01;284 anymarks |= 01;285 continue;287 case 'm':288 move(0);289 continue;291 case 'n':292 listn++;293 newline();294 printcom();295 continue;297 case '\n':298 if(a1==0) {299 a1 = dot+1;300 addr2 = a1;301 addr1 = a1;302 }303 if(lastsep==';')304 addr1 = a1;305 printcom();306 continue;308 case 'l':309 listf++;310 case 'p':311 case 'P':312 newline();313 printcom();314 continue;316 case 'Q':317 fchange = 0;318 case 'q':319 setnoaddr();320 newline();321 quit();323 case 'r':324 filename(c);325 caseread:326 if((io=open(file, OREAD)) < 0) {327 lastc = '\n';328 error(file);329 }330 if((d = dirfstat(io)) != nil){331 if(d->mode & DMAPPEND)332 print("warning: %s is append only\n", file);333 free(d);334 }335 Binit(&iobuf, io, OREAD);336 setwide();337 squeeze(0);338 c = zero != dol;339 append(getfile, addr2);340 exfile(OREAD);342 fchange = c;343 continue;345 case 's':346 nonzero();347 substitute(globp != 0);348 continue;350 case 't':351 move(1);352 continue;354 case 'u':355 nonzero();356 newline();357 if((*addr2&~01) != subnewa)358 error(Q);359 *addr2 = subolda;360 dot = addr2;361 continue;363 case 'v':364 global(0);365 continue;367 case 'W':368 wrapp++;369 case 'w':370 setwide();371 squeeze(dol>zero);372 temp = getchr();373 if(temp != 'q' && temp != 'Q') {374 peekc = temp;375 temp = 0;376 }377 filename(c);378 if(!wrapp ||379 ((io = open(file, OWRITE)) == -1) ||380 ((seek(io, 0L, 2)) == -1))381 if((io = create(file, OWRITE, 0666)) < 0)382 error(file);383 Binit(&iobuf, io, OWRITE);384 wrapp = 0;385 if(dol > zero)386 putfile();387 exfile(OWRITE);388 if(addr1<=zero+1 && addr2==dol)389 fchange = 0;390 if(temp == 'Q')391 fchange = 0;392 if(temp)393 quit();394 continue;396 case '=':397 setwide();398 squeeze(0);399 newline();400 count = addr2 - zero;401 putd();402 putchr('\n');403 continue;405 case '!':406 callunix();407 continue;409 case EOF:410 return;412 }413 error(Q);414 }415 }417 void418 printcom(void)419 {420 int *a1;422 nonzero();423 a1 = addr1;424 do {425 if(listn) {426 count = a1-zero;427 putd();428 putchr('\t');429 }430 putshst(getline(*a1++));431 } while(a1 <= addr2);432 dot = addr2;433 listf = 0;434 listn = 0;435 pflag = 0;436 }438 int*439 address(void)440 {441 int sign, *a, opcnt, nextopand, *b, c;443 nextopand = -1;444 sign = 1;445 opcnt = 0;446 a = dot;447 do {448 do {449 c = getchr();450 } while(c == ' ' || c == '\t');451 if(c >= '0' && c <= '9') {452 peekc = c;453 if(!opcnt)454 a = zero;455 a += sign*getnum();456 } else457 switch(c) {458 case '$':459 a = dol;460 case '.':461 if(opcnt)462 error(Q);463 break;464 case '\'':465 c = getchr();466 if(opcnt || c < 'a' || c > 'z')467 error(Q);468 a = zero;469 do {470 a++;471 } while(a <= dol && names[c-'a'] != (*a & ~01));472 break;473 case '?':474 sign = -sign;475 case '/':476 compile(c);477 b = a;478 for(;;) {479 a += sign;480 if(a <= zero)481 a = dol;482 if(a > dol)483 a = zero;484 if(match(a))485 break;486 if(a == b)487 error(Q);488 }489 break;490 default:491 if(nextopand == opcnt) {492 a += sign;493 if(a < zero || dol < a)494 continue; /* error(Q); */495 }496 if(c != '+' && c != '-' && c != '^') {497 peekc = c;498 if(opcnt == 0)499 a = 0;500 return a;501 }502 sign = 1;503 if(c != '+')504 sign = -sign;505 nextopand = ++opcnt;506 continue;507 }508 sign = 1;509 opcnt++;510 } while(zero <= a && a <= dol);511 error(Q);512 return 0;513 }515 int516 getnum(void)517 {518 int r, c;520 r = 0;521 for(;;) {522 c = getchr();523 if(c < '0' || c > '9')524 break;525 r = r*10 + (c-'0');526 }527 peekc = c;528 return r;529 }531 void532 setwide(void)533 {534 if(!given) {535 addr1 = zero + (dol>zero);536 addr2 = dol;537 }538 }540 void541 setnoaddr(void)542 {543 if(given)544 error(Q);545 }547 void548 nonzero(void)549 {550 squeeze(1);551 }553 void554 squeeze(int i)555 {556 if(addr1 < zero+i || addr2 > dol || addr1 > addr2)557 error(Q);558 }560 void561 newline(void)562 {563 int c;565 c = getchr();566 if(c == '\n' || c == EOF)567 return;568 if(c == 'p' || c == 'l' || c == 'n') {569 pflag++;570 if(c == 'l')571 listf++;572 else573 if(c == 'n')574 listn++;575 c = getchr();576 if(c == '\n')577 return;578 }579 error(Q);580 }582 void583 filename(int comm)584 {585 char *p1, *p2;586 Rune rune;587 int c;589 count = 0;590 c = getchr();591 if(c == '\n' || c == EOF) {592 p1 = savedfile;593 if(*p1 == 0 && comm != 'f')594 error(Q);595 p2 = file;596 while(*p2++ = *p1++)597 ;598 return;599 }600 if(c != ' ')601 error(Q);602 while((c=getchr()) == ' ')603 ;604 if(c == '\n')605 error(Q);606 p1 = file;607 do {608 if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)609 error(Q);610 rune = c;611 p1 += runetochar(p1, &rune);612 } while((c=getchr()) != '\n');613 *p1 = 0;614 if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {615 p1 = savedfile;616 p2 = file;617 while(*p1++ = *p2++)618 ;619 }620 }622 void623 exfile(int om)624 {626 if(om == OWRITE)627 if(Bflush(&iobuf) < 0)628 error(Q);629 close(io);630 io = -1;631 if(vflag) {632 putd();633 putchr('\n');634 }635 }637 void638 error1(char *s)639 {640 int c;642 wrapp = 0;643 listf = 0;644 listn = 0;645 count = 0;646 seek(0, 0, 2);647 pflag = 0;648 if(globp)649 lastc = '\n';650 globp = 0;651 peekc = lastc;652 if(lastc)653 for(;;) {654 c = getchr();655 if(c == '\n' || c == EOF)656 break;657 }658 if(io > 0) {659 close(io);660 io = -1;661 }662 putchr('?');663 putst(s);664 }666 void667 error(char *s)668 {669 error1(s);670 longjmp(savej, 1);671 }673 void674 rescue(void)675 {676 rescuing = 1;677 if(dol > zero) {678 addr1 = zero+1;679 addr2 = dol;680 io = create("ed.hup", OWRITE, 0666);681 if(io > 0){682 Binit(&iobuf, io, OWRITE);683 putfile();684 }685 }686 fchange = 0;687 quit();688 }690 void691 notifyf(void *a, char *s)692 {693 if(strcmp(s, "interrupt") == 0){694 if(rescuing || waiting)695 noted(NCONT);696 putchr('\n');697 lastc = '\n';698 error1(Q);699 notejmp(a, savej, 0);700 }701 if(strcmp(s, "hangup") == 0 || strcmp(s, "kill") == 0){702 if(rescuing)703 noted(NDFLT);704 rescue();705 }706 if(strstr(s, "child"))707 noted(NCONT);708 fprint(2, "ed: note: %s\n", s);709 abort();710 }712 int713 getchr(void)714 {715 char s[UTFmax];716 int i;717 Rune r;719 if(lastc = peekc) {720 peekc = 0;721 return lastc;722 }723 if(globp) {724 if((lastc=*globp++) != 0)725 return lastc;726 globp = 0;727 return EOF;728 }729 for(i=0;;) {730 if(read(0, s+i, 1) <= 0)731 return lastc = EOF;732 i++;733 if(fullrune(s, i))734 break;736 }737 chartorune(&r, s);738 lastc = r;739 return lastc;740 }742 int743 gety(void)744 {745 int c;746 Rune *gf, *p;748 p = linebuf;749 gf = globp;750 for(;;) {751 c = getchr();752 if(c == '\n') {753 *p = 0;754 return 0;755 }756 if(c == EOF) {757 if(gf)758 peekc = c;759 return c;760 }761 if(c == 0)762 continue;763 *p++ = c;764 if(p >= &linebuf[LBSIZE-2])765 error(Q);766 }767 }769 int770 gettty(void)771 {772 int rc;774 rc = gety();775 if(rc)776 return rc;777 if(linebuf[0] == '.' && linebuf[1] == 0)778 return EOF;779 return 0;780 }782 int783 getfile(void)784 {785 int c;786 Rune *lp;788 lp = linebuf;789 do {790 c = Bgetrune(&iobuf);791 if(c < 0) {792 if(lp > linebuf) {793 putst("'\\n' appended");794 c = '\n';795 } else796 return EOF;797 }798 if(lp >= &linebuf[LBSIZE]) {799 lastc = '\n';800 error(Q);801 }802 *lp++ = c;803 count++;804 } while(c != '\n');805 lp[-1] = 0;806 return 0;807 }809 void810 putfile(void)811 {812 int *a1;813 Rune *lp;814 long c;816 a1 = addr1;817 do {818 lp = getline(*a1++);819 for(;;) {820 count++;821 c = *lp++;822 if(c == 0) {823 if(Bputrune(&iobuf, '\n') < 0)824 error(Q);825 break;826 }827 if(Bputrune(&iobuf, c) < 0)828 error(Q);829 }830 } while(a1 <= addr2);831 if(Bflush(&iobuf) < 0)832 error(Q);833 }835 int836 append(int (*f)(void), int *a)837 {838 int *a1, *a2, *rdot, nline, d;840 nline = 0;841 dot = a;842 while((*f)() == 0) {843 if((dol-zero) >= nlall) {844 nlall += 512;845 a1 = realloc(zero, (nlall+50)*sizeof(int*));846 if(a1 == 0) {847 error("MEM?");848 rescue();849 }850 /* relocate pointers; avoid wraparound if sizeof(int) < sizeof(int*) */851 d = addr1 - zero;852 addr1 = a1 + d;853 d = addr2 - zero;854 addr2 = a1 + d;855 d = dol - zero;856 dol = a1 + d;857 d = dot - zero;858 dot = a1 + d;859 zero = a1;860 }861 d = putline();862 nline++;863 a1 = ++dol;864 a2 = a1+1;865 rdot = ++dot;866 while(a1 > rdot)867 *--a2 = *--a1;868 *rdot = d;869 }870 return nline;871 }873 void874 add(int i)875 {876 if(i && (given || dol > zero)) {877 addr1--;878 addr2--;879 }880 squeeze(0);881 newline();882 append(gettty, addr2);883 }885 void886 browse(void)887 {888 int forward, n;889 static int bformat, bnum; /* 0 */891 forward = 1;892 peekc = getchr();893 if(peekc != '\n'){894 if(peekc == '-' || peekc == '+') {895 if(peekc == '-')896 forward = 0;897 getchr();898 }899 n = getnum();900 if(n > 0)901 bpagesize = n;902 }903 newline();904 if(pflag) {905 bformat = listf;906 bnum = listn;907 } else {908 listf = bformat;909 listn = bnum;910 }911 if(forward) {912 addr1 = addr2;913 addr2 += bpagesize;914 if(addr2 > dol)915 addr2 = dol;916 } else {917 addr1 = addr2-bpagesize;918 if(addr1 <= zero)919 addr1 = zero+1;920 }921 printcom();922 }924 void925 callunix(void)926 {927 int c, pid;928 Rune rune;929 char buf[512];930 char *p;932 setnoaddr();933 p = buf;934 while((c=getchr()) != EOF && c != '\n')935 if(p < &buf[sizeof(buf) - 6]) {936 rune = c;937 p += runetochar(p, &rune);938 }939 *p = 0;940 pid = fork();941 if(pid == 0) {942 execlp("rc", "rc", "-c", buf, (char*)0);943 sysfatal("exec failed: %r");944 exits("execl failed");945 }946 waiting = 1;947 while(waitpid() != pid)948 ;949 waiting = 0;950 if(vflag)951 putst("!");952 }954 void955 quit(void)956 {957 if(vflag && fchange && dol!=zero) {958 fchange = 0;959 error(Q);960 }961 remove(tfname);962 exits(0);963 }965 void966 onquit(int sig)967 {968 USED(sig);969 quit();970 }972 void973 rdelete(int *ad1, int *ad2)974 {975 int *a1, *a2, *a3;977 a1 = ad1;978 a2 = ad2+1;979 a3 = dol;980 dol -= a2 - a1;981 do {982 *a1++ = *a2++;983 } while(a2 <= a3);984 a1 = ad1;985 if(a1 > dol)986 a1 = dol;987 dot = a1;988 fchange = 1;989 }991 void992 gdelete(void)993 {994 int *a1, *a2, *a3;996 a3 = dol;997 for(a1=zero; (*a1&01)==0; a1++)998 if(a1>=a3)999 return;1000 for(a2=a1+1; a2<=a3;) {1001 if(*a2 & 01) {1002 a2++;1003 dot = a1;1004 } else1005 *a1++ = *a2++;1006 }1007 dol = a1-1;1008 if(dot > dol)1009 dot = dol;1010 fchange = 1;1011 }1013 Rune*1014 getline(int tl)1015 {1016 Rune *lp, *bp;1017 int nl;1019 lp = linebuf;1020 bp = getblock(tl, OREAD);1021 nl = nleft;1022 tl &= ~((BLKSIZE/sizeof(Rune)) - 1);1023 while(*lp++ = *bp++) {1024 nl -= sizeof(Rune);1025 if(nl == 0) {1026 bp = getblock(tl += BLKSIZE/sizeof(Rune), OREAD);1027 nl = nleft;1028 }1029 }1030 return linebuf;1031 }1033 int1034 putline(void)1035 {1036 Rune *lp, *bp;1037 int nl, tl;1039 fchange = 1;1040 lp = linebuf;1041 tl = tline;1042 bp = getblock(tl, OWRITE);1043 nl = nleft;1044 tl &= ~((BLKSIZE/sizeof(Rune))-1);1045 while(*bp = *lp++) {1046 if(*bp++ == '\n') {1047 bp[-1] = 0;1048 linebp = lp;1049 break;1050 }1051 nl -= sizeof(Rune);1052 if(nl == 0) {1053 tl += BLKSIZE/sizeof(Rune);1054 bp = getblock(tl, OWRITE);1055 nl = nleft;1056 }1057 }1058 nl = tline;1059 tline += ((lp-linebuf) + 03) & (NBLK-1);1060 return nl;1061 }1063 void1064 blkio(int b, uchar *buf, int isread)1065 {1066 int n;1068 seek(tfile, b*BLKSIZE, 0);1069 if(isread)1070 n = read(tfile, buf, BLKSIZE);1071 else1072 n = write(tfile, buf, BLKSIZE);1073 if(n != BLKSIZE)1074 error(T);1075 }1077 Rune*1078 getblock(int atl, int iof)1079 {1080 int bno, off;1082 static uchar ibuff[BLKSIZE];1083 static uchar obuff[BLKSIZE];1085 bno = atl / (BLKSIZE/sizeof(Rune));1086 off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~03;1087 if(bno >= NBLK) {1088 lastc = '\n';1089 error(T);1090 }1091 nleft = BLKSIZE - off;1092 if(bno == iblock) {1093 ichanged |= iof;1094 return (Rune*)(ibuff+off);1095 }1096 if(bno == oblock)1097 return (Rune*)(obuff+off);1098 if(iof == OREAD) {1099 if(ichanged)1100 blkio(iblock, ibuff, 0);1101 ichanged = 0;1102 iblock = bno;1103 blkio(bno, ibuff, 1);1104 return (Rune*)(ibuff+off);1105 }1106 if(oblock >= 0)1107 blkio(oblock, obuff, 0);1108 oblock = bno;1109 return (Rune*)(obuff+off);1110 }1112 void1113 init(void)1114 {1115 int *markp;1117 close(tfile);1118 tline = 2;1119 for(markp = names; markp < &names[26]; )1120 *markp++ = 0;1121 subnewa = 0;1122 anymarks = 0;1123 iblock = -1;1124 oblock = -1;1125 ichanged = 0;1126 if((tfile = create(tfname, ORDWR, 0600)) < 0){1127 error1(T);1128 exits(0);1129 }1130 dot = dol = zero;1131 }1133 void1134 global(int k)1135 {1136 Rune *gp, globuf[GBSIZE];1137 int c, *a1;1139 if(globp)1140 error(Q);1141 setwide();1142 squeeze(dol > zero);1143 c = getchr();1144 if(c == '\n')1145 error(Q);1146 compile(c);1147 gp = globuf;1148 while((c=getchr()) != '\n') {1149 if(c == EOF)1150 error(Q);1151 if(c == '\\') {1152 c = getchr();1153 if(c != '\n')1154 *gp++ = '\\';1155 }1156 *gp++ = c;1157 if(gp >= &globuf[GBSIZE-2])1158 error(Q);1159 }1160 if(gp == globuf)1161 *gp++ = 'p';1162 *gp++ = '\n';1163 *gp = 0;1164 for(a1=zero; a1<=dol; a1++) {1165 *a1 &= ~01;1166 if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)1167 *a1 |= 01;1168 }1170 /*1171 * Special case: g/.../d (avoid n^2 algorithm)1172 */1173 if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {1174 gdelete();1175 return;1176 }1177 for(a1=zero; a1<=dol; a1++) {1178 if(*a1 & 01) {1179 *a1 &= ~01;1180 dot = a1;1181 globp = globuf;1182 commands();1183 a1 = zero;1184 }1185 }1186 }1188 void1189 join(void)1190 {1191 Rune *gp, *lp;1192 int *a1;1194 nonzero();1195 gp = genbuf;1196 for(a1=addr1; a1<=addr2; a1++) {1197 lp = getline(*a1);1198 while(*gp = *lp++)1199 if(gp++ >= &genbuf[LBSIZE-2])1200 error(Q);1201 }1202 lp = linebuf;1203 gp = genbuf;1204 while(*lp++ = *gp++)1205 ;1206 *addr1 = putline();1207 if(addr1 < addr2)1208 rdelete(addr1+1, addr2);1209 dot = addr1;1210 }1212 void1213 substitute(int inglob)1214 {1215 int *mp, *a1, nl, gsubf, n;1217 n = getnum(); /* OK even if n==0 */1218 gsubf = compsub();1219 for(a1 = addr1; a1 <= addr2; a1++) {1220 if(match(a1)){1221 int *ozero;1222 int m = n;1224 do {1225 int span = loc2-loc1;1227 if(--m <= 0) {1228 dosub();1229 if(!gsubf)1230 break;1231 if(span == 0) { /* null RE match */1232 if(*loc2 == 0)1233 break;1234 loc2++;1235 }1236 }1237 } while(match(0));1238 if(m <= 0) {1239 inglob |= 01;1240 subnewa = putline();1241 *a1 &= ~01;1242 if(anymarks) {1243 for(mp=names; mp<&names[26]; mp++)1244 if(*mp == *a1)1245 *mp = subnewa;1246 }1247 subolda = *a1;1248 *a1 = subnewa;1249 ozero = zero;1250 nl = append(getsub, a1);1251 addr2 += nl;1252 nl += zero-ozero;1253 a1 += nl;1254 }1255 }1256 }1257 if(inglob == 0)1258 error(Q);1259 }1261 int1262 compsub(void)1263 {1264 int seof, c;1265 Rune *p;1267 seof = getchr();1268 if(seof == '\n' || seof == ' ')1269 error(Q);1270 compile(seof);1271 p = rhsbuf;1272 for(;;) {1273 c = getchr();1274 if(c == '\\') {1275 c = getchr();1276 *p++ = ESCFLG;1277 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])1278 error(Q);1279 } else1280 if(c == '\n' && (!globp || !globp[0])) {1281 peekc = c;1282 pflag++;1283 break;1284 } else1285 if(c == seof)1286 break;1287 *p++ = c;1288 if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])1289 error(Q);1290 }1291 *p = 0;1292 peekc = getchr();1293 if(peekc == 'g') {1294 peekc = 0;1295 newline();1296 return 1;1297 }1298 newline();1299 return 0;1300 }1302 int1303 getsub(void)1304 {1305 Rune *p1, *p2;1307 p1 = linebuf;1308 if((p2 = linebp) == 0)1309 return EOF;1310 while(*p1++ = *p2++)1311 ;1312 linebp = 0;1313 return 0;1314 }1316 void1317 dosub(void)1318 {1319 Rune *lp, *sp, *rp;1320 int c, n;1322 lp = linebuf;1323 sp = genbuf;1324 rp = rhsbuf;1325 while(lp < loc1)1326 *sp++ = *lp++;1327 while(c = *rp++) {1328 if(c == '&'){1329 sp = place(sp, loc1, loc2);1330 continue;1331 }1332 if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {1333 n = c-'0';1334 if(subexp[n].s.rsp && subexp[n].e.rep) {1335 sp = place(sp, subexp[n].s.rsp, subexp[n].e.rep);1336 continue;1337 }1338 error(Q);1339 }1340 *sp++ = c;1341 if(sp >= &genbuf[LBSIZE])1342 error(Q);1343 }1344 lp = loc2;1345 loc2 = sp - genbuf + linebuf;1346 while(*sp++ = *lp++)1347 if(sp >= &genbuf[LBSIZE])1348 error(Q);1349 lp = linebuf;1350 sp = genbuf;1351 while(*lp++ = *sp++)1352 ;1353 }1355 Rune*1356 place(Rune *sp, Rune *l1, Rune *l2)1357 {1359 while(l1 < l2) {1360 *sp++ = *l1++;1361 if(sp >= &genbuf[LBSIZE])1362 error(Q);1363 }1364 return sp;1365 }1367 void1368 move(int cflag)1369 {1370 int *adt, *ad1, *ad2;1372 nonzero();1373 if((adt = address())==0) /* address() guarantees addr is in range */1374 error(Q);1375 newline();1376 if(cflag) {1377 int *ozero, delta;1378 ad1 = dol;1379 ozero = zero;1380 append(getcopy, ad1++);1381 ad2 = dol;1382 delta = zero - ozero;1383 ad1 += delta;1384 adt += delta;1385 } else {1386 ad2 = addr2;1387 for(ad1 = addr1; ad1 <= ad2;)1388 *ad1++ &= ~01;1389 ad1 = addr1;1390 }1391 ad2++;1392 if(adt<ad1) {1393 dot = adt + (ad2-ad1);1394 if((++adt)==ad1)1395 return;1396 reverse(adt, ad1);1397 reverse(ad1, ad2);1398 reverse(adt, ad2);1399 } else1400 if(adt >= ad2) {1401 dot = adt++;1402 reverse(ad1, ad2);1403 reverse(ad2, adt);1404 reverse(ad1, adt);1405 } else1406 error(Q);1407 fchange = 1;1408 }1410 void1411 reverse(int *a1, int *a2)1412 {1413 int t;1415 for(;;) {1416 t = *--a2;1417 if(a2 <= a1)1418 return;1419 *a2 = *a1;1420 *a1++ = t;1421 }1422 }1424 int1425 getcopy(void)1426 {1427 if(addr1 > addr2)1428 return EOF;1429 getline(*addr1++);1430 return 0;1431 }1433 void1434 compile(int eof)1435 {1436 Rune c;1437 char *ep;1438 char expbuf[ESIZE];1440 if((c = getchr()) == '\n') {1441 peekc = c;1442 c = eof;1443 }1444 if(c == eof) {1445 if(!pattern)1446 error(Q);1447 return;1448 }1449 if(pattern) {1450 free(pattern);1451 pattern = 0;1452 }1453 ep = expbuf;1454 do {1455 if(c == '\\') {1456 if(ep >= expbuf+sizeof(expbuf)) {1457 error(Q);1458 return;1459 }1460 ep += runetochar(ep, &c);1461 if((c = getchr()) == '\n') {1462 error(Q);1463 return;1464 }1465 }1466 if(ep >= expbuf+sizeof(expbuf)) {1467 error(Q);1468 return;1469 }1470 ep += runetochar(ep, &c);1471 } while((c = getchr()) != eof && c != '\n');1472 if(c == '\n')1473 peekc = c;1474 *ep = 0;1475 pattern = regcomp(expbuf);1476 }1478 int1479 match(int *addr)1480 {1481 if(!pattern)1482 return 0;1483 if(addr){1484 if(addr == zero)1485 return 0;1486 subexp[0].s.rsp = getline(*addr);1487 } else1488 subexp[0].s.rsp = loc2;1489 subexp[0].e.rep = 0;1490 if(rregexec(pattern, linebuf, subexp, MAXSUB)) {1491 loc1 = subexp[0].s.rsp;1492 loc2 = subexp[0].e.rep;1493 return 1;1494 }1495 loc1 = loc2 = 0;1496 return 0;1498 }1500 void1501 putd(void)1502 {1503 int r;1505 r = count%10;1506 count /= 10;1507 if(count)1508 putd();1509 putchr(r + '0');1510 }1512 void1513 putst(char *sp)1514 {1515 Rune r;1517 col = 0;1518 for(;;) {1519 sp += chartorune(&r, sp);1520 if(r == 0)1521 break;1522 putchr(r);1523 }1524 putchr('\n');1525 }1527 void1528 putshst(Rune *sp)1529 {1530 col = 0;1531 while(*sp)1532 putchr(*sp++);1533 putchr('\n');1534 }1536 void1537 putchr(int ac)1538 {1539 char *lp;1540 int c;1541 Rune rune;1543 lp = linp;1544 c = ac;1545 if(listf) {1546 if(c == '\n') {1547 if(linp != line && linp[-1] == ' ') {1548 *lp++ = '\\';1549 *lp++ = 'n';1550 }1551 } else {1552 if(col > (LINELEN-BELL)) {1553 col = 8;1554 *lp++ = '\\';1555 *lp++ = '\n';1556 *lp++ = '\t';1557 }1558 col++;1559 if(c=='\b' || c=='\t' || c=='\\') {1560 *lp++ = '\\';1561 if(c == '\b')1562 c = 'b';1563 else1564 if(c == '\t')1565 c = 't';1566 col++;1567 } else if (c<' ' || c=='\177') {1568 *lp++ = '\\';1569 *lp++ = 'x';1570 *lp++ = hex[(c>>4)&0xF];1571 c = hex[c&0xF];1572 col += 3;1573 } else if (c>'\177' && c<=0xFFFF) {1574 *lp++ = '\\';1575 *lp++ = 'u';1576 *lp++ = hex[(c>>12)&0xF];1577 *lp++ = hex[(c>>8)&0xF];1578 *lp++ = hex[(c>>4)&0xF];1579 c = hex[c&0xF];1580 col += 5;1581 } else if (c>0xFFFF) {1582 *lp++ = '\\';1583 *lp++ = 'U';1584 *lp++ = hex[(c>>28)&0xF];1585 *lp++ = hex[(c>>24)&0xF];1586 *lp++ = hex[(c>>20)&0xF];1587 *lp++ = hex[(c>>16)&0xF];1588 *lp++ = hex[(c>>12)&0xF];1589 *lp++ = hex[(c>>8)&0xF];1590 *lp++ = hex[(c>>4)&0xF];1591 c = hex[c&0xF];1592 col += 9;1593 }1594 }1595 }1597 rune = c;1598 lp += runetochar(lp, &rune);1600 if(c == '\n' || lp >= &line[LINELEN-BELL]) {1601 linp = line;1602 write(oflag? 2: 1, line, lp-line);1603 return;1604 }1605 linp = lp;1606 }1608 char*1609 mktemp(char *as)1610 {1611 char *s;1612 unsigned pid;1613 int i;1615 pid = getpid();1616 s = as;1617 while(*s++)1618 ;1619 s--;1620 while(*--s == 'X') {1621 *s = pid % 10 + '0';1622 pid /= 10;1623 }1624 s++;1625 i = 'a';1626 while(access(as, 0) != -1) {1627 if(i == 'z')1628 return "/";1629 *s = i++;1630 }1631 return as;1632 }1634 void1635 regerror(char *s)1636 {1637 USED(s);1638 error(Q);1639 }