Introduction
Introduction Statistics Contact Development Disclaimer Help
sam.c - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
sam.c (12567B)
---
1 #include "sam.h"
2
3 Rune genbuf[BLOCKSIZE];
4 int io;
5 int panicking;
6 int rescuing;
7 String genstr;
8 String rhs;
9 String curwd;
10 String cmdstr;
11 Rune empty[] = { 0 };
12 char *genc;
13 File *curfile;
14 File *flist;
15 File *cmd;
16 jmp_buf mainloop;
17 List tempfile = { 'p' };
18 int quitok = TRUE;
19 int downloaded;
20 int dflag;
21 int Rflag;
22 char *machine;
23 char *home;
24 int bpipeok;
25 int termlocked;
26 char *samterm = SAMTERM;
27 char *rsamname = RSAM;
28 File *lastfile;
29 Disk *disk;
30 long seq;
31
32 char *winsize;
33
34 Rune baddir[] = { '<', 'b', 'a', 'd', 'd', 'i', 'r', '>', '\n'};
35
36 void usage(void);
37
38 extern int notify(void(*)(void*,char*));
39
40 void
41 main(int _argc, char **_argv)
42 {
43 volatile int i, argc;
44 char **volatile argv;
45 String *t;
46 char *termargs[10], **ap;
47
48 argc = _argc;
49 argv = _argv;
50 ap = termargs;
51 *ap++ = "samterm";
52 ARGBEGIN{
53 case 'd':
54 dflag++;
55 break;
56 case 'r':
57 machine = EARGF(usage());
58 break;
59 case 'R':
60 Rflag++;
61 break;
62 case 't':
63 samterm = EARGF(usage());
64 break;
65 case 's':
66 rsamname = EARGF(usage());
67 break;
68 default:
69 dprint("sam: unknown flag %c\n", ARGC());
70 usage();
71 /* options for samterm */
72 case 'a':
73 *ap++ = "-a";
74 break;
75 case 'W':
76 *ap++ = "-W";
77 *ap++ = EARGF(usage());
78 break;
79 }ARGEND
80 *ap = nil;
81
82 Strinit(&cmdstr);
83 Strinit0(&lastpat);
84 Strinit0(&lastregexp);
85 Strinit0(&genstr);
86 Strinit0(&rhs);
87 Strinit0(&curwd);
88 Strinit0(&plan9cmd);
89 home = getenv(HOME);
90 disk = diskinit();
91 if(home == 0)
92 home = "/";
93 if(!dflag)
94 startup(machine, Rflag, termargs, (char**)argv);
95 notify(notifyf);
96 getcurwd();
97 if(argc>0){
98 for(i=0; i<argc; i++){
99 if(!setjmp(mainloop)){
100 t = tmpcstr(argv[i]);
101 Straddc(t, '\0');
102 Strduplstr(&genstr, t);
103 freetmpstr(t);
104 fixname(&genstr);
105 logsetname(newfile(), &genstr);
106 }
107 }
108 }else if(!downloaded)
109 newfile();
110 seq++;
111 if(file.nused)
112 current(file.filepptr[0]);
113 setjmp(mainloop);
114 cmdloop();
115 trytoquit(); /* if we already q'ed, quitok will be TRUE */
116 exits(0);
117 }
118
119 void
120 usage(void)
121 {
122 dprint("usage: sam [-d] [-t samterm] [-s sam name] [-r machine] …
123 exits("usage");
124 }
125
126 void
127 rescue(void)
128 {
129 int i, nblank = 0;
130 File *f;
131 char *c;
132 char buf[256];
133 char *root;
134
135 if(rescuing++)
136 return;
137 io = -1;
138 for(i=0; i<file.nused; i++){
139 f = file.filepptr[i];
140 if(f==cmd || f->b.nc==0 || !fileisdirty(f))
141 continue;
142 if(io == -1){
143 sprint(buf, "%s/sam.save", home);
144 io = create(buf, 1, 0777);
145 if(io<0)
146 return;
147 }
148 if(f->name.s[0]){
149 c = Strtoc(&f->name);
150 strncpy(buf, c, sizeof buf-1);
151 buf[sizeof buf-1] = 0;
152 free(c);
153 }else
154 sprint(buf, "nameless.%d", nblank++);
155 root = getenv("PLAN9");
156 if(root == nil)
157 root = "/usr/local/plan9";
158 fprint(io, "#!/bin/sh\n%s/bin/samsave '%s' $* <<'---%s'\…
159 addr.r.p1 = 0, addr.r.p2 = f->b.nc;
160 writeio(f);
161 fprint(io, "\n---%s\n", (char *)buf);
162 }
163 }
164
165 void
166 panic(char *s)
167 {
168 int wasd;
169
170 if(!panicking++ && !setjmp(mainloop)){
171 wasd = downloaded;
172 downloaded = 0;
173 dprint("sam: panic: %s: %r\n", s);
174 if(wasd)
175 fprint(2, "sam: panic: %s: %r\n", s);
176 rescue();
177 abort();
178 }
179 }
180
181 void
182 hiccough(char *s)
183 {
184 File *f;
185 int i;
186
187 if(rescuing)
188 exits("rescue");
189 if(s)
190 dprint("%s\n", s);
191 resetcmd();
192 resetxec();
193 resetsys();
194 if(io > 0)
195 close(io);
196
197 /*
198 * back out any logged changes & restore old sequences
199 */
200 for(i=0; i<file.nused; i++){
201 f = file.filepptr[i];
202 if(f==cmd)
203 continue;
204 if(f->seq==seq){
205 bufdelete(&f->epsilon, 0, f->epsilon.nc);
206 f->seq = f->prevseq;
207 f->dot.r = f->prevdot;
208 f->mark = f->prevmark;
209 state(f, f->prevmod ? Dirty: Clean);
210 }
211 }
212
213 update();
214 if (curfile) {
215 if (curfile->unread)
216 curfile->unread = FALSE;
217 else if (downloaded)
218 outTs(Hcurrent, curfile->tag);
219 }
220 longjmp(mainloop, 1);
221 }
222
223 void
224 intr(void)
225 {
226 error(Eintr);
227 }
228
229 void
230 trytoclose(File *f)
231 {
232 char *t;
233 char buf[256];
234
235 if(f == cmd) /* possible? */
236 return;
237 if(f->deleted)
238 return;
239 if(fileisdirty(f) && !f->closeok){
240 f->closeok = TRUE;
241 if(f->name.s[0]){
242 t = Strtoc(&f->name);
243 strncpy(buf, t, sizeof buf-1);
244 free(t);
245 }else
246 strcpy(buf, "nameless file");
247 error_s(Emodified, buf);
248 }
249 f->deleted = TRUE;
250 }
251
252 void
253 trytoquit(void)
254 {
255 int c;
256 File *f;
257
258 if(!quitok){
259 for(c = 0; c<file.nused; c++){
260 f = file.filepptr[c];
261 if(f!=cmd && fileisdirty(f)){
262 quitok = TRUE;
263 eof = FALSE;
264 error(Echanges);
265 }
266 }
267 }
268 }
269
270 void
271 load(File *f)
272 {
273 Address saveaddr;
274
275 Strduplstr(&genstr, &f->name);
276 filename(f);
277 if(f->name.s[0]){
278 saveaddr = addr;
279 edit(f, 'I');
280 addr = saveaddr;
281 }else{
282 f->unread = 0;
283 f->cleanseq = f->seq;
284 }
285
286 fileupdate(f, TRUE, TRUE);
287 }
288
289 void
290 cmdupdate(void)
291 {
292 if(cmd && cmd->seq!=0){
293 fileupdate(cmd, FALSE, downloaded);
294 cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc;
295 telldot(cmd);
296 }
297 }
298
299 void
300 delete(File *f)
301 {
302 if(downloaded && f->rasp)
303 outTs(Hclose, f->tag);
304 delfile(f);
305 if(f == curfile)
306 current(0);
307 }
308
309 void
310 update(void)
311 {
312 int i, anymod;
313 File *f;
314
315 settempfile();
316 for(anymod = i=0; i<tempfile.nused; i++){
317 f = tempfile.filepptr[i];
318 if(f==cmd) /* cmd gets done in main() */
319 continue;
320 if(f->deleted) {
321 delete(f);
322 continue;
323 }
324 if(f->seq==seq && fileupdate(f, FALSE, downloaded))
325 anymod++;
326 if(f->rasp)
327 telldot(f);
328 }
329 if(anymod)
330 seq++;
331 }
332
333 File *
334 current(File *f)
335 {
336 return curfile = f;
337 }
338
339 void
340 edit(File *f, int cmd)
341 {
342 int empty = TRUE;
343 Posn p;
344 int nulls;
345
346 if(cmd == 'r')
347 logdelete(f, addr.r.p1, addr.r.p2);
348 if(cmd=='e' || cmd=='I'){
349 logdelete(f, (Posn)0, f->b.nc);
350 addr.r.p2 = f->b.nc;
351 }else if(f->b.nc!=0 || (f->name.s[0] && Strcmp(&genstr, &f->name…
352 empty = FALSE;
353 if((io = open(genc, OREAD))<0) {
354 if (curfile && curfile->unread)
355 curfile->unread = FALSE;
356 error_r(Eopen, genc);
357 }
358 p = readio(f, &nulls, empty, TRUE);
359 closeio((cmd=='e' || cmd=='I')? -1 : p);
360 if(cmd == 'r')
361 f->ndot.r.p1 = addr.r.p2, f->ndot.r.p2 = addr.r.p2+p;
362 else
363 f->ndot.r.p1 = f->ndot.r.p2 = 0;
364 f->closeok = empty;
365 if (quitok)
366 quitok = empty;
367 else
368 quitok = FALSE;
369 state(f, empty && !nulls? Clean : Dirty);
370 if(empty && !nulls)
371 f->cleanseq = f->seq;
372 if(cmd == 'e')
373 filename(f);
374 }
375
376 int
377 getname(File *f, String *s, int save)
378 {
379 int c, i;
380
381 Strzero(&genstr);
382 if(genc){
383 free(genc);
384 genc = 0;
385 }
386 if(s==0 || (c = s->s[0])==0){ /* no name provided…
387 if(f)
388 Strduplstr(&genstr, &f->name);
389 goto Return;
390 }
391 if(c!=' ' && c!='\t')
392 error(Eblank);
393 for(i=0; (c=s->s[i])==' ' || c=='\t'; i++)
394 ;
395 while(s->s[i] > ' ')
396 Straddc(&genstr, s->s[i++]);
397 if(s->s[i])
398 error(Enewline);
399 fixname(&genstr);
400 if(f && (save || f->name.s[0]==0)){
401 logsetname(f, &genstr);
402 if(Strcmp(&f->name, &genstr)){
403 quitok = f->closeok = FALSE;
404 f->qidpath = 0;
405 f->mtime = 0;
406 state(f, Dirty); /* if it's 'e', fix later */
407 }
408 }
409 Return:
410 genc = Strtoc(&genstr);
411 i = genstr.n;
412 if(i && genstr.s[i-1]==0)
413 i--;
414 return i; /* strlen(name) */
415 }
416
417 void
418 filename(File *f)
419 {
420 if(genc)
421 free(genc);
422 genc = Strtoc(&genstr);
423 dprint("%c%c%c %s\n", " '"[f->mod],
424 "-+"[f->rasp!=0], " ."[f==curfile], genc);
425 }
426
427 void
428 undostep(File *f, int isundo)
429 {
430 uint p1, p2;
431 int mod;
432
433 mod = f->mod;
434 fileundo(f, isundo, 1, &p1, &p2, TRUE);
435 f->ndot = f->dot;
436 if(f->mod){
437 f->closeok = 0;
438 quitok = 0;
439 }else
440 f->closeok = 1;
441
442 if(f->mod != mod){
443 f->mod = mod;
444 if(mod)
445 mod = Clean;
446 else
447 mod = Dirty;
448 state(f, mod);
449 }
450 }
451
452 int
453 undo(int isundo)
454 {
455 File *f;
456 int i;
457 Mod max;
458
459 max = undoseq(curfile, isundo);
460 if(max == 0)
461 return 0;
462 settempfile();
463 for(i = 0; i<tempfile.nused; i++){
464 f = tempfile.filepptr[i];
465 if(f!=cmd && undoseq(f, isundo)==max)
466 undostep(f, isundo);
467 }
468 return 1;
469 }
470
471 int
472 readcmd(String *s)
473 {
474 int retcode;
475
476 if(flist != 0)
477 fileclose(flist);
478 flist = fileopen();
479
480 addr.r.p1 = 0, addr.r.p2 = flist->b.nc;
481 retcode = plan9(flist, '<', s, FALSE);
482 fileupdate(flist, FALSE, FALSE);
483 flist->seq = 0;
484 if (flist->b.nc > BLOCKSIZE)
485 error(Etoolong);
486 Strzero(&genstr);
487 Strinsure(&genstr, flist->b.nc);
488 bufread(&flist->b, (Posn)0, genbuf, flist->b.nc);
489 memmove(genstr.s, genbuf, flist->b.nc*RUNESIZE);
490 genstr.n = flist->b.nc;
491 Straddc(&genstr, '\0');
492 return retcode;
493 }
494
495 void
496 getcurwd(void)
497 {
498 String *t;
499 char buf[256];
500
501 buf[0] = 0;
502 getwd(buf, sizeof(buf));
503 t = tmpcstr(buf);
504 Strduplstr(&curwd, t);
505 freetmpstr(t);
506 if(curwd.n == 0)
507 warn(Wpwd);
508 else if(curwd.s[curwd.n-1] != '/')
509 Straddc(&curwd, '/');
510 }
511
512 void
513 cd(String *str)
514 {
515 int i, fd;
516 char *s;
517 File *f;
518 String owd;
519
520 getcurwd();
521 if(getname((File *)0, str, FALSE))
522 s = genc;
523 else
524 s = home;
525 if(chdir(s))
526 syserror("chdir");
527 fd = open("/dev/wdir", OWRITE);
528 if(fd > 0)
529 write(fd, s, strlen(s));
530 dprint("!\n");
531 Strinit(&owd);
532 Strduplstr(&owd, &curwd);
533 getcurwd();
534 settempfile();
535 /*
536 * Two passes so that if we have open
537 * /a/foo.c and /b/foo.c and cd from /b to /a,
538 * we don't ever have two foo.c simultaneously.
539 */
540 for(i=0; i<tempfile.nused; i++){
541 f = tempfile.filepptr[i];
542 if(f!=cmd && f->name.s[0]!='/' && f->name.s[0]!=0){
543 Strinsert(&f->name, &owd, (Posn)0);
544 fixname(&f->name);
545 sortname(f);
546 }
547 }
548 for(i=0; i<tempfile.nused; i++){
549 f = tempfile.filepptr[i];
550 if(f != cmd && Strispre(&curwd, &f->name)){
551 fixname(&f->name);
552 sortname(f);
553 }
554 }
555 Strclose(&owd);
556 }
557
558 int
559 loadflist(String *s)
560 {
561 int c, i;
562
563 c = s->s[0];
564 for(i = 0; s->s[i]==' ' || s->s[i]=='\t'; i++)
565 ;
566 if((c==' ' || c=='\t') && s->s[i]!='\n'){
567 if(s->s[i]=='<'){
568 Strdelete(s, 0L, (long)i+1);
569 readcmd(s);
570 }else{
571 Strzero(&genstr);
572 while((c = s->s[i++]) && c!='\n')
573 Straddc(&genstr, c);
574 Straddc(&genstr, '\0');
575 }
576 }else{
577 if(c != '\n')
578 error(Eblank);
579 Strdupl(&genstr, empty);
580 }
581 if(genc)
582 free(genc);
583 genc = Strtoc(&genstr);
584 return genstr.s[0];
585 }
586
587 File *
588 readflist(int readall, int delete)
589 {
590 Posn i;
591 int c;
592 File *f;
593 String t;
594
595 Strinit(&t);
596 for(i=0,f=0; f==0 || readall || delete; i++){ /* ++ skips…
597 Strdelete(&genstr, (Posn)0, i);
598 for(i=0; (c = genstr.s[i])==' ' || c=='\t' || c=='\n'; i…
599 ;
600 if(i >= genstr.n)
601 break;
602 Strdelete(&genstr, (Posn)0, i);
603 for(i=0; (c=genstr.s[i]) && c!=' ' && c!='\t' && c!='\n'…
604 ;
605
606 if(i == 0)
607 break;
608 genstr.s[i] = 0;
609 Strduplstr(&t, tmprstr(genstr.s, i+1));
610 fixname(&t);
611 f = lookfile(&t);
612 if(delete){
613 if(f == 0)
614 warn_S(Wfile, &t);
615 else
616 trytoclose(f);
617 }else if(f==0 && readall)
618 logsetname(f = newfile(), &t);
619 }
620 Strclose(&t);
621 return f;
622 }
623
624 File *
625 tofile(String *s)
626 {
627 File *f;
628
629 if(s->s[0] != ' ')
630 error(Eblank);
631 if(loadflist(s) == 0){
632 f = lookfile(&genstr); /* empty string ==> namele…
633 if(f == 0)
634 error_s(Emenu, genc);
635 }else if((f=readflist(FALSE, FALSE)) == 0)
636 error_s(Emenu, genc);
637 return current(f);
638 }
639
640 File *
641 getfile(String *s)
642 {
643 File *f;
644
645 if(loadflist(s) == 0)
646 logsetname(f = newfile(), &genstr);
647 else if((f=readflist(TRUE, FALSE)) == 0)
648 error(Eblank);
649 return current(f);
650 }
651
652 void
653 closefiles(File *f, String *s)
654 {
655 if(s->s[0] == 0){
656 if(f == 0)
657 error(Enofile);
658 trytoclose(f);
659 return;
660 }
661 if(s->s[0] != ' ')
662 error(Eblank);
663 if(loadflist(s) == 0)
664 error(Enewline);
665 readflist(FALSE, TRUE);
666 }
667
668 void
669 copy(File *f, Address addr2)
670 {
671 Posn p;
672 int ni;
673 for(p=addr.r.p1; p<addr.r.p2; p+=ni){
674 ni = addr.r.p2-p;
675 if(ni > BLOCKSIZE)
676 ni = BLOCKSIZE;
677 bufread(&f->b, p, genbuf, ni);
678 loginsert(addr2.f, addr2.r.p2, tmprstr(genbuf, ni)->s, n…
679 }
680 addr2.f->ndot.r.p2 = addr2.r.p2+(f->dot.r.p2-f->dot.r.p1);
681 addr2.f->ndot.r.p1 = addr2.r.p2;
682 }
683
684 void
685 move(File *f, Address addr2)
686 {
687 if(addr.r.p2 <= addr2.r.p2){
688 logdelete(f, addr.r.p1, addr.r.p2);
689 copy(f, addr2);
690 }else if(addr.r.p1 >= addr2.r.p2){
691 copy(f, addr2);
692 logdelete(f, addr.r.p1, addr.r.p2);
693 }else
694 error(Eoverlap);
695 }
696
697 Posn
698 nlcount(File *f, Posn p0, Posn p1)
699 {
700 Posn nl = 0;
701
702 while(p0 < p1)
703 if(filereadc(f, p0++)=='\n')
704 nl++;
705 return nl;
706 }
707
708 void
709 printposn(File *f, int charsonly)
710 {
711 Posn l1, l2;
712
713 if(!charsonly){
714 l1 = 1+nlcount(f, (Posn)0, addr.r.p1);
715 l2 = l1+nlcount(f, addr.r.p1, addr.r.p2);
716 /* check if addr ends with '\n' */
717 if(addr.r.p2>0 && addr.r.p2>addr.r.p1 && filereadc(f, ad…
718 --l2;
719 dprint("%lud", l1);
720 if(l2 != l1)
721 dprint(",%lud", l2);
722 dprint("; ");
723 }
724 dprint("#%lud", addr.r.p1);
725 if(addr.r.p2 != addr.r.p1)
726 dprint(",#%lud", addr.r.p2);
727 dprint("\n");
728 }
729
730 void
731 settempfile(void)
732 {
733 if(tempfile.nalloc < file.nused){
734 if(tempfile.filepptr)
735 free(tempfile.filepptr);
736 tempfile.filepptr = emalloc(sizeof(File*)*file.nused);
737 tempfile.nalloc = file.nused;
738 }
739 memmove(tempfile.filepptr, file.filepptr, sizeof(File*)*file.nus…
740 tempfile.nused = file.nused;
741 }
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.