mescc: Mes C Library: Add buffered read.
[mes.git] / lib / mes / __buffered_read.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * GNU Mes --- Maxwell Equations of Software
3  * Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
4  *
5  * This file is part of GNU Mes.
6  *
7  * GNU Mes is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or (at
10  * your option) any later version.
11  *
12  * GNU Mes is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <mes/lib.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #define __READ_BUFFER_MAX 100
26
27 struct __read_buffer
28 {
29   ssize_t size;
30   char string[__READ_BUFFER_MAX];
31 };
32
33 struct __read_buffer *__read_cache = 0;
34
35 void
36 __buffered_read_init (int filedes)
37 {
38   if (!__read_cache)
39     __read_cache = (struct __read_buffer *) malloc (sizeof (struct __read_buffer) * __FILEDES_MAX);
40 }
41
42 size_t
43 __buffered_read_clear (int filedes)
44 {
45   __buffered_read_init (filedes);
46   size_t size = __read_cache[filedes].size;
47   __read_cache[filedes].size = 0;
48   return size;
49 }
50
51 ssize_t
52 __buffered_read (int filedes, void *buffer, size_t size)
53 {
54   size_t todo = size;
55   __buffered_read_init (filedes);
56   struct __read_buffer *cache = &__read_cache[filedes];
57   char *p = buffer;
58   if (!cache->size && size > __READ_BUFFER_MAX)
59     return _read (filedes, buffer, size);
60   while (cache->size > 0 && todo)
61     {
62       todo--;
63       *p++ = cache->string[__READ_BUFFER_MAX - cache->size--];
64     }
65   if (todo)
66     {
67       ssize_t bytes = _read (filedes, cache->string, __READ_BUFFER_MAX);
68       if (bytes < 0)
69         return -1;
70       if (bytes)
71         {
72           cache->size = bytes;
73           if (bytes < __READ_BUFFER_MAX)
74             memmove (cache->string + __READ_BUFFER_MAX - bytes, cache->string, bytes);
75           return size - todo + __buffered_read (filedes, p, todo);
76         }
77     }
78   return size - todo;
79 }