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.
Showing
1 changed file
with
289 additions
and
0 deletions
libmu_scm/mu_port.c
0 → 100644
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 | } |
-
Please register or sign in to post a comment