TAG replacement C string - c

Hope you can give me some light on this:
Have this entry:
BODY
10
<><BODY garbage>body</BODY>
so I have to replace all tags in < > and make the output look like this:
<><10 garbage>body</10>
any ideias?
thanks!

#include <stdio.h>
#include <string.h>
int main (void){
char tag[128];//enough?
char tag_r[128];
char text[1024] = "";//enough? or dynamic array like as vector
int text_pos = 0;
int ch;
enum { OUT, IN };
int status = OUT;
scanf("%127s %127[^\n]%*c", tag, tag_r);
while((ch = getchar())!=EOF){
if(status == OUT){
putchar(ch);
if(ch == '<')
status = IN;
} else {//if(status == IN){
if(ch == '>'){
size_t len = strcspn(text, " \t\n");
if(len && strncmp(text, tag, len)==0){//match start tag(insufficient rigor), ignore case?
printf("%s", tag_r);
printf("%s", text + len);
} else if(text[0]=='/' && strcmp(text+1, tag)==0){//match end tag
printf("/%s", tag_r);
} else {
printf("%s", text);
}
text[text_pos=0]=0;
putchar(ch);
status = OUT;
} else {
text[text_pos++] = ch;//check omitted
text[text_pos] = 0;
}
}
}
if(text_pos)//invalid syntax
printf("%s", text);
return 0;
}

Related

C program in CLion runs perfectly in Debug mode but returns exit code -1073741819 (0xC0000005) when executed normally

I am doing the Advent of Code, and I am trying to do it all in C. I am currently on day three, and I kind of solved it, but as the title says it behaves very strangely in my IDE CLion. Here is the objective.
I would very much like to know why it is not running properly, and finding out why appears to be beyond my capability.
This is my code:
//
// Created by gusta on 2022-12-06.
//
#include "aocio.h"
#include <string.h>
int cexists(char* cp, char c, int length);
char getDuplicate(char* line);
int main() {
FILE* fptr = openFile("../Inputs/day3.txt");
char* line;
while (readLine(fptr, &line)) {
char c = getDuplicate(line);
putchar(c);
}
return 0;
}
char getDuplicate(char* line) { // Returnerar STRING_END om ingen fanns
unsigned int length = strlen(line);
char letters[length/2];
char* cp = &letters[0];
for (int i = 0; i < length/2; i++) {
letters[i] = ' ';
}
for (int index = 0; line[index] != STRING_END; index++) {
if (index < length/2) {
int i_char = cexists(letters, line[index], length/2);
if (i_char == -1) {
*cp = line[index];
cp++;
}
}
else {
if (cexists(letters, line[index], length/2) != -1) {
return line[index];
}
}
}
}
int cexists(char* cp, char c, int length) {
for (int i = 0; i < length; i++) {
if (cp[i] == c) {
return i;
}
}
return -1;
}
Here is aocoi.h (advent of code input output.h):
//
// Created by gusta on 2022-12-01.
//
#ifndef ADVENTOFCODE_AOCIO_H
#define ADVENTOFCODE_AOCIO_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define SIGN_ASCII 45
#define TRUE 1
#define FALSE 0
#endif //ADVENTOFCODE_AOCIO_H
#define STRING_END '\0'
#define NUMBERS_ASCII 48
char* prompt(const char* question) {
printf(question);
char* string = malloc(1);
int curChar = 0, index = 0;
while (curChar != '\n') {
curChar = getchar();
if (curChar == '\n'){
string[index] = STRING_END;
}
else{
if (index > 0) {
string = (char*) realloc(string, index+1);
}
string[index] = curChar;
}
index++;
}
return string;
}
FILE* openFile(const char* fileName) {
FILE *fptr;
fptr = fopen(fileName, "r");
if (fptr == NULL) {
printf("Big fat file error!!\n");
fclose(fptr);
getchar();
exit(-1);
}
return fptr;
}
char readLine(FILE* fptr, char** line) {
int index = 0, end = 0;
char* string = (char *) malloc(1);
char curChar;
do {
end = fscanf(fptr, "%c", &curChar);
if (end == EOF) {
string[index] = STRING_END;
fclose(fptr);
*line = string;
return FALSE;
}
if (curChar == '\n') {
string[index] = STRING_END;
*line = string;
return TRUE;
}
else {
if (index > 0) {
string = (char *) realloc(string, index + 1);
}
string[index] = curChar;
index++;
}
} while (end != EOF);
}
int parseToInt(char* string) {
int numberLength = 0, number = 0;
int sign = FALSE;
for (int index = 0; string[index] != STRING_END; index++) {
numberLength++;
}
for (int index = numberLength-1; index >= 0; index--) {
char curChar = string[index];
if (index == 0 && curChar - SIGN_ASCII == 0) {
sign = TRUE;
continue;
}
if (curChar - NUMBERS_ASCII >= 0 && curChar - NUMBERS_ASCII <= 9) {
int num = (int) (curChar - NUMBERS_ASCII);
num *= (int)(pow(10, numberLength-index-1));
number += num;
}
else {
printf("Felaktig inmatning. parseInt kan bara ta in tal"); // Invalid input. parseInt can only take in numbers
getchar();
exit(-1);
}
}
if (sign == TRUE) {
number *= -1;
}
return number;
}
Through searching the web I found that the error code should mean stack overflow (ha!) or something like that, but I cannot for the life of me find any place in my code where that could occur. All pointers and stuff should be automatically freed - is there something I have missed?
In readLine():
if (index > 0) {
string = (char *) realloc(string, index + 1);
}
string[index] = curChar;
After this section, the buffer has size index+1, therefore string[index] is the last element you can write to. Afterwards, you do
index++;
Now, writing to string[index] is out of bounds, resulting in a buffer overflow. This is what happens when an EOF or EOL is detected.

