FBB::Mstream(3bobcat)

πŸ’– FBB::Mstream β€” Message handler πŸ’–

okay so bestie, pull up a chair, because we're talking about FBB::Mstream(3bobcat) β€” the generic message handling stream. it's giving organized, it's giving labeled, and ngl it's about to make your error messages look so much better than a raw std::cerr << "oops". πŸŽ€


✨ NAME ✨

FBB::Mstream β€” Generic message handling stream πŸ¦‹


✨ SYNOPSIS ✨

#include <bobcat/mstream>

Linking option: -lbobcat


✨ DESCRIPTION ✨

so, objects of this class handle your messages in a standardized way. like, unbothered, consistent, iconic. Messages may be prefixed with order (line) numbers and/or labels, so your output actually tells you what happened and when. And as a lil extra flair, messages generated by Mstream objects may optionally end by throwing an FBB::Exception (which is an std::exception, so it plays nicely with the rest of the world) β€” which makes implementing stuff like fatal error messages genuinely simple. no cap. πŸ”₯

The BOBCAT library provides four message streams, and you can use them as soon as you've included the mstream header file. They're all defined in the FBB namespace:

  • FBB::emsg β€” for generating standard (labeled and numbered) error messages, e.g.
[Error 1] this is an error message
  • FBB::fmsg β€” for generating (labeled) fatal error messages, ending in an exception, e.g.
[Fatal] this fatal message is followed by an exception

The exception's what member contains FBB::fmsg's id value (see the member id below).

  • FBB::imsg β€” for generating plain informational messages, e.g.
this is a plain message
  • FBB::wmsg β€” for generating (labeled) warning messages, e.g.
[Warning] this is a warning

By default all messages are inserted into the standard output stream, but other destinations (standard error, a named file, etc.) can easily be configured. so you're not stuck, bestie. πŸ’…

Mstream objects themselves are std::ostream objects, which means they can totally be passed to functions expecting ostream arguments. main character energy fr fr. πŸ‘‘

Messages inserted into Mstream objects are buffered until the buffer is flushed by their std::ostream parts, or when either the FBB::endl or FBB::flush manipulator is inserted into the message stream. And here's the cute part: since these manipulators act like std::endl and std::flush when inserted into another kind of std::ostream object, using FBB::endl and using FBB::flush might be worth considering. also β€” when using namespace std and using namespace FBB are specified, the FBB::endl and FBB::flush manipulator will automatically be used with Mstream objects. so convenient, we're obsessed. πŸ˜­πŸ’–

Messages inserted into Mstream objects are considered completed at the insertion of the FBB::endl or FBB::flush manipulators. Message labels, line number labels and line numbers will only be shown for the next line after these manipulators have been inserted, and exceptions are, if needed, thrown from these manipulators. so yeah β€” the manipulators are doing a lot of heavy lifting here. respect. 🫢


✨ NAMESPACE ✨

FBB

All elements mentioned in this man-page, are defined in the namespace FBB. 🌸


✨ INHERITS FROM ✨

std::ostream


✨ CONSTRUCTORS ✨

  • Mstream() β€” the default constructor generates messages using the std::streambuf used by std::cout. There is no limit to the number of messages that may be inserted. No message or line numbers are shown, and no exceptions are thrown when inserting messages. chill vibes only. 🌈
  • explicit Mstream(std::ostream &ostr, size_t maxCount = std::numeric_limits<size_t>::max(), std::string const &tag = "", bool throwing = false) β€” this constructor uses the std::streambuf that is also used by the ostream ostr. By default (i.e. using the default argument values) there is no limit to the number of messages that may be inserted, no message or line numbers are shown, and no exceptions are thrown when inserting messages. ✨ Specifying any other value than std::numeric_limits<size_t>::max() will set the maximum number of messages that can be inserted to that value. The tag defines the text of the message label (e.g., Error).

