0

I have created a function that takes as a parameter the name of a source file, the name of a destination file and the beginning and end lines of the source file lines that will be copied to the destination file, like the example below. All I want to do is to input the lines that I want to copy to the other text file like the example below:

The code I show you just "reads" the content of the one text file and "writes" another one. I want to "write" specific lines that the user gives, not the whole text file

Inputs by the user:
Source_file.txt //the file that the destination file will read from
destination_file.txt //the new file that the program has written
2 3 // the lines that it will print to the destination file: 2-3

Source_file.txt:

1
2
3
4
5
6

destination_file.txt

2
3

code:

#include <stdio.h>
#include <stdlib.h>

void cp(char source_file[], char destination_file[], int lines_copy) {
    char ch;
    FILE *source, *destination;

    source = fopen(source_file, "r");
    if (source == NULL) {
        printf("File name not found, make sure the source file exists and is ending at .txt\n");
        exit(EXIT_FAILURE);
    }

    destination = fopen(destination_file, "w");
    if (destination == NULL) {
        fclose(source);
        printf("Press any key to exit...\n");
        exit(EXIT_FAILURE);
    }

    while ((ch = fgetc(source)) != EOF)
        fputc(ch, destination);

    printf("Copied lines %d  from %s to %s \n",
           lines_copy, source_file, destination_file, ".txt");

    fclose(source);
    fclose(destination);
}

int main() {
    char s[20];
    char d[20];
    int lines;

    printf("-Enter the name of the source file ending in .txt\n"
           "-Enter the name of the destination file ending in .txt\n"
           "-Enter the number of lines you want to copy\n\n");

    printf(">subcopy.o ");
    gets(s);
    printf("destination file-> ");
    gets(d);
    printf("Lines: ");
    scanf("%d", &lines);

    cp(s, d, lines);

    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Could you describe the problem you have? – Honza Dejdar Dec 01 '16 at 14:09
  • I am trying to evaluate Linux cp command. The program accepts 3 inputs:1)The file that we will read from 2) the file we will write (the content from the source file) 3)The lines we want to copy from source file to destination file –  Dec 01 '16 at 14:11
  • 1
    And what is your *problem* you have with the code you show? Do you get build errors? Do you get runtime errors or crashes? Unexpected results? ***What is your question?*** Please [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask). – Some programmer dude Dec 01 '16 at 14:14
  • okay. The program works fine, it reads from the one file and creates the whole content. All I want to do is to accept the lines by the user eg 3 5. Meaning it will write the lines 3 to 5 from the source file to the destination file. –  Dec 01 '16 at 14:16
  • The code I show you just "reads" the content of the one text file and "writes" another one. I want to "write" specific lines that the user gives, not the whole text file –  Dec 01 '16 at 14:19
  • 1
    ` char ch; ... while( ( ch = fgetc(source) ) != EOF )` won't work. `fgetc()` returns an `int`, not a `char`, because `EOF` can't be represented as a `char` And for reading lines from a text file, see [the `getline()` function.](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html) – Andrew Henle Dec 01 '16 at 14:29
  • @AndrewHenle if I remove that code it won't write anything –  Dec 01 '16 at 14:32
  • See [Why `gets()` is too dangerous to be used, ever](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) for why you don't use `gets()` and what to use instead. – Jonathan Leffler Dec 01 '16 at 15:15
  • If you need to output a range of line numbers, why not read and write whole lines. It will be a lot easier than keeping tabs on line numbers while reading single characters. – Jonathan Leffler Dec 01 '16 at 15:15

3 Answers3

2

In cp(), in order to select the lines to keep, you have to know their position in the input-file. Thus, you need to count lines.

Using fgets instead of fgetc will allow you to count the lines.


On the other hand, if I wanted to select lines 3 and 7 to 12 in a file, I'd use:

sed -n -e "3p;7,12p" < input.txt > output.txt
1

this is a very simple solution, let's say you know that the maximun length of a line will be 100 characters for simplicity (if a line is longer than 100 characters only the first 100 will be taken)

at the top (outside main) you can write

#ifndef MAX_LINE_SIZE
#define MAX_LINE_SIZE 100
#endif

i know many people don't like this but i think in this case it makes the code more elegant and easier to change if you need to modify the maximum line size.

to print only the wanted lines you can do something like this

char line[MAX_LINE_SIZE];

int count = 0;

while (fgets(line, MAX_LINE_SIZE, source)){
    count++;
    if (3 <= count && count <= 5){
        fputs(line, destination);
    }
}

