Differenze tra le versioni di "Indirizzare dati da un programma ad un altro e ad un Terminale"

Da Gambas-it.org - Wikipedia.
 
(40 versioni intermedie di uno stesso utente non sono mostrate)
Riga 2: Riga 2:
  
  
 +
=Invio dei dati da un programma Gambas ad un altro=
 +
In questo caso, abbiamo due progetti Gambas, che per comodità chiameremo A e B. Il progetto "B" invia dati al progetto "A". Per inviare i dati dal programma "B" al programma "A" si potranno utilizzare alcune modalità.
  
=Invio dei dati da un programma Gambas ad un altro=
+
==Uso della risorsa ''Pipe'' di Gambas==
In questo caso, abbiamo due progetti Gambas, che per comodità chiameremo A e B. Il progetto A invia dati al progetto B. Per inviare i dati dal programma A al programma B si potranno utilizzare i rispettivi file speciali, ai quali essi sono associati: il loro percorso è ''/dev/pts/<FONT color=#B22222>n</font>''; oppure si potrà usare il ''file descriptor'' associato al processo del programma B che riceve i dati.
+
Gambas fornisce la propria risorsa ''Pipe'' per consentire la comuncazione di dati da un programma mittente ad un programma ricevente.
 +
 
 +
In particolare tale funzionalità crea una ''Pipe'', ossia un ''file speciale'' di tipo [https://it.wikipedia.org/wiki/FIFO FIFO] mediante il quale uno o più programmi inviano dati ad un programma ricevente.
  
==Uso dei file speciali /dev/pts/''n''==
+
===Caso in cui il programma Gambas crea la ''Pipe'' e riceve dati===
Nel progetto A avremo il seguente codice:
+
Mostriamo un semplice esempio, nel quale il codice del programma Gambas genera la ''Pipe'' e solo ricevere i dati inviati da altro programma:
 
  Private fl As File
 
  Private fl As File
 
   
 
   
 
   
 
   
  '''Public''' Sub Form_Open()
+
  '''Public''' Sub Main()
+
 
<FONT color=#006400>' ''Viene aperto il file speciale (da individuarsi preliminarmente) che rappresenta il progetto B:''</font>
+
  fl = <FONT Color=#B22222>Pipe</font> "<FONT Color=gray>''/percorso/del/file/speciale/FIFO</font>" For Write Watch
  fl = Open "/dev/pts/''<FONT color=#B22222>B</font>''" For Output
+
 
 +
'''End'''
 
   
 
   
 +
'''Public''' Sub File_Write()
 +
 
 +
  Dim s As String
 +
 
 +
  Read #fl, s, -256
 +
  Print s
 +
 
 
  '''End'''
 
  '''End'''
 +
oppure senza porre in ''osservazione'' il file speciale ''FIFO'', bensì utilizzando con un ciclo:
 +
Private fl As File
 
   
 
   
 
   
 
   
  '''Public''' Sub Button1_Click()
+
  '''Public''' Sub Main()
 +
 
 +
  Dim s As String
 +
 
 +
  fl = <FONT Color=#B22222>Pipe</font> "<FONT Color=gray>''/percorso/del/file/speciale/FIFO</font>" For Write
 
   
 
   
<FONT color=#006400>' ''Viene inviata la stringa di caratteri al file speciale che rappresenta il progetto B:''</font>
+
  While True
  Print #fl, "Testo qualsiasi"
+
    Read #fl, s, -256
 +
    Print s
 +
  Wend
 
   
 
   
 
  '''End'''
 
  '''End'''
 +
Il programma Gambas esterno che deve inviare i dati, dovrà aprire in scrittura il file speciale ''FIFO'' con la funzione consueta ''OPEN'':
 +
fl = Open "<FONT Color=gray>''/percorso/del/file/speciale/FIFO</font>" For Write
 +
L'invio dei dati avverrà con la funzione ''Write'' o con ''Print''.
 +
 +
Si potrà utilizzare anche un Terminale per l'invio di dati o comandi da far eseguire al programma Gambas ricevente; ad esempio come le seguenti righe:
 +
<BR>''~ $ echo testo qualsiasi ls > <FONT Color=gray>'/percorso/del/file/speciale/FIFO'</font>''
 +
<BR>''~ $ echo -ne '\n' | ls > <FONT Color=gray>'/percorso/del/file/speciale/FIFO'</font>''
  
Nel progetto B avremo, invece, il seguente codice:
+
===Caso in cui il programma Gambas crea la ''Pipe'' ed invia dati===
 +
Ovviamente il programma Gambas che genera la ''Pipe'' può anche aprirla in scrittura, inviando così esso stesso ad un programma esterno i dati.
 +
<BR>In tal caso il codice del programma Gambas potrà - ad esempio - essere il seguente:
 
  Private fl As File
 
  Private fl As File
 
   
 
   
 
   
 
   
  '''Public''' Sub Form_Open()
+
  '''Public''' Sub Main()
 +
 
 +
  Dim s As String
 +
 
 +
  fl = <FONT Color=#B22222>Pipe</font> "<FONT Color=gray>''/percorso/del/file/speciale/FIFO''</font>" For Write
 +
 
 +
  While True
 +
    Write #fl, "invio dati"
 +
    Wait 0.5
 +
  Wend
 +
 
 +
'''End'''
 +
Ovviamente il programma Gambas esterno, che riceve i dati inviati dal predetto programma, aprirà il file speciale ''FIFO'' in lettura con la funzione consueta ''Open''. Usando un Terminale, si potranno ricevere i dati lanciando la seguente riga di comando:
 +
''~ $ cat < <FONT Color=gray>'/percorso/del/file/speciale/FIFO'</font>''
 +
 
 +
===Caso in cui il programma Gambas crea la ''Pipe'' e rimane inerte===
 +
Ora mostriamo un caso in cui il programma Gambas crea la ''Pipe'', ma poi il codice non prevede il ricevimento né l'invio di dati. Saranno altri programmi a dover inviare ed a ricevere i dati.
 +
 
 +
Il codice del programma Gambas sarà dunque questo:
 +
'''Public''' Sub Main()
 +
 
 +
  Dim fl As File
 +
 
 +
  fl = <FONT Color=#B22222>Pipe</font> "<FONT Color=gray>''/percorso/del/file/speciale/FIFO''</font>" For Write
 +
 
 +
  While True
 +
    Sleep 0.01
 +
  Wend
 +
 
 +
'''End'''
 +
In ordine ai due programmi esterni poniamo il semplice caso di avere due Terminali: uno invierà i dati e l'altro li riceverà.
 +
 
 +
Innanzitutto va lanciato il programma Gambas che crea il file speciale ''FIFO''; quindi nel Terminale che deve ricevere i dati si lancerà la seguente linea di comando:
 +
''~ $ cat < /tmp/FIFO''
 +
mentre nel secondo Terminale si invieranno i dati nelle modalità già viste sopra:
 +
<BR>''~ $ echo testo qualsiasi ls > /tmp/FIFO''
 +
<BR>o anche una riga di comando da far eseguire dal programma ricevente, come ad esempio:
 +
<BR>''~ $ echo -ne '\n' | ls > /tmp/FIFO''
 +
 
 +
 
 +
==Uso di una ''named pipe'' mediante le funzioni esterne ''umask()'' e ''__xmknod()'' della libreria ''libc.so.6''==
 +
Questa modalità è sostanzialmente analoga alla precedente, ma fa uso delle funzioni esterne ''umask()'' e ''__xmknod()'' della libreria ''libc.so.6''.
 +
 
 +
Con la realizzazione di una ''named pipe'' viene creato un ''file speciale'' FIFO, avente i permessi di lettura e scrittura, che fa da ''medium'', da ''conduttore'' di dati tra un programma che invia i dati e il programma che riceve i dati.
 +
[MITTENTE]------->||[file-device]||------>[RICEVENTE]
 +
Nel programma Gambas che crea la ''named pipe'', ossia il file speciale FIFO, va invocata innanzitutto la funzione esterna ''umask()'' che imposta la maschera di creazione del file del processo in corso, quello cioè che crea la ''named pipe''. Tale funzione esterna consente di impostare nel file-device i permessi da noi prescelti.
 +
 
 +
Successivamente va invocata la funzione esterna ''__xmknod()'', che crea appunto il nodo, il punto di contatto possibile fra il programma mittente ed il programma ricevente, ossia il file speciale, per la comunicazione dei dati.
 +
 
 +
Il primo argomento, che rappresenta la versione dell'interfaccia ''xmknod'', per i sistemi a 64-bit va posto a zero. (Per i sistemi a 32-bit bisognerà provare il valore 0 e il valore 1).
 +
 
 +
Particolare attenzione va dato al valore da assegnare al terzo argomento ''__mode'' che è un valore intero formato dalla <SPAN Style="text-decoration:underline">somma</span> dei valori delle impostazioni dei permessi per i tre utenti. L'argomento ''__mode'' specifica, in particolare, sia la modalità del file da utilizzare sia il tipo di nodo da creare. Dovrebbe essere una combinazione (usando l'operatore OR bit-a-bit) fra il valore della modalità prescelta e il valore della costante-direttiva ''S_IFIFO'', pari a 4096, utile per specificare il tipo di file da creare, in questo caso il file speciale FIFO.
 +
 
 +
