tee command in C with option - c

I have command tee in C, and I should add option -a which :supports the -a option file, which results in adding the data being read to the end of the file, if available. Anyone could help?
I try put inside :
if ( (option = getopt(argc,argv,"a")) != -1 ){
switch (option){
case 'a':
But I don't know what next.
main(int argc, char *argv[]){
FILE *fp, *fp1;
char buffer;
if(argc != 4){
printf("\nError");
printf("\nSintaxis: tee [archivo1] [archivo2]\n");
exit(0);
}
if(strcmp(argv[1], "tee") == 0){
fp = fopen(argv[2], "r");
fp1 = fopen(argv[3], "w");
printf("\Content in %s:\n", argv[2]);
while(!feof(fp)){
buffer = fgetc(fp);
fputc(buffer, fp1);
printf("%c", buffer);
}
printf("\n\n%s received %s\n", argv[3], argv[2]);
fclose(fp);
fclose(fp1);
}
else
printf("\nThe first argument have to be tee\n");
}
Second version , I think better.
But if I run program without option -a else if (argc == 2) {
printf("Write to file: %s\n", argv[1]);
process_save_reading(argv[1],"w+") write some text in file argv[1] -file is empty
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void usage() {
fprintf(stderr, "Usage: [-a program]");
exit(1);
}
void err(char * s1, char * s2) {
fprintf(stderr, "Error: %s ", s1);
perror(s2);
exit(1);
}
void process_reading() {
int c = fgetc(stdin);
while (c != EOF) {
putchar(c);
c = getchar();
}
}
void write_file_content(char * filename, int cnt, const char* mode) {
FILE *fp;
if ((fp = fopen(filename, mode)) == NULL) {
fprintf(stderr, "Can not open file: %s\n", filename);
exit(1);
}
fputc(cnt, fp);
fclose (fp);
}
void process_save_reading(char * filename, const char* mode) {
int c = fgetc(stdin);
while (c != EOF) {
putchar(c);
write_file_content(filename, c, mode);
c = getchar();
}
}
int file_exists(char * filename) {
return access(filename, F_OK) != -1;
}
int main(int argc, char * argv[]) {
char * opts = "a:";
int c;
if (argc == 1) {
process_reading();
}
else if (argc == 2) {
printf("Write to file: %s\n", argv[1]);
process_save_reading(argv[1],"w+");
}
else {
while ((c = getopt(argc, argv, opts)) != -1) {
switch (c) {
case 'a':
if (!file_exists(optarg)) {
fprintf(stderr, "File: '%s' doesn't exists\n", optarg);
exit(1);
}
printf("Save to file: %s\n", optarg);
process_save_reading(optarg,"a+");

Related

's' case with getopt dosent print out the active files

This certain getopt case is supposed to be used as an ls (the unix/linux command) alternative that returns the active files but once compiled and ran nothing is returned in the terminal.
Here is the full code:
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#define DATA_SIZE 1000
void print_help(void)
{
printf("Help\n");
printf("> cast -d (deletes file)\n");
printf("> cast -r (renames file)\n");
printf("> cast -c (create new file)\n");
printf("> cast -s (searches contents of file)\n");
printf("________________________________________\n");
printf("Find an error or a bug? please submit it in the issues section on github\n");
}
case 's': {
int main(void)
{
DIR *directory;
struct dirent *entry;
directory = opendir(".");
if (directory == NULL)
{
printf("Error reading directory\n");
return 1;
}
while ((entry = readdir(directory)) != NULL)
if (entry->d_type == DT_REG)
{
printf("file: %s\n", entry->d_name);
}
}
if (closedir(directory) == -1)
{
printf("Error closing directory\n");
return 1;
}
return 0;
}
}
int main(int argc, char **argv)
{
int option_val = 0;
int opt_delete = 0;
int opt_help = 0;
int opt_rename = 0;
int opt_create = 0;
int opt_search = 0;
while ((option_val = getopt(argc, argv, "dhrcs")) != -1) {
switch (option_val) {
case 'd': {
char filename[65]; //Hope your filename isnt bigger than this
printf("Filename or path to file: ");
scanf("%s", filename); // checks to see if your filename isnt bigger than specified
if (remove(filename) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s, deleted.\n", filename);
opt_delete = 1;
break;
case 'r': {
char file[65], new[65];
printf("File: ");
scanf("%s", file);
printf("New name: ");
scanf("%s", new);
if (rename(file, new) != 0)
{
fprintf(stderr, "Errno: %d\n", errno);
perror("Error msg");
} else printf("%s --> %s", file, new);
opt_rename = 1;
break;
case 'c': {
FILE *f = fopen("Castdocument.txt", "w+");
fprintf(f, "Finished with maybe no errors? Rename this file to whatever you would like and change the filename extension with ""cast -r""");
printf("File created! (Check your home directory for ""Castdocument.txt"" file and modify that to fit your needs)");
fclose(f);
opt_create = 1;
case 'h': {
print_help();
opt_help = 1;
break;
default:; /* '?' */
//print_help();
}
if (opt_delete) {
printf("\n");
} if (opt_rename) {
printf("\n");
} if (opt_help) {
print_help();
} if (opt_search) {
printf("\n");
} if (opt_create) {
printf("\n");
}
}
}
}
}
}
}
and here is the 's' case:
case 's': {
int main(void)
{
DIR *directory;
struct dirent *entry;
directory = opendir(".");
if (directory == NULL)
{
printf("Error reading directory\n");
return 1;
}
while ((entry = readdir(directory)) != NULL)
if (entry->d_type == DT_REG)
{
printf("file: %s\n", entry->d_name);
}
}
if (closedir(directory) == -1)
{
printf("Error closing directory\n");
return 1;
}
return 0;
}
}
I attempted to move the case out of the switch statement but to no avail.

Segmentation fault instead of showing message - reading from a file by using pointers in c

I wrote a program, which reads from a file. I use a condition in which I print that the array is too big, but when I use a too big array instead of showing this message I have segmentation fault.
This is my program
#include <stdio.h>
#include <stdlib.h>
#define N 10000 // Maximum array size
int _strlen(char *array) {
int i;
for (i = 0; array[i] != '\0'; ++i);
return i;
}
int readText(FILE *wp, char *s, int max) {
int sum = 0;
if (_strlen(s) > max) {
printf("This array is too big. Maximum size is %d", max);
} else {
while ((*s++ = fgetc(wp)) != EOF) {
sum++;
}
*(s-1) = '\0';
}
return sum;
}
int main(int argc, char *argv[]) {
FILE *wz, *wc;
char *s;
char array[N];
s = array;
if (argc != 3) {
printf("Wrong arguments number\n");
printf("I should run this way:\n");
printf("%s source result\n",argv[0]);
exit(1);
}
if ((wz = fopen(argv[1], "r")) == NULL) {
printf("Open error %s\n", argv[1]);
exit(1);
}
if ((wc = fopen(argv[2], "w")) == NULL) {
printf("Open error %s\n", argv[2]);
exit(2);
}
fprintf(wc, "Read text from file source.txt");
readText(wz, s, 10000);
return 0;
}
In output I want to have: This array is too big. Maximum size is %d
Instead of Segmentation fault core dumped
In addition, I want to say that the program is when I use a smaller array, but I want to show the user a proper message when he uses too big array instead of segmentation fault.
Thanks, I change my program in that way. The only problem is that this program check the if condition in every while loop so this program could be slow.
int readText(FILE *wp, char *s, int max) {
int sum = 0;
if (_strlen(s) > max) {
printf("This array is too big. Maximum size is %d", max);
} else {
while ((*s++ = fgetc(wp)) != EOF) {
sum++;
if (sum > max) {
printf("This array is too big. Maximum size is %d", max);
break;
}
}
*(s-1) = '\0';
}
return sum;
}
The remarks / other answer solve your undefined behavior (segmentation fault in your case).
The only problem is that this program check the if condition in every while loop so this program could be slow.
Your program is not slow because of a 'if' but because you read the file char per char.
Using stat or equivalent function you can get the size of the file to read it throw only one fread :
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#define N 10000 // Maximum array size
int main(int argc, char *argv[]) {
char array[N];
FILE *wz, *wc;
struct stat st;
off_t sz;
if (argc != 3) {
printf("Wrong arguments number\n"
"I should run this way:\n"
"%s source result\n", argv[0]);
exit(1);
}
if ((wz = fopen(argv[1], "r")) == NULL) {
printf("Cannot open %s to read : %s\n", argv[1], strerror(errno));
exit(1);
}
if (stat(argv[1], &st) == -1) {
printf("Cannot get stat of %s : %s\n", argv[1], strerror(errno));
exit(1);
}
if (st.st_size > N-1) {
printf("This array is too big. Maximum size is %d", N-1);
sz = N-1;
}
else
sz = st.st_size;
if (fread(array, 1, sz, wz) != sz) {
printf("cannot read %s : %s", argv[1], strerror(errno));
fclose(wz); /* for valgrind end test etc */
exit(1);
}
array[sz] = 0;
fclose(wz);
if ((wc = fopen(argv[2], "w")) == NULL) {
printf("Cannot open %s to write : %s\n", argv[2], strerror(errno));
fclose(wz); /* for valgrind end test etc */
exit(2);
}
/* ... */
fclose(wc);
return 0;
}
Knowing the size of the file allows to remove that limitation to a constant size and try to read the file while you can allocate enough memory for :
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char *argv[]) {
char * array;
FILE *wz, *wc;
struct stat st;
if (argc != 3) {
printf("Wrong arguments number\n"
"I should run this way:\n"
"%s source result\n", argv[0]);
exit(1);
}
if ((wz = fopen(argv[1], "r")) == NULL) {
printf("Cannot open %s to read : %s\n", argv[1], strerror(errno));
exit(1);
}
if (stat(argv[1], &st) == -1) {
printf("Cannot get stat of %s : %s\n", argv[1], strerror(errno));
exit(2);
}
if ((array = malloc(st.st_size + 1)) == NULL) {
printf("Not enough memory to memorize the file %s\n", argv[1]);
exit(3);
}
if (fread(array, 1, st.st_size, wz) != st.st_size) {
printf("cannot read %s : %s", argv[1], strerror(errno));
fclose(wz); /* for valgrind end test etc */
free(array); /* for valgrind etc */
exit(4);
}
array[st.st_size] = 0;
fclose(wz);
if ((wc = fopen(argv[2], "w")) == NULL) {
printf("Cannot open %s to write : %s\n", argv[2], strerror(errno));
free(array); /* for valgrind etc */
exit(5);
}
/* ... */
fclose(wc);
free(array); /* for valgrind etc */
return 0;
}
Anyway because of the usage of the program "source result" may be you want to copy the file specified by argv[1] in the file specified by argv[2], in that case better to read and write block by block rather than to read all to not use a lot of memory for nothing and to manage the case the input file size is greater than the memory size.
You cannot measure the length of the destination array with _strlen(s), the size is given as an argument and reading an uninitialized array with _strlen() has undefined behavior.
Furthermore, you store fgetc(fp) to *s++ before testing for EOF. This is incorrect in all cases:
if char type is signed, EOF cannot be distinguished from a valid byte value of \377.
if char is unsigned, EOF cannot be tested because it has been converted as a char value of 0xff, hence the loop runs forever, writing beyond the end of the destination array until this causes a crash.
You simply want to add a test in the reading loop to stop reading bytes from the file when the buffer is full and read the bytes into an int variable so you can test for end of file reliably.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#define N 10000 // Maximum array size
int readText(FILE *wp, char *s, int max) {
int i = 0, c;
while (i < max - 1 && (c = fgetc(wp)) != EOF) {
s[i++] = c;
}
s[i] = '\0';
return i;
}
int main(int argc, char *argv[]) {
FILE *wz, *wc;
char array[N];
int nread;
if (argc != 3) {
printf("Wrong arguments number\n");
printf("I should run this way:\n");
printf("%s source result\n", argv[0]);
exit(1);
}
if ((wz = fopen(argv[1], "r")) == NULL) {
printf("Open error %s\n", argv[1]);
exit(1);
}
if ((wc = fopen(argv[2], "w")) == NULL) {
printf("Open error %s\n", argv[2]);
exit(2);
}
fprintf(wc, "Read text from file source.txt\n");
nread = readText(wz, array, N);
printf("Read %d bytes\n", nread);
return 0;
}

Merging a list of files into another

I'm trying to make a program that takes a series of files and copies them into another one.
for example
./foobar arch1.txt arch2.txt arch3.txt
must create arch3.txt with the contents of arch1.txt arch2.txt, archN.txt.
This is my code:
#include <stdio.h>
#include <stdlib.h>
void usage (char *argv[], int code)
{
printf("usage: %s [<file> <out_file>] \n", argv[0]);
exit(code);
}
void copyFile (FILE *ifp, FILE *ofp)
{
int c;
while ((c = fgetc(ifp)) != EOF)
fputc(c, ofp);
}
int main(int argc, char *argv[])
{
system ("clear");
FILE *fp, *fp2;
if (argc < 3)
usage(argv, EXIT_FAILURE);
else
if ((fp2 = fopen(argv[argc-1], "w")) == NULL) {
printf("Can't open file to write: %s\n", *argv);
exit(EXIT_FAILURE);
}
while(--argc > 0)
printf("%d",argc);
if ((fp = fopen(*++argv, "r")) == NULL) {
printf("Can't open file: %s\n", *argv);
exit(EXIT_FAILURE);
}
else {
copyFile(fp, fp2);
fclose(fp);
fclose(fp2);
}
return 0;
}
My ouput:
Can't open file to write: ./foobar
That's because you're using *argv for the filename parameter in fopen(). It should be argv[argc - 1].
*argv is not the first argument, but rather the path of the executable.
Increment argv once before using it directly:
argv++ ;
if ((fp2 = fopen(argv[argc-1], "w")) == NULL) {
or perhaps better use array indexing and start from argv[1].
I fixed it. It's not pretty but it works now.
#include <stdio.h>
#include <stdlib.h>
void usage (char *argv[], int code)
{
printf("usage: %s [<file> <out_file>] \n", argv[0]);
exit(code);
}
void copyFile (FILE *ifp, FILE *ofp)
{
int c;
while ((c = fgetc(ifp)) != EOF)
fputc(c, ofp);
}
int main(int argc, char *argv[])
{
FILE *f_read, *f_write;
int i;
if (argc < 3)
usage(argv, EXIT_FAILURE);
if ((f_write = fopen(argv[argc-1], "w")) == NULL) {
printf("Can't write in: %s\n", argv[argc-1]);
exit(EXIT_FAILURE);
}
for (i = 1; i < argc-1; ++i)
{
if ((f_read = fopen(argv[i], "r")) == NULL) {
printf("Can't open file: %s\n", argv[i]);
exit(EXIT_FAILURE);
}
else
copyFile(f_read, f_write);
}
fclose(f_read);
fclose(f_write);
return 0;
}

how to get the source file's (the file which I want to copy) and the copied file's information in C

I want to get the source file information, when I want to copy the source file and then get the destination file information, when the source file has already being copied. The problem with the code is that I can't copy and get the source and destination file information.
How could you be able to fix my code to copy a file and get source and destination information?
Code:
#define BUFFER 100 // ** increased - file path can get pretty long
#define BUFFERSIZE 4096
#define COPYMODE 0644
void oops(char *, char *);
int file_exist(char *filename)
{
struct stat buffer;
return (stat (filename, &buffer) == 0);
}
int main(int argc, char *argv[])
{
char ch, source_file[20], target_file[20];
FILE *source, *target;
// printf("Enter name of file to copy\n");
// fgets(source_file, 20, stdin);
source_file = argv[20];
source = fopen(source_file, "r");
if( source == NULL )
{
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
printf("Enter name of target file\n");
fgets(target_file, 20 , stdin);
target = fopen(target_file, "w");
if( target == NULL )
{
fclose(source);
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
while( ( ch = fgetc(source) ) != EOF )
fputc(ch, target);
printf("File copied successfully.\n");
fclose(source);
fclose(target);
struct stat sb;
if (argc != 2) {
fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &sb) == -1) {
perror("stat");
exit(EXIT_SUCCESS);
}
printf("File type: ");
switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
printf("I-node number: %ld\n", (long) sb.st_ino);
exit(EXIT_SUCCESS);
}
void oops(char *s1, char *s2)
{
fprintf(stderr,"Error: %s ", s1);
perror(s2);
exit(1);
}
I am unsure where your difficulty lies, apart from errors mentioned in comment. I've simplified your code, removing the bitfield masks as I don't have their definitions.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
int ch; // <--- int not char
struct stat sb;
FILE *source, *target;
if (argc < 3) {
printf("Enter two args: source and destination file names\n");
exit(EXIT_FAILURE);
}
source = fopen(argv[1], "r");
if( source == NULL ) {
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
target = fopen(argv[2], "w");
if( target == NULL ) {
fclose(source);
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
while( ( ch = fgetc(source) ) != EOF )
fputc(ch, target);
fclose(source);
fclose(target);
printf("File copied successfully.\n");
if (stat(argv[1], &sb) == -1) {
perror("stat");
exit(EXIT_SUCCESS);
}
printf("File %s type: 0x%04X Mode: 0x%04X\n", argv[1], (unsigned)sb.st_ino, (unsigned)sb.st_mode);
if (stat(argv[2], &sb) == -1) {
perror("stat");
exit(EXIT_SUCCESS);
}
printf("File %s type: 0x%04X Mode: 0x%04X\n", argv[2], (unsigned)sb.st_ino, (unsigned)sb.st_mode);
return 0;
}
Program output:
>test test.c test2.c
File copied successfully.
File test.c type: 0x0000 Mode: 0x81B6
File test2.c type: 0x0000 Mode: 0x81B6

strange behaviour in output

I have a problem with my program to get it run correctly.
here is the code:
#include <stdio.h>
#include <stdlib.h> // for EXIT_SUCCESS and EXIT_FAILURE
#include <ctype.h>
#include <string.h>
void ReadFile(FILE* file) {
unsigned lines = 0;
int braces = 0;
int curlyBraces = 0;
int comments = 0;
int c;
char* line = 0;
unsigned col = 0;
while ((c = fgetc(file)) != EOF) {
if(c == '\n') { // new line
lines++;
printf("%4d: {%d} (%d) /*%d*/ |%s\n", lines, curlyBraces, braces, comments, line);
free(line); line = 0;
col = 0;
} else {
// add character to line
line = (char*)realloc(line, (col+1)*sizeof(char));
if (line == 0) {
fprintf(stderr, "error reallocating memory");
return;
}
line[col] = c;
col++;
if (c == '(') {
braces++;
} else if (c == ')') {
braces--;
} else if (c == '{') {
curlyBraces++;
} else if (c == '}') {
curlyBraces--;
} else if (c == '/') {
if (fgetc(file) == '*') {
comments++;
} else {
fseek(file, -1, SEEK_CUR);
}
} else if (c == '*') {
if (fgetc(file) == '/') {
comments--;
} else {
fseek(file, -1, SEEK_CUR);
}
}
}
}
}
int main(int argc, char** argv) {
short lines = 0, words = 0, chars = 0;
/* check for arguments */
if (argc == 1) {
fprintf(stderr, "usage: %s filename\n", argv[0]);
return EXIT_FAILURE;
}
/* open file */
FILE* file = fopen(argv[1], "r");
if(file == 0) {
fprintf(stderr, "error open file '%s'\n", argv[1]);
return EXIT_FAILURE;
}
ReadFile(file);
if (fclose(file) == EOF) {
fprintf(stderr, "error in fclose()\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
on the output i get some weird output, like realloc overwrites some data...
i already tried strcat, but i can't use constant chars. so i have to use realloc.
here is a short excerpt of the output
P 68: {1} (0) /*0*/ | / open file *
69: {1} (0) /*0*/ | FILE* file = fopen(argv[1], "r");
70: {2} (0) /*0*/ | if(file == 0) {
rn EXIT_FA(0) /*0*/ | fprintf(stderr, "error open file '%s'\n", argv[1]);
r open fi (0) /*0*/ | return EXIT_FAILURE;
73: {1} (0) /*0*/ | }
} 74: {1} (0) /*0*/ |
maybe there is another way to reaize this? with fgets() i could get the whole line, but increments the pointer in the file and i have to give fgets() a count of chars. so that wouldn't be the perfect solution.
You need to terminate your string before you print it out:
lines++;
line[col] = 0; // new
printf("%4d: {%d} (%d) /*%d*/ |%s\n", lines, curlyBraces, braces, comments, line);
Unfortunately line[col] is out of bounds here. So you need realloc line before adding the terminator like this:
lines++;
line = (char*)realloc(line, (col+1)*sizeof(char));
if (line == 0) {
fprintf(stderr, "error reallocating memory");
return;
}
line[col] = 0; // new
printf("%4d: {%d} (%d) /*%d*/ |%s\n", lines, curlyBraces, braces, comments, line);
Also, do you know about ungetc? You can replace those fseek(-1) with ungetc.

Resources