version 1.4.36b
[polyglot.git] / io.c
1 #ifndef _WIN32
2
3 // io.c
4
5 // includes
6
7 #include <errno.h>
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
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>%s: 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    char string[FormatBufferSize];
200    int len;
201
202    ASSERT(io_is_ok(io));
203    ASSERT(format!=NULL);
204
205    ASSERT(io->out_fd>=0);
206
207    // format
208
209    CONSTRUCT_ARG_STRING(format,string);
210
211    // append string to buffer
212
213    len = strlen(string);
214    if (io->out_size + len > BufferSize-2) my_fatal("io_send(): buffer overflow\n");
215
216    memcpy(&io->out_buffer[io->out_size],string,len);
217    io->out_size += len;
218
219    ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
220
221    // log
222
223    io->out_buffer[io->out_size] = '\0';
224    my_log("Adapter->%s: %s\n",io->name,io->out_buffer);
225     
226    // append EOL to buffer
227
228    if (UseCR) io->out_buffer[io->out_size++] = CR;
229    io->out_buffer[io->out_size++] = LF;
230
231    ASSERT(io->out_size>=0&&io->out_size<=BufferSize);
232
233    // flush buffer
234
235    if (UseDebug) my_log("POLYGLOT writing %d byte%s to %s\n",io->out_size,(io->out_size>1)?"s":"",io->name);
236    my_write(io->out_fd,io->out_buffer,io->out_size);
237
238    io->out_size = 0;
239 }
240
241 // io_send_queue()
242
243 void io_send_queue(io_t * io, const char format[], ...) {
244
245    char string[FormatBufferSize];
246    int len;
247
248    ASSERT(io_is_ok(io));
249    ASSERT(format!=NULL);
250
251    ASSERT(io->out_fd>=0);
252
253    // format
254
255    CONSTRUCT_ARG_STRING(format,string);
256
257    // append string to buffer
258
259    len = strlen(string);
260    if (io->out_size + len > BufferSize-2) my_fatal("io_send_queue(): buffer overflow\n");
261
262    memcpy(&io->out_buffer[io->out_size],string,len);
263    io->out_size += len;
264
265    ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
266 }
267
268 // my_read()
269
270 static int my_read(int fd, char string[], int size) {
271
272    int n;
273
274    ASSERT(fd>=0);
275    ASSERT(string!=NULL);
276    ASSERT(size>0);
277
278    do {
279       n = read(fd,string,size);
280    } while (n == -1 && errno == EINTR);
281
282    if (n == -1) my_fatal("my_read(): read(): %s\n",strerror(errno));
283
284    ASSERT(n>=0);
285
286    return n;
287 }
288
289 // my_write()
290
291 static void my_write(int fd, const char string[], int size) {
292
293    int n;
294
295    ASSERT(fd>=0);
296    ASSERT(string!=NULL);
297    ASSERT(size>0);
298
299    do {
300
301       n = write(fd,string,size);
302
303       // if (n == -1 && errno != EINTR && errno != EPIPE) my_fatal("my_write(): write(): %s\n",strerror(errno));
304
305       if (n == -1) {
306          if (FALSE) {
307          } else if (errno == EINTR) {
308             n = 0; // nothing has been written
309          } else if (errno == EPIPE) {
310             n = size; // pretend everything has been written
311          } else {
312             my_fatal("my_write(): write(): %s\n",strerror(errno));
313          }
314       }
315
316       ASSERT(n>=0);
317
318       string += n;
319       size -= n;
320
321    } while (size > 0);
322
323    ASSERT(size==0);
324 }
325
326 // end of io.cpp
327
328 #endif