version 1.4.39b
[polyglot.git] / io.cpp
1 #ifndef _WIN32
2
3 // io.cpp
4
5 // includes
6
7 #include <cerrno>
8 #include <cstdarg>
9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12
13 #include <sys/types.h>
14 #include <unistd.h>
15
16 #include "io.h"
17 #include "util.h"
18
19 // constants
20
21 static const bool UseDebug = false;
22 static const bool UseCR = false;
23
24 static const int StringSize = 4096;
25
26 static const char LF = '\n';
27 static const char CR = '\r';
28
29 // prototypes
30
31 static int  my_read  (int fd, char string[], int size);
32 static void my_write (int fd, const char string[], int size);
33
34 // functions
35
36 // io_is_ok()
37
38 bool io_is_ok(const io_t * io) {
39
40    if (io == NULL) return false;
41
42    if (io->name == NULL) return false;
43
44    if (io->in_eof != true && io->in_eof != false) return false;
45
46    if (io->in_size < 0 || io->in_size > BufferSize) return false;
47    if (io->out_size < 0 || io->out_size > BufferSize) return false;
48
49    return true;
50 }
51
52 // io_init()
53
54 void io_init(io_t * io) {
55
56    ASSERT(io!=NULL);
57
58    io->in_eof = false;
59
60    io->in_size = 0;
61    io->out_size = 0;
62
63    ASSERT(io_is_ok(io));
64 }
65
66 // io_close()
67
68 void io_close(io_t * io) {
69
70    ASSERT(io_is_ok(io));
71
72    ASSERT(io->out_fd>=0);
73
74    my_log("Adapter>Engine: EOF\n",io->name);
75
76    if (close(io->out_fd) == -1) {
77       my_fatal("io_close(): close(): %s\n",strerror(errno));
78    }
79
80    io->out_fd = -1;
81 }
82
83 // io_get_update()
84
85 void io_get_update(io_t * io) {
86
87    int pos, size;
88    int n;
89
90    ASSERT(io_is_ok(io));
91
92    ASSERT(io->in_fd>=0);
93    ASSERT(!io->in_eof);
94
95    // init
96
97    pos = io->in_size;
98
99    size = BufferSize - pos;
100    if (size <= 0) my_fatal("io_get_update(): buffer overflow\n");
101
102    // read as many data as possible
103    n = my_read(io->in_fd,&io->in_buffer[pos],size);
104    if (UseDebug) my_log("POLYGLOT read %d byte%s from %s\n",n,(n>1)?"s":"",io->name);
105
106    if (n > 0) { // at least one character was read
107
108       // update buffer size
109
110       ASSERT(n>=1&&n<=size);
111
112       io->in_size += n;
113       ASSERT(io->in_size>=0&&io->in_size<=BufferSize);
114
115    } else { // EOF
116
117       ASSERT(n==0);
118
119       io->in_eof = true;
120    }
121 }
122
123 // io_line_ready()
124
125 bool io_line_ready(const io_t * io) {
126
127    ASSERT(io_is_ok(io));
128
129    if (io->in_eof) return true;
130
131    if (memchr(io->in_buffer,LF,io->in_size) != NULL) return true; // buffer contains LF
132
133    return false;
134 }
135
136 // io_get_line()
137
138 bool io_get_line(io_t * io, char string[], int size) {
139
140    int src, dst;
141    int c;
142
143    ASSERT(io_is_ok(io));
144    ASSERT(string!=NULL);
145    ASSERT(size>=256);
146
147    src = 0;
148    dst = 0;
149
150    while (true) {
151
152       // test for end of buffer
153
154       if (src >= io->in_size) {
155          if (io->in_eof) {
156             my_log("%s->Adapter: EOF\n",io->name);
157             return false;
158          } else {
159             my_fatal("io_get_line(): no EOL in buffer\n");
160          }
161       }
162
163       // test for end of string
164
165       if (dst >= size) my_fatal("io_get_line(): buffer overflow\n");
166
167       // copy the next character
168
169       c = io->in_buffer[src++];
170
171       if (c == LF) { // LF => line complete
172          string[dst] = '\0';
173          break;
174       } else if (c != CR) { // skip CRs
175          string[dst++] = c;
176       }
177    }
178
179    // shift the buffer
180
181    ASSERT(src>0);
182
183    io->in_size -= src;
184    ASSERT(io->in_size>=0);
185
186    if (io->in_size > 0) memmove(&io->in_buffer[0],&io->in_buffer[src],io->in_size);
187
188    // return
189
190    my_log("%s->Adapter: %s\n",io->name,string);
191
192    return true;
193 }
194
195 // io_send()
196
197 void io_send(io_t * io, const char format[], ...) {
198
199    va_list arg_list;
200    char string[StringSize];
201    int len;
202
203    ASSERT(io_is_ok(io));
204    ASSERT(format!=NULL);
205
206    ASSERT(io->out_fd>=0);
207
208    // format
209
210    va_start(arg_list,format);
211    vsprintf(string,format,arg_list);
212    va_end(arg_list);
213
214    // append string to buffer
215
216    len = strlen(string);
217    if (io->out_size + len > BufferSize-2) my_fatal("io_send(): buffer overflow\n");
218
219    memcpy(&io->out_buffer[io->out_size],string,len);
220    io->out_size += len;
221
222    ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
223
224    // log
225
226    io->out_buffer[io->out_size] = '\0';
227    my_log("Adapter->%s: %s\n",io->name,io->out_buffer);
228 //      my_log("> %f %s %s\n",now_real(),io->name,io->out_buffer);
229    // append EOL to buffer
230
231    if (UseCR) io->out_buffer[io->out_size++] = CR;
232    io->out_buffer[io->out_size++] = LF;
233
234    ASSERT(io->out_size>=0&&io->out_size<=BufferSize);
235
236    // flush buffer
237
238    if (UseDebug) my_log("POLYGLOT writing %d byte%s to %s\n",io->out_size,(io->out_size>1)?"s":"",io->name);
239    my_write(io->out_fd,io->out_buffer,io->out_size);
240
241    io->out_size = 0;
242 }
243
244 // io_send_queue()
245
246 void io_send_queue(io_t * io, const char format[], ...) {
247
248    va_list arg_list;
249    char string[StringSize];
250    int len;
251
252    ASSERT(io_is_ok(io));
253    ASSERT(format!=NULL);
254
255    ASSERT(io->out_fd>=0);
256
257    // format
258
259    va_start(arg_list,format);
260    vsprintf(string,format,arg_list);
261    va_end(arg_list);
262
263    // append string to buffer
264
265    len = strlen(string);
266    if (io->out_size + len > BufferSize-2) my_fatal("io_send_queue(): buffer overflow\n");
267
268    memcpy(&io->out_buffer[io->out_size],string,len);
269    io->out_size += len;
270
271    ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
272 }
273
274 // my_read()
275
276 static int my_read(int fd, char string[], int size) {
277
278    int n;
279
280    ASSERT(fd>=0);
281    ASSERT(string!=NULL);
282    ASSERT(size>0);
283
284    do {
285       n = read(fd,string,size);
286    } while (n == -1 && errno == EINTR);
287
288    if (n == -1) my_fatal("my_read(): read(): %s\n",strerror(errno));
289
290    ASSERT(n>=0);
291
292    return n;
293 }
294
295 // my_write()
296
297 static void my_write(int fd, const char string[], int size) {
298
299    int n;
300
301    ASSERT(fd>=0);
302    ASSERT(string!=NULL);
303    ASSERT(size>0);
304
305    do {
306
307       n = write(fd,string,size);
308
309       // if (n == -1 && errno != EINTR && errno != EPIPE) my_fatal("my_write(): write(): %s\n",strerror(errno));
310
311       if (n == -1) {
312          if (false) {
313          } else if (errno == EINTR) {
314             n = 0; // nothing has been written
315          } else if (errno == EPIPE) {
316             n = size; // pretend everything has been written
317          } else {
318             my_fatal("my_write(): write(): %s\n",strerror(errno));
319          }
320       }
321
322       ASSERT(n>=0);
323
324       string += n;
325       size -= n;
326
327    } while (size > 0);
328
329    ASSERT(size==0);
330 }
331
332 // end of io.cpp
333
334 #endif