przetwarzanie pliklu ini w C

0

plik typu

wpis = wartosc wpisu

muszę odczytać za pomocą c. wczytuję po linijce i potem
mając tablice char nazwa i wartsc

if (sscanf(bufor,"%[^=]=%150c",nazwa,wartosc)==2){
           if(strcmp("wpis",nazwa)==0){
        	   wpis=malloc(sizeof(char)*(strlen(wartosc)+1));
        	   strcpy(wpis,wartosc);
           }

ma ktoś lepszy pomysł?

3

Możesz pokazać więcej kodu?
I czemu nie sprawdzisz gotowca, np.:
https://github.com/benhoyt/inih/blob/master/ini.c

0
alagner napisał(a):

Możesz pokazać więcej kodu?

a co chcesz zobaczyć, jak wczytać całą linijkę z pliku do bufora?

I czemu nie sprawdzisz gotowca, np.:
https://github.com/benhoyt/inih/blob/master/ini.c

bo szybciej napisać to co potrzebuję niż nauczyć się jak użyć kobyłę

1

Ja bym użył stałych i ograniczył długość linii do iluś bajtów/ znaków, żeby psikus w pliku nie zrobił bałaganu. Jeśli linia okaże się zbyt długa, najlepiej wywalić użytkownikowi komunikat, że linia jest za długa.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

static const size_t MAX_VALUE_SIZE = 1000;
static const size_t MAX_LINE_SIZE = UINT_MAX - 100;//przykładowa duża wartość

int main() {
	const char* const buffer = "smerf=maruda";//powiedzmy, że tu jest jakieś sprawdzenie długości linii i jej wczytanie
	char key[MAX_VALUE_SIZE];
	char value[MAX_VALUE_SIZE];

	memset(key, 0, MAX_VALUE_SIZE);
	memset(value, 0, MAX_VALUE_SIZE);

	if (MAX_LINE_SIZE < strlen(buffer)) {
		printf("Line to long!\n");
		return 1;
	}

	if (sscanf(buffer,"%[^=]=%150c", key, value) == 2) {
		if (strcmp("smerf", key) == 0) {
			const size_t length = strlen(value) + 1;
			char* dupa = NULL;
			
			if (length >= MAX_VALUE_SIZE) {
				printf("String to long!\n");
				return 2;
			}
			
			dupa = malloc(length * sizeof(char));
			strcpy(dupa, value);
			
			printf("%s\n\n", dupa);
		} else {
			printf("dupa\n");
		}
	}
	
	//tutaj można po sobie posprzątać
	
	return 0;
}

Tutaj nie weryfikowałem jeszcze czy strlen się nie wywali, bo długość linii powinna być sprawdzona przed jej wczytaniem. Teraz taki kod kompiluje się bez problemu poleceniem

gcc -Wall --pedantic -Wextra dupa.c
0

dałam tylko środek, wcześniej sprawdzam  jakie są długie linię w pliku, w tej chwili zresztą jest już dynamicznie podawana wartość

    if (sscanf(buffer,"%[^=]=%150c", key, value) == 2) 

zamiast tego 150

0

A co jak tym 150 utniesz resztę?

1

A co z sekcjami i komentarzami?
https://pl.wikipedia.org/wiki/INI

0

@Miang: poleciłem Ci gotowca, bo Twoje rozwiązanie zadziała dla xyz=123. Ale spróbuj już spacje tam dodać i Ci się wybiedronkuje.
https://godbolt.org/z/8oTGv4Phd
Komentarze i sekcje - tak samo będziesz pisać ręcznie, potem jeszcze pytanie czy będziesz używać cudzysłowów.
@vpiotr polecił regex - można tak. Można zrobić to na piechotę: trim, split on =, potem znowu trim obu. Pytanie jak chcesz to ugryźć.

3

w ogóle dobrym pomysłem bedzie użycie unit testów tu dla różnych przypadków.
http://check.sourceforge.net/doc/check_html/
http://check.sourceforge.net/doc/check_html/check_2.html#Other-Frameworks-for-C

2

A rozważałaś użycie jakiejś gotowej biblioteki?
Jeśli nie jest to zdanie "napisz sam parser ini" to po co marnować czas?

1

Dużo już zostało tu powiedziane, więc wersja edukacyjna, z komentarzami, ale bez unit testów:

#include <stdio.h>

char *get_ini_value(char *input, char *var_name) {

    // skip leading spaces	
	while(*input == ' ' || *input == '\t') input++;

	// find end of var name 
	while(*input && *var_name) {
		
		if (*input == ';' || *input == '[' || *input != *var_name) { 
			return NULL;
		} 
		
		input++;
		var_name++;
	}
	
	// skip spaces before equal char
	while(*input == ' ' || *input == '\t') input++;
	
	// check equal char exists
	if (*input != '=') {
		return NULL;
	}
	
	// skip equal char
       input++;
	
	// skip spaces after equal char
	while(*input == ' ' || *input == '\t') input++;
	
	// return result
	return input;
}

int main(void) {
	char *tekst = "  var1 =   this-is-a-test";
	char *val_ptr;
	if ((val_ptr = get_ini_value(tekst, "var1")) != NULL) {
		printf("value: [%s]\n", val_ptr);
	}
	return 0;
}

https://ideone.com/lwSSe5

Gdyby nie było to oczywiste - wersja ta ignoruje sekcje i komentarze oraz wiodące spacje w wartości.

1

@Miang w komentarzu przycina mi do jednej spacji:
Jak coś takiego chcesz wczytać:

char x[] = "    abc    =      1234    "; /* to chcemy parsować */

to format string do sscanfa powininen być +- taki:

" %[^= ] = %150c"

zakładajac oczywiście, że chcesz pomijać spacje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1