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