Successivo: Funzioni di allocazione memoria, Precedente: Intro funzioni estensione API, Su: Descrizione dell'estensione API [Contenuti][Indice]
Ho un vero rapporto di amore/odio con le unioni.
Questo è ciò che contraddistingue le unioni: il compilatore è in grado di accomodare le cose in modo da far coesistere amore e odio.
L’estensione API definisce un certo numero di semplici tipi di dato e strutture di uso generale. Ulteriori strutture di dati, più specializzate, saranno introdotte nelle successive sezioni, insieme alle funzioni che ne fanno uso.
I tipi di dati e le strutture di uso generale sono le seguenti:
typedef void *awk_ext_id_t;
Un valore di questo tipo è trasmesso da gawk
a un’estensione nel
momento in cui viene caricata. Tale valore dev’essere restituito
a gawk
come primo parametro di ogni funzione API.
#define awk_const …
Questa macro genera delle ‘costanti’ nel momento in cui si compila
un’estensione, e non genera nulla quando si compila il comando gawk
vero e proprio. Ciò rende alcuni
campi nelle strutture dei dati dell’API non alterabili dal codice sorgente
dell’estensione, ma consente al comando gawk
di usarle secondo
necessità.
typedef enum awk_bool {
awk_false = 0,
awk_true
} awk_bool_t;
Un semplice tipo di variabile booleana.
typedef struct awk_string {
char *str; /* dati veri e propri */
size_t len; /* lunghezza degli stessi, in caratteri */
} awk_string_t;
Questo rappresenta una stringa modificabile. gawk
è responsabile
per la gestione della memoria utilizzata, se ha fornito il valore della
stringa. Altrimenti, assume il possesso della memoria in questione.
Questa memoria dev’essere resa disponibile chiamando una delle funzioni
gawk_malloc()
, gawk_calloc()
o gawk_realloc()
!
Come già detto, la rappresentazione delle stringhe in memoria usa la codifica multibyte corrente.
typedef enum {
AWK_UNDEFINED,
AWK_NUMBER,
AWK_STRING,
AWK_REGEX,
AWK_STRNUM,
AWK_ARRAY,
AWK_SCALAR, /* accesso opaco a una variabile */
AWK_VALUE_COOKIE /* per aggiornare un valore
già creato */
} awk_valtype_t;
L’elenco enum
indica di che tipo è un certo valore.
È usato nella seguente struttura struct
.
typedef struct awk_value {
awk_valtype_t val_type;
union {
awk_string_t s;
awknum_t n;
awk_array_t a;
awk_scalar_t scl;
awk_value_cookie_t vc;
} u;
} awk_value_t;
Un “valore di awk
”.
Il campo val_type
indica che tipo di valore union
contiene,
e ogni campo è del tipo appropriato.
#define str_value u.s
#define strnum_value str_value
#define regex_value str_value
#define num_value u.n.d
#define num_type u.n.type
#define num_ptr u.n.ptr
#define array_cookie u.a
#define scalar_cookie u.scl
#define value_cookie u.vc
L’uso di queste macro rende più facile da seguire l’accesso ai campi di
awk_value_t
.
enum AWK_NUMBER_TYPE {
AWK_NUMBER_TYPE_DOUBLE,
AWK_NUMBER_TYPE_MPFR,
AWK_NUMBER_TYPE_MPZ
};
La lista enum
è usata nella struttura seguente per definire
il tipo di valore numerico con cui si ha a che fare. Va dichiarata al
livello più alto del file, in modo da poter essere usata sia con il
linguaggio C++ che con il C.
typedef struct awk_number {
double d;
enum AWK_NUMBER_TYPE type;
void *ptr;
} awk_number_t;
Questo rappresenta un valore numerico. Internamente, gawk
memorizza ogni numero o come una variabile C di tipo double
,
o come un numero intero GMP, o come un numero MPFR in virgola mobile
di precisione arbitraria. Per consentire alle estensioni di
supportare valori numerici GMP ed MPFR, i valori numerici sono
trasmessi utilizzando questa struttura.
L’elemento in doppia-precisione d
è sempre presente nei dati
ricevuti da gawk
. Inoltre, esaminando il membro
type
, un’estensione è in grado di determinare se il membro puntato
da ptr
sia un numero intero GMP (tipo mpz_ptr
), o un numero
MPFR in virgola mobile (tipo mpfr_ptr_t
), e trasformarlo a seconda
delle necessità.
typedef void *awk_scalar_t;
La variabili scalari possono essere rappresentate da un tipo opaco. Questi
valori sono ottenuti da gawk
e in seguito gli vengono restituiti.
Questo argomento è discusso in maniera generale nel testo che segue questa
lista, e più in dettaglio
in
Accedere alle variabili per “cookie” e aggiornarle.
typedef void *awk_value_cookie_t;
Un “value cookie” è un tipo di variabile opaca, e rappresenta un valore nascosto. Anche questo argomento è discusso in maniera generale nel testo che segue questa lista, e più in dettaglio in Creare e usare valori nascosti.
I valori di tipo scalare in awk
sono numeri, stringhe, strnum
o regexp fortemente tipizzate.
La struttura awk_value_t
rappresenta valori.
Il campo val_type
indica cosa contiene union
.
Rappresentare numeri è facile: l’API usa una variabile C di tipo
double
. Le stringhe richiedono
uno sforzo maggiore. Poiché
gawk
consente che le stringhe contengano dei byte NUL
(a zeri binari) nel valore di una stringa, una stringa dev’essere
rappresentata da una coppia di campi che contengono il puntatore al dato vero
e proprio e la lunghezza della stringa.
È questo è il tipo awk_string_t
.
Un valore di tipo strnum (stringa numerica) è rappresentato come una
stringa e consiste di dati in input forniti dall’utente che appaiono essere
numerici.
Quando una funzione di estensione crea un valore di tipo strnum, il
risultato è una stringa che viene marcata come immessa dall’utente. La
successiva analisi da parte di gawk
servirà poi a determinare se
la stringa appare essere un numero, e va quindi trattata come strnum,
invece che come una normale stringa di caratteri.
Ciò è utile nei casi un cui una funzione di estensione desideri fare qualcosa
di paragonabile alla funzione split
, la quale imposta l’attributo
di strnum agli elementi di vettore che crea.
Per esempio, un’estensione che implementi la divisione di record CSV
(Comma Separated Values, i cui elementi sono delimitati da virgole)
potrebbe voler usare questa funzionalità. Un’altra situazione in cui ciò
è utile è quello di una funzione che richieda campi-dati ad una banca di
dati. La funzione PQgetvalue()
della banca dati PostgreSQ, per
esempio, restituisce una stringa che può essere numerica o di tipo carattere,
a seconda del contesto.
I valori di regexp fortemente tipizzate
(vedi la sezione Costanti regexp fortemente tipizzate non sono molto utili nelle funzioni di
estensione. Le funzioni di estensione possono stabilire di averli ricevuti,
e crearne, attribuendo valori di tipo scalare. In alternativa, è possibile
esaminare il testo della regexp utilizzando campi regex_value.str
e regex_value.len
.
Identificativi (cioè, nomi di variabili globali) possono essere
associati sia a valori scalari che a vettori. Inoltre, gawk
consente veri vettori di vettori, in cui ogni singolo elemento di un vettore
può a sua volta essere un vettore. La spiegazione dei vettori è rinviata
a
Manipolazione di vettori.
La varie macro sopra elencate facilitano l’uso degli elementi delle
union
come se
fossero campi in una struttura struct
; è questa una pratica
comunemente adottata
nella scrittura di programmi in C. Questo tipo di codice è più semplice da
scrivere e da leggere, ma resta una responsabilità del programmatore
assicurarsi che il campo val_type
rifletta correttamente il tipo
del valore contenuto nella struttura awk_value_t
.
Dal punti di vista concettuale, i primi tre campi dell’union
(numero,
stringa, e vettore) sono sufficienti per lavorare con i valori awk
.
Tuttavia, poiché l’API fornisce routine per ottenere e modificare
il valore di una variabile scalare globale usando solo il nome della
variabile, si ha qui una perdita di efficienza: gawk
deve cercare
la variabile ogni volta che questa è utilizzata e modificata. Questo
è un probelma reale, non solo un problema teorico.
Per questo motivo, se si sa che una certa estensione passerà molto tempo
a leggere e/o modificare il valore di una o più variabili scalari, si può
ottenere uno scalar cookie108
per quella variabile, e poi usare
il cookie per ottenere il valore della variabile o per modificarne il
valore.
Il tipo awk_scalar_t
contiene uno scalar cookie, e la macro
scalar_cookie
fornisce accesso al valore di quel tipo
nella struttura awk_value_t
.
Dato uno scalar cookie, gawk
può trovare o modificare
direttamente il valore, come richiesto, senza bisogno di andarlo
a cercare ogni volta.
Il tipo awk_value_cookie_t
e la macro value_cookie
sono simili.
Se si pensa di dover usare
lo stesso valore numerico o la stessa stringa per una o più
variabili, si può creare il valore una volta per tutte, mettendo da parte un
value cookie per quel valore, e in seguito specificare quel
value cookie quando si desidera impostare il valore di una variabile.
Ciò consente di risparmiare spazio in memoria all’interno del processo
di gawk
e riduce il tempo richiesto per creare il valore.
Si veda la voce “cookie” nello Jargon file per una definizione di cookie, e la voce “magic cookie” sempre nello Jargon file per un bell’esempio. Si veda anche la voce “Cookie” nel Glossario. [È disponibile in rete anche una traduzione italiana dello Jargon file]
Successivo: Funzioni di allocazione memoria, Precedente: Intro funzioni estensione API, Su: Descrizione dell'estensione API [Contenuti][Indice]