program doesnt work if called from another folder - c

In Command Prompt, this works: whatever\folder> bezier.exe
but this doesn't: whatever> folder\bezier.exe
My bezier program loads some settings from a local file, so I believe the problem is that the program thinks its directory is whatever\ when it is actually whatever\folder\. I'm calling it from within a C program using CreateProcess(). If I am correct in guessing the problem, is there any way to ensure the program has the right directory for itself?
the main method of bezier.exe:
int main(int argc, char* argv[]) {
char buf[200];
FILE* f = fopen("out.txt","w");
GetCurrentDirectory(200,buf);
fprintf(f,buf);
fclose(f);
SDL_Surface* screen;
SDL_Event e;
SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_FULLSCREEN|SDL_HWSURFACE);
if (screen == NULL)
exit(-1);
SDL_ShowCursor(SDL_DISABLE);
srand(time(NULL));
loadColors(COLOR_FILE);
fill(screen, backColor);
initialiseVars();
while (e.type != SDL_KEYDOWN)
{
//do stuff
}
SDL_Quit();
return 0;
}
Here's the crazy part. With "..> folder\bezier.exe" it doesn't write its path, but it does start a new window. That doesn't make any sense to me, because SDL_SetVideoMode is after writing the path.

You can use GetModuleHandle and GetModuleFileName to find out where your execuatble file is, then use that information to create a file specification for your local settings file.
GetModuleHandle with a NULL argument will give you the handle for the current executable. Then, passing that to GetModuleFileName will give you the fully qualified name of that executable. Just strip off the executable filename from the end and add your configuration file name.
However, that's been a bad idea for a long time now, since Windows provides per-application and per-user settings areas for this sort of stuff - you can generally get those locations with SHGetFolderLocation() and its brethren.
Use the first method only if this is for a personal project. If you plan to release your software to the wild, you should separate executable and configuration information as per Microsoft guidelines.
Regardless of that, it appears you now have the problem that you think the file is not being written to. You need to check that. When you open that file out.txt for write, it does so in the current directory. If you're running in the parent directory (with folder\bezier.exe), it will create it in the parent directory and looking for it in the folder directory is a waste of time.
If you are looking in the directory where you're running the program from, and it's still not being created, there are possible reasons for this. For a start, you should check (ie, capture and output) the return codes from all those f* functions, fopen, fprintf and fclose.

Related

How to fix "too few arguments to function mkdir"

Im a coding noob. I have to compile some codes for my project in a HPC server. I can compile the codes in my laptop but when i run it on the HPC i get the error message
"too few arguments to function mkdir".
I have tried to print the output in the cwd and not in the output directory but it still didnt fix the problem. If i use the check command declared as a comment (which one of my instructors advised), I get the error check undeclared first use in the function.
void write_collection_pvd(int time_total, int time_save, char *directory, char *filename)
{
int x;
char dataFileName[255];
FILE *dataFile;
//#ifdef WIN32
mkdir(directory);
//#else
// check = mkdir(directory,0777);
//#endif
sprintf(dataFileName, "%s/%s.pvd", directory, filename);
}
i expect the pvd file to be written in the ouput directory. Thanks in advanceenter code here
In C, the mkdir function accepts two parameters: the name of the directory to create and the (typically octal) permission mode to give it. So instead of calling
mkdir(directory);
you should call something like
mkdir(directory, 0777);
That will give the new directory permissions of read, write, and search (execute) by the owner, group, and everybody else. But (at least under Unix and Linux) these permissions will be adjusted downward by your process's default permissions, which will typically turn off writability by world and often group.

Unexpected error when reading from a text file in C

I'm trying to read text from a file (should be pretty easy right?). As far as I recall, the syntax should look something like
FILE *filename;
filename = fopen("filename.txt", "r"); /*when file is the same
folder of the .exe*/
Below is my code. When I run it, I simply get "Error", which is the prompt I wanted in case of an error. I included here a global struct declaration because it's literally the only other thing in the code, even though I'm positive it's not causing any problem with opening the file.
#include <stdio.h>
#include <stdlib.h>
struct list {
char subject[20];
char prof_name[20];
char prof_surname[20];
char period[20];
int credits;
int pass_rate;
};
int main()
{
struct list data[80];
FILE *prof;
prof = fopen("professor.txt", "r");
if (prof == NULL) {
fprintf(stderr, "Error");
exit(EXIT_FAILURE);
}
return 0;
}
The file has the correct name and extension, it's in the same folder as the .exe (I've also tried with the address, it still does the same). I feel like I'm going to get crazy if I look at the code even for just one more minute. There must be something I missed
Regarding the comment "when file is the same folder of the .exe", that is incorrect.
Instead relative paths (like your professor.txt) is relative from the process current working directory. Which might be very different from the location of the .exe file.
My guess is that you're running inside Visual Studio (or other IDE) which places the executable files in a sub-directory. The working directory when running, though, is usually the project root directory.
So either go into the project settings and change the working directory when running the program into the directory where the file is located, or move the file to the actual working directory.
You can use the _getcwd function to get the process working directory, to verify that it is what you believe it is.

Daemon process unable to find file (specified via relative path)

