How do I uppercase to lowercase and vice versa COMMENTS in C - c

Is there any way to do uppercase to lowercase and vice versa for COMMENTS?
For example:
*** input_file.c ***
#include <stdio.h>
/* My FIRST program */
void main(void) {
printf("Hello world!\n"); // PRINT Message
}
*** output_file.c ***
#include <stdio.h>
/* mY first PROGRAM */
void main(void) {
printf("Hello world!\n"); // print mESSAGE
}
I've seen codes that lowercase to uppercase strings or chars and vice versa for example with functions help, but is there any similar or any other code that does this work for comments? :
#include <stdio.h>
#include <string.h>
int main()
{
char s[1000];
printf("Enter the string: ");
gets(s);
strlwr(s);
printf("string in lowercase ='%s'\n",s);
return 0;
}
Thank you in advance

Parsing the C syntax is a non trivial task. Here is a small program that strips comments from a C source file. You can modify it to change comments. Hint: start by changing comments to uppercase, then transpose the case of characters.
This program reads the file contents one byte at a time, via a function getcpp that handles the infamous line continuation sequence, \ immediately followed by a newline, and maintains the line number for error messages.
The main() function parses the C syntax including comments, characters constants and string literals. It supports most of the syntax but does not handle trigraphs (an obsolete feature of historical interest only).
As posted, it removes all comments, replacing them with a space or a newline as appropriate. Study the code and see how you can modify it for your purpose. Learning by example is a good method, once you get the program to do what you need, you can try and rewrite one from scratch to hone your skills and make progress.
Here is the code:
/* strip C comments by chqrlie */
#include <errno.h>
#include <stdio.h>
#include <string.h>
/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
int ch;
while ((ch = getc(fp)) == '\\') {
if ((ch = getc(fp)) != '\n') {
ungetc(ch, fp);
return '\\';
}
*lineno_p += 1;
}
if (ch == '\n')
*lineno_p += 1;
return ch;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *ft = stdout;
const char *filename = "<stdin>";
int ch, lineno;
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: %s\n",
filename, strerror(errno));
return 1;
}
}
if (argc > 2) {
if ((ft = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: %s\n",
argv[2], strerror(errno));
return 1;
}
}
lineno = 1;
while ((ch = getcpp(fp, &lineno)) != EOF) {
int startline = lineno;
if (ch == '/') {
if ((ch = getcpp(fp, &lineno)) == '/') {
/* single-line comment */
//putc('/', ft);
//putc('/', ft);
while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n') {
// Do something with the comment character
//putc(ch, ft);
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated single line comment\n",
filename, startline);
break;
}
putc('\n', ft); /* replace comment with newline */
continue;
}
if (ch == '*') {
/* multi-line comment */
int lastc = 0;
//putc('/', ft);
//putc('*', ft);
while ((ch = getcpp(fp, &lineno)) != EOF) {
// Do something with the comment character
//putc(ch, ft);
if (ch == '/' && lastc == '*') {
break;
}
lastc = ch;
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated comment\n",
filename, startline);
break;
}
putc(' ', ft); /* replace comment with single space */
continue;
}
putc('/', ft);
/* keep parsing to handle n/"a//"[i] */
}
if (ch == '\'' || ch == '"') {
int sep = ch;
const char *const_type = (ch == '"') ? "string" : "character";
putc(sep, ft);
while ((ch = getcpp(fp, &lineno)) != EOF) {
putc(ch, ft);
if (ch == sep)
break;;
if (ch == '\\') {
if ((ch = getcpp(fp, &lineno)) == EOF)
break;
putc(ch, ft);
}
if (ch == '\n') {
fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
filename, lineno - 1, const_type);
/* This is a syntax error but keep going as if constant was terminated */
break;
}
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated %s constant\n",
filename, startline, const_type);
break;
}
continue;
}
putc(ch, ft);
}
if (fp != stdin)
fclose(fp);
if (ft != stdout)
fclose(ft);
return 0;
}