I valori attribuibili sono 4 per ciascuna classe di utenti considerata:
 +
* il primo (sempre zero) significa negazione di ogni permesso sul file;
 +
* il secondo consente la sola scrittura del file;
 +
* il terzo consente la sola lettura del file;
 +
* il quarto consente la lettura e la scrittura del file.
 +
 
 +
In particolare:
 +
* i valori riferiti all'utente ''Altri'' sono: 0, 2, 4, 6 (quindi partendo da 0 un comando ogni 2 valori). Aggiungendo 1 ad uno dei predetti valori, si consente anche l'esecuzione del file.
 +
* i valori riferiti all'utente ''Gruppo'' sono: 0, 16, 32, 48 (quindi partendo da 0 un comando ogni 16 valori). Aggiungendo 8 ad uno dei predetti valori, si consente anche l'esecuzione del file.
 +
* i valori riferiti all'utente ''Proprietario'' sono: 0, 128, 256, 384 (quindi partendo da 0 un comando ogni 128 valori). Aggiungendo 8 ad uno dei predetti valori, si consente anche l'esecuzione del file.
 +
 
 +
Il quarto argomento *__dev della funzione esterna deve essere un ''Puntatore'' ad una variabile di tipo ''Intero'' istanziata a 0 (zero) in caso di ''named pipe''.
 +
 
 +
===Caso in cui il programma Gambas crea la ''named pipe'' e riceve dati===
 +
Mostriamo un esempio pratico in cui il programma Gambas, che crea la ''named pipe'' (ossia il file speciale di tipo FIFO) e riceve dati inviati da altro programma,  avrà il seguente codice:
 +
Private Const FIFO As String = "/tmp/FIFO"
 +
Private fl As File
 
   
 
   
<FONT color=#006400>' ''Resta in attesa sino a quando non viene creato il file speciale''
 
' ''(da individuarsi preliminarmente) che rappresenta il progetto A:''</font>
 
  Do
 
    Wait 0.01
 
  Loop Until Exist("/dev/pts/''<FONT color=#B22222>A</font>''")
 
 
   
 
   
  <FONT color=#006400>' ''Poniamo sotto "osservazione" il file speciale che rappresenta il progetto A:''</font>
+
  Library "libc:6"
  fl = Open "/dev/pts/''<FONT color=#B22222>A</font>''" For Read Watch
 
 
   
 
   
  <FONT color=#006400>' ''Può essere utilizzato anche "Process":''
+
  Private Const _MKNOD_VER As Integer = 0
  ''pr = Shell "cat < /dev/pts/A" For Read Write As "pr"''</font>
+
Private Const S_IFIFO As Integer = 4096
 
   
 
   
  '''End'''
+
  <FONT Color=gray>' ''__mode_t umask (__mode_t __mask)''
 +
' ''Set the file creation mask of the current process to MASK.''</font>
 +
Private Extern umask(mask As Integer) As Integer
 
   
 
   
 +
<FONT Color=gray>' ''int __xmknod (int __ver, const char *__path, __mode_t __mode, __dev_t *__dev)''
 +
' ''Create a device file named PATH, with permission and special bits MODE and device number DEV.''</font>
 +
Private Extern __xmknod(ver As Integer, path As String, mode As Integer, dev As Pointer) As Integer 'In "libarchive"
 
   
 
   
'''Public''' Sub File_Read()
 
 
   
 
   
  <FONT color=#006400>' ''Oppure, se si è utilizzato "Process":''
+
'''Public''' Sub Main()
''Public Sub pr_Read()''</font>
+
 
 +
  Dim err, mode As Integer
 +
 
 +
  If Exist(FIFO) Then Kill FIFO
 +
 
 +
  <FONT Color=gray>' ''Crea la 'pipe' FIFO:''</font>
 +
  umask(0)
 +
 
 +
  err = __xmknod(_MKNOD_VER, FIFO, S_IFIFO Or 438, VarPtr(mode))
 +
  If err = -1 Then Error.Raise("Impossibile creare il file-device !")
 
    
 
    
 +
<FONT Color=gray>' ''Apre il file speciale FIFO in scrittura e lo pone sotto 'osservazione':''</font>
 +
  fl = Open FIFO For Write Watch
 +
   
 +
'''End'''
 +
 +
'''Public''' Sub File_Read()
 +
 
 
   Dim s As String
 
   Dim s As String
 
    
 
    
  Read #fl, s, -256
+
  Read #fl, s, -256
 +
  Print s
 +
 
 +
'''End'''
 +
Il programma che invia i dati può essere molto semplicemente il seguente:
 +
Private Const FIFO_FILE As String = "/tmp/FIFO"
 
   
 
   
  TextArea1.Text &= s
 
 
   
 
   
 +
'''Public''' Sub Main()
 +
 
 +
  Dim fl As File
 +
  Dim s As String
 +
 
 +
  fl = Open FIFO_FILE For Write
 +
   
 +
  Write #fl, "Questa è una prova"
 +
 
 +
  fl.Close
 +
 
 
  '''End'''
 
  '''End'''
Va sottolineato che, se il programma A scrive i dati nel programma B mediante ''Print'' o ''Write'', la stringa compare nella ''console'' del progetto B.
+
Ovviamente va <SPAN Style="text-decoration:underline">prima</span> avviato il programma che crea il file speciale, la ''named pipe'', e che in questo caso dovrà ricevere i dati. <SPAN Style="text-decoration:underline">Poi</span> va lanciato il programma che invia i dati. Volendo, dopo aver avviato il programma che riceve i dati, si potrà anche anche utilizzare un Terminale per trasmettere semplicemente dati, scrivendo ed inviando ad esempio la seguente riga di comando:
<BR>Se, invece, l'utente scrive manualmente in console un testo qualsiasi, e, avendo il cursore alla fine di tale testo, preme il relativo tasto ''Invio'' della tastiera, la riga di caratteri verrà intercettata dall' "osservatore" ''Watch'' del progetto B; e verrà quindi sollevato l'evento ''File_Read()''.
+
<BR>''~ $ echo testo qualsiasi ls > /tmp/FIFO''
 +
<BR>o anche una riga di comando da far eseguire dal programma ricevente, come ad esempio:
 +
<BR>''~ $ echo -ne '\n' | ls > /tmp/FIFO''
  
 +
===Caso in cui il programma Gambas crea la ''named pipe'' ed invia dati===
 +
In quest'altro caso il programma Gambas, che genera la ''named pipe'', invierà dati al ''file speciale'' e quindi ad altro programma ricevente.
  
==Uso del ''file descriptor'' n. 1==
+
Mostriamo un esempio pratico:
Nel progamma A, che invia i dati, avremo il seguente codice:
+
Private Const FIFO As String = "/tmp/FIFO"
 
  Private fl As File
 
  Private fl As File
 
   
 
   
 
   
 
   
  '''Public''' Sub Form_Open()
+
  Library "libc:6"
 +
 +
Private Const _MKNOD_VER As Integer = 0
 +
Private Const S_IFIFO As Integer = 4096
 +
 +
<FONT Color=gray>' ''__mode_t umask (__mode_t __mask)''
 +
' ''Set the file creation mask of the current process to MASK.''</font>
 +
Private Extern umask(mask As Integer) As Integer
 +
 +
<FONT Color=gray>' ''int __xmknod (int __ver, const char *__path, __mode_t __mode, __dev_t *__dev)''
 +
' ''Create a device file named PATH, with permission and special bits MODE and device number DEV.''</font>
 +
Private Extern __xmknod(ver As Integer, path As String, mode As Integer, dev As Pointer) As Integer 'In "libarchive"
 +
 
   
 
   
   fl = Open "/proc/<FONT color=#B22222>''PID_del_programma_B</font>/fd/1" For Output
+
'''Public''' Sub Main()
 +
 
 +
  Dim err, mode As Integer
 +
 
 +
  If Exist(FIFO) Then Kill FIFO
 +
 
 +
<FONT Color=gray>' ''Crea la 'pipe' FIFO:''</font>
 +
  umask(0)
 +
    
 +
  err = __xmknod(_MKNOD_VER, FIFO, S_IFIFO Or 438, VarPtr(mode))
 +
  If err = -1 Then Error.Raise("Impossibile creare il file-device !")
 +
 
 +
<FONT Color=gray>' ''Apre il file speciale FIFO in scrittura:''</font>
 +
  fl = Open FIFO For Write
 
   
 
   
 +
  While True
 +
    Write #fl, "Invio di dati alla 'pipe'"
 +
    Wait 0.5
 +
  Wend
 +
     
 
  '''End'''
 
  '''End'''
 +
Ovviamente va <SPAN Style="text-decoration:underline">prima</span> avviato il programma che crea il file speciale, la ''named pipe'', e che in questo caso invia i dati. <SPAN Style="text-decoration:underline">Poi</span> va lanciato il programma Gambas esterno (o ugualmente un Terminale) che deve ricevere i dati dalla ''named pipe''.
 +
 +
===Caso in cui il programma Gambas crea la ''named pipe'' e rimane inerte===
 +
Ora mostriamo un caso in cui il programma Gambas crea la ''named pipe'', ma poi il codice non prevede il ricevimento né l'invio di dati. Saranno altri programmi a dover inviare ed a ricevere i dati.
 +
 +
Il codice del programma Gambas sarà dunque questo:
 +
Private Const FIFO As String = "/tmp/FIFO"
 +
Private fl As File
 +
 +
 +
Library "libc:6"
 +
 +
Private Const _MKNOD_VER As Integer = 0
 +
Private Const S_IFIFO As Integer = 4096
 
   
 
   
 +
<FONT Color=gray>' ''__mode_t umask (__mode_t __mask)''
 +
' ''Set the file creation mask of the current process to MASK.''</font>
 +
Private Extern umask(mask As Integer) As Integer
 
   
 
   
  '''Public''' Sub Button1_Click()
+
  <FONT Color=gray>' ''int __xmknod (int __ver, const char *__path, __mode_t __mode, __dev_t *__dev)''
 +
' ''Create a device file named PATH, with permission and special bits MODE and device number DEV.''</font>
 +
Private Extern __xmknod(ver As Integer, path As String, mode As Integer, dev As Pointer) As Integer 'In "libarchive"
 
   
 
   
<FONT color=#006400>' ''Se si vuole far scrivere nel terminale una riga "sotto" l'altra''
 
' ''ogni volta che si preme il tasto, allora si utilizzerà "Print":''</font>
 
  Print #fl, "testo qualsiasi"
 
 
   
 
   
  <FONT color=#006400>' ''Se si vuole far scrivere nel terminale una riga "dopo" l'altra''
+
'''Public''' Sub Main()
  ' ''ogni volta che si preme il tasto, allora si utilizzerà "Write":''</font>
+
 
  Write #fl, "testo qualsiasi"
+
  Dim err, mode As Integer
 +
 
 +
  If Exist(FIFO) Then Kill FIFO
 +
 
 +
  <FONT Color=gray>' ''Crea la 'pipe' FIFO:''</font>
 +
  umask(0)
 +
 
 +
  err = __xmknod(_MKNOD_VER, FIFO, S_IFIFO Or 438, VarPtr(mode))
 +
  If err = -1 Then Error.Raise("Impossibile creare il file-device !")
 +
 
 +
  <FONT Color=gray>' ''Apre il file speciale FIFO in scrittura:''</font>
 +
  fl = Open FIFO For Write
 
   
 
   
 +
  While True
 +
    Wait 0.01
 +
  Wend
 +
     
 
  '''End'''
 
  '''End'''
 +
In ordine ai due programmi esterni poniamo il semplice caso di avere due Terminali: uno invierà i dati e l'altro li riceverà.
 +
 +
Innanzitutto va lanciato il programma Gambas che crea il file speciale ''FIFO''; quindi nel Terminale che deve ricevere i dati si lancerà la seguente linea di comando:
 +
''~ $ cat < /tmp/FIFO''
 +
mentre nel secondo Terminale si invieranno i dati nelle modalità già viste sopra:
 +
<BR>''~ $ echo testo qualsiasi ls > /tmp/FIFO''
 +
<BR>o anche una riga di comando da far eseguire dal programma ricevente, come ad esempio:
 +
<BR>''~ $ echo -ne '\n' | ls > /tmp/FIFO''
 +
 +
 +
==Uso del file speciale ''/dev/pts/...'' e del ''file descriptor 1'' associati al processo del programma ricevente==
 +
Sarà possibile inviare i dati anche utilizzando il file speciale (''/dev/pts/...'') associato al programma "A" ricevente, oppure il ''file descriptor'' n. 1 (''/proc/PID_del_processo_di_A/fd/1'') associato al processo del programma "A" ricevente. In questo caso si potranno avere due effetti a seconda del codice scritto nei due programmi.
  
Il programma B, che riceve i dati, avrò un codice simile al seguente:
+
===Caso in cui i dati ricevuti in console/Terminale possono essere ''soltanto'' visualizzati===
  Private pr As Process
+
Inviando i dati semplicemente con le funzioni ''Write'' o ''Print'' al ''file-descriptor'' associato al programma ricevente o al file speciale ''pts'' del programma ricevente, i dati potranno essere ''soltanto'' visualizzati in console/Terminale, ma non recuperati per essere eventualmente gestiti.
 +
 
 +
====Uso dei file speciali ''/dev/pts/...''====
 +
Nel progetto "A", che <SPAN Style="text-decoration:underline">riceve</span> i dati inviati dal programma "B", avremo il seguente codice:
 +
'''Public''' Sub Main()
 +
 
 +
  Dim pts As String
 +
 
 +
<FONT color=gray>' ''Ricaviamo e mostriamo in console/Terminale il file speciale che rappresenta il progetto "A" (il nome del file "pts" servirà per il programma "B" inviante):''</font>
 +
  pts = Dir("/dev/pts", "*", gb.Device)[0]
 +
 
 +
  Print pts
 +
 
 +
<FONT color=gray>' ''Restiamo in attesa dei dati inviati:''</font>
 +
  While True
 +
    Wait 0.01
 +
  Wend
 +
 
 +
'''End'''
 +
Nel progetto "B", che <SPAN Style="text-decoration:underline">invia</span> i dati al programma "A", avremo il seguente codice:
 +
  Private fl As File
 +
 +
 +
'''Public''' Sub Main()
 +
 +
  Dim pts As String
 +
 +
<FONT color=gray>' ''Qui va inserito il nome numerico del file speciale (pts) che rappresenta il progetto "A":''</font>
 +
  pts = ....
 
   
 
   
 +
<FONT color=gray>' ''Viene aperto il file speciale che rappresenta il progetto "A":''</font>
 +
  fl = Open "/dev/pts/''<FONT color=#B22222>...</font>''" For Write
 +
   
 +
<FONT color=gray>' ''Viene inviata la stringa di caratteri al file speciale che rappresenta il progetto "A":''</font>
 +
  While True
 +
    Print #fl, "Testo qualsiasi"
 +
    Wait 0.3
 +
  Wend
 +
   
 +
'''End'''
 +
====Uso del ''file descriptor'' n. 1====
 +
In quest'altro esempio il programma "B" <SPAN STYLE="text-decoration:underline">invia</span> di continuo il valore progressivamente incrementato di una variabile. La stringa dei dati inviata è formattata in modo tale che nella console del programma "A" ricevente (se esso è aperto come progetto nell'IDE) ovvero nel Terminale (se il programma "A" è stato lanciato da Terminale) i dati verranno di volta in volta visualizzati sovrascritti.
 +
 +
Nel progamma "A", che <SPAN STYLE="text-decoration:underline">riceve</span> i dati, avremo il seguente codice:
 +
'''Public''' Sub Main()
 +
 
 +
