Capitolo 12. Programmazione

# Capitolo 12. Programmazione

Vengono forniti in questo capitolo alcune informazioni base da cui partire per imparare a programmare su un sistema Debian abbastanza da seguire il codice sorgente impacchettato. Quello che segue è un elenco dei pacchetti importanti per la programmazione e dei corrispettivi pacchetti di documentazione.

Guide di riferimento in linea sono disponibili digitando "`man nome`" dopo aver installato i pacchetti `manpages` e `manpages-dev`. Le guide di riferimento in linea per gli strumenti GNU sono disponibili digitando "`info nome_programma`", dopo aver installato i pertinenti pacchetti di documentazione. Può essere necessario includere gli archivi "`contrib` e `non-free`, oltre all'archivio `main`, dato che alcune documentazioni GFDL non sono considerate conformi alle DFSG.

Considerare l'uso degli strumenti dei sistemi di controllo di versione. Vedere Sezione 10.5, «Git».

| Avvertimento
Non usare "`test`" come nome di un file di prova eseguibile. "`test`" è un comando interno della shell.

| Attenzione
I programmi software compilati direttamente dai sorgenti andrebbero installati in "`/usr/local`" o "`/opt`" per evitare conflitti.

| Suggerimento
Esempi di codice per creare la "Canzone 99 bottiglie di birra" dovrebbe dare buone idee per praticamente tutti i linguaggi di programmazione.

## 12.1. Script shell

Uno script di shell è un file di testo con il bit di esecuzione impostato e contiene i comandi nel formato seguente.

    #!/bin/sh
     ... command lines

La prima riga specifica l'interprete di shell che legge ed esegue il contenuto di questo file.

