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