Add iostream to CTL

This commit is contained in:
Justine Tunney 2024-06-29 15:45:09 -07:00
parent 617ddfee93
commit 98e684622b
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
20 changed files with 1531 additions and 7 deletions

View file

@ -256,7 +256,6 @@ include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
include libc/proc/BUILD.mk # │ You can now use threads
include libc/dlopen/BUILD.mk # │ You can now use processes
include libc/thread/BUILD.mk # │ You can finally call malloc()
include ctl/BUILD.mk # │
include third_party/zlib/BUILD.mk # │
include libc/stdio/BUILD.mk # │
include tool/hello/BUILD.mk # │
@ -285,6 +284,7 @@ include third_party/ncurses/BUILD.mk # │
include third_party/readline/BUILD.mk # │
include third_party/libunwind/BUILD.mk # |
include third_party/libcxxabi/BUILD.mk # |
include ctl/BUILD.mk # │
include third_party/libcxx/BUILD.mk # │
include third_party/openmp/BUILD.mk # │
include third_party/double-conversion/BUILD.mk # │

View file

@ -18,7 +18,11 @@ CTL_A_CHECKS = \
CTL_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_MEM \
LIBC_STDIO \
LIBC_STR \
THIRD_PARTY_GDTOA \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))

39
ctl/ios.cc Normal file
View file

@ -0,0 +1,39 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ios.h"
namespace ctl {
ios::ios(FILE* file) : file_(file)
{
}
ios::~ios() = default;
ios&
ios::operator=(ios&& other) noexcept
{
if (this != &other) {
file_ = other.file_;
other.file_ = nullptr;
}
return *this;
}
} // namespace ctl

27
ctl/ios.h Normal file
View file

@ -0,0 +1,27 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IOS_H_
#define CTL_IOS_H_
#include "ios_base.h"
struct FILE;
namespace ctl {
class ios : public ios_base
{
public:
explicit ios(FILE*);
virtual ~ios();
protected:
ios& operator=(ios&&) noexcept;
FILE* file_;
private:
ios(const ios&) = delete;
};
} // namespace ctl
#endif // CTL_IOS_H_

118
ctl/ios_base.cc Normal file
View file

@ -0,0 +1,118 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ios_base.h"
namespace ctl {
ios_base::ios_base() : state_(goodbit), flags_(skipws | dec)
{
}
ios_base::~ios_base() = default;
ios_base::fmtflags
ios_base::flags() const
{
return static_cast<ios_base::fmtflags>(flags_);
}
ios_base::fmtflags
ios_base::flags(fmtflags fmtfl)
{
int old = flags_;
flags_ = fmtfl;
return static_cast<ios_base::fmtflags>(old);
}
ios_base::fmtflags
ios_base::setf(fmtflags fmtfl)
{
int old = flags_;
flags_ |= fmtfl;
return static_cast<ios_base::fmtflags>(old);
}
ios_base::fmtflags
ios_base::setf(fmtflags fmtfl, fmtflags mask)
{
int old = flags_;
flags_ = (flags_ & ~mask) | (fmtfl & mask);
return static_cast<ios_base::fmtflags>(old);
}
void
ios_base::unsetf(fmtflags mask)
{
flags_ &= ~mask;
}
ios_base::iostate
ios_base::rdstate() const
{
return static_cast<ios_base::iostate>(state_);
}
void
ios_base::clear(int state)
{
state_ = state;
}
void
ios_base::setstate(int state)
{
state_ |= state;
}
bool
ios_base::good() const
{
return state_ == goodbit;
}
bool
ios_base::eof() const
{
return (state_ & eofbit) != 0;
}
bool
ios_base::fail() const
{
return (state_ & (failbit | badbit)) != 0;
}
bool
ios_base::bad() const
{
return (state_ & badbit) != 0;
}
bool
ios_base::operator!() const
{
return fail();
}
ios_base::operator bool() const
{
return !fail();
}
} // namespace ctl

86
ctl/ios_base.h Normal file
View file

