I have a program that copies a source file to a destination file.
In the event that only 1 or neither of these files are provided by the user, I'd like to use stdin or stdout.
For example: The source file name is not provided in command line arguments, but the destination file is. The program should read input from stdin and write to the given destination file.
I know of freopen() but I don't know how I should use it in this case.
Below is my boilerplate code for how I think the logic is done, but I can't find any examples of this that are helpful for me to learn. Any insight is appreciated.
char *src = NULL; (unless user provides in preceding code not shown)
char *dest = NULL; (^^)
// open files based on availability
// src and dest not provided, read from stdin and write to stdout
if (src == NULL && dest == NULL) {
FILE *in = freopen(src, "r", stdin);
FILE *out = freopen(dest, "w", stdout);
// TODO
fclose(in);
fclose(out);
// src not provided, read from stdin
} else if (src == NULL) {
FILE *in = freopen(src, "r", stdin);
// TODO
fclose(in);
// dest not provided, write result to stdout
} else {
FILE *out = freopen(dest, "w", stdout);
// TODO
fclose(out);
}
I tend to avoid freopen and use a different approach. I define two FILE * variables and either use fopen() if the filename is provided or set them to stdin or stdout as appropriate if not:
#include <stdio.h>
/* copying files: 0, 1 or 2 arguments */
int main(int argc, char *argv[]) {
FILE *in = stdin;
FILE *out = stdout;
char *srcfile = NULL;
char *destfile = NULL;
int c;
if (argc > 1) {
srcfile = argv[1];
if (argc > 2)
destfile = argv[2];
}
if (srcfile && strcmp(srcfile, "-")) {
if ((in = fopen(srcfile, "r")) == NULL) {
perror(srcfile);
return 1;
}
}
if (destfile && strcmp(destfile, "-")) {
if ((out = fopen(destfile, "w")) == NULL) {
perror(destfile);
return 1;
}
}
while ((c = getc(in)) != EOF) {
putc(c, out);
}
if (in != stdin)
fclose(in);
if (out != stdout)
fclose(out);
return 0;
}
Just if statements that's it. Verify if the src is NULL, if so fopen(stdin, "r") but don't close it after or it will cause undefined behaviour (I'm talking about stdin).
For stdout you don't even have to open it so you can write in it just like that. Example:
int is_in = src == NULL;
FILE *in = fopen(is_in ? stdin : src, "r")
if (!is_in)
fclose(in);
Related
I have a text file, "input", in which some lines contain the character '$'. I want to copy this file into a new text file, "output", but with all the lines truncated after (and including) the '$' character (if present).
I have tried the following:
while (fgets(line, LINE_LENGTH, input) != NULL)
{
strcpy(tmp_line, line);
cmt_ptr = strchr(tmp_line, '$');
if (cmt_ptr != NULL)
{
*cmt_ptr = '\n';
}
fputs(tmp_line, output);
}
This compiles, but all the text after '$' in each line gets copied into a new line.
I then tried this:
while (fgets(line, LINE_LENGTH, input) != NULL)
{
strcpy(tmp_line, line);
cmt_ptr = strchr(tmp_line, '$');
if (cmt_ptr != NULL)
{
strtok(tmp_line, '$');
}
fputs(tmp_line, output);
}
but I get an error message saying "Access violation reading location".
Can someone please advise me on how to correct the code?
Below code is insufficient as only the $ is substituted with a '\n'. To shorten the string, set a null character. #Some programmer dude
if (cmt_ptr != NULL)
{
*cmt_ptr = '\n';
cmt_ptr[1] = '\0'; // Add
}
Alternative approach: Use different ways to print when a $ is found. No tmp_line needed.
while (fgets(line, LINE_LENGTH, input) != NULL) {
char *cmt = strchr(line, '$');
if (cmt) {
int length = cmt - line;
printf("%.*s\n", length, line); // Print limited character array.
} else {
fputs(line, output);
}
}
Using fgets is over-complicating the issue, since there's no need to read full lines. Just read one character at a atime. eg:
#include <stdlib.h>
#include <stdio.h>
FILE * xfopen(const char *path, const char *mode);
int
main(int argc, char **argv)
{
FILE *input = argc > 1 ? xfopen(argv[1], "r") : stdin;
FILE *output = argc > 2 ? xfopen(argv[2], "w") : stdout;
enum { print, noprint } state = print;
int c;
while( (c = getc(input)) != EOF ){
switch( c ){
case '$':
state = noprint;
break;
case '\n':
state = print;
}
if( state == print ){
putc(c, output);
}
}
return 0;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ){
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
I have a practice question in C that asks me to create a function that only copies part of a file to another one. The restrictions are that lines with greater than maxlen characters are not copied to the new file, and the newline character does not count, so it should not be copied. Part of my function says that if a file does not exist, it should explicitly say so, and I am getting those error messages when I run that code; however, I can see that the files are created are inside my folder. Whenever I open the file I'm trying to read after running the code, I get this:
./Debug/main.c.o ./Debug/dot.c.o ./Debug/dataBase.c.o ./Debug/intPrompt.c.o ./Debug/numWords.c.o ./Debug/LinkedList.c.o
Below is my code :
void shortLines(char* f1, char* f2, int maxlen) {
FILE* fp = fopen(f1, "r");
FILE* fp2 = fopen(f2, "w");
if (fp == NULL) {
perror("File does not exist");
}
if (fp2 == NULL) {
perror("File does not exist");
}
char singleLine[maxlen];
char check;
size_t len;
do {
fgets(singleLine, maxlen, fp);
len = strlen(singleLine);
if (singleLine[len-1] == '\n') {
singleLine[len-1] = '\0';
}
fprintf(fp2, "%s", singleLine);
} while ((check=getc(fp) != EOF));
}
int main(int argc, char **argv) {
shortLines("Andrew.txt", "Andrew2.txt", 25);
return 0;
}
I just made new files called Andrew.txt and Andrew2.txt and these ones seem to be working for some strange reason. Regardless, there were a few problems in the code. First of all, after fgets is called, I needed to make sure to flush out the remaining characters in the line. I do this with a while loop and fgetc. If I reach an EOF, then I continue, and then fgets also returns an EOF, thus breaking the outer loop.
void shortLines(char* f1, char* f2, int maxlen) {
FILE* fp = fopen(f1, "r");
FILE* fp2 = fopen(f2, "w");
if (fp == NULL) {
perror(f1);
}
if (fp2 == NULL) {
perror(f2);
}
char line[maxlen+1];
size_t len;
char c;
while (fgets(line, maxlen+1, fp) != NULL) {
len = strlen(line);
if (len == maxlen) {
while ((c=fgetc(fp)) != '\n') {
if (feof(fp)) {
break;
}
}
continue;
}
if (line[len-1] == '\n') {
line[len-1] = '\0';
}
fprintf(fp2, "%s\n", line);
}
}
I am trying to read strings from a file. File contains below text:
<1a>This is line 1<1a>
<2f>This is line 2<2f>
<3c>This is line 3<3c>
In my program I get this value 1a or 2f. Based on this, I need to extract that particular line like for 2f, I only need to read This is line 2 and save it in a buffer.
I have been able to read write using fopen fput but dont know how to read this.Can anyone please point me into some right direction which shows how to read this. Any demo code. Thanks.
This should do the trick:
#include <stdio.h>
#include <string.h>
int extract_line (char* line, char* buffer, char* ctag)
{
char line_buffer[255] = {0};
char* tagStart;
char* tagEnd;
if( strlen(line) < (sizeof(line_buffer)/sizeof(char)) )
{
strcpy(line_buffer,line);
}
else
{
printf("Line size is too big.\n");
return 1;
}
tagStart = strstr(line_buffer,ctag);
if(tagStart != NULL)
{
tagEnd = strstr(tagStart+1,ctag);
if(tagEnd != NULL && (tagEnd > (tagStart + strlen(ctag))))
{
*(tagEnd) = '\0';
strcpy(buffer, tagStart + strlen(ctag));
printf("%s\n",buffer);
}
else
{
printf("Could not find closing tag.\n");
return 1;
}
}
return 0;
}
int main ()
{
char buffer[255] = {0};
char line_buffer[255] = {0};
char tag[] = "<2a>";
char* cptr;
FILE* data;
data = fopen ("file.txt", "r");
if (data == NULL)
{
printf("\n Failed to open file!");
}
else {
while(( fgets( line_buffer, 255, data )) != NULL)
{
cptr = strstr(line_buffer,tag);
if(cptr == NULL)
{
continue;
}
if(!extract_line(line_buffer,buffer,tag))
{
//Do the rest of processing
puts(buffer);
strcpy(buffer,"");
}
}
fclose (data);
}
return 0;
}
Basicly, what you need to do is get the tag field and use it as a delimeter to exctract the token. Just get the line tag and then use it to exctract the data.
char* returnSpecificString(char* valueBetweenQuotes)
{
FILE* file= fopen("test.txt", "r"); // Open in reading only mode
char *line= malloc(sizeof(char[150]));
if (NULL == line) // Checks if enough memory
fprintf(stderr, "Not enough memory. \n");
else
{
while(fgets(line, sizeof(line), file)) //Iterate until end of file
{
if (strstr(line, valueBetweenQuotes) != NULL) // Meaning it's the line we want
return functionToExtractTextBetweenQuote();
}
}
return line;
}
As for the functionToExtractTextBetweenQuote() I advise you look functions like strtok() strchr()or sprintf() which will help you extract what you want from a string. I know this is unsufficiant but I ain't got the time to finish it now so I hope it will help you.
I am trying to read from files and write to a temp file. However, I am stuck in an infinite loop right now. The function below is called multiple times by a recursive function that goes through directories to read files.
My approach is that I would read each word from one file, then those words to another file.
The function I have works fine if I just print out each word. It prints out each word in each file in all directories. However, when I try to start writing to a temp file (the code commented out), I am stuck in the while loop.
On the other hand, if I just call the function once in a test program where I just read from one file in the current directory, and write to a temp file, it's fine.
This is what I have (fileName when passed in is actually the absolute path, and I do ../tmp so it does not get caught in the recursion function):
void fileReadWrite(char *pattern, char *before, char *replace, char *fileName) {
FILE *file = fopen(fileName, "r");
if (file != NULL) {
int ch, word = 0;
while ((ch = fgetc(file)) != EOF) {
if (isspace(ch) || ispunct(ch)) {
if (word) {
word = 0;
putchar('\n');
}
}
else {
word = 1;
putchar(ch);
/*
FILE *f = fopen("../tmp", "wb"); // create and write
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "Some text"); // Or fprintf(f, ch);
fclose(f);
*/
}
}
fclose(file);
}
}
There's nothing in your code that suggests an infinite loop. However, if fileName is very large, you could be opening and closing "..\tmp" millions of times. As Joachim Pileborg points out in the comments, you should open that file just once at the beginning of your function, and close it again at the end.
If you want to convince yourself that you are not in an infinite loop, print out the value of ch on each iteration.
Okay so I did this and it worked. But I don't understand why though. Can someone explain it please?
void fileReadWrite(char *pattern, char *before, char *replace, char *fileName) {
FILE *file = fopen(fileName, "r");
FILE *f = fopen("../tmp", "wb"); // MOVE HERE
if (file != NULL) {
int ch, word = 0;
while ((ch = fgetc(file)) != EOF) {
if (isspace(ch) || ispunct(ch)) {
if (word) {
word = 0;
putchar('\n');
}
}
else {
word = 1;
putchar(ch);
/*
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "Some text"); // Or fprintf(f, ch);
*/
}
}
fclose(file);
fclose(f); // MOVE HERE
}
}
I am trying to read two files in my program I wrote earlier, but it always fails.
char line[BUFSIZ];
FILE *fp2=freopen("source.dat","r");
if(fp2==NULL)
printf("Problm opening: source.dat");
FILE *fp3=freopen("result.dat", "r");
if(fp3==NULL)
printf("Problm opening: result.dat");
char line2[BUFSIZ];
int len;
while( (fgets(line2, BUFSIZ, fp2) != NULL) && (fgets(line, BUFSIZ, fp3) != NULL)) {
len=strlen(line);
if( line[len - 1] == '\n' ) line[len-1] = '\0'; len=strlen(line2);
if( line2[len - 1] == '\n' ) line2[len-1] = '\0';
rename(line, line2);
}
I'm not sure why, I know my program writes the two files I want to open. It just doesn't get past the while loop.
freopen takes 3 arguments viz., filename, mode and FILE Stream object. Hence, to reopen a file, it should already be open. If we invoke a freopen as the first call, the runtime may throw an exception of uninitialized access.
Modifying the code as below
fp2 = fopen("source.dat", "r");
fp3 = fopen("result.dat", "r");
I am able to run your code without any problem and control continues beyond the while loop. The files stored in first file are renamed to the names stored in second file, which I presume is the objective of your program.
This code works for me and apparently should do the same yours does, except where noted.
The first note apparently was the right one :-)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char line[2][BUFSIZ];
FILE *fp[2];
char *file[2] = { "source.dat", "result.dat" };
int f, finished = 0;
// Any pointers to source and result must be flushed and closed at this point,
// i.e. if this same program has created the files, it must now close them.
for (f = 0; f < 2; f++)
{
if (NULL == (fp[f] = fopen(file[f],"r")))
{
fprintf(stderr, "Error opening %s\n", file[f]);
exit(-1);
}
}
while(!finished)
{
int len;
for (f = 0; f < 2 && (!finished); f++)
{
if (NULL == fgets(line[f], BUFSIZ, fp[f]))
{
fprintf(stderr, "NULL on %s\n", file[f]);
finished = 1;
break;
}
if (feof(fp[f]))
{
fprintf(stderr, "end of %s\n", file[f]);
finished = 1;
break;
}
len = strlen(line[f]);
// if one of the file contains an empty line, program might crash
if (0 == len)
{
fprintf(stderr, "empty line in %s\n", file[f]);
finished = 1;
break;
}
if ('\n' == line[f][len-1])
line[f][len-1] = 0x0;
}
if (finished)
break;
fprintf(stderr, "Rename(%s, %s)\n", line[0], line[1]);
// rename(line, line2);
}
for (f = 0; f < 2; f++)
fclose(fp[f]);
return 0;
}