// -*- C++ -*-
//  Boost general library 'format'  ---------------------------
//  See http://www.boost.org for updates, documentation, and revision history.

//  (C) Samuel Krempp 2001
//                  krempp@crans.ens-cachan.fr
//  Permission to copy, use, modify, sell and
//  distribute this software is granted provided this copyright notice appears
//  in all copies. This software is provided "as is" without express or implied
//  warranty, and with no claim as to its suitability for any purpose.

// ------------------------------------------------------------------------------
// sample_advanced.cc :  format の高度な使い方の例
// ------------------------------------------------------------------------------

#include <iostream>
#include <iomanip>

#include "boost/format.hpp"

int main(){
    using namespace std;
    using boost::format;
    using boost::io::group;
    using boost::io::str;
    string s;
    stringstream oss;



    //------------------------------------------------------------------------
    // 構文解析された書式文字列を 'formatter' に格納する : 
    // format オブジェクトは通常のオブジェクトである。コピーし、代入し、
    // 引数を与え、ストリームにダンプし、再び引数を与え、等ができる。
    // 従って、ユーザは好きなようにそれらを使うことができる。

    format fmter("%1% %2% %3% %1% \n");
    fmter % 10 % 20 % 30; 
    cout  << fmter;
    //          "10 20 30 10 \n" と表示する
    
    // いったん fmter がすべての引数を与えられると、書式化された文字列は
    // 利用可能なまま残る。 (次の '%' の呼び出しまで)
    // その結果は str() 関数またはストリームの << を通じて利用できる :
    cout << fmter; 
    //          同じ文字列を表示する


    // operator% を再び呼び出すと、引数はオブジェクトの内部でクリアされ、
    // すべての引数が与えられる前に変換文字列を問い合わすことはエラーになる。
    fmter % 1001;
    try  { cout << fmter;   }
    catch (boost::io::too_few_args& exc) { 
      cout <<  exc.what() << "***Dont worry, that was planned\n";
    }

    // 最後の二つの引数だけを与える必要がある。そうすれば再び出力する準備が整う :
    cout << fmter % 1002 % 1003;
    //          "1001 1002 1003 1001 \n" と表示する

    cout  << fmter % 10 % 1 % 2;
    //          "10 1 2 10 \n" と表示する



    //---------------------------------------------------------------
    // format オブジェクトの利用

    // 与えられた命令のために書式化オプションを更新する
    fmter = format("%1% %2% %3% %2% %1% \n");
    fmter.modify_item(4, group(setfill('_'), hex, showbase, setw(5)) );
    cout << fmter % 1 % 2 % 3;
    //          "1 2 3 __0x2 1 \n" と表示
    
    // 引数の一つを束縛する :
    fmter.bind_arg(1, 18);
    cout << fmter % group(hex, showbase, 20) % 30;        // %2 は 20 で 20 == 0x14
    //          "18 0x14 30  _0x14 18 \n" と表示
    
    
    fmter.modify_item(4, setw(0)); // 直前の幅 5 をキャンセルする
    fmter.bind_arg(1, 77); // 最初の引数に関して 18 を 77 で置き換える。
    cout << fmter % 10 % 20;
    //          "77 10 20 0xa 77 \n" と表示する

    try  
    { 
      cout << fmter % 6 % 7 % 8;   // あいやー！arg1 はすでに束縛されているから引数が多すぎる
    }
    catch (boost::io::too_many_args& exc) 
    { 
      cout <<  exc.what() << "***Dont worry, that was planned\n";
    }

    // clear() は通常の引数をクリアするが、束縛された変数はクリアしない :
    fmter.clear();
    cout << fmter % 2 % 3;
    //          "77 2 3 0x2 77 \n" と表示する

    // 通常の引数と束縛された引数の両方をクリアするには clear_binds() を使う :
    fmter.clear_binds(); 
    cout << fmter % 1 % 2 % 3;
    //          "1 2 3 0x2 1 \n" と表示する
    
 
    // 望みの例外を設定する :
    fmter.exceptions( boost::io::all_error_bits ^( boost::io::too_many_args_bit ) );
    cout << fmter % 1 % 2 % 3 % 4 % 5 % 6 ;


   // -----------------------------------------------------------
    // その他:

    // サポートされていない printf の命令 %n と アスタリスク-フィールドは純粋に無視される。
    // それらに引数を与えては *ならない* 。そうするとエラーになる。
    cout << format("|%5d| %n") % 7 << endl;
    //          "|    7| " と表示する
    cout << format("|%*.*d|")  % 7 << endl;
    //          "|7|" と表示する


    // 文字列の切り捨て :
    cout << format("%|.2s| %|8c|.\n") % "root" % "user";
    //          "ro        u.\n" と表示する


    // マニピュレータが書式文字列と衝突する場合 : マニピュレータが勝つ。
    cout << format("%2s")  % group(setfill('0'), setw(6), 1) << endl;
    //          "000001" と表示する
    cout << format("%2$5s %1% %2$3s\n")  % 1    % group(setfill('X'), setw(4), 2) ;
    //          "XXX2 1 XXX2\n" と表示する
    //          幅は書式文字列ではなくマニピュレータによってセットしたように 4 である。
    
    // 入れ子 :
    cout << format("%2$014x [%1%] %2$05s\n") % (format("%05s / %s") % -18 % 7)
                                             % group(showbase, -100);
    //          "0x0000ffffff9c [-0018 / 7] -0100\n" と表示する


    cout << "\n\nEverything went OK, exiting. \n";
    return 0;
}
