Home> 備忘録: 2007年6月アーカイブ

備忘録: 2007年6月アーカイブ

prefixed_ostream

  • 2007年6月23日 05:37
  • 備忘録
目的

次のような出力を行いたい.


#include <iostream>
#include <fstream>
#include "prefixed_ostream.h"

int main(void)
{
    prefixed_ostream  warning(std::cerr, "WARNING: ");  // 警告出力用フィルタ
    prefixed_ostream  error(std::cerr, "ERROR: ");      // エラー出力用フィルタ

    warning << "This is a warning message." << std::endl;
    error << "This is a long error message from here...\n"
          << "(snip)\n"
          << "to here." << std::endl;

    std::ofstream     ofs("output.txt");    // 例外処理は省略
    prefixed_ostream  comment(ofs, "# ");   // コメント出力用フィルタ

    ofs << "This is a usual line." << std::endl;
    comment << "This is a comment line." << std::endl;
    ofs << "This is a usual line again." << std::endl;

    return 0;
}

$ ./a.out
WARNING: This is a warning message.
ERROR: This is a long error message from here...
ERROR: (snip)
ERROR: to here.
$ cat output.txt
This is a usual line.
# This is a comment line.
This is a usual line again.
$ 

つまり,指定した文字列を各行の先頭に自動的に付記して出力できるようにしたい.

実現方法

このページで提案されている 「フィルタ」 なる概念を利用する.

実装例

バッファが溢れた場合の処理が不適切なためにセグフォが発生し得る事が判明したので,関数 write_with_prefix() の処理を修正 (及びメンバ is_line_head_ を追加).

極力 1 行単位で出力するように修正.


#if !defined PREFIXED_OSTREAM_H_INCLUDED_
#define PREFIXED_OSTREAM_H_INCLUDED_

#include <streambuf>

/// プレフィックスを付記する出力ストリームクラステンプレート
template <typename CharT, typename Traits = std::char_traits<CharT> >
class basic_prefixed_ostream : public std::basic_ostream<CharT, Traits>
{
public:
    /**
     * @brief コンストラクタ
     * @param [in,out] os          対象とする出力ストリーム
     * @param [in]     prefix      プレフィックス
     * @param [in]     buffer_size バッファのサイズ
     */
    basic_prefixed_ostream(
        std::ostream& os,
        const char* prefix = "# ", std::size_t buffer_size = 1024)
        : std::basic_ostream<CharT, Traits>(
            new streambuf<CharT, Traits>(os, prefix, buffer_size)) {}

    /// デストラクタ
    virtual ~basic_prefixed_ostream()
    {
        this->flush();
        delete this->rdbuf();
    }

protected:
    /// basic_prefixed_ostream 専用のストリームバッファクラステンプレート
    template <class CharT2, class Traits2 = std::char_traits<CharT2> >
    class streambuf : public std::basic_streambuf<CharT2, Traits2>
    {
        typedef CharT2                                      char_type;
        typedef Traits2                                     traits_type;
        typedef typename traits_type::int_type              int_type;
        typedef std::basic_ostream<char_type, traits_type>  ostream_type;

        ostream_type*     os_;           ///< 対象とする出力ストリーム
        const char_type*  prefix_;       ///< プレフィックス
        std::size_t       prefix_size_;  ///< prefix_ の文字列長
        char_type*        buffer_;       ///< バッファ
        std::size_t       buffer_size_;  ///< バッファのサイズ
        char_type*        head_;         ///< 書き出すデータの先頭位置
        bool              is_line_head_; ///< 真の時 prefix_ を出力する

        /// バッファをクリアする
        inline void clear_buffer(void)
        {
            traits_type::assign(buffer_, 0, buffer_size_);
            this->setp(buffer_, buffer_ + buffer_size_);
            head_ = buffer_;
        }

