2013年2月27日水曜日

[TeX]数式文字列を png ファイルにして出力する

dvipng コマンドを使って TeX から作成した dvi ファイルを png に変換する
\documentclass[11pt,a4paper]{report}
\pagestyle{empty}
\begin{document}
$y = 2x$
\end{document}
ページ番号が入ると数式のみの出力とならないので \pagestyle{empty} を付ける

実行手順
$ platex y_2x.tex
This is pTeXk, Version 3.141592-p3.1.10 (euc) (Web2C 7.5.6)
 %&-line parsing enabled.
(./y_2x.tex
pLaTeX2e <2006/11/10>+0 (based on LaTeX2e <2005/12/01> patch level 0)
(/usr/share/texmf/tex/latex/base/report.cls
Document Class: report 2005/09/16 v1.4f Standard LaTeX document class
(/usr/share/texmf/tex/latex/base/size11.clo)) (./y_2x.aux) [1] (./y_2x.aux) )
Output written on y_2x.dvi (1 page, 260 bytes).
Transcript written on y_2x.log.

$ dvipng y_2x.dvi -T tight -o y_2x.png
This is dvipng 1.13 Copyright 2002-2010 Jan-Ake Larsson
[1] 
dvipng に -T tight オプションを渡すことで余白を削除して出力できる

出力結果


サイズを変更する
数式のサイズを変更する場合は
\documentclass[11pt,a4paper]{jsarticle}
\pagestyle{empty}
\begin{document}
$y = 2x$
\end{document}
出力手順
$ platex y_2xhuge.tex
$ dvipng y_2xhuge.dvi -T tight -o y_2xhuge.png
出力結果

[TeX]Command

