skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

string_unquote_withdelim.c (2303B)


      1 /* ISC license. */
      2 
      3 #include <errno.h>
      4 
      5 #include <skalibs/bytestr.h>
      6 #include <skalibs/fmtscan.h>
      7 #include <skalibs/skamisc.h>
      8 #include <skalibs/posixishard.h>
      9 
     10 #define PUSH0 0x40
     11 #define PUSH  0x20
     12 #define PUSHSPEC 0x10
     13 #define STORE 0x08
     14 #define CALC 0x04
     15 #define SYNTAXERROR 0x02
     16 #define BROKENPIPE 0x01
     17 
     18 int string_unquote_withdelim (char *d, size_t *w, char const *s, size_t len, size_t *r, char const *delim, size_t delimlen)
     19 {
     20   static unsigned char const actions[5][9] =
     21   {
     22     { 0, 0, PUSH, PUSH, PUSH, PUSH, PUSH, PUSH, 0 },
     23     { PUSH, PUSH, 0, PUSH, PUSHSPEC, PUSH, PUSHSPEC, PUSH, BROKENPIPE },
     24     { PUSH0, PUSH0, PUSH0|PUSH, 0, PUSH0|PUSH, PUSH0|PUSH, PUSH0|PUSH, PUSH0|PUSH, PUSH0 },
     25     { SYNTAXERROR, SYNTAXERROR, STORE, SYNTAXERROR, STORE, STORE, SYNTAXERROR, SYNTAXERROR, BROKENPIPE },
     26     { SYNTAXERROR, SYNTAXERROR, CALC, SYNTAXERROR, CALC, CALC, SYNTAXERROR, SYNTAXERROR, BROKENPIPE }
     27   } ;
     28   static unsigned char const states[5][9] =
     29   {
     30     { 1, 5, 0, 0, 0, 0, 0, 0, 5 },
     31     { 0, 0, 2, 0, 0, 0, 0, 0, 6 },
     32     { 1, 5, 0, 3, 0, 0, 0, 0, 5 },
     33     { 6, 6, 4, 6, 4, 4, 6, 6, 6 },
     34     { 6, 6, 0, 6, 0, 0, 6, 6, 6 }
     35   } ;
     36   unsigned char class[256] = "7777777777777777777777777777777777777777777777772555555555777777777777777777777777777777777707777445554777777767776667673777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777" ;
     37   size_t i = 0 ;
     38   unsigned char store = 0 ;
     39   unsigned char state = 0 ;
     40   for (; i < delimlen ; i++)
     41     if (class[(unsigned char)delim[i]] == '7')
     42       class[(unsigned char)delim[i]] = '1' ;
     43     else return (errno = EINVAL, 0) ;
     44   *w = 0 ;
     45 
     46   for (i = 0 ; state < 5 ; i++)
     47   {
     48     unsigned char c = i < len ? class[(unsigned char)s[i]] - '0' : 8 ;
     49     unsigned char action = actions[state][c] ;
     50     state = states[state][c] ;
     51     if (action & PUSH0) d[(*w)++] = 0 ;
     52     if (action & PUSH) d[(*w)++] = s[i] ;
     53     if (action & PUSHSPEC) d[(*w)++] = s[i] == 's' ? ' ' : 7 + byte_chr("abtnvfr", 7, s[i]) ;
     54     if (action & STORE) store = fmtscan_num(s[i], 16) << 4 ;
     55     if (action & CALC) d[(*w)++] = store | fmtscan_num(s[i], 16) ;
     56     if (action & SYNTAXERROR) errno = EPROTO ;
     57     if (action & BROKENPIPE) errno = EPIPE ;
     58   }
     59   *r = i - 1 ;
     60   return (state == 5) ;
     61 }