about summary refs log tree commit diff
path: root/src/libstddjb/string_unquote_withdelim.c
blob: 43da0db5c8254a7acf970c28885bc0779c67b9b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* ISC license. */

#include <errno.h>

#include <skalibs/bytestr.h>
#include <skalibs/fmtscan.h>
#include <skalibs/skamisc.h>
#include <skalibs/posixishard.h>

#define PUSH0 0x40
#define PUSH  0x20
#define PUSHSPEC 0x10
#define STORE 0x08
#define CALC 0x04
#define SYNTAXERROR 0x02
#define BROKENPIPE 0x01

int string_unquote_withdelim (char *d, size_t *w, char const *s, size_t len, size_t *r, char const *delim, size_t delimlen)
{
  static unsigned char const actions[5][9] =
  {
    { 0, 0, PUSH, PUSH, PUSH, PUSH, PUSH, PUSH, 0 },
    { PUSH, PUSH, 0, PUSH, PUSHSPEC, PUSH, PUSHSPEC, PUSH, BROKENPIPE },
    { PUSH0, PUSH0, PUSH0|PUSH, 0, PUSH0|PUSH, PUSH0|PUSH, PUSH0|PUSH, PUSH0|PUSH, PUSH0 },
    { SYNTAXERROR, SYNTAXERROR, STORE, SYNTAXERROR, STORE, STORE, SYNTAXERROR, SYNTAXERROR, BROKENPIPE },
    { SYNTAXERROR, SYNTAXERROR, CALC, SYNTAXERROR, CALC, CALC, SYNTAXERROR, SYNTAXERROR, BROKENPIPE }
  } ;
  static unsigned char const states[5][9] =
  {
    { 1, 5, 0, 0, 0, 0, 0, 0, 5 },
    { 0, 0, 2, 0, 0, 0, 0, 0, 6 },
    { 1, 5, 0, 3, 0, 0, 0, 0, 5 },
    { 6, 6, 4, 6, 4, 4, 6, 6, 6 },
    { 6, 6, 0, 6, 0, 0, 6, 6, 6 }
  } ;
  unsigned char class[256] = "7777777777777777777777777777777777777777777777772555555555777777777777777777777777777777777707777445554777777767776767673777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777" ;
  size_t i = 0 ;
  unsigned char store = 0 ;
  unsigned char state = 0 ;
  for (; i < delimlen ; i++)
    if (class[(unsigned char)delim[i]] == '7')
      class[(unsigned char)delim[i]] = '1' ;
    else return (errno = EINVAL, 0) ;
  *w = 0 ;

  for (i = 0 ; state < 5 ; i++)
  {
    unsigned char c = i < len ? class[(unsigned char)s[i]] - '0' : 8 ;
    unsigned char action = actions[state][c] ;
    state = states[state][c] ;
    if (action & PUSH0) d[(*w)++] = 0 ;
    if (action & PUSH) d[(*w)++] = s[i] ;
    if (action & PUSHSPEC) d[(*w)++] = 7 + byte_chr("abtnvfr", 7, s[i]) ;
    if (action & STORE) store = fmtscan_num(s[i], 16) << 4 ;
    if (action & CALC) d[(*w)++] = store | fmtscan_num(s[i], 16) ;
    if (action & SYNTAXERROR) errno = EPROTO ;
    if (action & BROKENPIPE) errno = EPIPE ;
  }
  *r = i - 1 ;
  return (state == 5) ;
}