Leggere script di shell è il modo migliore per capire come funzioni un sistema *nix. In questa sezione vengono forniti alcune nozioni di riferimento e promemoria per la programmazione di shell. Vedere "Errori in shell" (https://www.greenend.org.uk/rjk/2001/04/shell.html) per imparare dagli errori.

A differenza della modalità interattiva della shell (vedere Sezione 1.5, «Il semplice comando di shell» e Sezione 1.6, «Elaborazione di testo stile Unix»), gli script di shell usano spesso parametri, costrutti condizionali e cicli.

### 12.1.1. Compatibilità con la shell POSIX

Molti script di sistema possono essere interpretati da una qualsiasi delle shell POSIX (vedere Tabella 1.13, «Elenco di programmi shell»).

- La shell POSIX non interattiva predefinita "`/usr/bin/sh`" è un collegamento simbolico che punta a `/usr/bin/dash` ed è usata da molti programmi di sistema.

- La shell POSIX interattiva predefinita è `/usr/bin/bash`.

Evitare di scrivere uno script di shell con bashismi o zshismi per renderlo portabile tra tutte le shell POSIX. Si può controllare uno script con `checkbashisms`(1).

Tabella 12.1. Elenco di bashismi tipici

Buono: POSIX | Da evitare: bashismo
--- | ---
`if [ "$pippo" = "$pluto" ] ; then …` | `if [ "$pippo" == "$pluto" ] ; then …`
`diff -u file.c.orig file.c` | `diff -u file.c{.orig,}`
`mkdir /pippopluto /pippopaperino` | `mkdir /pippo{pluto,paperino}`
`nomefunzione() { … }` | `function nomefunzione() { … }`
formato ottale: "`\377`" | formato esadecimale: "`\xff`"

Il comando "`echo`" deve essere usato con le precauzioni seguenti dato che la sua implementazione è diversa negli svariati comandi interni della shell ed esterni.

- Evitare l'uso di qualsiasi opzione di comando tranne "`-n`".

- Evitare l'uso di sequenze di escape nelle stringhe dato che la loro gestione è variabile.

| Nota
Sebbene l'opzione "`-n`" non faccia veramente parte della sintassi POSIX, è generalmente accettata.

| Suggerimento
Se è necessario inserire sequenze di escape nella stringa in output, usare il comando "`printf`" al posto del comando "`echo`".

### 12.1.2. Parametri di shell

Negli script di shell vengono spesso usati parametri speciali.

Tabella 12.2. Elenco di parametri di shell

parametro di shell | valore
--- | ---
`$0` | nome della shell o dello script di shell
`$1` | primo (1°) argomento di shell
`$9` | nono (9°) argomento di shell
`$#` | numero di parametri posizionali
`"$*"` | `"$1 $2 $3 $4 … "`
`"$@"` | `"$1" "$2" "$3" "$4" …`
`$?` | stato d'uscita del comando più recente
`$$` | PID dello script di shell
`$!` | PID del compito sullo sfondo avviato più recentemente

Le nozioni base da ricordare riguardanti la espansione dei parametri sono le seguenti.

Tabella 12.3. Elenco di espansioni di parametri di shell

forma della espressione con parametri | valore se `var` è impostata | valore se `var` non è impostata
--- | --- | ---
`${var:-stringa}` | "`$var`" | "`stringa`"
`${var:+stringa}` | "`stringa`" | "`null`"
`${var:=stringa}` | "`$var`" | "`stringa`" (ed esegue "`var=stringa`")
`${var:?string}` | "`$var`" | invia con echo "`stringa`" allo stderr (ed esce con stato di errore)

I due punti "`:`" in tutti gli operatori nell'elenco precedente sono di fatto opzionali.

- con "`:`" l'operatore = controlla che il suo operando esista e sia non nullo

- senza "`:`" l'operatore = controlla solo che il suo operando esista

Tabella 12.4. Elenco di sostituzioni chiave di parametri di shell

forma della sostituzione di parametri | risultato
--- | ---
`${var%suffisso}` | rimuove il più piccolo modello di suffisso
`${var%%suffisso}` | rimuove il più grande modello di suffisso
`${var#prefisso}` | rimuove il più piccolo modello di prefisso
`${var##prefisso}` | rimuove il più grande modello di prefisso

### 12.1.3. Costrutti condizionali della shell

Ogni comando restituisce uno stato di uscita che può essere usato in costrutti condizionali.

- Successo: 0 ("Vero")

- Errore: non 0 ("Falso")

| Nota
"0" nel contesto condizionale della shell significa "Vero", mentre "0" nel contesto condizionale in C significa "Falso".

| Nota
"`[`" è l'equivalente del comando "`test` che valuta i propri argomenti sino a "`]`" come un'espressione condizionale.

Le espressioni condizionali di base che è bene ricordare sono le seguenti.

- "`comando && se_successo_esegue_anche_questo_comando || true`"

- "`comando || se_non_successo_esegue_anche_questo_comando || true`"

- Una porzione su più righe di script come la seguente

    if [ conditional_expression ]; then
     if_success_run_this_command
    else
     if_not_success_run_this_command
    fi

In questo caso il "`|| true`" finale era necessario per assicurare che lo script non termini accidentalmente a tale riga quando la shell è invocata con l'opzione "`-e`".

Tabella 12.5. Elenco di operatori per paragonare file in espressioni condizionali

equazione | condizione perché venga restituito il valore logico "vero"
--- | ---
`-e file` | file esiste
`-d file` | file esiste ed è una directory
`-f file` | file esiste ed è un file regolare
`-w file` | file esiste ed è scrivibile
`-x file` | file esiste ed è eseguibile
`file1 -nt file2` | file1 è più recente di file2 (data di modifica)
`file1 -ot file2` | file1 è più vecchio di file2 (data di modifica)
`file1 -ef file2` | file1 e file2 sono sullo stesso device e stesso numero inode

Tabella 12.6. Elenco di operatori per paragonare stringhe in espressioni condizionali

equazione | condizione perché venga restituito il valore logico "vero"
--- | ---
`-z str` | la lunghezza di str è zero
`-n str` | la lunghezza di str è diversa da zero
`str1 = str2` | str1 e str2 sono uguali
`str1 != str2` | str1 e str2 non sono uguali
`str1 < str2` | se ordinate, str1 viene prima di str2 (dipendente dalla localizzazione)
`str1 > str2` | se ordinate, str1 viene dopo di str2 (dipendente dalla localizzazione)

Gli operatori aritmetici di comparazione di interi nelle espressioni condizionali sono "`-eq`", "`-ne`", "`-lt`", "`-le`", "`-gt`" e "`-ge`".

### 12.1.4. Cicli di shell

Ci sono diverse espressioni per cicli usabili nella shell POSIX.

- "`for x in pippo1 pippo2 … ; do comando ; done`" ripete il ciclo assegnando gli elementi nell'elenco "`pippo1 pippo2 …`" alla variabile "`x`" ed eseguendo "`comando`".

- "`while condizione ; do comando ; done`" ripete "`comando`" fintanto che "`condizione`" è vera.

- "`until condizione ; do comando ; done`" ripete "`comando`" fintanto che "`condition`" è non vera.

- "`break`" permette di uscire dal ciclo.

- "`continue`" permette di riprendere dalla successiva iterazione del ciclo.

| Suggerimento
L'iterazione numerica in stile linguaggio C può essere realizzata usando `seq`(1) come "`pippo1 pippo2 …`"

| Suggerimento
Vedere Sezione 9.4.9, «Ripetere un comando su diversi file».

### 12.1.5. Variabile d'ambiente della shell

Alcune popolari variabili d'ambiente per il normale prompt dei comandi della shell possono non essere disponibili nell'ambiente di esecuzione di uno script utente.

- Per "`$USER`", usare "`$(id -un)`"

- Per "`$UID`", usare "`$(id -u)`"

- Per "`$HOME`", usare "`$(getent passwd "$(id -u)"|cut -d ":" -f 6)`" (questo funziona anche con Sezione 4.5.2, «La moderna gestione centralizzata del sistema»)

### 12.1.6. La sequenza di elaborazione della riga di comando di shell

A grandi linee la shell elabora uno script nel modo seguente.

- La shell legge una riga.

- La shell raggruppa parte della riga come un unico elemento se è racchiusa in `"…"` o `'…'`.

- La shell spezza le altre parti della riga in elementi in base ai caratteri seguenti.

  - Spazi bianchi: `spazio tabulazione a capo`

  - Metacaratteri: `< > | ; & ( )`

- La shell controlla, per ciascun elemento non racchiuso tra `"…"` o `'…'`, la presenza di parole riservate per regolare il proprio comportamento.

  - Parole riservate: `if then elif else fi for in while unless do done case esac`

- La shell espande gli alias se non sono racchiusi in `"…"` o `'…'`.

- La shell espande il carattere tilde se non è racchiuso in `"…"` o `'…'`.

  - "`~`" → directory home dell'utente attuale

  - "`~utente`" → directory home di `utente`

- La shell espande parametri nei loro valori, se non sono racchiusi in `'…'`.

  - Parametro: "`$PARAMETRO`" o "`${PARAMETRO}`"

- La shell espande sostituzioni di comandi, se non sono racchiuse in `'…'`.

  - "`$( comando )`" → output di "`comando`"

  - "`` command ``" → output di "`comando`"

- La shell espande glob di nomi percorso nei nomi di file corrispondenti, se non sono racchiusi in `"…"` o `'…'`.

  - `*` → qualsiasi carattere

  - `?` → un carattere

  - `[…]` → uno qualunque dei caratteri in "`…`"

- La shell cerca comando tra le cose seguenti e lo esegue.

  - Definizione di funzione

  - comando interno

  - file eseguibile in "`$PATH`"

- La shell si sposta alla riga seguente e ripete nuovamente questo processo dall'inizio di questa sequenza.

Virgolette singole all'interno di virgolette doppie non hanno alcun effetto.

L'esecuzione di "`set -x`" nella shell o l'invocazione della shell con l'opzione "`-x`" fanno sì che la shell stampi tutti i comandi eseguiti. Ciò è piuttosto utile per il debug.

### 12.1.7. Programmi di utilità per script di shell

Per far sì che il proprio programma di shell sia il più portabile possibile tra i sistemi Debian, è una buona idea limitare i programmi di utilità a quelli forniti dai pacchetti essenziali.

- "`aptitude search ~E`" elenca i pacchetti essenziali.

- "`dpkg -L nome_pacchetto |grep '/man/man.*/'`" elenca le pagine man per i comandi forniti dal pacchetto `nome_pacchetto`.

Tabella 12.7. Elenco di pacchetti contenenti piccoli programmi di utilità per script di shell

pacchetto | popcon | dimensione | descrizione
--- | --- | --- | ---
`dash` | V:906, I:998 | 207 | piccola e veloce shell conforme a POSIX per `sh`
`coreutils` | V:892, I:999 | 18457 | Utilità GNU di base
`grep` | V:765, I:999 | 1297 | GNU `grep`, `egrep` e `fgrep`
`sed` | V:804, I:999 | 987 | GNU `sed`
`mawk` | V:466, I:997 | 296 | `awk` piccolo e veloce
`debianutils` | V:915, I:996 | 225 | utilità varie specifiche di Debian
`bsdutils` | V:439, I:999 | 335 | utilità di base per 4.4BSD-Lite
`bsdextrautils` | V:728, I:849 | 361 | utilità aggiuntive da 4.4BSD-Lite
`moreutils` | V:16, I:37 | 231 | utilità Unix aggiuntive

| Suggerimento
Sebbene `moreutils` possa non esistere al di fuori di Debian, offre piccoli programmi interessanti. Quello più degno di nota è `sponge`(8) che è piuttosto utile quando si desidera sovrascrivere il file originale.

Vedere Sezione 1.6, «Elaborazione di testo stile Unix» per esempi.

## 12.2. Creazione di script in linguaggi interpretati

Tabella 12.8. Elenco di pacchetti relativi ad interpreti

pacchetto | popcon | dimensione | documentazione
--- | --- | --- | ---
`dash` | V:906, I:998 | 207 | sh: piccola e veloce shell conforme a POSIX per `sh`
`bash` | V:866, I:999 | 7277 | sh: "`info bash`" fornito da `bash-doc`
`mawk` | V:466, I:997 | 296 | AWK: `awk` piccolo e veloce
`gawk` | V:251, I:310 | 3289 | AWK: "`info gawk`" fornito da `gawk-doc`
`perl` | V:672, I:991 | 841 | Perl: `perl`(1) e pagine HTML fornite da `perl-doc` e `perl-doc-html`
`libterm-readline-gnu-perl` | V:2, I:28 | 439 | Estensione Perl per la libreria GNU ReadLine/History: `perlsh`(1)
`libreply-perl` | V:0, I:0 | 171 | REPL per Perl: `reply`(1)
`libdevel-repl-perl` | V:0, I:0 | 237 | REPL per Perl: `re.pl`(1)
`python3` | V:713, I:970 | 82 | Python: `python3`(1) e pagine HTML fornite da `python3-doc`
`tcl` | V:24, I:184 | 20 | Tcl: `tcl`(3) e le pagine dettagliate di manuale fornite da `tcl-doc`
`tk` | V:18, I:178 | 20 | Tk: `tk`(3) e le pagine dettagliate di manuale fornite da `tk-doc`
`ruby` | V:69, I:166 | 32 | Ruby: `ruby`(1), `erb`(1), `irb`(1), `rdoc`(1), `ri`(1)

Quando si desidera automatizzare un compito in Debian, si dovrebbe prima creare uno script per esso con un linguaggio interpretato. Le linee guida per la scelta del linguaggio interpretato sono:

- Usare `dash` se il compito è semplice e combina programmi CLI con un programma della shell.

- Usare `python3` se il compito non è semplice e si sta cercando di scriverlo da zero.

- Usare `perl`, `tcl`, `ruby`, ... se è disponibile del codice preesistente in Debian che usa uno di questi linguaggi e che deve essere ritoccato per fare il compito.

Se il codice risultante è troppo lento, si può riscrivere solo la porzione critica per la velocità d'esecuzione in un linguaggio compilato e chiamarla dal linguaggio interpretato.

### 12.2.1. Fare il debug di codice di linguaggi interpretati

La maggior parte degli interpreti offre un controllo di base della sintassi e funzionalità di tracciamento del codice.

- “dash -n script.sh” - Controllo della sintassi di uno script di Shell

- “dash -x script.sh” - Tracciamento di uno script di Shell

- “python -m py_compile script.py” - Controllo della sintassi di uno script Python

- “python -mtrace --trace script.py” - Tracciamento di uno script Python

- “perl -I ../libpath -c script.pl” - Controllo della sintassi di uno script Perl

- “perl -d:Trace script.pl” - Tracciamento di uno script Perl

Per testare codice per `dash`, provare Sezione 9.1.4, «Wrapper per readline» che è adatto ad ambienti interattivi in stile `bash`.

Per testare codice per `perl` provare l'ambiente REPL per Perl che crea un ambiente REPL (=READ + EVAL + PRINT + LOOP) in stile Python per Perl.

### 12.2.2. Programma GUI con script di shell

Uno script di shell può essere migliorato per creare un attraente programma GUI. Il trucco è di usare uno dei cosiddetti programmi di dialogo invece di interazioni tristi che usano i comandi `echo` e `read`.

Tabella 12.9. Elenco di programmi per dialoghi

pacchetto | popcon | dimensione | descrizione
--- | --- | --- | ---
`x11-utils` | V:227, I:568 | 651 | `xmessage`(1): mostra un messaggio o richiesta in una finestra (X)
`whiptail` | V:298, I:996 | 61 | mostra riquadri di dialogo amichevoli da script di shell (newt)
`dialog` | V:9, I:82 | 520 | mostra riquadri di dialogo amichevoli da script di shell (ncurses)
`zenity` | V:67, I:357 | 194 | mostra riquadri di dialogo grafici da script di shell (GTK)
`ssft` | V:0, I:0 | 75 | Shell Scripts Frontend Tool, strumento per frontend per script di shell (contenitore per zenity, kdialog, e dialog con gettext)
`gettext` | V:53, I:229 | 7165 | "`/usr/bin/gettext.sh`": traduce messaggi

Ecco un esempio di programma con GUI per dimostrare come è semplice facile farlo con uno script di shell.

Questo script usa `zenity` per selezionare un file (in maniera predefinita `/etc/motd`) e visualizzarlo.

L'avviatore GUI per questo script può essere creato seguendo Sezione 9.4.10, «Avviare un programma dalla GUI».

    #!/bin/sh -e
    # Copyright (C) 2021 Osamu Aoki <osamu@debian.org>, Public Domain
    # vim:set sw=2 sts=2 et:
    DATA_FILE=$(zenity --file-selection --filename="/etc/motd" --title="Select a file to check") || \
      ( echo "E: File selection error" >&2 ; exit 1 )
    # Check size of archive
    if ( file -ib "$DATA_FILE" | grep -qe '^text/' ) ; then
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="$(head -n 20 "$DATA_FILE")"
    else
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="The data is MIME=$(file -ib "$DATA_FILE")"
    fi

Questo tipo di approccio ad un programma GUI con script di shell è utile solamente per casi di scelta semplice. Se si sta scrivendo un programma con funzioni complesse, considerare l'idea di scriverlo con una piattaforma con più potenzialità.

### 12.2.3. Azioni personalizzate per un gestore di file con GUI

I programmi di gestione di file con GUI possono essere estesi per effettuare alcune azioni comuni su file selezionati usando pacchetti di estensione aggiuntivi. È anche possibile fargli fare azioni personalizzate specifiche aggiungendo script specifici dell'utente.

- Per GNOME, vedere NautilusScriptsHowto.

- Per KDE, vedere Creating Dolphin Service Menus.

- Per Xfce, vedere Thunar - Custom Actions e https://help.ubuntu.com/community/ThunarCustomActions.

- Per LXDE, vedere Custom Actions.

### 12.2.4. Pazzie con corti script Perl

Per elaborare dati, `sh` deve generare sottoprocessi che eseguono `cut`, `grep`, `sed`, ecc., ed è lento. D'altro canto, `perl` ha capacità interne per elaborare i dati, perciò è veloce. Molti script di manutenzione del sistema in Debian usano `perl`.

Si consideri il seguente pezzetto di script AWK e i suoi equivalenti in Perl.

    awk '($2=="1957") { print $3 }' |

Ciò equivale ad una qualsiasi delle righe seguenti.

    perl -ne '@f=split; if ($f[1] eq "1957") { print "$f[2]\n"}' |

    perl -ne 'if ((@f=split)[1] eq "1957") { print "$f[2]\n"}' |

    perl -ne '@f=split; print $f[2] if ( $f[1]==1957 )' |

    perl -lane 'print $F[2] if $F[1] eq "1957"' |

    perl -lane 'print$F[2]if$F[1]eq+1957' |

L'ultima è una sorta di indovinello; sfrutta le seguenti caratteristiche di Perl.

- Gli spazi bianchi sono opzionali.

- Esiste una conversione automatica da numero a stringa.

- Trucchi di esecuzione di Perl attraverso opzioni della riga di comando: `perlrun`(1)

- Variabili speciali di Perl: `perlvar`(1)

La flessibilità è il punto di forza di Perl. Al contempo, ciò permette di creare codici criptici e ingarbugliati. Perciò fare attenzione.

## 12.3. Scrivere codice in linguaggi compilati

Tabella 12.10. Elenco di pacchetti relativi al compilatore

pacchetto | popcon | dimensione | descrizione
--- | --- | --- | ---
`gcc` | V:151, I:561 | 36 | Compilatore di GNU C
`libc6-dev` | V:268, I:579 | 12694 | Libreria GNU C: librerie di sviluppo e file header
`g++` | V:56, I:524 | 13 | Compilatore di GNU C++
`libstdc++-14-dev` | V:31, I:227 | 24527 | Libreria GNU Standard C++ v3 (file di sviluppo)
`cpp` | V:335, I:725 | 18 | Preprocessore GNU C
`gettext` | V:53, I:229 | 7165 | Utilità GNU Internationalization
`glade` | V:0, I:3 | 1613 | Costruttore dell'interfaccia utente GTK
`valac` | V:0, I:3 | 532 | Linguaggio in stile C# per il sistema GObject
`flex` | V:6, I:69 | 1247 | Veloce generatore di analizzatori lessicali compatibile con LEX
`bison` | V:6, I:73 | 3122 | generatore di parser compatibile con YACC
`susv2` | I:0 | 16 | scarica le specifiche "The Single UNIX Specifications v2"
`susv3` | I:0 | 16 | scarica le specifiche "The Single UNIX Specifications v3"
`susv4` | I:0 | 16 | scarica le specifiche "The Single UNIX Specifications v4"
`golang` | I:21 | 12 | Compilatore del linguaggio di programmazione Go
`rustc` | V:5, I:18 | 13748 | Linguaggio di programmazione Rust
`gfortran` | V:5, I:52 | 15 | Compilatore GNU Fortran 95
`fpc` | I:2 | 104 | Free Pascal

Qui sono inclusi Sezione 12.3.3, «Flex - un Lex migliorato» e Sezione 12.3.4, «Bison - Yacc migliorato» per indicare come programmi simili a compilatori possono essere scritti in linguaggio C compilando descrizioni di più alto livello in linguaggio C.

### 12.3.1. C

Si può impostare l'ambiente appropriato per compilare programmi scritti nel linguaggio di programmazione C nel modo seguente.

    # apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential

Il pacchetto `libc6-dev`, cioè la libreria GNU C, fornisce la libreria standard C che è una raccolta di file header e routine di libreria usati dal linguaggio di programmazione C.

Vedere come documenti di riferimento per C i seguenti.

- "`info libc`" (documento di riferimento per le funzioni della libreria C)

- `gcc`(1) e "`info gcc`"

- `ogni_nome_di_funzione_della_libreria_C`(3)

- Kernighan & Ritchie, "The C Programming Language", 2nd edition (Prentice Hall)

### 12.3.2. Semplice programma in C (gcc)

Un semplice esempio "`esempio.c`" può essere compilato con una libreria "`libm`" in un eseguibile "`eseg_esempio`" nel modo seguente.

    $ cat > example.c << EOF
    #include <stdio.h>
    #include <math.h>
    #include <string.h>

    int main(int argc, char **argv, char **envp){
            double x;
            char y[11];
            x=sqrt(argc+7.5);
            strncpy(y, argv[0], 10); /* prevent buffer overflow */
            y[10] = '\0'; /* fill to make sure string ends with '\0' */
            printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]);
            return 0;
    }
    EOF
    $ gcc -Wall -g -o run_example example.c -lm
    $ ./run_example
            1, 2.915, ./run_exam,     (null)
    $ ./run_example 1234567890qwerty
            2, 3.082, ./run_exam, 1234567890qwerty

