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