address.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) 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 }