@ -0,0 +1,86 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IOS_BASE_H_
#define CTL_IOS_BASE_H_
namespace ctl {
class ios_base
{
public:
typedef size_t streamsize;
enum iostate
{
goodbit = 0,
badbit = 1,
failbit = 2,
eofbit = 4
};
enum fmtflags
{
boolalpha = 1 << 0,
dec = 1 << 1,
fixed = 1 << 2,
hex = 1 << 3,
internal = 1 << 4,
left = 1 << 5,
oct = 1 << 6,
right = 1 << 7,
scientific = 1 << 8,
showbase = 1 << 9,
showpoint = 1 << 10,
showpos = 1 << 11,
skipws = 1 << 12,
unitbuf = 1 << 13,
uppercase = 1 << 14,
adjustfield = left | right | internal,
basefield = dec | oct | hex,
floatfield = scientific | fixed
};
enum openmode
{
app = 1 << 0,
binary = 1 << 1,
in = 1 << 2,
out = 1 << 3,
trunc = 1 << 4,
ate = 1 << 5
};
protected:
ios_base();
virtual ~ios_base();
int state_;
int flags_;
public:
fmtflags flags() const;
fmtflags flags(fmtflags);
fmtflags setf(fmtflags);
fmtflags setf(fmtflags, fmtflags);
void unsetf(fmtflags);
iostate rdstate() const;
void clear(int = goodbit);
void setstate(int);
bool good() const;
bool eof() const;
bool fail() const;
bool bad() const;
bool operator!() const;
explicit operator bool() const;
private:
ios_base(const ios_base&) = delete;
ios_base& operator=(const ios_base&) = delete;
};
} // namespace ctl
#endif // CTL_IOS_BASE_H_

View file

@ -2,7 +2,6 @@
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_IS_CONVERTIBLE_H_
#define CTL_IS_CONVERTIBLE_H_
#include "ctl/integral_constant.h"
#include "ctl/void_t.h"

237
ctl/istream.cc Normal file
View file

@ -0,0 +1,237 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "istream.h"
#include "libc/fmt/conv.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "numeric_limits.h"
#include "string.h"
#include "utility.h"
namespace ctl {
istream cin(stdin);
istream::~istream() = default;
istream::istream(FILE* file) : ios(file), gcount_(0)
{
}
istream::istream(istream&& other) noexcept
: ios(other.file_), gcount_(other.gcount_)
{
other.file_ = nullptr;
other.gcount_ = 0;
}
istream&
istream::operator=(istream&& other) noexcept
{
if (this != &other) {
ios::operator=(ctl::move(other));
gcount_ = other.gcount_;
other.gcount_ = 0;
}
return *this;
}
istream&
istream::operator>>(char& c)
{
gcount_ = 0;
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit | failbit);
} else {
c = static_cast<char>(ch);
gcount_ = 1;
}
return *this;
}
istream&
istream::operator>>(int& n)
{
if (fscanf(file_, "%d", &n) != 1)
setstate(failbit);
return *this;
}
istream&
istream::operator>>(long& n)
{
if (fscanf(file_, "%ld", &n) != 1)
setstate(failbit);
return *this;
}
istream&
istream::operator>>(double& d)
{
if (fscanf(file_, "%f", &d) != 1)
setstate(failbit);
return *this;
}
istream&
istream::operator>>(ctl::string& s)
{
char buffer[1024];
if (fscanf(file_, "%1023s", buffer) == 1) {
s = buffer;
} else {
setstate(failbit);
}
return *this;
}
istream&
istream::operator>>(bool& b)
{
char buffer[6];
if (fscanf(file_, "%5s", buffer) == 1) {
if (strcmp(buffer, "true") == 0 || strcmp(buffer, "1") == 0) {
b = true;
} else if (strcmp(buffer, "false") == 0 || strcmp(buffer, "0") == 0) {
b = false;
} else {
setstate(failbit);
}
} else {
setstate(failbit);
}
return *this;
}
istream&
istream::operator>>(istream& (*manip)(istream&))
{
return manip(*this);
}
int
istream::get()
{
gcount_ = 0;
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit);
} else {
gcount_ = 1;
}
return ch;
}
istream&
istream::get(char& c)
{
int ch = get();
if (ch != EOF)
c = static_cast<char>(ch);
return *this;
}
istream&
istream::getline(char* s, streamsize n)
{
return getline(s, n, '\n');
}
istream&
istream::getline(char* s, streamsize n, char delim)
{
gcount_ = 0;
if (n <= 0) {
setstate(failbit);
return *this;
}
while (gcount_ < n - 1) {
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit);
break;
}
if (ch == delim)
break;
s[gcount_++] = static_cast<char>(ch);
}
s[gcount_] = '\0';
if (gcount_ == 0)
setstate(failbit);
return *this;
}
istream&
istream::read(char* s, streamsize n)
{
gcount_ = fread(s, 1, n, file_);
if (gcount_ < n) {
setstate(eofbit);
if (gcount_ == 0)
setstate(failbit);
}
return *this;
}
istream::streamsize
istream::gcount() const
{
return gcount_;
}
int
istream::peek()
{
int ch = fgetc(file_);
if (ch != EOF) {
ungetc(ch, file_);
} else {
setstate(eofbit);
}
return ch;
}
istream&
istream::ignore(streamsize n, int delim)
{
gcount_ = 0;
while (gcount_ < n) {
int ch = fgetc(file_);
if (ch == EOF) {
setstate(eofbit);
break;
}
++gcount_;
if (ch == delim)
break;
}
return *this;
}
istream&
ws(istream& is)
{
int ch;
while ((ch = is.peek()) != EOF && isspace(ch))
is.get();
return is;
}
} // namespace ctl