In questo esempio, l'uso di "`-lm`" è necessario per fare il link alla libreria "`/usr/lib/libm.so`" nel pacchetto `libc6` per `sqrt`(3). La libreria reale è in "`/lib/`" con nome file "`libm.so.6`", che è un collegamento simbolico a "`libm-2.7.so`".

Si guardi l'ultimo elemento nel testo di output: ci sono più di 10 caratteri anche se è stato specificato "`%10s`".

L'uso di funzioni che operano su puntatori di memoria senza controlli sui limiti, come `sprintf`(3) e `strcpy`(3) è deprecato per prevenire exploit di tipo buffer overflow che sfruttano gli effetti di superamento dei limiti di grandezza dei dati. Usare invece `snprintf`(3) e `strncpy`(3).

### 12.3.3. Flex - un Lex migliorato

Flex è un veloce generatore di analizzatori lessicali compatibile con Lex.

Un tutorial per `flex`(1) viene fornito da "`info flex`".

Molti esempi semplici possono essere trovati in "`/usr/share/doc/flex/examples/`". [7]

### 12.3.4. Bison - Yacc migliorato

Svariati pacchetti Debian forniscono un generatore di parser LR lookahead o parser LALR combatibile con Yacc.

Tabella 12.11. Elenco di generatori di parser LALR compatibili con Yacc

