C read conf file - c

Hello i have a problem when i try to read conf file (line by line)
this is my code :
bool EndWith(const char* haystack, const char* needle)
{
bool rv = 0;
if (haystack && needle)
{
size_t needle_size = strlen(needle);
const char* act = haystack;
while (NULL != (act = strstr(act, needle)))
{
if (*(act + needle_size) == '\0')
{
rv = 1;
break;
}
act += needle_size;
}
}
return rv;
}
FILE *file2 = fopen ("config.conf", "r");
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, file2) != NULL) {
puts(line);
if(EndWith(line, "toto")) {
puts("yes");
}
}
and my conf file :
vm.user_reserve_kbytes = 131072 toto
vm.vfs_cache_pressure = 100 toto
vm.zone_reclaim_mode = 0 toto
My code return 2 "Yes" but if my conf file, if i add a line feed in first line i read my 3 lines and my code return 3 "Yes"
Why ?
i want to return 3 "Yes" without need to add a line feed in line0 of my conf file
bug retrurn :
vm.user_reserve_kbytes = 131072 toto
yes
vm.vfs_cache_pressure = 100 toto
yes
vm.zone_reclaim_mode = 0 toto
correct return (with add a line feed)
yes
vm.user_reserve_kbytes = 131072 toto
yes
vm.vfs_cache_pressure = 100 toto
yes
vm.zone_reclaim_mode = 0 toto
i tested solution Filip Kočica (thanks for your help) but i have same problem :
the code:
bool EndWith(const char* haystack, const char* needle)
{
if (haystack == NULL || needle == NULL)
{
return false;
}
const char* p;
if ((p = strstr(haystack, needle)) != NULL)
{
if (!strcmp(p, haystack + strlen(haystack) - strlen(needle)))
{
return true;
}
}
else
{
return false;
}
return false;
}
int main(int argc, char **argv)
{
FILE *file2 = fopen ("config.conf", "r");
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, file2) != NULL) {
puts(line);
if (EndWith(line, "za"))
{
puts("it does.");
}
}
return 0;
}
my file config.conf :
vm.user_reserve_kbytes = 131072 za
vm.vfs_cache_pressure = 1001 za
vm.zone_reclaim_mode = 01 za

1]
It return's 2 becouse last row doesn't end with new line character \n.
Everytime you call getline it gives you one line from file (If there is another line).
There is no need for checking if this line really end's with NL character.
Just count how many times getline didn't return EOF.
Get puts out of condition
while (fgets(line, line_size, file2) != NULL)
{
puts(line);
puts("yes");
if(EndWith(line, /*special strings*/ ))
{
}
}
2]
bool EndWith(const char* haystack, const char* needle)
{
if (haystack == NULL || needle == NULL)
{
return false;
}
const char* p;
if ((p = strstr(haystack, needle)) != NULL)
{
if (!strcmp(p, haystack + strlen(haystack) - strlen(needle) - 1))
{
return true;
}
}
else
{
return false;
}
return false;
}
int main(int argc, char **argv)
{
FILE *file2 = fopen ("config.conf", "r");
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, file2) != NULL) {
if (EndWith(line, "za"))
{
puts("it does.");
}
puts(line);
}
return 0;
}
config file:
vm.user_reserve_kbytes = 131072 za
vm.vfs_cache_pressure = 1001 za
vm.zone_reclaim_mode = 01 za
OUTPUT:
it does.
vm.user_reserve_kbytes = 131072 za
it does.
vm.vfs_cache_pressure = 1001 za
it does.
vm.zone_reclaim_mode = 01 za

Related

Memory leak with getline C

