1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2018-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library 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 GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #include "mu_scm.h"
19 #include <mailutils/sys/stream.h>
20
21 struct port_stream {
22 struct _mu_stream stream;
23 SCM port;
24 };
25
26 static int
port_stream_read(struct _mu_stream * str,char * buf,size_t bufsize,size_t * pnread)27 port_stream_read (struct _mu_stream *str, char *buf, size_t bufsize,
28 size_t *pnread)
29 {
30 struct port_stream *pstr = (struct port_stream *)str;
31 size_t n = scm_c_read (pstr->port, buf, bufsize);
32 if (pnread)
33 *pnread = n;
34 return 0;
35 }
36
37 static int
port_stream_write(struct _mu_stream * str,const char * buf,size_t bufsize,size_t * pnwrite)38 port_stream_write (struct _mu_stream *str, const char *buf, size_t bufsize,
39 size_t *pnwrite)
40 {
41 struct port_stream *pstr = (struct port_stream *)str;
42 scm_c_write (pstr->port, buf, bufsize);
43 if (pnwrite)
44 *pnwrite = bufsize;
45 return 0;
46 }
47
48 static int
port_stream_seek(struct _mu_stream * str,mu_off_t off,mu_off_t * presult)49 port_stream_seek (struct _mu_stream *str, mu_off_t off, mu_off_t *presult)
50 {
51 struct port_stream *pstr = (struct port_stream *)str;
52 SCM ret = scm_seek (pstr->port,
53 scm_from_signed_integer (off),
54 scm_from_int (SEEK_SET));
55 if (presult)
56 *presult = scm_to_int64 (ret); /* FIXME: scm_to_off_t is not exposed */
57 return 0;
58 }
59
60 static int
port_stream_truncate(mu_stream_t stream,mu_off_t size)61 port_stream_truncate (mu_stream_t stream, mu_off_t size)
62 {
63 struct port_stream *pstr = (struct port_stream *)stream;
64 scm_truncate_file (pstr->port, scm_from_signed_integer (size));
65 return 0;
66 }
67
68 static void
port_stream_done(struct _mu_stream * str)69 port_stream_done (struct _mu_stream *str)
70 {
71 struct port_stream *pstr = (struct port_stream *)str;
72 scm_gc_unprotect_object (pstr->port);
73 }
74
75 static int
port_stream_size(struct _mu_stream * str,mu_off_t * psize)76 port_stream_size (struct _mu_stream *str, mu_off_t *psize)
77 {
78 struct port_stream *pstr = (struct port_stream *)str;
79 mu_off_t cur;
80 int rc;
81 SCM ret;
82
83 rc = mu_stream_seek (str, 0, MU_SEEK_CUR, &cur);
84 if (rc)
85 return rc;
86 ret = scm_seek (pstr->port,
87 scm_from_signed_integer (0),
88 scm_from_int (SEEK_END));
89 rc = mu_stream_seek (str, cur, MU_SEEK_SET, NULL);
90 if (rc == 0)
91 *psize = scm_to_int64 (ret);
92 return rc;
93 }
94
95 int
mu_scm_port_stream_create(mu_stream_t * pstream,SCM port)96 mu_scm_port_stream_create (mu_stream_t *pstream, SCM port)
97 {
98 char *mode;
99 int flags = MU_STREAM_SEEK|_MU_STR_OPEN;
100 struct port_stream *pstr;
101
102 mode = scm_to_locale_string (scm_port_mode (port));
103 if (strchr (mode, 'r'))
104 flags |= MU_STREAM_READ;
105 if (strchr (mode, 'w'))
106 flags |= MU_STREAM_WRITE;
107 free (mode);
108
109 pstr = (struct port_stream *) _mu_stream_create (sizeof (*pstr), flags);
110 if (!pstr)
111 return ENOMEM;
112 pstr->stream.read = port_stream_read;
113 pstr->stream.write = port_stream_write;
114 pstr->stream.seek = port_stream_seek;
115 pstr->stream.size = port_stream_size;
116 pstr->stream.truncate = port_stream_truncate;
117 pstr->stream.done = port_stream_done;
118 pstr->port = port;
119 scm_gc_protect_object (port);
120 *pstream = (mu_stream_t) pstr;
121 return 0;
122 }
123
124
125
126