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