I am trying to parse a config file with getline but sometimes I have a memory leak and sometimes not.
#define _GNU_SOURCE
#include "parser.h"
#include <stdlib.h>
#include <string.h>
struct global parse_global(char *line, FILE *file)
{
char *log_file = NULL;
bool log = false;
char *pid_file = NULL;
size_t len;
ssize_t nread;
char *saveptr = NULL;
while ((nread = getline(&line, &len, file)) != -1
&& strcmp(line, "[[vhosts]]\n") != 0)
{
char *arg_name = strtok_r(line, " =", &saveptr);
char *arg_value = strtok_r(NULL, " =\n", &saveptr);
if (strcmp(arg_name, "log_file") == 0)
{
log_file = strdup(arg_value);
}
else if (strcmp(arg_name, "log") == 0)
{
if (strcmp(arg_value, "true") == 0)
{
log = true;
}
else
{
log = false;
}
}
else if (strcmp(arg_name, "pid_file") == 0)
{
pid_file = strdup(arg_value);
}
}
return global_init(log_file, log, pid_file);
}
struct vhost parse_vhost(char *line, FILE *file)
{
char *server_name = "my_server";
char *port = NULL;
char *ip = NULL;
char *root_dir = NULL;
char *default_file = NULL;
size_t len;
ssize_t nread;
char *saveptr = NULL;
while ((nread = getline(&line, &len, file)) != -1
&& strcmp(line, "\n") != 0)
{
char *arg_name = strtok_r(line, " =", &saveptr);
char *arg_value = strtok_r(NULL, " =\n", &saveptr);
if (strcmp(arg_name, "server_name") == 0)
{
server_name = strdup(arg_value);
}
else if (strcmp(arg_name, "port") == 0)
{
port = strdup(arg_value);
}
else if (strcmp(arg_name, "ip") == 0)
{
ip = strdup(arg_value);
}
else if (strcmp(arg_name, "root_dir") == 0)
{
root_dir = strdup(arg_value);
}
else if (strcmp(arg_name, "default_file") == 0)
{
default_file = strdup(arg_value);
}
}
return vhost_init(server_name, port, ip, root_dir, default_file);
}
void free_global(struct global g)
{
free(g.pid_file);
free(g.log_file);
}
void free_vhost(struct vhost v)
{
free(v.server_name);
free(v.port);
free(v.ip);
free(v.root_dir);
free(v.default_file);
}
struct server *fileconfig_parser(char *file)
{
FILE *f = fopen(file, "r");
if (!f)
{
perror("cannot open file");
return NULL;
}
char *line = NULL;
size_t len = 0;
ssize_t nread = getline(&line, &len, f);
if (nread == -1 || strcmp(line, "[global]\n") != 0)
{
free(line);
perror("invalid file");
fclose(f);
return NULL;
}
struct global global = parse_global(line, f);
if (global.pid_file == NULL)
{
free_global(global);
fclose(f);
free(line);
return NULL;
}
struct vhost vhost = parse_vhost(line, f);
if (vhost.server_name == NULL || vhost.port == NULL || vhost.ip == NULL
|| vhost.root_dir == NULL)
{
free_global(global);
free_vhost(vhost);
fclose(f);
free(line);
return NULL;
}
struct server *server = server_init(global, vhost);
free(line);
fclose(f);
return server;
}
The memory come from the line allocated by getline but sometimes when I run the programme there is no memory leak and I dont know why.
It seems to me that I free line in every cases.
I also don’t know why it happened randomly.
=================================================================
==1561==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 120 byte(s) in 1 object(s) allocated from:
#0 0x7fad2918a808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
#1 0x7fad28f0e543 in _IO_getdelim /build/glibc-SzIz7B/glibc-2.31/libio/iogetdelim.c:62
#2 0x7ffde0365e1f ([stack]+0x1ee1f)
SUMMARY: AddressSanitizer: 120 byte(s) leaked in 1 allocation(s).

How to Parse an AT command response and one among the fields from the output in C

Im trying to capture the data from the AT command response but im unable to do so.
My Approach.
functions():
#define MAX_LINE_LENGTH (8 * 1024)
static char buf[MAX_LINE_LENGTH];
static char buf2[MAX_LINE_LENGTH];
static bool tr_lf_cr(const char *s)
{
char *p;
p = strchr(s, '\n');
if (p == NULL || p[1] != '\0') {
return false;
}
*p = '\r';
return true;
}
static void strip_cr(char *s)
{
char *from, *to;
from = to = s;
while (*from != '\0') {
if (*from == '\r') {
from++;
continue;
}
*to++ = *from++;
}
*to = '\0';
}
#define STARTS_WITH(a, b) ( strncmp((a), (b), strlen(b)) == 0)
main()
fd = fopen(*mp, "r+b");
if (fd == NULL) {
/* Could not open the port. */
perror("open_port: Unable to open /dev/ttyUSB0\n");
}
char str = '\n';
strncat(cmd, &str, 1);
success = tr_lf_cr(cmd);
if (! success) {
fprintf(stderr, "invalid string: '%s'\n", cmd);
return EXIT_FAILURE;
}
int res = fputs(cmd, fd);
if (res < 0) {
fprintf(stderr, "failed to send '%s' to modem (res = %d)\n", cmd, res);
return EXIT_FAILURE;
}
do {
line = fgets(buf, (int)sizeof(buf), fd);
if (line == NULL) {
fprintf(stderr, "EOF from modem\n");
return EXIT_FAILURE;
}
strcpy(buf2, line);
strip_cr(buf2);
char delim[] = ",";
char *ptr = strtok(buf2, delim);
printf("\n0++++++++++++++++++++\n");
while (ptr != NULL) {
printf("'%s'\n", ptr);
ptr = strtok(NULL, delim);
}
printf("\n1********************\n");
} while (STARTS_WITH(line, "OK") == 0);
I get the following output when i run this command AT^HCSQ?
0++++++++++++++++++++
'AT^HCSQ?
'
0++++++++++++++++++++
'^HCSQ: "WCDMA"'
'64'
'64'
'60'
'0
'
0++++++++++++++++++++
'
'
0++++++++++++++++++++
'OK
'
What i want to achieve is to store each value separately from the buffer like
char p = WCDMA;
int rssi = atoi[ptr];
[etc...]
Im using strtok() to achieve this but im unable to skip the empty lines i get from the response. What should i do here?

