Intercettare i dati inviati allo standard output da un programma C
Mostreremo due casi, nei quali un applicativo Gambas lancia mediante l'istruzione "Shell" (o "Exec") un programma scritto in linguaggio C, e ne intercetta i dati che quest'ultimo invia allo "standard output" (stdout). [nota 1]
Indice
Programma C che invia "immediatamente" e "una volta" soltanto dati all'output non appena avviato
In questo caso il programma Gambas avvia mediante "Shell" o "Exec" il programma scritto in C, il quale invia immediatamente e una volta soltanto i dati allo standard output.
Il programma scritto in Gambas in tale circostanza intercetterà i dati, trasmessi dal programma in C allo standard output, mediante la parola "To" assegnandoli ad una variabile stringa:
Shell "/percorso/del/programma_C" To variabile_stringa
Esempio pratico
Facciamo, dunque, un semplice esempio, nel quale il codice dell'applicativo Gambas include anche il codice del programma scritto in C:
Public Sub Main() Dim s As String ' Va a creare il programma scritto in C: Crea_C() ' Avvia il programma, scritto in C, inviandogli - come argomento - il PID del programma Gambas: Shell "/tmp/programma_C " & Application.Handle To s Print "Il PID dell'applicativo Gambas letto dalla variabile 's' = "; s End Private Procedure Crea_C() File.Save("/tmp/programma_C.c", "#include <stdio.h>\n\n" & "void main(int argc, char **argv) { /* Riceve il PID del programma Gambas */\n" & " printf(\"%s\", argv[1]);\n}") Shell "gcc -o /tmp/programma_C /tmp/programma_C.c" Wait End
Altro esempio
In quest'altro esempio sarà lanciato un programma in C, al quale si passerà un valore di tipo Stringa. Il programma, quindi, convertirà in un numerico Intero questo valore ricevuto e, dopo averlo sommato al valore 100, lo scriverà nello standard output. Il programma Gambas intercetterà il dato dallo standard output e lo mostrerà, come nel caso precedente, in una TextArea.
Private pr As Process Private i As Integer Public Sub Form_Open() ' Va a creare il programma scritto in C: Crea_C() End Public Sub Button1_Click() Dim s As String Shell "/tmp/programma_C " & CStr(i) To s TextArea1.Text = s ' Ogni qual volta si clicca sul tasto, si vedrà nella TextArea il valore numerico incrementato di un'unità: Inc i End Private Procedure Crea_C() File.Save("/tmp/programma_C.c", "#include <stdio.h>\n" & "#include <stdlib.h>\n\n" & "void main(int argc, char *argv[]) {\n\n" & " int a, b;\n\n" & " // Converte la Stringa in un numero \"Intero\":\n" & " a = atoi(argv[ 1 ]);\n" & " b = a + 100;\n" & " printf(\"%d\", b);\n}") Shell "gcc -o /tmp/programma_C /tmp/programma_C.c" Wait End
Programma C che invia dati allo standard output durante il suo funzionamento
In quest'altro caso il programma Gambas avvia il programma scritto in C, il quale invierà i dati allo standard output successivamente, dopo uno o anche più intervalli di tempo, durante il suo funzionamento.
Usando la Classe Process
Il programma scritto in Gambas in tale circostanza intercetterà i dati, trasmessi dal programma in C allo standard output, ponendo in osservazione il processo aperto del programma C mediante le parole "For Input" (è necessaria la risorsa "Input " anziché "Read ", perché è stato posta la funzione di attesa "sleep( ) " nel codice del programma C).
Lo standard output del programma C sarà, quindi, intercettato da un'apposita subroutine di Gambas, che viene sollevata quando c'è qualcosa da leggere nello standard output. I dati saranno raccolti da una specifica variabile appositamente dichiarata per gestire il processo avviato del programma scritto in C.
Facciamo, dunque, un semplice esempio, nel quale il codice dell'applicativo Gambas, contenente anche il codice del programma scritto in C, sarà il seguente:
Private pr As Process Public Sub Main() ' Va a creare il programma scritto in C: Crea_C() pr = Shell "/tmp/programma_C" For Input As "Processo" End Public Sub processo_Read() Dim s As String ' Legge i dati dalla variabile, con la quale si gestisce il processo: Line Input #pr, s Print "Dato intercettato: "; s End Private Procedure Crea_C() File.Save("/tmp/programma_C.c", "#include <stdio.h>\n" & "#include <unistd.h>\n\n" & "void main() {\n\n" & " int i;\n\n" & " for (i = 1; i <= 5000; i++) {\n" & " if ((i % 100) == 0) {\n" & " printf(\"%d\\n\", i);\n" & " sleep(1);\n }\n }\n}") Shell "gcc -o /tmp/programma_C /tmp/programma_C.c" Wait End
Altro esempio
Private pr As Process Public Sub Form_Open() Crea() pr = Shell "/tmp/prova" For Input As "prova" End Public Sub prova_Read() TextArea1.Text &= pr.ReadLine() & gb.NewLine End Private Procedure Crea() File.Save("/tmp/prova.c", "#include <stdio.h>\n" & "#include <unistd.h>\n\n" & "int a;\n\n" & "void main() {\n\n" & " while (1) {\n" & " printf(\"%d\\n\", a);\n" & " sleep(1);\n" & " a++;\n}\n\n}") Shell "gcc -o /tmp/prova /tmp/prova.c" Wait End
Note
[1] Quando un programma viene eseguito, il sistema operativo genera tre file chiamati rispettivamente:
- "standard input ";
- "standard output ";
- "standard error ".
Di norma lo Standard Input è riferito alla tastiera, mentre lo Standard Output e lo Standard Error sono riferiti allo schermo.
Ogni rapporto e riferimento ai file avviene attraverso un proprio Puntatore al file, chiamato "descrittore di file ".
I descrittori di questi tre file sono rappresentati con i numeri: 0, 1 e 2.
0 = "standard input ": il programma legge i dati scritti/inviati dalla periferica.
1 = "standard output ": il programma scrive/invia dati alla periferica, la quale legge i dati inviati dal programma.
2 = "standard error ": il programma scrive/invia messaggi d'errore al video.
I dati introdotti in input con la tastiera vengono inseriti all'interno di un canale costituito da una sequenza continua di byte. Allo stesso modo i dati prodotti a video vengono inseriti all'interno di un altro canale. Tali canali vengono definiti standard input e standard output. Pertanto la tastiera e' il canale standard input ed il video e' il canale standard output. Qualsiasi comando quindi, accetta in input dei valori che legge dallo standard input (la tastiera) e produce dei risultati scrivendoli nello standard output (il video). Ma un comando può produrre anche dei messaggi di errore se per esempio vengono introdotti dei valori in input non validi. I messaggi di errore dei comandi vengono scritti in un terzo canale, lo standard error.
Come già visto, ogni canale standard e' identificabile da un numero: 0 per il canale standard input, 1 per il canale standard output e 2 per il canale standard error.