        /**
         * @brief プレフィックスを付記して出力する
         * @param [in] force 真の時バッファの中身を強制的に出力する
         */
        void write_with_prefix(bool force)
        {
            // 改行文字が現れる度に 1 行ずつ出力する
            for (char_type* pos = head_; pos < this->pptr(); pos++)
                if (*pos == '\n')
                {
                    if (is_line_head_)
                        os_->write(prefix_, prefix_size_);
                    os_->write(head_, pos + 1 - head_);
                    head_ = pos + 1;
                    is_line_head_ = true;
                }

            // 改行文字が現れないままバッファの先頭から末尾まで使い切った場合
            // または force が真の時 バッファの中身を強制的に全て出力する
            // force が偽であり かつバッファの先頭の方に余裕がある場合は
            // 詰めるだけにする
            if (head_ != this->pptr() && this->pptr() == this->epptr())
            {
                const std::size_t   length = this->pptr() - head_;
                if (head_ == this->pbase() || force)
                {
                    if (is_line_head_)
                        os_->write(prefix_, prefix_size_);
                    os_->write(head_, length);
                    this->clear_buffer();
                    is_line_head_ = false;
                }
                else
                {
                    char_type   temp[length];
                    traits_type::copy(temp, head_, length);
                    this->clear_buffer();
                    traits_type::copy(head_, temp, length);
                    this->pbump(length);
                }
            }
        }

    public:
        /**
         * @brief コンストラクタ
         * @param [in] os          対象とする出力ストリーム
         * @param [in] prefix      プレフィックス
         * @param [in] buffer_size バッファのサイズ
         */
        streambuf(
            ostream_type& os, const char* prefix, std::size_t buffer_size)
            : os_(&os), prefix_(prefix),
              buffer_(new char_type[buffer_size]),
              buffer_size_(buffer_size), is_line_head_(true)
        {
            prefix_size_ = traits_type::length(prefix_);
            this->clear_buffer();
        }

        /// デストラクタ
        virtual ~streambuf()
        {
            delete [] buffer_;
        }

    protected:
        /// バッファが溢れた時に呼ばれるメンバ関数
        virtual int_type overflow(int_type c = traits_type::eof())
        {
            this->write_with_prefix(false);

            if (c != traits_type::eof())
            {
                *(this->pptr()) = traits_type::to_char_type(c);
                this->pbump(1);
                return traits_type::not_eof(c);
            }
            else
                return traits_type::eof();
        }

        /// 書き出し先とバッファを同期する時などに呼ばれるメンバ関数
        virtual int sync(void)
        {
            this->write_with_prefix(true);
            return 0;
        }
    };
};

// 頻繁に利用されるであろうクラスを予め型定義しておく.(<iosfwd> 参照)
typedef basic_prefixed_ostream<char>  prefixed_ostream;

#endif  // !define PREFIXED_OSTREAM_H_INCLUDED_
備考

以下のコンパイラでのみ動作確認済み.

  • g++ (GCC) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.0)
  • g++ (GCC) 4.1.2 (Gentoo 4.1.2)
余談

std::basic_streambuf を継承するなんて真似,自力で見出すことは到底不可能だと思うんだけど.

  • Comments (Close): 0
  • TrackBack (Close): 0

mutt-j と OpenCV の ebuild

  • 2007年6月 3日 20:21
  • 備忘録

勝手に作って勝手に晒しても良いもんなのかねぇ,と思いながら晒してみる.利用は自己責任で.それと 記述ミスなどが見つかったら教えてほしい.


# /usr/local/portage/mypackages/mail-client/mutt-j/mutt-j-1.5.14-r1.ebuild
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

inherit eutils flag-o-matic autotools

MY_PN="mutt"    # PN=mutt-j
MY_P="${MY_PN}-${PV}"
MY_S="${WORKDIR}/${MY_P}"

DESCRIPTION="Mutt Japanese edition"
HOMEPAGE="http://www.emaillab.org/mutt/"
SRC_URI="ftp://ftp.mutt.org/mutt/devel/${MY_P}.tar.gz
    http://www.emaillab.org/mutt/${PV}/patch-${PV}.mutt-j.ja.1.gz"
