I've written a program to probe the limits of a system's C time.h functions and dump them out in JSON. Then other things which depend on those functions can know their limits.
# system time.h limits, as JSON
{
"gmtime": {
"max": 2147483647,
"min": -2147483648
},
"localtime": {
"max": 2147483647,
"min": -2147483648
},
"mktime": {
"max": {
"tm_sec": 7,
"tm_min": 14,
"tm_hour": 19,
"tm_mday": 18,
"tm_mon": 0,
"tm_year": 138,
"tm_wday": 1,
"tm_yday": 17,
"tm_isdst": 0
},
"min": {
"tm_sec": 52,
"tm_min": 45,
"tm_hour": 12,
"tm_mday": 13,
"tm_mon": 11,
"tm_year": 1,
"tm_wday": 5,
"tm_yday": 346,
"tm_isdst": 0
}
}
}
gmtime() and localtime() are simple enough, they just take numbers, but mktime() takes a tm struct. I wrote a custom function to turn a tm struct into a JSON hash.
/* Dump a tm struct as a json fragment */
char * tm_as_json(const struct tm* date) {
char *date_json = malloc(sizeof(char) * 512);
#ifdef HAS_TM_TM_ZONE
char zone_json[32];
#endif
#ifdef HAS_TM_TM_GMTOFF
char gmtoff_json[32];
#endif
sprintf(date_json,
"\"tm_sec\": %d, \"tm_min\": %d, \"tm_hour\": %d, \"tm_mday\": %d, \"tm_mon\": %d, \"tm_year\": %d, \"tm_wday\": %d, \"tm_yday\": %d, \"tm_isdst\": %d",
date->tm_sec, date->tm_min, date->tm_hour, date->tm_mday,
date->tm_mon, date->tm_year, date->tm_wday, date->tm_yday, date->tm_isdst
);
#ifdef HAS_TM_TM_ZONE
sprintf(&zone_json, ", \"tm_zone\": %s", date->tm_zone);
strcat(date_json, zone_json);
#endif
#ifdef HAS_TM_TM_GMTOFF
sprintf(&gmtoff_json", \"tm_gmtoff\": %ld", date->tm_gmtoff);
strcat(date_json, gmtoff_json);
#endif
return date_json;
}
Is there a way to do this generically, for any given struct?
Note: C, not C++.
Not in C—at least in general. But if the C module is compiled with debug symbols, and the object module is available, you could parse that and discover everything about the structure. I bet there's a library for your system to assist with that.
This won't quite give you what you're asking for, but it might help a little:
#define NAME_AND_INT(buf, obj, param) \
sprintf((buf), "\"%s\": %d, ", #param, (obj)->(param))
You could then iterate, e.g. something like (note: not tested; consider this pseudo-code):
char * tm_as_json(const struct tm* date) {
/* ... */
char buf[BUFSIZ]; /* or, use your date_json */
pos = buf; /* I note you use the equivalent of &buf -- that works too */
/* (not sure which is "better", but I've always left the & off
* things like that -- buf is essentially a pointer, it's just
* been allocated in a different way. At least that's how I
* think of it. */
pos += NAME_AND_INT(pos, date, tm_sec);
pos += NAME_AND_INT(pos, date, tm_min);
/* ... more like this ... */
/* strip trailing ", " (comma-space): */
pos-=2;
*pos = '\0';
/* ... */
}
You could similarly define NAME_AND_STRING
, NAME_AND_LONG
, etc. (for tm_zone and tm_gmtoff) as needed.
Again, it's not a generic solution, but it at least gets you a little closer, maybe.
Having come across the same issue, i wrote one myself. https://github.com/jamie-pate/jstruct . It's written to allow annotating existing c structures, then generate meta-data information based on the annotations. The library reads the metadata to import/export c structures to json strings and back. A python script takes care of parsing the annotated header and generating new headers and metadata initializers. The jstruct library uses https://github.com/json-c/json-c internally. I have also noticed https://github.com/marel-keytech... but that was after writing the entire thing. (and info on that project's page is sparse)
There's no support yet for annotating a single struct from an existing system lib but you could wrap the tm
struct in an annotated custom struct. (I think?)
Feel free to add features requests or even pull requests if you have ideas that would make the library more useful to you. One idea I had would be to add a way to embed that kind of read only struct inside an annotated wrapper with a @inline
annotation: eg (currently unsupported but could be added)
//@json
struct my_time {
//@inline
struct tm tm;
}
Code:
struct my_time t;
mktime(&t.tm);
struct json_object *result = jstruct_export(t, my_time);
In the mean time you could do the same thing without @inline
(since it hasn't been written yet) and just extract the tm property by hand with json_object_to_json_string(json_object_object_get(result, "tm"))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With