How to initialize a file only once - c

I have this function for initializing admin account,
the adminAcc.txt should be initialized only once, regardless of how many times the program has been executed. .
The code does not work tho, it still initializes the file everytime i run the program,
anyone can help? ty...
static int file_initialized = 0; //global variable
void initAdmin(){
struct form adminAcc;
FILE *fptr;
if((fptr = fopen("adminAcc.txt", "a")) == NULL){
printf("\nError Opening Admin File!");
getch();
system("cls");
main();
}
if(file_initialized != 1){
strcpy(adminAcc.username, "admin#gmail.com");
strcpy(adminAcc.password, "admin");
strcpy(adminAcc.roles, "admin");
fwrite(&adminAcc, sizeof(struct form), 1, fptr);
file_initialized = 1;
}else{
return;
}
fclose(fptr);
}
int main(){
initAdmin();
return 0;
}

If you want to retain the value of file_initialized across calls (as your code implies) you need to make it static:
static int file_initialized = 0;
If you only want to initialize it once across multiple program executions, then you need to persist the initialization state. Below I inspect the position of newly opened file and initialize it if empty:
#include <errno.h>
#include <stdio.h>
#define FILENAME "adminAcc.txt"
#define LEN 64
struct form {
char username[LEN];
char password[LEN];
char roles[LEN];
};
int initAdmin(){
FILE *fptr = fopen(FILENAME, "a");
if(!fptr) {
printf("Error Opening Admin File!\n");
return 1;
}
if(!ftell(fptr)) {
printf("initialize\n");
fwrite(
&(struct form) { "admin#gmail.com", "admin", "admin" },
sizeof(struct form),
1,
fptr
);
}
fclose(fptr);
return 0;
}
int main() {
initAdmin();
}
and example runs:
$ ./a.out
initialize
$ ./a.out
$

sorry for not updating...
this is how i solved the problem:
I included the library below, to use access() function.
#include <unistd.h>
The access() function checks to see if the file or directory specified by path exists and if it can be accessed with the file access permissions given by amode.
the function will only create and initialize a file named(filename) if the file does not exists, otherwise skip the initialization
void initAdmin(){
struct form adminAcc;
if(access("adminAcc.txt", F_OK) == -1){
FILE *fptr = fopen("adminAcc.txt", "w");
strcpy(adminAcc.username, "admin#gmail.com");
strcpy(adminAcc.password, "admin");
strcpy(adminAcc.roles, "admin");
fwrite(&adminAcc, sizeof(struct form), 1, fptr);
fclose(fptr);
}
}

