1 /*
2 *
3 * C++ Portable Types Library (PTypes)
4 * Version 2.1.1 Released 27-Jun-2007
5 *
6 * Copyright (C) 2001-2007 Hovik Melikyan
7 *
8 * http://www.melikyan.com/ptypes/
9 *
10 */
11
12 #include <errno.h>
13 #include <string.h>
14 #include <limits.h>
15
16 #ifdef WIN32
17 # include <windows.h>
18 #else
19 # include <unistd.h>
20 #endif
21
22 #include "pstreams.h"
23
24
25 PTYPES_BEGIN
26
27
instm(int ibufsize)28 instm::instm(int ibufsize): iobase(ibufsize)
29 {
30 }
31
32
~instm()33 instm::~instm()
34 {
35 }
36
37
classid()38 int instm::classid()
39 {
40 return CLASS_INSTM;
41 }
42
43
dorawread(char * buf,int count)44 int instm::dorawread(char* buf, int count)
45 {
46 if (handle == invhandle)
47 return -1;
48 #ifdef WIN32
49 unsigned long ret;
50 if (!ReadFile(HANDLE(handle), buf, count, &ret, nil))
51 #else
52 int ret;
53 if ((ret = ::read(handle, buf, count)) < 0)
54 #endif
55 {
56 int e = uerrno();
57 if (e == EPIPE)
58 ret = 0;
59 else
60 error(e, "Couldn't read");
61 }
62 return ret;
63 }
64
65
rawread(char * buf,int count)66 int instm::rawread(char* buf, int count)
67 {
68 requireactive();
69 try
70 {
71 int ret = dorawread(buf, count);
72 if (ret <= 0) {
73 ret = 0;
74 eof = true;
75 chstat(IO_EOF);
76 }
77 else
78 {
79 abspos += ret;
80 chstat(IO_READING);
81 }
82 return ret;
83 }
84 catch (estream*)
85 {
86 eof = true;
87 chstat(IO_EOF);
88 throw;
89 }
90 }
91
92
tellx()93 large instm::tellx()
94 {
95 return abspos - bufend + bufpos;
96 }
97
98
bufvalidate()99 void instm::bufvalidate()
100 {
101 requirebuf();
102 bufclear();
103 bufend = rawread(bufdata, bufsize);
104 }
105
106
seekx(large newpos,ioseekmode mode)107 large instm::seekx(large newpos, ioseekmode mode)
108 {
109 if (bufdata != 0 && mode != IO_END)
110 {
111 if (mode == IO_CURRENT)
112 {
113 newpos += tellx();
114 mode = IO_BEGIN;
115 }
116
117 // see if it is possible to seek within the buffer
118 large newbufpos = newpos - (abspos - bufend);
119 if (newbufpos >= 0 && newbufpos <= bufend)
120 {
121 bufpos = (int)newbufpos;
122 eof = false;
123 return tellx();
124 }
125 }
126
127 // if IO_END or if not possible to seek within the buffer
128 return iobase::seekx(newpos, mode);
129 }
130
131
get_eof()132 bool instm::get_eof()
133 {
134 if (!eof && bufdata != 0 && bufpos >= bufend)
135 bufvalidate();
136 return eof;
137 }
138
139
get_dataavail()140 int instm::get_dataavail()
141 {
142 get_eof();
143 return bufend - bufpos;
144 }
145
146
preview()147 char instm::preview()
148 {
149 if (!eof && bufpos >= bufend)
150 bufvalidate();
151 if (eof)
152 return eofchar;
153 return bufdata[bufpos];
154 }
155
156
putback()157 void instm::putback()
158 {
159 requireactive();
160 if (bufpos == 0)
161 fatal(CRIT_FIRST + 14, "putback() failed");
162 bufpos--;
163 eof = false;
164 }
165
166
get_eol()167 bool instm::get_eol()
168 {
169 char c = preview();
170 return (eof || c == 10 || c == 13);
171 }
172
173
skipeol()174 void instm::skipeol()
175 {
176 switch (preview())
177 {
178 case 10:
179 get();
180 break;
181 case 13:
182 get();
183 if (preview() == 10)
184 get();
185 break;
186 }
187 }
188
189
get()190 char instm::get()
191 {
192 char ret = preview();
193 if (!eof)
194 bufpos++;
195 return ret;
196 }
197
198
token(const cset & chars,int limit)199 string instm::token(const cset& chars, int limit)
200 {
201 requirebuf();
202 string ret;
203 while (!get_eof())
204 {
205 char* b = bufdata + bufpos;
206 char* e = bufdata + bufend;
207 char* p = b;
208 while (p < e && (*p & chars))
209 p++;
210 int n = p - b;
211 limit -= n;
212 if (limit < 0)
213 {
214 bufpos += n + limit;
215 error(ERANGE, "Token too long");
216 }
217 concat(ret, b, n);
218 bufpos += n;
219 if (p < e)
220 break;
221 }
222 return ret;
223 }
224
225
token(const cset & chars)226 string instm::token(const cset& chars)
227 {
228 return token(chars, INT_MAX);
229 }
230
231
232 static cset linechars = cset("*") - cset("~0a~0d");
233
234
line(int limit)235 string instm::line(int limit)
236 {
237 string ret = token(linechars, limit);
238 skipeol();
239 return ret;
240 }
241
242
line()243 string instm::line()
244 {
245 string ret = token(linechars, INT_MAX);
246 skipeol();
247 return ret;
248 }
249
250
token(const cset & chars,char * buf,int count)251 int instm::token(const cset& chars, char* buf, int count)
252 {
253 requirebuf();
254 int ret = 0;
255 while (count > 0 && !get_eof())
256 {
257 char* b = bufdata + bufpos;
258 char* e = b + imin(count, bufend - bufpos);
259 char* p = b;
260 while (p < e && (*p & chars))
261 p++;
262 int n = p - b;
263 memcpy(buf, b, n);
264 buf += n;
265 ret += n;
266 count -= n;
267 bufpos += n;
268 if (p < e)
269 break;
270 }
271 return ret;
272 }
273
274
line(char * buf,int size,bool eateol)275 int instm::line(char* buf, int size, bool eateol)
276 {
277 int ret = token(linechars, buf, size);
278 if (eateol)
279 skipeol();
280 return ret;
281 }
282
283
read(void * buf,int count)284 int instm::read(void* buf, int count)
285 {
286 int ret = 0;
287 if (bufdata == 0)
288 ret = rawread(pchar(buf), count);
289 else
290 {
291 while (count > 0 && !get_eof())
292 {
293 int n = imin(count, bufend - bufpos);
294 memcpy(buf, bufdata + bufpos, n);
295 buf = pchar(buf) + n;
296 ret += n;
297 count -= n;
298 bufpos += n;
299 }
300 }
301 return ret;
302 }
303
304
skip(int count)305 int instm::skip(int count)
306 {
307 int ret = 0;
308 requirebuf();
309 while (count > 0 && !get_eof())
310 {
311 int n = imin(count, bufend - bufpos);
312 ret += n;
313 count -= n;
314 bufpos += n;
315 }
316 return ret;
317 }
318
319
skiptoken(const cset & chars)320 int instm::skiptoken(const cset& chars)
321 {
322 int ret = 0;
323 requirebuf();
324 while (!get_eof())
325 {
326 char* b = bufdata + bufpos;
327 char* e = bufdata + bufend;
328 char* p = b;
329 while (p < e && (*p & chars))
330 p++;
331 int n = p - b;
332 bufpos += n;
333 ret += n;
334 if (p < e)
335 break;
336 }
337 return ret;
338 }
339
340
skipline(bool eateol)341 void instm::skipline(bool eateol)
342 {
343 if (!get_eol())
344 skiptoken(linechars);
345 if (eateol)
346 skipeol();
347 }
348
349
350 PTYPES_END
351