As an exercise to improve my coding ability in C, I have attempted to write a simple and safe file reader. I believe this should be portable as well to major platforms (correct me if I'm wrong). For simplicity's sake I assume the file will fit in memory which is mostly true for my use case.
Please let me know where I can improve.
(Note: I've used goto
because I think it makes the code flow better)
int read_file(const char* filename, char** buffer) {
FILE* fp = fopen(filename, "r");
if (!fp) {
goto f_read_error;
}
ssize_t file_len;
if (fseek(fp, 0L, SEEK_END) == 0) {
file_len = ftell(fp);
if (file_len == -1) {
goto f_read_error;
}
if (fseek(fp, 0L, SEEK_SET) != 0) {
goto f_read_error;
}
*buffer = (char*) malloc(sizeof(char) * (file_len + 1));
int output = fread(*buffer, sizeof(char), file_len, fp);
if (output != file_len) {
goto f_read_error;
};
(*buffer)[file_len] = '\0';
} else {
f_read_error: ;
char error_msg[1024];
// let's trunc filenames larger than 256, to not overflow error_msg buffer
char safe_filename[256];
if (strlen(filename) > 256) {
memcpy(safe_filename, filename, 256);
}
sprintf(error_msg, "Unable to read file : %s", safe_filename);
perror(error_msg);
if (buffer) {
free(buffer);
}
if (fp) {
fclose(fp);
}
return -1;
}
if (fp) {
fclose(fp);
}
return 1;
}
int main(int argc, char** argv) {
char* source = NULL;
int success = read_file("test.txt", &source);
if (success) {
//read_file("test.txt", &source); - a copy paste error, edited as a comment
printf("%s\n", source);
free(source);
}
}