The code does not work tho, it still initializes the file everytime i run the program
You cannot retain program state in the program across multiple runs. Every run of the program starts with a clean slate. Depending on the system on which it runs, however, you can generally retain state in the system. In this case, the natural state is whether the adminAcc.txt file exists, and possibly whether it has valid contents.
Although it is possible to check that before trying to open the file, a better paradigm is usually simply to attempt an operation (such as opening the file) and seeing whether that works. Because you need to do that anyway, and it's always possible for the system to be modified at just the right time such that the wanted operation fails even though an appropriate pre-check predicts that it will succeed.
So, something along these lines would make sense, then:
#include <stdio.h>
#include <string.h>
void initAdminIfNecessary(){
struct form adminAcc;
FILE *fptr;
if((fptr = fopen("adminAcc.txt", "ab")) == NULL){
fprintf(stderr, "\nError Opening Admin File!\n");
abort();
}
long fileSize = ftell(fptr);
if (fileSize == -1) {
fprintf(stderr, "\nError determining Admin File length!\n");
abort();
else if (fileSize == 0) {
strcpy(adminAcc.username, "admin#gmail.com");
strcpy(adminAcc.password, "admin");
strcpy(adminAcc.roles, "admin");
fwrite(&adminAcc, sizeof(struct form), 1, fptr);
// TODO: check return value
} else if (fileSize < sizeof(struct form)) {
fprintf(stderr, "\nAdmin File has invalid content\n");
abort();
}
fclose(fptr);
}
int main(){
initAdminIfNecessary();
return 0;
}
That opens the file as a binary (b) file in append (a) mode, which creates it if it does not already exist, but does not modify it if it does exist. The file is initially positioned at its end (and each write will go to the then-end of the file).
It uses ftell() to determine the length of the file, and acts accordingly.

Related

Is fclose() necessary in read only file pointers?

I know it's good practice closing every file pointer that is opened, but I've been thinking that fclose() only actually does something when someone is working with files on write/all mode where the user actually needs to save the new content on the file.
But does having no fclose() actually affects read only pointers in any way? I've done some testing but I haven't gotten anything different from when I was using fclose().
Is there something else that I should be aware?
Opened file pointers may leak without fclose() and they may prevent from opening more files when you do file operations many times.
This is a test code that do fopen() many times.
#include <stdio.h>
int main(void) {
int i;
for (i = 0; i < 1000; i++) {
FILE* fp = fopen("test.txt", "r");
int data;
printf("%3d : ", i);
if (fp != NULL) {
if (fscanf(fp, "%d", &data) == 1) {
printf("data = %d\n", data);
} else {
puts("read failed");
}
fclose(fp);
} else {
puts("fopen failed");
}
}
return 0;
}
This code successfully done 1000 operations on Wandbox.
On the other hand, When I commented out the fclose(fp); line, the operation began to fail after successful 251 operations.
When working with files I open file with "w+" to create or overwrite existing file. And then when I want to write new entry to the file I open it again with "wa" write what you need using fprintf and then close it.

read a text file, make some trivial transformation character by character (swapping the case of all letters), write result to text file

I have to read a text file, make some trivial transformation character by character (swapping the case of all letters), write results to the text files. I wrote this code, but it's not working. Please guide me in this regard. Thanks for in Advance
#include <stdio.h>
#include <stdlib.h>
int main() {
char c[1000];
char x[100];
char var;
int i;
FILE *fptr;
if ((fptr = fopen("text.txt", "r")) == NULL) {
printf("Error! opening file");
// Program exits if file pointer returns NULL...
exit(1);
}
// reads text until a newline is encountered...
fscanf(fptr, "%[^\n]", c);
printf("Data from the file:\n%s", c);
// Convert the file to upper case....
for( i=0;i<= strlen(c);i++){
if(c[i]>=65&&c[i]<=90)
c[i]=c[i]+32;
}
fptr = fopen("program.txt","w");
fprintf(fptr,"%[^\n]",c);
fclose(fptr);
return 0;
}
Edit: added #include <stdlib.h>, removed static describing main()
My proposition, based on example of copying a file given at my uni.
I used toupper() from ctype.h, if you don't want to use it you can just add 32 under condition similarly to your solution
Note: there could be char c instead of int c. (In the original version it actually was char; I changed it because if you look at the headers in the docs of all functions dealing with c, they all take/return int, not char; in your version it would matter more as you keep an array, in my program it changes pretty much nothing – int is just my preferred practice).
Note2: I actually never delved into the difference between "w"/"r" (write/read) and "wb"/"rb" (write/read binary). The code seems to work either way.
(I think there is no big difference when the files are text files anyway, for further assurance that both versions work, note that the code uses feof() to handle EOF)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
FILE *from, *to;
int c;//could be char
/* opening the source file */
if ((from = fopen("text.txt", "rb")) == NULL) {
printf("no such source file\n");
exit(1);
}
/* opening the target file */
if ((to = fopen("program.txt", "wb")) == NULL) {
printf("error while opening target file\n");
exit(1);
}
while (!feof(from)) {
c = fgetc(from);
if (ferror(from)) {
printf("error while reading from the source file\n");
exit(1);
}
if (!feof(from)) {//we avoid writing EOF
fputc(toupper(c), to);
if (ferror(to)) {
printf("error while writing to the target file\n");
exit(1);
}
}
}
if (fclose(from) == EOF) {
printf("error while closing...\n");
exit(1);
}
if (fclose(to) == EOF) {
printf("error while closing...\n");
exit(1);
}
return 0;
}
For a version taking arguments from command line (works on windows too) replace the beginning of main with
int main(int argc, char *argv[]) {
FILE *from, *to;
char c;
/* checking the number of arguments in the command line */
if (argc != 3) {
printf("usage: name_of_executable_of_this_main <f1> <f2>\n");//name_of_exe could be copy_to_upper, for example; change adequately
exit(1);
}
/* opening the source file */
if ((from = fopen(argv[1], "rb")) == NULL) {
printf("no such source file\n");
exit(1);
}
/* opening the target file */
if ((to = fopen(argv[2], "wb")) == NULL) {
printf("error while opening the target file\n");
exit(1);
}
I don't know how to code in that language(i think it's C++), but basically want you should be doing is a for loop to iterate through every character in the string. In Python it would look like:
x = open("text.txt", "r")
y = open("new text.txt","w")
z = ""
for char in x:
z += char.upper()
y.write(z)
I hope I was able to give an idea of how to solve your problem. I'm a newbie as well, but in Python.