The while loop will end when EOF is reched because fgets returns NULL.

P.S. there could be some slight errors here and there since i wrote it pretty fast and going by memory but in general it should work.

John Doe
  • 1,613
  • 1
  • 17
  • 35
  • I'd suggest that `MAX_LINE_SIZE` is too short (use 4096 or something similar). Apart from that, you're double-spacing the output (because `fgets()` keeps the newlines, so the output format doesn't need to add a second one. Both are trivia, though. – Jonathan Leffler Dec 01 '16 at 15:18
  • @JonathanLeffler oh yeah i didn't remember that fgets keeps the newline, fixed :) as for the 100, i just chose a random number as a placeholder but i agree it's pretty small – John Doe Dec 01 '16 at 15:21
  • I need to insert the lines as an input. Also there is a parameter lines_copy that is going to be used for that purpose –  Dec 01 '16 at 16:38
  • @Eternal to read from the file rather than from stdin you just need to put the name of your variable inside fgets. in your case it should be `fgets(line,MAX_LINE_SIZE,source)`. If that's not what you're asking i didn't really understand your question sorry. Also, for what purpose is lines_copy used? – John Doe Dec 04 '16 at 20:56
  • lines_copy is something I was trying to do to solve the problem. My question is explained at my post in the yellow background. I want to copy specific lines from the text file (a) and make an other text file (copy of a) with the specific lines eg lines 2-3 like the example in yellow background –  Dec 04 '16 at 21:00
  • @Eternal my solution does exactly what you want, you just need to change `stdin` to `source` in your case and change the printf to `fputs(line,destination)`. – John Doe Dec 04 '16 at 21:07
  • I got confused there can you update your answer so I can directly copy and paste to see if that works? –  Dec 04 '16 at 21:14
  • @Eternal here, if you replace your while loop with this one you should write to the destination file the lines 3,4 and 5. now you just need to change 3 and 5 with the lines your user inputs – John Doe Dec 04 '16 at 21:22
  • in your solution I cant see anywhere that asks as input the lines , also the lines should be passed as parameter in the cp function –  Dec 04 '16 at 21:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/129758/discussion-between-eternal-and-john-smith). –  Dec 04 '16 at 21:35
0

There are some problems in your program:

  • Do not use gets(), it may cause buffer overflows.

  • Always use type int to store the return value of fgetc() in order to distinguish EOF from regular byte values.

  • You pass an extra argument ".txt" to printf(). It will be ignored but should be removed nonetheless.

To copy a range of lines from source to destination, you can just modify your function this way:

#include <stdio.h>
#include <string.h>
#include <errno.h>

void cp(char source_file[], char destination_file[], int start_line, int end_line) {
    int ch;
    int line = 1, lines_copied;
    FILE *source, *destination;

    source = fopen(source_file, "r");
    if (source == NULL) {
        printf("Cannot open input file %s: %s\n",
               source_file, strerror(errno));
        exit(EXIT_FAILURE);
    }

    destination = fopen(destination_file, "w");
    if (destination == NULL) {
        printf("Cannot open output file %s: %s\n",
               destination_file, strerror(errno));
        fclose(source);
        exit(EXIT_FAILURE);
    }

    while ((ch = fgetc(source)) != EOF) {
        if (line >= start_line && line <= end_line) {
            fputc(ch, destination);
        }
        if (ch == '\n') {
            line++;
        }
    }
    lines_copied = 0;
    if (line > start_line) {
        if (line >= end_line) {
            lines_copied = end_line - start_line + 1;
        } else {
            lines_copied = line - start_line + 1;
        }
    }
    printf("Copied lines %d from %s to %s\n",
           lines_copy, source_file, destination_file);

    fclose(source);
    fclose(destination);
}

int main() {
    char source_file[80];
    char destination_file[80];
    int start_line, end_line;

    printf("-Enter the name of the source file ending in .txt\n"
           "-Enter the name of the destination file ending in .txt\n"
           "-Enter the start and end line\n\n");

    printf(">subcopy.o ");
    if (scanf("%79s", source_file) != 1) {
        return 1;
    }
    printf("destination file-> ");
    if (scanf("%79s", destination_file) != 1) {
        return 1;
    }
    printf("Start and end lines: ");
    if (scanf("%d %d", &start_line, &end_line) != 2) {
        return 1;
    }

    cp(source_file, destination_file, start_line, end_line);

    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189