1 /* inputbuf.c */
2 
3 /*
4     Copyright (C) 2008 Micah Cowan
5 
6     This file is part of GNU teseq.
7 
8     GNU teseq is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12 
13     GNU teseq is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "teseq.h"
23 
24 #include <errno.h>
25 #include <stdlib.h>
26 
27 #include "inputbuf.h"
28 #include "ringbuf.h"
29 
30 struct inputbuf
31 {
32   FILE *file;
33   int saving;
34   size_t count;
35   size_t saved_count;
36   struct ringbuf *rb;
37   struct ringbuf_reader *reader;
38   int err;
39 };
40 
41 struct inputbuf *
inputbuf_new(FILE * f,size_t bufsz)42 inputbuf_new (FILE * f, size_t bufsz)
43 {
44   struct inputbuf *ret = NULL;
45   struct ringbuf *rb = NULL;
46   struct ringbuf_reader *reader = NULL;
47 
48   ret = malloc (sizeof *ret);
49   if (!ret)
50     goto cleanup;
51   rb = ringbuf_new (bufsz);
52   if (!rb)
53     goto cleanup;
54   reader = ringbuf_reader_new (rb);
55   if (!reader)
56     goto cleanup;
57 
58   ret->rb = rb;
59   ret->reader = reader;
60   ret->file = f;
61   ret->saving = 0;
62   ret->count = 0;
63   ret->err = 0;
64   return ret;
65 
66 cleanup:
67   free (ret);
68   free (rb);
69   free (reader);
70   return NULL;
71 }
72 
73 void
inputbuf_delete(struct inputbuf * ib)74 inputbuf_delete (struct inputbuf *ib)
75 {
76   ringbuf_delete (ib->rb);
77   free (ib);
78 }
79 
80 int
inputbuf_io_error(struct inputbuf * ib)81 inputbuf_io_error (struct inputbuf *ib)
82 {
83   return ib->err;
84 }
85 
86 int
inputbuf_get(struct inputbuf * ib)87 inputbuf_get (struct inputbuf *ib)
88 {
89   int c;
90   if (ib->saving)
91     {
92       c = ringbuf_reader_get (ib->reader);
93       if (c == EOF && ringbuf_space_avail (ib->rb))
94         {
95           errno = 0;
96           c = getc (ib->file);
97           if (c == EOF)
98             ib->err = errno;
99           else
100             ringbuf_put (ib->rb, c);
101         }
102       if (c != EOF)
103         ++ib->saved_count;
104     }
105   else
106     {
107       c = ringbuf_get (ib->rb);
108       if (c == EOF)
109         {
110           errno = 0;
111           c = getc (ib->file);
112         }
113       if (c == EOF)
114         ib->err = errno;
115       else
116         ++ib->count;
117     }
118   return c;
119 }
120 
121 int
inputbuf_saving(struct inputbuf * ib)122 inputbuf_saving (struct inputbuf *ib)
123 {
124   if (ib->saving)
125     return 1;
126   ib->saving = 1;
127   ib->saved_count = 0;
128   ringbuf_reader_reset (ib->reader);
129   return 0;
130 }
131 
132 int
inputbuf_rewind(struct inputbuf * ib)133 inputbuf_rewind (struct inputbuf *ib)
134 {
135   ringbuf_reader_reset (ib->reader);
136   ib->saving = 0;
137   return 0;
138 }
139 
140 int
inputbuf_forget(struct inputbuf * ib)141 inputbuf_forget (struct inputbuf *ib)
142 {
143   if (!ib->saving)
144     return 1;
145   ringbuf_reader_consume (ib->reader);
146   ib->saving = 0;
147   ib->count += ib->saved_count;
148   return 0;
149 }
150 
151 size_t
inputbuf_get_count(struct inputbuf * ib)152 inputbuf_get_count (struct inputbuf *ib)
153 {
154   return ib->count;
155 }
156 
157 void
inputbuf_reset_count(struct inputbuf * ib)158 inputbuf_reset_count (struct inputbuf *ib)
159 {
160   ib->count = 0;
161   ib->saved_count = 0;
162 }
163 
164 int
inputbuf_avail(struct inputbuf * ib)165 inputbuf_avail (struct inputbuf *ib)
166 {
167   return ib->saving ? !ringbuf_reader_at_end (ib->reader)
168     : !ringbuf_is_empty (ib->rb);
169 }
170 
171