Since a few ramdisks / images over various "size challenged" architectures recently did grow I wondered about the recent addition of JSON support to libprop. The library is common kernel/userland code but AFAICT there is no use for JSON in the kernel variant.
So I did the patch below and tried to find out how easy it is to separate this feature (for userland only and also avoid it in size challenged cruchned ramdisks). I only did test mips and amd64 sizes for now, but the results were discuraging: savings were less thank 1k overall. And the patch is quite ugly. Maybe I overlooked something and there were more savings possible - or maybe it is just not worth the obfuscation. Martin Index: common/include/prop/prop_object.h =================================================================== RCS file: /cvsroot/src/common/include/prop/prop_object.h,v retrieving revision 1.9 diff -u -p -r1.9 prop_object.h --- common/include/prop/prop_object.h 23 Apr 2025 02:58:52 -0000 1.9 +++ common/include/prop/prop_object.h 9 May 2025 18:40:40 -0000 @@ -55,7 +55,9 @@ typedef enum { typedef enum { PROP_FORMAT_XML = 0, +#ifdef _PROPLIB_WITH_JSON PROP_FORMAT_JSON = 1 +#endif } prop_format_t; __BEGIN_DECLS Index: common/lib/libprop/prop_array.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_array.c,v retrieving revision 1.24 diff -u -p -r1.24 prop_array.c --- common/lib/libprop/prop_array.c 26 Apr 2025 17:13:23 -0000 1.24 +++ common/lib/libprop/prop_array.c 9 May 2025 18:40:40 -0000 @@ -55,9 +55,11 @@ _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop static const struct _prop_object_type_tags _prop_array_type_tags = { .xml_tag = "array", +#ifdef _PROPLIB_WITH_JSON .json_open_tag = "[", .json_close_tag = "]", .json_empty_sep = " ", +#endif }; struct _prop_array_iterator { @@ -161,10 +163,15 @@ _prop_array_externalize(struct _prop_obj struct _prop_array_iterator *pai; bool rv = false; const char * const sep = - ctx->poec_format == PROP_FORMAT_JSON ? "," : NULL; +#ifdef _PROPLIB_WITH_JSON + ctx->poec_format == PROP_FORMAT_JSON ? "," : +#endif + NULL; +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); +#endif _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); @@ -827,6 +834,7 @@ _prop_array_internalize_continue(prop_st * * (FWIW, RFC 8259 section 9 seems to specifically allow this.) */ +#ifdef _PROPLIB_WITH_JSON if (ctx->poic_format == PROP_FORMAT_JSON) { ctx->poic_cp = _prop_object_internalize_skip_whitespace(ctx->poic_cp); @@ -834,6 +842,7 @@ _prop_array_internalize_continue(prop_st ctx->poic_cp++; } } +#endif return (_prop_array_internalize_body(stack, obj, ctx)); bad: @@ -850,6 +859,7 @@ _prop_array_internalize_body(prop_stack_ _PROP_ASSERT(array != NULL); +#ifdef _PROPLIB_WITH_JSON if (ctx->poic_format == PROP_FORMAT_JSON) { ctx->poic_cp = _prop_object_internalize_skip_whitespace(ctx->poic_cp); @@ -860,7 +870,9 @@ _prop_array_internalize_body(prop_stack_ ctx->poic_cp++; return true; } - } else { + } else +#endif + { /* Fetch the next tag. */ if (_prop_object_internalize_find_tag(ctx, NULL, _PROP_TAG_TYPE_EITHER) == false) Index: common/lib/libprop/prop_bool.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_bool.c,v retrieving revision 1.21 diff -u -p -r1.21 prop_bool.c --- common/lib/libprop/prop_bool.c 26 Apr 2025 17:13:23 -0000 1.21 +++ common/lib/libprop/prop_bool.c 9 May 2025 18:40:40 -0000 @@ -45,11 +45,15 @@ static const char falsestr[] = "false"; static const struct _prop_object_type_tags _prop_bool_true_type_tags = { .xml_tag = truestr, +#ifdef _PROPLIB_WITH_JSON .json_open_tag = truestr, +#endif }; static const struct _prop_object_type_tags _prop_bool_false_type_tags = { .xml_tag = falsestr, +#ifdef _PROPLIB_WITH_JSON .json_open_tag = falsestr, +#endif }; static _prop_object_free_rv_t Index: common/lib/libprop/prop_data.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_data.c,v retrieving revision 1.20 diff -u -p -r1.20 prop_data.c --- common/lib/libprop/prop_data.c 26 Apr 2025 17:13:23 -0000 1.20 +++ common/lib/libprop/prop_data.c 9 May 2025 18:40:40 -0000 @@ -112,6 +112,7 @@ _prop_data_externalize(struct _prop_obje uint8_t output[4]; uint8_t input[3]; +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); @@ -121,6 +122,7 @@ _prop_data_externalize(struct _prop_obje if (ctx->poec_format == PROP_FORMAT_JSON) { return false; } +#endif if (pd->pd_size == 0) return (_prop_object_externalize_empty_tag(ctx, @@ -637,10 +639,12 @@ _prop_data_internalize(prop_stack_t stac uint8_t *buf; size_t len, alen; +#ifdef _PROPLIB_WITH_JSON /* No JSON binary data object representation. */ if (ctx->poic_format == PROP_FORMAT_JSON) { return true; } +#endif /* * We don't accept empty elements. Index: common/lib/libprop/prop_dictionary.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_dictionary.c,v retrieving revision 1.48 diff -u -p -r1.48 prop_dictionary.c --- common/lib/libprop/prop_dictionary.c 26 Apr 2025 17:13:23 -0000 1.48 +++ common/lib/libprop/prop_dictionary.c 9 May 2025 18:40:40 -0000 @@ -103,15 +103,19 @@ _PROP_MALLOC_DEFINE(M_PROP_DICT, "prop d static const struct _prop_object_type_tags _prop_dictionary_type_tags = { .xml_tag = "dict", +#ifdef _PROPLIB_WITH_JSON .json_open_tag = "{", .json_close_tag = "}", .json_empty_sep = " ", +#endif }; static const struct _prop_object_type_tags _prop_dict_key_type_tags = { .xml_tag = "key", +#ifdef _PROPLIB_WITH_JSON .json_open_tag = "\"", .json_close_tag = "\"", +#endif }; struct _prop_dictionary_iterator { @@ -445,6 +449,7 @@ _prop_dictionary_externalize_one(struct return false; } +#ifdef _PROPLIB_WITH_JSON switch (ctx->poec_format) { case PROP_FORMAT_JSON: if (_prop_object_externalize_append_cstring(ctx, @@ -454,12 +459,15 @@ _prop_dictionary_externalize_one(struct break; default: /* XML */ +#endif if (_prop_object_externalize_end_line(ctx, NULL) == false || _prop_object_externalize_start_line(ctx) == false) { return false; } +#ifdef _PROPLIB_WITH_JSON break; } +#endif return (*po->po_type->pot_extern)(ctx, po); } @@ -474,10 +482,15 @@ _prop_dictionary_externalize(struct _pro struct _prop_dictionary_iterator *pdi; bool rv = false; const char * const sep = - ctx->poec_format == PROP_FORMAT_JSON ? "," : NULL; +#ifdef _PROPLIB_WITH_JSON + ctx->poec_format == PROP_FORMAT_JSON ? "," : +#endif + NULL; +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); +#endif _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); @@ -1361,6 +1374,7 @@ _prop_dictionary_internalize_continue(pr * * (FWIW, RFC 8259 section 9 seems to specifically allow this.) */ +#ifdef _PROPLIB_WITH_JSON if (ctx->poic_format == PROP_FORMAT_JSON) { ctx->poic_cp = _prop_object_internalize_skip_whitespace(ctx->poic_cp); @@ -1368,6 +1382,7 @@ _prop_dictionary_internalize_continue(pr ctx->poic_cp++; } } +#endif return _prop_dictionary_internalize_body(stack, obj, ctx, tmpkey); } @@ -1378,6 +1393,7 @@ _prop_dictionary_internalize_body(prop_s prop_dictionary_t dict = *obj; size_t keylen; +#ifdef _PROPLIB_WITH_JSON if (ctx->poic_format == PROP_FORMAT_JSON) { ctx->poic_cp = _prop_object_internalize_skip_whitespace(ctx->poic_cp); @@ -1399,7 +1415,9 @@ _prop_dictionary_internalize_body(prop_s if (*ctx->poic_cp == '"') { goto bad; } - } else { + } else +#endif + { /* Fetch the next tag. */ if (_prop_object_internalize_find_tag(ctx, NULL, _PROP_TAG_TYPE_EITHER) == false) @@ -1427,6 +1445,7 @@ _prop_dictionary_internalize_body(prop_s _PROP_ASSERT(keylen <= PDK_MAXKEY); tmpkey[keylen] = '\0'; +#ifdef _PROPLIB_WITH_JSON if (ctx->poic_format == PROP_FORMAT_JSON) { if (*ctx->poic_cp != '"') { goto bad; @@ -1443,7 +1462,9 @@ _prop_dictionary_internalize_body(prop_s goto bad; } ctx->poic_cp++; - } else { + } else +#endif + { if (_prop_object_internalize_find_tag(ctx, "key", _PROP_TAG_TYPE_END) == false) goto bad; Index: common/lib/libprop/prop_number.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_number.c,v retrieving revision 1.36 diff -u -p -r1.36 prop_number.c --- common/lib/libprop/prop_number.c 26 Apr 2025 17:13:23 -0000 1.36 +++ common/lib/libprop/prop_number.c 9 May 2025 18:40:40 -0000 @@ -200,10 +200,12 @@ _prop_number_externalize(struct _prop_ob { prop_number_t pn = v; char tmpstr[32]; +#ifdef _PROPLIB_WITH_JSON const bool json = ctx->poec_format == PROP_FORMAT_JSON; _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); +#endif /* * For unsigned numbers, we output in hex for XML, decimal for JSON. @@ -211,7 +213,10 @@ _prop_number_externalize(struct _prop_ob */ if (pn->pn_value.pnv_is_unsigned) { snprintf(tmpstr, sizeof(tmpstr), - json ? "%" PRIu64 : "0x%" PRIx64, +#ifdef _PROPLIB_WITH_JSON + json ? "%" PRIu64 : +#endif + "0x%" PRIx64, pn->pn_value.pnv_unsigned); } else { snprintf(tmpstr, sizeof(tmpstr), "%" PRIi64, @@ -684,7 +689,11 @@ _prop_number_internalize(prop_stack_t st struct _prop_number_value pnv; /* JSON numbers are always base-10. */ - const int base = ctx->poic_format == PROP_FORMAT_JSON ? 10 : 0; + const int base = +#ifdef _PROPLIB_WITH_JSON + ctx->poic_format == PROP_FORMAT_JSON ? 10 : +#endif + 0; memset(&pnv, 0, sizeof(pnv)); @@ -704,7 +713,10 @@ _prop_number_internalize(prop_stack_t st return (true); } else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') { /* No hex numbers in JSON. */ - if (ctx->poic_format == PROP_FORMAT_JSON || + if ( +#ifdef _PROPLIB_WITH_JSON + ctx->poic_format == PROP_FORMAT_JSON || +#endif _prop_number_internalize_unsigned(ctx, &pnv, 16) == false) return (true); } else { @@ -714,7 +726,10 @@ _prop_number_internalize(prop_stack_t st } /* No end tag to advance over in JSON. */ - if (ctx->poic_format != PROP_FORMAT_JSON && + if ( +#ifdef _PROPLIB_WITH_JSON + ctx->poic_format != PROP_FORMAT_JSON && +#endif _prop_object_internalize_find_tag(ctx, "integer", _PROP_TAG_TYPE_END) == false) return (true); Index: common/lib/libprop/prop_object.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_object.c,v retrieving revision 1.39 diff -u -p -r1.39 prop_object.c --- common/lib/libprop/prop_object.c 26 Apr 2025 17:13:23 -0000 1.39 +++ common/lib/libprop/prop_object.c 9 May 2025 18:40:40 -0000 @@ -143,6 +143,7 @@ _prop_object_externalize_start_tag( { bool rv; +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); @@ -154,6 +155,7 @@ _prop_object_externalize_start_tag( break; default: /* XML */ +#endif rv = _prop_object_externalize_append_char(ctx, '<') && _prop_object_externalize_append_cstring(ctx, tags->xml_tag) && @@ -162,8 +164,10 @@ _prop_object_externalize_start_tag( _prop_object_externalize_append_cstring(ctx, tagattrs))) && _prop_object_externalize_append_char(ctx, '>'); +#ifdef _PROPLIB_WITH_JSON break; } +#endif return rv; } @@ -179,6 +183,7 @@ _prop_object_externalize_end_tag( { bool rv; +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); @@ -190,13 +195,16 @@ _prop_object_externalize_end_tag( break; default: /* XML */ +#endif rv = _prop_object_externalize_append_char(ctx, '<') && _prop_object_externalize_append_char(ctx, '/') && _prop_object_externalize_append_cstring(ctx, tags->xml_tag) && _prop_object_externalize_append_char(ctx, '>'); +#ifdef _PROPLIB_WITH_JSON break; } +#endif return rv; } @@ -212,6 +220,7 @@ _prop_object_externalize_empty_tag( { bool rv; +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); @@ -236,13 +245,16 @@ _prop_object_externalize_empty_tag( break; default: /* XML */ +#endif rv = _prop_object_externalize_append_char(ctx, '<') && _prop_object_externalize_append_cstring(ctx, tags->xml_tag) && _prop_object_externalize_append_char(ctx, '/') && _prop_object_externalize_append_char(ctx, '>'); +#ifdef _PROPLIB_WITH_JSON break; } +#endif return rv; } @@ -304,6 +316,7 @@ _prop_object_externalize_append_encoded_ return (true); } +#ifdef _PROPLIB_WITH_JSON static bool _prop_object_externalize_append_escu( struct _prop_object_externalize_context *ctx, uint16_t val) @@ -399,11 +412,13 @@ _prop_object_externalize_append_encoded_ return true; } +#endif bool _prop_object_externalize_append_encoded_cstring( struct _prop_object_externalize_context *ctx, const char *cp) { +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML || ctx->poec_format == PROP_FORMAT_JSON); @@ -412,9 +427,12 @@ _prop_object_externalize_append_encoded_ return _prop_object_externalize_append_encoded_cstring_json(ctx, cp); default: +#endif return _prop_object_externalize_append_encoded_cstring_xml(ctx, cp); +#ifdef _PROPLIB_WITH_JSON } +#endif } #define BUF_EXPAND 256 @@ -462,9 +480,11 @@ _prop_object_externalize_header(struct _ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"; +#ifdef _PROPLIB_WITH_JSON if (ctx->poec_format != PROP_FORMAT_XML) { return true; } +#endif if (_prop_object_externalize_append_cstring(ctx, _plist_xml_header) == false || @@ -489,13 +509,17 @@ _prop_object_externalize_footer(struct _ return false; } +#ifdef _PROPLIB_WITH_JSON if (ctx->poec_format == PROP_FORMAT_XML) { +#endif if (_prop_object_externalize_end_tag(ctx, &_plist_type_tags) == false || _prop_object_externalize_end_line(ctx, NULL) == false) { return false; } +#ifdef _PROPLIB_WITH_JSON } +#endif return _prop_object_externalize_append_char(ctx, '\0'); } @@ -519,7 +543,9 @@ _prop_object_externalize_context_alloc(p ctx->poec_len = 0; ctx->poec_capacity = BUF_EXPAND; ctx->poec_depth = 0; +#ifdef _PROPLIB_WITH_JSON ctx->poec_format = fmt; +#endif } return (ctx); } @@ -552,9 +578,11 @@ _prop_object_externalize(struct _prop_ob if (obj == NULL || obj->po_type->pot_extern == NULL) { return NULL; } +#ifdef _PROPLIB_WITH_JSON if (fmt != PROP_FORMAT_XML && fmt != PROP_FORMAT_JSON) { return NULL; } +#endif ctx = _prop_object_externalize_context_alloc(fmt); if (ctx == NULL) { @@ -823,6 +851,8 @@ _prop_object_internalize_decode_string_x return (true); } +#ifdef _PROPLIB_WITH_JSON + static unsigned int _prop_object_decode_string_uesc_getu16(const char *src, unsigned int idx, uint16_t *valp) @@ -1039,6 +1069,7 @@ _prop_object_internalize_decode_string_j } #undef ADDCHAR +#endif bool _prop_object_internalize_decode_string( @@ -1046,6 +1077,7 @@ _prop_object_internalize_decode_string( char *target, size_t targsize, size_t *sizep, const char **cpp) { +#ifdef _PROPLIB_WITH_JSON _PROP_ASSERT(ctx->poic_format == PROP_FORMAT_XML || ctx->poic_format == PROP_FORMAT_JSON); @@ -1055,9 +1087,12 @@ _prop_object_internalize_decode_string( target, targsize, sizep, cpp); default: /* XML */ +#endif return _prop_object_internalize_decode_string_xml(ctx, target, targsize, sizep, cpp); +#ifdef _PROPLIB_WITH_JSON } +#endif } /* @@ -1353,7 +1388,11 @@ _prop_object_internalize(const char *dat return NULL; } +#ifdef _PROPLIB_WITH_JSON fmt = *data == '<' ? PROP_FORMAT_XML : PROP_FORMAT_JSON; +#else + fmt = PROP_FORMAT_XML; +#endif ctx = _prop_object_internalize_context_alloc(data, fmt); if (ctx == NULL) { @@ -1389,7 +1428,9 @@ _prop_object_internalize_context_alloc(c if (ctx == NULL) return (NULL); +#ifdef _PROPLIB_WITH_JSON ctx->poic_format = fmt; +#endif ctx->poic_data = ctx->poic_cp = data; /* @@ -1397,6 +1438,7 @@ _prop_object_internalize_context_alloc(c * skip it, if present. We should never see one, but we're * allowed to detect and ignore it. (RFC 8259 section 8.1) */ +#ifdef _PROPLIB_WITH_JSON if (fmt == PROP_FORMAT_JSON) { if (((unsigned char)data[0] == 0xff && (unsigned char)data[1] == 0xfe) || @@ -1408,6 +1450,7 @@ _prop_object_internalize_context_alloc(c /* No additional processing work to do for JSON. */ return ctx; } +#endif /* * Skip any whitespace and XML preamble stuff that we don't Index: common/lib/libprop/prop_object_impl.h =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_object_impl.h,v retrieving revision 1.38 diff -u -p -r1.38 prop_object_impl.h --- common/lib/libprop/prop_object_impl.h 26 Apr 2025 17:13:23 -0000 1.38 +++ common/lib/libprop/prop_object_impl.h 9 May 2025 18:40:40 -0000 @@ -51,14 +51,18 @@ struct _prop_object_externalize_context size_t poec_capacity; /* capacity of buffer */ size_t poec_len; /* current length of string */ unsigned int poec_depth; /* nesting depth */ +#ifdef _PROPLIB_WITH_JSON prop_format_t poec_format; /* output format */ +#endif }; struct _prop_object_type_tags { const char *xml_tag; +#ifdef _PROPLIB_WITH_JSON const char *json_open_tag; const char *json_close_tag; const char *json_empty_sep; +#endif }; bool _prop_object_externalize_start_line( @@ -107,7 +111,9 @@ typedef enum { } _prop_tag_type_t; struct _prop_object_internalize_context { +#ifdef _PROPLIB_WITH_JSON prop_format_t poic_format; +#endif const char *poic_data; const char *poic_cp; Index: common/lib/libprop/prop_string.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_string.c,v retrieving revision 1.21 diff -u -p -r1.21 prop_string.c --- common/lib/libprop/prop_string.c 26 Apr 2025 17:13:23 -0000 1.21 +++ common/lib/libprop/prop_string.c 9 May 2025 18:40:40 -0000 @@ -61,8 +61,10 @@ _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop static const struct _prop_object_type_tags _prop_string_type_tags = { .xml_tag = "string", +#ifdef _PROPLIB_WITH_JSON .json_open_tag = "\"", .json_close_tag = "\"", +#endif }; static _prop_object_free_rv_t @@ -696,13 +698,16 @@ _prop_string_internalize(prop_stack_t st } str[len] = '\0'; +#ifdef _PROPLIB_WITH_JSON if (ctx->poic_format == PROP_FORMAT_JSON) { if (*ctx->poic_cp != '"') { _PROP_FREE(str, M_PROP_STRING); return (true); } ctx->poic_cp++; - } else { + } else +#endif + { if (_prop_object_internalize_find_tag(ctx, "string", _PROP_TAG_TYPE_END) == false) { _PROP_FREE(str, M_PROP_STRING); Index: lib/libprop/Makefile =================================================================== RCS file: /cvsroot/src/lib/libprop/Makefile,v retrieving revision 1.23 diff -u -p -r1.23 Makefile --- lib/libprop/Makefile 26 Apr 2025 17:13:23 -0000 1.23 +++ lib/libprop/Makefile 9 May 2025 18:40:40 -0000 @@ -11,6 +11,9 @@ PROPLIBDIR=${NETBSDSRCDIR}/common/lib/li CPPFLAGS+=-D_LIBPROP CPPFLAGS+=-D_REENTRANT -I${NETBSDSRCDIR}/lib/libc/include +.if !defined(SMALL) +CPPFLAGS+=-D_PROPLIB_WITH_JSON +.endif .for src in ${SRCS} COPTS.${src}+= -fvisibility=hidden