C language: reading a .txt file

I'm trying to write a program that reads a text file, using C with Visual Studio.
This is my current code (which doesn't work):
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *filePTR;
char fileRow[100];
filePTR = fopen_s(&filePTR, "text.txt", "r");
// Opens the file
if(filePTR){
while(!feof(filePTR)) {
// Reads file row
fgets(fileRow, 100, filePTR);
// Displays file row
printf("%s \n", fileRow);
}
printf("\nEnd of file.");
}
else {
printf("ERROR! Impossible to read the file.");
}
// Closes the file
fclose(filePTR);
return 0;
}
I'm getting the following warning:
'filePTR' may be '0': this condition does not meet the function specification 'fclose'.
What am I doing wrong? I haven't been programming in C since a while ...
The problems begin long before the fclose. This line is incorrect:
filePTR = fopen_s(&filePTR, "text.txt", "r");
It overwites the file pointer already assigned by passing a pointer as the function argument &filePTR.
The function returns an error status, not the file pointer. Please see the man page:
Return Value Zero if successful; an error code on failure.
Also, please see Why is while ( !feof (file) ) always wrong?
I suggest this:
#include <stdio.h>
#include <stdlib.h>
int main(void) { // correct definition
FILE *filePTR;
char fileRow[100];
if(fopen_s(&filePTR, "text.txt", "r") == 0) {
while(fgets(fileRow, sizeof fileRow, filePTR) != NULL) {
printf("%s", fileRow); // the string already contains a newline
}
fclose(filePTR); // only close if it was opened
printf("\nEnd of file.");
}
else {
printf("ERROR! Impossible to read the file.");
}
return 0;
}
Note that I moved the fclose call up. You can't close a file that you did not open.

fwrite() appends instead of write C

I have to write a program witch reads from a file received by line and then it overwrites it with the read words uppercased.
This is my code
void toUpperCase(char* string) {
int i=0;
while(string[i])
{
string[i]=toupper(string[i]);
i++;
} }
int main(int argc, char** argv) {
if(argc==1)
{
puts("Error: INSERT PATH");
exit(0);
}
char* file=argv[1];
FILE* fd=fopen(file,"r+");
if(fd<0)
{
perror("Error opening file: ");
exit(0);
}
char buffer[30][30];
int i=0;
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
int j=0;
for(j=0; j<i; j++)
{
toUpperCase(buffer[j]);
fwrite(buffer[j],strlen(buffer[j]),1,fd);
}
fclose(fd);
return 0; }
but this program appends the words contained in buffer[][] instead of overwriting the file.
If the file contain was something like pippo pluto foo then, after the execution is pippo pluto fooPIPPOPLUTOFOO instead of PIPPO PLUTO FOO.
Where am i wrong? Thank you
You have to reset the file position indicator using fseek, as fscanf will advance it. Something like
fseek(fd, length_of_read_string, SEEK_CUR);
This allows you to read the file in chunks, but it will be tricky to get right. Or of course reset it to the file start because you read everything in 1 go:
fseek(fd, 0L, SEEK_SET);
I strongly recommend writing the modified data into a new file, and then after the program has run, delete the initial file and rename the new one. That will also take care of another issue with your program, you are reading the entire file into memory before handling it.
If you want to do in-place translation that doesn't change lengths, you can open the source file in two streams and then do read-chunk, write-chunk in lockstep. That has the advantage of being super-easy to convert to a non-in-place version that will work with nonseekable files too (stdin/stdout, pipes, and sockets).
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h> //toupper
inline void upcaseStr(char* str){
for(;*str;str++) { *str=toupper(*str); }
}
int upcaseStream(FILE* in, FILE* out){
char buf[BUFSIZ]; //BUFSIZ is an implementation-defined constant for an optimal buffer size
while(fgets(buf, BUFSIZ, in)){
upcaseStr(buf);
if(fputs(buf, out) == EOF){ return 1; }
}
if(!feof){ return 1; }
return 0;
}
int main(int argc, char **argv)
{
//default in and out
FILE* in = stdin;
FILE* out = stdout;
if(argc == 2) {
in = fopen(argv[1], "r"); //for reading
out = fopen(argv[1], "r+"); //for writing (and reading) starting at the beginning
if(!(in && out)){
fprintf(stderr, "Error opening file %s for reading and writing: %s\n", argv[1], strerror(errno));
}
}
return upcaseStream(in, out);
}
If you do use the in-place version, then in the unlikely event that the if(fputs(buf, out) == EOF){ return 1; } line should return, you're screwed unless you have a backup copy of the file. :)
Note:
You shouldn't name your FILE pointers fd because C people will tend to think you mean "file descriptor". FILE is a struct around a file descriptor. A file descriptor is just an int that you can use for FILE access with the raw system calls. FILE streams are an abstraction layer on top of file descriptors--they aren't file descriptors.
As you read from the file, its internal position indicator gets moved. Once you start writing, you start writing from that position on, which happens to be at the end of the file. So you effectively append the data to the file.
Rewind the handle to reset the position indicator before writing into the file:
rewind(fp);
On a side note, you are reading the file incorrectly:
while(!feof(fd))
{
fscanf(fd,"%s",buffer[i]);
i++;
}
When you reach the end of the file, fscanf will return an error and not read anything, yet you still increment variable i, as if the read was successful. And then you check feof() for end-of-file, but i was already incremented.
Check feof() and return of fscanf() immediately after calling fscanf():
while(1)
{
int read = fscanf(fd,"%s",buffer[i]);
if( read != 1 )
//handle invalid read
if( feof(fd) )
break;
i++;
}
Think about what happens if the string is longer than 29 characters and/or the file contains more than 30 strings. char buffer[30][30];
Welcome to StackOverflow!
Reopening the stream with fopen with the "w" parameter:
fd=fopen(file, "w");
It opens the file and if there are any contents in the file, it clears them.