realloc : corrupted data returned

I'm trying to read from a file using C and after shrinking the size using realloc I get corrupted data. I don't really see what the problem could be.
Here's the function that returns the string :
char *read_string(FILE *fichier) {
char car = 0;
size_t size = 1;
char *symbole = realloc(NULL, sizeof(char) * size);
char *s;
size_t len = 0;
if (!symbole)
return symbole;
else
s = symbole;
do {
car = getc(fichier);
} while (car != '"' && car != EOF);
if (car == EOF)
return EOFP;
else {
car = getc(fichier);
while (car != '"' ) {
s[len] = car;
car = getc(fichier);
len++;
if (len == size) {
symbole = realloc(s, sizeof(char) * (size += 1));
if (!symbole)
return symbole;
else
s = symbole;
}
}
s[len] = '\0' ;
symbole = realloc(s, sizeof(char) * len);
if (!symbole) {
printf("WTF");
return symbole;
} else
s = symbole;
return s;
}
}
My main function is:
int main(int argc, char *argv[]) {
FILE *fichier = NULL;
fichier = fopen("C:/Users/Nabila K/Documents/test.json", "r");
if ((fichier != NULL)) {
while (feof(fichier) == 0) {
char *test = read_string(fichier);
if (test == NULL) {
printf("test == NULL\n");
exit(1);
} else
if (test == EOFP) {
} else {
printf("%s\n", test);
free(test);
}
}
fclose(fichier);
} else {
exit(EXIT_FAILURE);
}
return 0;
}
UPDATE
My json file looks something like this :
{
"KARIM BENNI" : {
"2017-08-07 09:50:50" : {
"Anomalie" : {
"description" : "Test",
"theme" : "Engins mobiles"
},
"date" : "2017-08-07",
"date_now" : "2017-08-07 09:50:50",
"entite" : "USINE LAMINAGE A FROID",
"etat" : "Cree",
"nb_personne" : 2,
"temps" : 5,
"visiteur" : "KARIM BENNI",
"visite" : "AHMED RABII",
"zone" : "COUPE"
}
}
}
There are multiple issues in your code:
char car = 0; is incorrect: you must define car as int to correctly distinguish all values returned by getc(), especially EOF.
while (feof(fichier) == 0) is always wrong. Learn why there: Why is “while ( !feof (file) )” always wrong?
EOFP is not defined, you should probably use NULL instead for more clarity.
the final realloc() to shrink the allocated block is one byte too short. You must keep len+1 bytes for len characters plus the null terminator.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
char EOFP[1]; /* special value used to signal end of file */
char *read_string(FILE *file) {
int c;
size_t size, len;
char *symbol;
char *s;
while ((c = getc(file)) != '"') {
if (c == EOF)
return EOFP;
}
size = 16;
len = 0;
symbol = malloc(size);
if (symbol == NULL) {
/* allocation failure */
return NULL;
}
while ((c = getc(file)) != '"') {
if (c == EOF) {
/* premature end of file in the middle of a string */
free(symbol);
return EOFP;
}
if (len + 2 < size) {
size += size;
s = realloc(symbol, size);
if (s == NULL) {
/* allocation failure */
free(symbol);
return NULL;
}
symbol = s;
}
symbol[len++] = c;
}
symbol[len] = '\0';
s = realloc(symbol, len + 1);
return s ? s : symbol;
}
int main(int argc, char *argv[]) {
FILE *file = fopen("C:/Users/Nabila K/Documents/test.json", "r");
if (file != NULL)) {
char *test;
while ((test = read_string(file)) != EOFP) {
if (test == NULL) {
printf("test == NULL\n");
exit(1);
} else {
printf("%s\n", test);
free(test);
}
}
fclose(file);
} else {
exit(EXIT_FAILURE);
}
return 0;
}
Notes:
Parsing the full JSON syntax for strings would be required if the strings can contain escaped characters such as \" or \n, \\ etc.

