package c_frontend_preprocess import "core:unicode/utf8" unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) { hex_to_int :: proc(c: byte) -> int { switch c { case '0'..='9': return int(c-'0') case 'a'..='f': return int(c-'a')+10 case 'A'..='F': return int(c-'A')+10 } return -1 } w: int if str[0] == quote && quote == '"' { return } else if str[0] >= 0x80 { r, w = utf8.decode_rune_in_string(str) return r, true, str[w:], true } else if str[0] != '\\' { return rune(str[0]), false, str[1:], true } if len(str) <= 1 { return } s := str c := s[1] s = s[2:] switch c { case: r = rune(c) case 'a': r = '\a' case 'b': r = '\b' case 'e': r = '\e' case 'f': r = '\f' case 'n': r = '\n' case 'r': r = '\r' case 't': r = '\t' case 'v': r = '\v' case '\\': r = '\\' case '"': r = '"' case '\'': r = '\'' case '0'..='7': v := int(c-'0') if len(s) < 2 { return } for i in 0.. 7 { return } v = (v<<3) | d } s = s[2:] if v > 0xff { return } r = rune(v) case 'x', 'u', 'U': count: int switch c { case 'x': count = 2 case 'u': count = 4 case 'U': count = 8 } if len(s) < count { return } for i in 0.. utf8.MAX_RUNE { return } multiple_bytes = true } success = true tail_string = s return } unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: string, allocated, success: bool) { contains_rune :: proc(s: string, r: rune) -> int { for c, offset in s { if c == r { return offset } } return -1 } assert(len(lit) >= 2) s := lit quote := '"' if s == `""` { return "", false, true } if contains_rune(s, '\n') >= 0 { return s, false, false } if contains_rune(s, '\\') < 0 && contains_rune(s, quote) < 0 { if quote == '"' { return s, false, true } } s = s[1:len(s)-1] buf_len := 3*len(s) / 2 buf := make([]byte, buf_len, allocator) offset := 0 for len(s) > 0 { r, multiple_bytes, tail_string, ok := unquote_char(s, byte(quote)) if !ok { delete(buf) return s, false, false } s = tail_string if r < 0x80 || !multiple_bytes { buf[offset] = byte(r) offset += 1 } else { b, w := utf8.encode_rune(r) copy(buf[offset:], b[:w]) offset += w } } new_string := string(buf[:offset]) return new_string, true, true }