/* This file is part of limb https://lila.oss/limb
* Copyright (C) 2023 Olivier Brunel jjk@jjacky.com */
/* SPDX-License-Identifier: GPL-2.0-only */
#include <errno.h>
#include <skalibs/fmtscan.h>
#include <limb/bytestr.h>
#include <limb/esc.h>
int
escall_scan(char *dst, size_t dlen, const char *sce, size_t slen, size_t *w, size_t *r)
{
if (*w > dlen || *r > slen) return (errno = EINVAL, 0);
while ((!dst || *w < dlen) && *r < slen) {
size_t n = byte_in(sce + *r, slen - *r, "\\\"", 2);
if (dst) {
if (n > dlen - *w)
n = dlen - *w;
memmove(dst + *w, sce + *r, n);
}
*w += n;
*r += n;
if ((dst && *w == dlen) || *r == slen)
break;
if (sce[*r] != '\\') return (errno = EINVAL, 0);
if (*r + 1 == slen) return (errno = ENODATA, 0);
++*r;
if (sce[*r] == '\\' || sce[*r] == '"') {
if (dst) dst[*w] = sce[*r];
} else if (sce[*r] == 'x') {
if (slen - *r < 2) return (--*r, errno = ENODATA, 0);
++*r;
if (dst) {
char c = fmtscan_num(sce[*r], 16);
if (c >= 16) return (*r -= 2, errno = EINVAL, 0);
dst[*w] = c << 4;
c = fmtscan_num(sce[*r + 1], 16);
if (c >= 16) return (*r -= 2, errno = EINVAL, 0);
dst[*w] += c;
}
++*r;
} else {
const char esc[7] = "abtnvfr";
size_t n = byte_chr(esc, 7, sce[*r]);
if (n == 7) return (--*r, errno = EINVAL, 0);
if (dst) dst[*w] = 7 + n;
}
++*w;
++*r;
}
if (*r < slen) return (errno = ENOBUFS, 0);
return 1;
}