(いいんです。C言語が書きたいんです!)
でっかく記事いっぱいにコードだけ...
ちなみに、json-cというライブラリとcURLを使っています。
昨日のパッチを使えばVC6でもビルド出来ます。
よろしければどうぞ。
最新ソースはCodeReposのコノ辺におきました。
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <curl/curl.h>
#include <json.h>
#define APP_NAME "wassr_todo"
#ifdef _WIN32
# ifndef snprintf
# define snprintf _snprintf
# endif
#endif
#define TODO_MODIFY_URL "http://api.wassr.jp/todo/"
#define TODO_JSON_EXT ".json"
static char* response_cond = NULL; /* response condition */
static char* response_mime = NULL; /* response content-type. ex: "text/html" */
static char* response_data = NULL; /* response data from server. */
static size_t response_size = 0; /* response size of data */
static void initialize_http_response() {
response_cond = NULL;
response_mime = NULL;
response_data = NULL;
response_size = 0;
}
static void terminate_http_response() {
if (response_cond) free(response_cond);
if (response_mime) free(response_mime);
if (response_data) free(response_data);
response_cond = NULL;
response_mime = NULL;
response_data = NULL;
response_size = 0;
}
static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream) {
if (!response_data)
response_data = (char*)malloc(size*nmemb);
else
response_data = (char*)realloc(response_data, response_size+size*nmemb);
if (response_data) {
memcpy(response_data+response_size, ptr, size*nmemb);
response_size += size*nmemb;
}
return size*nmemb;
}
static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream) {
char* header = NULL;
header = (char*)malloc(size*nmemb + 1);
memcpy(header, ptr, size*nmemb);
header[size*nmemb] = 0;
if (strncmp(header, "Content-Type: ", 14) == 0) {
char* stop = header + 14;
stop = strpbrk(header + 14, "\r\n;");
if (stop) *stop = 0;
if (response_mime) free(response_mime);
response_mime = strdup(header + 14);
}
if (strncmp(header, "Last-Modified: ", 15) == 0) {
char* stop = strpbrk(header, "\r\n;");
if (stop) *stop = 0;
if (response_cond) free(response_cond);
response_cond = strdup(header);
}
if (strncmp(header, "ETag: ", 6) == 0) {
char* stop = strpbrk(header, "\r\n;");
if (stop) *stop = 0;
if (response_cond) free(response_cond);
response_cond = strdup(header);
}
free(header);
return size*nmemb;
}
char* get_http_data(char* url, char* user, char* pass) {
CURLcode res;
CURL* curl;
char* ret = NULL;
int status = 0;
char auth[512];
initialize_http_response();
memset(auth, 0, sizeof(auth));
snprintf(auth, sizeof(auth)-1, "%s:%s", user, pass);
curl = curl_easy_init();
if (!curl) return NULL;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, APP_NAME);
res = curl_easy_perform(curl);
res = res == CURLE_OK ? curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &status) : res;
curl_easy_cleanup(curl);
if (res == CURLE_OK && status == 200) {
ret = (char*)malloc(response_size+1);
memset(ret, 0, response_size+1);
memcpy(ret, (char*)response_data, response_size);
}
terminate_http_response();
return ret;
}
char* post_http_data(char* url, char* user, char* pass, char* data) {
CURLcode res;
CURL* curl;
char* ret = NULL;
int status = 0;
char auth[512];
initialize_http_response();
memset(auth, 0, sizeof(auth));
snprintf(auth, sizeof(auth)-1, "%s:%s", user, pass);
curl = curl_easy_init();
if (!curl) return NULL;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, APP_NAME);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void*)data);
res = curl_easy_perform(curl);
res = res == CURLE_OK ? curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &status) : res;
curl_easy_cleanup(curl);
if (res == CURLE_OK && status == 200) {
ret = (char*)malloc(response_size+1);
memset(ret, 0, response_size+1);
memcpy(ret, (char*)response_data, response_size);
}
terminate_http_response();
return ret;
}
char* string_to_utf8_alloc(const char* str) {
if (!str) return NULL;
#ifdef WIN32
UINT codePage;
size_t in_len = strlen(str);
codePage = GetACP();
size_t wcssize = MultiByteToWideChar(codePage, 0, str, in_len, NULL, 0);
wchar_t* pszStrWC = (wchar_t*)malloc(sizeof(wchar_t)*(wcssize + 1));
wcssize = MultiByteToWideChar(codePage, 0, str, in_len, pszStrWC, wcssize + 1);
pszStrWC[wcssize] = '\0';
codePage = CP_UTF8;
size_t mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, NULL, 0, NULL, NULL);
char* pszStrMB = (char*)malloc(mbssize + 1);
mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, pszStrMB, mbssize, NULL, NULL);
pszStrMB[mbssize] = '\0';
free(pszStrWC);
return pszStrMB;
#else
return strdup(str);
#endif
}
char* utf8_to_string_alloc(const char* str) {
if (!str) return NULL;
#ifdef WIN32
UINT codePage = CP_UTF8;
const char* ptr = str;
if (str[0] == (char)0xef && str[1] == (char)0xbb && str[2] == (char)0xbf)
ptr += 3;
size_t wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, NULL, 0);
wchar_t* pszStrWC = (wchar_t*)malloc(sizeof(wchar_t)*(wcssize + 1));
wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, pszStrWC, wcssize + 1);
pszStrWC[wcssize] = '\0';
codePage = GetACP();
size_t mbssize = WideCharToMultiByte(codePage, 0, pszStrWC,-1, NULL, 0, NULL, NULL);
char* pszStrMB = (char*)malloc(mbssize + 1);
mbssize = WideCharToMultiByte(codePage, 0, pszStrWC, -1, pszStrMB, mbssize, NULL, NULL);
pszStrMB[mbssize] = '\0';
free(pszStrWC);
return pszStrMB;
#else
return strdup(str);
#endif
}
static char* url_encode_alloc(const char* str) {
static const int force_encode_all = TRUE;
const char* hex = "0123456789abcdef";
char* buf = NULL;
unsigned char* pbuf = NULL;
int len = 0;
if (!str) return NULL;
len = strlen(str)*3;
buf = (char*)malloc(len+1);
memset(buf, 0, len+1);
pbuf = (unsigned char*)buf;
while(*str) {
unsigned char c = (unsigned char)*str;
if (c == ' ')
*pbuf++ = '+';
else if (c & 0x80 || force_encode_all) {
*pbuf++ = '%';
*pbuf++ = hex[c >> 4];
*pbuf++ = hex[c & 0x0f];
} else
*pbuf++ = c;
str++;
}
return buf;
}
char* add_todo(char* user, char* pass, char* body) {
int size;
char* body_utf8;
char* body_data;
char* post;
char* data;
body_utf8 = string_to_utf8_alloc(body);
if (!body_utf8) return NULL;
body_data = url_encode_alloc(body_utf8);
free(body_utf8);
size = 5 + strlen(body_data);
post = (char*)malloc(size + 1);
memset(post, 0, size + 1);
strcpy(post, "body=");
strcat(post, body_data);
free(body_data);
data = post_http_data("http://api.wassr.jp/todo/add.json", user, pass, post);
free(post);
return data;
}
char* modify_todo(char* user, char* pass, char* command, char* todo_rid) {
int size;
char* url;
char* post;
char* data;
size = 9 + strlen(todo_rid);
post = (char*)malloc(size + 1);
memset(post, 0, size + 1);
strcpy(post, "todo_rid=");
strcat(post, todo_rid);
size = strlen(TODO_MODIFY_URL) + strlen(command) + strlen(TODO_JSON_EXT);
url = (char*)malloc(size + 1);
memset(url, 0, size + 1);
strcpy(url, TODO_MODIFY_URL);
strcat(url, command);
strcat(url, TODO_JSON_EXT);
data = post_http_data(url, user, pass, post);
free(post);
free(url);
return data;
}
char* list_todo(char* user, char* pass, int done_fg) {
char* data;
if (done_fg)
data = get_http_data("http://api.wassr.jp/todo/list.json?done_fg=1", user, pass);
else
data = get_http_data("http://api.wassr.jp/todo/list.json?done_fg=0", user, pass);
if (!data) {
perror("Unknown server response(server down or invalid authenticate?)");
return NULL;
}
return data;
}
int main(int argc, char* argv[]) {
FILE* fp = NULL;
char* home = NULL;
char* user = NULL;
char* pass = NULL;
char conf[_MAX_PATH];
char buff[BUFSIZ];
char* data = NULL;
struct json_object* obj = NULL;
struct json_object* res = NULL;
int i;
home = getenv("HOME");
if (!home) home = getenv("USERPROFILE");
snprintf(conf, sizeof(conf), "%s/.wassr-todo", home);
fp = fopen(conf, "rt");
if (!fp) {
perror("404 ~/.wassr-todo NOT FOUND");
goto error;
}
while(fgets(buff, sizeof(buff), fp)) {
char *ptr = strpbrk(buff, "\r\n");
if (*ptr) *ptr = 0;
if (!strncmp(buff, "username: ", 10))
user = strdup(buff + 10);
if (!strncmp(buff, "password: ", 10))
pass = strdup(buff + 10);
}
fclose(fp);
if (argc == 1)
data = list_todo(user, pass, FALSE);
else {
if (argc == 2 && !strcmp(argv[1], "list"))
data = list_todo(user, pass, FALSE);
else
if (argc == 2 && !strcmp(argv[1], "listdone"))
data = list_todo(user, pass, TRUE);
else
if (argc == 3 && !strcmp(argv[1], "add"))
data = add_todo(user, pass, argv[2]);
else
if (argc == 3 && (
!strcmp(argv[1], "delete") ||
!strcmp(argv[1], "start") ||
!strcmp(argv[1], "stop") ||
!strcmp(argv[1], "done")))
data = modify_todo(user, pass, argv[1], argv[2]);
else {
puts("usage: wassr_todo [command] [argument]");
puts("\t* command");
puts("\t\tlist\t\tlist todo.");
puts("\t\tlistdone\tlist todo which is done.");
puts("\t\tadd [body]\tpost new todo to wassr.");
puts("\t\tdelete [rid]\tdelete the todo.");
puts("\t\tstart [rid]\tstart the todo.");
puts("\t\tstop [rid]\tstop the todo.");
puts("\t\tdone [rid]\tdone the todo.");
goto error;
}
}
if (!data) {
perror("Unknown server response(server down or invalid authenticate?)");
goto error;
}
obj = json_tokener_parse(data);
free(data);
if (is_error(obj)) {
perror("Unknown server response(not json?)");
goto error;
}
if (json_object_is_type(obj, json_type_object)) {
res = json_object_object_get(obj, "error");
if (!is_error(res)) {
char* _res = utf8_to_string_alloc(json_object_get_string(res));
if (_res) {
printf("error: %s\n", _res);
free(_res);
goto error;
}
}
res = json_object_object_get(obj, "message");
if (!is_error(res)) {
char* _res = utf8_to_string_alloc(json_object_get_string(res));
if (_res) {
printf("message: %s\n", _res);
free(_res);
}
}
}
if (json_object_is_type(obj, json_type_array)) {
for(i = 0; i < json_object_array_length(obj); i++) {
struct json_object *item = json_object_array_get_idx(obj, i);
struct json_object* todo_rid = json_object_object_get(item, "todo_rid");
struct json_object* body = json_object_object_get(item, "body");
if (!is_error(todo_rid) && !is_error(body)) {
char* _todo_rid = utf8_to_string_alloc(json_object_get_string(todo_rid));
char* _body = utf8_to_string_alloc(json_object_get_string(body));
printf("TODO-%03d [%s] %s\n", i+1, _todo_rid, _body);
free(_todo_rid);
free(_body);
}
}
} else
if (json_object_is_type(obj, json_type_object)) {
struct json_object* todo_rid = json_object_object_get(obj, "todo_rid");
if (!is_error(todo_rid)) {
char* _todo_rid = utf8_to_string_alloc(json_object_get_string(todo_rid));
if (_todo_rid) {
printf("%s\n", _todo_rid);
free(_todo_rid);
}
}
}
return 0;
error:
if (user) free(user);
if (pass) free(pass);
return -1;
}