IUSE="berkdb buffysize cjk crypt debug gdbm gnutls gpgme idn imap mbox nls nntp
pop qdbm sasl smime ssl"
SLOT="0"
LICENSE="GPL-2"
KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~sparc ~x86 ~x86-fbsd"
RDEPEND=">=sys-libs/ncurses-5.2
    qdbm?    ( dev-db/qdbm )
    !qdbm?   (
        gdbm?  ( sys-libs/gdbm )
        !gdbm? ( berkdb? ( >=sys-libs/db-4 ) )
    )
    imap?    (
        gnutls?  ( >=net-libs/gnutls-1.0.17 )
        !gnutls? ( ssl? ( >=dev-libs/openssl-0.9.6 ) )
        sasl?    ( >=dev-libs/cyrus-sasl-2 )
    )
    pop?     (
        gnutls?  ( >=net-libs/gnutls-1.0.17 )
        !gnutls? ( ssl? ( >=dev-libs/openssl-0.9.6 ) )
        sasl?    ( >=dev-libs/cyrus-sasl-2 )
    )
    idn?     ( net-dns/libidn )
    gpgme?   ( >=app-crypt/gpgme-0.9.0 )
    smime?   ( >=dev-libs/openssl-0.9.6 )
    app-misc/mime-types"
DEPEND="${RDEPEND}
    net-mail/mailbase"

src_unpack() {
    unpack ${A} && cd ${MY_S} || die "unpack failed"

    epatch "${WORKDIR}"/patch-${PV}.mutt-j.ja.1

    AT_M4DIR="m4" eautoreconf
}

src_compile() {
    declare myconf="
        $(use_enable nls) \
        $(use_enable gpgme) \
        $(use_enable imap) \
        $(use_enable pop) \
        $(use_enable crypt pgp) \
        $(use_enable smime) \
        $(use_enable cjk default-japanese) \
        $(use_enable debug) \
        $(use_with idn) \
        --with-curses \
        --sysconfdir=/etc/${PN} \
        --with-docdir=/usr/share/doc/${PN}-${PVR} \
        --with-regex \
        --disable-fcntl --enable-flock \
        --enable-nfs-fix --enable-external-dotlock \
        --with-mixmaster"

    # See Bug #22787
    unset WANT_AUTOCONF_2_5 WANT_AUTOCONF

    # mutt prioritizes gdbm over bdb, so we will too.
    # hcache feature requires at least one database is in USE.
    if use qdbm; then
        myconf="${myconf} --enable-hcache \
        --with-qdbm --without-gdbm --without-bdb"
    elif use gdbm ; then
        myconf="${myconf} --enable-hcache \
            --without-qdbm --with-gdbm --without-bdb"
    elif use berkdb; then
        myconf="${myconf} --enable-hcache \
            --without-gdbm --without-qdbm --with-bdb"
    else
        myconf="${myconf} --disable-hcache \
            --without-qdbm --without-gdbm --without-bdb"
    fi

    # there's no need for gnutls, ssl or sasl without either pop or imap.
    # in fact mutt's configure will bail if you do:
    #   --without-pop --without-imap --with-ssl
    if use pop || use imap; then
        if use gnutls; then
            myconf="${myconf} --with-gnutls"
        elif use ssl; then
            myconf="${myconf} --with-ssl"
        fi
        # not sure if this should be mutually exclusive with the other two
        myconf="${myconf} $(use_with sasl)"
    else
        myconf="${myconf} --without-gnutls --without-ssl --without-sasl"
    fi

    # See Bug #11170
    case ${ARCH} in
        alpha|ppc) replace-flags "-O[3-9]" "-O2" ;;
    esac

    if use buffysize; then
        ewarn "USE=buffy-size is just a workaround. Disable it if you don't need it."
        myconf="${myconf} --enable-buffy-size"
    fi

    if use mbox; then
        myconf="${myconf} --with-mailpath=/var/spool/mail"
    else
        myconf="${myconf} --with-homespool=Maildir"
    fi

    # rr.compressed patch
    myconf="${myconf} --enable-compressed"

    # nntp patch
    myconf="${myconf} $(use_enable nntp)"

    cd "${MY_S}"
    econf ${myconf} || die "configure failed"
    emake || die "make failed"
}

