blob: f9c44901fb4d4a0f197ccc69b23420a092b7a60b [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This file is part of GNU uCommon C++.
5//
6// GNU uCommon C++ is free software: you can redistribute it and/or modify
7// it under the terms of the GNU Lesser General Public License as published
8// by the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// GNU uCommon C++ is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU Lesser General Public License for more details.
15//
16// You should have received a copy of the GNU Lesser General Public License
17// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
18
19#include <ucommon-config.h>
20#include <ucommon/export.h>
21#include <ucommon/protocols.h>
22#include <ucommon/string.h>
23#include <ucommon/memory.h>
24#include <stdlib.h>
25#include <ctype.h>
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29
30#undef getc
31#undef putc
32#undef puts
33#undef gets
34
35using namespace UCOMMON_NAMESPACE;
36
37void MemoryProtocol::fault(void) const
38{
39}
40
41char *MemoryProtocol::dup(const char *str)
42{
43 if(!str)
44 return NULL;
45 size_t len = strlen(str) + 1;
46 char *mem = static_cast<char *>(alloc(len));
47 if(mem)
48 String::set(mem, len, str);
49 else
50 fault();
51 return mem;
52}
53
54void *MemoryProtocol::dup(void *obj, size_t size)
55{
56 assert(obj != NULL);
57 assert(size > 0);
58
59 char *mem = static_cast<char *>(alloc(size));
60 if(mem)
61 memcpy(mem, obj, size);
62 else
63 fault();
64 return mem;
65}
66
67void *MemoryProtocol::zalloc(size_t size)
68{
69 void *mem = alloc(size);
70
71 if(mem)
72 memset(mem, 0, size);
73 else
74 fault();
75
76 return mem;
77}
78
79MemoryProtocol::~MemoryProtocol()
80{
81}
82
83MemoryRedirect::MemoryRedirect(MemoryProtocol *protocol)
84{
85 target = protocol;
86}
87
88void *MemoryRedirect::_alloc(size_t size)
89{
90 // a null redirect uses the heap...
91 if(!target)
92 return malloc(size);
93
94 return target->_alloc(size);
95}
96
97BufferProtocol::BufferProtocol() : CharacterProtocol()
98{
99 end = true;
100 eol = "\r\n";
101 input = output = buffer = NULL;
102}
103
104BufferProtocol::BufferProtocol(size_t size, mode_t mode)
105{
106 end = true;
107 eol = "\r\n";
108 input = output = buffer = NULL;
109 allocate(size, mode);
110}
111
112BufferProtocol::~BufferProtocol()
113{
114 release();
115}
116
117void BufferProtocol::fault(void) const
118{
119}
120
121void BufferProtocol::release(void)
122{
123 if(buffer) {
124 flush();
125 free(buffer);
126 input = output = buffer = NULL;
127 end = true;
128 }
129}
130
131void BufferProtocol::allocate(size_t size, mode_t mode)
132{
133 release();
134 _clear();
135
136 if(!size)
137 return;
138
139 back = 0;
140 switch(mode) {
141 case RDWR:
142 input = buffer = (char *)malloc(size * 2);
143 if(buffer)
144 output = buffer + size;
145 else
146 fault();
147 break;
148 case RDONLY:
149 input = buffer = (char *)malloc(size);
150 if(!buffer)
151 fault();
152 break;
153 case WRONLY:
154 output = buffer = (char *)malloc(size);
155 if(!buffer)
156 fault();
157 break;
158 }
159
160 bufpos = insize = outsize = 0;
161 bufsize = size;
162
163 if(buffer)
164 end = false;
165}
166
167bool BufferProtocol::_blocking(void)
168{
169 return false;
170}
171
172size_t BufferProtocol::put(const void *address, size_t size)
173{
174 size_t count = 0;
175
176 if(!output || !address || !size)
177 return 0;
178
179 const char *cp = (const char *)address;
180
181 while(count < size) {
182 if(outsize == bufsize) {
183 outsize = 0;
184 if(_push(output, bufsize) < bufsize) {
185 output = NULL;
186 end = true; // marks a disconnection...
187 return count;
188 }
189 }
190 output[outsize++] = cp[count++];
191 }
192 return count;
193}
194
195size_t BufferProtocol::get(void *address, size_t size)
196{
197 size_t count = 0;
198
199 if(!input || !address || !size)
200 return 0;
201
202 char *cp = (char *)address;
203
204 while(count < size) {
205 if(bufpos == insize) {
206 if(end)
207 return count;
208
209 insize = _pull(input, bufsize);
210 bufpos = 0;
211 if(insize == 0)
212 end = true;
213 else if(insize < bufsize && !_blocking())
214 end = true;
215
216 if(!insize)
217 return count;
218 }
219 cp[count++] = input[bufpos++];
220 }
221 return count;
222}
223
224int BufferProtocol::_getch(void)
225{
226 if(!input)
227 return EOF;
228
229 if(back) {
230 back = 0;
231 return back;
232 }
233
234 if(bufpos == insize) {
235 if(end)
236 return EOF;
237
238 insize = _pull(input, bufsize);
239 bufpos = 0;
240 if(insize == 0)
241 end = true;
242 else if(insize < bufsize && !_blocking())
243 end = true;
244
245 if(!insize)
246 return EOF;
247 }
248
249 return input[bufpos++];
250}
251
252size_t CharacterProtocol::putchars(const char *address, size_t size)
253{
254 size_t count = 0;
255
256 if(!address)
257 return 0;
258
259 if(!size)
260 size = strlen(address);
261
262 while(count < size) {
263 if(_putch(*address) == EOF)
264 break;
265 ++count;
266 ++address;
267 }
268
269 return count;
270}
271
272int BufferProtocol::_putch(int ch)
273{
274 if(!output)
275 return EOF;
276
277 if(ch == 0) {
278 puts(eol);
279 flush();
280 return 0;
281 }
282
283 if(outsize == bufsize) {
284 outsize = 0;
285 if(_push(output, bufsize) < bufsize) {
286 output = NULL;
287 end = true; // marks a disconnection...
288 return EOF;
289 }
290 }
291
292 output[outsize++] = ch;
293 return ch;
294}
295
296size_t BufferProtocol::printf(const char *pformat, ...)
297{
298 va_list args;
299 int result;
300 size_t count;
301
302 if(!flush() || !output || !pformat)
303 return 0;
304
305 va_start(args, pformat);
306 result = vsnprintf(output, bufsize, pformat, args);
307 va_end(args);
308 if(result < 1)
309 return 0;
310
311 if((size_t)result > bufsize)
312 result = bufsize;
313
314 count = _push(output, result);
315 if(count < (size_t)result) {
316 output = NULL;
317 end = true;
318 }
319
320 return count;
321}
322
323void BufferProtocol::purge(void)
324{
325 outsize = insize = bufpos = 0;
326}
327
328bool BufferProtocol::_flush(void)
329{
330 if(!output)
331 return false;
332
333 if(!outsize)
334 return true;
335
336 if(_push(output, outsize) == outsize) {
337 outsize = 0;
338 return true;
339 }
340 output = NULL;
341 end = true;
342 return false;
343}
344
345char *BufferProtocol::gather(size_t size)
346{
347 if(!input || size > bufsize)
348 return NULL;
349
350 if(size + bufpos > insize) {
351 if(end)
352 return NULL;
353
354 size_t adjust = outsize - bufpos;
355 memmove(input, input + bufpos, adjust);
356 insize = adjust + _pull(input, bufsize - adjust);
357 bufpos = 0;
358
359 if(insize < bufsize)
360 end = true;
361 }
362
363 if(size + bufpos <= insize) {
364 char *bp = input + bufpos;
365 bufpos += size;
366 return bp;
367 }
368
369 return NULL;
370}
371
372char *BufferProtocol::request(size_t size)
373{
374 if(!output || size > bufsize)
375 return NULL;
376
377 if(size + outsize > bufsize)
378 flush();
379
380 size_t offset = outsize;
381 outsize += size;
382 return output + offset;
383}
384
385size_t CharacterProtocol::putline(const char *string)
386{
387 size_t count = 0;
388
389 while(string && *string && (EOF != _putch(*string)))
390 ++count;
391
392 string = eol;
393 while(string && *string && (EOF != _putch(*string)))
394 ++count;
395
396 return count;
397}
398
399size_t CharacterProtocol::getline(String& s)
400{
401 size_t result = getline(s.c_mem(), s.size() + 1);
402 String::fix(s);
403 return result;
404}
405
406size_t CharacterProtocol::getline(char *string, size_t size)
407{
408 size_t count = 0;
409 unsigned eolp = 0;
410 const char *eols = eol;
411 bool eof = false;
412
413 if(!eols)
414 eols = "\0";
415
416 if(string)
417 string[0] = 0;
418
419 while(count < size - 1) {
420 int ch = _getch();
421 if(ch == EOF) {
422 eolp = 0;
423 eof = true;
424 break;
425 }
426
427 string[count++] = ch;
428
429 if(ch == eols[eolp]) {
430 ++eolp;
431 if(eols[eolp] == 0)
432 break;
433 }
434 else
435 eolp = 0;
436
437 // special case for \r\n can also be just eol as \n
438 if(eq(eol, "\r\n") && ch == '\n') {
439 ++eolp;
440 break;
441 }
442 }
443 count -= eolp;
444 string[count] = 0;
445 if(!eof)
446 ++count;
447 return count;
448}
449
450size_t CharacterProtocol::print(const PrintProtocol& f)
451{
452 const char *cp = f._print();
453
454 if(cp == NULL)
455 return putchar(0);
456
457 return putchars(cp);
458}
459
460size_t CharacterProtocol::input(InputProtocol& f)
461{
462 int c;
463 size_t count = 0;
464
465 for(;;) {
466 if(back) {
467 c = back;
468 back = 0;
469 }
470 else
471 c = _getch();
472
473 c = f._input(c);
474 if(c) {
475 if(c != EOF)
476 back = c;
477 else
478 ++count;
479 break;
480 }
481 ++count;
482 }
483 return count;
484}
485
486size_t CharacterProtocol::load(StringPager *list)
487{
488 if(!list)
489 return 0;
490
491 size_t used = 0;
492 size_t size = list->size() - 64;
493
494 char *tmp = (char *)malloc(size);
495 while(getline(tmp, size)) {
496 if(!list->filter(tmp, size))
497 break;
498
499 ++used;
500 }
501 free(tmp);
502 return used;
503}
504
505size_t CharacterProtocol::save(const StringPager *list)
506{
507 size_t used = 0;
508 if(!list)
509 return 0;
510
511 StringPager::iterator sp = list->begin();
512 while(is(sp) && putline(sp->get())) {
513 ++used;
514 sp.next();
515 }
516 return used;
517}
518
519void BufferProtocol::reset(void)
520{
521 insize = bufpos = 0;
522}
523
524bool BufferProtocol::eof(void)
525{
526 if(!input)
527 return true;
528
529 if(end && bufpos == insize)
530 return true;
531
532 return false;
533}
534
535bool BufferProtocol::_pending(void)
536{
537 if(!input)
538 return false;
539
540 if(!bufpos)
541 return false;
542
543 return true;
544}
545
546void LockingProtocol::_lock(void)
547{
548}
549
550void LockingProtocol::_unlock(void)
551{
552}
553
554LockingProtocol::~LockingProtocol()
555{
556}
557
558CharacterProtocol::CharacterProtocol()
559{
560 back = 0;
561 eol = "\n";
562}
563
564CharacterProtocol::~CharacterProtocol()
565{
566}
567
568ObjectProtocol::~ObjectProtocol()
569{
570}
571
572ObjectProtocol *ObjectProtocol::copy(void)
573{
574 retain();
575 return this;
576}
577
578CharacterProtocol& _character_operators::print(CharacterProtocol& p, const char& c)
579{
580 p.putchar((int)c);
581 return p;
582}
583
584CharacterProtocol& _character_operators::input(CharacterProtocol& p, char& c)
585{
586 int code = p.getchar();
587 if(code == EOF)
588 code = 0;
589 c = code;
590 return p;
591}
592
593CharacterProtocol& _character_operators::print(CharacterProtocol& p, const char *str)
594{
595 if(!str)
596 p.putline("");
597 else
598 p.putchars(str);
599 return p;
600}
601
602CharacterProtocol& _character_operators::input(CharacterProtocol& p, String& str)
603{
604 if(str.c_mem()) {
605 p.getline(str.c_mem(), str.size());
606 String::fix(str);
607 }
608 return p;
609}
610
611CharacterProtocol& _character_operators::print(CharacterProtocol& p, const long& v)
612{
613 char buf[40];
614 snprintf(buf, sizeof(buf), "%ld", v);
615 p.putchars(buf);
616 return p;
617}
618
619CharacterProtocol& _character_operators::print(CharacterProtocol& p, const double& v)
620{
621 char buf[40];
622 snprintf(buf, sizeof(buf), "%f", v);
623 p.putchars(buf);
624 return p;
625}
626
627
628class __LOCAL _input_long : public InputProtocol
629{
630public:
631 long* ref;
632 size_t pos;
633 char buf[32];
634
635 _input_long(long& v);
636
637 int _input(int code);
638};
639
640class __LOCAL _input_double : public InputProtocol
641{
642public:
643 double* ref;
644 bool dot;
645 bool e;
646 size_t pos;
647 char buf[60];
648
649 _input_double(double& v);
650
651 int _input(int code);
652};
653
654_input_long::_input_long(long& v)
655{
656 ref = &v;
657 v = 0l;
658 pos = 0;
659}
660
661_input_double::_input_double(double& v)
662{
663 dot = e = false;
664 v = 0.0;
665 pos = 0;
666 ref = &v;
667}
668
669int _input_long::_input(int code)
670{
671 if(code == '-' && !pos)
672 goto valid;
673
674 if(isdigit(code) && pos < sizeof(buf) - 1)
675 goto valid;
676
677 buf[pos] = 0;
678 if(pos)
679 sscanf(buf, "%ld", ref);
680
681 return code;
682
683valid:
684 buf[pos++] = code;
685 return 0;
686}
687
688int _input_double::_input(int code)
689{
690 if(code == '-' && !pos)
691 goto valid;
692
693 if(code == '-' && buf[pos] == 'e')
694 goto valid;
695
696 if(tolower(code) == 'e' && !e) {
697 e = true;
698 code = 'e';
699 goto valid;
700 }
701
702 if(code == '.' && !dot) {
703 dot = true;
704 goto valid;
705 }
706
707 if(isdigit(code) && pos < sizeof(buf) - 1)
708 goto valid;
709
710 buf[pos] = 0;
711 if(pos)
712 sscanf(buf, "%lf", ref);
713
714 return code;
715
716valid:
717 buf[pos++] = code;
718 return 0;
719}
720
721CharacterProtocol& _character_operators::input(CharacterProtocol& p, long& v)
722{
723 _input_long lv(v);
724 p.input(lv);
725 return p;
726}
727
728CharacterProtocol& _character_operators::input(CharacterProtocol& p, double& v)
729{
730 _input_double lv(v);
731 p.input(lv);
732 return p;
733}
734
735PrintProtocol::~PrintProtocol()
736{
737}
738
739InputProtocol::~InputProtocol()
740{
741}