diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index a65906e19c..12078622aa 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -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 ( diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 7a9a647da2..3f4c736f32 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -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 diff --git a/vlib/v/gen/c/str.v b/vlib/v/gen/c/str.v index 3d5c719a71..8203be08cc 100644 --- a/vlib/v/gen/c/str.v +++ b/vlib/v/gen/c/str.v @@ -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= '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) { diff --git a/vlib/v/tests/printing_c_structs/cstruct.h b/vlib/v/tests/printing_c_structs/cstruct.h new file mode 100644 index 0000000000..7ab5587830 --- /dev/null +++ b/vlib/v/tests/printing_c_structs/cstruct.h @@ -0,0 +1,4 @@ + +struct Abc { + char *char_pointer_field; +}; diff --git a/vlib/v/tests/printing_c_structs/string_interpolation_test.v b/vlib/v/tests/printing_c_structs/string_interpolation_test.v new file mode 100644 index 0000000000..9b6a63eb06 --- /dev/null +++ b/vlib/v/tests/printing_c_structs/string_interpolation_test.v @@ -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" + } +}' +} diff --git a/vlib/v/tests/printing_c_structs/v.mod b/vlib/v/tests/printing_c_structs/v.mod new file mode 100644 index 0000000000..e69de29bb2