When throwing is true an exception is thrown after completing a message. The generated exception's what member may show the FBB::Mstream object's id (see below at the member id) of the Mstream object throwing the exception.

  • explicit Mstream(std::streambuf *buf, size_t maxCount = std::numeric_limits<size_t>::max(), std::string const &tag = "", bool throwing = false) β€” this constructor uses buf to insert messages into. The remaining parameters are identical to those of the previous constructor. same energy, different destination. πŸ’«
  • explicit Mstream(std::string const &name, size_t maxCount = std::numeric_limits<size_t>::max(), std::string const &tag = "", bool throwing = false) β€” this constructor creates a std::ofstream from the provided name parameter. It throws an exception if the stream cannot be opened for writing. If a file by that name already exists it is rewritten β€” so heads up on that one, bestie. ⚠️ The remaining parameters are identical to those of the previous two constructors.
lowkey important: copy and move constructors (and assignment operators) are not available. no duplicating this stream, periodt. πŸ’€

πŸ’– MEMBER FUNCTIONS πŸ’–

okay bestie, here's the whole toolbox, every single one, no skips πŸ”₯

  • size_t count() const β€” hands you back the number of messages that got inserted. and if you called setCount at some point, it's the value from that last setCount call plus however many messages have been inserted since then. math but make it messages πŸ’…
  • bool isActive() const β€” true if messages can actually make it into the FBB::MStream object, false if inserted messages are just getting ignored. heads up: while it's ignoring stuff, the message count does not get updated. ghosted messages don't count fr fr.
  • int id() const β€” the unique id of the Mstream object. it's giving government name πŸͺͺ
  • bool lineExcess() const β€” true once you've tried to insert one more message after maxCount messages already went in. you overstayed, bestie 😭
  • std::string const &lineTag() const β€” the line-tag currently in use. default is Line. ✨
  • size_t maxCount() const β€” the maximum number of messages that can be inserted. if what comes back equals std::numeric_limits<size_t>::max(), then congrats, there's literally no limit, the limit is a myth πŸ‘‘
  • void noLineNr() β€” calling this suppresses the display of a line number, but only if you call it after setLineNr (scroll down πŸ‘‡) and before a message is being inserted (or has already been inserted). timing is everything πŸ’…
  • void off() β€” after this, any message you insert into the Mstream object gets silently ignored. and nope, the internal message counter does not get incremented when messages are inserted. silence, but make it on purpose 🀫
  • void on() β€” this is the default state, and after calling it, messages inserted into the Mstream object get sent to their destination stream. we're back, baby 🌈
  • void reset(std::ostream &ostr) β€” messages inserted into the Mstream object now get handled by the std::streambuf that ostr also uses. everything else (like maxCount, the message label) stays exactly as it was. only the vibe of where changed.
  • void reset(std::streambuf *buf) β€” messages inserted into the Mstream object now get handled by the std::streambuf buf. other parameters (e.g., maxCount, the message label) are kept as-is. same energy, different buffer.
  • void reset(FBB::Mstream const &mstream) β€” the current object gets reset using the parameters of the mstream parameter. copy-paste but for settings πŸŽ€
  • void reset(std::string const &name) β€” messages inserted into Mstream objects get handled by a std::ofstream created using the name you passed. if the stream can't be opened for writing, an exception is thrown. and yes, if a file by that name already exists, it gets rewritten (so, gone, bestie πŸ’€). other parameters (e.g., maxCount, the message label) are kept as-is.
  • void reset(std::ostream &ostr, size_t maxCount, std::string const &tag, bool throwing) β€” messages inserted into Mstream objects get handled by the std::streambuf that ostr also uses. if you specify std::numeric_limits<size_t>::max() for maxCount, there is no limit to the number of messages that this std::streambuf may handle. tag defines the text of the message label (e.g., Error, or the empty string for no message label at all). when throwing is specified as true, an exception is thrown after completing a message. dramatic much? correct answer: yes ✨
  • void reset(std::streambuf *buf, size_t maxCount, std::string const &tag, bool throwing) β€” messages inserted into Mstream objects get handled by std::streambuf buf. the remaining parameters are identical to those of the previous reset member. same deal, new home πŸ“¦
  • void reset(std::string const &name, size_t maxCount, std::string const &tag, bool throwing) β€” messages inserted into Mstream objects get handled by a std::ofstream created using the name you passed. it throws an exception if the stream can't be opened for writing. if a file by that name already exists it is rewritten (rip to whatever was in there πŸ™ˆ). the remaining parameters are identical to those of the previous two reset members.
  • void reset(FBB::Mstream const &mstream) β€” the current object is reset using the parameters of the mstream parameter. and here's the glow-up: following the reset, all of the current object's parameters can be modified independently from those used by mstream. it's giving main character energy, you're your own person now πŸ’…
  • bool setActive(bool ifTrue) β€” if ifTrue equals true the Mstream gets activated, otherwise its actions are suppressed. and it returns ifTrue. polite and functional 🫢
  • void setCount(size_t count) β€” assigns the value count to the object's message counter. reset the tally, bestie πŸ”’
  • void setLineNr(size_t lineNr) β€” sets the value lineNr as the message's line number for when the next line is displayed (peep noLineNr too πŸ‘€). lowkey important: this value is not changed by the Mstream object itself. to display another line number you'll have to call this member again β€” meaning the line number does not just automatically show up again at every new line. you have to keep asking. needy, but iconic.
  • void setLineTag(std::string const &tag) β€” sets the tag that prefixes line numbers. by default the line tag equals Line. πŸŽ€
  • void setMaxCount(size_t maxCount) β€” defines maxCount as the maximum number of messages that can be inserted into the Mstream object. the ceiling. the cap. the limit 🌸
  • void setTag(std::string const &tag) β€” specifies the tag that prefixes messages. by default the tag is empty. if it's not empty, the tag is enclosed by square brackets. e.g., specifying the tag Error will prefix messages with [Error]. so cute, so labeled πŸ’–
  • std::string const &tag() const β€” returns the message tag currently in use. by default that's an empty string. nothing there. a void. a moment of silence 🀫
  • bool throws() β€” returns true when the Mstream object will throw an exception at the next completed message. the generated exception's what member contains the id (see earlier for the member id) of the Mstream object throwing the exception. snitch behavior, honestly πŸ’€
  • void throwing(bool ifTrue) β€” modifies the behavior of Mstream objects at completed messages. after passing true, Mstream objects will throw an exception at the next completed message, otherwise this exception is not thrown. the generated exception's what member contains the id (see earlier for the member id) of the Mstream object throwing the exception. same id-in-the-error situation as above bestie πŸ”₯

