Welcome to little lamb

Code » limb » master » tree

[master] / src / liblimb / esc.h / escall_fmt.c

/* 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;
}