How to execute a single preprocessor directive in a C file

I have a main.c file containing one or more preprocessor macros defined:
#include <stdio.h>
#define VALUE 12
int main(void) {
printf("This file is in version %s and contains value %d\n", VERSION, VALUE);
return 0;
}
I want to export a main2.c file with only the #define VERSION "1.0" applied to the original source file.
What I tried:
gcc -DVERSION=\"1.0\" -E will apply ALL the preprocessor directives instead of the single one I want
sed 's/VERSION/\"1.0\"/g' will probably replace more than needed, and will need more work if I need more than a single directive
cppp is a nice tool but may alter the source file a lot. Only supports simple defines with numerical values
Is there any way to execute only parts of preprocessor directives with gcc ?
Partial preprocessing is a nifty idea and exactly what you are looking for. The cppp utility by Brian Raiter only handles #ifdef and #ifndef lines, it does not perform macro substitution as you require.
Here is a utility I just wrote for this purpose: you can define any number of identifiers on the command line with -Didentifier (expands to 1) or -Didentifier= (expands to nothing), -Didentifier=str or simply identifier=str.
It will substitute identifiers only, preserving comments and strings, but some corner cases are not handled, albeit should not be a problem:
no support for non ASCII identifiers.
stdio in #include <stdio.h> will be seen as an identifier that can be substituted.
some numbers will be parsed as 3 tokens: 1.0E+1.
identifiers will not be substituted if they are split on multiple lines with escaped newlines
defining include, ifdef and other preprocessing directives will cause them to be substituted, unlike the C preprocessor
macro argument names may be substituted whereas the C preprocessor would preserve them.
pcpp.c:
/* Partial preprocessing by chqrlie */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct define_t {
struct define_t *next;
size_t len;
const char *tok;
const char *def;
} define_t;
static void *xmalloc(size_t size) {
void *p = malloc(size);
if (!p) {
fprintf(stderr, "pcpp: cannot allocate memory\n");
exit(1);
}
return p;
}
static void add_define(define_t **defsp, const char *str) {
define_t *dp = xmalloc(sizeof(*dp));
size_t len = strcspn(str, "=");
const char *def = str[len] ? str + len + 1 : "1";
dp->len = len;
dp->tok = str;
dp->def = def;
dp->next = *defsp;
*defsp = dp;
}
struct context {
FILE *fp;
int lineno;
size_t size, pos;
char *buf;
};
static int append_char(struct context *ctx, int ch) {
if (ctx->pos == ctx->size) {
size_t new_size = ctx->size + ctx->size / 2 + 32;
char *new_buf = xmalloc(new_size);
memcpy(new_buf, ctx->buf, ctx->size);
free(ctx->buf);
ctx->buf = new_buf;
ctx->size = new_size;
}
ctx->buf[ctx->pos++] = (char)ch;
return ch;
}
static void flush_context(struct context *ctx, FILE *ft) {
if (ctx->pos) {
fwrite(ctx->buf, ctx->pos, 1, ft);
ctx->pos = 0;
}
}
/* read the next byte from the C source file, handing escaped newlines */
static int getcpp(struct context *ctx) {
int ch;
while ((ch = getc(ctx->fp)) == '\\') {
append_char(ctx, ch);
if ((ch = getc(ctx->fp)) != '\n') {
ungetc(ch, ctx->fp);
return '\\';
}
append_char(ctx, ch);
ctx->lineno += 1;
}
if (ch != EOF)
append_char(ctx, ch);
if (ch == '\n')
ctx->lineno += 1;
return ch;
}
static void ungetcpp(struct context *ctx, int ch) {
if (ch != EOF && ctx->pos > 0) {
ungetc(ch, ctx->fp);
ctx->pos--;
}
}
static int preprocess(const char *filename, FILE *fp, const char *outname, define_t *defs) {
FILE *ft = stdout;
int ch;
struct context ctx[1] = {{ fp, 1, 0, 0, NULL }};
if (outname) {
if ((ft = fopen(outname, "w")) == NULL) {
fprintf(stderr, "pcpp: cannot open output file %s: %s\n",
outname, strerror(errno));
return 1;
}
}
while ((ch = getcpp(ctx)) != EOF) {
int startline = ctx->lineno;
if (ch == '/') {
if ((ch = getcpp(ctx)) == '/') {
/* single-line comment */
while ((ch = getcpp(ctx)) != 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 */
flush_context(ctx, ft);
continue;
}
if (ch == '*') {
/* multi-line comment */
int lastc = 0;
while ((ch = getcpp(ctx)) != 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 */
flush_context(ctx, ft);
continue;
}
if (ch != '=') {
ungetcpp(ctx, ch);
}
flush_context(ctx, ft);
continue;
}
if (ch == '\'' || ch == '"') {
int sep = ch;
const char *const_type = (ch == '"') ? "string" : "character";
while ((ch = getcpp(ctx)) != EOF) {
if (ch == sep)
break;;
if (ch == '\\') {
if ((ch = getcpp(ctx)) == EOF)
break;
}
if (ch == '\n') {
fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
filename, ctx->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);
}
flush_context(ctx, ft);
continue;
}
if (ch == '_' || isalpha(ch)) {
/* identifier or keyword */
define_t *dp;
while (isalnum(ch = getcpp(ctx)) || ch == '_')
continue;
ungetcpp(ctx, ch);
for (dp = defs; dp; dp = dp->next) {
if (dp->len == ctx->pos && !memcmp(dp->tok, ctx->buf, ctx->pos)) {
/* matching symbol */
fputs(dp->def, ft);
ctx->pos = 0;
break;
}
}
flush_context(ctx, ft);
continue;
}
if (ch == '.' || isdigit(ch)) {
/* preprocessing number: should parse precise syntax */
while (isalnum(ch = getcpp(ctx)) || ch == '.')
continue;
ungetcpp(ctx, ch);
flush_context(ctx, ft);
continue;
}
flush_context(ctx, ft);
}
if (outname) {
fclose(ft);
}
free(ctx->buf);
return 0;
}
int main(int argc, char *argv[]) {
char *filename = NULL;
char *outname = NULL;
define_t *defs = NULL;
FILE *fp;
int i;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (*arg == '-') {
if (arg[1] == 'h' || arg[1] == '?' || !strcmp(arg, "--help")) {
printf("usage: pcpp [-o FILENAME] [-Dname[=value]] ... [FILE] ...\n");
return 2;
} else
if (arg[1] == 'o') {
if (arg[2]) {
outname = arg + 2;
} else
if (i + 1 < argc) {
outname = argv[++i];
} else {
fprintf(stderr, "pcpp: missing filename for -o\n");
return 1;
}
} else
if (arg[1] == 'D') {
if (arg[2]) {
add_define(&defs, arg + 2);
} else
if (i + 1 < argc) {
add_define(&defs, argv[++i]);
} else {
fprintf(stderr, "pcpp: missing definition for -D\n");
return 1;
}
} else {
fprintf(stderr, "pcpp: bad option: %s\n", arg);
return 1;
}
} else
if (strchr(arg, '=')) {
add_define(&defs, arg);
} else {
filename = arg;
if ((fp = fopen(filename, "r")) == NULL) {
fprintf(stderr, "pcpp: cannot open input file %s: %s\n",
filename, strerror(errno));
return 1;
}
preprocess(filename, fp, outname, defs);
fclose(fp);
}
}
if (!filename) {
preprocess("<stdin>", stdin, outname, defs);
}
return 0;
}
EDIT: This is a non maintainable solution - but it works. Don't use this if you expect your project to grow into several versions over time.
My attempt makes use of preprocessor conditional code and string concatenation (the fact that in C you can do "abc" "def"and it will be trated as "abcdef".
#include <stdio.h>
#ifdef V1
#define VERSION "1"
#define VALUE 99
#else
#define VERSION "2"
#define VALUE 66
#endif
int main(void) {
printf("This file is in version " VERSION " and contains value %d\n", VALUE);
return 0;
}
which prints
>> ~/playground/so$ gcc -DV1 q1.c
>> ~/playground/so$ ./a.out
This file is in version 1 and contains value 99
>> ~/playground/so$ gcc -DV2 q1.c
>> ~/playground/so$ ./a.out
This file is in version 2 and contains value 66
Read about autoconf https://www.gnu.org/software/autoconf/
and maybe even about automaker (if you want to generate makefiles) https://www.gnu.org/software/automake/.

How to get the length of the longest Line in a File in C

this is my first Question here so im grateful for every kind of Help.
Im trying to get the length of the longest Line in a File, so i can later calloc it and read the whole File in. My first attempt was Dynamic, but it didnt work.
My Code till now is:
FILE *inputData;
inputData = fopen("input.txt", "r");
char *input = NULL;
int longestLinelength = 0;
while(fscanf(inputData,"%[^\n]", input) != EOF) {
if(longestLineLength<strlen(input)){
longestLineLength=strlen(input);
}
}
fclose()
This code unfortunetly leads to a memory access error.
size_t longestLine(FILE *fi)
{
size_t largest = 0, current = 0;
int ch;
if(fi)
{
while((ch = fgetc(fi)) != EOF)
{
if(ch == '\n')
{
if(current > largest) largest = current;
current = 0;
}
else
{
current++;
}
}
if(current > largest) largest = current;
}
return largest;
}
I think the problem is not with realloc, but with a misunderstanding of how things work.
It would be best to read carefully what scanf does. And how pointers work.
input is a NULL pointer and you want to write to it, this causes a crash in the application. scanf needs allocated memory to write to, it does not allocate it itself. Generally I would suggest to use fgets instead of scanf as it is better to handle. The formating options of scanf can be done after you read it with fgets.
Probably this help this is based on the book The C Programming Language.
First we need a main function to get the lines in the file
int get_file_line(char line[], int maxline, FILE *fptr) {
int ch, i;
for (i = 0; i < (maxline - 1) && ((ch = getc(fptr)) != EOF) && (ch != '\n'); ++i) {
line[i] = ch;
}
if (ch == '\n') {
line[i] = ch;
++i;
}
line[i] = '\0';
return i;
}
Then we will store the data into a new array of chars
void copy(char to[], char from[]) {
int i = 0;
while (from[i] != '\0') {
to[i] = from[i];
i++;
}
}
And finally in the main function we gonna open the file and use the previous functions
FILE *ptr;
const char *file_name = "your_file.txt";
ptr = fopen(file_name, "r");
while ((len = get_file_line(line, MAXLINE, ptr)) > 0) {
if (len > max) {
max = len;
copy(longest, line);
}
}
fclose(ptr);
if (max > 0) {
printf("longest: %s\n", longest);
printf("len : %d\n", max);
}
All together
#include <stdio.h>
#define MAXLINE 1000
int get_file_line(char line[], int maxline, FILE *fptr) {
int ch, i;
for (i = 0; i < (maxline - 1) && ((ch = getc(fptr)) != EOF) && (ch != '\n'); ++i) {
line[i] = ch;
}
if (ch == '\n') {
line[i] = ch;
++i;
}
line[i] = '\0';
return i;
}
void copy(char to[], char from[]) {
int i = 0;
while (from[i] != '\0') {
to[i] = from[i];
i++;
}
}
int main() {
int len, max = 0;
char line[MAXLINE];
char longest[MAXLINE];
FILE *ptr;
const char *file_name = "your_file.txt";
ptr = fopen(file_name, "r");
while ((len = get_file_line(line, MAXLINE, ptr)) > 0) {
if (len > max) {
max = len;
copy(longest, line);
}
}
fclose(ptr);
if (max > 0) {
printf("longest: %s\n", longest);
printf("len : %d\n", max);
}
return 0;
}
I hope this was helpful
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LENGTH 4096
static void process_file(char *filename);
int main(int argc, char **argv) {
int q;
if(argc <= 1) {
printf("Usage: %s <files>\n", argv[0]);
return 1;
}
for(q = 1; q < argc; q++) {
process_file(argv[q]);
}
return 0;
}
void process_file(char *filename) {
char buf[MAX_LINE_LENGTH] = {0};
FILE *file;
char line_val[MAX_LINE_LENGTH] = {0};
int line_len = -1;
int line_num = -1;
int cur_line = 1;
file = fopen(filename, "r");
if(file == NULL) {
return;
}
while(fgets(buf, MAX_LINE_LENGTH, file) != NULL) {
int len_tmp = strlen(buf) - 1;
if(buf[len_tmp] == '\n')
buf[len_tmp] = '\0';
if(line_len < len_tmp) {
strncpy(line_val, buf, len_tmp + 1);
line_len = len_tmp;
line_num = cur_line;
}
cur_line++;
/*printf("%s", buf);*/
}
fclose(file);
if(line_num < 1) {
return;
}
printf("%d:%s:%d:%s\n", line_len, filename, line_num, line_val);
}

C getting unknown input length

My question was answered in another previous old question here but it was answered with code only & no explanation link.
I would love an answer why the code there works & mine not (what I'm missing?), this is mine:
#include <stdio.h>
#include <stdlib.h>
void get_sentence(char* sentence) {
char end_of_input = 'a', * temp_pointer = NULL;
for (unsigned short int input_index = 0; end_of_input != '\n'; input_index -= -1) {
temp_pointer = sentence;
sentence[input_index] = end_of_input = getchar();
printf("%d: %c\n", (1 + input_index), end_of_input);
if (end_of_input == '\n') {
printf("end of input\n");
sentence[input_index] = '\0';
return;
}
sentence = (char*)realloc(sentence, ((int)(input_index + 2)) * sizeof(char));
if (sentence == NULL) {
free(temp_pointer);
return;
}
}
}
void main(int argc, char const* argv[]) {
char* sentence = malloc(sizeof(char));
if (sentence == NULL) {
printf("blyat");
exit(1);
}
get_sentence(sentence);
printf("Answer = ");
for (unsigned short int run = 0; sentence[run] != '\0'; run -= -1)
printf("%c", sentence[run]);
printf("\n");
free(sentence);
exit(0);
}
In the answer code he also does +=16 which is a waste of memory isn't it?.
IT IS WORKING THANK YOU "#Johnny Mopp" ♥.
#include <stdio.h>
#include <stdlib.h>
char* get_sentence() {
char end_of_input = 'a', *sentence = malloc(sizeof(char)), *temp_pointer = NULL;
for (unsigned short int input_index = 0; end_of_input != '\n'; input_index -= -1) {
temp_pointer = sentence;
sentence[input_index] = end_of_input = getchar();
if (end_of_input == '\n') {
sentence[input_index] = '\0';
return sentence;
}
sentence = (char*)realloc(sentence, ((int)(input_index + 2)) * sizeof(char));
if (sentence == NULL) {
free(temp_pointer);
return NULL;
}
}
}
int main(int argc, char const* argv[]) {
char* sentence = get_sentence(&sentence);
if (!sentence)
exit(1);
printf("Answer: %s\n", sentence);
free(sentence);
exit(0);
}

How to empty Char Array and reuse the same in C?

I am trying to read a file. I want to read each line from the file and check if there are any spelling error in that line.
For that I have added condition that data from file will store in buffer until it gets a new line characher '\n'. And after getting this line I want to empty the buffer and re insert the values in that.
Code I am using for the same is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define W_COUNT 23800
#define MAX_LEN 100
char *dict[W_COUNT];
char buffer[MAX_LEN];
int num_words; //No of Words
char *statement[W_COUNT];
char buffer1[MAX_LEN];
void read_dictionary();
void file_read(char *);
void spell_check();
int word_search(char*);
int main(int argc, char*argv[]){
int i;
if(argc < 2){
printf("Expected Filename.\n");
exit(0);
}
read_dictionary();
file_read(argv[1]);
// spell_check();
}
void read_dictionary(){
FILE *fd;
int i = 0;
fd = fopen("dictionary", "r");
while ( fscanf(fd,"%s",buffer) != EOF)
dict[i++] = strdup(buffer);
num_words = i;
fclose(fd);
}
void file_read(char *filename){
FILE *fd;
int i = 0;
char c;
fd = fopen(filename,"r");
/*while ( fscanf(fd,"%s",buffer1) != EOF)
{
word[i++] = strdup(buffer1);
printf("File : %s\n", buffer1);
}*/
while ( ( c = fgetc(fd)) != EOF )
{
buffer1[i++] = tolower(c);
if ( c == '\n')
{
//printf("New Line\n");
spell_check();
buffer1[i] = 0;
}
//buffer1[i] = 0;
}
printf("Statement : %s\n", buffer1);
fclose(fd);
}
void spell_check(){
char *str;
str = strtok(buffer1," .?,!-");
while( str != NULL){
if(!word_search(str))
printf("%s Not found.\n",str);
str = strtok(0," .?,!-");
}
}
int word_search(char *word){
int high, low, mid;
high = num_words - 1;
low = 0;
int found = 0;
while (found == 0){
mid = (low + high) / 2;
if(strcmp(word, dict[mid]) == 0)
return 1;
else if(strcmp(word,dict[mid]) < 0)
high = mid - 1;
else
low = mid + 1;
if ( low > high)
return 0;
}
}
Any suggestions will be appreciated.
Thank you in advance.
while ( ( c = fgetc(fd)) != EOF )
{
buffer1[i++] = tolower(c);
if ( c == '\n')
{
//printf("New Line\n");
spell_check();
i = 0;
buffer1[i] = 0;
}
//buffer1[i] = 0;
}
For each line reading you have to assign the 0 to the i. After that you have to assign the null to the 0th position in the buffer.
You can try the above code for loop it will work.

Resources