mirror of
https://github.com/apache/nuttx.git
synced 2026-05-29 04:19:37 +08:00
lib_libvsprintf.c:Add buffer data type conversion interface.
Signed-off-by: likun17 <likun17@xiaomi.com>
This commit is contained in:
@@ -685,6 +685,18 @@ int lib_snoflush(FAR struct lib_sostream_s *self);
|
|||||||
int lib_sprintf(FAR struct lib_outstream_s *stream,
|
int lib_sprintf(FAR struct lib_outstream_s *stream,
|
||||||
FAR const IPTR char *fmt, ...) printf_like(2, 3);
|
FAR const IPTR char *fmt, ...) printf_like(2, 3);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: lib_bsprintf
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Implementation of sprintf formatted output buffer data. Structure data
|
||||||
|
* types must be one-byte aligned.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int lib_bsprintf(FAR struct lib_outstream_s *s, FAR const IPTR char *fmt,
|
||||||
|
FAR const void *buf);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: lib_sprintf_internal
|
* Name: lib_sprintf_internal
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ set(SRCS
|
|||||||
lib_sscanf.c
|
lib_sscanf.c
|
||||||
lib_vsscanf.c
|
lib_vsscanf.c
|
||||||
lib_libvscanf.c
|
lib_libvscanf.c
|
||||||
|
lib_libbsprintf.c
|
||||||
lib_libvsprintf.c
|
lib_libvsprintf.c
|
||||||
lib_remove.c
|
lib_remove.c
|
||||||
lib_tempnam.c
|
lib_tempnam.c
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ CSRCS += lib_perror.c lib_putchar.c lib_getchar.c lib_puts.c
|
|||||||
CSRCS += lib_gets_s.c lib_gets.c lib_libdgets.c
|
CSRCS += lib_gets_s.c lib_gets.c lib_libdgets.c
|
||||||
CSRCS += lib_sscanf.c lib_vsscanf.c lib_libvscanf.c lib_libvsprintf.c
|
CSRCS += lib_sscanf.c lib_vsscanf.c lib_libvscanf.c lib_libvsprintf.c
|
||||||
CSRCS += lib_remove.c lib_tempnam.c lib_tmpnam.c lib_ultoa_invert.c
|
CSRCS += lib_remove.c lib_tempnam.c lib_tmpnam.c lib_ultoa_invert.c
|
||||||
CSRCS += lib_renameat.c lib_putwchar.c
|
CSRCS += lib_renameat.c lib_putwchar.c lib_libbsprintf.c
|
||||||
|
|
||||||
ifeq ($(CONFIG_LIBC_FLOATINGPOINT),y)
|
ifeq ($(CONFIG_LIBC_FLOATINGPOINT),y)
|
||||||
CSRCS += lib_dtoa_engine.c lib_dtoa_data.c
|
CSRCS += lib_dtoa_engine.c lib_dtoa_data.c
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# lib_libbsprintf
|
||||||
|
This function is mainly used to output the contents of the input structure. Most standards follow the standards of printf and scanf.
|
||||||
|
For detailed parameters, see:
|
||||||
|
1. https://en.cppreference.com/w/c/io/fprintf
|
||||||
|
2. https://en.cppreference.com/w/c/io/fscanf
|
||||||
|
|
||||||
|
- **special**:
|
||||||
|
1. Float use %hf, and double for all others.
|
||||||
|
2. The char array is specified with %.xs. for example: "char t[30]" is specified with "%.30s", char a [20] - " %.20s "
|
||||||
|
3. "%u" is unsigned int.
|
||||||
|
4. "%d" is int.
|
||||||
|
5. When using %f to format a double data type, the double is truncated to 6 decimal places by default.
|
||||||
|
6. It is recommended that the "char[]" array be placed at the end of the structure to prevent parameter configuration errors such as "%.20s" from causing problems in parsing the entire buffer.
|
||||||
|
- **demo**
|
||||||
|
1. **struct**:
|
||||||
|
~~~
|
||||||
|
begin_packed_struct
|
||||||
|
struct test
|
||||||
|
{
|
||||||
|
uint8_t a;
|
||||||
|
uint16_t b;
|
||||||
|
uint32_t c;
|
||||||
|
int8_t d;
|
||||||
|
int16_t e;
|
||||||
|
int32_t f;
|
||||||
|
float g;
|
||||||
|
double h;
|
||||||
|
char i[32];
|
||||||
|
uint64_t j;
|
||||||
|
int64_t k;
|
||||||
|
char l;
|
||||||
|
unsigned char m;
|
||||||
|
short int n;
|
||||||
|
unsigned short int o;
|
||||||
|
int p;
|
||||||
|
unsigned int q;
|
||||||
|
long r;
|
||||||
|
unsigned long s;
|
||||||
|
long long t;
|
||||||
|
unsigned long long u;
|
||||||
|
size_t v;
|
||||||
|
long double w;
|
||||||
|
}end_packed_struct;
|
||||||
|
~~~
|
||||||
|
1. **format string**:
|
||||||
|
~~~
|
||||||
|
const char* sg = " uint8_t:[%hhu]\n" \
|
||||||
|
" uint16_t:[%hu]\n" \
|
||||||
|
" uint32_t:[%u]\n" \
|
||||||
|
" int8_t:[%hhd]\n" \
|
||||||
|
" int16_t:[%hd]\n" \
|
||||||
|
" int32_t:[%d]\n" \
|
||||||
|
" float:[%hf]\n" \
|
||||||
|
" double:[%f]\n" \
|
||||||
|
" char[]:[%.32s]\n" \
|
||||||
|
" uint64_t:[%lu]\n" \
|
||||||
|
" int64_t:[%ld]\n" \
|
||||||
|
" char:[%hhd]\n" \
|
||||||
|
" unsigned char:[%hhu]\n" \
|
||||||
|
" short int:[%hd]\n" \
|
||||||
|
"unsigned short int:[%hu]\n" \
|
||||||
|
" int:[%d]\n" \
|
||||||
|
" unsigned int:[%u]\n" \
|
||||||
|
" long:[%ld]\n" \
|
||||||
|
" unsigned long:[%lu]\n" \
|
||||||
|
" long long:[%lld]\n" \
|
||||||
|
"unsigned long long:[%llu]\n" \
|
||||||
|
" size_t:[%uz]\n" \
|
||||||
|
" long double:[%Lf]\n";
|
||||||
|
~~~
|
||||||
|
1. **use**:
|
||||||
|
- output to terminal:
|
||||||
|
~~~
|
||||||
|
#ifdef CONFIG_FILE_STREAM
|
||||||
|
struct lib_stdoutstream_s stdoutstream;
|
||||||
|
|
||||||
|
lib_stdoutstream(&stdoutstream, stdout);
|
||||||
|
|
||||||
|
flockfile(stdout);
|
||||||
|
lib_bsprintf(&stdoutstream.common, sv, &test_v);
|
||||||
|
lib_bsprintf(&stdoutstream.common, sg, &test_g);
|
||||||
|
funlockfile(stdout);
|
||||||
|
#else
|
||||||
|
struct lib_rawoutstream_s rawoutstream;
|
||||||
|
struct lib_bufferedoutstream_s outstream;
|
||||||
|
|
||||||
|
lib_rawoutstream(&rawoutstream, STDOUT_FILENO);
|
||||||
|
lib_bufferedoutstream(&outstream, &rawoutstream.common);
|
||||||
|
|
||||||
|
lib_bsprintf(&outstream.common, sv, &test_v);
|
||||||
|
lib_bsprintf(&outstream.common, sg, &test_g);
|
||||||
|
|
||||||
|
lib_stream_flush(&outstream.common);
|
||||||
|
#endif
|
||||||
|
~~~
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* libs/libc/stdio/lib_libbsprintf.c
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
#include <nuttx/streams.h>
|
||||||
|
#include <nuttx/compiler.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int lib_bsprintf(FAR struct lib_outstream_s *s, FAR const IPTR char *fmt,
|
||||||
|
FAR const void *buf)
|
||||||
|
{
|
||||||
|
begin_packed_struct union
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
short int si;
|
||||||
|
int i;
|
||||||
|
long l;
|
||||||
|
#ifdef CONFIG_HAVE_LONG_LONG
|
||||||
|
long long ll;
|
||||||
|
#endif
|
||||||
|
intmax_t im;
|
||||||
|
size_t sz;
|
||||||
|
ptrdiff_t pd;
|
||||||
|
uintptr_t p;
|
||||||
|
#ifdef CONFIG_HAVE_DOUBLE
|
||||||
|
float f;
|
||||||
|
double d;
|
||||||
|
# ifdef CONFIG_HAVE_LONG_DOUBLE
|
||||||
|
long double ld;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
end_packed_struct *var;
|
||||||
|
FAR const char *prec = NULL;
|
||||||
|
FAR const char *data = buf;
|
||||||
|
char fmtstr[64];
|
||||||
|
bool infmt = false;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t ret = 0;
|
||||||
|
size_t len = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
while ((c = *fmt++) != '\0')
|
||||||
|
{
|
||||||
|
if (c != '%' && !infmt)
|
||||||
|
{
|
||||||
|
lib_stream_putc(s, c);
|
||||||
|
ret++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!infmt)
|
||||||
|
{
|
||||||
|
len = 0;
|
||||||
|
infmt = true;
|
||||||
|
memset(fmtstr, 0, sizeof(fmtstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
var = (FAR void *)((char *)buf + offset);
|
||||||
|
fmtstr[len++] = c;
|
||||||
|
|
||||||
|
if (c == 'c' || c == 'd' || c == 'i' || c == 'u' ||
|
||||||
|
c == 'o' || c == 'x' || c == 'X')
|
||||||
|
{
|
||||||
|
if (*(fmt - 2) == 'j')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->im);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->im);
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_HAVE_LONG_LONG
|
||||||
|
else if (*(fmt - 2) == 'l' && *(fmt - 3) == 'l')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->ll);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->ll);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (*(fmt - 2) == 'l')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->l);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->l);
|
||||||
|
}
|
||||||
|
else if (*(fmt - 2) == 'z')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->sz);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->sz);
|
||||||
|
}
|
||||||
|
else if (*(fmt - 2) == 't')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->pd);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->pd);
|
||||||
|
}
|
||||||
|
else if (*(fmt - 2) == 'h' && *(fmt - 3) == 'h')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->c);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->c);
|
||||||
|
}
|
||||||
|
else if (*(fmt - 2) == 'h')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->si);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->si);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset += sizeof(var->i);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->i);
|
||||||
|
}
|
||||||
|
|
||||||
|
infmt = false;
|
||||||
|
}
|
||||||
|
else if (c == 'e' || c == 'f' || c == 'g' || c == 'a' ||
|
||||||
|
c == 'A' || c == 'E' || c == 'F' || c == 'G')
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_HAVE_DOUBLE
|
||||||
|
if (*(fmt - 2) == 'h')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->f);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->f);
|
||||||
|
}
|
||||||
|
# ifdef CONFIG_HAVE_LONG_DOUBLE
|
||||||
|
else if (*(fmt - 2) == 'L')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->ld);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->ld);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset += sizeof(var->d);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->d);
|
||||||
|
}
|
||||||
|
|
||||||
|
infmt = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (c == '*')
|
||||||
|
{
|
||||||
|
itoa(var->i, fmtstr + len - 1, 10);
|
||||||
|
len = strlen(fmtstr);
|
||||||
|
offset += sizeof(var->i);
|
||||||
|
}
|
||||||
|
else if (c == 's')
|
||||||
|
{
|
||||||
|
FAR const char *value = data + offset;
|
||||||
|
|
||||||
|
if (prec != NULL)
|
||||||
|
{
|
||||||
|
offset += strtol(prec, NULL, 10);
|
||||||
|
prec = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset += strlen(value) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += lib_sprintf(s, fmtstr, value);
|
||||||
|
infmt = false;
|
||||||
|
}
|
||||||
|
else if (c == 'p')
|
||||||
|
{
|
||||||
|
offset += sizeof(var->p);
|
||||||
|
ret += lib_sprintf(s, fmtstr, var->p);
|
||||||
|
infmt = false;
|
||||||
|
}
|
||||||
|
else if (c == '.')
|
||||||
|
{
|
||||||
|
prec = fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(fmt - 2) != '\n')
|
||||||
|
{
|
||||||
|
lib_stream_putc(s, '\n');
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user