C implementation of cp - c

This is a primitive implementation of cp, i compiled and ran it on Linux machine(Ubuntu), this code works fine for text files of any size but not for pdfs or mp3, i dont know what im dong wrong. Is it wrong the way i use EOF? It compiles and runs without error, but does not work for every kind of file.
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#define MAX_SIZE 2
#define MAX_BUF_SIZE 256
int main(int argc, char* argv[])
{
FILE *pFile_src=NULL;
FILE *pFile_dest=NULL;
char* mychar;
char *SRC, *DEST;
int i=0,j;
char char_buff[MAX_BUF_SIZE];
mychar= (char *)malloc(sizeof(char *));
if(argv[1]!=NULL)
SRC=argv[1];
else
printf("\nUSAGE: ./Ex_ManualCP_prog src_file dest_file.\nFirst arg should be a filename, cannot be empty.\n");
if(argv[2]!=NULL)
DEST=argv[2];
else
printf("\nSecond arg should be a filename, cannot be empty.\n");
mychar= (char *)malloc(MAX_SIZE*sizeof(char *));
//initialize text buffer
for(j=0;j<MAX_BUF_SIZE;j++)
char_buff[j]='\0';
pFile_src=fopen(SRC,"r"); //Open file to read and store in a character buffer
pFile_dest=fopen(DEST,"w"); //open destination file
if(pFile_dest==NULL)
printf("\nFile specified as Destination DOES NOT EXIST.\n");
if(pFile_src==NULL)
printf("\nFile specified as Source, DOES NOT EXIST.\n");
else
{
//printf("\n----File opened successfully-----\n");
while(((*mychar=fgetc(pFile_src))!=EOF))
{
if(i>=MAX_BUF_SIZE)
{
i=0;
}
char_buff[i]=*mychar;
fputc(char_buff[i],pFile_dest); //write buffer data into opened file
++i;
}
char_buff[i]='\0';
fclose(pFile_src); //close source file
}
fclose(pFile_dest);
if(pFile_src!=NULL && pFile_dest!=NULL)
printf("\n\n-----Copy Done!----\n-----Reached end of file.-----\n");
return 0;
}

Is it wrong the way i use EOF?
It is wrong. EOF is of type int. The return value of fgetc is also of type int. You store the value in a char.
Your code will fail if the file contains any byte with the value -1/255. Text files won't, of course, but large binary files are likely to contain such bytes.
Changing the type of mychar to int will fix that problem.
Another bug is the possible buffer overflow when you NUL-terminate char_buff. If the file is an even multiple of 256 then i will be
256 when you add the NUL-terminator and you will write outside the buffer.

Related

How do i check if a file is empty in C?

