1 // Copyright 2016-2021 Doug Moen
2 // Licensed under the Apache License, version 2.0
3 // See accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0
4
5 #include <libcurv/string.h>
6 #include <libcurv/list.h>
7 #include <libcurv/exception.h>
8
9 namespace curv {
10
is_string(Value val)11 bool is_string(Value val)
12 {
13 if (val.maybe<String>() != nullptr) return true;
14 if (auto list = val.maybe<List>()) {
15 for (auto c : *list)
16 if (!c.is_char()) return false;
17 return true;
18 }
19 return false;
20 }
21
22 Shared<const String>
value_to_string(Value val,Fail fl,const Context & cx)23 value_to_string(Value val, Fail fl, const Context& cx)
24 {
25 if (auto str = val.maybe<const String>())
26 return str;
27 if (auto list = val.maybe<const List>()) {
28 auto str = make_uninitialized_string(list->size());
29 for (unsigned i = 0; i < list->size(); ++i) {
30 Value c = list->at(i);
31 if (c.is_char())
32 str->at(i) = c.to_char_unsafe();
33 else goto error;
34 }
35 return str;
36 }
37 error:
38 FAIL(fl, nullptr, cx, stringify(val," is not a string"));
39 }
40
41 const char String_Base::name[] = "string";
42
43 Shared<String>
make_uninitialized_string(size_t len)44 make_uninitialized_string(size_t len)
45 {
46 return String::make(len);
47 }
48
49 Shared<String>
make_string(const char * str,size_t len)50 make_string(const char* str, size_t len)
51 {
52 return String::make(str, len);
53 }
54
55 Shared<const String>
to_print_string(Value val)56 to_print_string(Value val)
57 {
58 auto s = val.maybe<const String>();
59 if (s) return s;
60 String_Builder sb;
61 val.print_string(sb);
62 return sb.get_string();
63 }
64
65 Shared<String>
get_string()66 String_Builder::get_string()
67 {
68 auto s = str(); // copies the data
69 return make_string(s.data(), s.size()); // copies the data again
70 }
71 Value
get_value()72 String_Builder::get_value()
73 {
74 auto s = str(); // copies the data
75 if (s.empty()) return {List::make(0)};
76 return {make_string(s.data(), s.size())}; // copies the data again
77 }
78
79 void
print_repr(std::ostream & out) const80 String_Base::print_repr(std::ostream& out) const
81 {
82 write_curv_string(data_, 0, out);
83 }
84
85 void
write_curv_string(const char * s,unsigned indent,std::ostream & out)86 write_curv_string(const char* s, unsigned indent, std::ostream& out)
87 {
88 // Normally, a String should not be empty, but be robust and handle anyway.
89 if (*s == '\0') {
90 out << "[]";
91 return;
92 }
93 out << '"';
94 for (; *s != '\0'; ++s) {
95 char c = *s;
96 if (c == '$') {
97 out << c;
98 if (is_dollar_next_char(s[1]))
99 out << '_';
100 }
101 else if (c == '"')
102 out << "\"_";
103 else if (c == '\n') {
104 out << "\n";
105 for (unsigned i = 0; i < indent; ++i)
106 out << " ";
107 if (s[1] != '\0')
108 out << "|";
109 } else if (c == '\t')
110 out << c;
111 else if (c < ' ' || c > '~')
112 out << "$[" << unsigned(c) << "]";
113 else
114 out << c;
115 }
116 out << '"';
117 }
118
119 void
write_curv_char(char c,char next,unsigned indent,std::ostream & out)120 write_curv_char(char c, char next, unsigned indent, std::ostream& out)
121 {
122 if (c == '$') {
123 out << c;
124 if (is_dollar_next_char(next))
125 out << '_';
126 }
127 else if (c == '"')
128 out << "\"_";
129 else if (c == '\n') {
130 out << "\n";
131 for (unsigned i = 0; i < indent; ++i)
132 out << " ";
133 if (next != '\0')
134 out << "|";
135 } else if (c == '\t')
136 out << c;
137 else if (c < ' ' || c > '~')
138 out << "$[" << unsigned(c) << "]";
139 else
140 out << c;
141 }
142
143 } // namespace curv
144