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]