How to use relative path to open files in C using xcode? - c

I need to make a game in C for my finals. The user should input the map file he wants to play.
Here's my simple code:
int main(){
FILE *map;
char fileToRead[100];
do{
printf("Insert file name: ");
fgets(fileToRead, 100, stdin);
map = fopen("/Users/rajunior/Desktop/map_2.txt", "r");
//map = fopen(fileToRead, "r");
printf("%s", fileToRead);
If I use the "map = fopen("/Users/rajunior...)" hardcoded, it works!
But I need to use the second (commented) option; the first one is useless for my purpose.
In other words, I need the fileToRead to be in the same directory as my .c, but how?
screenshot: https://imgur.com/a/DbX9tw4

Option 1: Install the command line tools. Put the C file and the text file in the same directory. Open a terminal window. Compile and run from the command line. If I recall correctly, the command line tools download can be found in Preferences.../Downloads.
Option 2: Go to the Product/Scheme/Edit Scheme... menu. When the dialog box appears, select Run at the left and Options at the top. Then look for Working Directory. Set the working directory to point to the directory where the text file is.

This was going to be a comment, but it is too long for comfort.
You'll need to know the current directory of the process when it is run. If you run it from the shell, the current directory of your program will be the same as the current directory of the program. If you run it from within XCode, I've no idea what the directory will be, but it probably won't be where the source is — it'll be in a build directory of some sort, probably.
Your program can find out where it is run from with getcwd(). Then you'll be able to tell how to chdir() to the directory where the source is (as long as the program knows where the source is, because you told it somehow — argument or command line variable, or …). Or you can determine how to create a relative path name that will find the file in the source directory.
There's probably an XCode (maybe Objective-C) way to find the information, perhaps via plists.
I don't code for a Mac; I only code on a Mac, and I run XCode itself rather seldom.

Related

How to interact with an external text editor in C

I am developing a command line application in C (linux environment) to edit a particular file format. This file format is a plain XML file, which is compressed, then encrypted, then cryptographically signed.
I'd like to offer an option to the user to edit this kind of file in an easy way, without the hassle of manualy extracting the file, editing it, and then compressing, encrypting and signing it.
Ideally, when called, my application should do the following:
Open the encrypted/compressed file and extract it to a temporary location (like /tmp)
Call an external text editor like nano or sublime-text or gedit depending on which is installed and maybe the user preferences. Wait until the user have edited the file and closed the text editor.
Read the modified temporary file and encrypt/compress it, replacing the old encrypted/compressed file
How can I achieve point no. 2?
I thought about calling nano with system() and waiting for it to return, or placing an inotify() on the temp file to know when it is modified by the graphical text editor.
Which solution is better?
How can i call the default text editor of the user?
Anything that can be done in a better way?
First, consider not writing an actual application or wrapper yourself, which calls another editor, but rather writing some kind of plugin for some existing editor which is flexible enough to support additional formats and passing its input through decompression.
That's not the only solution, of course, but it might be easier for you.
With your particular approach, you could:
Use the EDITOR and/or VISUAL command-line variables (as also pointed out by #KamilCuk) to determine which editor to use.
Run the editor as a child process so that you know when it ends execution, rather than having to otherwise communicate with it. Being notified of changes to the file, or even to its opening or closing, is not good enough, since the editor may make changes multiple files, and some editors don't even keep the file open while you work on it in them.
Remember to handle the cases of the editor failing to come up; or hanging; or you getting some notification to stop waiting for the editor; etc.
Call an external text editor like nano or sublime-text or gedit depending on which is installed and maybe the user preferences. Wait until the user have edited the file and closed the text editor.
Interesting question. One way to open the xml file with the user's default editor is using the xdg-open, but it doesn't give the pid of the application, in which user will edit the file.
You can use xdg-mime query default application/xml to find out the .desktop file of the default editor, but then you have to parse this file to figure out the executable path of the program - this is exactly how xdg-open actually works, in the search_desktop_file() function the line starting with Exec= entry is simply extracted from the *.desktop to call the editor executable and pass the target file as argument... What I am trying to say, is, after you find the editor executable, you can start it, and wait until it's closed, and then check if the file content has been changed. Well, this looks like a lot of unnecessary work...
Instead, you can try a fixed well-known editor, such as gedit, to achieve the desired workflow. You can also provide user a way (i.e. a prompt or config file) to set a default xml editor, i.e. /usr/bin/sublime_text, which then can be used in your programm on next run.
However, the key is here to open an editor that blocks the calling process, until user closes the editor. After the editor is closed, you can simply check if the file has been changed and if so, perform further operations.
To find out, if the file contents have been modified, you can use the stat system call to get the inode change time of the file, before you open the file, and then compare the timestamp value with the current one once it is closed.
i.e.:
stat -c %Z filename
Output: 1558650334
Wrapping up:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void execute_command(char* cmd, char* result) {
FILE *fp;
fp = popen(cmd, "r");
fscanf (fp, "%s" , result);
}
int get_changetime(char* filename) {
char cmd[4096];
char output[10];
sprintf(cmd, "stat -c %%Z %s", filename);
execute_command(cmd, output);
return atoi(output);
}
int main() {
char cmd[4096];
char* filename = "path/to/xml-file.xml";
uint ctime = get_changetime(filename);
sprintf(cmd, "gedit %s", filename);
execute_command(cmd, NULL);
if (ctime != get_changetime(filename)) {
printf("file modified!");
// do your work here...
}
return 0;
}

How to allocate an input file instead of the stdin in an Eclipse CDT application?

My application is a simple executable used from the command line and takes stdin as input and stdout as output, so it behaves like many GNU tools.
To test it, I want to set up an Eclipse CDT DEBUG Configuration to pass a file to stdin and another one to stdout.
I have tried unsuccessfully a few solutions, all inside the DEBUG Configuration GUI :
In Common / Standard Input and Output / Input File: I put inputfile.txt and in the same section Output file: I put outputfile.txt. As the GUI indicates that the working directory is ${workspace_loc:/myprogram}, it should be alright, but when the debugger is started, it warns :
[Invalid file specified for console output: test/WittenACM87ArithmCoding-1.txt.coded]
[Invalid file specified for stdin file: test/WittenACM87ArithmCoding-1.txt]
In Arguments I put < inputfile.txt > outputfile.txt which is obviously not designed for that
Of course, both files are in the working directory. All attempts fails on the ch = getc(stdin); code line with some strange message:
Can't find a source file at "/build/glibc-p3Km7c/glibc-2.24/io/../sysdeps/unix/syscall-template.S"
Locate the file or edit the source lookup path to include its location.
Here is the stack:
Thread #1 [myprogram] 31960 [core: 5] (Suspended : Signal : SIGINT:Interrupt)
__read_nocancel() at /build/glibc-p3Km7c/glibc-2.24/io/../sysdeps/unix/syscall-template.S:84 0x7ffff7811700
_IO_new_file_underflow() at /build/glibc-p3Km7c/glibc-2.24/libio/fileops.c:600 0x7ffff77a9a00
__GI__IO_default_uflow() at /build/glibc-p3Km7c/glibc-2.24/libio/genops.c:413 0x7ffff77aab02
_IO_getc() at /build/glibc-p3Km7c/glibc-2.24/libio/getc.c:38 0x7ffff77a54f0
main() at /xxxxxx/src/myprogram.c:20 0x555555554f01
When I run the application directly in the console, it works:
./myprogram < inputfile.txt > outputfile.txt
I assume from this that Eclipse does not manage to realise the files redirections to stdin and stdout, so obviously, I do it the wrong way. I have searched for it, but here and here don't provide solution for my use case.
So, in order to be able to use the debugger from Eclipse, what is the right way to set up the Eclipse DEBUG Configuration ?
In fact, solution 1 was using a relative path not related to the working directory. Using either button Workspace... or File System... in the GUI enables to select the files which shall already exist.
For example with Workspace definition, the field becomes :
${workspace_loc:/myprogram/inputfile.txt} (same for output)
And it works. Debuggers says :
[Console output redirected to file:/.../myprogram/outputfile.txt]

Get current path when C app is launched from /bin/ in Linux

So, I am working on an application that reads files, much the way vim or cat would, where you type "appname /path/to/file.txt" and it passes the file path as a perameter to the program which manipulates the file in some way.
I have run into a roadblock though. In vim, cat, or a similar program, you can type "appname file.txt", and it will read the file in the current directory that you launch the application from terminal in.
For example, I want to edit a file my documents directory. I type "cd ~/Documents", and then I can either type "vim ~/Documents/Essay.txt", or I just can type "vim Essay.txt".
My application will be stored in a binary file in the /bin/ directory so I can launch it from anywhere using the Terminal, but how do I pass the path name of the directory I am in when I call it from terminal?
As I am a new Linux developer (I have always worked with the .NET launguages in Windows) I am not sure weather this is handled by the Linux terminal, or by the C application itself.
Any help or suggestions would be much appreciated!
Also, if there is a more efficiant way to run it from the terminal than sticking it in the /bin/, let me know.
If you want to get the directory the process was run from you can use the system call getcwd to copy a string into a buffer and return it. The kernel keeps track of this for every process.
e.g.
char buf[100];
printf("Current directory: %s\n", getcwd(buf, 100));
The working directory can be changed, but will default to where the process launched.
This should work just fine without you having to do anything special. Did you try something that didn't work as you expected?
Generally you don't put user programs in /bin. I would store your program in /usr/local/bin.
https://unix.stackexchange.com/a/8658

fprintf() present in a C .exe file called from MATLAB doesn't work

I'm calling a C executable compiled using Cygwin in MATLAB, using the unix() function. This works fine, and I can see the desired output on the MATLAB command window. However, there is an fprintf() inside the executable that is supposed to create and write to a text file which does not run - no such file is created. The text file is created just fine when I run the executable directly through Cygwin.
I was wondering if I need to grant permissions to the MATLAB file/executable to enable this? How could I go about this?
What path are you using to create the file? It might have been created -- just not where you expected it.
If it's a relative path, you could use getcwd(2) inside your C program to get and print the working directory (or e.g. getpid(2) to get the PID and then do ls -d /proc/<pid>/cwd, which will work on Linux at least). Once you have the working directory, check if the file is somewhere in there.
If it looks like the file really isn't being created, my next step would be to add some error checking to functions and print messages for errors to try to figure out what's going on. strerror(3) and perror(3) might come in handy.

working with files on "start without debugging"

I'm programming in C, and
I have the following problem:
I use fopen and try to read from a csv file, that is currently storred in the folder of the exe file of the program.
the program works fine in debug mode and release mode, but when I try to run the program in "start without debugging" on visual studio 2008 express edition, the program stops working and windows is showing a message: "*.exe has stopped working. a program caused the program to stop working correctly. windows will close the program and notify you if a solution is available".
I've tried running the program on several computers, and it's the same.
another information I can give you is that if I enter the full path of the file (C:....file.csv) - then is works just fine, without any problem.
I know I didn't write any code, but I hope someone will have an idea why this can happend.
thanks is advance.
Your program is not finding the csv file, fopen() fails and return a null pointer, you try to use it without checking and your program crashes (just my guess).
Firstly, you must make a check to see if fopen() could indeed open your file:
FILE* f = fopen("file.csv", "r");
if(f == NULL) {
/* print some meaningful error */
} else {
/* use the file */
}
Secondly, you may solve the problem by executing your program from the same folder the file is present. I am not a Windows guy, but if you create a link to the ".exe", in its properties may have some configuration called "Working Directory" or something like that, that you may set to the path on where the file can be found.
Every process has a working directory, that is usually the directory from where it was started, though it may be inherited from the parent process and it may be changed programmatically. If you do not specify the full path when loading a file, the process will search for the file in its current working directory.

Resources