static char *request(const char *url) { CURL *curl; CURLcode status; char *data; long code; curl = curl_easy_init(); data = malloc(BUFFER_SIZE); if(!curl || !data) return NULL; struct write_result write_result = { .data = data, .pos = 0 }; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); status = curl_easy_perform(curl); if(status != 0) { fprintf(stderr, "error: unable to request data from %s:\n", url); fprintf(stderr, "%s\n", curl_easy_strerror(status)); return NULL; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if(code != 200) { fprintf(stderr, "error: server responded with code %ld\n", code); return NULL; } curl_easy_cleanup(curl); curl_global_cleanup(); /* zero-terminate the result */ data[write_result.pos] = '\0'; return data; } int main(int argc, char *argv[]) { size_t i; char *text; char url[URL_SIZE]; json_t *root; json_error_t error; json_t *commits; if(argc != 3) { fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); return 2; } snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); text = request(url); if(!text) return 1; root = json_loads(text, 0, &error); free(text); if(!root) { fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); return 1; } commits = json_object_get(root, "commits"); if(!json_is_array(commits)) { fprintf(stderr, "error: commits is not an array\n"); return 1; } for(i = 0; i < json_array_size(commits); i++) { json_t *commit, *id, *message; const char *message_text; commit = json_array_get(commits, i); if(!json_is_object(commit)) { fprintf(stderr, "error: commit %d is not an object\n", i + 1); return 1; } id = json_object_get(commit, "id"); if(!json_is_string(id)) { fprintf(stderr, "error: commit %d: id is not a string\n", i + 1); return 1; } message = json_object_get(commit, "message"); if(!json_is_string(message)) { fprintf(stderr, "error: commit %d: message is not a string\n", i + 1); return 1; } message_text = json_string_value(message); printf("%.8s %.*s\n", json_string_value(id), newline_offset(message_text), message_text); } json_decref(root); return 0; }
static char *request(const char *url) { CURL *curl = NULL; CURLcode status; struct curl_slist *headers = NULL; char *data = NULL; long code; curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if (!curl) { goto error; } data = malloc(BUFFER_SIZE); if (!data) { goto error; } struct write_result write_result = { .data = data, .pos = 0 }; curl_easy_setopt(curl, CURLOPT_URL, url); /* GitHub commits API v3 requires a User-Agent header */ headers = curl_slist_append(headers, "User-Agent: Jansson-Tutorial"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); status = curl_easy_perform(curl); if (status != 0) { fprintf(stderr, "error: unable to request data from %s:\n", url); fprintf(stderr, "%s\n", curl_easy_strerror(status)); goto error; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if (code != 200) { fprintf(stderr, "error: server responded with code %ld\n", code); goto error; } curl_easy_cleanup(curl); curl_slist_free_all(headers); curl_global_cleanup(); /* zero-terminate the result */ data[write_result.pos] = '\0'; return data; error: if (data) { free(data); } if (curl) { curl_easy_cleanup(curl); } if (headers) { curl_slist_free_all(headers); } curl_global_cleanup(); return NULL; } int main(int argc, char *argv[]) { size_t i; char *text; char url[URL_SIZE]; json_t *root; json_error_t error; if (argc != 3) { fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); return 2; } snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); printf("Query url: %s\n", url); text = request(url); if (!text) { return 1; } root = json_loads(text, 0, &error); free(text); if (!root) { fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); return 1; } if (!json_is_array(root)) { fprintf(stderr, "error: root is not an array\n"); json_decref(root); return 1; } for (i = 0; i < json_array_size(root); i++) { json_t *data, *sha, *commit, *message; const char *message_text; data = json_array_get(root, i); if (!json_is_object(data)) { fprintf(stderr, "error: commit data %d is not an object\n", (int) (i + 1)); json_decref(root); return 1; } sha = json_object_get(data, "sha"); if (!json_is_string(sha)) { fprintf(stderr, "error: commit %d: sha is not a string\n", (int) (i + 1)); return 1; } commit = json_object_get(data, "commit"); if (!json_is_object(commit)) { fprintf(stderr, "error: commit %d: commit is not an object\n", (int) (i + 1)); json_decref(root); return 1; } message = json_object_get(commit, "message"); if (!json_is_string(message)) { fprintf(stderr, "error: commit %d: message is not a string\n", (int) (i + 1)); json_decref(root); return 1; } message_text = json_string_value(message); printf("%.8s %.*s\n", json_string_value(sha), newline_offset(message_text), message_text); } json_decref(root); return 0; }