I'm almost done with my first original game, but I have two little problems that I'm hooked up on.
1. In trying to delete a file, the remove() function isn't working in an if() or switch() statement or outside of main(). I want to be able to do this outside of main(), in its own function, but I've searched and searched and I can't find a single example program of that, even in C programming books. The way I'm using it is: "remove("mb1.txt");" Apparently it is returning a fail on the delete, but I have no clue as to why. If I put that same line of code in main() with no if() or switch() statements, it'll delete it. But that's useless.
EDIT: Found a solution to my second question. Thanks allegro.cc
I only see one question???
Anyway can you show me your code that fails.
He removed it, because he solved it.
But it´s still in the title.
I call the function from another function in the program similar to this:
for(n=0; n<4; n++) if((cursor->x >= sframe[n]->x + 120) && (cursor->y > sframe[n]->y) && (cursor->x < sframe[n]->x + 200) && (cursor->y < sframe[n]->y + 125) && (mouse_b & 1)) trash_file(n);
And the actual function trash_file(int x) is like so:
I had it set up before so that it would return an error and exit the program if the deletion didn't work. But I guess I deleted that code.
I also tried without the switch() statement, and just called trash_file(int x) to see what would happen, and it still failed.
Your code looks ok, not sure what would cause it to fail. How exactly is it failing? Is it not compiling or is the code just not doing anything? Try "./mb1.txt".
The code just isn't doing anything. The program will compile and run without any errors or warnings. I also have another action occur when the user clicks that is grouped with the trash_file(int x), and it works. So the program is definitely reading the click. But when I tested remove() for a fail with...
if(remove("mb1.txt")) { set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("ERROR: File deletion unsuccessful", allegro_error); }
...it confirmed that the remove was failing. Also, I just look every time to see if the file is there, and it remains there... just as stubborn as ever.
The only time I got it to work is when I typed "remove("mb1.txt");" right in the main() function with no if loops or switch statements. This, however, is of course useless.
I tried your suggestion of "./mb1.txt" and that didn't work either. I greatly appreciate the effort though.
Oh, and if it helps. The function that calls trash_file(int x) and the function trash_file(int x) itself are in two different .c files.
Are the files open?
When they are deleted, no. I think I tried it with them open once (which doesn't sound right, but I tried it anyway), and I got an error.
What does it say when you use this:
allegro_message("ERROR: File deletion unsuccessful: %s", strerror(errno));? And you really should compile with warnings enabled (and not ignore them).
Thanks, that was really handy. I wasn't aware of strerror(errno).
The response was: "ERROR: File deletion unsuccessful: Permission denied"
However, as useful as that was, I'm not sure why that is the case. The file is not read only or hidden, and it shouldn't be open.
How is the file created? What Operating System?
You need to have the necessary permissions to delete the file. Under Windows you just need to be owner, in most cases, unless you've got a crazy configuration. Under Linux, I'm not sure what permission flag it is (I'm not too studied on permissions in Linux). I suppose the write permission would do it?
The file was created with the games save_file(int x) function.
| 1 | void save_file(x) |
| 2 | { |
| 3 | FILE* mb_save; |
| 4 | |
| 5 | int tx, ty, tw, th, tr, tg, tb; //temporary numbers, mainly for float to int conversion |
| 6 | |
| 7 | switch(x) |
| 8 | { |
| 9 | case 0: |
| 10 | mb_save = fopen("mb1.txt", "w+"); |
| 11 | |
| 12 | //save information to file |
| 13 | fprintf(mb_save, "c%-5d", r); |
| 14 | fprintf(mb_save, ":%-5d", g); |
| 15 | fprintf(mb_save, ":%-5d", b); |
| 16 | fprintf(mb_save, "\n"); |
| 17 | |
| 18 | for(n=0; n<MAX_SHAPES; n++) |
| 19 | if(n != 994) //for some reason, this shape doesn't get saved right, so ignore it |
| 20 | { |
| 21 | tx = shape[n]->x; |
| 22 | ty = shape[n]->y; |
| 23 | tw = shape[n]->width; |
| 24 | th = shape[n]->height; |
| 25 | tr = shape[n]->red; |
| 26 | tg = shape[n]->green; |
| 27 | tb = shape[n]->blue; |
| 28 | |
| 29 | fprintf(mb_save, "s%-5d", n); |
| 30 | fprintf(mb_save, ":%-5d", shape[n]->alive); |
| 31 | fprintf(mb_save, ":%-5d", tx); |
| 32 | fprintf(mb_save, ":%-5d", ty); |
| 33 | fprintf(mb_save, ":%-5d", shape[n]->width); |
| 34 | fprintf(mb_save, ":%-5d", shape[n]->height); |
| 35 | fprintf(mb_save, ":%-5d", shape[n]->type); |
| 36 | fprintf(mb_save, ":%-5d", tr); |
| 37 | fprintf(mb_save, ":%-5d", tg); |
| 38 | fprintf(mb_save, ":%-5d", tb); |
| 39 | fprintf(mb_save, "\n"); |
| 40 | } |
| 41 | break; |
| 42 | case 1: |
| 43 | mb_save = fopen("mb2.txt", "w+"); |
| 44 | break; |
| 45 | case 2: |
| 46 | mb_save = fopen("mb3.txt", "w+"); |
| 47 | break; |
| 48 | case 3: |
| 49 | mb_save = fopen("mb4.txt", "w+"); |
| 50 | break; |
| 51 | } |
| 52 | |
| 53 | fclose(mb_save); |
| 54 | } |
My operating system is WinXP and I am the owner of this PC, not to mention the sole user.
how are you running the app? Your CWD is probably not being set to the one containing the files. Open up the shell, go to the directory and run it and see if you have the same results.
I'm sorry, but that comment just went over my head.
If you're talking about command-line compiling, I'm just using Dev-c++ to compile.
I don't know what a CWD is and I'm not sure what you mean by open up the shell.
Both your code examples start like
void trash_file(x)
when it should be like
void trash_file(int x)
That's strange. Sure you haven't typed in the code in your post, but pasted? You should get compiler errors from that. OTOH x might be a macro that compiles fine but screws everything.
Before remove(), try to examin the state of the file and write it on the screen. Is the file open, is it protected, whatever. I bet it is open.
I agree with Johan, "Permission denied" under Windows is usually only caused by the file still being open, either by the same or another process. Double-check that all handles to the file are closed.
Indeed, in Windows "Permission denied" means "the OS won't let you" 
You can try Sysinternals' "Process Explorer" to check for open files: This program is very much like a task manager on steroids.
I think the explanation is that you are in the wrong directory. Does Dev-C++ run your programs from its bin directory or from the directory you loaded the project from?
EDIT:
You could try typing the full path to the file:
remove("C:/home/you/mb1.txt");
Or whatever Windows uses.
[quote Johan]it should be like
void trash_file(int x)</quote>
You're correct. However, when I changed that, it didn't fix the error.
[quote Johan]Sure you haven't typed in the code in your post, but pasted?</quote>
I copied and pasted my code right in. Except for the very first for loop near the top of this post. That was just an example. The actual code is like this.
I just figured it would be a lot of code to go through.
[quote Johan]Before remove(), try to examin the state of the file and write it on the screen. Is the file open, is it protected, whatever. I bet it is open.</quote>
Capital idea! However, file handling in C is new to me, and I wasn't really well versed with it in C++ to begin with. So I'm not sure how to do that, but I am currently googling it.
[quote Jakub]"Permission denied" under Windows is usually only caused by the file still being open, either by the same or another process. Double-check that all handles to the file are closed.</quote>
Yup, that sounds like the case. However, every function that handles a file starts with FILE* mb_save; and ends with fclose(mb_save); And it's only three functions, so it's not easy to miss one.
[quote Audric]You can try Sysinternals' "Process Explorer" to check for open files</quote>
Thanks, I will look into that.
[quote James]I think the explanation is that you are in the wrong directory. Does Dev-C++ run your programs from its bin directory or from the directory you loaded the project from?</quote>
I do believe it runs programs from the directory the project was loaded from. Also, the fact that it can be deleted in main() leads me to believe this as well.
[quote James]You could try typing the full path to the file</quote>
No good, the error remains the same. You don't think that the file being on a partitioned drive would affect it do you? I mean, this works in main(), so I assume that's not the problem.
Are you sure that no other program has the file or directory open?
I'm gonna throw this up in case anyone really wants to check my file handling.
Here's the only file that does any file handling on the saves.
| 1 | //////////////////////////////////////////////////////////////////////////////// |
| 2 | //Corey Gardner |
| 3 | //Music Box.exe |
| 4 | //save.c |
| 5 | //7/20/2006 |
| 6 | //////////////////////////////////////////////////////////////////////////////// |
| 7 | |
| 8 | void load_file(int); |
| 9 | void trash_file(int); |
| 10 | int save_check(int); |
| 11 | void save_file(int); |
| 12 | |
| 13 | void load_file(int x) |
| 14 | { |
| 15 | FILE* mb_save; |
| 16 | |
| 17 | switch(x) |
| 18 | { |
| 19 | case 0: |
| 20 | mb_save = fopen("mb1.txt", "r+"); |
| 21 | break; |
| 22 | case 1: |
| 23 | remove("mb2.txt"); |
| 24 | break; |
| 25 | case 2: |
| 26 | remove("mb3.txt"); |
| 27 | break; |
| 28 | case 3: |
| 29 | remove("mb4.txt"); |
| 30 | break; |
| 31 | } |
| 32 | |
| 33 | fclose(mb_save); |
| 34 | } |
| 35 | |
| 36 | void trash_file(int x) |
| 37 | { |
| 38 | switch(x) |
| 39 | { |
| 40 | case 0: |
| 41 | remove("mb1.txt"); |
| 42 | /*if(remove("mb1.txt")) |
| 43 | set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); |
| 44 | allegro_message("ERROR: File deletion unsuccessful: %s", strerror(errno));*/ |
| 45 | break; |
| 46 | case 1: |
| 47 | remove("mb2.txt"); |
| 48 | break; |
| 49 | case 2: |
| 50 | remove("mb3.txt"); |
| 51 | break; |
| 52 | case 3: |
| 53 | remove("mb4.txt"); |
| 54 | break; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | int save_check(int x) |
| 59 | { |
| 60 | FILE* mb_save; |
| 61 | |
| 62 | switch(x) |
| 63 | { |
| 64 | case 0: |
| 65 | mb_save = fopen("mb1.txt", "r+"); |
| 66 | if(mb_save == NULL) return 0; |
| 67 | else return 1; |
| 68 | break; |
| 69 | case 1: |
| 70 | mb_save = fopen("mb2.txt", "r+"); |
| 71 | if(mb_save == NULL) return 0; |
| 72 | else return 1; |
| 73 | break; |
| 74 | case 2: |
| 75 | mb_save = fopen("mb3.txt", "r+"); |
| 76 | if(mb_save == NULL) return 0; |
| 77 | else return 1; |
| 78 | break; |
| 79 | case 3: |
| 80 | mb_save = fopen("mb4.txt", "r+"); |
| 81 | if(mb_save == NULL) return 0; |
| 82 | else return 1; |
| 83 | break; |
| 84 | } |
| 85 | |
| 86 | fclose(mb_save); |
| 87 | } |
| 88 | |
| 89 | void save_file(int x) |
| 90 | { |
| 91 | FILE* mb_save; |
| 92 | |
| 93 | int tx, ty, tw, th, tr, tg, tb; //temporary numbers, mainly for float to int conversion |
| 94 | |
| 95 | switch(x) |
| 96 | { |
| 97 | case 0: |
| 98 | mb_save = fopen("mb1.txt", "w+"); |
| 99 | |
| 100 | //save information to file |
| 101 | fprintf(mb_save, "c%-5d", r); |
| 102 | fprintf(mb_save, ":%-5d", g); |
| 103 | fprintf(mb_save, ":%-5d", b); |
| 104 | fprintf(mb_save, "\n"); |
| 105 | |
| 106 | for(n=0; n<MAX_SHAPES; n++) |
| 107 | if(n != 994) //for some reason, this shape doesn't get saved right, so ignore it |
| 108 | { |
| 109 | tx = shape[n]->x; |
| 110 | ty = shape[n]->y; |
| 111 | tw = shape[n]->width; |
| 112 | th = shape[n]->height; |
| 113 | tr = shape[n]->red; |
| 114 | tg = shape[n]->green; |
| 115 | tb = shape[n]->blue; |
| 116 | |
| 117 | fprintf(mb_save, "s%-5d", n); |
| 118 | fprintf(mb_save, ":%-5d", shape[n]->alive); |
| 119 | fprintf(mb_save, ":%-5d", tx); |
| 120 | fprintf(mb_save, ":%-5d", ty); |
| 121 | fprintf(mb_save, ":%-5d", shape[n]->width); |
| 122 | fprintf(mb_save, ":%-5d", shape[n]->height); |
| 123 | fprintf(mb_save, ":%-5d", shape[n]->type); |
| 124 | fprintf(mb_save, ":%-5d", tr); |
| 125 | fprintf(mb_save, ":%-5d", tg); |
| 126 | fprintf(mb_save, ":%-5d", tb); |
| 127 | fprintf(mb_save, "\n"); |
| 128 | } |
| 129 | break; |
| 130 | case 1: |
| 131 | mb_save = fopen("mb2.txt", "w+"); |
| 132 | break; |
| 133 | case 2: |
| 134 | mb_save = fopen("mb3.txt", "w+"); |
| 135 | break; |
| 136 | case 3: |
| 137 | mb_save = fopen("mb4.txt", "w+"); |
| 138 | break; |
| 139 | } |
| 140 | |
| 141 | fclose(mb_save); |
| 142 | } |
The only other file handling that the program does is the main() function with the data file. Speaking of which, you don't think the *argv[] in main's parameters would be causing this do you?
EDIT: I think I may have figured it out. Apparently the constant checking of if a file exists is interfering with completing other actions on the file. Which is odd because logically, the way the functions run, they shouldn't be interfering with each other. But I got rid of constantly checking on the file's existance, and it deleted fine. Now I just have to reprogram the same effect without constantly checking the file.
I hope you realize your save_check function does NOT close the file if it is found, notice you return from the function yet your flcose statement is at the bottom. If you close it before returning, it should fix your issue. Why would you check to see if a file exists anyway every time in a loop? Besides that use stat instead of fopen to check if a file exists, it will be much quicker and less resources will be used.
Cookies for teh win!!!!!!!
What's wrong with using Allegro's exists() function?
I hope you realize your save_check function does NOT close the file if it is found
Thanks, I notice that now. Very stupid mistake that slipped by me.
Why would you check to see if a file exists anyway every time in a loop?
I think I did it so that... you know what? I don't remember why. Hmm...
Besides that use stat instead of fopen to check if a file exists, it will be much quicker and less resources will be used.
Thanks, I assume that checks the status of the file (hence "stat"). I'm not sure I completely get how it works quite yet, but it's not too hard to understand.
What's wrong with using Allegro's exists() function?
I'm not familiar with that function. Is there somewhere on allegro.cc I could read about it?
A note to everyone who posted here, my credits for the game are short, so I decided I could fit all who contributed help in a little thanks section of the credits.
int file_exists(const char *filename, int attrib, int *aret);
And your switch way of figuring out which file to load is very ugly. You could just make the filename based on the id: