Trasformazione in lettere 3985

Transcript

Trasformazione in lettere 3985
Trasformazione in lettere
THEN
RETURN "LX"
ELSE IF DIGIT = 6
THEN
RETURN "LXX"
ELSE IF DIGIT = 8
THEN
RETURN "LXXX"
ELSE IF DIGIT = 9
THEN
RETURN "XC"
END IF
END DIGIT_2_TO_ROMAN
DIGIT_3_TO_ROMAN (DIGIT)
IF DIGIT = 0
THEN
RETURN ""
ELSE IF DIGIT = 1
THEN
RETURN "C"
ELSE IF DIGIT = 2
THEN
RETURN "CC"
ELSE IF DIGIT = 3
THEN
RETURN "CCC"
ELSE IF DIGIT = 4
THEN
RETURN "CD"
ELSE IF DIGIT = 5
THEN
RETURN "D"
ELSE IF DIGIT = 6
THEN
RETURN "DC"
ELSE IF DIGIT = 7
THEN
RETURN "DCC"
ELSE IF DIGIT = 8
THEN
RETURN "DCCC"
ELSE IF DIGIT = 9
THEN
RETURN "CM"
END IF
END DIGIT_3_TO_ROMAN
DIGIT_4_TO_ROMAN (DIGIT)
IF DIGIT = 0
THEN
RETURN ""
ELSE IF DIGIT = 1
THEN
RETURN "M"
ELSE IF DIGIT = 2
THEN
RETURN "MM"
ELSE IF DIGIT = 3
THEN
RETURN "MMM"
ELSE IF DIGIT = 4
THEN
RETURN "MMMM"
ELSE IF DIGIT = 5
THEN
RETURN "MMMMM"
3985
Trasformazione in lettere
3986
ELSE IF DIGIT = 6
THEN
RETURN "MMMMMM"
ELSE IF DIGIT = 7
THEN
RETURN "MMMMMMM"
ELSE IF DIGIT = 8
THEN
RETURN "MMMMMMMM"
ELSE IF DIGIT = 9
THEN
RETURN "MMMMMMMMM"
END IF
END DIGIT_4_TO_ROMAN
DIGIT_4 := int (N/1000)
N := N - (DIGIT_4 * 1000)
DIGIT_3 := int (N/100)
N := N - (DIGIT_3 * 100)
DIGIT_2 := int (N/10)
N := N - (DIGIT_2 * 10)
DIGIT_1 := N
RETURN DIGIT_4_TO_ROMAN
DIGIT_3_TO_ROMAN
DIGIT_2_TO_ROMAN
DIGIT_1_TO_ROMAN
(DIGIT_4)
(DIGIT_3)
(DIGIT_2)
(DIGIT_2)
END INTEGER_TO_ROMAN
Come si vede, dopo aver scomposto il valore in quattro fasce, si utilizzano quattro funzioni
distinte per ottenere la porzione di stringa che traduce il valore relativo. L’istruzione ‘RETURN’
finale intende concatenare tutte le stringhe risultanti.
354.3 Da numero a lettere, nel senso verbale
Quando si trasforma un numero in lettere, per esempio quando si vuole trasformare 123 in «centoventitre», l’algoritmo di conversione deve tenere conto delle convenzioni linguistiche e non
esiste una soluzione generale per tutte le lingue.
Per quanto riguarda la lingua italiana, esistono nomi diversi fino al 19, poi ci sono delle particolarità per i plurali o i singolari. La pseudocodifica seguente risolve il problema in una sola funzione
ricorsiva. Le omissioni dovrebbero essere sufficientemente intuitive.
INTEGER_TO_ITALIAN (N)
LOCAL X INTEGER
LOCAL Y INTEGER
IF N = 0
THEN
RETURN
ELSE IF N = 1
THEN
RETURN
ELSE IF N = 2
THEN
RETURN
ELSE IF N = 3
THEN
RETURN
""
"UNO"
"DUE"
"TRE"
Trasformazione in lettere
ELSE IF N = 4
THEN
RETURN "QUATTRO"
ELSE IF N = 5
THEN
RETURN "CINQUE"
ELSE IF N = 6
THEN
RETURN "SEI"
ELSE IF N = 7
THEN
RETURN "SETTE"
ELSE IF N = 8
THEN
RETURN "OTTO"
ELSE IF N = 9
THEN
RETURN "NOVE"
ELSE IF N = 10
THEN
RETURN "DIECI"
ELSE IF N = 11
THEN
RETURN "UNDICI"
ELSE IF N = 12
THEN
RETURN "DODICI"
ELSE IF N = 13
THEN
RETURN "TREDICI"
ELSE IF N = 14
THEN
RETURN "QUATTORDICI"
ELSE IF N = 15
THEN
RETURN "QUINDICI"
ELSE IF N = 16
THEN
RETURN "SEDICI"
ELSE IF N = 17
THEN
RETURN "DICIASSETTE"
ELSE IF N = 18
THEN
RETURN "DICIOTTO"
ELSE IF N = 19
THEN
RETURN "DICIANNOVE"
ELSE IF N = 20
THEN
RETURN "VENTI"
ELSE IF N = 21
THEN
RETURN "VENTUNO"
ELSE IF (N >= 22) AND (N <= 29)
THEN
RETURN "VENTI" INTEGER_TO_ITALIAN (N-20)
ELSE IF N = 30
THEN
RETURN "TRENTA"
ELSE IF N = 31
THEN
RETURN "TRENTUNO"
ELSE IF (N >= 32) AND (N <= 39)
THEN
RETURN "TRENTA" INTEGER_TO_ITALIAN (N-30)
3987
3988
Trasformazione in lettere
...
...
ELSE IF N = 90
THEN
RETURN "NOVANTA"
ELSE IF N = 91
THEN
RETURN "NOVANTUNO"
ELSE IF (N >= 92) AND (N <= 99)
THEN
RETURN "NOVANTA" INTEGER_TO_ITALIAN (N-90)
ELSE IF (N >= 100) AND (N <= 199)
THEN
RETURN "CENTO" INTEGER_TO_ITALIAN (N-100)
ELSE IF (N >= 200) AND (N <= 999)
THEN
X := int (N / 100)
Y := N - (X * 100)
RETURN INTEGER_TO_ITALIAN (X)
"CENTO"
INTEGER_TO_ITALIAN (Y)
ELSE IF (N >= 1000) AND (N <= 1999)
THEN
RETURN "MILLE" INTEGER_TO_ITALIAN (N-1000)
ELSE IF (N >= 2000) AND (N <= 999999)
THEN
X := int (N / 1000)
Y := N - (X * 1000)
RETURN INTEGER_TO_ITALIAN (X)
"MILA"
INTEGER_TO_ITALIAN (Y)
ELSE IF (N >= 1000000) AND (N <= 1999999)
THEN
RETURN "UNMILIONE" INTEGER_TO_ITALIAN (N-1000000)
ELSE IF (N >= 2000000) AND (N <= 999999999)
THEN
X := int (N / 1000000)
Y := N - (X * 1000000)
RETURN INTEGER_TO_ITALIAN (X)
"MILIONI"
INTEGER_TO_ITALIAN (Y)
ELSE IF (N >= 1000000000) AND (N <= 1999999999)
THEN
RETURN "UNMILIARDO" INTEGER_TO_ITALIAN (N-1000000000)
ELSE IF (N >= 2000000000) AND (N <= 999999999999)
THEN
X := int (N / 1000000000)
Y := N - (X * 1000000000)
RETURN INTEGER_TO_ITALIAN (X)
"MILIARDI"
INTEGER_TO_ITALIAN (Y)
ELSE
"##ERROR##"
END IF
END INTEGER_TO_ITALIAN
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Parte lxxiv
Annotazioni sulla distribuzione
Debian
355 Configurazione di una distribuzione Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3990
355.1 Procedura di inizializzazione del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3990
355.2 Configurazione del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3996
355.3 Configurazione di shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3998
355.4 Utenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3998
355.5 Stampa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3998
355.6 Configurazione del nome del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3999
355.7 Configurazione dei permessi degli eseguibili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4000
355.8 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4000
356 Accorgimenti per una distribuzione Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4001
356.1 Raccogliere gli aggiornamenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4001
356.2 Realizzazione di una copia personale della distribuzione . . . . . . . . . . . . . . . . . . 4005
356.3 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4011
3989
Capitolo
355
Configurazione di una distribuzione Debian
Dal punto di vista della configurazione, la distribuzione Debian cerca di interferire il meno possibile con le convenzioni acquisite nei sistemi Unix. In questo senso, sono poche le particolarità
da tenere in considerazione per amministrare un sistema GNU/Linux Debian.
355.1 Procedura di inizializzazione del sistema
La procedura di inizializzazione del sistema è attivata dal’eseguibile ‘init’ attraverso le indicazioni di ‘/etc/inittab’. I livelli di esecuzione sono indicati brevemente nella tabella 355.1; di
fatto si usa normalmente il livello numero due.
Tabella 355.1. Livelli di esecuzione tipici di una distribuzione Debian.
Livello di esecuzione
0
1
2
3
4
5
6
Utilizzo
Arresto del sistema.
Utente singolo.
Livello normale per la multiutenza.
Livello ausiliario per la multiutenza.
Livello disponibile per la multiutenza.
Livello disponibile per la multiutenza.
Riavvio del sistema.
Il file ‘/etc/inittab’ è quello che dirige il funzionamento di Init; analizzandone il contenuto
si può intendere il ruolo degli script della procedura di inizializzazione del sistema.
# /etc/inittab: init(8) configuration.
# $Id: inittab,v 1.8 1998/05/10 10:37:50 miquels Exp $
# The default runlevel.
id:2:initdefault:
# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS
# What to do in single-user mode.
~~:S:wait:/sbin/sulogin
#
#
#
#
#
#
#
/etc/init.d executes the S and K scripts upon change
of runlevel.
Runlevel 0 is
Runlevel 1 is
Runlevels 2-5
Runlevel 6 is
halt.
single-user.
are multi-user.
reboot.
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin
# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
3990
Configurazione di una distribuzione Debian
3991
# Action on special keypress (ALT-UpArrow).
kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work."
# What to do when the power fails/returns.
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop
# /sbin/getty invocations for the runlevels.
#
# The "id" field MUST be the same as the last
# characters of the device (after "tty").
#
# Format:
# <id>:<runlevels>:<action>:<process>
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6
# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100
# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3
355.1.1 Collegamento tra i vari componenti della procedura di
inizializzazione del sistema
Attraverso il file ‘/etc/inittab’ vengono indicati due script fondamentali, attraverso cui si
articola la procedura di inizializzazione del sistema. Si tratta di ‘/etc/init.d/rcS’ e ‘/etc/
init.d/rc’. Il primo viene utilizzato a ogni avvio del sistema e da questo dipendono le operazioni che vanno svolte una volta sola in quella occasione; il secondo serve ogni volta che si
cambia il livello di esecuzione.
• ‘/etc/init.d/’
È la directory che raccoglie gli script utilizzati nella fase di avvio del sistema e in quella di
arresto.
• ‘/etc/init.d/rcS’
È lo script di inizializzazione del sistema, organizzato in modo tale da eseguire gli script
contenuti nella directory ‘/etc/rcS.d/’, con l’argomento ‘start’. Per la precisione, si
tratta di tutti gli script che corrispondono al modello ‘S??*’, ovvero quelli che hanno un
nome che inizia con una lettera «S» maiuscola ed è lungo almeno tre caratteri. In realtà,
gli script della directory ‘/etc/rcS.d/’ sono solo collegamenti simbolici a script reali
contenuti nella directory ‘/etc/init.d/’.
In questo modo, tra le altre cose, si configura la tastiera, si attiva la memoria virtuale, si
verifica il file system principale e lo si rimonta in lettura e scrittura. Se l’attivazione del
file system principale fallisce, viene attivata una shell di emergenza per permettere una
correzione del problema. Successivamente si attivano i moduli del kernel, quindi si passa
al controllo degli altri file system e al loro montaggio. Infine, si configura e si attiva la rete,
assieme ad altre operazioni di importanza minore, come il montaggio di file system di rete.
Configurazione di una distribuzione Debian
3992
È importante osservare che lo script ‘/etc/init.d/rcS’ carica inizialmente il file
‘/etc/default/rcS’, che in pratica viene usato per la sua configurazione, definendo alcune variabili di ambiente che dopo vengono analizzate. A queste variabili possono
avere accesso anche gli script avviati da ‘/etc/init.d/rcS’.
Al termine del suo lavoro normale, lo script ‘/etc/init.d/rcS’ esegue anche gli script
che trova nella directory ‘/etc/rc.boot/’, che esiste ancora per motivi di compatibilità
con il passato.
• ‘/etc/rc.boot/’
È una directory che dovrebbe essere eliminata nel prossimo futuro. Il suo scopo è contenere script da eseguire all’avvio del sistema, prima di entrare in un livello di esecuzione
particolare.
In generale, questi script dovrebbero essere spostati nella directory ‘/etc/init.d/’,
collegandoli poi con dei collegamenti simbolici opportuni nella directory ‘/etc/rcS.d/’.
• ‘/etc/init.d/rc’
È lo script principale per il controllo dei livelli di esecuzione. Viene utilizzato da Init,
attraverso le indicazioni di ‘/etc/inittab’, con un argomento corrispondente al numero
di livello di esecuzione da attivare.
/etc/init.d/rc livello_di_esecuzione
Semplificando un po’ le cose, ‘/etc/init.d/rc’ si limita ad avviare tutti gli script che
trova nella directory ‘/etc/n .d/’ (dove n rappresenta il livello di esecuzione richiesto),
cominciando da quelli che iniziano con la lettera ‘K’ e terminando con quelli che iniziano
con la lettera ‘S’.
In realtà, questi script sono contenuti nella directory ‘/etc/init.d/’, con nomi più
espressivi, mentre nelle directory ‘/etc/rcn .d/’ sono contenuti solo dei collegamenti
simbolici con nomi scelti appositamente per definire l’ordine in cui le operazioni devono
essere svolte.
In questo modo, è possibile definire i livelli di esecuzione lasciati a disposizione, semplicemente copiandovi all’interno i collegamenti simbolici necessari e senza toccare alcuno
script.
• ‘/etc/rcn .d/’
Come accennato, si tratta delle directory riferite a ogni livello di esecuzione (n rappresenta
il numero del livello stesso). Al loro interno si trovano solo collegamenti simbolici riferiti
agli script che si vuole siano eseguiti.
Quando viene selezionato il livello di esecuzione relativo, vengono eseguiti in ordine alfabetico, prima gli script (o meglio i collegamenti) che iniziano con la lettera ‘K’ (Kill) nella
forma
/etc/rcn .d/script stop
allo scopo di disattivare il servizio particolare cui si riferiscono, quindi quelli che iniziano
con la lettera ‘S’ (Start), nella forma seguente:
/etc/rcn .d/script start
• ‘/etc/init.d/’
È il vero contenitore degli script utilizzati dalla procedura di inizializzazione del sistema.
Questi vengono utilizzati indirettamente attraverso collegamenti simbolici contenuti nella
directory ‘/etc/rcS.d/’ e nelle directory ‘/etc/rcn .d/’.
Configurazione di una distribuzione Debian
3993
Molti di questi script possono essere utilizzati dall’amministratore per disattivare o attivare
un servizio particolare, senza dover intervenire direttamente nel livello di esecuzione e
senza dover ricordare tutte le implicazioni di un servizio particolare. Il formato generale è
il seguente:
/etc/init.d/servizio
{start|stop|restart|force-reload}
• ‘/sbin/start-stop-daemon’
Si tratta di un programma specifico della distribuzione Debian (dovrebbe far parte del pacchetto ‘dpkg’) che facilita l’avvio e la conclusione del funzionamento dei demoni avviati
attraverso la procedura di inizializzazione del sistema. Per esempio, l’avvio del demone
‘gpm’ viene fatto nel modo seguente (le opzioni di ‘gpm’ sono solo un esempio per semplificare lo script; si tenga presente inoltre che la riga significativa è divisa in due per motivi
tipografici, utilizzando il simbolo ci continuazione ‘\’ delle shell Bourne):
echo -n "Starting mouse interface server: gpm"
start-stop-daemon --start --quiet --exec /usr/sbin/gpm -- \
-m /dev/mouse -t ms
echo "."
Nello stesso modo, l’arresto del demone viene fatto nel modo seguente:
echo -n "Stopping mouse interface server: gpm"
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/gpmpid \
--exec /usr/sbin/gpm
echo "."
L’uso di ‘start-stop-daemon’ può essere approfondito leggendo la sua pagina di
manuale: start-stop-daemon(8).
355.1.2 /etc/init.d/*
I file contenuti nella directory ‘/etc/init.d/’, quando si riferiscono a dei servizi, hanno una
struttura abbastanza comune, simile a quella seguente. Si fa riferimento all’ipotetico servizio
«pippo», a cui corrisponde un demone con lo stesso nome.
#!/bin/sh
#
# Avvia o arresta il servizio «pippo» gestito attraverso il demone «pippo»
#
# Tizio Tizi <[email protected]>
# Prima di cominciare verifica che esista l’eseguibile del demone.
test -x /usr/sbin/pippo || exit 0
# Analizza l’argomento e vi si adegua.
case "$1" in
start)
echo -n "Avvio di un servizio inutile: pippo"
start-stop-daemon --start --quiet --exec /usr/sbin/pippo
echo "."
;;
stop)
echo -n "Arresto di un servizio inutile: pippo"
start-stop-daemon --stop --quiet \
--pidfile /var/run/pippo.pid --exec /usr/sbin/pippo
echo "."
;;
restart)
$0 stop
$0 start
Configurazione di una distribuzione Debian
3994
;;
reload)
echo -n "Rilettura della configurazione di pippo..."
start-stop-daemon --stop --signal 1 --quiet \
--pidfile /var/run/named.pid --exec /usr/sbin/named
echo "fatto."
;;
force-reload)
$0 restart
;;
*)
echo "Utilizzo: /etc/init.d/pippo {start|stop|reload|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
Nella prima parte viene verificato che esista effettivamente l’eseguibile del demone ‘pippo’; in
caso contrario conclude lo script, ma senza restituire un errore (‘exit 0’).
Subito dopo si passa all’analisi del primo (e unico) argomento fornito allo script:
• se è ‘start’, si provvede ad avviare il demone attraverso ‘start-stop-daemon’;
• se è ‘stop’, si provvede a eliminare il processo relativo, utilizzando l’informazione sul
numero PID che dovrebbe essere contenuta nel file ‘/var/run/pippo.pid’, creato dal
demone ‘pippo’ stesso;
• se è ‘restart’, vengono ripetute le operazioni corrispondenti a ‘stop’ e ‘start’ in
sequenza;
• se è ‘reload’ (si tratta di un’opzione che non è disponibile in tutti gli script di questo
tipo), viene inviato un segnale ‘SIGHUP’ (1) al demone, in modo che questo rilegga la
configurazione;
• se è ‘force-reload’, viene eseguita in pratica l’operazione corrispondente a ‘restart’,
con lo scopo di obbligare alla rilettura della configurazione, anche se ciò costringe ad
arrestare e a riavviare il servizio.
355.1.3 /etc/rc?.d/
Le directory ‘/etc/rcn .d/’ e ‘/etc/rcS.d/’, servono a contenere una serie di collegamenti simbolici che puntano a script reali contenuti in ‘/etc/init.d’. I due listati seguenti si
riferiscono al contenuto ipotetico di ‘/etc/rc1.d/’ e ‘/etc/rc2.d/’:
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
1
1
1
1
1
1
1
1
1
1
1
1
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
14
17
21
17
14
14
13
17
15
13
13
20
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
9
9
9
9
9
9
9
9
9
9
9
9
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
K11cron -> ../init.d/cron
K12kerneld -> ../init.d/kerneld
K15netstd_init -> ../init.d/netstd_init
K18netbase -> ../init.d/netbase
K19bind -> ../init.d/bind
K20exim -> ../init.d/exim
K20gpm -> ../init.d/gpm
K20logoutd -> ../init.d/logoutd
K20lprng -> ../init.d/lprng
K20ppp -> ../init.d/ppp
K20ssh -> ../init.d/ssh
K25nfs-server -> ../init.d/nfs-server
Configurazione di una distribuzione Debian
3995
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
1
1
1
1
root
root
root
root
root
root
root
root
21
16
18
16
ago
ago
ago
ago
9
9
9
9
15:18
15:18
15:18
15:18
K30netstd_misc -> ../init.d/netstd_misc
K89pcmcia -> ../init.d/pcmcia
K90sysklogd -> ../init.d/sysklogd
S20single -> ../init.d/single
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
18
16
17
21
17
14
14
13
17
15
13
13
20
21
14
19
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
ago
9
9
9
9
9
9
9
9
9
9
9
9
9
9
9
9
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
15:18
S10sysklogd -> ../init.d/sysklogd
S11pcmcia -> ../init.d/pcmcia
S12kerneld -> ../init.d/kerneld
S15netstd_init -> ../init.d/netstd_init
S18netbase -> ../init.d/netbase
S19bind -> ../init.d/bind
S20exim -> ../init.d/exim
S20gpm -> ../init.d/gpm
S20logoutd -> ../init.d/logoutd
S20lprng -> ../init.d/lprng
S20ppp -> ../init.d/ppp
S20ssh -> ../init.d/ssh
S25nfs-server -> ../init.d/nfs-server
S30netstd_misc -> ../init.d/netstd_misc
S89cron -> ../init.d/cron
S99rmnologin -> ../init.d/rmnologin
I collegamenti che iniziano con la lettera «S» vengono avviati ordinatamente all’attivazione del
livello di esecuzione corrispondente, con l’argomento ‘start’, mentre quelli che iniziano con la
lettera «K» vengono avviati prima di passare a un nuovo livello di esecuzione, con l’argomento
‘stop’.
Il numero che segue la lettera «S» e «K», serve a definire un ordine (alfanumerico), corrispondente a quello in cui i servizi vanno avviati o arrestati. Se si volesse aggiungere uno script, nella
directory ‘/etc/init.d/’ per la gestione di un servizio addizionale, si dovrebbero predisporre
i collegamenti relativi nella directory in cui servono: per esempio potrebbe essere necessario un
collegamento «K» nelle directory ‘/etc/rc0.d/’, ‘/etc/rc1.d/’ e ‘/etc/rc6.d/’, mentre
nelle altre directory ‘/etc/rc[2-5].d/’ si potrebbe inserire un collegamento «S», a seconda
di come si vogliono gestire i livelli di esecuzione da due a cinque.
La distribuzione Debian non dispone di uno script ‘rc.local’. Per ottenere lo stesso risultato,
si può predisporre uno script normale, che eventualmente non sia influenzato dagli argomenti;
quindi si devono predisporre i collegamenti simbolici di tipo «S» necessari, probabilmente
con un numero abbastanza elevato, in modo da farlo intervenire alla fine della procedura di
avvio del sistema.
355.1.4 # update-rc.d
Il programma ‘update-rc.d’ permette di facilitare la creazione e l’eliminazione dei collegamenti simbolici nelle directory ‘/etc/rcn .d/’. In generale, il suo utilizzo non è indispensabile,
ma torna molto utile nella realizzazione di script legati all’installazione e alla disinstallazione
dei pacchetti. Qui viene descritto solo il suo uso elementare, dal momento che si può fare tutto
quello che si vuole anche senza l’aiuto di questo programma. Eventualmente si può consultare la
sua pagina di manuale update-rc.d(8).
update-rc.d nome_script remove
update-rc.d nome_script defaults
Nel primo caso, ‘update-rc.d’ elimina i collegamenti simbolici, riferiti allo script indicato,
da tutte le directory ‘/etc/rcn .d/’, compresa la directory ‘/etc/rcS.d/’, purché questo sia
effettivamente assente dalla directory ‘/etc/init.d/’.
Configurazione di una distribuzione Debian
3996
Nel secondo caso, ‘update-rc.d’ crea i collegamenti simbolici, riferiti allo script indicato, che
deve trovarsi nella directory ‘/etc/init.d/’, in base a ciò che di solito è più opportuno: nelle
directory corrispondenti ai livelli zero, uno e sei, vengono creati dei collegamenti di tipo
K20nome_script
Mentre nelle directory dei livelli da due a cinque, vengono creati dei collegamenti di tipo
S20nome_script
Per esempio, se è stato creato lo script ‘pippo’, ed è stato collocato nella directory ‘/etc/
init.d/’, si possono predisporre i collegamenti simbolici con il comando seguente:
# update-rc.d pippo defaults[ Invio ]
Adding system startup
/etc/rc0.d/K20pippo
/etc/rc1.d/K20pippo
/etc/rc6.d/K20pippo
/etc/rc2.d/S20pippo
/etc/rc3.d/S20pippo
/etc/rc4.d/S20pippo
/etc/rc5.d/S20pippo
for /etc/init.d/pippo ...
-> ../init.d/pippo
-> ../init.d/pippo
-> ../init.d/pippo
-> ../init.d/pippo
-> ../init.d/pippo
-> ../init.d/pippo
-> ../init.d/pippo
Una volta eliminato lo script ‘pippo’ dalla directory ‘/etc/init.d/’, si possono eliminare i
collegamenti simbolici relativi con il comando seguente:
# update-rc.d pippo remove[ Invio ]
Removing any system startup links for /etc/init.d/pippo ...
/etc/rc0.d/K20pippo
/etc/rc1.d/K20pippo
/etc/rc2.d/S20pippo
/etc/rc3.d/S20pippo
/etc/rc4.d/S20pippo
/etc/rc5.d/S20pippo
/etc/rc6.d/K20pippo
355.2 Configurazione del sistema
La distribuzione Debian non ha un sistema centralizzato per la configurazione, lasciando che
ogni pacchetto gestisca la configurazione a suo modo. L’esempio più importante di questa impostazione sta nella configurazione della rete, che avviene attraverso la modifica diretta di uno
script di quelli che appartengono alla procedura di inizializzazione del sistema: ‘/etc/init.d/
network’.
355.2.1 Configurazione della tastiera e dei caratteri dello schermo
La configurazione della tastiera riguarda il pacchetto ‘kbd’ e avviene per mezzo dello script
‘/etc/init.d/keymaps.sh’, che viene avviato tramite un collegamento simbolico contenuto
nella directory ‘/etc/rcS.d/’. Questo script carica automaticamente la mappa della tastiera
corrispondente al file ‘/etc/kbd/default.kmap.gz’. Evidentemente, per definire una mappa
per la tastiera differente, basta copiare il file opportuno nella directory ‘/etc/kbd/’, dandogli il
nome ‘default.kmap.gz’.
Sempre riguardo al pacchetto ‘kbd’, la configurazione dei caratteri dello schermo avviene per
mezzo dello script ‘/etc/rc.boot/kbd’, che utilizza le definizioni contenute nel file ‘/etc/
kbd/config’. Questo ultimo file è in pratica un pezzo di script, per cui basta assegnare alla variabile ‘CONSOLE_FONT’ il nome del file di definizione dei caratteri che si desidera. Per
esempio,
Configurazione di una distribuzione Debian
3997
CONSOLE_FONT=lat1u-16.psf.gz
fa sì che venga caricato il file ‘/usr/share/consolefonts/lat1u-16.psf.gz’.
355.2.2 Configurazione della rete
Come accennato, la rete viene configurata attraverso lo script ‘/etc/init.d/network’. Questo
non ha bisogno di accorgimenti particolari, dal momento che è collegato normalmente solo alla
directory ‘/etc/rcS.d/’, che contiene i collegamenti simbolici avviati una volta sola all’avvio
del sistema.
Di solito, lo script in questione viene creato nel momento in cui si installa la distribuzione
per la prima volta, in ogni caso, può bastare una cosa come l’esempio seguente, da modificare
opportunamente, soprattutto in base al tipo e al numero di interfacce di rete.
#! /bin/sh
ifconfig lo 127.0.0.1 netmask 255.0.0.0
# route add -net 127.0.0.0 netmask 255.0.0.0 dev lo
route add -host 127.0.0.1 dev lo
ifconfig eth0 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255
route add -net 192.168.1.0 netmask 255.255.255.0 dev eth0
route add default gw 192.168.1.254 metric 1
Nella directory ‘/etc/rcS.d/’ basta quindi il collegamento simbolico ‘S40network’, che
punta a ‘../init.d/network’.
355.2.3 Configurazione dell’orologio hardware
In generale, la correzione dell’orologio hardware si ottiene configurando opportunamente il file ‘/etc/adjtime’. Tuttavia, in fase di avvio del sistema operativo, è importante sapere se
l’orologio hardware è puntato sul tempo universale coordinato, oppure sull’ora locale.
Dal momento che lo script che si occupa di queste cose è controllato da ‘/etc/init.d/rcS’ e
dato che questo viene configurato con il file ‘/etc/default/rcS’, all’interno di questo ultimo
si può modificare la variabile ‘GMT’. In pratica, per indicare che l’orologio hardware è posizionato
sul tempo universale si assegna il valore ‘-u’:
# Set GMT="-u" if your system clock is set to GMT, and GMT="" if not.
GMT="-u"
355.2.4 Configurazione del mouse per lo schermo a caratteri
La gestione del mouse per lo schermo a caratteri avviene attraverso il demone ‘gpm’, come di consueto. L’avvio e l’arresto del servizio è organizzato come al solito attraverso uno script contenuto
nella directory ‘/etc/init.d/’. Normalmente, questo script carica la configurazione contenuta
nel file ‘/etc/gpm.conf’. Attraverso le variabili dichiarate in questo file di configurazione, lo
script di avvio del servizio genera le opzioni opportune per la riga di comando di ‘gpm’.
3998
Configurazione di una distribuzione Debian
355.3 Configurazione di shell
Secondo la politica della distribuzione Debian, se un programma ha bisogno che siano definite
delle variabili di ambiente, o delle funzioni di shell, per questo deve essere predisposto uno
script di avvio apposito, in modo da non dover disturbare l’utente con questa configurazione. In
pratica, la configurazione globale delle shell non deve essere modificata dall’installazione di un
pacchetto.
In generale, se necessario per qualche ragione, l’amministratore del sistema può intervenire nel
file ‘/etc/profile’ e negli altri file di configurazione delle altre shell. Come al solito, potrebbe
convenire l’inserimento di alcuni alias per evitare la cancellazione involontaria dei file e inoltre
si potrebbe impostare il linguaggio predefinito. L’esempio seguente fa riferimento al caso della
shell Bash:
alias rm=’rm -i’
alias cp=’cp -i’
alias mv=’mv -i’
LANG="it_IT.ISO-8859-1"
export LANG
Per quanto riguarda la configurazione personale delle shell, non è previsto niente di particolare,
a parte il caso dell’utente ‘root’.
355.4 Utenti
Con la distribuzione Debian si utilizzano preferibilmente i programmi ‘adduser’ e ‘addgroup’
per registrare nel sistema degli utenti nuovi. Questi due sono un programma Perl unico, che si
configura con il file ‘/etc/adduser.conf’.
In generale, non dovrebbe essere necessario modificare questa configurazione, soprattutto per
non uscire dalla politica predefinita della distribuzione. In generale, si può osservare che vengano
gestiti i gruppi privati, per cui, alla registrazione di un utente, viene aggiunto anche un nuovo
gruppo con lo stesso nome e lo stesso numero GID.
In generale, gli utenti e i gruppi ricevono un numero UID e GID compreso tra 1000 e 29999;
l’utente ‘nobody’ ha il numero UID 65534, ed è abbinato al gruppo ‘nogroup’, con lo stesso
numero GID.
355.5 Stampa
Il sistema di stampa adottato dalla distribuzione Debian è LPRng, che in generale è abbastanza
compatibile con quello tradizionale dello Unix BSD. Rispetto ad altre distribuzioni GNU/Linux,
Debian lascia all’amministratore la configurazione manuale del file ‘/etc/printcap’ che è
comunque piuttosto semplice.
Assieme al pacchetto di LPRng viene installato normalmente anche Magicfilter, che come suggerisce il nome è un sistema di filtri per stampanti. Nella directory ‘/etc/magicfilter/’ si
trovano una serie di script di Magicfilter, uno per ogni tipo di stampante previsto. È sufficiente
modificare la configurazione del file ‘/etc/printcap’, in modo da utilizzare il filtro adatto per
la propria stampante. L’esempio seguente definisce la stampante ‘lp’ abbinata alla prima porta
parallela a cui si trova connessa una stampante compatibile con il modello HP Laserjet:
# /etc/printcap: printer capability database. See printcap(5).
# You can use the filter entries df, tf, cf, gf etc. for
# your own filters. See the printcap(5) manual page for further
Configurazione di una distribuzione Debian
3999
# details.
lp|HP Laserjet
:lp=/dev/lp0
:sd=/var/spool/lpd/lp
:af=/var/log/lp-acct
:lf=/var/log/lp-errs
:if=/etc/magicfilter/laserjet-filter
:pl#66
:pw#80
:pc#150
:mx#0
:sh
Come si può osservare, le righe della direttiva ‘lp’ non sono terminate dal simbolo di
continuazione ‘\’, che con LPRng non è necessario.
Per determinare quale sia il filtro migliore per la propria stampante, occorre fare qualche prova,
dal momento che per uno stesso modello ci possono essere diverse alternative.
Per quanto riguarda la stampa dei file di testo, volendo sfruttare sistematicamente A2ps per
l’impaginazione, si può modificare in coda allo script di Magicfilter l’istruzione seguente:
#! /usr/sbin/magicfilter
#...
# Default entry -- for normal (text) files. MUST BE LAST.
#default
cat
\eE\e&k2G\e(0N \eE
default
pipe a2ps --portrait --columns=1 --margin=30
--no-header --borders=no
--chars-per-line=80 --font-size=10
--interpret=yes --output=2> /dev/null
\
\
\
\
355.5.1 Configurazione del formato della carta
La distribuzione Debian organizza la definizione del formato della carta attraverso il file ‘/etc/
papersize’, il quale deve contenere la sigla corrispondente. Di solito i programmi interpretano correttamente i nomi: ‘a3’, ‘a4’, ‘a5’, ‘b5’, ‘letter’, ‘legal’. Eventualmente, per gli altri
formati si può utilizzare una delle definizioni comprensibili per Ghostscript.
A questo file di configurazione è abbinata una libreria, che in teoria dovrebbe essere utilizzata
dai programmi che hanno qualcosa a che fare con la stampa. Per esempio, Ghostscript non ha
bisogno dell’opzione ‘-sPAPERSIZE’ perché riesce a ottenere questa informazione dal file di
configurazione.
355.6 Configurazione del nome del sistema
Il nome del sistema, così come lo intende il programma di servizio ‘hostname’, viene definito
nel file ‘/etc/hostname’. Da lì viene letto in fase di avvio del sistema.
Un altro file di configurazione simile è ‘/etc/mailname’, che dovrebbe contenere il nome di
dominio completo da utilizzare per inviare messaggi di posta elettronica.
Configurazione di una distribuzione Debian
4000
355.7 Configurazione dei permessi degli eseguibili
Per evitare la proliferazione incontrollata di permessi strani attribuiti agli eseguibili, soprattutto
per ciò che riguarda i bit SUID e SGID, la distribuzione GNU/Linux Debian organizza uno script
eseguito giornalmente nell’ambito del sistema Cron, con lo scopo di controllare e correggere tali
permessi. Questo script si avvale della configurazione contenuta nel file ‘/etc/suid.conf’, che
contiene semplicemente un elenco di eseguibili con i permessi che dovrebbero avere. Segue un
estratto molto semplice e intuitivo del suo contenuto:
# Configuration File for suid programs or special permissions
#
# The format is:
# package file user group permissions
lsof-2.0.35 /usr/sbin/lsof root kmem 2755
emacs /usr/lib/emacs/20.3/i386-debian-linux-gnu/movemail root mail 2755
emacs /usr/lib/emacs/19.34/i386-debian-linux/movemail root mail 2755
apache-common /usr/bin/htpasswd root root 755
apache-common /usr/lib/apache/suexec root root 755
xscreensaver /usr/X11R6/bin/xscreensaver root shadow 2755
xcdroast /usr/bin/xcdroast root root 4755
ssh /usr/bin/ssh1 root root 4755
...
In generale, questo file viene aggiornato automaticamente ogni volta che si installa un pacchetto
che richiede dei permessi speciali sui suoi eseguibili; tuttavia, quando si vuole cambiare qualcosa
in modo manuale, occorre ricordarsi di intervenire anche qui per rendere la modifica permanente.
355.8 Riferimenti
• Susan G. Kleinmann, Sven Rudolph, Joost Witteveen, The Debian GNU/Linux FAQ, 1999
<http://ftp.it.debian.org/debian/doc/FAQ/>
• Ian Jackson, Christian Schwarz, Debian Policy Manual, 1998
<http://ftp.it.debian.org/debian/doc/package-developer/policy.txt.gz>
<http://ftp.it.debian.org/debian/doc/package-developer/policy.html.tar.gz>
<http://ftp.it.debian.org/debian/doc/package-developer/policy.pdf.gz>
<http://ftp.it.debian.org/debian/doc/package-developer/policy.ps.gz>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
356
Accorgimenti per una distribuzione Debian
In generale, la distribuzione GNU/Linux Debian non ha bisogno di accorgimenti particolari. In
questo capitolo vengono annotate poche cose; in particolare sul modo di gestire una raccolta degli
archivi Debian e sulla possibilità di realizzare una copia personalizzata della distribuzione.
356.1 Raccogliere gli aggiornamenti
La distribuzione Debian, data la sua natura collaborativa, è molto dinamica e nel susseguirsi
delle sue edizioni viene prodotta una grande quantità di pacchetti aggiornati. Data la dimensione
che ha raggiunto ormai la distribuzione, è improbabile che si riesca ad avere sempre una copia
completa della distribuzione; piuttosto è facile trovare nelle riviste dei CD-ROM con questo o
quel gruppo di applicativi, più o meno aggiornati. Volendo realizzare una propria copia locale
della distribuzione (su disco fisso, o su dischi rimovibili), occorre realizzare qualche script per
gestire un po’ meglio la cosa.
356.1.1 Composizione del nome degli archivi Debian
Il nome degli archivi Debian è organizzato secondo la struttura seguente:
nome_del_pacchetto _versione_e_revisione .deb
Per essere precisi, questo è il nome normale, da utilizzare quando si conosce a quale architettura
è destinato, in base alla directory in cui si trova a essere conservato.
Alle volte, per qualche ragione, il nome degli archivi che si trovano in circolazione non è conforme a questo modello; tuttavia, con l’aiuto delle informazioni contenute negli archivi stessi, è
possibile riprodurre il nome standard. I comandi seguenti, che utilizzano ‘dpkg’, permettono di
ottenere le informazioni necessarie a ricostruire il nome di un archivio Debian:
dpkg --field archivio package
restituisce il nome del pacchetto;
dpkg --field archivio version
Restituisce la stringa che rappresenta la versione e la revisione del pacchetto.
Quello che segue è l’esempio di uno script in grado di scandire gli archivi contenuti nella directory corrente, allo scopo di modificarne il nome se questo non corrisponde al modello standard.
La scansione viene fatta in due fasi, per verificare alla fine quali archivi non sono stati corretti.
#!/bin/bash
#=======================================================================
# debian-nomi
#
# Interviene nella directory *corrente* correggendo i nomi degli
# archivi che sembrano non essere coerenti. Si utilizza in particolare:
#
#
dpkg --field <archivio> package
#
dpkg --field <archivio> version
#
#=======================================================================
#----------------------------------------------------------------------# Inizializza le variabili di ambiente che servono per accumulare
# i valori per il confronto.
#-----------------------------------------------------------------------
4001
4002
Accorgimenti per una distribuzione Debian
ARCHIVIO=""
PACCHETTO=""
VERSIONE=""
NOME_CORRETTO=""
#---------------------------------------------------------------------# Inizia il ciclo di scansione degli archivi Debian che si trovano
# nella directory corrente.
# Prima fase silenziosa.
#---------------------------------------------------------------------for ARCHIVIO in *.deb
do
#-----------------------------------------------------------------# Se il nome è «*.deb», non ci sono file del genere.
#-----------------------------------------------------------------if [ "$ARCHIVIO" = "*.deb" ]
then
#-------------------------------------------------------------# Non si fa nulla.
#-------------------------------------------------------------exit
fi
#-----------------------------------------------------------------# Estrae il nome del pacchetto.
#-----------------------------------------------------------------PACCHETTO=‘dpkg --field $ARCHIVIO package‘
#-----------------------------------------------------------------# Estrae la versione del pacchetto.
#-----------------------------------------------------------------VERSIONE=‘dpkg --field $ARCHIVIO version‘
#-----------------------------------------------------------------# Compone il nome teorico.
#-----------------------------------------------------------------NOME_CORRETTO="${PACCHETTO}_${VERSIONE}.deb"
#-----------------------------------------------------------------# Confronta con il nome dell’archivio.
#-----------------------------------------------------------------if [ "$NOME_CORRETTO" != "$ARCHIVIO" ]
then
#-------------------------------------------------------------# I nomi sono differenti.
# Modifica il nome solo se è possibile.
#-------------------------------------------------------------echo "n" | mv -i "$ARCHIVIO" "$NOME_CORRETTO" 2> /dev/null
fi
done
#---------------------------------------------------------------------# Inizia il ciclo di scansione degli archivi Debian che si trovano
# nella directory corrente.
# Seconda fase di verifica.
#---------------------------------------------------------------------for ARCHIVIO in *.deb
do
#-----------------------------------------------------------------# Estrae il nome del pacchetto.
#-----------------------------------------------------------------PACCHETTO=‘dpkg --field $ARCHIVIO package‘
#-----------------------------------------------------------------# Estrae la versione del pacchetto.
#-----------------------------------------------------------------VERSIONE=‘dpkg --field $ARCHIVIO version‘
Accorgimenti per una distribuzione Debian
4003
#-----------------------------------------------------------------# Compone il nome teorico.
#-----------------------------------------------------------------NOME_CORRETTO="${PACCHETTO}_${VERSIONE}.deb"
#-----------------------------------------------------------------# Confronta con il nome dell’archivio.
#-----------------------------------------------------------------if [ "$NOME_CORRETTO" != "$ARCHIVIO" ]
then
#-------------------------------------------------------------# A quanto pare, il nome di questo archivio non è stato
# corretto.
#-------------------------------------------------------------echo "Non è stato possibile correggere il nome dell’archivio"
echo "$ARCHIVIO, che dovrebbe chiamarsi $NOME_CORRETTO."
echo
fi
done
#=======================================================================
356.1.2 Eliminazione delle versioni precedenti
La versione di un pacchetto è composta da due parti: la versione (vera e propria) e la revisione.
Si tratta di due stringhe unite da un trattino:
versione -revisione
In generale, non è facile confrontare questi valori e per fortuna viene in aiuto ‘dpkg’ che è in
grado di affermare quale sia più recente. In pratica, si utilizza uno dei comandi seguenti, per
determinare se una versione è maggiore, minore o uguale all’altra:
dpkg --compare-versions versione1 gt versione2
dpkg --compare-versions versione1 lt versione2
dpkg --compare-versions versione1 eq versione2
Lo script seguente serve a scandire gli archivi Debian contenuti nella directory corrente, allo
scopo di eliminare quelli che contengono uno stesso pacchetto ma di una versione precedente a
quanto già disponibile. Durante la scansione, si presume che i nomi degli archivi siano composti
correttamente, in modo tale che gli archivi di uno stesso pacchetto si trovino di seguito, nella
sequenza alfabetica.
#!/bin/bash
#=======================================================================
# debian-doppi
#
# Interviene nella directory *corrente* eliminando i file doppi,
# più vecchi. Il confronto viene fatto utilizzando:
#
#
dpkg --field <archivio> package
#
dpkg --field <archivio> version
#
dpkg --compare-versions <versione1> eq <versione0>
#
dpkg --compare-versions <versione1> gt <versione0>
#
dpkg --compare-versions <versione1> lt <versione0>
#
#=======================================================================
#----------------------------------------------------------------------# Inizializza le variabili di ambiente che servono per accumulare
# i valori per il confronto.
#-----------------------------------------------------------------------
Accorgimenti per una distribuzione Debian
4004
ARCHIVIO0=""
ARCHIVIO1=""
PACCHETTO0=""
PACCHETTO1=""
VERSIONE0=""
VERSIONE1=""
#---------------------------------------------------------------------# Inizia il ciclo di scansione degli archivi Debian che si trovano
# nella directory corrente.
#---------------------------------------------------------------------for ARCHIVIO1 in *.deb
do
#-----------------------------------------------------------------# Se il nome è «*.deb», non ci sono file del genere.
#-----------------------------------------------------------------if [ "$ARCHIVIO1" = "*.deb" ]
then
#-------------------------------------------------------------# Non si fa nulla.
#-------------------------------------------------------------exit
fi
#-----------------------------------------------------------------# Estrae il nome del pacchetto.
#-----------------------------------------------------------------PACCHETTO1=‘dpkg --field $ARCHIVIO1 package‘
#-----------------------------------------------------------------# Estrae la versione del pacchetto.
#-----------------------------------------------------------------VERSIONE1=‘dpkg --field $ARCHIVIO1 version‘
#-----------------------------------------------------------------# Confronta con il pacchetto precedente.
#-----------------------------------------------------------------if [ "$PACCHETTO1" == "$PACCHETTO0" ]
then
if dpkg --compare-versions "$VERSIONE1" eq "$VERSIONE0"
then
#---------------------------------------------------------# Si tratta di un’anomalia in cui si deve intervenire a
# mano.
#---------------------------------------------------------echo "Gli archivi seguenti hanno la stessa versione:"
echo "
$ARCHIVIO0"
echo "
$ARCHIVIO1"
echo
#---------------------------------------------------------# In questo caso, non occorre spostare i valori nelle
# variabili.
#---------------------------------------------------------elif dpkg --compare-versions "$VERSIONE1" gt "$VERSIONE0"
then
#---------------------------------------------------------# Si elimina l’archivio del pacchetto più vecchio.
#---------------------------------------------------------rm -f "$ARCHIVIO0"
echo "Eliminato $ARCHIVIO0"
#---------------------------------------------------------# Sposta i valori nelle variabili.
#----------------------------------------------------------
Accorgimenti per una distribuzione Debian
4005
ARCHIVIO0="$ARCHIVIO1"
PACCHETTO0="$PACCHETTO1"
VERSIONE0="$VERSIONE1"
elif dpkg --compare-versions "$VERSIONE1" lt "$VERSIONE0"
then
#---------------------------------------------------------# Si elimina l’archivio del pacchetto più vecchio.
#---------------------------------------------------------rm -f "$ARCHIVIO1"
echo "Eliminato $ARCHIVIO1"
#---------------------------------------------------------# In questo caso, non occorre spostare i valori nelle
# variabili.
#---------------------------------------------------------else
#---------------------------------------------------------# Questo caso non dovrebbe verificarsi.
#---------------------------------------------------------echo "C’è un errore nel confronto degli archivi seguenti:"
echo "
$ARCHIVIO0"
echo "
$ARCHIVIO1"
echo
#---------------------------------------------------------# In questo caso, non occorre spostare i valori nelle
# variabili.
#---------------------------------------------------------fi
else
#-------------------------------------------------------------# Dal momento che i pacchetti sono differenti, si devono
# salvare le variabili prima di procedere.
#-------------------------------------------------------------ARCHIVIO0="$ARCHIVIO1"
PACCHETTO0="$PACCHETTO1"
VERSIONE0="$VERSIONE1"
fi
done
#=======================================================================
356.2 Realizzazione di una copia personale della
distribuzione
Per comprendere come realizzare una copia locale della distribuzione GNU/Linux Debian, occorre andare per gradi, partendo dal caso in cui questa è disponibile completamente in un supporto
unico, per poi arrivare a comprendere le differenze che si devono introdurre per ottenere una
versione distribuita su più supporti.
356.2.1 Distribuzione completa su un supporto unico
Si suppone che l’utente ‘tizio’ voglia predisporre una copia locale della distribuzione Debian,
a partire dalla directory ‘/home/tizio/DEBIAN/’. La struttura minima che dovrebbe articolarsi
a partire da questa directory dovrebbe essere quella che si vede nella figura 356.1.
4006
Accorgimenti per una distribuzione Debian
Figura 356.1. Struttura minima di una distribuzione GNU/Linux Debian organizzata in
modo da utilizzare un supporto unico.
debian/
|-- dists/
|
|-- stable --> ../codename
|
|
|
‘-- codename /
|
|
|
|-- main/
|
|
|-- disks-arch /
|
|
|
‘-- current/
|
|
|
|
|
‘-- binary-arch /
|
|
|-- Packages
|
|
|-- Packages.gz
|
|
|-- admin/
|
|
|-- base/
|
|
|-- comm/
|
|
:
|
|
|
|-- contrib/
|
|
|
|
|
‘-- binary-arch /
|
|
|-- Packages
|
|
|-- Packages.gz
|
|
:
|
|
|
|-- non-free/
|
|
:
|
|
|
|-- non-US/
|
|
:
|
|
|
‘-- local/
|
:
|
‘-- indices/
‘-- override.gz
In breve, viene descritto il senso di questa struttura.
• La directory ‘debian/dists/stable/main/disks-i386/current/’ contiene i file
delle immagini dei dischetti (per l’architettura i386) da utilizzare per avviare l’installazione
e per riprodurre il sistema minimo precedente alla selezione dei pacchetti.
• Le directory ‘debian/dists/stable/*/binary-i386/’ contengono la gerarchia finale
dei pacchetti di ogni gruppo (‘main/’, ‘contrib/’, ‘non-free/’, ‘non-US/’ e ‘local/’),
che potrebbe essere suddivisa o meno in sezioni (‘admin/’, ‘base/’, ecc.). Da quel punto,
poi, si inseriscono gli archivi Debian.
• I file ‘Packages’ e ‘Packages.gz’, contenuti nelle directory ‘debian/dists/stable/
*/binary-i386/’, sono indispensabili per fornire ai programmi come DSelect e APT le
informazioni importanti sui pacchetti.
• Il file, o i file ‘debian/indices/override*.gz’ servono per ricostruire correttamente i
file ‘Packages’.
Il problema nella riproduzione di una distribuzione Debian sta nella creazione dei file
‘Packages’ (e di conseguenza anche ‘Packages.gz’). Per arrivare a questo risultato, occorre
definire una stringa che serva a individuare la distribuzione, per esempio:
Debian GNU/Linux 2.1 slink personalizzata
Accorgimenti per una distribuzione Debian
4007
Inoltre occorre un file override (‘debian/indices/override.gz’ o un altro nome simile), contenente l’abbinamento tra i pacchetti, la priorità e la classificazione in sezioni, come
nell’estratto seguente:
at
cron
locales
ncurses-term
acct
adjtimex
...
adduser
ae
amiga-fdisk
...
lilo
silo
...
newt0.25
ppp
pppconfig
syslinux
...
important
important
standard
standard
optional
optional
admin
admin
admin
admin
admin
admin
required
required
required
base
base
base
important
important
base
base
optional
optional
optional
optional
base
base
base
base
Infine occorrono i pacchetti, che si trovano lì dove sono. I file override vanno prelevati da una
delle varie riproduzioni speculari, tenendo presente che possono essere aggiornati frequentemente. Di solito, questi file sono suddivisi in base ai raggruppamenti principali in cui si articola una
versione: ‘main/’, ‘contrib/’,... Per semplificare le operazioni, può convenire la realizzazione
di un file unico, come è stato mostrato nella struttura di esempio. A questo file si farà riferimento
come ‘override.gz’.1
Disponendo di questo materiale, si può utilizzare ‘dpkg-scanpackages’ per rigenerare i file
‘Packages’. Eventualmente si può vedere la pagina di manuale dpkg-scanpackages(8).
tizio$ cd /home/tizio/DEBIAN/debian
Ci si posiziona nella directory principale della distribuzione.
tizio$ dpkg-scanpackages ←,→-m "Debian GNU/Linux 2.1 slink personalizzata" ←,→dists/stable/main/binary-i386 indices/override.gz ←,→> dists/stable/main/binary-i386/Packages
Si genera il file ‘Packages’ per il gruppo di pacchetti della classificazione ‘main/’ (il comando
è stato mostrato suddiviso su più righe per motivi tipografici).
tizio$ cat dists/stable/main/binary-i386/Packages ←,→| gzip | dists/stable/main/binary-i386/Packages.gz
Si genera il file ‘Packages.gz’, comprimendo ‘Packages’ creato precedentemente.
In seguito, si fa la stessa cosa per i raggruppamenti ‘contrib/’, ‘non-free/’, ‘non-US/’ e
‘local/’.
1
I file override originali della distribuzione ‘slink’ hanno i nomi: ‘override.slink.gz’,
‘override.slink.contrib.gz’, ‘override.slink.non-free.gz’ e ‘override.slink.non-US.gz’. Per
realizzare la propria copia della distribuzione, nulla vieta di fonderli tutti assieme in un file unico, come descritto in
questi esempi, dove si fa riferimento a un solo file ‘override.gz’.
4008
Accorgimenti per una distribuzione Debian
Anche se alcuni di questi raggruppamenti non vengono utilizzati, nel senso che non si vogliono
tenere pacchetti che vi appartengano, è molto importante che siano predisposte le directory
vuote e anche i file ‘Packages*’, per facilitare le operazioni con DSelect e APT.
‘dpkg-scanpackages’ può generare delle segnalazioni di errore, in particolare quando trova
un pacchetto che non è indicato nel file override. In generale questo non provoca conseguenze
gravi, tranne la mancanza di qualche informazione per quel pacchetto.
L’esempio seguente è un estratto di uno dei file ‘Packages’, dove si vede la descrizione del
pacchetto ‘wget’. Si deve osservare in particolare che le informazioni dei campi ‘Priority’
e ‘Section’ sono state determinate in base al file override, mentre la descrizione del campo
‘X-Medium’ è stata ottenuta dall’opzione ‘-m’ di ‘dpkg-scanpackages’.
Package: wget
Version: 1.5.3-1.1
Priority: optional
Section: web
Maintainer: Nicolás Lichtmaier <[email protected]>
Depends: libc6
Architecture: i386
Filename: dists/stable/main/binary-i386/wget_1.5.3-1.1.deb
Size: 221932
MD5sum: 323962a35dabbf88edfe665ad70eb382
Description: utility to retrieve files from the WWW via HTTP and FTP
Wget [formerly known as Geturl] is a freely available network utility
to retrieve files from the World Wide Web using HTTP and FTP, the two
most widely used Internet protocols. It works non-interactively, thus
enabling work in the background, after having logged off.
.
The recursive retrieval of HTML pages, as well as FTP sites is
supported -- you can use Wget to make mirrors of archives and home
pages, or traverse the web like a WWW robot (Wget understands
/robots.txt).
installed-size: 535
X-Medium: Debian GNU/Linux 2.1 slink personalizzata
Per accedere facilmente a questa distribuzione locale, basta configurare APT attraverso il file
‘/etc/apt/sources.list’:
deb file:/home/tizio/DEBIAN/debian stable main contrib non-free non-US local
Se le dimensioni lo consentono, si può trasferire una copia della gerarchia ‘/home/tizio/
DEBIAN/’ in un disco rimovibile, o in un CD-ROM.
356.2.2 Distribuzione suddivisa su diversi supporti
Se si vuole masterizzare un CD-R, o comunque si vuole fare una copia della distribuzione suddividendola in più supporti, le cose si complicano. Per prima cosa si deve iniziare da una copia
locale organizzata già nelle suddivisioni che si vogliono ottenere. Supponendo di partire dalla
directory ‘/home/tizio/DEBIAN/’, conviene aggiungere altre sottodirectory ulteriori, una per
ogni suddivisione che si vuole ottenere: ‘1/’, ‘2/’,...
La struttura della gerarchia che si articola a partire da queste sottodirectory deve essere la stessa,
anche quando alcuni gruppi di pacchetti (‘main/’, ‘contrib/’, ecc.) risultano senza archivi. La
figura 356.2 mostra le varianti rispetto al modello già mostrato.
Accorgimenti per una distribuzione Debian
4009
Figura 356.2. Struttura minima di una distribuzione GNU/Linux Debian organizzata in
modo da utilizzare più supporti.
debian/
|-- .disk/
|
‘-- info
|
|-- local/
|
‘-- local --> ../stable/local
|
|-- dists/
|
|-- stable --> ../codename
|
|
|
‘-- codename /
|
|-- main/
|
|
|
|
|
|-- disks-arch /
|
|
|
‘-- current/
|
|
|
|
|
‘-- binary-arch /
|
|
|-- Packages
|
|
|-- Packages.gz
|
|
|-- Packages.cd
|
|
|-- Packages.cd.gz
|
|
:
|
|
|
|-- contrib/
|
|
:
|
|
|
|-- non-free/
|
|
:
|
|
|
|-- non-US/
|
|
:
|
|
|
‘-- local/
|
:
|
‘-- indices/
‘-- override.gz
Rispetto alla situazione precedente, si aggiunge il file ‘debian/.disk/info’, che deve
contenere la stringa di descrizione del supporto, una cosa del tipo
Debian GNU/Linux 2.1 slink personalizzata disco 1
oppure
Debian GNU/Linux 2.1 slink personalizzata disco 2
ecc., mentre nelle directory ‘debian/dists/stable/*/binary-i386/’ appaiono dei file
nuovi: ‘Packages.cd’ e ‘Packages.cd.gz’. Infine, il raggruppamento di pacchetti ‘local’,
dovrebbe trovarsi nella directory ‘debian/dists/local/local/’. Probabilmente, conviene
realizzare un collegamento simbolico per portarlo nella collocazione normale.
I supporti distinti, vengono riconosciuti in base alla stringa contenuta nel file ‘debian/.disk/
info’, che va scelta opportunamente e va utilizzata anche per la definizione del campo
‘X-Medium’.
Si comincia dalla preparazione dei file ‘Packages’ e ‘Packages.gz’, più o meno come è stato
fatto nella situazione precedente:
tizio$ cd /home/tizio/DEBIAN/1/debian
tizio$ dpkg-scanpackages -m ‘cat .disk/info‘ ←,→dists/stable/main/binary-i386 indices/override.gz ←-
4010
Accorgimenti per una distribuzione Debian
,→> dists/stable/main/binary-i386/Packages
tizio$ cat dists/stable/main/binary-i386/Packages ←,→| gzip | dists/stable/main/binary-i386/Packages.gz
Come prima, si fa la stessa cosa per gli altri gruppi di pacchetti e poi si ripete il procedimento per
la copia contenuta nella directory ‘/home/tizio/DEBIAN/2/’ (si suppone che si tratti di una
suddivisione in due soli supporti):
tizio$ cd /home/tizio/DEBIAN/2/debian
tizio$ dpkg-scanpackages -m ‘cat .disk/info‘ ←,→dists/stable/main/binary-i386 indices/override.gz ←,→> dists/stable/main/binary-i386/Packages
tizio$ cat dists/stable/main/binary-i386/Packages ←,→| gzip | dists/stable/main/binary-i386/Packages.gz
Alla fine, si devono realizzare i file ‘Packages.cd’, che si compongono della somma dei file
‘Packages’ di ogni gruppo:
tizio$ cd /home/tizio/DEBIAN/
tizio$ cat 1/debian/dists/stable/main/binary-i386/Packages ←,→2/debian/dists/stable/main/binary-i386/Packages ←,→> 1/debian/dists/stable/main/binary-i386/Packages.cd
tizio$ cat 1/debian/dists/stable/main/binary-i386/Packages ←,→2/debian/dists/stable/main/binary-i386/Packages ←,→> 2/debian/dists/stable/main/binary-i386/Packages.cd
tizio$ cat 1/debian/dists/stable/main/binary-i386/Packages.cd ←,→| gzip | 1/debian/dists/stable/main/binary-i386/Packages.cd.gz
tizio$ cat 2/debian/dists/stable/main/binary-i386/Packages.cd ←,→| gzip | 2/debian/dists/stable/main/binary-i386/Packages.cd.gz
In pratica, i file ‘Packages.cd’ contengono le informazioni su tutti i pacchetti del proprio gruppo; sia quelli presenti effettivamente nel supporto che quelli che si trovano negli altri. I programmi come DSelect distingueranno il supporto in base al nome che gli è stato attribuito, indicato
nel file ‘debian/.disk/info’ e riportato nel campo ‘X-Medium’ dei file ‘Packages.cd*’.
Per accedere facilmente a questa distribuzione locale, spezzata in due o più parti, basta
configurare APT attraverso il file ‘/etc/apt/sources.list’:
deb file:/home/tizio/DEBIAN/1/debian stable main contrib non-free non-US local
deb file:/home/tizio/DEBIAN/2/debian stable main contrib non-free non-US local
# ...
Per copiare le due strutture in dischi separati, basta trasferire una copia delle gerarchie ‘/home/
tizio/DEBIAN/*/’.
Accorgimenti per una distribuzione Debian
4011
356.3 Riferimenti
• Susan G. Kleinmann, Sven Rudolph, Joost Witteveen, The Debian GNU/Linux FAQ, 1999
<http://ftp.it.debian.org/debian/doc/FAQ/>
• Ian Jackson, Christian Schwarz, Debian Policy Manual, 1998
<http://ftp.it.debian.org/debian/doc/package-developer/policy.txt.gz>
<http://ftp.it.debian.org/debian/doc/package-developer/policy.html.tar.gz>
<http://ftp.it.debian.org/debian/doc/package-developer/policy.pdf.gz>
<http://ftp.it.debian.org/debian/doc/package-developer/policy.ps.gz>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
4012
Accorgimenti per una distribuzione Debian
Parte lxxv
Annotazioni sulla distribuzione
Red Hat
357 Configurazione di una distribuzione Red Hat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4014
357.1 Procedura di inizializzazione del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4014
357.2 Configurazione del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4019
357.3 Configurazione di shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4023
357.4 Utenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4025
357.5 Stampa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4026
358 Accorgimenti per una distribuzione Red Hat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4029
358.1 Gestione dei pacchetti non ufficiali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4029
358.2 Personalizzazione e aggiornamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4034
358.3 Aggiornamento del kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4036
358.4 Aggiornamento manuale di un’installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4037
358.5 Semplificazione della configurazione della rete . . . . . . . . . . . . . . . . . . . . . . . . . . 4039
358.6 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4041
4013
Capitolo
357
Configurazione di una distribuzione Red Hat
La distribuzione Red Hat utilizza un sistema di configurazione composto da script, che non
dovrebbero essere modificati, e da file di configurazione utilizzati dagli script, modificabili
attraverso programmi che guidano l’amministratore.
Il difetto di questo approccio sta nel fatto che non sempre tutto funziona come previsto e allora
occorre mettere le mani sui file, lasciando stare i programmi di configurazione.1
357.1 Procedura di inizializzazione del sistema
La procedura di inizializzazione del sistema è attivata dal’eseguibile ‘init’ attraverso le
indicazioni di ‘/etc/inittab’. I livelli di esecuzione sono:
• 0 arresto del sistema;
• 1 singolo utente;
• 2 multiutente senza l’utilizzo di eventuali NFS;
• 3 multiutente;
• 4 non definito (disponibile);
• 5 multiutente con procedura di accesso grafica;
• 6 riavvio.
Il file ‘/etc/inittab’ è quello che dirige il funzionamento di Init e analizzandone il contenuto
si può intendere il ruolo degli script della procedura di inizializzazione del sistema.
# Default runlevel. The runlevels used by RHS are:
#
0 - halt (Do NOT set initdefault to this)
#
1 - Single user mode
#
2 - Multiuser, without NFS (The same as 3, if you do not have networking)
#
3 - Full multiuser mode
#
4 - unused
#
5 - X11
#
6 - reboot (Do NOT set initdefault to this)
#
id:3:initdefault:
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc
l1:1:wait:/etc/rc.d/rc
l2:2:wait:/etc/rc.d/rc
l3:3:wait:/etc/rc.d/rc
l4:4:wait:/etc/rc.d/rc
l5:5:wait:/etc/rc.d/rc
l6:6:wait:/etc/rc.d/rc
0
1
2
3
4
5
6
# Things to run in every runlevel.
ud::once:/sbin/update
# Trap CTRL-ALT-DELETE
1
Le notizie che si raccolgono qui, sono riferite a vecchie edizioni della distribuzione. Queste informazioni, benché
obsolete, vengono conservate perché potrebbero ancora essere utili.
4014
Configurazione di una distribuzione Red Hat
4015
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powerd installed and your
# UPS connected and working correctly.
pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"
# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
# Run gettys in standard runlevels
1:12345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
# Run xdm in runlevel 5
x:5:respawn:/usr/bin/X11/xdm -nodaemon
357.1.1 Collegamento tra i vari componenti della procedura di
inizializzazione del sistema
Attraverso il file ‘/etc/inittab’ vengono indicati due script fondamentali, attraverso cui si
articola la procedura di inizializzazione del sistema. Si tratta di ‘/etc/rc.d/rc.sysinit’ e
‘/etc/rc.d/rc’. Il primo viene utilizzato a ogni avvio del sistema e da questo dipendono le
operazioni che vanno svolte una volta sola in quella occasione; il secondo serve ogni volta che si
cambia il livello di esecuzione.
• ‘/etc/rc.d/’
È la directory che raccoglie gli script utilizzati nella fase di avvio del sistema e in quella di
arresto.
• ‘/etc/rc.d/rc.sysinit’
È lo script di inizializzazione del sistema. In particolare:
– attiva la gestione della memoria virtuale per l’uso delle aree di scambio previste nelle
partizioni, in base al contenuto del file ‘/etc/fstab’;
– verifica il file system principale e al termine ne esegue il montaggio;
– verifica la dipendenza dei moduli;
– avvia ‘kerneld’ per automatizzare il caricamento dei moduli del kernel;
– verifica gli altri file system indicati per questo nel file ‘/etc/fstab’ e al termine ne
esegue il montaggio;
– elimina o ripulisce i file utilizzati nella sessione di lavoro precedente, che servivano
per segnalare lo stato di funzionamento;
– configura l’orologio del sistema;
– attiva la gestione della memoria virtuale per l’uso delle aree di scambio previste sui
file;
– eventualmente esegue ‘/etc/rc.d/rc.serial’ per l’attivazione della porta seriale;
– eventualmente esegue ‘/etc/rc.d/rc.modules’ per l’attivazione di moduli del
kernel.
Configurazione di una distribuzione Red Hat
4016
• ‘/etc/rc.d/rc’
È lo script principale per il controllo dei livelli di esecuzione. Viene utilizzato da Init,
attraverso le indicazioni di ‘/etc/inittab’, con un argomento corrispondente al numero
di livello di esecuzione da attivare.
/etc/rc.d/rc livello_di_esecuzione
Semplificando un po’ le cose, ‘/etc/rc.d/rc’ si limita a determinare se è stato richiesto un cambiamento nel livello di esecuzione, quindi avvia tutti gli script che trova nella
directory ‘/etc/rc.d/rcn .d/’ (dove n rappresenta il livello di esecuzione richiesto), cominciando da quelli che iniziano con la lettera ‘K’ e terminando con quelli che iniziano con
la lettera ‘S’.
In realtà, questi script sono contenuti nella directory ‘/etc/rc.d/init.d/’, con nomi
più espressivi, mentre nelle directory ‘/etc/rc.d/rcn .d/’ sono contenuti solo dei collegamenti simbolici con nomi scelti appositamente per definire l’ordine in cui le operazioni
devono essere svolte.
In questo modo, è possibile definire il livello di esecuzione numero quattro, lasciato a disposizione, semplicemente copiandovi all’interno i collegamenti simbolici necessari e senza
toccare alcuno script.
• ‘/etc/rc.d/rcn .d/’
Come accennato, si tratta delle directory riferite a ogni livello di esecuzione (n rappresenta
il numero del livello stesso). Al loro interno si trovano solo collegamenti simbolici riferiti
agli script che si vuole siano eseguiti.
Quando viene selezionato il livello di esecuzione relativo, vengono eseguiti in ordine alfabetico, prima gli script (o meglio i collegamenti) che iniziano con la lettera ‘K’ (Kill) nella
forma
/etc/rc.d/rcn .d/script stop
allo scopo di disattivare il servizio particolare cui si riferiscono, quindi quelli che iniziano
con la lettera ‘S’ (Start), nella forma seguente:
/etc/rc.d/rcn .d/script start
• ‘/etc/rc.d/init.d/’
È il vero contenitore degli script utilizzati dalla procedura di inizializzazione del sistema.
Questi vengono utilizzati indirettamente attraverso collegamenti simbolici contenuti nelle
directory ‘/etc/rc.d/rcn .d/’. Molti di questi script caricano le informazioni contenute
in file di configurazione collocati altrove e ciò rappresenta la base del sistema di configurazione della distribuzione Red Hat, perché permette di limitarsi alla modifica di questi file,
invece che intervenire direttamente sugli script stessi.
Molti di questi script possono essere utilizzati dall’amministratore per disattivare o attivare
un servizio particolare, senza dover utilizzare un livello di esecuzione diverso e senza dover
ricordare tutte le implicazioni di un particolare servizio. Il formato generale è il seguente:
/etc/rc.d/init.d/servizio
{start|stop|status}
• ‘/etc/rc.d/init.d/functions’
Si tratta di uno script utilizzato da quasi tutti gli altri, per definire alcune funzioni standard.
In particolare, queste funzioni, servono per evitare l’avvio di demoni già in funzione e
comunque per uniformare il sistema di avvio e conclusione del loro funzionamento.
– ‘pidofproc’
Restituisce attraverso lo standard output i numeri PID abbinati a processi con il nome
fornito. Per questo, tenta inizialmente di utilizzare il programma ‘pidof’; se fallisce,
Configurazione di una distribuzione Red Hat
4017
analizza quanto contenuto nella directory ‘/var/run/’; come ultima risorsa tenta di
analizzare il risultato dell’esecuzione di ‘ps’.
– ‘daemon’
Avvia un programma dopo aver verificato che non sia già in funzione, restituendo
attraverso lo standard output il nome di questo, senza l’eventuale percorso di avvio.
– ‘killproc’
Elimina un processo utilizzando la funzione ‘pidofproc’ per determinare il suo
numero PID. Restituisce attraverso lo standard output il nome del processo eliminato.
– ‘status’
Restituisce, attraverso lo standard output, lo stato del servizio corrispondente.
• ‘/var/lock/subsys/’
Questa directory viene utilizzata dagli script contenuti in ‘/etc/rc.d/init.d/’ per annotare la presenza in funzione di un servizio determinato: se esiste un file (vuoto) con quel
nome, il servizio è considerato attivo.
357.1.2 /etc/rc.d/init.d/*
I file contenuti nella directory ‘/etc/rc.d/init.d/’, quando si riferiscono a dei servizi, hanno
una struttura abbastanza comune, simile a quella seguente. Si fa riferimento all’ipotetico servizio
«pippo», a cui corrisponde un demone con lo stesso nome.
#!/bin/sh
#
# chkconfig: 345 85 15
# description: Servizio Pippo. Si tratta di un servizio che non serve \
#
a nulla e non interessa a nessuno.
#
# Caricamento delle funzioni standard.
. /etc/rc.d/init.d/functions
# Analisi dell’argomento usato nella chiamata.
case "$1" in
start)
echo -n "Avvio del servizio Pippo: "
daemon pippo
echo
touch /var/lock/subsys/pippo
;;
stop)
echo -n "Spegnimento del servizio Pippo: "
killproc pippo
rm -f /var/lock/subsys/pippo
echo
;;
status)
status pippo
;;
restart)
killall -HUP pippo
;;
*)
echo "Usage: pippo {start|stop|restart|status}"
exit 1
esac
exit 0
Configurazione di una distribuzione Red Hat
4018
Nella prima parte viene letto il contenuto del file contenente la definizione delle funzioni standard, quindi si analizza il primo argomento fornito allo script. Se era ‘start’ si provvede ad
avviare uno o più programmi attraverso la funzione ‘daemon’, quindi si segnala il fatto creando
un file vuoto (con ‘touch’) nella directory ‘/var/lock/subsys/’. Se l’argomento era ‘stop’
si provvede a eliminare i processi relativi, normalmente attraverso la funzione ‘killproc’,
quindi si elimina il file corrispondente nella directory ‘/var/lock/subsys’. Se l’argomento
era ‘status’ si visualizza lo stato del servizio attraverso la funzione ‘status’. Infine, se l’argomento era ‘restart’, di solito si invia un segnale ‘SIGHUP’ al processo corrispondente al
servizio.
In questi script, alcuni commenti introduttivi hanno un ruolo preciso: servono a definire i livelli
di esecuzione con cui questi vengono presi in considerazione, il momento in cui devono essere
avviati i servizi relativi e il momento in cui devono essere chiusi gli stessi servizi. Nell’esempio
mostrato si tratta del pezzo seguente:
# chkconfig: 345 85 15
# description: Servizio Pippo. Si tratta di un servizio che non serve \
#
a nulla e non interessa a nessuno.
La riga ‘# chkconfig 345 85 15’, serve a stabilire che il servizio corrispondente può essere
avviato solo quando il livello di esecuzione va da tre a cinque. Il numero 85 successivo, indica
l’ordine nell’avvio del servizio e, dato il numero, si intuisce che si vuole fare in modo che questo
avvenga dopo molti altri. Il numero 15 finale, indica l’ordine di disattivazione del servizio in fase
di arresto del sistema; si intende dal numero che si vuole fare in modo di chiuderlo abbastanza
presto rispetto agli altri. Verrà chiarito meglio nella prossima sezione il senso di questi numeri.
La riga ‘# description:’ serve ad annotare una descrizione del servizio, come promemoria
per facilitare l’utilizzo del programma ‘ntsysv’, che sarà mostrato successivamente. Per il momento, si osservi che la descrizione può continuare su più righe di commento, purché si utilizzi
il simbolo ‘\’ subito prima della conclusione della riga.
357.1.3 /etc/rc.d/rc?.d/
Le directory ‘/etc/rc.d/rcn .d/’ servono a contenere una serie di collegamenti simbolici che
puntano a script della directory ‘/etc/rc.d/init.d’. Il listato seguente dovrebbe chiarire il
meccanismo.
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
lrwxrwxrwx
1
1
1
1
1
1
1
1
1
1
1
1
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
13
13
15
16
17
17
15
16
16
14
18
11
13:39
13:39
13:39
13:39
13:39
13:39
13:39
13:39
13:39
13:39
13:39
12:44
K15gpm -> ../init.d/gpm
K60atd -> ../init.d/atd
K60crond -> ../init.d/crond
K96pcmcia -> ../init.d/pcmcia
S01kerneld -> ../init.d/kerneld
S10network -> ../init.d/network
S15nfsfs -> ../init.d/nfsfs
S20random -> ../init.d/random
S30syslog -> ../init.d/syslog
S50inet -> ../init.d/inet
S75keytable -> ../init.d/keytable
S99local -> ../rc.local
I collegamenti che iniziano con la lettera «S» vengono avviati ordinatamente all’attivazione del
livello di esecuzione corrispondente, con l’argomento ‘start’, mentre quelli che iniziano con la
lettera «K» vengono avviati prima di passare a un nuovo livello di esecuzione, con l’argomento
‘stop’.
Il numero che segue la lettera «S» e «K», serve a definire un ordine (alfabetico) corrispondente a
quello in cui i servizi vanno avviati o interrotti. Se si volesse predisporre uno script, nella directory ‘/etc/rc.d/init.d/’ per la gestione di un servizio addizionale, si dovrebbero predisporre
Configurazione di una distribuzione Red Hat
4019
due collegamenti nella directory del livello di esecuzione prescelto, simili a quelli già visti, con
un numero adatto a collocarli nella posizione giusta nell’ordine delle azioni da compiere.
Si osservi la presenza del collegamento ‘S99local’ che punta allo script ‘/etc/rc.d/
rc.local’. Si tratta di un’anomalia nella logica generale, dal momento che si fa riferimento
a qualcosa di esterno alla directory ‘/etc/rc.d/init.d/’. Il numero, 99, è obbligatorio, dal
momento che l’esecuzione di questo deve avvenire alla fine dell’avvio di tutti gli altri servizi.
357.1.4 # ntsysv e chkconfig
Attraverso il programma ‘ntsysv’, è possibile aggiungere o togliere servizi da attivare nel livello
di esecuzione standard. ‘ntsysv’ provvede da solo a creare i collegamenti simbolici mostrati
nella sezione precedente, utilizzando la convenzione mostrata. Per stabilire il numero da usare
per i collegamenti di avvio (quelli che iniziano con la lettera ‘S’) e per quelli di conclusione (‘K’),
si avvale del commento iniziale contenuto negli script originali.
Per riprendere l’esempio già mostrato in precedenza, se nella directory ‘/etc/rc.d/init.d/’
si trova lo script ‘pippo’, che contiene il commento iniziale seguente,
#! /bin/sh
#
# chkconfig: 345 85 15
# description: Servizio Pippo. Si tratta di un servizio che non serve \
#
a nulla e non interessa a nessuno.
‘ntsysv’ sarà in grado di creare i collegamenti ‘S85pippo’ e ‘K15pippo’. La descrizione, inol-
tre, è utile per ricordare a cosa serve questo servizio (o comunque a cosa serve questo script),
quando è il momento di scegliere se attivarlo o meno.
Il programma ‘chkconfig’ serve fondamentalmente alle stesse funzioni di ‘ntsysv’, con la
differenza che si tratta di un programma a riga di comando, mentre il secondo è interattivo e
utilizza una maschera visiva piuttosto amichevole.
357.2 Configurazione del sistema
La maggior parte dei file di configurazione della distribuzione Red Hat si trova nella directory ‘/etc/sysconfig’. I nomi dei file permettono di capire, intuitivamente, il genere di
cose che con essi si intendono configurare. In particolare, la directory ‘/etc/sysconfig/
network-scripts/’ contiene una serie di script e di altri file necessari a facilitare la gestione
delle interfacce di rete e degli instradamenti.
357.2.1 Configurazione della rete
L’organizzazione dei file di configurazione e degli script per la connessione in rete è un po’
complicata, per permetterne il controllo attraverso il pannello di controllo, o più precisamente,
attraverso ‘netcfg’.
Configurazione di una distribuzione Red Hat
4020
357.2.1.1 /etc/sysconfig/network
Si tratta del file contenente le informazioni fondamentali sulla connessione alla rete:
• attivazione o meno della rete;
• nome completo dell’elaboratore;
• nome del dominio;
• router (gateway) predefinito;
• interfaccia di rete che porta verso il router predefinito.
Come al solito si utilizza la semplificazione per cui l’elaboratore ha un solo nome e un solo
dominio di appartenenza, anche se ha più interfacce di rete (e quindi più nomi e più domini).
Evidentemente, se ci sono più interfacce, si deve scegliere un nome e un dominio.
Alcune direttive
{ | }
NETWORKING= yes no
Permette di attivare (‘yes’) o di disattivare (‘no’) la configurazione delle rete.
HOSTNAME=nome_fqdn
Il nome completo (FQDN) dell’elaboratore, possibilmente quello corrispondente a un’interfaccia di rete realmente esistente. Il file ‘/etc/HOSTNAME’, generato normalmente in
modo automatico, dovrebbe contenere questo nome.
DOMAINNAME=dominio
Permette di definire il nome del dominio dell’elaboratore. In pratica, si può riferire solo a
un dominio di un’interfaccia di rete particolare.
{ | }
FORWARD_IPV4= yes no
Permette di attivare (‘yes’) o di disattivare (‘no’) l’inoltro IP. Perché l’elaboratore possa
funzionare come router, è indispensabile che questa funzione sia attivata, mentre, per motivi
di sicurezza, il valore predefinito è ‘no’.
GATEWAY=indirizzo_ip_del_router_predefinito
Permette di definire l’indirizzo IP di un router per l’instradamento predefinito, cioè quel
router da utilizzare quando si vuole inoltrare un pacchetto verso un indirizzo per il quale
non esista già un instradamento specifico.
GATEWAYDEV=interfaccia_di_rete
Permette di indicare esplicitamente il nome dell’interfaccia di rete da utilizzare per
l’instradamento predefinito.
NISDOMAIN=dominio_nis
Permette di definire il dominio NIS a cui appartiene l’elaboratore.
Esempi
L’esempio
seguente
si
riferisce
alla
configurazione
dell’elaboratore
portatile.plip.dg. In particolare, si utilizza un router che ha indirizzo IP
192.168.254.254, raggiungibile attraverso l’interfaccia ‘plip1’.
NETWORKING=yes
FORWARD_IPV4=false
HOSTNAME=portatile.plip.dg
DOMAINNAME=plip.dg
GATEWAY=192.168.254.254
GATEWAYDEV=plip1
Configurazione di una distribuzione Red Hat
4021
357.2.1.2 /etc/sysconfig/static-routes
Si tratta della definizione degli instradamenti statici, cioè quelli che non cambiano. Riguarda
sia gli instradamenti alle reti accessibili direttamente che a quelle raggiungibili solo attraverso
un router. L’esempio seguente dovrebbe essere abbastanza chiaro: la prima riga definisce un
instradamento alla rete locale, le altre due definiscono gli instradamenti verso altre reti accessibili
attraverso il router 192.168.1.254.
eth0 net 192.168.1.0 netmask 255.255.255.0
eth0 net 192.168.2.0 netmask 255.255.255.0 gw 192.168.1.254
eth0 net 192.168.3.0 netmask 255.255.255.0 gw 192.168.1.254
357.2.1.3 /etc/sysconfig/network-scripts/ifcfg-*
Per ogni interfaccia di rete gestita, appare un file di configurazione con il nome
‘ifcfg-interfaccia ’ nella directory ‘/etc/sysconfig/network-scripts/’. Questi file
contengono informazioni differenti in funzione del tipo di interfaccia.
Alcune direttive
DEVICE=interfaccia
Definisce il nome dell’interfaccia di rete corrispondente.
IPADDR=indirizzo_ip
L’indirizzo IP dell’interfaccia.
NETMASK=maschera_di_rete
La maschera di rete.
NETWORK=indirizzo_di_rete
Indirizzo della rete.
BROADCAST=indirizzo_broadcast
Indirizzo broadcast.
{ | }
ONBOOT= yes no
Permette di attivare (‘yes’), o di disattivare (‘no’), l’interfaccia all’avvio del sistema.
Esempi
L’esempio seguente si riferisce alla configurazione dell’interfaccia ‘lo’, praticamente
obbligatoria, corrispondente al file ‘/etc/sysconfig/network-scripts/ifcfg-lo’.
DEVICE=lo
IPADDR=127.0.0.1
NETMASK=255.0.0.0
NETWORK=127.0.0.0
BROADCAST=127.255.255.255
ONBOOT=yes
L’esempio seguente si riferisce alla configurazione dell’interfaccia ‘eth0’ con un indirizzo
IP 192.168.1.1 e la maschera di rete 255.255.255.0.
DEVICE=eth0
IPADDR=192.168.1.1
NETMASK=255.255.255.0
NETWORK=192.168.1.0
BROADCAST=192.168.1.255
ONBOOT=yes
BOOTPROTO=none
Configurazione di una distribuzione Red Hat
4022
357.2.2 Configurazione di altri elementi
Il resto della configurazione è gestito attraverso file contenuti esclusivamente nella directory
‘/etc/sysconfig/’.
357.2.2.1 /etc/sysconfig/clock
Il file ‘/etc/sysconfig/clock’ permette di configurare l’orologio del sistema. Per farlo, si
deve conoscere come è impostato l’orologio hardware. In pratica, è importante sapere se questo è
allineato al tempo universale oppure all’ora locale. Eventualmente può essere usato il programma
‘timeconfig’ per definire correttamente questo file.
Alcune direttive
{
|
}
UTC= true false
Se viene utilizzato il valore ‘true’, si intende che l’orologio hardware sia allineato al tempo
universale; diversamente, si intende che sia allineato all’ora locale.
357.2.2.2 /etc/sysconfig/keyboard
Il file ‘/etc/sysconfig/keyboard’ permette di configurare la tastiera. Eventualmente può
essere usato il programma ‘kbdconfig’ per definire correttamente questo file.
Alcune direttive
KEYTABLE=mappa_tastiera
Definisce la mappa della tastiera, indicando il file corrispondente.
Esempi
KEYTABLE="/usr/share/keymaps/i386/qwerty/it.kmap"
Definisce la configurazione della tastiera italiana.
KEYTABLE=it.kmap
Esattamente come nell’esempio precedente, senza il problema di dover indicare tutto il
percorso per raggiungere il file, dal momento che si tratta di quello predefinito.
357.2.2.3 /etc/sysconfig/mouse
Il file ‘/etc/sysconfig/mouse’ permette di configurare il mouse per l’utilizzo attraverso il
programma ‘gpm’. Eventualmente può essere usato il programma ‘mouseconfig’ per definire
correttamente questo file.
Alcune direttive
MOUSETYPE=tipo
Permette di definire il tipo di mouse utilizzato. Sono validi i nomi seguenti.
• ‘microsoft’
• ‘mouseman’
• ‘mousesystems’
Configurazione di una distribuzione Red Hat
•
•
•
•
•
•
•
4023
‘ps/2’
‘msbm’
‘logibm’
‘atibm’
‘logitech’
‘mmseries’
‘mmhittab’
{ | }
XEMU3= yes no
Abilita o disabilita l’emulazione del tasto centrale.
Esempi
L’esempio seguente rappresenta la configurazione per un mouse compatibile con il tipo
Microsoft a due tasti, per cui il terzo deve essere emulato.
MOUSETYPE="Microsoft"
XEMU3=yes
357.3 Configurazione di shell
Anche la configurazione della shell è molto importante per il sistema, risultando relativamente
complessa.
357.3.1 Bash
• ‘/etc/profile’
Si tratta del file di configurazione generale, secondo lo standard, ma è organizzato in modo da permettere l’inserimento di altri segmenti, senza toccarlo. Infatti, alla fine vengono caricati tutti i file che si trovano nella directory ‘/etc/profile.d/’ e terminano con
l’estensione ‘.sh’.
# /etc/profile
# System wide environment and startup programs
# Functions and aliases go in /etc/bashrc
PATH="$PATH:/usr/X11R6/bin"
PS1="[\u@\h \W]\\$ "
ulimit -c 1000000
if [ ‘id -gn‘ = ‘id -un‘ -a ‘id -u‘ -gt 14 ]; then
umask 002
else
umask 022
fi
USER=‘id -un‘
LOGNAME=$USER
MAIL="/var/mail/$USER"
HOSTNAME=‘/bin/hostname‘
HISTSIZE=1000
HISTFILESIZE=1000
export PATH PS1 HOSTNAME HISTSIZE HISTFILESIZE USER LOGNAME MAIL
for i in /etc/profile.d/*.sh ; do
if [ -x $i ]; then
. $i
fi
done
Configurazione di una distribuzione Red Hat
4024
• ‘/etc/bashrc’
Secondo le intenzioni di chi ha organizzato la distribuzione, questo file dovrebbe contenere
solo la definizione di funzioni e di alias di interesse generale, ma il suo utilizzo dipende dalla configurazione personalizzata di ogni utente, che potrebbe anche escludere l’inclusione
di questo file.
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
# For some unknown reason bash refuses to inherit
# PS1 in some circumstances that I can’t figure out.
# Putting PS1 here ensures that it gets loaded every time.
PS1="[\u@\h \W]\\$ "
alias which="type -path"
Per qualche motivo, il file ‘/etc/bashrc’ fornito con la distribuzione contiene la definizione della variabile ‘PS1’, che va a sovrapporsi a quanto già indicato nel file di configurazione
generale, ‘/etc/profile’. Se si intende modificare l’aspetto predefinito dell’invito della
shell, conviene agire in questo file.
Potrebbe essere conveniente definire, per tutti gli utenti, una serie di alias ai comandi più
«pericolosi», trasformando quindi il file nel modo seguente (la dichiarazione della variabile
‘PS1’ viene commentata).
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
## For some unknown reason bash refuses to inherit
## PS1 in some circumstances that I can’t figure out.
## Putting PS1 here ensures that it gets loaded every time.
#PS1="[\u@\h \W]\\$ "
alias which="type -path"
alias rm=’rm -i’
alias cp=’cp -i’
alias mv=’mv -i’
• ‘~/.bashrc’
È il file di configurazione di una shell Bash interattiva. Secondo le intenzioni di chi ha
organizzato la distribuzione, questo file dovrebbe contenere solo la definizione di funzioni
e di alias personalizzati, dove alla fine dovrebbe richiamare il file ‘/etc/bashrc’ che
contiene le stesse cose, ma a livello generale.
# .bashrc
# User specific aliases and functions
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
• ‘~/.bash_profile’
È il file di configurazione utilizzato dalla shell Bash quando questa viene avviata a seguito
di un accesso. Per mantenere uniformità con l’insieme, esegue a sua volta il contenuto di
‘~/.bashrc’
# .bash_profile
# Get the aliases and functions
Configurazione di una distribuzione Red Hat
4025
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
ENV=$HOME/.bashrc
USERNAME=""
export USERNAME ENV PATH
357.3.1.1 Configurazione aggiuntiva
La directory ‘/etc/profile.d/’ viene usata per contenere una serie di file da inserire ordinatamente alla fine di ‘/etc/profile’. Attraverso questo meccanismo, l’installazione di un
programma può definire un’aggiunta nella configurazione della shell senza dover modificare il
file ‘/etc/profile’.
I file in questione, devono terminare con l’estensione ‘.sh’, non serve che siano eseguibili e
nemmeno che inizino con la definizione della shell che deve interpretarli. L’esempio seguente
mostra uno di questi file con la definizione di alcune variabili utili.
# /etc/profile.d/config.sh
LANG="it_IT.ISO-8859-1"
export LANG
PATH="$PATH:$HOME/bin:."
export PATH
PS1=’\u@\h:\w\$ ’
export PS1
alias rm=’rm -i’
alias cp=’cp -i’
alias mv=’mv -i’
Nell’esempio viene definita la variabile ‘LANG’, nel modo corretto per l’Italia, quindi vengono aggiunte al percorso di ricerca degli eseguibili, la directory ‘~/bin’ e la directory corrente.
Successivamente, viene definita la variabile ‘PS1’ (l’invito della shell) e una serie di alias.
In precedenza si è visto che la distribuzione Red Hat indica il file ‘/etc/bashrc’ come il contenitore adatto per la definizione dell’invito e degli alias. Dipende dal gusto dell’amministratore
del sistema la scelta di come intervenire.
357.4 Utenti
Utenti e gruppi vengono gestiti in modo differente dal solito: si tende ad abbinare a ogni utente
un gruppo con lo stesso nome e lo stesso numero. Questa tecnica permette di lasciare al gruppo
gli stessi permessi dell’utente, facilitando la creazione e lo scioglimento di gruppi di lavoro con
la semplice creazione di gruppi nuovi a cui si abbinano gli utenti che ne fanno parte. Questo
viene descritto un po’ meglio nella sezione 54.5.4.
In queste condizioni, la maschera dei permessi utilizzata normalmente è 0028.
È il caso di osservare che l’utente e il gruppo ‘nobody’ hanno il numero 99.
Lo script ‘useradd’ inserisce gli utenti a partire dal numero 500 in poi, aggregando a ognuno un
gruppo privato.
4026
Configurazione di una distribuzione Red Hat
357.4.1 /etc/passwd
root::0:0:root:/root:/bin/bash
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
adm:*:3:4:adm:/var/adm:
lp:*:4:7:lp:/var/spool/lpd:
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/mail:
news:*:9:13:news:/var/spool/news:
uucp:*:10:14:uucp:/var/spool/uucp:
operator:*:11:0:operator:/root:
games:*:12:100:games:/usr/games:
gopher:*:13:30:gopher:/usr/lib/gopher-data:
ftp:*:14:50:FTP User:/home/ftp:
nobody:*:99:99:Nobody:/:
357.4.2 /etc/group
root::0:root
bin::1:root,bin,daemon
daemon::2:root,bin,daemon
sys::3:root,bin,adm
adm::4:root,adm,daemon
tty::5:
disk::6:root
lp::7:daemon,lp
mem::8:
kmem::9:
wheel::10:root
mail::12:mail
news::13:news
uucp::14:uucp,root
man::15:
games::20:
gopher::30:
dip::40:
ftp::50:
nobody::99:
users::100:
357.5 Stampa
Il sistema di stampa adottato da Red Hat è quello tradizionale, cioè BSD. Le directory delle code,
riferite ad altrettante voci del file ‘/etc/printcap’, si diramano a partire da ‘/var/spool/
lpd/’. Ognuna di queste contiene il filtro di stampa (se viene utilizzato) e i file di configurazione
utilizzati dal filtro.
Tutto questo, compreso il file ‘/etc/printcap’, è gestito direttamente dal programma di
configurazione della stampa, ‘printtool’.
Configurazione di una distribuzione Red Hat
4027
357.5.1 /var/spool/lpd/*/
All’interno della directory per la coda di stampa si trovano, oltre ai file utilizzati da ‘lpr’ e ‘lpd’,
anche lo script usato come filtro e i relativi file di configurazione.
• ‘filter’
È il filtro che fa riferimento a diversi componenti collocati sotto ‘/usr/lib/rhs/
rhs-printfilters/’.
• ‘general.cfg’
È un file di configurazione generale della stampa. Segue un esempio nel quale si fa
riferimento a:
– stampante locale;
– sistema di stampa PostScript (attraverso un filtro);
– foglio A4;
– file ASCII trasformati in PostScript.
#
# General config options for printing on this queue
# Generated by PRINTTOOL, do not modify.
#
export DESIRED_TO=ps
export PAPERSIZE=a4
export PRINTER_TYPE=LOCAL
export ASCII_TO_PS=YES
• ‘postscript.cfg’
È un file di configurazione per l’emulazione della stampa PostScript. Segue un esempio nel
quale si fa riferimento a:
– stampante compatibile con HP Laserjet;
– risoluzione 300×300 dpi;
– foglio A4.
#
# configuration related to postscript printing
# generated automatically by PRINTTOOL
# manual changes to this file may be lost
#
GSDEVICE=laserjet
RESOLUTION=300x300
COLOR=
PAPERSIZE=a4
EXTRA_GS_OPTIONS=""
REVERSE_ORDER=
PS_SEND_EOF=NO
#
# following is related to printing multiple pages per output page
#
NUP=1
RTLFTMAR=18
TOPBOTMAR=18
• ‘textonly.cfg’
È un file di configurazione della stampa di solo testo. Segue un esempio, nel quale si fa
riferimento, in particolare, alla trasformazione dei codici di interruzione di riga in modo
che corrispondano sempre a <CR><LF>.
Configurazione di una distribuzione Red Hat
4028
#
# text-only printing options for printing on this queue
# Generated by PRINTTOOL, do not modify.
#
TEXTONLYOPTIONS=
CRLFTRANS=1
TEXT_SEND_EOF=YES
357.5.2 /etc/printcap
Dal momento che la stampa è organizzata attraverso questo sistema di filtri, controllato da
‘printtool’, sarebbe meglio non modificare il file standard ‘/etc/printcap’, o almeno
limitarsi a utilizzare le sole caratteristiche che ‘printtool’ può gestire.
#
#
#
#
#
#
#
/etc/printcap
Please don’t edit this file directly unless you know what you are doing!
Be warned that the control-panel printtool requires a very strict format!
Look at the printcap(5) man page for more info.
This file can be edited with the printtool in the control-panel.
##PRINTTOOL3## LOCAL laserjet 300x300 a4 {} LaserJet Default {}
lp:\
:sd=/var/spool/lpd/lp:\
:mx#0:\
:sh:\
:lp=/dev/lp1:\
:if=/var/spool/lpd/lp/filter:
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
358
Accorgimenti per una distribuzione Red Hat
Ogni distribuzione ha i suoi limiti; a volte dei piccoli accorgimenti possono risolvere problemi
importanti.
358.1 Gestione dei pacchetti non ufficiali
La Red Hat, come azienda, produce una distribuzione GNU/Linux limitata a un certo numero di
applicativi, quelli che è in grado di seguire e garantire in base al personale a sua disposizione.
Naturalmente, questo è il limite comune delle distribuzioni GNU/Linux commerciali.
Tutti i pacchetti assemblati all’esterno dell’azienda, vengono «relegati» all’area dei contributi
(‘contrib/’) e, spesso, di questi programmi non si può fare a meno.
Se non si ha un accesso permanente a Internet, diventa utile conservare da qualche parte questi
programmi che non fanno parte della distribuzione standard. Si pone però un problema nel momento in cui si viene in possesso di un CD-ROM contenente parte di questi contributi, che si
ritiene essere aggiornato. Infatti, tale CD-ROM non li può contenere tutti e se si eliminano quelli
conservati precedentemente si rischia di perdere qualcosa che serve; inoltre, se si mescolano i
file, si rischia di avere due o tre versioni diverse di uno stesso pacchetto.
Con un po’ di abilità si può realizzare un programmino che analizza una directory, cerca di
identificare i pacchetti uguali ed elimina quelli delle versioni più vecchie.
358.1.1 Composizione del nome dei pacchetti RPM
Il nome dei pacchetti RPM è organizzato secondo la struttura seguente:
nome_dell’applicativo -versione -rilascio.architettura .rpm
In pratica, dopo il nome dell’applicativo segue un trattino e quindi l’indicazione della versione,
quindi ancora un trattino e poi il rilascio, ovvero la versione riferita alla trasformazione in un
pacchetto RPM. Nella parte finale, dopo un punto di separazione, appare la sigla dell’architettura
e l’estensione ‘.rpm’. L’esempio seguente mostra il nome del pacchetto contenente il kernel
generico e i moduli precompilati per la versione 2.0.34, rilascio 1, per l’architettura i386.
kernel-2.0.34-1.i386.rpm
Volendo confrontare i nomi di file di versioni differenti, occorre estrapolare la versione e il rilascio. Nella migliore delle ipotesi, la versione è composta da una serie di numeri separati da un
punto, dove il primo numero è quello più significativo; nello stesso modo può essere organizzato
il rilascio. Il problema si pone quando la versione o il rilascio contengono dei dati alfabetici:
diventa impossibile determinare a priori il modo corretto di confronto.
358.1.2 Programma per l’eliminazione dei file RPM doppi
Quello che segue è uno script scritto in Perl per la scansione di una directory, quella corrente nel
momento in cui si avvia, allo scopo di eliminare i file corrispondenti a pacchetti già esistenti in
versioni più recenti.
#!/usr/bin/perl
#======================================================================
# rpmdoppi
#
# Interviene nella directory *corrente* eliminando i file doppi,
4029
Accorgimenti per una distribuzione Red Hat
4030
# più vecchi.
#======================================================================
$file0 = "";
$file1 = "";
$nome0 = "";
$nome1 = "";
$versione0 = "";
$versione1 = "";
$rilascio0 = "";
$rilascio1 = "";
$architettura0 = "";
$architettura1 = "";
$verA0
$verA1
$verB0
$verB1
$verC0
$verC1
$verD0
$verD1
$verE0
$verE1
$verF0
$verF1
=
=
=
=
=
=
=
=
=
=
=
=
"";
"";
"";
"";
"";
"";
"";
"";
"";
"";
"";
"";
#---------------------------------------------------------------------# Carica l’elenco dei file dalla directory corrente.
#---------------------------------------------------------------------open ( ELENCO, "ls *.rpm | sort |" );
#---------------------------------------------------------------------# Scandisce nome per nome.
#---------------------------------------------------------------------while ( $file1 = <ELENCO> ) {
#-----------------------------------------------------------------# Estrae gli elementi che compongono il nome del file.
#-----------------------------------------------------------------$file1 =~ m{^(.*)-([^-]*)-([^-]*)\.([^._-]*)\.rpm};
#-----------------------------------------------------------------# Distribuisce i vari pezzi a variabili più comprensibili.
#-----------------------------------------------------------------$nome1 = $1;
$versione1 = $2;
$rilascio1 = $3;
$architettura1 = $4;
#-----------------------------------------------------------------# Verifica se i nomi sono comparabili.
#-----------------------------------------------------------------if ( $nome1 eq $nome0 ) {
if ( $architettura1 eq $architettura0 ) {
#---------------------------------------------------------# Ok, i nomi sono comparabili.
#---------------------------------------------------------;
} else {
Accorgimenti per una distribuzione Red Hat
#---------------------------------------------------------# Le architetture sono differenti.
#---------------------------------------------------------print "Attenzione all’architettura:\n";
print "
$file0";
print "
$file1";
#---------------------------------------------------------# Riprende il ciclo.
#---------------------------------------------------------next;
}
} else {
#-------------------------------------------------------------# I nomi sono differenti, quindi ripete il ciclo.
#-------------------------------------------------------------next;
}
#-----------------------------------------------------------------# Qui i nomi e le architetture sono uguali.
#-----------------------------------------------------------------#-----------------------------------------------------------------# Se l’ultima cifra della versione è alfabetica e la penultima
# è numerica, quella alfabetica viene
# trasformata in numerica per facilitare il confronto.
#-----------------------------------------------------------------if ( $versione1 =~ m{^.*\d[A-Za-z]$}
&& $versione0 =~ m{^.*\d[A-Za-z]$} ) {
#-------------------------------------------------------------# L’ultimo elemento della versione è una lettera alfabetica.
# Converte la lettera in numero.
#-------------------------------------------------------------$versione1 =~ m{^(.*)([A-Za-z])$};
$versione1 = $1 . ord $2;
$versione0 =~ m{^(.*)([A-Za-z])$};
$versione0 = $1 . ord $2;
}
#-----------------------------------------------------------------# Si verifica che la versione sia numerica.
#-----------------------------------------------------------------if ( $versione1 =~ m{^[0-9.]*$} && $versione0 =~ m{^[0-9.]*$} ) {
#-------------------------------------------------------------# La versione è correttamente numerica.
# Si procede a estrarre i vari valori separati da punti
# (al massimo sei).
#-------------------------------------------------------------$versione1 =~ m{^(\d*)\.*(\d*)\.*(\d*)\.*(\d*)\.*(\d*)\.*(\d*)$};
$verA1 = $1;
$verB1 = $2;
$verC1 = $3;
$verD1 = $4;
$verE1 = $5;
$verF1 = $6;
$versione0 =~ m{^(\d*)\.*(\d*)\.*(\d*)\.*(\d*)\.*(\d*)\.*(\d*)$};
$verA0 = $1;
$verB0 = $2;
$verC0 = $3;
$verD0 = $4;
$verE0 = $5;
4031
Accorgimenti per una distribuzione Red Hat
4032
$verF0 = $6;
#-------------------------------------------------------------# Si procede al confronto tra le versioni.
#-------------------------------------------------------------if ( $verA1 > $verA0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verA1 < $verA0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} elsif ( $verB1 > $verB0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verB1 < $verB0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} elsif ( $verC1 > $verC0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verC1 < $verC0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} elsif ( $verD1 > $verD0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verD1 < $verD0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} elsif ( $verE1 > $verE0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verE1 < $verE0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} elsif ( $verF1 > $verF0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verF1 < $verF0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
}
} elsif ( $versione1 =~ m{^$versione0$} ) {
#-------------------------------------------------------------# Le versioni sono uguali; più avanti si verifica il numero
# di rilascio.
#-------------------------------------------------------------;
} else {
#--------------------------------------------------------------
Accorgimenti per una distribuzione Red Hat
# La versione contiene simboli non numerici.
#-------------------------------------------------------------print "Attenzione ai file seguenti (versione non numerica)\n";
print " $file0";
print " $file1";
next;
}
#-----------------------------------------------------------------# Qui le versioni sono uguali.
#-----------------------------------------------------------------#-----------------------------------------------------------------# Si verifica che il rilascio sia numerico.
#-----------------------------------------------------------------if ( $rilascio1 =~ m{^[0-9.]*$} && $rilascio0 =~ m{^[0-9.]*$} ) {
#-------------------------------------------------------------# Il rilascio è correttamente numerico.
# Si procede a estrarre i vari valori separati da punti
# (al massimo 3).
#-------------------------------------------------------------$rilascio1 =~ m{^(\d*)\.*(\d*)\.*(\d*)$};
$verA1 = $1;
$verB1 = $2;
$verC1 = $3;
$rilascio0 =~ m{^(\d*)\.*(\d*)\.*(\d*)$};
$verA0 = $1;
$verB0 = $2;
$verC0 = $3;
#-------------------------------------------------------------# Si procede al confronto tra i rilasci.
#-------------------------------------------------------------if ( $verA1 > $verA0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verA1 < $verA0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} elsif ( $verB1 > $verB0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verB1 < $verB0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} elsif ( $verC1 > $verC0 ) {
print "Eliminazione del file $file0";
system( "rm $file0" );
next;
} elsif ( $verC1 < $verC0 ) {
print "Eliminazione del file $file1";
system( "rm $file1" );
next;
} else {
print "I file seguenti sembrano identici\n";
print "
$file0";
print "
$file1";
next;
}
} else {
4033
Accorgimenti per una distribuzione Red Hat
4034
#-------------------------------------------------------------# Il rilascio contiene simboli non numerici.
#-------------------------------------------------------------print "Attenzione ai file seguenti (rilascio non numerico)\n";
print " $file0";
print " $file1";
next;
}
} continue {
#-----------------------------------------------------------------# Accantona i dati per il confronto.
#-----------------------------------------------------------------$file0 = $file1;
$nome0 = $nome1;
$versione0 = $versione1;
$rilascio0 = $rilascio1;
$architettura0 = $architettura1;
}
#---------------------------------------------------------------------# Il lavoro è terminato; viene chiuso l’elenco dei file.
#---------------------------------------------------------------------close ( ELENCO );
#======================================================================
Come si può intuire, questo programma potrebbe anche fallire nel suo intento. In ogni caso,
bisogna analizzare i messaggi per intervenire manualmente sui file che non possono essere trattati
automaticamente.
358.2 Personalizzazione e aggiornamento
Una delle cose più fastidiose della distribuzione GNU/Linux Red Hat sono gli aggiornamenti numerosi, già dopo pochi giorni che una nuova versione viene pubblicata. Se si scarica la distribuzione dalla rete, o se la si acquista attraverso uno dei tanti distributori non ufficiali, si ottiene sempre solo una versione «originale», con tutti i difetti che potrebbe avere, dove gli aggiornamenti
vanno fatti dopo l’installazione, in modo manuale.
Quando si installa GNU/Linux in modo sistematico su un gran numero di elaboratori, questo
problema diventa delicato, perché il lavoro di aggiornamento deve essere moltiplicato su tutte
le macchine, mentre sarebbe utile la possibilità di ottenere una distribuzione personalizzata e
aggiornata come si vuole.
358.2.1 Installazione normale o attraverso il dischetto
supplementare
Allo stato attuale, i dischetti per l’installazione sono due. Il primo è sufficiente per le forme di
installazione più comuni, come quella da un CD-ROM o da un file system di rete NFS, mentre il
secondo deve essere usato in tutti gli altri casi.
Il programma di installazione aggiuntivo, collocato nel dischetto supplementare è più tollerante e
in molti casi è in grado di installare una distribuzione contenente file di versioni differenti rispetto
a quelle previste nell’edizione standard. Al contrario, il programma del primo dischetto richiede
un’esatta corrispondenza tra i nomi dei file.
Accorgimenti per una distribuzione Red Hat
4035
Per la precisione, le forme di installazione che fanno uso del solo dischetto di avvio, richiedono
la presenza del file ‘RedHat/base/hdlist’, che contiene l’elenco e le descrizioni dei pacchetti
RPM disponibili.
358.2.2 Personalizzazione
Come accennato, per poter personalizzare una distribuzione Red Hat con i pacchetti aggiornati,
occorre rigenerare il file ‘RedHat/base/hdlist’. Questo si ottiene con il programma ‘misc/
src/install/genhdlist’.
Supponendo di disporre di una distribuzione Red Hat per la piattaforma i386, a partire dalla directory ‘/MIO_RHL/’, strutturata come si vede dallo schema seguente (che è comunque semplificato
rispetto alla realtà), si devono compiere i passi elencati successivamente.
/MIO_RHL
|-- RedHat/
|
|-- RPMS/
|
|-- base/
|
|-- instimage/
|
|
‘...
|
|
|
‘-- i386
|
|-- doc/
|
|-- dosutils/
|
‘...
|
|-- images/
|
|-- misc/
|
|-- boot/
|
‘-- src/
|
|-- install/
|
‘...
|
|-- updates/
|
|-- COPYING
|-- README
‘-- RPM-PGP-KEY
1. Si copiano i file dei pacchetti aggiornati nella directory ‘RPMS/’ della versione
personalizzata che si sta predisponendo.
# cp /MIO_RHL/updates/* /MIO_RHL/RedHat/RPMS/
2. In qualche modo si eliminano i pacchetti doppi più vecchi.
3. Si rigenera il file ‘RedHat/base/hdlist’, ma prima si sistemano i permessi, nel caso
serva.
# chmod u+x /MIO_RHL/misc/src/install/genhdlist
# chmod 644 /MIO_RHL/RedHat/base/hdlist
# /MIO_RHL/misc/src/install/genhdlist /MIO_RHL/
Come si può intuire, l’eliminazione dei pacchetti doppi più vecchi può essere fatta con l’aiuto
dello script ‘rpmdoppi’ già descritto in questo capitolo.
4036
Accorgimenti per una distribuzione Red Hat
358.3 Aggiornamento del kernel
Comunque si decida di aggiornare una distribuzione Red Hat, il kernel è un punto che crea
solitamente dei problemi. Segue la descrizione del modo più conveniente per aggiornarlo.
358.3.1 Installazione fisica
Per prima cosa, con il sistema già funzionante, si procede all’aggiornamento simultaneo di
tutti i pacchetti del kernel, saltando solo quelli che non vengono già utilizzati nel sistema.
L’aggiornamento simultaneo è necessario per evitare problemi di conflitti.
Il modo più semplice è quello di collocare i file dei pacchetti desiderati in una directory
temporanea e da lì installarli contemporaneamente.
# rpm -Uv /tmp/updates/*.rpm
358.3.2 initrd
Se il sistema utilizza unità SCSI, dal momento che i kernel modulari predisposti dalle distribuzioni Red Hat non includono nel blocco principale la gestione di questi dispositivi, occorre
aggiornare anche l’immagine ‘initrd’. Questa infatti deve contenere i moduli necessari per il
riconoscimento delle unità SCSI esistenti e, avendo aggiornato il kernel, occorre ricostruire anche
questo file.
Se la gestione dei moduli è configurata correttamente, dovrebbe bastare il comando seguente,
dove la versione e il rilascio vanno sostituiti con quelli del kernel aggiornato.
mkinitrd /boot/initrd-versione -rilascio versione -rilascio
In pratica, immaginando che si tratti della versione 2.0.34 rilascio 1, si dovrebbe procedere nel
modo seguente:
# mkinitrd /boot/initrd-2.0.34-1 2.0.34-1
358.3.3 LILO
Una volta che i file del kernel e l’immagine ‘initrd’ sono al loro posto, ci si deve prendere cura del sistema di avvio, di solito con LILO. Evidentemente, occorre ritoccare il file
‘/etc/lilo.conf’ in modo che venga avviato il file corretto del kernel e venga utilizzato
eventualmente la nuova immagine ‘initrd’.
L’esempio seguente riguarda il caso di un kernel 2.0.34-1.
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/boot/vmlinuz-2.0.34-1
label=linux
root=/dev/hda3
initrd=/boot/initrd-2.0.34-1
read-only
Naturalmente, alla fine, occorre avviare ‘lilo’ per sistemare il settore di avvio.
# lilo
Accorgimenti per una distribuzione Red Hat
4037
358.3.4 Dischetto di avvio di emergenza
Anche il dischetto di avvio di emergenza può essere ricostruito facilmente. Basta utilizzare il
comando seguente, che si rifà al solito caso del kernel 2.0.34-1.
# mkbootdisk --device /dev/fd0 2.0.34-1
358.4 Aggiornamento manuale di un’installazione
Un altro difetto importante della distribuzione Red Hat è che l’aggiornamento di un’edizione
precedente funziona di rado: quasi sempre il programma di installazione si interrompe a metà.
Esistendo questo rischio, è decisamente sconsigliabile di tentare un’operazione del genere: o si
reinstalla da zero, o è meglio aggiornare pacchetto per pacchetto, al momento della necessità.
Chi ha già una buona pratica con il programma ‘rpm’ ed è in grado di superare i problemi comuni
dovuti alle dipendenze, potrebbe cimentarsi in una sorta di aggiornamento semiautomatico che
viene descritto qui. Si tratta comunque di un’operazione delicata da fare con prudenza e che
potrebbe anche fallire.
Prima di proseguire è bene chiarire che il pacchetto ‘basesystem’ non deve essere aggiornato e che i pacchetti RPM del kernel vanno aggiornati a parte secondo le modalità già descritte
a questo proposito.
358.4.1 Estrazione dell’elenco dei pacchetti installati
Il programma ‘rpm’ non prevede un modo per aggiornare solo i pacchetti già esistenti nel sistema.
Per arrivare a questo occorre un po’ di lavoro e per prima cosa è necessario ottenere un elenco
dei nomi dei pacchetti (vecchi) già installati che si presume di volere aggiornare.
# rpm --queryformat ’%{NAME}\n’ -qa | sort
Il comando mostrato genera un elenco ordinato dei nomi dei pacchetti installati. La cosa
importante è che i nomi sono senza l’indicazione della versione.
L’idea è che con l’elenco che si ottiene, dopo aver tolto ‘basesystem’ e i pacchetti del kernel,
si potrebbe alimentare un comando di aggiornamento (‘rpm -U’). Si può modificare il comando
che genera l’elenco nel modo seguente, per i motivi che si chiariranno in seguito.
# rpm --queryformat ’%{NAME}-\[0-9\]\*.rpm\n’ -qa | sort
Si ottiene qualcosa di molto simile all’elenco seguente:
AfterStep-APPS-[0-9]*.rpm
AfterStep-[0-9]*.rpm
AnotherLevel-[0-9]*.rpm
ElectricFence-[0-9]*.rpm
ImageMagick-[0-9]*.rpm
MAKEDEV-[0-9]*.rpm
SysVinit-[0-9]*.rpm
...
Come si può intuire, l’intenzione è quella di ottenere un elenco di modelli (glob) che corrispondano ai rispettivi file dei pacchetti aggiornati, di cui non si conosce a priori il numero della versione.
Da come sono stati scritti, si presume che dopo il nome di un pacchetto ci sia un trattino (‘-’),
seguito da una cifra numerica, da una stringa indefinita e infine dall’estensione ‘.rpm’. Ciò non
può essere sempre vero, però funziona nella maggior parte dei casi.
Accorgimenti per una distribuzione Red Hat
4038
358.4.2 Aggiornare i pacchetti in base all’elenco
L’elenco descritto nella sezione precedente, quello contenente i modelli di shell (o modelli glob),
va controllato e da lì si devono eliminare i pacchetti che non si possono o non si vogliono aggiornare. È già stato ripetuto che non si deve aggiornare ‘basesystem’ e che i pacchetti del kernel
vanno aggiornati a parte.
Una volta che l’elenco è corretto, ci si può posizionare nella directory che contiene i file RPM
aggiornati e si può lanciare il comando di aggiornamento.
# cd /mnt/cdrom/RedHat/RPMS
# rpm -Uv ‘cat /tmp/elenco‘ 2>&1 | tee /tmp/risultato
Dall’esempio si intende che i pacchetti si trovano nella directory ‘/mnt/cdrom/RedHat/
RPMS/’, che l’elenco dei modelli da aggiornare si trova nel file ‘/tmp/elenco’ e che si vuole
conservare una copia dei messaggi nel file ‘/tmp/risultato’.
Purtroppo, di solito non funziona...
358.4.3 Problemi
Questo tipo di procedimento lascia aperti una serie di problemi che si manifestano in modo non
del tutto prevedibile.
• Alcune dipendenze potrebbero risultare non soddisfatte.
Se per qualunque motivo non dovessero essere soddisfatte tutte le dipendenze, si può tentare
di isolare i pacchetti che creano questo problema, togliendo le voci relative dal file di elenco,
installandoli successivamente a mano, cercando di risolvere le dipendenze.
Di solito può trattarsi di librerie nuove o di parti che sono state scorporate in pacchetti separati. Eventualmente si può tentare di installare tali pacchetti prima di iniziare con
l’aggiornamento generale.
• Alcuni pacchetti potrebbero avere cambiato nome.
Se un pacchetto nella versione nuova della distribuzione ha cambiato nome, non si ottiene
il suo aggiornamento, perché il modello che si utilizza per indicarlo non coincide. Se si
tratta di un pacchetto indispensabile ad altri, si otterrà la segnalazione di errori dovuti alle
dipendenze.
• Alcuni pacchetti potrebbero essere stati scissi in diversi pacchetti più specifici.
Se un pacchetto è stato scisso, può darsi che il nome vecchio sia stato mantenuto per la
parte principale di questo, così non si ottiene l’installazione della parte aggiuntiva.
Questo fatto può portare comunque a problemi di dipendenza.
• A un certo punto dell’aggiornamento si potrebbe arrivare a uno scarico della memoria (core
dump).
Se l’aggiornamento si interrompe, è possibile modificare il file contenente l’elenco dei modelli in modo da eliminare le voci corrispondenti ai pacchetti già esaminati e aggiornati;
quindi si può ripetere il comando di aggiornamento.
Accorgimenti per una distribuzione Red Hat
4039
358.5 Semplificazione della configurazione della rete
La configurazione della rete secondo l’impostazione della Red Hat, in presenza di situazioni particolari potrebbe tradursi in un labirinto troppo complicato. Anche l’uso degli strumenti previsti,
come ‘netcfg’ o ‘linuxconf’, potrebbe essere insufficiente per le proprie esigenze.
358.5.1 Raggiro parziale del problema
Si potrebbe decidere di saltare questo sistema, inserendo i comandi necessari all’attivazione delle
interfacce di rete e alla definizione degli instradamenti nel file ‘/etc/rc.d/rc.local’. In tal
caso conviene:
• predisporre il file ‘/etc/sysconfig/network’, avendo cura di attivare la rete
(‘NETWORKING=yes’);
• predisporre il file ‘/etc/sysconfig/network-scripts/ifcfg-lo’ in modo che sia
definita l’interfaccia di loopback;
• eliminare ogni altro file ‘/etc/sysconfig/network-scripts/ifcfg-*’ in modo che
non venga definita alcuna interfaccia reale;
• aggiungere in coda al file ‘/etc/rc.d/rc.local’ i comandi necessari ad attivare le
interfacce di rete e a definire gli instradamenti.
In alternativa si potrebbe eliminare completamente la directory ‘/etc/sysconfig/
network-scripts/’. In tal caso, nel file ‘/etc/rc.d/rc.local’ andrebbero aggiunti anche
i comandi necessari a configurare e instradare l’interfaccia di loopback.
Questo tipo di approccio ha anche altre conseguenze, per esempio l’impossibilità di attivare
un’interfaccia PPP attraverso gli strumenti della distribuzione. Anche per queste cose occorre
creare degli script appositi.
L’effetto peggiore di questo metodo sta nel fatto che lo script ‘/etc/rc.d/rc.local’ viene
avviato per ultimo, nella sequenza della procedura di inizializzazione del sistema, per cui alcuni servizi che fanno affidamento sull’attivazione precedente della rete potrebbero non essere in
grado di avviarsi correttamente.
358.5.2 Sostituzione del file /etc/rc.d/init.d/network
Nella procedura di inizializzazione del sistema utilizzato da Red Hat, lo script ‘/etc/rc.d/
init.d/network’ è quello che si utilizza per attivare le interfacce di rete nel momento giusto.
La sostituzione del contenuto di questo script con un altro che sia indipendente dai meccanismi
che compongono la directory ‘/etc/sysconfig/network-scripts/’, potrebbe essere una
soluzione migliore, anche se non perfetta.
Quello che segue è un esempio più o meno complesso di quello che potrebbe contenere questo script: si utilizza una porta parallela PLIP con il mascheramento IP e una scheda Ethernet
connessa a Internet.
#!/bin/sh
#
# network
Attiva/disattiva la rete
#
# chkconfig: 345 10 97
# description: Attiva/Disattiva la rete.
Accorgimenti per una distribuzione Red Hat
4040
# Riutilizza le variabili definite nel file di configurazione
# della rete della Red Hat.
. /etc/sysconfig/network
RiattivazioneRete() {
# Si prende cura della configurazione dell’inoltro IPv4 secondo
# Red Hat.
if [ "$FORWARD_IPV4" = "no" -o "$FORWARD_IPV4" = "false" ]
then
echo "0" > /proc/sys/net/ipv4/ip_forward
echo "L’inoltro IPv4 è disabilitato."
else
echo "1" > /proc/sys/net/ipv4/ip_forward
echo "L’inoltro IPv4 è abilitato."
fi
# loopback
/sbin/ifconfig lo down
/sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0
/sbin/route del 127.0.0.1
/sbin/route del 127.0.0.0
# /sbin/route add -net 127.0.0.0 netmask 255.0.0.0 dev lo
/sbin/route add -host 127.0.0.1 dev lo
# plip
/sbin/modprobe plip
/sbin/ifconfig plip0 down
/sbin/ifconfig plip0 192.168.254.254 pointopoint 0.0.0.0
/sbin/route del 192.168.254.0
/sbin/route add -net 192.168.254.0 dev plip0
# firewall
/sbin/ipchains
/sbin/ipchains
/sbin/ipchains
/sbin/ipchains
-F
-P
-A
-L
forward
forward ACCEPT
forward -s 192.168.0.0/16 -d 0/0 -j MASQ
forward -n
# eth0
/sbin/modprobe eth0
/sbin/ifconfig eth0 down
/sbin/ifconfig eth0 196.195.194.7 netmask 255.255.255.0
/sbin/route del 196.195.194.0
/sbin/route add -net 196.195.194.0 netmask 255.255.255.0 dev eth0
Instradamento predefinito
/sbin/route del 0.0.0.0
/sbin/route add -net default gw 196.195.194.1 dev eth0
}
# Verifica del modo in cui è stato chiamato lo script.
case "$1" in
start | restart | reload)
RiattivazioneRete
touch /var/lock/subsys/network
;;
stop)
/sbin/ifconfig
/sbin/ifconfig
/sbin/ifconfig
/sbin/ifconfig
/sbin/ifconfig
/sbin/ifconfig
eth0 down
eth1 down
eth2 down
plip0 down
plip1 down
plip2 down
Accorgimenti per una distribuzione Red Hat
4041
echo "0" > /proc/sys/net/ipv4/ip_forward
echo "L’inoltro IPv4 è disabilitato."
rm -f /var/lock/subsys/network
;;
status)
/sbin/ifconfig
/sbin/route -n
/sbin/ipchains -L -n
;;
probe)
exit 0
;;
*)
echo "Utilizzo: network {start|stop|restart|reload|status}"
exit 1
esac
exit 0
Questa alternativa consente l’eliminazione di tutta la directory ‘/etc/sysconfig/
network-scripts/’ e del file ‘/etc/sysconfig/static-routes’; inoltre risolve il
problema legato al momento in cui si attiva o disattiva la rete.
È evidente che anche in questo caso non è più possibile configurare la rete attraverso gli strumenti consueti e l’attivazione di una possibile connessione PPP deve essere fatta in modo
personalizzato, eventualmente attraverso degli script.
358.6 Riferimenti
• Morten Kjeldgaard, Peter von der Ahé, Burning a Red Hat CD mini-HOWTO
<http://www.linux.org/docs/ldp/howto/HOWTO-INDEX/howtos.html>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
4042
Accorgimenti per una distribuzione Red Hat
Parte lxxvi
i86
359 Minix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4044
359.1 Procurarsi il software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4044
359.2 Preparazione all’installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4045
359.3 Avvio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4046
359.4 Installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4048
359.5 Ricompilazione del kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4052
359.6 Parametri di avvio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4054
359.7 Configurazione della rete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4055
359.8 Personalizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4057
359.9 Tastiera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4057
359.10 Altri programmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4060
359.11 Copie di sicurezza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4062
359.12 Convivenza tra Minix e GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4063
359.13 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4063
360 ELKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4064
360.1 Sperimentare ELKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4064
360.2 Immagini di dischetti già pronti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4065
360.3 Avvio di ELKS all’interno di DOSEMU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4065
360.4 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4065
4043
Capitolo
359
Minix
Minix 1 è nato originariamente come sistema didattico. Minix non ha avuto il successo e la
diffusione che avrebbe potuto avere a causa delle limitazioni della sua licenza iniziale. In seguito
le cose sono cambiate, fortunatamente, perché Minix resta probabilmente l’unica possibilità reale
per chi vuole utilizzare elaboratori con architettura i286 o inferiore.
Lo scopo di questo capitolo è introdurre all’uso di Minix per poter riutilizzare i vecchi elaboratori
i286, in particolare, collegandoli a una rete locale TCP/IP. Le informazioni seguenti si riferiscono
alla versione 2.0.0.
359.1 Procurarsi il software
Minix è ottenibile dalla rete, precisamente a partire dalla sua pagina di presentazione ufficiale,
quella del suo primo autore (La sigla «AST» rappresenta le iniziali di Andrew S. Tanenbaum),
oltre che dai vari siti speculari del relativo FTP.
<http://www.cs.vu.nl/~ast/minix.html>
Minix è nato assieme a un libro che tuttora dovrebbe essere accompagnato da un CD-ROM
contenente il sistema operativo:
• Andrew S. Tanenbaum, Alber S. Woodhull, Operating Systems: Design and Implementation, 2/e, Prentice-Hall
359.1.1 Pacchetti essenziali
Minix è un sistema molto piccolo e composto da pochi pacchetti. Questi hanno alcune particolarità: i nomi sono composti con lettere maiuscole e gli archivi compressi utilizzano la combinazione
‘tar’+‘compress’ e sono evidenziati dall’uso dell’estensione ‘.TAZ’.
Per prima cosa è necessario riprodurre la coppia di dischetti ‘ROOT’ e ‘USR’, a partire dai file
omonimi. Il primo è in grado di avviarsi e contiene un file system minimo che si installa in
un disco RAM, il secondo contiene una piccola serie di programmi da montare nella directory
‘/usr/’, che servono per poter installare Minix nel disco fisso. Se si ha poca memoria a disposizione (i classici 640 Kibyte sono il minimo in assoluto per poter fare funzionare Minix), si può
evitare l’utilizzo del disco RAM fondendo i due file in un solo dischetto. Data l’intenzione di
questo capitolo verrà descritta l’ultima di queste modalità di installazione.
Il mini sistema che si ottiene attraverso i due file appena citati, permette di installare, più o meno
automaticamente, un insieme minimo di programmi contenuto nell’archivio ‘USR.TAZ’
Esistono due versioni di questi tre file: una per architettura i386 o superiore e l’altra per i microprocessori inferiori. Date le intenzioni, si dovranno utilizzare i file della versione denominata
‘i86’.
1
Minix licenza simile a BSD
4044
Minix
4045
359.2 Preparazione all’installazione
Il procedimento che viene descritto è valido sia per dischetti da 1440 Kibyte che da 1200 Kibyte.
I due file ‘ROOT’ e ‘USR’ vanno copiati uno di seguito all’altro. Utilizzando GNU/Linux, si può
fare nel modo seguente:
# cat ROOT USR > /dev/fd0
Dal punto di vista di Minix, il dischetto inserito nella prima unità a dischetti corrisponde al dispositivo ‘/dev/fd0’, come per GNU/Linux, ma risulta diviso in partizioni: l’immagine ‘ROOT’
risulta essere ‘/dev/fd0a’ e l’immagine ‘USR’ è ‘/dev/fd0c’ (la partizione ‘b’ è vuota).2
L’archivio ‘USR.TAZ’ deve essere suddiviso in diversi dischetti, con un procedimento un po’ insolito: viene semplicemente tagliato a fettine della dimensione massima contenibile dal tipo di dischetti che si utilizza. Nel caso si tratti di dischetti da 1440 Kibyte, si può utilizzare GNU/Linux,
o un altro sistema Unix, nel modo seguente:
# dd if=/USR.TAZ of=/dev/fd0 bs=1440k count=1 skip=0
# dd if=/USR.TAZ of=/dev/fd0 bs=1440k count=1 skip=1
# dd if=/USR.TAZ of=/dev/fd0 bs=1440k count=1 skip=2
Se si trattasse di dischetti da 1200 Kibyte, occorrerebbe modificare la dimensione del blocco,
come nell’esempio seguente:
# dd if=/USR.TAZ of=/dev/fd0 bs=1200k count=1 skip=0
# dd if=/USR.TAZ of=/dev/fd0 bs=1200k count=1 skip=1
# dd if=/USR.TAZ of=/dev/fd0 bs=1200k count=1 skip=2
359.2.1 Nomi di dispositivo riferiti alle partizioni
Minix viene installato normalmente all’interno di una partizione primaria suddivisa in almeno
due partizioni secondarie. La prima partizione serve a contenere il file system principale ed è
di piccole dimensioni: 1440 Kibyte. La seconda serve per tutto il resto e viene montata in corrispondenza della directory ‘/usr/’. Inizialmente le partizioni erano tre e ‘/usr/’ era la terza.
Attualmente, ‘/usr/’ continua a essere la terza partizione e si finge che esista una seconda
partizione senza alcuno spazio a disposizione.
Il primo disco fisso viene identificato dal dispositivo ‘/dev/hd0’, il secondo da ‘/dev/hd5’.
Le partizioni primarie del primo disco fisso vanno da ‘/dev/hd1’ a ‘/dev/hd4’; quelle del
secondo disco fisso da ‘/dev/hd6’ a ‘/dev/hd9’. Le partizioni secondarie corrispondono al
nome del dispositivo della partizione primaria con l’aggiunta di una lettera alfabetica che ne
indica l’ordine.
• /dev/hd0
– /dev/hd1
* /dev/hd1a
* /dev/hd1b
2
Se si trattasse della seconda unità a dischetti, si parlerebbe di ‘/dev/fd1’, ‘/dev/fd1a’ e ‘/dev/fd1c’.
Minix
4046
* /dev/hd1c
* ...
– /dev/hd2
– /dev/hd3
– /dev/hd4
• /dev/hd5
– /dev/hd6
– /dev/hd7
– /dev/hd8
– /dev/hd9
Minix può essere installato in una partizione primaria qualunque, purché ci siano almeno 40 Mibyte a disposizione. Utilizzando la versione di Minix ‘i86’, non conviene tentare di superare i
128 Mibyte.
359.3 Avvio
Minix utilizza un sistema di avvio piuttosto sofisticato; per fare un paragone con GNU/Linux, si
tratta di qualcosa che compie le stesse funzioni di LILO, o di un cosiddetto bootloader.
Il sistema che svolge questa funzione in Minix si chiama boot monitor ed è importante capire
subito come si utilizza se non si ha molta memoria RAM a disposizione, quanta ne richiederebbe
un disco RAM per l’immagine ‘ROOT’.
Per cominciare, dopo aver preparato il dischetto ‘ROOT’+‘USR’, lo si inserisce senza la protezione
contro la scrittura e si avvia l’elaboratore. Questo è ciò che appare.
Minix boot monitor 2.5
Press ESC to enter the monitor
Hit a key as follows:
= Start Minix
Premendo il tasto [ Esc ] si attiva il boot monitor, mentre premendo [ = ] (si fa riferimento alla
tastiera americana e questo simbolo si trova in corrispondenza della nostra lettera «ì») si avvia
Minix con le impostazioni predefinite.
Dal momento che si immagina di avere a disposizione poca memoria (solo 1 Mibyte), non
si può avviare Minix così, perché il contenuto dell’immagine ‘ROOT’ verrebbe caricato come
disco RAM. È necessario utilizzare subito il boot monitor.
[ Esc ]
[ESC]
fd0>
Si ottiene un invito (prompt), attraverso il quale possono essere utilizzati alcuni comandi importanti per predisporre l’avvio del sistema Minix. Per ottenere aiuto si può utilizzare il comando
‘help’.
fd0> help[ Invio ]
Minix
4047
Si ottiene un riepilogo dei comandi e del modo con cui possono essere utilizzati. Le cose più importanti che si possono fare con il boot monitor sono: l’avvio a partire da una partizione differente
da quella prestabilita; l’assegnamento o il ripristino al valore predefinito di una variabile.
Queste variabili sono solo entità riferite al sistema di avvio e la loro modifica permette di cambiare il modo con cui si avvia il kernel. Il comando ‘set’ permette di elencare il contenuto di
queste variabili.
fd0> set[ Invio ]
rootdev = (ram)
ramimagedev = (bootdev)
ramsize = (0)
processor = (286)
bus = (at)
memsize = (640)
emssize = (330)
video = (vga)
chrome = (mono)
image = (minix)
main() = (menu)
I valori appaiono tutti tra parentesi tonde perché rappresentano le impostazioni predefinite.
Quando si cambia qualche valore, questo appare senza le parentesi.
La prima cosa da cambiare è il dispositivo di avvio, ‘rootdev’. Si deve assegnare il nome di
dispositivo riferito all’immagine ‘ROOT’ su dischetto. Si tratta di ‘/dev/fd0a’, come dire, la
prima partizione secondaria del dischetto. In questo caso, il nome del dispositivo può anche
essere indicato senza la parte iniziale, limitandolo al solo ‘fd0a’.
fd0> rootdev=fd0a[ Invio ]
fd0> set[ Invio ]
rootdev = fd0a
ramimagedev = (bootdev)
ramsize = (0)
processor = (286)
bus = (at)
memsize = (640)
emssize = (330)
video = (vga)
chrome = (mono)
image = (minix)
main() = (menu)
Per avviare il sistema, basta utilizzare il comando ‘boot’ senza argomenti.
fd0> boot[ Invio ]
In questo modo si lascia il boot monitor e si avvia il kernel. Una volta avviato il sistema, viene
richiesto immediatamente il montaggio della seconda immagine, ‘USR’, contenente gli strumenti
necessari all’installazione. Avendo avviato senza disco RAM, il dischetto contenente l’immagine
‘ROOT’ non può essere tolto e questo è il motivo per il quale deve essere contenuta nello stesso
dischetto insieme a ‘USR’.3
Minix 2.0.0
Copyright 1997 Prentice-Hall, Inc.
Executing in 16-bit protected mode
3
Una cosa da sapere subito è che Minix non utilizza la sequenza [ Ctrl+C ] per interrompere un programma. Per questo
si usa il tasto [ Canc ] da solo.
Minix
4048
Memory size = 970K
MINIX = 206K
RAM disk =
0K
Available = 765K
Mon Nov 3 15:24:15 MET 1997
Finish the name of device to mount as /usr: /dev/
Date le premesse, occorre specificare il nome del dispositivo corrispondente all’immagine ‘USR’:
si tratta di ‘fd0c’.
fd0c[ Invio ]
/dev/fd0c is read-write mounted on /usr
Starting standard daemons: update.
Login as root and run ’setup’ to install Minix.
Minix
Release 2.0 Version 0
noname login:
root[ Invio ]
#
359.4 Installazione
L’installazione di Minix avviene in tre fasi:
1. preparazione della partizione di destinazione;
2. trasferimento del contenuto del dischetto, ovvero delle immagini ‘ROOT’ e ‘USR’;
3. dopo il riavvio, trasferimento dell’archivio ‘USR.TAZ’ e possibilmente, se si dispone di una
partizione di almeno 40 Mibyte, anche di ‘SYS.TAZ’ e ‘CMD.TAZ’.
359.4.1 Setup
Per iniziare l’installazione, dopo aver avviato il sistema Minix dal dischetto, si utilizza lo script
‘setup’.
# setup[ Invio ]
This is the Minix installation script.
Note 1: If the screen blanks suddenly then hit F3 to select "software
scrolling".
Note 2: If things go wrong then hit DEL and start over.
Note 3: The installation procedure is described in the manual page
usage(8). It will be hard without it.
Note 4: Some questions have default answers, like this: [y]
Simply hit RETURN (or ENTER) if you want to choose that answer.
Note 5: If you see a colon (:) then you should hit RETURN to continue.
:
[ Invio ]
Dopo la breve spiegazione, avendo premuto il tasto [ Invio ] si passa all’indicazione del tipo di
tastiera. La scelta è ovvia, ‘italian’, anche se non corrisponde esattamente: la barra verticale
Minix
4049
(quella per le pipeline) si trova al posto della lettera «ì» (i accentata). Durante questa fase di
installazione conviene utilizzare la tastiera nazionale (‘italian’) per evitare spiacevoli incidenti
quando si utilizza il programma di gestione delle partizioni.
What type of keyboard do you have?
french
german
italian
japanese
latin-am
olivetti
You can choose one of:
scandinavn
spanish
uk
us-std
us-swap
Keyboard type? [us-std]
italian[ Invio ]
Minix needs one primary partition of at least 30 Mb (it fits in 20 Mb, but
it needs 30 Mb if fully recompiled. Add more space to taste.)
If there is no free space on your disk then you have to back up one of the
other partitions, shrink, and reinstall. See the appropriate manuals of the
the operating systems currently installed. Restart your Minix installation
after you have made space.
To make this partition you will be put in the editor "part". Follow the
advice under the ’!’ key to make a new partition of type MINIX. Do not
touch an existing partition unless you know precisely what you are doing!
Please note the name of the partition (hd1, hd2, ..., hd9, sd1, sd2, ...
sd9) you make. (See the devices section in usage(8) on Minix device names.)
:
Il programma di Minix che permette di accedere alla tabella delle partizioni è ‘part’ ed è ciò che
sta per essere avviato. Come sempre, l’uso di un programma di questo genere è molto delicato:
un piccolo errore mette fuori uso tutti i dati eventualmente contenuti in altre partizioni.
[ Invio ]
Select device
Device
/dev/hd0
Num Sort
? ?
? ?
? ?
? ?
Type
? ?
? ?
? ?
? ?
----first---Cyl Head Sec
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
--geom/last-Cyl Head Sec
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
------sectors----Base
Size
Kb
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
Type ’+’ or ’-’ to change, ’r’ to read, ’?’ for more help, ’!’ for advice
Prima di utilizzare questo programma conviene leggere la sua guida interna, ottenibile con la
pressione del tasto [ ? ]. Il cursore si presenta inizialmente sull’indicazione del disco, ‘/dev/
hd0’, e può essere cambiato semplicemente premendo i tasti [ + ] o [ - ]. Una volta raggiunto
il disco desiderato (in questo caso il primo disco va bene), si deve leggere la sua tabella delle
partizioni, in modo da rimpiazzare tutti i punti interrogativi che riempiono lo schermo.
[r]
Select device
Device
/dev/hd0
Num
1*
2
3
4
Sort
hd1
hd2
hd3
hd4
Type
86 DOS-BIG
00 None
00 None
00 None
----first---Cyl Head Sec
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
--geom/last-Cyl Head Sec
615
8 17
614
7 16
613
0
0
0
7
0
0
0
16
-1
-1
-1
------sectors----Base
Size
Kb
0
83640
41820
17
0
0
0
83487
0
0
0
41743
0
0
0
Minix
4050
Con questo esempio si suppone di avere solo un vecchio disco fisso MFM di circa 40 Mibyte, nel
quale la prima partizione primaria era stata dedicata in precedenza al Dos. Così, basta cambiare
il numero che identifica il tipo di partizione. Per farlo, vi si posiziona sopra il cursore, spostandolo con i tasti freccia, quindi si usano i tasti [ + ] o [ - ] fino a fare apparire il numero 8116. Al
primo intervento per cambiare un valore qualsiasi, viene richiesto esplicitamente se si intende
modificare effettivamente i dati della tabella delle partizioni.
Do you wish to modify existing partitions (y/n) [ y ]
Una volta modificato il tipo, la prima partizione dovrebbe apparire così come segue:
Num Sort
Type
1* hd1 81 MINIX
0
1
0
613
7
16
17
83487
41743
Quindi si conclude.
[q]
Save partition table? (y/n) [ y ]
Lo script di configurazione e installazione riprende richiedendo quale sia la partizione su cui
installare Minix. In questo caso si tratta della prima, cioè ‘/dev/hd1’.
Please finish the name of the primary partition you have created:
(Just type RETURN if you want to rerun "part")
/dev/
hd1[ Invio ]
You have created a partition named:
/dev/hd1
The following subpartitions are about to be created on /dev/hd3:
Root subpartition:
/usr subpartition:
/dev/hd1a
/dev/hd1c
1440 kb
rest of hd1
Hit return if everything looks fine, or hit DEL to bail out if you want to
think it over. The next step will destroy /dev/hd1.
:
Come accennato in precedenza, Minix viene installato in due partizioni secondarie: la prima
serve a contenere il file system principale, la seconda per il resto. In seguito si possono montare
anche partizioni successive.
Migrating from floppy to disk...
Scanning /dev/hd1c for bad blocks. (Hit DEL to stop the scan if are absolutely
sure that there can not be any bad blocks. Otherwise just wait.)
La scansione del disco fisso è necessaria se si utilizza un vecchio disco MFM, come si suppone
di avere in questo esempio, mentre può essere inutile con un disco ATA. È importante fare attenzione: se ci sono settori inutilizzabili, vengono creati alcuni file ‘/usr/.Bad_*’ che non vanno
cancellati! Alla fine, lo script procede a copiare il contenuto del dischetto nel disco fisso.
What is the memory size of this system in kilobytes? [4096 or more]
La dimensione di memoria RAM disponibile effettivamente è solo di 970 Kibyte, quindi si inserisce questo valore; se la memoria a disposizione fosse maggiore o uguale a 4 Mibyte, non
occorrerebbe indicare alcunché, basterebbe solo confermare.
970[ Invio ]
Second level file system block cache set to 0 kb.
Minix
4051
A questo punto, termina l’installazione del dischetto nel disco fisso e si può passare a riavviare il
sistema da lì.
Please insert the installation ROOT floppy and type ’halt’ to exit Minix.
You can type ’boot hd1’ to try the newly installed Minix system. See
"TESTING" in the usage manual.
# halt[ Invio ]
System Halted
359.4.2 Avvio del sistema copiato nel disco fisso
Una volta conclusa l’esecuzione dello script di configurazione e installazione, si ritorna sotto il
controllo del boot monitor, attraverso il quale è possibile avviare il sistema dalla prima partizione
del disco fisso.
fd0> boot /dev/hd1[ Invio ]
Minix 2.0.0
Copyright 1997 Prentice-Hall, Inc.
Executing in 16-bit protected mode
at-hd0: 615x8x17
Memory size = 970K
MINIX = 206K
RAM disk =
0K
Available = 765K
Mon Nov 3 16:01:27 MET 1997
Starting standard daemons: update.
Login as root and run ’setup /usr’ to install floppy sets.
Minix
Release 2.0 Version 0
noname login:
# root[ Invio ]
Il suggerimento dato all’avvio ricorda che è possibile installare altre serie di dischetti, a
cominciare da ‘USR.TAZ’, utilizzando il comando ‘setup /usr’.
359.4.3 Installazione delle serie di dischetti
Tra i pacchetti di Minix, ‘USR.TAZ’ è essenziale e cambia a seconda del tipo di architettura (i86
o i386). Però, dal momento che c’è spazio sufficiente nel disco fisso, conviene installare anche
‘SYS.TAZ’ per poter ricompilare il kernel e ‘CMD.TAZ’ che contiene i sorgenti dei vari programmi
di servizio.
Tutti questi pacchetti devono essere suddivisi in dischetti nel modo visto in precedenza per il
caso di ‘USR.TAZ’.
# setup /usr[ Invio ]
Lo script ‘setup’ chiede una serie di conferme.
What is the size of the images on the diskettes? [all]
Premendo semplicemente [ Invio ] si intende che i dischetti vadano letti nella loro interezza.
[ Invio ]
4052
Minix
What floppy drive to use? [0]
Premendo semplicemente [ Invio ] si fa riferimento alla prima unità, ‘/dev/fd0’.
[ Invio ]
Please insert input volume 1 and hit return
Si inserisce il primo dischetto e si conferma
[ Invio ]
Inizia la fase di estrazione di quanto contenuto nel primo dischetto, a partire dalla directory
‘/usr/’. Quando termina l’estrazione del primo dischetto, viene richiesto il successivo, fino alla
conclusione.
Conviene ripetere la procedura fino a quando sono stati installati anche gli archivi ‘SYS.TAZ’ e
‘CMD.TAZ’.
359.4.4 Dischetto di avvio
Minix è molto semplice e non è necessario un dischetto di avvio realizzato appositamente. È sufficiente il dischetto utilizzato per iniziare l’installazione. Se si hanno difficoltà con l’avviamento
di Minix dal disco fisso, si può avviare il boot monitor dal dischetto e con quello utilizzare il
comando ‘boot /dev/hd1’.
359.4.5 Conclusione
Per chiudere l’attività di Minix, si può fare nel solito modo comune a quasi tutti i sistemi Unix.
# shutdown -h now[ Invio ]
359.5 Ricompilazione del kernel
Anche Minix, nella sua semplicità, richiede una ricompilazione del kernel per la sua ottimizzazione. In particolare, per poter attivare la gestione del TCP/IP occorre passare per la configurazione
e ricompilazione.
Il file del kernel, secondo la tradizione di Minix, dovrebbe trovarsi nella directory radice e avere
il nome ‘minix’. Se però, invece di trattarsi di un file, si tratta di una directory, nella fase di avvio
viene eseguito il file più recente contenuto in tale directory. Il kernel normale, cioè quello che si
trova dopo l’installazione, dovrebbe essere ‘/minix/2.0.0’.
Per poter ricompilare il kernel occorre avere installato il pacchetto ‘SYS.TAZ’. Si procede come
segue:
1. si modifica il file ‘/usr/include/minix/config.h’;
2. ci si posiziona nella directory ‘/usr/src/tools/’;
3. si avvia la compilazione con il comando ‘make’.
Al termine si ottiene il file del kernel (o immagine) corrispondente a ‘/usr/src/tools/image’
che si può copiare e rinominare come si ritiene più opportuno.
Minix
4053
359.5.1 /usr/include/minix/config.h
La configurazione che viene proposta deriva dagli esempi precedenti, in cui si ha una particolare
penuria di memoria. Seguono solo alcuni pezzi.
/* If ROBUST is set to 1, writes of i-node, directory, and indirect blocks
* from the cache happen as soon as the blocks are modified. This gives a more
* robust, but slower, file system. If it is set to 0, these blocks are not
* given any special treatment, which may cause problems if the system crashes.
*/
#define ROBUST
1
/* 0 for speed, 1 for robustness */
La macro ‘ROBUST’ permette di sincronizzare le operazioni di accesso al disco. Nell’esempio mostrato si attiva questa opzione, in modo da poter utilizzare il sistema con tranquillità (e
ovviamente con maggiore lentezza).
/* Number of slots in the process table for user processes. */
#define NR_PROCS
32
Il numero massimo dei processi eseguibili può essere una seria limitazione all’uso simultaneo
dell’elaboratore da parte di più utenti, ma la scarsa memoria a disposizione consiglia di mantenere
basso questo valore.
/* Enable or disable the second level file system cache on the RAM disk. */
#define ENABLE_CACHE2
0
Sempre a causa della carenza di memoria, è opportuno disabilitare la memoria cache.
/* Include or exclude device drivers. Set to 1 to include, 0 to exclude. */
#define ENABLE_NETWORKING 1
/* enable TCP/IP code */
#define ENABLE_AT_WINI
1
/* enable AT winchester driver */
#define ENABLE_BIOS_WINI
1
/* enable BIOS winchester driver */
#define ENABLE_ESDI_WINI
1
/* enable ESDI winchester driver */
#define ENABLE_XT_WINI
0
/* enable XT winchester driver */
#define ENABLE_ADAPTEC_SCSI 0
/* enable ADAPTEC SCSI driver */
#define ENABLE_MITSUMI_CDROM 0 /* enable Mitsumi CD-ROM driver */
#define ENABLE_SB_AUDIO
0
/* enable Soundblaster audio driver */
In questa sezione è importante abilitare ciò che serve ed eliminare il resto. In particolare, è qui
che si attiva la connettività TCP/IP, che non risulta attivata in modo predefinito.
/* NR_CONS, NR_RS_LINES, and NR_PTYS determine the number of terminals the
* system can handle.
*/
#define NR_CONS
2
/* # system consoles (1 to 8) */
#define NR_RS_LINES
1
/* # rs232 terminals (0, 1, or 2) */
#define NR_PTYS
2
/* # pseudo terminals (0 to 64) */
Il numero predefinito di console virtuali è due, ma può essere espanso, sempre che ciò possa
avere senso date le limitazioni del sistema. Invece è importante attivare gli pseudoterminali, cioè
il numero massimo di connessioni remote. Volendo gestire la rete, è il caso di indicare almeno
uno pseduoterminale.
Per modificare il file ‘/usr/include/minix/config.h’ si può utilizzare ‘vi’, che è un
collegamento a ‘elvis’, oppure ‘elle’.4
Si procede con la compilazione.
# cd /usr/src/tools[ Invio ]
# make[ Invio ]
4
Il programma ‘elvis’ in particolare, è molto tradizionale: i tasti freccia generano proprio le lettere corrispondenti e
quindi non possono essere usati durante la fase di inserimento. ‘elle’ è un Emacs ridotto al minimo.
4054
Minix
Al termine della compilazione, se non sono occorsi incidenti, si ottiene il file ‘image’.
# cp image /minix/rete.0.1[ Invio ]
Questo dovrebbe bastare, trattandosi del file più recente nella directory ‘/minix/’, è anche quello
che verrà avviato la prossima volta.
# shutdown -h[ Invio ]
359.5.2 File di dispositivo
Quando si ricompila il kernel è probabile che si renda necessaria la creazione di file di dispositivo
che prima non erano necessari. Nel caso della gestione della rete, sono necessari i file seguenti:
• ‘/dev/eth’;
• ‘/dev/ip’;
• ‘/dev/tcp’;
• ‘/dev/udp’;
• ‘/dev/ttyp0’ e successivi;
• ‘/dev/ptyp0’ e successivi.
Questo ragionamento vale anche per le console virtuali: se si vogliono molte console, forse è
necessario aggiungere i file relativi.
Probabilmente c’è già tutto ciò di cui si può avere bisogno, ma se manca si può creare con lo
script ‘MAKEDEV’.
MAKEDEV dispositivo
Per esempio, trovandosi già nella directory ‘/dev/’, si può creare il dispositivo ‘/dev/tcp’ nel
modo seguente:
# MAKEDEV tcp
359.6 Parametri di avvio
Anche Minix richiede alcuni parametri di avvio in presenza di hardware particolare. La gestione
di questi avviene in modo molto semplice attraverso il boot monitor: basta definire una nuova
variabile, assegnandole il valore corretto.
359.6.1 Scheda di rete
Per gestire una rete occorre una scheda di rete Ethernet. Nell’esempio seguente si immagina di
disporre di una scheda compatibile con il modello NE2000 configurata con indirizzo di I/O 30016
e IRQ 11.
Il parametro di avvio per ottenere il riconoscimento della scheda Ethernet è ‘DPETHn ’, dove n è
il numero della scheda, a partire da zero.
DPETHn =indirizzo_i/o :irq:indirizzo_di_memoria
Minix
4055
La scheda NE2000 non utilizza alcun indirizzo di memoria, quindi, per il nostro esempio occorre
il parametro seguente:
DPETH0=300:11
Come si vede, l’indirizzo di I/O è espresso implicitamente in esadecimale e l’IRQ in decimale, mentre l’indirizzo di memoria viene omesso trattandosi di una NE2000. Per inserire tale
parametro si utilizza il boot monitor nel modo seguente:
hd0> DPETH0=300:11[ Invio ]
hd0> save[ Invio ]
L’ultima istruzione, ‘save’, salva questo parametro che altrimenti dovrebbe essere indicato ogni
volta che si avvia il sistema.
Se la scheda di rete viene riconosciuta, all’avvio appare il messaggio seguente:
Minix 2.0.0
Copyright 1997 Prentice-Hall, Inc.
Executing in 16-bit protected mode
ne2000: NE2000 at 300:11
359.7 Configurazione della rete
La configurazione della rete va fatta con cura, in modo da non avere bisogno di alcuni demoni che
permettono una sorta di autoconfigurazione. Negli esempi seguenti si configura il nuovo sistema
Minix tenendo conto di questa situazione:
• dinkel.brot.dg, IP 192.168.1.1, servizio DNS e router predefinito;
• minix.brot.dg, IP 192.168.1.25, elaboratore Minix.
Per quanto possibile, si fa in modo di non avere bisogno del DNS.
359.7.1 /etc/hosts
Volendo attivare localmente la risoluzione dei nomi e degli indirizzi è necessario il file ‘/etc/
hosts’, che va configurato come al solito, esattamente come si fa con GNU/Linux.
127.0.0.1
192.168.1.1
192.168.1.25
localhost
dinkel.brot.dg
minix.brot.dg
359.7.2 /etc/hostname.file
Il file ‘/etc/hostname.file’ serve solo a definire il nome dell’elaboratore locale, in senso
generale. Non ha niente a che vedere con le interfacce di rete.
# echo "minix.brot.dg" > /etc/hostname.file[ Invio ]
Minix
4056
359.7.3 /etc/resolv.conf
Il file ‘/etc/resolv.conf’ permette di indicare gli indirizzi dei nodi che forniscono un servizio
DNS. Nell’esempio proposto si vuole fare in modo che il sistema di risoluzione dei nomi avvenga
localmente, per mezzo di quanto contenuto nel file ‘/etc/hosts’. Per questo viene indicato
come servente DNS anche l’indirizzo locale (loopback).
nameserver 127.0.0.1
nameserver 192.168.1.1
359.7.4 /etc/rc.net
Lo script ‘/etc/rc.net’ viene utilizzato da ‘/etc/rc’ per attivare la rete. Lo si può utilizzare
per attivare l’interfaccia di rete e per definire l’instradamento verso il router (l’instradamento
verso la rete connessa all’interfaccia è predefinito).
# Attiva l’interfaccia e l’instradamento verso la sua rete.
ifconfig -h 192.168.1.25
# Definisce l’instradamento predefinito verso il router
add_route -g 192.168.1.1
359.7.5 /etc/rc
Probabilmente, è utile ritoccare il file ‘/etc/rc’, per eliminare l’avvio automatico di alcuni
demoni inutili dal momento che la rete è configurata. Quello che segue è il pezzo che attiva la
gestione della rete.
# Network initialization.
(</dev/eth </dev/tcp) 2>/dev/null && net=true
# Is there a TCP/IP server?
if [ "$net" -a -f /etc/rc.net ]
then
# There is a customized TCP/IP initialization script; run it.
. /etc/rc.net
elif [ "$net" ] && [ "‘hostaddr -e‘" = 0:0:0:0:0:0 ]
then
# No network hardware, configure a fixed address to run TCP/IP alone.
ifconfig -h 192.9.200.1
fi
if [ "$net" ]
then
echo -n "Starting network daemons: "
for daemon in rarpd nonamed irdpd talkd
do
if [ -f /usr/bin/$daemon ]
then
echo -n " $daemon"
$daemon &
fi
done
echo .
# Get the nodename from the DNS and set it.
hostaddr -a >/etc/hostname.file || echo noname >/etc/hostname.file
echo -n "Starting network services:"
for pair in ’shell in.rshd’ ’login in.rld’ \
’telnet in.telnetd’ ’ftp in.ftpd’
do
Minix
4057
set $pair
if [ -f /usr/bin/$2 ]
then
echo -n " $1"
tcpd $1 /usr/bin/$2 &
fi
done
echo .
fi
Vale la pena di modificare quanto segue:
if [ "$net" ]
then
echo -n "Starting network daemons: "
for daemon in nonamed talkd ### rarpd nonamed irdpd talkd
do
...
Nel pezzo precedente non vengono avviati i demoni ‘rarpd’ e ‘irdpd’, che sono necessari rispettivamente per ottenere l’indirizzo IP in base all’indirizzo hardware della scheda Ethernet
e a definire gli instradamenti verso i router. Eventualmente, si potrebbe anche evitare di avviare
‘talkd’ se non si intende utilizzare ‘talk’. Il demone ‘nonamed’ è necessario se non si vuole essere obbligati ad avere un servizio DNS esterno; in pratica è necessario perché venga interpretato
il contenuto del file ‘/etc/hosts’.
359.8 Personalizzazione
Il sistema risulta configurato in maniera piuttosto disordinata, a cominciare dal fatto che la directory personale dell’utente ‘root’ corrisponde alla directory radice; così, al suo interno si trovano
i file di configurazione dell’amministratore. Probabilmente, la prima cosa da fare è quella di
creare una directory ‘/root/’, porvi al suo interno i file di configurazione (dovrebbe trattarsi di
‘.ellepro.b1’, ‘.exrc’ e ‘.profile’), modificando anche il file ‘/etc/passwd’ in modo da
assegnare all’utente ‘root’ questa nuova directory.
359.8.1 /etc/passwd, /etc/group e /etc/shadow
Minix, nonostante la sua semplicità, utilizza le password shadow. Pertanto, se si tenta di inserire un utente manualmente, occorre intervenire anche su questo file, ‘/etc/shadow’, altrimenti
l’utente non riuscirà ad accedere.
Il file ‘/etc/group’, se non va bene com’è, deve essere modificato manualmente, mentre per gli
utenti conviene affidarsi allo script ‘adduser’.
adduser utente gruppo directory_home
Dopo aver creato un utente, come al solito è opportuno utilizzare il programma ‘passwd’ per
assegnare la parola d’ordine.5
359.9 Tastiera
La mappa della tastiera viene definita attraverso il programma ‘loadkeys’ e il file contenente la
mappa desiderata. Per cui,
5
Lo script ‘adduser’ si avvale della directory personale dell’utente ‘ast’ per inserire i file di configurazione iniziali.
Questa directory, corrispondente a ‘/usr/ast/’, svolge il ruolo di scheletro delle directory personali da creare. Volendo
si può realizzare un proprio script per rendere la cosa più elegante.
Minix
4058
# loadkeys ./tastiera.map
permette di caricare la mappa del file ‘tastiera.map’ contenuto nella directory corrente.
La mappa della tastiera, secondo la scelta fatta durante l’installazione di Minix, avviene per
mezzo del file ‘/etc/keymap’: se lo script ‘/etc/rc’ lo trova durante la fase di avvio, lo carica
attraverso ‘loadkeys’.
359.9.1 Modifica della mappa
La configurazione della tastiera italiana, per quanto riguarda la versione 2.0 di Minix, non è
perfetta. Per modificare la mappa occorre intervenire sul file ‘/usr/src/kernel/keymaps/
italian.src’. Dopo la modifica si deve compilare il sorgente in modo da ottenere il file
‘/usr/src/kernel/keymaps/italian.map’. Al termine, questo file va copiato e rinominato
in modo da sostituire ‘/etc/keymap’.
Il sorgente corretto potrebbe apparire come nell’esempio seguente, in particolare, per ottenere la
tilde (‘~’) si deve usare la combinazione [ AltGr+ì ], mentre per ottenere l’apostrofo inverso (‘‘’)
si deve usare la combinazione [ AltGr+’ ]. I caratteri che si trovano oltre il settimo bit, vengono
rappresentati in ottale.
/* Modified by Daniele Giacomini daniele @ swlibero.org
1998.12.22
/* Keymap for Italian standard keyboard, similar to Linux layout.
*/
*/
u16_t keymap[NR_SCAN_CODES * MAP_COLS] = {
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
scan-code
!Shift Shift
Alt
AltGr
Alt+Sh Ctrl
*/
==================================================================== */
00 - none
*/
0,
0,
0,
0,
0,
0,
01 - ESC
*/
C(’[’), C(’[’), CA(’[’),C(’[’), C(’[’), C(’[’),
02 - ’1’
*/
’1’,
’!’,
A(’1’), ’1’,
’!’,
C(’A’),
03 - ’2’
*/
’2’,
’"’,
A(’2’), ’2’,
’@’,
C(’@’),
04 - ’3’
*/
’3’,
0234,
A(’3’), ’3’,
0234,
C(’C’),
05 - ’4’
*/
’4’,
’$’,
A(’4’), ’4’,
’$’,
C(’D’),
06 - ’5’
*/
’5’,
’%’,
A(’5’), ’5’,
’%’,
C(’E’),
07 - ’6’
*/
’6’,
’&’,
A(’6’), ’6’,
’&’,
C(’F’),
08 - ’7’
*/
’7’,
’/’,
A(’7’), ’{’,
’/’,
C(’G’),
09 - ’8’
*/
’8’,
’(’,
A(’8’), ’[’,
’(’,
C(’H’),
10 - ’9’
*/
’9’,
’)’,
A(’9’), ’]’,
’)’,
C(’I’),
11 - ’0’
*/
’0’,
’=’,
A(’0’), ’}’,
’=’,
C(’@’),
12 - ’-’
*/
’\’’,
’?’,
A(’\’’),’\‘’,
’?’,
C(’@’),
13 - ’=’
*/
0215,
’^’,
0215,
’~’,
’^’,
C(’^’),
14 - BS
*/
C(’H’), C(’H’), CA(’H’),C(’H’), C(’H’), 0177,
15 - TAB
*/
C(’I’), C(’I’), CA(’I’),C(’I’), C(’I’), C(’I’),
16 - ’q’
*/
L(’q’), ’Q’,
A(’q’), ’q’,
’Q’,
C(’Q’),
17 - ’w’
*/
L(’w’), ’W’,
A(’w’), ’w’,
’W’,
C(’W’),
18 - ’e’
*/
L(’e’), ’E’,
A(’e’), ’e’,
’E’,
C(’E’),
19 - ’r’
*/
L(’r’), ’R’,
A(’r’), ’r’,
’R’,
C(’R’),
20 - ’t’
*/
L(’t’), ’T’,
A(’t’), ’t’,
’T’,
C(’T’),
21 - ’y’
*/
L(’y’), ’Y’,
A(’y’), ’y’,
’Y’,
C(’Y’),
22 - ’u’
*/
L(’u’), ’U’,
A(’u’), ’u’,
’U’,
C(’U’),
23 - ’i’
*/
L(’i’), ’I’,
A(’i’), ’i’,
’I’,
C(’I’),
24 - ’o’
*/
L(’o’), ’O’,
A(’o’), ’o’,
’O’,
C(’O’),
25 - ’p’
*/
L(’p’), ’P’,
A(’p’), ’p’,
’P’,
C(’P’),
26 - ’[’
*/
0212,
0202,
0212,
’[’,
’{’,
C(’[’),
27 - ’]’
*/
’+’,
’*’,
A(’+’), ’]’,
’}’,
C(’]’),
28 - CR/LF
*/
C(’M’), C(’M’), CA(’M’),C(’M’), C(’M’), C(’J’),
29 - Ctrl
*/
CTRL,
CTRL,
CTRL,
CTRL,
CTRL,
CTRL,
30 - ’a’
*/
L(’a’), ’A’,
A(’a’), ’a’,
’A’,
C(’A’),
31 - ’s’
*/
L(’s’), ’S’,
A(’s’), ’s’,
’S’,
C(’S’),
32 - ’d’
*/
L(’d’), ’D’,
A(’d’), ’d’,
’D’,
C(’D’),
33 - ’f’
*/
L(’f’), ’F’,
A(’f’), ’f’,
’F’,
C(’F’),
34 - ’g’
*/
L(’g’), ’G’,
A(’g’), ’g’,
’G’,
C(’G’),
Minix
/* 35
/* 36
/* 37
/* 38
/* 39
/* 40
/* 41
/* 42
/* 43
/* 44
/* 45
/* 46
/* 47
/* 48
/* 49
/* 50
/* 51
/* 52
/* 53
/* 54
/* 55
/* 56
/* 57
/* 58
/* 59
/* 60
/* 61
/* 62
/* 63
/* 64
/* 65
/* 66
/* 67
/* 68
/* 69
/* 70
/* 71
/* 72
/* 73
/* 74
/* 75
/* 76
/* 77
/* 78
/* 79
/* 80
/* 81
/* 82
/* 83
/* 84
/* 85
/* 86
/* 87
/* 88
/* 89
/* 90
/* 91
/* 92
/* 93
/* 94
/* 95
/* 96
/* 97
/* 98
/* 99
/*100
4059
-
’h’
*/
’j’
*/
’k’
*/
’l’
*/
’;’
*/
’\’’
*/
’‘’
*/
l. SHIFT*/
’\\’
*/
’z’
*/
’x’
*/
’c’
*/
’v’
*/
’b’
*/
’n’
*/
’m’
*/
’,’
*/
’.’
*/
’/’
*/
r. SHIFT*/
’*’
*/
ALT
*/
’ ’
*/
CapsLck */
F1
*/
F2
*/
F3
*/
F4
*/
F5
*/
F6
*/
F7
*/
F8
*/
F9
*/
F10
*/
NumLock */
ScrLock */
Home
*/
CurUp
*/
PgUp
*/
’-’
*/
Left
*/
MID
*/
Right
*/
’+’
*/
End
*/
Down
*/
PgDown */
Insert */
Delete */
Enter
*/
???
*/
???
*/
F11
*/
F12
*/
???
*/
???
*/
???
*/
???
*/
???
*/
???
*/
???
*/
EXT_KEY */
???
*/
???
*/
???
*/
???
*/
L(’h’),
L(’j’),
L(’k’),
L(’l’),
0225,
0205,
’\\’,
SHIFT,
0227,
L(’z’),
L(’x’),
L(’c’),
L(’v’),
L(’b’),
L(’n’),
L(’m’),
’,’,
’.’,
’-’,
SHIFT,
’*’,
ALT,
’ ’,
CALOCK,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
NLOCK,
SLOCK,
HOME,
UP,
PGUP,
NMIN,
LEFT,
MID,
RIGHT,
PLUS,
END,
DOWN,
PGDN,
INSRT,
0177,
C(’M’),
0,
’<’,
F11,
F12,
0,
0,
0,
0,
0,
0,
0,
EXTKEY,
0,
0,
0,
0,
’H’,
’J’,
’K’,
’L’,
0207,
0370,
’|’,
SHIFT,
’|’,
’Z’,
’X’,
’C’,
’V’,
’B’,
’N’,
’M’,
’;’,
’:’,
’_’,
SHIFT,
’*’,
ALT,
’ ’,
CALOCK,
SF1,
SF2,
SF3,
SF4,
SF5,
SF6,
SF7,
SF8,
SF9,
SF10,
NLOCK,
SLOCK,
’7’,
’8’,
’9’,
’-’,
’4’,
’5’,
’6’,
’+’,
’1’,
’2’,
’3’,
’0’,
’.’,
C(’M’),
0,
’>’,
SF11,
SF12,
0,
0,
0,
0,
0,
0,
0,
EXTKEY,
0,
0,
0,
0,
A(’h’), ’h’,
A(’j’), ’j’,
A(’k’), ’k’,
A(’l’), ’l’,
0225,
’@’,
0205,
’#’,
’\\’,
’\\’,
SHIFT, SHIFT,
0227,
0227,
A(’z’), ’z’,
A(’x’), ’x’,
A(’c’), ’c’,
A(’v’), ’v’,
A(’b’), ’b’,
A(’n’), ’n’,
A(’m’), ’m’,
A(’,’), ’,’,
A(’.’), ’.’,
A(’-’), ’-’,
SHIFT, SHIFT,
A(’*’), ’*’,
ALT,
ALT,
A(’ ’), ’ ’,
CALOCK, CALOCK,
AF1,
AF1,
AF2,
AF2,
AF3,
AF3,
AF4,
AF4,
AF5,
AF5,
AF6,
AF6,
AF7,
AF7,
AF8,
AF8,
AF9,
AF9,
AF10,
AF10,
NLOCK, NLOCK,
SLOCK, SLOCK,
AHOME, AHOME,
AUP,
AUP,
APGUP, APGUP,
ANMIN, ANMIN,
ALEFT, ALEFT,
AMID,
AMID,
ARIGHT, ARIGHT,
APLUS, APLUS,
AEND,
AEND,
ADOWN, ADOWN,
APGDN, APGDN,
AINSRT, AINSRT,
A(0177),0177,
CA(’M’),C(’M’),
0,
0,
A(’<’), ’|’,
AF11,
AF11,
AF12,
AF12,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
EXTKEY, EXTKEY,
0,
0,
0,
0,
0,
0,
0,
0,
’H’,
’J’,
’K’,
’L’,
’@’,
’#’,
’|’,
SHIFT,
’|’,
’Z’,
’X’,
’C’,
’V’,
’B’,
’N’,
’M’,
’;’,
’:’,
’_’,
SHIFT,
’*’,
ALT,
’ ’,
CALOCK,
ASF1,
ASF2,
ASF3,
ASF4,
ASF5,
ASF6,
ASF7,
ASF8,
ASF9,
ASF10,
NLOCK,
SLOCK,
’7’,
’8’,
’9’,
’-’,
’4’,
’5’,
’6’,
’+’,
’1’,
’2’,
’3’,
’0’,
’.’,
C(’M’),
0,
’>’,
ASF11,
ASF12,
0,
0,
0,
0,
0,
0,
0,
EXTKEY,
0,
0,
0,
0,
C(’H’),
C(’J’),
C(’K’),
C(’L’),
C(’@’),
C(’@’),
C(’\\’),
SHIFT,
C(’@’),
C(’Z’),
C(’X’),
C(’C’),
C(’V’),
C(’B’),
C(’N’),
C(’M’),
C(’@’),
C(’@’),
C(’_’),
SHIFT,
C(’M’),
ALT,
C(’@’),
CALOCK,
CF1,
CF2,
CF3,
CF4,
CF5,
CF6,
CF7,
CF8,
CF9,
CF10,
NLOCK,
SLOCK,
CHOME,
CUP,
CPGUP,
CNMIN,
CLEFT,
CMID,
CRIGHT,
CPLUS,
CEND,
CDOWN,
CPGDN,
CINSRT,
0177,
C(’J’),
0,
C(’@’),
CF11,
CF12,
0,
0,
0,
0,
0,
0,
0,
EXTKEY,
0,
0,
0,
0,
Minix
4060
/*101
/*102
/*103
/*104
/*105
/*106
/*107
/*108
/*109
/*110
/*111
/*112
/*113
/*114
/*115
/*116
/*117
/*118
/*119
/*120
/*121
/*122
/*123
/*124
/*125
/*126
/*127
};
-
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
Dopo la modifica, si avvia la compilazione.
# cd /usr/src/kernel/keymaps/[ Invio ]
# make[ Invio ]
Vengono generati tutti i file di configurazione che non siano già presenti (se si vuole ripetere la
compilazione occorre prima rimuovere il file ‘italian.map’).
# cp italian.map /etc/keymap[ Invio ]
Al prossimo riavvio sarà utilizzata la nuova mappa.
359.10 Altri programmi
Il software a disposizione per Minix non è molto e può essere trovato negli stessi FTP da cui
si accede ai file del sistema operativo citati qui. In particolare, tra i programmi riferiti alla rete,
vale la pena di ricordare i pacchetti ‘HTTPD.TAZ’ e ‘FROG.TAZ’. Il primo è un servente HTTP
molto semplice e il secondo è un programma per il tracciamento dell’instradamento (simile a
Traceroute). Sono entrambi molto utili e compilabili facilmente.
359.10.1 HTTPD.TAZ
Minix dispone di un servente HTTP elementare e lo si trova distribuito nel pacchetto
‘HTTPD.TAZ’. I pacchetti supplementari, come questo, vanno installati a partire dalla directory
‘/usr/local/’ e i sorgenti vanno collocati in ‘/usr/local/src/’.
# cd /usr/local/src[ Invio ]
Supponendo che il file ‘HTTPD.TAZ’ si trovi nel dischetto, montato nella directory ‘/mnt/’, si
può agire come segue:
Minix
4061
# cat /mnt/HTTPD.TAZ | compress -d | tar xvf -[ Invio ]
Si ottiene la creazione della directory ‘httpd/’ a partire dalla posizione corrente, cioè ‘/usr/
local/src/’.
# cd httpd[ Invio ]
Si procede con la compilazione.
# make[ Invio ]
Quindi si installa il programma.
# make install[ Invio ]
L’installazione non si occupa di copiare i file di configurazione: bisogna farlo manualmente.
# cp httpd.conf /etc[ Invio ]
# cp httpd.mtype /etc[ Invio ]
Il demone ‘httpd’, installato in ‘/usr/local/bin/’, ha bisogno di un utente ‘www’, in base
alla configurazione predefinita del file ‘/etc/httpd.conf’ che non serve modificare.
# adduser www operator /usr/home/www[ Invio ]
Naturalmente la scelta della directory personale di questo utente fittizio è solo un fatto di gusto personale. Sempre in base alla configurazione predefinita, occorre aggiungere alla directory
personale la directory ‘exec/’ e all’interno di questa si devono collocare un paio di file.
# mkdir /usr/home/www/exec[ Invio ]
# cp dir2html /usr/home/www/exec[ Invio ]
# cp dir2html.sh /usr/home/www/exec[ Invio ]
Per ultimo, occorre avviare il demone. Per questo conviene ritoccare il file ‘/etc/rc.net’ in
modo da aggiungere la riga seguente:
tcpd
http
/usr/local/bin/httpd &
359.10.2 FROG.TAZ
‘frog’ è un programma per il tracciamento dell’instradamento. È semplice, ma anche molto
importante. L’estrazione dell’archivio avviene nel modo solito, così come la compilazione e
l’installazione.
# cd /usr/local/src[ Invio ]
# cat /mnt/FROG.TAZ | compress -d | tar xvf -[ Invio ]
# cd frog[ Invio ]
# make[ Invio ]
# make install[ Invio ]
Tutto qui.
4062
Minix
359.11 Copie di sicurezza
Le copie di sicurezza possono essere fatte soltanto utilizzano ‘tar’ e ‘compress’. Dal momento
che il sistema è organizzato in modo piuttosto rigido, con una partizione principale molto piccola
e una partizione ‘/usr/’, normalmente conviene preoccuparsi solo di questa seconda partizione.
Per la prima converrebbe realizzare un dischetto di avvio e installazione con gli stessi file di
configurazione, compresi ‘/etc/passwd’, ‘/etc/group’ e ‘/etc/shadow’.
359.11.1 Archiviazione
Se si dispone di abbastanza spazio libero nella partizione ‘/usr/’, se ne può fare la copia di
sicurezza in un file collocato all’interno della stessa partizione. Successivamente si può scaricare
su dischetti. Si può procedere nel modo seguente:
# cd /usr[ Invio ]
# tar cf - . | compress -c > .BKP.TAZ[ Invio ]
Si ottiene il file ‘/usr/.BKP.TAZ’ contenente la copia di quanto contenuto nella directory corrente ‘/usr/’. Successivamente si può copiare il file ottenuto, a pezzi, su una serie di dischetti
formattati in precedenza. Si comincia con la formattazione e si suppone di disporre di dischetti
da 1440 Kibyte.
# format /dev/fd0 1440[ Invio ]
...
Una volta preparati i dischetti formattati, si può scaricare il file nei dischetti.
# dd if=/usr/.BKP.TAZ of=/dev/fd0 bs=1440k count=1 skip=0[ Invio ]
# dd if=/usr/.BKP.TAZ of=/dev/fd0 bs=1440k count=1 skip=2[ Invio ]
...
359.11.2 Recupero
Per recuperare un sistema archiviato nel modo mostrato nella sezione precedente, si deve cominciare dall’installazione con il dischetto iniziale. La cosa migliore sarebbe l’utilizzo di un dischetto
modificato opportunamente in modo che i file di configurazione corrispondano a quanto utilizzato
nel proprio sistema.
Dopo l’installazione iniziale che consiste nel trasferimento di quanto contenuto nel dischetto
iniziale nel disco fisso, si procede con l’installazione della copia (preparata in precedenza) della
partizione collocata a partire da ‘/usr/’.
# setup /usr[ Invio ]
Uno dopo l’altro verranno richiesti tutti i dischetti.
Minix
4063
359.12 Convivenza tra Minix e GNU/Linux
Se lo si desidera, si può fare convivere Minix assieme a GNU/Linux, nello stesso disco fisso, su
partizioni distinte. Ma installare Minix in una partizione libera di un disco in cui GNU/Linux è
già stato installato richiede prudenza e attenzione.
• L’installazione di Minix provoca l’alterazione dell’MBR del disco fisso, di conseguenza, al
termine si avvia solo Minix. Quindi, prima di installare Minix occorre preparare uno o più
dischi di avvio di GNU/Linux, in modo da poter in seguito ripristinare il sistema di avvio
attraverso LILO.
• Quando si conclude il lavoro con Minix e si esegue un riavvio con un semplice
[ Ctrl+Alt+Canc ], si ottiene un avvio a caldo (warm boot), ma se dopo si vuole avviare un
kernel Linux, questo non potrà essere caricato. Pertanto, è necessario un riavvio a freddo,
al limite attraverso lo spegnimento e la riaccensione dell’elaboratore.
359.12.1 LILO
Una volta che si è riusciti a fare riavviare il sistema GNU/Linux, con i dischetti di avvio a cui si
faceva riferimento in precedenza, conviene modificare il file ‘/etc/lilo.conf’ in modo che si
possa scegliere tra l’avvio di GNU/Linux, Minix ed eventualmente altro.
Supponendo di avere installato Minix nella seconda partizione del primo disco fisso, le righe
necessarie nel file ‘/etc/lilo.conf’ sono quelle seguenti:
other=/dev/hda2
label=minix
table=/dev/hda
Volendo supporre che Minix sia stato installato nel secondo disco fisso, sempre nella seconda
partizione, le righe sarebbero quelle seguenti:
other=/dev/hdb2
label=minix
table=/dev/hdb
loader=/boot/chain.b
In pratica, è esattamente ciò che si fa quando si vuole controllare l’avvio del Dos.
359.13 Riferimenti
Minix è un sistema operativo molto limitato rispetto a GNU/Linux. Resta comunque l’unica
opportunità, almeno per ora, di fronte a vecchi elaboratori i286 o inferiori.
Molti particolari importanti non sono stati descritti, ma le informazioni relative sono comunque
accessibili dai siti FTP di distribuzione di Minix e dalla documentazione interna costituita delle
pagine di manuale (‘man’).
• Andrew S. Tanenbaum, Alber S. Woodhull, Operating Systems: Design and Implementation, 2/e, Prentice-Hall
• <http://www.cs.vu.nl/~ast/minix.html>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
360
ELKS
Il progetto ELKS (Embeddable linux kernel subset) vuole creare un sistema operativo per i
microprocessori ix86 di fascia bassa, a partire da un sottoinsieme di funzionalità di GNU/Linux.
È possibile avviare un mini sistema composto da un dischetto di avvio (boot) e un dischetto contenente un sistema minimo; con un po’ di pazienza è anche possibile installarlo in una partizione
del disco fisso.
È disponibile un compilatore da utilizzare con GNU/Linux, per produrre binari ELKS, cioè
tutto il necessario per sviluppare questo nuovo sistema; è possibile eseguire i binari ELKS su
GNU/Linux, attraverso una libreria di emulazione; è possibile avviare ELKS anche all’interno di
DOSEMU.
360.1 Sperimentare ELKS
ELKS non è un sistema completo, quindi necessita di un pacchetto di sviluppo, composto essenzialmente da un compilatore, da utilizzare in una piattaforma GNU/Linux normale. Questo
pacchetto è Dev86, distribuito normalmente in forma sorgente.
Una volta scaricato il pacchetto di sviluppo, questo può essere espanso a partire dalla directory
‘/usr/src/’, nell’elaboratore GNU/Linux, come mostrato dall’esempio seguente:
# cd /usr/src[ Invio ]
# tar xzvf Dev86src-0.13.4.tar.gz[ Invio ]
Si otterrà la directory ‘/usr/src/linux-86’ che si articola ulteriormente. Terminata
l’installazione occorre compilare questi sorgenti e installarli.
# cd /usr/src/linux-86[ Invio ]
# make install[ Invio ]
A questo punto si può pensare ai sorgenti del kernel di ELKS e dei vari programmi di sistema e
di servizio. Anche questi vanno installati a partire da ‘/usr/src/’.
# cd /usr/src[ Invio ]
# tar xzvf elks-0.0.67.tar.gz[ Invio ]
# tar xzvf elkscmd.tar.gz[ Invio ]
Si ottengono le directory ‘/usr/src/elks/’ e ‘/usr/src/elkscmd/’. La prima contiene il
kernel, la seconda i programmi di contorno. Per compilare il kernel basta eseguire i passi seguenti.
# cd /usr/src/elks[ Invio ]
# make config[ Invio ]
# make dep ; make clean[ Invio ]
# make[ Invio ]
Si ottiene il file ‘/usr/src/elks/Image’ che può essere trasferito nel modo solito in un
dischetto, attraverso ‘cp’ o ‘dd’.
4064
ELKS
4065
Per compilare gli altri programmi occorre passare le varie directory in cui si articola ‘/usr/src/
elkscmd/’ e usare il comando ‘make’.
360.2 Immagini di dischetti già pronti
La realizzazione di un sistema ELKS è un po’ difficoltosa in questa fase iniziale del suo progetto
di realizzazione. La cosa migliore è partire dalle immagini già pronte, contenute normalmente in
un pacchetto unico. Per trasferirle nei dischetti ci si comporta nel modo solito, esattamente come
si fa per le immagini di dischetti di GNU/Linux.
Volendo, l’immagine ‘boot’ (quella di avvio) può essere sostituita semplicemente con un kernel compilato personalmente, mentre l’immagine ‘root’ può essere rielaborata aggiungendo o
sostituendo altri programmi. L’immagine ‘root’ contiene un file system Minix.
Per mettere in funzione il sistema ELKS è sufficiente avviare l’elaboratore con il dischetto ottenuto dall’immagine ‘boot’, sostituendolo con quello dell’immagine ‘root’, quando il kernel lo
richiede.
360.3 Avvio di ELKS all’interno di DOSEMU
ELKS può essere avviato all’interno di DOSEMU, sia in una console che in una finestra di X.
Per farlo basta avviare l’emulatore in modo che esegua il caricamento dal dischetto. Questo si
ottiene di solito utilizzando l’opzione ‘-A’.
# dos -A[ Invio ]
La figura 360.1 mostra la fase finale dell’avvio di ELKS. Si nota in particolare l’invito della
shell (il prompt), che è molto scarno: per ora non si possono usare i caratteri jolly e tutte le altre
funzioni cui si è abituati con le shell normali.
Figura 360.1. L’avvio di ELKS.
360.4 Riferimenti
• ELKS: the embeddable Linux kernel system
<http://elks.sourceforge.net/>
• Source Forge: ELKS
<http://sourceforge.net/projects/elks/>
4066
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
ELKS
Parte lxxvii
Dos
361 Dos: introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4070
361.1 Avvio del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4070
361.2 Dispositivi secondo il Dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4071
361.3 Directory, file ed eseguibili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4071
361.4 Comandi e ambiente di avvio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4073
361.5 Caratteri jolly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4074
361.6 Invito dell’interprete dei comandi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4075
361.7 Comandi interni principali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4075
361.8 Flussi standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4081
361.9 Accesso diretto ai dispositivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4083
361.10 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4083
362 Dos: dischi, file system, directory e file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4084
362.1 Suddivisione in partizioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4084
362.2 Inizializzazione di un’unità di memorizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . 4084
362.3 Etichetta di un’unità di memorizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4085
362.4 Analisi e correzione del file system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4086
362.5 Copia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4086
362.6 Trasferimento del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4087
362.7 Modifica delle unità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4087
362.8 Altre particolarità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4088
363 Dos: configurazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4092
363.1 CONFIG.SYS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4092
363.2 AUTOEXEC.BAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4096
363.3 Comandi ridondanti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4096
363.4 Localizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4097
363.5 Orologio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4098
364 Dos: script dell’interprete dei comandi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4099
364.1 Parametri, variabili ed espansione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4099
364.2 Chiamate di altri script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4099
364.3 Strutture di controllo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4099
364.4 Comandi utili negli script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4102
365 Dos: gestione della memoria centrale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4105
365.1 Gestione particolare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4105
4067
365.2 Comandi appositi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4105
365.3 Verifica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4106
366 FreeDOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4107
366.1 Installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4107
366.2 Impostazione e configurazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4108
366.3 RxDOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4109
366.4 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4109
367 Progetto GNUish . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4110
367.1 Programmi di servizio vari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4110
367.2 Gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4110
367.3 Spreadsheet Calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4111
367.4 Ispell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4111
367.5 Perl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4111
367.6 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4111
368 The valuable DOS Freeware page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4112
368.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4112
368.2 OS and GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4113
368.3 Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4113
368.4 Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4114
368.5 Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4115
368.6 Typesetting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4116
368.7 More Dos software sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4116
368.8 Search engines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4117
369 Clean the Clipper 5.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4118
369.1 Step 1: try to compile with the /P parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4120
369.2 Step 2: understand well the use of code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . 4120
369.3 Step 3: understand the object programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4121
369.4 Step 4: understand the get object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4122
369.5 Step 5: trying to stop using commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4124
369.6 Step 6: free yourself from STD.CH - /U . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4136
369.7 Step 7: take control over all include files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4136
370 nanoBase 1997 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4143
370.1 What is it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4143
370.2 The dot command line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4143
370.3 The menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4144
370.4 The macro recording, compiling and execution . . . . . . . . . . . . . . . . . . . . . . . . . . 4144
370.5 The report system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4145
370.6 The integrated text editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4146
4068
370.7 The internal documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4146
370.8 Download it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4147
370.9 Bugs and known problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4147
371 nanoBase 1997 user manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4149
371.1 Dos xBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4150
371.2 Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4154
371.3 How to use nB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4156
371.4 Status line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4157
371.5 The dot line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4158
371.6 The menu system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4158
371.7 The text editor DOC() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4169
371.8 The help text file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4170
371.9 Macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4170
371.10 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4174
371.11 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4182
371.12 Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4183
371.13 Code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4184
371.14 Standard functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4184
371.15 nB functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4232
371.16 Normal command substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4262
371.17 nB command substitution functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4269
371.18 RPT: the nB print function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4273
371.19 How can I... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4277
371.20 The source files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4277
4069
Capitolo
361
Dos: introduzione
DOS è acronimo di Disk Operating System e sta a indicare il nome di un sistema operativo per
micro elaboratori basati su microprocessori i86, successore del vecchio CP/M. Probabilmente,
data la sua estrema limitatezza, è un po’ azzardato voler parlare di «sistema operativo», tanto che
qualcuno lo appella: «gestore di interruzioni» (interrupt).
Questo sistema operativo nasce come software proprietario; tuttavia, attualmente il progetto più
attivo attorno a questo tipo di sistema è FreeDOS, il cui scopo è quello di realizzarne un’edizione
libera e completa.
361.1 Avvio del sistema
Un sistema Dos è composto essenzialmente da un kernel, un interprete dei comandi e da una
serie di programmi di servizio. Questo concetto è analogo ai sistemi Unix, con la differenza che
il kernel offre funzionalità molto scarse e solo per mezzo di interruzioni software (IRQ).
Nelle versioni proprietarie del Dos, il kernel era suddiviso in due file, che raccoglievano funzionalità distinte in base all’importanza relativa. I nomi usati sono stati differenti e nel caso di
FreeDOS il kernel è contenuto tutto in un solo file (tabella 361.1).
Tabella 361.1. Comparazione tra i nomi dei file che compongono il kernel di un
sistema Dos.
Microsoft
IO.SYS
MSDOS.SYS
IBM
IBMBIO.COM
IBMDOS.COM
Novell, Caldera
IBMBIO.COM
IBMDOS.COM
RxDOS
RXDOSBIO.SYS
RXDOS.SYS
FreeDOS
KERNEL.SYS
--
I file del kernel devono trovarsi nella directory radice della partizione o del dischetto per poter
essere avviati. Per la precisione, l’avvio del kernel viene gestito direttamente dal codice inserito
nel settore di avvio della partizione o del dischetto (512 Kibyte), che a sua volta viene avviato
dal firmware (il BIOS, secondo la terminologia specifica dell’architettura i86 e successiva).
Il kernel, dopo essere stato avviato, non attiva una procedura di avvio, ma si limita a interpretare uno script speciale, ‘CONFIG.SYS’, e subito dopo avvia l’interprete dei comandi, ovvero
la shell. Tradizionalmente, il programma in questione è ‘COMMAND.COM’. Secondo la tradizione, l’interprete dei comandi che viene avviato dal kernel si occupa subito di eseguire lo script
‘AUTOEXEC.BAT’. Gli script ‘CONFIG.SYS’ e ‘AUTOEXEC.BAT’ devono trovarsi nella directory
radice del disco o della partizione da cui si avvia il sistema, ovvero quella in cui si trova già il
kernel che viene avviato.
L’interprete dei comandi, ‘COMMAND.COM’, è in grado di eseguire direttamente alcune funzionalità, attraverso comandi interni che non si traducono in programmi di servizio veri e propri.
Tradizionalmente ‘COMMAND.COM’ si colloca nella directory radice del disco o della partizione
in cui si trova il kernel stesso. Ciò non è propriamente indispensabile, ma conviene attenersi a
questa linea per evitare fastidi inutili.
4070
Dos: introduzione
4071
361.2 Dispositivi secondo il Dos
I dispositivi secondo il Dos hanno un nome, composto da lettere e cifre numeriche, terminato da
due punti opzionali:
[]
nome_dispositivo :
Il nome in questione può essere indicato utilizzando lettere maiuscole o minuscole, senza che la
cosa faccia differenza. I nomi più comuni sono elencati nella tabella 361.2. È il caso di osservare che i due punti che concludono il nome, vanno usati necessariamente quando questo viene
abbinato ad altre informazioni da cui non potrebbe essere distinto (per esempio un percorso).
Tabella 361.2. Nomi dei dispositivi più comuni in Dos.
Dispositivo
‘A:’
‘B:’
‘C:’
‘D:’, ‘E:’,... ‘Z:’
‘CON:’
‘PRN:’
‘LPT1:’, ‘LPT2:’,...
‘COM1:’, ‘COM2:’,...
Descrizione
Disco nella prima unità a dischetti.
Disco nella seconda unità a dischetti.
Prima partizione Dos nel primo disco fisso.
Partizione Dos o altro tipo di disco.
Console: tastiera e schermo.
Porta stampante principale.
Porte parallele.
Porte seriali.
Il Dos mantiene distinti i dischi e le partizioni, nel senso che questi non devono creare una
struttura unica come avviene nei sistemi Unix. Pertanto, quando si fa riferimento a un percorso
di un file o di una directory, si deve tenere in considerazione anche il disco o la partizione in cui
si trova.
Il modo utilizzato dal Dos per identificare i dischi e le partizioni, di fatto impedisce di accedere a
questi dispositivi in modo indipendente dal file system sottostante. Per intenderci, l’«unità» ‘X:’
può essere una partizione Dos di un disco non meglio identificato; mentre non esiste un modo
univoco per poter raggiungere il dispositivo fisico in cui si trova questo disco.
361.3 Directory, file ed eseguibili
Il Dos è nato dopo Unix e da questo sistema ha ereditato alcuni concetti elementari (forse troppo
pochi). I percorsi di file e directory si separano con una barra obliqua, che però è inversa rispetto
allo Unix. Anche con il Dos c’è una directory radice; tuttavia si aggiunge l’indicazione dell’unità
di memorizzazione (il disco o la partizione). Si può osservare a questo proposito la figura 361.1.
Figura 361.1. Struttura di un percorso in un file system Dos.
C:\PRIMO\SECONDO\TERZO\QUARTO
^ ^
^
^
^
| |
|
|
|
| |
|
|
file o directory finale
| |
|
|
| |
|
directory
| |
|
| |
separazione tra una directory e la successiva
| |
| directory radice
|
unità di memorizzazione
I nomi di file e directory possono essere indicati utilizzando lettere maiuscole o minuscole, senza
che la cosa possa fare differenza. Questi nomi possono essere composti utilizzando anche cifre
numeriche e altri simboli (che comunque è bene usare con parsimonia).
4072
Dos: introduzione
Per la precisione, sono esclusi i simboli: ‘/’, ‘\’, ‘[’, ‘]’, ‘<’, ‘>’, ‘+’, ‘=’, ‘;’, ‘:’, ‘,’, ‘?’, ‘*’,
‘{’, ‘}’ e il punto che va usato esattamente come descritto nel seguito.
Tradizionalmente, il Dos utilizza un tipo di file system elementare, denominato FAT (Dos-FAT),
in cui i nomi dei file e delle directory possono essere composti utilizzando al massimo 11 caratteri, di cui otto compongono un prefisso e tre un suffisso. Il prefisso e il suffisso di questi nomi
appaiono uniti attraverso un punto. Per esempio: ‘CIAO.COM’, ‘LETTERA.TXT’, ‘PIPPO.NB’,...
Questa conformazione dei nomi è una caratteristica fondamentale del Dos, da cui derivano una
serie di consuetudini e di limitazioni molto importanti.
È importante osservare che non è opportuno che i nomi dei file coincidano con quelli dei dispositivi (senza i due punti finali). In pratica, non conviene creare file del tipo ‘CON:’, ‘PRN:’,
ecc. Tutto dipende dal contesto, ma in generale è bene fare attenzione a questo particolare.
Come nei sistemi Unix il Dos annovera il concetto di directory corrente, a cui si aggiunge il
concetto di unità di memorizzazione corrente. Infatti, la directory va collocata in un disco o
in una partizione. In base a questo principio, si possono indicare dei percorsi relativi, che fanno riferimento alla posizione corrente (nell’unità di memorizzazione corrente). Tuttavia, in più,
ogni unità di memorizzazione ha una sua directory corrente. Per esempio, fare riferimento a un
file in una certa unità di memorizzazione ‘x :’, senza specificare il percorso, significa indicare
implicitamente la directory corrente di quella unità.
Per esempio, supponendo che la directory corrente dell’unità ‘X:’ sia ‘X:\PRIMO\SECONDO\’,
facendo riferimento al file ‘X:CIAO’, si intende indicare implicitamente il file ‘X:\PRIMO\
SECONDO\CIAO’.
In un percorso si possono usare anche i simboli ‘.’ e ‘..’, con lo stesso significato che hanno in
un sistema Unix: la directory stessa e la directory genitrice.
Il file system tradizionale del Dos consente di annotare solo poche informazioni per i file e le
directory: la data di modifica e quattro indicatori booleani, rappresentati da altrettante lettere:
• H file o directory nascosti;
• S file o directory di sistema;
• R file o directory in sola lettura e non cancellabile;
• A file o directory da archiviare (i dati sono stati modificati).
Si tratta di attributi completamente differenti da quelli di Unix. Si può osservare in particolare la
mancanza di un attributo che specifichi la possibilità di eseguire un programma o di attraversare
una directory. Secondo la tradizione Dos, gli attributi vanno considerati nel modo seguente:
• A viene attivato ogni volta che il file viene scritto o modificato e serve per automatizzare
i sistemi di copia periodica;
• R se attivo, il Dos non consente la scrittura o la rimozione;
• S se attivo si tratta di un file di «sistema», ma in pratica si comporta come l’attributo H;
• H se attivo si tratta di un file «nascosto», che così non dovrebbe apparire nelle liste di file
e directory.
Dos: introduzione
4073
In generale, file e directory nascosti o di sistema non dovrebbero essere spostati fisicamente,
nemmeno nell’ambito della stessa unità di memorizzazione. Questa esigenza nasce in particolare per i file del kernel, che non possono essere spostati se si vuole poter riavviare il sistema
operativo.
Dal momento che il file system non permette di determinare se un file è un eseguibile, l’unico
modo per permettere al sistema di conoscere questa caratteristica sta nell’uso di suffissi convenzionali nei nomi: i file che terminano con l’estensione ‘.COM’ e ‘.EXE’ sono programmi binari
(la differenza tra i due tipi di estensione riguarda il formato del binario); quelli che terminano per
‘.BAT’ sono script dell’interprete dei comandi (‘COMMAND.COM’).
La prima stranezza che deriva da questa caratteristica del Dos sta nel fatto che per avviare un
eseguibile di questi, è sufficiente indicare il nome del file senza l’estensione, che diventa così
un componente opzionale agli occhi dell’utilizzatore.
361.4 Comandi e ambiente di avvio
L’interprete dei comandi tradizionale dei sistemi Dos è il programma ‘COMMAND.COM’, che viene
avviato direttamente dal kernel. ‘COMMAND.COM’ può essere avviato più volte successive, anche
se di solito ciò è di scarsa utilità, dal momento che il Dos non è un sistema operativo in multiprogrammazione. In ogni caso, quando viene avviato dal kernel, si occupa di interpretare ed eseguire
lo script ‘AUTOEXEC.BAT’ che si trova nella directory radice dell’unità di avvio.
‘COMMAND.COM’ mostra un invito simile idealmente a quello delle shell Unix, dopo il quale possono essere inseriti i comandi. A loro volta, questi possono essere riferiti a comandi interni
corrispondenti a funzionalità offerte direttamente dall’interprete, oppure possono rappresentare
la richiesta di avvio di un programma esterno.
Figura 361.2. Riga di comando.
C:\>DIR A: /W
^
^ ^ ^
|
| | |
|
| | opzione
|
| |
|
| argomento
|
|
|
comando
|
invito
Il Dos ha ereditato da Unix anche il concetto di variabile di ambiente. Il meccanismo è lo stesso
ed è fondamentale la variabile di ambiente ‘PATH’, con la quale si possono indicare i percorsi di
ricerca degli eseguibili. Tuttavia, il Dos ha delle caratteristiche speciali, per cui, è il caso di fare
alcuni esempi di comandi:
• C:\>C:\PRIMO\SECONDO.EXE
questo comando avvia l’esecuzione del file ‘C:\PRIMO\SECONDO.EXE’;
• C:\>C:\PRIMO\SECONDO
questo comando potrebbe avviare l’esecuzione del primo dei file seguenti che riesce a
trovare;
– ‘C:\PRIMO\SECONDO.COM’
Dos: introduzione
4074
– ‘C:\PRIMO\SECONDO.EXE’
– ‘C:\PRIMO\SECONDO.BAT’
• C:\>SECONDO
questo comando potrebbe avviare l’esecuzione del primo dei file seguenti che dovesse riuscire a trovare, ma in mancanza può continuare la ricerca nei percorsi indicati nella variabile
di ambiente ‘PATH’.
– ‘C:.\SECONDO.COM’
– ‘C:.\SECONDO.EXE’
– ‘C:.\SECONDO.BAT’
I percorsi indicati nella variabile di ambiente ‘PATH’ sono separati da un punto e virgola; per
esempio:
C:\;C:\DOS;C:\FDOS\BIN
Di solito, il Dos dà per scontato che si cerchino gli eseguibili a cominciare dalla directory corrente. Per questo, occorre considerare che è sempre come se la variabile di ambiente ‘PATH’
contenesse questa indicazione prima delle altre: ‘.;C:\;C:\DOS;C:\FDOS\BIN’. È da osservare che FreeDOS si comporta in maniera differente, in quanto richiede espressamente
questa indicazione della directory corrente.
361.5 Caratteri jolly
Il Dos imita l’utilizzo dei caratteri jolly come avviene nei sistemi Unix per opera delle shell.
Tuttavia, nel Dos non si tratta di un’espansione che avviene per opera della shell, ma vi deve
provvedere ogni programma per conto proprio. Questo rappresenta una gravissima deficienza del
Dos, che però è irrimediabile.
Su questa base, i comandi tendono a richiedere l’indicazione di un argomento che rappresenta il
nome di uno o più file prima delle opzioni eventuali.
Ma c’è un altro problema. Il punto che divide in due i nomi dei file e delle directory è un muro
insuperabile per i caratteri jolly.
I simboli che si possono utilizzare sono solo l’asterisco e il punto interrogativo. L’asterisco vale per una sequenza qualunque di caratteri, escluso il punto; il punto interrogativo vale per un
carattere qualunque.1
Esempi
*.*
Corrisponde a un nome qualunque.
*.COM
Un nome che termina con l’estensione ‘.COM’.
CIAO.X?X
Tutti i nomi che iniziano per ‘CIAO’ e hanno un’estensione composta da un lettera «X»
iniziale e finale, senza specificare cosa ci sia al secondo posto.
*
Tutti i nomi che non hanno estensione (che non contengono il punto).
1
Ci sono programmi di origine Unix, portati in Dos, che non hanno questa limitazione riferita al punto che separa
l’estensione.
Dos: introduzione
4075
361.6 Invito dell’interprete dei comandi
Esiste un’altra variabile di ambiente fondamentale per il Dos. Si tratta di ‘PROMPT’, che consente
di modificare l’aspetto dell’invito dell’interprete dei comandi. La cosa funziona un po’ come nelle shell Unix, per cui si assegna una stringa che può contenere dei simboli speciali, praticamente
delle sequenze di escape che vengono espanse prima della visualizzazione. La tabella 361.3 riepiloga questi simboli particolari. In origine, il Dos mostrava in modo predefinito un invito simile
all’esempio seguente,
C>
in cui appare solo l’unità di memorizzazione corrente. Questo tipo di impostazione corrisponderebbe alla stringa ‘$N$G’. In seguito, si è passati a un invito simile al prossimo
esempio,
C:\BIN\>
in cui si aggiunge anche l’informazione della directory corrente. Questo corrisponde alla stringa
‘$P$G’.
Tabella 361.3. Sequenze di escape per definire dei componenti speciali all’interno di
una stringa di invito.
Simbolo
$Q
$$
$T
$D
$V
$N
$G
$L
$B
$H
$E
$_
Corrispondenza
=
$
Ora corrente.
Data corrente.
Numero della versione.
Lettera dell’unità corrente.
>
<
|
<BS> (cancella il carattere precedente)
<ESC> (1B16)
Codice di interruzione di riga.
Cancellando il contenuto della variabile di ambiente ‘PROMPT’ si ripristina la stringa di invito
predefinita.
361.7 Comandi interni principali
I comandi interni sono quelli che non corrispondono a programmi di servizio veri e propri,
ma sono funzionalità svolte direttamente dall’interprete dei comandi. Nelle sezioni seguenti ne
vengono descritti brevemente alcuni.
361.7.1 CH, CHDIR
[percorso]
CHDIR [percorso]
CH
‘CH’, o ‘CHDIR’, è un comando interno dell’interprete dei comandi, che consente di visualizzare
o di cambiare la directory corrente. È indifferente l’uso di ‘CD’ o di ‘CHDIR’; se il comando non
è seguito dal percorso, si ottiene solo la visualizzazione della directory corrente. Si osservi che
Dos: introduzione
4076
se si indica un percorso assoluto di unità di memorizzazione, se questa non corrisponde a quella
attuale, si cambia la directory corrente di quella unità.
Esempi
C:\>CD
Visualizza la directory corrente.
C:\>CD \TMP\LAVORO
Sposta la directory corrente in ‘\TMP\LAVORO\’.
C:\TMP\LAVORO>CD DATI\LETTERE
Sposta la directory corrente in ‘DATI\LETTERE\’ che a sua volta discende dalla posizione
iniziale precedente.
C:\TMP\LAVORO\DATI\LETTERE>CD ..
Sposta la directory corrente nella posizione della directory genitrice di quella iniziale.
C:\TMP\LAVORO\DATI>CD F:\TMP
Cambia la directory corrente dell’unità ‘F:’, senza intervenire nell’unità corrente.
361.7.2 X:
{A|B|...|Z}:
Il Dos gestisce le unità di memorizzazione in modo speciale. Per cambiare l’unità di memorizzazione corrente, non esiste un comando analogo a ‘CD’: si deve indicare il nome dell’unità a cui si
vuole accedere.
Esempi
C:\>A:
Cambia l’unità di memorizzazione attuale, facendola diventare ‘A:’.
A:\>F:
Cambia l’unità di memorizzazione attuale, facendola diventare ‘F:’.
361.7.3 MD, MKDIR
MD directory
MKDIR directory
‘MD’, o ‘MKDIR’, è un comando interno dell’interprete dei comandi, che consente di creare una
directory vuota.
Esempi
C:\>MD LAVORO
Crea la directory ‘LAVORO\’ a partire da quella corrente.
C:\>MD \TMP\DATA
Dos: introduzione
Crea la directory ‘\TMP\DATA\’ nell’unità corrente.
C:\>MD F:\TMP\DATA
Crea la directory ‘\TMP\DATA\’ nell’unità ‘F:’.
4077
Dos: introduzione
4078
361.7.4 RD, RMDIR
RM directory
RMDIR directory
‘RD’, o ‘RMDIR’, è un comando interno dell’interprete dei comandi, che consente di cancellare
una directory vuota.
Esempi
C:\>RD LAVORO
Cancella la directory ‘LAVORO\’ a partire da quella corrente.
C:\>RD \TMP\DATA
Cancella la directory ‘\TMP\DATA\’ nell’unità corrente.
C:\>RD F:\TMP\DATA
Cancella la directory ‘\TMP\DATA\’ nell’unità ‘F:’.
361.7.5 DIR
DIR
[directory|file] [/P] [/W]
‘DIR’ è un comando interno dell’interprete dei comandi, che consente di visualizzare l’elenco del
contenuto di una directory o l’elenco di un gruppo di file. L’argomento del comando può essere
composto utilizzando caratteri jolly, secondo lo standard del Dos, ovvero i simboli ‘*’ e ‘?’.
Alcune opzioni
/P
Blocca lo scorrimento dell’elenco in attesa della pressione di un tasto quando questo è più
lungo del numero di righe che possono apparire sullo schermo.
/W
Visualizza solo i nomi dei file e delle directory, senza altre informazioni, permettendo così
di vedere più nomi assieme in un’unica schermata.
Esempi
C:\>DIR *.*
Visualizza l’elenco di tutti i file contenuti nella directory corrente.
C:\>DIR ESEMPIO.*
Visualizza l’elenco di tutti i file il cui nome inizia per ‘ESEMPIO’ e continua con
un’estensione qualunque.
C:\>DIR *.DOC
Visualizza l’elenco di tutti i file il cui nome termina con l’estensione ‘.DOC’.
C:\>DIR F:\DOC\*.*
Visualizza l’elenco di tutti i file contenuti nella directory ‘\DOC\’ dell’unità ‘F:’.
C:\>DIR F:
Visualizza l’elenco di tutti i file contenuti nella directory corrente dell’unità ‘F:’.
Dos: introduzione
4079
361.7.6 COPY
[file_destinazione ] [opzioni]
file_2 [+ ...] [file_destinazione ] [opzioni]
COPY file_origine
COPY file_1 +
‘COPY’ è un comando interno dell’interprete dei comandi, che consente di copiare uno o più file
(sono escluse le directory). Anche qui è consentito l’uso di caratteri jolly, ma al contrario dei
sistemi Unix, i caratteri jolly possono essere usati anche nella destinazione. Il ‘COPY’ del Dos
consente anche di unire assieme più file.
Alcune opzioni
/V
Fa in modo che venga verificato il risultato della copia.
/B
Fa sì che la copia avvenga in modo «binario». Questa opzione può servire quando si copia
un file su un dispositivo e si vuole evitare che alcuni codici vengano interpretati in modo
speciale.
/Y
Non chiede conferma prima di sovrascrivere i file, se questi esistono già nella destinazione.
Esempi
C:\>COPY ESEMPIO PROVA
Copia il file ‘ESEMPIO’ nella directory corrente ottenendo il file ‘PROVA’, sempre nella
directory corrente.
C:\>COPY C:\DOS\*.* C:\TMP
Copia tutto il contenuto della directory ‘\DOS\’ dell’unità ‘C:’ nella directory ‘\TMP\’
nella stessa unità ‘C:’, mantenendo gli stessi nomi.
C:\>COPY TESTA+CORPO+CODA LETTERA
Copia, unendoli, i file ‘TESTA’, ‘CORPO’ e ‘CODA’, ottenendo il file ‘LETTERA’.
C:\>COPY *.DOC *.TXT
Copia tutti i file che nella directory corrente hanno un nome che termina con l’estensione
‘.DOC’, generando altrettanti file, con lo stesso prefisso, ma con l’estensione ‘.TXT’.
C:\>COPY PROVA.PRN PRN: /B
Copia il file ‘PROVA.PRN’ nel dispositivo ‘PRN:’, ovvero sulla stampante, assicurandosi
che la copia avvenga senza alterare alcunché.
361.7.7 DEL, ERASE
DEL file
ERASE file
‘DEL’, o ‘ERASE’, è un comando interno dell’interprete dei comandi, che consente di cancellare
uno o più file (sono escluse le directory). È da considerare che i file che hanno l’attributo di sola
lettura attivo, non possono essere modificati e nemmeno cancellati.
Dos: introduzione
4080
Esempi
C:\TMP>DEL *.*
Cancella tutti i file nella directory corrente.
C:\TMP>DEL ESEMPIO.*
Cancella tutti i file contenuti nella directory corrente, il cui nome inizia per ‘ESEMPIO’ e
termina con qualunque estensione.
C:\TMP>DEL *.BAK
Cancella tutti i file contenuti nella directory corrente, il cui nome termina con l’estensione
‘.BAK’.
361.7.8 REN, RENAME
REN file_origine nome_nuovo
RENAME file_origine nome_nuovo
‘REN’, o ‘RENAME’, è un comando interno dell’interprete dei comandi, che consente di cambiare
il nome di uno o più file (sono escluse le directory). Il primo argomento può essere un percorso
relativo o assoluto, completo anche dell’indicazione dell’unità, mentre il secondo argomento è il
nuovo nome, che implicitamente non può essere collocato altrove.
Esempi
C:\>REN ESEMPIO PROVA
Cambia il nome del file ‘ESEMPIO’, che si trova nella directory corrente, in ‘PROVA’.
C:\>REN *.TXT *.DOC
Cambia il nome di tutti i file che, nella directory corrente, hanno l’estensione ‘.TXT’,
trasformandoli in modo tale da avere un’estensione ‘.DOC’.
361.7.9 SET
SET
[variabile_di_ambiente =stringa]
‘SET’ è un comando interno dell’interprete dei comandi che ha lo scopo di assegnare un valore
a una variabile di ambiente, oppure di leggere lo stato di tutte le variabili di ambiente esistenti.
Quando si assegna un valore a una variabile, questa viene creata simultaneamente; quando non
si assegna nulla a una variabile, la si elimina.
Esempi
C:\>SET
Elenca le variabili di ambiente esistenti assieme al loro valore.
C:\>SET PROMPT=$P$G$G
Assegna alla variabile di ambiente ‘PROMPT’ la stringa ‘$P$G$G’. Questo si traduce nella
modifica dell’aspetto dell’invito dell’interprete dei comandi.
C:\>SET PATH=.;C:\BIN;D:\BIN
Dos: introduzione
4081
Assegna alla variabile di ambiente ‘PATH’ la stringa ‘.;C:\BIN;D:\BIN’.
C:\>SET PROMPT=
Elimina la variabile di ambiente ‘PROMPT’, assegnandole la stringa nulla.
361.7.10 TYPE
TYPE file
‘TYPE’ è un comando interno dell’interprete dei comandi, che consente di leggere ed emet-
tere il contenuto di un file attraverso lo standard output. Questo si traduce in pratica nella
visualizzazione del file in questione.
Esempi
C:\>TYPE LETTERA
Emette il contenuto del file ‘LETTERA’ che si trova nella directory e nell’unità corrente.
C:\>TYPE C:\DOC\MANUALE
Emette il contenuto del file ‘MANUALE’ che si trova nella directory ‘\DOC\’ dell’unità ‘C:’.
361.8 Flussi standard
Il Dos ha ereditato da Unix anche i concetti legati ai flussi standard. In pratica, i programmi
hanno a disposizione tre flussi predefiniti: uno in lettura rappresentato dallo standard input, due
in scrittura rappresentati dallo standard output e dallo standard error. Il meccanismo è lo stesso di
Unix, anche se non funziona altrettanto bene; infatti, non è possibile ridirigere lo standard error
attraverso l’interprete dei comandi.
Secondo la tradizione delle shell Unix, la ridirezione dello standard output si ottiene con il simbolo ‘>’ posto alla fine del comando interessato, seguito poi dal nome del file che si vuole generare
in questo modo. Per esempio,
C:\>TYPE LETTERA > PRN:
invece di visualizzare il contenuto del file ‘LETTERA’, lo invia al dispositivo di stampa
corrispondente al nome ‘PRN:’; inoltre,
C:\>DIR *.* > ELENCO
invece di visualizzare l’elenco dei file che si trovano nella directory corrente, crea il file ‘ELENCO’
con questi dati.
La ridirezione dello standard output fatta in questo modo, va a cancellare completamente il contenuto del file di destinazione, se questo esiste già; al contrario, si può utilizzare anche ‘>>’, con
il quale, il file di destinazione viene creato se non esiste, oppure viene solo esteso.
Lo standard input viene ridiretto utilizzando il simbolo ‘<’, con il quale è possibile inviare un file
a un comando utilizzando il flusso dello standard input.
Alcuni comandi hanno la caratteristica di utilizzare esclusivamente i flussi standard. Si parla in
questi casi di programmi filtro. Il programma di servizio tipico che si comporta in questo modo
è ‘SORT’, il quale riceve un file di testo dallo standard input e lo riordina restituendolo attraverso
lo standard output. Si osservi l’esempio seguente:
Dos: introduzione
4082
C:\>SORT < ELENCO > ORDINATO
In questo modo, ‘SORT’ riceve dallo standard input il file ‘ELENCO’ e genera attraverso la
ridirezione dello standard output il file ‘ORDINATO’.
Per mettere in contatto lo standard output di un comando con lo standard input del successivo, si
utilizza il simbolo ‘|’. L’esempio seguente mostra un modo alternativo di ottenere l’ordinamento
di un file:
C:\>TYPE ELENCO | SORT > ORDINATO
In generale, tutti i comandi che generano un risultato visuale che scorre sullo schermo, utilizzano
semplicemente lo standard output, che può essere ridiretto in questo modo. Si osservi ancora
l’esempio seguente che riordina il risultato del comando ‘DIR’, mostrandolo comunque sullo
schermo:
C:\>DIR *.DOC | SORT
Nelle sezioni seguenti vengono mostrati alcuni comandi filtro.
361.8.1 SORT
SORT
[opzioni]
< file_da_ordinare > file_ordinato
Il comando ‘SORT’, che dovrebbe corrispondere a un programma di servizio vero e proprio, riordina il file di testo che ottiene dallo standard input, generando un risultato che emette attraverso
lo standard output.
Alcune opzioni
/R
Riordina in modo decrescente
/+n_colonna
Riordina in base al testo che inizia a partire dalla colonna indicata come argomento (si tratta
di un numero a partire da uno, per indicare la prima colonna).
Esempi
C:\>DIR *.DOC | SORT /+10
Emette l’elenco della directory corrente riordinato in base all’estensione, che è
un’informazione collocata a partire dalla decima colonna.
361.8.2 MORE
MORE < file_da_leggere
MORE file_da_leggere
Il comando ‘MORE’ legge un file, fornito come argomento o attraverso lo standard input, mostrandolo poi sullo schermo una pagina dopo l’altra. In questo modo, è possibile leggere il contenuto
dei file più lunghi delle righe a disposizione sullo schermo.
Per passare alla pagina successiva, basta premere un tasto qualunque, oppure ciò che viene
indicato espressamente.
Dos: introduzione
4083
Esempi
C:\>DIR | MORE
Permette di controllare lo scorrimento a video del risultato del comando ‘DIR’.
C:\>MORE LETTERA.TXT
Permette di controllare lo scorrimento a video del contenuto del file ‘LETTERA.TXT’.
C:\>TYPE LETTERA.TXT | MORE
Si ottiene lo stesso risultato dell’esempio precedente, attraverso l’uso di una pipeline.
361.9 Accesso diretto ai dispositivi
Il Dos offre poche occasioni per accedere direttamente ai dispositivi. Si tratta generalmente solo della console e della porta parallela. L’esempio seguente mostra come «copiare» un file sul
dispositivo di stampa, per ottenere così la sua stampa diretta:
C:\>COPY LETTERA PRN:
La stessa cosa avrebbe potuto essere ottenuta con la ridirezione dei flussi standard:
C:\>TYPE LETTERA > PRN:
Può essere interessante la possibilità di copiare il flusso di ingresso della console in un file:
C:\>COPY CON: LETTERA
In questo caso, l’inserimento nel file ‘LETTERA’ prosegue fino a quando viene ricevuto un codice
EOF, che si ottiene qui con la combinazione di tasti [ Ctrl+z ] seguita da [ Invio ].
È bene ricordare che la console, ovvero il dispositivo ‘CON:’, riceve dati in ingresso attraverso la
tastiera ed emette dati in uscita utilizzando lo schermo. In pratica, quando un programma attende
dati dallo standard input non ridiretto, li riceve dalla console, cioè dalla tastiera; nello stesso
modo, quando un programma emette dati attraverso lo standard output non ridiretto, li invia alla
console, cioè sullo schermo.
361.10 Riferimenti
• FreeDOS
<http://www.freedos.org>
• OpenDOS Unofficial Home Page
<http://www.deltasoft.com/opendos.htm>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
362
Dos: dischi, file system, directory e file
La gestione dei dischi, ovvero delle unità di memorizzazione di massa, è molto particolare nel
Dos. In generale, si fa riferimento a queste cose attraverso un lettera che ne rappresenta il dispositivo; tuttavia, tale dispositivo può indicare un disco intero o solo una partizione, riferendosi
sempre solo a dischi e partizioni Dos.
362.1 Suddivisione in partizioni
Nel Dos, tutti i dischi rimovibili, come i dischetti, non vanno suddivisi in partizioni, mentre i
dischi fissi devono essere preparati in questo modo. Il programma che si usa per queste cose è
‘FDISK’.
Secondo il Dos, le partizioni di un disco possono essere solo quattro. Tuttavia, una partizione
normale può essere suddivisa in sottopartizioni, che vengono definite tradizionalmente «estese», dove anche queste possono essere al massimo quattro. Una tale struttura ha condizionato
in pratica anche altri sistemi operativi, per esempio GNU/Linux. Bisogna tenere in considerazione l’origine storica per comprendere che altri sistemi operativi possono comportarsi in
modo completamente differente.
Di solito, ‘FDISK’ ha una visione delle partizioni tutta orientata verso il Dos. Infatti, consente
di creare una sola partizione primaria (ovvero una partizione normale) e altre partizioni estese
(ovvero altre sottopartizioni di una seconda partizione primaria).
Bisogna considerare che il settore di avvio del Dos viene collocato nel primo settore della partizione primaria utilizzata per il Dos. In questo modo, manca la sistemazione del primo settore del
disco, l’MBR, che deve contenere il codice necessario a raggiungere il settore di avvio.
FDISK
[/MBR]
In generale, sembra che le varie edizioni di ‘FDISK’ per Dos funzionino solo con il primo disco
fisso.
Fondamentalmente, il programma è interattivo, per cui si avvia una maschera con la quale si
interviene per mezzo di un menù. Di norma viene consentito di cancellare le partizioni, di crearne
una primaria e probabilmente una sola di estesa.
Di solito, è possibile riscrivere il settore di avvio MBR attraverso l’opzione ‘/MBR’.
362.2 Inizializzazione di un’unità di memorizzazione
L’inizializzazione di un’unità di memorizzazione, intesa come un dischetto o una partizione, si
ottiene con il comando ‘FORMAT’. Questo si occupa anche di predisporre il file system Dos-FAT
ed eventualmente anche di trasferire il kernel, per renderlo avviabile.
FORMAT lettera_unità :
[/N:settori] [/T:cilindri] [/S] [/U]
In alcune edizioni del Dos, questo comando non inizializza l’unità di memorizzazione, ma si
limita a sovrascrivere la parte iniziale. Ciò viene fatto per accelerare il procedimento e per
permettere eventualmente il recupero dei dati, in caso di ripensamenti. In generale, sarebbe
meglio evitare questa scorciatoia quando si tratta di unità corrispondenti ai dischetti; così, per
confermare la richiesta di un’inizializzazione tradizionale, si può aggiungere l’opzione ‘/U’.
4084
Dos: dischi, file system, directory e file
4085
Esempi
C:\>FORMAT A: /U
Inizializza l’unità ‘A:’, corrispondente a un dischetto. L’inizializzazione avviene in modo completo, essendo stata usata l’opzione ‘/U’; inoltre, dal momento che non sono state
indicate altre cose, il formato usato è quello predefinito in base alla configurazione del
firmware.
C:\>FORMAT A: /N:9 /T:40 /U
Come nell’esempio precedente, con l’aggiunta dell’indicazione della geometria: nove settori per traccia e 40 cilindri; si sottintende la presenza di due tracce per cilindro. Pertanto,
dal momento che ogni settore è di 512 byte: 2 * 40 * 9 * 512 byte = 360 Kibyte.
C:\>FORMAT A: /N:9 /T:80 /U
Come nell’esempio precedente, ma con 80 cilindri: 2 * 80 * 9 * 512 byte = 720 Kibyte.
C:\>FORMAT A: /N:15 /T:80 /U
Come nell’esempio precedente, ma con 15 settori per traccia: 2 * 80 * 15 * 512 byte =
1200 Kibyte.
C:\>FORMAT A: /N:18 /T:80 /U
Come nell’esempio precedente, ma con 18 settori per traccia: 2 * 80 * 18 * 512 byte =
1440 Kibyte.
C:\>FORMAT A: /S
Inizializza il dischetto corrispondente all’unità ‘A:’, trasferendo successivamente il kernel
e probabilmente anche l’interprete dei comandi (‘COMMAND.COM’). Ciò avviene perché è
stata usata l’opzione ‘/S’.
362.3 Etichetta di un’unità di memorizzazione
Tradizionalmente, il Dos prevede la possibilità di attribuire un nome a un’unità di memorizzazione. Questo nome viene definito solitamente «etichetta» e di fatto viene annotato come un file
speciale nella directory radice (anche se poi non appare nell’elenco). Per modificare o attribuire
questo nome si utilizza il comando ‘LABEL’:
LABEL
[lettera_unità :][nome]
Se non si indica la lettera dell’unità di memorizzazione su cui intervenire, si tratta implicitamente
di quella da cui è stato avviato il sistema; se non si indica il nome da attribuire, ‘LABEL’ funziona
in modo interattivo, chiedendo il da farsi.
In linea di principio, l’etichetta di un’unità non serve, salvo il caso di qualche programma che
potrebbe utilizzarla per uno scopo particolare (per esempio i programmi di installazione per
identificare i dischetti).
Esiste anche un altro comando interno per la verifica del nome di un’unità; si tratta di ‘VOL’:
VOL
[lettera_unità :]
Il risultato è solo l’informazione del nome stesso, con l’aggiunta del numero di serie se questo
dato è disponibile.
Dos: dischi, file system, directory e file
4086
362.4 Analisi e correzione del file system
Esistono pochi strumenti di analisi e correzione degli errori nel file system. In origine si tratta del
comando ‘CHKDSK’, a cui in seguito si è aggiunto ‘SCANDISK’.
CHKDSK lettera_unità :
[/F]
‘CHKDSK’ può essere usato solo con l’indicazione di un’unità di memorizzazione; in tal caso restituisce le informazioni disponibili su questa. Se si aggiunge l’opzione ‘/F’, si richiede
esplicitamente la correzione, per quanto possibile, degli errori rilevati.
L’errore tipico di un file system Dos-FAT si traduce in «concatenamenti perduti», ovvero file,
interi o parziali, di cui non si può conoscere il nome. Questi file potrebbero essere solo dati
temporanei che è bene siano cancellati, ma questa non è la regola. ‘CHKDSK’ tende a salvare
questi file assegnando loro un nome più o meno casuale, lasciando all’utilizzatore l’onere di
decidere cosa farne.
362.5 Copia
Nei sistemi Dos la copia è un’attività piuttosto articolata. In pratica, il comando interno ‘COPY’
consente solo di copiare file puri e semplici. Per copiare un dischetto occorre il comando
‘DISKCOPY’; per copiare file e directory occorre il comando ‘XCOPY’.
362.5.1 DISKCOPY
DISKCOPY unità_di_origine : unità_di_destinazione :
‘DISKCOPY’ permette di eseguire la copia di un’unità di memorizzazione, purché si tratti di un
dischetto. Il dischetto di destinazione dovrebbe essere inizializzato preventivamente.
L’unità indicata come secondo argomento, che rappresenta la destinazione, può essere la stessa
di quella di origine. In questo caso, i dischetti andranno alternati nel dispositivo che li ospita,
seguendo le istruzioni che dà ‘DISKCOPY’ stesso.
Esempi
C:\>DISKCOPY A: A:
Esegue la copia di un dischetto usando lo stesso dispositivo fisico.
362.5.2 XCOPY
XCOPY percorso_origine
[percorso_destinazione] [/E] [/S] [/H] [/V]
‘XCOPY’ consente di copiare uno o più file assieme alla struttura di directory. In altri termini, ciò
significa che è possibile copiare anche una directory intera.
Alcune opzioni
/S
Copia solo le directory e le sottodirectory non vuote.
/E
Copia tutte le sottodirectory, anche se vuote.
Dos: dischi, file system, directory e file
4087
/H
Copia anche i file nascosti e di sistema.
/V
Verifica la copia.
Esempi
C:\>XCOPY \PIPPO\*.* \PAPPA\*.* /E /S /H /V
Copia tutta la struttura che si articola a partire dalla directory ‘\PIPPO\’, nella directory
‘\PAPPA\’, includendo anche i file nascosti e quelli di sistema.
362.6 Trasferimento del sistema
Il Dos è un sistema operativo elementare. L’essenziale in assoluto è costituito dal kernel e dall’interprete dei comandi. Per rendere «avviabile» un dischetto o una partizione basta copiare questi
file e sistemare il settore di avvio, in modo che punti correttamente al kernel. Questo si può ottenere con il comando ‘FORMAT’, quando lo si usa con l’opzione ‘/S’ (cosa che naturalmente
implica anche l’inizializzazione dell’unità), oppure con il comando ‘SYS’, fatto appositamente
per questo:
FORMAT lettera_unità : /S
SYS lettera_unità :
A seconda del tipo di Dos, vengono copiati solo i file del kernel, oppure anche l’interprete dei
comandi (necessario per avviare il sistema).
362.7 Modifica delle unità
La caratteristica del Dos per cui si distinguono le unità di memorizzazione, introduce l’esigenza
di comandi particolari, che vengono descritti brevemente nelle sezioni seguenti. In particolare,
si tratta della possibilità di attribuire una lettera di unità differente e di poter inserire un’unità in
una directory come avviene con l’innesto di un file system nei sistemi Unix.
362.7.1 ASSIGN
[]
[]
ASSIGN lettera_unità_1 : =lettera_unità_2 :
ASSIGN /STATUS
ASSIGN
Il comando ‘ASSIGN’ permette di modifica il nome di un’unità di memorizzazione. Per ottenere questo risultato, rimane attivo come programma residente in memoria. Quando si usa senza
argomenti, ‘ASSIGN’ elimina tutte le ridefinizioni; con l’opzione ‘/STATUS’ si ottiene lo stato
attuale delle ridefinizioni; quando si indicano le lettere di unità, la prima è l’unità virtuale che
viene creata come riproduzione della seconda.
Esempi
C:\>ASSIGN E:=A:
Dopo questo comando, per accedere all’unità corrispondente al primo dischetto, si potrà
indicare l’unità ‘E:’.
C:\>ASSIGN
Cancella tutte le ridefinizioni delle unità di memorizzazione.
Dos: dischi, file system, directory e file
4088
362.7.2 JOIN
JOIN lettera_unità : percorso
JOIN lettera_unità : /D
JOIN
Il comando ‘JOIN’ permette di attaccare un’unità di memorizzazione in corrispondenza di un
percorso (una directory). Si tratta in pratica di montare l’unità, come avviene nei sistemi Unix.
Quando si usa ‘JOIN’ senza argomenti, si ottiene un elenco degli innesti attivi; quando si usa
l’opzione ‘/D’, si vuole annullare il collegamento dell’unità.
Esempi
C:\>JOIN A: C:\MNT\A
Innesta l’unità ‘A:’ nella directory ‘C:\MNT\A\’.
C:\>JOIN A: /D
Distacca l’unità ‘A:’ da un collegamento precedente.
362.7.3 SUBST
SUBST lettera_unità : percorso
SUBST /D
Il comando ‘SUBST’ permette di creare un’unità virtuale a partire da una directory di un’altra
unità. In pratica, si fa in modo di permettere l’identificazione di una certa directory attraverso
l’uso di una lettera di unità.
Quando si usa ‘JOIN’ con l’opzione ‘/D’, si vuole annullare l’unità virtuale relativa.
Esempi
C:\>SUBST E: C:\EXTRA\E
Crea l’unità virtuale ‘E:’ a partire dal contenuto delle directory ‘C:\EXTRA\E\’.
C:\>JOIN E: /D
Elimina l’unità virtuale ‘E:’.
362.8 Altre particolarità
La gestione del Dos di file e directory è molto strana. Nelle sezioni seguenti vengono descritti
alcuni programmi tipici dei sistemi Dos riguardanti la gestione di file e directory, che non hanno
trovato un’altra collocazione in questo documento, a causa della loro particolarità.
Dos: dischi, file system, directory e file
4089
362.8.1 VERIFY
VERIFY
[ON|OFF]
Il comando interno ‘VERIFY’ permette di richiedere al sistema operativo di verificare la registrazione nelle unità di memorizzazione. Come si vede dallo schema sintattico, si attiva o si disattiva
la modalità, attraverso l’uso delle parole chiave ‘ON’ oppure ‘OFF’. Di solito, questa modalità è
disabilitata ed è difficile definire la reale importanza di questa impostazione.
Se si usa il comando senza alcun argomento, si ottiene di sapere quale sia l’impostazione attuale.
362.8.2 APPEND
APPEND directory
APPEND ;
APPEND
Il comando ‘APPEND’ consente di definire un percorso per la ricerca dei file di dati. In pratica,
si vuole permettere ai programmi di accedere a file di dati anche quando questi si trovano fuori
della collocazione prevista. ‘APPEND’ può essere usato più volte, per aggiungere altre directory.
Se viene usato con l’argomento ‘;’, si intende cancellare tutto l’elenco di directory di ricerca dei
file di dati. Se viene usato senza argomenti, si ottiene l’elenco di queste directory.
Esempi
C:\>APPEND C:\DATI
Aggiunge la directory ‘C:\DATI\’ all’elenco dei percorsi di ricerca per i file di dati.
362.8.3 ATTRIB
ATTRIB
[+R|-R] [+A|-A] [+S|-S] [+H|-H]
file
Il comando ‘ATTRIB’ permette di visualizzare o cambiare gli attributi del file. In pratica,
utilizzando la forma ‘+x ’ si attiva l’attributo x , mentre con ‘-x ’ si disattiva l’attributo stesso.
Esempi
C:\>ATTRIB *.*
Mostra gli attributi di tutti i file contenuti nella directory corrente.
C:\>ATTRIB +R *.*
Imposta l’attributo di sola lettura per tutti i file della directory corrente.
362.8.4 DELTREE
DELTREE directory
Il comando ‘DELTREE’ consente di eliminare una directory con tutto il suo contenuto,
ricorsivamente.
Esempi
C:\>DELTREE C:\TEMP\CIAO
Elimina la directory ‘C:\TEMP\CIAO\’ assieme a tutto il suo contenuto.
Dos: dischi, file system, directory e file
4090
362.8.5 FIND
FIND
[opzioni]
"stringa "
[file]
Il comando ‘FIND’ è uno dei più complessi nei sistemi Dos. Serve per fare una ricerca di una
stringa in uno o più file, in base a quanto indicato nell’ultimo argomento, oppure all’interno
dello standard input. Il risultato normale della ricerca è l’emissione delle righe che contengono
la stringa cercata, assieme all’indicazione del file a cui appartengono.
Alcune opzioni
/V
La ricerca avviene per le righe che non contengono la stringa cercata.
/C
Mostra solo il totale delle righe che contengono la stringa cercata.
/N
Mostra il numero di ogni riga che contiene la stringa cercata.
/I
Ignora la differenza tra maiuscole e minuscole per il confronto con la stringa di ricerca.
In alcune edizioni del Dos, questa modalità di funzionamento è predefinita.
Esempi
C:\>FIND "ciao" *.*
Cerca la stringa ‘ciao’ in tutti i file della directory corrente.
C:\>FIND "ciao" < MIO.TXT
Cerca la stringa ‘ciao’ nel file ‘MIO.TXT’ che viene fornito attraverso lo standard input.
362.8.6 MOVE
MOVE file_origine directory_destinazione
MOVE directory_origine directory_destinazione
Il comando ‘MOVE’ consente di spostare file o directory in altre collocazioni. In generale, ‘MOVE’
si occupa di spostare e non di rinominare i file, che invece è una funzione del comando ‘REN’.
Il comando ‘MOVE’ è ambiguo e si comporta in maniera differente da una realizzazione all’altra
dei sistemi Dos. In generale bisogna considerare che la destinazione può esistere o meno,
implicando dei comportamenti differenti da valutare.
Esempi
C:\>MOVE C:\CIAO\*.* C:\MIA
Sposta i file e le directory contenute in ‘C:\CIAO\’ nella directory ‘C:\MIA\’. Se la directory di destinazione non c’è, questa dovrebbe essere creata automaticamente, ma la cosa va
verificata.
Dos: dischi, file system, directory e file
4091
362.8.7 TREE
TREE
[directory]
Il comando ‘TREE’ consente di visualizzare la struttura della directory corrente, oppure di un’altra
directory indicata come argomento.
Esempi
C:\>TREE C:\CIAO
Mostra la struttura della directory ‘C:\CIAO\’.
362.8.8 COMP e FC
[opzioni]
[opzioni]
COMP file_1 file_2
FC file_1 file_2
I comandi ‘COMP’ e ‘FC’ permettono di verificare se due file sono identici, oppure no. Non sono
molto facili da utilizzare, specialmente il primo; probabilmente vale la pena di sapere che ci sono,
senza poi pretendere di sfruttare tutte le loro possibilità.
‘FC’ assomiglia molto vagamente a un comando ‘diff’ di Unix, dal momento che di fronte a file
di testo cerca di comprendere quale cambiamento è stato fatto. In questo senso, è probabile che
‘FC’ sia il più utile tra questi due.
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
363
Dos: configurazione
Nel Dos è un po’ difficile scindere i concetti di configurazione e script, perché per configurare il
sistema, occorre predisporre degli script. Si tratta dei file ‘\CONFIG.SYS’ e ‘\AUTOEXEC.BAT’,
collocati nell’unità di avvio. Questo fatto è già stato accennato nel capitolo introduttivo; in questo
si vuole approfondire un po’ la cosa.
363.1 CONFIG.SYS
Il file ‘CONFIG.SYS’, collocato nella directory radice dell’unità di avvio, è uno script speciale
avviato dal kernel prima dell’interprete dei comandi. In linea di massima, si tratta di una sequenza di direttive che occupano ognuna una riga; alcune versioni recenti del Dos consentono di
suddividere le direttive in sezioni da scegliere in base a un menù iniziale.
Le direttive di ‘CONFIG.SYS’ hanno la forma seguente:
nome =valore
In pratica, si assegna una stringa (senza delimitatori espliciti) a un nome che ha un significato
particolare.
In questo file, vengono ignorate le righe vuote, quelle bianche e quelle che iniziano con la parola
chiave ‘REM’:
REM annotazione
È importante osservare che i nomi delle direttive non fanno differenza tra lettere maiuscole
e minuscole. In generale, questo vale anche per le stringhe che vengono assegnate a questi
nomi.
363.1.1 BREAK
{ | }
BREAK= ON OFF
Teoricamente, questa istruzione consente di attivare o di disattivare la funzionalità abbinata alla
combinazione di tasti [ Ctrl+c ]. In condizioni normali, quando si assegna la parola chiave ‘ON’, si
attiva il funzionamento della combinazione [ Ctrl+c ].
363.1.2 BUFFERS
BUFFERS=n_buffer
[,n_buffer_secondari ]
Questa istruzione consente di definire la quantità di memoria tampone per gli accessi ai dischi.
Si assegnano uno o due valori numerici, separati da una virgola. Il primo valore va da 1 a 99 ed
esprime il numero di aree da usare come memoria tampone; il secondo valore, facoltativo, indica
delle memorie tampone secondarie, con valori che vanno da uno a otto.
4092
Dos: configurazione
4093
363.1.3 COUNTRY
[[
COUNTRY=n_codice_paese , n_codifica
][,file_informazioni_nazionali ]]
Questa istruzione, attraverso quanto contenuto in un file che tradizionalmente si chiama
‘COUNTRY.SYS’, permette di configurare il sistema in base alla nazionalità. Per la precisione,
si può specificare un codice riferito alla nazionalità, attraverso il quale si ottiene una forma particolare per le date e gli orari, con l’aggiunta eventuale di un altro codice che specifica la codifica
dei caratteri prescelta (codepage). La tabella 363.1 riepiloga questi codici che fanno riferimento
tradizionalmente anche a paesi che non esistono più.
Si può osservare che la stringa assegnata alla direttiva ‘COUNTRY’ può contenere l’indicazione
di un file (con il percorso, completo di unità o meno). Questo file è quello che contiene poi
le indicazioni relative alla nazionalità prescelta; come già accennato, di solito si tratta del file
‘COUNTRY.SYS’.
Tabella 363.1. Codici di nazionalità.
Località
USA
Canada francese
America latina
Russia
Olanda
Belgio
Francia
Spagna
Ungheria
Jugoslavia
Italia
Svizzera
Cecoslovacchia
Regno unito
Danimarca
Svezia
Norvegia
Polonia
Germania
Brasile
Australia
Giappone
Corea
Cina
Turchia
Asia (inglese)
Portogallo
Islanda
Finlandia
Codice di nazionalità
001
002
003
007
031
032
033
034
036
038
039
041
042
044
045
046
047
048
049
055
061
081
082
088
090
099
351
354
358
Codifiche utili
437, 850
863, 850
850, 437
866, 437
850, 437
850, 437
850, 437
850, 437
850, 852
850, 852
850, 437
850, 437
850, 852
850, 437
850, 865
850, 437
850, 865
850, 852
850, 437
850, 860
850, 437
932, 437, 850, 942
934, 437, 850, 944
938, 437, 850, 948
857, 850
850, 437
850, 860
850, 861
850, 437
Esempi
COUNTRY=039,850,C:\DOS\COUNTRY.SYS
Predispone l’impostazione nazionale per l’Italia, utilizzando la codifica 850, che ha il
vantaggio di essere quella più comune dei paesi che usano l’alfabeto latino.
Dos: configurazione
4094
363.1.4 DEVICE, DEVICEHIGH
[opzioni]
DEVICEHIGH=programma_di_gestione_dispositivo [opzioni]
DEVICE=programma_di_gestione_dispositivo
Si tratta di un modo per avviare un programma speciale che ha lo scopo di rimanere residente in memoria. In generale, tali programmi servono per la gestione di qualche dispositivo,
indispensabile prima di avviare l’interprete dei comandi.
La differenza tra le due direttive sta nel fatto che la seconda cerca di caricare il programma nella
memoria «alta».
Le opzioni riguardano il programma.
Esempi
DEVICE=C:\MOUSE\MOUSE.SYS /2
Avvia il programma ‘MOUSE.SYS’ che presumibilmente gestisce il mouse (l’opzione ‘/2’
serve probabilmente a utilizzare il mouse collegato alla seconda porta seriale).
363.1.5 DOS
{ | }[,{UMB|NOUMB}]
DOS=[{HIGH|LOW},]{UMB|NOUMB}
DOS= HIGH LOW
Questa istruzione richiede al kernel di allocarsi nella memoria convenzionale, ‘LOW’, o in quella
alta, ‘HIGH’. La parola chiave ‘UMB’ richiede di mantenere un collegamento tra la UMB e la
memoria convenzionale; la parola chiave ‘NOUMB’ fa sì che questo collegamento non abbia luogo.
363.1.6 DRIVEPARM
[
]
DRIVEPARM= opzioni
Si tratta di una direttiva attraverso cui si possono definire i parametri relativi ai dispositivi a
blocchi, per la precisione si tratta solo di dischi, se questo può essere necessario. Le opzioni
assomigliano a quelle dei programmi di servizio, iniziando con una barra obliqua normale: ‘/x ...’.
Alcune opzioni
/d:n_dispositivo_fisico
Consente di indicare il dispositivo attraverso un numero, da 0 a 255. Lo zero corrisponde
alla prima unità a dischetti.
/c
Se si utilizza questa opzione, si intende che l’unità fisica è in grado di sapere se il disco è
inserito o meno.
/f:n_formato
Stabilisce il formato del dispositivo fisico; in pratica, fissa la geometria:
• 0 dischetto 160 Kibyte, 180 Kibyte, 320 Kibyte, 360 Kibyte
• 1 dischetto 1200 Kibyte
• 2 dischetto 720 Kibyte
Dos: configurazione
4095
• 5 disco fisso
• 6 nastro
• 7 dischetto 1440 Kibyte
• 9 dischetto 2880 Kibyte
/h:n_testine
Definisce il numero di testine.
/i
Indica che si tratta di un dischetto da 3,5 pollici.
/n
Si tratta di un disco fisso.
/s:n_settori
Definisce il numero di settori per traccia.
/t:n_cilindri
Definisce il numero dei cilindri (in altri termini: il numero di tracce per faccia).
363.1.7 FCBS
FCBS=n_blocchi
Permette di definire il numero di blocchi di controllo dei file (file control block). Il valore va da 1
a 255, mentre il valore normale è di quattro blocchi.
363.1.8 FILES
FILES=n_blocchi
Permette di indicare il numero massimo di file aperti. Il numero che può essere assegnato va da
8 a 255. Il valore predefinito dovrebbe essere di otto file.
363.1.9 INSTALL
INSTALL=programma
[opzioni]
Si tratta di un’istruzione con la quale si può avviare preventivamente un programma (che dovrebbe essere residente in memoria), prima dell’avvio dell’interprete dei comandi. In questo caso, a
differenza della direttiva ‘DEVICE’, o ‘DEVICEHIGH’, si tratta di un programma normale.
Le opzioni riguardano il programma.
363.1.10 LASTDRIVE
LASTDRIVE=lettera_unità_finale
Consente di specificare l’ultima lettera di unità che può essere richiesta. Questo consente di
risparmiare risorse, se si è consapevoli del fatto che non servono lettere oltre un certo punto. La
lettera in questione può essere indifferentemente maiuscola o minuscola, senza che ciò possa fare
differenza.
Dos: configurazione
4096
363.1.11 SHELL
SHELL=programma
[opzioni]
Permette di indicare esplicitamente il programma da avviare alla fine della procedura di avvio
del kernel. In generale si tratta dell’interprete dei comandi. Questa direttiva può consentire di avviare un interprete alternativo a quello normale, oppure permette di avviarlo da una collocazione
insolita; inoltre permette di dare al programma in questione delle opzioni particolari.
Esempi
SHELL=C:\DOS\COMMAND.COM
Avvia il programma ‘COMMAND.COM’ che si trova nella directory ‘C:\DOS\’.
363.1.12 STACK
[
STACK=n_livelli ,dimensione_in_byte
]
Con questa istruzione è possibile fissare la dimensione dello stack, utilizzando valori da 8 a 64,
oltre allo zero. Il valore dopo la virgola indica la dimensione in byte di ogni livello dello stack.
In questo caso i valori vanno da 32 a 512.
363.2 AUTOEXEC.BAT
Il file ‘AUTOEXEC.BAT’ collocato nella directory radice dell’unità di avvio, è inteso essere uno
script che viene eseguito dall’interprete dei comandi, ‘COMMAND.COM’, dopo l’avvio del sistema.
Questo script viene realizzato normalmente in modo sequenziale, senza strutture di controllo.
In generale è importante per due cose: impostare alcune variabili di ambiente fondamentali, per
esempio ‘PATH’; avviare dei programmi che poi restano residenti in memoria, quando questo non
si ottiene già attraverso il file ‘\CONFIG.SYS’.
363.3 Comandi ridondanti
Anche nel Dos è molto importante l’uso delle variabili di ambiente. È già stato mostrato il
comando ‘SET’, attraverso il quale si impostano o si annullano le variabili di ambiente:
SET nome_variabile =stringa_assegnata
Alcune variabili hanno un’importanza particolare, per cui esiste un comando interno apposito
(dell’interprete dei comandi), che serve a inizializzarle senza nemmeno l’uso del comando ‘SET’.
•
PROMPT stringa_di_invito
Il comando interno ‘PROMPT’ rappresenta un modo alternativo per impostare la variabile di
ambiente con lo stesso nome. Se si usa il comando senza l’argomento, si ripristina l’invito
predefinito.
•
PATH
[percorsi_degli_eseguibili]
Il comando interno ‘PATH’ rappresenta un modo alternativo per impostare la variabile di
ambiente con lo stesso nome. Se non si indica l’argomento, si ottiene la visualizzazione
dell’elenco dei percorsi attivo.
Dos: configurazione
4097
Esistono altri comandi particolari che si sovrappongono alle istruzioni del file ‘CONFIG.SYS’.
•
BREAK
[ON|OFF]
Abilita o disabilita la funzionalità abbinata alla combinazione di tasti [ Ctrl+c ]. Utilizzando
il comando senza argomento, si ottiene la visualizzazione dello stato attuale.
363.4 Localizzazione
La localizzazione del Dos si riduce alla configurazione della mappa della tastiera e alla definizione dell’insieme di caratteri. L’insieme di caratteri dipende dalla scelta della nazionalità, fatta
nel file ‘CONFIG.SYS’, attraverso la direttiva ‘COUNTRY’.
Nelle sezioni seguenti vengono mostrati alcuni comandi utili per le impostazioni che riguardano
la localizzazione.
363.4.1 CHCP
CHCP
[n_codifica]
Si tratta di un comando interno dell’interprete dei comandi che interviene nella definizione della
codifica utilizzata. In pratica, se si utilizza senza argomenti, mostra il numero della codifica attiva;
se si indica un numero come argomento, cambia la codifica attiva, purché questa sia una di quelle
ammissibili in base alla nazionalità stabilita con la direttiva ‘COUNTRY’ nel file di configurazione
‘CONFIG.SYS’.
Esempi
C:\>CHCP 850
Fa in modo che sia attivata la codifica corrispondente al numero 850.
363.4.2 KEYB
KEYB
[sigla_nazionale[,[n_codifica][,file_informazioni_tastiere ]]]
‘KEYB’ è un comando esterno che consente di cambiare la configurazione della tastiera secondo
alcuni modelli di nazionalità predefiniti. La sigla nazionale è un codice di due lettere che, assieme
alla nazionalità, dovrebbe indicare anche la lingua utilizzata. La tabella 363.2 elenca queste sigle.
Tabella 363.2. Sigle nazionali-linguistiche per l’impostazione della mappa della
tastiera.
Sigla
US
FR
GR
IT
SP
UK
PO
SG
SF
DK
Corrispondenza
USA (predefinito)
Francia
Germania
Italia
Spagna
Gran Bretagna
Portogallo
Svizzera tedesca
Svizzera francese
Danimarca
Dos: configurazione
4098
Sigla
BE
NL
NO
LA
SV
SU
CF
Corrispondenza
Belgio
Olanda (Nederland)
Norvegia
America latina
Svezia
Finlandia (Suomi)
Canada francese
Esempi
C:\>KEYB
Mostra la configurazione attuale.
C:\>KEYB IT
Predispone la mappa dei tasti per la disposizione italiana.
C:\>KEYB IT,850,C:\DOS\KEYBOARD.SYS
Predispone la mappa dei tasti per la disposizione italiana, specificando l’uso della codifica
850 e del file ‘C:\DOS\KEYBOARD.SYS’ per trovare le impostazioni standard delle tastiere.
363.4.3 GRAFTABL
GRAFTABL
[n_codifica]
GRAFTABL /STATUS
‘GRAFTABL’ è un comando esterno che consente di cambiare la codifica per i caratteri visualizzati sullo schermo. L’opzione ‘/STATUS’ permette di conoscere la situazione attuale, mentre
l’indicazione di un numero di codifica cambia l’impostazione.
Esempi
C:\>GRAFTABL 850
Imposta l’uso della codifica 850.
363.5 Orologio
Il Dos consente di accedere all’orologio dell’elaboratore, per leggere la data e l’ora, o per cambiare tali informazioni. In generale, il Dos non prevede la gestione di un orologio hardware allineato
al tempo universale; pertanto, l’orologio hardware deve corrispondere necessariamente all’ora
locale, lasciando all’utente il problema legato alle variazioni dell’ora estiva.
I comandi per accedere all’orologio sono ‘DATE’ e ‘TIME’:
[data]
TIME [orario]
DATE
Se non si indica la data o l’orario, viene mostrato quello attuale e viene richiesto all’utente di
modificarlo o di confermarlo.
Il modo in cui va scritta da data o l’ora, dipende dalla localizzazione. Per conoscere quello giusto,
basta osservare in che modo vengono visualizzate tali informazioni.
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
364
Dos: script dell’interprete dei comandi
Uno script dell’interprete dei comandi, conosciuto solitamente con il nome di file batch, potrebbe
essere definito come un file di testo normale in cui può essere indicato un elenco di comandi da
eseguire. Tuttavia, questi script consentono l’uso anche di strutture di controllo elementari, per
cui si possono realizzare dei programmi molto semplici, senza troppe pretese.
È interessante osservare che questi script vengono individuati solo attraverso l’estensione che ha
il nome: ‘.BAT’. Inoltre, non esiste la necessità di renderli «eseguibili» come si fa nei sistemi
Unix.
364.1 Parametri, variabili ed espansione
Gli script dell’interprete dei comandi hanno accesso agli argomenti che vengono loro forniti. Si
possono gestire solo nove di questi argomenti alla volta, attraverso i parametri posizionali relativi,
da ‘%1’ a ‘%9’. Come avviene nelle shell Unix, è disponibile il comando interno ‘SHIFT’ per fare
scorrere in avanti gli argomenti nei parametri disponibili.
Bisogna ricordare che in Dos i caratteri jolly non vengono espansi dalla shell, per cui la
limitazione a soli nove parametri posizionali, non dovrebbe costituire un problema.
Nell’ambito di uno script possono essere dichiarate e utilizzate delle variabili di ambiente. È già
stato mostrato in precedenza l’uso del comando ‘SET’ per impostare o eliminare le variabili di
ambiente. Per fare riferimento al contenuto di una variabile, si usa la notazione seguente:
%nome_variabile %
L’esempio seguente rappresenta il caso tipico di estensione di un percorso di ricerca degli
eseguibili, quando si ritiene che la variabile ‘PATH’ sia già stata usata:
SET PATH=%PATH%;C:\PIPPO
364.2 Chiamate di altri script
Tradizionalmente, il Dos ha un baco molto grave, ormai divenuto una caratteristica fondamentale, riguardante l’avvio di script all’interno di altri script. In generale, quando si chiama un
programma che in realtà corrisponde a uno script, al termine di questo non riprende l’esecuzione
di quello chiamante. Per ottenere la ripresa dell’interpretazione dello script di partenza occorre
usare il comando speciale ‘CALL’.
CALL nome_script
[argomenti_dello_script]
364.3 Strutture di controllo
Le strutture di controllo per la programmazione attraverso gli script dell’interprete dei comandi
sono molto limitate. È disponibile una struttura condizionale semplificata e un ciclo di scansione
di file, che vengono descritti brevemente.
4099
Dos: script dell’interprete dei comandi
4100
364.3.1 IF
[NOT]
IF [NOT]
IF [NOT]
IF
ERRORLEVEL valore_di_uscita_ultimo_comando comando
stringa_1 ==stringa_2 comando
EXIST file comando
La struttura condizionale degli script dell’interprete dei comandi Dos è in pratica un comando
interno dello stesso interprete. Come si può vedere dagli schemi sintattici, viene fornita una
condizione che può essere invertita con la parola chiave ‘NOT’ e il risultato è solo l’esecuzione di
un altro comando se la condizione risulta vera.
Nel primo caso, la condizione si riferisce alla verifica del valore di uscita dell’ultimo comando eseguito. La condizione si verifica se il numero indicato è inferiore o uguale al valore restituito effettivamente da tale comando; nel secondo, la condizione si verifica se le due stringhe (non delimitate) sono identiche; nel terzo si verifica la condizione se il file indicato esiste
effettivamente.
Esempi
IF ERRORLEVEL 1 GOTO :errore
Se il comando precedente ha restituito un valore maggiore o uguale a uno, salta all’etichetta
‘:errore’.
IF %1==ciao ECHO L’argomento è corretto
In questo caso, se l’espansione del parametro ‘%1’, corrispondente al primo argomento
ricevuto all’avvio, si traduce nella stringa ‘ciao’, viene emesso un messaggio per mezzo
del comando ‘ECHO’.
IF %1x==x ECHO L’argomento è mancante
Quello che si vede è il trucco necessario per poter verificare se un parametro contiene la stringa nulla: si aggiunge una lettera, in questo caso una «x», verificando che la
corrispondenza avvenga solo con la stessa lettera.
IF NOT EXIST LETTERA.TXT ECHO Scrivi! > LETTERA.TXT
Qui, se non esiste il file ‘LETTERA.TXT’ nella directory corrente, questo file viene creato
attraverso il comando ‘ECHO’ che invia il suo standard output verso un file con lo stesso
nome.
364.3.2 FOR
FOR
[%]%x
IN (nome ...) DO comando
[argomenti_del_comando ]
Si tratta di un comando interno che svolge un ciclo di scansione di un gruppo di nomi, generalmente file, attraverso il quale viene creato un parametro variabile speciale, il cui nome si compone
di una sola lettera, a cui viene assegnato a ogni ciclo uno dei nomi contenuti tra parentesi tonde.
A ogni ciclo viene eseguito il comando, che a sua volta può fare uso del parametro.1
Quando viene usato all’interno di uno script dell’interprete dei comandi, il parametro viene
indicato con due simboli di percentuale (‘%%x ’); al contrario, se il comando viene impartito
dalla riga di comando, se ne usa uno solo.
1
Questo parametro assomiglia a una variabile di ambiente, ma non si comporta allo stesso modo. Si tratta di una
particolarità del comando ‘FOR’.
Dos: script dell’interprete dei comandi
4101
Esempi
FOR %A IN (uno due tre) DO ECHO %A
In questo modo, si ottiene la visualizzazione delle parole ‘uno’, ‘due’ e ‘tre’. In pratica, è
come se fosse stato fatto:
ECHO uno
ECHO due
ECHO tre
Volendo fare la stessa cosa dalla riga di comando, è necessario il raddoppio del simbolo ‘%’:
C:\>FOR %%A IN (uno due tre) DO ECHO %%A
FOR %A IN (*.TMP *.BAD) DO DEL %A
Cancella, uno a uno, tutti i file che terminano con le estensioni ‘.TMP’ e ‘.BAD’.
364.3.3 GOTO
GOTO etichetta
Gli script dell’interprete dei comandi dispongono dell’istruzione di salto incondizionato, non
avendo di meglio. Anche questa istruzione può essere presa come un comando interno
dell’interprete, con la differenza che non c’è modo di utilizzarlo al di fuori di uno script.
Nel corso di uno script del genere, possono apparire delle righe che contengono solo un’etichetta,
nella forma:
:nome_etichetta
La posizione corrispondente a queste etichette può essere raggiunta con il comando ‘GOTO’, che
può fare riferimento solo al nome dell’etichetta, oppure a tutta l’etichetta, includendo anche i due
punti.
Esempi
IF EXIST LETTERA.TXT GOTO riprendi
ECHO Il file LETTERA.TXT è assente
:riprendi
In questo esempio, se il file ‘LETTERA.TXT’ esiste, si salta all’etichetta ‘:riprendi’;
altrimenti si esegue il comando ‘ECHO’.
IF EXIST LETTERA.TXT GOTO :riprendi
ECHO Il file LETTERA.TXT è assente
:riprendi
Esattamente come nell’esempio precedente, con la differenza che il comando ‘GOTO’ indica
l’etichetta con i suoi due punti iniziali.
364.3.4 Emulazione di un ciclo iterativo
Dal momento che non è disponibile una struttura di controllo per il ciclo iterativo, questo può
essere ottenuto solo attraverso l’uso del comando ‘GOTO’. Vale la pena di mostrare in che modo
si può ottenere tale risultato.
:etichetta_di_ingresso
IF condizione GOTO :etichetta_di_uscita
...
...
...
GOTO etichetta_di_ingresso
:etichetta_di_uscita
Dos: script dell’interprete dei comandi
4102
:etichetta_di_ingresso
...
...
...
IF condizione GOTO :etichetta_di_ingresso
:etichetta_di_uscita
I due modelli sintattici mostrano due esempi di cicli iterativi. Nel primo caso si verifica una
condizione, in base alla quale si decide se proseguire o se terminare il ciclo; nel secondo si
esegue una volta il ciclo e quindi si verifica una condizione per decidere se ripeterlo o se uscire.
364.4 Comandi utili negli script
Alcuni comandi sono particolarmente utili all’interno di script dell’interprete dei comandi.
Vengono descritti brevemente nelle sezioni seguenti.
364.4.1 REM
REM commento
I commenti negli script dell’interprete dei comandi si indicano attraverso un comando apposito:
‘REM’. Il funzionamento è evidente: tutto quello che segue il comando, fino alla fine della riga,
viene ignorato.
Alcune edizioni del Dos hanno introdotto anche l’uso del punto e virgola, come simbolo per
indicare l’inizio di un commento. Segue un esempio tipico di utilizzo di questo comando:
REM
REM (c) 2000 Pinco pallino
REM
364.4.2 ECHO
ECHO
[ON|OFF]
ECHO stringa
Il comando interno ‘ECHO’ ha un significato duplice: da una parte consente di visualizzare un testo; dall’altra controlla la visualizzazione dei comandi contenuti in uno script. Infatti, si distingue
il fatto che l’eco dei comandi sia attivo o meno. utilizzando il comando ‘ECHO’ senza argomenti,
si ottiene l’informazione sul suo stato di attivazione. Di solito si disattiva l’eco dei comandi negli
script.
Per disattivare l’eco di un comando particolare, senza disattivare l’eco in generale, basta
inserire inizialmente il simbolo ‘@’.
Esempi
@ECHO OFF
Disattiva l’eco dei comandi, facendo in modo che anche questo comando non venga
visualizzato (si usa per questo il simbolo ‘@’).
ECHO Premi un tasto per continuare
Mostra un messaggio per spiegare come comportarsi.
Dos: script dell’interprete dei comandi
4103
364.4.3 PAUSE
PAUSE
Il comando interno ‘PAUSE’ sospende l’esecuzione di uno script in attesa della pressione di un
tasto. Il comando emette attraverso lo standard output un messaggio di avvertimento in tal senso.
Di solito, per evitare di vedere tale messaggio, si ridirige lo standard output in un file nullo.
Esempi
ECHO Premere un tasto per proseguire
PAUSE > C:\NULL
Prima mostra un messaggio in cui si avverte che per proseguire occorre premere un tasto, quindi si usa il comando ‘PAUSE’ che sospende l’esecuzione dello script, senza però
mostrare altri messaggi.
364.4.4 CLS
CLS
Il comando interno ‘CLS’ ripulisce lo schermo. Si utilizza senza argomenti.
364.4.5 CHOICE
CHOICE
[opzioni] [testo_di_invito]
Il comando ‘CHOICE’ serve a presentare una richiesta per l’inserimento di una lettera, tra un elenco determinato. La pressione del tasto corrispondente alla lettera scelta, da parte dell’utilizzatore,
provoca la conclusione del funzionamento di ‘CHOICE’ che restituisce un valore corrispondente
alla scelta: zero per la prima lettera, uno per la seconda,...
Si osservi che l’ultimo argomento rappresenta un messaggio che serve all’utente per comprendere
il senso della scelta che sta facendo.
Alcune opzioni
[
]
/C:lettera lettera ...
Permette di fissare l’elenco di lettere che possono essere usate nella risposta. Se non si
indica questa opzione, la scelta sarà solo tra ‘y’ e ‘n’.
/N
Questa opzione fa in modo di escludere la visualizzazione delle lettere che possono essere
scelte. In questo modo si fa affidamento esclusivamente sul testo indicato come ultimo
argomento.
/S
Distingue tra maiuscole e minuscole per quanto riguarda le lettere tra cui scegliere.
Esempi
CHOICE /C:abcdef Inserisci una lettera
IF ERRORLEVEL 5 GOTO :f
IF ERRORLEVEL 4 GOTO :e
IF ERRORLEVEL 3 GOTO :d
IF ERRORLEVEL 2 GOTO :c
IF ERRORLEVEL 1 GOTO :b
Dos: script dell’interprete dei comandi
4104
IF ERRORLEVEL 0 GOTO :a
...
In base alla scelta di una lettera da «a» a «f», salta a un punto differente dello script. Si
osservi che non sarebbe possibile eseguire l’analisi secondo una sequenza differente, perché
‘IF ERRORLEVEL’ prende in considerazione tutti i valori di uscita maggiori o uguali a
quanto indicato nella condizione.
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
365
Dos: gestione della memoria centrale
Quando è nato il Dos non si prevedeva l’uso di memoria centrale oltre il singolo mebibyte (1 Mibyte). In base a questa considerazione veniva articolata l’architettura hardware degli elaboratori
«XT» e poi «AT», dove si prevedeva l’uso di un massimo di 640 Kibyte di memoria centrale,
riservando la parte successiva, fino alla fine di 1 Mibyte, per la memoria video e altri dispositivi
fisici.
In questo senso, il Dos tradizionale può operare con un massimo di 640 Kibyte di memoria
centrale; per sfruttarne di più occorrono degli accorgimenti non facili da applicare.
365.1 Gestione particolare
Per sfruttare la memoria oltre il primo mebibyte, si fa uso normalmente di due programmi, avviati
attraverso ‘CONFIG.SYS’, prima ancora dell’interprete di comandi. Si tratta di ‘HIMEM.SYS’ e di
‘EMM386.EXE’. In generale, le cose si fanno nel modo seguente:
DEVICE=C:\DOS\HIMEM.SYS
DEVICE=C:\DOS\EMM386.EXE
Il primo dei due programmi può essere utilizzato a partire da architetture i286, mentre il secondo
si può inserire solo a partire da architetture i386.
‘HIMEM.SYS’ è in grado di utilizzare solo una piccola parte di memoria aggiuntiva, mentre
‘EMM386.EXE’ permette teoricamente di sfruttare tutto il resto.
In generale, è molto difficile la gestione ottimale della memoria centrale, perché le applicazioni
si comportano in maniera differente. Di solito si possono solo fare dei tentativi.
365.2 Comandi appositi
Per sfruttare la memoria centrale che supera la soglia convenzionale, sono disponibili alcuni comandi specifici. In generale, si comincia dalla configurazione con il file ‘CONFIG.SYS’: dopo
l’attivazione dei gestori speciali della memoria, è possibile indicare di collocare parte dell’interprete dei comandi e dello spazio richiesto dai programmi residenti in memoria, oltre il limite
della memoria convenzionale:
DOS=HIGH,UMB
In seguito, sempre nell’ambito del file ‘CONFIG.SYS’, si può richiedere esplicitamente l’avvio di
programmi nella memoria alta attraverso la direttiva ‘DEVICEHIGH’, come si vede nell’esempio
seguente:
DEVICEHIGH=C:\MOUSE\MOUSE.SYS /2
Per quanto riguarda i programmi avviati attraverso l’interprete dei comandi, è disponibile il
comando ‘LH’, ovvero ‘LOADHIGH’:
[argomenti_del_programma ]
programma [argomenti_del_programma ]
LH programma
LOADHIGH
Per esempio, si potrebbe tentare di avviare in questo modo il programma di gestione della tastiera:
C:\>LH KEYB IT
4105
Dos: gestione della memoria centrale
4106
365.3 Verifica
Il Dos offre un solo programma molto semplice per la verifica dell’utilizzo della memoria: ‘MEM’.
MEM
[opzioni]
Se ‘MEM’ viene usato senza opzioni, visualizza brevemente la quantità di memoria utilizzata rispetto al totale disponibile. È interessante l’opzione ‘/CLASSIFY’, attraverso la quale è possibile distinguere l’utilizzo della memoria da parte dei programmi residenti; inoltre è interessante
l’opzione ‘/FREE’, con cui si hanno informazioni dettagliate sulla memoria libera.
Le opzioni disponibili del comando ‘MEM’ variano molto da una realizzazione all’altra. In
generale conviene verificare prima di utilizzarlo, per conoscere le possibilità effettive.
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Capitolo
366
FreeDOS
FreeDOS è il nome di un progetto per la realizzazione di un sistema operativo libero compatibile
con il Dos. Il Dos, per quanto limitato, ha delle caratteristiche che lo possono rendere ancora
interessante per elaboratori con architettura i86 particolarmente poveri di risorse, come nel caso
dei sistemi cosiddetti embedded.
366.1 Installazione
L’installazione della distribuzione standard di FreeDOS è abbastanza semplice. Si parte da un dischetto di avvio, con il quale si predispone la partizione e la si inizializza, quindi si prosegue con
il programma di installazione che chiede l’inserimento dei dischetti successivi. La riproduzione
del dischetto di avvio a partire dalla sua immagine avviene come al solito attraverso il programma ‘RAWRITE.EXE’, oppure per mezzo di un sistema Unix nei modi già mostrati per GNU/Linux
e altri sistemi simili.
C:\>RAWRITE FULL.BIN A:
L’esempio mostra l’uso di ‘RAWRITE.EXE’ per ottenere un dischetto dall’immagine
rappresentata dal file ‘FULL.BIN’.
La distribuzione standard di FreeDOS si compone di un file-immagine del dischetto di avvio,
che potrebbe chiamarsi ‘FULL.BIN’, e da una serie di file con estensione ‘.ZIP’ che servono
per ottenere i dischetti successivi. Ognuno di questi file compressi rappresenta il contenuto di un
dischetto, che quindi deve essere prima estratto:
C:\>A:
A:\>UNZIP C:\TMP\BASE1.ZIP
L’esempio mostra in breve il procedimento: ci si sposta nell’unità ‘A:’ e da lì si estrae il file
compresso che probabilmente si trova da qualche parte nel disco fisso.
Questi file compressi rappresentano una raccolta di applicativi e hanno una struttura particolare
che viene descritta nel seguito.
•
nome_raccolta .1
L’archivio compresso deve contenere un file che rappresenta il nome della raccolta, con
un’estensione numerica. La raccolta potrebbe essere suddivisa in più archivi ed è per questo
che si usa l’estensione numerica, che indica il numero di sequenza dell’archivio nell’ambito
della raccolta.
Il file contiene l’elenco dei pacchetti contenuti, con l’indicazione dell’opzione di installazione predefinita o meno. Si osservi l’estratto seguente (la lettera «Y» rappresenta la
conferma all’installazione predefinita):
asgn14x: Y
attr063x: Y
bwb210x: Y
choic20x: Y
•
nome_raccolta .END
Si tratta di un file vuoto, che rappresenta la conclusione della raccolta, nel senso che non ci
sono altri dischetti ulteriori.
4107
FreeDOS
4108
•
nome_pacchetto .LSM
Si tratta di un file che descrive un pacchetto applicativo. Quello che segue è l’esempio del
contenuto del file ‘DELTR10X.LSM’:
Begin3
Title:
Version:
Entered-date:
Description:
Keywords:
Author:
Maintained-by:
Primary-site:
Alternate-site:
Original-site:
Platforms:
Copying-policy:
End
•
deltree
1.02b
27 Jul 1999
Delete a directory and all directories under it
freedos delete
[email protected]
[email protected]
http://www.highfiber.com/~raster/freeware.htm
www.freedos.org
http://www.highfiber.com/~raster/freeware.htm
dos
GPL
nome_pacchetto .ZIP
Si tratta dell’archivio compresso che contiene i file dell’applicativo. In base alla struttura
standard di FreeDOS, potrebbe distribuirsi nelle directory ‘BIN\’, ‘DOC\’ e ‘HELP\’.
Dopo aver preparato i dischetti, si può procedere con l’avvio del sistema attraverso il dischetto
di avvio; quindi si passa a predisporre la partizione:
A:\>FDISK
Purtroppo, il kernel di FreeDOS non è in grado di gestire partizioni più grandi di 512 Mibyte,
per cui occorre tenerne conto durante l’uso di ‘FDISK’. Dopo aver preparato la partizione la si
inizializza:
A:\>FORMAT C: /U
Successivamente si trasferisce il sistema, con il comando ‘SYS’:
A:\>SYS C:
Infine si avvia il programma di installazione che provvederà a chiedere la sostituzione dei
dischetti:
A:\>INSTALL
366.2 Impostazione e configurazione
Da quanto è stato descritto sull’installazione di FreeDOS si intende che, pur trattandosi di un
sistema Dos, si cerca di introdurre qualche buona idea proveniente da Unix. In particolare, è
prevista una struttura per la collocazione dei file:
• ‘BIN\’ per contenere i file eseguibili;
• ‘DOC\’ per contenere la documentazione che si articola in altre sottodirectory successive,
come avviene con GNU/Linux
• ‘HELP\’ per contenere i file della guida interna relativa.
Questa struttura potrebbe essere collocata anche a partire da un punto differente della radice
dell’unità, in base alle scelte fatte in fase di installazione. In ogni caso, occorre poi predisporre
FreeDOS
4109
coerentemente alcune variabili di ambiente: ‘PAGER’ per indicare il programma da utilizzare per
lo scorrimento dei file delle guide; ‘HELPPATH’ per indicare la directory contenente i file delle
guide; ‘EMACS’ per indicare la directory contenente i file di Emacs.
In condizioni normali, gli applicativi FreeDOS vengono installati a partire dalla directory
‘\FDOS\’, per cui la configurazione si traduce nelle istruzioni seguenti nel file ‘AUTOEXEC.BAT’:
SET PAGER=MORE
SET HELPPATH=C:\FDOS\HELP
SET EMACS=C:\FDOS\EMACS\
In base alla documentazione originale, nel caso della variabile di ambiente ‘EMACS’ deve essere
indicata la barra obliqua inversa finale.
A seconda della distribuzione di FreeDOS, può darsi che il file ‘CONFIG.SYS’ debba essere
sostituito con uno avente un nome differente. Potrebbe trattarsi del file ‘FDCONFIG.SYS’.
366.3 RxDOS
RxDOS è un altro progetto analogo a FreeDOS, scritto in maniera indipendente. È provvisto di
un proprio interprete dei comandi e non ha ancora un suo sistema di installazione. Per provare il
funzionamento di RxDOS ci si può avvalere solo di un dischetto, realizzato nel modo seguente:
1. si inizializza il dischetto in qualche modo, assicurando che alla fine sia disponibile un
file system Dos-FAT;1
2. si esegue lo script ‘MAKEBOOT.BAT’, il cui scopo è la predisposizione del settore di avvio
nel dischetto;
3. si copiano ordinatamente nel dischetto i file elencati qui sotto.
• ‘RXDOSBIO.SYS’
• ‘RXDOS.SYS’
• ‘RXDOSCMD.EXE’
• ‘RXDVDISK.SYS’
• ‘AUTOEXEC.DEF’
• ‘CONFIG.DEF’
366.4 Riferimenti
• FreeDOS
<http://www.freedos.org>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
1
Il dischetto non deve avere l’etichetta, ovvero non deve avere un nome.
Capitolo
367
Progetto GNUish
Il progetto «GNUish» è una sorta di derivazione povera del progetto GNU, con lo scopo di
rendere disponibile parte del software che compone il sistema GNU anche nei sistemi Dos. Il
progetto ha un’importanza molto piccola, ma viene ancora mantenuto. Evidentemente, date le
peculiarità dei sistemi Dos, il software che viene adattato non può avere le stesse potenzialità che
ha invece in un sistema Unix.
I siti principali da cui si può ottenere copia del materiale prodotto dal progetto GNUish sono
quelli seguenti, da cui poi si articolano anche una serie di riproduzioni speculari:
• <ftp://ftp.simtel.net/pub/simtelnet/gnu/gnuish/>
In questo capitolo viene mostrato il funzionamento di alcuni programmi, nell’ambito del sistema
Dos, per i quali è il caso di spendere qualche parola.
367.1 Programmi di servizio vari
Molti dei programmi di servizio del progetto GNU sono disponibili anche per Dos. Tuttavia, è il
caso di osservare alcune particolarità che possono confondere chi è abituato a usare sistemi Dos.
La prima cosa da notare è il fatto che i percorsi si possono indicare secondo lo stile Unix,
utilizzando barre oblique normali. Per esempio:
C:\>MV C:/PRIMO/SECONDO C:/TERZO
Diversamente, utilizzando lo stesso comando, ma secondo l’indicazione tipica del Dos, la cosa
può funzionare ugualmente, oppure si possono presentare delle segnalazioni di errore. Bisogna
tenere presente la possibilità.
Un’altra cosa da notare è l’uso dei caratteri jolly, che con questi programmi segue la logica
di Unix, dove l’asterisco indica qualunque nome, senza trattare in modo speciale il punto di
separazione dell’estensione:
C:\>CP C:/PRIMO/SECONDO/* C:/TERZO
L’esempio mostra proprio questo fatto: vengono copiati tutti i file contenuti nella directory ‘C:\
PRIMO\SECONDO\’, nella directory ‘C:\TERZO\’.
367.2 Gnuplot
Il funzionamento generale di Gnuplot è descritto nel capitolo 331. Per funzionare, questa edizione
di Gnuplot richiede due file: ‘GNUPLOT.EXE’ e ‘GNUPLOT.GIH’. Il primo dei due è l’eseguibile in
grado di gestire la grafica VGA, mentre il secondo contiene le informazioni della guida interna.
Se si vuole accedere alla guida interna, è necessario che il file ‘GNUPLOT.GIH’ si trovi nella
directory corrente. Forse è sufficiente utilizzare il comando ‘APPEND’ del Dos per risolvere il
problema.
4110
Progetto GNUish
4111
367.3 Spreadsheet Calculator
Il funzionamento generale di SC (Spreadsheet Calculator) è descritto nel capitolo 330. La versione per Dos funziona correttamente (è sufficiente disporre dell’eseguibile ‘SC.EXE’), riconoscendo anche l’uso dei tasti freccia, per cui non si è più costretti a utilizzare le lettere ‘h’, ‘j’, ‘k’ e
‘l’.
367.4 Ispell
Ispell è descritto in generale nel capitolo 269. Questa edizione di Ispell richiede due file:
‘ISPELL.EXE’ e ‘ISPELL.DIC’. Come si intuisce, il primo è l’eseguibile, mentre il secondo
è il file del dizionario. Purtroppo, il file ‘ISPELL.DIC’ non è sostituibile o eliminabile; l’unica
cosa che si può fare è predisporre un dizionario personalizzato che si richiama con l’opzione
‘-p’.
ISPELL
[-d
dizionario_standard
] [-p
dizionario_personale
]
file
Quella che si vede è la sintassi essenziale su cui si può contare nell’edizione di Ispell per Dos. Il
file del dizionario standard, ‘ISPELL.DIC’, può essere collocato nella stessa directory in cui si
trova il file eseguibile; altrimenti si deve usare l’opzione ‘-d’ per indicarlo esplicitamente.
Il dizionario personale è un file di testo normale (Dos), che può anche essere creato inizialmente dallo stesso Ispell. L’esempio seguente, mostra il caso in cui si voglia analizzare il file
‘LETTERA.TXT’ attraverso il dizionario standard e il dizionario personale ‘VOCAB.TXT’. Se il
file ‘VOCAB.TXT’ non dovesse esistere, verrebbe creato per l’occasione.
C:\LETTERE>ISPELL -p VOCAB.TXT LETTERA.TXT
367.5 Perl
Perl è un linguaggio di programmazione descritto in generale a partire dal capitolo 295. L’edizione Dos dell’interprete Perl richiede due file: ‘PERL.EXE’ e ‘PERLGLOB.EXE’. È sufficiente che
questi siano disponibili nei percorsi degli eseguibili della variabile di ambiente ‘PATH’.
Bisogna tenere a mente che si tratta di una versione molto vecchia del linguaggio, per cui alcune
novità non saranno disponibili. Inoltre, l’avvio dei programmi può avvenire solo richiamando
direttamente l’interprete:
C:\ESERCIZI>PERL FATT.PL 5
L’esempio mostra l’avvio del programma Perl contenuto nel file ‘FATT.PL’, che riceve un
argomento costituito dal numero cinque.
367.6 Riferimenti
• Darrel Hankerson, François Pinard, The GNUish Project
<ftp://ftp.simtel.net/pub/simtelnet/gnu/gnuish/gnuish_t.htm>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Chapter
368
The valuable DOS Freeware page
Links to valuable free Dos programs working on low equipped computers.
This material appeared originally at ‘http://www.geocities.com/SiliconValley/
7737/’, in 1996. Now it is incorporated inside the Italian document ‘‘Appunti
di informatica libera’’, and it might be reached at the URI <http://a2.swlibero.org/
the_valuable_dos_freeware_page.html>.
Questo materiale è apparso in origine, nel 1996, presso ‘http://www.geocities.com/
SiliconValley/7737/’. Adesso viene incorporato nel documento «Appunti di
informatica libera» e può essere raggiunto attraverso l’URI <http://a2.swlibero.org/
the_valuable_dos_freeware_page.html>. L’intento dell’autore è solo quello di continuare a curare un vecchio lavoro che potrebbe essere ancora utile, nonostante si tratti di riferimenti a
software in parte libero e in parte solo gratuito, oltre che evidentemente obsoleto.
368.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4112
368.2 OS and GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4113
368.3 Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4113
368.4 Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4114
368.5 Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4115
368.6 Typesetting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4116
368.7 More Dos software sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4116
368.8 Search engines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4117
368.1 Introduction
The Dos operating system meant much for many people. Today, proprietary Dos-like operating
systems seem to be no more developed. In this situation, the only possible future for Dos is the
‘‘free’’ software, and it is not just a matter of money anymore.
Unfortunately, ‘‘free’’ is a word with many meanings. Today, this is still the biggest obstacle to
the future of the Dos world. There is so much software for Dos, with so many different license
agreements. The typical Dos user doesn’t mind to it. But this problem prevents the realization of
big serious projects based on it.
Today, the Dos world needs philosophy, and the GNU idea is still the right one (<http://
www.gnu.org>).
The author of this space would like to list here only ‘‘free software’’ in the sense stated by the
Free Software Foundation, but it is impossible, as there isn’t enough good real free software for
Dos.
The listed software is meant to work on i286 and below.
It is attempted to give some kind of classification about the legal condition of the software presented here. The definition used might be outdated, or there might be other wrong assumption.
In particular, the definition ‘‘public domain’’ means here, in most cases, that there is the source,
but there is no clear license statement.
4112
The valuable DOS Freeware page
4113
Beside the URI links of some FTP services there is an additional ‘‘search link’’ that queries a
FTP search engine for the same file. These additional links should be used when there are troubles
with the main links.
Anyone can link this document anywhere, so, there is no need to ask for it. Anyway, it is better to
link to this document using at the file name <http://a2.swlibero.org/the_valuable_dos_freeware_page.html>.
In the future, many links may disappear on this page, because of more selective choices
concerning software license.
368.2 OS and GUI
• FreeDOS 1 <http://www.freedos.org>
• FreeGEM 2 <http://www.cableone.net/eathan/gem.htm>
368.3 Utility
archive, backup
• Gzip
- ‘.GZ’ archive compressor and extractor. <ftp://ftp.simtel.net/pub/simtelnet/msdos/
<http://www.alltheweb.com/search?cat=ftp&amp;q=gzip124.zip>
3
compress/gzip124.zip>
• TAR 4 - portable TAR - DOS/UNIX backup, compressor, with hardware
support. <ftp://ftp.simtel.net/pub/simtelnet/msdos/arcers/tar320g.zip> <http://www.alltheweb.com/
search?cat=ftp&amp;q=tar320g.zip>
• Untgz
- ‘.TGZ’, ‘.TAR’, ‘.GZ’, ‘.ZIP’ file extractor. <ftp://ftp.simtel.net/pub/simtelnet/
<http://www.alltheweb.com/search?cat=ftp&amp;q=untgz095.zip>
5
msdos/arcers/untgz095.zip>
• Info-ZIP
6
- ‘.ZIP’ compatible compression and extraction utility. <http://www.info<ftp://ftp.info-zip.org/pub/infozip/MSDOS/>
zip.org/pub/infozip/>
- Replacement for Dos Restore, <ftp://ftp.simtel.net/pub/simtelnet/msdos/diskutil/
restaur1.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=restaur1.zip>
• Restaur
7
communication
• DosFax 8 - Send a fax using Dos command line <http://www.Adr.de/speicherplatz/cs/dosfax.htm>
• Bgfax 9 <http://www.blkbox.com/~bgfax/>
- Disk sharing over a serial line, <ftp://ftp.simtel.net/pub/simtelnet/msdos/lan/dosrifs2.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=dosrifs2.zip>
• Rifs
10
directory, file
1
FreeDOS GNU GPL
FreeGEM GNU GPL
3
Gzip GNU GPL
4
TAR (Dos) public domain
5
Untgz GNU GPL
6
Info-ZIP free software with special license
7
Restaur cannot be sold for profit
8
DosFax public domain
9
Bgfax promised to become free software
10
Rifs cannot be sold for profit
2
The valuable DOS Freeware page
4114
• WCD 11 - Powerful chdir for Dos and Unix <http://www.xs4all.nl/~waterlan/>
disk
• Fips 12 - Non-destructive splitting of hard disk partitions <ftp://ftp.simtel.net/pub/simtelnet/
msdos/diskutil/fips15.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=fips15.zip>
• Part 13 - MBR partition manager <http://www.intercom.com/~ranish/>
help
• NG_clone 14 - Norton Guides clone <ftp://ftp.simtel.net/pub/simtelnet/msdos/txtutl/ngclon11.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=ngclon11.zip>
shell
• DC 15 - The Dos Controller - A Norton Commander clone <ftp://ftp.simtel.net/pub/simtelnet/
msdos/fileutil/dc-sk.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=dc-sk.zip>
system
• Cmos
16
- Save/Restore extended C/MOS <ftp://ftp.simtel.net/pub/simtelnet/msdos/sysutl/
<http://www.alltheweb.com/search?cat=ftp&amp;q=cmos93cd.zip>
cmos93cd.zip>
• KGB 17 - Utility to monitor some Dos functions and reporting into a
log file <ftp://ftp.simtel.net/pub/simtelnet/msdos/sysutl/kgb104.zip> <http://www.alltheweb.com/
search?cat=ftp&amp;q=kgb104.zip>
text
• Vim 18 - VI improved, a small text editor that can handle very big files with low
RAM <ftp://ftp.simtel.net/pub/simtelnet/msdos/editor/vim53d16.zip> <http://www.alltheweb.com/
search?cat=ftp&amp;q=vim53d16.zip>
See also:
• Richard L. Green, Free software for Dos
<http://www.geocities.com/rlcgreen/softlib1.htm>
368.4 Network
packet driver
• PC/TCP Packet Driver Collection
drivers/pktd11.zip>
11
WCD GNU GPL
Fips GNU GPL
13
Part public domain
14
NG_clone public domain
15
DC public domain (no license at all, and no sources)
16
Cmos public domain
17
KGB public domain
18
Vim free software with special license
19
Crynwr packet driver collection GNU GPL
12
19
<ftp://ftp.crynwr.com/drivers/> <ftp://ftp.crynwr.com/
The valuable DOS Freeware page
4115
• WATTCP 20 - TCP/IP library routines <http://www.wattcp.com/>
- Dos port of Linux PPP packet driver <ftp://ftp.simtel.net/pub/simtelnet/
msdos/pktdrvr/dosppp05.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=dosppp05.zip>
• DOS PPPD
• Comring
22
21
- packet driver emulating ethernet over serial link(s) <http://wiz-
ard.ae.krakow.pl/~jb/ComRing/>
TCP/IP
- some common client application using WATTCP library <http://
www.smashco.com/wattcp/apps.zip>
• WATTCP apps
23
• MiniTelnet 24 - TELNET client <http://www.smashco.com/wattcp/mt.zip>
• Bobcat 25 - Text based web browser <http://www.fdisk.com/doslynx/bobcat.htm> (derived
from DosLynx, <ftp://ftp2.cc.ukans.edu/pub/WWW/DosLynx/>)
• PCroute 26 - IP routing program for IBM PC <ftp://ftp.simtel.net/pub/simtelnet/msdos/network/
pcrte224.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=pcrte224.zip>
• PPRD 27 - Turn a dedicated PC (XT/AT) into a LPD server <ftp://ftp.simtel.net/pub/simtelnet/msdos/lan/pprd200.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=pprd200.zip>
• NCSA Telnet 28 - Telnet, Ftp,... NCSA <http://archive.ncsa.uiuc.edu/SDG/Software/PCTelnet/>
<ftp://ftp.ncsa.uiuc.edu/Telnet/DOS/> <ftp://ftp.simtel.net/pub/simtelnet/msdos/ncsatlnt/>
• NOS (KA9Q) 29 - A complete mini TCP/IP system <ftp://ftp.simtel.net/pub/simtelnet/msdos/
tcpip/> <http://www.alltheweb.com/search?cat=ftp&amp;q=e920603.zip>
To use NOS you need documentation, for example the package <ftp://ftp.simtel.net/pub/
simtelnet/msdos/tcpip/intronos.zip>
• SSHDOS 30 - SSH client for Dos <http://sourceforge.net/projects/sshdos>
• Talk 31 - Talk client for Dos <http://www.smashco.com/wattcp/talk-13.zip>
• ABC-nslookup 32 - DNS query clients for Dos <http://www.smashco.com/wattcp/nslb01a.zip>
See also:
• Marc S. Ressl, Dos Internet Pages
<http://www.fdisk.com/doslynx/>
• Smash-Co Communications, TCP/IP for MS-DOS
<http://www.smashco.com/wattcp.asp>
• The U-M Software Archive
<http://www.umich.edu/~archive/msdos/communications/wattcp/>
<http://www.umich.edu/~archive/msdos/communications/packet/>
20
WATTCP free of charge library
DOS PPPD mixed licenses
22
Comring GNU GPL
23
WATTCP apps cannot be sold
24
MiniTelnet free software with a special license
25
Bobcat GNU GPL
26
PCroute cannot distribute modifications
27
PPRD software non libero: licenza Artistic
28
NCSA Telnet public domain
29
NOS public domain
30
SSHDOS GNU GPL
31
Talk GNU GPL
32
ABC-nslookup UCB BSD
21
The valuable DOS Freeware page
4116
368.5 Compilers
assembler
See the FreeDOS project (<http://www.freedos.org>) for assembler compilers.
batch
• BAT2EXE 33 - Compile batch files for speed <ftp://ftp.simtel.net/pub/simtelnet/msdos/batchutl/
bat2ex15.zip> <http://www.alltheweb.com/search?cat=ftp&amp;q=bat2ex15.zip>
C/C++
See the FreeDOS project (<http://www.freedos.org>) for C and C++ compilers.
Perl
Perl 34 - Practical Extraction Report Language <ftp://ftp.simtel.net/pub/simtelnet/msdos/perl/>
Rexx
• BREXX 35 - Rexx interpreter for Dos/Unix <http://ftp.gwdg.de/pub/languages/rexx/brexx/html/
rx.html>
xBase
• nanoBase 36 - Mini, but nearly complete xBase <http://a2.swlibero.org/nanobase_1997.html>
See also:
• David Muir Shamoff, Catalog of free compilers and interpreters
<http://www.idiom.com/free-compilers/>
368.6 Typesetting
• Nro 37 - A Nroff implementation for Dos <ftp://ftp.simtel.net/pub/simtelnet/msdos/txtutl/nroff1.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nroff1.zip>
• Ghostscript 38 - ‘‘GNU’’ original edition - PostScript previewing, conversion, and printing
<ftp://mirror.cs.wisc.edu/pub/mirrors/ghost/gnu/>
• emTeX
tex/>
39
- TeX-LaTeX distribution for Dos <ftp://www.ctan.org/tex-archive/systems/msdos/em-
368.7 More Dos software sources
• <ftp://ftp.simtel.net/pub/simtelnet/msdos/>
• <http://garbo.uwasa.fi/pc/>
33
BAT2EXE public domain
Perl GNU GPL or Artistic
35
BREXX public domain
36
nanoBase GNU GPL
37
Nro public domain
38
Ghostscript GNU GPL
39
emTeX LPPL but some files have different conditions
34
The valuable DOS Freeware page
368.8 Search engines
• <http://www.alltheweb.com/?c=ftp>
• <http://www.shareware.com/>
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
4117
Chapter
369
Clean the Clipper 5.2
A different way to program using Clipper 5.2 without commands, that is, without the file
‘STD.CH’.
This material appeared originally at ‘http://www.geocities.com/SiliconValley/
7737/clipper52clean.html’, in 1996. Now it is incorporated inside the Italian document ‘‘Appunti di informatica libera’’, and might be reached at the URI <http://a2.swlibero.org/
clean_the_clipper_5_2.html>.
Questo materiale è apparso in origine, nel 1996, presso ‘http://www.geocities.com/
SiliconValley/7737/clipper52clean.html’. Adesso viene incorporato nel documento «Appunti di informatica libera» e può essere raggiunto attraverso l’URI <http://
a2.swlibero.org/clean_the_clipper_5_2.html>. L’intento dell’autore è solo quello di conservare un
vecchio lavoro che potrebbe essere ancora utile, nonostante si tratti di considerazioni su un
compilatore proprietario, ormai obsoleto.
369.1 Step 1: try to compile with the /P parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4120
369.2 Step 2: understand well the use of code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4120
369.3 Step 3: understand the object programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4121
369.3.1 Classes and methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4121
369.3.2 Class definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4121
369.3.3 Object creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4121
369.3.4 Instantiating an object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4121
369.3.5 The ‘‘send’’ symbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4122
369.3.6 More about objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4122
369.4 Step 4: understand the get object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4122
369.5 Step 5: trying to stop using commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4124
369.5.1 ?/?? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4124
369.5.2 @...BOX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4124
369.5.3 @...GET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4124
369.5.4 @...SAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4125
369.5.5 @...TO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4125
369.5.6 APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4125
369.5.7 APPEND FROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4125
369.5.8 CLEAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4126
369.5.9 CLOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4126
369.5.10 COMMIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4126
369.5.11 CONTINUE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4126
369.5.12 COPY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4126
369.5.13 COUNT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4127
369.5.14 CREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4127
369.5.15 DEFAULT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4127
4118
Clean the Clipper 5.2
369.5.16
369.5.17
369.5.18
369.5.19
369.5.20
369.5.21
369.5.22
369.5.23
369.5.24
369.5.25
369.5.26
369.5.27
369.5.28
369.5.29
369.5.30
369.5.31
369.5.32
369.5.33
369.5.34
369.5.35
369.5.36
369.5.37
369.5.38
369.5.39
369.5.40
369.5.41
369.5.42
369.5.43
369.5.44
369.5.45
369.5.46
369.5.47
369.5.48
369.5.49
369.5.50
369.5.51
369.5.52
4119
DELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4127
EJECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4128
ERASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4128
FIND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4128
GO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4128
INDEX ON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4128
JOIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4128
KEYBOARD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4128
LABEL FORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4129
LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4129
LOCATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4129
PACK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4129
QUIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4129
READ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4129
RECALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4129
REINDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4130
RELEASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4130
RENAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4130
REPLACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4130
REPORT FORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4130
RESTORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
RESTORE FROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
RUN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
SAVE SCREEN TO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
SAVE TO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
SEEK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
SET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4131
SKIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4135
SORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4135
STORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4135
SUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4135
TOTAL ON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4135
UNLOCK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4135
UPDATE FROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4136
USE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4136
ZAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4136
369.6 Step 6: free yourself from STD.CH - /U . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4136
369.7 Step 7: take control over all include files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4136
Clipper 5.2, as the xBase tradition imposes, is not an ordered, clear, simple programming language. The question is: which is the right way to write a Clipper program? If the intention is not
to make a xBase program, but a Clipper program, maybe it can be decided that it is better to use
Clipper without commands.
Clean the Clipper 5.2
4120
369.1 Step 1: try to compile with the /P parameter
Supposing to compile the file ‘TEST.PRG’ this way:
C:\>CLIPPER TEST.PRG /P
It generates a preprocessed output file (‘test.PPO’), that is a source file without comments,
where commands are translated into real Clipper instructions. That is, all the ‘#COMMAND’ substitution are executed and the translation is sent to the ‘.PPO’ file. It may be difficult to read this
file the first time.
369.2 Step 2: understand well the use of code blocks
The code block is a small piece of executable program code that can be stored inside a variable,
or can be used as a literal constant. The good of it, is that pieces of code may be sent to functions.
A code block is something like a little user defined function where only a sequence of expressions
(functions and/or assignments) may appear: no loops, no conditional structures.
A code block may receive arguments and return a value after execution, just like a function. The
syntax is the following, where curly brackets are part of the code block:
{ |
[argument_list ]
| exp_list }
That is: the argument_list is optional; the exp_list may contain one or more expressions separated with a comma.
For example, calling the following code block will give the string ‘‘hello world’’ as result.
{ || "hello world" }
The following code block requires a numeric argument and returns the number passed as argument incremented:
{ | n | n+1 }
The following code block requires two numeric arguments and returns the sum of the two square
radix:
{ | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }
But code blocks may contain more expressions and the result of the execution of the code block
is the result of the last expression. The following code block executes in sequence some functions
and gives ‘‘hello world’’ as a result.
{ | a, b | functionOne(a), functionTwo(b), "hello world" }
To start the execution of a code block a function is used: ‘EVAL()’. For example, a code block is
assigned to a variable and then executed.
B := { || "hello world" }
EVAL( B ) == "hello world"
Another example with one parameter.
B := { | n | n+1 }
EVAL( B, 1 ) == 2
Another example with two parameters.
B := { | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }
EVAL( B, 2, 4 ) == 20
And so on.
Clean the Clipper 5.2
4121
369.3 Step 3: understand the object programming
Clipper 5.2 do not permit to create objects, but it gives some good objects to use: ‘GET’ and
‘TBROWSE’. Before starting to clean programming from commands, it is necessary to understand
how to use well the Clipper objects.
369.3.1 Classes and methods
A class defines the structure of a ‘‘black box’’, that is a data container; a method is an action
to make on a piece of data contained inside the black box. There is no way to reach the data
contained inside the black box without a method.
The black box can be called object.
The methods may be seen as they where special functions which interact with a specific piece of
data contained inside the object.
369.3.2 Class definition
Supposing that Clipper permits to define classes (unluckily only predefined classes can be used),
the hypothetical syntax could be:
[
]
CLASS ClassName
FROM ParentClass
VAR Var1 ,Var2 ,... VarN
METHOD {method_definition_1 } ,
ENDCLASS
[
[
]]
[
...{method_definition_n
}
]
This way, the class defines a group of variables and a group of method to use with these variables.
369.3.3 Object creation
The presence of classes permits to create objects: the black boxes.
Variable_name := ClassName
This way, a variable contains (is) an object. Please note that inside Clipper, an object may be
generated also from a function, that is, a function can return an object. This way the example can
be:
Variable_name := classfunction(
...
)
The next problem is to handle this object.
369.3.4 Instantiating an object
As already stated before, methods are used to handle data contained inside an object. This is said
to be instantiating an object. Clipper permits also to handle directly (apparently without methods)
some variables contained inside objects. These are called ‘‘Exported Instance Variables’’. So, an
object can be instantiated this way:
object:exported_instance_variable := new_value
object:method()
An exported instance variable may be read and/or modified depending on the allowed access to it;
a method, inside Clipper, is something like a function with or without parameters (if parameters
are present, these are usually used to modify data inside the object), that normally returns a value.
4122
Clean the Clipper 5.2
369.3.5 The ‘‘send’’ symbol
To instantiate an object or simply to access an exported instance variable, the ‘‘send’’ symbol
(colon) is used.
369.3.6 More about objects
If this is not enough to understand objects inside Clipper, the following document should be read:
Peter M. Freese, o:Clip - An Object Oriented Extension to Clipper 5.01 1991, CyberSoft
<ftp://ftp.simtel.net/pub/simtelnet/msdos/clipper/oclip.zip>
369.4 Step 4: understand the get object
What happens with a command like the following:
@ nTop , nLeft GET Var
A get object is created containing all the necessary information for editing the variable Var at
the screen position nTop , nLeft . After that, this get object is added to a get objects array (usually
called ‘GetList’). The get objects array will contain all the get objects used during a ‘READ’.
So, what happens when a ‘READ’ command is encountered. The get objects array (‘GetList’) is
read and the editing of all get objects is executed. After that, the get objects array is cleared.
This method hides what Clipper really makes. The suggestion here is to create a ‘GET()’ function
that will substitute the ‘@...GET’ command and to use the ‘READMODAL()’ function to read the get
objects array. Here is an example of it:
function GET( aoGet, nRow, nCol, bVar, cGetPicture,
cColorString, bPreValid, bPostValid )
// declare a local get object
local oGet
// create the get object using the function GETENV()
oGet := GETENV( nRow, nCol, bVar, NIL, cGetPicture, cGetColor )
// send to the get object the pre-validation condition code block (WHEN)
oGet:preBlock := bPreValid
// send to the get object the post-validation condition code block (VALID)
oGet:postBlock := bPostValid
// display the get on the screen using the display() method
oGet:display()
// add the get object to the get objects array
AADD( aoGet, oGet )
return NIL
• ‘aoGet’ is the get objects array (so here is explicitly passed). This get objects array is
modified (grown) and there is no need to return it as inside Clipper, arrays are always
passed by reference to functions.
• ‘nRow’ and ‘nCol’ are the screen coordinates where the get field should appear at, as it
works with the ‘@...GET’ command.
Clean the Clipper 5.2
4123
• ‘bVar’ is a special code block that permits the editing of a variable. If the variable ‘Var’ is
to be edited, the code block is:
{ |x| iif( pcount() > 0, Var := x, Var }
• ‘cGetPicture’ is the picture to use: same as the ‘@...GET’ command.
• ‘cColorString’ is the color string to use: same as the ‘@...GET’ command.
• ‘bPreValid’ is a code block containing the condition that must be valid before the cursor
can reach this get field. It is equivalent to the ‘WHEN’ condition used with the ‘@...GET’
command, but it must be converted into a code block. For example, if the condition is
‘A > B’, the code block is ‘{|| A > B}’
• ‘bPostValid’ is a code block containing the condition that must be valid before the cursor
can leave this get field. It is equivalent to the ‘VALID’ condition used with the ‘@...GET’
command, but it must be converted into a code block. For example, if the condition is
‘A > B’, the code block is ‘{|| A > B}’
If there is a get function like the above one, screen I/O may be performed like the following
example:
function do_some_editing()
// define a variable to use as a get objects array
// and initialise it to the empty array
local aoGet := {}
...
...
// add a new get object to the get objects array
get(;
aoGet,;
10, 10,;
{ |x| iif( pcount() > 0, myVariable := x, myVariable },;
"@s30@",;
"gb+/b, n/w,
n, n, w/n",;
{ || .T. },;
{ || .T. };
)
...
// read the get objects array
readmodal( aoGet )
// clear the get objects array
aoGet := {}
...
return ...
If the function ‘GET()’ is not liked, the above I/O may be done as it follows:
function do_some_editing()
// define a variable to use as a get object
local aoGet
// define a variable to use as a get objects array
// and initialise it to the empty array
local aoGet := {}
...
Clean the Clipper 5.2
4124
...
// add a new get object to the get objects array
oGet :=;
GETENV(;
10, 10,;
{ |x| iif( pcount() > 0, myVariable := x, myVariable },;
NIL,;
"@s30@",;
"gb+/b, n/w,
n, n, w/n",;
)
AADD( aoGet, oGet )
...
// read the get objects array
readmodal( aoGet )
// clear the get objects array
aoGet := {}
...
return ...
369.5 Step 5: trying to stop using commands
To stop using commands, it is important to understand how commands are or may be translated
into functions. Sometimes Clipper uses some undocumented functions: these are functions that
start with a underline.
369.5.1 ?/??
[exp_list]
qout([exp_list])
?? [exp_list]
qqout([exp_list])
?
369.5.2 @...BOX
[COLOR cColorString]
nRight , [cnBoxString ], [cColorString ])
@ nTop , nLeft , nBottom , nRight BOX cnBoxString
dispbox(nTop , nLeft , nBottom ,
369.5.3 @...GET
[
]
] [COLOR
@ nTop , nLeft GET Var PICTURE cGetPicture
,→ VALID lPostExpression
[
cColorString
] [WHEN
lPreExpression
]
←-
setpos(nTop , nLeft )
[
]
aadd( GetList, _GET_( Var , "Var ", cGetPicture , {|| lPostExpression } ,←,→ {|| lPreExpression } ):display() ) atail(GetList):colorDisp(cColorString )
[
]
This is the command substitution made automatically, but it shouldn’t be used to make clean
programs. The step 4 (369.1) suggests to create a get function.
Clean the Clipper 5.2
4125
369.5.4 @...SAY
@ nTop , nLeft SAY exp
[COLOR
cColorString
]
devpos(nTop , nLeft )
devout(exp
[,
]
cColorString )
@ nTop , nLeft SAY exp PICTURE cSayPicture
[COLOR
cColorString
]
devpos(nTop , nLeft )
devoutpic(exp , cSayPicture ,
[cColorString])
369.5.5 @...TO
[COLOR cColorString]
dispbox(nTop , nLeft , nBottom , nRight , 2 [,cColorString ])
@ nTop , nLeft TO nBottom , nRight [COLOR cColorString ]
dispbox(nTop , nLeft , nBottom , nRight , 1 [,cColorString ])
@ nTop , nLeft CLEAR [TO nBottom , nRight ]
scroll([nTop ], [nLeft ], [nBottom , nRight ])
@ nTop , nLeft TO nBottom , nRight DOUBLE
setpos(nRow , nCol )
369.5.6 APPEND
APPEND BLANK
dbappend()
369.5.7 APPEND FROM
[FIELDS idField_list] [scope] [WHILE lCondition]←] [VIA xcDriver]
__dbApp( cFileName , [acFields], [bForCondition ], [bWhileCondition ], [nNextRecords ],←,→[nRecord ], [lRest], [cDriver] )
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition ] [FOR lCondition ]←,→
APPEND FROM xcFile
,→ FOR lCondition
[
DELIMITED xcDelimiter
[
] [
] [acFields], [bForCondition ], [bWhileCondition ]
__dbDelim( .f., cFileName , cDelimiter ,
,←,→ nNextRecords , nRecord , lRest )
[
] [
]
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition ]←,→[FOR lCondition ] SDF
__dbSDF( .f., cFileName , [acFields], [bForCondition ], [bWhileCondition ], [nNextRecords ]
,←,→[nRecord ], [lRest] )
Clean the Clipper 5.2
4126
369.5.8 CLEAR
CLEAR
Scroll()
SetPos(0,0)
ReadKill(.T.)
GetList := {}
CLEAR GETS
ReadKill(.T.)
GetList := {}
CLEAR SCREEN
| CLS
Scroll()
SetPos(0,0)
369.5.9 CLOSE
CLOSE
dbCloseArea()
CLOSE idAlias
idAlias ->( dbCloseArea() )
CLOSE ALTERNATE
Set(19, "")
CLOSE DATABASES
dbCloseAll()
CLOSE INDEXES
dbClearIndex()
369.5.10 COMMIT
COMMIT
dbCommitAll()
369.5.11 CONTINUE
CONTINUE
__dbContinue()
369.5.12 COPY
|xcDevice
__CopyFile( cSourceFile , cTargetFile |cDevice )
COPY STRUCTURE [FIELDS idField_list] TO xcDatabase
__dbCopyStruct( cDatabase, [acFields] )
COPY FILE xcSourceFile TO xcTargetFile
COPY STRUCTURE EXTENDED TO xcExtendedDatabase
__dbCopyXStruct( cExtendedDatabase )
[
][
] [scope] [WHILE
]
COPY TO xcFile
FIELDS idField_list
,→ FOR lCondition
VIA xcDriver
[
]
lCondition ←-
Clean the Clipper 5.2
4127
[
] [
], [bWhileCondition ], [nNextRecords ],←] [ ] [
]
xcFile [FIELDS idField_list] [scope] [WHILE lCondition ] [FOR lCondition ]←-
__dbCopy( cFileName , acFields , bForCondition
,→ nRecord , lRest , cDriver )
[
COPY TO
,→DELIMITED xcDelimiter
[
] [
] [acFields], [bForCondition ], [bWhileCondition ]
__dbDelim( .t., cFileName , cDelimiter ,
,←,→ nNextRecords , nRecord , lRest )
[
] [
COPY TO xcFile [FIELDS
,→[FOR lCondition ] SDF
]
idField_list] [scope] [WHILE
__dbSDF( .t., cFileName ,
,←,→ nRecord , lRest )
[
] [
]
lCondition ←-
[acFields], [bForCondition ], [bWhileCondition ], [nNextRecords ]
]
369.5.13 COUNT
[
] [WHILE
][ ]
COUNT TO idVar FOR lForCondition
,→ RECORD nRecord
REST
ALL
[
][
lWhileCondition
] [NEXT
nNextRecords
]←-
dbeval( {||idVar :=idVar +1}, {||lForCondition }, {||lWhileCondition },←,→ nNextRecords , nRecord , lRest )
369.5.14 CREATE
[NEW] [ALIAS cAlias] [VIA cDriver]
cExtendedDatabase , [cDriver], [lNew], [cAlias] )
CREATE xcDatabase FROM xcExtendedDatabase
__dbCreate( cDatabase,
369.5.15 DEFAULT
DEFAULT xVar TO xDefaultValue
if xVar == NIL
xVar := xDefaultValue
end
369.5.16 DELETE
DELETE
dbDelete()
[
] [WHILE lWhileCondition ] [NEXT
] [ ] [ALL]
DELETE FOR lForCondition
,→ RECORD nRecord
REST
[
nNextRecords
dbeval( {||dbDelete()}, {||lForCondition }, {||lWhileCondition },←,→ nNextRecords , nRecord , lRest )
DELETE FILE xcFile
ferase( cFile )
]←-
Clean the Clipper 5.2
4128
369.5.17 EJECT
EJECT
qqout( chr(13) )
369.5.18 ERASE
ERASE xcFile
ferase( cFile )
369.5.19 FIND
FIND xcSearchString
dbSeek( cSearchString )
369.5.20 GO
[ ]
GO TO
nRecord
dbgoto(nRecord )
[ ]
GO TO
BOTTOM
dbGoBottom()
[ ]
GO TO
TOP
dbgotop()
369.5.21 INDEX ON
[
][
]
INDEX ON expKey TO xcIndexName
UNIQUE
FOR lForCondition ←,→ WHILE lWhileCondition
EVAL lEvalCondition
EVERY nRecords
[
] [[
][
]] [ASCENDING|
]
DESCENDING
[
] [
]
]
[
ordCondSet( cForCondition , bForCondition , , bWhileCondition
,→ bEvalCondition , nRecords , RECNO(), , , , lDescending )
[
] [
],←-
ordCreate( cIndexName , , cExpKey , bExpKey , lUnique )
369.5.22 JOIN
] [FIELDS idField_list]
cDatabase, [acFields], [bForCondition ] )
JOIN WITH xcAlias TO xcDatabase
__dbJoin( cAlias ,
[FOR
369.5.23 KEYBOARD
KEYBOARD cString
__Keyboard(
[cString]
) --> NIL
lCondition
Clean the Clipper 5.2
4129
369.5.24 LABEL FORM
[TO PRINTER] [TO FILE xcFile] [NOCONSOLE] [scope]←[
] [FOR lCondition] [SAMPLE]
__LabelForm( cLabel , [lToPrinter ], [cFile], [lNoConsole ],←,→[bForCondition ], [bWhileCondition ], [nNextRecords ], [nRecord ],←,→[lRest], [lSample ] )
LABEL FORM xcLabel
,→ WHILE lCondition
369.5.25 LIST
[
][
] [scope]←][
][ ]
__dbList( [lToDisplay], abListColumns , [lAll], [bForCondition ], [bWhileCondition ],←,→[nNextRecords ], [nRecord ], [lRest], [lToPrinter], [cFileName ] )
LIST exp_list TO PRINTER
TO FILE xcFile
,→ WHILE lCondition
FOR lCondition
OFF
[
369.5.26 LOCATE
[scope] FOR lCondition [WHILE lCondition]
__dbLocate( [bForCondition ], [bWhileCondition ], [nNextRecords ], [nRecord ], [lRest]
LOCATE
369.5.27 PACK
PACK
__dbPack()
369.5.28 QUIT
QUIT
__Quit()
369.5.29 READ
READ
ReadModal(GetList)
GetList := {}
READ SAVE
ReadModal(GetList)
369.5.30 RECALL
RECALL
dbRecall()
[
] [WHILE lWhileCondition ] [NEXT
] [ALL]
RECALL FOR lForCondition
,→ RECORD nRecord
REST
[
][
nNextRecords
dbeval( {||dbRecall()}, {||lForCondition }, {||lWhileCondition },←,→ nNextRecords , nRecord , lRest )
]←-
)
Clean the Clipper 5.2
4130
369.5.31 REINDEX
REINDEX
[EVAL
] [EVERY nRecords]
, [bEvalCondition ], [nRecords ],
lEvalCondition
ordCondSet(, , ,
, , , , , , )
ordListRebuild()
369.5.32 RELEASE
RELEASE idMemvar
__MXRelease( "idMemvar " )
RELEASE ALL
__MRelease("*", .t.)
RELEASE ALL LIKE skeleton
__MRelease( "skeleton ", .t. )
RELEASE ALL EXCEPT skeleton
__MRelease( "skeleton ", .F. )
369.5.33 RENAME
RENAME xcOldFile TO xcNewFile
frename( cOldFile , cNewFile )
369.5.34 REPLACE
[
][
][ ][ ]
idField1 := exp1 [, idField2
]
REPLACE idField1 WITH exp1 , idField2 WITH exp2 ... ←,→ FOR lForCondition
WHILE lWhileCondition
NEXT nNextRecords
,→ RECORD nRecord
REST
ALL
[
[
][
]←-
]
dbeval( {||
:= exp2 ... },←,→{||lForCondition }, {||lWhileCondition }, nNextRecords ,←,→ nRecord , lRest )
REPLACE idField1 WITH exp1
idField1 := exp1
369.5.35 REPORT FORM
[TO PRINTER] [TO FILE xcFile] [NOCONSOLE] [scope]←] [FOR lCondition] [PLAIN | HEADING cHeading] [NOEJECT] [SUMMARY
REPORT FORM xcReport
,→ WHILE lCondition
[
]
[
] [
] [
] [
] [
__ReportForm( cForm , lToPrinter , cToFile , lNoConsole , bForCondition ,
bWhileCondition ,←,→ nNext , nRecord , lRest , lPlain , cbHeading , lBeforeEject , lSummary
[
]
] [
] [
] [
] [
] [
] [
]
)
Clean the Clipper 5.2
4131
369.5.36 RESTORE
RESTORE SCREEN FROM cScreen
restscreen( 0, 0, Maxrow(), Maxcol(), cScreen )
369.5.37 RESTORE FROM
[ADDITIVE]
cMemFileName , [lAdditive]
RESTORE FROM xcMemFile
__MRestore(
)
369.5.38 RUN
RUN xcCommandLine
__Run( cCommand )
369.5.39 SAVE SCREEN TO
SAVE SCREEN TO cScreen
cScreen := savescreen( 0, 0, maxrow(), maxcol() )
369.5.40 SAVE TO
[ALL [LIKE|EXCEPT skeleton]]
cMemFileName , [cSkeleton ], [lLike ] )
SAVE TO xcMemFile
_MSave(
369.5.41 SEEK
[SOFTSEEK]
expSearch [, lSoftSeek ]
SEEK expSearch
dbSeek(
)
369.5.42 SELECT
SELECT xnWorkArea
|
idAlias
dbSelectArea( nWorkArea
|
cIdAlias )
369.5.43 SET
Most of the ‘SET...’ commands are translated into the ‘SET()’ function that distinguishes different modes depending on a number. As this number is difficult to handle during programming
(essentially because it is difficult to remember the meaning of it), Clipper offers the ‘SET.CH’
include file that helps with manifest constants.
#define
#define
#define
#define
#define
#define
_SET_EXACT
_SET_FIXED
_SET_DECIMALS
_SET_DATEFORMAT
_SET_EPOCH
_SET_PATH
1
2
3
4
5
6
Clean the Clipper 5.2
4132
#define _SET_DEFAULT
#define
#define
#define
#define
7
_SET_EXCLUSIVE
_SET_SOFTSEEK
_SET_UNIQUE
_SET_DELETED
8
9
10
11
#define _SET_CANCEL
#define _SET_DEBUG
#define _SET_TYPEAHEAD
12
13
14
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
_SET_COLOR
_SET_CURSOR
_SET_CONSOLE
_SET_ALTERNATE
_SET_ALTFILE
_SET_DEVICE
_SET_EXTRA
_SET_EXTRAFILE
_SET_PRINTER
_SET_PRINTFILE
_SET_MARGIN
15
16
17
18
19
20
21
22
23
24
25
#define
#define
#define
#define
#define
#define
#define
#define
#define
_SET_BELL
_SET_CONFIRM
_SET_ESCAPE
_SET_INSERT
_SET_EXIT
_SET_INTENSITY
_SET_SCOREBOARD
_SET_DELIMITERS
_SET_DELIMCHARS
26
27
28
29
30
31
32
33
34
#define
#define
#define
#define
_SET_WRAP
_SET_MESSAGE
_SET_MCENTER
_SET_SCROLLBREAK
35
36
37
38
SET ALTERNATE TO xcFile
[ADDITIVE]
Set( _SET_ALTFILE, cFile , lAdditive )
SET ALTERNATE ON
| OFF |
Set( _SET_ALTERNATE, "ON"
SET BELL ON
| OFF |
Set( _SET_BELL, "ON"
SET COLOR
| COLOUR
xlToggle
| "OFF" |
lToggle )
xlToggle
| "OFF" |
lToggle )
TO (cColorString)
SetColor( cColorString )
SET CONFIRM ON
| OFF |
Set( _SET_CONFIRM, "ON"
SET CONSOLE ON
| OFF |
Set( _SET_CONSOLE, "ON"
xlToggle
| "OFF" |
lToggle )
xlToggle
| "OFF" |
| OFF | xlToggle
SetCursor( 1 | 0 | iif( lToggle ,
SET DATE FORMAT [TO] cDateFormat
lToggle )
SET CURSOR ON
1, 0 ) )
Clean the Clipper 5.2
4133
Set( _SET_DATEFORMAT, cDateFormat )
SET DECIMALS TO
Set( _SET_DECIMALS, 0 )
SET DECIMALS TO nDecimals
Set( _SET_DECIMALS, nDecimals )
SET DEFAULT TO
Set( _SET_DEFAULT, "" )
SET DEFAULT TO xcPathspec
Set( _SET_DEFAULT, cPathspec )
SET DELETED ON
| OFF |
xlToggle
| "OFF" | lToggle )
SET DELIMITERS ON | OFF | xlToggle
Set( _SET_DELIMITERS, "ON" | "OFF" | lToggle
SET DELIMITERS TO [DEFAULT]
Set( _SET_DELETED, "ON"
)
Set( _SET_DELIMCHARS, "::" )
SET DELIMITERS TO cDelimiters
Set( _SET_DELIMCHARS, cDelimiters )
| PRINTER
"SCREEN" | "PRINTER"
SET DEVICE TO SCREEN
Set( _SET_DEVICE,
)
SET EPOCH TO nYear
Set( _SET_EPOCH, nYear )
SET ESCAPE ON
| OFF |
xlToggle
Set( _SET_ESCAPE, "ON"
SET EXACT ON
| OFF |
| "OFF" |
lToggle )
xlToggle
| "OFF" | lToggle )
SET EXCLUSIVE ON | OFF | xlToggle
Set( _SET_EXCLUSIVE, "ON" | "OFF" | lToggle
Set( _SET_EXACT, "ON"
SET FILTER TO
dbclearfilter()
SET FILTER TO lCondition
dbsetfilter( bCondition , cCondition )
SET FIXED ON
| OFF |
Set( _SET_FIXED, "ON"
xlToggle
| "OFF" |
lToggle )
SET FUNCTION nFunctionKey TO cString
__SetFunction( nFunctionKey , cString )
SET INDEX TO
[xcIndex [,
xcIndex1 ...
ordListClear()
ordListAdd( cIndex )
ordListAdd( cIndex1 )
...
SET INTENSITY ON
| OFF |
xlToggle
]]
)
Clean the Clipper 5.2
4134
Set( _SET_INTENSITY, "ON"
SET KEY nInkeyCode
| "OFF" |
lToggle )
[TO]
SetKey( nInkeyCode , NIL )
SET KEY nInkeyCode TO
[idProcedure]
SetKey( nInkeyCode , { |p, l, v| idProcedure(p, l, v)} )
SET MARGIN TO
Set( _SET_MARGIN, 0 )
SET MARGIN TO
[nPageOffset ]
Set( _SET_MARGIN, nPageOffset )
SET MESSAGE TO
Set( _SET_MESSAGE, 0 )
Set( _SET_MCENTER, .F. )
SET MESSAGE TO
[nRow [CENTER | CENTRE]]
Set( _SET_MESSAGE, nRow )
Set( _SET_MCENTER, lCenter )
SET ORDER TO
[nIndex ]
ordSetFocus( nIndex )
SET PATH TO
Set( _SET_PATH, "" )
[xcPathspec [, cPathspec1 ... ] ]
Set( _SET_PATH, cPathspec [, cPathspec1 ... ] )
SET PRINTER ON | OFF | xlToggle
Set( _SET_PRINTER, "ON" | "OFF" | lToggle
SET PATH TO
)
SET PRINTER TO
Set( _SET_PRINTFILE, "" )
[xcDevice|xcFile [ADDITIVE]]
_SET_PRINTFILE, cDevice|cFile , lAdditive
SET PRINTER TO
Set(
)
SET RELATION TO
dbclearrelation()
SET RELATION TO
[expKey1
INTO xcAlias1
] [, [TO]
dbClearRel()
["expKey1 "] )
dbSetRelation( cAlias2 , {||expKey2 }, ["expKey1 "] )
SET RELATION TO [expKey1 INTO xcAlias1 ]←,→[, [TO] expKey2 INTO xcAlias2 ...] ADDITIVE
dbSetRelation( cAlias1 , {||expKey1 }, ["expKey1 "] )
dbSetRelation( cAlias2 , {||expKey2 }, ["expKey1 "] )
SET SCOREBOARD ON | OFF | xlToggle
Set( _SET_SCOREBOARD, "ON" | "OFF" | lToggle )
SET SOFTSEEK ON | OFF | xlToggle
Set( _SET_SOFTSEEK, "ON" | "OFF" | lToggle )
dbSetRelation( cAlias1 , {||expKey1 },
]
expKey2 INTO xcAlias2 ...
Clean the Clipper 5.2
4135
SET TYPEAHEAD TO nKeyboardSise
Set( _SET_TYPEAHEAD, nKeyboardSise )
| OFF | xlToggle
Set( _SET_UNIQUE, "ON" | "OFF" | lToggle
SET WRAP ON | OFF | xlToggle
Set( _SET_WRAP, "ON" | "OFF" | lToggle )
SET UNIQUE ON
)
369.5.44 SKIP
[nRecords] [ALIAS idAlias|nWorkArea ]
[idAlias|nWorkArea -> ]( dbSkip([nRecords])
SKIP
)
369.5.45 SORT
[/[A|D][C]] [, idField2 [/[A|D][C]] ...]←[ ][
] [FOR lCondition]
__dbSort( cDatabase, [acFields], [bForCondition ], [bWhileCondition ],←,→[nNextRecords ], [nRecord ], [lRest] )
SORT TO xcDatabase ON idField1
,→ scope
WHILE lCondition
369.5.46 STORE
STORE value TO variable
variable := value
369.5.47 SUM
[
]
[
] [FOR lForCondition ]←] [RECORD nRecord] [REST] [ALL]
[, idVar2 :=idVar2 +nExp2 ...] },←-
SUM nExp1
, nExp2 ... TO idVar1 , idVar2 ...
,→ WHILE lWhileCondition
NEXT nNextRecords
[
][
dbeval( {||idVar1 :=idVar1 +nExp1
,→{||lForCondition }, {||lWhileCondition }, nNextRecords , nRecord , lRest )
369.5.48 TOTAL ON
[
][
] TO xcDatabase [scope]←]
__dbTotal( cDatabase, bKey, [acFields], [bForCondition ], [bWhileCondition ],←,→[nNextRecords ], [nRecord ], [lRest] )
TOTAL ON expKey FIELDS idField_list
,→ WHILE lCondition
FOR lCondition
[
369.5.49 UNLOCK
UNLOCK
dbUnlock()
UNLOCK ALL
dbUnlockAll()
Clean the Clipper 5.2
4136
369.5.50 UPDATE FROM
[
]
UPDATE FROM xcAlias ON expKey RANDOM
,→WITH exp , idField2 WITH exp ...
[
__dbUpdate( cAlias ,
REPLACE idField1 ←-
]
bKey, [lRandom ], [bReplacement ]
)
Example:
__dbUpdate( "INVOICE", {|| LAST}, .T.,; {|| FIELD->TOTAL1 := ←,→INVOICE->SUM1,; FIELD->TOTAL2 := INVOICE->SUM2 } )
369.5.51 USE
USE
dbclosearea()
[
]
USE xcDatabase ←,→ INDEX xcIndex1
, xcIndex2 ...
[
[
] [ALIAS
] [VIA cDriver]]
dbUseArea( [lNewArea ], [cDriver],
[dbSetIndex( cIndex1 )]
[dbSetIndex( cIndex2 )]
xcAlias
] [EXCLUSIVE|SHARED] [NEW] [
READONLY
cDatabase,
[cAlias], [lShared], [lReadOnly]
)
...
369.5.52 ZAP
ZAP
dbZap()
369.6 Step 6: free yourself from STD.CH - /U
Now that no command is used, the standard include file ‘STD.CH’ is no more necessary. Clipper
uses ‘STD.CH’ automatically, unless specified differently. Just compile this way:
C:>CLIPPER TEST.PRG /U
369.7 Step 7: take control over all include files
Clipper comes with so many include files (‘*.CH’). To avoid confusion, a single ‘STANDARD.CH’
file containing all what is needed for the application may be prepared. At least, it is necessary the
following.
*=================================================================
* DISPBOX()
*=================================================================
* Single-line box
#define BOX_SINGLE;
(;
CHR(218) +;
CHR(196) +;
CHR(191) +;
CHR(179) +;
Clean the Clipper 5.2
4137
CHR(217) +;
CHR(196) +;
CHR(192) +;
CHR(179);
)
* Double-line box
#define BOX_DOUBLE;
(;
CHR(201) +;
CHR(205) +;
CHR(187) +;
CHR(186) +;
CHR(188) +;
CHR(205) +;
CHR(200) +;
CHR(186);
)
* Single-line top, double-line sides
#define BOX_SINGLE_DOUBLE;
(;
CHR(214) +;
CHR(196) +;
CHR(183) +;
CHR(186) +;
CHR(189) +;
CHR(196) +;
CHR(211) +;
CHR(186);
)
* Double-line top, single-line sides
#define BOX_DOUBLE_SINGLE;
(;
CHR(213) +;
CHR(205) +;
CHR(184) +;
CHR(179) +;
CHR(190) +;
CHR(205) +;
CHR(212) +;
CHR(179);
)
*=================================================================
* ERRORS
*=================================================================
* Severity levels (e:severity)
#define ERROR_SEVERITY_WHOCARES
#define ERROR_SEVERITY_WARNING
#define ERROR_SEVERITY_ERROR
#define ERROR_SEVERITY_CATASTROPHIC
* Generic error codes (e:genCode)
#define ERROR_GENERIC_ARG
#define ERROR_GENERIC_BOUND
#define ERROR_GENERIC_STROVERFLOW
#define ERROR_GENERIC_NUMOVERFLOW
#define ERROR_GENERIC_ZERODIV
#define ERROR_GENERIC_NUMERR
#define ERROR_GENERIC_SYNTAX
#define ERROR_GENERIC_COMPLEXITY
0
1
2
3
1
2
3
4
5
6
7
8
Clean the Clipper 5.2
4138
#define
#define
#define
#define
#define
#define
#define
#define
ERROR_GENERIC_MEM
ERROR_GENERIC_NOFUNC
ERROR_GENERIC_NOMETHOD
ERROR_GENERIC_NOVAR
ERROR_GENERIC_NOALIAS
ERROR_GENERIC_NOVARMETHOD
ERROR_GENERIC_BADALIAS
ERROR_GENERIC_DUPALIAS
11
12
13
14
15
16
17
18
#define
#define
#define
#define
#define
#define
ERROR_GENERIC_CREATE
ERROR_GENERIC_OPEN
ERROR_GENERIC_CLOSE
ERROR_GENERIC_READ
ERROR_GENERIC_WRITE
ERROR_GENERIC_PRINT
20
21
22
23
24
25
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
ERROR_GENERIC_UNSUPPORTED
ERROR_GENERIC_LIMIT
ERROR_GENERIC_CORRUPTION
ERROR_GENERIC_DATATYPE
ERROR_GENERIC_DATAWIDTH
ERROR_GENERIC_NOTABLE
ERROR_GENERIC_NOORDER
ERROR_GENERIC_SHARED
ERROR_GENERIC_UNLOCKED
ERROR_GENERIC_READONLY
30
31
32
33
34
35
36
37
38
39
#define ERROR_GENERIC_APPENDLOCK
#define ERROR_GENERIC_LOCK
40
41
*=================================================================
* INKEY()
*=================================================================
#define
#define
#define
#define
#define
#define
#define
#define
K_UP
K_DOWN
K_LEFT
K_RIGHT
K_HOME
K_END
K_PGUP
K_PGDN
5
24
19
4
1
6
18
3
//
//
//
//
//
//
//
//
Up arrow, Ctrl-E
Down arrow, Ctrl-X
Left arrow, Ctrl-S
Right arrow, Ctrl-D
Home, Ctrl-A
End, Ctrl-F
PgUp, Ctrl-R
PgDn, Ctrl-C
#define
#define
#define
#define
#define
#define
#define
#define
K_CTRL_UP
K_CTRL_DOWN
K_CTRL_LEFT
K_CTRL_RIGHT
K_CTRL_HOME
K_CTRL_END
K_CTRL_PGUP
K_CTRL_PGDN
397
401
26
2
29
23
31
30
// * Ctrl-Up arrow
// * Ctrl-Down arrow
//
Ctrl-Left arrow, Ctrl-Z
//
Ctrl-Right arrow, Ctrl-B
//
Ctrl-Home, Ctrl-</synsqb>
//
Ctrl-End, Ctrl-W
//
Ctrl-PgUp, Ctrl-Hyphen
//
Ctrl-PgDn, Ctrl-^
#define
#define
#define
#define
#define
#define
#define
#define
K_ALT_UP
K_ALT_DOWN
K_ALT_LEFT
K_ALT_RIGHT
K_ALT_HOME
K_ALT_END
K_ALT_PGUP
K_ALT_PGDN
408
416
411
413
407
415
409
417
//
//
//
//
//
//
//
//
#define
#define
#define
#define
K_ENTER
K_RETURN
K_SPACE
K_ESC
13
13
32
27
//
//
//
//
*
*
*
*
*
*
*
*
Alt-Up arrow
Alt-Down arrow
Alt-Left arrow
Alt-Right arrow
Alt-Home
Alt-End
Alt-PgUp
Alt-PgDn
Enter, Ctrl-M
Return, Ctrl-M
Space bar
Esc, Ctrl-<synsqb>
Clean the Clipper 5.2
4139
#define
#define
#define
#define
#define
K_CTRL_ENTER
K_CTRL_RETURN
K_CTRL_RET
K_CTRL_PRTSCR
K_CTRL_QUESTION
10
10
10
379
309
//
Ctrl-Enter
//
Ctrl-Return
//
Ctrl-Return (Compat.)
// * Ctrl-Print Screen
//
Ctrl-?
#define
#define
#define
#define
K_ALT_ENTER
K_ALT_RETURN
K_ALT_EQUALS
K_ALT_ESC
284
284
387
257
//
//
//
//
#define KP_ALT_ENTER
422
// * Keypad Alt-Enter
#define
#define
#define
#define
#define
KP_CTRL_5
KP_CTRL_SLASH
KP_CTRL_ASTERISK
KP_CTRL_MINUS
KP_CTRL_PLUS
399
405
406
398
400
//
//
//
//
//
*
*
*
*
*
Keypad
Keypad
Keypad
Keypad
Keypad
Ctrl-5
Ctrl-/
Ctrl-*
Ctrl-Ctrl-+
#define
#define
#define
#define
#define
KP_ALT_5
KP_ALT_SLASH
KP_ALT_ASTERISK
KP_ALT_MINUS
KP_ALT_PLUS
5
420
311
330
334
//
//
//
//
//
*
*
*
*
*
Keypad
Keypad
Keypad
Keypad
Keypad
Alt-5
Alt-/
Alt-*
Alt-Alt-+
#define
#define
#define
#define
#define
K_INS
K_DEL
K_BS
K_TAB
K_SH_TAB
22
7
8
9
271
//
//
//
//
//
#define
#define
#define
#define
K_CTRL_INS
K_CTRL_DEL
K_CTRL_BS
K_CTRL_TAB
402
403
127
404
// * Ctrl-Ins
// * Ctrl-Del
//
Ctrl-Backspace
// * Ctrl-Tab
#define
#define
#define
#define
K_ALT_INS
K_ALT_DEL
K_ALT_BS
K_ALT_TAB
418
419
270
421
//
//
//
//
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
K_CTRL_A
K_CTRL_B
K_CTRL_C
K_CTRL_D
K_CTRL_E
K_CTRL_F
K_CTRL_G
K_CTRL_H
K_CTRL_I
K_CTRL_J
K_CTRL_K
K_CTRL_L
K_CTRL_M
K_CTRL_N
K_CTRL_O
K_CTRL_P
K_CTRL_Q
K_CTRL_R
K_CTRL_S
K_CTRL_T
K_CTRL_U
K_CTRL_V
K_CTRL_W
K_CTRL_X
K_CTRL_Y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
*
*
*
*
Alt-Enter
Alt-Return
Alt-Equals
Alt-Esc
Ins, Ctrl-V
Del, Ctrl-G
Backspace, Ctrl-H
Tab, Ctrl-I
Shift-Tab
*
*
*
*
Alt-Ins
Alt-Del
Alt-Backspace
Alt-Tab
Ctrl-A,
Ctrl-B,
Ctrl-C,
Ctrl-D,
Ctrl-E,
Ctrl-F,
Ctrl-G,
Ctrl-H,
Ctrl-I,
Ctrl-J
Ctrl-K
Ctrl-L
Ctrl-M,
Ctrl-N
Ctrl-O
Ctrl-P
Ctrl-Q
Ctrl-R,
Ctrl-S,
Ctrl-T
Ctrl-U
Ctrl-V,
Ctrl-W,
Ctrl-X,
Ctrl-Y
Home
Ctrl-Right arrow
PgDn, Ctrl-ScrollLock
Right arrow
Up arrow
End
Del
Backspace
Tab
Return
PgUp
Left arrow
Ins
Ctrl-End
Down arrow
Clean the Clipper 5.2
4140
#define K_CTRL_Z
26
//
Ctrl-Z, Ctrl-Left arrow
Alt-A
Alt-B
Alt-C
Alt-D
Alt-E
Alt-F
Alt-G
Alt-H
Alt-I
Alt-J
Alt-K
Alt-L
Alt-M
Alt-N
Alt-O
Alt-P
Alt-Q
Alt-R
Alt-S
Alt-T
Alt-U
Alt-V
Alt-W
Alt-X
Alt-Y
Alt-Z
Alt-1
Alt-2
Alt-3
Alt-4
Alt-5
Alt-6
Alt-7
Alt-8
Alt-9
Alt-0
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
K_ALT_A
K_ALT_B
K_ALT_C
K_ALT_D
K_ALT_E
K_ALT_F
K_ALT_G
K_ALT_H
K_ALT_I
K_ALT_J
K_ALT_K
K_ALT_L
K_ALT_M
K_ALT_N
K_ALT_O
K_ALT_P
K_ALT_Q
K_ALT_R
K_ALT_S
K_ALT_T
K_ALT_U
K_ALT_V
K_ALT_W
K_ALT_X
K_ALT_Y
K_ALT_Z
K_ALT_1
K_ALT_2
K_ALT_3
K_ALT_4
K_ALT_5
K_ALT_6
K_ALT_7
K_ALT_8
K_ALT_9
K_ALT_0
286
304
302
288
274
289
290
291
279
292
293
294
306
305
280
281
272
275
287
276
278
303
273
301
277
300
376
377
378
379
380
381
382
383
384
385
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
K_F1
K_F2
K_F3
K_F4
K_F5
K_F6
K_F7
K_F8
K_F9
K_F10
K_F11
K_F12
28
-1
-2
-3
-4
-5
-6
-7
-8
-9
-40
-41
//
F1, Ctrl-Backslash
//
F2
//
F3
//
F4
//
F5
//
F6
//
F7
//
F8
//
F9
//
F10
// * F11
// * F12
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
K_CTRL_F1
K_CTRL_F2
K_CTRL_F3
K_CTRL_F4
K_CTRL_F5
K_CTRL_F6
K_CTRL_F7
K_CTRL_F8
K_CTRL_F9
K_CTRL_F10
K_CTRL_F11
K_CTRL_F12
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-44
-45
//
Ctrl-F1
//
Ctrl-F2
//
Ctrl-F4
//
Ctrl-F3
//
Ctrl-F5
//
Ctrl-F6
//
Ctrl-F7
//
Ctrl-F8
//
Ctrl-F9
//
Ctrl-F10
// * Ctrl-F11
// * Ctrl-F12
-30
//
#define K_ALT_F1
Alt-F1
Clean the Clipper 5.2
4141
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
K_ALT_F2
K_ALT_F3
K_ALT_F4
K_ALT_F5
K_ALT_F6
K_ALT_F7
K_ALT_F8
K_ALT_F9
K_ALT_F10
K_ALT_F11
K_ALT_F12
-31
-32
-33
-34
-35
-36
-37
-38
-39
-46
-47
//
Alt-F2
//
Alt-F3
//
Alt-F4
//
Alt-F5
//
Alt-F6
//
Alt-F7
//
Alt-F8
//
Alt-F9
//
Alt-F10
// * Alt-F11
// * Alt-F12
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
K_SH_F1
K_SH_F2
K_SH_F3
K_SH_F4
K_SH_F5
K_SH_F6
K_SH_F7
K_SH_F8
K_SH_F9
K_SH_F10
K_SH_F11
K_SH_F12
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-42
-43
//
Shift-F1
//
Shift-F2
//
Shift-F3
//
Shift-F4
//
Shift-F5
//
Shift-F6
//
Shift-F7
//
Shift-F8
//
Shift-F9
//
Shift-F10
// * Shift-F11
// * Shift-F12
*=================================================================
* MEMOEDIT()
*=================================================================
* User function entry modes
#define MEMOEDIT_IDLE
#define MEMOEDIT_UNKEY
#define MEMOEDIT_UNKEYX
#define MEMOEDIT_INIT
0
1
2
3
//
//
//
//
idle, all keys processed
unknown key, memo unaltered
unknown key, memo altered
initialization mode
* User function return codes
#define MEMOEDIT_DEFAULT
0
#define MEMOEDIT_IGNORE
32
#define MEMOEDIT_DATA
33
#define MEMOEDIT_TOGGLEWRAP
34
#define MEMOEDIT_TOGGLESCROLL 35
#define MEMOEDIT_WORDRIGHT
100
#define MEMOEDIT_BOTTOMRIGHT 101
//
//
//
//
//
//
//
perform default action
ignore unknown key
treat unknown key as data
toggle word-wrap mode
toggle scrolling mode
perform word-right operation
perform bottom-right operation
*=================================================================
* SET()
*=================================================================
#define
#define
#define
#define
#define
#define
#define
_SET_EXACT
_SET_FIXED
_SET_DECIMALS
_SET_DATEFORMAT
_SET_EPOCH
_SET_PATH
_SET_DEFAULT
#define
#define
#define
#define
_SET_EXCLUSIVE
_SET_SOFTSEEK
_SET_UNIQUE
_SET_DELETED
#define _SET_CANCEL
#define _SET_DEBUG
1
2
3
4
5
6
7
8
9
10
11
12
13
Clean the Clipper 5.2
4142
#define _SET_TYPEAHEAD
14
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
_SET_COLOR
_SET_CURSOR
_SET_CONSOLE
_SET_ALTERNATE
_SET_ALTFILE
_SET_DEVICE
_SET_EXTRA
_SET_EXTRAFILE
_SET_PRINTER
_SET_PRINTFILE
_SET_MARGIN
15
16
17
18
19
20
21
22
23
24
25
#define
#define
#define
#define
#define
#define
#define
#define
#define
_SET_BELL
_SET_CONFIRM
_SET_ESCAPE
_SET_INSERT
_SET_EXIT
_SET_INTENSITY
_SET_SCOREBOARD
_SET_DELIMITERS
_SET_DELIMCHARS
26
27
28
29
30
31
32
33
34
#define
#define
#define
#define
_SET_WRAP
_SET_MESSAGE
_SET_MCENTER
_SET_SCROLLBREAK
35
36
37
38
*=================================================================
* SETCURSOR()
*=================================================================
#define
#define
#define
#define
#define
SETCURSOR_NONE
SETCURSOR_NORMAL
SETCURSOR_INSERT
SETCURSOR_SPECIAL1
SETCURSOR_SPECIAL2
0
1
2
3
4
//
//
//
//
//
No cursor
Normal cursor (underline)
Insert cursor (lower half block)
Special cursor (full block)
Special cursor (upper half block)
*=================================================================
* RDD REQUESTs
*=================================================================
external dbfndx
external dbfntx // default
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Chapter
370
nanoBase 1997
A free xBase for Dos.
This material appeared originally at ‘http://www.geocities.com/SiliconValley/
7737/nanobase.html’, in 1997. Now it is incorporated inside the Italian document
‘‘Appunti di informatica libera’’, and might be reached at the URI <http://a2.swlibero.org/
nanobase_1997.html>.
Questo materiale è apparso in origine, nel 1997, presso ‘http://www.geocities.com/
SiliconValley/7737/nanobase.html’. Adesso viene incorporato nel documento «Appunti di informatica libera» e può essere raggiunto attraverso l’URI <http://a2.swlibero.org/
nanobase_1997.html>.
370.1 What is it
nanoBase 1 is a Dos program that works essentially as:
• a dot command line xBase,
• a menu driven xBase,
• a xBase program interpreter.
nanoBase 1997 is compiled in two versions: a small one to be used with old computers (i86 with
640 Kibyte RAM), and a second one to be used with better computers, at least i286 (or better)
with 2 Mibyte RAM.
370.2 The dot command line
Figure 370.1. The dot line.
The dot command line is the first face of nanoBase, the one that appears starting the program
normally. It recalls the dot line command of the old xBases.
Please note that nanoBase recognise only expressions (that is: no commands).
1
nanoBase GNU GPL
4143
nanoBase 1997
4144
370.3 The menu
Figure 370.2. The file menu.
Pressing [ F10 ] the nanoBase menu appears.
From this menu the operations are easier than writing all commands on a prompt line, but it is
always possible to come back to the dot line to do an operation not available from the menu.
370.4 The macro recording, compiling and execution
Figure 370.3. The macro menu.
nanoBase is able to record some actions made with the menu and all what is correctly typed from
the dot prompt. This may be the begin for a little program (called macro inside nanoBase) that
can be executed as it is (ASCII), or compiled into another format, faster to execute.
Macros for nanoBase are made with a reduced set of the Clipper syntax. The statements recognised from nanoBase are:
PROCEDURE procedure_name
statements ...
RETURN
statements ...
ENDPROCEDURE
[
]
DO PROCEDURE procedure_name
BEGIN SEQUENCE
statements ...
BREAK
statements ...
END
[
]
nanoBase 1997
DO CASE
CASE lCondition1
statements ...
CASE lCondition2
statements ...
OTHERWISE
statements ...
END
[
[
4145
]
]
WHILE lCondition
statements ...
EXIT
statements ...
LOOP
statements ...
END
[
[
]
]
IF lCondition1
statements ...
ELSE
statements ...
END
[
]
• the ‘FOR’ loop is not available (too difficult to implement),
• there may be no user defined functions (code blocks may be created instead),
• procedure calls cannot transfer variables,
• there are only public (global) variables.
Beside these limitations, there are many added functions to the standard language that make the
programming easier.
All you need is inside ‘NB.EXE’:
• the utility to handle manually the data,
• the macro compiler,
• the macro executor.
370.5 The report system
Figure 370.4. The report menu.
nanoBase can handle label (‘.LBL’) and form (‘.FRM’) files in the dBaseIII format. Labels and
nanoBase 1997
4146
forms may be created and edited inside nanoBase. Beside these old report system there is another
way to make a little bit complicated reports without making a complex macro: it is called RPT.
A RPT file is a ASCII file with text mixed with code. The text may contain variables (usually a
field or an expression containing fields).
To make a complex report some work is needed, but surely less than the time needed to make a
report program.
The main purpose of it was to be able to print text with variables (typically names and addresses)
for every record of a particular ‘.DBF’ file. Now the RPT system makes something more.
370.6 The integrated text editor
Figure 370.5. The integrated text editor.
nanoBase contains an integrated text editor not particularly good, but very usefull for RPT files
(as the expression insertion is very easy with the use of the [ F2 ] key) and whenever there isn’t
any other editor there.
370.7 The internal documentation
Figure 370.6. The internal documentation.
nanoBase’s documentation si translated also inside the HTF format: ‘NB.HLP’. Pressing
normally, a contextual piece of the manual appears.
[ F1 ],
Some standard functions have its own internal help, contained inside the ‘.EXE’ file. This was
made to help programming with nanoBase.
nanoBase 1997
4147
370.8 Download it
Here is the 1997 edition of nanoBase.
• EXE for small computers.
<ftp://ftp.simtel.net/pub/simtelnet/msdos/database/nbase7a1.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nbase7a1.zip>
• EXE for i286 with more than 2 Mibyte.
<ftp://ftp.simtel.net/pub/simtelnet/msdos/database/nbase7a2.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nbase7a2.zip>
• Runtime for small computers.
<ftp://ftp.simtel.net/pub/simtelnet/msdos/database/nbase7a3.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nbase7a3.zip>
• Documentation in many different formats.
<ftp://ftp.simtel.net/pub/simtelnet/msdos/database/nbase7a4.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nbase7a4.zip>
• Macro programming examples.
<ftp://ftp.simtel.net/pub/simtelnet/msdos/database/nbase7a5.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nbase7a5.zip>
• Source for version 96.06.16, without mouse support (1996).
<ftp://ftp.simtel.net/pub/simtelnet/msdos/database/nbase7a6.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nbase7a6.zip>
• Source for version 1997.
<ftp://ftp.simtel.net/pub/simtelnet/msdos/database/nbase7a7.zip>
<http://www.alltheweb.com/search?cat=ftp&amp;q=nbase7a7.zip>
370.9 Bugs and known problems
Here is the list of known bugs and problems.
• Comparison with floating point numbers may fail. It is better to convert numbers into string
before comparing them.
• Macros may be contained inside ASCII files or a ‘‘compiled’’ ‘.DBF’ file. In the second
case, when nanoBase executes the macro, a work area (the last available one) is used, so it
should not be closed or the macro execution will be stopped. A ‘dbcloseall()’ will stop
execution of the macro. In substitution of ‘dbcloseall()’, ‘DBCLOSE()’ should be used.
• To simplify the macro interpretation, lines such as this:
qqout( "You can’t do that // you can’t do that!" )
will generate an error as the interpreter will read only:
qqout( "You can’t do that
4148
nanoBase 1997
• nanoBase works good also if you have a screen configuration that permits you to show more
than the usual 80 columns and 25 lines, but the library used to handle the mouse is not able
to work outside the 80×25 area.
Appunti di informatica libera 2003.01.01 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Chapter
371
nanoBase 1997 user manual
This is the documentation of nanoBase 1997, with minor modifications, that appeared originally at ‘http://www.geocities.com/SiliconValley/7737/nb.htm’. Now it is incorporated inside the Italian document ‘‘Appunti di informatica libera’’, and might be reached at
the URI <http://a2.swlibero.org/nanobase_1997.html>.
Questo è il manuale di nanoBase 1997, modificato leggermente, che è apparso inizialmente presso ‘http://www.geocities.com/SiliconValley/7737/nb.htm’. Adesso
viene incorporato nel documento «Appunti di informatica libera» e può essere raggiunto attraverso l’URI <http://a2.swlibero.org/nanobase_1997.html>.
371.1 Dos xBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4150
371.2 Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4154
371.3 How to use nB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4156
371.4 Status line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4157
371.5 The dot line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4158
371.6 The menu system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4158
371.7 The text editor DOC() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4169
371.8 The help text file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4170
371.9 Macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4170
371.10 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4174
371.11 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4182
371.12 Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4183
371.13 Code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4184
371.14 Standard functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4184
371.15 nB functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4232
371.16 Normal command substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4262
371.17 nB command substitution functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4269
371.18 RPT: the nB print function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4273
371.19 How can I... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4277
371.20 The source files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4277
nB (‘‘nano Base’’: ‘‘n’’ = ‘‘nano’’ = 10**(-9) = ‘‘very little’’) is a little Dos xBase written in
Clipper 5.2 that can help to access ‘.DBF’ file created with different standards.
nB is:
• a dot command interpreter,
• a menu driven xBase,
• a xBase program interpreter.
4149
nanoBase 1997 user manual
4150
371.1 Dos xBase
This section is a brief description of the functionality of a typical Dos xBase.
The first purpose of a xBase program is to handle data inside a ‘.DBF’ file. These files may be
indexed with the help of index files and more ‘.DBF’ files may be linked with a relation to obtain
something like a relational database.
371.1.1 .DBF files
‘.DBF’ files are files organised in a table structure:
---------------------------| field1 | field2 | field3 |
---------------------------|
|
|
|
---------------------------|
|
|
|
---------------------------|
|
|
|
---------------------------|
|
|
|
---------------------------|
|
|
|
----------------------------
record1
record2
record3
record4
record5
record6
The lines of this table are records and the columns are fields. Records are numbered starting from
the first that is number 1.
Columns are defined as fields and fields are distinguished by name and these names are saved
inside the ‘.DBF’ file.
Every field (column) can contain only one specified kind of data with a specified dimension:
• ‘C’, character, originally the maximum dimension was 254 characters, minimum is 1;
• ‘N’, numeric, a numeric field that can contain also sign and decimal values;
• ‘D’, date, a field dedicated to date information;
• ‘L’, logic, a filed that may contain only ‘T’ for True or ‘F’ for False used as a boolean
variable;
• ‘M’, memo, a character field with no predefined dimension, not allocated directly inside the
‘.DBF’, but inside a ‘.DBT’ file, automatically linked.
No other field type is available for a typical xBase ‘.DBF’ file.
To access the data contained inside a ‘.DBF’ file the following list of action may be followed:
• Open a ‘.DBF’ file inside the current area, where these areas are something like file handlers.
• After the ‘.DBF’ file is opened, it referenced only by the alias name that usually correspond
to the original filename without extention.
• Move the record pointer to the desired location.
• Lock the current record to avoid access from other users.
nanoBase 1997 user manual
4151
• Do some editing with the data contained inside the current record using the field names like
they were variables.
• Release the lock.
• Move the record pointer to another desired location.
• Lock the current record to avoid access from other users.
• ...
• Close the alias.
Before you go further, you have to understand that:
• A ‘.DBF’ file is opened using a free WORK AREA that may be associated to the concept
of the file handler.
• The ‘.DBF’ file is opened with a alias name that permit to open the same ‘.DBF’ file more
times when using different alias names.
• After the ‘.DBF’ file is opened, we don’t speak any more of file, but alias.
• If the work area "n" is used from the alias "myAlias", speaking of work area "n" or of alias
"myAlias" is the same thing.
371.1.2 Index files
‘.DBF’ files are organised with record number, that is, you can reach a specific record and not a
specific information unless that you scan record by record.
To obtain to "see" a ‘.DBF’ file somehow logically ordered (when physically it is not), index files
are used.
A index file, also called INDEX BAG, is a file that contains one or more indexes
Indexes are rules by which a ‘.DBF’ file may be seen ordered.
A typical index file may contain only one index.
A index file may have the following extention:
• ‘.NDX’, single index, dBase III and dBase III plus;
• ‘.NTX’, single index, Clipper;
• ‘.MBX’, multiple index, dBase IV;
• ‘.CDX’, multiple index, FoxPro.
Every index file may be used only in association with the ‘.DBF’ for what it was made. The
problem is that normally there is no way to avoid errors when the user try to associate the right
‘.DBF’ file with the wrong index.
To access the data contained inside a ‘.DBF’ file the following list of action may be followed:
• Open a ‘.DBF’ file.
4152
nanoBase 1997 user manual
• Open a index file.
• Select a particular order.
• Search for a key or move the record pointer on a different way.
• Lock the current record to avoid access from other users.
• Do some editing with the data contained inside the current record using the field names like
they were variables.
• Release the lock.
• Move the record pointer to another desired location.
• Lock the current record to avoid access from other users.
• ...
• Close the alias.
Before you go further, you have to understand that:
• As orders are contained inside a INDEX BAG file physically distinguished form the ‘.DBF’
file, it may happen that a ‘.DBF’ file is wrongly opened and edited without the index. In
this case, the INDEX BAG is not updated and when the INDEX BAG will be opened, the
records contained inside the ‘.DBF’ file may not correspond.
• For the same reason, an improper program termination may result in an incomplete data
update. That is: ‘.DBF’ file may be all right, INDEX BAG not.
• This is why xBase programs are "weak" relational databases or they are not relational
databases at all.
• When troubles occurs, indexes must be rebuild.
371.1.3 Relations
Many ‘.DBF’ files with indexes may be opened simultaneously. Data contained inside more
‘.DBF’ files may be somehow connected together. See the example.
-----------------------------------------| Date | Time IN | Time OUT | Employee # |
-----------------------------------------| xxxx | xxxxxxx | xxxxxxxx |
01
| -------->|
-----------------------------------------|
| yyyy | yyyyyyy | yyyyyyyy |
02
|
|
-----------------------------------------|
| zzzz | zzzzzzz | zzzzzzzz |
01
| -------->|
-----------------------------------------|
[...]
|
|
|<-----------------------------------------|
|
|
|
---------------------------------------|
| Employee # | Name
| Address |.....|
|
---------------------------------------|------->|
01
| aaaaaaa | aaaaaaa |.....|
----------------------------------------
nanoBase 1997 user manual
4153
|
02
| bbbbbbb | bbbbbbb |.....|
---------------------------------------|
03
| ccccccc | ccccccc |.....|
----------------------------------------
The first ‘.DBF’ file contains some data that refers to an Employee number that may appear
repeated on more records.
Employee informations are stored inside another ‘.DBF’ file that contains only one record for
every employee.
Establishing a relation from the first ‘.DBF’ file to the second, moving the record pointer of the
first ‘.DBF’ file, that is the first alias, the record pointer of the second, the child alias, is moved
automatically to the record containing the right data.
The relation is an expression that should result in a number if the child alias is opened without
index, or in a valid index key if the child alias is opened with an index.
To relate two ‘.DBF’ files the following list of action may be followed:
• Open the first ‘.DBF’ file.
• Open a index file for the first alias.
• Select a particular order.
• Open the second ‘.DBF’ file.
• Open a index file for the second alias.
• Select a particular order.
• Select the first alias.
• Define a relation form the first alias and the second alias: the child alias.
• Search for a key or move the record pointer of the first alias (don’t care about the Child
alias).
• Lock the current record to avoid access from other users.
• If data contained inside the Child alias should be edited (usually it doesn’t happen), lock
the current record of the Child alias.
• Do some editing with the data contained inside the current record using the field names like
they were variables.
• Release the lock (also with the Child alias if a lock was made).
• Move the record pointer to another desired location.
• Lock the current record to avoid access from other users.
• [...]
• Release the relation.
• Close the Child alias.
• Close the first alias.
As may be seen, relations are not saved inside files, but are obtained with lines of code.
nanoBase 1997 user manual
4154
371.2 Composition
nB is composed from the following files, where xx is the the version code.
NBASExx1.ZIP
NBASExx2.ZIP
NBASExx3.ZIP
NBASExx4.ZIP
NBASExx5.ZIP
NBASExx6.ZIP
NBASExx7.ZIP
EXEs for small PCs
Runtime EXEs for small PCs
EXEs for i286 with 2M+
DOCs
EXAMPLEs
SRCs for version 96.06.16
SRCs for the current version
Every archive file contains:
‘COPYING.TXT’
‘README.TXT’
‘FILE_ID.DIZ’
GNU General Public License version 2 in Dos text format.
the readme file.
definition.
The file ‘NBASExx1.ZIP’ contains also the following files.
‘NB.EXE’
‘NB.HLP’
the executable program for DBFNTX and DBFNDX files,
linked with RTLINK.
this manual in "Help Text File" format.
The file NBASExx2.ZIP contains also the following files.
‘NB.EXE’
the run-time to execute macro programs for DBFNTX and
DBFNDX files handling, linked with RTLINK.
The file ‘NBASExx3.ZIP’ contains also the following files.
‘NB.EXE’
‘NB.HLP’
the executable program for DBFCDX, DBFMDX, DBFNDX
and DBFNTX files, linked with EXOSPACE.
the user manual in "Help Text File" format.
The file ‘NBASExx4.ZIP’ contains also the following files.
‘NB.PRN’
‘NB.RTF’
‘NB.TXT’
‘NB.HTM’
the user manual in printed text format.
the user manual in RTF format.
the user manual in ASCII text format.
the user manual in HTML format.
The file ‘NBASExx5.ZIP’ contains also the following files.
‘_ADDRESS.DBF’
‘_ADDRESS.NTX’
‘_ADDRESS.LBL’
‘_ADDRESS.FRM’
‘_ADDRESS.RPT’
an example database file.
index file associated to ‘_ADDRESS.DBF’.
a label form file used to print data contained inside
‘_ADDRESS.DBF’ .
a report form file used to print data contained inside
‘_ADDRESS.DBF’ .
a RPT text file used to print data contained inside
‘_ADDRESS.DBF’ .
nanoBase 1997 user manual
‘_MAINMNU.&’
‘0MAINMNU.&’
‘0MAINMNU.NB’
‘0MAINMNU.BAT’
‘1ADDRESS.&’
‘1ADDRESS.NB’
‘2ADDRESS.&’
‘2ADDRESS.NB’
‘3ADDRESS.&’
‘3ADDRESS.NB’
‘4ADDRESS.&’
‘4ADDRESS.NB’
‘ABIORITM.&’
‘ABIORITM.NB’
‘_STUDENT.DBF’
‘_STUDENT.NTX’
‘_STUDSTD.DBF’
‘_STUDENT.RPT’
‘_STUDSTD.RPT’
‘BSTUDENT.&’
‘BSTUDENT.NB’
‘CBATMAKE.&’
‘CBATMAKE.NB’
‘BROWSE.&’
‘BROWSE.NB’
‘BROWSE.BAT’
‘MENU.&’
‘MENU.NB’
‘MENU.BAT’
4155
a macro program source example of a menu that executes
some others macro programs. This example is made to
demonstrate how nB can execute directly a source code without compiling it. This example is made only to taste it: it is
very slow and only a speedy machine can give the idea of it.
a macro program source example of a menu that executes
some others macro programs. It is the same as ‘_MAINMNU.&’
but it is made to start the execution of the compiled macros.
compiled macro program ‘0MAINMNU.&’
a batch file to show how to run the execution of
‘0MAINMNU.NB’
a macro program source example for handling a ‘.DBF’ file
containing addresses in various ways.
compiled macro ‘1ADDRESS.&’ .
a macro program source example for handling a ‘.DBF’ file
containing addresses in various ways: a little bit more complicated than 1ADDRESS.&.
compiled macro ‘2ADDRESS.&’ .
a macro program source example for handling a ‘.DBF’ file
containing addresses in various ways: a little bit more complicated than ‘2ADDRESS.&’ .
compiled macro ‘3ADDRESS.&’.
a macro program source example for handling a ‘.DBF’ file
containing addresses in various ways: a little bit more complicated than ‘3ADDRESS.&’ .
compiled macro ‘4ADDRESS.&’ .
a macro program source example for calculating the personal
bio wave.
compiled macro ‘ABIORITM.&’ .
a ‘.DBF’ file used inside the BSTUDENT macro example.
index file used for ‘_STUDENT.DBF’ .
a ‘.DBF’ file used inside the BSTUDENT macro example.
a RPT text file used to print data contained inside
‘_STUDENT.DBF’ .
a RPT text file used to print data contained inside
‘_STUDSTD.DBF’ .
a macro program source example for students evaluation: a
description about students is obtained linking other standard
descriptions.
compiled macro ‘BSTUDENT.&’ .
a macro program source example to generate a batch file to be
used to back up an entire hard disk.
compiled macro ‘CBATMAKE.&’ .
a macro program source example to start an automatic
browse.
compiled macro ‘BROWSE.&’ .
batch file to start a ‘.DBF’ browse with the BROWSE macro
program.
a macro program source example for a Dos menu.
compiled macro ‘MENU.&’ .
batch file to use the MENU macro.
The file ‘NBASExx6.ZIP’ contains also the following files: source code for the version 96.06.16.
‘NB.PRG’
‘NB_REQ.PRG’
‘NB.LNK’
the main source file for version 96.06.16.
the source file containing links to all the standard functions.
link file for compilation.
nanoBase 1997 user manual
4156
rmake file to compile with RTLink.
rmake file to compile with Exospace.
rmake file to compile with RTLink defining RUNTIME to obtain a small nB runtime version.
link file to compile and link a macro.
rmake file to compile and link a macro.
‘NB_NRMAL.RMK’
‘NB_EXOSP.RMK’
‘NB_RUNTI.RMK’
‘MACRO.LNK’
‘MACRO.RMK’
The file ‘NBASExx7.ZIP’ contains also the following files: source code for the current version.
the main source file.
the source file containing links to all the Clipper functions.
the source file for standard functions.
the source file for other standard functions.
general include file that substitutes all include file normally
used for normal Clipper compilations.
include file specific for nB.
link file for compilation.
link file for runtime compilation.
rmake file to compile with RTLink.
rmake file to compile with Exospace.
rmake file to compile with RTLink defining RUNTIME to obtain a small nB runtime version.
include file to compile and link a macro.
link file to compile and link a macro.
rmake file to compile and link a macro.
a simple free library for mouse support under Clipper (c) 1992
Martin Brousseau.
‘NB.PRG’
‘REQUEST.PRG’
‘STANDARD.PRG’
‘EXTRA.PRG’
‘STANDARD.CH’
‘NB.CH’
‘NB.LNK’
‘NB_RUNTI.LNK’
‘NB_NRMAL.RMK’
‘NB_EXOSP.RMK’
‘NB_RUNTI.RMK’
‘MACRO.CH’
‘MACRO.LNK’
‘MACRO.RMK’
‘CLIPMOUSE.ZIP’
371.3 How to use nB
nB normal syntax is:
nB
[nB_parameters ] [macro_filename ] [macro_parameters]
To run nB, just type the word "NB" and press [ Enter ] to execute. It will run in command mode,
this means that it will look like an old xBASE command prompt.
To run the program as a macro interpreter, type the word NB followed from the macro file name
with extention (no default extention is supposed). If parameters are given, after the macro file
name, these will be available inside the public variables: c_Par1, c_Par2, ..., c_Par9. c_Par0 will
contain the macro file name (see the macro file BROWSE.&). nB will terminate execution when
the macro terminates.
These parameters are available for nB:
Suppress the copyright notice. It is usefull when using nB for
macro interpretation.
Suppress the "Wait-Wheel" if not desired. It is the "Wheel"
that appears at top-left when a macro is interpreted or other
long elaborations are executed.
Shows a short help.
-c
-w
-?
nB macro "compilation" syntax is:
nB -m source_macro_filename
[destination_macro_filename ]
nanoBase 1997 user manual
With the -m parameter, nB "compiles" the ASCII
destination_macro_filename .
4157
source_macro_filename
into
371.4 Status line
nB shows a "status line" at the top of the screen when the nB command prompt or the menu
system is active. It shows some important informations.
| |DBFNTX
||*| 1|ADDRESS
|
1/
4|ADDRESS.NTX |
| |
| |
|
|
|
| |
| |
|
|
|
| |
| |
|
|
Last record (7).
| |
| |
|
|
| |
| |
|
Record pointer position (6).
| |
| |
|
| |
| |
Active alias (5).
| |
| |
| |
| Current Work Area (4)
| |
|
| |
Deleted record appearance (3)
| |
| Actual default database driver (2).
|
Macro recorder indicator (1).
|
1/
4|ADDRESS.NTX | 1|ADDRESS
|
|
|
|
|
|
|
|
| Order Tag Name (10)
|
|
|
Order number (9)
|
Order Bag name (8)
(1) This is the place for the macro recorder indicator. The symbol used is "&". Blank means that
the macro recorder is OFF; & blinking means that the macro recorder is ON; & fixed means that
the macro recorder is PAUSED.
(2) The name of the default database driver. It is not necessarily the database driver for the active
alias; it is only the database driver that will be used for the next open/create operation.
(3) An asterisk (*) at this position indicates that SET DELETED is OFF. This means that deleted
records are not filtered. When a BLANK is in this place, SET DELETED is ON, so that deleted
records are filtered.
(4) The active work area number, that is, the area of the active alias.
(5) The active alias name. Note that the alias name is not necessarily equal to the ‘.DBF’ file
name.
(6) The actual record pointer position for the active alias.
(7) The number of records contained inside the active alias.
(8) The Order Bag name; that is the index file name.
(9) The order number.
(10) The order tag (name). When DBFNTX database driver is used, it correspond to the Order
Bag name.
nanoBase 1997 user manual
4158
371.5 The dot line
Starting nB without parameters, the dot line appears. This is the place where commands in form
of functions may be written and executed like a old xBase.
The functions written inside the command line that don’t result in an error, are saved inside a
history list. This history list may be recalled with [ F2 ] and then the selected history line may be
reused (eventually edited). Key [ up ]/[ down ] may be used to scroll inside the history list without
showing the all list with [ F2 ].
[ Enter ]
is used to tell nB to execute the written function.
As the dot line is not an easy way to use such a program, a menu is available pressing [ F10 ] or
[ Alt+M ]. The [ F10 ] key starts the ASSIST() menu. This menu may be started also entering the
name of the function: "ASSIST()".
nB includes a simple built-in text editor: DOC(). It may be started from the dot line entering
"DOT()". No special key is dedicated to start this function.
371.6 The menu system
The nB menu system appears differently depending on the place where it is "called". When
available, the menu system appears pressing [ Alt+M ] or [ F10 ].
The Menu system is organised into horizontal menu, vertical menu, and pop-up menu.
The horizontal menu contains selectable items organised horizontally:
One Two Three Four Five
The cursor may be moved on a different position using arrow keys [ Left ]/[ Right ]; [ Esc ] terminates
the menu; [ Enter ] opens a vertical menu.
The vertical menu contains selectable items organised vertically:
One Two Three Four Five
-----------|First
|
|Second
|
|Third
|
------------
The cursor may be moved on a different position using arrow keys [ Up ]/[ Down ]; the arrow keys
[ Left ]/[ Right ] change the vertical menu; [ Esc ] closes the vertical the menu; [ Enter ] starts the selected menu function.
The vertical menu contains selectable items organised vertically:
One Two Three Four Five
-----------|First
|
|Second
>|--------------|Third
|Sub function 1|
-----------|Sub function 2|
----------------
The cursor may be moved on a different position using arrow keys [ Up ]/[ Down ]; [ Esc ] closes the
pop-up the menu; [ Enter ] starts the selected menu function.
The following sections describe the menu system.
nanoBase 1997 user manual
4159
371.6.1 Menu File
The menu File contains important function on ‘.DBF’ file, indexes, relations and Replaceable
database drivers.
For database files are considered two aspects: the physical aspect, and the logical alias. When a
‘.DBF’ file is opened, it becomes a alias.
Indexes are considered as index files and index orders.
It follows a brief menu function description.
Change directory
Changes the actual drive and directory.
File .DBF
Contains a pop-up menu for ‘.DBF’ operations.
New .DBF
A ‘.DBF’ file is a table where columns, called Fields, must be specified and lines,
called records, are added, edited and deleted by the program.
Field characteristics are:
NAME
TYPE
LENGTH
DECIMAL
the field name must be unique inside the same file, it is composed of letters, number and underscore (_), but it must start
with a letter and it is not case sensitive.
the field type determinates the type of data it can hold.
is the field total length in characters; it doesn’t matter of the
type of data.
is the length of positions after decimal point. This information
is used normally for numeric fields. In this case, take note
that the DECIMAL length, together with the decimal point,
will subtract space for the integer part of the number from the
total LENGTH of the filed.
Field Types:
C Character
N Numeric
D Date
L Logic
M Memo
it is a text field long LENGTH characters.
it is a numeric field long LENGTH characters with DECIMAL characters for decimal positions. Note that if LENGTH
is 4 and DECIMAL is 0 (zero), the field may contain integers
from -999 to 9999; but if LENGTH is 4 and DECIMAL 1, the
field may contain numbers from -9.9 to 99.9: two position for
the integer part, one position for the decimal point and one
position for decimal.
it is a date field: it contains only dates; the length should not
be specified as it is automatically 8.
it is a logical (boolean) field: it contains only TRUE, represented by "Y" or "T", or FALSE, represented by "N" or "F".
The length should not be specified as it is automatically 1.
it is a character field with unknown dimension. It is recorded
into a parallel file with ‘.DBT’ extention. The original ‘.DBF’
file holds a space for a pointer inside the ‘.DBT’ file. The
length of a Memo field is automatically 10 and is referred
to the memo pointer.
After the function "NEW .DBF" is selected, a table for the field specifications appears.
nanoBase 1997 user manual
4160
+--------------------------------+
|
Database file structure
|
|
|
| Field Name Type Length Decimal |
|--------------------------------|
|
|
|
0|
0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To navigate and to edit the table use the following keys:
[ Up ]/[ Down ]/[ Left ][ Right ]
[ PgUp ]
[ PgDn ]
[ Ctrl+PgUp ]
[ Ctrl+PgDn ]
[ Ctrl+Home ]
[ Ctrl+End ]
[ Ctrl+Enter ]
[ Ctrl+F1 ]
[ Ctrl+F2 ]
[ Ctrl+F3 ]
[ Enter ]
[ Esc ]
[x]
move the cursor one position (up, down, left or right);
move to previous screen page;
move to next screen page;
move to top of table;
move to bottom of table;
move to first column;
move to last column;
append a new empty line;
delete (cut) the current line and save a copy into the "clipboard";
copy current line into the table "clipboard";
insert (paste) the content of the "clipboard" in the current position;
start editing in the current position;
terminate;
any other key will be written in the current position.
When the editing is terminated, press [ Esc ] and a dialog box will ask for the file name
and the RDD.
xBase files (.DBF) are not all equal, this way, when a new ‘.DBF’ file si created, the
RDD (Replaceable Database Driver) is asked. The normal RDD is DBFNTX, the one
used by Clipper.
Modify .DBF structure
The modification of a ‘.DBF’ file structure is a delicate matter if it contains data.
In fact, it is a data transfer from a source ‘.DBF’ file to a destination ‘.DBF’ file with
a different structure. This way, the destination ‘.DBF’ will be updated only for the
fields with the same name of the source one. The position may be different, but names
cannot be changed (not so easily).
Mistakes may be dangerous, so, before doing it, it is recommended a backup copy of
the original ‘.DBF’ file.
Open .DBF
When a ‘.DBF’ file is opened, it becomes a alias, a logical file, placed inside a work
area. The same ‘.DBF’ file may be opened inside different areas with different alias
names.
The required information to open the file are:
FILENAME
ALIAS
RDD
SHARED
the physical file name.
the alias name. If not assigned, it becomes automatically the
same of FILENAME without extention.
the Replaceable Database Driver to use to access to this file.
a logical value: TRUE means that the file will be accessible to
other users, FALSE means use exclusive.
nanoBase 1997 user manual
READ ONLY
4161
a logical value: TRUE means that the file will be only readable
and no modification will be allowed, FALSE means that no
restriction on editing will be made.
File .NTX
Contains a pop-up menu for physical indexes operations.
New .NTX / new tag
If the active area is used we have an active alias. In this case a index may be created. The index is a way to see the active alias ordered without changing the physical
position of records.
There are two words to understand: ORDER and INDEX-BAG. The index bag is the
file that contains the information on the record ordering, the order is the rule followed
to order the records. A index bag may contains one or more orders depending on the
Replaceable Database Driver in use.
Typical ‘.NTX’ file are index bag containing only one order.
Depending on the RDD in use the following field may be filled.
INDEX FILENAME
KEY EXPRESSION
ORDER NAME
FOR EXPRESSION
this is the name of the index bag.
the expression that defines the rule for the record ordering.
this is the name to give to the order (tag) when the RDD permits to have a index bag containing more than one order. In
the other case, the index bag name correspond to the order
name.
a FOR condition to filter records before indexing.
Open index
If a index file already exists, it can be associated to the active alias simply opening it.
Take note that the system is not able to verify if the index belong the active alias
and if it is not so a error will result.
INDEX NAME
is the name of the index bag file to open.
Alias
Contains a pop-up menu for logical databases (alias) operations.
Select
Only one may be the active alias and with this function the active alias may be changed
choosing from the list of used areas.
Selecting the area number zero, no alias is active.
Display structure
With this function the active alias structure may be viewed.
Close active alias
Selecting this function the active alias is closed. That is: the ‘.DBF’ file and eventual
indexes are closed.
Close all aliases
With this function all Aliases are closed.
Order
Contains a pop-up menu for logical indexes (orders).
nanoBase 1997 user manual
4162
Order list rebuild
This function rebuild the indexes opened and associated to the active alias.
Order set focus
This function permits to change the active order selecting form the ones opened and
associated to the active alias.
Order list clear
This function closes all orders associated to the active alias.
Relation
Contains a pop-up menu for relations (links with other Aliases).
Set relation
This function permits to establish a relation between a alias and a Child alias showing
as a result a unique database.
CHILD
EXPRESSION
is the alias name to connect to the active alias.
is the relation expression that specify the rule for the relation.
The value of this expression is the key to access the Child
alias: if this Child alias is accessed without index, it must be
the record number, if this Child alias is accessed via index, it
must be a valid index key.
Clear relation
This function eliminates any relation that originate form the active alias.
RDD default
Contains a pop-up menu for Replaceable Database Driver defaults.
Show actual RDD default
It simply shows the actual Replaceable Database Driver.
Set default RDD
Select a new default Replaceable Database Driver.
371.6.2 Menu Edit
The menu Edit contains functions to access data from the active alias (the actual area).
View
This function permits you to view the active alias with eventual relations as a table.
No edit is allowed.
To navigate the table use the following keys.
[ Enter ]
[ PgUp ]
[ PgDn ]
[ Ctrl+PgUp ]
[ Ctrl+PgDn ]
[ Ctrl+Home ]
[ Ctrl+End ]
start field editing.
show previous screen page.
show next screen page.
show top of alias.
show bottom of file.
show the first column.
show last column.
nanoBase 1997 user manual
4163
Edit/browse
This function permits you to edit the active alias with eventual relations as a table.
To navigate and edit the table use the following keys.
[ Enter ]
[ PgUp ]
[ PgDn ]
[ Ctrl+PgUp ]
[ Ctrl+PgDn ]
[ Ctrl+Home ]
[ Ctrl+End ]
[ Ctrl+Enter ]
[ Ctrl+F2 ]
[ Ctrl+F3 ]
[ Ctrl+F4 ]
[ Ctrl+Y ]
[ Ctrl+Del ]
start field editing.
show previous screen page.
show next screen page.
show top of alias.
show bottom of file.
show the first column.
show last column.
append a new empty record.
copy the current record.
append and paste a record.
paste a previously copied record, overwriting the content of
the current one.
delete or recall the current record.
delete or recall the current record.
When a memo field is edited:
[ Esc ]
[ Ctrl+Y ]
[ Ctrl+W ]
cancel and close the memo window.
line delete.
save and close the memo window.
Replace
The content of a Field of the active alias may be replaced with an expression.
The required data is:
FIELD TO REPLACE
NEW VALUE EXPRESSION
WHILE EXPRESSION
FOR EXPRESSION
the Field name to be replaced.
the expression that obtain the new value for the selected Field.
the WHILE condition expression: the replacement continue
until this expression results True. The constant ‘.T.’ is ever
True and is the default.
the FOR condition expression: the replacement is made for all
records that satisfy the condition. The constant ‘.T.’ is ever
True and is the default.
Recall
The records signed for deletion (deleted but still there), may be recalled (undeleted).
The required data is:
WHILE EXPRESSION
FOR EXPRESSION
the WHILE condition expression: the record recall continue
until this expression results True. The constant ‘.T.’ is ever
True and is the default.
the FOR condition expression: the record recall is made for all
records that satisfy the condition. The constant ‘.T.’ is ever
True and is the default.
Delete
Deletes (sign for deletion) a group of record depending on the required conditions.
The required data is:
nanoBase 1997 user manual
4164
WHILE EXPRESSION
FOR EXPRESSION
the WHILE condition expression: the record deletion continue until this expression results True. The constant ‘.T.’
is ever True and is the default.
the FOR condition expression: the record deletion is made for
all records that satisfy the condition. The constant ‘.T.’ is
ever True and is the default.
Pack
This function eliminates definitely records previously deleted (signed for deletion).
It may work only if the active alias was opened in exclusive mode.
371.6.3 Menu Report
The menu Report contains functions for data report (print). In particular, label files ‘.LBL’ and
report file ‘.RPT’ may be created and used for printing. There is also another way to print, with
the RPT() system that is available inside the nB internal editor DOC().
DBGOTOP()
Moves the record pointer for the active alias at the first logical record.
New label
With this function can be created a standard label file (.LBL under the dBaseIII standard).
Labels may be printed in more than one column and can contain 16 lines maximum.
The label data is the following.
REMARK
HEIGHT
WIDTH
MARGIN
LINES
SPACES
ACROSS
LINE 1
LINE n
LINE 16
a label remark that will not be printed.
the label vertical dimension.
the label horizontal dimension.
the left margin in characters.
the vertical spacing between labels.
the horizontal spacing between labels in characters.
the number of label columns.
The first line inside labels.
The n-th line inside labels.
The 16th line inside labels.
The number of lines inside the labels depend on the HEIGHT and the maximum value is
16.
The label lines can contain constant string and/or string expressions.
See the example below.
nanoBase 1997 user manual
4165
Margin
<-->
XXXXXXX|XXXXXXXX
XXXXXXX|XXXXXXXX
XXXX Height XXXX
XXXXXXX|XXXXXXXX
XXXXXXX|XXXXXXXX
XX
XX
XX
XX
XX
Line
Line
Line
Line
Line
1
2
3
4
5
XXXXXX
XXXXXX
XXXXXX
XXXXXX
XXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
<--- Width ---->
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
|
| Lines
<-->
|
Spaces
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
|
|
|
|
|
|
|
|
|
+---------------- Across ---------------+
Modify label
This function permits you to modify a label file.
Label form
This function permits you to print labels with the data provided by the active alias: one
label each record.
The following data is required.
LABEL FILENAME
WHILE
FOR
the label filename.
the WHILE condition: the label printing goes on as long as
this condition remain True.
the FOR condition: only the records from the active alias that
satisfy the condition are used for the label print.
New report
This function permits you to create a standard report form file (.FRM under the dBaseIII
standard).
The informations to create a ‘.FRM’ file are divided into two parts: the head and groups; the
columns.
The first part: head and groups, requires the folliwing informations:
PAGE WIDTH
LINES PER PAGE
LEFT MARGIN
DOUBLE SPACED?
PAGE EJECT BEFORE PRINT?
PAGE EJECT AFTER PRINT?
PLAIN PAGE?
PAGE HEADER
GROUP HEADER
the page width in characters.
the usable lines per per page.
the left margin in characters.
double spaced print, yes or no.
form feed before print, yes or no.
form feed after print, yes or no.
plain page, yes or no.
the page header, max 4 lines (the separation between one line
and the other is obtained writing a semicolon, ";").
the group title.
nanoBase 1997 user manual
4166
GROUP EXPRESSION
SUMMARY REPORT ONLY?
PAGE EJECT AFTER GROUP?
SUB GROUP HEADER
SUB GROUP EXPRESSION
the group expression (when it changes, the group changes)
only totals and no columns, yes or no.
form feed when the group changes, yes or no.
sub group title.
the sub group expression.
The second part: columns, requires the following informations structured in table form:
COLUMN HEADER
CONTENT
WIDTH
DEC.
TOTALS
column head description (it can contain 4 lines separated with
a semicolon).
the column expression.
the column width.
the decimal length for numeric columns.
totals to be calculated, yes or no (usefull only for numeric
columns).
To navigate and to edit the table use the following keys:
[ Up ]/[ Down ]/[ Left ][ Right ]
[ PgUp ]
[ PgDn ]
[ Ctrl+PgUp ]
[ Ctrl+PgDn ]
[ Ctrl+Home ]
[ Ctrl+End ]
[ Ctrl+Enter ]
[ Ctrl+F1 ]
[ Ctrl+F2 ]
[ Ctrl+F3 ]
[ Enter ]
[ Esc ]
[x]
move the cursor one position (up, down, left or right);
move to previous screen page;
move to next screen page;
move to top of table;
move to bottom of table;
move to first column;
move to last column;
append a new empty line;
delete (cut) the current line and save a copy into the "clipboard";
copy current line into the table "clipboard";
insert (paste) the content of the "clipboard" in the current position;
start editing in the current position;
terminate;
any other key will be written in the current position.
When the editing is terminated, press [ Esc ] and a dialog box will ask for the name to give
to the report form file.
Modify report
This function permits you to modify a standard report form file (.FRM under the dBaseIII
standard).
Report form
This function permits you to print a report form with the data provided by the active alias.
The following data is required.
REPORT FORM FILENAME
WHILE
FOR
the label filename.
the WHILE condition: the form printing goes on as long as
this condition remain True.
the FOR condition: only the records from the active alias that
satisfy the condition are used for the report form print.
Create/modify/print text
This function activates the text editor.
nanoBase 1997 user manual
4167
371.6.4 Menu HTF
The menu Htf helps on creating and accessing the "Help Text Files". This name, help text file, is
just the name given to it.
A text (Ascii) file prepared like this manual may be transformed into a "Help Text File" that is a
simple text with pointers.
Open help text file
This function permits to open a Help Text File and browse it. The Help Text File name is
required.
New help text file
This function permits to create a new "Help Text File" that is a help file under the nB style.
The source is an Ascii file where three kind of information are available: Normal text,
Indexes and pointers.
Indexes and Pointers are word or phrases delimited with user defined delimiters; indexes
are placed inside the text to indicate an argument, pointers are placed inside the text to
indicate a reference to indexes.
Inside this manual, indexes are delimited with ## and ##, so the titles are here indexes;
pointers are delimited with < and >.
Only one index per line is allowed, only one pointer per line is allowed.
The Delimiters used do identify indexes and pointers are user defined; the _start_ identifier
symbol can be equal to the _end_ identifier symbol. The symbols used for indexes cannot
be used for the pointers.
So, the informations required are:
SOURCE TEXT FILENAME
DESTINATION FILENAME
INDEX START CODE
INDEX END CODE
POINTER START CODE
POINTER END CODE
the filename of the text source file.
the filename of the destination Help Text File (suggested
‘.HLP’ extention).
the index start symbol; suggested ##.
the index end symbol; suggested ##.
the pointer start symbol; suggested <.
the pointer end symbol; suggested >.
New HTML file
This function permits to create a new HTML file form a text file formatted to obtain a HTF
file.
The informations required are:
SOURCE TEXT FILENAME
DESTINATION FILENAME
INDEX START CODE
INDEX END CODE
POINTER START CODE
POINTER END CODE
HTML TITLE
the filename of the text source file.
the filename of the destination Help Text File (suggested
‘.HLP’ extention).
the index start symbol; suggested ##.
the index end symbol; suggested ##.
the pointer start symbol; suggested <.
the pointer end symbol; suggested >.
the title for the html page.
nanoBase 1997 user manual
4168
371.6.5 Menu Macro
The menu Macro helps on creating macros (programs) with a macro recorder, a macro "compiler"
and a macro executor.
Start recording
This function simply starts or pause the macro recording. The menu items that end with
"&", may be recorded by this macro recorder.
Save recording
A recorded macro may be saved into a ASCII file that may be later modified or simply used
as it is. The filename is requested.
Erase recording
While recording or when the macro recorder is paused, it is possible to erase all previous
recording with this function.
Edit recording
While recording or when the macro recorder is paused, it is possible to edit all previous
recording, for example adding more comments or simply to see what the recorder does.
Macro compilation
A macro file (a program) contained inside a ASCII file, may be compiled into a different
file format to speed up execution. The source filename and the destination filename are
requested.
Load + execute macro
A macro file (a program) in ASCII form or compiled, may be executed.
A macro file may require some parameters.
This function asks for the macro filename to start and the possible parameter to pass to it.
371.6.6 Menu Info
The menu Info is the information menu.
ABOUT
MANUAL BROWSE
[F1] HELP
[F3] ALIAS INFO
[F5] SET OUTPUT TO
a brief copyright notice.
starts the browse of ‘NB.HLP’ , the nB Help Text File manual
if it is present in the current directory or it is found in the
PATH (the Dos SET PATH).
[F1] reminder.
[F3] reminder. It shows all the available information on the
active alias.
[F5] reminder. It defines the output peripheral or file.
371.6.7 Menu Doc
This menu actually appears only inside the DOC() function, the nB text editor.
New
It starts the editing of a new empty text.
nanoBase 1997 user manual
4169
Open
It opens for editing a new textfile.
Save
It saves the text file under editing.
Save as
It saves the text file under editing asking for a new name.
Set output to
It permits to change the default output peripheral: the default is the screen.
Print as it is
It prints on the output peripheral the content of the text as it is.
Print with RPT() once
It prints on the output peripheral the content of the text only once replacing possible text
variables.
Print with RPT() std
It prints on the output peripheral the content of the text repeating this print for every record
contained inside the archive alias.
Exit DOC()
Terminates the use of DOC() the text/document editing/print function.
371.7 The text editor DOC()
The function Doc() activates a simple text editor usefull to build some simple reports.
Inside this function a menu is available and is activated pressing
menu is part of the nB menu system.
[ Alt+M ]
or
[ F10 ].
The Doc()
DOC() may handle text files of a teorical maximum of 64K.
DOC() may be particularly useful to create formatted text with variables identified by CHR(174)
and CHR(175) delimiters: when an active alias exists, [ F2 ] gives a list of insertable fields.
[ Esc ]
[ F1 ]
[ F2 ]
[ up ] / [ Ctrl+E ]
[ down ] / [ Ctrl+X ]
[ left ] / [ Ctrl+S ]
[ right ] / [ Ctrl+D ]
[ Ctrl+right ] / [ Ctrl+A ]
[ Ctrl+left ] / [ Ctrl+F ]
[ Home ]
[ End ]
[ Ctrl+Home ]
[ Ctrl+End ]
[ PgUp ]
[ PgDn ]
[ Ctrl+PgUp ]
Exit DOC().
Call the help.
Field list.
Line up.
Line down.
Character left.
Character right.
Word left.
Word right.
Line start.
Line end.
Top window.
Bottom window.
Previous window.
Next window.
Document start.
nanoBase 1997 user manual
4170
[ Ctrl+PgDn ]
[ Del ]
[ Backspace ]
[ Tab ]
[ Ins ]
[ Enter ]
[ Ctrl+Y ]
[ Ctrl+T ]
[ F10 ] / [ Alt+M ]
End document.
Delete character (right).
Delete character Left.
Insert tab.
Toggle insert/overwrite.
Next line.
Delete line.
Delete word right.
DOC() menu.
371.8 The help text file
nB provides a basic hypertext system to build simple help files. A source text file with "indexes"
and "pointers" to indexes is translated into a "help text file" (a ‘.DBF’ file); then, this file is
browsed by nB.
The source file can have a maximum line width of 80 characters; each line can terminate with
CR or CR+LF.
"Indexes" are string delimited by index delimiters (default "##"); "pointers" are string delimited
by pointer delimiters (default "<" and ">") and refers to indexes.
Inside a text, indexes must be unique; pointers can be repeated anywhere. A text can contain a
maximum of 4000 indexes.
Inside this manual, titles are delimited with "##" as they are indexes; strings delimited with "<"
and ">" identify a reference to a title with the same string.
To browse a previously created Help Text File, use the following keys:
[ Esc ]
[ UpArrow ]
[ DownArrow ]
[ PgUp ]
[ PgDn ]
[ Ctrl+PgUp ]
[ Ctrl+PgDn ]
[ Enter ]
[ <- ]
[ -> ]
[ Shift+F3 ]
[ F3 ]
Exit.
Move cursor up.
Move cursor down.
Move cursor PageUp.
Move cursor Pagedown.
Move cursor Top.
Move cursor Bottom.
Select a reference (pointer).
Go to previous selected reference (pointer).
Go to next selected reference (pointer).
Search for a new pattern.
Repeat previous search.
371.9 Macro
nB can execute (run) macro files. There may be three kind of macro files: ASCII (usually with
.& extention); "compiled" (usually with .NB extention); EXE files (compiled with Clipper and
linked).
"Compiled" macro files are executed faster then the ASCII source files.
EXE macro files are the fastest.
nanoBase 1997 user manual
4171
371.9.1 Macro statements
The statements recognised from nB are very similar to Clipper, with some restrictions.
Note that: the FOR statement is not included; there is no function declaration; procedure calls
cannot transfer variables; only public variables are allowed.
PROCEDURE
Procedures are the basic building blocks of a nB macro.
Procedures are visible only inside the current macro file.
The procedure structure is as follows:
PROCEDURE procedure_name
statements ...
RETURN
statements ...
ENDPROCEDURE
[
]
A procedure definition begins with a PROCEDURE declaration followed with the
procedure_name and ends with ENDPROCEDURE.
Inside the PROCEDURE - ENDPROCEDURE declaration are placed the executable
statements which are executed when the procedure is called.
Inside the PROCEDURE - ENDPROCEDURE declaration, the RETURN statement may
appear. In this case, encountering this RETURN statement, the procedure execution is immediately terminated and control is passed to the statement following the calling one.
The procedure definition do not permit to receive parameters from the calling statement.
DO PROCEDURE
There is only one way to call a procedure:
DO PROCEDURE procedure_name
When the statement DO PROCEDURE is encountered, the control is passed to the begin of
the called PROCEDURE. After the PROCEDURE execution, the control is returned to the
statement following DO PROCEDURE.
The procedure call do not permit to send parameters to the procedure.
BEGIN SEQUENCE
The BEGIN SEQUENCE - END structure permits to define a sequence of operation that
may be broken.
Inside nB, this control structure is useful only because there is the possibility to break the
execution and pass control over the end of it.
This way, encountering BREAK means: "go to end".
BEGIN SEQUENCE
statements ...
BREAK
statements ...
END
[
]
Inside nB, error exception handling is not supported.
DO CASE
This is a control structure where only the statements following a True CASE condition are
executed.
nanoBase 1997 user manual
4172
When the DO CASE statement is encountered, the following CASE statements are tested.
The first time that a condition returns True, the CASE’s statements are executed and then
control is passed over the END case.
That is: only one CASE is taken into consideration.
If no condition is True, the statements following OTHERWISE are executed.
DO CASE
CASE lCondition1
statements ...
CASE lCondition2
statements ...
OTHERWISE
statements ...
END
[
[
]
]
WHILE
The structure WHILE - END defines a loop based on a condition: the loop is repeated until
the condition is True.
The loop execution may be broken with the EXIT statement: it transfer control after the
END while.
The LOOP statement may be use to repeat the loop: it transfer the control to the beginning
of the loop.
WHILE lCondition
statements ...
EXIT
statements ...
LOOP
statements ...
END
[
[
]
]
IF
The IF - END control structure executes a section of code if a specified condition is True.
The structure can also specify alternative code to execute if the condition is False.
IF lCondition1
statements ...
ELSE
statements ...
END
[
]
371.9.2 Variable declaration
Inside nB, variables are created using a specific function:
MEMPUBLIC( "cVarName " )
For example,
MEMPUBLIC( "Name" )
creates the variable Name.
The scope of the created variable is global and there is no way to restrict the visibility of it.
When a variable is no more needed or desired, it can be released:
MEMRELEASE( "cVarName " )
The variable declaration do not defines the variable type. Every variable may receive any kind of
data; that is that the type depends on the type of data contained.
nanoBase 1997 user manual
4173
371.9.3 Macro structure
A nB macro must be organised as follow. There may be two situations: Macros with procedures
and macros without procedures.
Macro with procedures:
PROCEDURE procedure_name_1
statements ...
RETURN
statements ...
ENDPROCEDURE
PROCEDURE procedure_name_2
statements ...
RETURN
statements ...
ENDPROCEDURE
[
]
[
]
...
...
DO PROCEDURE procedure_name_n
Macro without procedures:
statements ...
statements ...
statements ...
statements ...
statements ...
nB Macros may be compiled with Clipper. To do so, the first structure example must be changed
as follows:
#INCLUDE MACRO.CH
DO PROCEDURE procedure_name_nth
...
PROCEDURE procedure_name_1
statements ...
RETURN
statements ...
ENDPROCEDURE
PROCEDURE procedure_name_2
statements ...
RETURN
statements ...
ENDPROCEDURE
[
]
[
]
...
...
To compile a macro with Clipper, the macro file name can be changed into ‘MACRO.PRG’ and
RTLINK MACRO.RMK [Enter]
should be started.
371.9.4 Macro comments
A nB Macro source file can contain comments. only the "//" comment is recognised! This way:
* and /*...*/ will generate errors!
4174
nanoBase 1997 user manual
ATTENTION: to simplify the macro interpretation, lines such as this:
qqout( "You can’t do that // you can’t do that!" )
will generate an error as the interpreter will read only:
qqout( "You can’t do that
Sorry!
371.9.5 Macro long lines split
Inside a nB macro, long lines may be splitted using ";" (semicolon). Please note that: lines can
only be splitted and not joined; a resulting command line cannot be longer then 254 characters.
371.9.6 The macro recorder
Inside the functions ASSIST() and DOC() is available the Macro recorder menu.
When a macro recording is started, a "&" appears on the left side of the status bar. It it blinks, the
recording is active, if it is stable, the recording is paused.
The macro recording is not exactly a step-by-step recording of all action taken, but a translation
(as good as possible) of what you have done.
The macro recorder is able to record only the menu functions that terminates with the "&" symbol
and all what is inserted at the dot command line.
The macro recording can be viewed and edited during the recording. The macro recording can
be saved into a text file (a macro file).
371.10 Data types
The data types supported in the nB macro language are the same as Clipper:
Array
Character
Code Block
Numeric
Date
Logical
Memo
NIL
371.10.1 Character
The character data type identifies character strings of a fixed length. The character set corresponds
to: CHR(32) through CHR(255) and the null character, CHR(0).
Valid character strings consist of zero or more characters with a theoretical maximum of 65535
characters. The real maximum dimension depends on the available memory.
Character string constants are formed by enclosing a valid string of characters within a designed
pair of delimiters. There are three possible delimiter pairs:
nanoBase 1997 user manual
4175
two single quotes like ‘’string_constant ’’;
two double quotes like ‘"string_constant "’;
left and right square brackets like ‘[string_constant ]’.
These three different kind of delimiters are available to resolve some possible problems:
I don’t want it -> "I don’t want it"
She said, "I love hin" -> ’She said, "I love hin"’
He said, "I don’t want it" -> [He said, "I don’t want it"]
The following table shows all operations available inside nB for character data types. These
operations act on one or more character expressions and the result is not necessarily a character
data type.
+
==
!=, <>, #
<
<=
>
>=
:=
$
ALLTRIM()
ASC()
AT()
CTOD()
DESCEND()
EMPTY()
ISALPHA()
ISDIGIT()
ISLOWER()
ISUPPER()
LEFT()
LEN()
LOWER()
LTRIM()
PADC()
PADL()
PADR()
RAT()
RIGHT()
RTRIM()
SOUNDEX()
SPACE()
STRTRAN()
STUFF()
SUBSTR()
TRANSFORM()
UPPER()
VAL()
VALTYPE()
Concatenate.
Concatenate without intervening spaces.
Compare for exact equity.
Compare for inequity.
Compare for sorts before
Compare for sorts before or same as.
Compare for sorts after.
Compare for sorts after or same as.
In line assign.
Test for substring existence.
Remove leading and trailing spaces.
Convert to numeric ASCII code equivalent.
Locate substring position.
Convert to date.
Convert to complemented form.
Test for null or blank string.
Test for initial letter.
Test for initial digit.
Test for initial lowercase letter.
Test for initial uppercase letter.
Extract substring form the left.
Compute string length in characters.
Convert letters to lowercase.
Remove leading spaces.
Pad with leading and trailing spaces.
Pad with leading spaces.
Pad with trailing spaces.
Locate substring position starting from the right.
Extract substring form the right.
Remove trailing spaces.
Convert to soundex equivalent.
Create a blank string of a defined length.
Search and replace substring.
Replace substring.
Extract substring.
Convert to formatted string.
Convert letters to uppercase
Convert to numeric.
Evaluates data type directly.
nanoBase 1997 user manual
4176
371.10.2 Memo
The memo data type is used to represent variable length character data that can only exist in the
form of a database field.
Memo fields are not stored inside the main database file (.DBF) but inside a separate file (.DBT).
A memo field can contain up to 65535 characters, that is the same maximum dimension of character fields. In fact, originally xBases, couldn’t have character string longer than 254 characters.
As here memo fields are very similar to long character strings, you may forget that there is a
difference.
All the operations that may be applied to character strings, may be used with memo fields; the
following functions may be use especially for memo fields or long character strings.
HARDCR()
MEMOEDIT()
MEMOLINE()
MEMOREAD()
MEMOTRAN()
MEMOWRIT()
MLCOUNT()
MLPOS()
Replace soft with hard carriage returns.
Edit contents.
Extract a line of a text.
Read form a disk text file.
Replace soft and hard carriage returns.
Write to disk text file.
Count lines.
Compute position.
371.10.3 Date
The date data type is used to represent calendar dates.
Supported dates are from 0100.01.01 to 2999.12.31 and null or blank date.
The appearance of a date is controlled from SETVERB("DATEFORMAT"). The default is
"dd/mm/yyyy" and it may easily changed for example with SETVERB("DATEFORMAT",
"MM/DD/YYYY") to the US standard.
There is no way to represent date constants; these must be replaced with the CTOD() function.
For example if the date 11/11/1995 is to be written, the right way is:
CTOD( "11/11/1995" )
The character string "11/11/1995" must respect the date format defined as before explained.
The function CTOD() will accept only valid dates, and null dates:
CTOD( "" )
A null date is ever less than any other valid date.
The following table shows all operations available inside nB for date data types. These operations
act on one or more date expressions and the result is not necessarily a character data type.
+
==
!=, <>, #
<
<=
>
>=
Add a number of days to a date.
Subtract days to a date.
Compare for equity.
Compare for inequity.
Compare for earlier
Compare for earlier or same as.
Compare for later.
Compare for later or same as.
nanoBase 1997 user manual
:=
CDOW()
CMONTH()
DAY()
DESCEND()
DOW()
DTOC()
DOTOS()
EMPTY()
MONTH()
VALTYPE()
YEAR()
4177
In line assign.
Compute day of week name.
Compute month name.
Extract day number.
Convert to complemented form.
Compute day of week.
Convert to character string with the format defined with
SETVERB( "DATEFORMAT" ).
Convert to character string in sorting format (YYYYMMDD).
Test for null date.
Extract month number.
Evaluates data type directly.
Extract entire year number, including century.
371.10.4 Numeric
The numeric data type identifies real number. The theoretical range is form 10^-308 to 10^308
but the numeric precision is guaranteed up to 16 significant digits, and formatting a numeric
value for display is guaranteed up to a length of 32 (30 digits, a sign, and a decimal point). That
is: numbers longer than 32 bytes may be displayed as asterisks, and digits other then most 16
significant ones are displayed as zeroes.
Numeric constants are written without delimiters. The following are valid constant numbers:
12345
12345.678
-156
+1256.789
-.789
If a numeric constant is delimited like character strings, it becomes a character string.
The following table shows all operations available inside nB for numeric data types. These operations act on one or more numeric expressions and the result is not necessarily a numeric data
type.
+
*
/
%
^, **
==
!=, <>, #
<
>=
>
>=
:=
ABS()
CHR()
DESCEND()
EMPTY()
Add or Unary Positive.
Subtract or Unary Negative.
Multiply.
Divide.
Modulus.
Exponentiate.
Compare for equity.
Compare for inequity.
Compare for less than.
Compare for less than or equal.
Compare for greater than.
Compare for greater than or equal.
In line assign.
Compute absolute value.
Convert to ASCII character equivalent.
Convert to complemented form.
Test for zero.
nanoBase 1997 user manual
4178
EXP()
INT()
LOG()
MAX()
MIN()
ROUND()
SQRT()
STR()
TRANSFORM()
VALTYPE()
Exponentiate with e as the base.
Convert to integer.
Compute natural logarithm.
Compute maximum.
Compute minimum.
Round up or down()
Compute square root.
Convert to character.
Convert to formatted string.
Evaluates data type directly.
Number appearence may be affected by SETVERB("FIXED") and consequently by
SETVERB("DECIMALS"). If SETVERB("FIXED") is True, numbers are displayed with a fixed
decimal position. The number of decimal positions is defined by SETVERB("DECIMALS"). For
that reason, the default is SETVERB("FIXED", .F.) and SETVERB("DECIMALS", 2), that is,
no fixed decimal position, but if they will be activated, the default is two decimal digits.
371.10.5 Logical
The logical data type identifies Boolean values.
Logical constants are:
‘.T.’
‘.F.’
True.
False.
When editing a logical field, inputs may be:
y, Y, t, T
n, N, f, F
for True
for False
The following table shows all operations available inside nB for logical data types. These operations act on one or more logical expressions and the result is not necessarily a logical data
type.
.AND.
.OR.
.NOT. or !
==
!=, <>, or #
And.
Or.
Negate.
Compare for equity.
Compare for inequity.
Comparing two logical values, False (‘.F.’) is always less than True (‘.T.’).
371.10.6 NIL
NIL is not properly a data type, it represent the value of an uninitialised variable.
Inside nB (like what it happens inside Clipper), variables are not declared with the data type that
they will contain. This means that a variable can contain any kind of data. In fact, nB variables
are pointer to data and a pointer to "nothing" is NIL.
NIL may be used as constant for assignment or comparing purpose:
nanoBase 1997 user manual
4179
NIL
Fields (database fields) cannot contain NIL.
The following table shows all operations available inside nB for the NIL data type. Except for
these operations, attempting to operate on a NIL results in a runtime error.
==
!=, <>, #
<
<=
>
>=
:=
EMPTY()
VALTYPE()
Compare for equity.
Compare for inequity.
Compare for less than.
Compare for less than or equal.
Compare for greater than.
Compare for greater than or equal.
In line assign.
Test for NIL.
Evaluates data type directly.
For the purpose of comparison, NIL is the only value that is equal to NIL. All other values are
greater than NIL.
Variables are created inside nB with MEMPUBLIC(). This function creates variables which will
be automatically initialised to NIL.
371.10.7 Array
The array data type identifies a collection of related data items that share the same name. Each
value in an array is referred to as an element.
Array elements can be of any data type except memo (memo is available only inside database
fields). For example the first element can be a character string, the second a number, the third a
date and so on. Arrays can contain other arrays and code blocks as elements.
The variable containing the array does not contains the entire array, but the reference to it.
When the NIL type was described, it was cleared that variables doesn’t contains real data,
but pointer to data. But this happens in a transparent way, that is that when the a variable is
assigned to another (for example A := B) the variable receiving the assignment will receive
a pointer to a new copy of the source data. This is not the same with arrays: assigning to a
variable an array, will assign to that variable a pointer to the same source array and not to a
new copy of it.
If arrays are to be duplicated, the ACLONE() function is to be used.
An array constant may be expressed using curly brackets {}. See the examples below.
A := { "first_element ", "second_element ", "third_element " }
With this example, the variable A contain the reference to an array with three element containing
character string.
A[1] == "first_element "
A[2] == "second_element "
A[3] == "third_element "
Arrays may contain also no element: empty array and may be expressed as:
{}
nanoBase 1997 user manual
4180
The array element is identified by a number enclosed with square brackets, following the variable
name containing the reference to the array. The first array element is one.
If an array contains arrays, we obtain a multidimensional array. For example:
A := { { 1, 2 }, { 3, 4 }, { 5, 6 } }
is equivalent to the following table.
1
2
3
4
5
6
With this example, the variable A contain the reference to a bidimensional array containing numbers.
A[1,1] or A[1][1] contains 1
A[1,2] or A[1][2] contains 2
A[2,1] or A[2][1] contains 3
and so on.
As arrays may contain mixed data, it is the user who have to handle correctly the element numbers. For example:
A := { "hello", { 3, 4 }, 1234 }
A[1] == "hello"
A[2] == reference to { 3, 4 }
A[3] == 1234
A[2,1] or A[2][1] contains 3
A[2,2] or A[2][2] contains 4
A[1,1] is an error!
The following table shows all operations available inside nB for arrays.
:=
AADD()
ACLONE()
ACOPY()
ADEL()
AFILL()
AINS()
ARRAY()
ASCAN()
ASIZE()
ASORT()
EMPTY()
VALTYPE()
In line assign.
Add dynamically an element to an array.
Create a copy of an array.
Copy element by element an array to another.
Delete one element inside an array.
Fill all array elements with a value.
Insert an element inside an array.
Creates an array of empty elements.
Scan the array elements.
Resize an array.
Sort the array elements.
Test for no elements.
Evaluates data type directly.
nanoBase 1997 user manual
4181
371.10.8 Code block
The code block data type identifies a small piece of executable program code.
A code block is something like a little user defined function where only a sequence of functions
or assignments may appear: no loops, no IF ELSE END.
A code block may receive argument and return a value after execution, just like a function.
The syntax is:
{ |
[argument_list ]
| exp_list }
That is: the argument_list is optional; the exp_list may contain one or more expressions separated with a comma.
For example, calling the following code block will give the string "hello world" as result.
{ || "hello world" }
The following code block require a numeric argument an returns the number passed as argument
incremented:
{ | n | n+1 }
The following code block requires two numeric arguments and returns the sum of the two square
radix:
{ | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }
But code blocks may contains more expressions and the result of the execution of the code block
is the result of the last expression.
The following code block executes in sequence some functions and give ever "hello world" as a
result.
{ | a, b | functionOne(a), functionTwo(b), "hello world" }
To start the execution of a code block a function is used: EVAL()
For example, a code block is assigned to a variable and then executed.
B := { || "hello world" }
EVAL( B ) == "hello world"
Another example with a parameter.
B := { | n | n+1 }
EVAL( B, 1 ) == 2
Another example with two parameters.
B := { | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }
EVAL( B, 2, 4 ) == 20
And so on.
The following table shows some operations available inside nB for code blocks: many functions
use code blocks as argument.
:=
AEVAL()
BCOMPILE()
DBEVAL()
In line assign.
Evaluate (execute) a code block for each element in an array.
Convert (compile) a character string into a code block.
Evaluate (execute) a code block for each record in the active
alias.
4182
EVAL()
VALTYPE()
nanoBase 1997 user manual
Evaluate a code block once.
Evaluates data type directly.
371.11 Operators
Here is a list with a brief description of the operators available inside nB.
cString1 $ cString2
Substring comparison.
If cString1 is contained inside cString2 the result is true (‘.T.’).
nNumber1 % nNumber2
Modulus.
The result is the remainder of nNumber1 divided by nNuber2 .
()
Function or grouping indicator.
nNumber1 * nNumber2
Multiplication.
nNumber1 ** nNumber2
nNumber1 ^ nNumber2
Exponentiation.
nNumber1 + nNumber2
dDate + nNumber
Addition, unary positive.
cString1 + cString2
String concatenation.
The result is a string beginning with the content of cString1 and following with the content of
cString2 .
nNumber1 - nNumber2
dDate1 - dDate2
dDate - nNumber
Subtraction, unary negative.
cString1 - cString2
String concatenation.
The result is a string containing cString1 after trimming trailing blanks and cString2 .
idAlias ->idField
FIELD->idVar
MEMVAR->idVar
Alias assignment.
The alias operator implicitly SELECTs the idAlias before evaluating idField . When the evaluation is complete, the original work area is SELECTed again.
lCondition1 .AND. lCondition2
nanoBase 1997 user manual
Logical AND.
.NOT. lCondition
Logical NOT.
lCondition1 .OR. lCondition2
Logical OR.
nNumber1 / nNumber2
Division.
object:message [(argument list)]
Send.
idVar := exp
Inline assign.
exp1 <= exp2
Less than or equal.
exp1 <> exp2
Not equal.
exp1 = exp2
Equal.
exp1 == exp2
Exactly equal.
exp1 > exp2
Greater than.
exp1 >= exp2
Greater than or equal.
@idVar
Pass-by-reference.
[]
aArray [nSubscript , ...]
aArray [nSubscript1 ][nSubscript2 ]
...
Array element indicator.
371.12 Delimiters
Here is the delimiter list recognised from nB.
{ exp_list }
Literal array delimiters.
{ |param_list | exp_list }
Code block delimiters.
4183
nanoBase 1997 user manual
4184
"cString "
’cString ’
[cString ]
String delimiters.
371.13 Code blocks
A code block is a sequence of function, assignments and constant like the following:
sqrt(10)
nResult := 10 * nIndex
Suppose that the above sequence of operations has a meaning for you. We want to create a box
containing this sequence of operation. This box is contained inside a variable:
bBlackBox := { || sqrt(10), nResult := 10 * nIndex }
Note the comma used as separator.
Now bBlackBox contains the small sequence seen before. To execute this sequence, the function
EVAL() is used:
EVAL(bBlackBox)
The execution of the code block gives a result: the value of the last operation contained inside
the code block. In this case it is the result of 10*nIndex . For that reason, if the execution of the
code block must give a fixed result, it can terminate with a constant.
A code block may receive parameters working like a function. Try to imagine that we need to do
the following.
function multiply( nVar1, nVar2 )
return nVar * nVar2
endfunction
A code block that does the same is:
bMultiply := { | nVar1, nVar2 | nVar1 * nVar2 }
To evaluate it, for example trying to multiply 10 * 5:
nResult := EVAL( bMultiply, 10, 5 )
and nResult will contain 50.
371.14 Standard functions
With nB all Clipper standard functions may be used. Here follows a short description.
AADD()
Array add
AADD(aTarget , expValue ) ⇒ Value
aTarget
expValue
is the array to add a new element to.
is the value assigned to the new element.
It increases the actual length of the target array by one. The newly created array element is
assigned the value specified by expValue .
nanoBase 1997 user manual
4185
ABS()
Absolute
ABS(nExp ) ⇒ nPositive
is the numeric expression to evaluate.
nExp
ABS() returns a number representing the absolute value of its argument.
ACLONE()
Array clone
ACLONE(aSource ) ⇒ aDuplicate
is the array to duplicate.
aSource
ACLONE() returns a duplicate of aSource .
ACOPY()
Array copy
ACOPY(aSource , aTarget ,
nStart , nCount
[
] [
], [nTargetPos])
⇒ aTarget
is the array to copy elements from.
is the array to copy elements to.
is the starting element position in the aSource array. If not
specified, the default value is one.
is the number of elements to copy from the aSource array
beginning at the nStart position. If nCount is not specified,
all elements in aSource beginning with the starting element
are copied.
is the starting element position in the aTarget array to receive
elements from aSource . If not specified, the default value is
one.
aSource
aTarget
nStart
nCount
nTargetPos
ACOPY() is an array function that copies elements from the aSource array to the aTarget
array. The aTarget array must already exist and be large enough to hold the copied elements.
ADEL()
Array delete
ADEL(aTarget , nPosition ) ⇒ aTarget
is the array to delete an element from.
is the position of the target array element to delete.
aTarget
nPosition
ADEL() is an array function that deletes an element from an array. The contents of the
specified array element is lost, and all elements from that position to the end of the array
are shifted up one element. The last element in the array becomes NIL.
AEVAL()
Array evaluation
AEVAL(aArray , bBlock ,
nStart , nCount
[
] [
])
⇒ aArray
nanoBase 1997 user manual
4186
is the array to be evaluated.
is a code block to execute for each element encountered.
is the starting element. If not specified, the default is element
one.
is the number of elements to process from nStart . If not specified, the default is all elements to the end of the array.
aArray
bBlock
nStart
nCount
AEVAL() is an array function that evaluates a code block once for each element of an array,
passing the element value and the element index as block parameters. The return value of
the block is ignored. All elements in aArray are processed unless either the nStart or the
nCount argument is specified.
AFILL()
Array fill
AFILL(aTarget , expValue ,
nStart , nCount ) ⇒ aTarget
[
] [
]
is the array to fill.
is the value to place in each array element. It can be an expression of any valid data type.
is the position of the first element to fill. If this argument is
omitted, the default value is one.
is the number of elements to fill starting with element nStart .
If this argument is omitted, elements are filled from the starting element position to the end of the array.
aTarget
expValue
nStart
nCount
AFILL() is an array function that fills the specified array with a single value of any data
type (including an array, code block, or NIL) by assigning expValue to each array element
in the specified range.
AINS()
Array insert
AINS(aTarget , nPosition ) ⇒ aTarget
is the array into which a new element will be inserted.
is the position at which the new element will be inserted.
aTarget
nPosition
AINS() is an array function that inserts a new element into a specified array. The newly
inserted element is NIL data type until a new value is assigned to it. After the insertion,
the last element in the array is discarded, and all elements after the new element are shifted
down one position.
ALERT()
ALERT( cMessage ,
cMessage
aOptions
[aOptions]
) ⇒ nChoice
is the message text displayed, centered, in the alert box. If the
message contains one or more semicolons, the text after the
semicolons is centered on succeeding lines in the dialog box.
defines a list of up to 4 possible responses to the dialog box.
ALERT() returns a numeric value indicating which option was chosen. If the Esc key is
pressed, the value returned is zero. The ALERT() function creates a simple modal dialog.
The user can respond by moving a highlight bar and pressing the Return or SpaceBar keys,
nanoBase 1997 user manual
4187
or by pressing the key corresponding to the first letter of the option. If aOptions is not
supplied, a single "Ok" option is presented.
ALIAS()
[
ALIAS( nWorkArea
])
⇒ cAlias
is any work area number.
nWorkArea
ALIAS() returns the alias of the specified work area as a character string. If nWorkArea is
not specified, the alias of the current work area is returned. If there is no database file in
USE for the specified work area, ALIAS() returns a null string ("").
ALLTRIM()
ALLTRIM(cString ) ⇒ cTrimmedString
is the character expression to trim.
cString
ALLTRIM() returns a character string with leading and trailing spaces removed.
ARRAY()
ARRAY(nElements
[,
]
nElements ... ) ⇒ aArray
is the number of elements in the specified dimension.
nElements
ARRAY() is an array function that returns an uninitialized array with the specified number
of elements and dimensions.
ASC()
ASCII
ASC(cExp ) ⇒ nCode
is the character expression to convert to a number.
cExp
ASC() returns an integer numeric value in the range of zero to 255 , representing the ASCII
value of cExp .
ASCAN()
Array scan
ASCAN(aTarget , expSearch ,
nStart , nCount ) ⇒ nStoppedAt
[
aTarget
expSearch
nStart
nCount
] [
]
is the array to scan.
is either a simple value to scan for, or a code block. If
expSearch is a simple value it can be character, date, logical, or numeric type.
is the starting element of the scan. If this argument is not specified, the default starting position is one.
is the number of elements to scan from the starting position.
If this argument is not specified, all elements from the starting
element to the end of the array are scanned.
ASCAN() returns a numeric value representing the array position of the last element
scanned. If expSearch is a simple value, ASCAN() returns the position of the first matching
nanoBase 1997 user manual
4188
element, or zero if a match is not found. If expSearch is a code block, ASCAN() returns
the position of the element where the block returned true (‘.T.’).
ASIZE()
Array size
ASIZE(aTarget , nLength ) ⇒ aTarget
is the array to grow or shrink.
is the new size of the array.
aTarget
nLength
ASIZE() is an array function that changes the actual length of the aTarget array. The array
is shortened or lengthened to match the specified length. If the array is shortened, elements
at the end of the array are lost. If the array is lengthened, new elements are added to the end
of the array and assigned NIL.
ASORT()
Array sort
[ ]
] [
]
ASORT(aTarget , nStart ,
nCount , bOrder ) ⇒ aTarget
[
aTarget
nStart
nCount
bOrder
is the array to sort.
is the first element of the sort. If not specified, the default
starting position is one.
is the number of elements to sort. If not specified, all elements
in the array beginning with the starting element are sorted.
is an optional code block used to determine sorting order. If
not specified, the default order is ascending.
ASORT() is an array function that sorts all or part of an array containing elements of a
single data type. Data types that can be sorted include character, date, logical, and numeric.
If the bOrder argument is not specified, the default order is ascending. Each time the block
is evaluated, two elements from the target array are passed as block parameters. The block
must return true (‘.T.’) if the elements are in sorted order.
AT()
AT(cSearch , cTarget ) ⇒ nPosition
cSearch
cTarget
is the character substring for which to search.
is the character string to search.
AT() returns the position of the first instance of cSearch within cTarget as an integer numeric value. If cSearch is not found, AT() returns zero.
AT() is a character function used to determine the position of the first occurrence of a
character substring within another string.
ATAIL()
Array TAIL
ATAIL(aArray ) ⇒ Element
aArray
is the array.
ATAIL() is an array function that returns the highest numbered element of an array. It can
nanoBase 1997 user manual
4189
[
]
be used in applications as shorthand for aArray LEN(aArray ) when you need to obtain
the last element of an array.
BIN2I()
Binary to integer
BIN2I(cSignedInt ) ⇒ nNumber
cSignedInt
is a character string in the form of a 16-bit signed integer
number--least significant byte first.
BIN2I() returns an integer obtained converting the first two byte contained inside
cSignedInt .
BIN2L()
Binary to long
BIN2L(cSignedInt ) ⇒ nNumber
cSignedInt
is a character string in the form of a 32-bit signed integer
number--least significant byte first.
BIN2L() returns an integer obtained from the first tour characters contained in cSignedInt .
BIN2W()
Binary to word
BIN2W(cUnsignedInt ) ⇒ nNumber
cUnsignedInt
is a character string in the form of a 16-bit unsigned integer
number--least significant byte first.
BIN2W() returns an integer obtained from the first two characters contained in cSignedInt .
BOF()
Begin of file
BOF() ⇒ lBoundary
BOF() returns true (‘.T.’) after an attempt to SKIP backward beyond the first logical record
in a database file; otherwise, it returns false (‘.F.’). If there is no database file open in
the current work area, BOF() returns false (‘.F.’). If the current database file contains no
records, BOF() returns true (‘.T.’).
CDOW()
Character day of week
CDOW(dExp ) ⇒ cDayName
dExp
is the date value to convert.
CDOW() returns the name of the day of the week as a character string. The first letter is
uppercase and the rest of the string is lowercase. For a null date value, CDOW() returns a
null string ("").
CHR()
Character
nanoBase 1997 user manual
4190
CHR(nCode ) ⇒ cChar
is an ASCII code in the range of zero to 255.
nCode
CHR() returns a single character value whose ASCII code is specified by nCode .
CMONTH()
Character month
CMONTH(dDate) ⇒ cMonth
is the date value to convert.
dDate
CMONTH() returns the name of the month as a character string from a date value with the
first letter uppercase and the rest of the string lowercase. For a null date value, CMONTH()
returns a null string ("").
COL()
Column
COL() ⇒ nCol
COL() is a screen function that returns the current column position of the cursor. The value
of COL() changes whenever the cursor position changes on the screen.
COLORSELECT()
COLORSELECT(nColorIndex ) ⇒ NIL
is a number corresponding to the ordinal positions in the current list of color attributes, as set by SETCOLOR().
nColorIndex
COLORSELECT() activates the specified color pair from the current list of color attributes
(established by SETCOLOR()).
CTOD()
Character to date
CTOD(cDate) ⇒ dDate
is a character string consisting of numbers representing the
month, day, and year separated by any character other than a
number. The month, day, and year digits must be specified in
accordance with the SET DATE format. If the century digits
are not specified, the century is determined by the rules of
SET EPOCH.
cDate
CTOD() returns a date value. If cDate is not a valid date, CTOD() returns an empty date.
CURDIR()
Current directory
[
]
CURDIR( cDrivespec ) ⇒ cDirectory
cDrivespec
specifies the letter of the disk drive to query. If not specified,
the default is the current DOS drive.
CURDIR() returns the current DOS directory of the drive specified by cDrivespec as a
nanoBase 1997 user manual
4191
character string without either leading or trailing backslash (\) characters.
DATE()
DATE() ⇒ dSystemDate
DATE() returns the system date as a date value.
DAY()
DAY(dDate) ⇒ nDay
is a date value to convert.
dDate
DAY() returns the day number from dDate.
DBAPPEND()
[
DBAPPEND( lReleaseRecLocks
])
lReleaseRecLocks
⇒ NIL
is a logical data type that if true (‘.T.’), clears all
pending record locks, then appends the next record. If
lReleaseRecLocks is false (‘.F.’), all pending record locks
are maintained and the new record is added to the end of
the Lock List. The default value of lReleaseRecLocks is true
(‘.T.’).
DBAPPEND() adds a new empty record to the active alias.
DBCLEARFILTER()
DBCLEARFILTER() ⇒ NIL
DBCLEARFILTER() clears the logical filter condition, if any, for the current work area.
DBCLEARINDEX()
DBCLEARINDEX() ⇒ NIL
DBCLEARINDEX() closes any active indexes for the active alias.
DBCLEARRELATION()
DBCLEARRELATION() ⇒ NIL
DBCLEARRELATION() clears any active relations for the active alias.
DBCLOSEALL()
DBCLOSEALL() ⇒ NIL
DBCLOSEALL() releases all occupied work areas from use. It is equivalent to calling
DBCLOSEAREA() on every occupied work area.
Attention: DBCLOSEALL() cannot be used inside a "compiled" macro as this will stop
the macro execution. In substitution, DBCLOSE() should be used.
DBCLOSEAREA()
DBCLOSEAREA() ⇒ NIL
DBCLOSEAREA() releases the current work area from use.
nanoBase 1997 user manual
4192
DBCOMMIT()
DBCOMMIT() ⇒ NIL
DBCOMMIT() causes all updates to the current work area to be written to disk. All updated
database and index buffers are written to DOS and a DOS COMMIT request is issued for
the database (.dbf) file and any index files associated with the work area. Inside a network
environment, DBCOMMIT() makes database updates visible to other processes. To insure
data integrity, issue DBCOMMIT() before an UNLOCK operation.
DBCOMMITALL()
DBCOMMITALL() ⇒ NIL
DBCOMMITALL() causes all pending updates to all work areas to be written to disk. It is
equivalent to calling DBCOMMIT() for every occupied work area.
DBCREATE()
DBCREATE(cDatabase, aStruct ,
cDatabase
aStruct
cDriver
[cDriver])
⇒ NIL
is the name of the new database file, with an optional drive and
directory, specified as a character string. If specified without
an extension (.dbf) is assumed.
is an array that contains the structure of cDatabase as a series
of subarrays, one per field. Each subarray contains the definition of each field’s attributes and has the following structure:
aStruct[n][1] == cName
aStruct[n][2] == cType
aStruct[n][3] == nLength
aStruct[n][4] == nDecimals
specifies the replaceable database driver (RDD) to use to process the current work area. cDriver is name of the RDD specified as a character expression.
DBCREATE() is a database function that creates a database file from an array containing
the structure of the file.
DBCREATEINDEX()
DBCREATEINDEX(cIndexName , cKeyExpr , bKeyExpr ,
⇒ NIL
cIndexName
cKeyExpr
bKeyExpr
lUnique
[lUnique])
is a character value that specifies the filename of the index file
(order bag) to be created.
is a character value that expresses the index key expression in
textual form.
is a code block that expresses the index key expression in executable form.
is an optional logical value that specifies whether a unique
index is to be created. If lUnique is omitted, the current global
_SET_UNIQUE setting is used.
DBCREATEINDEX() creates an index for the active alias. If the alias has active indexes,
they are closed.
DBDELETE()
DBDELETE() ⇒ NIL
DBDELETE() marks the current record as deleted (*). Records marked for deletion can be
filtered using SET DELETED or removed from the file using the PACK command.
nanoBase 1997 user manual
4193
DBEVAL()
DB evaluate
DBEVAL(bBlock ,
bForCondition ,
bWhileCondition ,
nNextRecords ,
nRecord ,
lRest ) ⇒ NIL
[
[
[
[
[
]
]
]
]
]
bBlock
bForCondition
bWhileCondition
nNextRecords
nRecord
lRest
is a code block to execute for each record processed.
the FOR condition expressed as code block.
the WHILE condition expressed as code block.
is an optional number that specifies the number of records to
process starting with the current record. It is the same as the
NEXT clause.
is an optional record number to process. If this argument is
specified, bBlock will be evaluated for the specified record.
This argument is the same as the RECORD clause.
is an optional logical value that determines whether the scope
of DBEVAL() is all records, or, starting with the current
record, all records to the end of file.
DBEVAL() is a database function that evaluates a single block for each record within the
active alias.
DBFILTER()
DBFILTER() ⇒ cFilter
BFILTER() returns the filter condition defined in the current work area as a character string.
If no FILTER has been SET, DBFILTER() returns a null string ("").
DBGOBOTTOM()
DBGOBOTTOM() ⇒ NIL
DBGOBOTTOM() moves to last logical record in the active alias.
DBGOTO()
DBGOTO(nRecordNumber ) ⇒ NIL
nRecordNumber
is a numeric value that specifies the record number of the desired record.
DBGOTO() moves to the record whose record number is equal to nRecordNumber . If no
such record exists, the work area is positioned to LASTREC() + 1 and both EOF() and
BOF() return true (‘.T.’).
DBGOTOP()
DBGOTOP() ⇒ NIL
DBGOTOP() moves to the first logical record in the current work area.
DBRECALL()
DBRECALL() ⇒ NIL
DBRECALL() causes the current record to be reinstated if it is marked for deletion.
DBREINDEX()
DBREINDEX() ⇒ NIL
nanoBase 1997 user manual
4194
DBREINDEX() rebuilds all active indexes associated with the active alias.
DBRELATION()
DBRELATION(nRelation ) ⇒ cLinkExp
is the position of the desired relation in the list of active alias
relations.
nRelation
DBRELATION() returns a character string containing the linking expression of the relation
specified by nRelation . If there is no RELATION SET for nRelation , DBRELATION()
returns a null string ("").
DBRLOCK()
DB record lock
[
DBRLOCK( nRecNo
])
⇒ lSuccess
is the record number to be locked. The default is the current
record.
nRecNo
DBRLOCK() is a database function that locks the record identified by nRecNo or the current record.
DBRLOCKLIST()
DBRLOCKLIST() ⇒ aRecordLocks
DBRLOCKLIST() returns a one-dimensional array of the locked records in the active alias.
DBRSELECT()
DB relation select
DBRSELECT(nRelation ) ⇒ nWorkArea
is the position of the desired relation in the list of current work
area relations.
nRelation
DBRSELECT() returns the work area number of the relation specified by nRelation as
an integer numeric value. If there is no RELATION SET for nRelation , DBRSELECT()
returns zero.
DBRUNLOCK()
DB relation unlock
[
DBRUNLOCK( nRecNo
])
⇒ NIL
is the record number to be unlocked. The default is all previously locked records.
nRecNo
DBRUNLOCK() is a database function that unlocks the record identified by nRecNo or all
locked records.
DBSEEK()
DBSEEK(expKey ,
expKey
[lSoftSeek ])
⇒ lFound
is a value of any type that specifies the key value associated
with the desired record.
nanoBase 1997 user manual
4195
is an optional logical value that specifies whether a soft seek
is to be performed. This determines how the work area is positioned if the specified key value is not found. If lSoftSeek is
omitted, the current global _SET_SOFTSEEK setting is used.
lSoftSeek
DBSEEK() returns true (‘.T.’) if the specified key value was found; otherwise, it returns
false (‘.F.’).
DBSELECTAREA()
DBSELECTAREA(nArea
|
cAlias ) ⇒ NIL
is a numeric value between zero and 250, inclusive, that specifies the work area being selected.
is a character value that specifies the alias of a currently occupied work area being selected.
nArea
cAlias
DBSELECTAREA() causes the specified work area to become the current work area. All
subsequent database operations will apply to this work area unless another work area is
explicitly specified for an operation.
DBSETDRIVER()
[
]
DBSETDRIVER( cDriver ) ⇒ cCurrentDriver
cDriver
is an optional character value that specifies the name of the
database driver that should be used to activate and manage
new work areas when no driver is explicitly specified.
DBSETDRIVER() returns the name of the current default driver.
DBSETFILTER()
DBSETFILTER(bCondition ,
bCondition
cCondition
[cCondition])
⇒ NIL
is a code block that expresses the filter condition in executable
form.
is a character value that expresses the filter condition in textual form. If cCondition is omitted, the DBSETFILTER()
function will return an empty string for the work area.
DBSETFILTER() sets a logical filter condition for the current work area. When a filter is
set, records which do not meet the filter condition are not logically visible. That is, database
operations which act on logical records will not consider these records. The filter expression
supplied to DBSETFILTER() evaluates to true (‘.T.’) if the current record meets the filter
condition; otherwise, it should evaluate to false (‘.F.’).
DBSETINDEX()
DBSETINDEX(cOrderBagName ) ⇒ NIL
cOrderBagName
is a character value that specifies the filename of the index file
(index bag) to be opened.
DBSETINDEX() is a database function that adds the contents of an Order Bag into the
Order List of the current work area. Any Orders already associated with the work area
continue to be active. If the newly opened Order Bag is the only Order associated with
nanoBase 1997 user manual
4196
the work area, it becomes the controlling Order; otherwise, the controlling Order remains
unchanged. If the Order Bag contains more than one Order, and there are no other Orders
associated with the work area, the first Order in the new Order Bag becomes the controlling
Order.
DBSETORDER()
DBSETORDER(nOrderNum ) ⇒ NIL
is a numeric value that specifies which of the active indexes is
to be the controlling index.
nOrderNum
DBSETORDER() controls which of the active alias’ active indexes is the controlling index.
DBSETRELATION()
DBSETRELATION(nArea
|
cAlias , bExpr ,
[cExpr])
⇒ NIL
is a numeric value that specifies the work area number of the
child work area.
is a character value that specifies the alias of the child work
area.
is a code block that expresses the relational expression in executable form.
is an optional character value that expresses the relational expression in textual form. If cExpr is omitted, the DBRELATION() function returns an empty string for the relation.
nArea
cAlias
bExpr
cExpr
DBSETRELATION() relates the work area specified by nArea or cAlias (the child work
area), to the current work area (the parent work area). Any existing relations remain active.
DBSKIP()
[
]
DBSKIP( nRecords ) ⇒ NIL
is the number of logical records to move, relative to the current record. A positive value means to skip forward, and a
negative value means to skip backward. If nRecords is omitted, a value of 1 is assumed.
nRecords
DBSKIP() moves either forward or backward relative to the current record. Attempting to
skip forward beyond the last record positions the work area to LASTREC() + 1 and EOF()
returns true (‘.T.’). Attempting to skip backward beyond the first record positions the work
area to the first record and BOF() returns true (‘.T.’).
DBSTRUCT()
DBSTRUCT() ⇒ aStruct
DBSTRUCT() returns the structure of the current database file in an array whose length is
equal to the number of fields in the database file. Each element of the array is a subarray
containing information for one field. The subarrays have the following format:
aStruct[n][1]
aStruct[n][2]
aStruct[n][3]
aStruct[n][4]
==
==
==
==
cName
cType
nLength
nDecimals
If there is no database file in USE in the current work area, DBSTRUCT() returns an empty
array ({}).
nanoBase 1997 user manual
4197
DBUNLOCK()
DBUNLOCK() ⇒ NIL
DBUNLOCK() releases any record or file locks obtained by the current process for the
current work area. DBUNLOCK() is only meaningful on a shared database in a network
environment.
DBUNLOCKALL()
DBUNLOCKALL() ⇒ NIL
DBUNLOCKALL() releases any record or file locks obtained by the current process for
any work area. DBUNLOCKALL() is only meaningful on a shared database in a network
environment.
DBUSEAREA()
[
] [
] [
]
]
DBUSEAREA( lNewArea , cDriver , cName ,
lShared , lReadonly ) ⇒ NIL
[
lNewArea
cDriver
cName
xcAlias
lShared
lReadonly
[xcAlias],
is an optional logical value. A value of true (‘.T.’) selects the
lowest numbered unoccupied work area as the current work
area before the use operation. If lNewArea is false (‘.F.’)
or omitted, the current work area is used; if the work area is
occupied, it is closed first.
is an optional character value. If present, it specifies the name
of the database driver which will service the work area. If
cDriver is omitted, the current default driver is used.
specifies the name of the database (.dbf) file to be opened.
is an optional character value. If present, it specifies the alias
to be associated with the work area. The alias must constitute
a valid identifier. A valid xcAlias may be any legal identifier
(i.e., it must begin with an alphabetic character and may contain numeric or alphabetic characters and the underscore). If
xcAlias is omitted, a default alias is constructed from cName .
is an optional logical value. If present, it specifies whether the
database (.dbf) file should be accessible to other processes
on a network. A value of true (‘.T.’) specifies that other processes should be allowed access; a value of false (‘.F.’) specifies that the current process is to have exclusive access. If
lShared is omitted, the current global _SET_EXCLUSIVE
setting determines whether shared access is allowed.
is an optional logical value that specifies whether updates to
the work area are prohibited. A value of true (‘.T.’) prohibits
updates; a value of false (‘.F.’) permits updates. A value
of true (‘.T.’) also permits read-only access to the specified
database (.dbf) file. If lReadonly is omitted, the default value
is false (‘.F.’).
DBUSEAREA() opens the specified database (.DBF).
DBDELETE()
DELETED() ⇒ lDeleted
DELETED() returns true (‘.T.’) if the current record is marked for deletion; otherwise,
it returns false (‘.F.’). If there is no database file in USE in the current work area,
DELETED() returns false (‘.F.’).
DESCEND()
DESCEND(exp ) ⇒ ValueInverted
nanoBase 1997 user manual
4198
is any valid expression of character, date, logical, or numeric
type.
exp
DESCEND() returns an inverted expression of the same data type as the exp , except for
dates which return a numeric value. A DESCEND() of CHR(0) always returns CHR(0).
DEVOUT()
Device output
DEVOUT(exp ,
[cColorString])
exp
cColorString
⇒ NIL
is the value to display.
is an optional argument that defines the display color of exp .
DEVOUT() is a full-screen display function that writes the value of a single expression to
the current device at the current cursor or printhead position.
DEVOUTPICT()
Device output picture
DEVOUTPICT(exp , cPicture ,
[cColorString])
exp
cPicture
cColorString
⇒ NIL
is the value to display.
defines the formatting control for the display of exp .
is an optional argument that defines the display color of exp .
DEVOUTPICT() is a full-screen display function that writes the value of a single expression to the current device at the current cursor or printhead position.
DEVPOS()
Device position
DEVPOS(nRow , nCol ) ⇒ NIL
nRow , nCol
are the new row and column positions of the cursor or printhead.
DEVPOS() is an environment function that moves the screen or printhead depending on the
current DEVICE.
DIRECTORY()
DIRECTORY(cDirSpec ,
cDirSpec
cAttributes
[cAttributes])
⇒ aDirectory
identifies the drive, directory and file specification for the directory search. Wildcards are allowed in the file specification.
If cDirSpec is omitted, the default value is *.*.
specifies inclusion of files with special attributes in the returned information. cAttributes is a string containing one or
more of the following characters:
H Include hidden files
S Include system files
D Include directories
V Search for the DOS volume label only
Normal files are always included in the search, unless you
specify V.
nanoBase 1997 user manual
4199
DIRECTORY() returns an array of subarrays, with each subarray containing information
about each file matching cDirSpec . The subarray has the following structure:
aDirectory[n][1]
aDirectory[n][2]
aDirectory[n][3]
aDirectory[n][4]
aDirectory[n][5]
==
==
==
==
==
cName
cSize
dDate
cTime
cAttributes
If no files are found matching cDirSpec or if cDirSpec is an illegal path or file specification,
DIRECTORY() returns an empty ({}) array.
DISKSPACE()
[
]
DISKSPACE( nDrive ) ⇒ nBytes
is the number of the drive to query, where one is drive A, two
is B, three is C, etc. The default is the current DOS drive if
nDrive is omitted or specified as zero.
nDrive
DISKSPACE() returns the number of bytes of empty space on the specified disk drive as an
integer numeric value.
DISPBOX()
Display box
DISPBOX(nTop , nLeft , nBottom , nRight ,
cnBoxString , cColorString ) ⇒ NIL
[
] [
nTop , nLeft , nBottom , nRight
cnBoxString
cColorString
]
define the coordinates of the box.
is a numeric or character expression that defines the border
characters of the box. If specified as a numeric expression, a
value of 1 displays a single-line box and a value of 2 displays
a double-line box. All other numeric values display a singleline box. If cnBoxString is a character expression, it specifies
the characters to be used in drawing the box. This is a string
of eight border characters and a fill character.
defines the display color of the box that is drawn.
DISPBOX() is a screen function that draws a box at the specified display coordinates in the
specified color.
DISPOUT()
Display out
DISPOUT(exp ,
[cColorString])
exp
cColorString
cColorString
⇒ NIL
is the value to display.
is an optional argument that defines the display color of exp .
is a character expression containing the standard color setting.
DISPOUT() is a simple output function that writes the value of a single expression to the
display at the current cursor position. This function ignores the SET DEVICE setting; output always goes to the screen.
DOW()
Day of week
DOW(dDate) ⇒ nDay
nanoBase 1997 user manual
4200
is a date value to convert.
dDate
DOW() returns the day of the week as a number between zero and seven. The first day of
the week is one (Sunday) and the last day is seven (Saturday). If dDate is empty, DOW()
returns zero.
DTOC()
Date to character
DTOC(dDate) ⇒ cDate
is the date value to convert.
dDate
DTOC() returns a character string representation of a date value. The return value is formatted in the current date format. A null date returns a string of spaces equal in length to
the current date format.
DTOS()
Date to sort
DTOS(dDate) ⇒ cDate
is the date value to convert.
dDate
DTOS() returns a character string eight characters long in the form, yyyymmdd. When
dDate is a null date (CTOD("")), DTOS() returns a string of eight spaces.
EMPTY()
EMPTY(exp ) ⇒ lEmpty
exp
is an expression of any data type.
EMPTY() returns true (‘.T.’) if the expression results in an empty value; otherwise, it
returns false (‘.F.’):
Array
Character/Memo
Numeric
Date
Logical
NIL
{}
Spaces, tabs, CR/LF, or ""
0
CTOD("")
‘.F.’
NIL
EOF()
End of file
EOF() ⇒ lBoundary
EOF() returns true (‘.T.’) when an attempt is made to move the record pointer beyond the
last logical record in a database file; otherwise, it returns false (‘.F.’). If there is no database
file open in the current work area, EOF() returns false (‘.F.’). If the current database file
contains no records, EOF() returns true (‘.T.’).
EVAL()
Code block evaluation
EVAL(bBlock ,
[BlockArg_list ])
⇒ LastBlockValue
nanoBase 1997 user manual
4201
is the code block to evaluate.
is a list of arguments to send to the code block before it is
evaluated.
bBlock
BlockArg_list
To execute or evaluate a code block, call EVAL() with the block value and any parameters.
The parameters are supplied to the block when it is executed. Code blocks may be a series
of expressions separated by commas. When a code block is evaluated, the returned value is
the value of the last expression in the block.
EXP()
Exponent
EXP(nExponent ) ⇒ nAntilogarithm
is the natural logarithm for which a numeric value is to be
calculated.
nExponent
EXP() returns a numeric value that is equivalent to the value e raised to the specified power.
FCLOSE()
File close
FCLOSE(nHandle ) ⇒ lError
is the file handle obtained previously from FOPEN() or
FCREATE().
nHandle
FCLOSE() is a low-level file function that closes binary files and forces the associated
DOS buffers to be written to disk. If the operation fails, FCLOSE() returns false (‘.F.’).
FERROR() can then be used to determine the reason for the failure.
FCOUNT()
Field count
FCOUNT() ⇒ nFields
FCOUNT() returns the number of fields in the database file in the active alias as an integer
numeric value. If there is no database file open, FCOUNT() returns zero.
FCREATE()
Field create
FCREATE(cFile ,
cFile
nAttribute
[nAttribute ])
⇒ nHandle
is the name of the file to create. If the file already exists, its
length is truncated to zero without warning.
is the binary file attribute, the default value is zero.
nAttribute = 0 Normal (default)
nAttribute = 1 Read-only
nAttribute = 2 Hidden
nAttribute = 4 System
FCREATE() returns the DOS file handle number of the new binary file in the range of zero
to 65,535. If an error occurs, FCREATE() returns -1 and FERROR() is set to indicate an
error code.
nanoBase 1997 user manual
4202
FERASE()
File erase
FERASE(cFile ) ⇒ nSuccess
cFile
is the name (with or without path) of the file to be deleted
from disk.
FERASE() is a file function that deletes a specified file from disk. FERASE() returns -1 if
the operation fails and zero if it succeeds.
FERROR()
File error
FERROR() ⇒ nErrorCode
FERROR() returns the DOS error from the last file operation as an integer numeric value.
If there is no error, FERROR() returns zero.
nErrorCode value
0
2
3
4
5
6
8
15
19
21
23
29
30
32
33
Meaning
Successful
File not found
Path not found
Too many files open
Access denied
Invalid handle
Insufficient memory
Invalid drive specified
Attempted to write to a write-protected disk
Drive not ready
Data CRC error
Write fault
Read fault
Sharing violation
Lock Violation
FERROR() is a low-level file function that indicates a DOS error after a file function is
used.
FIELDBLOCK()
FIELDBLOCK(cFieldName ) ⇒ bFieldBlock
cFieldName
is the name of the field to which the set-get block will refer.
FIELDBLOCK() returns a code block that, when evaluated, sets (assigns) or gets (retrieves)
the value of the given field. If cFieldName does not exist in the current work area, FIELDBLOCK() returns NIL.
FIELDGET()
FIELDGET(nField ) ⇒ ValueField
nField
is the ordinal position of the field in the record structure for
the current work area.
FIELDGET() returns the value of the specified field. If nField does not correspond to the
position of any field in the current database file, FIELDGET() returns NIL.
nanoBase 1997 user manual
4203
FIELDNAME()
FIELDNAME(nPosition ) ⇒ cFieldName
nPosition
is the position of a field in the database file structure.
FIELDNAME() returns the name of the specified field as a character string. If nPosition
does not correspond to an existing field in the current database file or if no database file is
open in the current work area, FIELDNAME() returns a null string ("").
FIELDPOS()
Field position
FIELDPOS(cFieldName ) ⇒ nFieldPos
cFieldName
is the name of a field in the current or specified work area.
FIELDPOS() returns the position of the specified field within the list of fields associated
with the current or specified work area. If the current work area has no field with the specified name, FIELDPOS() returns zero.
FIELDPUT()
FIELDPUT(nField , expAssign ) ⇒ ValueAssigned
nField
expAssign
is the ordinal position of the field in the current database file.
is the value to assign to the given field. The data type of this
expression must match the data type of the designated field
variable.
FIELDPUT() is a database function that assigns expAssign to the field at ordinal position
nField in the current work area. This function allows you to set the value of a field using
its position within the database file structure rather than its field name.
FIELDWBLOCK()
Field work area block
FIELDWBLOCK(cFieldName , nWorkArea ) ⇒ bFieldWBlock
cFieldName
nWorkArea
is the name of the field specified as a character string.
is the work area number where the field resides specified as a
numeric value.
FIELDWBLOCK() returns a code block that, when evaluated, sets (assigns) or gets
(retrieves) the value of cFieldName in the work area designated by nWorkArea . If
cFieldName does not exist in the specified work area, FIELDWBLOCK() returns NIL.
FILE()
FILE(cFilespec ) ⇒ lExists
cFilespec
is in the current default directory and path. It is a standard file
specification that can include the wildcard characters * and ?
as well as a drive and path reference.
FILE() returns true (‘.T.’) if there is a match for any file matching the cFilespec pattern;
otherwise, it returns false (‘.F.’).
nanoBase 1997 user manual
4204
FLOCK()
File lock
FLOCK() ⇒ lSuccess
FLOCK() tries to lock the active alias and returns true (‘.T.’) if it succeeds; otherwise, it
returns false (‘.F.’).
FOPEN()
File open
FOPEN(cFile ,
[nMode])
cFile
nMode
⇒ nHandle
is the name of the file to open including the path if there is
one.
is the requested DOS open mode indicating how the opened
file is to be accessed. The open mode is composed of the sum
of two elements: the Open mode and the Sharing mode.
Open mode:
0 Open for reading (default)
1 Open for writing
2 Open for reading or writing
Sharing mode:
0 Compatibility mode (default)
16 Exclusive use
32 Prevent others from writing
48 Prevent others from reading
64 Allow others to read or write
FOPEN() returns the file handle of the opened file in the range of zero to 65,535. If an error
occurs, FOPEN() returns -1.
FOUND()
FOUND() ⇒ lSuccess
FOUND() returns true (‘.T.’) if the last search command was successful; otherwise, it
returns false (‘.F.’).
FREAD()
File read
FREAD(nHandle , @cBufferVar , nBytes ) ⇒ nBytes
nHandle
cBufferVar
nBytes
is the file handle obtained from FOPEN(), FCREATE(), or
predefined by DOS.
is the name of an existing and initialized character variable
used to store data read from the specified file. The length
of this variable must be greater than or equal to nBytes .
cBufferVar must be passed by reference and, therefore, must
be prefaced by the pass-by-reference operator (@).
is the number of bytes to read into the buffer.
FREAD() tries to read nBytes of the binary file nHandle inside cBufferVar . It returns the
number of bytes successfully read as an integer numeric value. A return value less than
nBytes or zero indicates end of file or some other read error.
FREADSTR()
File read string
nanoBase 1997 user manual
4205
FREADSTR(nHandle , nBytes ) ⇒ cString
nHandle
nBytes
is the file handle obtained from FOPEN(), FCREATE(), or
predefined by DOS.
is the number of bytes to read, beginning at the current DOS
file pointer position.
FREADSTR() returns a character string up to 65,535 (64K) bytes. A null return value
("") indicates an error or end of file. FREADSTR() is a low-level file function that reads
characters from an open binary file beginning with the current DOS file pointer position.
Characters are read up to nBytes or until a null character (CHR(0)) is encountered. All
characters are read including control characters except for CHR(0). The file pointer is then
moved forward nBytes . If nBytes is greater than the number of bytes from the pointer
position to the end of the file, the file pointer is positioned to the last byte in the file.
FRENAME()
File rename
FRENAME(cOldFile , cNewFile ) ⇒ nSuccess
cOldFile
cNewFile
is the name of the file to rename, including the file extension.
A drive letter and/or path name may also be included as part
of the filename.
is the new name of the file, including the file extension. A
drive letter and/or path name may also be included as part of
the name.
FRENAME() returns -1 if the operation fails and zero if it succeeds.
FSEEK()
File seek
FSEEK(nHandle , nOffset ,
nHandle
nOffset
nOrigin
nOrigin == 0
nOrigin == 1
nOrigin == 2
[nOrigin])
⇒ nPosition
is the file handle obtained from FOPEN(), FCREATE(), or
predefined by DOS.
is the number of bytes to move the file pointer from the position defined by nOrigin . It can be a positive or negative
number. A positive number moves the pointer forward, and
a negative number moves the pointer backward in the file.
defines the starting location of the file pointer before FSEEK()
is executed. The default value is zero, representing the beginning of file. If nOrigin is the end of file, nOffset must be zero
or negative.
Seek from beginning of file
Seek from the current pointer position
Seek from end of file
FSEEK() returns the new position of the file pointer relative to the beginning of file (position 0) as an integer numeric value. This value is without regard to the original position
of the file pointer. FSEEK() is a low-level file function that moves the file pointer forward
or backward in an open binary file without actually reading the contents of the specified
file. The beginning position and offset are specified as function arguments, and the new file
position is returned.
nanoBase 1997 user manual
4206
FWRITE()
File write
FWRITE(nHandle , cBuffer ,
[nBytes])
⇒ nBytesWritten
is the file handle obtained from FOPEN(), FCREATE(), or
predefined by DOS.
is the character string to write to the specified file.
indicates the number of bytes to write beginning at the current
file pointer position. If omitted, the entire content of cBuffer
is written.
nHandle
cBuffer
nBytes
FWRITE() returns the number of bytes written as an integer numeric value. If the value
returned is equal to nBytes , the operation was successful. If the return value is less than
nBytes or zero, either the disk is full or another error has occurred.
GETENV()
Get environment
GETENV(cEnvironmentVariable ) ⇒ cString
is the name of the DOS environment variable. When specifying this argument, you can use any combination of upper and
lowercase letters; GETENV() is not case- sensitive.
cEnvironmentVariable
GETENV() returns the contents of the specified DOS environment variable as a character
string. If the variable cannot be found, GETENV() returns a null string ("").
HARDCR()
Hard carriage return
HARDCR(cString ) ⇒ cConvertedString
is the character string or memo field to convert.
cString
HARDCR() is a memo function that replaces all soft carriage returns (CHR(141)) with
hard carriage returns (CHR(13)). It is used to display long character strings and memo
fields containing soft carriage returns with console commands.
HEADER()
HEADER() ⇒ nBytes
HEADER() returns the number of bytes in the header of the current database file as an
integer numeric value. If no database file is in use, HEADER() returns a zero (0).
I2BIN()
Integer to binary
I2BIN(nInteger ) ⇒ cBinaryInteger
nInteger
is an integer numeric value to convert. Decimal digits are truncated.
I2BIN() returns a two-byte character string containing a 16-bit binary integer.
IF()
[I]IF(lCondition ,
expTrue , expFalse ) ⇒ Value
nanoBase 1997 user manual
4207
is a logical expression to be evaluated.
is the value, a condition-expression, of any data type, returned
if lCondition is true (‘.T.’).
is the value, of any date type, returned if lCondition is false
(‘.F.’). This argument need not be the same data type as
expTrue .
lCondition
expTrue
expFalse
IF() returns the evaluation of expTrue if lCondition evaluates to true (‘.T.’) and expFalse
if it evaluates to false (‘.F.’).
INDEXEXT()
Index extention
INDEXEXT() ⇒ cExtension
INDEXEXT() returns the default index file extension by determining which database driver
is currently linked.
INDEXKEY()
INDEXKEY(nOrder ) ⇒ cKeyExp
is the ordinal position of the index in the list of index files
opened by the last USE...INDEX or SET INDEX TO command for the current work area. A zero value specifies the
controlling index, without regard to its actual position in the
list.
nOrder
INDEXKEY() returns the key expression of the specified index as a character string. If
there is no corresponding index or if no database file is open, INDEXKEY() returns a null
string ("").
INDEXORD()
Index order
INDEXORD() ⇒ nOrder
INDEXORD() returns an integer numeric value. The value returned is equal to the position
of the controlling index in the list of open indexes for the current work area. A value of zero
indicates that there is no controlling index and records are being accessed in natural order.
If no database file is open, INDEXORD() will also return a zero.
INKEY()
Input key
[
INKEY( nSeconds
nSeconds
])
⇒ nInkeyCode
specifies the number of seconds INKEY() waits for a keypress. You can specify the value in increments as small as
one-tenth of a second. Specifying zero halts the program until
a key is pressed. If nSeconds is omitted, INKEY() does not
wait for a keypress.
INKEY() returns an integer numeric value from -39 to 386, identifying the key extracted
from the keyboard buffer. If the keyboard buffer is empty, INKEY() returns zero. INKEY()
returns values for all ASCII characters, function, Alt+function, Ctrl+function, Alt+letter,
and Ctrl+letter key combinations.
4208
nInkeyCode value
5
24
19
4
1
6
18
3
397
401
26
2
29
23
31
30
408
416
411
413
407
415
409
417
13
32
27
10
379
309
284
387
257
422
399
405
406
398
400
5
420
311
330
334
22
7
8
9
271
402
403
127
404
418
419
nanoBase 1997 user manual
Key or key combination
[ Up arrow ], [ Ctrl ]+E
[ Down arrow ], [ Ctrl ]+X
[ Left arrow ], [ Ctrl ]+S
[ Right arrow ], [ Ctrl ]+D
[ Home ], [ Ctrl ]+A
[ End ], [ Ctrl ]+F
[ PgUp ], [ Ctrl ]+R
[ PgDn ], [ Ctrl ]+C
[ Ctrl ]+[ Up arrow ]
[ Ctrl ]+[ Down arrow ]
[ Ctrl ]+[ Left arrow ], [ Ctrl ]+Z
[ Ctrl ]+[ Right arrow ], [ Ctrl ]+B
[ Ctrl ]+[ Home ]
[ Ctrl ]+[ End ], [ Ctrl ]+W
[ Ctrl ]+[ PgUp ], [ Ctrl ]+Hyphen
[ Ctrl ]+[ PgDn ], [ Ctrl ]+^
[ Alt ]+[ Up arrow ]
[ Alt ]+[ Down arrow ]
[ Alt ]+[ Left arrow ]
[ Alt ]+[ Right arrow ]
[ Alt ]+[ Home ]
[ Alt ]+[ End ]
[ Alt ]+[ PgUp ]
[ Alt ]+[ PgDn ]
[ Enter ], [ Ctrl ]+M
Space bar
Esc
[ Ctrl ]+[ Enter ]
[ Ctrl ]+Print Screen
[ Ctrl ]+?
[ Alt ]+[ Enter ]
[ Alt ]+Equals
[ Alt ]+Esc
Keypad [ Alt ]+[ Enter ]
Keypad [ Ctrl ]+5
Keypad [ Ctrl ]+/
Keypad [ Ctrl ]+*
Keypad [ Ctrl ]+Keypad [ Ctrl ]++
Keypad [ Alt ]+5
Keypad [ Alt ]+/
Keypad [ Alt ]+*
Keypad [ Alt ]+Keypad [ Alt ]++
[ Ins ], [ Ctrl ]+V
[ Del ], [ Ctrl ]+G
[ Backspace ], [ Ctrl ]+H
[ Tab ], [ Ctrl ]+I
[ Shift ]+[ Tab ]
[ Ctrl ]+[ Ins ]
[ Ctrl ]+[ Del ]
[ Ctrl ]+[ Backspace ]
[ Ctrl ]+[ Tab ]
[ Alt ]+[ Ins ]
[ Alt ]+[ Del ]
nanoBase 1997 user manual
nInkeyCode value
270
421
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
286
304
302
288
274
289
290
291
279
292
293
294
306
305
280
281
272
275
287
276
278
303
273
301
277
300
376
4209
Key or key combination
[ Alt ]+[ Backspace ]
[ Alt ]+[ Tab ]
[ Ctrl ]+A, [ Home ]
[ Ctrl ]+B, [ Ctrl ]+[ Right arrow ]
[ Ctrl ]+C, [ PgDn ], [ Ctrl ]+[ ScrollLock ]
[ Ctrl ]+D, [ Right arrow ]
[ Ctrl ]+E, [ Up arrow ]
[ Ctrl ]+F, [ End ]
[ Ctrl ]+G, [ Del ]
[ Ctrl ]+H, [ Backspace ]
[ Ctrl ]+I, [ Tab ]
[ Ctrl ]+J
[ Ctrl ]+K
[ Ctrl ]+L
[ Ctrl ]+M, Return
[ Ctrl ]+N
[ Ctrl ]+O
[ Ctrl ]+P
[ Ctrl ]+Q
[ Ctrl ]+R, [ PgUp ]
[ Ctrl ]+S, [ Left arrow ]
[ Ctrl ]+T
[ Ctrl ]+U
[ Ctrl ]+V, [ Ins ]
[ Ctrl ]+W, [ Ctrl ]+[ End ]
[ Ctrl ]+X, [ Down arrow ]
[ Ctrl ]+Y
[ Ctrl ]+Z, [ Ctrl ]+[ Left arrow ]
[ Alt ]+A
[ Alt ]+B
[ Alt ]+C
[ Alt ]+D
[ Alt ]+E
[ Alt ]+F
[ Alt ]+G
[ Alt ]+H
[ Alt ]+I
[ Alt ]+J
[ Alt ]+K
[ Alt ]+L
[ Alt ]+M
[ Alt ]+N
[ Alt ]+O
[ Alt ]+P
[ Alt ]+Q
[ Alt ]+R
[ Alt ]+S
[ Alt ]+T
[ Alt ]+U
[ Alt ]+V
[ Alt ]+W
[ Alt ]+X
[ Alt ]+Y
[ Alt ]+Z
[ Alt ]+1
nanoBase 1997 user manual
4210
nInkeyCode value
Key or key combination
377
378
379
380
381
382
383
384
385
28
-1
-2
-3
-4
-5
-6
-7
-8
-9
-40
-41
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-44
-45
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-46
-47
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
[ Alt ]+2
[ Alt ]+3
[ Alt ]+4
[ Alt ]+5
[ Alt ]+6
[ Alt ]+7
[ Alt ]+8
[ Alt ]+9
[ Alt ]+0
F1, [ Ctrl ]+[ Backslash ]
F2
F3
F4
F5
F6
F7
F8
F9
F10
F11
F12
[ Ctrl ]+F1
[ Ctrl ]+F2
[ Ctrl ]+F4
[ Ctrl ]+F3
[ Ctrl ]+F5
[ Ctrl ]+F6
[ Ctrl ]+F7
[ Ctrl ]+F8
[ Ctrl ]+F9
[ Ctrl ]+F10
[ Ctrl ]+F11
[ Ctrl ]+F12
[ Alt ]+F1
[ Alt ]+F2
[ Alt ]+F3
[ Alt ]+F4
[ Alt ]+F5
[ Alt ]+F6
[ Alt ]+F7
[ Alt ]+F8
[ Alt ]+F9
[ Alt ]+F10
[ Alt ]+F11
[ Alt ]+F12
[ Shift ]+F1
[ Shift ]+F2
[ Shift ]+F3
[ Shift ]+F4
[ Shift ]+F5
[ Shift ]+F6
[ Shift ]+F7
[ Shift ]+F8
[ Shift ]+F9
[ Shift ]+F10
nanoBase 1997 user manual
4211
nInkeyCode value
Key or key combination
-42
-43
[ Shift ]+F11
[ Shift ]+F12
INT()
Integer
INT(nExp ) ⇒ nInteger
is a numeric expression to convert to an integer.
nExp
INT() is a numeric function that converts a numeric value to an integer by truncating all
digits to the right of the decimal point. INT() is useful in operations where the decimal
portion of a number is not needed.
ISALPHA()
ISALPHA(cString ) ⇒ lBoolean
is the character string to examine.
cString
ISALPHA() returns true (‘.T.’) if the first character in cString is alphabetic; otherwise, it
returns false (‘.F.’).
ISCOLOR()
ISCOLOR()
| ISCOLOUR()
⇒ lBoolean
ISCOLOR() returns true (‘.T.’) if there is a color graphics card installed; otherwise, it
returns false (‘.F.’).
ISDIGIT()
ISDIGIT(cString ) ⇒ lBoolean
cString
is the character string to examine.
ISDIGIT() returns true (‘.T.’) if the first character of the character string is a digit between
zero and nine; otherwise, it returns false (‘.F.’).
ISLOWER()
ISLOWER(cString ) ⇒ lBoolean
cString
is the character string to examine.
ISLOWER() returns true (‘.T.’) if the first character of the character string is a lowercase
letter; otherwise, it returns false (‘.F.’).
ISPRINTER()
ISPRINTER() ⇒ lReady
ISPRINTER() returns true (‘.T.’) if ‘LPT1:’ is ready; otherwise, it returns false (‘.F.’).
ISUPPER()
ISUPPER(cString ) ⇒ lBoolean
cString
is the character string to examine.
nanoBase 1997 user manual
4212
ISUPPER() returns true (‘.T.’) if the first character is an uppercase letter; otherwise, it
returns false (‘.F.’).
L2BIN()
Long to binary
L2BIN(nExp ) ⇒ cBinaryInteger
is the numeric value to convert. Decimal digits are truncated.
nExp
L2BIN() returns a four-byte character string formatted as a 32- bit binary integer.
LASTKEY()
LASTKEY() ⇒ nInkeyCode
LASTKEY() is a keyboard function that reports the INKEY() value of the last key fetched
from the keyboard buffer by the INKEY() function, or a wait state. LASTKEY() retains its
current value until another key is fetched from the keyboard buffer.
LASTREC()
Last record
LASTREC() ⇒ nRecords
LASTREC() returns the number of physical records in the active alias as an integer numeric
value.
LEFT()
LEFT(cString , nCount ) ⇒ cSubString
is a character string from which to extract characters.
is the number of characters to extract.
cString
nCount
LEFT() returns the leftmost nCount characters of cString as a character string. If nCount
is negative or zero, LEFT() returns a null string (""). If nCount is larger than the length of
the character string, LEFT() returns the entire string.
LEN()
Length
LEN(cString
|
aTarget ) ⇒ nCount
cString
aTarget
is the character string to count.
is the array to count.
LEN() returns the length of a character string or the number of elements in an array as an
integer numeric value.
LOG()
LOG(nExp ) ⇒ nNaturalLog
nExp
is a numeric value greater than zero to convert to its natural
logarithm.
LOG() returns the natural logarithm as a numeric value. If nExp is less than or equal to
zero, LOG() returns a numeric overflow (displayed as a row of asterisks).
nanoBase 1997 user manual
4213
LOWER()
LOWER(cString ) ⇒ cLowerString
is a character string to convert to lowercase.
cString
LOWER() returns a copy of cString with all alphabetic characters converted to lowercase.
LTRIM()
Left trim
LTRIM(cString ) ⇒ cTrimString
is the character string to copy without leading spaces.
cString
LTRIM() returns a copy of cString with the leading spaces removed.
LUPDATE()
Last update
LUPDATE() ⇒ dModification
LUPDATE() returns the date of last change to the open database file in the current work
area.
MAX()
MAX(nExp1 , nExp2 ) ⇒ nLarger
MAX(dExp1 , dExp2 ) ⇒ dLarger
are the numeric values to compare.
are the date values to compare.
nExp1 , nExp2
dExp1 , dExp2
MAX() returns the larger of the two arguments. The value returned is the same type as the
arguments.
MAXCOL()
Max column
MAXCOL() ⇒ nColumn
MAXCOL() returns the column number of the rightmost visible column for display purposes.
MAXROW()
MAXROW() ⇒ nRow
MAXROW() returns the row number of the bottommost visible row for display purposes.
MEMOEDIT()
[
]
] [ ]
] [
]
]
]
]
]
]
]
]
]
MEMOEDIT( cString ,
nTop , nLeft ,
nBottom , nRight ,
lEditMode ,
cUserFunction ,
nLineLength ,
nTabSize ,
nTextBufferRow ,
nTextBufferColumn ,
nWindowRow ,
nWindowColumn ) ⇒ cTextBuffer
[
[
[
[
[
[
[
[
[
[
nanoBase 1997 user manual
4214
cString
nTop , nLeft , nBottom , nRight
lEditMode
cUserFunction
nLineLength
nTabSize
nTextBufferRow ,
nTextBufferColumn
nWindowRow , nWindowColumn
is the character string or memo field to copy to the MEMOEDIT() text buffer.
are window coordinates. The default coordinates are 0, 0,
MAXROW(), and MAXCOL().
determines whether the text buffer can be edited or merely
displayed. If not specified, the default value is true (‘.T.’).
is the name of a user-defined function that executes when the
user presses a key not recognized by MEMOEDIT() and when
no keys are pending in the keyboard buffer.
determines the length of lines displayed in the MEMOEDIT()
window. If a line is greater than nLineLength , it is word
wrapped to the next line in the MEMOEDIT() window. The
default line length is (nRight - nLeft ).
determines the size of a tab character to insert when the user
presses Tab. The default is four.
define the display position of the cursor within the text buffer
when MEMOEDIT() is invoked. nTextBufferRow begins
with one and nTextBufferColumn begins with zero. Default
is the beginning of MEMOEDIT() window.
define the initial position of the cursor within the MEMOEDIT() window. Row and column positions begin with zero.
If these arguments are not specified, the initial window position is row zero and the current cursor column position.
MEMOEDIT() is a user interface and general purpose text editing function that edits memo
fields and long character strings. Editing occurs within a specified window region placed
anywhere on the screen.
[ Uparrow ]/[ Ctrl ]+E
[ Dnarrow ]/[ Ctrl ]+X
[ Leftarrow ]/[ Ctrl ]+S
[ Rightarrow ]/[ Ctrl ]+D
[ Ctrl ]-[ Leftarrow ]/[ Ctrl ]+A
[ Ctrl ]-[ Rightarrow ]/[ Ctrl ]+F
[ Home ]
[ End ]
[ Ctrl ]+[ Home ]
[ Ctrl ]+[ End ]
[ PgUp ]
[ PgDn ]
[ Ctrl ]+[ PgUp ]
[ Ctrl ]+[ PgDn ]
[ Return ]
[ Delete ]
[ Backspace ]
[ Tab ]
Printable characters
[ Ctrl ]+Y
[ Ctrl ]+T
[ Ctrl ]+B
[ Ctrl ]+V/[ Ins ]
[ Ctrl ]+W
[ Esc ]
Move up one line
Move down one line
Move left one character
Move right one character
Move left one word
Move right one word
Move to beginning of current line
Move to end of current line
Move to beginning of current window
Move to end of current window
Move to previous edit window
Move to next edit window
Move to beginning of memo
Move to end of memo
Move to beginning of next line
Delete character at cursor
Delete character to left of cursor
Insert tab character or spaces
Insert character
Delete the current line
Delete word right
Reform paragraph
Toggle insert mode
Finish editing with save
Abort edit and return original
nanoBase 1997 user manual
4215
MEMOLINE()
MEMOLINE(cString ,
nLineLength ,
nLineNumber ,
nTabSize ,
lWrap ) ⇒ cLine
[
[
[
[
]
]
]
]
is the memo field or character string from which to extract a
line of text.
specifies the number of characters per line and can be between
four and 254 . If not specified, the default line length is 79.
is the line number to extract. If not specified, the default value
is one.
defines the tab size. If not specified, the default value is four.
toggles word wrap on and off. Specifying true (‘.T.’) toggles
word wrap on; false (‘.F.’) toggles it off. If not specified, the
default value is true (‘.T.’).
cString
nLineLength
nLineNumber
nTabSize
lWrap
MEMOLINE() returns the line of text specified by nLineNumber in cString as a character
string. If the line has fewer characters than the indicated length, the return value is padded
with blanks. If the line number is greater than the total number of lines in cString , MEMOLINE() returns a null string (""). If lWrap is true (‘.T.’) and the indicated line length
breaks the line in the middle of a word, that word is not included as part of the return value
but shows up at the beginning of the next line extracted with MEMOLINE(). If lWrap is
false (‘.F.’), MEMOLINE() returns only the number of characters specified by the line
length. The next line extracted by MEMOLINE() begins with the character following the
next hard carriage return, and all intervening characters are not processed.
MEMOREAD()
MEMOREAD(cFile ) ⇒ cString
is the name of the file to read from disk. It must include an
extension if there is one, and can optionally include a path.
cFile
MEMOREAD() returns the contents of a text file as a character string.
MEMORY()
MEMORY(nExp ) ⇒ nKbytes
is a numeric value that determines the type of value MEMORY() returns.
nExp
MEMORY() returns an integer numeric value representing the amount of memory available.
Estimated total space available for character values
Largest contiguous block available for character values
Area available for RUN commands
MEMORY(0)
MEMORY(1)
MEMORY(2)
MEMOTRAN()
Memo translate
MEMOTRAN(cString ,
cReplaceHardCR ,
cReplaceSoftCR ) ⇒ cNewString
[
[
]
]
nanoBase 1997 user manual
4216
is the character string or memo field to search.
is the character to replace a hard carriage return/linefeed pair
with. If not specified, the default value is a semicolon (;).
is the character to replace a soft carriage return/linefeed pair
with. If not specified, the default value is a space.
cString
cReplaceHardCR
cReplaceSoftCR
MEMOTRAN() returns a copy of cString with the specified carriage return/linefeed pairs
replaced.
MEMOWRIT()
Memo write
MEMOWRIT(cFile , cString ) ⇒ lSuccess
is the name of the target disk file including the file extension
and optional path and drive designator.
is the character string or memo field to write to cFile .
cFile
cString
MEMOWRIT() is a memo function that writes a character string or memo field to a disk file.
If a path is not specified, MEMOWRIT() writes cFile to the current DOS directory and not
the current DEFAULT directory. If cFile already exists, it is overwritten. MEMOWRIT()
returns true (‘.T.’) if the writing operation is successful; otherwise, it returns false (‘.F.’).
MEMVARBLOCK()
MEMVARBLOCK(cMemvarName ) ⇒ bMemvarBlock
is the name of the variable referred to by the set-get block,
specified as a character string.
cMemvarName
MEMVARBLOCK() returns a code block that when evaluated sets (assigns) or gets (retrieves) the value of the given memory variable. If cMemvarName does not exist, MEMVARBLOCK() returns NIL.
MIN()
MIN(nExp1 , nExp2 ) ⇒ nSmaller
MIN(dExp1 , dExp2 ) ⇒ dSmaller
are the numeric values to compare.
are the date values to compare.
nExp1 , nExp2
dExp1 , dExp2
MIN() returns the smaller of the two arguments. The value returned is the same data type
as the arguments.
MLCOUNT()
Memo line count
[
] [
]
MLCOUNT(cString , nLineLength ,
nTabSize , lWrap ) ⇒ nLines
[
cString
nLineLength
nTabSize
]
is the character string or memo field to count.
specifies the number of characters per line and can range from
four to 254 . If not specified, the default line length is 79.
defines the tab size. If not specified, the default value is four.
nanoBase 1997 user manual
4217
toggles word wrap on and off. Specifying true (‘.T.’) toggles
word wrap on; false (‘.F.’) toggles it off. If not specified, the
default value is true (‘.T.’).
lWrap
MLCOUNT() returns the number of lines in cString depending on the nLineLength , the
nTabSize , and whether word wrapping is on or off.
MLCTOPOS()
Memo line column to position
MLCTOPOS(cText , nWidth , nLine ,
nCol , nTabSize , lWrap ) ⇒ nPosition
[
] [
]
is the text string to scan.
is the line length formatting width.
is the line number counting from 1.
is the column number counting from 0.
is the number of columns between tab stops. If not specified,
the default is 4.
is the word wrap flag. If not specified, the default is true
(‘.T.’).
cText
nWidth
nLine
nCol
nTabSize
lWrap
MLCTOPOS() returns the byte position within cText counting from 1.
MLPOS()
Memo line position
MLPOS(cString , nLineLength ,
nLine , nTabSize , lWrap ) ⇒ nPosition
[
] [
]
is a character string or memo field.
specifies the number of characters per line.
specifies the line number.
defines the tab size. The default is four.
toggles word wrap on and off. Specifying true (‘.T.’) toggles
word wrap on, and false (‘.F.’) toggles it off. The default is
true (‘.T.’).
cString
nLineLength
nLine
nTabSize
lWrap
MLPOS() returns the character position of nLine in cString as an integer numeric value.
If nLine is greater than the number of lines in cString , MLPOS() returns the length of
cString .
MONTH()
MONTH(dDate) ⇒ nMonth
is the date value to convert.
dDate
MONTH() returns an integer numeric value in the range of zero to 12. Specifying a null
date (CTOD("")) returns zero.
MPOSTOLC()
Memo position to line column
MPOSTOLC(cText , nWidth , nPos ,
nTabSize , lWrap ) ⇒ aLineColumn
[
cText
] [
]
is a text string.
nanoBase 1997 user manual
4218
is the length of the formatted line.
is the byte position within text counting from one.
is the number of columns between tab stops. If not specified,
the default is four.
is the word wrap flag. If not specified, the default is true
(‘.T.’).
nWidth
nPos
nTabSize
lWrap
MPOSTOLC() returns an array containing the line and the column values for the specified
byte position, nPos . MPOSTOLC() is a memo function that determines the formatted line
and column corresponding to a particular byte position within cText . Note that the line
number returned is one-relative, the column number is zero-relative. This is compatible
with MEMOEDIT(). nPos is one-relative, compatible with AT(), RAT(), and other string
functions.
NETERR()
Net error
[
]
NETERR( lNewError ) ⇒ lError
lNewError
if specified sets the value returned by NETERR() to the specified status. lNewError can be either true (‘.T.’) or false
(‘.F.’). Setting NETERR() to a specified value allows the
runtime error handler to control the way certain file errors are
handled.
NETERR() returns true (‘.T.’) if a USE or APPEND BLANK fails. The initial value of
NETERR() is false (‘.F.’). If the current process is not running under a network operating
system, NETERR() always returns false (‘.F.’).
NETNAME()
NETNAME() ⇒ cWorkstationName
NETNAME() returns the workstation identification as a character string up to 15 characters
in length. If the workstation identification was never set or the application is not operating
under the IBM PC Network, it returns a null string ("").
NEXTKEY()
NEXTKEY() ⇒ nInkeyCode
NEXTKEY() returns an integer numeric value ranging from -39 to 386. If the keyboard
buffer is empty, NEXTKEY() returns zero. If SET TYPEAHEAD is zero, NEXTKEY()
always returns zero. NEXTKEY() is like the INKEY() function, but differs in one fundamental respect. INKEY() removes the pending key from the keyboard buffer and updates
LASTKEY() with the value of the key. NEXTKEY(), by contrast, reads, but does not remove the key from the keyboard buffer and does not update LASTKEY().
NOSNOW()
NOSNOW(lToggle ) ⇒ NIL
lToggle
is a logical value that toggles the current state of snow suppression. A value of true (‘.T.’) enables the snow suppression
on, while a value of false (‘.F.’) disables snow suppression.
NOSNOW() is used to suppress snow on old CGA monitors.
nanoBase 1997 user manual
4219
ORDBAGEXT()
ORDBAGEXT() ⇒ cBagExt
ORDBAGEXT() returns a character expression that is the default Order Bag extension of
the current work area. cBagExt is determined by the RDD active in the current work area.
ORDBAGNAME()
ORDBAGNAME(nOrder
|
cOrderName ) ⇒ cOrderBagName
is an integer that identifies the position in the Order List of the
target Order whose Order Bag name is sought.
is a character string that represents the name of the target Order whose Order Bag name is sought.
nOrder
cOrderName
ORDBAGNAME() returns a character string, the Order Bag name of the specific Order.
ORDCREATE()
[
]
ORDCREATE(cOrderBagName , cOrderName , cExpKey ,
lUnique ) ⇒ NIL
[
[bExpKey],
]
is the name of a disk file containing one or more Orders.
is the name of the Order to be created.
is an expression that returns the key value to place in the Order
for each record in the current work area. The maximum length
of the index key expression is determined by the database
driver.
is a code block that evaluates to a key value that is placed in
the Order for each record in the current work area.
specifies whether a unique Order is to be created. Default is
the current global _SET_UNIQUE setting.
cOrderBagName
cOrderName
cExpKey
bExpKey
lUnique
ORDCREATE() is an Order management function that creates an Order in the current work
area. It works like DBCREATEINDEX() except that it lets you create Orders in RDDs that
recognize multiple Order Bags.
ORDDESTROY()
ORDDESTROY(cOrderName
[,
cOrderBagName
])
⇒ NIL
is the name of the Order to be removed from the current or
specified work area.
is the name of a disk file containing one or more Orders.
cOrderName
cOrderBagName
ORDDESTROY() is an Order management function that removes a specified Order from
multiple-Order Bags. ORDDESTROY() is not supported for DBFNDX and DBFNTX.
ORDFOR()
ORDFOR(cOrderName
cOrderName
nOrder
cOrderBagName
|
nOrder
[,
cOrderBagName
])
⇒ cForExp
is the name of the target Order, whose cForExp is sought.
is an integer that identifies the position in the Order List of the
target Order whose cForExp is sought.
is the name of an Order Bag containing one or more Orders.
ORDFOR() returns a character expression, cForExp, that represents the FOR condition of
nanoBase 1997 user manual
4220
the specified Order. If the Order was not created using the FOR clause the return value will
be an empty string (""). If the database driver does not support the FOR condition, it may
either return an empty string ("") or raise an "unsupported function" error, depending on
the driver.
ORDKEY()
ORDKEY(cOrderName
|
nOrder
[,
cOrderBagName
])
⇒ cExpKey
is the name of an Order, a logical ordering of a database.
is an integer that identifies the position in the Order List of the
target Order whose cExpKey is sought.
is the name of a disk file containing one or more Orders.
cOrderName
nOrder
cOrderBagName
ORDKEY() is an Order management function that returns a character expression, cExpKey,
that represents the key expression of the specified Order.
ORDLISTADD()
ORDLISTADD(cOrderBagName
[,
]
cOrderName ) ⇒ NIL
is the name of a disk file containing one or more Orders.
the name of the specific Order from the Order Bag to be added
to the Order List of the current work area. If you do not specify cOrderName , all orders in the Order Bag are added to the
Order List of the current work area.
cOrderBagName
cOrderName
ORDLISTADD() is an Order management function that adds the contents of an Order Bag
, or a single Order in an Order Bag, to the Order List. Any Orders already associated with
the work area continue to be active. If the newly opened Order Bag contains the only Order
associated with the work area, it becomes the controlling Order; otherwise, the controlling
Order remains unchanged.
ORDLISTCLEAR()
ORDLISTCLEAR() ⇒ NIL
ORDLISTCLEAR() is an Order management function that removes all Orders from the
Order List for the current work area.
ORDLISTREBUILD()
ORDLISTREBUILD() ⇒ NIL
ORDLISTREBUILD() is an Order management function that rebuilds all the orders in the
current Order List.
ORDNAME()
[
ORDNAME(nOrder ,cOrderBagName
])
⇒ cOrderName
is an integer that identifies the position in the Order List of the
target Order whose database name is sought.
is the name of a disk file containing one or more Orders.
nOrder
cOrderBagName
ORDNAME() returns the name of the specified Order in the current Order List or the specified Order Bag if opened in the Current Order list.
ORDNUMBER()
ORDNUMBER(cOrderName
[,
cOrderBagName
])
⇒ nOrderNo
nanoBase 1997 user manual
4221
the name of the specific Order whose position in the Order
List is sought.
is the name of a disk file containing one or more Orders.
cOrderName
cOrderBagName
ORDNUMBER() returns nOrderNo, an integer that represents the position of the specified
Order in the Order List.
ORDSETFOCUS()
[
] [,cOrderBagName ])
ORDSETFOCUS( cOrderName | nOrder
⇒ cPrevOrderNameInFocus
cOrderName
nOrder
cOrderBagName
is the name of the selected Order, a logical ordering of a
database.
is a number representing the position in the Order List of the
selected Order.
is the name of a disk file containing one or more Orders.
ORDSETFOCUS() is an Order management function that returns the Order Name of the
previous controlling Order and optionally sets the focus to an new Order.
OS()
OS() ⇒ cOsName
OS() returns the operating system name as a character string.
OUTERR()
Output error
OUTERR(exp_list ) ⇒ NIL
is a list of values to display and can consist of any combination of data types including memo.
exp_list
OUTERR() is identical to OUTSTD() except that it writes to the standard error device
rather than the standard output device. Output sent to the standard error device bypasses
the console and output devices as well as any DOS redirection. It is typically used to log
error messages in a manner that will not interfere with the standard screen or printer output.
OUTSTD()
Output standard
OUTSTD(exp_list ) ⇒ NIL
is a list of values to display and can consist of any combination of data types including memo.
exp_list
OUTSTD() is a simple output function similar to QOUT(), except that it writes to the
STDOUT device (instead of to the console output stream).
PAD?()
[cFillChar])
nLength , [cFillChar ])
nLength , [cFillChar ])
PADL(exp , nLength ,
⇒ cPaddedString
PADC(exp ,
⇒ cPaddedString
PADR(exp ,
⇒ cPaddedString
nanoBase 1997 user manual
4222
is a character, numeric, or date value to pad with a fill character.
is the length of the character string to return.
is the character to pad exp with. If not specified, the default is
a space character.
exp
nLength
cFillChar
PADC(), PADL(), and PADR() are character functions that pad character, date, and numeric
values with a fill character to create a new character string of a specified length. PADC()
centers exp within nLength adding fill characters to the left and right sides; PADL() adds
fill characters on the left side; and PADR() adds fill characters on the right side.
PCOL()
Printed column
PCOL() ⇒ nColumn
PCOL() returns an integer numeric value representing the last printed column position, plus
one. The beginning column position is zero.
PROW()
Printed row
PROW() ⇒ nRow
PROW() returns an integer numeric value that represents the number of the current line sent
to the printer. The beginning row position is zero.
QOUT()
[
]
QQOUT([exp_list])
QOUT( exp_list ) ⇒ NIL
⇒ NIL
is a comma-separated list of expressions (of any data type
other than array or block) to display to the console. If no argument is specified and QOUT() is specified, a carriage return/linefeed pair is displayed. If QQOUT() is specified without arguments, nothing displays.
exp_list
QOUT() and QQOUT() are console functions. They display the results of one or more
expressions to the console. QOUT() outputs carriage return and linefeed characters before
displaying the results of exp_list . QQOUT() displays the results of exp_list at the current
ROW() and COL() position. When QOUT() and QQOUT() display to the console, ROW()
and COL() are updated.
RAT()
Right at
RAT(cSearch , cTarget ) ⇒ nPosition
is the character string to locate.
is the character string to search.
cSearch
cTarget
RAT() returns the position of cSearch within cTarget as an integer numeric value, starting
the search from the right. If cSearch is not found, RAT() returns zero.
RDDLIST()
[
RDDLIST( nRDDType
])
⇒ aRDDList
nanoBase 1997 user manual
4223
is an integer that represents the type of the RDD you wish to
list.
nRDDType = 1 Full RDD implementation
nRDDType = 2 Import/Export only driver.
nRDDType
RDDLIST() returns a one-dimensional array of the RDD names registered with the application as nRDDType .
RDDNAME()
RDDNAME() ⇒ cRDDName
RDDNAME() returns a character string, cRDDName, the registered name of the active
RDD in the current or specified work area.
RDDSETDEFAULT()
[
RDDSETDEFAULT( cNewDefaultRDD
])
⇒ cPreviousDefaultRDD
is a character string, the name of the RDD that is to be made
the new default RDD in the application.
cNewDefaultRDD
RDDSETDEFAULT() is an RDD function that sets or returns the name of the previous
default RDD driver and, optionally, sets the current driver to the new RDD driver specified
by cNewDefaultRDD .
READINSERT()
[
]
READINSERT( lToggle ) ⇒ lCurrentMode
lToggle
toggles the insert mode on or off. True (‘.T.’) turns insert on,
while false (‘.F.’) turns insert off. The default is false (‘.F.’)
or the last user-selected mode in READ or MEMOEDIT().
READINSERT() returns the current insert mode state as a logical value.
READMODAL()
READMODAL(aGetList ) ⇒ NIL
aGetList
is an array containing a list of Get objects to edit.
READMODAL() is like the READ command, but takes a GetList array as an argument and
does not reinitialize the GetList array when it terminates. The GET system is implemented
using a public array called GetList. Each time an @...GET command executes, it creates a
Get object and adds to the currently visible GetList array. The standard READ command is
preprocessed into a call to READMODAL() using the GetList array as its argument.
READVAR()
READVAR() ⇒ cVarName
READVAR() returns the name of the variable associated with the current Get object or
the variable being assigned by the current MENU TO command as an uppercase character
string.
RECNO()
Record number
RECNO() ⇒ nRecord
nanoBase 1997 user manual
4224
RECNO() returns the current record number as an integer numeric value. If the work area
contains a database file with zero records, RECNO() returns one, BOF() and EOF() both
return true (‘.T.’), and LASTREC() returns zero. If the record pointer is moved past the
last record, RECNO() returns LASTREC() + 1 and EOF() returns true (‘.T.’). If an attempt
is made to move before the first record, RECNO() returns the record number of the first
logical record in the database file and BOF() returns true (‘.T.’). If no database file is
open, RECNO() will return a zero.
RECSIZE()
Record size
RECSIZE() ⇒ nBytes
RECSIZE() returns, as a numeric value, the record length, in bytes, of the database file open
in the current work area. RECSIZE() returns zero if no database file is open.
REPLICATE()
REPLICATE(cString , nCount ) ⇒ cRepeatedString
is the character string to repeat.
is the number of times to repeat cString .
cString
nCount
REPLICATE() returns a character string. Specifying a zero as the nCount argument returns
a null string ("").
RESTSCREEN()
Restore screen
[ ] [ ]
] [
]
RESTSCREEN( nTop , nLeft ,
nBottom , nRight , cScreen ) ⇒ NIL
[
nTop , nLeft , nBottom , nRight
cScreen
define the coordinates of the screen information contained in
cScreen . If the cScreen was saved without coordinates to preserve the entire screen, no screen coordinates are necessary
with RESTSCREEN().
is a character string containing the saved screen region.
RESTSCREEN() is a screen function that redisplays a screen region saved with SAVESCREEN(). The target screen location may be the same as or different than the original
location when the screen region was saved.
RIGHT()
RIGHT(cString , nCount ) ⇒ cSubString
cString
nCount
is the character string from which to extract characters.
is the number of characters to extract.
RIGHT() returns the rightmost nCount characters of cString . If nCount is zero, RIGHT()
returns a null string (""). If nCount is negative or larger than the length of the character
string, RIGHT() returns cString .
RLOCK()
Record lock
RLOCK() ⇒ lSuccess
RLOCK() is a network function that locks the current record, preventing other users from
nanoBase 1997 user manual
4225
updating the record until the lock is released. RLOCK() provides a shared lock, allowing
other users read-only access to the locked record while allowing only the current user to
modify it. A record lock remains until another record is locked, an UNLOCK is executed,
the current database file is closed, or an FLOCK() is obtained on the current database file.
ROUND()
ROUND(nNumber , nDecimals ) ⇒ nRounded
is the numeric value to round.
defines the number of decimal places to retain. Specifying a
negative nDecimals value rounds whole number digits.
nNumber
nDecimals
ROUND() is a numeric function that rounds nNumber to the number of places specified by
nDecimals . Specifying a zero or negative value for nDecimals allows rounding of whole
numbers. A negative nDecimals indicates the number of digits to the left of the decimal
point to round. Digits between five to nine, inclusive, are rounded up. Digits below five are
rounded down.
ROW()
ROW() ⇒ nRow
ROW() returns the cursor row position as an integer numeric value. The range of the return
value is zero to MAXROW().
RTRIM()
Right trim
[R]TRIM(cString )
⇒ cTrimString
is the character string to copy without trailing spaces.
cString
RTRIM() returns a copy of cString with the trailing spaces removed. If cString is a null
string ("") or all spaces, RTRIM() returns a null string ("").
SAVESCREEN()
[ ] [ ]
] [
]
SAVESCREEN( nTop , nLeft ,
nBottom , nRight ) ⇒ cScreen
[
nTop , nLeft , nBottom , nRight
define the coordinates of the screen region to save. Default is
the entire screen.
SAVESCREEN() returns the specified screen region as a character string.
SCROLL()
[
] [nLeft ],
] [nRight ], [nVert] [nHoriz])
SCROLL( nTop ,
nBottom ,
[
⇒ NIL
nTop , nLeft , nBottom , nRight define the scroll region coordinates.
nVert
defines the number of rows to scroll, vertically. A positive
value scrolls up the specified number of rows. A negative
value scrolls down the specified number of rows. A value of
zero disables vertical scrolling. If nVert is not specified, zero
is assumed.
nanoBase 1997 user manual
4226
defines the number of rows to scroll horizontally. A positive
value scrolls left the specified number of columns. A negative
value scrolls right the specified number of columns. A value
of zero disables horizontal scrolling. If nHoriz is not specified, zero is assumed. If you supply neither nVert or nHoriz
parameters to SCROLL(), the area specified by the first four
parameters will be blanked.
nHoriz
SCROLL() is a screen function that scrolls a screen region up or down a specified number
of rows. When a screen scrolls up, the first line of the region is erased, all other lines are
moved up, and a blank line is displayed in the current standard color on the bottom line
of the specified region. If the region scrolls down, the operation is reversed. If the screen
region is scrolled more than one line, this process is repeated.
SECONDS()
SECONDS() ⇒ nSeconds
SECONDS() returns the system time as a numeric value in the form seconds.hundredths.
The numeric value returned is the number of seconds elapsed since midnight, and is based
on a twenty-four hour clock in a range from zero to 86399.
SELECT()
[
]
SELECT( cAlias ) ⇒ nWorkArea
is the target work area alias name.
cAlias
SELECT() returns the work area of the specified alias as a integer numeric value.
SET()
[
SET(nSpecifier , expNewSetting
⇒ CurrentSetting
], [lOpenMode])
is a numeric value that identifies the setting to be inspected or
changed.
is an optional argument that specifies a new value for
the nSpecifier . The type of expNewSetting depends on
nSpecifier .
is a logical value that indicates whether or not files are opened
for some settings. A value of false (‘.F.’) means the file
should be truncated. A value of true (‘.T.’) means the file
should be opened in append mode. In either case, if the file
does not exist, it is created. If this argument is not specified,
the default is append mode.
nSpecifier
expNewSetting
lOpenMode
SET() returns the current value of the specified setting.
Inside nB, the function SET() is not so easy to use as inside the Clipper environment. This
because nB cannot support manifest constants and a numeric specifier nSpecifier is not
easy to manage. Instead of SET() you can use SETVERB().
SETBLINK()
[
]
SETBLINK( lToggle ) ⇒ lCurrentSetting
nanoBase 1997 user manual
4227
changes the meaning of the asterisk (*) character when it
is encountered in a SETCOLOR() string. Specifying true
(‘.T.’) sets character blinking on and false (‘.F.’) sets background intensity. The default is true (‘.T.’).
lToggle
SETBLINK() returns the current setting as a logical value.
SETCANCEL()
[
]
SETCANCEL( lToggle ) ⇒ lCurrentSetting
changes the availability of Alt-C and Ctrl-Break as termination keys. Specifying true (‘.T.’) allows either of these keys
to terminate an application and false (‘.F.’) disables both
keys. The default is true (‘.T.’).
lToggle
SETCANCEL() returns the current setting as a logical value.
SETCOLOR()
[
]
SETCOLOR( cColorString ) ⇒ cColorString
is a character string containing a list of color attribute settings
for subsequent screen painting.
cColorString
SETCURSOR()
[
SETCURSOR( nCursorShape
])
⇒ nCurrentSetting
is a number indicating the shape of the cursor.
nCursorShape == 0 None
nCursorShape == 1 Underline
nCursorShape == 2 Lower half block
nCursorShape == 3 Full block
nCursorShape == 4 Upper half block
nCursorShape
SETCURSOR() returns the current cursor shape as a numeric value.
SETKEY()
SETKEY(nInkeyCode ,
[bAction])
⇒ bCurrentAction
nInkeyCode
bAction
is the INKEY() value of the key to be associated or queried.
specifies a code block that is automatically executed whenever the specified key is pressed during a wait state.
SETKEY() returns the action block currently associated with the specified key, or NIL if
the specified key is not currently associated with a block.
SETMODE()
SETMODE(nRows , nCols ) ⇒ lSuccess
nRows
nCols
is the number of rows in the desired display mode.
is the number of columns in the desired display mode.
SETMODE() is an environment function that attempts to change the mode of the display
hardware to match the number of rows and columns specified. The change in screen size is
nanoBase 1997 user manual
4228
reflected in the values returned by MAXROW() and MAXCOL().
SETPOS()
Set position
SETPOS(nRow , nCol ) ⇒ NIL
define the new screen position of the cursor. These values may
range from 0, 0 to MAXROW(), MAXCOL().
nRow , nCol
SETPOS() is an environment function that moves the cursor to a new position on the screen.
After the cursor is positioned, ROW() and COL() are updated accordingly.
SETPRC()
Set printer row column
SETPRC(nRow , nCol ) ⇒ NIL
is the new PROW() value.
is the new PCOL() value.
nRow
nCol
SETPRC() is a printer function that sends control codes to the printer without changing the
tracking of the printhead position.
SOUNDEX()
SOUNDEX(cString ) ⇒ cSoundexString
is the character string to convert.
cString
SOUNDEX() returns a four-digit character string in the form A999.
SPACE()
SPACE(nCount ) ⇒ cSpaces
is the number of spaces to return.
nCount
SPACE() returns a character string. If nCount is zero, SPACE() returns a null string ("").
SQRT()
SQRT(nNumber ) ⇒ nRoot
nNumber
is a positive number to take the square root of.
SQRT() returns a numeric value calculated to double precision. The number of decimal
places displayed is determined solely by SET DECIMALS regardless of SET FIXED. A
negative nNumber returns zero.
STR()
String
STR(nNumber ,
nNumber
nLength
nDecimals
[nLength ], [nDecimals])
⇒ cNumber
is the numeric expression to convert to a character string.
is the length of the character string to return, including decimal digits, decimal point, and sign.
is the number of decimal places to return.
nanoBase 1997 user manual
4229
STR() returns nNumber formatted as a character string.
STRTRAN()
STRTRAN(cString , cSearch ,
cReplace , nStart ,
[
] [
] [nCount ])
⇒ cNewString
is the character string or memo field to search.
is the sequence of characters to locate.
is the sequence of characters with which to replace cSearch .
If this argument is not specified, the specified instances of the
search argument are replaced with a null string ("").
is the first occurrence that will be replaced. If this argument is
omitted, the default is one.
is the number of occurrences to replace. If this argument is
not specified, the default is all.
cString
cSearch
cReplace
nStart
nCount
STRTRAN() returns a new character string with the specified instances of cSearch replaced
with cReplace .
STUFF()
STUFF(cString , nStart ,
nDelete , cInsert ) ⇒ cNewString
is the target character string into which characters are inserted
and deleted.
is the starting position in the target string where the insertion/deletion occurs.
is the number of characters to delete.
is the string to insert.
cString
nStart
nDelete
cInsert
STUFF() returns a copy of cString with the specified characters deleted and with cInsert
inserted.
SUBSTR()
Sub string
SUBSTR(cString , nStart ,
cString
nStart
nCount
[nCount ])
⇒ cSubstring
is the character string from which to extract a substring.
is the starting position in cString . If nStart is positive, it is
relative to the leftmost character in cString . If nStart is negative, it is relative to the rightmost character in the cString .
is the number of characters to extract. If omitted, the substring
begins at nStart and continues to the end of the string. If
nCount is greater than the number of characters from nStart
to the end of cString , the extra is ignored.
SUBSTR() is a character function that extracts a substring from another character string or
memo field.
TIME()
TIME() ⇒ cTimeString
TIME() returns the system time as a character string in the form hh:mm:ss. hh is hours in
24-hour format, mm is minutes, and ss is seconds.
TIME() is a time function that displays the system time on the screen or prints it on a report.
nanoBase 1997 user manual
4230
TONE()
TONE(nFrequency , nDuration ) ⇒ NIL
nFrequency
nDuration
is a positive numeric value indicating the frequency of the
tone to sound.
is a positive numeric value indicating the duration of the tone
measured in increments of 1/18 of a second. For example, an
nDuration value of 18 represents one second.
For both arguments, noninteger values are truncated (not rounded) to their integer portion.
TRANSFORM()
TRANSFORM(exp , cSayPicture ) ⇒ cFormatString
exp
cSayPicture
is the value to format. This expression can be any valid data
type except array, code block, and NIL.
is a string of picture and template characters that describes the
format of the returned haracter string.
TRANSFORM() converts exp to a formatted character string as defined by cSayPicture .
TYPE()
TYPE(cExp ) ⇒ cType
cExp
is a character expression whose type is to be determined.
cExp can be a field, with or without the alias, a private or
public variable, or an expression of any type.
TYPE() returns one of the following characters:
Array
Block
Character
Date
Logical
Memo
Numeric
Object
NIL, local, or static
Error syntactical
Error indeterminate
A
B
C
D
L
M
N
O
U
UE
UI
TYPE() is a system function that returns the type of the specified expression. TYPE() is
like VALTYPE() but uses the macro operator (&) to determine the type of the argument.
VALTYPE(), by contrast, evaluates an expression and determines the data type of the return
value.
UPDATED()
UPDATED() ⇒ lChange
UPDATED() returns true (‘.T.’) if data in a GET is added or changed; otherwise, it returns
false (‘.F.’).
UPPER()
UPPER(cString ) ⇒ cUpperString
nanoBase 1997 user manual
cString
4231
is the character string to convert.
UPPER() returns a copy of cString with all alphabetical characters converted to uppercase.
All other characters remain the same as in the original string.
USED()
USED() ⇒ lDbfOpen
USED() returns true (‘.T.’) if there is a database file in USE in the current work area;
otherwise, it returns false (‘.F.’).
VAL()
Value
VAL(cNumber ) ⇒ nNumber
cNumber
is the character expression to convert.
VAL() is a character conversion function that converts a character string containing numeric
digits to a numeric value. When VAL() is executed, it evaluates cNumber until a second
decimal point, the first non-numeric character, or the end of the expression is encountered.
VALTYPE()
Value type
VALTYPE(exp ) ⇒ cType
exp
is an expression of any type.
VALTYPE() returns a single character representing the data type returned by exp . VALTYPE() returns one of the following characters:
Array
Block
Character
Date
Logical
Memo
Numeric
Object
NIL
A
B
C
D
L
M
N
O
U
VALTYPE() is a system function that takes a single argument, evaluates it, and returns a
one character string describing the data type of the return value.
YEAR()
YEAR(dDate) ⇒ nYear
dDate
is the date value to convert.
YEAR() returns the year of the specified date value including the century digits as a fourdigit numeric value. The value returned is not affected by the current DATE or CENTURY
format. Specifying a null date (CTOD("")) returns zero.
nanoBase 1997 user manual
4232
371.15 nB functions
Some functions made into nB are available for macro use. Not all available functions are here
documented.
ACCEPT()
ACCEPT( Field ,
[cMessage], [cHeader]
) ⇒ updatedField |NIL
It is a prompt function that shows cMessage asking to type something into Field . It returns
the updated data or NIL if [ Esc ] was pressed. The string cHeader is showed centered at the
top window.
ACHOICE()
ACHOICE(nTop , nLeft , nBottom , nRight ,
acMenuItems ,
alSelectableItems ,
nInitialItem ,
[
]
[
]
[lButtons | aButtons ])
⇒ nPosition
nTop , nLeft , nBottom , nRight
acMenuItems
are the window coordinates.
is an array of character strings to display as the menu items.
is a parallel array of logical values (one element for each item
in acMenuItems ) that specify the selectable menu items. Elements can be logical values or character strings. If the element is a character string, it is evaluated as a macro expression which should evaluate to a logical data type. A value of
false (‘.F.’) means that the corresponding menu item is not
available, and a value of true (‘.T.’) means that it is available.
By default, all menu items are available for selection.
is the position in the acMenuItems array of the item that will
be highlighted when the menu is initially displayed.
if True means that default buttons will appear.
is an array of buttons.
the nth button row position;
the nth button column position;
the nth button text;
the nth button code block.
alSelectableItems
nInitialItem
lButtons
aButtons
aButtons [n ][1] == N
aButtons [n ][2] == N
aButtons [n ][3] == C
aButtons [n ][4] == B
ACHOICE() returns the numeric position in the acMenuItems array of the menu item
selected. If no choice is made, ACHOICE() returns zero.
ACHOICEWINDOW()
[
]
ACHOICEWINDOW( acMenuItems , cDescription ,
nTop , nLeft , nBottom , nRight ,
alSelectableItems ,
nInitialItem
) ⇒ nPosition
[
[
]
]
acMenuItems
cDescription
nTop , nLeft , nBottom , nRight
is an array of character strings to display as the menu items.
is a header to be shown at the top of window.
are the window coordinates.
nanoBase 1997 user manual
4233
is a parallel array of logical values (one element for each item
in acMenuItems ) that specify the selectable menu items. Elements can be logical values or character strings. If the element is a character string, it is evaluated as a macro expression which should evaluate to a logical data type. A value of
false (‘.F.’) means that the corresponding menu item is not
available, and a value of true (‘.T.’) means that it is available.
By default, all menu items are available for selection.
is the position in the acMenuItems array of the item that will
be highlighted when the menu is initially displayed.
alSelectableItems
nInitialItem
ACHOICEWINDOW() calls ACHOICE() with a window border around the ACHOICE()
screen area.
ALERTBOX()
ALERTBOX( cMessage ,
[aOptions]
) ⇒ nChoice
is the message text displayed, centered, in the alert box. If the
message contains one or more semicolons, the text after the
semicolons is centered on succeeding lines in the dialog box.
defines a list of up to 4 possible responses to the dialog box.
cMessage
aOptions
ALERTBOX() returns a numeric value indicating which option was chosen. If the [ Esc ]
key is pressed, the value returned is zero. The ALERTBOX() function creates a simple
modal dialog. The user can respond by moving a highlight bar and pressing the Return
or SpaceBar keys, or by pressing the key corresponding to the first letter of the option. If
aOptions is not supplied, a single "Ok" option is presented.
ALERTBOX() is similar to ALERT() but it accept mouse input.
ATB()
ATB(
[nTop], [nLeft ], [nBottom ], [nRight ],
aArray , [nSubscript ],
[acColSayPic],
[acColTopSep], [acColBodySep], [acColBotSep],
[acColHead], [acColFoot],
[abColValid],
[abColMsg],
[cColor], [abColColors],
[lModify],
[lButtons | aButtons ] ) ⇒ NIL
nTop , nLeft , nBottom , nRight
aArray
nSubscript
acColSayPic
acColTopSep
acColBodySep
acColBotSep
acColHead
acColFoot
abColValid
abColMsg
defines the screen area where browse have to take place.
bidimensional array to be browsed.
starting array position.
is the picture array.
is the top separation array: default is chr(194)+chr(196).
is the body separation array: default is chr(179).
is the bottom separation array: default is chr(193)+chr(196).
is the header array for every column.
is the footer array for every column.
is the validation array that specify when a field is properly
filled. The condition must be specified in code block format.
is the message array that permits to show information at the
bottom of browse area. The array must be composed with
code blocks which result with a character string.
nanoBase 1997 user manual
4234
is the color string: it may be longer than the usual 5 elements.
is the color code block array. The code block receive as parameter the value contained inside the field and must return
an array containing two numbers: they correspond to the two
color couple from cColor.
indicates whether the browse can modify data.
if True, default buttons are displayed.
array of buttons.
the nth button row position;
the nth button column position;
the nth button text;
the nth button code block.
cColor
abColColors
lModify
lButtons
aButtons
aButtons [n ][1] N
aButtons [n ][2] N
aButtons [n ][3] C
aButtons [n ][4] B
This function starts the browse of a bidimensional array. Only arrays containing monodimensional array containing the same kind of editable data are allowed. The function can
handle a maximum of 61 columns.
BCOMPILE()
BCOMPILE( cString ) ⇒ bBlock
Compiles the string cString and returns the code block bBlock
BUTTON()
BUTTON( @aButtons ,
nRow , nCol , cText ,
bAction
) ⇒ NIL
[
[
] [
]
] [
] [cColor],
the array of buttons to be increased with a new button array.
is the row and column starting position for the button string.
is the text that make up the button.
is the color string.
is the code block associated to the button.
aButtons
nRow and nCol
cText
cColor
bAction
This function adds to aButtons a new button array. Please note that the button array added
is compatible only with the READ() function and not the other function using array of
buttons: the others do not have a color string.
COLORARRAY()
COLORARRAY( cColor ) ⇒ aColors
a color string to be translated into a color array.
cColors
This function transform a color string into a color array. The array has as many elements as
the colors contained inside cColor string.
COORDINATE()
[
]
]
COORDINATE( @nTop , @nLeft , @nBottom , @nRight ,
cHorizontal , cVertical
) ⇒ NIL
[
] [
nTop , nLeft , nBottom and nRight
are the starting position of a window that is to be differently
aligned.