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.
Related
int main(void) {
int status = EXIT_SUCCESS;
FILE *in;
struct sigrecord {
int signum;
char signame[10];
char sigdesc[100];
} sigrec;
if ((in = fopen("signals.txt", "r")) == NULL) {
fputs("Cannot open signals.txt file\n", stderr);
return EXIT_FAILURE;
}
do {
int n = fscanf(in, "%d%9s%*[ \t]%99[^\n]", &sigrec.signum,
sigrec.signame, sigrec.sigdesc);
if (n == 3) {
printf("Signal\n number = %d\n name = %s\n description = %s\n\n",
sigrec.signum, sigrec.signame, sigrec.sigdesc);
} else if (n != EOF) {
fputs("Failed to match signum, signame or sigdesc\n", stderr);
status = EXIT_FAILURE;
break;
}
} while (1);
if (fclose(in) == EOF) {
fputs("Failed to close file\n", stderr);
status = EXIT_FAILURE;
}
return status;
}
Output is fine, but while(1) loop does not end do{} loop and my program gets stuck after doing its purpose, printing output perfectly. Thanks for any help.
You need to break if scanf was not successful despite the reason.
}
else {
if (n != EOF) {
fputs("Failed to match signum, signame or sigdesc\n", stderr);
status = EXIT_FAILURE;
}
break;
}
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+");
i've created a program which is a re-make of the wc program in BASH. For some reason my check doesn't work as it should. Word count and Line count (which are handled by my child processes, using fork) still display when they should not. if i type './test -n' it is only meant to display the current user. however it seems to display that followed by word and line count, even though i didn't ask for it. the if statement which doesn't seem to work is near the bottom of the code. here is my code:
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
/* Size of character buffer to read in a file. */
#define BUFFSIZE 1000000
/* Read file 'filename' into character buffer 'text'.
*
* #param filename file to read from
* #param text character buffer to read into
*
* #return the number of bytes read.
*/
long read_file(char *filename, char *buff)
{
FILE *fp = fopen(filename, "r");
long size = 0; // Number of characters read.
int len = 0;
if (fp == NULL)
{
fprintf(stderr,"1 Error could not open file: %s\n",strerror(errno));
return -1;
}
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0)
{
/* Get the size of the file. */
size = ftell(fp);
if (size == -1)
{
fprintf(stderr,"2 Error could not open file: %s\n",strerror(errno));
return -1;
}
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0)
{
fprintf(stderr,"3 Error rewinding to start of file: %s\n",strerror(errno));
return -1;
}
/* Read the entire file into memory. */
len = fread(buff, sizeof(char), (size_t)size, fp);
if (len == 0)
{
fprintf(stderr,"4 Error reading file into memory: %s\n",strerror(errno));
return -1;
}
else
{
buff[++len] = '\0'; /* Add a null-terminator. */
}
}
(void)fclose(fp);
return size;
}
int compute_words(char* fileloc)
{
int wordcount = 0;
int check = 1;
char file;
FILE *f = fopen(fileloc, "r");
while((file=getc(f)) != EOF)
{
if(isspace(file) || file == '\t' || file == '\n')
{
if (check == 0)
{
check++;
wordcount++;
}
}
else
{
check = 0;
}
}
fclose(f);
return wordcount;
}
int compute_lines(char* fileloc)
{
int linecount = 0;
char file;
FILE *f = fopen(fileloc, "r");
while((file=getc(f)) != EOF)
{
if(file == '\n')
linecount++;
}
fclose(f);
return linecount;
}
/* The name of this program. */
const char* program_name;
/* Prints usage information for this program to STREAM (typically
stdout or stderr), and exit the program with EXIT_CODE. Does not
return. */
void print_usage (FILE* stream, int exit_code)
{
fprintf (stream, "Usage: %s options [ inputfile .... ]\n", program_name);
fprintf (stream,
" -h --help Display this usage information.\n"
" -n --num Display my student number.\n"
" -c --chars Print number of characters in FILENAME.\n"
" -w --words Print number of words in FILENAME.\n"
" -l --lines Print number of lines in FILENAME.\n"
" -f --file FILENAME Read from file.\n");
exit (exit_code);
}
/* Main program entry point. ARGC contains number of argument list
elements; ARGV is an array of pointers to them. */
int main (int argc, char* argv[])
{
int pipes[2][2];
pid_t child[2];
int status = 0;
int i;
//printf("\nParents Pro ID is %d\n\n", getpid());
char* fileloc = "/usr/share/dict/words";
char buffer[BUFFSIZE];
char* buff = &buffer[0];
int num = 0, chars = 0, words = 0, lines = 0;
int wordcount = 0;
int linecount = 0;
int next_option;
/* A string listing valid short options letters. */
const char* const short_options = "hncwlf:";
/* An array describing valid long options. */
const struct option long_options[] = {
{ "help", 0, NULL, 'h' },
{ "num", 0, NULL, 'n' },
{ "chars", 0, NULL, 'c' },
{ "words", 0, NULL, 'w' },
{ "lines", 0, NULL, 'l' },
{ "file", 1, NULL, 'f' },
{ NULL, 0, NULL, 0 } /* Required at end of array. */};
/* The name of the file to receive program output, or NULL for
standard output. */
const char* output_filename = NULL;
/* Remember the name of the program, to incorporate in messages.
The name is stored in argv[0]. */
program_name = argv[0];
do
{
next_option = getopt_long (argc, argv, short_options,long_options, NULL);
switch (next_option)
{
case 'h': /* -h or --help */
/* User has requested usage information. Print it to standard
output, and exit with exit code zero (normal termination). */
print_usage (stdout, 0);
case 'n':
num=1;
break;
case 'c':
chars=1;
break;
case 'w':
words=1;
break;
case 'l':
lines=1;
break;
case 'f':
fileloc = optarg;
break;
case '?': /* The user specified an invalid option. */
/* Print usage information to standard error, and exit with exit
code one (indicating abnormal termination). */
print_usage (stderr, 1);
case -1: /* Done with options. */
if(!num && !chars && !words && !lines)
chars=1;words=1;lines=1;
break;
default: /* Something else: unexpected. */
abort ();
}
}
while (next_option != -1);
for(i = 0; i < 3; i++)
{
if (pipe(pipes[i]) != 0)
{
printf("Error pipe %d could not be created\n", i);
exit(1);
}
if ((child[i] = fork()) == -1)//create fork
{
printf("Error fork %d could not be created\n", i);
exit(1);
}
else if (child[i] == 0) //fork successful
{
close(pipes[i][0]);
if(words && child[0]) //child 1
{
int computewords = compute_words(fileloc);
write(pipes[0][1], &computewords, sizeof(computewords));
}
if(lines && child[1]) //child 2
{
int computelines = compute_lines(fileloc);
write(pipes[1][1], &computelines, sizeof(computelines));
}
exit(0);
}
}
for (i = 0; i < 2; i++)
{
wait(&status);
}
if(num)
{
char *z=getenv("USER");
if(z == NULL) return EXIT_FAILURE;
printf("\nStudent number: 12345 and logged in as %s\n", z);
}
if(chars)
printf("\nNumber of Characters in the file:%s:\t%ld\n", fileloc, read_file(fileloc, buff));
if(words)
{
close(pipes[0][1]);
read(pipes[0][0], &wordcount, 50);
close(pipes[0][0]);
printf("\nNumber of Words in the file:%s:\t%d\n", fileloc, wordcount);
}
if(lines)
{
close(pipes[1][1]);
read(pipes[1][0], &linecount, 50);
close(pipes[1][0]);
printf("\nNumber of Lines in the file:%s:\t%d\n", fileloc, linecount);
}
close(pipes[0][0]);
close(pipes[1][0]);
close(pipes[0][1]);
close(pipes[1][1]);
return 0;
}
There's something else going on here - an if statement will work if you're getting the expected arguments. Try debugging the main program as it appears you have an error in your option parsing.
Consider the following case statement:
case -1: /* Done with options. */
if(!num && !chars && !words && !lines)
chars=1;words=1;lines=1;
break;
You have an if without braces around the assignments. Just because the statements are on the same line, doesn't mean the parser understands your intent. Instead it'll be parsed as such:
case -1: /* Done with options. */
if(!num && !chars && !words && !lines)
chars=1;
words=1;
lines=1;
break;
Which certainly will lead to unexpected behavior.
if(!num && !chars && !words && !lines)
chars=1;words=1;lines=1;
is equivalent to
if(!num && !chars && !words && !lines)
chars=1;
words=1;
lines=1;
You need some braces, or to put everything in a single statement like this:
if(!num && !chars && !words && !lines)
chars=words=lines=1;
Hello I have a project I'm doing and I need my program to run from the command line and be able to read flags and file names that will be used in the program.
This is my current code. It compiles without entering any flags. I don't think my GetArgs does anything. I had help with that part of the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1024
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* count lines, words, and characters in input */
int numInputArgs;
int idx;
void GetArgs (int argc, char **argv){
for (idx = 1; idx < 4; idx++) {
if (strcmp(argv[idx], "-c") == 0) {
printf("Flag -c passed\n");
break;
}
else if (strcmp(argv[idx], "-w") == 0) {
printf("Flag -w passed\n");
break;
}
else if (strcmp(argv[idx], "-l") == 0) {
printf("Flag -l passed\n");
break;
}
else if (strcmp(argv[idx], "-L") == 0) {
printf("Flag -L passed\n");
break;
}
else {
printf("Error: unknown flag\n");
exit(-1);
}
}
}// end GetArgs
void lineWordCount ( ) {
int c, nl, nw, nc, state;
state = OUT; nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN; ++nw;
}
printf("%d %d %d\n", nl, nw, nc);
}
}// end lineWordCount
int main(int argc, char **argv){
GetArgs(argc, argv);
lineWordCount();
printf("Hello");
//fclose( src );
}
You can either use a standard function like getopt() as mentioned by #Joachim, if it is available on your system, or you can code it yourself. If you have a complicated command line syntax, getopt() might be better suited - if you only need to check for a limited set of flags, it might be easier to code it yourself, for example:
void GetArgs (int argc, char **argv){
int idx = 0;
for (idx = 1; idx < argc; idx++) {
if (strcmp(argv[idx], "-a") == 0) {
printf("Flag -a passed\n");
} else if (strcmp(argv[idx], "-b") == 0) {
printf("Flag -b passed\n");
} else if (strcmp(argv[idx], "-c") == 0) {
printf("Flag -c passed\n");
} else {
printf("Error: unknown flag %s\n");
}
}
}
I recommend you to use argtable2 library. I have used it for a long time and I think it is great. There are tutorials available to see how powerful and easy to use it is.
I included the code below, sorry to bother you with so much code. Argument parsing is ok, i checked it out with watches. I've put some printfs to check out where the problem may be and it seems that it doesn't open the file cat receives as argument. It is called from a shell as "cat -b file"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define TRUE 0
#define FALSE 1
void yes(int argc, char *argv[]);
int cat(int argc, char *argv[]);
//#include "cat.h"
//#include "yes.h"
//#include"tee.h"
char buf[50],c[10], *p2,*p, *pch;
int count;
char *matrix[20];
void yes(int argc, char *argv[])
{
int i;
// if (argc >= 2 && *argv[1] == '-')
// {
//printf("ERROR!");
//}
//if (argc == 1)
// {
while (1)
if (puts("y") == EOF)
{
perror("yes");
exit(FALSE);
}
// }
while (1)
for (i = 1; i < argc; i++)
if (fputs(argv[i], stdout) == EOF || putchar(i == argc - 1 ? '\n' : ' ') == EOF)
{
perror("yes");
exit(FALSE);
}
//exit(TRUE);
}
int main(int argc, char *argv[])
{
//p=(char *)malloc(sizeof(char)*50);
do
{
fprintf (stderr, "$ ");
fgets (buf,50,stdin);
p=buf;
fprintf (stderr, "Comanda primita de la tastatura: ");
fputs (buf, stderr);
int i=0,j=0;
//strcpy(p,buf);
strcpy(c,"\0");
while (buf[i] == ' ')
{
i++;
p++;
}
if (buf[i] == '#')
fprintf (stderr, "Nici o comanda, ci e un comentariu!\n");
else
{
j=0;
while (buf[i] != ' ' && buf[i] != '\n')
{
i++;
j++;
}
strncpy (c,p,j);
fprintf (stderr, "%s\n",c);
if (strcmp (c,"yes") == 0)
{
p2 = p+j+1;
pch = strtok (p2," ");
count = 0;
while (pch != NULL)
{
//printf ("%s\n",pch);
matrix[count] = strdup(pch);
pch = strtok (NULL, " ");
count++;
}
yes(count, matrix);
fprintf (stderr, "Aici se va executa comanda yes\n");
}
else if (strcmp (c,"cat") == 0)
{
p2 = p+j+1;
pch = strtok (p2," ");
count = 0;
while (pch != NULL)
{
//printf ("%s\n",pch);
matrix[count] = strdup(pch);
pch = strtok (NULL, " ");
count++;
}
cat(count,matrix);
fprintf (stderr, "Aici se va executa comanda cat \n");
}
else if (strcmp (c,"tee") == 0)
{
//tee();
fprintf(stderr, "Aici se va executa comanda tee\n");
}
fprintf (stderr, "Aici se va executa comanda basename\n");
strcpy(buf,"\0");
}
}
while (strcmp(c, "exit") != 0);
fprintf (stderr, "Terminat corect!\n");
return 0;
}
int cat(int argc, char *argv[])
{
int c ;
opterr = 0 ;
optind = 0 ;
char number = 0;
char squeeze = 0;
char marker = 0;
fprintf(stderr,"SALUT< SUNT IN FUNCTIZE>\n");
while ((c = getopt (argc, argv, "bnsE")) != -1)
switch (c)
{
case 'b' :
number = 1;
break;
case 'n' :
number = 2;
break;
case 'm' :
marker = 1;
break;
case 's' :
squeeze = 1;
break;
case 'E' :
marker = 1;
break;
}
if (optind + 1 != argc)
{
fprintf (stderr, "\tWrong arguments!\n") ;
return -1 ;
}
FILE * fd = fopen (argv[optind], "r");
printf("am deschis fisierul %s ",argv[optind]);
if (fd == NULL)
{
printf("FISIER NULL asdasdasdasdasd");
return 1;
}
char line[1025];
int line_count = 1;
while (!feof(fd))
{
fgets(line, 1025, fd);
printf("sunt in while :> %s",line);
int len = strlen(line);
if (line[len - 1] == '\n')
{
if(len - 2 >= 0)
{
if(line[len - 2] == '\r')
{
line[len - 2] = '\0';
len -= 2;
}
else
{
line[len - 1] = '\0';
len -= 1;
}
}
else
{
line[len - 1] = '\0';
len -= 1;
}
}
if (squeeze == 1 && len == 0)
continue;
if (number == 1)
{
fprintf (stdout, "%4d ", line_count);
line_count++;
}
else if (number == 2)
{
if (len > 0)
{
fprintf (stdout, "%4d ", line_count);
line_count++;
}
else
fprintf (stdout, " ");
}
fprintf(stdout, "%s", line);
if (marker == 1)
fprintf(stdout, "$");
fprintf(stdout, "\n");
}
fclose (fd);
return 0 ;
}
The problem is that when you are using fgets it includes the newline into the string. Thus when you are passing the file name, it is appended with a \n character which was enter when entering the command. So the file name passed is incorrect. Get ride of the new line maybe on these lines (just a pointer):
char *filename = strtok(argv[optind], "\n");
if( filename == NULL)
{
/*What the .... */
Handle error!
}
FILE * fd = fopen (filename, "r");
printf("am deschis fisierul %s ",argv[optind]);
if (fd == NULL)
{
printf("FISIER NULL asdasdasdasdasd");
return 1;
}
Hope this helps!
PS: Debugging process
When fopen fails it sets the errno. To get exact error use strerror(errno); or perror. So adding perror("fopen"); in if(fd == NULL) showed fopen : No such file or directory. Next printing the file name as fprintf(stderr, "\n |%s|\n", argv[optind]); showed file name with newline character i.e.
|hello.txt
|
... then saw fgets. Ah! the new line from there