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
- Newer: 備忘録: 2007年9月
- Older: 備忘録: 2007年5月
Home> 備忘録: 2007年6月アーカイブ