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