Hei!
Tarkoitus olisi saada aikaan sellainen c-kielen funktio, joka hakee kansiosta XML-päätteiset tiedostot. Lisäksi ohjelman pitäisi pystyä palauttamaan nollia ja ykkösiä sen mukaan, onko XML validia vai ei. XML-tiedostot on nyt luotu kansioihin, mutta en osaa poimia niitä sieltä. Kansiossa on siis muillakin päätteillä olevia tiedostoja.
Hakemistossa olevien tiedostojen selvitykseen on eri käyttöjärjestelmissä omat tapansa. Esim. Windowsissa on funktiot FindFirstFile ja FindNextFile, Linuxissa taas voi käyttää funktiota scandir ja kumppaneita. Jos ohjelma on luonteeltaan tilapäinen, helpoin konsti on kuitenkin ohjata käyttöjärjestelmän oma hakemiston listaus väliaikaiseen tiedostoon ja lukea nimet sieltä seuraavaan tapaan.
#include <stdio.h> #include <stdlib.h> int main(void) { FILE *tiedosto; char nimi[50]; /* Windowsissa: */ system("dir /b *.xml > tlista.txt"); /* Linuxissa: system("ls -1 *.xml > tlista.txt"); */ tiedosto = fopen("tlista.txt", "r"); while (!feof(tiedosto)) { fgets(nimi, 50, tiedosto); printf("Tutkitaan tiedostoa %s", nimi); } fclose(tiedosto); return 0; }
XML-tiedoston muodon tarkistus onkin mutkikkaampi juttu. Joudutko tekemään sen alusta alkaen itse vai voiko apuna käyttää jotain ulkoista ohjelmaa?
Joudun tekemään sen luultavasti itse, aivan varma en asiasta tässä vaiheessa ole. Mutta oletan, että sen voisi tehdä niinkin, että haen ensin kaikki tiedostot kansiosta ja tarkistan vasta sen jälkeen, onko kyseessä kunnollinen xml-tiedosto. Ja tämä tulee siis pyörimään Linuxissa. Ja tuo kansio on ihan pysyvä, ei mikään tilapäisesti luotu. Kyseessä on testiohjelma, jonka tarkoituksena on varmistaa, ettei koko softa kaadu, jos xml-tiedosto onkin täynnä kuraa.
Tajusin, että unohdin tuosta tiedostopolusta mainita, että main sijaitsee eri kansiossa kuin nämä xml:t. Hoituuko se ihan tuota yhtä riviä muuttamalla?
system("cd /home/oikea_kansio/ ls -1 *.xml > xmllist.txt");
Koodin tekeminen on siinä mielessä hieman pulmallista, etten pääse itse sitä vielä testaamaan Linux-ympäristössä, joten toiminnallisuutta joutuu vähän arvailemaan.
Ja sain juurikin tiedon, että parserina käytetään Expatia, joten pitääpä tutkailla, kuinka tuo tarkistetaan sillä.
luultavasti se pitäisi olla system("cd /home/oikea_kansio/ && ls *.xml > xmllist.txt");
Selvempi muoto tuolle listauskomennolle on aivan toisenlainen. Listauksen voi kutsua myös jostain muusta hakemistosta, kuin missä nyt ollaan:
system("ls -l /home/xml-data/*.xml > xmllist.txt");
Tuossa esimerkissä tuo xmllist.txt tallentuu siis nykyiseen työhakemistoon. Jos sen pitäisi olla samassa hakemistossa, kuin xml-tiedostojen, niin lisätään vain polku:
system("ls -l /home/xml-data/*.xml > /home/xml-data/xmllist.txt");
Mutta pitäisi tuon tesmunkin cd-esimerkin toimia.
Kiitän tuosta! En tiedä, onko tuo toiminnallisesti sen parempi, mutta ainakin itse näen nyt koodin selkeämpänä.
Onko kukaan käyttänyt tuota Expatia XML-koodin "hyvin-muodostuneisuuden" (anteeksi!) tarkistamiseen? Luin täältä vähän ohjetta parametrien käyttöön: http://www.jclark.com/xml/expat.html
Jos nyt tuon ymmärrän oikein, niin komennolla
xmlwf(d, /home/oikea_kansio/xmllist.txt
sen pitäisi tarkistaa se muoto ja palauttaa 0 tai muuta.
Tuli tässä juurikin mieleen, että jos otan tuolla
system("ls -l /home/xml-data/*.xml > /home/xml-data/xmllist.txt");
kahdesta eri kansiosta tavaraa, niin laittaako se toisella kerralla ne uudemmat vanhojen perään samaan tiedostoon vai kirjoittaako se päälle?
Jos ohjausmerkki on >, uudet tiedot korvaavat vanhan, mutta jos ohjausmerkki on >>, tiedot menevät peräkkäin.
Kun lisäilee parametreja, niin kuinka niistä osan saisi valinnaisiksi eli ettei niitä ole pakko antaa? Voiko niille esim. asettaa oletusarvoksi NULL? Joko aivot tai Google oli jostain syystä kovin nihkeänä...
Mille olet lisäilemässä parametreja? C-kieliselle funktiolleko? C++ sallii oletusarvojen käytön, luonnollisesti kuitenkin vain viimeisille parametreille:
int funktio(int a, int b, int c = 10, int d = 15);
C:ssä sen sijaan pitää käyttää stdarg.h-otsikon tarjoamia mahdollisuuksia:
#include <stdarg.h> void tulosta_luvut(int parametreja, ...) { va_list lista; int i, j; va_start(lista, parametreja); // Annetaan tälle viimeinen (ainoa) nimetty parametri i = 1; while (parametreja > 0) { parametreja--; ++i; // Jostain pitää tietää, mitä tyyppiä parametrit ovat. Yksi tapa on tuo printf:n tapa eli formaattiteksti. Tämä funktio nyt ottaa vain int-tyyppisiä. j = va_arg(lista, int); printf("%d: %d\n", i, j); } va_end(lista); } //... tulosta_luvut(10, 1,2,3,4,5,6,7,8,9,0);
Kiitos Metabolix tuosta! Eiköhän tästä tuolla päästä eteenpäin. Kyseessä on siis C-kielinen testipääohjelma.
Niin tietysti, jos ohjelmalle annettavia komentoriviparametreja tarkoitit, niin nehän välittyvät merkkijonoina. Niitä voi sitten parsia muuhun muotoon sscanf-funktiolla. Ensin voi säätää oletusarvot ja sitten tarkistaa, mitä parametreja on annettu. Patametriin on syytä liittää jokin tunniste alkuun, siis vaikkapa antaa ne muodossa "nopeus=100", jotta selviää, mille muuttujalle arvo pitäisi laittaa. ;) Tässä on vielä varmuuden vuoksi esimerkki, kuinka noita käytetään.
#include <stdio.h> int main(int argc, char **argv) { int i, luku; int nopeus = 100, pituus = 10; for (i = 1; i < argc; ++i) { // Alkaa ykkösestä, argv[0] on komento, jolla ohjelma ajettiin if (sscanf(argv[i], "nopeus=%d", &luku) == 1) { nopeus = luku; } else if (sscanf(argv[i], "pituus=%d", &luku) == 1) { pituus = luku; } else { printf("Tuntematon parametri (%d: %s)\n", i, argv[i]); } } return 0; }
Tein sen ensin tuohon tyyliin, mutta päädyin sitten kuitenkin loppujen lopuksi switch-case -rakenteeseen. Parametrit kun tulee muodossa -vjotain -ulisää jne., niin ne sai omasta mielestäni kätevimmin tuolla rakenteella.
Mitenhän mahdoit saada ne case-rakenteeseen, eihän se tue tekstinpätkiä?
Luovuin tekstinpätkistä em. syystä. Laitoin siis näin:
for (j = 1; j < argc - 1; j += 2) { if (argv[j][0] != '-') { printUsage(); return -1; } switch (argv[j][1]) { case 'd': dir = argv[j+1]; fprintf(stdout, "directory specified: %s\n", dir); break;
Uusi "ongelma" ilmennyt. Debuggaan koodia gdb:llä ja se antaa joidenkin funktioiden kutsun jälkeen seuraavanlaisia rivejä:
0x08048637 in oma_funktio@plt ()
0x0804861c in ?? ()
0xb7f39620 in _dl_runtime_resolve () from /lib/ld-linux.so.2
0xb7f34190 in _dl_fixup () from /lib/ld-linux.so.2
Onko tuo ihan normaalia? Jotenkin nuo kysymysmerkit nostavat verenpainetta.
voisiko joku kertoa miten tuon saa toimimaan windowsissa niin että se hakee ne toisesta hakemistosta? en saanut toimimaan vaikka kuinka yritin...
ThaFox: Et kertonut, mitä debuggeri valittaa, vaan vain sen, missä se valittaa.
krey:
dir /w [polku]
Nyt on sit ohitettu nuokin ja päästy siihen vaiheeseen, että Expat-parserin xmlwf-nimisellä palasella pitäisi tarkistaa XML-tiedoston well-formedness (saa ehdottaa suomennosta, joka sopii tähän kohtaan). Eli ohjelma tekee XML-tiedoston muuttujaan "dump". Nyt kutsun sitä:
(system("xmlwf(dump)")
Tämähän ei mene läpi, koska Linux ei tiedä ohjelman muuttujasta mitään. Voisiko tämän kiertää jotenkin?
Eipä mitään enää. Onnistuinkin kiertämään tuon bufferin avulla.
Aihe on jo aika vanha, joten et voi enää vastata siihen.