1#include "include/pw.h"
2#include "include/pwlib/string_io.h"
3#include "src/pw_interfaces_internal.h"
4#include "src/types/string/string_internal.h"
5
6typedef struct {
7 // line reader iterator data
8 _PwValue line;
9 _PwValue pushback;
10 unsigned line_number;
11 unsigned line_position;
12} _PwStringIO;
13
14#define get_this_stringio(value) _pw_get_this_struct_ptr(_PwStringIO*, mthis, (value))
15
16/****************************************************************
17 * Basic interface
18 */
19
20uint16_t PwTypeId_StringIO = 0;
21
22static bool stringio_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
23{
24 PwStringIOCtorArgs* args = pw_get_ctor_args(PwTypeId_StringIO, ctor_args);
25
26 if (!pw_validate(args->string, PwTypeId_String)) {
27 return false;
28 }
29
30 if (!pw_super(mthis, result, ctor_args)) {
31 return false;
32 }
33 _PwStringIO* sio = get_this_stringio(result);
34 pw_clone2(args->string, &sio->line);
35 sio->pushback = PwNull();
36 return true;
37}
38
39static bool stringio_destroy(PwMethod_Basic_destroy* mthis, PwValuePtr self, _PwCompoundChain* tail)
40{
41 PwValuePtr value_seen = _pw_on_chain(self, tail);
42 if (value_seen) {
43 return true;
44 }
45 _PwStringIO* sio = get_this_stringio(self);
46 pw_destroy(&sio->line);
47 pw_destroy(&sio->pushback);
48 return pw_super(mthis, self, nullptr);
49}
50
51static bool stringio_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
52{
53 _pw_hash_uint64(ctx, PwTypeId_StringIO);
54
55 _PwStringIO* sio = get_this_stringio(self);
56 PwValuePtr line = &sio->line;
57 _pw_call_hash(line, ctx, nullptr);
58 return true;
59}
60
61static bool stringio_deepcopy(PwMethod_Basic_deepcopy* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
62{
63 _PwStringIO* sio = get_this_stringio(self);
64
65 return pw_create_string_io(&sio->line, result);
66}
67
68static bool stringio_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
69{
70 if (!pw_super(mthis, self, fp, indent, tail)) {
71 return false;
72 }
73
74 _PwStringIO* sio = get_this_stringio(self);
75
76 _pw_print_indent(fp, indent);
77 _pw_string_dump_data(fp, &sio->line, indent);
78
79 _pw_print_indent(fp, indent);
80 fprintf(fp, "Current position: %u\n", sio->line_position);
81
82 _pw_print_indent(fp, indent);
83 if (pw_is_null(&sio->pushback)) {
84 fputs("Pushback: none\n", fp);
85 } else if (!pw_is_string(&sio->pushback)) {
86 fputs("WARNING: bad pushback:\n", fp);
87 pw_dump(fp, &sio->pushback);
88 } else {
89 fputs("Pushback:\n", fp);
90 _pw_string_dump_data(fp, &sio->pushback, indent);
91 }
92 return true;
93}
94
95static bool stringio_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
96{
97 _PwStringIO* sio = get_this_stringio(self);
98 pw_clone2(&sio->line, result);
99 return true;
100}
101
102static bool stringio_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
103{
104 _PwStringIO* sio = get_this_stringio(self);
105 return pw_is_true(&sio->line);
106}
107
108static bool stringio_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
109{
110 _PwStringIO* sio_self = get_this_stringio(self);
111 _PwStringIO* sio_other = _pw_get_struct_ptr(other, PwTypeId_StringIO);
112
113 if (sio_other) {
114 return pw_equal(&sio_self->line, &sio_other->line);
115 } else {
116 return false;
117 }
118}
119
120// inherited methods:
121#define stringio_clone nullptr
122#define stringio_decref nullptr
123#define stringio_iter_children nullptr
124
125static PwInterface_Basic basic_interface = {
126#define X(name, ...) .name = { .func = stringio_##name } __VA_OPT__(,)
127 PW_BASIC_INTERFACE_METHODS
128#undef X
129};
130
131/****************************************************************
132 * LineReader interface
133 */
134
135static bool stringio_start(PwMethod_LineReader_start* mthis, PwValuePtr self)
136{
137 _PwStringIO* sio = get_this_stringio(self);
138 sio->line_position = 0;
139 sio->line_number = 0;
140 pw_destroy(&sio->pushback);
141 return true;
142}
143
144static bool do_read_line_inplace(_PwStringIO* sio, PwValuePtr self, PwValuePtr line)
145{
146 if (!pw_string_truncate(line, 0)) {
147 return false;
148 }
149 if (pw_is_string(&sio->pushback)) {
150 if (!pw_string_append(line, &sio->pushback)) {
151 return false;
152 }
153 pw_destroy(&sio->pushback);
154 sio->line_number++;
155 return true;
156 }
157 if (!pw_string_index_valid(&sio->line, sio->line_position)) {
158 pw_set_status(PwStatus(PW_ERROR_EOF));
159 return false;
160 }
161
162 unsigned lf_pos;
163 if (!pw_strchr(&sio->line, '\n', sio->line_position, &lf_pos)) {
164 lf_pos = pw_strlen(&sio->line) - 1;
165 }
166 if (!pw_string_append_substring(line, &sio->line, sio->line_position, lf_pos + 1)) {
167 return false;
168 }
169 sio->line_position = lf_pos + 1;
170 sio->line_number++;
171 return true;
172}
173
174static bool stringio_read_line(PwMethod_LineReader_read_line* mthis, PwValuePtr self, PwValuePtr result)
175{
176 if (!pw_create_empty_string(0, 1, result)) {
177 return false;
178 }
179 return do_read_line_inplace(get_this_stringio(self), self, result);
180}
181
182static bool stringio_read_line_inplace(PwMethod_LineReader_read_line_inplace* mthis, PwValuePtr self, PwValuePtr line)
183{
184 return do_read_line_inplace(get_this_stringio(self), self, line);
185}
186
187static bool stringio_unread_line(PwMethod_LineReader_unread_line* mthis, PwValuePtr self, PwValuePtr line)
188{
189 _PwStringIO* sio = get_this_stringio(self);
190
191 if (pw_is_null(&sio->pushback)) {
192 __pw_clone(line, &sio->pushback); // puchback is already Null, so use __pw_clone here
193 sio->line_number--;
194 return true;
195 } else {
196 return false;
197 }
198}
199
200static bool stringio_get_line_number(PwMethod_LineReader_get_line_number* mthis, PwValuePtr self, unsigned* result)
201{
202 *result = get_this_stringio(self)->line_number;
203 return true;
204}
205
206static bool stringio_stop(PwMethod_LineReader_stop* mthis, PwValuePtr self)
207{
208 _PwStringIO* sio = get_this_stringio(self);
209 pw_destroy(&sio->pushback);
210 return true;
211}
212
213static PwInterface_LineReader line_reader_interface = {
214#define X(name, ...) .name = { .func = stringio_##name } __VA_OPT__(,)
215 PW_LINE_READER_INTERFACE_METHODS
216#undef X
217};
218
219
220/****************************************************************
221 * Initialization
222 */
223
224[[ gnu::constructor ]]
225static void init_stringio_type()
226{
227 if (PwTypeId_StringIO == 0) {
228
229 _pw_init_types();
230
231 PwTypeId_StringIO = pw_add_type2(
232 "StringIO", _PwStringIO,
233 PW_PARENTS,
234 PwTypeId_Struct,
235 PW_INTERFACES,
236 PwInterfaceId_Basic, &basic_interface,
237 PwInterfaceId_LineReader, &line_reader_interface
238 );
239 }
240}