Cannot understand why program crashes after a couple iterations of while loop?

I am writing the following program to parse the text file (attached) but it keeps crashing after couple of iterations of while loop or it seems that the buffer storing file contents is corrupted somehow?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char * pick_question(char *, char, int);
char * print_answer(char *, char, int);
int no_of_questions(char*, char);
void clear();
int debug = 0;
int main(int argc, char* argv[])
{
system("cmd /c chcp 1252");
// system("cmd /c chcp 65001");
if (argc < 2)
{
perror("Please enter a filename!\n");
exit(0);
}
if (argc > 2)
{
debug = atoi(argv[2]);
}
char const* const fileName = argv[1];
FILE* file = fopen(fileName, "r");
if (!file)
{
perror("Unable to read file!\n");
exit(0);
}
else
{
if (debug == 1)
{
printf("File opened successfully\n");
}
}
static char *buffer;
int fileSz;
fseek(file, 0, SEEK_END);
fileSz = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = (char*) malloc((fileSz + 1) * sizeof(char));
if (!buffer)
{
perror("Unable to allocate buffer!");
exit(0);
}
fread(buffer, sizeof(char), fileSz, file);
while (1)
{
time_t t;
srand((unsigned) time(&t));
int sub = rand() % 5 + 1;
char del;
switch (sub)
{
case 1:
del = 'A';
break;
case 2:
del = 'B';
break;
case 3:
del = 'C';
break;
case 4:
del = 'D';
break;
case 5:
del = 'E';
}
int nrOfQues = no_of_questions(buffer, del);
if (nrOfQues == 0)
{
perror("main(): no_of_questions() returned 0. Unsupported text structure in file or incorrect file encoding!");
fclose(file);
exit(0);
}
int qNo = rand() % nrOfQues + 1;
char *ques = pick_question(buffer, del, qNo);
if (ques)
{
printf("\n\n");
puts(ques);
printf("\n\n");
}
else
{
perror("main(): pick_question() returned NULL. Unsupported text structure in file!");
fclose(file);
exit(0);
}
printf("\n\n");
printf("Do you want to see the answer(y/n)?");
char ans, repeat;
scanf("%c", &ans);
if ( ans == 'Y' || ans == 'y')
{
char *ans = print_answer(buffer, del, qNo);
if (ans)
{
printf("\n\n");
puts(ans);
printf("\n\n");
}
else
{
printf("\n\n");
perror("main(): print_answer() returned NULL. Unsupported text structure in file!");
fclose(file);
exit(0);
}
}
printf("Do you want to try more questions (y/n)?");
clear();
scanf("%c", &repeat);
if (repeat == 'N' || repeat == 'n')
{
break;
}
clear();
}
printf("\n\n");
printf("******** Thank you for using TULE Master! ********");
printf("\n\n");
fclose(file);
return 0;
}
char * pick_question(char * buffer, char sub, int qNo)
{
char tmpBuff[20];
char tmpBuff2[20];
const char * searchStr = "FRÅGA";
const char * searchStr2 = "A 1 SVAR:";
const char * searchStr3 = "*****************************************";
char *pStr, *currPos, *nStr, *tmpStr, *tmpStr2;
currPos = buffer;
int count = snprintf(tmpBuff, 20, "FRÅGA %c %d", sub, qNo);
if (count >= 0 || count < 20)
{
if (debug)
{
printf("tmpBuff is %s\n", tmpBuff);
}
currPos = strstr(currPos, tmpBuff);
if (currPos)
{
pStr = currPos;
nStr = currPos + 1;
nStr = strstr(nStr, searchStr);
if (!nStr)
{
nStr = currPos;
nStr = strstr(nStr, searchStr2);
if (!nStr)
{
printf("pick_qestion(): nStr is NULL. Unsupported "
"text structure");
return NULL;
}
}
// Check if it is a scenario based question
count = snprintf(tmpBuff2, 20, "FRÅGA %c %d", sub, qNo-1);
if (count >= 0 || count < 20)
{
tmpStr = strstr(buffer, tmpBuff2);
tmpStr2 = strstr(tmpStr, searchStr3);
if (tmpStr < tmpStr2 && tmpStr2 < pStr)
{
pStr = tmpStr2;
}
}
int qLen = nStr - pStr;
char *ques = malloc(sizeof(char) * (qLen+1));
snprintf(ques,qLen,"%s", pStr);
return ques;
}
else
{
printf("pick_qestion(): string \"FRÅGA\" not found in file!");
return NULL;
}
}
printf("pick_qestion(): snprintf was not successful!");
return NULL;
}
char * print_answer(char * buffer, char sub, int qNo)
{
char tmpBuff[20];
char *pStr, *currPos, *nStr;
int count = snprintf(tmpBuff, 20, "%c %d SVAR:", sub, qNo);
if (count >= 0 || count < 20)
{
currPos = strstr(buffer, tmpBuff);
if (!currPos)
{
printf("print_answer(): string \"SVAR\" not found in file!");
}
pStr = currPos;
nStr = currPos + 1;
char tmpBuff2[20];
int count = snprintf(tmpBuff2, 20, "%c %d SVAR:", sub, qNo+1);
if (count < 0 || count >= 20)
{
printf("print_answer(): snprint was not successful!");
return NULL;
}
nStr = strstr(nStr, tmpBuff2);
if (!nStr)
{
nStr = buffer + strlen(buffer);
}
int ansLen = nStr - pStr;
char *ans = malloc(sizeof(char) * (ansLen+1));
snprintf(ans, ansLen, "%s", pStr);
return ans;
}
printf("print_answer(): snprint was not successful!");
return NULL;
}
int no_of_questions(char *buffer, char sub)
{
char tmpBuff[20];
char *currPos, *pStr;
int count = snprintf(tmpBuff, 20, "FRÅGA %c", sub);
if (count >= 0 || count < 20)
{
if (debug)
{
printf("tmpBuff is %s\n", tmpBuff);
}
currPos = strstr(buffer, tmpBuff);
while (currPos != NULL)
{
pStr = currPos;
currPos = currPos + 1;
currPos = strstr(currPos, tmpBuff);
}
if (pStr != buffer)
{
pStr += 9;
char tmpBuff2[20];
memcpy(tmpBuff2, pStr, 2);
if (debug)
{
printf("No. of questions for %c DEL is are %d\n", sub,
atoi(tmpBuff2));
}
return atoi(tmpBuff2);
}
return 0;
}
return 0;
}
void clear()
{
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
}
This is the file that is given as input to the program:
Link

