I'm trying to write a C program, that make user able to write stuff in a file. My Problem is that after making and running the program the file stay empty ?? any idea how can I solve this.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
// the user should give a file to write the file
int main (int argc , char**argv)
{
int fd; // file descriptor
char ret; // the character
int offset;
if(argc != 2) {
printf("You have to give the name or the path of the file to work with \n");
printf("Exiting the program \n")
return -1;
}
fd = open (argv[1], O_WRONLY/*write*/|O_CREAT/*create if not found */, S_IRUSR|S_IWUSR/*user can read and write*/);
if (fd == -1) {
printf("can'T open the file ");
return -1;
}
printf("At wich position you want to start ");
scanf("%d",&offset);
lseek(fd,offset,SEEK_SET);
while(1) {
ret = getchar();
if(ret == '1') {
printf("closing the file");
close (fd);
return 1;
}
else
write (fd,red, sizeof(char));
}
return 0;
}
thanks in advance for you help.
I have made some changes,this should work:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main (int argc , char**argv)
{
int fd; // file descriptor
char ret; // the character
int offset;
if(argc != 2){
printf("You have to give the name or the path of the file to work with \n");
printf("Exiting the program \n"); **//There was ';' missing here**
return -1;
}
fd = open (argv[1], O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR);
if (fd == -1) {
printf("can'T open the file ");
return -1;
}
printf("At wich position you want to start ");
scanf("%d",&offset);
lseek(fd,offset,SEEK_SET);
while(1){
ret = getchar();
if(ret == '1'){
printf("closing the file");
close (fd);
return 1;
}
else
write (fd,&ret, sizeof(char)); **//red has been changed to &ret**
}
return 0;
}
One error I can notice, the call of write function:
write (fd,red, sizeof(char));
should be:
write (fd, &red, sizeof(char));
You forgot & before red, write need address.
syntax of write: int write( int handle, void *buffer, int nbyte );
This will cause an undefined behavior in your code at run time
Edit: in write function you are using red that is not defined, I think it should be ret variable in your code. correct it as write (fd, &ret, sizeof(char));
second, you forgot ; after printf("Exiting the program \n") in if, but I also think its mistake while posting question as you says you are getting run time error.
side note: If you are using gcc compiler then you can use gcc -Wall -pedantic to generate warnings
It should be:
write (fd,&ret, sizeof(char));
write takes the pointer to the memory position, and since ret is a single char, you need to pass a pointer to it.
Related
Is there a way to redirect output of a command line which returns integer as an output to a variable in C?
for example, if the command is "cmd", then is there a way to redirect its output (an integer) and store it in variable in C?
I tried using popen and fgets but it seems to be working only with characters. Any suggestions?
It works perfectly fine with popen and fgets:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
const char *cmd = argc > 1 ? argv[1] : "echo 42";
char buf[32];
FILE *fp = popen(cmd, "r");
if( fp == NULL ){
perror("popen");
return 1;
}
if( fgets(buf, sizeof buf, fp) == buf ){
int v = strtol(buf, NULL, 10);
printf("read: %d\n", v);
}
return 0;
}
If you want to convert a character string from the standard input, you could use fgets and then use atoi to convert the input to an integer.
If you want to convert the output of a command, let's say ls and store the output of the command to a variable, you could learn about fork, dup2, pipe, and exec function family.
More about this topic on this tutorial : Capture the output of a child in C. This tutorial also provide an example with popen if you want to keep things "high level".
Here is an even simpler example using popen() and fscanf():
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE *fp = popen("date '+%s'", "r");
long seconds;
if (fp == NULL) {
fprintf(stderr, "popen failed: %s\n", strerror(errno));
return 1;
}
if (fscanf(fp, "%ld", &seconds) == 1) {
printf("epoch seconds: %ld\n", seconds);
pclose(fp);
return 0;
} else {
fprintf(stderr, "invalid program output\n");
pclose(fp);
return 1;
}
}
So im trying to redirect the I/O to read command from file then when user runs the output command it will print the compiled command to output file.
For example on the terminal:
./run 2 < test.txt // This would take file using dup and take the input
Then when you want to output the compile:
./run 1 > output.txt // and it would put into an output file
So far i know how to output to a file but my problem is with the input. how do i get the command from the file using the dup2() function? I tried researching this but no luck.
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
char inputForOutput[100];
void functionOutput(int argc, char **argv){
int ofd; //Init of file desc.
ofd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY);
dup2(ofd, 1);//Duplicates to stdout
system("ls");//Copies commnd given to output_file
}
//Function is called when argument number is == 1
void functionInput(int argc, char **argv){
FILE *ifd;
printf("\n %s \n ", argv[2]);
ifd = fopen(argv[2] , "r");
if (ifd == NULL){
perror("No file found");
exit(1);
}
fscanf(ifd,"%s",inputForOutput);
printf("\n**%s**\n",inputForOutput);
}
int main(int argc, char **argv)
{
int output;
int input;
output = strcmp("1", argv[1]);
input = strcmp("2" ,argv[1]);
if (output == 0 ) { //Fail safe for number of arguments
functionOutput(argc, argv);
}
else if ( input == 0){
functionInput(argc, argv);
}
else{
fprintf(stderr, "How to use: %s function output_file\n", argv[0]); // FAIL SAFE IF INPUT DOES NOT MATCH BOTH FUNCTIONS
}
return 0;
}
To redirect input and output, use this format
myprogram > out.txt < in.txt //read from in.txt, write to out.txt
myprogram < in.txt > out.txt //read from in.txt, write to out.txt
myprogram < in.txt //redirect stdin only
myprogram > out.txt //redirect stdout only
myprogram //no redirection
...
This should work with any program. Example:
int main(void)
{
char buf[1000];
if(fgets(buf, sizeof(buf), stdin))
printf("write: %s\n", buf);
return 0;
}
To redirect stdin/stdout in the program, use the standard method
freopen("output.txt", "w", stdout);
printf("Testing...");
fclose(stdout);
freopen("input.txt", "r", stdin);
char buf[100];
fgets(buf, sizeof(buf), stdin);
fclose(stdin);
Alternatively, set FILE *fin = stdin; FILE* fout = stdout; to redirect the opposite way.
Next, to write a program using argv elements, always test argc first. The code below shows an example.
#include <stdio.h>
#include <string.h>
int redirect(int argc, char **argv, int *index)
{
//no more redirection!
if(*index >= argc)
return 1;
//not enough parameters
if(*index + 1 >= argc)
{
printf("wrong usage\n");
return 0;
}
if(strcmp(argv[*index], "<") == 0)
{
*index++; //next parameter is to redirect input
if(!freopen(argv[*index], "r", stdin))
printf("error, redirect input failed");
}
else if(strcmp(argv[*index], ">") == 0)
{
*index++; //next parameter is to redirect output
if(!freopen(argv[*index], "w", stdout))
printf("error, redirect output failed");
}
else
{
printf("wrong usage\n");
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
int index = 1;
if(!redirect(argc, argv, &index))
return 1;
if(!redirect(argc, argv, &index))
return 1;
//read
char buf[1000];
if(fgets(buf, sizeof(buf), stdin))
{
//write
printf("write: %s\n", buf);
}
fclose(stdin);
fclose(stdout);
return 0;
}
With functionOutput() you have a good first attempt at capturing the output of a system command to a file. Actually, that is the function called when the first argument is 1, so you might want to update your comment. Also, you're creating a file with the name stored in argv[1], which we already know is 1 so it's probably not doing what you expect, and you probably want:
ofd = open(argv[2], O_CREAT|O_TRUNC|O_WRONLY);
With functionInput() you're reading the first non-whitespace entry from the file. If you're telling it to read the file which you output using the functionOutput() function, that is likely to be (some of) the name of the first file which was listed by ls.
I'm finding it unclear what you're wanting to do which isn't that. If you want to find out what the command was which you ran to generate the output, that information is not available from the file itself, because you didn't write it there. If that's what you want, you may want to consider writing the command as the first line of the file, followed by the output. Then when you read it, you can assume that the first line is the command run, followed by the output of that command.
If I understand your question, and you want to run your program in essentially two different modes, (1) you want to take input if there is input to be taken on stdin; and (2) if there is no input waiting, you want to do an output, then select/pselect or poll are what you are looking for.
For example select allows you to check whether there is input ready to be read on a file descriptor (or set of descriptors) and it will return the number of descriptors with input waiting (or -1 and set errno on error). You could simply use the STDIN_FILENO (a/k/a fd 0) to check if there is input on stdin, e.g.
#include <stdio.h>
#include <unistd.h> /* for STDIN_FILENO */
#include <sys/select.h> /* for pselect */
int input (int filedes)
{
fd_set set;
/* declare/initialize zero timeout */
struct timespec timeout = { .tv_sec = 0 };
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* check whether input is ready on filedes */
return pselect (filedes + 1, &set, NULL, NULL, &timeout, NULL);
}
int main (void)
{
if (input (STDIN_FILENO))
puts ("doing input routine");
else
puts ("doing output routine");
return 0;
}
(note: from the man page "select() uses a timeout that is a struct timeval (with seconds and microseconds), while pselect() uses a struct timespec (with seconds and nanoseconds).")
Example Use/Output
$ ./bin/select_peekstdin < file
doing input routine
$ ./bin/select_peekstdin
doing output routine
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
My professor asked me to write a simple C program, then asked me to convert using Unix system calls. I have try changing the values around but nothing is working.
Requirement:
Write a new C program newcat, which performs exactly as oldcat, but uses the following UNIX system calls for I/O.
int read(int fd, char *buf, int n);
int write(int fd, char *buf, int n);
int open(char *name, int accessmode, int permission);
int close(int fd);
To open a file for read, you can use the symbolic constant O_RDONLY defined in fcntl.h header file to specify the accessmode. Simply pass 0 for permission. That is, the code will appear as follows:
fd = open (filename, O_RDONLY, 0);
You will need the following header files: sys/types.h, unistd.h and fcntl.h
#include <stdio.h>
/* oldcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(FILE *, FILE *); /* prototype for function */
int fd = open(*fp, O_RDONLy,0)
char *prog = argv[0]; /* program name for errors */
if (argc == 1) /* no args; copy standard input */
filecopy(0, 1);
else
while (--argc > 0)
if (fd == -1) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(fp, 1);
fclose(fp);
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(FILE *ifp, FILE *ofp)
{
int c;
while ((c = getc(ifp)) != EOF)
putc(c, ofp);
}
Is this the write idea? It still won't compile:
#include <stdio.h>
/* oldcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(int ifp, int ifo);
int fd = open(*File,O_RDONLY,0); //is this correct?
char *prog = argv[0];
if (argc == 1) /* no args; copy standard input */
filecopy(0, 1); //is this correct?
else
while (--argc > 0)
if ((fd == -1) //is this correct?{
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(*FILE, 1);//is this correct?
close(*FILE);//is this correct?
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(FILE *ifp, FILE *ofp)//NO CLUE HOW THIS SHOULD BE
{
int c;
while (c = read(fd ,&something,1)//What is &ch/&something?
putc(c, ofp);
}
Assuming your oldcat uses the C standard library calls (like fopen), it's a simple matter of mapping those to the UNIX calls.
At a high level:
fopen -> open
fread -> read
fwrite -> write
fclose -> close
For example, when opening your input file with:
FILE *fIn = fopen ("jargon.txt", "r");
you could instead use:
int inFd = open ("jargon.txt", O_RDONLY, 0);
The other calls are very similar, with similar functionality at the C standard library and UNIX system call levels. Details on those calls can usually be obtained from the manpages by entering something like man 2 open into your shell, or by plugging man open into your favourite search engine.
The only "tricky" mapping is if you've used getchar/putchar-style calls to do the actual reading and writing but that too becomes easy when you realise that (for example) reading a character is functionally identical to reading a block of size one:
int c = getc (fIn);
or:
char c;
int numread = read (inFd, &c, 1);
For your added question:
So to open a file: if (fd = open (fp, O_RDONLY, 0); ) == NULL)
Not quite. The fopen function returns NULL on error because it returns a pointer to a FILE structure.
The lower level calls use file descriptors rather than file handles, the former being a small integer value. So, instead of:
FILE *fp = fopen ("nosuchfile", "r");
if (fp == NULL) doSomethingIntelligent();
you would do something like:
int fd = open ("nosuchfile", O_RDONLY, 0);
if (fd == -1) doSomethingIntelligentUsing (errno);
In terms of what you need to change, the following comes off the top of my head (so may not be totally exhaustive but should be a very good start):
Add the required headers.
Stop using FILE* totally, using int instead.
Translate the fopen/fclose calls to open/close. This includes the function name, different parameters and different return types.
Modify filecopy to use file descriptors rather than file handles.
use 1 instead of stdout when calling filecopy (the latter is a FILE *).
As an example of how to do this, the following program testprog.c will read itself and echo each character to standard output:
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
int main (void) {
int num, ch, inFd;
// Open as read only.
inFd = open ("testprog.c", O_RDONLY, 0);
if (inFd == -1)
printf ("\n**Error %d opening file\n", errno);
// Get and output esach char until EOF/error.
while ((num = read (inFd, &ch, 1) != 0) == 1)
putchar (ch);
// Detect error.
if (num != 0)
printf ("\n**Error %d reading file\n", errno);
// Close file and exit.
close (inFd);
return 0;
}
Please note that documentation of linux sys calls is present in manual called man pages which you can access by using man command in bash shell in a linux system. As UNIX and Linux are quite similar (maybe equivalent) for the syscalls you are interested in you can check the man page for those syscalls in Linux.
All the four read, write, open and close linux syscalls are explained in man pages. You can access the manual page for these syscalls by typing below commands in shell:
man 2 read
man 2 write
man 2 open
man 2 close
These should probably guide you to right direction.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
/* newcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(int ifp, int ofp); /* prototype for function */
int fd;
char *prog = argv[0]; /* program name for errors */
if (argc == 1) /* no args; copy standard input */
filecopy(0,1);
else
while (--argc > 0)
fd = open(*++argv , O_RDONLY,0);
if ( fd == -1) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(fd, 1);
close(fd);
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(int ifp, int ofp)
{
int c;
while (read(ifp,&c,ofp ) != 0)
write(ofp,&c,ofp);
}
I am trying to write a program on how to read a file 10 bytes per time using read, however, I do not know how to go about it. How should I modify this code to read 10bytes per time. Thanks!!!!
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
int main (int argc, char *argv[])
{
printf("I am here1\n");
int fd, readd = 0;
char* buf[1024];
printf("I am here2\n");
fd =open("text.txt", O_RDWR);
if (fd == -1)
{
perror("open failed");
exit(1);
}
else
{
printf("I am here3\n");
if(("text.txt",buf, 1024)<0)
printf("read error\n");
else
{
printf("I am here3\n");
/*******************************
* I suspect this should be the place I make the modification
*******************************/
if(read("text.txt",buf, 1024)<0)
printf("read error\n");
else
{
printf("I am here4\n");
printf("\nN: %c",buf);
if(write(fd,buf,readd) != readd)
printf("write error\n");
}
}
return 0;
}
The final parameter of read() is the maximum size of the data you wish to read so, to try and read ten bytes at a time, you would need:
read (fd, buf, 10)
You'll notice I've also changed the first parameter to the file descriptor rather than the file name string.
Now, you'll probably want that in a loop since you'll want to do something with the data, and you also need to check the return value since it can give you less than what you asked for.
A good example for doing this would be:
int copyTenAtATime (char *infile, char *outfile) {
// Buffer details (size and data).
int sz;
char buff[10];
// Try open input and output.
int ifd = open (infile, O_RDWR);
int ofd = open (outfile, O_WRONLY|O_CREAT);
// Do nothing unless both opened okay.
if ((ifd >= 0) && (ofd >= 0)) {
// Read chunk, stopping on error or end of file.
while ((sz = read (ifd, buff, sizeof (buff))) > 0) {
// Write chunk, flagging error if not all written.
if (write (ofd, buff, sz) != sz) {
sz = -1;
break;
}
}
}
// Finished or errored here, close files that were opened.
if (ifd >= 0) close (ifd);
if (ofd >= 0) close (ofd);
// Return zero if all okay, otherwise error indicator.
return (sz == 0) ? 0 : -1;
}
change the value in read,
read(fd,buf,10);
From man of read
ssize_t read(int fd, void *buf, size_t count);
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
if(read("text.txt",buf, 1024)<0)// this will give you the error.
First argument must be an file descriptor.
I'm trying to get my open function to work with this program, it is reading the input correctly, as I can see if I printf the file name after I type it in, but my open function must be wrong, I can't seem to figure out what is wrong with it and it keeps returning -1 and exiting. I am trying to just open a file called tester.txt and I'm using a virtual machine running ubuntu. Any help is appreciated,thanks everyone.
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
int bytes_read = 1;
int nbytes = 32;
char buffer[32];
char s[] = "name";
printf("Welcome to File Copy by %s!\n", s);
char *inputFile = NULL;
puts("Enter the name of the source file: ");
bytes_read = getline(&inputFile, &nbytes, stdin);
//if fail exit
int inputOpen = open("inputFile", O_RDONLY);
//if fail exit
if (inputOpen == -1){
printf("file not found.\n");
return -1;
}
return 0;
}
No matter what is entered as the name of the file, you try to open a file called "inputFile". You need to add code to extract the filename from the line entered.
This would be one way:
char *eol;
bytes_read = getline(&inputFile, &nbytes, stdin);
eol = strchr(inputFile, '\n');
if (eol != NULL) // remove end of line
*eol = 0;
int inputOpen = open(inputFile, O_RDONLY);