🧚 MANIPULATORS 🧚

quick note before we dive in: the following two manipulators are not members of the class Mstream. they're free functions defined in the namespace FBB. plot twist πŸ¦‹

  • std::ostream &endl(std::ostream &out) β€” this manipulator inserts a newline character into the Mstream's stream and then calls FBB::flush. and when you insert it into some other kind of std::ostream object, it acts just like std::endl and std::flush. dual citizenship ✨
  • std::ostream &flush(std::ostream &out) β€” this manipulator completes the message that's currently being inserted into an Mstream object. it flushes the object's destination stream and gets the object ready for the next message. when the object's throws member returns true, it throws an exception whose what member contains the id (see earlier for the member id) of the Mstream object throwing the exception. when used with another kind of std::ostream object, it acts like std::flush. versatile queen πŸ‘‘
  • std::ostream &noid(std::ostream &out) β€” this manipulator completes the message currently being inserted into an Mstream object. it flushes the object's destination stream and prepares the object for the next message. when the object's throws member returns true, it throws an exception whose what member does not contain the Mstream object's ID. (see how it's noid? no id. the name ate πŸ’…) when used with another kind of std::ostream object, it acts like std::flush.
  • std::ostream &noidl(std::ostream &out) β€” this manipulator inserts a newline character into the Mstream's stream and then calls FBB::noid. this manipulator acts like std::endl and std::flush when inserted into another kind of std::ostream object. it's noid but with a line break, hence the l. iykyk 🌈