Write char[] to array

I have the following code which is working but it's kinda annoying to define a variable in each and every line:
char *argv[100];
int argc = 0;
argv[0] = "test";
argc = 1;
char verbose[4], source[20], target[20];
int linenum=0;
while(fgets(line, 256, file) != NULL)
{
char arg[20], value[20];
if(line[0] == '#' || strlen(line) < 6) continue;
linenum++;
if(sscanf(line, "%[^=]=%s", arg, value) != 2)
{
fprintf(stderr,"Syntax error: %s\n",line);
continue;
}
if (value && strcmp(arg,"verbose")==0) {
strncpy(verbose,value,sizeof(verbose) - 1);
argv[argc++] = "-v";
argv[argc++] = verbose;
//argv[argc++] = value; //not working, shows 0
}
if (value && strcmp(arg,"source")==0) {
strncpy(source,value,sizeof(source) - 1);
argv[argc++] = "-s";
argv[argc++] = source;
}
if (value && strcmp(arg,"target")==0) {
strncpy(target,value,sizeof(target) - 1);
argv[argc++] = "-t";
argv[argc++] = target;
}
//and so on
|
|
|
|
}
How can I copy to a single char the "value" from inside the loop ? I mean by avoiding the usage of strncpy().
You can use a table like this:
int source_checker(char *value) { /* .... */; return 0; }
int verbose_checker(char *value) { /* .... */; return 0; }
int target_checker(char *value) { /* .... */; return 0; }
typedef int (*checker_function)(char *);
const char *label_table[] = { "source", "verbose", "target", 0 };
checker_function checker_table[] = { source_checker, verbose_checker,
target_checker, 0 };
typedef enum { tk_source, tk_verbose, tk_target, tk_END } token;
while(fgets(line, 256, file) != NULL)
{
// ...
for (size_t i = tk_source; i < tk_END; i++) {
if (value && strcmp(arg, label_table[i]) == 0) {
if (checker_table[i](value)) {
break;
}
}
}
You can use a loop for each of your if conditions, and store the differing values in arrays populated beforehand.
If you are trying to save a few lines of code, you could do this
#include <string.h>
....
char* tempstrings[100];
int temps=0;
..
if (value && strcmp(arg,"verbose")==0) {
argv[argc++] = "-v";
argv[argc++] = tempstrings[temps++] = strdup(value);
}
...
// at the end of the program, clean up all the temporary strings
for(int i=0;i<temps;i++) free(tempstrings[i];

Resources