フォーマット
\newcommand{\commandname}[number of arguments]{command text, using #1, #2 etc to denote arguments}
コマンド定義例
\RequirePackage{ifthen}
\newcommand{\weekday}[1]{%
  \ifthenelse{\equal{#1}{1}}{Monday}{}%
  \ifthenelse{\equal{#1}{2}}{Tuesday}{}%
  \ifthenelse{\equal{#1}{3}}{Wednesday}{}%
  \ifthenelse{\equal{#1}{4}}{Thursday}{}%
  \ifthenelse{\equal{#1}{5}}{Friday}{}%
  \ifthenelse{\equal{#1}{6}}{Saturday}{}%
  \ifthenelse{\equal{#1}{7}}{Sunday}{}%
}
tex ファイル中での使い方
weekday command: \weekday{3}\\

[TeX]行間

Section 前の行間を詰める
beforesection というコマンドを追加し、引数で詰める行間の幅 (上行との行間を縮める) を指定する
\documentclass[a4paper,9pt]{jsarticle}
\newcommand{\beforesection}[1]{
 \vspace{-#1mm}
}

\begin{document}
\section{第1章タイトル}
\noindent
第1章本文 \\

\section{第2章タイトル}
\noindent
第2章本文 \\

\beforesection{13}
\section{第3章タイトル -13mm}
\noindent
第3章本文 \\

\beforesection{8}
\section{第4章タイトル -8mm}
\noindent
第4章本文 \\

\end{document}
出力結果では 2 章の本文と 3 章のタイトルが行間を詰めて表示される。

部分的に行間を変える
minilinespace という環境を準備し、そこで囲まれている箇所は行間 3mm となるようにしている。
\documentclass[a4paper,9pt]{jsarticle}

\newenvironment{minilinespace}{
 \baselineskip = 3.0mm
}

\begin{document}
\noindent
ほげほげ \\
ほげほげ \\
ほげほげ \\ \\

\begin{minilinespace}
\noindent
ほげほげ ここから行間 3.0mm \\
ほげほげ \\
ほげほげ ここまで行間 3.0mm \\ \\
\end{minilinespace}

\noindent
ほげほげ \\
ほげほげ \\
ほげほげ \\

\end{document}
出力結果

[TeX] 途中で縦置き・横置きを変更する

文章の途中で用紙の縦置き・横置きを変更するには lscape パッケージを使用する。
\documentclass[a6paper,9pt]{jsarticle}
\usepackage{lscape}
\usepackage{fancyhdr}
\pagestyle{fancy}

% ヘッダ・フッターの定義
\chead{lscape の使い方}
\cfoot{\thepage}

\begin{document}
1 ページ目 (縦置き)\\
\newpage

\begin{landscape}
2 ページ目 (横置き)\\
\newpage

3 ページ目 (横置き)\\
\newpage
\end{landscape}

4 ページ目 (縦置き)\\
\newpage

5 ページ目 (縦置き)
\end{document}
  • 最初に lscape パッケージを使用することを宣言し、横置きにしたい箇所 (ページ) を \begin{landscape} 〜 \end{landscape} で囲む。
  • Header, Footer (ページ番号など) は全て同じとなるため、上記の例では用紙縦置き方向の上下に配置される。
出力結果

[TeX]Header, Footer

\documentclass[a6paper,9pt]{jsarticle}
\usepackage{fancyhdr}
\pagestyle{fancy}

% ヘッダー・フッターの定義
\chead{ヘッダー・フッターテスト}
\cfoot{\thepage}

\begin{document}
\section{第一頁}
このページは 1 ページ目です。
\newpage

\section{第二頁}
このページは 2 ページ目です。

\end{document}
出力結果

[TeX]dvipdfm で紙サイズを指定して出力する

p オプションで出力紙サイズを指定できる
-p papersize Set papersize (letter, legal, ledger, tabloid, a6, a5, a4, a3, b6, b5, b4, b3, or b5var) [a4]
> dvipdfm -p a6 test.dvi

[TeX]Fedora で PNG 埋め込みの PDF を作成する

ebb コマンドの代わりにに ebbx、dvipdfm コマンドの代わりに dvipdfmx を使う
  1. ebbx コマンドで png ファイルから bbファイルを作成
  2. platex コマンドで tex ファイルから dvi ファイルを作成
  3. dvipdfmx コマンドで dvi ファイルから pdf ファイルを作成
    $ ebbx test.png
    $ platex test.tex
    $ dvipdfmx test.dvi
    test.dvi -> test.pdf
    

[TeX]png 画像を埋め込む

以下の手順で PDF ファイルに出力した時に png 画像を埋め込むことができる。
  1. dvipdfm パッケージを使用して tex ファイルを作成する
  2. ebb コマンドで png ファイルから bb ファイルを作成する
  3. platex コマンドで tex ファイルから dvi ファイルを作成する
  4. dvipdfm コマンドで dvi ファイルから pdf ファイルを作成する
具体例は次のようになる。
  1. dfipdfm パッケージを本文前に記載した tex ファイルを作成する。画像を貼り付ける場所にはpngファイルを指定している
    \documentclass[a4paper,9pt]{jsarticle}
    \usepackage[dvipdfm]{graphicx,color}
    \begin{document}
    
    \section{png 画像貼り付け}
    ここに png 画像を貼り付けたい。\\
    \begin{figure}[htbp]
     \begin{center}
     \includegraphics[width=5cm,clip]{cat.png}
     \end{center}
     \caption{テスト図}
    \end{figure}
    
    \end{document}
    
  2. ebb コマンドの引数に埋め込みたい png ファイルを指定して、bb ファイルを作成する
    >ebb cat.png
    
    ebb コマンドは指定の画像ファイルから BoundingBox 情報 (bb ファイル)を作成するもの。BoundingBox 情報とは画像の縦横幅と原点を指定したものである
    上記コマンドを実行して生成された cat.bb ファイル
    %%Title: ./cat.png
    %%Creator: extractbb Version 0.2
    %%BoundingBox: 0 0 175 180
    %%CreationDate: Tue Jul 21 10:44:00 2009
    
  3. platex コマンドで dvi ファイルを作成する。
    > platex png_image.tex
    
    これで、png_image.dvi ファイルが作成される。DVIファイルを見ても画像位置は確保されているが、画像は埋め込まれていない。BoundingBox情報があるので、画像を配 置すべき領域は確保することができる。
  4. dvipdfm コマンドで PDF ファイルを作成する。
    > dvipdfm png_image.dvi
    png_image.dvi -> png_image.pdf
    [1(c:/home/tex/test/cat.png)]
    138768 bytes written
    
    これで指定した cat.png ファイルが埋め込まれる。作成された PDF ファイルを見ると指定した画像が埋め込まれている。

[TeX]値・長さの設定と表示

newcounter と newlength を使用して値 (カウンタ) と長さの設定を行う。
値の表示には\arabic, \theを使用する。
\documentclass[9pt,a4paper]{jsarticle}

% 値の代入
\newcounter{count}
\setcounter{count}{6}

% length の代入
\newlength{\mylength}
\setlength{\mylength}{1mm}

\begin{document}
\noindent
値の表示 \\
count = \arabic{count} \\

\noindent
length の表示 \\
paperwidth = \the\paperwidth \\
paperheight = \the\paperheight \\
textwidth = \the\textwidth \\
textheight = \the\textheight \\
1mm = \the\mylength \\

\end{document}
表示結果

[TeX]レイアウト調整

preamble に以下を記述することでテキストの領域を広げることができる。
% 上・左の幅調整
\topmargin=-10.0mm
\oddsidemargin=-10.0mm
\evensidemargin=-10.0mm

% テキスト領域の縦横長
\textheight=236.2mm
\textwidth=179.2mm

% 行間を通常の 0.8 倍に
\renewcommand{\baselinestretch}{0.8}

[TeX]DVI からPDF への変換

dvipdfmx コマンドで dvi から pdf への変換ができる。 以下のコマンドを実行すると hoge.pdf が生成される。
$ dvipdfmx hoge.dvi

[TeX]タイトル、著者表記を自前で用意する

デフォルトの maketitleを使用すると著者や日付表示がページ中央に配置されてしまう。
右寄せして著者・日付表記をしたい場合は自前で記述する方法がある。
\begin{center}
 {\Large タイトル} % title
\end{center}
\begin{flushright}
 \today \\ % date
 {\large 所属\\名前} % author
\end{flushright}

[TeX]ページ番号を表示しない

preamble に以下を追加する。
\pagestyle{empty} % ページ番号なし

Windows の Java アプリケーションでメニューバー等のフォントが汚い

  • OpenOffice など Java で動作するアプリケーションのメニューバー等で使用される日本語フォント表示が汚い場合がある
  • 原因は判明していないがこのフォントを直すことができたのでメモしておく
    1. デスクトップを右クリック → プロパティ で「画面のプロパティ」を開く
    2. デザインタブにある「フォント サイズ」を一度変更する (この PC では「標準」になっていたので「大」に変更した)
    3. フォントサイズが切り替わったら元の設定に戻す (「大」から「標準」に戻す)
    4. Java で動作するアプリのメニューバーのフォントがきれいに表示されていれば成功

Redmine + Subversion

  1. Subversion 1.6.1-2 をインストール
  2. Redmine に管理者権限でログインし各プロジェクトの [管理] → [設定] → [リポジトリ] で以下の設定を行う。
    • SCM - Subversion
    • URL - file://localhost/c:/...
    • Login - Subversion repository にログインするユーザ名
    • Password - Subversion repository にログインするパスワード

W3C Markup Validation をローカルに構築する

以下に Windows + Apache での W3C Markup Validation のインストール方法を記述する。
  1. Source code availability for the W3C Markup Validator から validator と collection of DTDs をダウンロードする
  2. ダウンロードした validator.tar.gz と sgml-lib.tar.gz を解凍すると validator-x.x.x というディレクトリが生成される。これを validator に改名して htdocs 以下に移動する
  3. validator/httpd/cgi-bin/check の以下の箇所を変更する
    • 1 行目
      perl.exe のあるディレクトリに変更
      変更前
      #!/usr/bin/perl -T
      
      変更後
      #!c:/usr/perl/bin/perl.exe
      
    • 107 行目
      Config ファイルを指定する箇所を直接指定に書き換える
      変更前
      -ConfigFile => ($ENV{W3C_VALIDATOR_CFG} || '/etc/w3c/validator.conf'),
      
      変更後
      # -ConfigFile => ($ENV{W3C_VALIDATOR_CFG} || '/etc/w3c/validator.conf'),
      -ConfigFile => '(validator を配置したディレクトリ)/validator/htdocs/config/validator.conf',
      
    • 120 行目
      Base ディレクトリを指定する箇所を直接指定に書き換える
      変更前
      Base => ($ENV{W3C_VALIDATOR_HOME} || '/usr/local/validator'),
      
      変更後
      # Base => ($ENV{W3C_VALIDATOR_HOME} || '/usr/local/validator'),
      Base => '(validator を配置したディレクトリ)',
      
  4. Apache 経由でスクリプトが実行できることを確認する。以下の URL にアクセスして確認ができる。
    http://localhost/validator/htdocs/check
  5. ここで perl module が不足しているとエラー表示されるので、必要なものを順次インストールしていく。
    Installation Documentation for The W3C Markup Validation Service (Windows, Apache) の "Needed programs and other prerequisites" に必要なモジュールが zip パッケージで置いてあるのでこれを利用するとよい。
    1. ダウンロードしたファイルを展開し c:\temp の下に置く
    2. c:\temp\ppm ディレクトリに移動し次のコマンドを実行することでローカルにあるモジュールのインストールができる
      ppm install SGML-Parser-OpenSP.ppd
      
    3. インストールが必要だったモジュール
      ppm install Config-General
      ppm install HTML-Encoding
      ppm install HTML-Template
      ppm install Encode-HanExtra
      ppm install Encode-JIS2K
      ppm install SGML-Parser-OpenSP
      ppm install XML-LibXML
      ppm install Net-IP
      
  6. httpd.conf に以下を追加して apache の設定を変更する
    ScriptAlias /cgi-bin "C:\usr\xampp\htdocs\validator\cgi-bin"
    ScriptAlias /validator/htdocs/check "C:\usr\xampp\htdocs\validator\httpd\cgi-bin\check"
    <Directory "C:\usr\xampp\htdocs\validator\htdocs">
        Options ExecCGI Includes Indexes MultiViews
        AllowOverride None
        Order deny,allow
        Allow from localhost
    </Directory>
    
  7. validator/htdocs/config/validator.conf の以下の箇所を変更して localhost からのチェックも行えるようにする
    Allow Private IPs = yes
    

参照: Installation Documentation for The W3C Markup Validation Service (Windows, Apache)

a2ps for Windows

インストール
  1. A2Ps for Windows から Binaries をダウンロード
  2. ダウンロードしたファイルを解凍し、msys ディレクトリ以下に移動
  3. a2ps.exe を実行すると libintl3.dll, libiconv2.dll, libpaper1.dll が見つからないというエラーが出るので、GnuWin - Browse Files at SourceForge.net から該当のライブラリをダウンロードする。(libintl-0.14.4-bin.zip, libiconv-1.9.2-1-bin.zip, libpaper-1.1.21-bin.zip)
  4. ダウンロードしたファイルを解凍し、msys ディレクトリ以下に移動

使用方法
a2ps.exe でテキストファイルを ps に変換し、gsview で表示する
> a2ps.exe test.txt -o test.ps
> gsview32.exe test.ps

[XAMPP]XAMPP + Python for Windows

現在 mod_python は not active developemtn となっている (2011/05/19)
mod_python の代替として mod_wsgi がある modwsgi - Python WSGI adapter module for Apache
  1. Mod_python Apache/Python Integration から Windows 用 mod_python (mod_python-3.3.1.win32-py2.5-Apache2.2.exe) をダウンロードする
  2. ダウンロードしたファイルをインストールする
  3. Apache の設定 (xampp/apache/conf/httpd.conf) を変更する
    LoadModule python_module modules/mod_python.so
    ScriptAlias /python/ "D:/htdocs/python/"
    <Directory "D:/htdocs/python">
        AddHandler mod_python .py
        PythonHandler mod_python.publisher
        PythonDebug On
    </Directory>
      
  4. 動作確認
    Example: py_test.html
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <html>
        <head>
            <title>Python CGI</title>
            <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8">
        </head>
    
        <body>
            <h1>Python CGI</h1>
            <pre>test</pre>
            <form action="python/test00.py/test" method="GET">
                <input type="submit"/>
            </form>
    
            <pre>test2</pre>
            <form action="python/test00.py/test2" method="GET">
                <input type="submit"/>
            </form>
        </body>
    </html>
    
    Example: python/test00.py
    def test(req):
        req.content_type = 'text/plain'
        req.write("Hello World!")
        return
    
    def test2(req):
        ans = 4 * 2
        req.content_type = 'text/plain'
        msg = "ANS = %d" % ans
        req.write(msg)
        return
    
  5. 引数を取る場合
    Example 3. py_test01.html
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
        <head>
            <title>Python CGI 2</title>
            <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8"/>
        </head>
    
        <body>
            <form action="python/test01.py/test" method="GET">
                <select name="year">
                    <option value="2010">2010 年</option>
                </select>
                <select name="month">
                    <option value="4">4 月</value>
                    <option value="5">5 月</value>
                    <option value="6">6 月</value>
                </select>
                <input type="submit" id="sumbitButton" value="Submit"/>
            </form>
        </body>
    </html>
    
    Example: python/test01.py
    # -*- coding: utf-8 -*-
    def test(req, year, month):
        s = """
    <html>
        <body>
            Year = %s<BR>
            Month = %s<BR>
        </body>
    </html>
    """ % (year, month)
        return s
    

[GTK+]Glade で Hello World 作成

  1. Glade を起動して Top level に Main window, Container に 3 段の virtual box (垂直ボックス), その中に Text entry, label, button を配置する
  2. Main window の名前を Hello World にする。Entry, Label, Button はデフォルトのまま entry1, label1, button1 としておく
  3. button1 のシグナル clicked にハンドラ button1_clicked_cb を登録する
  4. 作成した glade ファイルを保存する (hello_world.glade)
  5. hello_world.c を作成する。main 内で hello_world.glade を読み出して各 widget を紐付ける
    Example: hello_world.c
    #include <gtk/gtk.h>
    
    GtkBuilder *builder;
    GtkWidget *label1;
    GtkWidget *entry1;
    
    G_MODULE_EXPORT void button1_clicked_cb(GtkWidget *widget, gpointer data)
    {
        const gchar *text;
        char buf[256];
    
        g_print("%s is called\n", __FUNCTION__);
        text = gtk_entry_get_text(GTK_ENTRY(entry1));
        sprintf(buf, "%s", text);
        gtk_label_set_text(GTK_LABEL(label1), buf);
    }
    
    int main(int argc, char **argv)
    {
        GtkWidget *window;
        GError *error = NULL;
        GtkSettings *settings;
    
        gtk_init(&argc, &argv);
    
        /* Create a new GtkBuilder object */
        builder = gtk_builder_new();
    
        if (!gtk_builder_add_from_file(builder, "hello_world.glade", &error)) {
         g_warning("%s", error->message);
         g_free(error);
         return 1;
        }
    
        settings = gtk_settings_get_default();
    // gtk_settings_set_string_property (settings, "gtk-font-name", "MS Mincho 14", "");
        gtk_settings_set_string_property (settings, "gtk-font-name", "Sazanami Gothic 14", "");
    
        window = GTK_WIDGET(gtk_builder_get_object(builder, "Hello World"));
        label1 = GTK_WIDGET(gtk_builder_get_object(builder, "label1"));
        entry1 = GTK_WIDGET(gtk_builder_get_object(builder, "entry1"));
    
        gtk_builder_connect_signals(builder, NULL);
        g_object_unref(G_OBJECT(builder));
        gtk_widget_show(window);
    
        gtk_main();
    
        return 0;
    }
    
  6. コンパイル
    Makefile の CFLAGS に CFLAGS に gmodule-2.0 を付ける。LDFLAGS に -mwindows を付けると DOS 窓を開くことなくプログラムが実行できるようになる
    Example: Makefile
    CC=gcc
    PKG_CONFIG = c:/usr/MinGW/bin/pkg-config
    CFLAGS = -Wall -DGTK_DISABLE_DEPRECATED `$(PKG_CONFIG) --cflags gtk+-2.0 gmodule-2.0`
    LDFLAGS = `$(PKG_CONFIG) --libs gtk+-2.0` -mwindows
    TARGET = \
        hello_world.exe
    
    .SUFFIXES: .exe .c .o
    
    # $@ は生成しようとしているターゲット名
    # $< は依存しているファイル
    .c.o:
        $(CC) $(CFLAGS) -c -o $@ $<
    
    .o.exe:
        $(CC) -o $@ $< $(LDFLAGS)
    
    default: $(TARGET)
    
    pkgconfig:
        $(PKG_CONFIG) --cflags gtk+-2.0
        $(PKG_CONFIG) --libs gtk+-2.0
    
    clean:
        rm -rf *.o *.exe
    
  7. 実行結果

[GTK+]Glade のインストール

  1. Glade - A User Interface Designer の Windows Binaries にある glade3-3.6.7-with-GTK+.exe (2009/10/09 現在) をダウンロードする
  2. ダウンロードしたファイルを実行して Glade をインストールする

[GTK+]アプリのフォント変更

GtkSetting を呼び出して gtk-font-name という property を変更することでアプリに使用するフォントを変更できる
    GtkSettings *settings;

    settings = gtk_settings_get_default();
//    gtk_settings_set_string_property (settings, "gtk-font-name", "MS Mincho 14", "");
    gtk_settings_set_string_property (settings, "gtk-font-name", "Sazanami Gothic 14", "");

[GTK+]ボタンにアイコンを追加する

  • box 内に image と label を配置して画像付きボタンを作成する
  • 画像には xpm ファイルを使用する
Example: button.c
#include <gtk/gtk.h>

static GtkWidget *xpm_label_box(gchar *xpm_filename, gchar *label_text)
{
    GtkWidget *box;
    GtkWidget *label;
    GtkWidget *image;

    /* Create box for image and label */
    box = gtk_hbox_new(FALSE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(box), 2);

    /* Load image for the button */
    image = gtk_image_new_from_file(xpm_filename);

    /* Create a label for the button */
    label = gtk_label_new(label_text);

    /* Pack the image and label into the box */
    gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 3);
    gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 3);

    gtk_widget_show(image);
    gtk_widget_show(label);

    return box;
}

static void callback(GtkWidget *widget, gpointer data)
{
    g_print("Hello again - %s was pressed\n", (char*)data);
}

int main(int argc, char **argv)
{
    GtkWidget *window;
    GtkWidget *button, *toggle_button;
    GtkWidget *box;

    gtk_init(&argc, &argv);

    /* Create a new window */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Pixmap'd buttons");

    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL);

    /* ボーダーの幅を設定 */
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);

    /* Create a new button */
    button = gtk_button_new();

    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), (gpointer)"cool button");

    box = xpm_label_box("CarGrey.xpm", "cool button");

    /* Create a new toggle_button */
    toggle_button = gtk_toggle_button_new();
    g_signal_connect(G_OBJECT(toggle_button), "clicked", G_CALLBACK(callback), (gpointer)"toggle button");

    /* Pack and show all our widget */
    gtk_widget_show(box);
    gtk_container_add(GTK_CONTAINER(button), box);
    gtk_widget_show(button);
    gtk_container_add(GTK_CONTAINER(window), button);
    gtk_widget_show(window);

    gtk_main();

    return 0;
}
実行結果

[GTK+]テキスト入力欄

  • テキスト入力欄に入力した文字列を label に反映する
  • ボタンをクリックすると button_click() が呼び出され、その中で entry に書き込まれた文字列を gtk_entry_get_text() で読み出し、label に gtk_label_set_text() で反映する
Example: entry.c
#include <gtk/gtk.h>

typedef struct main_dialog_type {
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *table;
    GtkWidget *entry;
    GtkWidget *label;
} MainDialog;

/* ボタンがクリックされたら entry に入力された文字列を読み込み label を更新する */
void button_click(GtkWidget *widget, gpointer data)
{
    const gchar *text;
    char buf[256];

    text = gtk_entry_get_text(GTK_ENTRY(((MainDialog*)data)->entry));
    sprintf(buf, "%s", text);
    gtk_label_set_text(GTK_LABEL(((MainDialog*)data)->label), buf);
}

int main(int argc, char **argv)
{
    MainDialog dialog;

    gtk_init(&argc, &argv);

    dialog.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(dialog.window), "GtkEntry");
    gtk_window_set_position(GTK_WINDOW(dialog.window), GTK_WIN_POS_CENTER);
    /* table を作成し、各要素を table 上に配置する */
    /*  0          1          2
     * 0+----------+----------+
     *  |          |          |
     * 1+----------+----------+
     *  |          |          |
     * 2+----------+----------+
     */
    /* gtk_table_attach_defaults(*table, *child, left_attach, right_attach, top_attach, bottom_attach); */

    dialog.table = gtk_table_new(2, 2, TRUE);
    gtk_container_add(GTK_CONTAINER(dialog.window), dialog.table);

    /* entry を下記の場所に配置する */
    /*  0          1          2
     * 0+----------+----------+
     *  |   XXXX   |          |
     * 1+----------+----------+
     *  |          |          |
     * 2+----------+----------+
     */
    dialog.entry = gtk_entry_new();
    gtk_table_attach_defaults(GTK_TABLE(dialog.table), dialog.entry, 0, 1, 0, 1);

    /* label を下記の場所に配置する */
    /*  0          1          2
     * 0+----------+----------+
     *  |          |   XXXX   |
     * 1+----------+----------+
     *  |          |          |
     * 2+----------+----------+
     */
    dialog.label = gtk_label_new("blank");
    gtk_table_attach_defaults(GTK_TABLE(dialog.table), dialog.label, 1, 2, 0, 1);

    /* button を下記の場所に配置する */
    /*  0          1          2
     * 0+----------+----------+
     *  |          |          |
     * 1+----------+----------+
     *  |   XXXXXXXXXXXXXXX   |
     * 2+----------+----------+
     */
    dialog.button = gtk_button_new_with_label("Enter");
    gtk_table_attach_defaults(GTK_TABLE(dialog.table), dialog.button, 0, 2, 1, 2);
    g_signal_connect(dialog.button, "clicked", G_CALLBACK(button_click), &dialog);

    gtk_widget_show_all(dialog.window);

    g_signal_connect_swapped(G_OBJECT(dialog.window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_main();

    return 0;
}
実行結果

[GTK+]ボタンをクリックした時のイベント

  • 配置したボタンをクリックすることでイベントを実行するには g_signal_connect() で clicked イベントを指定する
  • "+" のボタンを押すと increase() が呼び出され、label 表記が gtk_label_set_text() によって書き換えられる
Example: increase_decrease.c
#include <gtk/gtk.h>

gint count = 0;
char buf[5];

void increase(GtkWidget *widget, gpointer label)
{
    count++;

    sprintf(buf, "%d", count);
    gtk_label_set_text(label, buf);
}

void decrease(GtkWidget *widget, gpointer label)
{
    count--;

    sprintf(buf, "%d", count);
    gtk_label_set_text(label, buf);
}

int main(int argc, char **argv)
{
    GtkWidget *window;
    GtkWidget *label;
    GtkWidget *frame;
    GtkWidget *plus;
    GtkWidget *minus;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "+-");
    gtk_window_set_default_size(GTK_WINDOW(window), 250, 180);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    frame = gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(window), frame);

    plus = gtk_button_new_with_label("+");
    gtk_widget_set_size_request(plus, 80, 35);
    gtk_fixed_put(GTK_FIXED(frame), plus, 50, 20);

    minus = gtk_button_new_with_label("-");
    gtk_widget_set_size_request(minus, 80, 35);
    gtk_fixed_put(GTK_FIXED(frame), minus, 50, 80);

    label = gtk_label_new("0");
    gtk_fixed_put(GTK_FIXED(frame), label, 190, 58);

    gtk_widget_show_all(window);

    g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(plus, "clicked", G_CALLBACK(increase), label);
    g_signal_connect(minus, "clicked", G_CALLBACK(decrease), label);

    gtk_main();

    return 0;
}
実行結果

[GTK+]アプリケーションアイコンを追加する

gtk_window_set_icon() でアプリの左上に表示されるアイコンを追加できる
Example: application_icon.c
#include <gtk/gtk.h>

GdkPixbuf *create_pixbuf(const gchar *filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;

    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if (!pixbuf) {
     fprintf(stderr, "%s\n", error->message);
     g_error_free(error);
    }

    return pixbuf;
}

int main(int argc, char **argv)
{
    GtkWidget *window;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "icon");
    gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("Hippopotamus.ico"));
    gtk_widget_show(window);

    g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    gtk_main();

    return 0;
}
実行結果

[GTK+]アプリを画面中央に表示する

gtk_window_set_position() で Center position を指定することでアプリウィンドウを画面中央に表示できる
Example: centering.c
#include <gtk/gtk.h>

int main(int argc, char **argv)
{
   GtkWidget *window;

   gtk_init(&argc, &argv);

   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(window), "Center");
   gtk_window_set_default_size(GTK_WINDOW(window), 230, 150);
   gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
   gtk_widget_show(window);

   g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

   gtk_main();

   return 0;
}
実行結果

[GTK+]アプリ起動時に DOS 窓を表示させない

リンカーオプションに -mwindows を付けることで DOS 窓を表示させないようにできる
Example: Makefile
CC=gcc
PKG_CONFIG = c:/usr/MinGW/bin/pkg-config
CFLAGS = -Wall -DGTK_DISABLE_DEPRECATED `$(PKG_CONFIG) --cflags gtk+-2.0`
LDFLAGS = `$(PKG_CONFIG) --libs gtk+-2.0` -mwindows

(中略)
.c.o:
   $(CC) $(CFLAGS) -c -o $@ $<

.o.exe:
   $(CC) -o $@ $< $(LDFLAGS)
 

[GTK+]MinGW + GDK+ 環境設定

  1. GTK+ - Download for Windows から boundle パッケージををダウンロードする
  2. 展開したファイルを MinGW をインストールしてあるディレクトリに移動する
  3. サンプルプログラムを準備する
    Example: hello.c
    #include <gtk/gtk.h>
    
    static void destroy(GtkWidget *widget, gpointer data)
    {
        gtk_main_quit();
    }
    
    int main(int argc, char **argv)
    {
        GtkWidget *window;
        GtkWidget *label;
    
        gtk_init(&argc, &argv);
    
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        label = gtk_label_new("Hello, world!");
        gtk_container_add(GTK_CONTAINER(window), label);
        gtk_widget_show(label);
        gtk_widget_show(window);
    
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
        gtk_main();
    
        return 0;
    }
    
    Example: Makefile
    CC=gcc
    PKG_CONFIG = c:/usr/MinGW/bin/pkg-config
    CFLAGS = -Wall -DGTK_DISABLE_DEPRECATED `$(PKG_CONFIG) --cflags gtk+-2.0`
    LDFLAGS = `$(PKG_CONFIG) --libs gtk+-2.0`
    TARGET = \
        hello.exe
    
    .SUFFIXES: .exe .c .o
    
    # $@ は生成しようとしているターゲット名
    # $< は依存しているファイル
    .c.o:
        $(CC) $(CFLAGS) -c -o $@ $<
    
    .o.exe:
        $(CC) -o $@ $< $(LDFLAGS)
    
    default: $(TARGET)
    
    pkgconfig:
        $(PKG_CONFIG) --cflags gtk+-2.0
        $(PKG_CONFIG) --libs gtk+-2.0
    
    clean:
        rm -rf *.o *.exe
    
  4. コンパイルする
  5. 作成された hello.exe を実行する

2013年2月24日日曜日

[OpenSSL]OpenSSL ライブラリを使用したプログラム

テストプログラム
#include <iostream>
#include <iomanip>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/des.h>
#include <openssl/aes.h>
using namespace std;
static unsigned char test_data[32]={
        0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x20,
        0x4E,0x6F,0x77,0x20,0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74,0x69,0x6D,0x65,0x20,
        0x66,0x6F,0x72,0x20,0x00,0x00,0x00,0x00,
};
static unsigned char cbc_key [8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
static unsigned char cbc_iv [8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
static unsigned char cbc2_key[8]={0xf1,0xe0,0xd3,0xc2,0xb5,0xa4,0x97,0x86};
static unsigned char cbc3_key[8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};

/* DES CBC 用 encode 済み確認データ */
static unsigned char cbc_ok[32]={
    0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
    0xac,0xd8,0xae,0xfd,0xdf,0xd8,0xa1,0xeb,
    0x46,0x8e,0x91,0x15,0x78,0x88,0xba,0x68,
    0x1d,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4
};

/* 3DES CBC 用 encode 済み確認データ */
static unsigned char cbc3_ok[32]={
    0x3F,0xE3,0x01,0xC9,0x62,0xAC,0x01,0xD0,
    0x22,0x13,0x76,0x3C,0x1C,0xBD,0x4C,0xDC,
    0x79,0x96,0x57,0xC0,0x64,0xEC,0xF5,0xD4,
    0x1C,0x67,0x38,0x12,0xCF,0xDE,0x96,0x75
};

static unsigned char aes_cbc_key[] = {
    0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
    0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10
};

static unsigned char aes_cbc_iv[] = {
    0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0x01,
    0x98,0x76,0x54,0x32,0x10,0xfe,0xdc,0xba
};

/* AES 128 bit CBC 用 encode 済み確認データ */
static unsigned char aes128_cbc_ok[] = {
    0xea,0xca,0xd1,0x95,0xf1,0x00,0xf8,0x77,
    0x5d,0x8b,0xb8,0x2a,0x5e,0xb7,0x04,0xf6,
    0x0f,0x8f,0x2c,0x09,0xaf,0xf6,0x76,0x06,
    0xbd,0x1e,0x19,0xac,0x57,0x68,0xfc,0x2d
};

/**
 * @brief バッファの dump を表示する
 *
 * @param p バッファポインタ
 * @param len バッファ長
 */
static void disp_dump(unsigned char* p, int len)
{
    int i;

    for (i = 0; i < len; i++) {
        cout << hex << setw(2) << setfill('0') << (unsigned int)(*(p + i)) << " ";
        if (((i+1)%16==0) && ((i+1) != len)) {
            cout << endl;
        }
    }
    cout << endl;
    cout << endl;
}

/**
 * @brief MD5 のテスト
 *
 * コマンドラインでの MD5 値を求める方法
 * @code
 * $ openssl dgst -md5 test_data.dat
 * MD5(test_data.dat)= c7e05d2749805b61e43ddf7a4e73aa3d
 * @endcode
 *
 * @retval 0
 */
static int digest_md5_test(void)
{
    MD5_CTX ctx;
    unsigned char md[MD5_DIGEST_LENGTH];

    cout << "Digest MD5" << endl;
    MD5_Init(&ctx);
    MD5_Update(&ctx, test_data, sizeof(test_data));
    MD5_Final(md, &ctx);
    disp_dump(md, sizeof(md));

    return 0;
}

/**
 * @brief SHA1 のテスト
 *
 * コマンドラインでの SHA1 値を求める方法
 * @code
 * $ openssl dgst -sha1 test_data.dat
 * SHA1(test_data.dat)= 3f115bbb9bc96fed0fe2b5b3f2a50442203d3599
 * @endcode
 *
 * @retval 0
 */
static int digest_sha1_test(void)
{
    SHA_CTX ctx;
    unsigned char sha[SHA_DIGEST_LENGTH];

    cout << "Digest SHA1" << endl;
    SHA1_Init(&ctx);
    SHA1_Update(&ctx, test_data, sizeof(test_data));
    SHA1_Final(sha, &ctx);
    disp_dump(sha, sizeof(sha));

    return 0;
}

/**
 * @brief DES CBC モードのテスト
 *
 * コマンドラインでのエンコード * @code
 * $ openssl enc -des-cbc -e -in test_data.dat -out enc.out
 * -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
 * key=0123456789ABCDEF
 * iv =FEDCBA9876543210
 * @endcode
 *
 * コマンドラインでのデコード
 * @code
 * $ openssl enc -des-cbc -d -in enc.out -out dec.out
 * -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
 * key=0123456789ABCDEF
 * iv =FEDCBA9876543210
 * @endcode
 *
 * @retval 0
 */
static int enc_des_cbc_test(void)
{
    int i;

    unsigned char des_enc[32];
    unsigned char des_dec[32];
    DES_cblock iv3;
    des_key_schedule schedule;

    memset(des_enc, 0, sizeof(des_enc));
    memset(des_dec, 0, sizeof(des_dec));

    /*** 暗号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule);
    if (i != 0) {
        cout << "Key error " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Encode */
    cout << "DES CBC encrypt" << endl;
    des_ncbc_encrypt((const unsigned char*)test_data, des_enc, sizeof(test_data), schedule, &iv3, DES_ENCRYPT);
    if (memcmp(des_enc, cbc_ok, sizeof(cbc_ok)) != 0) {
        cout << "cbc_encrypt encrypt error" << endl;
    }
    disp_dump(des_enc, sizeof(des_enc));

    /*** 復号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule);
    if (i != 0) {
        cout << "Key error " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Decode */
    cout << "DES CBC decrypt" << endl;
    des_ncbc_encrypt((const unsigned char*)des_enc, des_dec, sizeof(test_data), schedule, &iv3, DES_DECRYPT);
    if (memcmp(des_dec, test_data, sizeof(test_data)) != 0) {
        cout << "cbc_encrypt decrypt error" << endl;
    }
    disp_dump(des_dec, sizeof(des_dec));

    return 0;
}

/**
 * @brief 3DES CBC モードのテスト
 *
 * コマンドラインでのエンコード
 * @code
 * $ openssl enc -des-ede3-cbc -e -in test_data.dat -out enc.out -p -nosalt
 * -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
 * key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
 * iv =FEDCBA9876543210
 * @endcode
 * * コマンドラインでのデコード
 * @code
 * $ openssl enc -des-ede3-cbc -d -in enc.out -out dec.out -p -nosalt
 * -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
 * key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
 * iv =FEDCBA9876543210
 * @endcode
 *
 * @retval 0
 */
static int enc_3des_cbc_test(void)
{
    int i;
    unsigned char des_enc[32];
    unsigned char des_dec[32];
    DES_cblock iv3;
    des_key_schedule schedule1, schedule2, schedule3;

    memset(des_enc, 0, sizeof(des_enc));
    memset(des_dec, 0, sizeof(des_dec));

    /*** 暗号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule1);
    if (i != 0) {
        cout << "Key error (1) " << i << endl;
    }
    i = DES_set_key_checked(&cbc2_key, &schedule2);
    if (i != 0) {
        cout << "Key error (2) " << i << endl;
    }
    i = DES_set_key_checked(&cbc3_key, &schedule3);
    if (i != 0) {
        cout << "Key error (3) " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Encode */
    cout << "3DES CBC encrypt" << endl;
    des_ede3_cbc_encrypt((const unsigned char*)test_data, des_enc, sizeof(test_data), schedule1, schedule2, schedule3, &iv3, DES_ENCRYPT);
    if (memcmp(des_enc, cbc3_ok, sizeof(cbc3_ok)) != 0) {
        cout << "des_ede3_cbc_encrypt encrypt error" << endl;
    }
    disp_dump(des_enc, sizeof(des_enc));

    /*** 復号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule1);
    if (i != 0) {
        cout << "Key error (1) " << i << endl;
    }
    i = DES_set_key_checked(&cbc2_key, &schedule2);
    if (i != 0) {
        cout << "Key error (2) " << i << endl;
    }
    i = DES_set_key_checked(&cbc3_key, &schedule3);
    if (i != 0) {
        cout << "Key error (3) " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Decode */
    cout << "3DES CBC decrypt" << endl;
    des_ede3_cbc_encrypt((const unsigned char*)des_enc, des_dec, sizeof(des_enc), schedule1, schedule2, schedule3, &iv3, DES_DECRYPT);
    if (memcmp(des_dec, test_data, sizeof(test_data)) != 0) {
        cout << "des_ede3_cbc_encrypt encrypt error" << endl;
    }
    disp_dump(des_dec, sizeof(des_dec));

    return 0;
}

/**
 * @brief AES 128bit CBC モードのテスト
 *
 * コマンドラインでのエンコード
 * @code
 * $ openssl enc -aes-128-cbc -e -in test_data.dat -out enc.out -p -nosalt
 * -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
 * key=0123456789ABCDEFFEDCBA9876543210
 * iv =23456789ABCDEF019876543210FEDCBA
 * @endcode
 * * コマンドラインでのデコード
 * @code
 * $ openssl enc -aes-128-cbc -d -in enc.out -out dec.out -p -nosalt
 * -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
 * key=0123456789ABCDEFFEDCBA9876543210
 * iv =23456789ABCDEF019876543210FEDCBA
 * @endcode
 *
 * @retval 0
 */
static int enc_aes128_cbc_test(void)
{
    int i;
    unsigned char aes_enc[32];
    unsigned char aes_dec[32];
    AES_KEY key;
    unsigned char iv[AES_BLOCK_SIZE];

    memset(aes_enc, 0, sizeof(aes_enc));
    memset(aes_dec, 0, sizeof(aes_dec));

    /*** 暗号化 ***/
    /* AES Key 作成 */
    i = AES_set_encrypt_key(aes_cbc_key, 128, &key);

    /* IV 準備 */
    memcpy(iv, aes_cbc_iv, sizeof(aes_cbc_iv));

    /* Encode */
    cout << "AES 128 CBC encrypt" << endl;
    AES_cbc_encrypt((const unsigned char*)test_data, aes_enc, sizeof(test_data), &key, iv, AES_ENCRYPT);
    if (memcmp(aes_enc, aes128_cbc_ok, sizeof(aes128_cbc_ok)) != 0) {
        cout << "AES_cbc_encrypt encrypt error" << endl;
    }
    disp_dump(aes_enc, sizeof(aes_enc));

    /*** 復号化 ***/
    /* AES Key 作成 */
    i = AES_set_decrypt_key(aes_cbc_key, 128, &key);

    /* IV 準備 */
    memcpy(iv, aes_cbc_iv, sizeof(aes_cbc_iv));

    /* Decode */
    cout << "AES 128 CBC decrypt" << endl;
    AES_cbc_encrypt((const unsigned char*)aes_enc, aes_dec, sizeof(aes_enc), &key, iv, AES_DECRYPT);
    if (memcmp(aes_dec, test_data, sizeof(test_data)) != 0) {
        cout << "AES_cbc_encrypt decrypt error" << endl;
    }
    disp_dump(aes_dec, sizeof(aes_dec));

    return 0;
}

int main(void)
{
    digest_md5_test();
    digest_sha1_test();
    enc_des_cbc_test();
    enc_3des_cbc_test();
    enc_aes128_cbc_test();

    return 0;
}

コンパイル
$ g++ openssl_test.cpp -o openssl_test.out -lssl -Wall

実行結果
$ ./openssl_test.out
Digest MD5
c7 e0 5d 27 49 80 5b 61 e4 3d df 7a 4e 73 aa 3d
Digest SHA1
3f 11 5b bb 9b c9 6f ed 0f e2 b5 b3 f2 a5 04 42
20 3d 35 99
DES CBC encrypt
cc d1 73 ff ab 20 39 f4 ac d8 ae fd df d8 a1 eb
46 8e 91 15 78 88 ba 68 1d 26 93 97 f7 fe 62 b4
DES CBC decrypt
37 36 35 34 33 32 31 20 4e 6f 77 20 69 73 20 74
68 65 20 74 69 6d 65 20 66 6f 72 20 00 00 00 00
3DES CBC encrypt
3f e3 01 c9 62 ac 01 d0 22 13 76 3c 1c bd 4c dc
79 96 57 c0 64 ec f5 d4 1c 67 38 12 cf de 96 75
3DES CBC decrypt
37 36 35 34 33 32 31 20 4e 6f 77 20 69 73 20 74
68 65 20 74 69 6d 65 20 66 6f 72 20 00 00 00 00
AES 128 CBC encrypt
ea ca d1 95 f1 00 f8 77 5d 8b b8 2a 5e b7 04 f6
0f 8f 2c 09 af f6 76 06 bd 1e 19 ac 57 68 fc 2d
AES 128 CBC decrypt
37 36 35 34 33 32 31 20 4e 6f 77 20 69 73 20 74
68 65 20 74 69 6d 65 20 66 6f 72 20 00 00 00 00

openssl コマンドを使った場合の結 果
上記プログラム中の test_data[] と同じ内容のバイナリデータ (test_data.dat) を準備して openssl コマンドで結果を確認
  • hash
    $ openssl dgst -md5 test_data.dat
    MD5(test_data.dat)= c7e05d2749805b61e43ddf7a4e73aa3d
    $ openssl dgst -sha1 test_data.dat
    SHA1(test_data.dat)= 3f115bbb9bc96fed0fe2b5b3f2a50442203d3599
      
  • DES CBC による暗号化
    $ openssl enc -des-cbc -e -in test_data.dat -out enc.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
    key=0123456789ABCDEF
    iv =FEDCBA9876543210
      
  • DES CBC による復号化
    $ openssl enc -des-cbc -d -in enc.out -out dec.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
    key=0123456789ABCDEF
    iv =FEDCBA9876543210
      
  • 3DES CBC による暗号化
    $ openssl enc -des-ede3-cbc -e -in test_data.dat -out enc.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
    key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
    iv =FEDCBA9876543210
      
  • 3DES CBC による複合化
    $ openssl enc -des-ede3-cbc -d -in enc.out -out dec.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
    key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
    iv =FEDCBA9876543210
      
  • AES 128bit CBC による暗号化
    $ openssl enc -aes-128-cbc -e -in test_data.dat -out enc.out -p -nosalt -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
    key=0123456789ABCDEFFEDCBA9876543210
    iv =23456789ABCDEF019876543210FEDCBA
      
  • AES 128bit CBC による復号化
    $ openssl enc -aes-128-cbc -d -in enc.out -out dec.out -p -nosalt -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
    key=0123456789ABCDEFFEDCBA9876543210
    iv =23456789ABCDEF019876543210FEDCBA
      

[OpenSSL]証明書生成

作成した RSA 秘密鍵を使って証明書を生成する。証明書には RSA 公開鍵が埋め込まれる。
$ openssl req -new -x509 -out test.crt -key privateKeyRsa.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
$ openssl x509 -text -noout -in test.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
ac:4e:6d:50:42:99:af:85
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=JP, ST=Tokyo, L=Default City, O=Default Company Ltd
Validity
Not Before: Dec 29 22:06:28 2010 GMT
Not After : Jan 28 22:06:28 2011 GMT
Subject: C=JP, ST=Tokyo, L=Default City, O=Default Company Ltd
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (512 bit)
Modulus:
00:ef:8a:45:1b:c9:08:b6:c2:c6:f2:3c:e1:d0:2c:
80:17:08:ce:03:df:e1:62:3e:fa:c5:c7:c7:40:fd:
63:7a:bd:dc:02:b9:dd:dd:e6:ae:b4:b4:e9:70:b7:
23:c7:d8:5c:68:2c:14:f5:46:31:a0:8c:dd:1a:94:
f0:58:e6:f8:95
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
32:D1:27:F9:75:5F:5E:F4:66:2A:9E:73:B4:D1:2F:BB:AF:A7:02:1E
X509v3 Authority Key Identifier:
keyid:32:D1:27:F9:75:5F:5E:F4:66:2A:9E:73:B4:D1:2F:BB:AF:A7:02:1E
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
db:47:d6:7f:4e:b0:56:11:52:0d:c7:e9:be:d7:b9:7a:a5:51:
8e:ef:b8:cc:2d:53:d1:62:4a:82:5a:83:87:e6:14:9a:e9:65:
82:62:9e:52:02:a8:f2:d9:b0:5e:88:dc:c4:c9:d3:61:4e:07:
22:bc:af:4e:e6:d9:6b:eb:38:10

[OpenSSL]秘密鍵生成

DH 秘密鍵の生成 (512 bit)
$ openssl dhparam 512 -out privateKeyDh.pem
Generating DH parameters, 512 bit long safe prime, generator 2
This is going to take a long time
.....................................+...........+......+......+....................++*++*++*++*++*++*
$ cat privateKeyDh.pem
-----BEGIN DH PARAMETERS-----
MEYCQQCb3DR4LDwxIb1TNVyFQ055HjEBxEigm62Let76yVJQE1hSxo1+dTWcKEEc
N4EMbJZXdMZN+RM4rieozLPvQzGzAgEC
-----END DH PARAMETERS-----

RSA 秘密鍵生成
$ openssl genrsa -out privateKey.pem
Generating RSA private key, 512 bit long modulus
...++++++++++++
....................++++++++++++
e is 65537 (0x10001)
$ cat privateKey.pem
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANKkXr0Ub2qwhK0s/Wor7lq5kGsOFwYxXSURgeicbI4F7GcCWyaU
60l7JjvM+d0n8piF70fuv5twxVf7ktEdsyECAwEAAQJAPCK9AVISNO1ME3yipGsC
U1hiyI1vOU9ifjCvW888lpbJvPVbikS26kuHWMcFxHO4y59mNOodZQYHP8+6yR1h
WQIhAOlu4rwQxrPIeTZemzs977Y8+UxgEy6dp81SCcij+ap3AiEA5wFwpHswhfIZ
6eTu/mrEkvMYJUu8VrAvh4AWsnB03ScCIGJV6/39szcZRLa6s/oI5WqH1R1ve6Uv
lPjRjn2PViWRAiEAjUngL3n5T7OoDdqsIogC+y4cEpOj+hGAwIujVjhaAfkCIBEQ
9hTyf0rqTJa7+0IT1WoBpRkPrLCZdU7wiWy/5ZdM
-----END RSA PRIVATE KEY-----

作成した RSA 秘密鍵から RSA 公開鍵を生成
$ openssl rsa -in privateKeyRsa.pem -pubout -out publicKeyRsa.pem
writing RSA key
$ openssl rsa -in publicKeyRsa.pem -pubin -text
Public-Key: (512 bit)
Modulus:
00:ef:8a:45:1b:c9:08:b6:c2:c6:f2:3c:e1:d0:2c:
80:17:08:ce:03:df:e1:62:3e:fa:c5:c7:c7:40:fd:
63:7a:bd:dc:02:b9:dd:dd:e6:ae:b4:b4:e9:70:b7:
23:c7:d8:5c:68:2c:14:f5:46:31:a0:8c:dd:1a:94:
f0:58:e6:f8:95
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAO+KRRvJCLbCxvI84dAsgBcIzgPf4WI+
+sXHx0D9Y3q93AK53d3mrrS06XC3I8fYXGgsFPVGMaCM3RqU8Fjm+JUCAwEAAQ==
-----END PUBLIC KEY-----

[OpenSSL]RSA 公開鍵/秘密鍵で暗号化/復号化

公開鍵 (publicKeyRsa.pem) を使ってテキストファイルを暗号化する。
$ cat plain.txt
Hello, world
$ openssl rsautl -pubin -inkey publicKeyRsa.pem -in plain.txt -encrypt -out enc.dat
$ od -x enc.dat
0000000 013d 7976 bbe6 506b 3da5 a2ac 57f0 db18
0000020 6a75 afa3 0efa 0cee d4a4 4729 4285 d25b
0000040 4c17 66f0 1a98 d027 c950 640e 824d 8c43
0000060 d05b 4a82 badd 36f1 90eb c284 3707 5277
0000100

暗号化に使った公開鍵 (publicKeyRsa.pem) と対になる秘密鍵 (privateKeyRsa.pem) を使って暗号化されたファイル (enc.dat) を復号化する。
$ openssl rsautl -inkey privateKeyRsa.pem -in enc.dat -decrypt -out dec.dat
$ cat dec.dat
Hello, world

[OpenSSL]HMAC_SHA256_BASE64 を使う

OpenSSL の crypto ライブラリにある hmac と base64 を使って HMAC_SHA256_BASE64 を実行する
Example: hmac_sha256_base64.c
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
/**
 ***********************************************************************
 * @brief バッファの内容を HEX で表示
 *
 * @param[in] buff 表示するバッファのポインタ
 * @param[in] length バッファ長
 ***********************************************************************
 */
static void printDump(const unsigned char *buff, int length)
{
    int i;

    for (i = 0; i < length; i++) {
        printf("%02x", (buff[i] & 0x000000ff));
        if ((i + 1) % 16 == 0) {
            printf("\n");
        }
        else {
            printf(" ");
        }
    }
    printf("\n\n");
}

/**
 ***********************************************************************
 * @brief バッファの内容を文字列で表示
 *
 * @param[in] buff 表示するバッファのポインタ
 * @param[in] length バッファ長
 ***********************************************************************
 */
static void printChar(const unsigned char *buff, int length)
{
    int i;

    for (i = 0; i < length; i++) {
        printf("%c", buff[i]);
    }
    printf("\n\n");
}

/**
 ***********************************************************************
 * @brief BASE64 encode をする
 *
 * @param[in] buff Encode 対象バッファ
 * @param[in] length バッファ長
 ***********************************************************************
 */
static void base64(const unsigned char *input, int length)
{
    BIO *bmem, *b64;
    BUF_MEM *bptr;

    b64 = BIO_new(BIO_f_base64());
    bmem = BIO_new(BIO_s_mem());
    b64 = BIO_push(b64, bmem);
    BIO_write(b64, input, length);
    BIO_flush(b64);
    BIO_get_mem_ptr(b64, &bptr);

    printf("Base64 output:\n");
    printDump(bptr->data, bptr->length);
    printf("Base64 output(char):\n");
    printChar(bptr->data, bptr->length);
    BIO_free_all(b64);
}
/**
 ***********************************************************************
 * @brief hmac_sha256_base64.c のメイン関数
 *
 * @retval 0 正常終了
 ***********************************************************************
 */
int main(void)
{
    const char key[] = "0123456789";
    const char data[] = "abcdefghijklmnopqrstuvwxyz";
    char out[EVP_MAX_MD_SIZE];
    int key_len, data_len, out_len;

    key_len = strlen(key);
    data_len = strlen(data);
    HMAC(EVP_sha256(), key, key_len, data, data_len, out, &out_len);

    printf("hmac_sha256 output:\n");
    printDump(out, out_len);
    base64(out, out_len);

    return 0;
}

crypto ライブラリをリンクするには gdi32 ライブラリが必要となる
Example: Makefile
CC = gcc
CFLAGS = -Wall
# rand_win.c で使われている CreateDCA, GetDeviceCaps などをリンクするために gdi32 ライブラリが必要
LDFLAGS = -lcrypto -lgdi32
TARGET = \
    hmac_sha256_base64.exe

.SUFFIXES: .exe .c .o

.c.o:
    $(CC) $(CFLAGS) -c -o $@ $<

.o.exe:
    $(CC) -o $@ $< $(LDFLAGS)

default: $(TARGET)

clean:
    rm -rf *.o *.exe

実行結果
> hmac_sha256_base64.exe
hmac_sha256 output:
c3 11 d8 1f d6 71 5e 27 b0 e3 87 7e b9 79 13 c3
1b 6a 7f 41 53 ad e5 2c 7a 42 1c d7 5e 7e 7c 65
Base64 output:
77 78 48 59 48 39 5a 78 58 69 65 77 34 34 64 2b
75 58 6b 54 77 78 74 71 66 30 46 54 72 65 55 73
65 6b 49 63 31 31 35 2b 66 47 55 3d 0a
Base64 output(char):
wxHYH9ZxXiew44d+uXkTwxtqf0FTreUsekIc115+fGU=

[OpenSSL]MinGW でコンパイル

  1. OpenSSL: The Open Source toolkit for SSL/TLS から openssl-0.9.8k.tar.gz (2009/10/14 現在) をダウンロードする
  2. Perl も必要となるので perl.exe のある PATH も通しておく
    > path=C:\usr\MinGW\bin;C:\usr\msys\bin;C:\usr\Perl\bin
      
  3. コンパイル
    1. util/pl/Mingw32.pl にある以下の箇所をコメントアウトする
      $cp='copy';
      $rm='del';
      $ret.="\tif exist $target \$(RM) $target\n";
          
    2. コンパイル実行
      > ms/mingw32.bat
          
  4. Install
    1. outinc にある openssl フォルダを c:\usr\MinGW\include へコピー
    2. out\openssl.exe を c:\usr\MinGW\bin へコピー
    3. out\libssl.a, out\libcrypto.a を c:\usr\MinGW\lib へコピー
      > cp -r outinc\openssl c:\usr\MinGW\include
      > cp out\openssl.exe c:\usr\MinGW\bin
      > cp out\libssl.a out\libcrypto.a c:\usr\MinGW\lib
          

[OpenSSL]Hash

MD5
$ openssl dgst -md5 test.txt
MD5(test.txt)= 56130e4a58c1a1dff5fa92325e843fed
結果をバイナリ出力
$ openssl dgst -md5 -binary test.txt > test_md5.dat

SHA1
$ openssl dgst -sha1 test.txt
SHA1(test.txt)= f479d393efe0776a65b9523319422e0a3dfc9baf

[C]Shared library 内の関数呼び出し優先度

メイン関数
Example: test.c
#include <stdio.h>
#include <dlfcn.h>
void func(void);

int main(void)
{
  void *lib;
  void (*func)();

  printf("%s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__);

  lib = dlopen("./sharedlib.so", RTLD_LAZY);
  func = dlsym(lib, "func");

  func();

  return 0;
}

void func(void)
{
  printf("%s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
}

void func2(void)
{
  printf("%s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
}
Shared library ソース
Example: sharedlib.c
#include <stdio.h>

void func2(void);

void func(void)
{
  printf("%s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__);

  func2();
}

void func2(void)
{
  printf("%s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
}
Example: Makefile
CC = gcc

default: test sharedlib.so

test: test.o
  $(CC) -o test test.o -ldl

test.o: test.c
  $(CC) -c test.c

sharedlib.o: sharedlib.c
  $(CC) -fPIC -c sharedlib.c

sharedlib.so: sharedlib.o
  $(CC) -shared sharedlib.o -o sharedlib.so

clean:
  rm -rf *.o
  rm -rf *.so
  rm -rf test
このプログラムをコンパイルして実行すると以下のように test にある func, func2 は実行されず、sharedlib.c にある func, func2 が上書きされて実行される
$ ./test
main @ test.c:10
func @ sharedlib.c:7
func2 @ sharedlib.c:14

[C]共有ライブラリ (Shared Libary, Windows では Dynamic Link Libary と呼称する) の作成方法

静的ライブラリ (Static library)
  • コンパイル時に組み込まれるライブラリ。拡張子は .a になる。
  • Static library を使用する場合は直接ライブラリを指定してコンパイルする。
    $ gcc test.c libtest.a
    
共有ライブラリ (Shared library)
  • プログラムの実行時にロードされるライブラリ。拡張子は .so や .sa になる。
  • Shared library を使用する場合はライブラリの検索パスに使用するライブラリを配置し、-l オプションでライブラリを指定してコンパイルする。
    $ gcc test.c -lxxx
    
動的ライブラリ (Dynamic link)
  • 共有ライブラリの一種で、実行時に関数を使ってロード、アンロードできる。モジュールのロード位置に依存しないので gcc でコンパイルする時に -fPIC オプションをつける。

libtest.c を共有ライブラリにする
  1. libtest.c 作成
    /* libtest.c */
    #include <stdio.h>
    #include "libtest.h"
    
    int lib_function(char *str)
    {
      printf("Hello, %s\n", str);
    
      return 0;
    }
    
  2. libtest.c をコンパイルしてオブジェクト (libtest.o) を生成する。動的ライブラリとして使用するために -fPIC オプションをつける。
    $ gcc -fPIC -c libtest.c
    
  3. libtest.o から共有ライブラリ (libtest.so) を生成する。
    soname により libtest.so.1 という名前でもロードできるようにする。
    $ gcc -shared -Wl,-soname,libtest.so.1 -o libtest.so.1.0 libtest.o
    
  4. libtest.so.1 という名前で libtest.so.1.0 に対してシンボリックリンクを張る。
    $ ln -s libtest.so.1.0 libtest.so.1
    
  5. libtest.so.1.0 を使用する test_sl.c を作成する。shared library を呼び出すための関数郡である dl ライブラリ (dlfcn.h) を読み込んでおく。
    dlopen() にある RTLD_LAZY は「シンボルの解決はシンボルを参照するコードが実行される時に解決を行う」ということを表す。
    dlsym() では dlopen() が返した Dynamic library のハンドルを通して lib_function というシンボルを呼び出している。
    #include <stdio.h>
    #include <dlfcn.h>
    
    int main(void)
    {
      void *libtest;
      void (*test_call)();
    
      libtest = dlopen("./libtest.so.1.0", RTLD_LAZY);
      if (libtest == NULL) {
        printf("Fail to dlopen()\n");
        return -1;
      }
      test_call = dlsym(libtest, "lib_function");
      (*test_call)("hogehoge");
    
      return 0;
    }
    
  6. dl ライブラリをリンクしてコンパイルする。
    $ gcc -o test_sl.out test_sl.c -ldl
    

[C]C ソースと C++ ソースのリンクの違い

nm コマンド
リンクの様子を確認する
$ nm hoge.o > hoge.nmdmp

objdump コマンド
オブジェクトファイルのシンボルをリスト表示する
$ objdump -x hoge.o > hoge.dmp

c++filt コマンド
オブジェクトファイルの情報を表示する
$ c++filt symbol

mangling された symbol を解読する
C++ では同じ名前を持つ関数名が複数存在することが可能なので、リンク時に適切な関数と結合できるよう関数名にラベルを埋め込んでシンボル名を作成する。この動作を mangling (マングリング) という。
  1. ソースコード準備 & コンパイル
    呼び出し元 C++ ソースコード
    Example: test.cpp
    #include <stdio.h>
    #include "libtest.h"
    
    int main(void)
    {
      lib_function("Hogehoge");
    
      return 0;
    }
    
    $ g++ test.cpp -L. -ltest
    /tmp/ccCXPMsT.o(.text+0x19): In function `main':
    : undefined reference to `lib_function(char*)'
    collect2: ld はステータス 1 で終了しました
    
  2. nm コマンドにより各オブジェクトファイル内のシンボルを確認する
    $ nm libtest.a
    
    libtest.o:
    00000000 T lib_function
             U printf
    
    $ g++ -c test.cpp -o test.o
    $ nm test.o
             U _Z12lib_functionPc
             U __gxx_personality_v0
    00000000 T main
    
    libtest.o では lib_function というシンボル名で定義されているが、test.cpp 内では mangling により _Z12lib_functionPc というシンボル名に変更されている
  3. このシンボル名を c++filt により解読してみる
    $ c++filt _Z12lib_functionPc
    lib_function(char*)
    
    すなわち _Z12lib_functionPc というシンボル名になっているが実態は lib_function(char *) というものに紐付けされている。
  4. libtest.h にある lib_function の関数宣言を以下のように C 記述であると明記する
        extern "C" int lib_function(char *str);
    
    test.cpp から生成したオブジェクトファイルのシンボル名は以下のようになる
        $ g++ -c test.cpp -o test.o
        $ nm test.o
                 U __gxx_personality_v0
                 U lib_function
        00000000 T main
    
    ちなみに gcc でコンパイルすると
        $ gcc test.cpp -L. -ltest
        /tmp/ccYsLSPi.o(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
        collect2: ld はステータス 1 で終了しました
    
    となり __gxx_personality_v0 が見つからないとエラーがでるので g++ でコンパイルする必要あり。

[C]静的ライブラリのリンク

大前提
  • あるオブジェクトが静的ライブラリ内の関数を呼び出す時には、呼び出される側のライブラリは後でリンクする必要がある。
静的ライブラリのヘッダファイル
Example: libtest.h
/* libtest.h */
int lib_function(char *str);
静的ライブラリの中身
Example: libtest.c
/* libtest.c */
#include <stdio.h>
#include "libtest.h"

int lib_function(char *str)
{
  printf("Hello, %s\n", str);

  return 0;
}
静的ライブラリの関数を使用するプログラム
Example: test.c
#include <stdio.h>
#include "libtest.h"

int main(void)
{
  lib_function("Hogehoge");

  return 0;
}

コンパイル
  1. 静的ライブラリの作成
    $ gcc -c libtest.c -o libtest.o
    $ ar rcs libtest.a libtest.o
    
    1. -c オプションでコンパイルのみを行い libtest.o オブジェクトを生成する。
    2. ライブラリ・アーカイブ (library archive) を作成する ar コマンドでライブラリ libtest.a を作成する。
  2. 静的ライブラリをリンク(この場合は失敗する)
    $ gcc -L. -ltest test.c
    /tmp/cccBpkWx.o(.text+0x19): In function `main':
    : undefined reference to `lib_function'
    collect2: ld はステータス 1 で終了しました
    
    リンクファイルの指定順が間違っている(リンクされる libtest を指定する -ltest が参照元の test.c より前に指定されているためリンクに失敗する)。
  3. 静的ライブラリをリンク
    $ gcc test.c -L. -ltest
    
    リンクされる libtest (-ltest) が参照元の test.c より後ろに指定されているためリンカが lib_function を正しく見つけることができている。
  4. 完成したプログラムを実行
    $ ./a.out
    Hello, Hogehoge
    

コンパイルオプション
-llibrary link させるライブラリを指定する。記述順により link が変わるので注意。
例) foo.o -lz bar.o
bar.o が z ライブラリ内の関数を参照していた場合ロードすることができなくなる。すなわち参照先ライブラリは参照元より後に記述すること。
ライブラリは libhoge.a というファイル名で search directory に配置しておき -l オプションでは -lhoge と指定する
-Ldirlinker が search する directory を追加する。
-clinker を動作させることなく、object の生成のみを行う。

ar オプション
rarchive に object ファイルを追加する
carchive を作成する
sarchive に object ファイルのインデックスを書き込む。すでに archive が存在する場合はインデックスを更新する

[PHP] CSV ファイルの読み書き

読み込み read.php
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>PHP CSV 読み込み</title>
  </head>
  <body>
    <?php
$filepath = "sample.csv";
$data = file($filepath);
$num = 0;
echo "<table border=1>";
for ($i = 0; $i < sizeof($data); $i++) {
    $num++;
    $line = explode(",", $data[$i]); // csv ファイルの 1 行を "," 区切りで配列 $line に収める
    echo "<tr>";
    echo "<td>$line[0]</td><td>$line[1]</td>";
    echo "</tr>";
}
echo "</table>"
    ?>
  </body>
</html>

sample.csv
1,dog
2,cat

書き込み
write.php
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>PHP CSV 書き込み</title>
  </head>
  <body>
    <?php
$filepath = "write.csv";
$fh = fopen($filepath, 'w');

$raw = array(); // 配列を準備

// 配列の先頭から順番にデータを入れていく
$raw[] = 1;
$raw[] = 2;
$raw[] = 3;
fputcsv($fh, $raw); // csv ファイルに書き込み
unset($raw); // 配列のクリア

// 配列の先頭から順番にデータを入れていく
$raw[] = 'A';
$raw[] = 'B';
$raw[] = 'C';
fputcsv($fh, $raw);
fclose($fh);

// 結果表示
$fh = fopen($filepath, 'r');
while (($r = fgetcsv($fh)) != FALSE) {
    print_r($r);
    print("<br/>\n");
}
fclose($fh);
    ?>
  </body>
</html>

書き込み結果 (write.csv)
1,2,3
A,B,C

2013年2月10日日曜日

[Java]子スレッドの終了を待つ

join メソッドを使って子スレッドの終了を待つ。














メインスレッドは子スレッドの処理が完了するまで待ち、子スレッドの完了を受けてから End of main を出力する。
Example: java_thread_01.java

public class java_thread_01 extends Thread {
    public static void main(String args[]) {
        System.out.println("Start of main");

        /* 子スレッド生成、スタート */
        java_thread_01 thread = new java_thread_01("Child Thread");
        thread.start();

        /* 子スレッドの終了を待つ */
        try {
            thread.join();
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("End of main");
    }

    /* 子スレッドの初期化 */
    public java_thread_01(String name) {
        super(name);
    }

    public void run() {
        /* 子スレッドの処理 */
        int i;
        for (i = 0; i < 5; i++) {
            System.out.println(this.getName() + ": " + i);
            try {
                sleep(500); // 500msec 停止
            }
            catch (InterruptedException e) {

            }
        }
        System.out.println(this.getName() + ": End");
    }
}
実行結果
> javac java_thread_01.java
> java java_thread_01
Start of main
Child Thread: 0
Child Thread: 1
Child Thread: 2
Child Thread: 3
Child Thread: 4
Child Thread: End
End of main

[Java]マルチスレッド

Thrad クラスを継承してマルチスレッドを扱うクラスを作る










Example: java_thread_00.java
/* マルチスレッド */
public class java_thread_00 extends Thread {
    public java_thread_00(String name) {
        super(name);
    }

    public static void main(String[] args) {
        /* スレッドオブジェクトのインスタンス生成 */
        java_thread_00 thread0 = new java_thread_00("Thread 0");
        java_thread_00 thread1 = new java_thread_00("Thread 1");

        /* スレッドを開始 */
        thread0.start();
        thread1.start();

        System.out.println("End of main");
    }

    public void run() {
        int i;
        for (i = 0; i < 10; i++) {
            System.out.println(this.getName() + " : " + i);
            try {
                /* 500msec スレッド停止 */
                sleep(500);
            }
            catch (InterruptedException e) {

            }
        }
    }
}
実行結果
> javac java_thread_00.java
> java java_thread_00
End of main
Thread 0 : 0
Thread 1 : 0
Thread 1 : 1
Thread 0 : 1
Thread 0 : 2
Thread 1 : 2
Thread 0 : 3
Thread 1 : 3
Thread 1 : 4
Thread 0 : 4
Thread 1 : 5
Thread 0 : 5
Thread 0 : 6
Thread 1 : 6
Thread 0 : 7
Thread 1 : 7
Thread 1 : 8
Thread 0 : 8
Thread 1 : 9
Thread 0 : 9

[Java]Network Interface の一覧を表示する

NetworkInterface クラスの getNetworkInterfaces メソッドで Network Interface の一覧が取得できる
Example: java_net_04.java
// ネットワーク I/F を表示する
import java.net.*;
import java.util.Enumeration;

public class java_net_04 {
        public static void main(String[] args) {
                try {
                        // Network Interface のリスト
                        Enumeration enuIfs = NetworkInterface.getNetworkInterfaces();
                        while (enuIfs.hasMoreElements()) {
                                NetworkInterface ni = (NetworkInterface)enuIfs.nextElement();
                                System.out.println("Names: " + ni.getName() + " / " + ni.getDisplayName());
                                byte hwAddr[] = ni.getHardwareAddress();
                                if (hwAddr != null) {
                                        System.out.print("     MAC address: ");
                                        for (byte segment: hwAddr) {
                                                System.out.printf("%02x ", segment);
                                        }
                                        System.out.println();
                                }

                                Enumeration ipaddrs = ni.getInetAddresses();
                                while (ipaddrs.hasMoreElements()) {
                                        InetAddress address = (InetAddress)ipaddrs.nextElement();
                                        System.out.println("     Address: " + address.getHostAddress());
                                }
                        }
                }
                catch (Exception e) {
                        System.err.println(e);
                        return;
                }
        }
}
実行結果
> javac java_net_04.java
> java java_net_04
Names: lo / MS TCP Loopback interface
     Address: 127.0.0.1
Names: eth0 / VMware Virtual Ethernet Adapter for VMnet8
     MAC address: xx xx xx xx xx xx
     Address: 192.168.153.1
Names: eth1 / VMware Virtual Ethernet Adapter for VMnet1
     MAC address: xx xx xx xx xx xx
     Address: 192.168.247.1
Names: eth2 / Intel(R) 82566DM-2 Gigabit Network Connection - ?p?P?b?g ?X?P?W
     MAC address: xx xx xx xx xx xx
     Address: 192.168.1.1

[Java]ネットワーク経由でのデータの取得

URL クラスの openStream メソッドでデータを取得する
Proxy サーバを指定する場合は System.setProperty で各プロパティ値を設定する
Example: java_net_03.java
// データを取得する
import java.net.*;
import java.io.*;

public class java_net_03 {
        public static void main(String[] args) {
                try {
                        // Proxy の設定
                        System.setProperty("proxySet", "true");
                        System.setProperty("proxyHost", "myproxy.mydomain");
                        System.setProperty("proxyPort", "8080");

                        URL url = new URL(args[0]);
                        FileOutputStream out = new FileOutputStream(args[1]);
                        InputStream input = url.openStream();
                        while (true) {
                                int read = input.read();
                                if (read == -1) {
                                        break;
                                }
                                out.write(read);
                        }
                        out.close();
                }
                catch (Exception e) {
                        System.err.println(e);
                        return;
                }
        }
}
実行結果
> javac java_net_03.java
> java java_net_03 http://www.google.co.jp/intl/ja_jp/images/logo.gif logo.gif
実行したディレクトリに logo.gif というファイルが生成される

[Java]URL 成分の分解

URL クラスの getProtocol, getHost, getPort, getFile, getRef メソッドを使用して、URL の各成分を分解することができる
Example: java_net_02.java
// URL を各要素に分解
import java.net.*;

public class java_net_02 {
        public static void main(String[] args) {
                try {
                        URL url = new URL(args[0]);
                        System.out.println("Schema   : " + url.getProtocol());
                        System.out.println("Host     : " + url.getHost());
                        System.out.println("Port     : " + url.getPort());
                        System.out.println("Path     : " + url.getFile());
                        System.out.println("Reference: " + url.getRef());
                }
                catch (Exception e) {
                        System.err.println(e);
                        return;
                }
        }
}
実行結果
> javac java_net_02.java
> java java_net_02 http://localhost:80/new.html#hoge
Schema   : http
Host     : localhost
Port     : 80
Path     : /new.html
Reference: hoge

[Java]InetAddress クラス

Java のネットワークプログラムを作成するにあたり、ホストの情報を格納するクラス InetAddress クラスがある。

getByName
getByName メソッドで InetAddress クラスを取得し、取得後に getHostName, getHostAddress メソッドでホスト名や IP アドレスを取得することができる。
Example: java_net_00.java
import java.net.*;

public class java_net_00 {
    public static void main(String[] args) {
        InetAddress host = null;
        try {
            host = InetAddress.getByName(args[0]);
        }
        catch (UnknownHostException e) {
            System.out.println("Not found " + args[0]);
            return;
        }
        System.out.println("Host name = " + host.getHostName());
        System.out.println("IP = " + host.getHostAddress());
    }
}

実行結果
> javac java_net_00.java
> java java_net_00 www.google.com
Host name = www.google.com
IP = 66.249.89.147

getLocalHost
ローカルホストの情報を取得する場合は getLocalHost メソッドを使用する
Example: java_net_01.java
import java.net.*;

public class java_net_01 {
    public static void main(String[] args) {
        InetAddress host = null;
        try {
            host = InetAddress.getLocalHost();
        }
        catch (UnknownHostException e) {
            System.err.println(e);
            return;
        }
        System.out.println(host);
    }
}

実行結果
> javac java_net_01.java
> java java_net_01
my-windows-pc/192.168.0.1

[Java]ファイル入出力

ファイル読み込み
FileReader, BufferedReader クラスを使ってファイルの読み込みを行う
Example: java_file_00.java
/* ファイル読み込み */
import java.io.*;

public class java_file_00 {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Input file name");
            System.exit(1);
        }

        try {
            FileReader fr = new FileReader(args[0]);
            BufferedReader br = new BufferedReader(fr);

            String str;
            while ((str = br.readLine()) != null) {
                System.out.println(str);
            }
            br.close();
            System.out.println("------------------ End");
        }
        catch (IOException e) {
            e.printStackTrace();
            System.out.println("Error");
            System.exit(1);
        }
    }
}
実行結果
> javac java_file_00.java
> java java_file_00 java_file_00.java
/* ファイル読み込み */
import java.io.*;

public class java_file_00 {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Input file name");
            System.exit(1);
        }

        try {
            FileReader fr = new FileReader(args[0]);
            BufferedReader br = new BufferedReader(fr);

            String str;
            while ((str = br.readLine()) != null) {
                System.out.println(str);
            }
            br.close();
            System.out.println("------------------ End");
        }
        catch (IOException e) {
            e.printStackTrace();
            System.out.println("Error");
            System.exit(1);
        }
    }
}
------------------ End

ファイル書き込み
FileOutputStream, OutputStreamWriter, BufferedWriter クラスを使ってファイルへの書き込みを行う
Example: java_file_01.java
/* ファイル書き込み */
import java.io.*;

public class java_file_01 {
    public static void main(String[] args) {
        try {
            FileOutputStream fos = new FileOutputStream("test.txt");
            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
            BufferedWriter bw = new BufferedWriter(osw);
            String str = "Hello, world\n";
            bw.write(str);
            str = "日本語入力はできますか?\n";
            bw.write(str);

            bw.close();
            osw.close();
            fos.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
ソースコードのエンコードを UTF-8 にする場合はコンパイル時に -encoding UTF-8 オプションをつけないと日本語文字列の処理に失敗してしまう

実行結果
> javac -encoding UTF-8 java_file_01.java
> java java_file_01
test.txt は UTF-8 で以下のように書き込まれる
Hello, world
日本語入力はできますか?

[Trac]log 出力設定

C:\usr\Trac\projects\trac_test\conf の trac.ini の以下を変更
log_type = file

[Trac]プラグインのアンインストール

  • python setup.py install でインストールしたプラグインをアンインストールするには、プラグインがインストールされたディレクトリ (通常は Python ディレクトリ下の Lib/site-packages) にある該当プラグインの egg ファイルを直接削除すればよい
  • 削除後に Apache を再起動するとプラグインがアンインストールされている。

[Trac]チケットのコメントを編集するプラグイン

チケットに追記したコメントを編集する機能はデフォルトでは準備されていない。そこで TicketChange プラグインをインストールすることでコメントの編集が行えるようにする。
TicketChange プラグインのインストールには TicketDelete プラグインが必要となるので、事前に TicketDelete プラグインをインストールしておく。
  • TicketDelete プラグインのインストール
    1. TicketDeletePlugin - Trac Hacks - Plugins Macros etc. - Trac からプラグインをダウンロード、展開する
    2. 展開したディレクトリ内にある setup.py を実行する
      > python setup.py install
      
    3. Apache を再起動する
    4. Trac の Admin ページにある Plugins で tracticketdelete がインストールされていることを確認する
    5. TicketDeletePlugin を enalbe にする
  • TicketChange プラグインのインストール
    1. TicketChangePlugin - Trac Hacks - Plugins Macros etc. - Trac からプラグインをダウンロード、展開する
    2. 展開したディレクトリ内にある setup.py を実行する
      > python setup.py install
      
    3. Apache を再起動する。
    4. Trac の Admin ページにある Plugins で tracticketchange がインストールされていることを確認する
    5. TicketChangePlugin を enable にする
    6. チケットページのコメント欄に Change リンクが表示されるようになる

[Trac]Scrum Burndown プラグイン

Scrum Burndown には Timing and Estimation plugin が必要となる。
  1. ScrumBurndownPlugin - Trac Hacks - Plugins Macros etc. - Trac から Python 2.5 用 (TracBurndown-1.9.1-py2.5.egg) をダウンロードする
  2. Trac の Admin ページにある Plugins を選択すると右側に Install Plugin という項目がある。そこで TracBurndown-1.9.1-py2.5.egg を選び Install を実行する
  3. Project の upgrade が必要であるエラーが表示されるので指示に従い upgrade を行う
    > c:\usr\Python25\Scripts\trac-admin.exe c:\home\trac\test upgrade
    Attempting to create the burndown table
    Attempting to modify the milestone table
    Upgrade done.
    
  4. Trac の Admin ページにある Plugins で tracburndown がインストールされていることを確認する
  5. 「Burndown」の項目が画面上方のナビゲーションバーに追加される

[Trac]Timing and Estimation プラグイン

  1. TimingAndEstimationPlugin - Trac Hacks - Plugins Macros etc. - Trac から Trac 0.11 用のファイルをダウンロード、展開する
  2. 展開したディレクトリ内にある setup.py を実行する
    > python setup.py install
    
  3. Apache を再起動する
  4. Trac の Admin ページにある Plugins で timingandestimationplugin がインストールされていることを確認する
  5. timingandestimationplugin 以下のコンポーネントを enable にする
  6. Project の upgrade が必要であるエラーが表示されるので指示に従い updgrade を行う
    > c:\usr\Python25\Scripts\trac-admin.exe c:\home\trac\test upgrade
    Timing and Estimation needs an upgrade
    Upgrading Database
    Creating bill_date table
    Creating report_version table
    Upgrading report_version table to v4
    Dropping report_version table
    Upgrading reports
    Upgrading fields
    Upgrading usermanual
    Done Upgrading
    Upgrade done.
    

[Trac]GanttCalendar プラグイン

  1. Trac GanttCalendar plugin - Recursive Design から GanttCalendar (gantt-calendar.0.1.0.zip) をダウンロードする
  2. 展開したディレクトリ内にある setup.py を実行する
    > python setup.py install
    
  3. Apache を再起動する
  4. Trac の Admin ページにある Plugins で tracganttcalendarplugin がインストールされていることを確認する
  5. tracganttcalendarplugin 以下のコンポーネントを enable にすると「Gantt Ticket」の項目が画面上方のナビゲーションバーに追加される
  6. プロジェクトの conf/trac.ini に次の行を追加する
    [ticket-custom]
    complete         = select
    complete.label   = % Complete
    complete.options = 0|5|10|15|20|25|30|35|40|45|50|55|60|65|70|75|80|85|90|95|100
    complete.order   = 3
    due_assign       = text
    due_assign.label = Start (YYYY/MM/DD)
    due_assign.order = 1
    due_close        = text
    due_close.label  = End (YYYY/MM/DD)
    due_close.order  = 2
    
  7. チケット編集ページに Start, End, Complete の項目が追加され、この値が「Gantt Ticket」で表示される

[Trac]iniAdmin プラグイン

  1. IniAdminPlugin - Trac Hacks - Plugins Macros etc. - Trac から iniAdmin を入手する
  2. 展開したディレクトリ内にある setup.py を実行する
    > python setup.py install
    
  3. Apache を再起動する
  4. Trac の Admin ページにある Plugins で iniadmin がインストールされていることを確認する
  5. IniAdminPlugin を enable にすると Admin ページに trac.ini の設定を行う項目が追加される

[Trac]Windows に Trac をインストール

以下のパッケージをインストールする
Table 1. Trac に必要なパッケージ
パッケージバージョン入手先
Active Python2.5.5.7ActiveState
Python setuptools0.6c9(Python2.5 用)Python Package Index : setuptools 0.6c11
mod_python3.3.1 (Windows, Apache2.2 用)mod_python.org
  1. Active Python 2.5.5.7 をダウンロード、インストールする
  2. Windows 用の Python setupttols 0.6c をダウンロード、インストールする
  3. Python25/Scripts に easy_install.exe がインストールされているので実行する
    > easy_install.exe Trac
    Searching for Trac
    Reading http://pypi.python.org/simple/Trac/
    Reading http://trac.edgewall.com/
    Reading http://trac.edgewall.org/wiki/TracDownload
    Reading http://projects.edgewall.com/trac
    Reading http://projects.edgewall.com/trac/wiki/TracDownload
    Best match: Trac 0.11.4
    Downloading http://pypi.python.org/packages/2.5/T/Trac/Trac-0.11.4-py2.5.egg#md5
    =b97f05e8683b400c28cb022040c333e4
    Processing Trac-0.11.4-py2.5.egg
    creating c:\usr\python25\lib\site-packages\Trac-0.11.4-py2.5.egg
    Extracting Trac-0.11.4-py2.5.egg to c:\usr\python25\lib\site-packages
    Adding Trac 0.11.4 to easy-install.pth file
    Installing trac-admin-script.py script to C:\usr\Python25\Scripts
    Installing trac-admin.exe script to C:\usr\Python25\Scripts
    Installing tracd-script.py script to C:\usr\Python25\Scripts
    Installing tracd.exe script to C:\usr\Python25\Scripts
    
    Installed c:\usr\python25\lib\site-packages\trac-0.11.4-py2.5.egg
    Processing dependencies for Trac
    Searching for Genshi>=0.5
    Reading http://pypi.python.org/simple/Genshi/
    Reading http://genshi.edgewall.org/
    Reading http://genshi.edgewall.org/wiki/Download
    Best match: Genshi 0.5.1
    Downloading http://ftp.edgewall.com/pub/genshi/Genshi-0.5.1-py2.5-win32.egg
    Processing Genshi-0.5.1-py2.5-win32.egg
    Moving Genshi-0.5.1-py2.5-win32.egg to c:\usr\python25\lib\site-packages
    Adding Genshi 0.5.1 to easy-install.pth file
    
    Installed c:\usr\python25\lib\site-packages\genshi-0.5.1-py2.5-win32.egg
    Finished processing dependencies for Trac
    
  4. プロジェクトディレクトリを作成する
    C:\home>mkdir trac
    C:\home>cd trac
    C:\home\trac>mkdir test
    
  5. trac-admin.exe で初期化を行う
    C:\home\trac\test>c:\usr\Python25\Scripts\trac-admin.exe c:\home\trac\test initenv
    Creating a new Trac environment at c:\home\trac\test
    
    Trac will first ask a few questions about your environment
    in order to initialize and prepare the project database.
    
     Please enter the name of your project.
     This name will be used in page titles and descriptions.
    
    Project Name [My Project]> trac_test ← プロジェクト名を入力
    
     Please specify the connection string for the database to use.
     By default, a local SQLite database is created in the environment
     directory. It is also possible to use an already existing
     PostgreSQL database (check the Trac documentation for the exact
     connection string syntax).
    
    Database connection string [sqlite:db/trac.db]> (Enter)
    
     Please specify the type of version control system,
     By default, it will be svn.
    
     If you don't want to use Trac with version control integration,
     choose the default here and don't specify a repository directory.
     in the next question.
    
    Repository type [svn]> (Enter)
    
     Please specify the absolute path to the version control
     repository, or leave it blank to use Trac without a repository.
     You can also set the repository location later.
    
    Path to repository [/path/to/repos]> (Enter)
    
    Creating and Initializing Project
    (中略)
    Project environment for 'trac_test' created.
    
    You may now configure the environment by editing the file:
    
      c:\home\trac\test\conf\trac.ini
    
    If you'd like to take this new project environment for a test drive,
    try running the Trac standalone web server `tracd`:
    
      tracd --port 8000 c:\home\trac\test
    
    Then point your browser to http://localhost:8000/test.
    There you can also browse the documentation for your installed
    version of Trac, including information on further setup (such as
    deploying Trac to a real web server).
    
    The latest documentation can also always be found on the project
    website:
    
      http://trac.edgewall.org/
    
    Congratulations!
    
  6. Apache で動作するように mod_python 3.3.1 (win32, py2.5, Apache2.2) をダウンロード、インストールする
    Apache のインストール先を聞かれた時はインストーラは modules ディレクトリが知りたいので bin ディレクトリではなく Apache のルートディレクトリを指定する
  7. apache/conf/httpd.conf に以下を追記
    ### Trac ###
    LoadModule python_module modules/mod_python.so
    <IfModule python_module>
     <Location "/trac">
      SetHandler mod_python
      PythonInterpreter main_interpreter
      PythonHandler trac.web.modpython_frontend
      PythonOption TracEnvParentDir "c:\home\trac"
      PythonOption TracUriRoot /trac
     </Location>
    </IfModule>
    
  8. Apache を再起動する
  9. ブラウザで http://localhost/trac にアクセスし trac_test プロジェクトが表示されることを確認する
  10. ユーザ登録 (全プロジェクトを通してのユーザ登録) をする
    apache\bin\htpasswd.exe -c c:\home\trac\trac.htpasswd user-name
    Automatically using MD5 format.
    New password: ********
    Re-type new password: ********
    Adding password for user user-name
    
  11. httpd.conf の で囲まれた箇所に以下を追加
    AuthType Basic
    AuthName "Trac"
    AuthUserFile "c:\home\trac\trac.htpasswd"
    Require valid-user
    
  12. 作成したユーザに Admin 権限を与える
    C:\home\trac\test>c:\usr\Python25\Scripts\trac-admin.exe c:\home\trac\test
    Welcome to trac-admin 0.11.4
    Interactive Trac administration console.
    Copyright (c) 2003-2009 Edgewall Software
    
    Type:  '?' or 'help' for help on commands.
    
    Trac [c:\home\trac\test]> permission add user-name TRAC_ADMIN
    Trac [c:\home\trac\test]> permission list user-name
    (user-name で指定したユーザの権限一覧が表示される)
    
    User       Action
    --------------------------------
    user-name  BROWSER_VIEW
    user-name  CHANGESET_VIEW
    (以下略)
    

google-code-prettify

  1. google-code-prettify から prettify-21-Jul-2010.zip をダウンロードする
  2. ダウンロードしたファイルを展開する
  3. 適応する HTML ソースのヘッダに以下を追加する
    <head>
      <title>TEST</title>
      <link href="google-code-prettify/prettify.css" type="text/css" rel="stylesheet"/>
      <script type="text/javascript" src="google-code-prettify/prettify.js"></script>
    </head>
    
  4. 適応する HTML ソースの body タグに onload="prettyPrint()" を追加する
    <body onload="prettyPrint()">
    
  5. 適応するプログラムコードの pre 要素に class="prettyprint" を追加する
    <pre class="prettyprint">
    

[Ubuntu]フォント (ttf) のインストール

Ubuntu へのフォントインストール
  1. /etc/fonts/fonts.conf でフォントのインストール先を確認する
    <dir>/usr/share/fonts</dir>
    <dir>/usr/share/X11/fonts</dir>
    <dir>/usr/local/share/fonts</dir>
    <dir>~/.fonts</dir>
    
  2. TrueType フォントは /usr/share/fonts/truetype/ の下に配置するのが慣例
  3. フォントファイルをコピーする
  4. .ttf ファイルのモードを rw-r--r-- に変更する
    $ sudo chmod 644 *
    
  5. フォントキャッシュをリフレッシュする
    $ sudo fc-cache -f -v
    
年賀状作成に利用できる行書フォント: 白舟書体

[Subversion]merge

trunk の更新を branch に適合する
$ svn diff -r 7:9 file:///c:/usr/svn/repositories/svn_test/trunk
$ svn merge -r 7:9 file:///c:/usr/svn/repositories/svn_test/trunk

[Subverion]log

log 確認
以下のようにすると test.c が変更されたときの更新コメントが見ることができる
$ svn log test.c
ログファイルの修正
  1. 修正するリビジョンの確認
    $ svn log file:///c:/usr/svn/repositories/svn_test/trunk -r 8
    ------------------------------------------------------------------------
    r8 | User Name | 2008-10-29 22:26:44 +0900 (水, 29 10 2008) | 1 line
    Add
    ------------------------------------------------------------------------
    
  2. ログのバックアップを取る
    $ svn log file:///c:/usr/svn/repositories/svn_test/trunk -r 1:HEAD > log.txt
    
  3. newlog.txt を作成して修正文章を入れる
  4. newlog.txt を反映する
    $ svnadmin setlog --bypass-hooks c:\usr\svn\repositories\svn_test -r 8 newlog.txt
    

[Subverion]タグ付け

tags の下にコピーをしてタグ付けとする。基本はブランチと同じでただのコピー
$ svn copy file:///c:/usr/svn/repositories/svn_test/trunk file:///c:/usr/svn/repositories/svn_test/tags/release-1.0 -m "Tagging the 1.0 release"

[Subverion]ブランチ作成

branches の下にコピーをして分岐さる
$ svn copy file:///c:/usr/svn/repositories/svn_test/trunk file:///c:/usr/svn/repositories/svn_test/branches/nakao-branch -m "Creating a private branch of /svn_test/trunk"

[Subverion]export

レポジトリから Subversion 用管理ファイルを除いてファイルを取り出す
$ svn export file:///c:/usr/svn/repositories/svn_test/trunk svn_test

[Subversion]commit

作業結果をレポジトリに反映する
$ svn commit -m "Add comment"
Sending test.c
Transmitting file data .
Committed revision 2.

[Subverion]diff, 作業コピーと元のリビジョンの差分表示

$ svn diff
Index: test.c
===================================================================
--- test.c (revision 1)
+++ test.c (working copy)
@@ -2,6 +2,7 @@
int main(void)
{
+     /* Hello world と表示します */
      printf("Hello, world\n");
      return 0;

[Subverion]Checkout

レポジトリからローカルにコピーして作業を開始する
$ svn checkout file://localhost/c:/usr/svn/repositories/svn_test/trunk svn_test
A svn_test\test.c
Checked out revision 1.
カレントディレクトリ以下に svn_test ディレクトリが作られ、その下に .svn ディレクトリと test.c が作られる
作成されるディレクトリ構成は以下のようになる。
svn_test
   |
   +---- .svn
   +---- test.c

[Subverion]ソースファイル追加

カレントディレクトリ以下にあるファイルをレポジトリ管理化に追加 (import) する
$ svn import svn_test file://localhost/c:/usr/svn/repositories/svn_test/trunk -m "Initial import"
Adding test.c
Committed revision 1.
以下のようなツリー構成になる
svn_test
   |
   +-- trunk
   |    +----- test.c
   |
   +-- branches
   +-- tags

[Subverion]ソースファイル追加

カレントディレクトリ以下にあるファイルをレポジトリ管理化に追加 (import) する
$ svn import svn_test file://localhost/c:/usr/svn/repositories/svn_test/trunk -m "Initial import"
Adding test.c
Committed revision 1.
以下のようなツリー構成になる
svn_test
   |
   +-- trunk
   |    +----- test.c
   |
   +-- branches
   +-- tags

[Subverion]レポジトリのバックアップ・リストア

バックアップ
$ svnadmin dump /usr/svn/repositories/svn_test > svn_test_20081109.dump
リストア
$ svnadmin create /newdir/repositories/svn_test
$ svnadmin load /newdir/repositories/svn_test < svn_test_20081109.dump

[Subversion]プロジェクトのリポジトリ作成

  1. Repository の下にプロジェクト用ディレクトリを作成する
  2. c:\usr\svn\repositories\ に SVN サーバの管理するディレクトリがあるとする
    $ mkdir c:\usr\svn\repositories\svn_test
    $ svnadmin create c:\usr\svn\repositories\svn_test
    
  3. trunk, branches, tags のディレクトリを作成する。
    $ svn mkdir file://localhost/c:/usr/svn/repositories/svn_test/trunk -m "Initial"
    $ svn mkdir file://localhost/c:/usr/svn/repositories/svn_test/tags -m "Initial"
    $ svn mkdir file://localhost/c:/usr/svn/repositories/svn_test/branches -m "Initial"
    
Table: ツリー名一覧
trunk本流の開発ツリー
branch本流の開発ツリーとは異なる変更を加えるツリー
tagリポジトリで管理しているファイル群の特定のリビジョンを保存する機能

[Subversion]インストール for Windows XP

  1. subversion.tigris.org から win32 用のバイナリをダウンロード
  2. バイナリの本体は collab.net からダウンロードする
  3. c:/usr/svn にインストール
  4. レポジトリは c:/usr/svn/repositories を指定
  5. SVN_EDITOR export SVN_EDITOR=emacs と定義して commit 時のコメントを emacs で記述できるようにする

[gEDA]Title block の外し方

タイトルブロック (title-B.sym) は起動時から固定されているので削除は以下の手順で行う











  1. region select で Titleblock を選択する
  2. [編集] - [ロック解除]
  3. Delete キーを押して削除する

[gEDA]LinuxMint12 へのインストール

  1. Menu -> その他 -> ソフトウェアの管理
  2. 右上の検索窓に geda と入力
  3. geda を選択
  4. [インストール] ボタンを押す

[Ant]Ant から Makefile を呼び出す

Ant から Makefile を呼び出すのはいささか本末転倒のような気がするが、既に Makefile がある環境などで CruiseControl を使いたい場合などに応用ができるかもしれない。
build.xml に を使用して make を呼び出すようにしておく。
<?xml version="1.0"?>
<project name="hello" basedir="." default="all">
  <target name="clean">
    <exec executable="make">
      <arg value="clean"/>
    </exec>
  </target>
  <target name="compile">
    <exec executable="make">
      <arg value=""/>
    </exec>
  </target>
  <target name="all" depends="clean,compile"/>
</project>

[Ant]CppUnit テスト

以下のような build.xml を準備する
<?xml version="1.0"?>
<project name="CppUnit" basedir="." default="all">
  <taskdef resource="cpptasks.tasks"/>
  <property name="build.dir" value="build"/>
  <property name="dist.dir" value="dist"/>
  <property name="src.dir" value="src"/>
  <target name="init">
    <mkdir dir="${build.dir}"/>
    <mkdir dir="${dist.dir}"/>
  </target>
  <target name="clean">
    <delete dir="${build.dir}"/>
    <mkdir dir="${build.dir}"/>
    <delete dir="${dist.dir}"/>
    <mkdir dir="${dist.dir}"/>
  </target>
  <target name="compile" depends="init">
    <cc outtype="executable"
        subsystem="console"
        outfile="${dist.dir}/test"
        objdir="${build.dir}"
        debug="true">
      <compiler name="g++">
        <fileset dir="${src.dir}" includes="*.cpp"/>
      </compiler>
      <linker name="gcc" libtool="true">
        <libset libs="cppunit,stdc++"/>
      </linker>
    </cc>
  </target>
  <target name="test" depends="compile">
    <exec executable="${dist.dir}/test.exe">
      <arg value=""/>
    </exec>
  </target>
  <target name="all" depends="init,clean,compile"/>
</project>
ant, ant test を実行すると CppUnit のテスト用に作成した test.exe が実行され結果が表示される。
>ant test
Buildfile: build.xml
init:
compile:
[cc] Starting dependency analysis for 3 files.
[cc] 3 files are up to date.
[cc] 0 files to be recompiled from dependency analysis.
[cc] 0 total files to be compiled.
[cc] Starting link
test:
[exec] This is Counter test
[exec] CounterTest::test_init : OK
[exec] CounterTest::test_incr : OK
[exec] CounterTest::test_clear : assertion
[exec] CounterTest.cpp:34:Assertion
[exec] Test name: CounterTest::test_clear
[exec] equality assertion failed
[exec] - Expected: 1
[exec] - Actual : 0
[exec]
[exec] Failures !!!
[exec] Run: 3 Failure total: 1 Failures: 1 Errors: 0
[exec] Result: 1
BUILD SUCCESSFUL
Total time: 0 seconds