9base

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

address.c (4011B)


      1 #include "sam.h"
      2 #include "parse.h"
      3 
      4 Address	addr;
      5 String	lastpat;
      6 int	patset;
      7 File	*menu;
      8 
      9 File	*matchfile(String*);
     10 Address	charaddr(Posn, Address, int);
     11 
     12 Address
     13 address(Addr *ap, Address a, int sign)
     14 {
     15 	File *f = a.f;
     16 	Address a1, a2;
     17 
     18 	do{
     19 		switch(ap->type){
     20 		case 'l':
     21 		case '#':
     22 			a = (*(ap->type=='#'?charaddr:lineaddr))(ap->num, a, sign);
     23 			break;
     24 
     25 		case '.':
     26 			a = f->dot;
     27 			break;
     28 
     29 		case '$':
     30 			a.r.p1 = a.r.p2 = f->b.nc;
     31 			break;
     32 
     33 		case '\'':
     34 			a.r = f->mark;
     35 			break;
     36 
     37 		case '?':
     38 			sign = -sign;
     39 			if(sign == 0)
     40 				sign = -1;
     41 			/* fall through */
     42 		case '/':
     43 			nextmatch(f, ap->are, sign>=0? a.r.p2 : a.r.p1, sign);
     44 			a.r = sel.p[0];
     45 			break;
     46 
     47 		case '"':
     48 			a = matchfile(ap->are)->dot;
     49 			f = a.f;
     50 			if(f->unread)
     51 				load(f);
     52 			break;
     53 
     54 		case '*':
     55 			a.r.p1 = 0, a.r.p2 = f->b.nc;
     56 			return a;
     57 
     58 		case ',':
     59 		case ';':
     60 			if(ap->left)
     61 				a1 = address(ap->left, a, 0);
     62 			else
     63 				a1.f = a.f, a1.r.p1 = a1.r.p2 = 0;
     64 			if(ap->type == ';'){
     65 				f = a1.f;
     66 				a = a1;
     67 				f->dot = a1;
     68 			}
     69 			if(ap->next)
     70 				a2 = address(ap->next, a, 0);
     71 			else
     72 				a2.f = a.f, a2.r.p1 = a2.r.p2 = f->b.nc;
     73 			if(a1.f != a2.f)
     74 				error(Eorder);
     75 			a.f = a1.f, a.r.p1 = a1.r.p1, a.r.p2 = a2.r.p2;
     76 			if(a.r.p2 < a.r.p1)
     77 				error(Eorder);
     78 			return a;
     79 
     80 		case '+':
     81 		case '-':
     82 			sign = 1;
     83 			if(ap->type == '-')
     84 				sign = -1;
     85 			if(ap->next==0 || ap->next->type=='+' || ap->next->type=='-')
     86 				a = lineaddr(1L, a, sign);
     87 			break;
     88 		default:
     89 			panic("address");
     90 			return a;
     91 		}
     92 	}while(ap = ap->next);	/* assign = */
     93 	return a;
     94 }
     95 
     96 void
     97 nextmatch(File *f, String *r, Posn p, int sign)
     98 {
     99 	compile(r);
    100 	if(sign >= 0){
    101 		if(!execute(f, p, INFINITY))
    102 			error(Esearch);
    103 		if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p1==p){
    104 			if(++p>f->b.nc)
    105 				p = 0;
    106 			if(!execute(f, p, INFINITY))
    107 				panic("address");
    108 		}
    109 	}else{
    110 		if(!bexecute(f, p))
    111 			error(Esearch);
    112 		if(sel.p[0].p1==sel.p[0].p2 && sel.p[0].p2==p){
    113 			if(--p<0)
    114 				p = f->b.nc;
    115 			if(!bexecute(f, p))
    116 				panic("address");
    117 		}
    118 	}
    119 }
    120 
    121 File *
    122 matchfile(String *r)
    123 {
    124 	File *f;
    125 	File *match = 0;
    126 	int i;
    127 
    128 	for(i = 0; i<file.nused; i++){
    129 		f = file.filepptr[i];
    130 		if(f == cmd)
    131 			continue;
    132 		if(filematch(f, r)){
    133 			if(match)
    134 				error(Emanyfiles);
    135 			match = f;
    136 		}
    137 	}
    138 	if(!match)
    139 		error(Efsearch);
    140 	return match;
    141 }
    142 
    143 int
    144 filematch(File *f, String *r)
    145 {
    146 	char *c, buf[STRSIZE+100];
    147 	String *t;
    148 
    149 	c = Strtoc(&f->name);
    150 	sprint(buf, "%c%c%c %s\n", " '"[f->mod],
    151 		"-+"[f->rasp!=0], " ."[f==curfile], c);
    152 	free(c);
    153 	t = tmpcstr(buf);
    154 	Strduplstr(&genstr, t);
    155 	freetmpstr(t);
    156 	/* A little dirty... */
    157 	if(menu == 0)
    158 		menu = fileopen();
    159 	bufreset(&menu->b);
    160 	bufinsert(&menu->b, 0, genstr.s, genstr.n);
    161 	compile(r);
    162 	return execute(menu, 0, menu->b.nc);
    163 }
    164 
    165 Address
    166 charaddr(Posn l, Address addr, int sign)
    167 {
    168 	if(sign == 0)
    169 		addr.r.p1 = addr.r.p2 = l;
    170 	else if(sign < 0)
    171 		addr.r.p2 = addr.r.p1-=l;
    172 	else if(sign > 0)
    173 		addr.r.p1 = addr.r.p2+=l;
    174 	if(addr.r.p1<0 || addr.r.p2>addr.f->b.nc)
    175 		error(Erange);
    176 	return addr;
    177 }
    178 
    179 Address
    180 lineaddr(Posn l, Address addr, int sign)
    181 {
    182 	int n;
    183 	int c;
    184 	File *f = addr.f;
    185 	Address a;
    186 	Posn p;
    187 
    188 	a.f = f;
    189 	if(sign >= 0){
    190 		if(l == 0){
    191 			if(sign==0 || addr.r.p2==0){
    192 				a.r.p1 = a.r.p2 = 0;
    193 				return a;
    194 			}
    195 			a.r.p1 = addr.r.p2;
    196 			p = addr.r.p2-1;
    197 		}else{
    198 			if(sign==0 || addr.r.p2==0){
    199 				p = (Posn)0;
    200 				n = 1;
    201 			}else{
    202 				p = addr.r.p2-1;
    203 				n = filereadc(f, p++)=='\n';
    204 			}
    205 			while(n < l){
    206 				if(p >= f->b.nc)
    207 					error(Erange);
    208 				if(filereadc(f, p++) == '\n')
    209 					n++;
    210 			}
    211 			a.r.p1 = p;
    212 		}
    213 		while(p < f->b.nc && filereadc(f, p++)!='\n')
    214 			;
    215 		a.r.p2 = p;
    216 	}else{
    217 		p = addr.r.p1;
    218 		if(l == 0)
    219 			a.r.p2 = addr.r.p1;
    220 		else{
    221 			for(n = 0; n<l; ){	/* always runs once */
    222 				if(p == 0){
    223 					if(++n != l)
    224 						error(Erange);
    225 				}else{
    226 					c = filereadc(f, p-1);
    227 					if(c != '\n' || ++n != l)
    228 						p--;
    229 				}
    230 			}
    231 			a.r.p2 = p;
    232 			if(p > 0)
    233 				p--;
    234 		}
    235 		while(p > 0 && filereadc(f, p-1)!='\n')	/* lines start after a newline */
    236 			p--;
    237 		a.r.p1 = p;
    238 	}
    239 	return a;
    240 }