Commit a4a74f40 a4a74f40ebb7e67be3d2998295f5c0866abc1f1d by Sergey Poznyakoff

I/O port functions. This allows to write and read mailboxes/messages

using usual scheme primitives and thus effectively obsoletes mu_body
interface, but I'll keep it for a while.
1 parent 8e262d87
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include "mu_scm.h"
19
20 struct mu_port
21 {
22 stream_t stream; /* Associated stream */
23 int offset; /* Current offset in the stream */
24 SCM msg; /* Message the port belongs to */
25 };
26
27 #define DEFAULT_BUF_SIZE 1024
28 #define MU_PORT(x) ((struct mu_port *) SCM_STREAM (x))
29
30 static void
31 mu_port_alloc_buffer (SCM port, size_t read_size, size_t write_size)
32 {
33 struct mu_port *mp = MU_PORT (port);
34 scm_port *pt = SCM_PTAB_ENTRY (port);
35 static char *s_mu_port_alloc_buffer = "mu_port_alloc_buffer";
36
37 if (!read_size)
38 read_size = DEFAULT_BUF_SIZE;
39 if (!write_size)
40 write_size = DEFAULT_BUF_SIZE;
41
42 if (SCM_INPUT_PORT_P (port))
43 {
44 pt->read_buf = malloc (read_size);
45 if (pt->read_buf == NULL)
46 scm_memory_error (s_mu_port_alloc_buffer);
47 pt->read_pos = pt->read_end = pt->read_buf;
48 pt->read_buf_size = read_size;
49 }
50 else
51 {
52 pt->read_pos = pt->read_buf = pt->read_end = &pt->shortbuf;
53 pt->read_buf_size = 1;
54 }
55
56 if (SCM_OUTPUT_PORT_P (port))
57 {
58 pt->write_buf = malloc (write_size);
59 if (pt->write_buf == NULL)
60 scm_memory_error (s_mu_port_alloc_buffer);
61 pt->write_pos = pt->write_buf;
62 pt->write_buf_size = write_size;
63 pt->write_end = pt->write_buf + pt->write_buf_size;
64 }
65 else
66 {
67 pt->write_buf = pt->write_pos = &pt->shortbuf;
68 pt->write_buf_size = 1;
69 }
70
71 SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
72 }
73
74 static long scm_tc16_smuport;
75
76 SCM
77 mu_port_make_from_stream (SCM msg, stream_t stream, long mode)
78 {
79 struct mu_port *mp;
80 SCM port;
81 scm_port *pt;
82
83 mp = scm_must_malloc (sizeof (struct mu_port), "mu-port");
84 mp->msg = msg;
85 mp->stream = stream;
86 mp->offset = 0;
87
88 SCM_NEWCELL (port);
89 SCM_DEFER_INTS;
90 pt = scm_add_to_port_table (port);
91 SCM_SETPTAB_ENTRY (port, pt);
92 pt->rw_random = stream_is_seekable (stream);
93 SCM_SET_CELL_TYPE (port, (scm_tc16_smuport | mode));
94 SCM_SETSTREAM (port, mp);
95 mu_port_alloc_buffer (port, 0, 0);
96 SCM_ALLOW_INTS;
97 /* SCM_PTAB_ENTRY (port)->file_name = "name";FIXME*/
98 return port;
99 }
100
101 static SCM
102 mu_port_mark (SCM port)
103 {
104 struct mu_port *mp = MU_PORT (port);
105 return mp->msg;
106 }
107
108 static void
109 mu_port_flush (SCM port)
110 {
111 struct mu_port *mp = MU_PORT (port);
112 scm_port *pt = SCM_PTAB_ENTRY (port);
113 int wrsize = pt->write_pos - pt->write_buf;
114 size_t n;
115
116 if (wrsize)
117 {
118 if (stream_write (mp->stream, pt->write_buf, wrsize, mp->offset, &n))
119 return;
120 mp->offset += n;
121 }
122 pt->write_pos = pt->write_buf;
123 pt->rw_active = SCM_PORT_NEITHER;
124 }
125
126 static int
127 mu_port_close (SCM port)
128 {
129 struct mu_port *mp = MU_PORT (port);
130 scm_port *pt = SCM_PTAB_ENTRY (port);
131
132 mu_port_flush (port);
133 if (pt->read_buf != &pt->shortbuf)
134 free (pt->read_buf);
135 if (pt->write_buf != &pt->shortbuf)
136 free (pt->write_buf);
137 free (mp);
138 return 0;
139 }
140
141 static scm_sizet
142 mu_port_free (SCM port)
143 {
144 mu_port_close (port);
145 return sizeof (struct mu_port); /*FIXME: approximate */
146 }
147
148 static int
149 mu_port_fill_input (SCM port)
150 {
151 struct mu_port *mp = MU_PORT (port);
152 scm_port *pt = SCM_PTAB_ENTRY (port);
153 size_t nread = 0;
154
155 if (stream_read (mp->stream, pt->read_buf, pt->read_buf_size,
156 mp->offset, &nread))
157 scm_syserror ("mu_port_fill_input");
158
159 if (nread == 0)
160 return EOF;
161
162 mp->offset += nread;
163 pt->read_pos = pt->read_buf;
164 pt->read_end = pt->read_buf + nread;
165 return *pt->read_buf;
166 }
167
168 static void
169 mu_port_write (SCM port, const void *data, size_t size)
170 {
171 struct mu_port *mp = MU_PORT (port);
172 scm_port *pt = SCM_PTAB_ENTRY (port);
173 size_t remaining = size;
174 char *input = (char*) data;
175
176 while (remaining > 0)
177 {
178 int space = pt->write_end - pt->write_pos;
179 int write_len = (remaining > space) ? space : remaining;
180
181 memcpy (pt->write_pos, input, write_len);
182 pt->write_pos += write_len;
183 remaining -= write_len;
184 input += write_len;
185 if (write_len == space)
186 mu_port_flush (port);
187 }
188 }
189
190 /* Perform the synchronisation required for switching from input to
191 output on the port.
192 Clear the read buffer and adjust the file position for unread bytes. */
193 static void
194 mu_port_end_input (SCM port, int offset)
195 {
196 struct mu_port *mp = MU_PORT (port);
197 scm_port *pt = SCM_PTAB_ENTRY (port);
198 int delta = pt->read_end - pt->read_pos;
199
200 offset += delta;
201
202 if (offset > 0)
203 {
204 pt->read_pos = pt->read_end;
205 mp->offset -= delta;
206 }
207 pt->rw_active = SCM_PORT_NEITHER;
208 }
209
210 static off_t
211 mu_port_seek (SCM port, off_t offset, int whence)
212 {
213 struct mu_port *mp = MU_PORT (port);
214 scm_port *pt = SCM_PTAB_ENTRY (port);
215 off_t size = 0;
216
217 if (whence == SEEK_CUR && offset == 0)
218 return mp->offset;
219
220 if (pt->rw_active == SCM_PORT_WRITE)
221 {
222 mu_port_flush (port);
223 }
224 else if (pt->rw_active == SCM_PORT_READ)
225 {
226 scm_end_input (port);
227 }
228
229 stream_size (mp->stream, &size);
230 switch (whence)
231 {
232 case SEEK_SET:
233 break;
234 case SEEK_CUR:
235 offset += mp->offset;
236 break;
237 case SEEK_END:
238 offset += size;
239 }
240
241 if (offset > size)
242 return -1;
243 mp->offset = offset;
244 return offset;
245 }
246
247 static void
248 mu_port_truncate (SCM port, off_t length)
249 {
250 struct mu_port *mp = MU_PORT (port);
251 if (stream_truncate (mp->stream, length))
252 scm_syserror ("stream_truncate");
253 }
254
255 static int
256 mu_port_print (SCM exp, SCM port, scm_print_state *pstate)
257 {
258 struct mu_port *mp = MU_PORT (exp);
259 size_t size = 0;
260
261 scm_puts ("#<", port);
262 scm_print_port_mode (exp, port);
263 scm_puts ("mu-port", port);
264 if (stream_size (mp->stream, &size) == 0)
265 {
266 char buffer[64];
267 snprintf (buffer, sizeof (buffer), " %-5ld", size);
268 scm_puts (buffer, port);
269 scm_puts (" chars", port);
270 }
271 scm_putc ('>', port);
272 return 1;
273 }
274
275 void
276 mu_scm_port_init ()
277 {
278 scm_tc16_smuport = scm_make_port_type ("mu-port",
279 mu_port_fill_input, mu_port_write);
280 scm_set_port_mark (scm_tc16_smuport, mu_port_mark);
281 scm_set_port_free (scm_tc16_smuport, mu_port_free);
282 scm_set_port_print (scm_tc16_smuport, mu_port_print);
283 scm_set_port_flush (scm_tc16_smuport, mu_port_flush);
284 scm_set_port_end_input (scm_tc16_smuport, mu_port_end_input);
285 scm_set_port_close (scm_tc16_smuport, mu_port_close);
286 scm_set_port_seek (scm_tc16_smuport, mu_port_seek);
287 scm_set_port_truncate (scm_tc16_smuport, mu_port_truncate);
288 /* scm_set_port_input_waiting (scm_tc16_smuport, mu_port_input_waiting);*/
289 }