mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: allow printing of C.Structs containing &char/charptr fields
This commit is contained in:
parent
273655ecc8
commit
79fa15ec3a
@ -414,6 +414,8 @@ pub const (
|
||||
int_literal_type = new_type(int_literal_type_idx)
|
||||
thread_type = new_type(thread_type_idx)
|
||||
error_type = new_type(error_type_idx)
|
||||
charptr_types = [charptr_type, new_type(char_type_idx).set_nr_muls(1)]
|
||||
byteptr_types = [byteptr_type, new_type(byte_type_idx).set_nr_muls(1)]
|
||||
)
|
||||
|
||||
pub const (
|
||||
|
@ -41,6 +41,18 @@ fn (mut g Gen) gen_str_default(sym ast.TypeSymbol, styp string, str_fn_name stri
|
||||
}
|
||||
|
||||
fn (g &Gen) type_to_fmt(typ ast.Type) string {
|
||||
if typ == ast.byte_type_idx {
|
||||
return '%hhx\\000'
|
||||
}
|
||||
if typ == ast.char_type_idx {
|
||||
return '%c\\000'
|
||||
}
|
||||
if typ == ast.voidptr_type_idx || typ in ast.byteptr_types {
|
||||
return '%p\\000'
|
||||
}
|
||||
if typ in ast.charptr_types {
|
||||
return '%C\\000' // a C string
|
||||
}
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
|
||||
return '%.*s\\000'
|
||||
@ -51,6 +63,8 @@ fn (g &Gen) type_to_fmt(typ ast.Type) string {
|
||||
return "'%.*s\\000'"
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
return '%g\\000' // g removes trailing zeros unlike %f
|
||||
} else if sym.kind == .int {
|
||||
return '%d\\000'
|
||||
} else if sym.kind == .u32 {
|
||||
return '%u\\000'
|
||||
} else if sym.kind == .u64 {
|
||||
@ -506,9 +520,11 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri
|
||||
fnames2strfunc[field_styp]
|
||||
}
|
||||
g.auto_str_funcs.write_string('indents, ')
|
||||
func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name)
|
||||
mut func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name)
|
||||
// reference types can be "nil"
|
||||
if field.typ.is_ptr() {
|
||||
if field.typ.is_ptr() && !(field.typ in ast.charptr_types
|
||||
|| field.typ in ast.byteptr_types
|
||||
|| field.typ == ast.voidptr_type_idx) {
|
||||
g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})')
|
||||
g.auto_str_funcs.write_string(' ? _SLIT("nil") : ')
|
||||
// struct, floats and ints have a special case through the _str function
|
||||
|
@ -7,7 +7,7 @@ import v.util
|
||||
|
||||
fn (mut g Gen) write_str_fn_definitions() {
|
||||
// _STR function can't be defined in vlib
|
||||
g.writeln("
|
||||
g.writeln('
|
||||
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
||||
va_list args;
|
||||
va_start(args, guess);
|
||||
@ -16,15 +16,16 @@ void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize,
|
||||
// *nbytes === already occupied bytes of buffer refbufp
|
||||
// guess === how many bytes were taken during the current vsnprintf run
|
||||
for(;;) {
|
||||
if (guess < *memsize - *nbytes) {
|
||||
int remaining_space = *memsize - *nbytes;
|
||||
if (guess < remaining_space) {
|
||||
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
||||
if (guess < *memsize - *nbytes) { // result did fit into buffer
|
||||
if (guess < remaining_space) { // result did fit into buffer
|
||||
*nbytes += guess;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// increase buffer (somewhat exponentially)
|
||||
*memsize += (*memsize + *memsize) / 3 + guess;
|
||||
*memsize += guess + 3 * (*memsize) / 2;
|
||||
#ifdef _VGCBOEHM
|
||||
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
||||
#else
|
||||
@ -48,9 +49,9 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||
int k = strlen(fmt);
|
||||
bool is_fspec = false;
|
||||
for (int j=0; j<k; ++j) {
|
||||
if (fmt[j] == '%') {
|
||||
if (fmt[j] == \'%\') {
|
||||
j++;
|
||||
if (fmt[j] != '%') {
|
||||
if (fmt[j] != \'%\') {
|
||||
is_fspec = true;
|
||||
break;
|
||||
}
|
||||
@ -59,19 +60,31 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||
if (is_fspec) {
|
||||
char f = fmt[k-1];
|
||||
char fup = f & 0xdf; // toupper
|
||||
bool l = fmt[k-2] == 'l';
|
||||
bool ll = l && fmt[k-3] == 'l';
|
||||
if (f == 'u' || fup == 'X' || f == 'o' || f == 'd' || f == 'c') { // int...
|
||||
bool l = fmt[k-2] == \'l\';
|
||||
bool ll = l && fmt[k-3] == \'l\';
|
||||
if (f == \'u\' || fup == \'X\' || f == \'o\' || f == \'d\' || f == \'c\') { // int...
|
||||
if (ll) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+16, va_arg(argptr, long long));
|
||||
else if (l) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, long));
|
||||
else _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+8, va_arg(argptr, int));
|
||||
} else if (fup >= 'E' && fup <= 'G') { // floating point
|
||||
} else if (fup >= \'E\' && fup <= \'G\') { // floating point
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
||||
} else if (f == 'p') {
|
||||
} else if (f == \'p\') {
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+14, va_arg(argptr, void*));
|
||||
} else if (f == 's') { // v string
|
||||
} else if (f == \'C\') { // a C string
|
||||
char* sptr = va_arg(argptr, char*);
|
||||
char* fmt_no_c = (char*)v_malloc(k+4);
|
||||
memcpy(fmt_no_c, fmt, k);
|
||||
fmt_no_c[k-2]=\'C\';
|
||||
fmt_no_c[k-1]=\'"\';
|
||||
fmt_no_c[k]=\'%\';
|
||||
fmt_no_c[k+1]=\'s\';
|
||||
fmt_no_c[k+2]=\'"\';
|
||||
fmt_no_c[k+3]=0;
|
||||
_STR_PRINT_ARG(fmt_no_c, &buf, &nbytes, &memsize, k + 4 + 100, sptr);
|
||||
v_free(fmt_no_c);
|
||||
} else if (f == \'s\') { // v string
|
||||
string s = va_arg(argptr, string);
|
||||
if (fmt[k-4] == '*') { // %*.*s
|
||||
if (fmt[k-4] == \'*\') { // %*.*s
|
||||
int fwidth = va_arg(argptr, int);
|
||||
if (fwidth < 0)
|
||||
fwidth -= (s.len - utf8_str_visible_length(s));
|
||||
@ -82,7 +95,7 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
||||
}
|
||||
} else {
|
||||
//v_panic(tos3('Invaid format specifier'));
|
||||
//v_panic(tos3(\'Invaid format specifier\'));
|
||||
}
|
||||
} else {
|
||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
||||
@ -92,14 +105,8 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||
va_end(argptr);
|
||||
buf[nbytes] = 0;
|
||||
|
||||
#ifdef _VGCBOEHM
|
||||
buf = (char*)GC_REALLOC((void*)buf, nbytes+1);
|
||||
#else
|
||||
buf = (char*)realloc((void*)buf, nbytes+1);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
//puts('_STR:');
|
||||
//puts(\'_STR:\');
|
||||
puts(buf);
|
||||
#endif
|
||||
|
||||
@ -119,7 +126,7 @@ string _STR_TMP(const char *fmt, ...) {
|
||||
va_end(argptr);
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
//puts('_STR_TMP:');
|
||||
//puts(\'_STR_TMP:\');
|
||||
//puts(g_str_buf);
|
||||
#endif
|
||||
string res = tos(g_str_buf, len);
|
||||
@ -128,7 +135,7 @@ string _STR_TMP(const char *fmt, ...) {
|
||||
|
||||
} // endof _STR_TMP
|
||||
|
||||
")
|
||||
')
|
||||
}
|
||||
|
||||
fn (mut g Gen) string_literal(node ast.StringLiteral) {
|
||||
|
4
vlib/v/tests/printing_c_structs/cstruct.h
Normal file
4
vlib/v/tests/printing_c_structs/cstruct.h
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
struct Abc {
|
||||
char *char_pointer_field;
|
||||
};
|
26
vlib/v/tests/printing_c_structs/string_interpolation_test.v
Normal file
26
vlib/v/tests/printing_c_structs/string_interpolation_test.v
Normal file
@ -0,0 +1,26 @@
|
||||
#include "@VROOT/cstruct.h"
|
||||
|
||||
const the_string = 'the string'
|
||||
|
||||
struct C.Abc {
|
||||
char_pointer_field &char
|
||||
}
|
||||
|
||||
struct VStruct {
|
||||
a_c_struct C.Abc
|
||||
}
|
||||
|
||||
fn test_interpolation_of_v_structs_containing_c_structs() {
|
||||
abc := C.Abc{
|
||||
char_pointer_field: &char(the_string.str)
|
||||
}
|
||||
xxx := VStruct{
|
||||
a_c_struct: abc
|
||||
}
|
||||
sxxx := xxx.str()
|
||||
assert sxxx == 'VStruct{
|
||||
a_c_struct: struct Abc{
|
||||
char_pointer_field: &C"the string"
|
||||
}
|
||||
}'
|
||||
}
|
0
vlib/v/tests/printing_c_structs/v.mod
Normal file
0
vlib/v/tests/printing_c_structs/v.mod
Normal file
Loading…
Reference in New Issue
Block a user