feisty meow concerns codebase  2.140
byte_filer.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : byte_filer *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 2000-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
15 #include "byte_filer.h"
16 
18 #include <basis/astring.h>
19 #include <basis/byte_array.h>
20 #include <basis/functions.h>
21 #include <basis/utf_conversion.h>
22 
23 #include <stdio.h>
24 #include <string.h>
25 #ifdef __UNIX__
26  #include <unistd.h>
27 #endif
28 #ifdef __WIN32__
29  #include <io.h>
30 #endif
31 
32 #define DEBUG_BYTE_FILER
33  // uncomment for noisy version of class.
34 
35 using namespace basis;
36 
37 namespace filesystem {
38 
39 const size_t BTFL_FILE_TELL_LIMIT = size_t(2) * size_t(GIGABYTE);
40  // the largest a long integer can represent in the tell system call.
41 
42 class file_hider
43 {
44 public:
45  FILE *fp; // the real file pointer.
46 
47  file_hider() : fp(NULL_POINTER) {}
48 };
49 
51 
52 byte_filer::byte_filer()
53 : _handle(new file_hider),
54  _filename(new filename),
55  _auto_close(true)
56 {}
57 
58 byte_filer::byte_filer(const astring &fname, const astring &perms)
59 : _handle(new file_hider),
60  _filename(new filename),
61  _auto_close(true)
62 { open(fname, perms); }
63 
64 byte_filer::byte_filer(const char *fname, const char *perms)
65 : _handle(new file_hider),
66  _filename(new filename),
67  _auto_close(true)
68 { open(fname, perms); }
69 
70 byte_filer::byte_filer(bool auto_close, void *handle)
71 : _handle(new file_hider),
72  _filename(new filename),
73  _auto_close(auto_close)
74 {
75  if (handle) {
76  _handle->fp = (FILE *)handle;
77  }
78 }
79 
80 byte_filer::~byte_filer() { close(); WHACK(_handle); WHACK(_filename); }
81 
82 const astring &byte_filer::name() const { return _filename->raw(); }
83 
85 
86 bool byte_filer::open(const astring &fname, const astring &perms)
87 {
88  close();
89  _auto_close = true; // reset since we know we're opening this.
90  _filename->reset(fname);
91  _handle->fp = _filename->raw().t()? fopen(_filename->raw().s(), perms.s()) : NULL_POINTER;
92  if (_handle->fp == NULL_POINTER) return false;
93  return good();
94 }
95 
97 {
98  _filename->reset("");
99  if (_auto_close && _handle->fp) fclose(_handle->fp);
100  _handle->fp = NULL_POINTER;
101 }
102 
103 bool byte_filer::good() { return !!_handle->fp; }
104 
106 {
107  if (!_handle->fp) return 0;
108  long to_return = ::ftell(_handle->fp);
109  if (to_return == -1) {
110  // if we couldn't get the size, either the file isn't there or the size
111  // is too big for our OS to report.
113  if (good()) return BTFL_FILE_TELL_LIMIT;
114  else return 0;
115  }
116  return size_t(to_return);
117 }
118 
119 void *byte_filer::file_handle() { return _handle->fp; }
120 
121 bool byte_filer::eof() { return !_handle->fp ? true : !!feof(_handle->fp); }
122 
123 int byte_filer::read(abyte *buff, int size)
124 { return !_handle->fp ? 0 : int(::fread((char *)buff, 1, size, _handle->fp)); }
125 
126 int byte_filer::write(const abyte *buff, int size)
127 { return !_handle->fp ? 0 : int(::fwrite((char *)buff, 1, size, _handle->fp)); }
128 
129 int byte_filer::read(byte_array &buff, int desired_size)
130 {
131  buff.reset(desired_size);
132  int to_return = read(buff.access(), desired_size);
133  buff.zap(to_return, buff.length() - 1);
134  return to_return;
135 }
136 
138 { return write(buff.observe(), buff.length()); }
139 
141 {
142  size_t current_posn = tell();
143  seek(0, FROM_END); // jump to end of file.
144  size_t file_size = tell(); // get position.
145  seek(int(current_posn), FROM_START); // jump back to previous place.
146  return file_size;
147 }
148 
149 int byte_filer::read(astring &s, int desired_size)
150 {
151  s.pad(desired_size + 2);
152  int found = read((abyte *)s.observe(), desired_size);
153  if (non_negative(found)) s[found] = '\0';
154  s.shrink();
155  return found;
156 }
157 
158 int byte_filer::write(const astring &s, bool add_null)
159 {
160  int len = s.length();
161  if (add_null) len++;
162  return write((abyte *)s.observe(), len);
163 }
164 
166 {
167  if (!_handle->fp) return;
168  ::fflush(_handle->fp);
169 }
170 
172 {
173  flush();
174  int fnum = fileno(_handle->fp);
175 #ifdef __WIN32__
176  return SetEndOfFile((HANDLE)_get_osfhandle(fnum));
177 #else
178  size_t posn = tell();
179  // if we're at the highest point we can be, we no longer trust our
180  // ability to truncate properly.
181  if (posn >= file_size_limit())
182  return false;
183  return !ftruncate(fnum, posn);
184 #endif
185 }
186 
187 bool byte_filer::seek(int where, origins origin)
188 {
189  if (!_handle->fp) return false;
190  int real_origin;
191  switch (origin) {
192  case FROM_START: real_origin = SEEK_SET; break;
193  case FROM_END: real_origin = SEEK_END; break;
194  case FROM_CURRENT: real_origin = SEEK_CUR; break;
195  default: return false; // not a valid choice.
196  }
197  int ret = ::fseek(_handle->fp, where, real_origin);
198  return !ret;
199 }
200 
201 int byte_filer::getline(abyte *buff, int desired_size)
202 {
203  if (!_handle->fp) return 0;
204  char *ret = ::fgets((char *)buff, desired_size, _handle->fp);
205  return !ret? 0 : int(strlen((char *)buff)) + 1;
206 }
207 
208 int byte_filer::getline(byte_array &buff, int desired_size)
209 {
210  buff.reset(desired_size + 1);
211  return getline(buff.access(), desired_size);
212 }
213 
214 int byte_filer::getline(astring &buff, int desired_size)
215 {
216  buff.pad(desired_size + 1);
217  int to_return = getline((abyte *)buff.access(), desired_size);
218  if (non_negative(to_return)) buff[to_return] = '\0';
219  buff.shrink();
220  return to_return;
221 }
222 
223 } //namespace.
224 
225 
#define fileno
Definition: Xos2defs.h:27
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition: array.h:349
const contents * observe() const
Returns a pointer to the underlying C array of data.
Definition: array.h:172
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition: array.h:175
int length() const
Returns the current reported length of the allocated C array.
Definition: array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition: array.h:769
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
bool t() const
t() is a shortcut for the string being "true", as in non-empty.
Definition: astring.h:97
void shrink()
changes all occurrences of "to_replace" into "new_string".
Definition: astring.cpp:168
void pad(int length, char padding=' ')
makes the string "length" characters long.
Definition: astring.cpp:493
int length() const
Returns the current length of the string.
Definition: astring.cpp:132
virtual char * access()
provides access to the actual string held.
Definition: astring.cpp:136
virtual const char * observe() const
observes the underlying pointer to the zero-terminated string.
Definition: astring.cpp:140
A very common template for a dynamic array of bytes.
Definition: byte_array.h:36
int getline(basis::abyte *buffer, int desired_size)
reads a line of text (terminated by a return) into the "buffer".
Definition: byte_filer.cpp:201
static size_t file_size_limit()
returns the maximum size that seek and length can support.
Definition: byte_filer.cpp:84
int write(const basis::abyte *buffer, int buffer_size)
writes "buffer_size" bytes into the file from "buffer".
Definition: byte_filer.cpp:126
void * file_handle()
provides a hook to get at the operating system's file handle.
Definition: byte_filer.cpp:119
byte_filer()
constructs an object that doesn't access a file yet.
Definition: byte_filer.cpp:52
void close()
shuts down the open file, if any.
Definition: byte_filer.cpp:96
@ FROM_START
offset is from the beginning of the file.
Definition: byte_filer.h:94
@ FROM_CURRENT
offset is from current cursor position.
Definition: byte_filer.h:96
@ FROM_END
offset is from the end of the file.
Definition: byte_filer.h:95
bool seek(int where, origins origin=FROM_START)
places the cursor in the file at "where", based on the "origin".
Definition: byte_filer.cpp:187
const basis::astring & name() const
returns the file name that the object is operating on.
Definition: byte_filer.cpp:82
int read(basis::abyte *buffer, int buffer_size)
reads "buffer_size" bytes from the file into "buffer".
Definition: byte_filer.cpp:123
bool eof()
returns true if the cursor is at (or after) the end of the file.
Definition: byte_filer.cpp:121
size_t tell()
returns the current position within the file, in terms of bytes.
Definition: byte_filer.cpp:105
void flush()
forces any pending writes to actually be saved to the file.
Definition: byte_filer.cpp:165
size_t length()
returns the file's total length, in bytes.
Definition: byte_filer.cpp:140
bool truncate()
truncates the file after the current position.
Definition: byte_filer.cpp:171
bool good()
returns true if the file seems to be in the appropriate desired state.
Definition: byte_filer.cpp:103
bool open(const basis::astring &fname, const basis::astring &permissions)
opens a file with "fname" and "permissions" as in the constructor.
Definition: byte_filer.cpp:86
Provides operations commonly needed on file names.
Definition: filename.h:64
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
Definition: filename.cpp:97
void reset(const basis::astring &name)
changes the file name held by the object.
Definition: filename.cpp:103
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
const int GIGABYTE
Number of bytes in a gigabyte.
Definition: definitions.h:136
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
unsigned char abyte
A fairly important unit which is seldom defined...
Definition: definitions.h:51
bool non_negative(const type &a)
non_negative returns true if "a" is greater than or equal to zero.
Definition: functions.h:45
A platform independent way to obtain the timestamp of a file.
Definition: byte_filer.cpp:37
const size_t BTFL_FILE_TELL_LIMIT
Definition: byte_filer.cpp:39
Support for unicode builds.
Aids in achievement of platform independence.
void * HANDLE