<FONT color=gray>' ''Ricaviamo e mostriamo in console o in Terminale il PID del programma "A" ricevente (il PID servirà per il programma "B" inviante):''</font>
 +
  Print Application.Id
 +
 
 +
<FONT color=gray>' ''Restiamo in attesa dei dati inviati:''</font>
 +
  While True
 +
    Wait 0.01
 +
  Wend
 +
 
 +
'''End'''
 +
Il codice del programma "B", che invia i dati, in questo esempio sarà il seguente:
 +
Private fl As File
 
   
 
   
  '''Public''' Sub Form_Open()
+
 
 +
  '''Public''' Sub Main()
 
   
 
   
<FONT color=#006400>' ''Intercetta i dati dal "file descriptor" n. 1 del suo stesso processo:''</font>
+
  Dim fl As File
  pr = Shell "cat < /proc/" & Application.Handle & "/fd/1" For Read As "pr"
+
  Dim i As Integer
 +
  Dim nome_processo, PID As String
 
   
 
   
 +
<FONT color=gray>' ''Qui va assegnato il PID del programma "A" ricevente i dati:''</font>
 +
  PID = .....
 +
 
 +
<FONT color=gray>' ''Apriamo il "file-descriptor" n. 1 del processo del programma "A" in scrittura:''</font>
 +
  fl = Open "/proc" &/ PID &/ "fd/1" For Write
 +
 
 +
<FONT color=gray>' ''Ciclo per l'invio continuo - ogni 500 millisecondi - del valore progressivamente incrementato della variabile di tipi Intero:''</font>
 +
  While True
 +
<FONT color=gray>' ''Formattiamo la stringa in modo tale che i dati, di volta in volta inviati, si sovrascrivano ai precedenti:''</font>
 +
    Write #fl, "\r" & i
 +
    Wait 0.5
 +
    Inc i
 +
  Wend
 +
   
 
  '''End'''
 
  '''End'''
 +
===Caso in cui i dati ricevuti in console/Terminale possono essere anche recuperati ed utilizzati dal programma ricevente===
 +
Il programma che riceve i dati acquista la capacità di intercettarli, per poterli successivamente gestire direttamente, attraverso l'invio ''manuale'' dei dati dalla console/Terminale. Questa modalità, in particolare, prevede che i dati vengono scritti ed inviati ''manualmente'' dall'apposito spazio sottostante la console dell'IDE oppure nel Terminale, se il programma inviante è stato lanciato da Terminale.
 +
<BR>In tal caso è necessario nel programma ricevente aprire in lettura e porre in ''osservazione'' con la parola chiave ''Watch'' il file speciale ''pts'' del programma che invia i dati, ed il programma inviante deve aprire in scrittura il file speciale ''pts'' del programma ricevente o, in alternativa, il proprio file speciale ''pts'' a cui esso è associato. Com già accennato, i dati dovranno essere inviati scrivendoli nell'apposito spazio sottostante la console dell'IDE oppure nel Terminale, se il programma inviante è stato lanciato da Terminale. Dopo averli scritti si dovrà inviarli premendo come di consueto il tasto "Invia" (''Enter'') della tastiera.
 +
 +
Mostriamo di seguito un semplice esempio pratico, nel quale il codice del programma "A", che riceve i dati, sarà il seguente:
 +
Private fl As File
 +
 +
 +
'''Public''' Sub Main()
 +
 
 +
  Dim b As Byte
 +
  Dim pts As String
 +
 
 +
<FONT Color=gray>' ''Individua il file speciale 'pts' che sarà creato, associato al programma che invia i dati:''</font>
 +
  While True
 +
    If Not Exist("/dev/pts" &/ CStr(b)) Then Break
 +
    Inc b
 +
  Wend
 +
 
 +
  pts = CStr(b)
 +
 
 +
  Print "Il file spciale 'pts' del programma che invia i dati sarà:", pts
 +
 
 +
<FONT Color=gray>' ''Resta in attesa che il file speciale 'pts', associato al programma che invia i dati, sia generato:''</font>
 +
  Repeat
 +
    Wait 0.01
 +
  Until Exist("/dev/pts" &/ pts)
 
   
 
   
 +
<FONT Color=gray>' ''Apre il file speciale 'pts', associato al programma che invia i dati, in lettura e lo sottopone in 'osservazione':''</font>
 +
  fl = Open "/dev/pts" &/ pts For Read Watch
 
   
 
   
  '''Public''' Sub pr_Read()
+
  '''End'''
 
   
 
   
 +
'''Public''' Sub File_read()
 +
 
 
   Dim s As String
 
   Dim s As String
 +
 
 +
  Read #fl, s, -256
 +
 
 +
  Print s
 +
 +
'''End'''
 +
Il codice del programma "B", che invia i dati, sarà il seguente:
 +
Private i As Integer
 +
 +
 +
'''Public''' Sub Main()
 +
 
 +
  Dim fl As File
 +
  Dim pts As String
 +
 
 +
<FONT Color=gray>' ''Qui va attribuito il numero del file speciale 'pts' associato al programma che riceve i dati:''</font>
 +
  pts = ...
 
   
 
   
    Line Input #pr, s
+
<FONT Color=gray>' ''Apre in scrittura il file speciale 'pts' associato al programma che riceve i dati:''</font>
 +
  fl = Open "/dev/pts" &/ pts For Write
 
   
 
   
<FONT color=#006400>' ''Mostria i dati in una "TextLabel":''</font>
+
  While True
     TextLabel1.Text &= s
+
     Wait 0.01
 +
  Wend
 
   
 
   
 
  '''End'''
 
  '''End'''
Riga 115: Riga 440:
 
<BR>Durante il trasferimento dei dati da un programma all'altro bisogna prestare attenzione a non effettuare alcun'altra copia di caratteri (per esempio con il mouse), o comunque di altri dati, altrimenti verrà trasmesso il contenuto della nuova copia di dati appena effettuata.
 
<BR>Durante il trasferimento dei dati da un programma all'altro bisogna prestare attenzione a non effettuare alcun'altra copia di caratteri (per esempio con il mouse), o comunque di altri dati, altrimenti verrà trasmesso il contenuto della nuova copia di dati appena effettuata.
 
<BR>Ovviamente, trattandosi di "''Appunti''" di sistema, i dati potranno essere raccolti pure da altri programmi, anche non-Gambas.
 
<BR>Ovviamente, trattandosi di "''Appunti''" di sistema, i dati potranno essere raccolti pure da altri programmi, anche non-Gambas.
 
  
 
Facciamo un esempio pratico. Avendo due programmi, A che deve trasferire dei dati al programma B, nel programma A avremo il seguente codice, capace di copiare dati negli appunti:
 
Facciamo un esempio pratico. Avendo due programmi, A che deve trasferire dei dati al programma B, nel programma A avremo il seguente codice, capace di copiare dati negli appunti:
Riga 122: Riga 446:
 
   Dim s As String
 
   Dim s As String
 
   
 
   
  s = "Prova trasferimento dati stringa"
+
  s = "Prova trasferimento dati stringa"
 
   
 
   
  Clipboard.Copy(s)
+
  Clipboard.Copy(s)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 132: Riga 456:
 
   Dim s As String
 
   Dim s As String
 
   
 
   
  s = Clipboard.Paste()
+
  s = Clipboard.Paste()
 
   
 
   
  Print s
+
  Print s
 
   
 
   
 
  '''End'''
 
  '''End'''
 
 
 
=Scrivere nella finestra del Terminale=
 
Se viene aperto un Terminale virtuale distinto dal programma Gambas, e si intende scrivere al suo interno, si potranno utilizzare o il file speciale associato al Terminale aperto: il suo percorso è ''/dev/pts/n''; oppure si potrà usare il ''file descriptor'' num. '''1''' associato al processo del Terminale.
 
 
 
==Uso del ''file speciale'' della cartella pts==
 
Volendo utilizzare il comando Shell per conoscere il nome del file speciale associato ad un certo terminale virtuale è sufficiente dare allo shell di quel terminale il comando ''tty'':
 
Shell tty
 
Se, invece, si vuole fare a meno del comando Shell per conoscere il nome del file speciale associato, bisogna tenere in considerazione che la console dell'IDE di Gambas si comporta come un Terminale virtuale; e pertanto anche ad essa sarà associato un file speciale nella directory ''/dev/pts/<FONT color=#B22222>N</font>''.
 