How to load mruby code from external file in C program?

I'm getting started with mruby. I'm also pretty new to programming in C, so I may not be familiar with many of the basics. I was able to compile the example mruby program which loads the ruby code from a string. Now I would like to load it from an external file. Here's the example code that I'm using:
#include <stdlib.h>
#include <stdio.h>
#include <mruby.h>
static mrb_value my_c_method(mrb_state *mrb, mrb_value value)
{
puts("Called my C method");
return value;
}
int main(void)
{
mrb_state *mrb = mrb_open();
struct RClass *mymodule = mrb_define_module(mrb, "MyModule");
mrb_define_class_method(mrb, mymodule, "my_c_method", my_c_method, MRB_ARGS_NONE());
mrb_load_string(mrb, "MyModule.my_c_method"); // move this to an external file
return 0;
}
As you can see in the example above, I would like to move the ruby code to an external file. I'm a little confused as to whether or not I can simply "include" the ruby file, or if I need to precompile it into an .mrb file. Even then I'm not sure how to include that .mrb file when compiling.
What do I need to change to be able to load the ruby code from an external file?
Assuming your code is stored in file foo, all you need is to open the file and read it. To open the file, you need fopen(), defined in stdio.h. You can then read it line by line using fgets(). I'm not familiar with mruby, so I'm not exactly sure if mrb_load_string expects that every mruby code is in a single line. I will assume so. Here's how you can do it:
#define MAX_CODE_SIZE 128
FILE *code;
char code_buf[128]
code = fopen("foo", "r");
if (code == NULL) {
/* File couldn't be opened, handle error case... */
}
fgets(code_buf, MAX_CODE_SIZE, code);
/* Do some work ... */
fclose(code); /* Don't forget to close the file */
This piece of code reads the first line of file foo, up to a limit of 127 characters (including newline), and stores it in code_buf. You can then call mrb_load_string:
mrb_load_string(mrb, code);
I'm not sure if this is what you wanted, I never touched mruby, but from what I saw, mrb_load_string expects a char * with the code, and you want that to come from a file. That's how you do it.
If you want to read a file with code in multiple lines, you have no choice but to allocate a large enough buffer and read it using fread():
#include <stdio.h>
#define MAX_LINE_LENGTH 128
#define MAX_LINES 256
#define MAX_FILE_SIZE MAX_LINE_LENGTH*MAX_LINES
char code[MAX_FILE_SIZE];
int read_code(char *filepath) {
FILE *fp = fopen(filepath, "r");
if (fp == NULL)
return 0;
fread(code, 1, MAX_FILE_SIZE, fp);
fclose(fp);
return 1;
}
This function reads the whole file (assuming it doesn't exceed our buffer limits). code is global because you can easily reach the stack capacity if you allocate large local variables (another alternative is to use dynamic allocation). When you call read_code(), you should make sure to check its return value, to check for possible errors upon opening the file. Also, you can play with fread()'s return value to know if the buffer size wasn't enough to read everything.
Just make sure you don't forget to close the file when you're done.
EDIT: For the fgets() version, please note that in case the line holds less than 128 characters, newline will be retained in code_buf. You may want to set code_buf[strlen(code_buf)-1] to '\0' if that's the case.
UPDATE:
From our discussion on the comments below, I am updating my answer with a rudimentary parser to enable you to read the ruby file at compile time. Basically, the parser will read your ruby file and generate an output file with valid C code that inserts the file's content in a char array. Special characters are accordingly escaped. Here it is:
#include <stdio.h>
void inline insert(int, FILE *);
int main(int argc, char *argv[]) {
FILE *out, *in;
int c;
if (argc != 3) {
printf("Usage: %s <input_file> <output_file>\n", argv[0]);
return 1;
}
in = fopen(argv[1], "r");
out = fopen(argv[2], "w");
if (out == NULL) {
printf("Unable to create or write to %s\n", argv[1]);
return 1;
}
if (in == NULL) {
printf("Unable to read %s\n", argv[1]);
return 1;
}
fputs("#ifndef MRUBY_CODE_FILE_GUARD\n", out);
fputs("#define MRUBY_CODE_FILE_GUARD\n", out);
fputs("char mruby_code[] = \"", out);
while ((c = getc(in)) != EOF)
insert(c, out);
fputs("\";\n", out);
fputs("#endif\n", out);
fclose(in);
fclose(out);
return 0;
}
void inline insert(int c, FILE *fp) {
switch (c) {
case '\a':
fputs("\\a", fp);
break;
case '\b':
fputs("\\b", fp);
break;
case '\f':
fputs("\\f", fp);
break;
case '\n':
fputs("\\n", fp);
break;
case '\r':
fputs("\\r", fp);
break;
case '\t':
fputs("\\t", fp);
break;
case '\v':
fputs("\\v", fp);
break;
case '\\':
fputs("\\\\", fp);
break;
case '\'':
fputs("\\'", fp);
break;
case '"':
fputs("\\\"", fp);
break;
default:
fputc(c, fp);
}
}
Now, go back to your original program and add the following include directive in the beginning:
#include mruby_code.h
You have to do the following steps to compile a runnable program, assuming that this parser was compiled into a file named fileparser.c:
Run ./fileparser /path/to/mruby_code_file /path/to/program/mruby_code.h.
Compile your original program (it will include mruby_code.h)
The mruby code is provided in a variable called mruby_code. This is a char array, so you can pass it to mrb_load_string. And voila, you got the mruby file read once at compile time.
In the mruby/compile.h there is a method called mrb_load_file which allows you to load a ruby file and execute it with mruby:
#include <stdlib.h>
#include <stdio.h>
#include <mruby.h>
#include <mruby/compile.h>
static mrb_value my_c_method(mrb_state *mrb, mrb_value value)
{
puts("Called my C method");
return value;
}
int main(void)
{
mrb_state *mrb = mrb_open();
struct RClass *mymodule = mrb_define_module(mrb, "MyModule");
mrb_define_class_method(mrb, mymodule, "my_c_method", my_c_method, MRB_ARGS_NONE());
FILE *f = fopen("example.rb", "r");
mrb_load_file(mrb, f);
return 0;
}
Apart from using mrb_load_file:
FILE *f = fopen("the_file.rb", "r");
mrb_load_file(mrb, f);
fclose(f) ;
The manual option is to read the filename:
int load_ruby_file_to_state(char *filename, mrb_state *state) {
FILE *file = fopen(filename, "r") ;
if (!file) return -1 ;
fseek(file, 0, SEEK_END);
unsigned long length = ftell(file) ;
fseek(file, 0, SEEK_SET);
char *code = malloc(length + 1) ;
if (code) {
fread(code, 1, length, file) ;
code[length + 1] = '\0' ;
} else {
return -1 ;
}
fclose(file) ;
mrb_load_string(state, code) ;
free(code) ;
return 0 ;
}
And load file: load_ruby_file_to_state("the_file.rb", mrb) ;
Do note that mrb_load_file() will give a segfault if the file doesn't exist, so it's better to check for the file existence or if it's readable.

Resources