[flex] FILE* <-> char*

mueslirocker

Mitglied
Hallo,

ich arbeite mit Cygwin/Flex und möchte dort einen (recht langen) String parsen.
Leider verlangt Flex als yyin ja einen Stream FILE*.
Hab mir schonmal das struct angeschaut...
Code:
typedef struct _iobuf
{
	char*	_ptr;
	int	_cnt;
	char*	_base;
	int	_flag;
	int	_file;
	int	_charbuf;
	int	_bufsiz;
	char*	_tmpfname;
} FILE;
... aber ich bin mir nicht sicher, wie ich nun einen String in diesen Buffer/Stream überführen kann.

Mit dem Rückweg hab ich leider auch noch ein Problem.
Flex bzw mein Flexprogramm schreibt ebenfalls in einen FILE*.
Bislang hängt da eine Datei hinter, aber ich möchte diesen Buffer erst füllen und am Ende entweder in eine Datei schreiben oder wieder in einen String umwandeln und zurück geben.

Kann mir da jemand helfen?

MfG
Mueslirocker

/edit
Hab mal versucht, ein bisschen mit das Struct zu manipulieren.
Der Compiler (gcc) gibt Fehler aus, da ich "angeblich" in einem Struct namens __sFILE64 hantiere.
Ein solches Struct gibt es in der stdio.h aber nicht.
Meine Verwirrung wächst ständig..
 
Zuletzt bearbeitet:
moin


Warum machst du nciht einfach:
Code:
FILE *stream;

Und zugriff auf die einzelnen Elemente müsstesst du z.B. per:
Code:
stream->_cnt.....
bekommen.


mfg
umbrasaxum
 
Hm, du meinst, ich soll einfach ein Element von FILE* anlegen?
Hab ich versucht.
Allerdings weiß ich nicht, wie ich diesen "Stream" dann füllen soll/kann.

Auf die einzelnen Elemente hab ich versucht, zuzugreifen, aber da kam die Fehlermeldung, die ich im Edit meines ersten Posts ewähnt habe (falsches Struct).

Ich muss eigentlich nur ein FILE *stream so mit Zeichen füllen können, dass es hinterher mit getc(stream) wieder auslesbar ist.
Aber das will nicht klappen. :(
 
Also mit der FILE Struktur manuell rumzuhantieren bringt gar nichts. Erstens sind die Elemente der Struktur nirgendwo festgeschrieben (das erkennt man schon daran das die mit einem Unterstrich anfangen) und somit implementierungsspezifisch. Zweitens erwarten alle Funktionen die auf einem solchen FILE* operieren das da eine geöffnete Datei dahintersteht, das Dateihandle also valid ist (vorher mittels dem Betriebsystemaufruf "open" geholt wurde).

Aber das ist eigentlich kein Problem. Normalerweise ist doch Flex's yyin mit der Standardeingabe verbunden. Da kannste doch einfach den String reinschreiben:
Code:
puts(string); fclose(stdin);
Dann füllst du entsprechend deinen Buffer mit Zeichen und wenn du weißt wo die Ausgabe hingehen soll, schreibst du den Buffer entweder in den stdout stream (ein FILE*) bzw. in eine mit fopen() geöffnete Datei.

Oder hab ich da jetzt was nicht richtig verstanden?
 
Die Idee ist nicht schlecht.
Leider werden die Zeichen aus dem puts-Befehl abgearbeitet, bevor ich yylex() aufrufen kann.
Damit werden also alle Zeichen ausgegeben, der Puffer ist wieder leer und flex hat nichts zu parsen.

Hatte mich anfangs noch gefragt, warum du stdin schließt.
So stellst du sicher, dass flex ein EOF findet, richtig? :)
Das funktioniert auch.

Leider nützt mir das so noch nichts.

Hier mein aktuelles Programm:
Code:
%{

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

%}

%%

.           printf("%s",yytext);
\n          printf("%s",yytext);

%%

int main() {
  char *x = "abcd";
  puts(x);
  fclose(stdin);
  yylex();
}