Se non sarà già aperto un Terminale virtuale, il numero del file associato alla Console dell'IDE di Gambas, sarà 0, altrimenti sarà il primo numero successivo a quello dell'ultimo Terminale aperto. Identico discorso vale per i terminale virtuali aperti successivamente all'apertura dell'IDE di Gambas.
 
  
  
Mostriamo un codice esemplificativo, con il quale scriveremo all'interno di una finestra Terminale mediante le sole funzioni di Gambas.
+
=Invio di dati ad un Terminale distinto dal programma Gambas=
 +
Un modo di inviare meramente dei caratteri testuali ad un Terminale, esterno e distinto rispetto al nostro programma Gambas principale, è quello di individuare innanzitutto il file-device speciale del Terminale medesimo, quindi aprirlo in scrittura e scriverci i dati.
  
E' necessario aver impostato nel progetto anche il componente "''gb.desktop''" e "''gb.desktop.x11''":
+
Mostriamo un esempio pratico con un'applicazione grafica (lanciaare prima il programma Gambas e poi il Terminale).
 
  '''Public''' Sub Form_Open()
 
  '''Public''' Sub Form_Open()
 +
 
 +
  Dim b As Byte
 
   
 
   
  <FONT color=gray>' ''Apre un Terminale:''</font>
+
  <FONT Color=gray>' ''Verifichiamo innanzitutto quanti file 'pts' sono presenti in '/dev/pts':''</font>
   Desktop.OpenTerminal
+
   b = Dir("/dev/pts", Null, gb.Device).Count
+
 
 +
  Repeat
 +
    Wait 0.01
 +
  Until b < Dir("/dev/pts", Null, gb.Device).Count
 +
 
 
  '''End'''
 
  '''End'''
 
 
 
   
 
   
 
  '''Public''' Sub Button1_Click()
 
  '''Public''' Sub Button1_Click()
+
 
 
   Dim fl As File
 
   Dim fl As File
    
+
   Dim s As String
  <FONT color=gray>' ''Apre in scrittura il file "speciale" associato al Terminale virtuale appena lanciato.''
+
 
' ''Esso può essere individuato in questo modo:''</font>
+
  <FONT Color=gray>' ''L'ultimo file 'pts' creato è posizionato nel 1° elemento del vettore generato dalla funzione "Dir()":''</font>
  fl = Open "/dev/pts" &/ Dir("/dev/pts", "*")[0]" For Write  <FONT color=gray>  ' ''...o anche “'''For Output'''”''</font>
+
  s = Dir("/dev/pts", Null, gb.Device)[0]
 
<FONT color=gray>' ''Se si intende scrivere nel terminale ogni stringa appresso alla precedente, allora si userà “Write”:''</font>
 
  Write #fl, "stringa da scrivere nel terminale"
 
 
<FONT color=gray>' ''Se si intende scrivere ogni stringa l'una sotto l'altra, allora si utilizzerà “Print”:''</font>
 
  Print #fl, "stringa da scrivere nel terminale"
 
 
    
 
    
  <FONT color=gray>' ''Oppure semplicemente solo "Print":''</font>
+
  <FONT Color=gray>' ''Scriviamo qualcosa nel Terminale che è stato appena aperto:''</font>
  Print #fl, "stringa da scrivere nel terminale"
+
  fl = Open "/dev/pts" &/ s For Write
 
    
 
    
  fl.Close
+
  Write #fl, "Questa è una prova"
 
+
     
 +
  fl.Close
 +
     
 
  '''End'''
 
  '''End'''
 
+
Con un'applicazione Gambas a ''riga di comando'' (anche in questo caso si lancerà prima l'applicazione e poi il Terminale).
 
