I'm trying to develop an application in C with GTK for the GUI, libcurl to get data by a web API and cJSON to parse JSON.
My problem is that when I do my request with libcurl after gtk_init, the data that I get can not be parsing in JSON. Otherwise, if I get the data and parse it before gtk_init, the parsing works fine.
I have an example to demonstrate it, the first printf in the main returns the JSON correctly but the second printf which is after gtk_init returns NULL (to be exact, the parsing stops at the first decimal number and fail) :
initString :
void initString(String * s) {
s->len = 0;
s->ptr = malloc(s->len + 1);
if (s->ptr == NULL) {
fprintf(stderr, "malloc() failed\n");
exit(EXIT_FAILURE);
}
s->ptr[0] = '\0';
}
writeFunc :
size_t writeFunc(void *ptr, size_t size, size_t nmemb, String * s)
{
size_t newLen = s->len + size*nmemb;
s->ptr = realloc(s->ptr, newLen + 1);
if (s->ptr == NULL) {
fprintf(stderr, "realloc() failed\n");
exit(EXIT_FAILURE);
}
memcpy(s->ptr + s->len, ptr, size * nmemb);
s->ptr[newLen] = '\0';
s->len = newLen;
return size * nmemb;
}
My function to get data with libcurl :
char * getData(gpointer user_data)
{
curl_global_init(CURL_GLOBAL_ALL);
CURL * curl;
char * url = user_data;
CURLcode res;
String s;
struct curl_slist * headers = NULL;
curl = curl_easy_init();
if(curl)
{
initString(&s);
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8");
//curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_easy_setopt(curl, CURLOPT_SSLVERSION, 6);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
//write data in a string
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
res = curl_easy_perform(curl);
}
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return s.ptr;
}
The main :
int main(int argc, char ** argv)
{
char * str;
cJSON * json;
str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("DATA : %s\n", cJSON_Print(json));//returns the JSON perfectly
gtk_init(&argc,&argv);
str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("ERROR : %s\n", cJSON_GetErrorPtr());//returns half of data
printf("DATA : %s\n", cJSON_Print(json));//returns NULL
gtk_main();
curl_global_cleanup();
return EXIT_SUCCESS;
}
I have tried to resolve this by creating threads with g_idle_add, gdk_threads_idle_add, gdk_threads_entry and gdk_threads_leave, pthread_create and pthread_join but nothing worked.
Does someone know how to resolve this problem ?
Thanks.
You need to narrow down your problem. In other words, you need "M" in MVCE. Currently you have three libraries:
that might interact in arbitrary ways. What you need to check:
Does cURL return different data before and after gtk_init
call? If no, then problem is not with cURL.
If you hardcode JSON data in your program and parse it with cJSON, are results different before and after gtk_init
? If so, problem is in cJSON. If no, problem is not related to cJSON.
My guess is as follows. gtk_init
does several things, amongst them sets locale. Since you fetch data from .fr
domain, I assume that you have French locale set on your computer.
to be exact, the parsing stops at the first decimal number and fail
In French, decimal separator is comma ,
instead of period .
, so I suppose that after GTK+ changes locale, cJSON starts to look for ,
in decimal numbers but it finds .
and fails.
As a workaround, call gtk_disable_setlocale
before gtk_init
. This might cause unintended consequences, eg. your program starts to display numbers in English format instead of French in its UI.
The real solution would be to raise bug in cJSON, as JSON parsing should not take locale into account when parsing numbers. JSON mandates period .
as decimal separator.