I wrote and tested this program that does what you ask assuming that the only true C-comments either begin with // and end with '\n' or begin with /* and end with */
It's not overly efficient as it only reads and writes one character at a time, but I think the code is pretty easy to understand:
#include <stdio.h>
#include <stdlib.h>
int main(int args, char *argv[]){
if(args != 3){ //Ensure the program was run with the proper number of arguments
fprintf(stderr,"USAGE: %s <input file> <output file>\n",argv[0]);
exit(EXIT_FAILURE);
}
FILE *in = fopen(argv[1],"r");
FILE *out = fopen(argv[2],"w");
if(!in || !out){ //Ensure both files opened successfully
fprintf(stderr,in ? "File %s unopenable for writing\n" : "File %s unopenable for reading\n",in ? argv[2] : argv[1]);
exit(EXIT_FAILURE);
}
int first,second;
second = fgetc(in);
if(second == EOF) //Input file is empty
exit(EXIT_SUCCESS);
first = second;
enum {line_comment,multiline_comment, string_text, non_comment} status = non_comment; //Keeps track of what type of text we're reading right now
while((second = fgetc(in)) != EOF){
switch(status){
case line_comment: //Flip the case of every letter until we find a newline
if(second == '\n' && first != '\\') //Allow escaped newlines
status = non_comment;
else if(second >= 'A' && second <= 'Z')
second += 'a'-'A';
else if(second >= 'a' && second <='z')
second -= 'a'-'A';
break;
case multiline_comment: //Flip the case of every letter until we find "*/"
if(first == '*' && second == '/') //We found the end of the comment
status = non_comment;
else if(second >= 'A' && second <= 'Z')
second += 'a'-'A';
else if(second >= 'a' && second <= 'z')
second -= 'a'-'A';
break;
case string_text:
if(second == '"' && first != '\\') //Look for end of string but ignore '\"' as those are allowed in strings
status = non_comment;
break;
case non_comment: //Look for the two-character comment beginnings "//" and "/*"
if(first == '/'){
if(second == '/')
status = line_comment;
else if(second == '*')
status = multiline_comment;
}
else if(second == '"' && first != '\\') //Also check for the beginning of a string
status = string_text;
break;
}
fputc(first,out); //Write last round's possibly-modified char to the output file
first = second;
}
fputc(first,out); //Output the last character of the file
exit(EXIT_SUCCESS); //Close all open files
}

Related

Compute the source code length of C functions

