+otexrowstream & operator<<(otexrowstream & ots, TexString ts)
+{
+ ts.validate();
+ ots.os() << move(ts.str);
+ ots.texrow().append(move(ts.texrow));
+ return ots;
+}
+
+
+otexstream & operator<<(otexstream & ots, TexString ts)
+{
+ size_t const len = ts.str.length();
+ // Check whether there is something to output
+ if (len == 0)
+ return ots;
+
+ otexrowstream & otrs = ots;
+ bool isprotected = false;
+ char_type const c = ts.str[0];
+ if (ots.protectSpace()) {
+ if (!ots.canBreakLine() && c == ' ') {
+ otrs << "{}";
+ isprotected = true;
+ }
+ ots.protectSpace(false);
+ }
+ if (ots.terminateCommand()) {
+ if ((c == ' ' || c == '\0' || c == '\n') && !isprotected)
+ // A space or line break follows. Terminate with brackets.
+ otrs << "{}";
+ else if (c != '\\' && c != '{' && c != '}')
+ // Non-terminating character follows. Terminate with space.
+ otrs << " ";
+ ots.terminateCommand(false);
+ }
+
+ if (len > 1)
+ ots.canBreakLine(ts.str[len - 2] != '\n');
+ ots.lastChar(ts.str[len - 1]);
+
+ otrs << move(ts);
+ return ots;
+}
+
+