windows/SysFile.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.ibm.com/developerworks/oss/CPLv1.0.htm */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Kernel SysFile.cpp */
40 /* */
41 /* Windows implementation of the SysFile class. */
42 /* */
43 /******************************************************************************/
44 
45 #include "SysFile.hpp"
46 #include <errno.h>
47 #include <time.h>
48 #include <conio.h>
49 #include <stdio.h>
50 
51 /**
52  * Default constructor for a SysFile object.
53  */
55 {
56  fileHandle = -1;
57  errInfo = 0;
58  openedHandle = false;
59  flags = 0;
60  mode = 0;
61  share = 0;
62  filename = NULL;
63  buffered = true;
64  transient = false;
65  device = false;
66  writeable = false;
67  readable = false;
68  isTTY = false;
69  buffer = NULL;
71  bufferPosition = 0;
72  bufferedInput = 0;
73  append = true;
74  filePointer = 0;
75  ungetchar = -1;
76  writeBuffered = false; // no pending write operations
77 }
78 
79 
80 /**
81  * Opens a file. This opens the file for both lowlevel I/O
82  * and also for higher level I/O.
83  *
84  * @param name Name of the stream.
85  * @param openFlags The open flags. This are the same flags used on the _sopen()
86  * function.
87  * @param openMode Open mode. Same flag values as _sopen().
88  * @param fdopenMode fdopenMode character string. Same as values use for the
89  * fdopen() function.
90  * @param shareMode The sharing mode. Same as used by the _sopen() library
91  * function.
92  *
93  * @return true if the file was opened successfully, false otherwise.
94  */
95 bool SysFile::open(const char *name, int openFlags, int openMode, int shareMode)
96 {
97  flags = openFlags; // save the initial flag values
98  mode = openMode;
99  share = shareMode;
100 
101  // we must open this with the NOINHERIT and BINARY flags added
102  fileHandle = _sopen(name, openFlags|_O_NOINHERIT|_O_BINARY, shareMode, openMode);
103  if ( fileHandle == -1 )
104  {
105  errInfo = errno;
106  return false;
107  }
108 
109  // we did open this handle
110  openedHandle = true;
111 
112  // save a copy of the name
113  filename = strdup(name);
114  ungetchar = -1; // -1 indicates no char
115 
116  // is this append mode?
117  if ((flags & RX_O_APPEND) != 0)
118  {
119  // mark this true, and position at the end
120  append = true;
121  _lseeki64(fileHandle, 0, SEEK_END);
122  }
123 
125  // set the default buffer size (and allocate the buffer)
126  setBuffering(true, 0);
127  return true;
128 }
129 
130 
131 /**
132  * Open a stream using a provided handle value.
133  *
134  * @param handle The source stream handle.
135  * @param fdopenMode The fdopen() mode flags for the stream.
136  *
137  * @return true if the file opened ok, false otherwise.
138  */
139 bool SysFile::open(int handle)
140 {
141  // we didn't open this.
142  openedHandle = false;
143  fileHandle = handle;
144  ungetchar = -1; // -1 indicates no char
146  // set the default buffer size (and allocate the buffer)
147  setBuffering(true, 0);
148  return true;
149 }
150 
151 /**
152  * Reset this to an unopened state.
153  */
154 void SysFile::reset()
155 {
156  // make sure we flush anything pending.
157  flush();
158  if (buffer != NULL)
159  {
160  free(buffer);
161  buffer = NULL;
162  }
163  fileHandle = -1;
164 }
165 
166 /**
167  * Controls buffering for this stream.
168  *
169  * @param buffer True or false depending on the desired buffering mode.
170  */
171 void SysFile::setBuffering(bool buffering, size_t length)
172 {
173  if (buffering)
174  {
175  buffered = true;
176  if (length == 0)
177  {
178  length = DEFAULT_BUFFER_SIZE;
179  }
180  buffer = (char *)malloc(length);
181  if (buffer == NULL)
182  {
183  buffered = false;
184  }
185  }
186  else
187  {
188  buffered = false;
189  if (buffer != NULL)
190  {
191  free(buffer);
192  buffer = NULL;
193  }
194  }
195  // reset all of the buffering controls to the defaults
196  bufferPosition = 0;
197  bufferedInput = 0;
198  writeBuffered = false;
199 }
200 
201 
202 /**
203  * Close the stream, and free all associated resources.
204  *
205  * @return true if this closed successfully, false otherwise.
206  */
207 bool SysFile::close()
208 {
209  // don't do anything if not opened
210  if (fileHandle == -1)
211  {
212  return true;
213  }
214  // if we're buffering, make sure the buffers are flushed
215  if (buffered)
216  {
217  flush();
218  }
219  // free out storage areas first
220  if (filename != NULL)
221  {
222  free(filename);
223  filename = NULL;
224  }
225  if (buffer != NULL)
226  {
227  free(buffer);
228  buffer = NULL;
229  }
230  errInfo = 0;
231  // if we opened this handle, we need to close it too.
232  if (openedHandle)
233  {
234  if (::close(fileHandle) == EOF)
235  {
236  // we've got an error, but this needs to be cleared
237  fileHandle = -1;
238  errInfo = errno;
239  return false;
240  }
241  }
242  // always clear this on a close
243  fileHandle = -1;
244 
245  return true;
246 }
247 
248 /**
249  * Flush the stream buffers.
250  *
251  * @return True if this worked without error, false otherwise.
252  */
253 bool SysFile::flush()
254 {
255  if (buffered)
256  {
257  // do we have data in a write buffer?
258  if (writeBuffered && bufferPosition > 0)
259  {
260  // write this out...but if it fails, we need to bail
261  int written = writeData(buffer, (size_t)bufferPosition);
262  // did we have an error?
263  if (written <= 0)
264  {
265  errInfo = errno;
266  return false;
267  }
268  // update the real output position
269  filePointer += written;
270  // and invalidate the buffer
271  bufferPosition = 0;
272  bufferedInput = 0;
273  }
274  }
275  return true;
276 }
277 
278 /**
279  * Read bytes from the stream.
280  *
281  * @param buf The buffer to read into.
282  * @param len The requested number of bytes to read.
283  * @param bytesRead The actual number of bytes read.
284  *
285  * @return True if one or more bytes are read into buf, otherwise false.
286  */
287 bool SysFile::read(char *buf, size_t len, size_t &bytesRead)
288 {
289  // set bytesRead to 0 to be sure we can tell if we are returning any bytes.
290  bytesRead = 0;
291 
292  // asking for nothing? this is pretty easy
293  if (len == 0)
294  {
295  return true;
296  }
297 
298  // if we have an ungetchar, we need to grab that first
299  if (ungetchar != -1)
300  {
301  // add this to our count
302  bytesRead = 1;
303  // copy the character over
304  buf[0] = (char)ungetchar;
305  buf++;
306  len--;
307  ungetchar = -1;
308  // were we only looking for one character (very common in cases where
309  // we've had a char pushed back)
310  if (len == 0)
311  {
312  return true;
313  }
314  }
315 
316  // are we doing buffering?
317  if (buffered)
318  {
319  // do we have pending output in the buffer?
320  if (writeBuffered)
321  {
322  flush();
323  writeBuffered = false;
324  bufferPosition = 0;
325  bufferedInput = 0;
326  }
327 
328  while (len > 0)
329  {
330  // have we exhausted the buffer data?
332  {
333  // read another chunk of data.
334  int blockRead = _read(fileHandle, buffer, (unsigned int)bufferSize);
335  if (blockRead <= 0)
336  {
337  // not get anything?
338  if (_eof(fileHandle))
339  {
340  return bytesRead > 0 ? true : false;
341  }
342  else
343  {
344  // had an error, so raise it
345  errInfo = errno;
346  return false;
347  }
348  }
349  else
350  {
351  // update the positions
352  filePointer += blockRead;
353  bufferedInput = blockRead;
354  bufferPosition = 0;
355  }
356  }
357 
358  // see how much we can copy
359  size_t blocksize = (size_t)(len > bufferedInput - bufferPosition ? bufferedInput - bufferPosition : len);
360  memcpy(buf, buffer + bufferPosition, blocksize);
361  // and adjust all of the positions
362  bufferPosition += blocksize;
363  buf += blocksize;
364  len -= blocksize;
365  bytesRead += blocksize;
366  }
367  }
368  else
369  {
370  while (len > 0)
371  {
372  int blockRead = _read(fileHandle, buf + bytesRead, (unsigned int)len);
373  if (blockRead <= 0)
374  {
375  // not get anything?
376  if (_eof(fileHandle))
377  {
378  // could have had an ungetchar
379  return bytesRead > 0 ? true : false;
380  }
381  else
382  {
383  // had an error, so raise it
384  errInfo = errno;
385  return false;
386  }
387  }
388  // update the length
389  len -= blockRead;
390  bytesRead += blockRead;
391  }
392  }
393  return true;
394 }
395 
396 
397 /**
398  * Wrapper around _write to handle block size issues with
399  * device streams.
400  *
401  * @param data The data to write.
402  * @param length The data length.
403  *
404  * @return The number of bytes written
405  */
406 int SysFile::writeData(const char *data, size_t length)
407 {
408  // normal files seem to handle large writes ok, but for devices, we
409  // need to write this in blocks
410  if (!device || length < BLOCK_THRESHOLD)
411  {
412  return _write(fileHandle, data, (unsigned int)length);
413  }
414  else
415  {
416  // rats, need to write this out in segments
417  int bytesWritten = 0;
418  while (length > 0)
419  {
420  size_t segmentSize = length > BLOCK_THRESHOLD ? BLOCK_THRESHOLD : length;
421  int justWritten = _write(fileHandle, data, (unsigned int)segmentSize);
422  // write error? Return whatever we've written
423  if (justWritten <= 0)
424  {
425  return bytesWritten;
426  }
427  length -= justWritten;
428  bytesWritten += justWritten;
429  data += justWritten;
430  }
431  return bytesWritten;
432  }
433 }
434 
435 
436 /**
437  * write data to the stream
438  *
439  * @param data The data buffer to write.
440  * @param len The length to write
441  * @param bytesWritten
442  * The number bytes actually written (return value).
443  *
444  * @return true if the write succeeded, false for any errors.
445  */
446 bool SysFile::write(const char *data, size_t len, size_t &bytesWritten)
447 {
448  // writing zero bytes is a NOP
449  if (len == 0)
450  {
451  return true;
452  }
453  // are we buffering?
454  if (buffered)
455  {
456  // using the buffer for input at the moment?
457  if (!writeBuffered)
458  {
459  // We need to position the file write pointer to the postion of our
460  // last virtual read.
462  // set the absolute position
463  _lseeki64(fileHandle, offset, SEEK_SET);
464  bufferedInput = 0;
465  bufferPosition = 0;
466  // we're switching modes.
467  writeBuffered = true;
468  }
469 
470  // is this too large to bother copying into the buffer?
471  if (len > bufferSize)
472  {
473  // flush an existing data from the buffer
474  flush();
475  // write this out directly
476  int written = writeData(data, len);
477  // oh, oh...got a problem
478  if (written <= 0)
479  {
480  // save the error status and bail
481  errInfo = errno;
482  return false;
483  }
484  bytesWritten = written;
485  // update the real output position
486  filePointer += written;
487  return true;
488  }
489 
490  bytesWritten = len;
491  // ok, we have can fit in the buffer, but we might need to do this
492  // in chunks
493  while (len > 0)
494  {
495  // is the buffer full?
496  if (bufferPosition == bufferSize)
497  {
498  // flush the buffer now
499  flush();
500  }
501 
502  // append to the buffer
503  size_t blocksize = (size_t)(len > bufferSize - bufferPosition ? bufferSize - bufferPosition : len);
504  memcpy(buffer + bufferPosition, data, blocksize);
505  // and adjust all of the position pointers
506  bufferPosition += blocksize;
507  data += blocksize;
508  len -= blocksize;
509  }
510  return true;
511  }
512  else
513  {
514  // not a transient stream?
515  if (!transient)
516  {
517  // opened in append mode?
518  if ((flags & _O_APPEND) != 0)
519  {
520  // seek to the end of the file, return if there is an error
521  if (_lseeki64(fileHandle, 0, SEEK_END) < 0)
522  {
523  errInfo = errno;
524  return false;
525  }
526  }
527  // write the data
528  int written = writeData(data, len);
529  if (written <= 0)
530  {
531  // return error status if there was a problem
532  errInfo = errno;
533  return false;
534  }
535 
536  bytesWritten = written;
537  }
538  else
539  {
540  // write the data
541  int written = writeData(data, len);
542  if (written <= 0)
543  {
544  // return error status if there was a problem
545  errInfo = errno;
546  return false;
547  }
548 
549  bytesWritten = written;
550  }
551  }
552  return true;
553 }
554 
555 bool SysFile::putChar(char ch)
556 {
557  size_t len;
558  return write(&ch, 1, len);
559 }
560 
561 bool SysFile::ungetc(char ch)
562 {
563  // make sure there's no sign extension
564  ungetchar = ((int)ch) & 0xff;
565  return true;
566 }
567 
568 bool SysFile::getChar(char &ch)
569 {
570  size_t len;
571 
572  return read(&ch, 1, len);
573 }
574 
575 bool SysFile::puts(const char *data, size_t &len)
576 {
577  return write(data, strlen(data), len);
578 }
579 
580 /**
581  * Write a line to the stream, adding the platform specific
582  * line terminator.
583  *
584  * @param buffer Start of the line to write.
585  * @param len The length to write.
586  * @param bytesWritten
587  * The actual number of bytes written, including the line
588  * terminator.
589  *
590  * @return A success/failure indicator.
591  */
592 bool SysFile::putLine(const char *buffer, size_t len, size_t &bytesWritten)
593 {
594  // this could be a null line...don't try to write zero bytes
595  if (len > 0)
596  {
597  if (!write(buffer, len, bytesWritten))
598  {
599  return false;
600  }
601  }
602  size_t termlen;
603  if (puts(LINE_TERMINATOR, termlen))
604  {
605  bytesWritten += termlen;
606  return true;
607  }
608  return false;
609 }
610 
611 
612 bool SysFile::gets(char *buffer, size_t bufferLen, size_t &bytesRead)
613 {
614  size_t i;
615  for (i = 0; i < bufferLen - 1; i++)
616  {
617  size_t len;
618 
619  // if we don't get a character break out of here.
620  if (!read(buffer + i, 1, len))
621  {
622  break;
623  }
624 
625  // we only look for a newline character. On return, this
626  // line will have the terminator characters at the end, or
627  // if the buffer fills up before we find the terminator,
628  // this will just be null terminated. If this us a multi
629  // character line terminator, both characters will appear
630  // at the end of the line.
631  if (buffer[i] == '\n')
632  {
633  // once we hit a new line character, back up and see if the
634  // previous character is a carriage return. If it is, collapse
635  // it to the single line delimiter.
636  if (i >= 1 && buffer[i - 1] == '\r')
637  {
638  i--;
639  buffer[i] = '\n';
640  }
641  i++; // we need to step the position so that the null terminator doesn't overwrite
642  break;
643  }
644  }
645 
646  // if there is no data read at all, this is an eof failure;
647  if (i == 0)
648  {
649  return false;
650  }
651 
652  // null terminate, set the length, and return
653  buffer[i] = '\0';
654  // this is the length minus the terminating null
655  bytesRead = i;
656  // return an error state, but not EOF status.
657  return !error();
658 }
659 
660 /**
661  * Count the number of lines in the stream, starting from the
662  * current file pointer position.
663  *
664  * @param count The returned line count.
665  *
666  * @return The success/failure indicator.
667  */
668 bool SysFile::countLines(int64_t &count)
669 {
670  int64_t counter = 0;
671  size_t bytesRead;
672 
673  while (nextLine(bytesRead))
674  {
675  if (bytesRead == 0)
676  {
677  count = counter;
678  return true;
679  }
680  counter++;
681  }
682 
683  return false;
684 }
685 
686 /**
687  * Count the number of lines between two character positions.
688  *
689  * @param start The starting offset.
690  * @param end The ending offset
691  * @param lastLine The starting offset of the last line before the end position.
692  * @param count The returned offset
693  *
694  * @return The success/failure indicator
695  */
696 bool SysFile::countLines(int64_t start, int64_t end, int64_t &lastLine, int64_t &count)
697 {
698  // go to the target location, if possible
699  if (!seek(start, SEEK_SET, start))
700  {
701  return false;
702  }
703 
704  int64_t counter = 0;
705  size_t bytesRead;
706 
707  while (nextLine(bytesRead))
708  {
709  lastLine = start;
710  // hit an eof? we're done counting, return
711  if (bytesRead == 0)
712  {
713  count = counter;
714  return true;
715  }
716  counter++;
717  start += bytesRead;
718  // have we reached our end point?
719  if (start > end)
720  {
721  count = counter;
722  return true;
723  }
724  }
725 
726  return false;
727 }
728 
729 /**
730  * Move to the beginning of the next line in the stream, returning
731  * a count of the bytes moved forward.
732  *
733  * @param bytesRead The returned byte count for the line (including the terminators).
734  *
735  * @return True if this was processed ok, false for any errors.
736  */
737 bool SysFile::nextLine(size_t &bytesRead)
738 {
739  size_t len = 0;
740 
741  for (;;)
742  {
743  char ch;
744  // if we don't get a character break out of here.
745  if (!getChar(ch))
746  {
747  break;
748  }
749  len++; // count this
750  // found our newline character?
751  if (ch == '\n')
752  {
753  break;
754  }
755  }
756 
757  // this is the length including the line terminators
758  bytesRead = len;
759  // return an error state, but not EOF status.
760  return !error();
761 }
762 
763 bool SysFile::seekForwardLines(int64_t startPosition, int64_t &lineCount, int64_t &endPosition)
764 {
765  // make sure we flush any output data
766  flush();
767 
768  // get a buffer for searching
769  char *buffer = (char *)malloc(LINE_POSITIONING_BUFFER);
770  if (buffer == NULL)
771  {
772  errInfo = ENOMEM;
773  return false;
774  }
775 
776  for (;;)
777  {
778  int readLength = LINE_POSITIONING_BUFFER;
779 
780  // This is likely due to hitting the end-of-file. We'll just
781  // return our current count and indicate this worked.
782  if (!setPosition(startPosition, startPosition))
783  {
784  free(buffer);
785  // set the return position and get outta here
786  endPosition = startPosition;
787  return true;
788  }
789 
790  size_t bytesRead;
791  if (!read(buffer, readLength, bytesRead))
792  {
793  free(buffer);
794  // if we've hit an eof condition, this is the end
795  if (atEof())
796  {
797  // set the return position and get outta here
798  endPosition = startPosition;
799  return true;
800  }
801  // read error,
802  return false;
803  }
804  // have we hit the eof?
805  if (bytesRead == 0)
806  {
807  free(buffer);
808  // set the return position and get outta here
809  endPosition = startPosition;
810  return true;
811  }
812 
813 
814  size_t offset = 0;
815  while (offset < bytesRead)
816  {
817  // we're only interested in \n character, since this will
818  // mark the transition point between lines.
819  if (buffer[offset] == '\n')
820  {
821  // reduce the line count by one.
822  lineCount--;
823  // reached the requested point?
824  if (lineCount == 0)
825  {
826  // set the return position and get outta here
827  endPosition = startPosition + offset + 1;
828  free(buffer);
829  return true;
830  }
831  }
832  // step to the next character;
833  offset++;
834  }
835  // move the start position...if at the end, we might not
836  // get a full buffer
837  startPosition += bytesRead;
838  }
839 }
840 
841 
842 bool SysFile::setPosition(int64_t location, int64_t &position)
843 {
844  // have a pending write?
845  if (writeBuffered)
846  {
847  // flush any pending data
848  flush();
849  // reset all buffer pointers
850  writeBuffered = false;
851  bufferPosition = 0;
852  bufferedInput = 0;
853  }
854 
855 
856  // is this location within the buffer bounds?
857  if (location >= (int64_t)(filePointer - bufferedInput) && location < filePointer)
858  {
859  // just shift the buffer position;
860  bufferPosition = (size_t)(location - (filePointer - (int64_t)bufferedInput));
861  // just return the same value
862  position = location;
863  }
864  else
865  {
866  // go to the absolute position
867  position = _lseeki64(fileHandle, location, SEEK_SET);
868  // this return the error indicator?
869  if (position == -1)
870  {
871  errInfo = errno;
872  return false;
873  }
874 
875  // reset all of the buffer information and the current file pointer.
876  bufferPosition = 0;
877  bufferedInput = 0;
878  filePointer = position;
879  }
880  return true;
881 }
882 
883 bool SysFile::seek(int64_t offset, int direction, int64_t &position)
884 {
885  // we need special processing if buffered
886  if (buffered)
887  {
888  switch (direction)
889  {
890  case SEEK_SET:
891  return setPosition(offset, position);
892 
893  case SEEK_CUR:
894  return setPosition(filePointer - bufferedInput + bufferPosition + offset, position);
895 
896  case SEEK_END:
897  int64_t fileSize;
898  if (getSize(fileSize))
899  {
900  return setPosition(fileSize - offset, position);
901  }
902  return false;
903 
904  default:
905  return false;
906  }
907  }
908  else
909  {
910  switch (direction)
911  {
912  case SEEK_SET:
913  position = _lseeki64(fileHandle, offset, SEEK_SET);
914  break;
915 
916  case SEEK_CUR:
917  position = _lseeki64(fileHandle, offset, SEEK_CUR);
918  break;
919 
920  case SEEK_END:
921  position = _lseeki64(fileHandle, offset, SEEK_END);
922  break;
923 
924  default:
925  return false;
926  }
927 
928  // this return the error indicator?
929  if (position == -1)
930  {
931  errInfo = errno;
932  return false;
933  }
934  }
935  return true;
936 }
937 
938 bool SysFile::getPosition(int64_t &position)
939 {
940  // we need special processing if we have anything in the
941  // buffer right now
942  if (buffered && !(writeBuffered && bufferPosition == 0))
943  {
944  // just return the current buffer position
946  }
947  else
948  {
949  // get the stream postion
950  position = _telli64(fileHandle);
951  if (position == -1)
952  {
953  return false;
954  }
955  }
956  return true;
957 }
958 
959 /**
960  * Retrieve the size of the stream. If the stream is open,
961  * it returns the stream size. Zero is returned if this
962  * stream is not a regular file.
963  *
964  * @param size The returned size value.
965  *
966  * @return True if the size was retrievable, false otherwise.
967  */
968 bool SysFile::getSize(int64_t &size)
969 {
970  // are we open?
971  if (fileHandle >= 0)
972  {
973  // we might have pending output that might change the size
974  flush();
975  // have a handle, use fstat() to get the info
976  struct _stati64 fileInfo;
977  if (_fstati64(fileHandle, &fileInfo) == 0)
978  {
979  // regular file? return the defined size
980  if (fileInfo.st_dev == 0)
981  {
982  size = fileInfo.st_size;
983  }
984  else
985  {
986  size = 0;
987  }
988  return true;
989  }
990  }
991  return false;
992 }
993 
994 /**
995  * Retrieve the size of a file from the file name. If the
996  * name is a device, it zero is returned.
997  *
998  * @param size The returned size value.
999  *
1000  * @return True if the size was retrievable, false otherwise.
1001  */
1002 bool SysFile::getSize(const char *name, int64_t &size)
1003 {
1004  // the handle is not active, use the name
1005  struct _stati64 fileInfo;
1006  if (_stati64(name, &fileInfo) == 0)
1007  {
1008  // regular file? return the defined size
1009  if ((fileInfo.st_mode & _S_IFREG) != 0)
1010  {
1011  size = fileInfo.st_size;
1012  }
1013  else
1014  {
1015  size = 0;
1016  }
1017  return true;
1018  }
1019  return false;
1020 }
1021 
1022 /**
1023  * Retrieve the size of the stream. If the stream is open,
1024  * it returns the stream size. Zero is returned if this
1025  * stream is not a regular file.
1026  *
1027  * @param size The returned size value.
1028  *
1029  * @return True if the size was retrievable, false otherwise.
1030  */
1031 bool SysFile::getTimeStamp(const char *&time)
1032 {
1033  time = ""; // default return value
1034  // are we open?
1035  if (fileHandle >= 0)
1036  {
1037  // have a handle, use fstat() to get the info
1038  struct _stati64 fileInfo;
1039  if (_fstati64(fileHandle, &fileInfo) == 0)
1040  {
1041  // regular file? return the defined size
1042  if ((fileInfo.st_mode & _S_IFREG) != 0)
1043  {
1044  time = ctime(&fileInfo.st_mtime);
1045  }
1046  }
1047  }
1048  return false;
1049 }
1050 
1051 /**
1052  * Retrieve the size of a file from the file name. If the
1053  * name is a device, it zero is returned.
1054  *
1055  * @param size The returned size value.
1056  *
1057  * @return True if the size was retrievable, false otherwise.
1058  */
1059 bool SysFile::getTimeStamp(const char *name, const char *&time)
1060 {
1061  time = ""; // default return value
1062  // the handle is not active, use the name
1063  struct _stati64 fileInfo;
1064  if (_stati64(name, &fileInfo) == 0)
1065  {
1066  // regular file? return the defined size
1067  if ((fileInfo.st_mode & (_S_IFREG | _S_IFDIR)) != 0)
1068  {
1069  time = ctime(&fileInfo.st_mtime);
1070  }
1071  return true;
1072  }
1073  return false;
1074 }
1075 
1076 
1077 /**
1078  * Determine the stream characteristics after an open.
1079  */
1081 {
1082  transient = false;
1083  device = false;
1084  isTTY = false;
1085  writeable = false;
1086  readable = false;
1087 
1088  if (_isatty(fileHandle))
1089  {
1090  transient = true;
1091  device = true;
1092  isTTY = true;
1093  }
1094  // have a handle, use fstat() to get the info
1095  struct _stati64 fileInfo;
1096  if (_fstati64(fileHandle, &fileInfo) == 0)
1097  {
1098  // character device? set those characteristics
1099  if ((fileInfo.st_mode & _S_IFCHR) != 0)
1100  {
1101  device = true;
1102  transient = true;
1103  }
1104 
1105  if ((fileInfo.st_mode & _S_IWRITE) != 0)
1106  {
1107  writeable = true;
1108  }
1109 
1110  if ((fileInfo.st_mode & _S_IREAD) != 0)
1111  {
1112  readable = true;
1113  }
1114  // tagged as FIFO, then this is also a transient
1115  if ((fileInfo.st_mode & _S_IFIFO) != 0)
1116  {
1117  transient = true;
1118  }
1119  }
1120 }
1121 
1122 /**
1123  * Set a SysFile object to be the standard output stream.
1124  */
1125 void SysFile::setStdIn()
1126 {
1127  // set the file handle using the standard handles, but force binary mode
1128  fileHandle = _fileno(stdin);
1129  _setmode(fileHandle, _O_BINARY);
1130  ungetchar = -1; // -1 indicates no char
1132  // NB: On Windows, we get a strange overlay when reading one character at a time from
1133  // stdin, so allow this to work buffered.
1134  readable = true; // force this to readable
1135 }
1136 
1137 /**
1138  * Set a SysFile object to the standard output stream.
1139  */
1140 void SysFile::setStdOut()
1141 {
1142  // set the file handle using the standard handles, but force binary mode
1143  fileHandle = _fileno(stdout);
1144  _setmode(fileHandle, _O_BINARY);
1145  ungetchar = -1; // -1 indicates no char
1147  setBuffering(false, 0);
1148  writeable = true; // force this to writeable
1149  // make this unbuffered
1150  setbuf(stdout, NULL);
1151 }
1152 
1153 /**
1154  * Set a SysFile object to the stderr stream.
1155  */
1156 void SysFile::setStdErr()
1157 {
1158  // set the file handle using the standard handles, but force binary mode
1159  fileHandle = _fileno(stderr);
1160  _setmode(fileHandle, _O_BINARY);
1161  ungetchar = -1; // -1 indicates no char
1163  setBuffering(false, 0);
1164  writeable = true; // force this to writeable
1165  // make this unbuffered
1166  setbuf(stderr, NULL);
1167 }
1168 
1169 
1170 /**
1171  * Check to see if a stream still has data.
1172  *
1173  * @return True if data can be read from the stream, false otherwise.
1174  */
1175 bool SysFile::hasData()
1176 {
1177  // not available for reads? Can't have data
1178  if (!readable)
1179  {
1180  return false;
1181  }
1182  // tty devices require special handling
1183  if (isTTY)
1184  {
1185  return (_kbhit() != 0) ? 1 : 0;
1186  }
1187 
1188  // we might have something buffered, but also check the
1189  // actual stream.
1190  return !atEof();
1191 }
void setStdIn()
bool putChar(char ch)
bool putLine(const char *buffer, size_t len, size_t &bytesWritten)
bool writeable
char * buffer
bool openedHandle
bool atEof()
size_t bufferSize
const char * filename
void setStdErr()
bool gets(char *buffer, size_t len, size_t &bytesRead)
bool nextLine(size_t &bytesRead)
bool getSize(int64_t &size)
bool seek(int64_t offset, int direction, int64_t &position)
bool seekForwardLines(int64_t startPosition, int64_t &lineCount, int64_t &endPosition)
@ LINE_POSITIONING_BUFFER
@ DEFAULT_BUFFER_SIZE
bool flush()
int64_t filePointer
bool buffered
int fileHandle
int writeData(const char *data, size_t length)
bool close()
bool puts(const char *data, size_t &bytesWritten)
bool getPosition(int64_t &position)
size_t bufferPosition
void setBuffering(bool buffer, size_t length)
bool getTimeStamp(const char *&time)
bool open(const char *name, int openFlags, int openMode, int shareMode)
bool getChar(char &ch)
bool read(char *buf, size_t len, size_t &bytesRead)
bool error()
bool writeBuffered
bool countLines(int64_t &count)
bool write(const char *data, size_t len, size_t &bytesWritten)
bool setPosition(int64_t location, int64_t &position)
bool hasData()
bool readable
size_t bufferedInput
void getStreamTypeInfo()
bool ungetc(char ch)
void setStdOut()
void reset()
#define LINE_TERMINATOR
#define RX_O_APPEND
#define BLOCK_THRESHOLD
signed __int64 int64_t