Successivo: , Precedente: , Su: Manipolazione di vettori   [Contenuti][Indice]


17.4.11.3 Lavorare con tutti gli elementi di un vettore

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: , Precedente: , Su: Manipolazione di vettori   [Contenuti][Indice]