こちらの記事を参考にして、C言語からlibcurlを使ってHTTP GETするコードを書いて動かしてみました。
"cURL と libcurl を使ってインターネット経由でやりとりする"

さて取得したHTTP Bodyを変数に格納するためにコールバックを使うのですが、コールバックの中身が思ったよりも複雑になっていたので、その理由を調べてみました。

C言語+libcurlだとなぜこんな複雑になるの?

PHPだと $content = file_get_contents($url); みたいなのでいけるのに、C言語+libcurlだとなぜこんな複雑になるのだろう?
ひょっとして、このコールバックは1回のRequest内で複数呼ばれるのではないか?と思って 標準エラー出力にログを吐いてみたら(fprintfのところ)、やはりそうでした。

1回のリクエストで17回もコールバックが呼ばれてしました。
LTSVのログビューワーltsview (http://d.hatena.ne.jp/naoya/20130207/1360229220) のC言語版を作りました。

ソースコードはGithubにおいてあります。
https://github.com/DQNEO/c-ltsview

やる前は難しそうだと思っていたのですが、書いてみたら意外と簡単で、100行ほどでできました。
こんな感じです。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUF_MAX 10240
#define KEYS_MAX 100

struct item {
    char *key;
    char *value;
};

void parse_item(struct item *item, char *key_value);
int in_array(char *s, char **strings);

int main(int argc, char **argv)
{
    char *keys[KEYS_MAX];
    memset(keys, 0, sizeof(keys));
    int i;
    char *concate_keys;

    /* parse -k options */
    if (argc >= 2 && strcmp(argv[1],"-k") == 0) {
	if (argc == 2) {
	    fprintf(stderr, "no argument for -k option\n");
	    exit(1);
	}

	concate_keys = argv[2];

	keys[0] = strtok(concate_keys, ",");
	if (keys[0] != NULL) {
	    i = 1;
	    while((keys[i] = strtok(NULL, ",")) != NULL) {
		i++;
	    }
	}
    }

    char buf[BUF_MAX];
    struct item items[KEYS_MAX];
    char *tab;
    char *tmp;
    char *newline;

    while (fgets(buf, BUF_MAX, stdin) != NULL) {
	printf("=========\n");

	if (buf[BUF_MAX -2] != '\0') {
	    fprintf(stderr, "buffer over run!\n");
	    return 1;
	}

	tmp = buf;
	i = 0;
	memset(items,0, sizeof(items)); // is this right?
	while ((tab = strchr(tmp, '\t')) != NULL ) {
	    *tab = '\0';
	    parse_item(&items[i++], tmp);
	    tmp = tab + 1;
	}
	newline = strchr(tmp, '\n');
	*newline = '\0';
	parse_item(&items[i], tmp);

	for (i = 0;items[i].key != NULL;i++) {
	    if (keys[0] != NULL && ! in_array(items[i].key, keys)) {
		continue;
	    }
	    printf("%s: %s\n", items[i].key, items[i].value);
	}
    }

    return 0;
}

void parse_item(struct item *item, char *key_value)
{
    char *colon;
    colon = strchr(key_value, ':');
    if (colon == NULL) {
	fprintf(stderr, "invalid format:[%s]", key_value);
	exit(1);
    }
    *colon = '\0';
    item->key = key_value;
    item->value = colon + 1;
}

int in_array(char *s, char **strings)
{
    int j;
    for (j = 0; strings[j] != NULL; j++) {
	if (strcmp(s, strings[j]) == 0) {
	    return 1;  // found
	}
    }

    return 0; // not found
}
C言語はまだほんのド素人なので、この書き方はおかしいなどありましたらPull Requestをお待ちしております。
Githubでレポジトリを作って.mdファイルベースでドキュメント管理する場合、文書間のリンクで相対パス指定ができます。

これを知らずに絶対パスを書いてしまってるケースが非常に多いです。
身の回りでみかけたら教えてあげましょう。

どういうこと?

例えば、
https://github.com/DQNEO/memo
というレポジトリがあったとして、
README.md から AboutMe.md にリンクを貼りたいとします。

このときREADME.mdにリンクを書くわけですが、やり方が2つあります。
絶対パス指定
[AboutMe](https://github.com/DQNEO/memo/blob/master/AboutMe.md)
相対パス指定
[AboutMe](/AboutMe.md)

絶対パスで書いたらなぜダメなのか

ウェブサイトを運営したことがある人ならすぐわかるかと思います。
  • レポジトリの名前が変わったとき
  • forkして所有者の名前が変わったとき
に、URLを全部書きなおさないといけなくなります。

よいみほん

https://github.com/DQNEO/memo/blob/master/README.md
相対パスの方が短いし、これを使わない手はないでしょう。

C言語でlsを実装してみた

このエントリーをはてなブックマークに追加
C言語で何か書きたいと思って、lsコマンドの簡易版を実装してみました。

今回新しい試みとして一切ぐぐらずにやってみたら、意外とあっさりできました。
man 3 opendir
man 3 readdir
とmanを見るだけで必要な情報は得られました。

ソースコードはGithubにも置いておきますのでご自由にお使いください。
https://github.com/DQNEO/c-ls
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>

/**
 * 実行方法: gcc ls.c && ./a.out /tmp
 */
int main(int argc, char *argv[])
{
    DIR *dir;
    struct dirent *ent;
    char dirname[256];

    if (argc == 1) {
        strcpy(dirname, ".");
    } else {
        strcpy(dirname, argv[1]);
    }

    dir = opendir(dirname);
    if (dir == NULL) {
        fprintf(stderr, "unable to opendir %s\n", dirname);
        return 1;
    }

    while ((ent = readdir(dir)) != NULL) {
        if (ent->d_name[0] == '.') {
            continue;
        }

        printf("%s  ", ent->d_name);
    }
    printf("\n");

    closedir(dir);
    return 0;
}
エラー処理とかがちょと甘いかもしれません。
ご利用は自己責任でお願いします。
Mac OSX (mavericks) でPerlを使うとこんな警告が出ました。
$ perl -v
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
        LC_ALL = "ja_JP.utf8",
        LC_CTYPE = "ja_JP.utf8",
        LANG = "ja_JP.utf8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

This is perl 5, version 20, subversion 0 (v5.20.0) built for darwin-2level

原因と解決法

どうも、"ja_JP.utf8"という文字列が正しくなかったようです。
正しくは"ja_JP.UTF-8"のようです。
export LANG=ja_JP.UTF-8
export LC_ALL=ja_JP.UTF-8
と設定したら警告が消えました。

"utf8"だとなぜダメなの?

こちらの記事に詳しい解説があります。
ja_JP.UTF-8 vs ja_JP.utf8
brew install awscli
べんり!!

最新の開発版をインストルしたい場合はこう
brew install awscli --HEAD
参考

[Emacs]空行を一気に消す方法

このエントリーをはてなブックマークに追加
M-x flush-lines
で、
正規表現 ^$

[PHP]日付の連番を生成する方法

このエントリーをはてなブックマークに追加
for文を使って日付の連番を生成してみたらできました。

例:直近の過去1ヶ月分の日付を生成する

<?php

for ($d = (new DateTime())->modify('-1 month'); $d <= new DateTime(); $d->modify('+1 day')) {
    echo $d->format('Y-m-d'),"\n";
}
実行結果
2014-05-13
2014-05-14
2014-05-15
2014-05-16
2014-05-17
2014-05-18
...
[中略]
...
2014-06-12
2014-06-13
べんり!

準備

あらかじめgitをインストールしておきます。 gitのインストール方法は割愛します。

plenvとperl5.20とcpanmを一気にインストール

一般ユーザでログインして下記のようにします。
# plenvを取得
git clone git://github.com/tokuhirom/plenv.git ~/.plenv/

# Perl-Buildを取得
git clone git://github.com/tokuhirom/Perl-Build.git ~/.plenv/plugins/perl-build/

# パス設定など 
# (zshをお使いの場合は .bashrcのかわりに.zshrc)
echo 'export PATH=~/.plenv/bin:$PATH' >> ~/.bashrc
echo 'eval "$(plenv init -)"' >> ~/.bashrc

# シェルにログインしなおす
exec $SHELL -l

# インストール可能なバージョンを確認
plenv install --list

# v5.20.0をインストールするならこんな感じで
plenv install 5.20.0
plenv global 5.20.0
plenv rehash

# cpanmをインストール
plenv install-cpanm
plenv rehash

# 試しにAcme::Nyaaをインストールしてみましょう。
cpanm Acme::Nyaa
※MacOSXならHomebrewで入れる方法もあるようですが、私はこのやり方の方がLinux/Macで手法を統一できるので好みです。

動作確認

$ perl -MAcme::Nyaa -e 'print Acme::Nyaa->new->cat("こんにちわ\n");'
こんにちわニャーーーー!
完了です!!
⌘-w で iTerm2 が閉じてしまうと泣きたくなりますよね。
私はEmacsを使ってるときにalt-wを押そうとして⌘-wを押してしまう事故が毎日発生して、涙に明け暮れていました。
んがっそれも今日までです。

iTerm2の設定を変更してこのキーを無効にしてしまいましょう。

Preferences > Keys > Glocal Shortcut Keys
で "+"をクリックして
⌘w をAction: ignore に設定してあげればOKです。
購読する

最近の人気記事

人気記事