since the manipulators FBB::endl and FBB::flush act like, respectively, std::endl and std::flush when inserted into another kind of std::ostream object, maybe consider the declarations using FBB::endl and using FBB::flush. worth thinking about, bestie 🫢 also, when using namespace std and using namespace FBB is specified, the FBB::endl and FBB::flush manipulators will automatically be called when inserting endl or flush into Mstream objects. auto-pilot, slay ⭐


🌸 EXAMPLE 🌸

#include <iostream>
#include <algorithm>
#include <iterator>

#include <bobcat/mstream>

using namespace std;
using namespace FBB;

int main(int argc, char **argv)
try
{
    cout << sizeof(Mstream) << ’ ’ << sizeof(Mbuf) << ’\n’;

    imsg << "Informational: " << endl;
    imsg.off();
    cout << "The i-msg stream is now off. This message should appear once" <<
                                                                          endl;
    imsg << "The i-msg stream is now off. This message should appear once" <<
                                                                          endl;
    imsg << "The i-msg stream is now off. This message should appear once" <<
                                                                          endl;
    cout << "But this message is shown" << endl;

    wmsg << "Warning message" << endl;
    emsg << "Oops, this this is an error (not really)" << endl;
    emsg << "Oops, this goes wrong, too" << noid;

    imsg.on();
    imsg << "And another informational msg: " << emsg.count() <<
            " error messages\n" << flush;

    emsg << "Third error" << endl;
    emsg.setMaxCount(3);

    imsg << "Msg in between" << endl;

    imsg.setTag("tag");
    imsg << "tagged message" << endl;

    imsg.setTag("label");
    imsg << "labeled message" << endl;

    cerr << "(cerr) LineExcess: " << emsg.lineExcess() << ", count = " <<
            emsg.count() << endl;

    emsg << "Fourth error\n" << noid;       // no id is shown
    emsg << "Fourth error\n" << flush;      // shows id (remove the previous
                                            // statement)

    cerr << "(cerr) LineExcess: " << emsg.lineExcess() << ", count = " <<
            emsg.count() << endl;

    cerr << "Beyond\n";
}
catch(exception const &e)
{
    std::cerr << "Got a std::exception: " << e.what() << ’\n’;
}
catch(...)
{
    std::cerr << "Got an exception\n";
}

πŸŽ€ FILES πŸŽ€

  • bobcat/mstream β€” defines the class interface

πŸ¦‹ SEE ALSO πŸ¦‹

bobcat(7), exception(3bobcat), mbuf(3bobcat)


πŸ’€ BUGS πŸ’€

None Reported. flawless behavior, no notes, periodt πŸ’…

πŸ¦‹ BOBCAT PROJECT FILES πŸ¦‹

okay bestie, here's where to actually find everything, the receipts, the links, the whole fit πŸ’…

Debian Bobcat project files, aka the packages you install, no cap:

  • libbobcat6 β€” the debian package holding the shared library, the changelog and the copyright note πŸ’–
  • libbobcat-dev β€” the debian package holding the static library, the headers, the manual pages, and the developer info ✨

🌈 BOBCAT 🌈

okay so, plot twist, the name is an acronym fr fr β€” Bobcat stands for Brokken’s Own Base Classes And Templates. iconic name behavior honestly πŸŽ€


This is free software, distributed under the terms of the GNU General Public License (GPL). free software is the moment, we love to see it πŸ’œ


πŸ‘‘ AUTHOR πŸ‘‘

Frank B. Brokken (f.b.brokken@rug.nl). not me being obsessed with the person who literally wrote all of this πŸ˜­πŸ’–


that's the whole page bestie, you made it to the end 🌸 this whole thing is libbobcat-dev_6.15.01, dated 2005-2026, and the page itself is FBB::Mstream(3bobcat) β€” go read the source, go write something cute, and remember: read the docs, slay the bugs βœ¨πŸ’…πŸ¦‹

πŸ“¦ where this page comes from