bit

glibc regex.h

普段Perlを使ってたせいか、C言語で設定ファイルを読み込ませる処理を書いたとき意外と面倒だったので、その使い方をメモ。設定ファイルごときにPCREは大袈裟と思って、glibcregex にしたせいか。いずれにせよ、ウェブ上の情報が少ない…。

まずは、読み込む部分。

static int _read_config_file(const char * conf_filepath) {
    assert(conf_filepath != NULL);

    int rc;
    FILE * in_file = NULL;
    char line_buff[LINE_BUFF_SIZE];
    regex_t re_kvline;

    regcomp(&re_kvline, REGEXP_KVLINE, REG_EXTENDED | REG_NEWLINE);

    in_file = fopen(conf_filepath, "r");
    if (in_file == NULL) {
        perror("fopen");
        rc = -1;
        goto FINALLY;
    }

    while(fgets(line_buff, LINE_BUFF_SIZE, in_file) != NULL) {
        regmatch_t matched[NB_MATCHES];

        if (line_buff[0] == '#' || line_buff[0] == '\n') { // skip comments
            continue;
        }

        if (regexec(&re_kvline, line_buff, NB_MATCHES, matched, 0) == REG_NOMATCH) {
            fprintf(stderr, "not match:%s\n", line_buff);
            continue;
        }

        line_buff[matched[1].rm_eo] = '\0';
        line_buff[matched[2].rm_eo] = '\0';
        _set_config(line_buff + matched[1].rm_so, line_buff + matched[2].rm_so);
    }

    rc = 0;

FINALLY:

    if (in_file != NULL) {
        rc = fclose(in_file);
        if (rc != 0) {
            perror("fclose");
        }
    }

    regfree(&re_kvline);

    return(rc);
}

regcomp() にエラーチェックがないのは、単体試験で正しい正規表現になっているはずっていう横着。括弧でマッチした部分を抽出するために、REG_EXTENDEDフラグはたぶん必須。_set_config() の中身は適当に。

さて、REGEXP_KVLINEの値をいろいろ変えてみる。

#define REGEXP_KVLINE "^([[:alpha:]])=(.*)$"

とりあえずなら、これでもよい。
でも、イコール(=)の周りに空白を許容したいとか、キーに数字を入れたいとか、でもキーの先頭が数字はやだよねとか色気を出し始める。

#define REGEXP_KVLINE "^([[:alpha:]][[:alnum:]]*)[[:blank:]]*=[[:blank:]]*(.*)$"

これで↓とか、ピコピコ読み込める。

datadir = /var/tmp

さらに、キーにも空白入れたいなとか考える。

#define REGEXP_KVLINE "^([[:alpha:]]([[:alnum:] ]*[[:alnum:]])?)[[:blank:]]*=[[:blank:]]*(.*)$"

読み込む括弧位置が変わってくるので、プログラムの以下の部分も修正。Perl の (?: …) が使いたい。

        line_buff[matched[1].rm_eo] = '\0';
        line_buff[matched[3].rm_eo] = '\0';
        _set_config(line_buff + matched[1].rm_so, line_buff + matched[3].rm_so);

これで

special key 01 = (^o^)

としても読み込めてしまうようになる。