pacchetto | popcon | dimensione | descrizione
--- | --- | --- | ---
`bison` | V:6, I:73 | 3122 | generatore GNU di parser LALR
`byacc` | V:0, I:3 | 263 | generatore Berkeley di parser LALR
`btyacc` | V:0, I:0 | 251 | generatore di parser backtracking basato su `byacc`

Un tutorial per `bison`(1) viene fornito da "`info bison`".

È necessario fornire i propri "`main()`" e "`yyerror()`". "`main()`" chiama "`yyparse()`" che a sua volta chiama "`yylex()`", solitamente creato con Flex.

Ecco un esempio di come creare un semplice programma per calcolatrice nel terminale.

Creare `example.y`:

    /* calculator source for bison */
    %{
    #include <stdio.h>
    extern int yylex(void);
    extern int yyerror(char *);
    %}

    /* declare tokens */
    %token NUMBER
    %token OP_ADD OP_SUB OP_MUL OP_RGT OP_LFT OP_EQU

    %%
    calc:
     | calc exp OP_EQU    { printf("Y: RESULT = %d\n", $2); }
     ;

    exp: factor
     | exp OP_ADD factor  { $$ = $1 + $3; }
     | exp OP_SUB factor  { $$ = $1 - $3; }
     ;

    factor: term
     | factor OP_MUL term { $$ = $1 * $3; }
     ;

    term: NUMBER
     | OP_LFT exp OP_RGT  { $$ = $2; }
      ;
    %%

    int main(int argc, char **argv)
    {
      yyparse();
    }

    int yyerror(char *s)
    {
      fprintf(stderr, "error: '%s'\n", s);
    }

