Successivo: Creazione di vettori, Precedente: Funzioni per i vettori, Su: Manipolazione di vettori [Contenuti][Indice]
Appiattire un vettore vuol dire creare una struttura che rappresenta l’intero vettore in modo da facilitare la visita dell’intero vettore da parte del codice in C . Parte del codice in extension/testext.c fa questo, ed è anche un bell’esempio di come utilizzare l’API.
Questa parte del codice sorgente sarà descritta un po’ per volta.
Ecco, per iniziare, lo script gawk
che richiama l’estensione di test:
@load "testext" BEGIN { n = split("blacky rusty sophie raincloud lucky", pets) printf("pets ha %d elementi\n", length(pets)) ret = dump_array_and_delete("pets", "3") printf("dump_array_and_delete(pets) ha restituito %d\n", ret) if ("3" in pets) printf("dump_array_and_delete() NON ha rimosso l'indice \"3\"!\n") else printf("dump_array_and_delete() ha rimosso l'indice \"3\"!\n") print "" }
Questo codice crea un vettore usando la funzione split()
(vedi la sezione Funzioni di manipolazione di stringhe)
e poi chiama dump_array_and_delete()
. Questa funzione ricerca
il vettore il cui nome è passato come primo argomento, ed
elimina l’elemento il cui indice è passato come secondo argomento.
Il codice awk
stampa poi il valore restituito e controlla che
l’elemento sia stato effettivamente cancellato. Ecco il codice C che
costituisce la funzione
dump_array_and_delete()
. È stato leggermente modificato per facilitare
l’esposizione.
La prima parte dichiara variabili, imposta il codice di ritorno di default
in risultato
, e controlla che la funzione
sia stata chiamata con il numero corretto di argomenti:
static awk_value_t * dump_array_and_delete(int nargs, awk_value_t *risultato) { awk_value_t valore, valore2, valore3; awk_flat_array_t *flat_array; size_t count; char *nome; int i; assert(risultato != NULL); make_number(0.0, risultato); if (nargs != 2) { printf("dump_array_and_delete: nargs errato " "(%d dovrebbe essere 2)\n", nargs); goto out; }
La funzione poi prosegue un passo per volta, come segue. Il primo passo è ricuperare il nome del vettore, passato come primo argomento, seguito dal vettore stesso. Se una di queste operazioni non riesce, viene stampato un messaggio di errore e si ritorna al chiamante:
/* trasforma in un vettore piatto il vettore passato come argomento e lo stampa */ if (get_argument(0, AWK_STRING, & value)) { nome = valore.str_value.str; if (sym_lookup(nome, AWK_array, & value2)) printf("dump_array_and_delete: sym_lookup di %s effettuato\n", nome); else { printf("dump_array_and_delete: sym_lookup di %s non riuscito\n", nome); goto out; } } else { printf("dump_array_and_delete: get_argument(0) non riuscito\n"); goto out; }
Per controllo, e per assicurarsi che il codice C veda
lo stesso numero di elementi del codice awk
,
il secondo passo è quello di ottenere il numero di elementi nel vettore
e stamparlo:
if (! get_element_count(valore2.array_cookie, & count)) { printf("dump_array_and_delete: get_element_count non riuscito\n"); goto out; } printf("dump_array_and_delete: il vettore in input ha %lu elementi\n", (unsigned long) count);
Il terzo passo è quello di appiattire il vettore, e quindi
controllare che il numero di elementi nella struttura awk_flat_array_t
sia uguale a quello appena trovato:
if (! flatten_array_typed(valore2.array_cookie, & flat_array, AWK_STRING, AWK_UNDEFINED)) { printf("dump_array_and_delete: non sono riuscito ad appiattire \ il vettore\n"); goto out; } if (flat_array->count != count) { printf("dump_array_and_delete: flat_array->count (%lu)" " != count (%lu)\n", (unsigned long) flat_array->count, (unsigned long) count); goto out; }
Il quarto passo è ritrovare l’indice dell’elemento
da eliminare, che era stato passato come secondo argomento.
Va tenuto presente che i contatori di argomenti passati a get_argument()
partono da zero, e che quindi il secondo argomento è quello numero uno:
if (! get_argument(1, AWK_STRING, & value3)) { printf("dump_array_and_delete: get_argument(1) non riuscito\n"); goto out; }
Il quinto passo è quello in cui si fa il “vero lavoro”. La funzione esegue
un ciclo su ogni elemento nel vettore, stampando i valori degli indici e
degli elementi. Inoltre, dopo aver trovato, tramite l’indice, l’elemento
che si vorrebbe eliminare, la funzione imposta il bit
AWK_ELEMENT_DELETE
nel campo flags
dell’elemento. Quando il vettore è stato interamente percorso, gawk
visita il vettore appiattito, ed elimina ogni elemento in cui il relativo
bit della flag sia impostato:
for (i = 0; i < flat_array->count; i++) { printf("\t%s[\"%.*s\"] = %s\n", nome, (int) flat_array->elements[i].index.str_value.len, flat_array->elements[i].index.str_value.str, valrep2str(& flat_array->elements[i].valore)); if (strcmp(valore3.str_value.str, flat_array->elements[i].index.str_value.str) == 0) { flat_array->elements[i].flags |= AWK_ELEMENT_DELETE; printf("dump_array_and_delete: ho marcato l'elemento \"%s\" " "per eliminazione\n", flat_array->elements[i].index.str_value.str); } }
Il sesto passo è liberare il vettore appiattito. Questo segnala a
gawk
che l’estensione non sta più usando il vettore,
e che dovrebbe eliminare gli elementi marcati per l’eliminazione.
gawk
libera anche ogni area di memoria che era stata allocata,
e quindi non si dovrebbe più usare il puntatore (flat_array
in
questo codice) dopo aver chiamato release_flattened_array()
:
if (! release_flattened_array(valore2.array_cookie, flat_array)) { printf("dump_array_and_delete: non riesco a liberare \ il vettore appiattito\n"); goto out; }
Infine, poiché tutto è andato bene, la funzione imposta il codice di ritorno a "successo", e lo restituisce quando esce:
make_number(1.0, risultato); out: return risultato; }
Ecco l’output ottenuto eseguendo questa parte del test:
pets ha 5 elementi dump_array_and_delete: sym_lookup di pets effettuato dump_array_and_delete: il vettore in input ha 5 elementi pets["1"] = "blacky" pets["2"] = "rusty" pets["3"] = "sophie" dump_array_and_delete: ho marcato l'elemento "3" per eliminazione pets["4"] = "raincloud" pets["5"] = "lucky" dump_array_and_delete(pets) ha restituito 1 dump_array_and_delete() ha rimosso l'indice "3"!
Successivo: Creazione di vettori, Precedente: Funzioni per i vettori, Su: Manipolazione di vettori [Contenuti][Indice]