/* 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 <ctype.h>
#include <errno.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include <skalibs/fmtscan.h>
#include <limb/esc.h>
int
escall_fmt(char *dst, size_t dlen, const char *sce, size_t slen, size_t *w, size_t *r)
{
if ((dst && *w > dlen) || *r > slen) return (errno = EINVAL, 0);
while ((!dst || *w < dlen) && *r < slen) {
/* printable ASCII chars we can directly put */
if (sce[*r] != '\\' && sce[*r] != '"' && sce[*r] >= 32 && sce[*r] <= 126) {
if (dst) dst[*w] = sce[*r];
++*w;
++*r;
} else {
/* basic backslash escaping */
if (sce[*r] == '\\' || sce[*r] == '"') {
if (dst) {
if (*w + 2 > dlen)
return (errno = ENOBUFS, 0);
dst[*w] = '\\';
dst[*w + 1] = sce[*r];
}
*w += 2;
*r += 1;
/* simple backslash escaping */
} else if (sce[*r] >= 7 && sce[*r] <= 13) {
if (dst) {
if (*w + 2 > dlen)
return (errno = ENOBUFS, 0);
const char esc[7] = "abtnvfr";
dst[*w] = '\\';
dst[*w + 1] = esc[sce[*r] - 7];
}
*w += 2;
*r += 1;
} else {
mbstate_t state = { 0 };
/* try to get a multibyte char */
wchar_t wc;
size_t l = mbrtowc(&wc, sce + *r, slen - *r, &state);
/* if it is one and is printable, put the bytes */
if (l && l != (size_t) -2 && l != (size_t) -1 && iswprint(wc)) {
if (dst) {
if (*w + l > dlen)
return (errno = ENOBUFS, 0);
memcpy(dst + *w, sce + *r, l);
}
*w += l;
*r += l;
/* just a single-byte char */
} else if (isprint(sce[*r])) {
if (dst) dst[*w] = sce[*r];
++*w;
++*r;
/* hexa-escaping */
} else {
if (dst) {
if (*w + 4 > dlen)
return (errno = ENOBUFS, 0);
dst[*w] = '\\';
dst[*w + 1] = 'x';
ucharn_fmt(dst + *w + 2, sce + *r, 1);
}
*w += 4;
*r += 1;
}
}
}
}
if (*r < slen) return (errno = ENOBUFS, 0);
return 1;
}