Creare `example.l`:

    /* calculator source for flex */
    %{
    #include "example.tab.h"
    %}

    %%
    [0-9]+ { printf("L: NUMBER = %s\n", yytext); yylval = atoi(yytext); return NUMBER; }
    "+"    { printf("L: OP_ADD\n"); return OP_ADD; }
    "-"    { printf("L: OP_SUB\n"); return OP_SUB; }
    "*"    { printf("L: OP_MUL\n"); return OP_MUL; }
    "("    { printf("L: OP_LFT\n"); return OP_LFT; }
    ")"    { printf("L: OP_RGT\n"); return OP_RGT; }
    "="    { printf("L: OP_EQU\n"); return OP_EQU; }
    "exit" { printf("L: exit\n");   return YYEOF; } /* YYEOF = 0 */
    .      { /* ignore all other */ }
    %%

Poi eseguire quanto segue dal prompt di shell per testarlo:

    $ bison -d example.y
    $ flex example.l
    $ gcc -lfl example.tab.c lex.yy.c -o example
    $ ./example
    1 + 2 * ( 3 + 1 ) =
    L: NUMBER = 1
    L: OP_ADD
    L: NUMBER = 2
    L: OP_MUL
    L: OP_LFT
    L: NUMBER = 3
    L: OP_ADD
    L: NUMBER = 1
    L: OP_RGT
    L: OP_EQU
    Y: RESULT = 9

    exit
    L: exit

## 12.4. Strumenti di analisi statica del codice

Strumenti simili a lint possono aiutare nell'analisi statica del codice.

Strumenti simili ad Indent possono aiutare nella revisione manuale del codice riformattando in modo coerente il codice sorgente.

Strumenti simili a Ctags possono aiutare nella revisione manuale del codice generando un file indice (o tag) dei nomi trovati nel codice sorgente.

| Suggerimento
Configurare il proprio editor preferito (`emacs` o `vim`) in modo che usi plugin per motori per lint asincroni aiuta nella scrittura di codice. Questi plugin stanno diventando molto potenti poiché sfruttano il Language Server Protocol. Dato che sono in continuo sviluppo, usare il codice originale a monte, invece dei pacchetti Debian, potrebbe essere una buona opzione.

Tabella 12.12. Elenco di strumenti per l'analisi statica del codice

pacchetto | popcon | dimensione | descrizione
--- | --- | --- | ---
`vim-ale` | I:0 | 2833 | motore per lint asincrono per Vim 8 e NeoVim
`vim-syntastic` | I:2 | 1379 | trucchi per controllo della sintassi per vim
`elpa-flycheck` | V:0, I:1 | 815 | controllo della sintassi al-volo moderno per Emacs
`elpa-relint` | I:0 | 150 | strumento per trovare errori in regexp per Emacs Lisp
`cppcheck-gui` | V:0, I:1 | 7682 | strumento per l'analisi statica del codice C/C++ (GUI)
`shellcheck` | V:2, I:15 | 22859 | strumento lint per script di shell
`pyflakes3` | V:2, I:15 | 20 | controllo passivo di programmi Python 3
`pylint` | V:4, I:20 | 2089 | strumento di controllo statico del codice Python
`perl` | V:672, I:991 | 841 | interprete con controllore interno statico del codice: `B::Lint`(3perl)
`rubocop` | V:0, I:0 | 3247 | strumento di analisi statica del codice Ruby
`clang-tidy` | V:1, I:11 | 22 | strumento per ling per C++ basato su Clang
`splint` | V:0, I:1 | 2328 | strumento per controllare staticamente la presenza di bug in programmi C
`flawfinder` | V:0, I:0 | 205 | strumento per esaminare codice sorgente C/C++ e per cercare punti deboli per la sicurezza
`black` | V:4, I:16 | 10138 | formattatore di codice Python senza compromessi
`perltidy` | V:0, I:3 | 3086 | strumento per rientri e riformattazione di script Perl
`indent` | V:0, I:5 | 438 | programma per formattazione di codice sorgente in linguaggio C
`astyle` | V:0, I:2 | 769 | strumento per rientri in codice sorgente per C, C++, Objective-C, C# e Java
`bcpp` | V:0, I:0 | 114 | abbellitore di C(++)
`xmlindent` | V:0, I:0 | 52 | riformattatore di flussi XML
`global` | V:0, I:1 | 1923 | strumenti per ricerca e navigazione di codice sorgente
`exuberant-ctags` | V:1, I:14 | 341 | costruzione di file indice di tag di definizioni di codice sorgente
`universal-ctags` | V:1, I:12 | 4238 | costruzione di file indice di tag di definizioni di codice sorgente

