【C言語】glib2.0を使ってみた〜confファイル読み込み〜

# はじめに
C言語でアプリケーションを作成するとき、入出力の基本的な処理からコーディングするのは面倒ですし、バグの温床のなりえます。
良い解決策がないか調べたところ、glib2.0というライブラリが
* インストール・利用の容易さ
* 多機能
* ライセンス

という観点で、良さそうであると思いました。
一方、ネット上にあまり情報がなく、公式ドキュメントもわかりにくいということもあり、本記事にて基本的な使い方を紹介したいと思います。

今回は、**confファイルの読み込み**について記載します。

# 動作環境
本記事は、下記の環境で動作を確認しています。
* Ubuntu18.04
* gcc

# インストール手順
下記コマンドでglib2.0一式をインストールすることができます。
Ubuntu18.04の場合、バージョン2.56.4が入るようです。
```bash
sudo apt install libglib2.0-dev
```

# 使用例
本記事では、下記のような設定ファイルを読み込むことを想定します。

```config:keyfile.conf
[value]
key1=test
key2=1
key3=1.5
#シャープでコメント

[array]
key4=0.5,1,1.5
key5=true,false,true
```

上記、設定ファイルを読み込み、読み込み内容を標準出力に表示するソースは下記になります。

```c:main.c
#include <glib.h>

int main()
{
    int i;
    GKeyFile *file;
    GError *err = NULL;
    gchar *key1_value;
    gint key2_value;
    gdouble key3_value;
    gdouble *key4_array;
    gsize key4_array_len;
    gboolean *key5_array;
    gsize key5_array_len;

    //ファイルオブジェクト作成
    file = g_key_file_new();

    //配列の区切り文字を","に設定
    g_key_file_set_list_separator(file, ',');

    if (!g_key_file_load_from_file(file, "./keyfile.conf", 0, &err)) {
        g_print("failed to load keyfile. msg=%s\n", err->message);
    } else {
        g_print("success to load keyfile.\n");
        if ((NULL == (key1_value = g_key_file_get_string(file, "value", "key1", &err)) && (NULL != err))) {
            g_print("failed to parse key1. msg=%s\n", err->message);
        } else if ((0 == (key2_value = g_key_file_get_integer(file, "value", "key2", &err)) && (NULL != err))) {
            g_print("failed to parse key2. msg=%s\n", err->message);
        } else if ((0 == (key3_value = g_key_file_get_double(file, "value", "key3", &err)) && (NULL != err))) {
            g_print("failed to parse key3. msg=%s\n", err->message);
        } else if ((NULL == (key4_array = g_key_file_get_double_list(file, "array", "key4", &key4_array_len, &err)) && (NULL != err))) {
            g_print("failed to parse key4. msg=%s\n", err->message);
        } else if ((NULL == (key5_array = g_key_file_get_boolean_list(file, "array", "key5", &key5_array_len, &err)) && (NULL != err))) {
            g_print("failed to parse key4. msg=%s\n", err->message);
        } else {
            g_print("success to parse all keys.\n");
            g_print("key1 = %s\n", key1_value);
            g_print("key2 = %d\n", key2_value);
            g_print("key3 = %f\n", key3_value);
            
            g_print("key4 = ");
            for (i = 0; i < key4_array_len; i++) {
                g_print("%f,", key4_array[i]);
            }
            g_print("\n");

            g_print("key5 = ");
            for (i = 0; i < key5_array_len; i++) {
                g_print("%s,", key5_array[i] ? "true" : "false");
            }
            g_print("\n");

            //開放処理
            g_free(key1_value);
            g_free(key4_array);
            g_free(key5_array);
            g_key_file_free(file);
        }
    }

    if (NULL != err) {
        g_error_free(err);
    }

    return 0;
}
```
下記のコマンドでコンパイルを行うことができます。
```bash
gcc main.c -o main `pkg-config --cflags --libs glib-2.0`
```

下記のコマンドで実行します。設定ファイルがきちんと読み込めていることが確認できます。
```bash
./main
success to load keyfile.
success to parse all keys.
key1 = test
key2 = 1
key3 = 1.500000
key4 = 0.500000,1.000000,1.500000,
key5 = true,false,true,
```

上記ソースでは、設定ファイルの内容が正しくなかったとき、エラーメッセージを出力するようにしています。
例えば、設定ファイルのkey4の値に`key4=0.5,1,1.5,aa`と小数値の期待に対し、文字列をわざと設定してみます。この状態で再び実行すると、下記のように、aaがfloat値として解釈できない旨を表示してくれます。このようにglibが、エラー要因をわかりやすく表示してくれます。
```bash
./main
success to load keyfile.
failed to parse key4. msg=Value ?aa? cannot be interpreted as a float number.
```

# あとがき
C言語は文字列処理のコーディングに向いておらず、入出力の基本的な処理を作るのは骨が折れます。glib2.0を活用することで、本質ではない部分に割く時間を削減し、本当に重要なことに注力できると思います。


# 参考文献
* [glib2.56manpage](https://www.manpagez.com/html/glib/glib-2.56.0/glib-Key-value-file-parser.php)