9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

xec.c (8529B)


      1 #include "sam.h"
      2 #include "parse.h"
      3 
      4 int	Glooping;
      5 int	nest;
      6 
      7 int	append(File*, Cmd*, Posn);
      8 int	display(File*);
      9 void	looper(File*, Cmd*, int);
     10 void	filelooper(Cmd*, int);
     11 void	linelooper(File*, Cmd*);
     12 
     13 void
     14 resetxec(void)
     15 {
     16 	Glooping = nest = 0;
     17 }
     18 
     19 int
     20 cmdexec(File *f, Cmd *cp)
     21 {
     22 	int i;
     23 	Addr *ap;
     24 	Address a;
     25 
     26 	if(f && f->unread)
     27 		load(f);
     28 	if(f==0 && (cp->addr==0 || cp->addr->type!='"') &&
     29 	    !utfrune("bBnqUXY!", cp->cmdc) &&
     30 	    cp->cmdc!=('c'|0x100) && !(cp->cmdc=='D' && cp->ctext))
     31 		error(Enofile);
     32 	i = lookup(cp->cmdc);
     33 	if(i >= 0 && cmdtab[i].defaddr != aNo){
     34 		if((ap=cp->addr)==0 && cp->cmdc!='\n'){
     35 			cp->addr = ap = newaddr();
     36 			ap->type = '.';
     37 			if(cmdtab[i].defaddr == aAll)
     38 				ap->type = '*';
     39 		}else if(ap && ap->type=='"' && ap->next==0 && cp->cmdc!='\n'){
     40 			ap->next = newaddr();
     41 			ap->next->type = '.';
     42 			if(cmdtab[i].defaddr == aAll)
     43 				ap->next->type = '*';
     44 		}
     45 		if(cp->addr){	/* may be false for '\n' (only) */
     46 			static Address none = {0,0,0};
     47 			if(f)
     48 				addr = address(ap, f->dot, 0);
     49 			else	/* a " */
     50 				addr = address(ap, none, 0);
     51 			f = addr.f;
     52 		}
     53 	}
     54 	current(f);
     55 	switch(cp->cmdc){
     56 	case '{':
     57 		a = cp->addr? address(cp->addr, f->dot, 0): f->dot;
     58 		for(cp = cp->ccmd; cp; cp = cp->next){
     59 			a.f->dot = a;
     60 			cmdexec(a.f, cp);
     61 		}
     62 		break;
     63 	default:
     64 		i=(*cmdtab[i].fn)(f, cp);
     65 		return i;
     66 	}
     67 	return 1;
     68 }
     69 
     70 
     71 int
     72 a_cmd(File *f, Cmd *cp)
     73 {
     74 	return append(f, cp, addr.r.p2);
     75 }
     76 
     77 int
     78 b_cmd(File *f, Cmd *cp)
     79 {
     80 	USED(f);
     81 	f = cp->cmdc=='b'? tofile(cp->ctext) : getfile(cp->ctext);
     82 	if(f->unread)
     83 		load(f);
     84 	else if(nest == 0)
     85 		filename(f);
     86 	return TRUE;
     87 }
     88 
     89 int
     90 c_cmd(File *f, Cmd *cp)
     91 {
     92 	logdelete(f, addr.r.p1, addr.r.p2);
     93 	f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p2;
     94 	return append(f, cp, addr.r.p2);
     95 }
     96 
     97 int
     98 d_cmd(File *f, Cmd *cp)
     99 {
    100 	USED(cp);
    101 	logdelete(f, addr.r.p1, addr.r.p2);
    102 	f->ndot.r.p1 = f->ndot.r.p2 = addr.r.p1;
    103 	return TRUE;
    104 }
    105 
    106 int
    107 D_cmd(File *f, Cmd *cp)
    108 {
    109 	closefiles(f, cp->ctext);
    110 	return TRUE;
    111 }
    112 
    113 int
    114 e_cmd(File *f, Cmd *cp)
    115 {
    116 	if(getname(f, cp->ctext, cp->cmdc=='e')==0)
    117 		error(Enoname);
    118 	edit(f, cp->cmdc);
    119 	return TRUE;
    120 }
    121 
    122 int
    123 f_cmd(File *f, Cmd *cp)
    124 {
    125 	getname(f, cp->ctext, TRUE);
    126 	filename(f);
    127 	return TRUE;
    128 }
    129 
    130 int
    131 g_cmd(File *f, Cmd *cp)
    132 {
    133 	if(f!=addr.f)panic("g_cmd f!=addr.f");
    134 	compile(cp->re);
    135 	if(execute(f, addr.r.p1, addr.r.p2) ^ cp->cmdc=='v'){
    136 		f->dot = addr;
    137 		return cmdexec(f, cp->ccmd);
    138 	}
    139 	return TRUE;
    140 }
    141 
    142 int
    143 i_cmd(File *f, Cmd *cp)
    144 {
    145 	return append(f, cp, addr.r.p1);
    146 }
    147 
    148 int
    149 k_cmd(File *f, Cmd *cp)
    150 {
    151 	USED(cp);
    152 	f->mark = addr.r;
    153 	return TRUE;
    154 }
    155 
    156 int
    157 m_cmd(File *f, Cmd *cp)
    158 {
    159 	Address addr2;
    160 
    161 	addr2 = address(cp->caddr, f->dot, 0);
    162 	if(cp->cmdc=='m')
    163 		move(f, addr2);
    164 	else
    165 		copy(f, addr2);
    166 	return TRUE;
    167 }
    168 
    169 int
    170 n_cmd(File *f, Cmd *cp)
    171 {
    172 	int i;
    173 	USED(f);
    174 	USED(cp);
    175 	for(i = 0; i<file.nused; i++){
    176 		if(file.filepptr[i] == cmd)
    177 			continue;
    178 		f = file.filepptr[i];
    179 		Strduplstr(&genstr, &f->name);
    180 		filename(f);
    181 	}
    182 	return TRUE;
    183 }
    184 
    185 int
    186 p_cmd(File *f, Cmd *cp)
    187 {
    188 	USED(cp);
    189 	return display(f);
    190 }
    191 
    192 int
    193 q_cmd(File *f, Cmd *cp)
    194 {
    195 	USED(cp);
    196 	USED(f);
    197 	trytoquit();
    198 	if(downloaded){
    199 		outT0(Hexit);
    200 		return TRUE;
    201 	}
    202 	return FALSE;
    203 }
    204 
    205 int
    206 s_cmd(File *f, Cmd *cp)
    207 {
    208 	int i, j, c, n;
    209 	Posn p1, op, didsub = 0, delta = 0;
    210 
    211 	n = cp->num;
    212 	op= -1;
    213 	compile(cp->re);
    214 	for(p1 = addr.r.p1; p1<=addr.r.p2 && execute(f, p1, addr.r.p2); ){
    215 		if(sel.p[0].p1==sel.p[0].p2){	/* empty match? */
    216 			if(sel.p[0].p1==op){
    217 				p1++;
    218 				continue;
    219 			}
    220 			p1 = sel.p[0].p2+1;
    221 		}else
    222 			p1 = sel.p[0].p2;
    223 		op = sel.p[0].p2;
    224 		if(--n>0)
    225 			continue;
    226 		Strzero(&genstr);
    227 		for(i = 0; i<cp->ctext->n; i++)
    228 			if((c = cp->ctext->s[i])=='\\' && i<cp->ctext->n-1){
    229 				c = cp->ctext->s[++i];
    230 				if('1'<=c && c<='9') {
    231 					j = c-'0';
    232 					if(sel.p[j].p2-sel.p[j].p1>BLOCKSIZE)
    233 						error(Elongtag);
    234 					bufread(&f->b, sel.p[j].p1, genbuf, sel.p[j].p2-sel.p[j].p1);
    235 					Strinsert(&genstr, tmprstr(genbuf, (sel.p[j].p2-sel.p[j].p1)), genstr.n);
    236 				}else
    237 				 	Straddc(&genstr, c);
    238 			}else if(c!='&')
    239 				Straddc(&genstr, c);
    240 			else{
    241 				if(sel.p[0].p2-sel.p[0].p1>BLOCKSIZE)
    242 					error(Elongrhs);
    243 				bufread(&f->b, sel.p[0].p1, genbuf, sel.p[0].p2-sel.p[0].p1);
    244 				Strinsert(&genstr,
    245 					tmprstr(genbuf, (int)(sel.p[0].p2-sel.p[0].p1)),
    246 					genstr.n);
    247 			}
    248 		if(sel.p[0].p1!=sel.p[0].p2){
    249 			logdelete(f, sel.p[0].p1, sel.p[0].p2);
    250 			delta-=sel.p[0].p2-sel.p[0].p1;
    251 		}
    252 		if(genstr.n){
    253 			loginsert(f, sel.p[0].p2, genstr.s, genstr.n);
    254 			delta+=genstr.n;
    255 		}
    256 		didsub = 1;
    257 		if(!cp->flag)
    258 			break;
    259 	}
    260 	if(!didsub && nest==0)
    261 		error(Enosub);
    262 	f->ndot.r.p1 = addr.r.p1, f->ndot.r.p2 = addr.r.p2+delta;
    263 	return TRUE;
    264 }
    265 
    266 int
    267 u_cmd(File *f, Cmd *cp)
    268 {
    269 	int n;
    270 
    271 	USED(f);
    272 	USED(cp);
    273 	n = cp->num;
    274 	if(n >= 0)
    275 		while(n-- && undo(TRUE))
    276 			;
    277 	else
    278 		while(n++ && undo(FALSE))
    279 			;
    280 	return TRUE;
    281 }
    282 
    283 int
    284 w_cmd(File *f, Cmd *cp)
    285 {
    286 	int fseq;
    287 
    288 	fseq = f->seq;
    289 	if(getname(f, cp->ctext, FALSE)==0)
    290 		error(Enoname);
    291 	if(fseq == seq)
    292 		error_s(Ewseq, genc);
    293 	writef(f);
    294 	return TRUE;
    295 }
    296 
    297 int
    298 x_cmd(File *f, Cmd *cp)
    299 {
    300 	if(cp->re)
    301 		looper(f, cp, cp->cmdc=='x');
    302 	else
    303 		linelooper(f, cp);
    304 	return TRUE;
    305 }
    306 
    307 int
    308 X_cmd(File *f, Cmd *cp)
    309 {
    310 	USED(f);
    311 	filelooper(cp, cp->cmdc=='X');
    312 	return TRUE;
    313 }
    314 
    315 int
    316 plan9_cmd(File *f, Cmd *cp)
    317 {
    318 	plan9(f, cp->cmdc, cp->ctext, nest);
    319 	return TRUE;
    320 }
    321 
    322 int
    323 eq_cmd(File *f, Cmd *cp)
    324 {
    325 	int charsonly;
    326 
    327 	switch(cp->ctext->n){
    328 	case 1:
    329 		charsonly = FALSE;
    330 		break;
    331 	case 2:
    332 		if(cp->ctext->s[0]=='#'){
    333 			charsonly = TRUE;
    334 			break;
    335 		}
    336 	default:
    337 		SET(charsonly);
    338 		error(Enewline);
    339 	}
    340 	printposn(f, charsonly);
    341 	return TRUE;
    342 }
    343 
    344 int
    345 nl_cmd(File *f, Cmd *cp)
    346 {
    347 	Address a;
    348 
    349 	if(cp->addr == 0){
    350 		/* First put it on newline boundaries */
    351 		addr = lineaddr((Posn)0, f->dot, -1);
    352 		a = lineaddr((Posn)0, f->dot, 1);
    353 		addr.r.p2 = a.r.p2;
    354 		if(addr.r.p1==f->dot.r.p1 && addr.r.p2==f->dot.r.p2)
    355 			addr = lineaddr((Posn)1, f->dot, 1);
    356 		display(f);
    357 	}else if(downloaded)
    358 		moveto(f, addr.r);
    359 	else
    360 		display(f);
    361 	return TRUE;
    362 }
    363 
    364 int
    365 cd_cmd(File *f, Cmd *cp)
    366 {
    367 	USED(f);
    368 	cd(cp->ctext);
    369 	return TRUE;
    370 }
    371 
    372 int
    373 append(File *f, Cmd *cp, Posn p)
    374 {
    375 	if(cp->ctext->n>0 && cp->ctext->s[cp->ctext->n-1]==0)
    376 		--cp->ctext->n;
    377 	if(cp->ctext->n>0)
    378 		loginsert(f, p, cp->ctext->s, cp->ctext->n);
    379 	f->ndot.r.p1 = p;
    380 	f->ndot.r.p2 = p+cp->ctext->n;
    381 	return TRUE;
    382 }
    383 
    384 int
    385 display(File *f)
    386 {
    387 	Posn p1, p2;
    388 	int np;
    389 	char *c;
    390 
    391 	p1 = addr.r.p1;
    392 	p2 = addr.r.p2;
    393 	if(p2 > f->b.nc){
    394 		fprint(2, "bad display addr p1=%ld p2=%ld f->b.nc=%d\n", p1, p2, f->b.nc); /*ZZZ should never happen, can remove */
    395 		p2 = f->b.nc;
    396 	}
    397 	while(p1 < p2){
    398 		np = p2-p1;
    399 		if(np>BLOCKSIZE-1)
    400 			np = BLOCKSIZE-1;
    401 		bufread(&f->b, p1, genbuf, np);
    402 		genbuf[np] = 0;
    403 		c = Strtoc(tmprstr(genbuf, np+1));
    404 		if(downloaded)
    405 			termwrite(c);
    406 		else
    407 			Write(1, c, strlen(c));
    408 		free(c);
    409 		p1 += np;
    410 	}
    411 	f->dot = addr;
    412 	return TRUE;
    413 }
    414 
    415 void
    416 looper(File *f, Cmd *cp, int xy)
    417 {
    418 	Posn p, op;
    419 	Range r;
    420 
    421 	r = addr.r;
    422 	op= xy? -1 : r.p1;
    423 	nest++;
    424 	compile(cp->re);
    425 	for(p = r.p1; p<=r.p2; ){
    426 		if(!execute(f, p, r.p2)){ /* no match, but y should still run */
    427 			if(xy || op>r.p2)
    428 				break;
    429 			f->dot.r.p1 = op, f->dot.r.p2 = r.p2;
    430 			p = r.p2+1;	/* exit next loop */
    431 		}else{
    432 			if(sel.p[0].p1==sel.p[0].p2){	/* empty match? */
    433 				if(sel.p[0].p1==op){
    434 					p++;
    435 					continue;
    436 				}
    437 				p = sel.p[0].p2+1;
    438 			}else
    439 				p = sel.p[0].p2;
    440 			if(xy)
    441 				f->dot.r = sel.p[0];
    442 			else
    443 				f->dot.r.p1 = op, f->dot.r.p2 = sel.p[0].p1;
    444 		}
    445 		op = sel.p[0].p2;
    446 		cmdexec(f, cp->ccmd);
    447 		compile(cp->re);
    448 	}
    449 	--nest;
    450 }
    451 
    452 void
    453 linelooper(File *f, Cmd *cp)
    454 {
    455 	Posn p;
    456 	Range r, linesel;
    457 	Address a, a3;
    458 
    459 	nest++;
    460 	r = addr.r;
    461 	a3.f = f;
    462 	a3.r.p1 = a3.r.p2 = r.p1;
    463 	for(p = r.p1; p<r.p2; p = a3.r.p2){
    464 		a3.r.p1 = a3.r.p2;
    465 /*pjw		if(p!=r.p1 || (linesel = lineaddr((Posn)0, a3, 1)).r.p2==p)*/
    466 		if(p!=r.p1 || (a = lineaddr((Posn)0, a3, 1), linesel = a.r, linesel.p2==p)){
    467 			a = lineaddr((Posn)1, a3, 1);
    468 			linesel = a.r;
    469 		}
    470 		if(linesel.p1 >= r.p2)
    471 			break;
    472 		if(linesel.p2 >= r.p2)
    473 			linesel.p2 = r.p2;
    474 		if(linesel.p2 > linesel.p1)
    475 			if(linesel.p1>=a3.r.p2 && linesel.p2>a3.r.p2){
    476 				f->dot.r = linesel;
    477 				cmdexec(f, cp->ccmd);
    478 				a3.r = linesel;
    479 				continue;
    480 			}
    481 		break;
    482 	}
    483 	--nest;
    484 }
    485 
    486 void
    487 filelooper(Cmd *cp, int XY)
    488 {
    489 	File *f, *cur;
    490 	int i;
    491 
    492 	if(Glooping++)
    493 		error(EnestXY);
    494 	nest++;
    495 	settempfile();
    496 	cur = curfile;
    497 	for(i = 0; i<tempfile.nused; i++){
    498 		f = tempfile.filepptr[i];
    499 		if(f==cmd)
    500 			continue;
    501 		if(cp->re==0 || filematch(f, cp->re)==XY)
    502 			cmdexec(f, cp->ccmd);
    503 	}
    504 	if(cur && whichmenu(cur)>=0)	/* check that cur is still a file */
    505 		current(cur);
    506 	--Glooping;
    507 	--nest;
    508 }