//
//file/file.c
//
//
//-UserX
#include "base/mem.h"
#include "file/file.h"
#include "base/str.h"
#include "base/logger.h"
#include "misc/compat.h"
#ifdef _UNIX_
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#endif
/**
@name file
*/
//@{
FileHandle blankfilehandle = BLANKFILEHANDLE;
FileHandle *fhstdin = NULL;
FileHandle *fhstdout = NULL;
FileHandle *fhstderr = NULL;
StringArrayHandle *filepaths = NULL;
int defaultpathtotal = 0;
int filesysactive = 0;
/**
Initializes the file handler.
*/
void fileInit(void) {
fhstdin = memCopy(&blankfilehandle, sizeof(FileHandle), "FileHandle", "stdin");
fhstdout = memCopy(&blankfilehandle, sizeof(FileHandle), "FileHandle", "stdout");
fhstderr = memCopy(&blankfilehandle, sizeof(FileHandle), "FileHandle", "stderr");
fhstdin->filename = stringCopy("stdin");
fhstdout->filename = stringCopy("stdout");
fhstderr->filename = stringCopy("stderr");
fhstdin->file = stdin;
fhstdout->file = stdout;
fhstderr->file = stderr;
filepaths = saMake();
fileClearPath(NULL);
filesysactive = 1;
}
/**
Internal: Does the actual opening of a file.
@param filename The file to open.
@param mode The mode to open the file in, this is identical to fopen()'s.
@return The pointer to a FILE.
*/
FILE *fileOpenFile(char *filename, char *mode) {
char *s;
FILE *fh;
#ifdef _UNIX_
struct passwd *pw;
#endif
if(filename == NULL || mode == NULL){
return NULL;
}
if(filename[0] == '~') {
if(filename[1] == '/') {
#ifdef _UNIX_
pw = getpwuid(geteuid());
if(pw == NULL || pw->pw_dir == NULL) {
#endif
s = getenv("HOME");
if(s == NULL) {
s = stringCopyMany("/home/iip", filename + 1, NULL);
} else {
s = stringCopyMany(s, filename + 1, NULL);
}
#ifdef _UNIX_
} else {
s = stringCopyMany(pw->pw_dir, filename + 1, NULL);
}
#endif
} else {
s = stringCopyMany("/home/", filename + 1, NULL);
}
fh = fopen(s, mode);
stringFree(s);
return fh;
} else {
return fopen(filename, mode);
}
}
/**
Opens a file.
@param filename The file to open.
@param mode The mode to open the file in, this is identical to fopen()'s.
@return The pointer to a FileHandle.
*/
FileHandle *fileOpen(char *filename, char *mode) {
FileHandle *fh;
int i;
if(isStringBlank(filename)) {
return NULL;
}
if(mode == NULL) {
return NULL;
}
fh = memCopy(&blankfilehandle, sizeof(FileHandle), "FileHandle", NULL);
//todo:cycle through all paths/permutations
if(filename[0] == '@') {
filename++;
for(i = filepaths->size - 1; i >= 0 && fh->file == NULL; i--) {
if(stringCompare(filepaths->data[i], "-") != 0) {
fh->filename = stringCopyMany(filepaths->data[i], filename, NULL);
fh->file = fileOpenFile(fh->filename, mode);
if(fh->file != NULL) {
break;
}
stringFree(fh->filename);
fh->filename = NULL;
}
}
}
if(fh->file == NULL) {
fh->filename = stringCopy(filename);
fh->file = fileOpenFile(fh->filename, mode);
}
if(fh->file == NULL) {
//call fileClose() to clean up allocated structures
fileClose(fh);
return NULL;
}
#if BUFSIZE >= 1024
fh->buffer = memAlloc(BUFSIZ, "FileBuffer", NULL);
setvbuf(fh->file, fh->buffer, _IOFBF, BUFSIZE);
#else
fh->buffer = memAlloc(1024, "FileBuffer", NULL);
setvbuf(fh->file, fh->buffer, _IOFBF, 1024);
#endif
return fh;
}
/**
Closes a file and releases a FileHandle.
@param fh The FileHandle of an open file.
*/
void fileClose(FileHandle *fh) {
if(fh == NULL) {
return;
}
if(fh->file != NULL) {
//todo: handle cases where fclose() does return an error
fclose(fh->file);
}
memFree(fh->buffer);
stringFree(fh->filename);
memFree(fh);
}
/**
Reads x bytes of data from a file.
@param fh Pointer to a FileHandle.
@param buffer Pointer to a buffer to receive data.
@param bytes Number of bytes to be read.
@return The number of bytes actually read, or -1 if there was an error.
*/
int fileRead(FileHandle *fh, void *buffer, size_t bytes) {
if(fh == NULL) {
return -1;
}
if(fh->file == NULL) {
return -1;
}
if(buffer == NULL) {
return -1;
}
return fread(buffer, 1, bytes, fh->file);
}
/**
Reads a character from a file.
@param fh Pointer to a FileHandle.
@return The value of the character read, or EOF if there was an error.
*/
int fileReadChar(FileHandle *fh) {
if(fh == NULL) {
return EOF;
}
if(fh->file == NULL) {
return EOF;
}
return fgetc(fh->file);
}
/**
Writes x bytes of data to a file.
@param fh Pointer to a FileHandle.
@param buffer Pointer to a buffer of data to be written.
@param bytes Number of bytes to be written.
@return The number of bytes actually written, or -1 if there was an error.
*/
int fileWrite(FileHandle *fh, void *buffer, size_t bytes) {
if(fh == NULL) {
return -1;
}
if(fh->file == NULL) {
return -1;
}
if(buffer == NULL) {
return -1;
}
return fwrite(buffer, 1, bytes, fh->file);
}
/**
Writes a character to a file.
@param fh Pointer to a FileHandle.
@return -1 if there was an error.
*/
int fileWriteChar(FileHandle *fh, int c) {
if(fh == NULL) {
return -1;
}
if(fh->file == NULL) {
return -1;
}
return fputc(c, fh->file);
}
/**
Writes a string to a file, releasing the string afterwards.
@param fh Pointer to a FileHandle.
@param buffer The string to be written, the string is released after being written.
@return number of bytes written or -1 if there was an error.
*/
int fileWriteString(FileHandle *fh, char *buffer) {
int i;
if(buffer == NULL) {
return -1;
}
i = fileWrite(fh, buffer, stringLength(buffer));
stringFree(buffer);
return i;
}
/**
Writes a character to a file.
@param fh Pointer to a FileHandle.
@param buffer The string to be written.
@return number of bytes written or -1 if there was an error.
*/
int fileWriteStringKeep(FileHandle *fh, char *buffer) {
if(buffer == NULL) {
return -1;
}
return fileWrite(fh, buffer, stringLength(buffer));
}
/**
Flush the buffers for this file handle. Any outstand
disk writes will be written.
@param fh Pointer to the FileHandle to flush.
@return Zero if successful, non-zero if not.
*/
int fileFlush(FileHandle *fh) {
if(fh == NULL) {
return -1;
}
return fflush(fh->file);
}
/**
Check if a file is EOF.
@param fh Pointer to a FileHandle.
@return Non-zero if at EOF, zero if not.
*/
int fileEOF(FileHandle *fh) {
if(fh == NULL) {
return EOF;
}
if(fh->file == NULL) {
return EOF;
}
return feof(fh->file);
}
/**
Check if a file has had an error.
@param fh Pointer to a FileHandle.
@return Non-zero if there is an error, zero if not.
*/
int fileError(FileHandle *fh) {
if(fh == NULL) {
return -1;
}
if(fh->file == NULL) {
return -1;
}
return ferror(fh->file);
}
/**
Clears the last error flag.
@param fh Pointer to a FileHandle.
*/
void fileClearError(FileHandle *fh) {
if(fh == NULL) {
return;
}
if(fh->file == NULL) {
return;
}
clearerr(fh->file);
}
/**
Adds a file path (used by the '--filepath' option).
*/
void fileAddPath(void *extra, char *str) {
if(stringCompare(str, "-") == 0) {
saDeleteMany(filepaths, 0, defaultpathtotal);
defaultpathtotal = 0;
//append "-" anyway so config files get saved properly
}
saAppendCopy(filepaths, str);
}
/**
Gets the full list of filepaths.
*/
void fileGetPath(void *extra, StringArrayHandle **sa) {
if(sa == NULL) {
return;
}
*sa = saCopy(filepaths);
saDeleteMany(*sa, 0, defaultpathtotal);
}
/**
Clears the list of filepaths and fills it with the defaults.
*/
void fileClearPath(void *extra) {
int i;
char **paths;
char *s;
saDeleteMany(filepaths, 0, filepaths->size);
defaultpathtotal = 0;
if(extra == NULL) {
return;
}
//paths = *((char ***)extra);
paths = (char **)extra;
if(paths == NULL) {
return;
}
for(i = 0; paths[i] != NULL; i++) {
//Append a path seperator character if missing
if(paths[i][stringLength(paths[i]) - 1] == PATHSEPERATORCHAR) {
s = stringCopy(paths[i]);
} else {
s = stringCopyMany(paths[i], PATHSEPERATOR, NULL);
}
saAppend(filepaths, s);
defaultpathtotal++;
}
}
//@}
syntax highlighted by Code2HTML, v. 0.9.1