#endif
#ifndef _di_f_file_open_
- f_return_status f_file_open(f_file *file, const f_string filename) {
+ f_return_status f_file_open(f_file *file, const f_string file_name) {
#ifndef _di_level_0_parameter_checking_
if (file == 0) return f_status_set_error(f_invalid_parameter);
#endif // _di_level_0_parameter_checking_
- // if file->mode is unset, then this may cause a segfault, depending on whether or not the libc will handle this appropriately
+ // if file->mode is unset, then this may cause a segfault.
if (file->mode == 0) return f_status_set_error(f_invalid_parameter);
- file->address = fopen(filename, file->mode);
+ file->address = fopen(file_name, file->mode);
if (file->address == 0) return f_status_set_error(f_file_not_found);
if (ferror(file->address) != 0) return f_status_set_error(f_file_open_error);
if (file->address == 0) return f_status_set_error(f_file_not_open);
// if we were given a file descriptor as well, make sure to flush all changes to the disk that are not flushed by the 'fflush()' command
- if (file->id != 0) {
- // make sure all unfinished data gets completed
+ if (file->id) {
+ // make sure all unfinished data gets completed.
if (fsync(file->id) != 0) return f_status_set_error(f_file_synchronize_error);
}
file->address = 0;
return f_none;
}
- else return f_status_set_error(f_file_close_error);
+
+ return f_status_set_error(f_file_close_error);
}
#endif // _di_f_file_close_
if (file->address == 0) return f_status_set_error(f_file_not_open);
if (fflush(file->address) == 0) return f_none;
- else return f_status_set_error(f_file_flush_error);
+
+ return f_status_set_error(f_file_flush_error);
}
#endif // _di_f_file_flush_
#ifndef _di_f_file_read_
- f_return_status f_file_read(f_file *file, f_string_dynamic *buffer, const f_file_position location) {
+ f_return_status f_file_read(f_file *file, f_string_dynamic *buffer) {
+ #ifndef _di_level_0_parameter_checking_
+ if (file == 0) return f_status_set_error(f_invalid_parameter);
+ if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (file->address == 0) return f_status_set_error(f_file_not_open);
+
+ int result = fread(buffer->string + buffer->used, file->byte_size, buffer->size - buffer->used - 1, file->address);
+
+ if (file->address == 0) return f_status_set_error(f_file_read_error);
+ if (ferror(file->address) != 0) return f_status_set_error(f_file_read_error);
+
+ buffer->used += (result / file->byte_size);
+
+ if (feof(file->address)) {
+ return f_none_on_eof;
+ }
+
+ return f_none;
+ }
+#endif // _di_f_file_read_
+
+#ifndef _di_f_file_read_range_
+ f_return_status f_file_read_range(f_file *file, f_string_dynamic *buffer, const f_string_length buffer_start, const f_string_length total_elements) {
#ifndef _di_level_0_parameter_checking_
if (file == 0) return f_status_set_error(f_invalid_parameter);
if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter);
- if (location.buffer_start < 0) return f_status_set_error(f_invalid_parameter);
- if (location.file_start < 0) return f_status_set_error(f_invalid_parameter);
- if (location.total_elements < 0) return f_status_set_error(f_invalid_parameter);
+ if (buffer_start < 0) return f_status_set_error(f_invalid_parameter);
+ if (total_elements < 0) return f_status_set_error(f_invalid_parameter);
// when the available buffer size is smaller than the total elements, then there is not enough allocated memory available to read the file
- if (location.total_elements > 0) {
- if (buffer->size - location.buffer_start < location.total_elements) return f_status_set_error(f_invalid_parameter);
+ if (total_elements > 0) {
+ if (buffer->size - buffer_start < total_elements) return f_status_set_error(f_invalid_parameter);
}
#endif // _di_level_0_parameter_checking_
if (file->address == 0) return f_status_set_error(f_file_not_open);
- // first seek to 'where' we need to begin the read
- unsigned long current_file_position = ftell(file->address);
- if (current_file_position == (unsigned long) -1) return f_status_set_error(f_file_seek_error);
-
int result = 0;
- if (current_file_position > location.file_start) {
- result = f_file_seek_from_current(file->address, file->byte_size * (0 - (current_file_position - location.file_start)));
- }
- else if (current_file_position < location.file_start) {
- result = f_file_seek_from_current(file->address, file->byte_size * (location.file_start - current_file_position));
- }
-
- if (result != 0) return f_status_set_error(f_file_seek_error);
-
- // now do the actual read
- if (location.total_elements == 0) {
- result = fread(buffer->string + location.buffer_start, file->byte_size, buffer->size - buffer->used - 1, file->address);
+ if (total_elements == 0) {
+ result = fread(buffer->string + buffer_start, file->byte_size, buffer->size - buffer->used - 1, file->address);
}
else {
- result = fread(buffer->string + location.buffer_start, file->byte_size, location.total_elements, file->address);
+ result = fread(buffer->string + buffer_start, file->byte_size, total_elements, file->address);
}
if (file->address == 0) return f_status_set_error(f_file_read_error);
if (ferror(file->address) != 0) return f_status_set_error(f_file_read_error);
- // now save how much of our allocated buffer is actually used
- // also make sure that we aren't making used space vanish
- if (location.buffer_start + result > buffer->used) {
- buffer->used = location.buffer_start + (result / file->byte_size);
+ // Save how much of our allocated buffer is actually used.
+ if (buffer_start + result > buffer->used) {
+ buffer->used = buffer_start + (result / file->byte_size);
}
- // append an EOS only when the total elements were set to 0
- if (location.total_elements == 0) {
+ // Append an EOS only when the total elements were set to 0
+ if (total_elements == 0) {
buffer->string[buffer->used] = f_string_eos;
}
- // make sure to communicate that we are done without a problem and the eof was reached
+ // Make sure to communicate that we are done without a problem and the EOF was reached.
if (feof(file->address)) {
return f_none_on_eof;
}
return f_none;
}
-#endif // _di_f_file_read_
+#endif // _di_f_file_read_range_
-#ifndef _di_f_file_read_fifo_
- f_return_status f_file_read_fifo(f_file *file, f_string_dynamic *buffer) {
+#ifndef _di_f_file_read_at_
+ f_return_status f_file_read_at(f_file *file, f_string_dynamic *buffer, const f_file_position position) {
#ifndef _di_level_0_parameter_checking_
if (file == 0) return f_status_set_error(f_invalid_parameter);
if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter);
+
+ if (position.buffer_start < 0) return f_status_set_error(f_invalid_parameter);
+ if (position.file_start < 0) return f_status_set_error(f_invalid_parameter);
+ if (position.total_elements < 0) return f_status_set_error(f_invalid_parameter);
+
+ // when the available buffer size is smaller than the total elements, then there is not enough allocated memory available to read the file
+ if (position.total_elements > 0) {
+ if (buffer->size - position.buffer_start < position.total_elements) return f_status_set_error(f_invalid_parameter);
+ }
#endif // _di_level_0_parameter_checking_
if (file->address == 0) return f_status_set_error(f_file_not_open);
+ // first seek to 'where' we need to begin the read
+ unsigned long current_file_position = ftell(file->address);
+
+ if (current_file_position == (unsigned long) -1) return f_status_set_error(f_file_seek_error);
+
int result = 0;
+ if (current_file_position > position.file_start) {
+ result = f_macro_file_seek_to(file->address, file->byte_size * (0 - (current_file_position - position.file_start)));
+ }
+ else if (current_file_position < position.file_start) {
+ result = f_macro_file_seek_to(file->address, file->byte_size * (position.file_start - current_file_position));
+ }
+
+ if (result != 0) return f_status_set_error(f_file_seek_error);
+
// now do the actual read
- result = fread(buffer->string + buffer->used, file->byte_size, buffer->size - buffer->used - 1, file->address);
+ if (position.total_elements == 0) {
+ result = fread(buffer->string + position.buffer_start, file->byte_size, buffer->size - buffer->used - 1, file->address);
+ }
+ else {
+ result = fread(buffer->string + position.buffer_start, file->byte_size, position.total_elements, file->address);
+ }
if (file->address == 0) return f_status_set_error(f_file_read_error);
if (ferror(file->address) != 0) return f_status_set_error(f_file_read_error);
- buffer->used += (result / file->byte_size);
+ // now save how much of our allocated buffer is actually used
+ // also make sure that we aren't making used space vanish
+ if (position.buffer_start + result > buffer->used) {
+ buffer->used = position.buffer_start + (result / file->byte_size);
+ }
+
+ // append an EOS only when the total elements were set to 0
+ if (position.total_elements == 0) {
+ buffer->string[buffer->used] = f_string_eos;
+ }
- // make sure to communicate that we are done without a problem and the eof was reached
if (feof(file->address)) {
return f_none_on_eof;
}
return f_none;
}
-#endif // _di_f_file_read_fifo_
+#endif // _di_f_file_read_at_
#ifndef _di_f_file_stat_
f_return_status f_file_stat(const f_string file_name, struct stat *file_stat) {
}
#endif // _di_f_file_stat_
+#ifndef _di_f_file_stat_at_
+ f_return_status f_file_stat_at(const int file_id, const f_string file_name, struct stat *file_stat, const int flags) {
+ #ifndef _di_level_0_parameter_checking_
+ if (file_id <= 0) return f_status_set_error(f_invalid_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (file_stat != 0) {
+ return f_none;
+ }
+
+ int result = fstatat(file_id, file_name, file_stat, flags);
+ if (result < 0) {
+ if (errno == ENAMETOOLONG || errno == EFAULT) {
+ return f_status_set_error(f_invalid_name);
+ }
+ else if (errno == ENOMEM) {
+ return f_status_set_error(f_out_of_memory);
+ }
+ else if (errno == EOVERFLOW) {
+ return f_status_set_error(f_overflow);
+ }
+ else if (errno == ENOTDIR) {
+ return f_status_set_error(f_invalid_directory);
+ }
+ else if (errno == ENOENT) {
+ return f_file_not_found;
+ }
+ else if (errno == EACCES) {
+ return f_status_set_error(f_access_denied);
+ }
+ else if (errno == ELOOP) {
+ return f_status_set_error(f_loop);
+ }
+
+ return f_status_set_error(f_file_stat_error);
+ }
+
+ return f_none;
+ }
+#endif // _di_f_file_stat_by_at_
+
#ifndef _di_f_file_stat_by_id_
f_return_status f_file_stat_by_id(const int file_id, struct stat *file_stat) {
#ifndef _di_level_0_parameter_checking_
return f_none;
}
- int result = 0;
-
- result = fstat(file_id, file_stat);
+ int result = fstat(file_id, file_stat);
if (result < 0) {
if (errno == ENAMETOOLONG || errno == EFAULT) {
return f_status_set_error(f_invalid_name);
extern "C" {
#endif
+/**
+ * Provide common file-typ specific data types.
+ */
#ifndef _di_f_file_types_
typedef int f_file_id;
typedef f_string f_file_mode;
typedef mode_t f_file_mask;
- #define f_file_default_read_size 4096 // default to 4k read sizes
+ #define f_file_default_read_size 4096 // default to 4k read sizes.
#define f_file_max_path_length 1024
#endif // _di_f_file_types_
+/**
+ * Provide classic string-based file modes.
+ */
#ifndef _di_f_file_oldstyle_modes_
#define f_file_read_only "r"
#define f_file_read_write "r+"
#define f_file_write_append "a"
#endif // _di_f_file_oldstyle_modes_
+/**
+ * Provide macros for file-seek operations.
+ *
+ * The fseek() function parameters can be confusing, so provide a hopefully more readibly code via these macros.
+ *
+ * The f_macro_file_seek_begin() sets the file pointer from this many bytes from the beginning of the file.
+ * The f_macro_file_seek_to() sets the file pointer from this many bytes relative to the current position.
+ * The f_macro_file_seek_end() sets the file pointer from this many bytes from the end of the file.
+ */
#ifndef _di_f_file_seeks_
- #define f_file_seek_from_beginning(file, bytes) fseek(file, bytes, SEEK_SET)
- #define f_file_seek_from_current(file, bytes) fseek(file, bytes, SEEK_CUR)
- #define f_file_seek_from_end(file, bytes) fseek(file, bytes, SEEK_END)
+ #define f_macro_file_seek_begin(file, bytes) fseek(file, bytes, SEEK_SET)
+ #define f_macro_file_seek_to(file, bytes) fseek(file, bytes, SEEK_CUR)
+ #define f_macro_file_seek_end(file) fseek(file, bytes, SEEK_END)
#endif // _di_f_file_seeks_
+/**
+ * Commonly used file related properties.
+ *
+ * id: File descriptor.
+ * byte_size: How many bytes to use on each read/write (for normal string handling this should be sizeof(f_string).
+ * address: A pointer to a file (generally opened).
+ * mode: How the file is to be accessed (or is being accessed).
+ */
#ifndef _di_f_file_
typedef struct {
- f_file_id id; // file descriptor.
- size_t byte_size; // how many bytes to use on each read/write (for normal string handling this should be sizeof(f_string).
- FILE * address; // a pointer to a file (generally opened).
- f_file_mode mode; // how the file is to be accessed (or is being accessed).
+ f_file_id id;
+ size_t byte_size;
+ FILE * address;
+ f_file_mode mode;
} f_file;
#define f_file_initialize { 0, sizeof(char), 0, (f_file_mode) f_file_read_only }
#endif // _di_f_file_
+/**
+ * Store file positions.
+ *
+ * This is commonly used to instruct functions how to buffer and use a file.
+ *
+ * buffer_start: Designate where to start writing to the buffer.
+ * file_start: The positions where to begin reading the file.
+ * total_elements: The total number of elements to read from the file into the buffer.
+ * if total_elements: If set to 0, then this means to buffer the entire file no matter how big it is (crazy?).
+ */
#ifndef _di_f_file_position_
- /**
- * buffer_start designate where to start writing to the buffer.
- * file_start is the positions where to begin reading the file.
- * total_elements is the total number of elements to read from the file into the buffer.
- * if total_elements is set to 0, then this means to buffer the entire file no matter how big it is (crazy?).
- */
typedef struct {
f_string_length buffer_start;
f_string_length file_start;
#define f_file_position_initialize { 0, 0, 0 }
#endif // _di_f_file_position_
-// TODO: the information below needs to be confirmed and updated accordingly..
+/**
+ * File mode relation functionality.
+ *
+ * TODO: This information below needs to be confirmed and updated accordingly..
+ */
#ifndef _di_f_file_modes_
// file open modes
#define f_file_mode_world_wx (S_IWOTH | S_IXOTH)
#endif // _di_f_file_modes_
+/**
+ * Macro for resetting the file position and the total elements to the size of the file.
+ *
+ * @todo review why this is being done this way and consider renaming, changing, or removing this.
+ */
#ifndef _di_f_macro_file_reset_position_
#define f_macro_file_reset_position(position, file) \
if (position.total_elements == 0) { \
- fseek(file.address, 0, SEEK_END); \
+ fseek(file.address, 0L, SEEK_END); \
position.total_elements = ftell(file.address); \
- fseek(file.address, 0, SEEK_SET); \
+ fseek(file.address, 0L, SEEK_SET); \
}
#endif // _di_f_macro_file_reset_position_
+/**
+ * Open a particular file and save its stream.
+ *
+ * This will open the file and obtain the file descriptor.
+ *
+ * @param file
+ * The data related to the file being opened.
+ * This will be updated with the file descriptor and file address.
+ * @param file_name
+ * The name of the file to be opened.
+ *
+ * @return
+ * f_none on success.
+ * f_file_not_found (with error bit) if the file was not found.
+ * f_file_open_error (with error bit) if the file is already open.
+ * f_file_descriptor_error (with error bit) if unable to load the file descriptor (the file pointer may still be valid).
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ */
#ifndef _di_f_file_open_
- /**
- * open a particular file and save its stream.
- * file name = name of the file.
- */
- extern f_return_status f_file_open(f_file *file, const f_string filename);
+ extern f_return_status f_file_open(f_file *file, const f_string file_name);
#endif // _di_f_file_open_
+/**
+ * Close an opened file.
+ *
+ * If the file descriptor is defined, then fsync() is called before closing.
+ *
+ * @param file
+ * The file to close.
+ *
+ * @return
+ * f_none on success.
+ * f_file_not_open (with error bit) if the file is not open.
+ * f_file_synchronize_error (with error bit) on fsync() failure.
+ * f_file_close_error (with error bit) if fclose() failed.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fsync()
+ * @see fclose()
+ */
#ifndef _di_f_file_close_
- /**
- * close file.
- */
extern f_return_status f_file_close(f_file *file);
#endif // _di_f_file_close_
extern f_return_status f_file_exists_at(const int directory_file_descriptor, const f_string file_name, const int flags);
#endif // _di_f_file_exists_at_
+/**
+ * Flush the file.
+ *
+ * This calls fflush().
+ *
+ * @param file
+ * The file to flush.
+ *
+ * @return
+ * f_none is returned on success.
+ * f_file_not_open (with error bit) if the file is not open.
+ * f_file_flush_error (with error bit) if the flush failed.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fflush()
+ */
#ifndef _di_f_file_flush_
- /**
- * flush file.
- */
extern f_return_status f_file_flush(f_file *file);
#endif // _di_f_file_flush_
+/**
+ * Read a until the entire buffer is filled or EOF is reached.
+ *
+ * @param file
+ * The file to read.
+ * @param buffer
+ * The buffer the file is being read into.
+ *
+ * @return
+ * f_none on success.
+ * f_none_on_eof on success and EOF was reached.
+ * f_file_not_open (with error bit) if file is not open.
+ * f_file_read_error (with error bit) if file read failed.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ */
#ifndef _di_f_file_read_
- /**
- * read a given amount of data from the buffer, will auto-seek to where.
- */
- extern f_return_status f_file_read(f_file *file, f_string_dynamic *buffer, const f_file_position location);
+ extern f_return_status f_file_read(f_file *file, f_string_dynamic *buffer);
#endif // _di_f_file_read_
-#ifndef _di_f_file_read_fifo_
- /**
- * read a given amount of data from the buffer, will not auto seek.
- */
- extern f_return_status f_file_read_fifo(f_file *file, f_string_dynamic *buffer);
-#endif // _di_f_file_read_fifo_
+/**
+ * Read a given amount of data from the buffer, specified by the given range.
+ *
+ * @param file
+ * The file to read.
+ * @param buffer
+ * The buffer the file is being read into.
+ * @param buffer_start
+ * The start position of the buffer.
+ * @param total_elements
+ * The total elements to read.
+ * When set to 0, this will read until the entire buffer is filled or the EOF is reached.
+ *
+ * @return
+ * f_none on success.
+ * f_none is returned if file_stat has a non-zero address.
+ * f_none_on_eof on success and EOF was reached.
+ * f_file_not_open (with error bit) if file is not open.
+ * f_file_read_error (with error bit) if file read failed.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_file_read_range_
+ extern f_return_status f_file_read_range(f_file *file, f_string_dynamic *buffer, const f_string_length buffer_start, const f_string_length total_elements);
+#endif // _di_f_file_read_range_
+
+/**
+ * Read a given amount of data from the buffer, specified by the given range.
+ *
+ * Will auto-seek file position to position.file_start.
+ *
+ * @param file
+ * The file to read.
+ * @param buffer
+ * The buffer the file is being read into.
+ * @param position
+ * The file position information.
+ * When position.total_elemenets is set to 0, this will read until the entire buffer is filled or the EOF is reached.
+ *
+ * @return
+ * f_none on success.
+ * f_none is returned if file_stat has a non-zero address.
+ * f_none_on_eof on success and EOF was reached.
+ * f_file_not_open (with error bit) if file is not open.
+ * f_file_seek_error (with error bit) if file seek failed.
+ * f_file_read_error (with error bit) if file read failed.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_f_file_read_at_
+ extern f_return_status f_file_read_at(f_file *file, f_string_dynamic *buffer, const f_file_position position);
+#endif // _di_f_file_read_at_
+
+/**
+ * Read statistics of a file.
+ *
+ * This will not re-read the file statistics., file_status must not be allocated.
+ * This is because fstatat() will allocate to this variable.
+ *
+ * This is essentially a wrapper to fstatat() converting any error codes into the FLL format.
+ *
+ * @param file_id
+ * The file descriptor.
+ * @param file_name
+ * The name of the file.
+ * @param file_stat
+ * The statistics read.
+ * @param flags
+ * Any valid flag used by fstatat(), such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
+ *
+ * @return
+ * f_none on success.
+ * f_none is returned if file_stat has a non-zero address.
+ * f_invalid_name (with error bit) if the name is somehow invalid.
+ * f_out_of_memory (with error bit) if out of memory.
+ * f_overflow (with error bit) on overflow error.
+ * f_invalid_directory (with error bit) on invalid directory.
+ * f_file_not_found (with error bit) if the file was not found.
+ * f_access_denied (with error bit) if access to the file was denied.
+ * f_loop (with error bit) if a loop occurred.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fstatat()
+ */
+#ifndef _di_f_file_stat_at_
+ extern f_return_status f_file_stat_at(const int file_id, const f_string file_name, struct stat *file_stat, const int flags);
+#endif // _di_f_file_stat_at_
+/**
+ * Read statistics of a file.
+ *
+ * This will not re-read the file statistics., file_status must not be allocated.
+ * This is because stat() will allocate to this variable.
+ *
+ * This is essentially a wrapper to stat() converting any error codes into the FLL format.
+ *
+ * @param file_name
+ * The name of the file.
+ * @param file_stat
+ * The statistics read.
+ *
+ * @return
+ * f_none on success.
+ * f_invalid_name (with error bit) if the name is somehow invalid.
+ * f_out_of_memory (with error bit) if out of memory.
+ * f_overflow (with error bit) on overflow error.
+ * f_invalid_directory (with error bit) on invalid directory.
+ * f_file_not_found (with error bit) if the file was not found.
+ * f_access_denied (with error bit) if access to the file was denied.
+ * f_loop (with error bit) if a loop occurred.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see stat()
+ */
#ifndef _di_f_file_stat_
- /**
- * read file statistics.
- */
extern f_return_status f_file_stat(const f_string file_name, struct stat *file_stat);
#endif // _di_f_file_stat_
+/**
+ * Read statistics of a file.
+ *
+ * This will not re-read the file statistics., file_status must not be allocated.
+ * This is because fstat() will allocate to this variable.
+ *
+ * This is essentially a wrapper to fstat() converting any error codes into the FLL format.
+ *
+ * @param file_id
+ * The file descriptor.
+ * @param file_stat
+ * The statistics read.
+ *
+ * @return
+ * f_none on success.
+ * f_invalid_name (with error bit) if the name is somehow invalid.
+ * f_out_of_memory (with error bit) if out of memory.
+ * f_overflow (with error bit) on overflow error.
+ * f_invalid_directory (with error bit) on invalid directory.
+ * f_file_not_found (with error bit) if the file was not found.
+ * f_access_denied (with error bit) if access to the file was denied.
+ * f_loop (with error bit) if a loop occurred.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fstat()
+ */
#ifndef _di_f_file_stat_by_id_
- /**
- * read file statistics by file id.
- */
extern f_return_status f_file_stat_by_id(const int file_id, struct stat *file_stat);
#endif // _di_f_file_stat_by_id_