Welcome to little lamb

Code » limb » release » tree

[release] / src / liblimb / hex.h / hexall_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 <errno.h>
#include <skalibs/fmtscan.h>
#include <limb/hex.h>

int
hexall_fmt(char *dst, size_t dlen, const char *sce_, size_t slen, int options, size_t *w, size_t *r)
{
    if (*r > slen || *w > dlen) return (errno = EINVAL, 0);

    while (*r < slen && *w + 1 < dlen) {
        const unsigned char *sce = (const unsigned char *) sce_;
        int l = 2;

        /* actual hex converting */
        dst[*w    ] = fmtscan_asc(sce[*r] >> 4);
        dst[*w + 1] = fmtscan_asc(sce[*r] & 0xf);

        /* do we add a trailing LF? */
        if (*r + 1 == slen && (options & HEX_LF)) {
            if (*w + l >= dlen) goto err;
            dst[*w + l++] = '\n';
        }

        /* do we add LF/space every so often? */
        if (l == 2 && options & HEX_BLOCKS) {
            unsigned n;
            /* first see for a LF, the option's value being every nth byte */
            n = options & HEX_BLOCKS_LF;
            if (n && !((*r + 1) % n)) {
                if (*w + l >= dlen) goto err;
                dst[*w + l++] = '\n';
            } else {
                /* no LF, check for spaces then, shifting down to get the same
                 * option's value == every nth byte */
                n = (options & HEX_BLOCKS_SP) >> 3;
                n = (options & HEX_SP) + (n && !((*r + 1) % n));
                for ( ; n; --n) {
                    if (*w + l >= dlen) goto err;
                    dst[*w + l++] = ' ';
                }
            }
        }

        *r += 1;
        *w += l;
    }
    if (*r < slen) goto err;

    return 1;
err:
    errno = ENOBUFS;
    return 0;
}