jansson/doc/github_commits.c

181 lines
4.6 KiB
C
Raw Normal View History

/*
2016-09-18 19:17:03 +08:00
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
2009-10-17 19:18:40 +08:00
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
2019-10-17 14:08:51 +08:00
#include <jansson.h>
2009-10-17 19:18:40 +08:00
2019-10-17 14:08:51 +08:00
#define BUFFER_SIZE (256 * 1024) /* 256 KB */
2009-10-17 19:18:40 +08:00
2019-10-17 14:08:51 +08:00
#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
#define URL_SIZE 256
2009-10-17 19:18:40 +08:00
/* Return the offset of the first newline in text or the length of
text if there's no newline */
2019-10-17 14:08:51 +08:00
static int newline_offset(const char *text) {
2009-10-17 19:18:40 +08:00
const char *newline = strchr(text, '\n');
2019-10-17 14:08:51 +08:00
if (!newline)
2009-10-17 19:18:40 +08:00
return strlen(text);
else
return (int)(newline - text);
}
2019-10-17 14:08:51 +08:00
struct write_result {
2009-10-17 19:18:40 +08:00
char *data;
int pos;
};
static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) {
2009-10-17 19:18:40 +08:00
struct write_result *result = (struct write_result *)stream;
2019-10-17 14:08:51 +08:00
if (result->pos + size * nmemb >= BUFFER_SIZE - 1) {
2009-10-17 19:18:40 +08:00
fprintf(stderr, "error: too small buffer\n");
return 0;
}
memcpy(result->data + result->pos, ptr, size * nmemb);
result->pos += size * nmemb;
return size * nmemb;
}
2019-10-17 14:08:51 +08:00
static char *request(const char *url) {
CURL *curl = NULL;
2009-10-17 19:18:40 +08:00
CURLcode status;
struct curl_slist *headers = NULL;
char *data = NULL;
2009-10-17 19:18:40 +08:00
long code;
curl_global_init(CURL_GLOBAL_ALL);
2009-10-17 19:18:40 +08:00
curl = curl_easy_init();
2019-10-17 14:08:51 +08:00
if (!curl)
goto error;
2009-10-17 19:18:40 +08:00
data = malloc(BUFFER_SIZE);
2019-10-17 14:08:51 +08:00
if (!data)
goto error;
2009-10-17 19:18:40 +08:00
2019-10-17 14:08:51 +08:00
struct write_result write_result = {.data = data, .pos = 0};
2009-10-17 19:18:40 +08:00
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);
2009-10-17 19:18:40 +08:00
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result);
status = curl_easy_perform(curl);
2019-10-17 14:08:51 +08:00
if (status != 0) {
2009-10-17 19:18:40 +08:00
fprintf(stderr, "error: unable to request data from %s:\n", url);
fprintf(stderr, "%s\n", curl_easy_strerror(status));
goto error;
2009-10-17 19:18:40 +08:00
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
2019-10-17 14:08:51 +08:00
if (code != 200) {
2009-10-17 19:18:40 +08:00
fprintf(stderr, "error: server responded with code %ld\n", code);
goto error;
2009-10-17 19:18:40 +08:00
}
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
2009-10-17 19:18:40 +08:00
curl_global_cleanup();
/* zero-terminate the result */
data[write_result.pos] = '\0';
return data;
error:
2019-10-17 14:08:51 +08:00
if (data)
free(data);
2019-10-17 14:08:51 +08:00
if (curl)
curl_easy_cleanup(curl);
2019-10-17 14:08:51 +08:00
if (headers)
curl_slist_free_all(headers);
curl_global_cleanup();
return NULL;
2009-10-17 19:18:40 +08:00
}
2019-10-17 14:08:51 +08:00
int main(int argc, char *argv[]) {
size_t i;
2009-10-17 19:18:40 +08:00
char *text;
char url[URL_SIZE];
json_t *root;
json_error_t error;
2019-10-17 14:08:51 +08:00
if (argc != 3) {
2009-10-17 19:18:40 +08:00
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);
2019-10-17 14:08:51 +08:00
if (!text)
2009-10-17 19:18:40 +08:00
return 1;
root = json_loads(text, 0, &error);
2009-10-17 19:18:40 +08:00
free(text);
2019-10-17 14:08:51 +08:00
if (!root) {
2009-10-17 19:18:40 +08:00
fprintf(stderr, "error: on line %d: %s\n", error.line, error.text);
return 1;
}
2019-10-17 14:08:51 +08:00
if (!json_is_array(root)) {
fprintf(stderr, "error: root is not an array\n");
2013-03-10 03:15:09 +08:00
json_decref(root);
2009-10-17 19:18:40 +08:00
return 1;
}
2019-10-17 14:08:51 +08:00
for (i = 0; i < json_array_size(root); i++) {
json_t *data, *sha, *commit, *message;
2009-10-17 19:18:40 +08:00
const char *message_text;
data = json_array_get(root, i);
2019-10-17 14:08:51 +08:00
if (!json_is_object(data)) {
fprintf(stderr, "error: commit data %d is not an object\n", (int)(i + 1));
2013-03-10 03:15:09 +08:00
json_decref(root);
return 1;
}
sha = json_object_get(data, "sha");
2019-10-17 14:08:51 +08:00
if (!json_is_string(sha)) {
fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1));
2009-10-17 19:18:40 +08:00
return 1;
}
commit = json_object_get(data, "commit");
2019-10-17 14:08:51 +08:00
if (!json_is_object(commit)) {
fprintf(stderr, "error: commit %d: commit is not an object\n", (int)(i + 1));
2013-03-10 03:15:09 +08:00
json_decref(root);
2009-10-17 19:18:40 +08:00
return 1;
}
message = json_object_get(commit, "message");
2019-10-17 14:08:51 +08:00
if (!json_is_string(message)) {
fprintf(stderr, "error: commit %d: message is not a string\n", (int)(i + 1));
2013-03-10 03:15:09 +08:00
json_decref(root);
2009-10-17 19:18:40 +08:00
return 1;
}
message_text = json_string_value(message);
printf("%.8s %.*s\n", json_string_value(sha), newline_offset(message_text),
message_text);
2009-10-17 19:18:40 +08:00
}
json_decref(root);
return 0;
}