cURL einfach in C verwenden?


  • Mod

    popen funktioniert wie fopen. Man bekommt ein Dateihandle zurück, über das man dann lesend (über die ganz normalen Dateilesefunktionen, also fscanf, fread, usw.) auf die Ausgaben des geöffneten Prozesses zugreifen kann.



  • Und genau dafür steht ein Beispiel im Link.
    Willst du C programmieren, musst du sowieso mit fgets() usw. umgehen können.



  • Wutz schrieb:

    Und genau dafür steht ein Beispiel im Link.
    Willst du C programmieren, musst du sowieso mit fgets() usw. umgehen können.

    Ich hab mich mal an das Beispiel im Link gehalten:

    #include <stdio.h>
    #include <curl/curl.h>
    
      int main(void)
      {
    	FILE *fp;
        int status;
        char path[PATH_MAX];
    
        fp = popen("curl -H \"Authorization: \" -X GET \"url\"","w");
        /* Durch das Aufrufen von Curl werden die Daten in die Konsole geschrieben,
    das 1. Mal. */
    
        if (fp == NULL)
            /* Handle error */;
    
        while (fgets(path, PATH_MAX, fp) != NULL)
            printf("%s", path);
        /* Nach dieser Zeile erwarte ich, dass die Daten erneut ausgegeben werden. 
    Die Datei fp wurde in den String path eingelesen und müsste doch mit printf ausgegeben werden. */
    
        printf(path);
    /* ich hab diese Zeile eingefügt um halt nochmal händisch path auszugeben. Passiert nicht. */
    
        status = pclose(fp);
    
        if (status == -1) {
            /* Error reported by pclose() */
    
        } else {
        /* Use macros described under wait() to inspect `status' in order
           to determine success/failure of command executed by popen() */
    
        }
    
        // printf(path);
    
        return 0;
      }
    

    Wenn ich das Programm übersetze, werden die Daten einmal in die Konsole geschrieben. Ich erwarte aber, dass es 3 mal gemacht wird.
    Mit printf (path) scheint auch keine Ausgabe zu funktionieren.

    Letztenendes ist es doch egal, was mir popen für eine Datei zurückliefert, oder? Mit fgets wird daraus ein String und den müsste ich doch anzeigen lassen. Komplett oder Stückchenweise.



  • Du musst popen mit "r" statt "w" verwenden.



  • qweet schrieb:

    printf(path);
    

    Sowas sollte man sich nicht angewöhnen, denn der String könnte Format-Specifier enthalten (Stichwort: "format string vulnerability").



  • Wutz schrieb:

    Du musst popen mit "r" statt "w" verwenden.

    Da ist es ähnlich. Es wird zwar noch angezeigt, wie schnell die Daten gekommen sind und ob alle Daten abgerufen sind.

    Aber es wird nur 1x ausgegeben. Anscheinend ist nur

    while (fgets(path, PATH_MAX, fp) != NULL)
            printf("%s", path);
    

    dafür zuständig.

    ein

    printf("%s",path);
    

    macht leider nichts.

    Dann noch eine andere Frage: Ist es in Ordnung in diesem Forum/Thread auch nach der Einstellung von Codeblocks und libcurl zu fragen?
    Curl hab ich zwar die Verzeichnisse angegeben, aber ich muss noch den Linker einrichten.
    Angeblich ist libcurl bei curl mit dabei, ich find es aber nicht. Hab nur eine dll - Datei von libcurl.

    edit: Zwecks der ordentlichen Einrichtung von libcurl und Codeblocks werd ich wohl in einem anderen Forum fragen. Leider englisch. naja.



  • Du gehst offenbar davon aus, dass nach dem Durchlaufen der while-Schleife die eingelesen Daten komplett in 'path' zur Verfügung stehen und dann mit nur einem printf auch beliebig oft komplett ausgegeben werden können. Dem ist aber nicht so, im Normalfall (Schleife beendet wegen EOF) befindet sich dort dann der Inhalt der letzten erfolgreichen Leseoperation von fgets, oder, etwas vereinfacht, die letzte gelesene Zeile. Das könnte z.B. auch nur eine Leerzeile sein, demzufolge dein zusätzliches printf dann nur einen Zeilenvorschub ausgeben würde.


  • Mod

    Bezüglich Compiler&IDE-Fragen: Dafür gibt es hier ein anderes Unterforum. Bitte solche Fragen nicht im C-Forum stellen.



  • printf(path) schrieb:

    Das könnte z.B. auch nur eine Leerzeile sein, demzufolge dein zusätzliches printf dann nur einen Zeilenvorschub ausgeben würde.

    Sowas kannst du mit Begrenzern vor und nach dem String feststellen.

    printf("<%s>",path);
    

    Wenn dann in der Konsole nur <> steht, war es ein Leerstring.
    Bei
    <

    ist zumindest ein Zeilenvorschub drin.

    Oder du nimmst den Debugger.



  • printf(path) schrieb:

    Du gehst offenbar davon aus, dass nach dem Durchlaufen der while-Schleife die eingelesen Daten komplett in 'path' zur Verfügung stehen und dann mit nur einem printf auch beliebig oft komplett ausgegeben werden können. Dem ist aber nicht so, [...]

    Ja stimmt, davon bin ich ausgegangen. Ich möchte die Daten doch dann dauerhaft im Programm verwenden. Brauch ich vielleicht einen anderen Befehl als fgets?

    Oder muss ich jedesmal die while Schleife haben um die Datei zu lesen? Ich denke, das geht auch, find ich aber nicht sehr schön.

    Ich dachte es funktioniert so:

    1. Daten vom Server holen und in Datei schieben
    2. Datei in String übergeben
    3. Beliebig oft auf diesen String zugreifen. Einzelne oder alle Zeichen.



  • Entweder du weist curl an,

    - die gewünschten Daten gleich eine Datei zu speichern: dann musst du die Datei anschließend ständig (zeilenweise) einlesen oder einmal in eine Stringliste einlesen aus der du dich dann beliebig oft bedienen kannst
    - du lässt curl die Daten auf stdout ausgeben: dann kannst du via popen+fgets+pclose gleich in eine Stringliste einlesen (ohne Zwischendatei) und diese Stringliste im Programm beliebig verarbeiten


  • Mod

    qweet schrieb:

    Ja stimmt, davon bin ich ausgegangen. Ich möchte die Daten doch dann dauerhaft im Programm verwenden. Brauch ich vielleicht einen anderen Befehl als fgets?

    popen gibt dir, wie schon erwähnt, einen ganz normalen Dateistream (außer dass Hin- und Herspringen wahrscheinlich nicht funktioniert). Den kannst du auslesen, wie es dir gefällt und wie auch immer du die Daten hinterher im Programm haben musst. Das muss also nicht durch fgets geschehen. Man muss aber natürlich die üblichen Lesefunktionen kennen und was wissen, wie man die Daten in eine gewünschte Form bringt. Ein bisschen Erfahrung ist also schon nötig.

    Du solltest dich von der Vorstellung trennen, dass das irgendwelche geheimnisvolle Magie wäre. Würdest du mit dem Einlesen zurecht kommen, wenn jemand die curl-Ausgabe ausdrucken und von Hand in dein Programm eintippen würde? Oder wenn die Daten als Datei gespeichert wären? Falls ja, dann gibt es überhaupt kein Problem, denn dann erfolgt das Lesen des popen-Streams einfach exakt genau so, wie du es bei der manuellen Eingabe oder bei der Datei machen würdest. Falls nein, dann hast du ein anderes Problem, nämlich dass du nicht genug Übung in C hast, um einfache Ein-/Ausgabeoperationen selber zu programmieren.



  • SeppJ schrieb:

    [...] Man muss aber natürlich die üblichen Lesefunktionen kennen und was wissen, wie man die Daten in eine gewünschte Form bringt. Ein bisschen Erfahrung ist also schon nötig.

    Da muss ich passen, kenne mich überhaupt nicht aus.

    SeppJ schrieb:

    [...]nämlich dass du nicht genug Übung in C hast, um einfache Ein-/Ausgabeoperationen selber zu programmieren.

    Oje, ich hab überhaupt keine Übung in C. Kennst du ein gutes deutsches Buch als Einstieg? Ich suche aber eins wo gut erklärt wird, wie man Bibliotheken einbindet.

    Vielleicht sollte ich mir die Programmierleistung auch kaufen. Ich möchte aber gern den Quellcode haben. Kennt ihr da vielleicht was? Ich hab jetzt twago.de gefunden.

    Mit Curl kommen die Daten in stdout. Ich kann sie auch in eine Datei schicken, leider nur in einem speziellen Verzeichnis.
    Wenn ich

    popen("curl -H \"Authorization: \" -X GET \"url\" -o C:\Verzeichnis\fdsa.txt","r");
    

    wird die Datei nicht erstellt.



  • Der Backslash leitet eine Esacapesequenz ein.
    Den musst du genauso behandeln wie Anführungszeichen im Stringliteral.

    Denn ein Seitenvorschub '\f' kommt im Dateinamen nicht so gut.

    Aber das gilt nicht nur für C sondern in vielen Programmiersprachen.



  • DirkB schrieb:

    Der Backslash leitet eine Esacapesequenz ein.
    Den musst du genauso behandeln wie Anführungszeichen im Stringliteral.[...]

    Und wie mach ich das?

    Meine einzige Referenz ist z.Z. https://de.wikibooks.org/wiki/C-Programmierung

    Ich hab es versucht mit zwei \
    also C:\\Verzeichnis\\

    funktioniert aber auch nicht.



  • qweet schrieb:

    Und wie mach ich das?

    Meine einzige Referenz ist z.Z. https://de.wikibooks.org/wiki/C-Programmierung

    Steht doch drin: https://de.wikibooks.org/wiki/C-Programmierung:_Variablen_und_Konstanten#Kodierung_von_Zeichenketten

    qweet schrieb:

    Ich hab es versucht mit zwei \
    also C:\\Verzeichnis\\

    funktioniert aber auch nicht.

    Hast du wirklich Verzeichnis da stehen oder etwas anderes?



  • Ich wollte euch mal meine Lösung vorstellen:

    int main(void) {
        FILE *fp;
        int i=0, j=0;
        int c;
        int string[PATH_MAX];
    
        fp = popen("curl -H \"Authorization: \" -X GET \"url\"","r");
    
        if (fp == NULL) {
            printf("Konnte Datei nicht öffnen!\n");
        }
    
        while( (c=fgetc(fp)) != EOF) {
             string[i] = c;
             i++;
        }
        fclose (fp);
        j = i;
    
        for(i=0; i<=j; i++) {
            putchar(string[i]);
        //    printf ("%i",string[i]);
        }
    
        return 0;
    }
    

    Ich lese die Datei zeichenweise in einen Array ein um sie dort später wiederzuverwenden.
    Die Länge des Arrays wird in j gespeichert.

    Nun kann ich auf meinen Array zugreifen, diesen ausgeben oder anderweitig im Programm verwenden.
    Ich denke es sollte kein Problem sein diesen in einen char[] umzuwandeln.

    Vielleicht könnt ihr noch schreiben, was ihr davon haltet (gut/schlecht).
    Vielleicht könnt ihr was zu PATH_MAX sagen. Ich weiß nicht was das bedeutet, hab es nur drin weil ich es aus einem Beispiel kopiert habe.


  • Mod

    Nicht im Forum programmieren, sonst weiß man nicht, ob das nun echte Fehler oder Tippfehler sind. Copy&Paste. Beispielsweise ist hier offensichtlich, dass die Anführungsstriche nicht passen, wie man an der Formatierung erkennt. Weiterhin ist eine Zeichenkette in Form von ints offensichtlich Unsinn, aber aus oben erwähntem Grund weiß ich nun nicht, ob das echter Unsinn oder ein Abschreibfehler ist. Genauer schaue ich mir den Code daher vorerst nicht an.



  • Wieviel Daten und möchtest du einlesen? (wie groß ist die Datei, wenn du die Daten in einer speicherst, z.B. von der Kommandozeile aus)

    Ist die Datei immer so groß?

    Daraus solltest du die Größe für dein Array ableiten.
    Und du mußt überprüfen, ob du nicht schon die Arraygrenze erreicht hast.

    Aber dann kannst du auch fread nehmen.

    PATH_MAX wird durch den Wert für maximale Größe eines Dateinamens incl. der Verzeichnisse erstzt.
    Dieser ist systemabhängig.
    Ich denke, das ist für dein Problem der völlig falsche Wert. (auch wenn er ausreichend groß ist)



  • SeppJ schrieb:

    Nicht im Forum programmieren, sonst weiß man nicht, ob das nun echte Fehler oder Tippfehler sind. Copy&Paste. Beispielsweise ist hier offensichtlich, dass die Anführungsstriche nicht passen, wie man an der Formatierung erkennt.

    Ja das stimmt. Hatte einen Schrägstrich vergessen. Ich hab nur meine Authorisierung und die url rausgelöscht, das ist nur unnötiger Ballast.

    SeppJ schrieb:

    Weiterhin ist eine Zeichenkette in Form von ints offensichtlich Unsinn, [...]

    Naja, ich hab das gemacht, weil mir fgetc () ein integer zurückgibt. Wäre ja gut, wenn es eine Funktion gibt, die einem gleich char zurückgibt.

    DirkB schrieb:

    Wieviel Daten und möchtest du einlesen? (wie groß ist die Datei, wenn du die Daten in einer speicherst, z.B. von der Kommandozeile aus)

    Ist die Datei immer so groß?

    Die Datei ist an sich immer gleich groß. Vielleicht mal 1 Byte mehr oder weniger. Ja ich könnt manuell die Dateigröße bestimmen und dann den Array halt so groß machen. Cooler wäre natürlich, wenn das Programm das selber feststellt, irgendwie über EndOFFile. Naja aber nicht so wichtig.

    Bei fread gibt er mir einen unsigned int zurück. Hmm ist das soviel anders? Und was ist ein Block. Ist ein Zeichen ein Block?

    Ich mach es schon umständlich. Ich bekomme einen string und wandle den in integer um, um ihn dann wieder in einen string zu wandeln. Will dort dann nach Wörtern in der Zeichenkette suchen.

    DirkB schrieb:

    PATH_MAX wird durch den Wert für maximale Größe eines Dateinamens incl. der Verzeichnisse erstzt.
    Dieser ist systemabhängig.
    Ich denke, das ist für dein Problem der völlig falsche Wert. (auch wenn er ausreichend groß ist)

    Ok danke. Es gibt nicht zufällig eine Konstante wie vielleicht FILE_MAX? Ich hätte 10 Zeichen in meiner Datei und FILE_MAX macht meinen Array dann 10 groß?


Anmelden zum Antworten