53
ctl/istream.h Normal file
View file

@ -0,0 +1,53 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ISTREAM_H_
#define CTL_ISTREAM_H_
#include "ios.h"
namespace ctl {
struct string;
class istream : public ios
{
public:
istream() = delete;
explicit istream(FILE*);
virtual ~istream();
istream& operator>>(char&);
istream& operator>>(int&);
istream& operator>>(long&);
istream& operator>>(double&);
istream& operator>>(bool&);
istream& operator>>(string&);
istream& operator>>(istream& (*)(istream&));
int get();
istream& get(char&);
istream& getline(char*, streamsize);
istream& getline(char*, streamsize, char);
istream& read(char*, streamsize);
streamsize gcount() const;
int peek();
istream& ignore(streamsize = 1, int = -1);
istream(istream&&) noexcept;
istream& operator=(istream&&) noexcept;
private:
streamsize gcount_;
istream(const istream&) = delete;
istream& operator=(const istream&) = delete;
};
extern istream cin;
istream&
ws(istream& is);
} // namespace ctl
#endif // CTL_ISTREAM_H_

221
ctl/istringstream.cc Normal file
View file

@ -0,0 +1,221 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "istringstream.h"
#include "libc/fmt/conv.h"
#include "libc/str/str.h"
namespace ctl {
istringstream::istringstream() : buffer_(), read_pos_(0)
{
}
istringstream::istringstream(const string_view& str)
: buffer_(str), read_pos_(0)
{
}
string
istringstream::str() const
{
return buffer_;
}
void
istringstream::str(const string& s)
{
buffer_ = s;
read_pos_ = 0;
clear();
}
istringstream&
istringstream::operator>>(char& c)
{
if (good() && read_pos_ < buffer_.size()) {
c = buffer_[read_pos_++];
} else {
setstate(ios_base::failbit);
}
return *this;
}
istringstream&
istringstream::operator>>(char* s)
{
if (!good())
return *this;
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
++read_pos_;
size_t start = read_pos_;
while (read_pos_ < buffer_.size() && !isspace(buffer_[read_pos_])) {
s[read_pos_ - start] = buffer_[read_pos_];
++read_pos_;
}
s[read_pos_ - start] = '\0';
if (start == read_pos_) {
setstate(ios_base::failbit);
} else if (read_pos_ == buffer_.size()) {
setstate(ios_base::eofbit);
}
return *this;
}
istringstream&
istringstream::operator>>(string& s)
{
if (!good())
return *this;
s.clear();
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
++read_pos_;
while (read_pos_ < buffer_.size() && !isspace(buffer_[read_pos_])) {
s.push_back(buffer_[read_pos_]);
++read_pos_;
}
if (s.empty()) {
setstate(ios_base::failbit);
} else if (read_pos_ == buffer_.size()) {
setstate(ios_base::eofbit);
}
return *this;
}
template<typename T>
istringstream&
istringstream::read_numeric(T& value)
{
if (!good())
return *this;
while (read_pos_ < buffer_.size() && isspace(buffer_[read_pos_]))
++read_pos_;
// size_t start = read_pos_;
bool is_negative = false;
if (read_pos_ < buffer_.size() &&
(buffer_[read_pos_] == '-' || buffer_[read_pos_] == '+')) {
is_negative = (buffer_[read_pos_] == '-');
++read_pos_;
}
T result = 0;
bool valid = false;
while (read_pos_ < buffer_.size() && isdigit(buffer_[read_pos_])) {
result = result * 10 + (buffer_[read_pos_] - '0');
++read_pos_;
valid = true;
}
if (valid) {
value = is_negative ? -result : result;
if (read_pos_ == buffer_.size())
setstate(ios_base::eofbit);
} else {
setstate(ios_base::failbit);
}
return *this;
}
istringstream&
istringstream::operator>>(short& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(unsigned short& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(int& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(unsigned int& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(long& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(unsigned long& n)
{
return read_numeric(n);
}
istringstream&
istringstream::operator>>(float& f)
{
if (!good())
return *this;
char* end;
f = strtof(buffer_.c_str() + read_pos_, &end);
if (end == buffer_.c_str() + read_pos_) {
setstate(ios_base::failbit);
} else {
read_pos_ = end - buffer_.c_str();
if (read_pos_ == buffer_.size())
setstate(ios_base::eofbit);
}
return *this;
}
istringstream&
istringstream::operator>>(double& d)
{
if (!good())
return *this;
char* end;
d = strtod(buffer_.c_str() + read_pos_, &end);
if (end == buffer_.c_str() + read_pos_) {
setstate(ios_base::failbit);
} else {
read_pos_ = end - buffer_.c_str();
if (read_pos_ == buffer_.size())
setstate(ios_base::eofbit);
}
return *this;
}
} // namespace ctl

41
ctl/istringstream.h Normal file
View file

@ -0,0 +1,41 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ISTRINGSTREAM_H_
#define CTL_ISTRINGSTREAM_H_
#include "ios_base.h"
#include "string.h"
namespace ctl {
class istringstream : public ios_base
{
public:
istringstream();
explicit istringstream(const string_view&);
string str() const;
void str(const string&);
istringstream& operator>>(char&);
istringstream& operator>>(char*);
istringstream& operator>>(string&);
istringstream& operator>>(short&);
istringstream& operator>>(unsigned short&);
istringstream& operator>>(int&);
istringstream& operator>>(unsigned int&);
istringstream& operator>>(long&);
istringstream& operator>>(unsigned long&);
istringstream& operator>>(float&);
istringstream& operator>>(double&);
private:
string buffer_;
size_t read_pos_;
template<typename T>
istringstream& read_numeric(T&);
};
} // namespace ctl
#endif // CTL_ISTRINGSTREAM_H_

166
ctl/ostream.cc Normal file
View file

@ -0,0 +1,166 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ostream.h"
#include "libc/stdio/stdio.h"
#include "string_view.h"
namespace ctl {
ostream cout(stdout);
ostream cerr(stderr);
ostream::~ostream() = default;
ostream::ostream(FILE* file) : ios(file)
{
}
ostream::ostream(ostream&& other) noexcept : ios(other.file_)
{
other.file_ = nullptr;
}
ostream&
ostream::operator=(ostream&& other) noexcept
{
if (this != &other) {
file_ = other.file_;
other.file_ = nullptr;
}
return *this;
}
ostream&
ostream::operator<<(const char* str)
{
if (good() && str)
if (fprintf(file_, "%s", str) < 0)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(char c)
{
if (good())
if (fputc(c, file_) == EOF)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(int n)
{
if (good())
if (fprintf(file_, "%d", n) < 0)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(long n)
{
if (good())
if (fprintf(file_, "%ld", n) < 0)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(double d)
{
if (good())
if (fprintf(file_, "%f", d) < 0)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(const string_view& s)
{
if (good())
if (fprintf(file_, "%.*s", (int)s.size(), s.data()) < 0)
setstate(badbit);
return *this;
}
ostream&
ostream::operator<<(bool b)
{
if (good()) {
const char* value =
(flags() & boolalpha) ? (b ? "true" : "false") : (b ? "1" : "0");
if (fprintf(file_, "%s", value) < 0)
setstate(badbit);
}
return *this;
}
ostream&
ostream::operator<<(ostream& (*manip)(ostream&))
{
return manip(*this);
}
ostream&
ostream::put(char c)
{
if (good())
if (fputc(c, file_) == EOF)
setstate(badbit);
return *this;
}
ostream&
ostream::write(const char* s, streamsize n)
{
if (good())
if (fwrite(s, 1, n, file_) != static_cast<size_t>(n))
setstate(badbit);
return *this;
}
ostream&
ostream::flush()
{
if (good())
if (fflush(file_) != 0)
setstate(badbit);
return *this;
}
ostream&
endl(ostream& os)
{
return os.put('\n').flush();
}
ostream&
ends(ostream& os)
{
return os.put('\0');
}
ostream&
flush(ostream& os)
{
return os.flush();
}
} // namespace ctl

53
ctl/ostream.h Normal file
View file

@ -0,0 +1,53 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_OSTREAM_H_
#define CTL_OSTREAM_H_
#include "ios.h"
namespace ctl {
struct string_view;
class ostream : public ios
{
public:
ostream() = delete;
explicit ostream(FILE*);
virtual ~ostream();
ostream& operator<<(const char*);
ostream& operator<<(char);
ostream& operator<<(int);
ostream& operator<<(long);
ostream& operator<<(double);
ostream& operator<<(const string_view&);
ostream& operator<<(bool);
ostream& operator<<(ostream& (*)(ostream&));
ostream& put(char);
ostream& write(const char*, streamsize);
ostream& flush();
ostream(ostream&&) noexcept;
ostream& operator=(ostream&&) noexcept;
private:
ostream(const ostream&) = delete;
ostream& operator=(const ostream&) = delete;
};
extern ostream cout;
extern ostream cerr;
ostream&
endl(ostream&);
ostream&
ends(ostream&);
ostream&
flush(ostream&);
} // namespace ctl
#endif // CTL_OSTREAM_H_

140
ctl/ostringstream.cc Normal file
View file

@ -0,0 +1,140 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ostringstream.h"
#include "libc/fmt/itoa.h"
#include "libc/stdio/stdio.h"
namespace ctl {
ostringstream::ostringstream() : buffer_(), write_pos_(0)
{
}
ostringstream::ostringstream(const string_view& str)
: buffer_(str), write_pos_(0)
{
}
string
ostringstream::str() const
{
return buffer_;
}
void
ostringstream::str(const string& s)
{
buffer_ = s;
write_pos_ = 0;
}
void
ostringstream::clear()
{
ios_base::clear();
}
ostringstream&
ostringstream::operator<<(char c)
{
if (good()) {
if (write_pos_ < buffer_.size()) {
buffer_[write_pos_++] = c;
} else {
buffer_.push_back(c);
++write_pos_;
}
}
return *this;
}
ostringstream&
ostringstream::operator<<(const string_view& s)
{
if (good()) {
if (write_pos_ + s.size() <= buffer_.size()) {
buffer_.replace(write_pos_, s.size(), s);
} else {
buffer_.replace(write_pos_, buffer_.size() - write_pos_, s);
buffer_.append(s.substr(buffer_.size() - write_pos_));
}
write_pos_ += s.size();
}
return *this;
}
ostringstream&
ostringstream::operator<<(int n)
{
char temp[12];
if (good())
*this << string_view(temp, FormatInt32(temp, n) - temp);
return *this;
}
ostringstream&
ostringstream::operator<<(unsigned int n)
{
char temp[12];
if (good())
*this << string_view(temp, FormatUint32(temp, n) - temp);
return *this;
}
ostringstream&
ostringstream::operator<<(long n)
{
char temp[21];
if (good())
*this << string_view(temp, FormatInt64(temp, n) - temp);
return *this;
}
ostringstream&
ostringstream::operator<<(unsigned long n)
{
char temp[21];
if (good())
*this << string_view(temp, FormatUint64(temp, n) - temp);
return *this;
}
ostringstream&
ostringstream::operator<<(float f)
{
if (good()) {
char temp[32];
int len = snprintf(temp, sizeof(temp), "%g", f);
*this << string_view(temp, len);
}
return *this;
}
ostringstream&
ostringstream::operator<<(double d)
{
if (good()) {
char temp[32];
int len = snprintf(temp, sizeof(temp), "%g", d);
*this << string_view(temp, len);
}
return *this;
}
} // namespace ctl

36
ctl/ostringstream.h Normal file
View file

@ -0,0 +1,36 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_OSTRINGSTREAM_H_
#define CTL_OSTRINGSTREAM_H_
#include "ios_base.h"
#include "string.h"
namespace ctl {
class ostringstream : public ios_base
{
public:
ostringstream();
explicit ostringstream(const string_view&);
string str() const;
void str(const string& s);
void clear();
ostringstream& operator<<(char);
ostringstream& operator<<(const string_view&);
ostringstream& operator<<(int);
ostringstream& operator<<(unsigned int);
ostringstream& operator<<(long);
ostringstream& operator<<(unsigned long);
ostringstream& operator<<(float);
ostringstream& operator<<(double);
private:
string buffer_;
size_t write_pos_;
};
} // namespace ctl
#endif // CTL_OSTRINGSTREAM_H_

View file

@ -1,7 +1,7 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_UTILITY_H_
#define COSMOPOLITAN_CTL_UTILITY_H_
#ifndef CTL_UTILITY_H_
#define CTL_UTILITY_H_
#include "remove_reference.h"
namespace ctl {
@ -66,4 +66,4 @@ declval() noexcept;
} // namespace ctl
#endif // COSMOPOLITAN_CTL_UTILITY_H_
#endif // CTL_UTILITY_H_

View file

@ -5,7 +5,7 @@
#define SYSDEBUG 0
#endif
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 1 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _LOCKTRACE 0 /* not configurable w/ flag yet */

View file

@ -14,10 +14,11 @@ TEST_CTL_TESTS = $(TEST_CTL_COMS:%=%.ok)
TEST_CTL_DIRECTDEPS = \
CTL \
LIBC_CALLS \
LIBC_STDIO \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_STDIO \
LIBC_STDIO \
LIBC_THREAD \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \

View file

@ -0,0 +1,163 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/istringstream.h"
#include "libc/mem/leaks.h"
// #include <sstream>
// #define ctl std
int
main()
{
// Test default constructor
{
ctl::istringstream iss;
if (iss.eof())
return 1;
if (!iss.good())
return 1;
}
// Test constructor with initial string
{
ctl::istringstream iss("Hello, world!");
if (iss.str() != "Hello, world!")
return 2;
}
// Test reading a char
{
ctl::istringstream iss("A");
char c;
iss >> c;
if (c != 'A' || !iss.good())
return 3;
}
// Test reading a string
{
ctl::istringstream iss("Hello World");
ctl::string s;
iss >> s;
if (s != "Hello" || !iss.good())
return 4;
}
// Test reading multiple strings
{
ctl::istringstream iss("One Two Three");
ctl::string s1, s2, s3;
iss >> s1 >> s2 >> s3;
if (s1 != "One" || s2 != "Two" || s3 != "Three" || iss.good() ||
!iss.eof())
return 5;
}
// Test reading integers
{
ctl::istringstream iss("123 -456 789");
int a, b, c;
iss >> a >> b >> c;
if (a != 123 || b != -456 || c != 789 || iss.good() || !iss.eof())
return 6;
}
// Test reading floating-point numbers
{
ctl::istringstream iss("3.14 -2.718");
float f;
double d;
iss >> f >> d;
if (f != 3.14f || d != -2.718 || iss.good() || !iss.eof())
return 7;
}
// Test reading past the end of the stream
{
ctl::istringstream iss("42");
int n;
iss >> n;
if (n != 42 || iss.good() || !iss.eof())
return 8;
iss >> n;
if (iss.good())
return 9;
if (!iss.eof())
return 10;
}
// Test reading invalid data
{
ctl::istringstream iss("not_a_number");
int n;
iss >> n;
if (iss.good() || !iss.fail())
return 11;
}
// Test str() setter
{
ctl::istringstream iss;
iss.str("New content");
if (iss.str() != "New content" || !iss.good())
return 12;
}
// Test reading after setting a new string
{
ctl::istringstream iss("Old content");
iss.str("New content");
ctl::string s;
iss >> s;
if (s != "New" || !iss.good())
return 13;
}
// Test reading a mixture of types
{
ctl::istringstream iss("42 3.14 Hello");
int i;
double d;
ctl::string s;
iss >> i >> d >> s;
if (i != 42 || d != 3.14 || s != "Hello" || iss.good() || !iss.eof())
return 14;
}
// Test reading with leading whitespace
{
ctl::istringstream iss(" 42");
int n;
iss >> n;
if (n != 42 || iss.good() || !iss.eof())
return 15;
}
// Test clear() only affects error state, not content
{
ctl::istringstream iss("Test");
iss.setstate(ctl::ios_base::failbit);
iss.clear();
if (!iss.good() || iss.str() != "Test")
return 16;
}
CheckForMemoryLeaks();
}

View file

@ -0,0 +1,140 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/ostringstream.h"
#include "libc/mem/leaks.h"
// #include <sstream>
// #define ctl std
int
main()
{
// Test default constructor and basic string insertion
{
ctl::ostringstream oss;
oss << "Hello, world!";
if (oss.str() != "Hello, world!")
return 1;
}
// Test constructor with initial string (overwrite mode)
{
ctl::ostringstream oss("Initial content");
oss << "New";
if (oss.str() != "Newtial content")
return 2;
}
// Test overwrite and append behavior
{
ctl::ostringstream oss("Hello, world!");
oss << "Hi";
if (oss.str() != "Hillo, world!")
return 3;
oss << " Earth";
if (oss.str() != "Hi Earthorld!")
return 4;
}
// Test multiple insertions of different types
{
ctl::ostringstream oss;
oss << "Int: " << 42 << ", Float: " << 3.14f << ", Double: " << 2.718;
if (oss.str() != "Int: 42, Float: 3.14, Double: 2.718")
return 5;
}
// Test char insertion
{
ctl::ostringstream oss("ABCDEF");
oss << 'X' << 'Y' << 'Z';
if (oss.str() != "XYZDEF")
return 6;
}
// Test unsigned types
{
ctl::ostringstream oss("Numbers: ");
unsigned int ui = 12345;
unsigned long ul = 67890UL;
oss << ui << " " << ul;
if (oss.str() != "12345 67890")
return 7;
}
// Test long type
{
ctl::ostringstream oss("Long: ");
long l = -9876543210L;
oss << l;
if (oss.str() != "-9876543210")
return 8;
}
// Test clear() method
{
ctl::ostringstream oss("not that kind of clear");
oss.clear();
if (!oss.good() || oss.str() != "not that kind of clear")
return 9;
}
// Test str() setter method
{
ctl::ostringstream oss;
oss.str("New content");
oss << "Old";
if (oss.str() != "Old content")
return 10;
}
// Test chaining of insertion operators
{
ctl::ostringstream oss("Start: ");
oss << "Chain " << 1 << " " << 2.0 << " " << 'Z';
if (oss.str() != "Chain 1 2 Z")
return 11;
}
// Test insertion when stream is not in good state
{
ctl::ostringstream oss("Original");
oss.setstate(ctl::ios_base::failbit);
oss << "This should not be inserted";
if (oss.str() != "Original")
return 12;
}
// Test with larger amounts of data
{
ctl::ostringstream oss("Prefix: ");
for (int i = 0; i < 1000; ++i) {
oss << "Line " << i << "\n";
}
ctl::string result = oss.str();
if (result.substr(0, 14) != "Line 0\nLine 1\n")
return 13;
if (result.substr(result.length() - 8) != "ine 999\n")
return 14;
}
CheckForMemoryLeaks();
return 0;
}