+
<BR>In console - o nel Terminale ove sia stato lanciato l'eseguibile dell'applicazione Gambas - sarà mostrato lo scorrere temporale, basterà quindi premere il tasto "Invio" della tastiera per inviare la stringa temporale al nuovo Terminale aperto.
'''N.B.''' Seppure sia possibile - come abbiamo visto - scrivere all'interno della finestra del terminale, non è però possibile utilizzare tale possibilità per lanciare dalla finestra del Terminale dei comandi, magari in combinazione con l'istruzione "''Desktop.Sendkeys(Chr(10))''", se non [[Lanciare_un_programma_senza_Shell,_ma_da_una_finestra_di_un_Terminale|in quest'altra modalità]].
+
Private b As Byte
 
+
Private n As Byte
 
 
===Scrivere nel Terminale il risultato di un comando ''bash''===
 
Se si intende far scrivere in un Terminale il risultato complesso e non istantaneo di un comando ''bash'', si porrà sotto osservazione il file speciale ''pts'' relativo al Terminale predetto.
 
 
 
Anche nel seguente esempio dovremo attivare i componenti ''gb.desktop'' e ''gb.desktop.x11'':
 
 
  Private fl As File
 
  Private fl As File
 
   
 
   
 +
'''Public''' Sub Main()
 +
 +
  Dim s As String
 +
  Dim tm As Date
 
   
 
   
'''Public''' Sub Form_Open()
+
  For Each s In Dir("/dev/pts", Null, gb.Device)
 +
    If IsNumber(s) Then b += Val(s)
 +
  Next
 +
  n = b
 +
  Repeat
 +
    For Each s In Dir("/dev/pts", Null, gb.Device)
 +
      If IsNumber(s) Then b += Val(s)
 +
    Next
 +
  Until b > n
 
   
 
   
  Desktop.OpenTerminal()
+
  s = "/proc" &/ Application.Handle &/ "fd/0"
 
 
  Me.Center
 
 
 
'''End'''
 
 
   
 
   
 +
  fl = Open s For Input Watch
 
   
 
   
  '''Public''' Sub processus_Read()
+
  tm = Now
 +
  While True
 +
    Write "\r \e[31m" & CStr(Time(0, 0, 0, DateDiff(tm, Now, gb.Millisecond))) & Space(30)
 +
    Wait 0.001
 +
  Wend
 
   
 
   
  Dim s As String
 
 
 
  Line Input #Last, s
 
 
 
  Print #fl, s
 
   
 
 
  '''End'''
 
  '''End'''
 
   
 
   
+
  '''Public''' Sub File_Read()
  '''Public''' Sub Button1_Click()
+
 
+
  Dim s As String
  fl = Open "/dev/pts" &/ Dir("/dev/pts", "*")[0] For Write
+
  Dim pts As File
+
 
  Shell "echo '<FONT Color=gray>''MIA_PASSWORD''</font> | sudo -S fdisk -l" For Read As "processus"
+
  pts = Open "/dev/pts" &/ CStr(b - n) For Write
+
  Output To #pts
 +
  Line Input #fl, s
 +
 
 
  '''End'''
 
  '''End'''
 
+
Un'altra modalità può essere la seguente (in quest'altro esempio bisognerà invece aprire prima il Terminale e successivamente lanciare il codice Gambas).
 
 
 
 
==Uso del ''file descriptor'' associato al processo del Terminale ed utile alla scrittura dei dati==
 
In tal caso si tratta di individuare preliminarmente il numero del PID del processo del Terminale, e quindi il ''file descriptor'' utile per la scrittura nel Terminale dei dati desiderati.
 
 
 
Il codice può essere il seguente:
 
 
  Private fl As File
 
  Private fl As File
 
   
 
   
 
   
 
   
 
  '''Public''' Sub Form_Open()
 
  '''Public''' Sub Form_Open()
 
  Dim pr, s As String
 
 
    
 
    
  pr = "/proc" &/ <FONT color=gray>''PID_del_processo''</font> &/ "fd"
+
  Dim s As String
 +
  Dim ss As String[]
 +
  Dim c As Short
 +
 
 +
  ss = Dir("/proc", Null, gb.Directory)
 
    
 
    
  For Each s In Dir(pr, "*")
+
  c = ss.Count
    If Stat(pr &/ s).Link Like "/dev/pts/*" Then Exit
+
   
  Next
+
<FONT Color=gray>' ''Si cerca la parola "bash" all'interno del file di sistema "comm" presente negli ultimi processi aperti:''</font>
 +
  Repeat
 +
    Dec c
 +
  Until File.Load("/proc" &/ CStr(ss[c]) &/ "comm") Begins "bash"
 +
   
 +
  fl = Open "/proc" &/ CStr(ss[c]) &/ "fd/1" For Write
 
    
 
    
  fl = Open pr &/ s For Output
 
     
 
 
  '''End'''
 
  '''End'''
 
 
   
 
   
 
  '''Public''' Sub Button1_Click()
 
  '''Public''' Sub Button1_Click()
 +
 
 +
  Write #fl, "Testo qualsiasi"
 +
 
 +
'''End'''
 
   
 
   
  <FONT color=gray>' ''Se si vuole far scrivere nel terminale una riga "sotto" l'altra''
+
  '''Public''' Sub Button2_Click()
' ''ogni volta che si preme il tasto, allora si utilizzerà "Print":''</font>
+
 
  Print #fl, "testo qualsiasi"
+
  fl.Close
+
  Me.Close
<FONT color=gray>' ''Se si vuole far scrivere nel terminale una riga "dopo" l'altra''
 
' ''ogni volta che si preme il tasto, allora si utilizzerà "Write":''</font>
 
  Write #fl, "testo qualsiasi"
 
 
    
 
    
  fl.Close
 
 
 
  '''End'''
 
  '''End'''
 +
Va comunque sottolineato che la scrittura nel Terminale, nelle modalità sopra descritte, non è utile per lanciare efficacemente un eventuale comando ''bash'' o altro programma.

Versione attuale delle 02:52, 28 ago 2022

Il caso in questione è quello in cui si inviano dati da un programma Gambas ad un altro programma Gambas e ad un Terminale.


Invio dei dati da un programma Gambas ad un altro

In questo caso, abbiamo due progetti Gambas, che per comodità chiameremo A e B. Il progetto "B" invia dati al progetto "A". Per inviare i dati dal programma "B" al programma "A" si potranno utilizzare alcune modalità.

Uso della risorsa Pipe di Gambas

Gambas fornisce la propria risorsa Pipe per consentire la comuncazione di dati da un programma mittente ad un programma ricevente.

In particolare tale funzionalità crea una Pipe, ossia un file speciale di tipo FIFO mediante il quale uno o più programmi inviano dati ad un programma ricevente.

Caso in cui il programma Gambas crea la Pipe e riceve dati

Mostriamo un semplice esempio, nel quale il codice del programma Gambas genera la Pipe e solo ricevere i dati inviati da altro programma:

Private fl As File


Public Sub Main()
 
 fl = Pipe "/percorso/del/file/speciale/FIFO" For Write Watch
 
End

Public Sub File_Write()
 
 Dim s As String
 
 Read #fl, s, -256
 Print s
  
End

oppure senza porre in osservazione il file speciale FIFO, bensì utilizzando con un ciclo:

Private fl As File


Public Sub Main()
  
 Dim s As String
 
 fl = Pipe "/percorso/del/file/speciale/FIFO" For Write

 While True
   Read #fl, s, -256
   Print s
 Wend

End

Il programma Gambas esterno che deve inviare i dati, dovrà aprire in scrittura il file speciale FIFO con la funzione consueta OPEN:

fl = Open "/percorso/del/file/speciale/FIFO" For Write

L'invio dei dati avverrà con la funzione Write o con Print.

Si potrà utilizzare anche un Terminale per l'invio di dati o comandi da far eseguire al programma Gambas ricevente; ad esempio come le seguenti righe:
~ $ echo testo qualsiasi ls > '/percorso/del/file/speciale/FIFO'
~ $ echo -ne '\n' | ls > '/percorso/del/file/speciale/FIFO'

Caso in cui il programma Gambas crea la Pipe ed invia dati

Ovviamente il programma Gambas che genera la Pipe può anche aprirla in scrittura, inviando così esso stesso ad un programma esterno i dati.
In tal caso il codice del programma Gambas potrà - ad esempio - essere il seguente:

Private fl As File


Public Sub Main()
 
 Dim s As String
  
 fl = Pipe "/percorso/del/file/speciale/FIFO" For Write
  
 While True
   Write #fl, "invio dati"
   Wait 0.5
 Wend
 
End

Ovviamente il programma Gambas esterno, che riceve i dati inviati dal predetto programma, aprirà il file speciale FIFO in lettura con la funzione consueta Open. Usando un Terminale, si potranno ricevere i dati lanciando la seguente riga di comando:

~ $ cat < '/percorso/del/file/speciale/FIFO'

Caso in cui il programma Gambas crea la Pipe e rimane inerte

Ora mostriamo un caso in cui il programma Gambas crea la Pipe, ma poi il codice non prevede il ricevimento né l'invio di dati. Saranno altri programmi a dover inviare ed a ricevere i dati.

Il codice del programma Gambas sarà dunque questo:

Public Sub Main()
 
 Dim fl As File
 
 fl = Pipe "/percorso/del/file/speciale/FIFO" For Write
 
 While True
   Sleep 0.01
 Wend
 
End

In ordine ai due programmi esterni poniamo il semplice caso di avere due Terminali: uno invierà i dati e l'altro li riceverà.

Innanzitutto va lanciato il programma Gambas che crea il file speciale FIFO; quindi nel Terminale che deve ricevere i dati si lancerà la seguente linea di comando:

~ $ cat < /tmp/FIFO

mentre nel secondo Terminale si invieranno i dati nelle modalità già viste sopra:
~ $ echo testo qualsiasi ls > /tmp/FIFO
o anche una riga di comando da far eseguire dal programma ricevente, come ad esempio:
~ $ echo -ne '\n' | ls > /tmp/FIFO


Uso di una named pipe mediante le funzioni esterne umask() e __xmknod() della libreria libc.so.6

Questa modalità è sostanzialmente analoga alla precedente, ma fa uso delle funzioni esterne umask() e __xmknod() della libreria libc.so.6.

Con la realizzazione di una named pipe viene creato un file speciale FIFO, avente i permessi di lettura e scrittura, che fa da medium, da conduttore di dati tra un programma che invia i dati e il programma che riceve i dati.

[MITTENTE]------->||[file-device]||------>[RICEVENTE]

Nel programma Gambas che crea la named pipe, ossia il file speciale FIFO, va invocata innanzitutto la funzione esterna umask() che imposta la maschera di creazione del file del processo in corso, quello cioè che crea la named pipe. Tale funzione esterna consente di impostare nel file-device i permessi da noi prescelti.

Successivamente va invocata la funzione esterna __xmknod(), che crea appunto il nodo, il punto di contatto possibile fra il programma mittente ed il programma ricevente, ossia il file speciale, per la comunicazione dei dati.

Il primo argomento, che rappresenta la versione dell'interfaccia xmknod, per i sistemi a 64-bit va posto a zero. (Per i sistemi a 32-bit bisognerà provare il valore 0 e il valore 1).

Particolare attenzione va dato al valore da assegnare al terzo argomento __mode che è un valore intero formato dalla somma dei valori delle impostazioni dei permessi per i tre utenti. L'argomento __mode specifica, in particolare, sia la modalità del file da utilizzare sia il tipo di nodo da creare. Dovrebbe essere una combinazione (usando l'operatore OR bit-a-bit) fra il valore della modalità prescelta e il valore della costante-direttiva S_IFIFO, pari a 4096, utile per specificare il tipo di file da creare, in questo caso il file speciale FIFO.

I valori attribuibili sono 4 per ciascuna classe di utenti considerata:

  • il primo (sempre zero) significa negazione di ogni permesso sul file;
  • il secondo consente la sola scrittura del file;
  • il terzo consente la sola lettura del file;
  • il quarto consente la lettura e la scrittura del file.

In particolare:

  • i valori riferiti all'utente Altri sono: 0, 2, 4, 6 (quindi partendo da 0 un comando ogni 2 valori). Aggiungendo 1 ad uno dei predetti valori, si consente anche l'esecuzione del file.
  • i valori riferiti all'utente Gruppo sono: 0, 16, 32, 48 (quindi partendo da 0 un comando ogni 16 valori). Aggiungendo 8 ad uno dei predetti valori, si consente anche l'esecuzione del file.
  • i valori riferiti all'utente Proprietario sono: 0, 128, 256, 384 (quindi partendo da 0 un comando ogni 128 valori). Aggiungendo 8 ad uno dei predetti valori, si consente anche l'esecuzione del file.

Il quarto argomento *__dev della funzione esterna deve essere un Puntatore ad una variabile di tipo Intero istanziata a 0 (zero) in caso di named pipe.

Caso in cui il programma Gambas crea la named pipe e riceve dati

Mostriamo un esempio pratico in cui il programma Gambas, che crea la named pipe (ossia il file speciale di tipo FIFO) e riceve dati inviati da altro programma, avrà il seguente codice:

Private Const FIFO As String = "/tmp/FIFO"
Private fl As File


Library "libc:6"

Private Const _MKNOD_VER As Integer = 0
Private Const S_IFIFO As Integer = 4096

' __mode_t umask (__mode_t __mask)
' Set the file creation mask of the current process to MASK.
Private Extern umask(mask As Integer) As Integer

' int __xmknod (int __ver, const char *__path, __mode_t __mode, __dev_t *__dev)
' Create a device file named PATH, with permission and special bits MODE and device number DEV.
Private Extern __xmknod(ver As Integer, path As String, mode As Integer, dev As Pointer) As Integer 'In "libarchive"


Public Sub Main()
 
 Dim err, mode As Integer
  
 If Exist(FIFO) Then Kill FIFO
  
' Crea la 'pipe' FIFO:
 umask(0)
  
 err = __xmknod(_MKNOD_VER, FIFO, S_IFIFO Or 438, VarPtr(mode))
 If err = -1 Then Error.Raise("Impossibile creare il file-device !")
  
' Apre il file speciale FIFO in scrittura e lo pone sotto 'osservazione':
 fl = Open FIFO For Write Watch
   
End

Public Sub File_Read()
 
 Dim s As String
 
 Read #fl, s, -256
 Print s
  
End

Il programma che invia i dati può essere molto semplicemente il seguente:

Private Const FIFO_FILE As String = "/tmp/FIFO"


Public Sub Main()
 
 Dim fl As File
 Dim s As String
 
 fl = Open FIFO_FILE For Write
   
 Write #fl, "Questa è una prova"
  
 fl.Close
  
End

Ovviamente va prima avviato il programma che crea il file speciale, la named pipe, e che in questo caso dovrà ricevere i dati. Poi va lanciato il programma che invia i dati. Volendo, dopo aver avviato il programma che riceve i dati, si potrà anche anche utilizzare un Terminale per trasmettere semplicemente dati, scrivendo ed inviando ad esempio la seguente riga di comando:
~ $ echo testo qualsiasi ls > /tmp/FIFO
o anche una riga di comando da far eseguire dal programma ricevente, come ad esempio:
~ $ echo -ne '\n' | ls > /tmp/FIFO

Caso in cui il programma Gambas crea la named pipe ed invia dati

In quest'altro caso il programma Gambas, che genera la named pipe, invierà dati al file speciale e quindi ad altro programma ricevente.

Mostriamo un esempio pratico:

Private Const FIFO As String = "/tmp/FIFO"
Private fl As File


Library "libc:6"

Private Const _MKNOD_VER As Integer = 0
Private Const S_IFIFO As Integer = 4096

' __mode_t umask (__mode_t __mask)
' Set the file creation mask of the current process to MASK.
Private Extern umask(mask As Integer) As Integer

' int __xmknod (int __ver, const char *__path, __mode_t __mode, __dev_t *__dev)
' Create a device file named PATH, with permission and special bits MODE and device number DEV.
Private Extern __xmknod(ver As Integer, path As String, mode As Integer, dev As Pointer) As Integer 'In "libarchive"


Public Sub Main()
 
 Dim err, mode As Integer
 
 If Exist(FIFO) Then Kill FIFO
  
' Crea la 'pipe' FIFO:
 umask(0)
  
 err = __xmknod(_MKNOD_VER, FIFO, S_IFIFO Or 438, VarPtr(mode))
 If err = -1 Then Error.Raise("Impossibile creare il file-device !")
  
' Apre il file speciale FIFO in scrittura:
 fl = Open FIFO For Write

 While True
   Write #fl, "Invio di dati alla 'pipe'"
   Wait 0.5
 Wend
      
End

Ovviamente va prima avviato il programma che crea il file speciale, la named pipe, e che in questo caso invia i dati. Poi va lanciato il programma Gambas esterno (o ugualmente un Terminale) che deve ricevere i dati dalla named pipe.

Caso in cui il programma Gambas crea la named pipe e rimane inerte

Ora mostriamo un caso in cui il programma Gambas crea la named pipe, ma poi il codice non prevede il ricevimento né l'invio di dati. Saranno altri programmi a dover inviare ed a ricevere i dati.

Il codice del programma Gambas sarà dunque questo:

Private Const FIFO As String = "/tmp/FIFO"
Private fl As File


Library "libc:6"

Private Const _MKNOD_VER As Integer = 0
Private Const S_IFIFO As Integer = 4096

' __mode_t umask (__mode_t __mask)
' Set the file creation mask of the current process to MASK.
Private Extern umask(mask As Integer) As Integer

' int __xmknod (int __ver, const char *__path, __mode_t __mode, __dev_t *__dev)
' Create a device file named PATH, with permission and special bits MODE and device number DEV.
Private Extern __xmknod(ver As Integer, path As String, mode As Integer, dev As Pointer) As Integer 'In "libarchive"


Public Sub Main()
 
 Dim err, mode As Integer
  
 If Exist(FIFO) Then Kill FIFO
  
' Crea la 'pipe' FIFO:
 umask(0)
  
 err = __xmknod(_MKNOD_VER, FIFO, S_IFIFO Or 438, VarPtr(mode))
 If err = -1 Then Error.Raise("Impossibile creare il file-device !")
  
' Apre il file speciale FIFO in scrittura:
 fl = Open FIFO For Write

 While True
   Wait 0.01
 Wend
      
End

In ordine ai due programmi esterni poniamo il semplice caso di avere due Terminali: uno invierà i dati e l'altro li riceverà.

Innanzitutto va lanciato il programma Gambas che crea il file speciale FIFO; quindi nel Terminale che deve ricevere i dati si lancerà la seguente linea di comando:

~ $ cat < /tmp/FIFO

mentre nel secondo Terminale si invieranno i dati nelle modalità già viste sopra:
~ $ echo testo qualsiasi ls > /tmp/FIFO
o anche una riga di comando da far eseguire dal programma ricevente, come ad esempio:
~ $ echo -ne '\n' | ls > /tmp/FIFO


Uso del file speciale /dev/pts/... e del file descriptor 1 associati al processo del programma ricevente

Sarà possibile inviare i dati anche utilizzando il file speciale (/dev/pts/...) associato al programma "A" ricevente, oppure il file descriptor n. 1 (/proc/PID_del_processo_di_A/fd/1) associato al processo del programma "A" ricevente. In questo caso si potranno avere due effetti a seconda del codice scritto nei due programmi.

Caso in cui i dati ricevuti in console/Terminale possono essere soltanto visualizzati

Inviando i dati semplicemente con le funzioni Write o Print al file-descriptor associato al programma ricevente o al file speciale pts del programma ricevente, i dati potranno essere soltanto visualizzati in console/Terminale, ma non recuperati per essere eventualmente gestiti.

Uso dei file speciali /dev/pts/...

Nel progetto "A", che riceve i dati inviati dal programma "B", avremo il seguente codice:

Public Sub Main()
 
 Dim pts As String
 
' Ricaviamo e mostriamo in console/Terminale il file speciale che rappresenta il progetto "A" (il nome del file "pts" servirà per il programma "B" inviante):
 pts = Dir("/dev/pts", "*", gb.Device)[0]
  
 Print pts
  
' Restiamo in attesa dei dati inviati:
 While True
   Wait 0.01
 Wend
  
End

Nel progetto "B", che invia i dati al programma "A", avremo il seguente codice:

Private fl As File


Public Sub Main()

 Dim pts As String

' Qui va inserito il nome numerico del file speciale (pts) che rappresenta il progetto "A":
 pts = ....

' Viene aperto il file speciale che rappresenta il progetto "A":
 fl = Open "/dev/pts/..." For Write
   
' Viene inviata la stringa di caratteri al file speciale che rappresenta il progetto "A":
 While True
   Print #fl, "Testo qualsiasi" 
   Wait 0.3
 Wend
   
End

Uso del file descriptor n. 1

In quest'altro esempio il programma "B" invia di continuo il valore progressivamente incrementato di una variabile. La stringa dei dati inviata è formattata in modo tale che nella console del programma "A" ricevente (se esso è aperto come progetto nell'IDE) ovvero nel Terminale (se il programma "A" è stato lanciato da Terminale) i dati verranno di volta in volta visualizzati sovrascritti.

Nel progamma "A", che riceve i dati, avremo il seguente codice:

Public Sub Main()
  
' Ricaviamo e mostriamo in console o in Terminale il PID del programma "A" ricevente (il PID servirà per il programma "B" inviante):
 Print Application.Id
  