## 12.5. Debug

Il debug è un'importante fase del processo di programmazione. Sapere come fare il debug dei programmi rende buoni utenti Debian in grado di creare segnalazioni di bug sensate.

Tabella 12.13. Elenco di pacchetti relativi al debug

pacchetto | popcon | dimensione | documentazione
--- | --- | --- | ---
`gdb` | V:79, I:156 | 12478 | "`info gdb`" fornito da `gdb-doc`
`ddd` | V:0, I:5 | 4210 | "`info ddd`" fornito da `ddd-doc`

### 12.5.1. Esecuzione base di gdb

Lo strumento di debug principale in Debian è `gdb`(1) che permette di ispezionare un programma mentre viene eseguito.

Installare `gdb` e i programmi correlati nel modo seguente.

    # apt-get install gdb gdb-doc build-essential devscripts

Un buon tutorial per `gdb` può essere trovato su:

- “`info gdb`”

- “Debugging with GDB” in `/usr/share/doc/gdb-doc/html/gdb/index.html`

- “tutorial sul web”

Quello che segue è un piccolo esempio d'uso di `gdb`(1) su di un "`programma`" compilato con l'opzione "`-g`" per produrre informazioni di debug.

    $ gdb program
    (gdb) b 1                # set break point at line 1
    (gdb) run args           # run program with args
    (gdb) next               # next line
    ...
    (gdb) step               # step forward
    ...
    (gdb) p parm             # print parm
    ...
    (gdb) p parm=12          # set value to 12
    ...
    (gdb) quit

| Suggerimento
Molti comandi `gdb`(1) possono essere abbreviati. L'espansione del tasto di tabulazione funziona come nella shell.

### 12.5.2. Fare il debug di pacchetti Debian

Dato che tutti i binari installati in un sistema Debian dovrebbero avere, in maniera predefinita, le informazioni di debug rimosse, la maggior parte dei simboli di debug non sono presenti nei normali pacchetti. Per poter fare il debug dei pacchetti Debian con `gdb`(1), è necessario installare i pacchetti `*-dbgsym` (es. `coreutils-dbgsym` in the case of `coreutils`). I pacchetti sorgente generano automaticamente pacchetti `*-dbgsym` insieme ai pacchetti binari normale e tali pacchetti di debug vengono messi nell'archivio separato debian-debug. Per maggiori informazioni fare riferimento agli articoli nel Wiki Debian.

Se un pacchetto di cui si deve fare il debug non fornisce il proprio pacchetto `*-dbgsym`, è necessario installarlo dopo averlo ricompilato nel modo seguente.

    $ mkdir /path/new ; cd /path/new
    $ sudo apt-get update
    $ sudo apt-get dist-upgrade
    $ sudo apt-get install fakeroot devscripts build-essential
    $ apt-get source package_name
    $ cd package_name*
    $ sudo apt-get build-dep ./

Correggere i bug se necessario.

Spostare la versione del pacchetto ad una che non crei conflitti con le versioni ufficiali di Debian, ad esempio una che termini con "`+debug1`" quando si ricompilano versioni di cui esiste un pacchetto, o una che termini con "`~pre1`" quando si ricompilano versioni non ancora rilasciate in pacchetti nel modo seguente.

    $ dch -i

Compilare ed installare i pacchetti con i simboli di debug nel modo seguente.

    $ export DEB_BUILD_OPTIONS="nostrip noopt"
    $ debuild
    $ cd ..
    $ sudo debi package_name*.changes

È necessario controllare gli script di compilazione del pacchetto ed assicurarsi di usare "`CFLAGS=-g -Wall`" per la compilazione di binari.

### 12.5.3. Ottenere un backtrace

Quando un programma va in crash, è una buona idea inviare un segnalazione di bug riportando le informazioni di backtrace.

Il backtrace può essere ottenuto da `gdb`(1) utilizzando uno dei seguenti approcci:

- Approccio "crash in GDB":

  - Eseguire il programma da GDB.

  - Mandare in crash il programma.

  - Digitare "`bt`" al prompt di GDB.

- Approccio "prima il crash":

  - Aggiornare il file “/etc/security/limits.conf” in modo che includa quanto segue:

        * soft core unlimited

  - Digitare "`ulimit -c unlimited`" al prompt di shell.

  - Eseguire il programma da questo prompt di shell.

  - Mandare in crash il programma per produrre un file core dump.

  - Caricare il file del core dump in GDB con "`gdb gdb ./program_binary core`".

  - Digitare "`bt`" al prompt di GDB.