I have a daemon process that spawns several threads one of which handles HTTP requests. The handler is intended to return a file located in
resources/html/index.html
I have the following code:
void * read_file_ex(char *file_name, int32_t *data_len) {
FILE *fp;
fp = fopen(file_name, "r");
... // more code to fetch file contents
fclose(fp);
}
void * read_file(char *file_name){
return read_file_ex(file_name, NULL);
}
And in the thread, I call:
read_file("resources/html/index.html");
The code crashes with a "Segmentation Fault" error when a request is made for that file.
When I use GDB to break at fopen, I notice that a NULL is returned and errno is set to 2 (File not found).
Also, when I change the code to use the absolute path of the file:
/usr/sbin/app/resources/html/index.html
then `fopen()' is able to find the index file and everything works fine.
Another thing to mention is that this error happens when run on Debian Linux but not on Ubuntu 12.04 which makes my question look even dumber.
I forgot to add that I am running the program from the same folder that contains the `resources' folder.
If the current directory of the process is not /usr/sbin/app (and it seems a bit unlikely that the current directory would be /usr/bin/app), then the relative pathname won't work. You should always check the return result from fopen() before attempting to use it. There are endless reasons why an open operation can fail even if you're in the correct directory, let alone when there's a chance that you aren't.
Note that if your process uses functions like daemon(), or is run via a daemonize program, the current directory can be changed to / even if you expected it to be somewhere else.
If you need to check the current directory of the process (a process has a single current directory common to all threads), you can use the getcwd() to get the current working directory.
If you need to change directory (again) after daemonizing your process, you can use chdir() to do so. There's also fchdir() which can be used to change back to a directory if you have an open file descriptor for the directory.

Overwriting files in Windows by renaming randomly fails

I have a text file that I want to edit by rewriting it to a temp file and then overwrite the original. This code doesn't do that as it's simplified but it does include the problem I have. On Windows the EXAMPLE.TXT file will disappear after a seemly random number of runs when the rename function fails. I don't know why but so far it has worked fine on Linux. Why does this happen and how can I solve it going in an entirety different direction, such as overwriting the original file from within the program without renaming?
Furthermore, what other, better methods exist? This method has other flaws on Windows, such as the program being closed by a user just after remove is called but before rename, which would not be a problem on Linux (after getting rid of remove)?
#include <stdio.h>
#include <assert.h>
int main(int argc, char *argv[]) {
unsigned int i=0;
FILE *fileStream, *tempStream;
char fileName[] = "EXAMPLE.TXT";
char *tempName = tmpnam(NULL);
while(1) {
printf("%u\n",i++);
assert(fileStream = fopen(fileName, "r+"));
assert(tempStream = fopen(tempName, "w"));
fprintf(tempStream,"LINE\n");
fflush(tempStream); /* fclose alone is enough on linux, but windows will sometimes not fully flush when closing! */
assert(fclose(tempStream) == 0);
assert(fclose(fileStream) == 0);
assert(remove(fileName) == 0); /* windows fails if the file already exists, linux overwrites */
assert(rename(tempName,fileName) == 0);
}
}
Doing it this way is indeed likely to cause trouble. There are four possible outcomes of your code on Windows:
deletes fine, rename works, no problem
deletes fine, but another process had the file open with delete sharing. Common for malware scanners and file content indexers. Which ensures that the file actually gets deleted when the last handle on the file is closed. Problem is, the rename fails because the file still exists
doesn't delete because the file is locked, your assert fires
nothing at all happens because assert() is a no-op when you build the release version.
Good odds for the last bullet btw, it certainly explains repeatable failure. You'll need a more defensive strategy to deal with the 2nd bullet:
delete filename.bak, report error if that failed
rename fileName to filename.bak, report error if that failed
rename tempName to filename, report error and rename filename.back back if that failed
delete filename.bak, don't report error
This is such a common scenario that the winapi has a function for it, ReplaceFile(). Be sure to use the backup file option for maximum bang for the buck.
-
Sometimes antivirus software can cause such a problem by scanning a file at an inconvenient moment.
If the remove fails, try sleeping for a short time and then retrying.

Opening a file in Mac OS X

I am trying to open a text file with C++ in Mac OS X but I always get a Bus error.
I do not care where to put the file. I just need to read it. Am I writing its address wrong? or that Bus Error has another reason?
FILE *dic;
dic = fopen("DICT","rb");
dic = fopen("./DICT","rb");
dic = fopen("~/DICT","rb");
dic = fopen("~//DICT","rb");
With a little bit of clarification I see the problem in your C code (not C++!) is that fopen() returns NULL. You can check what the problem really is by reporting the detailed error:
if( (dic = fopen("DICT", "rb") == NULL ) {
fprintf(stderr, "%s\n", perror("ERROR:"));
exit(1);
}
If fopen() fails to find the file on the user's desktop and you wish your code to work on multiple platforms then you might define a function to get the user's desktop directory for using with fopen(). Something like
char* user_desktop(char* buf, size_t len)
{
const char* const DESKTOP_DIR =
#ifdef PC
"C:\\Documents and Settings\\Pooya\\Desktop\\"
#elif defined(OSX)
"/Users/Pooya/Desktop/"
#elif defined(LINUX)
"/home/users/pooya/Desktop/"
// fail to compile if no OS specified ...
#endif
return strncpy(buf, DESKTOP_DIR, len);
}
You probably want to look into a more robust way of getting the path of the desktop for each operating system. Most operating systems have an API for this, so do your research. There are also more robust ways of splitting behaviour for various platforms, you can look into that or open a different question about that. I just wanted to express my idea, of having a function which will return you the appropriate desktop path no matter on which platform you compile your code.
This code is correct! Pay attention to the directory where the executable is located. For sure the directory of the execution is not the same as you are expecting (I suppose, the directory of the .c files, right?).
I believe you are executing the app from the IDE. This is commom in Xcode, it mounts the exec`s in another location than that where the project files are located, and this such location that is considered when you execute the program, whether you execute it from the IDE or not!
Simply move the file you want to read to the location of the application and it will work properly.

Resources