Skip to content

Commit c1eec3f

Browse files
committed
Added boot_vsnprintf from calc84maniac, allowing boot_snprintf/boot_asprintf to be implemented as functions. Also added more printf tests
1 parent 8f1ca3f commit c1eec3f

File tree

12 files changed

+336
-63
lines changed

12 files changed

+336
-63
lines changed

src/ce/include/ti/sprintf.h

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <stddef.h>
55
#include <stdlib.h>
66

7+
#include <stdarg.h>
8+
79
#ifdef __cplusplus
810
extern "C" {
911
#endif
@@ -12,49 +14,40 @@ extern "C" {
1214
* @brief C89 `sprintf`. `long` arguments and width specifiers are unsupported.
1315
* @note `%s` will write up to 255 characters.
1416
*/
15-
int boot_sprintf(
16-
char *__restrict buffer, const char *__restrict format, ...
17-
) __attribute__((format (__printf__, 2, 3)));
17+
int boot_sprintf(char *__restrict buffer, const char *__restrict format, ...)
18+
__attribute__((format (__printf__, 2, 3)));
19+
20+
/**
21+
* @note calls va_copy to wrap boot_sprintf
22+
*/
23+
int boot_vsprintf(char *__restrict buffer, const char *__restrict format, va_list va)
24+
__attribute__((format(__printf__, 2, 0)));
1825

1926
/**
2027
* @brief Returns an empty string if the output from sprintf does not fit.
21-
* @warning `__VA_ARGS__` is evaluated twice.
2228
*/
23-
#define boot_snprintf(buffer, count, ...)\
24-
({\
25-
char * const __buffer = buffer;\
26-
const int __count = count;\
27-
int __ret = -1;\
28-
int __str_len = boot_sprintf((char*)0xE40000, __VA_ARGS__);\
29-
if (__buffer == NULL || __count == 0) {\
30-
__ret = __str_len;\
31-
} else if ((size_t)__str_len > __count) {\
32-
*__buffer = '\0'; /* won't fit or invalid formatting */\
33-
} else {\
34-
__ret = boot_sprintf(__buffer, __VA_ARGS__);\
35-
}\
36-
__ret;\
37-
})
29+
int boot_snprintf(char *__restrict buffer, size_t count, const char *__restrict format, ...)
30+
__attribute__((format(__printf__, 3, 4)));
31+
32+
/**
33+
* @brief Returns an empty string if the output from sprintf does not fit.
34+
*/
35+
int boot_vsnprintf(char *__restrict buffer, size_t count, const char *__restrict format, va_list va)
36+
__attribute__((format(__printf__, 3, 0)));
37+
38+
/**
39+
* @brief Allocates a null terminated string containing the output of sprintf.
40+
* The returned pointer shall be deallocated with `free`.
41+
*/
42+
int boot_asprintf(char **__restrict p_buffer, const char *__restrict format, ...)
43+
__attribute__((format (__printf__, 2, 3))) __attribute__((nonnull(1)));
3844

3945
/**
4046
* @brief Allocates a null terminated string containing the output of sprintf.
4147
* The returned pointer shall be deallocated with `free`.
42-
* @warning `__VA_ARGS__` is evaluated twice.
4348
*/
44-
#define boot_asprintf(p_buffer, ...)\
45-
({\
46-
char** const __p_buffer = p_buffer;\
47-
int __ret = -1;\
48-
int __str_len = boot_sprintf((char*)0xE40000, __VA_ARGS__);\
49-
if (__str_len >= 0) {\
50-
size_t __buffer_size = (size_t)__str_len + 1;\
51-
*__p_buffer = (char*)malloc(__buffer_size);\
52-
if (*__p_buffer != NULL) {\
53-
__ret = boot_sprintf(*__p_buffer, __VA_ARGS__);\
54-
}\
55-
}\
56-
__ret;\
57-
})
49+
int boot_vasprintf(char **__restrict p_buffer, const char *__restrict format, va_list va)
50+
__attribute__((format(__printf__, 2, 0))) __attribute__((nonnull(1)));
5851

5952
#ifdef __cplusplus
6053
}

src/libc/asprintf.src

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22

33
section .text
44

5-
if HAS_PRINTF
6-
75
public _asprintf
86
public _vasprintf
97

8+
if HAS_PRINTF
9+
1010
_asprintf := __asprintf_c
1111
_vasprintf := __vasprintf_c
1212

1313
extern __asprintf_c
1414
extern __vasprintf_c
1515

16+
else
17+
18+
_asprintf := _boot_asprintf
19+
_vasprintf := _boot_vasprintf
20+
21+
extern _boot_asprintf
22+
extern _boot_vasprintf
23+
1624
end if

src/libc/boot_vsprintf.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include <stddef.h>
2+
#include <stdarg.h>
3+
#include <string.h>
4+
#include <stdio.h>
5+
#include <stdbool.h>
6+
#include <stdlib.h>
7+
#include <ti/sprintf.h>
8+
9+
#define SINK (char *__restrict)0xE40000
10+
11+
int boot_vsnprintf(char *__restrict buffer, size_t count, const char *__restrict format, va_list args) {
12+
int str_len = boot_vsprintf(SINK, format, args);
13+
if (buffer == NULL || count == 0) {
14+
return str_len;
15+
}
16+
if ((size_t)str_len >= count || str_len <= 0) {
17+
// won't fit or invalid formatting
18+
*buffer = '\0';
19+
return str_len;
20+
}
21+
return boot_vsprintf(buffer, format, args);
22+
}
23+
24+
int boot_snprintf(char *__restrict buffer, size_t count, const char *__restrict format, ...) {
25+
va_list args;
26+
va_start(args, format);
27+
const int ret = vsnprintf(buffer, count, format, args);
28+
va_end(args);
29+
return ret;
30+
}
31+
32+
int boot_vasprintf(char **__restrict p_buffer, const char *__restrict format, va_list args) {
33+
int ret = -1;
34+
*p_buffer = NULL;
35+
int str_len = boot_vsprintf(SINK, format, args);
36+
if (str_len < 0) {
37+
// formatting error
38+
return str_len;
39+
}
40+
size_t buffer_size = (size_t)str_len + 1;
41+
*p_buffer = (char*)malloc(buffer_size);
42+
if (*p_buffer != NULL) {
43+
ret = boot_vsprintf(*p_buffer, format, args);
44+
}
45+
return ret;
46+
}
47+
48+
int boot_asprintf(char **__restrict p_str, const char *__restrict format, ...) {
49+
va_list args;
50+
va_start(args, format);
51+
const int ret = boot_vasprintf(p_str, format, args);
52+
va_end(args);
53+
return ret;
54+
}

src/libc/boot_vsprintf.src

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
assume adl=1
2+
3+
section .text
4+
5+
public _boot_vsprintf
6+
7+
; wraps boot_sprintf
8+
_boot_vsprintf:
9+
call __frameset0
10+
; Get length of format string, plus 1
11+
ld hl, (ix + 9)
12+
push hl
13+
push hl
14+
call _strlen
15+
pop bc
16+
ex (sp), hl
17+
pop bc
18+
inc bc
19+
; Track pointer to stack allocation
20+
lea de, ix
21+
.countSpecifiersLoop:
22+
ld a, '%'
23+
.countSpecifiersInnerLoop:
24+
; Find format specifier
25+
cpir
26+
jr nz, .countDone
27+
; Check for escaped specifier
28+
cpi
29+
jr z, .countSpecifiersInnerLoop
30+
dec hl
31+
inc bc
32+
ld a, '*'
33+
.countSpecifiersIncrement:
34+
; Add one parameter
35+
dec de
36+
dec de
37+
dec de
38+
.countSpecifiersFormat:
39+
; Check for end of specifier
40+
bit 6, (hl)
41+
jr nz, .countSpecifiersLoop
42+
; Check for additional variable-length parameter
43+
cpi
44+
jr z, .countSpecifiersIncrement
45+
; Check for end of string
46+
jp pe, .countSpecifiersFormat
47+
.countDone:
48+
; Get length of parameters
49+
lea hl, ix
50+
or a, a
51+
sbc hl, de
52+
jr z, .noCopy
53+
; Allocate space for parameters
54+
ex de, hl
55+
ld sp, hl
56+
ex de, hl
57+
; Copy parameters
58+
push hl
59+
pop bc
60+
ld hl, (ix + 12)
61+
ldir
62+
.noCopy:
63+
ld hl, (ix + 9)
64+
push hl
65+
ld hl, (ix + 6)
66+
push hl
67+
call _boot_sprintf
68+
ld sp, ix
69+
pop ix
70+
ret
71+
72+
extern _boot_sprintf
73+
extern __frameset0
74+
extern _strlen

src/libc/include/stdio.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
#include <cdefs.h>
55
#include <stdarg.h>
66

7-
#ifndef HAS_PRINTF
8-
# include <ti/sprintf.h>
9-
#endif /* HAS_PRINTF */
10-
117
#ifdef HAS_CUSTOM_FILE
128
#include CUSTOM_FILE_FILE
139
#else
@@ -159,9 +155,4 @@ namespace std {
159155
} /* namespace std */
160156
#endif /* __cplusplus */
161157

162-
#ifndef HAS_PRINTF
163-
# define snprintf boot_snprintf
164-
# define asprintf boot_asprintf
165-
#endif /* HAS_PRINTF */
166-
167158
#endif /* _STDIO_H */

src/libc/snprintf.src

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22

33
section .text
44

5-
if HAS_PRINTF
6-
75
public _snprintf
86
public _vsnprintf
97

8+
if HAS_PRINTF
9+
1010
_snprintf := __snprintf_c
1111
_vsnprintf := __vsnprintf_c
1212

1313
extern __snprintf_c
1414
extern __vsnprintf_c
1515

16+
else
17+
18+
_snprintf := _boot_snprintf
19+
_vsnprintf := _boot_vsnprintf
20+
21+
extern _boot_snprintf
22+
extern _boot_vsnprintf
23+
1624
end if

src/libc/sprintf.src

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,9 @@
66

77
if HAS_PRINTF
88

9-
public _vsprintf
10-
119
_sprintf := __sprintf_c
12-
_vsprintf := __vsprintf_c
1310

1411
extern __sprintf_c
15-
extern __vsprintf_c
1612

1713
else
1814

src/libc/vsprintf.src

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
assume adl=1
2+
3+
section .text
4+
5+
public _vsprintf
6+
7+
if HAS_PRINTF
8+
9+
_vsprintf := __vsprintf_c
10+
11+
extern __vsprintf_c
12+
13+
else
14+
15+
_vsprintf := _boot_vsprintf
16+
17+
extern _boot_vsprintf
18+
19+
end if

test/graphx/zx0/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ src/gfx/*.c
44
src/gfx/*.h
55
.DS_Store
66
convimg.out
7+
src/gfx/convimg.yaml.lst

test/standalone/asprintf_fprintf/autotest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"sequence": [
1010
"action|launch",
11-
"delay|1500",
11+
"delay|2000",
1212
"hashWait|1",
1313
"key|enter",
1414
"delay|300",

0 commit comments

Comments
 (0)