I'm importing a txtfile into my file, how do i check if the input file is blank.
I already check if it cannot read the input. This is what i have so far:
#include<stdio.h>
#include<stdlib.h>
int main (int argc, char *argv[]){
// argv[1] will contain the file name input.
FILE *file = fopen(argv[1], "r");
// need to make sure the file is not empty, error case.
if (file == NULL){
printf("error");
exit(0);
}
// if the file is empty, print an empty line.
int size = ftell(file); // see if file is empty (size 0)
if (size == 0){
printf("\n");
}
printf("%d",size);
the size checking obviously does not work because i put in a few numbers and the size is still 0. any suggestions?
If you are working with a regular file (e.g., a text file), you can use sys/stat.h and call the value of the st_size struct member:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main (int argc, char *argv[]) {
if (argc != 2) {
return EXIT_FAILURE;
}
const char *filename = argv[1];
struct stat st;
if (stat(filename, &st) != 0) {
return EXIT_FAILURE;
}
fprintf(stdout, "file size: %zd\n", st.st_size);
return EXIT_SUCCESS;
}
how about try read first row.
and see what characters you get?
Call ftell() does not tell you the size of the file. From the man page:
The ftell() function obtains the current value
of the file position indicator for the stream
pointed to by stream.
That is, it tell you your current position in the file...which will always be 0 for a newly opened file. You need to seek to the end of the file first (see fseek()).
ftell will tell you the position the file pointer is at, and immediately after you opened the file, this position is always 0.
You either use stat before opening, or use fseek to seek some distance in the file (or at end) and then use ftell.
Or you delay the check until afterwards. I.e., you try to read whatever you need to read, and then verify whether you succeeded or not.
Update: and speaking of checks, you have no guarantee that
// argv[1] will contain the file name input.
For that, you need to check out that argc is at least 2 (the first argument being the executable name). Otherwise your file name might be NULL. fopen should simply return NULL, but in other scenarios you might find yourself looking at a core dump.

fwrite creates an output file that is bigger than the input file

I want to read a file bytewise into an array and then write the data of the array reversed
in a new file (program takes filename over command line argument). Tried it with an txt-file
and it worked, but if I try it on a jpg-file the new file is bigger than the original!
The determined file size saved in long size; is also correct for jpg-files and write loop
get size-time executed writing one char (char is one byte big, I am right?).
Does anybody know how the output file can get bigger than size*byte?
It doesn't seem logical to me!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[])
{
FILE *file;
char *buffer;
long size;
char filename[32];
if(argc>1)
{
//determine file size
file=fopen(argv[1],"r");
fseek(file,0,SEEK_END);
size=ftell(file);
rewind(file);
if(size>33554432) //32MB
{
fclose(file);
return 0;
}
//create buffer and read file content
buffer=malloc(33554432);
fread(buffer,1,size,file);
fclose(file);
//create new file name and write new file
strcpy(filename,argv[1]);
strcat(filename,"_");
file=fopen(filename,"w");
{
long i;
for(i=size-1;i>=0;i--)
{
fputc(buffer[i],file);
}
}
fclose(file);
free(buffer);
}
return 0;
}
The comments you're receiving are implying something: the newline character \n works differently in text mode on Windows compared with some other systems.
fputc('\n', file) on Windows actually writes two bytes if file was opened in text mode "w", as if you did fwrite("\r\n", 1, 2, file). This means for any \n byte read by fread, you're writing two bytes back.
If you want to write binary data back, you need to open your output file using the mode "wb" to fopen(). You also need to open it for reading in binary mode, "rb".

C Delete last n characters from file

I need to delete the last n characters from a file using C code. At fist I was trying to use '\b', but it returns a Segmentation Fault. I have seen interesting answers to similar questions here and here, but I would prefer to use mmap function to do this, if it's possible. I know it could be simpler to truncate the file by creating a temp file, and writing chars to temp until some offset of the original file. The problem is I don't seem to understand how to use mmap function to do this, can't see what parameters I need to pass to that function, specially address, length and offset. From what I've read, I should use MAP_SHARED in flags and PROT_READ|PROT_WRITE in protect.
The function definition says:
void * mmap (void *address, size_t length, int protect, int flags, int filedes, off_t offset)
Here is my main:
int main(int argc, char * argv[])
{
FILE * InputFile;
off_t position;
int charsToDelete;
if ((InputFile = fopen(argv[1],"r+")) == NULL)
{
printf("tdes: file not found: %s\n",argv[1]);
}
else
{
charsToDelete = 5;
fseeko(InputFile,-charsToDelete,SEEK_END);
position = ftello(InputFile);
printf("Pos: %d\n",(int)position);
int i;
//for(i = 0;i < charsToDelete;i++)
//{
// putc(InputFile,'\b');
//}
}
fclose(InputFile);
return 0;
}
Why not use:
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
like for instance:
charsToDelete = 5;
fseeko(InputFile,-charsToDelete,SEEK_END);
position = ftello(InputFile);
ftruncate(fileno(InputFile), position);
Read all but n bytes from the file and write to a temporary file, close the original file, rename temporary file as original file.
Or use e.g. truncate or similar function if you have it.
Also, failure to open the file doesn't have to be that it can't be found, You should check errno on failure to see what the error is. Use e.g. strerror to get a printable string from the error code.
Unfortunately, mmap does not allow you to change size of underlying file object.
Instead, I would recommend to simply truncate your file, use something like this:
truncate(filename, new_length);

fopen doesn't open

I am using Code::Blocks and have set the command-line arugments via the IDE. I have also opened the executable with the proper argument and I can't manage to get a non-NULL on fopen() return. I've tried hard-coding the filename also with no success. The platform is Windows XP SP3.
The first is the one that fails, when i hardcoded it i used double backlash. Also i never knew if the second works because i never managed to start the process by opening the first one.
Obviously i put the text file in the same directory that the executable and rebuilt the executable many times, but it still doesn't work.
EDIT: I added the perror("fopen"); line in the if(finput==NULL) block. This is the output.
http://prntscr.com/h71pa
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define first_part_url "[url=http://magiccards.info/query?q="
#define second_part_url "&v=card&s=cname]"
#define end_bracket "[/url]\n"
#define output_file_prefix "output_"
char* get_card(FILE* finput);
int main(int n, char* arguments[])
{
FILE* finput;
FILE* foutput;
short int counter;
char* output_filename;
char* finalstring;
for(counter=1; counter<n; counter++)
{
finput=fopen(arguments[counter], "r");
if (finput==NULL)
{
printf("Unable to open ");
puts(arguments[counter]);
perror("fopen");
break;
}
strcpy(output_filename, output_file_prefix);
strcat(output_filename, arguments[counter]);
if((foutput=fopen(output_filename, "w"))==NULL)
{
printf("There was an error while trying to open ");
puts(arguments[counter]);
printf(" .\n");
break;
}
while(!feof(finput))
{
finalstring=get_card(finput);
fputs(finalstring, foutput);
while(((fgetc(finput))!='\n')||feof(finput));
}
printf("Autocarding ");
puts(arguments[counter]);
printf(" was a success.\n");
fclose(foutput);
}
if(finput!=NULL)
{
fclose(finput);
free(finalstring);
}
return 0;
}
char* get_card(FILE* finput)
{
char* currentcard;
char* finalstring;
currentcard=(char*)malloc(sizeof(char)*150);
fgets(currentcard, 150, finput);
/* Allocates the exact amount of space needed for the final string*/
finalstring=(char*)malloc(sizeof(char)*(strlen(first_part_url)+strlen(second_part_url)+strlen(end_bracket)+strlen(currentcard)));
/* Get all the final forum link together*/
strcat(finalstring, first_part_url);
strcat(finalstring, currentcard);
strcat(finalstring, second_part_url);
strcat(finalstring, end_bracket);
free(currentcard);
return finalstring;
}
The error you are getting, "No such file or directory" indicates that the file name you're trying to open doesn't exist.
In this case, it's probably because the program's current working directory is not the same as the directory containing the executable file.
This
finput=fopen(arguments[counter], "r");
Will only fail if you do not supply correct filenames (e.g. if there are non-ASCII characters in the names or the names do not include the correct path, fopen() opens files in the current directory if no path is specified in the file name).
This
output_filename=(char*)malloc(sizeof(arguments[counter]));
most likely does not allocate enough space for a name because arguments[counter] is a pointer, and sizeof() of a pointer is not the same as strlen(that_same_pointer) + 1.
This
output_filename=output_file_prefix;
loses the just allocated memory because you are reassigning the pointer output_filename to point to some other place, output_file_prefix ("output_").
After the above this
strcat(output_filename, arguments[counter]);
is likely going to crash your program because this is going to attempt to overwrite a string literal ("output_"), doing which causes undefined behavior per the C standard.
You have to allocate enough cumulative space for the strings that you want to concatenate and you have to concatenate them in the allocated space.
To save you even more trouble, here's another problem:
finput=fopen(arguments[counter], "r");
...
while(!feof(finput))
feof() only works after at least one read from a file. This has been asked ans answered multiple times.
Try changing
for(counter=1; counter<n; ++n)
{
to
for(counter=1; counter<n; ++counter)
It appears the code loops infinitely, therefore it would exhaust the possible elements in your argument array causing a NULL pointer to be returned.

Can I pass a string into fopen()? in c

My goal is to gather input and open files based on that input.
FILE*
open_input_file (char* fileName) //opens source file to be read
{
return fopen(fileName, "r");
}
In an earlier function, I collect input from the user and save it to fileName. When I debug the program, it tells me fopen is returning NULL. That's not what I want, and I'm not sure where the problem is.
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
inFile = open_input_file(infileName);
}
I don't know what the problem is. Any thoughts?
If fopen returns NULL, the open failed. errno will hold the failure code and strerror(errno) will return a short description of why the open failed.
#include <errno.h>
#include <string.h>
...
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName); // infileName is an output parameter for this
if (!(inFile = open_input_file(infileName))) {
fprintf(stderr, "Error opening '%s': %s\n",
infileName, strerror(errno));
} else {
// open successful
...
}
}
Off-topic
gather_input better make sure infileName is null-terminated to prevent buffer overflows. The simplest way to do this is to define the size of the file name buffer as a macro and set the last character to 0.
#define FILENAMELEN 32
void gather_input(char infileName[]) {
...
infileName[FILENAMELEN-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[FILENAMELEN] = {'\0'};
This isn't very flexible. You could instead pass the size of the file name buffer into gather_input.
#define LENGTH(a) (sizeof(a) / sizeof(a[0]))
void gather_input(char infileName[], size_t len) {
...
infileName[len-1]=0;
}
int main(void)
{ FILE* inFile = NULL;
char infileName[32] = {'\0'};
gather_input(infileName, LENGTH(infileName)); // infileName is an output parameter for this
An alternative to setting the last character, if using standard string manipulation functions, is to use the strl* functions (strlcpy and strlcat) rather than their unbounded cousins. If you aren't using strl*, you should be using strncpy and strncat.
Have you checked that the file pointed to by inFilename exists on your HDD ?
Check the value of infileName in your debugger or put a printf statement to show the value on screen. printf("'%s'\n", infileName);
Did you call fclose() on your file inside the open_input_file() call. Maybe the file is still locked ?
Edit: I just checked the code. I have modified your english_to_morse() function. 1. The while statement is easier to follow than the for. 2. fgetc() returns an int and not a char.
At the top of the initialise I added this. This initialises every string in the array with and undefined string of ".??.". This will make it easier to find strange bugs as everything in your array is at least initialised.
I have modified different sections of the code but you should be able to follow.
initialize_morse_alphanum (char morseStrings[91][6])
{
for (int i=0;i<91;i++)
strcpy(morseStrings[i], ".??.");
....
....
void
english_to_morse(FILE* inputFile, FILE* outputFile, char morseStrings[91][6])
{ int convert;
convert = fgetc(inputFile);
while (convert != EOF)
{
fputs(morseStrings[convert], outputFile);
fputc(' ', outputFile);
printf ("%s ", morseStrings[convert]);
convert = fgetc(inputFile);
}
}
open_output_file (char* fileName) //opens destination file to be written
{ FILE* handle = NULL;
handle = fopen (fileName, "w"); <---- Remove the * from filename
return handle; }
Also, as mentioned in a different answer, it would be good to add some bounds checks to different areas of the code. At the moment it is quite prone to crashing. If my input file contains a lowercase 'a' (ascii 96) your program will be accessing memory that is out of bounds. So you should add a line like if (convert >= '0' && convert <= 'Z') in there somewhere. I will let you work that out.
Make sure that gather_input works properly. Could it be a problem because you're trying to read a file you're also writing on? In this case, try to close and open again the stream.

Resources