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