I'm trying to learn File I/O concepts in C programming language. I'm using GNU / Linux ( Ubuntu 16.04 LTS ) and my IDE is eclipse 3.8. when I try to write in a file through fprintf() method, it doesn't create any files or if the file is even created, it doesn't write in it. I tried to fix the problem by using fflush() or setbuf(file_pointer, NULL) methods as is suggested here but still no change. I guess I'm writing the address of the file in a wrong way.
Here is the code:
#include <stdio.h>
int main(void){
FILE *file_pointer;
file_pointer=fopen("~/.textsfiless/test.txt","w+");
setbuf(file_pointer,NULL);
fprintf(file_pointer,"Testing...\n");
fclose(file_pointer);
return EXIT_SUCCESS;
}
Can someone explain what's wrong here?
On Linux, the ~ in ~/.textsfiless/test.txt is not expanded by the C library fopen... When you use ~ on the command line, it is expanded by your shell (but not by the program using it, started by the shell doing some execve(2)...) into your home directory; the expansion is called globbing. Read glob(7). You are very unlikely to have a directory named ~.
You should read Advanced Linux Programming
So you should check if fopen failed (it is very likely that it did fail). If you want to get a file in the home directory, you'll better use getenv(3) with "HOME" (or perhaps getpwuid(3) & getuid(2)...). See environ(7)
Perhaps a better code might be:
char*homedir = getenv("HOME");
if (!homedir) { perror("getenv HOME"); exit(EXIT_FAILURE); };
char pathbuf[512]; /// or perhaps PATH_MAX instead of 512
snprintf(pathbuf, sizeof(pathbuf),
"%s/.textsfiless/test.txt", homedir);
FILE *file_pointer = fopen(pathbuf, "r");
if (!file_pointer) { perror(pathbuf); exit(EXIT_FAILURE); };
and so on.
Notice that you should check against failures most C standard library (& POSIX) functions. The perror(3) function is useful to report errors to the user on stderr.
(pedantically, we should even test that snprintf(3) returns a length below sizeof(pathbuf) or use and test against failure asprintf(3) instead; I leave that test as an exercise to the reader)
More generally, read the documentation of every external function that you are using.
Beware of undefined behavior (your code is probably having some, e.g. fprintf to a NULL stream). Compile your code with all warnings & debug info (so gcc -Wall -g) and use the gdb debugger. Read What every C programmer should know about undefined behavior.
BTW, look into strace(1) and try it on your original (faulty) program. You'll learn a lot about the system calls used in it.
Most likely your call to fopen() fails. You don't have any checking in your program to ensure fopen even worked. It may not have, and this could be due to a variety of things, like you spelling the path wrong, wrong file or process permissions, etc.
To see what really happened, you should check fopen's return value:
#include <stdio.h>
int main(void){
FILE *file_pointer;
file_pointer=fopen("~/.textsfiless/test.txt","w+");
if (file_pointer == NULL) {
printf("Opening the file failed.");
return EXIT_FAILURE;
}
setbuf(file_pointer,NULL);
fprintf(file_pointer,"Testing...\n");
fclose(file_pointer);
return EXIT_SUCCESS;
}
Edit: Since your comment, you getting the path wrong is most certainly what happened. If you're executing your program from the current directory, and your file is in a folder called "textfiless" in your current directory and your file is called "test.txt", then you'd call fopen like this:
file_pointer=fopen("/textsfiless/test.txt","w+");
Related
I'm writing a C program and I would like to be able to store data inside the executable file.
I tried making a function to write a single byte at the end of the file but it looks like it can't open the file because it reaches the printf and then gives "segmentation fault".
void writeByte(char c){
FILE *f;
f = fopen("game","wb");
if(f == 0)
printf("\nFile not found\n");
fseek(f,-1,SEEK_END);
fwrite(&c,1,sizeof(char),f);
fclose(f);
}
The file is in the correct directory and the name is correct. When I try to read the last byte instead of writing it works without problems.
Edit: I know I should abort the program instead of trying to write anyway but my main problem is that the program can't open the file despite being in the same directory.
There are several unrelated problems in your code and the problem you're trying to solve.
First you lack proper error handling. If any function that can fail (like e.g. fopen) fails, you should act accordingly. If, for example you did
#include <error.h>
#include <errno.h>
...
f = fopen("game","wb");
if ( f == NULL ) {
error(1,errno,"File could not be opened");
}
...
You would have recieved an useful error message like
./game: File could not be opened: Text file busy
You printed a message, which is not even correct (the file not beeing able to be opened is somthing different, than not beeing found) and continued the program which resulted in a segmentation fault because you dereferenced the NULL pointer stored in f after the failure of fopen.
Second As the message tells us (at least on my linux machine), the file is busy. That means, that my operating system does not allow me to open the executable I'm running in write mode. The answers to this question lists numerous source of the explanation of this error message. There might be ways to get around this and open a running executable in write mode, but I doubt this is easy and I doubt that this would solve your problem because:...
Third Executable files are stored in a special binary format (usually ELF on Linux). They are not designed to be manually modified. I don't know what happens if you just append data to it, but you could run into serious problems if your not very careful and know what you're doing.
If you just try to store data, use another plain and fresh file. If you're hoping to append code to an executable, you really should gather some background information about ELF files (e.g. from man elf) before continuing.
I plan to use pandoc to generate the man files from markdown for a very small C program.
I do not want to repeat myself and type the help prompt (command [ -h | --help ]) into the source code of the program.
Question
Q: Could I permanently include man content from a file at compile time of a C program?
OR
Q: Is there a way in C to print the contents of the installed man page to stdout?
[WIP] Solution
Based on #KamilCuk's answer here's what i am doing:
In terminal:
file command.1
# OUTPUT --> command.1: troff or preprocessor input, ASCII text
xxd -i command.1 > command.hex
Then in main.c
#include "command.hex"
printf("%s", command_1);
This is almost exactly what I am looking for except
I need the hexed troff to be parsed before printing. Or parsed before hexing. I am not sure which to do / how to do that.
No, I do not want to call man and pipe the output.
I would prefer using a library + a macro to generate the hex but I am not sure how it's done.
Clarifications
What I mean by help prompt:
The output of git --help which prints to stdout
NOT the output of git --help branch which opens the man for git-branch
However, please do share the latter too. It isn't what I want: my manual is very short; but I would be glad to learn an alternative if not the exact one I seek.
Considerations I have noted:
man pages are not always installed to the same location
man pages may not be installed in some systems; or there may be no man program
Could I permanently include man content from a file at compile time?
You can include any content of any file at compile time. The simplest is use xxd -i and compile the output.
Is there a way in C to print the contents of the installed man page?
You can troff output from man -k
You can get output from man by replacing pager, along MANPAGER=cat man.
In C: setenv("MANPAGER", "cat"); execp("man", (char*[]){"man", "something", 0}); or just system("MANPAGER=cat man some_command").
man pages are not always installed to the same location
And system administractors can use /etc/man_db.conf to configure the behavior of man command.
man pages may not be installed in some systems; or there may be no man program
So it seems users of such systems do not care about man pages, so there's no point in supporting such cases.
I believe your intention is to render a man page from your program, where you have a static troff input saved and want to use man to display it. You could save the input to a file, save it and pass the filename to man - man will parse troff and render it. Or you could the usual pipe()+fork()+exec() and from one process pass troff data to stdin to man - - the - will make man read troff input from stdin.
Is there a way in C to print the contents of the installed man page to stdout?
You could invoke the mancommand by using a pipe stream . Function popen is what you are looking for. More info here.
This is an fgets() solution, though you might want to be careful, in case you want to read more characters.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp = NULL;
char buffer[1000];
fp = popen("man man","r");
if (fp == NULL)
{
/* error running the command */
exit(EXIT_FAILURE);
}
while (fgets(buffer,sizeof(buffer),fp))
{
puts(buffer);
}
fclose(fp);
return 0;
}
getline() solution, in case you don't know how many bytes you are going to read.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp = NULL;
char *buffer = NULL;
size_t len = 0U;
ssize_t nread = 0;
fp = popen("man man","r");
if (fp == NULL)
{
/* error running the command */
exit(EXIT_FAILURE);
}
/* getline will set errno uppon failure, you might want to check that too */
while ((nread = getline(&buffer,&len,fp)) != -1)
{
buffer[nread] = 0; /* NULL terminate your buffer */
puts(buffer);
}
free(buffer);
fclose(fp);
return 0;
}
More on getline() here.
The man program is written in C and is open source. It is more complex than you believe, since it deals with terminal (and their width). See also termios(3) and tty(4). Be aware of ANSI escape codes and the ncurses library. Take into account that in 2021 UTF-8 is used everywhere, and that some man pages could contain § or ° characters. Be also aware of internationalization and localization issues, see locale(7). In France, a lot of Linux systems are installed with man pages in French.
So you could get the source code of the man-db package, study it, and incorporate it inside your program.
My opinion is that it would be silly to do so.
You could instead read Advanced Linux Programming, study various syscalls(2), and use fork(2), execve(2), waitpid(2) to run the existing and installed /usr/bin/man program (whose existence could be tested with test(1) or access(2) or stat(2) in C code; but if it does not exist your execve(2) will fail...)
Regarding display of --help, you could use (if so allowed) GNU libc program argument parsing facilities, and take inspiration from the source code of existing free software programs, such as GNU coreutils.
Of course, your build infrastructure (e.g. your Makefile if you build your software with GNU make) could run programs to share data and textual descriptions. You could (if so allowed) use open source tools to generate some C code (e.g. #included stuff) at build time, such as GNU m4, GNU gawk, GPP, etc..
Take also inspiration from the source code of git. It is open source (and useful for you): you can download its source code and study it.
These terms may not be 100% accurate, but I'm using the GCC compiler and POSIX library. I have C code compiled with the SQLite amalgamation file to a single executable.
In the user interface that exchanges JSON messages with the C program, I'd like to make it possible for users to copy the SQLite database files they create through the C program, and copy a full directory/folder.
Thus far, I've been able to rename and move files and folders programmatically.
I've read many questions and answers here, at Microsoft's C runtime library, and other places but I must be missing the fundamental points. I'm using regular old C, not C++ or C#.
My question is are there POSIX functions similar to rename(), _mkdir(), rmdir(), remove(), _stat(), that allow for programmatic copying of files and folders in Windows and Linux?
If not, can one just make a new folder and/or file and fread/fwrite the bytes from the original file to the new file?
I am primarily concerned with copying SQLite database files, although I wouldn't mind knowing the answer in general also.
Is this answer an adequate method?
Is the system() function a poor method? It seems to work quite well. However, it took awhile to figure out how to stop the messages, such as "copied 2 files" from being sent to stdout and shutting down the requesting application since it's not well-formed JSON. This answer explains how and has a link to Microsoft "Using command redirection operators". A /q in xcopy may or may not be necessary also, but certainly didn't do the job alone.
Thank you very much for any direction you may be able to provide.
The question that someone suggested as an answer and placed the little submission box on this question is one that I had already linked to in my question. I don't mean to be rude but, if it had answered my question, I would not have written this one. Thank you whoever you are for taking the time to respond, I appreciate it.
I don't see how that would be a better option than using system() because with the right parameters all the sub-directories and files of a single parent folder can be copied in one statement without having to iterate through all of them manually. Is there any reason why it would not be better to use system() apart from the fact that code will need to be different for each OS?
Handling errors are a bit different because system() doesn't return an errno but an exit code; however, the errors can be redirected from stderr to a file and pulled from there, when necessary
rename(): posix
_mkdir(): not posix. You want mkdir which is. mkdir takes two arguments, the second of which should usually be 077.
rmdir(): posix
remove(): posix
_stat(): not posix, you want stat() which is.
_stat and _mkdir are called as such on the Windows C library because they're not quite compatible with the modern Unix calls. _mkdir is missing an argument, and _stat looks like a very old version of the Unix call. You'll have trouble on Windows with files larger than 2GB.
You could do:
#ifdef _WIN32
int mkdir(const char *path, int mode) { return _mkdir(path); } /* In the original C we could have #defined this but that doesn't work anymore */
#define stat _stat64
#endif
but if you do so, test it like crazy.
In the end, you're going to be copying stuff with stdio; this loop works. (beware the linked answer; it has bugs that'll bite ya.)
int copyfile(const char *src, const char *dst)
{
const int bufsz = 65536;
char *buf = malloc(bufsz);
if (!buf) return -1; /* like mkdir, rmdir, return 0 for success, -1 for failure */
FILE *hin = fopen(src, "rb");
if (!hin) { free(buf); return -1; }
FILE *hout = fopen(dst, "wb");
if (!hout) { free(buf); fclose(hin); return -1; }
size_t buflen;
while ((buflen = fread(buf, 1, bufsz)) > 0) {
if (buflen != fwrite(buf, 1, buflen)) {
fclose(hout);
fclose(hin);
free(buf);
return -1; /* IO error writing data */
}
}
free(buf);
int r = ferror(hin) ? -1 : 0; /* check if fread had indicated IO error on input */
fclose(hin);
return r | (fclose(hout) ? -1 : 0); /* final case: check if IO error flushing buffer -- don't omit this it really can happen; calling `fflush()` won't help. */
}
It looks like this question is pretty simple but I can't find the clear solution for copying files in C without platform dependency.
I used a system() call in my open source project for creating a directory, copying files and run external programs. It works very well in Mac OS X and other Unix-ish systems, but it fails on Windows. The problem was:
system( "cp a.txt destination/b.txt" );
Windows uses backslashes for path separator. (vs slashes in Unix-ish)
Windows uses 'copy' for the internal copy command. (vs cp in Unix-ish)
How can I write a copying code without dependency?
( Actually, I wrote macros to solve this problems, but it's not cool. http://code.google.com/p/npk/source/browse/trunk/npk/cli/tests/testutil.h, L22-56 )
The system() function is a lot more trouble than it's worth; it invokes the shell in a seperate proccess, and should usually be avoided.
Instead fopen() a.txt and dest/b.text, and use getc()/putc() to do the copying (because the standard library is more likely to do page-aligned buffering than you)
FILE *src = fopen("a.txt", "rb");
FILE *dst = fopen("dest/b.txt", "wb");
int i;
for (i = getc(src); i != EOF; i = getc(src))
{
putc(i, dst);
}
fclose(dst);
fclose(src);
You need to use the C standard library functions in stdio.h.
In particular, fopen, fread, fwrite, and fclose will be sufficient.
Be sure to include the b ("binary") option in the flags to fopen.
[edit]
Unfortunately, the file names themselves (forward-slashes vs. back-slashes) are still platform dependent. So you will need some sort of #ifdef or similar to deal with that.
Or you can use a cross-platform toolkit.
Use the standard C library stdio.h. First open input file for reading using fopen(inputFilename, "rb") and open output file for writing using fopen(outputFilename, "wb"), copy the content using fread and fwrire. Then close both files using fclose.
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.