I want to partially automate grading of C code (ANSI C99) for a university course. One property I would like to compute is the number of lines per C function (optionally excluding blank and comment lines).
I am aware of several tools that can filter out blank lines and comment lines in a file, but that would only solve half my problem. I want to separate lines that belong to an individual C function.
I have been told a regex will not work. Is there a clever way to use the gcc preprocessor?
Clang has a switch for printing the syntax tree.
For example, if I run
clang -Xclang -ast-dump -fsyntax-only lc.c
on
lc.c:
int main()
{
}
void f()
{
}
I get:
...
|-FunctionDecl 0x558d2c812890 <lc.c:1:1, line:5:1> line:1:5 main 'int ()'
| `-CompoundStmt 0x558d2c812970 <line:2:1, line:5:1>
`-FunctionDecl 0x558d2c8129c8 <line:7:1, line:9:1> line:7:6 f 'void ()'
`-CompoundStmt 0x558d2c812a68 <line:8:1, line:9:1>
If you write a script that extracts the line numbers from those depth=1 CompoundStmt's that preceded by FunctionDecl's (FunctionDecl + CompoundStmt == function definition) and subtract them, you get the line lengths of the your functions minus 1.
The preprocessor is little more than a tokenizer. You need a proper parser for this.
You can address this problem in 2 steps:
write a C parser that can remove comments
instrument this parser to detect function names and bodies and count the meaningful lines of code. You should consider blank lines and lines consisting of braces and punctuation meaningless ({, {, ,, ;...). This will make your count less dependent on the coding style used by the programmer.
Here is help for the first step: a parser that strips comments:
/* strip C comments by chqrlie */
#include <errno.h>
#include <stdio.h>
#include <string.h>
/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
int ch;
while ((ch = getc(fp)) == '\\') {
if ((ch = getc(fp)) != '\n') {
ungetc(ch, fp);
return '\\';
}
*lineno_p += 1;
}
if (ch == '\n')
*lineno_p += 1;
return ch;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *ft = stdout;
const char *filename = "<stdin>";
int ch, lineno;
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: %s\n",
filename, strerror(errno));
return 1;
}
}
if (argc > 2) {
if ((ft = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: %s\n",
argv[2], strerror(errno));
return 1;
}
}
lineno = 1;
while ((ch = getcpp(fp, &lineno)) != EOF) {
int startline = lineno;
if (ch == '/') {
if ((ch = getcpp(fp, &lineno)) == '/') {
/* single-line comment */
while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n')
continue;
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated single line comment\n",
filename, startline);
break;
}
putc('\n', ft); /* replace comment with newline */
continue;
}
if (ch == '*') {
/* multi-line comment */
int lastc = 0;
while ((ch = getcpp(fp, &lineno)) != EOF) {
if (ch == '/' && lastc == '*') {
break;
}
lastc = ch;
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated comment\n",
filename, startline);
break;
}
putc(' ', ft); /* replace comment with single space */
continue;
}
putc('/', ft);
/* keep parsing to handle n/"a//"[i] */
}
if (ch == '\'' || ch == '"') {
int sep = ch;
const char *const_type = (ch == '"') ? "string" : "character";
putc(sep, ft);
while ((ch = getcpp(fp, &lineno)) != EOF) {
putc(ch, ft);
if (ch == sep)
break;;
if (ch == '\\') {
if ((ch = getcpp(fp, &lineno)) == EOF)
break;
putc(ch, ft);
}
if (ch == '\n') {
fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
filename, lineno - 1, const_type);
/* This is a syntax error but keep going as if constant was terminated */
break;
}
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated %s constant\n",
filename, startline, const_type);
break;
}
continue;
}
putc(ch, ft);
}
if (fp != stdin)
fclose(fp);
if (ft != stdout)
fclose(ft);
return 0;
}

How can I detect unterminated comment and write an error message saying "Error: line X: unterminated comment" to the standard error stream in my code?

#include <stdio.h>
#include <stdbool.h>
void m_cmnt(FILE *fp) {
int prev;
int ch;
while ((ch = getc(fp)) != EOF) {
if (prev == '*' && ch == '/') {
return;
} else
prev = ch;
}
}
int main(int c, char **arr) {
FILE *fp, *np;
int ch, prev;
bool String = 0;
fp = fopen("test.txt", "r");
np = fopen("temp.txt", "w");
if (fp == NULL) {
printf("Invalid/No Filename given as Argument ! \n");
return 1;
}
while ((ch = getc(fp)) != EOF) {
if (!String) {
if (ch == '/') {
prev = ch;
ch = getc(fp);
switch (ch) {
case '*':
/* if(ch != 'a') putc('h', np); */
m_cmnt(fp);
putc(' ', np);
break;
default:
putc(prev, np);
putc(ch, np);
break;
}
} else
putc(ch, np);
} else
putc(ch, np);
if (ch == '\"' || ch == '\'')
String = !String;
prev = ch;
}
fclose(fp);
fclose(np);
remove(arr[1]);
//rename("temp.txt", arr[1]);
return 0;
}
This is a simple de-commenting C program (which is C pre-processor job). I was struggling adding a feature to write an error message when detecting unterminated comment (/* example) to the standard error stream. The error should say something like Error: line X: unterminated comment where X is the line number the error occurred. I have been trying this for days now and I can't make any progress and I am highly frustrated. So please someone help me with simple and to the point answer.
test.txt
hello\nworld
Me/*some\ncomment*/again
The result of test.txt after the program run should be like
hello
world
me
again
Both of them are in separate line because \n is present in each case. But what I am getting right now is
hello\nworld
Me again
You can modify the m_cmnt() function to output the error message if it encounters EOF while scanning for */:
void m_cmnt(FILE *fp) {
int prev, ch;
for (prev = 0; (ch = getc(fp)) != EOF; prev = ch) {
if (prev == '*' && ch == '/')
return;
}
fprintf(stderr, "error: unterminated comment\n");
}
If you want to output the line number, you must keep track of the line count everywhere.
Note also that you should handle // comments too and parse the strings more accurately, handling escape sequences.
Here is a version with line number handling:
#include <stdio.h>
#include <stdbool.h>
/* skip a C multi-line comment, return the last byte read or EOF */
int m_cmnt(FILE *fp, int *lineno_p) {
int prev, ch, replacement = ' ';
for (prev = 0; (ch = getc(fp)) != EOF; prev = ch) {
if (ch == '\n') {
replacement = '\n';
++*lineno_p;
}
if (prev == '*' && ch == '/')
return replacement;
}
return EOF;
}
int main(int c, char **arr) {
FILE *fp, *np;
int ch;
bool String = 0;
const char *filename = "test.txt";
int lineno = 1;
fp = fopen(filename, "r");
np = fopen("temp.txt", "w");
if (fp == NULL) {
printf("cannot open input file %s\n", filename);
return 1;
}
while ((ch = getc(fp)) != EOF) {
if (ch == '\n')
lineno++;
if (!String) {
if (ch == '/') {
ch = getc(fp);
if (ch == '\n')
lineno++;
if (ch == '*') {
int startline = lineno;
ch = m_cmnt(fp, &lineno);
if (ch == EOF) {
fprintf(stderr, "%s:%d: error: unterminated comment started on line %d\n",
filename, *lineno, startline);
break;
}
putc(ch, np);
} else {
putc('/', np);
putc(ch, np);
}
} else {
putc(ch, np);
}
} else {
putc(ch, np);
}
if (ch == '\"' || ch == '\'')
String = !String;
}
fclose(fp);
fclose(np);
remove(arr[1]);
//rename("temp.txt", arr[1]);
return 0;
}
For illustration, here is a more complete program that handles all special cases for character and string constants and escaped newlines:
/* strip C comments by chqrlie */
#include <errno.h>
#include <stdio.h>
#include <string.h>
/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
int ch;
while ((ch = getc(fp)) == '\\') {
if ((ch = getc(fp)) != '\n') {
ungetc(ch, fp);
return '\\';
}
++*lineno_p;
}
if (ch == '\n')
++*lineno_p;
return ch;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *ft = stdout;
const char *filename = "<stdin>";
int ch, lineno;
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: %s\n",
filename, strerror(errno));
return 1;
}
}
if (argc > 2) {
if ((ft = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: %s\n",
argv[2], strerror(errno));
return 1;
}
}
lineno = 1;
while ((ch = getcpp(fp, &lineno)) != EOF) {
int startline = lineno;
if (ch == '/') {
if ((ch = getcpp(fp, &lineno)) == '/') {
/* single-line comment */
while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n')
continue;
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated single line comment\n",
filename, startline);
break;
}
putc('\n', ft); /* replace comment with newline */
continue;
}
if (ch == '*') {
/* multi-line comment */
int lastc = 0, replacement = ' ';
while ((ch = getcpp(fp, &lineno)) != EOF) {
if (ch == '/' && lastc == '*') {
break;
}
if (ch == '\n')
replacement = '\n';
lastc = ch;
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated comment\n",
filename, startline);
break;
}
putc(replacement, ft); /* replace comment with single space */
continue;
}
putc('/', ft);
/* keep parsing to handle n/"a//"[i] */
}
if (ch == '\'' || ch == '"') {
int sep = ch;
const char *const_type = (ch == '"') ? "string" : "character";
putc(sep, ft);
while ((ch = getcpp(fp, &lineno)) != EOF) {
putc(ch, ft);
if (ch == sep)
break;;
if (ch == '\\') {
if ((ch = getcpp(fp, &lineno)) == EOF)
break;
putc(ch, ft);
}
if (ch == '\n') {
fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
filename, lineno - 1, const_type);
/* This is a syntax error but keep going as if constant was terminated */
break;
}
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated %s constant\n",
filename, startline, const_type);
break;
}
continue;
}
putc(ch, ft);
}
if (fp != stdin)
fclose(fp);
if (ft != stdout)
fclose(ft);
return 0;
}

I need to fix this two problems in the program. Based on the inputs, I need a fix on the code to produce the desired output

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void handle(FILE *np)// this is to handle newline characters
{
putc('\n', np);
}
/* skip a C multi-line comment, return the last byte read or EOF */
int m_cmnt(FILE *fp, int *lineno_p) {
FILE *np = stdout;
int prev, ch, replacement = ' ';
for (prev = 0; (ch = getc(fp)) != EOF; prev = ch) {
if (prev == '\\' && ch == 'n') {
replacement = '\n';
++*lineno_p;
}
if (prev == '*' && ch == '/')
return replacement;
}
return EOF;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *np = stdout;
int ch,prev;
bool String = 0;
const char *filename = "<stdin>";
int lineno = 1;
fp = fopen(filename, "r");
np = fopen(argv[2], "w");
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: \n",
filename);
exit(EXIT_FAILURE);
}
}
if (argc > 2) {
if ((np = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: \n",
argv[2]);
exit(EXIT_FAILURE);
}
}
while ((ch = getc(fp)) != EOF) {
if (ch == '\n')
lineno++;
/* file pointer currently not inside a string */
if (!String) {
if (ch == '/') {
ch = getc(fp);
if (ch == '\n')
lineno++;
if (ch == '*') {
int startline = lineno;
ch = m_cmnt(fp, &lineno);
if (ch == EOF) {
fprintf(stderr, "%s:%d: error: unterminated comment started on line %d\n",
filename, lineno, startline);
exit(EXIT_FAILURE);
break;
}
putc(ch, np);
} else {
putc('/', np);
putc(ch, np);
}
}
else if ( ch=='\\')/*to handle newline character*/
{
prev=ch ;
ch= getc(fp) ;
switch(ch)
{
case 'n' :
handle(np);
break ;
/*default :
putc(prev , np) ;
putc(ch , np) ;
break ;*/
}
}
else {
putc(ch, np);
}
} else {
putc(ch, np);
}
if (ch == '"' || ch == '\'')
String = !String;
}
fclose(fp);
fclose(np);
//remove(arr[1]);
//rename("temp.txt", arr[1]);
return EXIT_SUCCESS;
}
I have been working on this project for almost more than a week now. I have asked many questions on this site to help me get the desired result.The basics of this program is to remove multiline comments from source file and write the rest to some output file. It also need to to ignore any thing that is inside a string literal or character literal(like escaped characters). Now I have come to finalize it but I still need to achieve this two outputs shown below
INPUT1 = //*SOMECOMMENT*/
OUTPUT1 = /
INPUT2 = "this \"test"/*test*/
OUTOUT2 = "this \"test"
The current(erroneous) output is shown below
INPUT1 = //*SOMECOMMENT*/
OUTPUT1 = //*SOMECOMMENT*/ This is wrong.
INPUT2 = "this \"test"/*test*/
OUTOUT2 = "this \"test"/*test*/ This is also wrong.
The program don't work for the case where a comment comes after a forward slash(/) and the second failure of the program is it don't ignore escape character inside a string or character literal. I need a fix on this two problems please.
If your problem is that you want to read an input stream of characters, divide that stream into tokens, and then emit only a subset of those tokens, I think Lex is exactly the tool you're looking for.
If I understand your comment correctly, the file you're trying to read in and transform is itself C code. So you will need to build up a Lex definition of the C language rules.
A quick search turned up this Lex specification of the ANSI C grammar. I cannot vouch for its accuracy or speak to its licensing. At first glance it seems to only support C89. But it is probably enough to point you in the right direction.

Getting rid of all comments in C

Right now this code doesn't remove inline comments, how do I change it so it also removes inline comments?
FILE *output;
output = fopen("preprocess_output.c", "w");
while (fgets(line, LINE_LENGTH, file) != NULL)
{
for (int i = 0; i < strlen(line); i++)
{
if (line[i] == '/' && line[i + 1] == '/')
{
comment_lines++;
}
else
{
fprintf(output, line);
}
if (line[i] != '\n' && line[i] != '\t')
{
non_blank++;
break;
}
}
}
Here is a small program that strips C comments in almost all cases.
/* strip C comments by chqrlie */
#include <errno.h>
#include <stdio.h>
#include <string.h>
/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
int ch;
while ((ch = getc(fp)) == '\\') {
if ((ch = getc(fp)) != '\n') {
ungetc(ch, fp);
return '\\';
}
*lineno_p += 1;
}
if (ch == '\n')
*lineno_p += 1;
return ch;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *ft = stdout;
const char *filename = "<stdin>";
int ch, lineno;
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: %s\n",
filename, strerror(errno));
return 1;
}
}
if (argc > 2) {
if ((ft = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: %s\n",
argv[2], strerror(errno));
return 1;
}
}
lineno = 1;
while ((ch = getcpp(fp, &lineno)) != EOF) {
int startline = lineno;
if (ch == '/') {
if ((ch = getcpp(fp, &lineno)) == '/') {
/* single-line comment */
while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n')
continue;
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated single line comment\n",
filename, startline);
break;
}
putc('\n', ft); /* replace comment with newline */
continue;
}
if (ch == '*') {
/* multi-line comment */
int lastc = 0;
while ((ch = getcpp(fp, &lineno)) != EOF) {
if (ch == '/' && lastc == '*') {
break;
}
lastc = ch;
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated comment\n",
filename, startline);
break;
}
putc(' ', ft); /* replace comment with single space */
continue;
}
putc('/', ft);
/* keep parsing to handle n/"a//"[i] */
}
if (ch == '\'' || ch == '"') {
int sep = ch;
const char *const_type = (ch == '"') ? "string" : "character";
putc(sep, ft);
while ((ch = getcpp(fp, &lineno)) != EOF) {
putc(ch, ft);
if (ch == sep)
break;;
if (ch == '\\') {
if ((ch = getcpp(fp, &lineno)) == EOF)
break;
putc(ch, ft);
}
if (ch == '\n') {
fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
filename, lineno - 1, const_type);
/* This is a syntax error but keep going as if constant was terminated */
break;
}
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated %s constant\n",
filename, startline, const_type);
break;
}
continue;
}
putc(ch, ft);
}
if (fp != stdin)
fclose(fp);
if (ft != stdout)
fclose(ft);
return 0;
}
Since you get a full answer for free, try and learn how the above code handles strings and escaped newlines. There are still some corner cases that are not supported, can you find them?
one such corner case is the code does not parse trigraphs, an obsolescent feature that may be used to hide \ characters.
in the following solution, there is a single pass over the line. If a comment was found (//), we terminate and print it. supporting (/* */) requires more work.
while (fgets(line, LINE_LENGTH, file) != NULL)
{
size_t len = strlen(line);
size_t i;
for (i=0; i<len; i++)
{
if (line[i]=='/' && line[i + 1]=='/')
{
line[i] = '\0';
break;
}
}
fprintf(output, "%s", line);
}
note to two points in addition to the logic:
when printing using printf, always use a format string. If the line contains % it might do unexpected things.
do not put strlen in the condition of a loop. It generates a lot of unnecessary loops to calculate the length.

Implementing fgetc; trying to read word by word

I am trying to read word by word, and below is the logic that I have adopted. This is reading in the words fine, except when it gets to the last word in a line, in which it stores the last word of the current file AND the 1st word of the next new line. Could somebody tell me how I can get this to work?
int c;
int i =0;
char line[1000]
do{
c = fgetc(fp);
if( c != ' '){
printf("%c", c);
line[i++] = c;
}else if((c == '\n')){
//this is where It should do nothing
}else{
line[i] = '\0';
printf("\\0 reached\n");//meaning end of one word has been reached
strcpy(wordArr[counter++].word, line);//copy that word that's in line[xxx] to the struct's .word Char array
i=0;//reset the line's counter
}//if loop end
} while(c != EOF);//do-while end
fp is a file pointer.
HI BABY TYPE MAYBE
TODAY HELLO CAR
HELLO ZEBRA LION DON
TYPE BABY
I am getting (w/o quotes)
"HI"
"BABY"
"TYPE"
"MAYBE
TODAY"
Look at this:
if(c != ' ') {
// ...
} else if(c == '\n') {
// WILL NEVER BE REACHED
}
If c == '\n', then c != ' ' is also true, which means the second block will be skipped, and the first block will run for all '\n' characters, (i.e. they will be printed).
Other answers about line endings are wrong. C FILE *s not opened in binary mode will take care of EOL for you. If you have a file from DOS and you read it on Unix it might create problems, but I doubt that's your problem here, and if it was handling it could be a little more complicated than the answers here show. But you can cross that bridge when you reach it.
The encoding of the line terminating character is different from one operating system to another. In Linux, it is simply '\n', while in Windows and DOS it is '\r\n'. So, depending on your target OS, you may need to change your statement in something like:
if((c == '\r' || (c == '\n'))
{
//...
}
EDIT: after looking closely, I think that what you're doing wrong is that the first if statement is true even when you read the \n, so you should handle it this way:
if((c != ' ') && (c != '\n')){
printf("%c", c);
line[i++] = c;
}
else if((c == '\n') || (c == '\r')){
//this is where It should do nothing
}
else{
//...
}
Try this;
if((c == '\n') || (c == '\r'){
change
if( c != ' ')
to
if( c != ' '&&c!='\n')
this should fix the problem
This works for me (on Linux):
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char **argv)
{
char c;
size_t i = 0;
FILE *file = NULL;
char buffer[BUFSIZ];
int status = EXIT_SUCCESS;
if (argc < 2) {
fprintf(stderr, "%s <FILE>\n", argv[0]);
goto error;
}
file = fopen(argv[1], "r");
if (!file) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1],
strerror(errno));
goto error;
}
while (EOF != (c = fgetc(file))) {
if (BUFSIZ == i) {
fprintf(stderr, "%s: D'oh! Write a program that "
"doesn't use static buffers\n",
argv[0]);
goto error;
}
if (' ' == c || '\n' == c) {
buffer[i++] = '\0';
fprintf(stdout, "%s\n", buffer);
i = 0;
} else if ('\r' == c) {
/* ignore */
} else {
buffer[i++] = c;
}
}
exit:
if (file) {
fclose(file);
}
return status;
error:
status = EXIT_FAILURE;
goto exit;
}

Resources