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