I am trying to create a function that appends !! at the very end of each line from(inclusive)-to(exclusive) of a text file. After I had several complications I actually succeeded. But not entirely.
int incldue_auto (char *script, unsigned int offsetLine, unsigned int endLine)
{
size_t fileSize;
size_t content = (endLine - offsetLine) * 3; // New characters
char *buffer;
FILE* fp;
if((fp = fopen(script, "r")) == NULL) //return(1);
if(fseek(fp, 0l, SEEK_END) != 0) //return(2);
if((fileSize = ftell(fp)) == (-1l)) //return(3);
if(fseek(fp, 0l, SEEK_SET) != 0) //return(2);
if((buffer = calloc(fileSize + content, sizeof(char))) == NULL) //return(4);
if(fread(buffer, sizeof(char), fileSize, fp) != fileSize) //return(5);
if(fclose(fp) == EOF) //return(6);
{
int i, i2;
int lines = 0, ln = 0;
for(i = 0; i < fileSize; i++)
{
if(ln >= (endLine - offsetLine) || i[buffer] == '\0') break;
if(i[buffer] == '\n')
{
lines++;
if(lines >= offsetLine && lines < endLine)
{
char* p = (buffer + i); // \n
//if(*(p - 1) == '\n') continue;
memmove(p + 3,
p,
strlen(p)); // <-- Problematic line (I think)
memcpy(p, " !!", 3);
i += 3;
ln++;
}
}
}
fp = fopen(script, "w");
fwrite(buffer, fileSize + content, sizeof(char), fp);
fclose(fp);
}
free(buffer);
return 0;
}
It relatively works just fine, except for that it doesn't append to the last line. And it fills the text file with spaces (NULLs maybe) at the end.
I think it is because I am also moving the enzero-ed additional area content with that:
memmove(p + 3,
p,
strlen(p)); // <-- Problematic line (I think)
So maybe I need to figure out what is the appropriate formula I have to use in order to make this work.
Any ideas of how to make this work ?
Your loop condition is wrong:
for(i = 0; i < fileSize; i++)
After you have appended content to some lines, the end of the last line is moved beyond filesize and thus will no longer be treated.
You test whether the end of the buffer has been reached with i[buffer] == '\0', but that may lead to reading beyond the buffer after having done all shifts and there are nio more trailing zeroes. This shouldn't happen, because the end line condition is checked first, but better be safe by callocing one more char, which will then make buffer a zero-terminated string.
When you shift fewer lines than requested, because the file doesn't have the requested lines – say you shift lines 20 to 40 in a 30-line file – you still print out the trailing zeroes. You could either print the zero-terminated buffer as a string or you should keep track of the actual amount of data being appended.
You keep two redundant line counts, lines and ln. Pick one and remove the other; it only needlessly confuses the code.
Maybe you can put one more condition in your loop:
if(lines >= offsetLine && lines < endLine)
{
...//your code here before 'memcpy(p, " !!", 3);'
if(lines==endline)
{
memmove(p + 3, p, strlen(p));
}
//the end of your code here:
memcpy(p, " !!", 3);//your code here
i += 3;
ln++;
}
Then you will move 3 more characters if this is the last line and put '!!' just after this.
Related
I am writing a program that finds the number of occurrences of input substrings from the command line inside a text file (also read from the command line) which is written into a buffer.
When I run the code in bash, I get the error: Segmentation fault (core dumped).
I am still learning how to code with C in this environment and have some sort of idea as to why the segmentation fault occurred (misuse of dynamic memory allocation?), but I could not find the problem with it. All I could conclude was that the problem is coming from within the for loop (I labeled where the potential error is being caused in the code).
EDIT: I managed to fix the segmentation fault error by changing argv[j] to argv[i], however when I run the code now, count1 always returns 0 even if the substring occurs multiple times in the text file and I am not sure what is wrong even though I have gone through the code multiple times.
$ more foo.txt
aabbccc
$ ./main foo.txt a
0
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE *fp;
long lsize;
char *buf;
int count = 0, count1 = 0;
int i, j, k, l1, l2;
if (argc < 3) { printf("Error: insufficient arguments.\n"); return(1); };
fp = fopen(argv[1], "r");
if (!fp) {
perror(argv[1]);
exit(1);
}
//get size of file
fseek(fp, 0L, SEEK_END);
lsize = ftell(fp);
rewind(fp);
//allocate memory for entire content
buf = calloc(1, lsize+1);
if (!buf) {
fclose(fp);
fputs("Memory alloc fails.\n", stderr);
exit(1);
}
//copy the file into the buffer
if (1 != fread(buf, lsize, 1, fp)) {
fclose(fp);
free(buf);
fputs("Entire read fails.\n", stderr);
exit(1);
}
l1 = strlen(buf);
//error is somewhere here
for (i = 2; i < argc; i++) {
for (j = 0; j < l1;) {
k = 0;
count = 0;
while ((&buf[j] == argv[k])) {
count++;
j++;
k++;
}
if (count == strlen(argv[j])) {
count1++;
count = 0;
}
else
j++;
}
printf("%d\n", count1);
}
fclose(fp);
return 0;
}
fread(buf, lsize, 1, fp) will read 1 block of lsize bytes, however fread
doesn't care about the contents and won't add a '\0'-terminating byte for the
string, so l1 = strlen(buf); yields undefined behaviour, the rest of the
result can be ignored as a result of this (and your counting has errors as well).
Note that files usually don't have a 0-terminating byte at the end,
that applies even for files containing text, they usually end with a
newline.
You have to set the 0-terminating byte yourself:
if (1 != fread(buf, lsize, 1, fp)) {
fclose(fp);
free(buf);
fputs("Entire read fails.\n", stderr);
exit(1);
}
buf[lsize] = '0';
And you can use strstr to get the location of the substring, like this:
for(i = 2; i < argc; ++i)
{
char *content = buf;
int count = 0;
while((content = strstr(content, argv[i])))
{
count++;
content++; // point to the next char in the substring
}
printf("The substring '%s' appears %d time(s)\n", argv[i], count);
}
Your counting is wrong, there are some errors. This comparison
&buf[j] == argv[k]
is wrong, you are comparing pointers, not the contents. You have to use strcmp
to compare strings. In this case you would have to use strncmp because you
only want to match the substring:
while(strncmp(&buf[j], argv[k], strlen(argv[k])) == 0)
{
// substring matched
}
but this is also wrong, because you are incrementing k as well, which will
give you the next argument, at the end you might read beyond the limits of
argv if the substring is longer than the number of arguments. Based on your
code, you would have to compare characters:
while(buf[j] == argv[i][k])
{
j++;
k++;
}
You would have to increment the counter only when a substring is matched, like
this:
l1 = strlen(buf);
for (i = 2; i < argc; i++) {
int count = 0;
int k = 0; // running index for inspecting argv[i]
for (j = 0; j < l1; ++j) {
while(buf[j + k] == argv[i][k])
k++;
// if all characters of argv[i]
// matched, argv[i][k] will be the
// 0-terminating byte
if(argv[i][k] == 0)
count++;
// reset running index for argv[i]
// go to next char if buf
k = 0;
}
printf("The substring '%s' appears %d time(s)\n", argv[i], count);
}
basically trying to make an anti virus but all I get when trying to read the infected file into a buffer is EOF... it's a jpg and I have no idea how to fix this
about the file functions I'm allowed to use:
fread/fwrite
fgets
fputs
fclose
fopen
fgetc
fputc
fscanf
fprintf
int fullScan(FILE* sign, FILE* infected);
char* getFile(FILE* file);
int main(int argc, char** argv)
{
FILE* sign = fopen("KittenVirusSign", "rb");
FILE* infected = fopen("kitten_frog.jpg", "rb");
int j = 0;
if (infected == NULL)
{
printf("couldn't open the file (suspicious file)");
return -1;
}
if (sign == NULL)
{
printf("couldn't open the file (virus signature)");
return -1;
}
j = fullScan(sign, infected);
return 0;
}
int fullScan(FILE* sign, FILE* infected)
{
char* sign_c = NULL;
char* infec_c = NULL;
int infect_res = -1;
int sign_len = 0;
int infec_len = 0;
int i = 0;
int j = 0;
sign_c = getFile(sign);
infec_c = getFile(infected);
while (1)
{
if (*(infec_c + i) == *(sign_c + j))
{
infect_res = 1;
if (*(sign_c + j) == EOF)
{
break;
}
else if (*(infec_c + i) == EOF)
{
infect_res = -1;
break;
}
i++;
j++;
continue;
}
else if (*(infec_c + i) != *(sign_c + j))
{
if (*(infec_c + i) == EOF || *(sign_c + j) == EOF)
{
break;
}
i++;
j = 0;
infect_res = -1;
}
}
fclose(infected);
free(sign_c);
free(infec_c);
return infect_res;
}
char* getFile(FILE* file)
{
char* buffer;
long filelen;
int i;
fseek(file, 0, SEEK_END);
filelen = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = (char *)malloc((filelen + 1)*sizeof(char));
for (i = 0; i < filelen; i++)
{
fread(buffer + i, sizeof(char), 1, file);
}
return buffer;
}
EOF is a special integer value returned by some input functions to indicate that the end of the file has been reached, but it is not part of the file data. Your fread() will therefore never store an EOF character into the input buffer you provided. However, if your C implementation features signed default chars, as many do, then there is a char value that is numerically equal to EOF (usually -1).
If either file happens to contain that byte, then your code will misinterpret it as designating the end of that file. If it happens to be the first byte in either file then the program will misinterpret the file as being empty.
Since you are analyzing binary files,
I recommend using buffers of unsigned char rather than default char.
All possible byte values can appear in the file data, so you cannot identify the end of the data by the value of any byte within.
Probably, getFile() should return a struct that contains both a pointer to the buffer and its size.
As other answer suggested, you should also send the file length and iterate over that, rather than waiting for a EOF.
Also, in your getFile() function, when you determine the length of the file you don't have to read byte by byte, you can just send the filelen to fread() like so
fread(buffer, sizeof(char), filelen, file);
fread now reads filelen elements of data each the size of a char (you can write 1 instead) from the stream file to buffer.
I need to write a program that is copying the content of a file to another file and reverses it.
I found an example and read it through to understand what is going on.
The problem is that my program has to use two functions:
void reverse(char line[]){
int i;
int length;
char tmp;
..
..
..
return;
}
(no further paramters or local variables)
The second function does the rest of the work(opens files, copies files, closes files)
The main program only reads the name of the files and calls the copy function.
#include<stdio.h>
#include<string.h>
void reverse(char line[])
{
int i;
int length;
char temp;
if (line == NULL)
return;
length = strlen(line);
for (i = 0 ; i < length / 2 + length % 2 ; ++i)
{
if (line[i] == line[length - i - 1])
continue;
temp = line[i];
line[i] = line[length - i - 1];
line[length - i - 1] = temp;
}
return;
}
int main()
{
FILE *src_fh, *dst_fh;
char src_fn[256+1], dst_fn[256+1];
printf("Enter Source File Name:\n");
fgets(src_fn, sizeof(src_fn), stdin); reverse(src_fn);
if( (src_fh = fopen(src_fn, "r")) == NULL )
{
printf("ERROR: Source File %s Failed To Open...\n",src_fn);
return(-1);
}
printf("Enter Destination File Name:\n");
fgets(dst_fn, sizeof(dst_fn), stdin); reverse(dst_fn);
if( (dst_fh = fopen(dst_fn, "w+")) == NULL )
{
fclose(src_fh);
printf("ERROR: Destination File %s Failed To Open...\n",dst_fn);
return(-2);
}
int ch;
while( (ch = fgetc(src_fh)) != EOF )
{
fputc(ch, dst_fh);
}
fclose(src_fh);
fclose(dst_fh);
return 0;
}
You only need to swap the first character with the last, the second with the pre-last, and so on.
You actually don't need the int temp variable, but since it seems to be required, here it is
void reverse(char line[])
{
int i;
int length;
char temp;
if (line == NULL)
return;
length = strlen(line);
for (i = 0 ; i < length / 2 + length % 2 ; ++i)
{
if (line[i] == line[length - i - 1])
continue;
temp = line[i];
line[i] = line[length - i - 1];
line[length - i - 1] = temp;
}
return;
}
This is an improved version, without int temp, instead we store the result of length / 2 + length % 2 so it's not recalculated on each iteration
void reverse(char line[])
{
int i;
int length;
int half;
if (line == NULL)
return;
length = strlen(line);
half = length / 2 + length % 2;
for (i = 0 ; i < half ; ++i)
{
if (line[i] == line[length - i - 1])
continue;
line[length] = line[i];
line[i] = line[length - i - 1];
line[length - i - 1] = line[length];
}
line[length] = '\0';
return;
}
just use the location of the terminating '\0' byte as the temp when swapping.
For the second function, read each line using fgets and write it to the file with fprintf, just remember to remove the newline character from the read strings, you can use the chomp function y posted for that, if you don't remove the newline, the reversed lines will have the newline at the beginning of the line.
The prameter name line in the prototype void reverse(char line[]) seems to give a hint, how the given exercise might be intended to be solved.
split the file in lines
reverse every line
reverse the order of the lines
Nevertheless you should watch out following this strategy, as there is still a really nasty gotcha involved, if your file may contain any data.
In this case you'll get in big trouble finding the end of line[] as '\0' termination might get confused with a literal '\0' in the line.
As a workaround you might try to replace any literal occurance of '/0' by the sequence '\0' 'x' and mark the end of your line by the sequence '\0' '-' or whatever before passing it to reverse() and reaversing the substitution after writing the reversed line to the file.
Unfortunately this attempt doesn't look too elegant, but maybe reversing a file the way it is meant to be done in the exercise isn't really elegant anyays.
the following code
1) incorporates proper error checking
2) outputs each input line, reversed, to the output file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* chomp(char* p)
{
int len;
if(!p) return(p);
if( (len=strlen(p))<=0 ) return(p);
if( p[len-1] == '\n' ) { p[--len] = '\0'; }
if( p[len-1] == '\r' ) { p[--len] = '\0'; }
return(p);
} // end function: chomp
int main()
{
/* Create Usable Variables */
FILE *src_fh = NULL;
FILE *dst_fh = NULL;
char src_fn[256+1] = {'\0'};
char dst_fn[256+1] = {'\0'};
char line[2048] = {'\0'};
/* Retrieve Source File Name From User */
printf("Enter Source File Name:\n");
if( NULL == (fgets(src_fn, sizeof(src_fn), stdin) ) )
{ // fgets failed
perror("fgets for input file name failed" );
exit(EXIT_FAILURE);
}
// implied else, fgets successful
chomp(src_fn); // remove trailing newline characters
/* Attempt Opening Source File For Reading */
if( (src_fh = fopen(src_fn, "r")) == NULL )
{
perror( "fopen failed" );
printf("ERROR: Source File %s Failed To Open...\n",src_fn);
return(-1);
}
// implied else, fopen source file successful
/* Retrieve Destination File Name From User */
printf("Enter Destination File Name:\n");
if( NULL == (fgets(dst_fn, sizeof(dst_fn), stdin) ) )
{ // then fgets failed
perror( "fgets for output file name failed" );
fclose(src_fh); // cleanup
exit( EXIT_FAILURE );
}
// implied else, fgets for output file name successful
chomp(dst_fn); // remove trailing newline characters
/* Attempt Opening Destination File For Writing */
if( NULL == (dst_fh = fopen(dst_fn, "w")) )
{
perror( "fopen for output file failed" );
fclose(src_fh); // cleanup
printf("ERROR: Destination File %s Failed To Open...\n",dst_fn);
return(-2);
}
// implied else, fopen for output file successful
int index;
/* Copy Source File Contents (reversed, line by line) to destination file */
while( NULL != (fgets(line, sizeof(line), src_fh) ) )
{
chomp(line); // remove trailing newline characters
index = strlen(line) - 1; // -1 because arrays start with offset 0
// and strlen returns offset to '\0'
// output reversed line to file
while( index >= 0 )
{
fputc( line[index], dst_fh );
index--;
} // end while
fputc( '\n', dst_fh );
} // end while
/* Close Files On Success */
fclose(src_fh);
fclose(dst_fh);
return 0;
} // end function: main
I am trying to write a function that reads a line of text over a socket (it's part of the code I am writing for an HTTP Server for homework).
It works just fine writing to a file when I am writing using fputc. However, when I try and copy the characters to a buffer, and then use fprintf to print the whole buffer to the file, I don't seem to be getting any output.
Here's the code:
int read_line(int fd, char *buffer, int size) {
char *broken_buffer = (char*) malloc(sizeof(char) * 8096);
char next = '\0';
char err;
int i = 0;
FILE *f = fopen("read_line2.txt", "w");
while (i < size - 1 && next != '\n') {
err = read(fd, &next, 1);
if (err > 0) {
if (next == '\r') {
err = recv(fd, &next, 1, MSG_PEEK);
if (err > 0 && next == '\n') {
read(fd, &next, 1);
} else {
next = '\n';
}
}
fputc(next, f); // Works
broken_buffer[i] = next;
buffer[i] = next;
i++;
} else {
next = '\n';
}
}
broken_buffer[i] = '\0';
buffer[i] = '\0';
FILE *out = fopen("read_line.txt", "w");
fprintf(out, "%s\n", broken_buffer); // Does not work
fclose(out);
fclose(f);
return i;
}
EDIT: I have tried using this alternative function:
int read_socket(int fd, char *buffer, int size) {
int bytes_recvd = 0;
int retries = 0;
int total_recvd = 0;
while (retries < MAX_RETRIES && size > 0 && strstr(buffer, ">") == NULL) {
bytes_recvd = read(fd, buffer, size);
if (bytes_recvd > 0) {
buffer += bytes_recvd;
size -= bytes_recvd;
total_recvd += bytes_recvd;
} else {
retries++;
}
}
if (bytes_recvd >= 0) {
// Last read was not an error, return how many bytes were recvd
return total_recvd;
}
// Last read was an error, return error code
return -1;
}
And I have no problems printing this one out with fprintf.
EDIT2: I have figured out that i is somehow 0 after the loop, so the first character is being overwritten with a '\0'. However, when I put in debugging code to print out the value of i within the loop, I found it being incremented up to 22 (23 being the final value at which the loop breaks). How is this even possible? The resulting string is:
GET /blah.txt HTTP/1.1
Is the value of next ever 0? If it is 0 then that value will go into broken_buffer, which means that fprintf will think it's at the end of a string before you explicitly put the null there yourself.
The problem turned out to be two processes that were both connecting to the server (thanks, Google Chrome...), and both were writing to the same file somehow. The code WAS working correctly.
I program a program to split file in C in Ubuntu.
I have error when get buffer in readfile.
here is my code.
int split(char *filename, unsigned long part) {
FILE *fp;
char *buffer;
size_t result; // bytes read
off_t fileSize;
fp = fopen(filename, "rb");
if (fp == NULL) {
fprintf(stderr, "Cannot Open %s", filename);
exit(2);
}
// Get Size
fileSize = get_file_size(filename);
// Buffer
buffer = (char*) malloc(sizeof(char) * (fileSize + 1));
if (buffer == NULL) {
fputs("Memory error", stderr);
fclose(fp);
return 1;
}
// Copy file into buffer
//char buffers[11];
result = fread(buffer, 1, fileSize, fp);
buffer[fileSize] = '\0';
if (result != fileSize) {
fputs("Reading error", stderr);
return 1;
}
// Split file
off_t partSize = fileSize / part;
// Last Part
off_t lastPartSize = fileSize - partSize * part;
unsigned long i;
unsigned long j;
// create part 1 to n-1
for (j = 0; j < part; j++) {
char partName[255];
char *content;
char partNumber[3];
// Content of file part
// for (i = j; i < partSize * (j + 1); i++) {
//
// }
content = (char*) malloc(sizeof(char) * partSize);
content = copychar(buffer, j + i, partSize + i);
i += partSize;
//copy name
strcpy(partName, filename);
// part Number
sprintf(partNumber, "%d", j);
// file name with .part1 2 3 4 ....
strcat(partName, ".part");
strcat(partName, partNumber);
// Write to file
writeFile(partName, content);
free(content);
}
// last part
char *content;
content = (char*) malloc(sizeof(char) * (fileSize - partSize * (part - 1)));
content = copychar(buffer, (part - 1) * partSize + 1, fileSize);
char lastPartNumber[3];
char lastPartName[255];
sprintf(lastPartNumber, "%d", part);
strcpy(lastPartName, filename);
strcat(lastPartName, ".part");
strcat(lastPartName, lastPartNumber);
writeFile(lastPartName, content);
free(content);
free(buffer);
fclose(fp);
return 0;
}
here is function copychar from start to end
char *copychar(char* buffer, unsigned long start, unsigned long end) {
if (start >= end)
return NULL;
char *result;
result = (char*) malloc(sizeof(char) * (end - start) + 1);
unsigned long i;
for (i = start; i <= end; i++)
result[i] = buffer[i];
result[end] = '\0';
return result;
}
here is function to get filesize
off_t get_file_size(char *filename) {
struct stat st;
if (stat(filename, &st) == 0)
return st.st_size;
fprintf(stderr, "Cannot determine size of %s: %s\n", filename);
return -1;
}
here is function to write file
int writeFile(char* filename, char*buffer) {
if (buffer == NULL || filename == NULL)
return 1;
FILE *file;
file = fopen(filename, "wb");
fwrite(buffer, sizeof(char), sizeof(buffer) + 1, file);
fclose(file);
return 0;
}
When I test I use file test 29MB and it dumped.
I debug It return fileSize true but when readfile in buffer get from file it only return 135 characters and when use copychar it error.
Breakpoint 1, 0x0000000000400a0b in copychar (buffer=0x7ffff5e3a010 "!<arch>\ndebian-binary 1342169369 0 0 100644 4 `\n2.0\ncontrol.tar.gz 1342169369 0 0 100644 4557 `\n\037\213\b", start=4154703576, end=4164450461) at final.c:43
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400a0b in copychar (buffer=0x7ffff5e3a010 "!<arch>\ndebian-binary 1342169369 0 0 100644 4 `\n2.0\ncontrol.tar.gz 1342169369 0 0 100644 4557 `\n\037\213\b", start=4154703576, end=4164450461) at final.c:43
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
I don't know how to devide buffer into part to write into part when split.
Thank for advance!
It's highly impractical to copy files in 1 big block as you may have noticed. And it's not needed.
At the simplest level you could copy the file byte by byte, like this
while( ( ch = fgetc(source) ) != EOF ) {
fputc(ch, target);
}
Which will work, but it will be quite slow. Better to copy in blocks, like this:
unsigned char buf[4096];
size_t size;
while( (size = fread(buf, 1, sizeof(buf), fpRead) ) > 0) {
fwrite(buf, 1, size, fpWrite);
}
Notice that the resulting code is way simpler and contains no dynamic memory allocation.
You still need to add the splitting logic of course, but that can be done by tracking the number of bytes written and opening a new write-file before actually writing it.
EDIT: how to handle the multipart facet - schematically, you still need to implement extra checks for some special cases and test results of the different system calls of course
unsigned char buf[4096];
size_t size;
size_t partsize = 100000; // asssuming you want to write 100k parts.
size_t stilltobewritten = partsize; // bytes remaining to be written in current part
size_t chunksize = sizeof(buf); // first time around we read full buffersize
while( (size = fread(buf, 1, chunksize, fpRead) ) > 0) {
fwrite(buf, 1, size, fpWrite);
stilltobewritten -= size; // subtract bytes written from saldo
if (stilltobewritten == 0) {
// part is complete, close this part and open next
fclose(fpWrite);
fpWrite = fopen(nextpart,"wb");
// and reinit variables
stilltobewritten = partsize;
chunksize = sizeof(buf);
} else {
// prep next round on present file - just the special case of the last block
// to handle
chunksize = (stilltobewritten > sizeof(buf)) ? sizeof(buf) : stilltobewritten;
}
}
and EDIT 2: the file part name can be made a LOT simpler as well:
sprintf(partName, "%s.part%d",file, j);
concerning the original code, there's some confusion about start and end in the copychar. First, you probably meant sizeof(char) * (end - start + 1) rather than sizeof(char) * (end - start) + 1 in the malloc, second, you're copying end-start+1 symbols from the original buffer (for (i = start; i <= end; i++)) and then overwrite the last one with '\0', which probably isn't the intended behavior.