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