1 /* Copyright (C) 2008, 2014 Free Software Foundation, Inc.
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public License
5  * as published by the Free Software Foundation; either version 3 of
6  * the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16  * 02110-1301 USA
17  */
18 
19 /* Exercise `scm_c_read ()' and the port type API.  Verify assumptions that
20    can be made by port type implementations.  */
21 
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25 
26 #undef NDEBUG
27 
28 #include <libguile.h>
29 #include <assert.h>
30 
31 
32 
33 /* Size of our port's internal buffer.  */
34 #define PORT_BUFFER_SIZE 1024
35 
36 struct custom_port
37 {
38   size_t pos;
39   size_t len;
40   char *buf;
41 };
42 
43 
44 /* Return a new port of type PORT_TYPE.  */
45 static inline SCM
make_port(scm_t_port_type * port_type)46 make_port (scm_t_port_type *port_type)
47 {
48   struct custom_port *stream = scm_gc_typed_calloc (struct custom_port);
49 
50   stream->pos = 0;
51   stream->len = PORT_BUFFER_SIZE;
52   stream->buf = scm_gc_calloc (stream->len, "custom-port-buffer");
53 
54   return scm_c_make_port (port_type, SCM_RDNG, (scm_t_bits) stream);
55 }
56 
57 static size_t
custom_port_read(SCM port,SCM dst,size_t start,size_t count)58 custom_port_read (SCM port, SCM dst, size_t start, size_t count)
59 {
60   size_t to_copy = count;
61   struct custom_port *stream = (void *) SCM_STREAM (port);
62 
63   if (stream->pos + to_copy > stream->len)
64     to_copy = stream->len - stream->pos;
65 
66   memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
67           stream->buf + stream->pos, to_copy);
68   stream->pos += to_copy;
69 
70   return to_copy;
71 }
72 
73 /* Return true (non-zero) if BUF contains only zeros.  */
74 static inline int
zeroed_buffer_p(const char * buf,size_t len)75 zeroed_buffer_p (const char *buf, size_t len)
76 {
77   size_t i;
78 
79   for (i = 0; i < len; i++)
80     if (buf[i] != 0)
81       return 0;
82 
83   return 1;
84 }
85 
86 /* Run the test.  */
87 static void *
do_start(void * arg)88 do_start (void *arg)
89 {
90   SCM port;
91   scm_t_port_type *port_type;
92   char buffer[PORT_BUFFER_SIZE + (PORT_BUFFER_SIZE / 2)];
93   size_t read, last_read;
94 
95   port_type = scm_make_port_type ("custom-input-port", custom_port_read, NULL);
96   port = make_port (port_type);
97 
98   read = 0;
99   do
100     {
101       last_read = scm_c_read (port, &buffer[read], 123);
102       assert (last_read <= 123);
103       assert (zeroed_buffer_p (&buffer[read], last_read));
104 
105       read += last_read;
106     }
107   while (last_read > 0 && read < sizeof (buffer));
108 
109   /* We shouldn't be able to read more than what's in PORT's buffer.  */
110   assert (read == PORT_BUFFER_SIZE);
111 
112   return NULL;
113 }
114 
115 
116 int
main(int argc,char * argv[])117 main (int argc, char *argv[])
118 {
119   scm_with_guile (do_start, NULL);
120 
121   return 0;
122 }
123