Seite 2 von 2

Re: Lese piped stdout eines Programms am stdin meines Progra

Verfasst: 05.06.2014 03:24
von Regenduft
@Stefan2: Du bist immer noch nicht auf darauf eingegangen, ob Du bei PureBasic in "Compiler-Optionen" unter "Executeable-Format" auf "Console" gestellt hast, statt auf "Windows". :wink:
Stefan2 hat geschrieben:Aber warum sollte es am Zeichensatz liegen?
Bei VBScript und Pascal war das ja auch kein Problem.
Und ich bekomme ja gar nichts aus der Pipe übermittelt....
PureBasic ist recht maschinennah. Vereinfacht gesagt: Du hast sehr viel Kontrolle darüber, was Dein Programm genau macht und kannst Programme schreiben die sehr schnell und klein sind, hast aber oft mehr Schreibarbeit. Im Vergleich hast Du z.B. bei VisualBasic weniger Schreibarbeit, dafür aber weniger Kontrolle und weißt aber oft überhaupt nicht was Dein Programm wirklich macht, weil alles automatisch funktioniert, wie zum Beispiel fröhliches hin- und herkonvertieren von einem zum anderen Stringformat. VisualBasic (und vermutlich auch VBScript und Pascal) nutzt heimlich still und leise im Hintergrund CharToOem_() und OemToChar_(), während man das bei PureBasic manuell machen muss, dafür aber sicherstellen kann, dass nicht unnötig zigfach rumkonvertiert wird. Ist alles nicht auf- oder abwertend gemeint. Jede Sprache hat ihre Stärken und Schwächen!

Warum es (evetuell!) zu Problemen wegen dem OEM-Zeichensatz bei Pipes kommen kann, ist dass der OEM-Zeichensatz mehrdeutig ist. Der Zeilenumbruch im Windowsformat ist Chr(10) + Chr(13). In Ascii und Unicode ist 13 immer ein "Carriage Return" (Wagenrücklauf) und 10 ist immer ein "Linefeed" (Zeilenvorschub). Vereinfacht: "Cursor zum Anfang der Zeile und eins nach unten" (das stammt noch von der Schreibmaschine bzw. vom Fernschreiber :wink:). In OEM (hier nochmal der Link zur Zeichentabelle) kann es entweder das gleiche bedeuten, also 10 für "Linefeed" und 13 für "Carriage Return" oder aber auch im grafischen Modus 10 für "◙" und 13 für "♪".

Versuche mal folgendes zur Veranschaulichung:
  1. Notepad starten
  2. Alt drücken und halten
  3. 13 auf dem Nummernblock tippen
  4. Alt loslassen (ein "♪" erscheint)
  5. nochmal Alt drücken und halten
  6. 013 auf dem Nummernblock tippen
  7. Alt loslassen (ein Zeilenumbruch wird eingefügt)
Das sind Überbleibsel von MS-DOS und "vor XP" Windows. Ohne Null vor der 13 wird die Nummer als OEM-Zeichen interpretiert und mit Null davor als Ascii. Die Null hat nix mit dem Ascii-Code an sich zu tun! Die einleitende Null gilt nur für die Tastatur-Eingabe und wurde eingeführt, damit damals die MS-DOS-Nasen auch unter Windows weiter ihre OEM-Codes tippen konnten und nix neues lernen müssen. :wink:

Aber zu Deinem Code: Warum hat der mit Input() nicht funktioniert? Es ist gut möglich, dass es am OEM-Zeichensatz liegt.
Bedenke mal wie Input funktioniert: Es unterbricht die Programm-Ausführung, wartet auf eine Eingabe von einer Zeichenkette gefolgt von einem RETURN! Na? Klingelts? Return? Carriage Return? Ascii-Zeichen Nr. 13? Bzw. das mehrdeutige OEM-Zeichen 13: "Carriage Return" oder "♪". ;)

Wann wie wo das genau wie interpretiert wird kann ich Dir leider nicht sagen, da ich zu selten mit Pipes arbeite. Wenn etwas nicht funktioniert, dann schaue ich halt einfach mal ob's vielleicht am Zeichensatz liegt, und das tut es auch erstaunlich oft, aber oft auch leider dann doch nicht... :mrgreen:

Wollte Dir darum nur ein bisschen Hintergrundwissen vermitteln, damit Du selber Deinen Code besser untersuchen kannst. Danilo hat Dir ja inzwischen schon eine konkrete Lösung gepostet!

Tipp: Schau dir mit "ShowMemoryViewer()" gefolgt von "CallDebugger" mal an was Du da genau mit ReadConsoleData() empfängst! Wegen dem OEM-Zeichensatz werden z.B. die Umlaute trotzdem noch Probleme machen! :wink:

Wenn ich's richtig mitbekommen habe nutzt Du die Demo von PureBasic? Dann läuft mein ASCII-OEM-Wandlercode leider nicht... (nutzt WinAPI). Also folgend mal eine Konvertierungstabelle inkl. Erstellungscode.

Code: Alles auswählen

Procedure.s AsciiNachOem( Ascii$ )
    
  Define Oem$ = Space( Len( Ascii$ ) )
  If CharToOem_( Ascii$ , @Oem$ )
    ProcedureReturn Oem$
  EndIf
  ProcedureReturn #NUL$
    
EndProcedure

Debug "ASCII OEM"
For i = 0 To $FF
  Debug "$" + RSet( Hex(i) , 2 , "0" ) + " = $" + RSet( Hex( Asc( AsciiNachOem( Chr( i ) ) ) ) , 2 , "0" )
Next

Code: Alles auswählen

ASCII OEM
$00 = $00
$01 = $01
$02 = $02
$03 = $03
$04 = $04
$05 = $05
$06 = $06
$07 = $07
$08 = $08
$09 = $09
$0A = $0A
$0B = $0B
$0C = $0C
$0D = $0D
$0E = $0E
$0F = $0F
$10 = $10
$11 = $11
$12 = $12
$13 = $13
$14 = $14
$15 = $15
$16 = $16
$17 = $17
$18 = $18
$19 = $19
$1A = $1A
$1B = $1B
$1C = $1C
$1D = $1D
$1E = $1E
$1F = $1F
$20 = $20
$21 = $21
$22 = $22
$23 = $23
$24 = $24
$25 = $25
$26 = $26
$27 = $27
$28 = $28
$29 = $29
$2A = $2A
$2B = $2B
$2C = $2C
$2D = $2D
$2E = $2E
$2F = $2F
$30 = $30
$31 = $31
$32 = $32
$33 = $33
$34 = $34
$35 = $35
$36 = $36
$37 = $37
$38 = $38
$39 = $39
$3A = $3A
$3B = $3B
$3C = $3C
$3D = $3D
$3E = $3E
$3F = $3F
$40 = $40
$41 = $41
$42 = $42
$43 = $43
$44 = $44
$45 = $45
$46 = $46
$47 = $47
$48 = $48
$49 = $49
$4A = $4A
$4B = $4B
$4C = $4C
$4D = $4D
$4E = $4E
$4F = $4F
$50 = $50
$51 = $51
$52 = $52
$53 = $53
$54 = $54
$55 = $55
$56 = $56
$57 = $57
$58 = $58
$59 = $59
$5A = $5A
$5B = $5B
$5C = $5C
$5D = $5D
$5E = $5E
$5F = $5F
$60 = $60
$61 = $61
$62 = $62
$63 = $63
$64 = $64
$65 = $65
$66 = $66
$67 = $67
$68 = $68
$69 = $69
$6A = $6A
$6B = $6B
$6C = $6C
$6D = $6D
$6E = $6E
$6F = $6F
$70 = $70
$71 = $71
$72 = $72
$73 = $73
$74 = $74
$75 = $75
$76 = $76
$77 = $77
$78 = $78
$79 = $79
$7A = $7A
$7B = $7B
$7C = $7C
$7D = $7D
$7E = $7E
$7F = $7F
$80 = $5F
$81 = $5F
$82 = $27
$83 = $9F
$84 = $22
$85 = $2E
$86 = $C5
$87 = $CE
$88 = $5E
$89 = $25
$8A = $53
$8B = $3C
$8C = $4F
$8D = $5F
$8E = $5A
$8F = $5F
$90 = $5F
$91 = $27
$92 = $27
$93 = $22
$94 = $22
$95 = $07
$96 = $2D
$97 = $2D
$98 = $7E
$99 = $54
$9A = $73
$9B = $3E
$9C = $6F
$9D = $5F
$9E = $7A
$9F = $59
$A0 = $FF
$A1 = $AD
$A2 = $BD
$A3 = $9C
$A4 = $CF
$A5 = $BE
$A6 = $DD
$A7 = $F5
$A8 = $F9
$A9 = $B8
$AA = $A6
$AB = $AE
$AC = $AA
$AD = $F0
$AE = $A9
$AF = $EE
$B0 = $F8
$B1 = $F1
$B2 = $FD
$B3 = $FC
$B4 = $EF
$B5 = $E6
$B6 = $F4
$B7 = $FA
$B8 = $F7
$B9 = $FB
$BA = $A7
$BB = $AF
$BC = $AC
$BD = $AB
$BE = $F3
$BF = $A8
$C0 = $B7
$C1 = $B5
$C2 = $B6
$C3 = $C7
$C4 = $8E
$C5 = $8F
$C6 = $92
$C7 = $80
$C8 = $D4
$C9 = $90
$CA = $D2
$CB = $D3
$CC = $DE
$CD = $D6
$CE = $D7
$CF = $D8
$D0 = $D1
$D1 = $A5
$D2 = $E3
$D3 = $E0
$D4 = $E2
$D5 = $E5
$D6 = $99
$D7 = $9E
$D8 = $9D
$D9 = $EB
$DA = $E9
$DB = $EA
$DC = $9A
$DD = $ED
$DE = $E8
$DF = $E1
$E0 = $85
$E1 = $A0
$E2 = $83
$E3 = $C6
$E4 = $84
$E5 = $86
$E6 = $91
$E7 = $87
$E8 = $8A
$E9 = $82
$EA = $88
$EB = $89
$EC = $8D
$ED = $A1
$EE = $8C
$EF = $8B
$F0 = $D0
$F1 = $A4
$F2 = $95
$F3 = $A2
$F4 = $93
$F5 = $E4
$F6 = $94
$F7 = $F6
$F8 = $9B
$F9 = $97
$FA = $A3
$FB = $96
$FC = $81
$FD = $EC
$FE = $E7
$FF = $98
Oh mann! Spiele ich hier groß den Erklärbär und wundere mich dann gerade warum zunächst nach dem kompilieren so eine seltsame und definitiv falsche Konvetierungstabelle rauskam... Hatte ich jetzt auch erst vergessen den Haken bei "Unicode-Executeable" rauszunehmen... :lol:

Re: Lese piped stdout eines Programms am stdin meines Progra

Verfasst: 05.06.2014 11:28
von Stefan2
@Danilo : Danke, "Procedure vor dem Hauptcode, oder zumindest Declare verwenden" , damit funktioniert das.

@Regenduft: ich habe als Console subsystem kompiliert.

Und mit dem Zeichensatz hatte es nichts zu tun, ich wusste nur nicht wie man die Daten aus der Pipe einliest.
Aber trotzdem vielen Dank für deine ausführliche Erklärung! Das wird mir im nächsten Schritt bei der Anpassung an verschiedene Zeichencodes helfen.

@ "ShowMemoryViewer()" gefolgt von "CallDebugger"
Ohh :shock: , da kommt ja noch einiges zum Vorschein. Dankeschön.

Den Rest deines Postings verarbeite ich später noch, da brauch' ich ein bisschen Zeit.


- - -

Nachdem ich jetzt noch gemerkt habe, dass PeekS() mir den kompletten Inhalt der Pipe am Stück übermittelt,
und nicht Zeilenweise, wie ich zuerst vermutet hatte, konnte ich mittels eines split( at #CRLF$ ) meine Funktion für jede Zeile einzeln aufrufen.

Code: Alles auswählen

For Occu = 1 To CountString(input$, #CRLF$) 
        funcDoIt( StringField( input$, Occu, #CRLF$ ) )
Next


Danke für eure tolle Hilfe! Jetzt bin ich schonmal ein Stück weiter. (und finde es Klasse, wie klein die Exe's sind ;-) )

Re: Lese piped stdout eines Programms am stdin meines Progra

Verfasst: 05.06.2014 12:11
von Danilo
Stefan2 hat geschrieben:

Code: Alles auswählen

For Occu = 1 To CountString(input$, #CRLF$) 
        funcDoIt( StringField( input$, Occu, #CRLF$ ) )
Next
Pass nur auf, dass so CountString() für jeden Durchgang wieder aufgerufen wird,
obwohl es nur einmal nötig ist. Bei grossen Strings wird das ziemlich langsam,
da es jedes mal den ganzen String durchsucht.

Code: Alles auswählen

Procedure myCountString(input.s,stringToFind.s)
    Debug "myCountString()"
    ProcedureReturn CountString(input,stringToFind)
EndProcedure

input$ = "a"+#CRLF$+"b"+#CRLF$+"c"+#CRLF$+"d"+#CRLF$+"e"+#CRLF$+"f"+#CRLF$+"g"

For Occu = 1 To myCountString(input$, #CRLF$)
    ;funcDoIt( StringField( input$, Occu, #CRLF$ ) )
    Debug Occu
Next

Debug "----------------------"

count = myCountString(input$, #CRLF$)
If count>0
    For Occu = 1 To count
        ;funcDoIt( StringField( input$, Occu, #CRLF$ ) )
        Debug Occu
    Next
Else
    ;funcDoIt( input$, 1, #CRLF$ )
EndIf