CSV/TSV Converter Library in C
hacker emblem Happy Hacking!


English Here (machine translation)

CSV/TSV データ形式変換ライブラリ

この C 言語ライブラリは、いわゆる CSV ファイルを読み込んで通常の文字列として扱えるように変換することができます。また、通常の文字列から CSV 形式への変換も行えます。ライセンスは GPL とします。

API を使用するためのヘッダは csv_converter.h で、API の実装は csv_converter.c です。
また、テスト用のプログラムとして data.c も記述しました。テストデータファイルは テストデータファイルセットになります。

CSV 形式で文字列データ列をファイル出力するための API "write_csv_columns()" を追加しました。この write_csv_columns() をテストするプログラムは write_csv_columns_test.c です。

現在、Solaris 上の Fujitsu 製 C コンパイラ "fcc" でのコンパイルと動作確認が済んでいます。Makefileには、Cygwin GCC と Linux の場合についても定義してありますが、これらについてはコンパイルできることを確認してあります。

ライブラリ API の説明

  1. Parse the CSV/TSV formatted file
    Errcode_Parse_CSV_File_t parse_csv_file(const char *path
    , char delimit
    , Parsed_CSV_t *parsed
    )

    CSV 形式データのファイルを読み出し、すべてのレコードとその項目を通常の C 言語文字列に変換した結果を収めるデータ構造 Parsed_CSV_t を構築します。
    C 言語文字列配列などのデータ構造構築に必要な領域はすべて動的に獲得されます。

    このデータ構造から R 行目の C 番目の項目に対応する文字列にアクセスするには、以下のように記述します。

    pasred->lines[R].cols[C]

    また、parsed->line_cnt は CSV レコード数を、parsed->max_cols_cnt は最大の項目数を、parsed->min_cols_cnt は最小の項目数を、そして、parsed->lines[R].cols_cnt は R 行目のレコードの項目数をそれぞれ示します。

    • path -- CSV 形式データのファイルへのパス
    • delimit -- CSV 形式データの項目区切り文字。
      二重引用符 (")、改行 (\r)、行送り (\n) 以外のシングル・バイト文字を受け付けます。
    • parsed -- CSV 形式データを変換した結果を展開するデータ構造のハンドルへのアドレス

    戻り値 Errcode_Parse_CSV_File_t は以下の意味を持ちます。

    • EPCF_NORMAL_END = 0

      正常終了。ファイルの内容は変換され、parsed をハンドルとしてアクセス可能になりました。

    • EPCF_Null_Pointer_Para = 1

      不正な引数を渡された場合。

    • EPCS_Illegal_Delimiter = 2

      CSV データの項目区切り文字が、二重引用符 (")、改行 (\r)あるいは行送り (\n) のいずれかであった場合。

    • EPCF_Not_Readable_File = 3

      読み込み権限がないかあるいは存在していないファイルのパスを渡された場合。

    • EPCF_Cannot_Open_File = 4

      ファイルの読み込みに失敗した場合。

    • EPCF_Cannot_Reallocate_Parsed_CSV_t_Lines_Vector = 5

      CSV レコードの配列 parsed->lines の動的メモリ領域拡張に失敗した場合。

    • EPCF_Cannot_Allocate_Parsed_CSV_Line_t = 6

      CSV 形式データ・ファイルの読み込みバッファ領域の動的獲得に失敗した場合。

    • EPCF_Broken_CSV_File = 7

      CSV 形式データ・ファイル内に CSV レコードとして不正なものがある場合。不正な CSV レコードとは、行末が「改行・行送り "\r\n"」になっていないものをさします。

    • EPCF_Cannot_Allocate_Memory = 8

      CSV レコードを通常の C 言語文字列の配列に変換する際に動的メモリ獲得あるいは拡張に失敗した場合。

    • EPCF_Failed_Convert_CSV_Line = 9

      CSV レコードの C 言語文字列への変換に失敗した場合。

    • EPCF_Zero_Size_File = 10

      ファイルのサイズがゼロの場合。


  2. Release the memory blocks that `parse_csv_file()' allocated.
    void free_parsed_csv_t(Parsed_CSV_t *parsed)

    parse_csv_file()で動的に獲得したメモリ領域を解放します。

    • parsed -- parse_csv_file() API で獲得した動的メモリのアドレス

    戻り値はありません。

  3. Convert a CSV-line to the vector of C-strings
    char **csv_line_to_strings(char *csvl
    , char delimitch
    , int *colscnt
    )

    CSV 形式レコードを C 言語文字列の配列に変換します。各文字列はレコードの項目に対応します。
    CSV 形式レコードを格納している領域は動的に獲得されている必要があり、また、その領域は項目それぞれのデータ形式変換に使用しますので CSV レコードの内容は破壊されます。

    • csvl -- CSV 形式レコード文字列が展開されている動的に獲得されたメモリ領域のアドレス
    • delimitch -- 変換する CSV 形式の項目区切り文字。
      二重引用符 (")、改行 (\r)、行送り (\n) 以外のシングル・バイト文字を受け付けます。
    • colscnt -- 変換した CSV レコード中の項目数を出力する変数のアドレス

    戻り値は以下の意味を持ちます。

    • NULL 以外 -- 正常終了。CSV 形式レコードを変換した C 言語文字列の配列を展開した動的メモリ領域のアドレス
    • NULL で errno が ENOMEM あるいは EAGAIN -- C 言語文字列配列領域のメモリの獲得あるいは拡張に失敗した場合

  4. Read a CSV line from a stream. The CSV-line terminates with CR-LF sequence.
    char *get_csv_line(FILE *stream
    , char *csvl
    , size_t *csvlsz
    , int *is_broken
    )

    CSV 形式データのストリームから CSV レコードをひとつ読み出します。
    CSV レコードは動的に獲得されたメモリ領域に読み出されます。

    • stream -- CSV 形式のデータを読み出すストリーム
    • csvl -- 読み出した CSV レコードを展開する動的メモリ領域のアドレス。
      新たに領域を獲得したい場合は NULL を渡します。
      NULL を渡された場合、獲得したメモリ領域のアドレスが関数値になります。
    • csvlsz -- CSV レコードを展開している動的領域のサイズ変数のアドレス。
      読み出した CSV レコードを展開するために、csvl が示す動的領域のサイズが拡張される場合があるので、サイズ変数へのアドレスを要求しています。
    • is_broken -- 読み出した行が CSV レコードとして不良の場合に 1 に設定されます。
      正常な CSV レコードが読み出せた場合は 0 に設定されます。
      正常な CSV レコードとは、行末が「改行・行送り "\r\n"」シーケンスになっているものと定義しています。

    戻り値は以下の意味を持ちます。

    • NULL 以外 -- 正常終了。CSV 形式レコードを読み込んだ動的メモリ領域のアドレス。
    • NULL で errno が ENOMEM あるいは EAGAIN -- CSV 形式レコード読み込みメモリの獲得あるいは拡張に失敗した場合
    • NULL で errno が ENOMEM でも EAGAIN でもない -- ストリームの終端 EOF まで読み出した場合。
      あるいは、不正な引数を渡された場合

  5. Convert an array of C-strings to a CSV-line
    char *strings_to_csv_line(char *strings[]
    , int n
    , char *csv_line
    , size_t *csv_line_sz
    , char delimit
    )

    C 言語文字列の配列をひとつの CSV 形式のレコード文字列に変換します。
    変換後のレコード文字列を展開するメモリ領域は動的に獲得されます。

    • strings[] -- CSV 形式レコードに変換される C 言語文字列配列のアドレス
    • n -- strings[] の示す C 言語文字列配列の要素数
    • csv_line -- 変換後のCSV 形式レコード文字列を展開する動的獲得されたメモリ領域のアドレス。
      領域を新たに獲得したい場合は、NULL を指定してください。
      NULL が指定されると、新たに獲得した領域のアドレスを関数値として返します。
    • csv_line_sz -- csv_line の示すアドレスで獲得された動的メモリ領域のサイズ変数のアドレス。
      strings[] を変換した結果、CSV 展開メモリのサイズが拡張される場合があるので、サイズ変数へのアドレスを要求しています。
    • delimit -- CSV 形式レコードの項目を区切る文字を指定します。
      二重引用符 (")、改行 (\r)、行送り (\n) 以外のシングル・バイト文字であればなんでも項目区切り文字に使えます。

    戻り値は以下の意味を持ちます。

    • NULL 以外 -- 正常終了。CSV 形式レコード文字列が展開されている動的メモリ領域のアドレス
    • NULL で errno が ENOMEM あるいは EAGAIN -- CSV レコード展開メモリの獲得あるいは拡張に失敗した場合
    • NULL で errno が ENOMEM でも EAGAIN でもない -- 不正な引数を渡された場合

  6. Convert a C-string to a CSV-string
    char *string_to_csv_string(const char *string
    , char *csv
    , size_t *csv_str_sz
    )

    C 言語文字列を CSV 形式の文字列に変換します。変換後の文字列を展開するメモリ領域は動的に獲得されます。

    • string -- CSV 形式に変換する C 言語文字列のアドレス
    • csv -- 変換後の CSV 形式文字列を展開する動的獲得されたメモリ領域のアドレス。
      領域を新たに獲得したい場合は、NULL を指定してください。
      NULL が指定されると、新たに獲得した領域のアドレスを関数値として返します。
    • csv_str_sz -- csv が示すアドレスで獲得されたメモリ領域のサイズ変数のアドレス。
      string を変換した結果、CSV 展開メモリのサイズが拡張される場合があるので、サイズ変数へのアドレスを要求しています。

    戻り値は以下の意味を持ちます。

    • NULL 以外 -- 正常終了。CSV 形式に変換された文字列が展開されている動的メモリ領域のアドレス
    • NULL で errno が ENOMEM あるいは EAGAIN -- CSV 展開メモリの獲得あるいは拡張に失敗した場合
    • NULL で errno が ENOMEM でも EAGAIN でもない -- 不正な引数を渡された場合

  7. Writing several strings to the CSV file.
    FILE *write_csv_columns(const char *file_path
    , const char delimit
    , FILE *fp
    , long *column_pos
    , ...
    )

    C 言語文字列のデータ列を CSV 形式ファイルに出力します。文字列を CSV 形式に変換するためのメモリ領域は動的に獲得され、API から戻る際に解放されます。
    可変引数に出力処理の指示子と桁数、文字列アドレス、空カラム数などの必要な引数の指定を出力順で並べて使用します。

    • file_path -- 出力先の CSV 形式ファイルのパス。NULL 以外を指定することで出力ファイルを新規作成 (既存ファイルの場合はその内容を上書き) する。NULL を渡すと、以前にこの API に指定したファイルに追記することを指示したことになる。
    • delimit -- 出力先の CSV 形式ファイルの区切り文字。ヌル文字 '\0'、二重引用符 '"'、改行/行送り文字 ('\n', '\r') を指定することは出来ない。
    • fp -- 出力先ファイルのファイル・ポインタ。file_path に NULL を指定した場合、それ以前のこの API 呼び出しで返された戻り値を渡さなければならない (後述の CSV_CONTINUE 出力指示子も参照すること)
    • column_pos -- 出力ファイルのカレントな桁位置を出力するポインタ。API 内で CSV カラム区切り文字の出力が必要か否かを決定するのに使用している。
    • 可変引数並び (...) -- 出力指示子と出力文字列データの並びを指定する。

    出力指示子の指定形式と出力動作の定義:

    • CSV_COLUMN, 出力バイト数, 出力文字列アドレス -- 3 つの可変引数並びで文字列データ出力バイト数だけファイルに出力する。出力される文字列は CSV 形式に変換される。
      出力バイト数が負数であるか、あるいは出力文字列アドレスが NULL の場合は不正引数エラーで異常終了する。
    • CSV_EMPTY, 空カラム数 -- 2 つの可変引数並びで空カラム数分の空欄をファイルに出力する。
      空カラム数が負数の場合は不正引数エラーで異常終了する。
    • CSV_EOL -- CSV 形式ファイルのレコード区切りとして "\r\n" を出力する。
    • CSV_CONTINUE -- 次の呼び出しに継続するために制御を呼び出し元に返す。次の呼び出しでは、引数 file_path に NULL を、fp にこの呼び出しの戻り値を渡す必要がある。
    • CSV_END -- 出力ファイルを閉じる。

    戻り値は以下の意味を持ちます。

    • NULL 以外 -- 正常終了。CSV 形式の出力ファイルへのファイル・ポインタが返される。CSV_END でファイルを閉じた場合もファイル・ポインタが返されることに注意すること。
    • NULL で errno が EINVAL -- 不正な引数が渡された場合
    • NULL で errno が ENOMEM -- CSV 形式に文字列を変換するための動的メモリ獲得に失敗した場合。メモリ不足
    • NULL で errno が EINVAL, ENOMEM 以外 -- ファイルの操作に失敗した場合。errno でファイル操作エラーの内容を示す



2004/12/23 (Thu) 追記:
gcc -W で全ソースコードの検証を行いました。data.c に size_t と sszie_t の比較を行っている箇所があったので、関連する変数を size_t に統一しました。修正後の動作確認済み。

2005/09/24 (Sat) 追記:
文字列データ列を CSV 形式ファイルに出力する write_csv_columns() を追加しました。