src_install() {
    cd "${MY_S}"
    make DESTDIR=${D} install || die "install failed"
    find ${D}/usr/share/doc -type f | grep -v "html\|manual" | xargs gzip
    if use mbox; then
        insinto /etc/mutt
        newins ${FILESDIR}/Muttrc.mbox Muttrc
    else
        insinto /etc/mutt
        doins ${FILESDIR}/Muttrc
    fi

    # A newer file is provided by app-misc/mime-types. So we link it.
    rm ${D}/etc/${PN}/mime.types
    dosym /etc/mime.types /etc/${PN}/mime.types

    dodoc BEWARE COPYRIGHT ChangeLog NEWS OPS* PATCHES README* TODO VERSION
}

pkg_postinst() {
    echo
    elog "If you are new to mutt you may want to take a look at"
    elog "the Gentoo QuickStart Guide to Mutt E-Mail:"
    elog "   http://www.gentoo.org/doc/en/guide-to-mutt.xml"
    echo
}

これは /usr/portage/mail-client/mutt-1.5.14.ebuild をほんの少し書き換えただけで,USE フラグとか依存パッケージとかについての検証はほとんどしていない.


# /usr/local/portage/mypackages/sci-libs/opencv/opencv-1.0.0.ebuild
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

inherit eutils toolchain-funcs

DESCRIPTION="Open Source Computer Vision Library"
HOMEPAGE="http://www.intel.com/technology/computing/opencv/"

SRC_URI="http://downloads.sourceforge.net/opencvlibrary/${P}.tar.gz"

IUSE="debug examples ffmpeg gtk ieee1394 python quicktime swig v4l xine"
LICENSE="Intel"
KEYWORDS="~amd64 ~x86"
SLOT="0"

RDEPEND="dev-util/pkgconfig
    media-libs/libpng
    sys-libs/zlib
    media-libs/jpeg
    media-libs/tiff
    media-libs/jasper
    ffmpeg? ( >=media-video/ffmpeg-0.4.9 )
    gtk? ( >=x11-libs/gtk+-2 )
    ieee1394? ( media-libs/libdc1394
        sys-libs/libraw1394 )
    python? ( >=dev-lang/python-2.3 )
    quicktime? ( media-libs/libquicktime )
    swig? ( dev-lang/swig )
    xine? ( media-libs/xine-lib )"
DEPEND="${RDEPEND}"

src_compile() {
    declare myconf="
        $(use_enable debug) \
        $(use_enable examples apps) \
        $(use_with swig) \
        $(use_with python) \
        $(use_with xine) \
        $(use_with ffmpeg) \
        $(use_with ieee1394 1394libs) \
        $(use_with v4l) \
        $(use_with quicktime) \
        $(use_with gtk)"
    econf ${myconf} || die "econf failed"
    emake || die "emake failed"
}

src_test() {
    if use examples ; then
        emake check || die "emake check failed"
    fi
}

src_install() {
    make DESTDIR=${D} install || die "make install failed"
}

これも,./configure のオプションをほぼそのまま USE フラグに反映させただけで,実際に各 USE フラグを有効にして emerge, とかいう検証は行っていない.

さっき気づいたけど,いつの間にか Gentoo 本家の Portage ツリーに acml-3.6.0.ebuild, acml-3.6.1.ebuild が追加されてた.んじゃ以前作った ebuild は用無しになったなぁ.

  • Comments (Close): 0
  • TrackBack (Close): 0

Home> 備忘録: 2007年6月アーカイブ

カテゴリ
アーカイブ
購読
Powerd By

Return to page top