version 1.4.58b
[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    if (size <= 0) my_fatal("io_get_update(): buffer overflow\n");
123
124    // read as many data as possible
125    n = my_read(io->in_fd,&io->in_buffer[pos],size);
126    if (UseDebug) my_log("POLYGLOT read %d byte%s from %s\n",n,(n>1)?"s":"",io->name);
127
128    if (n > 0) { // at least one character was read
129
130       // update buffer size
131
132       ASSERT(n>=1&&n<=size);
133
134       io->in_size += n;
135       ASSERT(io->in_size>=0&&io->in_size<=BufferSize);
136
137    } else { // EOF
138
139       ASSERT(n==0);
140
141       io->in_eof = TRUE;
142    }
143 }
144
145 // io_line_ready()
146
147 bool io_line_ready(const io_t * io) {
148
149    ASSERT(io_is_ok(io));
150
151    if (io->in_eof) return TRUE;
152
153    if (memchr(io->in_buffer,LF,io->in_size) != NULL) return TRUE; // buffer contains LF
154
155    return FALSE;
156 }
157
158 // io_get_line()
159
160 bool io_get_line(io_t * io, char string[], int size) {
161
162    int src, dst;
163    int c;
164
165    ASSERT(io_is_ok(io));
166    ASSERT(string!=NULL);
167    ASSERT(size>=256);
168
169    src = 0;
170    dst = 0;
171
172    while (TRUE) {
173
174       // test for end of buffer
175
176       if (src >= io->in_size) {
177          if (io->in_eof) {
178             my_log("%s->Adapter: EOF\n",io->name);
179             return FALSE;
180          } else {
181             my_fatal("io_get_line(): no EOL in buffer\n");
182          }
183       }
184
185       // test for end of string
186
187       if (dst >= size) my_fatal("io_get_line(): buffer overflow\n");
188
189       // copy the next character
190
191       c = io->in_buffer[src++];
192
193       if (c == LF) { // LF => line complete
194          string[dst] = '\0';
195          break;
196       } else if (c != CR) { // skip CRs
197          string[dst++] = c;
198       }
199    }
200
201    // shift the buffer
202
203    ASSERT(src>0);
204
205    io->in_size -= src;
206    ASSERT(io->in_size>=0);
207
208    if (io->in_size > 0) memmove(&io->in_buffer[0],&io->in_buffer[src],io->in_size);
209
210    // return
211
212    my_log("%s->Adapter: %s\n",io->name,string);
213
214    return TRUE;
215 }
216
217 // io_send()
218
219 void io_send(io_t * io, const char format[], ...) {
220
221    char string[FormatBufferSize];
222    int len;
223
224    ASSERT(io_is_ok(io));
225    ASSERT(format!=NULL);
226
227    ASSERT(io->out_fd>=0);
228
229    // format
230
231    CONSTRUCT_ARG_STRING(format,string);
232
233    // append string to buffer
234
235    len = strlen(string);
236    if (io->out_size + len > BufferSize-2) my_fatal("io_send(): buffer overflow\n");
237
238    memcpy(&io->out_buffer[io->out_size],string,len);
239    io->out_size += len;
240
241    ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
242
243    // log
244
245    io->out_buffer[io->out_size] = '\0';
246    my_log("Adapter->%s: %s\n",io->name,io->out_buffer);
247     
248    // append EOL to buffer
249
250    if (UseCR) io->out_buffer[io->out_size++] = CR;
251    io->out_buffer[io->out_size++] = LF;
252
253    ASSERT(io->out_size>=0&&io->out_size<=BufferSize);
254
255    // flush buffer
256
257    if (UseDebug) my_log("POLYGLOT writing %d byte%s to %s\n",io->out_size,(io->out_size>1)?"s":"",io->name);
258    my_write(io->out_fd,io->out_buffer,io->out_size);
259
260    io->out_size = 0;
261 }
262
263 // io_send_queue()
264
265 void io_send_queue(io_t * io, const char format[], ...) {
266
267    char string[FormatBufferSize];
268    int len;
269
270    ASSERT(io_is_ok(io));
271    ASSERT(format!=NULL);
272
273    ASSERT(io->out_fd>=0);
274
275    // format
276
277    CONSTRUCT_ARG_STRING(format,string);
278
279    // append string to buffer
280
281    len = strlen(string);
282    if (io->out_size + len > BufferSize-2) my_fatal("io_send_queue(): buffer overflow\n");
283
284    memcpy(&io->out_buffer[io->out_size],string,len);
285    io->out_size += len;
286
287    ASSERT(io->out_size>=0&&io->out_size<=BufferSize-2);
288 }
289
290 // my_read()
291
292 static int my_read(int fd, char string[], int size) {
293
294    int n;
295
296    ASSERT(fd>=0);
297    ASSERT(string!=NULL);
298    ASSERT(size>0);
299
300    do {
301       n = read(fd,string,size);
302    } while (n == -1 && errno == EINTR);
303
304    if (n == -1) my_fatal("my_read(): read(): %s\n",strerror(errno));
305
306    ASSERT(n>=0);
307
308    return n;
309 }
310
311 // my_write()
312
313 static void my_write(int fd, const char string[], int size) {
314
315    int n;
316
317    ASSERT(fd>=0);
318    ASSERT(string!=NULL);
319    ASSERT(size>0);
320
321    do {
322
323       n = write(fd,string,size);
324
325       // if (n == -1 && errno != EINTR && errno != EPIPE) my_fatal("my_write(): write(): %s\n",strerror(errno));
326
327       if (n == -1) {
328          if (FALSE) {
329          } else if (errno == EINTR) {
330             n = 0; // nothing has been written
331          } else if (errno == EPIPE) {
332             n = size; // pretend everything has been written
333          } else {
334             my_fatal("my_write(): write(): %s\n",strerror(errno));
335          }
336       }
337
338       ASSERT(n>=0);
339
340       string += n;
341       size -= n;
342
343    } while (size > 0);
344
345    ASSERT(size==0);
346 }
347
348 // end of io.cpp
349
350 #endif