Per situazioni con cicli infiniti o tastiera bloccata, si può forzare il crash del programma premendo `Ctrl-\` o `Ctrl-C` o eseguendo “`kill -ABRT PID`”. (Vedere Sezione 9.4.12, «Uccidere un processo».)

| Suggerimento

Spesso si vede un backtrace in cui una o più delle prime righe sono in "`malloc()`" o "`g_malloc()`". Quando ciò accade è probabile che il backtrace non sia molto utile. Il metodo più semplice per trovare informazioni utili è di impostare la variabile d'ambiente "`$MALLOC_CHECK_`" al valore 2 (`malloc`(3)). Lo si può fare mentre si esegue `gdb` nel modo seguente.

     $ MALLOC_CHECK_=2 gdb hello

### 12.5.4. Comandi gdb avanzati

Tabella 12.14. Elenco di comandi gdb avanzati

comando | descrizione degli scopi del comando
--- | ---
`(gdb) thread apply all bt` | ottenere un backtrace per tutti i thread di un programma multi-thread
`(gdb) bt full` | ottenere i parametri nello stack delle chiamate di funzione
`(gdb) thread apply all bt full` | ottenere un backtrace e parametri: combinazione delle due opzioni precedenti
`(gdb) thread apply all bt full 10` | ottenere un backtrace e i parametri per le prime dieci chiamate nello stack per eliminare l'output irrilevante
`(gdb) set logging on` | scrivere un registro dell'output di `gdb` in un file (il file predefinito è "`gdb.txt`")

### 12.5.5. Controllare le dipendenze dalle librerie

Per scoprire le dipendenze di un programma da librerie, usare `ldd`(1) nel modo seguente.

    $ ldd /usr/bin/ls
            librt.so.1 => /lib/librt.so.1 (0x4001e000)
            libc.so.6 => /lib/libc.so.6 (0x40030000)
            libpthread.so.0 => /lib/libpthread.so.0 (0x40153000)
            /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Affinché `ls`(1) funzioni in un ambiente "chroot", le librerie in questione devono essere disponibili nell'ambiente "chroot".

Vedere Sezione 9.4.6, «Tenere traccia delle attività di un programma».

### 12.5.6. Strumenti per tracciamento di chiamate dinamiche

In Debian sono disponibili diversi strumenti di tracciamento di chiamate dinamiche. Vedere Sezione 9.4, «Monitorare, controllare ed avviare l'attività dei programmi».

### 12.5.7. Fare il debug di errori X

Se un programma gnome `preview1` ha ricevuto un errore X, si dovrebbe leggere un messaggio del tipo seguente.

    The program 'preview1' received an X Window System error.

Se ciò avviene, si può provare ad eseguire il programma con "`--sync`" ed interrompere alla funzione "`gdk_x_error`" per ottenere un backtrace.

### 12.5.8. Strumenti per rilevazione di memory leak

In Debian sono disponibili svariati strumenti di rilevazione di memory leak.

Tabella 12.15. Elenco di strumenti per rilevazione di memory leak

pacchetto | popcon | dimensione | descrizione
--- | --- | --- | ---
`libc6-dev` | V:268, I:579 | 12694 | `mtrace`(1): funzionalità di debug malloc in glibc
`valgrind` | V:6, I:34 | 87847 | strumento di debug e profilazione per la memoria
`electric-fence` | V:0, I:2 | 69 | strumento di debug `malloc`(3)
`libdmalloc5` | V:0, I:0 | 380 | libreria per il debug dell'allocazione di memoria
`duma` | V:0, I:0 | 297 | libreria per rilevare buffer overrun e underrun in programmi C e C++
`leaktracer` | I:0 | 56 | tracciatore di memory leak per programmi C++

### 12.5.9. Disassemblatore di binari

Si può disassemblare codice binario con `objdump`(1) nel modo seguente.

    $  objdump -m i386 -b binary -D /usr/lib/grub/x86_64-pc/stage1

| Nota
Per disassemblare codice in modo interattivo si può usare `gdb`(1).

## 12.6. Strumenti di compilazione

Tabella 12.16. Elenco di pacchetti relativi alla compilazione

pacchetto | popcon | dimensione | documentazione
--- | --- | --- | ---
`make` | V:145, I:562 | 1762 | "`info make`" fornito da `make-doc`
`autoconf` | V:29, I:205 | 2197 | "`info autoconf`" fornito da `autoconf-doc`
`automake` | V:28, I:204 | 1933 | "`info automake`" fornito da `automake1.10-doc`
`libtool` | V:23, I:187 | 1245 | "`info libtool`" fornito da `libtool-doc`
`cmake` | V:18, I:118 | 44267 | `cmake`(1), multipiattaforma, sistema make open source
`ninja-build` | V:7, I:51 | 456 | `ninja`(1), piccolo sistema di compilazione, il più vicino in spirito a Make
`meson` | V:6, I:28 | 4186 | `meson`(1), sistema di compilazione ad alta produttività sulla base di `ninja`
`xutils-dev` | V:0, I:7 | 1495 | `imake`(1), `xmkmf`(1), ecc.

### 12.6.1. Make

Make è un'utilità per mantenere gruppi di programmi. Quando `make`(1) viene eseguito, `make` legge il file di regole, "`Makefile`" e aggiorna il file target se dipende da file prerequisiti che sono stati modificati dall'ultima volta che esso stesso è stato modificato oppure se il file target non esiste. L'esecuzione di questi aggiornamenti può avvenire in modo concorrente.

La sintassi del file di regole è la seguente.

    target: [ prerequisites ... ]
     [TAB]  command1
     [TAB]  -command2 # ignore errors
     [TAB]  @command3 # suppress echoing

Qui "`[TAB]` è il codice di TAB. Ciascuna riga è interpretata dalla shell dopo la sostituzione delle variabili di make. Usare "`\`" alla fine di una riga per continuare lo script. Usare "`$$`" per inserire "`$`" per valori di ambiente per uno script di shell.

Regole implicite per il target ed i prerequisiti possono essere scritte, per esempio, nel modo seguente.

    %.o: %.c header.h

In questo caso il target contiene il carattere "`%`" (esattamente un carattere). Il "`%`" fa corrispondenza con qualsiasi sottostringa non vuota nei nomi di file dei target effettivi. Similmente i prerequisiti usano "`%`" per mostrare come i loro nomi trovino corrispondenza nei nomi dei target effettivi.

Tabella 12.17. Elenco di variabili automatiche di make

variabile automatica | valore
--- | ---
`$@` | target
`$<` | primo prerequisito
`$?` | tutti i prerequisiti più recenti
`$^` | tutti i prerequisiti
`$*` | "`%`" nome base con corrispondenza con il modello target

Tabella 12.18. Elenco di espansioni delle variabili di make

espansione di variabile | descrizione
--- | ---
`pippo1 := pluto` | espansione valida una volta sola
`pippo2 = pluto` | espansione ricorsiva
`pippo3 += pluto` | accoda

Eseguire "`make -p -f/dev/null`" per vedere le regole interne automatiche.

### 12.6.2. Autotools

Autotools è una suite di strumenti per programmazione progettata per assistere nella creazione di pacchetti di codice sorgente portabili su molti sistemi simil-UNIX.

- Autoconf è uno strumento per produrre uno script di shell chiamato "`configure`" da "`configure.ac`".

  - "`configure`" è successivamente usato per produrre "`Makefile`" da un modello "`Makefile.in`".

- Automake è uno strumento per produrre "`Makefile.in`" da "`Makefile.am`".

- Libtool è uno script di shell per affrontare il problema della portabilità del software quando si compilano librerie condivise da codice sorgente.

#### 12.6.2.1. Compilare ed installare un programma

| Avvertimento
Non sovrascrivere mai file di sistema quando si installano programmi compilati in proprio.

Debian non tocca i file in "`/usr/local/`" o "`/opt`". Perciò se si compila un programma dai sorgenti, installarlo in "`/usr/local/`" in modo che non interferisca con Debian.

    $ cd src
    $ ./configure --prefix=/usr/local
    $ make # this compiles program
    $ sudo make install # this installs the files in the system

#### 12.6.2.2. Disinstallare un programma

Se si hanno i sorgenti originali e questi usano `autoconf`(1)/`automake`(1), e se ci si ricorda la configurazione usata, eseguire quanto segue per disinstallare un programma.

    $ ./configure all-of-the-options-you-gave-it
    $ sudo make uninstall

In alternativa, se si è assolutamente certi che il processo di installazione mette i file solo in "`/usr/local/`" e lì non c'è nulla di importante, si può cancellare tutto ciò che contiene con la riga di comando seguente.

    # find /usr/local -type f -print0 | xargs -0 rm -f

Se non si è sicuri di dove siano installati i file, si dovrebbe prendere in considerazione l'uso di `checkinstall`(8) dal pacchetto `checkinstall`, che fornisce un percorso di disinstallazione pulita. Ora permette di creare un pacchetto Debian con l'opzione "`-D`".

### 12.6.3. Meson

Il sistema di compilazione del software si sta evolvendo:

- Autotools basato su Make è stato lo standard di fatto per le infrustrutture di compilazione portabili sin dagli anni '90. È estremamente lento.

- CMake inizialmente rilasciato nel 2000 ha migliorato significativamente la velocità, ma era ancora costruito sulla base dell'intrinsicamente lento Make. (Ora Ninja può essere il suo backend.)

- Ninja inizialmente rilasciato nel 2012 è pensato per rimpiazzare Make per una velocità di compilazione ulteriormente migliorata ed è progettato per avere i propri file di input generati da un sistema di compilazione di più alto livello.

- Meson rilasciato inizialmente nel 2013 è il nuovo popolare e veloce sistema di compilazione di più alto livello che usa Ninja come suo backend.

Vedere la documentazione in "The Meson Build system" e "The Ninja build system".

## 12.7. Web

Pagine web dinamiche interattive di base possono essere create nel modo seguente.

- Le interrogazioni vengono presentate all'utente del browser usando moduli HTML.

- La compilazione e il cliccare sulle voci nel modulo invia una delle stringhe URL seguenti con i parametri codificati dal browser al web server.

  - "`https://www.foo.dom/cgi-bin/program.pl?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3`"

  - "`https://www.foo.dom/cgi-bin/program.py?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3`"

  - "`https://www.foo.dom/program.php?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3`"

