Index: uspace/lib/cpp/include/internal/string.hpp
===================================================================
--- uspace/lib/cpp/include/internal/string.hpp	(revision 2e0256b05ada0e4652a7ad8b96393c1b3a881cc1)
+++ uspace/lib/cpp/include/internal/string.hpp	(revision 2e0256b05ada0e4652a7ad8b96393c1b3a881cc1)
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2017 Jaroslav Jindrak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBCPP_INTERNAL_STRING
+#define LIBCPP_INTERNAL_STRING
+
+#include <ios>
+#include <string>
+
+namespace std
+{
+    /**
+     * 21.4.8.9, inserters and extractors:
+     */
+
+    template<class Char, class Traits, class Allocator>
+    basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
+                                            basic_string<Char, Traits, Allocator>& str)
+    {
+        using sentry = typename basic_istream<Char, Traits>::sentry;
+        sentry sen{is, false};
+
+        if (sen)
+        {
+            str.erase();
+
+            auto max_size = is.width();
+            if (max_size <= 0)
+                max_size = static_cast<streamsize>(str.max_size());
+
+            streamsize i{};
+            for(; i < max_size; ++i)
+            {
+                auto ic = is.rdbuf()->sgetc();
+                if (Traits::eq_int_type(ic, Traits::eof()))
+                {
+                    is.setstate(ios_base::eofbit);
+                    break;
+                }
+
+                auto c = Traits::to_char_type(ic);
+                if(isspace(c, is.getloc()))
+                    break;
+
+                str.push_back(c);
+                is.rdbuf()->sbumpc();
+            }
+
+            if (i == 0)
+                is.setstate(ios_base::failbit);
+        }
+        else
+            is.setstate(ios_base::failbit);
+
+        return is;
+    }
+
+    template<class Char, class Traits, class Allocator>
+    basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os,
+                                            basic_string<Char, Traits, Allocator>& str)
+    {
+        // TODO: determine padding as described in 27.7.3.6.1
+        using sentry = typename basic_ostream<Char, Traits>::sentry;
+        sentry sen{os};
+
+        if (sen)
+        {
+            auto width = os.width();
+            auto size = str.size();
+
+            size_t to_pad{};
+            if (width > 0)
+                to_pad = (static_cast<size_t>(width) - size);
+
+            if (to_pad > 0)
+            {
+                if ((os.flags() & ios_base::adjustfield) != ios_base::left)
+                {
+                    for (std::size_t i = 0; i < to_pad; ++i)
+                        os.put(os.fill());
+                }
+
+                os.rdbuf()->sputn(str.data(), size);
+
+                if ((os.flags() & ios_base::adjustfield) == ios_base::left)
+                {
+                    for (std::size_t i = 0; i < to_pad; ++i)
+                        os.put(os.fill());
+                }
+            }
+            else
+                os.rdbuf()->sputn(str.data(), size);
+
+            os.width(0);
+        }
+
+        return os;
+    }
+
+    template<class Char, class Traits, class Allocator>
+    basic_istream<Char, Traits>& getline(basic_istream<Char, Traits>& is,
+                                         basic_string<Char, Traits, Allocator>& str,
+                                         Char delim)
+    {
+        typename basic_istream<Char, Traits>::sentry sen{is, true};
+
+        if (sen)
+        {
+            str.clear();
+            streamsize count{};
+
+            while (true)
+            {
+                auto ic = is.rdbuf()->sbumpc();
+                if (Traits::eq_int_type(ic, Traits::eof()))
+                {
+                    is.setstate(ios_base::eofbit);
+                    break;
+                }
+
+                auto c = Traits::to_char_type(ic);
+                if (Traits::eq(c, delim))
+                    break;
+
+                str.push_back(c);
+                ++count;
+
+                if (count >= static_cast<streamsize>(str.max_size()))
+                {
+                    is.setstate(ios_base::failbit);
+                    break;
+                }
+            }
+
+            if (count == 0)
+                is.setstate(ios_base::failbit);
+        }
+        else
+            is.setstate(ios_base::failbit);
+
+        return is;
+    }
+
+    template<class Char, class Traits, class Allocator>
+    basic_istream<Char, Traits>& getline(basic_istream<Char, Traits>&& is,
+                                         basic_string<Char, Traits, Allocator>& str,
+                                         Char delim)
+    {
+        return getline(is, str, delim);
+    }
+
+    template<class Char, class Traits, class Allocator>
+    basic_istream<Char, Traits>& getline(basic_istream<Char, Traits>& is,
+                                         basic_string<Char, Traits, Allocator>& str)
+    {
+        return getline(is, str, is.widen('\n'));
+    }
+
+    template<class Char, class Traits, class Allocator>
+    basic_istream<Char, Traits>& getline(basic_istream<Char, Traits>&& is,
+                                         basic_string<Char, Traits, Allocator>& str)
+    {
+        return getline(is, str, is.widen('\n'));
+    }
+}
+
+#endif
