Evo C++ Library v0.5.1
sysio.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_impl_sysio_h
9 #define INCL_evo_impl_sysio_h
10 
11 #include "rawbuffer.h"
12 #include "../string.h"
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 
17 #if defined(_WIN32)
18  // Windows
19  #include <io.h>
20 #endif
21 
22 // Disable certain MSVC warnings for this file
23 #if defined(_MSC_VER)
24  #pragma warning(push)
25  #pragma warning(disable:4100 4996)
26 #endif
27 
28 namespace evo {
31 
33 
34 #if !defined(_WIN32)
35  // Linux/Unix
36  struct SysLinuxIo {
37  static bool read_wait(Error& err, int handle, ulong timeout_ms, bool autoresume) {
38  assert(handle >= 0);
39  assert(timeout_ms > 0);
40 
41  fd_set read_set;
42  FD_ZERO(&read_set);
43  FD_SET(handle, &read_set);
44 
45  struct timeval timeout;
46  SysLinux::set_timeval_ms(timeout, timeout_ms);
47  for (;;) {
48  int waitresult = ::select(handle+1, &read_set, NULL, NULL, &timeout);
49  if (waitresult < 0) {
50  switch (errno) {
51  case EINTR:
52  if (autoresume) {
53  #if !defined(__linux__) // Linux select() updates timeout, others need to set it again
54  SysLinux::set_timeval_ms(timeout, timeout_ms);
55  #endif
56  continue;
57  }
58  err = ESignal;
59  break;
60  case EBADF: err = EClosed; break;
61  default: err = EUnknown; break;
62  }
63  return false;
64  } else if (waitresult == 0) {
65  err = ETimeout;
66  return false;
67  }
68  break;
69  }
70  return true;
71  }
72 
73  static ulong read(Error& err, int handle, void* buf, ulong size, ulong timeout_ms, bool autoresume) {
74  if (handle == -1) {
75  errno = EBADF;
76  err = EClosed;
77  return 0;
78  }
79  if (size > SSIZE_MAX)
80  size = SSIZE_MAX;
81  ssize_t result;
82  for (;;) {
83  if (timeout_ms > 0 && !SysLinuxIo::read_wait(err, handle, timeout_ms, autoresume))
84  return 0;
85  result = ::read(handle, buf, size);
86  if (result < 0) {
87  switch (errno) {
88  case EINTR:
89  if (autoresume)
90  continue;
91  err = ESignal; break;
92  case ENOSPC: err = ESpace; break;
93  case EFBIG: err = ESize; break;
94  case EFAULT: err = EPtr; break;
95  case EBADF: err = EClosed; break;
96  #if EAGAIN != EWOULDBLOCK
97  case EAGAIN: // fallthrough
98  #endif
99  case EWOULDBLOCK: err = ENonBlock; break;
100  default: err = ERead; break;
101  }
102  return 0;
103  }
104  break;
105  }
106  err = ENone;
107  return result;
108  }
109 
110  static bool write_wait(Error& err, int handle, ulong timeout_ms, bool autoresume) {
111  fd_set write_set;
112  FD_ZERO(&write_set);
113  FD_SET(handle, &write_set);
114 
115  struct timeval timeout;
116  SysLinux::set_timeval_ms(timeout, timeout_ms);
117  for (;;) {
118  int waitresult = ::select(handle+1, NULL, &write_set, NULL, &timeout);
119  if (waitresult < 0) {
120  switch (errno) {
121  case EINTR:
122  if (autoresume) {
123  #if !defined(__linux__) // Linux select() updates timeout, others need to set it again
124  SysLinux::set_timeval_ms(timeout, timeout_ms);
125  #endif
126  continue;
127  }
128  err = ESignal;
129  break;
130  case EBADF: err = EClosed; break;
131  default: err = EUnknown; break;
132  }
133  return false;
134  } else if (waitresult == 0) {
135  err = ETimeout;
136  return false;
137  }
138  break;
139  }
140  return true;
141  }
142 
143  static ulong write(Error& err, int handle, const void* buf, ulong size, ulong timeout_ms, bool autoresume) {
144  if (handle == -1) {
145  errno = EBADF;
146  err = EClosed;
147  return 0;
148  }
149  if (size > SSIZE_MAX)
150  size = SSIZE_MAX;
151  ssize_t result;
152  for (;;) {
153  if (timeout_ms > 0 && !SysLinuxIo::write_wait(err, handle, timeout_ms, autoresume))
154  return 0;
155  result = ::write(handle, buf, size);
156  if (result == 0) {
157  err = EFail;
158  return 0;
159  } else if (result < 0) {
160  switch (errno) {
161  case EINTR:
162  if (autoresume)
163  continue;
164  err = ESignal; break;
165  case ENOSPC: err = ESpace; break;
166  case EFBIG: err = ESize; break;
167  case EFAULT: err = EPtr; break;
168  case EBADF: err = EClosed; break;
169  #if EAGAIN != EWOULDBLOCK
170  case EAGAIN: // fallthrough
171  #endif
172  case EWOULDBLOCK: err = ENonBlock; break;
173  default: err = EWrite; break;
174  }
175  return 0;
176  }
177  break;
178  }
179  err = ENone;
180  return result;
181  }
182  };
183 #endif
184 
186 
190 enum Open {
191  oREAD = O_RDONLY,
192  oREAD_WRITE = O_RDWR,
193  oREAD_WRITE_NEW = O_RDWR | O_CREAT | O_TRUNC,
194  oREAD_APPEND = O_RDWR | O_APPEND,
195  oREAD_APPEND_NEW = O_RDWR | O_APPEND | O_CREAT | O_TRUNC,
196  oWRITE = O_WRONLY,
197  oWRITE_NEW = O_WRONLY | O_CREAT | O_TRUNC,
198  oAPPEND = O_WRONLY | O_CREAT | O_APPEND,
199  oAPPEND_NEW = O_WRONLY | O_APPEND | O_CREAT | O_TRUNC
200 };
201 
203 enum Seek {
204  sBegin = SEEK_SET,
205  sCurrent = SEEK_CUR,
206  sEnd = SEEK_END
207 };
208 
213 inline bool open_readable(Open open)
214  { return (open & O_RDWR || !(open & (O_WRONLY | O_APPEND))); } // O_RDONLY is 0 so check for absence of write flags
215 
220 inline bool open_writable(Open open)
221  { return ((open & (O_RDWR | O_WRONLY | O_APPEND)) != 0); }
222 
224 
230 class IoDevice {
231 public:
234 
236  void close()
237  { }
238 
249  ulong read(Error& err, void* buf, ulong size, ulong timeout_ms=0)
250  { err = ENone; return 0; }
251 
262  ulong write(Error& err, const void* buf, ulong size, ulong timeout_ms=0)
263  { err = ENotImpl; return 0; }
264 };
265 
267 
274 struct IoFile : public IoDevice {
275  static const bool STREAM_SEEKABLE = true;
276 
279 
280  typedef int Handle;
281 
283  static const Handle INVALID = -1;
284 
287  { close(); }
288 
292  bool isopen() const
293  { return (handle != INVALID); }
294 
298  Handle detach()
299  { Handle result = handle; handle = INVALID; return result; }
300 
301 #if defined(_WIN32)
302  // Windows
303 
304  static const int DEFPERM = _S_IREAD | _S_IWRITE;
305  static const int READONLY = _S_IREAD;
306  static const int USER_RD = _S_IREAD;
307  static const int USER_RW = _S_IREAD | _S_IWRITE;
308 
309  IoFile()
310  { handle = INVALID; }
311 
312  Error open(const char* path, Open mode, int perm=DEFPERM) {
313  close();
314  handle = ::_open(path, mode | _O_BINARY, perm);
315  Error err;
316  if (handle >= 0) {
317  err = ENone;
318  } else {
319  switch (errno) {
320  case EACCES: err = EAccess; break;
321  case EEXIST: err = EExist; break;
322  case ENOENT: err = ENotFound; break;
323  case EMFILE: err = EOutOfBounds; break;
324  default: err = EFail; break;
325  }
326  handle = INVALID;
327  }
328  return err;
329  }
330 
331  Error open_dup(Handle other, Handle target=INVALID) {
332  close();
333  if (target == INVALID) {
334  const int result = ::_dup(other);
335  if (result >= 0) {
336  handle = result;
337  return ENone;
338  }
339  } else if (::_dup2(other, target) == 0) {
340  handle = target;
341  return ENone;
342  }
343  Error err;
344  switch (errno) {
345  case EBADF: err = EClosed; break;
346  default: err = EFail; break;
347  }
348  return err;
349  }
350 
351  void close() {
352  if (handle != INVALID) {
353  ::_close(handle);
354  handle = INVALID;
355  }
356  }
357 
358  ulongl pos(Error& err) {
359  __int64 result = _lseeki64(handle, 0, SEEK_CUR);
360  if (result < 0) {
361  switch (errno) {
362  case EBADF: err = EClosed; break;
363  default: err = EFail; break;
364  }
365  return 0;
366  }
367  err = ENone;
368  return (ulongl)result;
369  }
370 
371  ulongl seek(Error& err, ulongl offset, Seek start=sBegin) {
372  if (offset > (ulongl)std::numeric_limits<__int64>::max())
373  { err = ESize; return 0; }
374  __int64 result = _lseeki64(handle, offset, (int)start);
375  if (result < 0) {
376  switch (errno) {
377  case EBADF: err = EClosed; break;
378  default: err = EFail; break;
379  }
380  return 0;
381  }
382  err = ENone;
383  return (ulongl)result;
384  }
385 
386  ulong read(Error& err, void* buf, ulong size, ulong timeout_ms=0) {
387  if (handle == INVALID) {
388  err = EClosed;
389  return 0;
390  }
391  if (size > std::numeric_limits<uint>::max())
393  int result;
394  for (;;) {
395  result = ::_read(handle, buf, size);
396  if (result < 0) {
397  switch (errno) {
398  case ENOSPC: err = ESpace; break;
399  case EFBIG: err = ESize; break;
400  case EFAULT: err = EPtr; break;
401  case EBADF: err = EClosed; break;
402  default: err = ERead; break;
403  }
404  return 0;
405  }
406  break;
407  }
408  err = ENone;
409  return (ulong)result;
410  }
411 
412  ulong write(Error& err, const void* buf, ulong size, ulong timeout_ms=0) {
413  if (handle == INVALID) {
414  err = EClosed;
415  return 0;
416  }
417  if (size > std::numeric_limits<uint>::max())
419  int result;
420  for (;;) {
421  result = ::_write(handle, buf, size);
422  if (result == 0) {
423  err = EFail;
424  return 0;
425  } else if (result < 0) {
426  switch (errno) {
427  case ENOSPC: err = ESpace; break;
428  case EINVAL: err = EPtr; break;
429  case EBADF: err = EClosed; break;
430  default: err = EWrite; break;
431  }
432  return 0;
433  }
434  break;
435  }
436  err = ENone;
437  return result;
438  }
439 
440 #else
441  // Linux/Unix
442 
444  static const int DEFPERM = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
446  static const int READONLY = S_IRUSR | S_IRGRP | S_IROTH;
448  static const int USER_RD = S_IRUSR;
450  static const int USER_RW = S_IRUSR | S_IWUSR;
451 
454  { handle = INVALID; autoresume = true; }
455 
462  Error open(const char* path, Open mode, int perm=DEFPERM) {
463  close();
464  handle = ::open(path, mode, perm);
465  Error err;
466  if (handle >= 0) {
467  err = ENone;
468  } else {
469  switch (errno) {
470  case EISDIR: // fallthrough
471  case EROFS: // fallthrough
472  case ETXTBSY: // fallthrough
473  case EACCES: err = EAccess; break;
474  case EEXIST: err = EExist; break;
475  case EFAULT: err = EPtr; break;
476  case ELOOP: // fallthrough
477  case ENAMETOOLONG: err = ESize; break;
478  case ENOTDIR: // fallthrough
479  case ENOENT: err = ENotFound; break;
480  case ENOSPC: err = ESpace; break;
481  case EFBIG: // fallthrough
482  case EOVERFLOW: err = EOutOfBounds; break;
483  default: err = EFail; break;
484  }
485  handle = INVALID;
486  }
487  return err;
488  }
489 
495  Error open_dup(Handle src, Handle target=INVALID) {
496  close();
497  if (target == INVALID) {
498  const int result = ::dup(src);
499  if (result >= 0) {
500  handle = result;
501  return ENone;
502  }
503  } else if (::dup2(src, target) == 0) {
504  handle = target;
505  return ENone;
506  }
507  Error err;
508  switch (errno) {
509  case EBADF: err = EClosed; break;
510  default: err = EFail; break;
511  }
512  return err;
513  }
514 
515  // Documented by parent
516  void close() {
517  if (handle != INVALID) {
518  ::close(handle);
519  handle = INVALID;
520  }
521  }
522 
527  ulongl pos(Error& err) {
528  off_t result = lseek(handle, 0, SEEK_CUR);
529  if (result < 0) {
530  switch (errno) {
531  case EBADF: err = EClosed; break;
532  case EOVERFLOW: err = ESize; break;
533  case ESPIPE: err = EInval; break;
534  default: err = EFail; break;
535  }
536  return 0;
537  }
538  err = ENone;
539  return result;
540  }
541 
548  ulongl seek(Error& err, ulongl offset, Seek start=sBegin) {
549  if (offset > (ulongl)std::numeric_limits<off_t>::max())
550  { err = ESize; return 0; }
551  off_t result = lseek(handle, offset, (int)start);
552  if (result < 0) {
553  switch (errno) {
554  case EBADF: err = EClosed; break;
555  case EOVERFLOW: err = ESize; break;
556  case ESPIPE: err = EInval; break;
557  default: err = EFail; break;
558  }
559  return 0;
560  }
561  err = ENone;
562  return result;
563  }
564 
565  // Documented by parent
566  ulong read(Error& err, void* buf, ulong size, ulong timeout_ms=0)
567  { return SysLinuxIo::read(err, handle, buf, size, timeout_ms, autoresume); }
568 
569  // Documented by parent
570  ulong write(Error& err, const void* buf, ulong size, ulong timeout_ms=0)
571  { return SysLinuxIo::write(err, handle, buf, size, timeout_ms, autoresume); }
572 
573  static Error mkdir(const char* path, int perm=0) {
574  if (perm == 0)
575  perm = DEFPERM;
576  Error err;
577  if (::mkdir(path, perm) == 0) {
578  err = ENone;
579  } else {
580  switch (errno) {
581  case EACCES: // fallthrough
582  case EPERM: // fallthrough
583  case EROFS: err = EAccess; break;
584  case EEXIST: err = EExist; break;
585  case EFAULT: err = EPtr; break;
586  case ELOOP: // fallthrough
587  case EMLINK: // fallthrough
588  case ENAMETOOLONG: err = ESize; break;
589  case ENOTDIR: // fallthrough
590  case ENOENT: err = ENotFound; break;
591  case ENOSPC: err = ESpace; break;
592  default: err = EFail; break;
593  }
594  }
595  return err;
596  }
597 
598  static Error rmdir(const char* path) {
599  Error err;
600  if (::rmdir(path) == 0) {
601  err = ENone;
602  } else {
603  switch (errno) {
604  case EACCES: // fallthrough
605  case EPERM: // fallthrough
606  case EBUSY: // fallthrough
607  case EROFS: err = EAccess; break;
608  case ENOTEMPTY: err = EExist; break;
609  case EFAULT: err = EPtr; break;
610  case EINVAL: err = EInval; break;
611  case ELOOP: // fallthrough
612  case ENAMETOOLONG: err = ESize; break;
613  case ENOTDIR: // fallthrough
614  case ENOENT: err = ENotFound; break;
615  case ENOSPC: err = ESpace; break;
616  default: err = EFail; break;
617  }
618  }
619  return err;
620  }
621 
622  static Error rm(const char* path) {
623  Error err;
624  if (::unlink(path) == 0) {
625  err = ENone;
626  } else {
627  switch (errno) {
628  case EACCES: // fallthrough
629  case EPERM: // fallthrough
630  case EBUSY: // fallthrough
631  case EROFS: err = EAccess; break;
632  case EFAULT: err = EPtr; break;
633  case ELOOP: // fallthrough
634  case ENAMETOOLONG: err = ESize; break;
635  case EISDIR: // fallthrough
636  case ENOTDIR: // fallthrough
637  case ENOENT: err = ENotFound; break;
638  default: err = EFail; break;
639  }
640  }
641  return err;
642  }
643 
644  bool autoresume;
645 #endif
646 
647  Handle handle;
648 };
649 
651 
658 struct IoReader {
659  static const ulong DEFSIZE = 8192;
660 
664 
665  ulong timeout_ms;
666  const char* newline;
667  uint newlinesize;
668  char rd_partnl;
669  char rl_partnl;
670 
675  IoReader(ulong newsize=0, Newline nl=NL_SYS) {
676  if (newsize > 0)
677  readbuf.resize(newsize);
678  curbuf = &readbuf;
679  curbuf_offset = 0;
680  timeout_ms = 0;
681  newline = getnewline(nl);
682  newlinesize = getnewlinesize(nl);
683  rd_partnl = 0;
684  rl_partnl = 0;
685  }
686 
690  void open() {
691  readbuf.used = curbuf_offset = 0;
692  if (readbuf.size == 0)
693  readbuf.resize(IoReader::DEFSIZE);
694  //if (filters != NULL)
695  // filters->onread_open(readbuf);
696  }
697 
699  void close() {
700  //if (filters != NULL)
701  // filters->onread_close();
702  }
703 
716  template<class T>
717  Error fill(T& in, ulong minsize=0) {
718  if (minsize == 0 || minsize > readbuf.size)
719  minsize = readbuf.size;
720  Error err;
721  ulong readsize;
722  {
723  // No filters, read from stream
724  readbuf.flush(curbuf_offset);
725  while (readbuf.used < minsize) {
726  readsize = in.read(err, readbuf.data+readbuf.used, readbuf.size-readbuf.used);
727  if (err != ENone)
728  return err;
729  if (readsize > 0)
730  readbuf.used += readsize;
731  else
732  return EEnd;
733  }
734  }
735  return ENone;
736  }
737 
750  template<class T>
751  ulong readbin(Error& err, T& in, void* buf, ulong bufsize) {
752  assert( bufsize > 0 );
753  assert( curbuf->used <= curbuf->size );
754  assert( curbuf_offset <= curbuf->used );
755 
756  ulong readtotal = 0, usedleft = curbuf->used - curbuf_offset;
757  if (bufsize <= usedleft) {
758  // Read from buffer, enough is there
759  memcpy(buf, curbuf->data+curbuf_offset, bufsize);
760  readtotal = bufsize;
761  curbuf_offset += bufsize;
762  } else {
763  // Read from buffer first
764  if (usedleft > 0) {
765  memcpy(buf, curbuf->data+curbuf_offset, usedleft);
766  (char*&)buf += usedleft;
767  bufsize -= usedleft;
768  readtotal = usedleft;
769  }
770 
771  // Read data larger than buffer directly
772  ulong readsize;
773  if (bufsize >= curbuf->size) {
774  readsize = in.read(err, buf, bufsize);
775  if (err != ENone)
776  return 0;
777  (char*&)buf += readsize;
778  bufsize -= readsize;
779  readtotal += readsize;
780  }
781 
782  // Read more if needed
783  if (bufsize > 0) {
784  // Fill buffer for next read
785  readsize = in.read(err, curbuf->data, curbuf->size);
786  if (err != ENone)
787  return 0;
788  curbuf->used = readsize;
789 
790  // Read more from buffer if needed
791  if (curbuf->used > 0) {
792  curbuf_offset = (bufsize > curbuf->used ? curbuf->used : bufsize);
793  memcpy(buf, curbuf->data, curbuf_offset);
794  readtotal += curbuf_offset;
795  } else
796  curbuf_offset = 0;
797  }
798  }
799  err = ENone;
800  return readtotal;
801  }
802 
825  template<class T>
826  ulong readtext(Error& err, T& in, char* buf, ulong bufsize) {
827  assert( curbuf->size >= 2 );
828  assert( curbuf->used <= curbuf->size );
829  assert( curbuf_offset <= curbuf->used );
830  assert( bufsize > 0 );
831  ulong bytesread = 0, len, len2;
832 
833  if (rd_partnl != 0) {
834  // Special case, newline pair broken up from last readtext(), complete newline pair using saved char
835  buf[0] = rd_partnl;
836  ++bytesread;
837  rd_partnl = 0;
838  }
839 
840  for (;;) {
841  if (curbuf_offset+1 >= curbuf->used) {
842  // Fill buffer -- need at least 2 bytes to handle newlines
843  err = fill(in);
844  if (err != ENone && err != EEnd)
845  return 0;
846  if (curbuf->used == 0) {
847  err = (bytesread > 0 ? ENone : EEnd);
848  return (ulong)bytesread;
849  }
850  }
851  if (rl_partnl != 0) {
852  // Ignore end of partial newline from readline()
853  if (curbuf->data[curbuf_offset] == rl_partnl)
854  ++curbuf_offset;
855  rl_partnl = 0;
856  }
857 
858  len = curbuf->used - curbuf_offset;
859  len2 = bufsize - bytesread;
860  const char* start = curbuf->data + curbuf_offset;
861  const char* end1 = start + (len2 < len ? len2 : len);
862  const char* end2 = start + len;
863  const char* p = start;
864  uint read_nl_size = 0;
865  char checknext = 0;
866 
867  // Find newlines, copy up to newline then write newline, repeat until end
868  while (p < end1) {
869  if (*p == '\n')
870  checknext = '\r';
871  else if (*p == '\r')
872  checknext = '\n';
873  else
874  { ++p; continue; }
875 
876  if (p+1 >= end2) {
877  break; // can't checknext, need to refill buffer
878  } else if (p[1] == checknext) {
879  // Found newline pair
880  if (newline[1] != '\0' && p+1 >= end1) {
881  read_nl_size = 0; // no room for full newline, stop here
882  } else {
883  if (checknext == newline[1])
884  { p += 2; continue; } // no need to convert, continue
885  read_nl_size = 2;
886  }
887  } else {
888  // Found newline char
889  if (newline[1] == '\0' && *p == newline[0])
890  { ++p; continue; } // no need to convert, continue
891  read_nl_size = 1;
892  }
893 
894  // Copy to newline
895  if (p > start) {
896  memcpy(buf+bytesread, start, (len=(ulong)(p-start)));
897  bytesread += len;
898  curbuf_offset += (ulong)len;
899  }
900  if (read_nl_size == 0 || bytesread+newlinesize > bufsize) {
901  if (bufsize == 1) {
902  // Special case, buffer too small so have to read first part of newline pair now, save remaining part for next call
903  buf[0] = newline[0];
904  rd_partnl = newline[1];
905  bytesread = 1;
906  curbuf_offset += read_nl_size;
907  }
908  goto done; // no room for full newline, stop here
909  }
910 
911  curbuf_offset += read_nl_size;
912  memcpy(buf+bytesread, newline, newlinesize);
913  bytesread += newlinesize;
914  start = (p += read_nl_size);
915  }
916 
917  // Copy remaining until end
918  if (p > start) {
919  memcpy(buf+bytesread, start, (len=(ulong)(p-start)));
920  bytesread += len;
921  curbuf_offset += (ulong)len;
922  }
923 
924  // Stop here if desired size read
925  if (bytesread >= bufsize)
926  break;
927  }
928 
929  done:
930  err = ENone;
931  assert( bytesread > 0 );
932  return (ulong)bytesread;
933  }
934 
946  template<class T>
947  Error readline(String& str, T& in, ulong maxlen=0) {
948  assert( curbuf->used <= curbuf->size );
949  assert( curbuf_offset <= curbuf->used );
950  if (rd_partnl != 0)
951  { str.clear(); return ELoss; }
952 
953  Error err;
954  ulong len = 0;
955  char checknext;
956  str.clear();
957  for (;;) {
958  if (curbuf_offset >= curbuf->used) {
959  // Fill buffer
960  err = fill(in, 1);
961  if (err != ENone && err != EEnd)
962  return err;
963  if (curbuf->used == 0)
964  return (len > 0 ? ENone : EEnd);
965  }
966  if (rl_partnl != 0) {
967  // Previous line ended with potential partial newline
968  if (curbuf->data[curbuf_offset] == rl_partnl) {
969  // Skip rest of newline, continue on
970  if (++curbuf_offset >= curbuf->used) {
971  rl_partnl = 0;
972  continue;
973  }
974  }
975  rl_partnl = 0;
976  }
977 
978  const char* start = curbuf->data + curbuf_offset;
979  const char* end = curbuf->data + curbuf->used;
980  for (const char* p=start; p < end; ++p) {
981  if (*p == '\n')
982  checknext = '\r';
983  else if (*p == '\r')
984  checknext = '\n';
985  else
986  continue;
987 
988  // Found newline
989  len = (ulong)(p - start);
990  if (maxlen > 0 && str.size()+len > maxlen)
991  return EOutOfBounds;
992  str.add(start, len);
993  curbuf_offset += len + 1;
994 
995  // Check next byte for remaining newline, if not available set rl_partnl to check later
996  if (++p < end) {
997  if (curbuf->data[curbuf_offset] == checknext)
998  ++curbuf_offset; // skip rest of newline
999  } else
1000  rl_partnl = checknext; // save partial to check later
1001  return ENone;
1002  }
1003 
1004  // Newline not found
1005  len = (ulong)(end - start);
1006  if (maxlen > 0 && str.size()+len > maxlen)
1007  break;
1008  str.add(start, len);
1009  curbuf_offset += len;
1010  }
1011  return EOutOfBounds;
1012  }
1013 };
1014 
1016 
1023 struct IoWriter : public RawBuffer {
1024  static const ulong DEFSIZE = 16384;
1025 
1026  ulong timeout_ms;
1027  const char* newline;
1029  bool flushlines;
1030  char partnl;
1031 
1036  IoWriter(ulong newsize=0, Newline nl=NL_SYS) {
1037  if (newsize > 0)
1038  resize(newsize);
1039  timeout_ms = 0;
1040  newline = getnewline(nl);
1041  newlinesize = getnewlinesize(nl);
1042  partnl = 0;
1043  flushlines = false;
1044  }
1045 
1051  void open(bool flushlines_val=false) {
1052  used = 0;
1053  if (size == 0)
1054  resize(IoWriter::DEFSIZE);
1055  flushlines = flushlines_val;
1056  }
1057 
1059  void close()
1060  { }
1061 
1070  template<class T>
1071  Error flush(T& out) {
1072  assert( used <= size );
1073  Error err;
1074  ulong flushpos = 0, writesize;
1075  while (flushpos < used) {
1076  writesize = out.write(err, data+flushpos, used-flushpos);
1077  if (err != ENone)
1078  return err;
1079  assert( writesize > 0 );
1080  flushpos += writesize;
1081  }
1082  used = 0;
1083  return ENone;
1084  }
1085 
1098  template<class T>
1099  ulong writebin(Error& err, T& out, const void* buf, ulong bufsize) {
1100  assert( used <= size );
1101  if (bufsize > 0) {
1102  ulong writesize = size - used;
1103  if (bufsize < writesize) {
1104  // Copy to buffer, partial fill
1105  memcpy(data+used, buf, bufsize);
1106  used += bufsize;
1107  } else {
1108  // Fill buffer and flush, if enabled
1109  ulong bufleft = bufsize;
1110  if (size > 0) {
1111  if (writesize > 0) {
1112  memcpy(data+used, buf, writesize);
1113  used += writesize;
1114  (char*&)buf += writesize;
1115  bufleft -= writesize;
1116  }
1117  if ( (err=flush(out)) != ENone )
1118  return 0;
1119  }
1120 
1121  if (bufleft >= size) {
1122  // Remaining data larger than buffer, write directly
1123  do {
1124  writesize = out.write(err, buf, bufleft);
1125  if (err != ENone)
1126  return 0;
1127  assert( writesize > 0 );
1128  (char*&)buf += writesize;
1129  bufleft -= writesize;
1130  } while (bufleft > 0);
1131  } else if (bufleft > 0) {
1132  // Copy to buffer, partial fill
1133  memcpy(data, buf, bufleft);
1134  used = bufleft;
1135  }
1136  }
1137  }
1138  assert( size == 0 || used < size );
1139  err = ENone;
1140  return bufsize;
1141  }
1142 
1156  template<class T>
1157  ulong writebin2(Error& err, T& out, const void* buf, ulong bufsize, ulong count) {
1158  assert( used <= size );
1159  const ulong countsize = count * bufsize;
1160  if (count > 0 && bufsize > 0) {
1161  if (size > 0) {
1162  const ulong BUF_THRESHOLD = size / 2;
1163  if (bufsize < BUF_THRESHOLD) {
1164  // Fill buffer and flush, repeat as needed
1165  char* const end = (data + size) - bufsize + 1;
1166  char* p = data + used;
1167  for (ulong writecount=0;;) {
1168  for (writecount=0; p < end && writecount < count; p+=bufsize, ++writecount)
1169  memcpy(p, buf, bufsize);
1170  used += (writecount * bufsize);
1171  count -= writecount;
1172  if ( p >= end && (err=flush(out)) != ENone )
1173  return 0;
1174  if (count <= 0)
1175  break;
1176  p = data;
1177  }
1178  } else
1179  // bufsize too large, flush before writing directly
1180  if ( (err=flush(out)) != ENone )
1181  return 0;
1182  }
1183 
1184  // Write data directly (no buffer or buffer too small)
1185  if (count > 0) {
1186  ulong writesize, writeleft; const char* p;
1187  do {
1188  // Write next repetition
1189  for (writeleft=bufsize, p=(const char*)buf;; p+=writesize) {
1190  writesize = out.write(err, p, writeleft);
1191  if (err != ENone)
1192  return 0;
1193  assert( writesize > 0 );
1194  writeleft -= writesize;
1195  if (writeleft <= 0)
1196  break;
1197  }
1198  } while (--count > 0);
1199  }
1200  }
1201  assert( size == 0 || used < size );
1202  err = ENone;
1203  return countsize;
1204  }
1205 
1218  template<class T>
1219  ulong writebin_char(Error& err, T& out, char ch, ulong count) {
1220  assert( used <= size );
1221  if (count > 0) {
1222  ulong writesize = size - used;
1223  if (count < writesize) {
1224  // Set in buffer, partial fill
1225  memset(data+used, ch, count);
1226  used += count;
1227  } else {
1228  ulong remain = count;
1229  if (size > 0) {
1230  // Using buffer, fill and flush, repeat as needed
1231  assert( writesize > 0 );
1232  for (;;) {
1233  if (used >= size) {
1234  if ((err=flush(out)) != ENone)
1235  return 0;
1236  writesize = (remain < size ? remain : size);
1237  }
1238  if (remain <= 0)
1239  break;
1240  assert( writesize <= remain );
1241  memset(data+used, ch, writesize);
1242  used += writesize;
1243  remain -= writesize;
1244  }
1245  } else {
1246  // No buffer, write 1 character at a time (expensive!)
1247  do {
1248  out.write(err, &ch, 1);
1249  if (err != ENone)
1250  return 0;
1251  } while (--remain > 0);
1252  }
1253  }
1254  }
1255  assert( size == 0 || used < size );
1256  err = ENone;
1257  return count;
1258  }
1259 
1274  template<class T>
1275  ulong writetext(Error& err, T& out, const char* buf, ulong bufsize) {
1276  assert( used <= size );
1277  ulong writesize = 0;
1278  if (bufsize > 0) {
1279  const char* start = buf;
1280  if (partnl > 0) {
1281  if (*start == partnl)
1282  ++start; // newline already written, skip remaining partial
1283  partnl = 0;
1284  }
1285 
1286  ulong flushlines_size = 0;
1287  ulong len, cur_newline_size; char checknext;
1288  const char* end = buf + bufsize;
1289  for (const char* p=start; p < end; ) {
1290  if (*p == '\n')
1291  checknext = '\r';
1292  else if (*p == '\r')
1293  checknext = '\n';
1294  else
1295  { ++p; continue; }
1296 
1297  if (p+1 >= end) {
1298  partnl = checknext; // can't checknext, note partial
1299  cur_newline_size = 1;
1300  } else if (p[1] == checknext) {
1301  if (newline[1] == checknext) {
1302  p += 2; // no need to convert 2-char newline
1303  flushlines_size = used + (ulong)(p - start);
1304  continue;
1305  }
1306  cur_newline_size = 2;
1307  } else if (*p == *newline && newline[1] == '\0') {
1308  ++p; // no need to convert 1-char newline
1309  flushlines_size = used + (ulong)(p - start);
1310  continue;
1311  } else
1312  cur_newline_size = 1;
1313 
1314  len = (ulong)(p - start);
1315  if ( ( p > start && !writebin(err, out, start, len) ) ||
1316  !writebin(err, out, newline, newlinesize)
1317  )
1318  return 0;
1319  start = (p += cur_newline_size);
1320  writesize += len + newlinesize;
1321  flushlines_size = used;
1322  }
1323 
1324  if (start < end) {
1325  len = (ulong)(end - start);
1326  if (!writebin(err, out, start, len))
1327  return 0;
1328  writesize += len;
1329  }
1330 
1331  if (flushlines && flushlines_size > 0 && used > 0) {
1332  // Flush up to last newline
1333  assert( flushlines_size <= used );
1334  ulong flushpos = 0, flushwritesize;
1335  do {
1336  flushwritesize = out.write(err, data+flushpos, flushlines_size-flushpos);
1337  if (err != ENone)
1338  return 0;
1339  assert( flushwritesize > 0 );
1340  flushpos += flushwritesize;
1341  } while (flushpos < flushlines_size);
1342  used -= flushlines_size;
1343  if (used > 0)
1344  memmove(data, data+flushlines_size, used);
1345  }
1346  }
1347  err = ENone;
1348  return writesize;
1349  }
1350 
1360  template<class TOut>
1361  Error writefmtchar(TOut& out, char ch, ulong count, const FmtSetField& field) {
1362  assert( used <= size );
1363  Error err;
1364  if (field.width >= 0 && (uint)field.width > count) {
1365  if (size < (uint)field.width)
1366  return ELength;
1367  if (size-used < (uint)field.width && (err=flush(out)) != ENone)
1368  return err;
1369 
1370  const int fillchar = (int)(field.fill != 0 ? (uchar)field.fill : (uchar)' ');
1371  const uint padding = (uint)field.width - count;
1372  char* p = data + used;
1373  switch (field.align) {
1374  case faCURRENT: // fallthrough
1375  case fLEFT:
1376  memset(p, (int)(uchar)ch, count);
1377  if (padding > 0)
1378  memset(p + count, fillchar, padding);
1379  break;
1380  case fCENTER: {
1381  const uint padleft = (padding / 2);
1382  if (padleft > 0) {
1383  memset(p, fillchar, padleft);
1384  p += padleft;
1385  }
1386  memset(p, (int)(uchar)ch, count);
1387  const uint padright = (padding - padleft);
1388  if (padright > 0) {
1389  p += count;
1390  memset(p, fillchar, padright);
1391  }
1392  break;
1393  }
1394  case fRIGHT:
1395  if (padding > 0) {
1396  memset(p, fillchar, padding);
1397  p += padding;
1398  }
1399  memset(p, (int)(uchar)ch, count);
1400  break;
1401  };
1402  used += (uint)field.width;
1403  } else if (count > 0) {
1404  if (size < count)
1405  return ELength;
1406  if (size-used < count && (err=flush(out)) != ENone)
1407  return err;
1408  memset(data + used, (int)(uchar)ch, count);
1409  used += count;
1410  }
1411  return ENone;
1412  }
1413 
1428  template<class TOut>
1429  Error writefmtstr(TOut& out, const char* str, ulong strsize, const FmtSetField& field) {
1430  assert( used <= size );
1431  if (size < strsize)
1432  return ELength;
1433  Error err;
1434  if (size-used < strsize && (err=flush(out)) != ENone)
1435  return err;
1436 
1437  if (field.width >= 0 && (ulong)field.width > strsize) {
1438  const int fillchar = (int)(field.fill != 0 ? (uchar)field.fill : (uchar)' ');
1439  const uint padding = field.width - strsize;
1440  char* p = data + used;
1441  used += strsize + padding;
1442 
1443  switch (field.align) {
1444  case faCURRENT: // fallthrough
1445  case fLEFT:
1446  memcpy(p, str, strsize);
1447  if (padding > 0)
1448  memset(p + strsize, fillchar, padding);
1449  break;
1450  case fCENTER: {
1451  const uint padleft = (padding / 2);
1452  if (padleft > 0) {
1453  memset(p, fillchar, padleft);
1454  p += padleft;
1455  }
1456  memcpy(p, str, strsize);
1457  const uint padright = (padding - padleft);
1458  if (padright > 0) {
1459  p += strsize;
1460  memset(p, fillchar, padright);
1461  }
1462  break;
1463  }
1464  case fRIGHT:
1465  if (padding > 0) {
1466  memset(p, fillchar, padding);
1467  p += padding;
1468  }
1469  memcpy(p, str, strsize);
1470  break;
1471  };
1472  } else if (strsize > 0) {
1473  memcpy(data + used, str, strsize);
1474  used += strsize;
1475  }
1476  return ENone;
1477  }
1478 
1496  template<class T>
1497  ulong writetext_char(Error& err, T& out, char ch, ulong count) {
1498  assert( used <= size );
1499  if (partnl > 0) {
1500  if (ch == partnl)
1501  --count; // newline already written, skip remaining partial
1502  partnl = 0;
1503  }
1504  if (count > 0) {
1505  if (ch == '\n')
1506  partnl = '\r';
1507  else if (ch == '\r')
1508  partnl = '\n';
1509  if (partnl == 0) {
1510  // Non-newline char
1511  count = writebin_char(err, out, ch, count);
1512  } else {
1513  // Newline char
1514  if (newlinesize == 1)
1515  // 1 char newlines
1516  count = writebin_char(err, out, *newline, count);
1517  else
1518  // 2 char newlines
1519  count = writebin2(err, out, newline, newlinesize, count);
1520  }
1521  if (err != ENone)
1522  return 0;
1523  }
1524  err = ENone;
1525  return count;
1526  }
1527 
1540  template<class TOut,class TNum>
1541  Error writenum(TOut& out, TNum num, int base=fDEC) {
1542  assert( used <= size );
1543  const uint len = IntegerT<TNum>::digits(num,base);
1544  if (size < len)
1545  return EBufSize;
1546  Error err;
1547  if (size-used < len && (err=flush(out)) != ENone)
1548  return err;
1549  used += len;
1550  impl::fnum(data+used, num, base);
1551  return ENone;
1552  }
1553 
1566  template<class TOut,class TNum>
1567  Error writenumu(TOut& out, TNum num, int base=fDEC) {
1568  assert( used <= size );
1569  const uint len = IntegerT<TNum>::digits(num,base);
1570  if (size < len)
1571  return EBufSize;
1572  Error err;
1573  if (size-used < len && (err=flush(out)) != ENone)
1574  return err;
1575  used += len;
1576  impl::fnumu(data+used, num, base);
1577  return ENone;
1578  }
1579 
1592  template<class TOut,class TNum>
1593  Error writenumf(TOut& out, TNum num, int precision=fPREC_AUTO) {
1594  assert( used <= size );
1595  int exp = 0; uint maxlen; Error err;
1596  if (precision < 0) {
1597  num = FloatT<TNum>::fexp10(exp, num);
1598  maxlen = (uint)FloatT<TNum>::MAXDIGITS_AUTO;
1599  if (size < maxlen)
1600  return EBufSize;
1601  if (size-used < maxlen && (err=flush(out)) != ENone)
1602  return err;
1603  used += impl::fnumfe(data+used, num, exp, false);
1604  } else {
1605  num = FloatT<TNum>::fexp10(exp, impl::fnumf_weight(num, precision));
1606  maxlen = (uint)FloatT<TNum>::maxdigits_prec(exp, precision);
1607  if (size < maxlen)
1608  return EBufSize;
1609  if (size-used < maxlen && (err=flush(out)) != ENone)
1610  return err;
1611  used += impl::fnumf(data+used, num, exp, precision);
1612  }
1613  return ENone;
1614  }
1615 
1629  template<class TOut,class TNum>
1630  Error writefmtnum(TOut& out, TNum num, const FmtSetInt& fmt, const FmtSetField* field=NULL) {
1631  if (fmt.base <= 0 || fmt.base == fDEC) {
1632  assert( used <= size );
1633  const int digits = IntegerT<TNum>::digits(num, fDEC);
1634  const int width = (fmt.pad_width > digits ? fmt.pad_width : digits);
1635  const int align_padding = (field != NULL && field->width > width ? field->width - width : 0);
1636  const uint len = width + align_padding;
1637 
1638  if (size < len)
1639  return EBufSize;
1640  Error err;
1641  if (size-used < len && (err=flush(out)) != ENone)
1642  return err;
1643 
1644  fmt.impl_num_write(data + used, num, digits, width, align_padding, field);
1645  used += len;
1646  } else
1647  return writefmtnumu(out, (typename ToUnsigned<TNum>::Type)num, fmt, field);
1648  return ENone;
1649  }
1650 
1664  template<class TOut,class TNum>
1665  Error writefmtnumu(TOut& out, TNum num, const FmtSetInt& fmt, const FmtSetField* field=NULL) {
1666  assert( used <= size );
1667  const int base = (fmt.base > 0 ? fmt.base : fDEC);
1668 
1669  char prefix_ch = 0;
1670  uint prefix_len = 0;
1671  fmt.impl_prefix_info(prefix_ch, prefix_len);
1672 
1673  const int digits = IntegerT<TNum>::digits(num, base);
1674  const int width = (fmt.pad_width > digits ? fmt.pad_width : digits);
1675  const int full_width = width + prefix_len;
1676  const int align_padding = (field != NULL && field->width > full_width ? field->width - full_width : 0);
1677  const uint len = full_width + align_padding;
1678 
1679  if (size < len)
1680  return EBufSize;
1681  Error err;
1682  if (size-used < len && (err=flush(out)) != ENone)
1683  return err;
1684 
1685  char* p = data + used;
1686  used += len;
1687 
1688  int align_padleft, align_padright;
1689  FmtSetField::setup_align(align_padleft, align_padright, align_padding, field);
1690 
1691  if (align_padleft > 0) {
1692  memset(p, (int)(uchar)field->fill, align_padleft);
1693  p += align_padleft;
1694  }
1695 
1696  FmtSetInt::impl_prefix_write(p, prefix_ch, prefix_len);
1697 
1698  if (digits < width) {
1699  const uint padlen = width - digits;
1700  const int ch = (fmt.pad_ch == 0 ? '0' : (int)(uchar)fmt.pad_ch);
1701  memset(p, ch, padlen);
1702  p += padlen;
1703  }
1704  p += digits;
1705  impl::fnumu(p, num, base);
1706 
1707  if (align_padright > 0)
1708  memset(p, (int)(uchar)field->fill, align_padright);
1709 
1710  return ENone;
1711  }
1712 
1726  template<class TOut,class TNum>
1727  Error writefmtnumf(TOut& out, TNum num, const FmtSetFloat& fmt, const FmtSetField* field=NULL) {
1728  const int align_width = (field != NULL ? field->width : 0);
1729  int exp = 0, maxlen;
1730  fmt.impl_info(num, exp, maxlen, align_width); // sets maxlen
1731 
1732  if (size < (uint)maxlen)
1733  return EBufSize;
1734  Error err;
1735  if (size-used < (uint)maxlen && (err=flush(out)) != ENone)
1736  return err;
1737 
1738  used += fmt.impl_write(data + used, num, exp, align_width, field);
1739  return ENone;
1740  }
1741 
1754  template<class TOut>
1755  Error writefmtdump(TOut& out, const FmtDump& fmt, const char* newline, uint newlinesize) {
1756  const char* DIGITS = (fmt.upper ? "0123456789ABCDEF" : "0123456789abcdef");
1757  const ulong LINE_SIZE = (fmt.maxline > 0 ? fmt.maxline : fmt.size);
1758  const ulong FLUSH_SIZE = size - 3; // Flush if not enough room for at least 3 bytes (2-digit hex and space, or newline)
1759 
1760  Error err;
1761  const uchar* ptr = (uchar*)fmt.buf;
1762  const uchar* ptr_end = ptr + fmt.size;
1763  const uchar* ptr_nl;
1764 
1765  FmtSetInt offset_fmt(fHEX, 0);
1766  ulong offset = 0;
1767  if (fmt.maxline > 0 && !fmt.compact)
1768  offset_fmt.pad_width = Int::digits(fmt.size, fHEX);
1769 
1770  // Loop for each line
1771  for (const uchar* ptr2; ptr < ptr_end; ) {
1772  // Show offset
1773  if (fmt.maxline > 0 && !fmt.compact) {
1774  if ((err = writefmtnumu(out, offset, offset_fmt)) != ENone)
1775  return err;
1776  offset += fmt.maxline;
1777 
1778  if (used >= FLUSH_SIZE && (err=flush(out)) != ENone)
1779  return err;
1780  data[used++] = ':';
1781  data[used++] = ' ';
1782  data[used++] = ' ';
1783  }
1784 
1785  // Figure newline position
1786  ptr_nl = ptr + LINE_SIZE;
1787  if (ptr_nl > ptr_end)
1788  ptr_nl = ptr_end;
1789 
1790  // Hex dump line
1791  ptr2 = ptr;
1792  for (; ptr < ptr_nl; ++ptr) {
1793  if (used >= FLUSH_SIZE && (err=flush(out)) != ENone)
1794  return err;
1795  data[used++] = DIGITS[(*ptr >> 4) & 0x0F];
1796  data[used++] = DIGITS[*ptr & 0x0F];
1797  data[used++] = ' ';
1798  }
1799 
1800  if (fmt.compact) {
1801  assert( used > 0 );
1802  --used; // trim extra space from last byte
1803  } else {
1804  if (ptr_nl >= ptr_end && fmt.maxline > 0 && ptr2 != (uchar*)fmt.buf) {
1805  // Pad last line, add separator
1806  const ulong remainder = fmt.size % fmt.maxline;
1807  ulong avail, wrlen, count = (remainder > 0 ? ((fmt.maxline - remainder) * 3) + 1 : 1);
1808  while (count > 0) {
1809  if (used >= FLUSH_SIZE && (err=flush(out)) != ENone)
1810  return err;
1811  avail = size - used;
1812  wrlen = (count > avail ? avail : count);
1813  memset(data + used, ' ', wrlen);
1814  count -= wrlen;
1815  used += wrlen;
1816  }
1817  } else {
1818  // Separator
1819  if (used >= FLUSH_SIZE && (err=flush(out)) != ENone)
1820  return err;
1821  data[used++] = ' ';
1822  }
1823 
1824  // ASCII dump
1825  for (; ptr2 < ptr_nl; ++ptr2) {
1826  if (used >= FLUSH_SIZE && (err=flush(out)) != ENone)
1827  return err;
1828  if (*ptr2 < ' ' || *ptr2 > '~')
1829  data[used++] = '.';
1830  else
1831  data[used++] = (char)*ptr2;
1832  }
1833  }
1834 
1835  // Newlie
1836  if (used >= FLUSH_SIZE && (err=flush(out)) != ENone)
1837  return err;
1838  memcpy(data + used, newline, newlinesize);
1839  used += newlinesize;
1840  }
1841  return ENone;
1842  }
1843 };
1844 
1846 
1847 }
1848 #if defined(_MSC_VER)
1849  #pragma warning(pop)
1850 #endif
1851 #endif
bool compact
Whether to use compact mode (no address or ASCII output)
Definition: str.h:3298
Error readline(String &str, T &in, ulong maxlen=0)
Read a line from file using buffer.
Definition: sysio.h:947
void open(bool flushlines_val=false)
Initialize and open for output (writing).
Definition: sysio.h:1051
int Handle
System file handle.
Definition: sysio.h:280
Operation timed out.
Definition: sys.h:1131
Size size() const
Get size.
Definition: list.h:759
T & max(T &a, T &b)
Returns highest of given values.
Definition: alg.h:47
const char * getnewline(Newline newline=NL)
Get newline string for given type.
Definition: sys.h:793
ulong size
Buffer size in bytes to dump.
Definition: str.h:3296
Seek
Seek starting position.
Definition: sysio.h:203
System call interrupted by signal (Linux/Unix), auto-resume disabled.
Definition: sys.h:1132
ExceptionFileIn ExceptionInT
Input exception type for file stream.
Definition: sysio.h:277
IoReader(ulong newsize=0, Newline nl=NL_SYS)
Constructor to set new buffer size.
Definition: sysio.h:675
General stream or resource read error.
Definition: sys.h:1143
Out of bounds error.
Definition: sys.h:1129
Holds integer formatting attributes.
Definition: str.h:2589
Error writefmtdump(TOut &out, const FmtDump &fmt, const char *newline, uint newlinesize)
Write formatted buffer dump in hex.
Definition: sysio.h:1755
char pad_ch
Fill character, 0 if unspecified (use baseline or default) (default: &#39;0&#39;)
Definition: str.h:2593
bool isopen() const
Get whether file is open.
Definition: sysio.h:292
ExceptionStreamOut ExceptionOutT
Output exception type for device (may be overridden by derived)
Definition: sysio.h:233
Operation would block (non-blocking I/O)
Definition: sys.h:1118
Invalid argument or data.
Definition: sys.h:1123
bool upper
Whether to use uppercase hex, false for lowercase.
Definition: str.h:3299
Permission denied.
Definition: sys.h:1135
Base 16: hexadecimal.
Definition: str.h:2324
bool open_writable(Open open)
Check whether open mode is writable.
Definition: sysio.h:220
Invalid pointer used.
Definition: sys.h:1133
ulong readbin(Error &err, T &in, void *buf, ulong bufsize)
Read from file using buffer.
Definition: sysio.h:751
static Error rmdir(const char *path)
Definition: sysio.h:598
void close()
Definition: sysio.h:516
ulong readtext(Error &err, T &in, char *buf, ulong bufsize)
Read from file using buffer.
Definition: sysio.h:826
Read and write.
Definition: sysio.h:192
Error open_dup(Handle src, Handle target=INVALID)
Open duplicate handle from source handle.
Definition: sysio.h:495
Seek to end.
Definition: sysio.h:206
Stream or resource is closed
Definition: sys.h:1130
IoFile()
Constructor.
Definition: sysio.h:453
Error writenumu(TOut &out, TNum num, int base=fDEC)
Write formatted unsigned number to device using buffer.
Definition: sysio.h:1567
Automatic floating point precision – either normal decimal notation or E notation, whichever is shorter (default)
Definition: str.h:2343
~IoFile()
Destructor.
Definition: sysio.h:286
ulong timeout_ms
Read timeout in milliseconds, 0 for none (don&#39;t timeout)
Definition: sysio.h:665
Seek from current position.
Definition: sysio.h:205
Not enough space/memory available.
Definition: sys.h:1134
char fill
Field fill character to pad up to width (default: &#39; &#39;)
Definition: str.h:2484
IoWriter(ulong newsize=0, Newline nl=NL_SYS)
Constructor to set new buffer size and newline value.
Definition: sysio.h:1036
static int digits(T num, int base=10)
Get number of digits for given number and base.
Definition: type.h:1028
Read and write, create/replace.
Definition: sysio.h:193
ulong size
Buffer size (capacity) in bytes – do not modify, use: resize(), minsize(), reset(), ref()
Definition: rawbuffer.h:36
Open
Open mode for files and streams.
Definition: sysio.h:190
bool open_readable(Open open)
Check whether open mode is readable.
Definition: sysio.h:213
Output stream exception for stream write errors, see Exception.
Definition: sys.h:1401
Newline
Newline type.
Definition: sys.h:748
ulong writetext_char(Error &err, T &out, char ch, ulong count)
Write data to device using buffer.
Definition: sysio.h:1497
bool flushlines
Whether to flush after each line (aka line buffering) – only applies to text writes, i.e. writetext()
Definition: sysio.h:1029
Evo I/O streams and Console I/O.
void open()
Initialize and open for input (reading).
Definition: sysio.h:690
String & clear()
Clear by removing all items.
Definition: string.h:4975
uint newlinesize
Size of default newline string to use, i.e. strlen(newline) – do not modify.
Definition: sysio.h:1028
uint maxline
Maximum bytes per line to dump, 0 for none (all 1 line)
Definition: str.h:3297
Evo RawBuffer classes.
ulong timeout_ms
Write timeout in milliseconds, 0 for none (no timeout)
Definition: sysio.h:1026
void close()
Close stream.
Definition: sysio.h:236
ulongl seek(Error &err, ulongl offset, Seek start=sBegin)
Seek to file position.
Definition: sysio.h:548
Resource not found.
Definition: sys.h:1137
bool autoresume
Whether to auto-resume I/O operation after signal received [Linux/Unix].
Definition: sysio.h:644
char rl_partnl
Used by readline() on partial newlines, holds next expected char for newline pair or 0...
Definition: sysio.h:669
Size limit exceeded.
Definition: sys.h:1139
No error.
Definition: sys.h:1115
Reached end of resource (not an error)
Definition: sys.h:1116
ulong writebin2(Error &err, T &out, const void *buf, ulong bufsize, ulong count)
Write repeated data to device using buffer.
Definition: sysio.h:1157
int pad_width
Width to fill to, 0 for none, -1 if unspecified (use baseline or default) (default: 0) ...
Definition: str.h:2592
Error writefmtstr(TOut &out, const char *str, ulong strsize, const FmtSetField &field)
Write string data to device using buffer, formatted with field alignment.
Definition: sysio.h:1429
Error
General Evo error code stored in exceptions, or used directly when exceptions are disabled...
Definition: sys.h:1113
Buffer too small error.
Definition: sys.h:1127
uint getnewlinesize(Newline newline=NL)
Get newline string size for given type.
Definition: sys.h:804
Error writefmtchar(TOut &out, char ch, ulong count, const FmtSetField &field)
Write repeated character data to device using buffer, formatted with field alignment.
Definition: sysio.h:1361
Seek from beginning.
Definition: sysio.h:204
uint newlinesize
Size of newlines string to use, i.e. strlen(newline) – do not modify.
Definition: sysio.h:667
Read and write/append, create/replace.
Definition: sysio.h:195
Base 10: decimal (default)
Definition: str.h:2323
ulong writebin(Error &err, T &out, const void *buf, ulong bufsize)
Write data to device using buffer.
Definition: sysio.h:1099
String container.
Definition: string.h:674
File I/O device (used internally).
Definition: sysio.h:274
const void * buf
Buffer to dump.
Definition: str.h:3295
static ulong read(Error &err, int handle, void *buf, ulong size, ulong timeout_ms, bool autoresume)
Definition: sysio.h:73
Read only.
Definition: sysio.h:191
const char * newline
Newline string to convert to when reading text – do not modify.
Definition: sysio.h:666
ExceptionStreamIn ExceptionInT
Input exception type for device (may be overridden by derived)
Definition: sysio.h:232
Buffered reader for IoDevice (used internally).
Definition: sysio.h:658
T Type
Translated type.
Definition: meta.h:373
void flush(ulong &offset)
Flush data already read from buffer using offset.
Definition: rawbuffer.h:229
static Error mkdir(const char *path, int perm=0)
Definition: sysio.h:573
Align center by adding filler on left and right sides.
Definition: str.h:2359
String length limit exceeded
Definition: sys.h:1141
RawBuffer readbuf
Primary read buffer – filtering may involve additional buffers.
Definition: sysio.h:661
char rd_partnl
Used by readtext() in special case, holds end of converted newline that didn&#39;t fit in buf or 0...
Definition: sysio.h:668
Write/append only, created if needed.
Definition: sysio.h:198
Error open(const char *path, Open mode, int perm=DEFPERM)
Open file for access.
Definition: sysio.h:462
FmtAlign align
Field alignment type (default: fLEFT)
Definition: str.h:2482
Error flush(T &out)
Flush buffer by writing to device.
Definition: sysio.h:1071
ulong write(Error &err, const void *buf, ulong size, ulong timeout_ms=0)
Definition: sysio.h:570
static const ulong DEFSIZE
Default buffer size (8KB, power of 2 and multiple of common filesystem block size 4KB) ...
Definition: sysio.h:659
Error writefmtnumu(TOut &out, TNum num, const FmtSetInt &fmt, const FmtSetField *field=NULL)
Write formatted unsigned number to device using buffer, using field attributes.
Definition: sysio.h:1665
ulong writebin_char(Error &err, T &out, char ch, ulong count)
Write repeated character to device using buffer.
Definition: sysio.h:1219
ulong writetext(Error &err, T &out, const char *buf, ulong bufsize)
Write data to device using buffer.
Definition: sysio.h:1275
Handle handle
System handle/descriptor.
Definition: sysio.h:647
Unknown or unspecified error.
Definition: sys.h:1120
RawBuffer & resize(ulong newsize)
Resize buffer.
Definition: rawbuffer.h:116
Read and write/append.
Definition: sysio.h:194
Evo C++ Library namespace.
Definition: alg.h:11
Definition: sysio.h:36
Input stream exception for stream read errors, see Exception.
Definition: sys.h:1397
static ulong write(Error &err, int handle, const void *buf, ulong size, ulong timeout_ms, bool autoresume)
Definition: sysio.h:143
static bool write_wait(Error &err, int handle, ulong timeout_ms, bool autoresume)
Definition: sysio.h:110
Holds floating point formatting attributes.
Definition: str.h:2775
Resource already exists.
Definition: sys.h:1136
const char * newline
Default newline string for formatting – do not modify.
Definition: sysio.h:1027
ulong read(Error &err, void *buf, ulong size, ulong timeout_ms=0)
Read input data from device.
Definition: sysio.h:249
I/O device base class for streams.
Definition: sysio.h:230
Error writefmtnumf(TOut &out, TNum num, const FmtSetFloat &fmt, const FmtSetField *field=NULL)
Write formatted floating point number to device using buffer, using field attributes.
Definition: sysio.h:1727
File output stream exception for file write errors, see Exception.
Definition: sys.h:1414
Write only.
Definition: sysio.h:196
static const Newline NL_SYS
Current system newline type.
Definition: sys.h:763
static T fexp10(int &exp, T num)
Extract normalized base 10 mantissa and exponent from number.
Definition: type.h:1438
char partnl
Used internally for handling partial newlines between writetext() calls.
Definition: sysio.h:1030
Buffered writer for IoDevice (used internally).
Definition: sysio.h:1023
Operation failed.
Definition: sys.h:1124
String & add(char ch)
Append character (modifier).
Definition: string.h:2741
RawBuffer * curbuf
Pointer to current buffer, either primary buffer or from last filter applied.
Definition: sysio.h:662
Align left by adding filler on right side.
Definition: str.h:2358
char * data
Buffer data pointer, NULL if empty (size=0)
Definition: rawbuffer.h:35
int base
Base for formatting (default: fDEC)
Definition: str.h:2590
void close()
Close output.
Definition: sysio.h:1059
ulong curbuf_offset
Bytes read from curbuf, i.e. buffer start offset.
Definition: sysio.h:663
static const ulong DEFSIZE
Default buffer size (16KB, power of 2 and multiple of common filesystem block size 4KB) ...
Definition: sysio.h:1024
Nullable basic floating-point base type.
Definition: type.h:1291
Error writenumf(TOut &out, TNum num, int precision=fPREC_AUTO)
Write formatted floating-point number to device using buffer.
Definition: sysio.h:1593
Write only, create/replace.
Definition: sysio.h:197
static void setup_align(int &align_padleft, int &align_padright, int align_padding, const FmtSetField *field)
Used to setup and calculate alignment padding (used internally).
Definition: str.h:2529
ulong read(Error &err, void *buf, ulong size, ulong timeout_ms=0)
Definition: sysio.h:566
int width
Field width to align in (default: 0)
Definition: str.h:2483
static bool read_wait(Error &err, int handle, ulong timeout_ms, bool autoresume)
Definition: sysio.h:37
Error fill(T &in, ulong minsize=0)
Reset and fill buffer by reading from file.
Definition: sysio.h:717
Align right by adding filler on left side.
Definition: str.h:2360
ulongl pos(Error &err)
Get current file position.
Definition: sysio.h:527
static Error rm(const char *path)
Definition: sysio.h:622
static void set_timeval_ms(struct timeval &tm, ulong ms)
Definition: sys.h:1526
Operation aborted to prevent data loss (used in special cases)
Definition: sys.h:1125
Error writefmtnum(TOut &out, TNum num, const FmtSetInt &fmt, const FmtSetField *field=NULL)
Write formatted signed number to device using buffer, using field attributes.
Definition: sysio.h:1630
File input stream exception for file read errors, see Exception.
Definition: sys.h:1410
void close()
Close input.
Definition: sysio.h:699
Simple raw memory buffer.
Definition: rawbuffer.h:34
Holds field and alignment formatting attributes.
Definition: str.h:2481
Function not supported/implemented.
Definition: sys.h:1121
Handle detach()
Detach and return file handle.
Definition: sysio.h:298
ulong write(Error &err, const void *buf, ulong size, ulong timeout_ms=0)
Write output data to device.
Definition: sysio.h:262
Error writenum(TOut &out, TNum num, int base=fDEC)
Write formatted signed number to device using buffer.
Definition: sysio.h:1541
General stream or resource write error.
Definition: sys.h:1144
ExceptionFileOut ExceptionOutT
Output exception type for file stream.
Definition: sysio.h:278
Explicitly format a hex dump from buffer.
Definition: str.h:3294
Current alignment (i.e. unspecified/default)
Definition: str.h:2357
ulong used
Buffer size in use in bytes.
Definition: rawbuffer.h:37
Write/append only, create/replace.
Definition: sysio.h:199