Ausgabe ist halt einmal "abcd". :(
 
@umbrasaxum: Das ist (F)Lex Code (Dateiendung .l), kein fertiges C Programm. (F)lex erstellt einen Scanner (für die lexikalische Analyse) einer Grammatik.

@mueslirocker: Naja, die Idee war wohl doch nicht so gut, denn mir ist da ein logischer Fehler unterlaufen. Das Problem ist ja, das puts() auf die Standardausgabe schreibt und die Standardausgabe ja nicht mit der Standardeingabe verbunden ist. DOH!

Aber, es gibt ja pipes. Unter Linux/Unix sieht das dann so aus:
Code:
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int main( )
{
  char *foo = "asdfaf";
  char *erg = (char*)malloc( 40 );

  int modus[2];
  if (pipe (modus) == 0 && dup2 (modus[0], fileno(stdin)) != -1) {

    write( modus[1], foo, strlen( foo ));
    close( modus[1] );

    scanf ("%s", erg );
    
    printf( "== %s ==\n", erg );
    
    return 0;
  } else return 1;
}
 
Ui, Respekt!
Ich arbeite mit cygwin und hab einfach mal dein Programm kopiert (statt scanf und printf yylex() geschrieben) und alles funktioniert. :)
Natürlich bin ich damit nicht zufrieden, denn ich will immer wissen, warum etwas funktioniert... in diesem Falle besonders wie es funktioniert.
Der Link nimmt dir schon etwas Arbeit ab. :)
Werd mich da mal durchwühlen. Hab bisher nur von Pipes gehört...

Leider muss ich wohl ne Windows-Pipe nehmen, da ich im Endeffekt auch alles unter mingw laufen lassen will (habs schon probiert.. mit "gcc -mno-cygwin" kennt er Pipes natürlich nicht) und da ich weit mehr als 4 KB (auf einmal wegen Lex) durch die Pipe jagen muss.
Hm, gibt es denn eine Möglichkeit, Linux/Unix-Pipes zu "vergrößern"?


Schon die erste Frage zu dem Beispiel hinter dem Link:
Entspricht das "CreateFile" dem "dup2" in deinem Beispiel?
Falls ja, wie kann ich da angeben, wohin die Pipe laufen soll?
(Bin mir nichtmal sicher, ob ich die Befehle aus deinem Beispiel richtig interpretiere, aber ich geh einfach mal davon aus. :))
 
Die Pipes unter Linux ließen sich vermutlich vergrößern wenn man den Kern rekompiliert. Was vermutlich nicht praktikabel ist. :)

Ansonsten könntest du z.B. mit Threads arbeiten so dass ein Thread die Daten schreibt (und evtl. blockiert wenn die Pipe voll ist) und der andere die Daten dann liest.

mueslirocker hat gesagt.:
Entspricht das "CreateFile" dem "dup2" in deinem Beispiel?
Nein, das dup2(old, new) macht new zu einer Kopie von old, wobei new geschlossen wird wenn der Dateideskriptor noch geöffnet ist.

Unter Windows mußt du anscheinend (ich kenn mich da wirklich nicht aus) mit DuplicateHandle arbeiten. Hier findest du auch ein Beispiel mit DuplicateHandle.

Wahrscheinlich müßte es ungefähr so funktionieren (es scheint doch nicht so kompliziert zu sein wie in dem Artikel von IBM den ich gefunden hatte):
Code:
    HANDLE fp[2];

    CreatePipe(&fp[0], &fp[1], NULL);

    DuplicateHandle(GetCurrentProcess(),
                  fp[0],           // Original handle
                  GetCurrentProcess(),
                  NULL,                    // don't create new handle
                  0,
                  FALSE,                   // Not inheritable
                  DUPLICATE_SAME_ACCESS);
    SetStdHandle(STD_INPUT_HANDLE, fp[0]);
Fehlerbehandlung hab ich jetzt mal weggelassen. Und ich bin mir jetzt nicht mal sicher, ob man DuplicateHandle überhaupt braucht...
 
Zurück