' Restiamo in attesa dei dati inviati:
 While True
   Wait 0.01
 Wend
 
End

Il codice del programma "B", che invia i dati, in questo esempio sarà il seguente:

Private fl As File

 
Public Sub Main()

 Dim fl As File
 Dim i As Integer
 Dim nome_processo, PID As String

' Qui va assegnato il PID del programma "A" ricevente i dati:
 PID = .....
  
' Apriamo il "file-descriptor" n. 1 del processo del programma "A" in scrittura:
 fl = Open "/proc" &/ PID &/ "fd/1" For Write
  
' Ciclo per l'invio continuo - ogni 500 millisecondi - del valore progressivamente incrementato della variabile di tipi Intero:
 While True
' Formattiamo la stringa in modo tale che i dati, di volta in volta inviati, si sovrascrivano ai precedenti:
   Write #fl, "\r" & i
   Wait 0.5
   Inc i
 Wend
   
End

Caso in cui i dati ricevuti in console/Terminale possono essere anche recuperati ed utilizzati dal programma ricevente

Il programma che riceve i dati acquista la capacità di intercettarli, per poterli successivamente gestire direttamente, attraverso l'invio manuale dei dati dalla console/Terminale. Questa modalità, in particolare, prevede che i dati vengono scritti ed inviati manualmente dall'apposito spazio sottostante la console dell'IDE oppure nel Terminale, se il programma inviante è stato lanciato da Terminale.
In tal caso è necessario nel programma ricevente aprire in lettura e porre in osservazione con la parola chiave Watch il file speciale pts del programma che invia i dati, ed il programma inviante deve aprire in scrittura il file speciale pts del programma ricevente o, in alternativa, il proprio file speciale pts a cui esso è associato. Com già accennato, i dati dovranno essere inviati scrivendoli nell'apposito spazio sottostante la console dell'IDE oppure nel Terminale, se il programma inviante è stato lanciato da Terminale. Dopo averli scritti si dovrà inviarli premendo come di consueto il tasto "Invia" (Enter) della tastiera.

Mostriamo di seguito un semplice esempio pratico, nel quale il codice del programma "A", che riceve i dati, sarà il seguente:

Private fl As File


Public Sub Main()
 
 Dim b As Byte
 Dim pts As String
 
' Individua il file speciale 'pts' che sarà creato, associato al programma che invia i dati:
 While True
   If Not Exist("/dev/pts" &/ CStr(b)) Then Break
   Inc b
 Wend
  
 pts = CStr(b)
  
 Print "Il file spciale 'pts' del programma che invia i dati sarà:", pts
  
' Resta in attesa che il file speciale 'pts', associato al programma che invia i dati, sia generato:
 Repeat
   Wait 0.01
 Until Exist("/dev/pts" &/ pts)

' Apre il file speciale 'pts', associato al programma che invia i dati, in lettura e lo sottopone in 'osservazione':
 fl = Open "/dev/pts" &/ pts For Read Watch

End

Public Sub File_read()
 
 Dim s As String
 
 Read #fl, s, -256
  
 Print s

End

Il codice del programma "B", che invia i dati, sarà il seguente:

Private i As Integer


Public Sub Main()
  
 Dim fl As File
 Dim pts As String
 
' Qui va attribuito il numero del file speciale 'pts' associato al programma che riceve i dati:
 pts = ...

' Apre in scrittura il file speciale 'pts' associato al programma che riceve i dati:
 fl = Open "/dev/pts" &/ pts For Write

 While True
   Wait 0.01
 Wend

End


Uso della Classe Clipboard

Si potranno trasmettere dati anche sfruttando gli "Appunti" di sistema con una sorta di copia-incolla, da effettuarsi mediante la Classe Clipboard di Gambas. In particolare utilizzeremo le funzioni .Copy() e .Paste() della Classe Clipboard.
Durante il trasferimento dei dati da un programma all'altro bisogna prestare attenzione a non effettuare alcun'altra copia di caratteri (per esempio con il mouse), o comunque di altri dati, altrimenti verrà trasmesso il contenuto della nuova copia di dati appena effettuata.
Ovviamente, trattandosi di "Appunti" di sistema, i dati potranno essere raccolti pure da altri programmi, anche non-Gambas.

Facciamo un esempio pratico. Avendo due programmi, A che deve trasferire dei dati al programma B, nel programma A avremo il seguente codice, capace di copiare dati negli appunti:

Public Sub Button1_Click()

 Dim s As String

 s = "Prova trasferimento dati stringa"

 Clipboard.Copy(s)
 
End

mentre nel programma B avremo il seguente codice, capace di raccogliere quanto precedentemente copiato negli appunti dal programma A:

Public Sub Button1_Click()

 Dim s As String

 s = Clipboard.Paste()

 Print s

End


Invio di dati ad un Terminale distinto dal programma Gambas

Un modo di inviare meramente dei caratteri testuali ad un Terminale, esterno e distinto rispetto al nostro programma Gambas principale, è quello di individuare innanzitutto il file-device speciale del Terminale medesimo, quindi aprirlo in scrittura e scriverci i dati.

Mostriamo un esempio pratico con un'applicazione grafica (lanciaare prima il programma Gambas e poi il Terminale).

Public Sub Form_Open()
 
 Dim b As Byte

' Verifichiamo innanzitutto quanti file 'pts' sono presenti in '/dev/pts':
 b = Dir("/dev/pts", Null, gb.Device).Count
  
 Repeat
   Wait 0.01
 Until b < Dir("/dev/pts", Null, gb.Device).Count
  
End

Public Sub Button1_Click()
 
 Dim fl As File
 Dim s As String
  
' L'ultimo file 'pts' creato è posizionato nel 1° elemento del vettore generato dalla funzione "Dir()":
 s = Dir("/dev/pts", Null, gb.Device)[0]
  
' Scriviamo qualcosa nel Terminale che è stato appena aperto:
 fl = Open "/dev/pts" &/ s For Write
  
 Write #fl, "Questa è una prova"
     
 fl.Close
     
End

Con un'applicazione Gambas a riga di comando (anche in questo caso si lancerà prima l'applicazione e poi il Terminale).
In console - o nel Terminale ove sia stato lanciato l'eseguibile dell'applicazione Gambas - sarà mostrato lo scorrere temporale, basterà quindi premere il tasto "Invio" della tastiera per inviare la stringa temporale al nuovo Terminale aperto.

Private b As Byte
Private n As Byte
Private fl As File

Public Sub Main()

 Dim s As String
 Dim tm As Date

 For Each s In Dir("/dev/pts", Null, gb.Device)
   If IsNumber(s) Then b += Val(s)
 Next
 n = b
 Repeat 
   For Each s In Dir("/dev/pts", Null, gb.Device)
     If IsNumber(s) Then b += Val(s)
   Next
 Until b > n

 s = "/proc" &/ Application.Handle &/ "fd/0"

 fl = Open s For Input Watch 

 tm = Now
 While True
   Write "\r  \e[31m" & CStr(Time(0, 0, 0, DateDiff(tm, Now, gb.Millisecond))) & Space(30)
   Wait 0.001
 Wend

End

Public Sub File_Read()
 
 Dim s As String
 Dim pts As File
 
 pts = Open "/dev/pts" &/ CStr(b - n) For Write
 Output To #pts
 Line Input #fl, s
 
End

Un'altra modalità può essere la seguente (in quest'altro esempio bisognerà invece aprire prima il Terminale e successivamente lanciare il codice Gambas).

Private fl As File


Public Sub Form_Open()
 
 Dim s As String
 Dim ss As String[]
 Dim c As Short
 
 ss = Dir("/proc", Null, gb.Directory)
  
 c = ss.Count
   
' Si cerca la parola "bash" all'interno del file di sistema "comm" presente negli ultimi processi aperti:
 Repeat
   Dec c
 Until File.Load("/proc" &/ CStr(ss[c]) &/ "comm") Begins "bash"
   
 fl = Open "/proc" &/ CStr(ss[c]) &/ "fd/1" For Write
  
End

Public Sub Button1_Click()
 
 Write #fl, "Testo qualsiasi"
  
End

Public Sub Button2_Click()
  
 fl.Close
 Me.Close
  
End

Va comunque sottolineato che la scrittura nel Terminale, nelle modalità sopra descritte, non è utile per lanciare efficacemente un eventuale comando bash o altro programma.