- "`%nn`" nell'URL viene sostituito dal carattere con valore esadecimale `nn`.

- Viene impostata la variabile d'ambiente: "`QUERY_STRING="VAR1=VAL1 VAR2=VAL2 VAR3=VAL3"`".

- Il programma CGI (uno qualsiasi dei "`program.*`") sul server web è eseguito con la variabile d'ambiente "`$QUERY_STRING`".

- Lo `stdout` del programma CGI viene inviato al browser web ed è presentato come pagina web dinamica interattiva.

Per ragioni di sicurezza è bene non creare a mano nuovi metodi per analizzare i parametri CGI. Per loro esistono moduli Perl e Python comprovati. PHP è fornito con queste funzionalità. Quando è necessaria l'archiviazione dei dati client vengono usati i cookie HTTP. Quando è necessaria l'elaborazione dei dati lato client, viene spesso usato Javascript.

Per maggiori informazioni vedere CGI (Common Gateway Interface), Apache Software Foundation e JavaScript.

Cercare "CGI tutorial" su Google digitando l'URL codificato https://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial direttamente nell'indirizzo del browser è un buon modo per vedere lo script CGI in azione sul server di Google.

## 12.8. Traduzione di codice sorgente

Esistono programmi per convertire codice sorgente.

Tabella 12.19. Elenco di strumenti per la traduzione di codice sorgente

pacchetto | popcon | dimensione | parola chiave | descrizione
--- | --- | --- | --- | ---
`perl` | V:672, I:991 | 841 | AWK→PERL | converte codice sorgente da AWK a PERL:`a2p`(1)
`f2c` | V:0, I:1 | 443 | FORTRAN→C | converte codice sorgente da FORTRAN 77 a C/C++: `f2c`(1)
`intel2gas` | V:0, I:0 | 178 | intel→gas | convertitore da NASM (formato Intel) a GAS (GNU Assembler)

## 12.9. Creare pacchetti Debian

Se si desidera creare un pacchetto Debian, leggere i documenti seguenti.

- Capitolo 2, Gestione dei pacchetti in Debian per capire le basi del sistema dei pacchetti

- Sezione 2.7.13, «Fare il port di un pacchetto nel sistema stabile» per capire le basi del processo di port

- Sezione 9.11.4, «Sistema chroot» per capire le basi delle tecniche chroot

- `debuild`(1) e `sbuild`(1)

- Sezione 12.5.2, «Fare il debug di pacchetti Debian» per la ricompilazione per il debug

- Guide for Debian Maintainers (il pacchetto `debmake-doc`)

- Debian Developer's Reference (pacchetto `developers-reference`)

- Manuale Debian Policyl (pacchetto `debian-policy`)

Ci sono pacchetti come `debmake`, `dh-make`, `dh-make-perl`, ecc., che aiutano nella creazione dei pacchetti.

[7] Potrebbero essere necessarie alcune regolazioni per far sì che funzionino nel sistema attuale.

Capitolo 11. Conversione di dati |  | Appendice A. Appendice