parse.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       parse.c (2010B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 /*
            9  * Generous estimate of number of fields, including terminal nil pointer
           10  */
           11 static int
           12 ncmdfield(char *p, int n)
           13 {
           14         int white, nwhite;
           15         char *ep;
           16         int nf;
           17 
           18         if(p == nil)
           19                 return 1;
           20 
           21         nf = 0;
           22         ep = p+n;
           23         white = 1;        /* first text will start field */
           24         while(p < ep){
           25                 nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0);        /* UTF is irrelevant */
           26                 if(white && !nwhite)        /* beginning of field */
           27                         nf++;
           28                 white = nwhite;
           29         }
           30         return nf+1;        /* +1 for nil */
           31 }
           32 
           33 /*
           34  *  parse a command written to a device
           35  */
           36 Cmdbuf*
           37 parsecmd(char *p, int n)
           38 {
           39         Cmdbuf *volatile cb;
           40         int nf;
           41         char *sp;
           42 
           43         nf = ncmdfield(p, n);
           44 
           45         /* allocate Cmdbuf plus string pointers plus copy of string including \0 */
           46         sp = smalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
           47         cb = (Cmdbuf*)sp;
           48         cb->f = (char**)(&cb[1]);
           49         cb->buf = (char*)(&cb->f[nf]);
           50 
           51         if(up!=nil && waserror()){
           52                 free(cb);
           53                 nexterror();
           54         }
           55         memmove(cb->buf, p, n);
           56         if(up != nil)
           57                 poperror();
           58 
           59         /* dump new line and null terminate */
           60         if(n > 0 && cb->buf[n-1] == '\n')
           61                 n--;
           62         cb->buf[n] = '\0';
           63 
           64         cb->nf = tokenize(cb->buf, cb->f, nf-1);
           65         cb->f[cb->nf] = nil;
           66 
           67         return cb;
           68 }
           69 
           70 /*
           71  * Reconstruct original message, for error diagnostic
           72  */
           73 void
           74 cmderror(Cmdbuf *cb, char *s)
           75 {
           76         int i;
           77         char *p, *e;
           78 
           79         p = up->genbuf;
           80         e = p+ERRMAX-10;
           81         p = seprint(p, e, "%s \"", s);
           82         for(i=0; i<cb->nf; i++){
           83                 if(i > 0)
           84                         p = seprint(p, e, " ");
           85                 p = seprint(p, e, "%q", cb->f[i]);
           86         }
           87         strcpy(p, "\"");
           88         error(up->genbuf);
           89 }
           90 
           91 /*
           92  * Look up entry in table
           93  */
           94 Cmdtab*
           95 lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
           96 {
           97         int i;
           98         Cmdtab *ct;
           99 
          100         if(cb->nf == 0)
          101                 error("empty control message");
          102 
          103         for(ct = ctab, i=0; i<nctab; i++, ct++){
          104                 if(strcmp(ct->cmd, "*") !=0)        /* wildcard always matches */
          105                 if(strcmp(ct->cmd, cb->f[0]) != 0)
          106                         continue;
          107                 if(ct->narg != 0 && ct->narg != cb->nf)
          108                         cmderror(cb, Ecmdargs);
          109                 return ct;
          110         }
          111 
          112         cmderror(cb, "unknown control message");
          113         return nil;
          114 }