You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Appunti di informatica libera 2003.06.29<br />
Volume VIII<br />
Argomenti avanzati e accessori<br />
1
Appunti Linux<br />
Copyright © 1997-2000 Daniele Giacomini<br />
Appunti di informatica libera<br />
Copyright © 2000-2003 Daniele Giacomini<br />
Via Morganella Est, 21 -- I-31050 Ponzano Veneto (TV) -- daniele @ swlibero.org<br />
Le informazioni contenute in questa opera possono essere diffuse e riutilizzate in base alle condizioni<br />
poste dalla licenza GNU General Public License, come pubblicato dalla Free S<strong>of</strong>tware<br />
Foundation.<br />
In caso di modifica dell’opera e/o di riutilizzo parziale della stessa, secondo i termini della licenza,<br />
le annotazioni riferite a queste modifiche e i riferimenti all’origine di questa opera, devono<br />
risultare evidenti e apportate secondo modalità appropriate alle caratteristiche dell’opera stessa.<br />
In nessun caso è consentita la modifica di quanto, in modo evidente, esprime il pensiero,<br />
l’opinione o i sentimenti del suo autore.<br />
L’opera è priva di garanzie di qualunque tipo, come spiegato nella stessa licenza GNU General<br />
Public License.<br />
Queste condizioni e questo copyright si applicano all’opera nel suo complesso, salvo ove indicato<br />
espressamente in modo diverso.<br />
The informations contained inside this work can be spread and reused under the terms <strong>of</strong> the<br />
GNU General Public License as published by the Free S<strong>of</strong>tware Foundation.<br />
If you modify this work and/or reuse it partially, under the terms <strong>of</strong> the license, the notices about<br />
these changes and the references about the original work, must be evidenced conforming to the<br />
work characteristics. IN NO EVENT IS ALLOWED TO MODIFY WHAT ARE CLEARLY<br />
THE THOUGHTS, THE OPINIONS AND/OR THE FEELINGS OF THE AUTHOR.<br />
This work is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without<br />
even the implied warranty <strong>of</strong> MERCHANTABILITY or FITNESS FOR A PARTICULAR<br />
PURPOSE. See the GNU General Public License for more details.<br />
These conditions and this copyright apply to the whole work, except where clearly stated in a<br />
different way.<br />
Una copia della licenza GNU General Public License, versione 2, si trova nell’appendice A.<br />
A copy <strong>of</strong> GNU General Public License, version 2, is available in appendix A.<br />
2
The main distribution for Appunti di informatica libera is described below. For every distribution<br />
channel the maintainer’s name and address is also reported.<br />
Ordering<br />
Prosa srl distribute Appunti di informatica libera and possibly oder related products through<br />
the commercial channel. Any request to buy something related to Appunti di informatica<br />
libera, can be addressed to Prosa srl:<br />
<br />
<br />
Internet mirrors with good bandwidth<br />
• direct reading: <br />
download: <br />
Fabrizio Rubino, fabrizio @ koalas<strong>of</strong>t.org<br />
• direct reading: <br />
download: <br />
download: <br />
mirror-service @ garr.it<br />
• direct reading: <br />
download: <br />
Fabrizio Rubino, fabrizio @ koalas<strong>of</strong>t.org<br />
• direct reading: <br />
download: <br />
Italian Linux Society, info @ linux.it<br />
Internet main distribution sites<br />
• direct reading: <br />
download: and <br />
Michele Dalla Silvestra, mds @ swlibero.org<br />
• direct reading: and <br />
download: and <br />
Fabrizio Rubino, fabrizio @ koalas<strong>of</strong>t.org<br />
• direct reading: <br />
download: <br />
Carlo Perassi, carlo @ linux.it<br />
• direct reading: <br />
download: <br />
Davide Barbieri, paci @ prosa.it<br />
• direct reading: <br />
download: <br />
Fabrizio Zeno Cornelli, zeno @ filibusta.crema.unimi.it<br />
3
• direct reading: <br />
download: <br />
Franco Lazzero, PCTIME, pctime @ pctime.net<br />
• direct reading: <br />
download: <br />
David Pisa, david @ iglu.cc.uniud.it<br />
• direct reading: <br />
download: <br />
Claudio Neri, Sincro Consulting, neri.c @ sincroconsulting.com<br />
GNU distributions<br />
• GNU/Linux Debian <br />
Massimo Dal Zotto, dz @ cs.unitn.it<br />
Italian magazine’s CD-ROM<br />
• inter-punto-net <br />
Michele Dalla Silvestra, mds @ swlibero.org<br />
• Internet News <br />
Francesco Facconi, francesc<strong>of</strong>acconi @ libero.it<br />
Fabio Ferrazzo, fabio.fr @ tiscalinet.it<br />
• Linux Magazine <br />
Emmanuele Somma, esomma @ ieee.org<br />
• Linux Pro <br />
Massimiliano Zagaglia, max @ linuxwaves.com<br />
• PC Upgrade <br />
info @ pcupgrade.it<br />
La diffusione di questa opera è incoraggiata in base ai termini della licenza.<br />
The spread <strong>of</strong> this work is encouraged under the terms <strong>of</strong> the license.<br />
4
Parte lxix Prevenzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />
351 Copie di sicurezza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />
352 Dischetti di emergenza con GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />
Parte lxx Informatica gestionale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
353 Codici a barre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
354 Barcode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />
355 Trasformazione in lettere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />
Parte lxxi i86 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57<br />
356 Minix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />
357 ELKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />
Parte lxxii Dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83<br />
358 Dos: introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />
359 Dos: dischi, file system, directory e file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
360 Dos: configurazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />
361 Dos: script dell’interprete dei comandi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />
362 Dos: gestione della memoria centrale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .121<br />
363 FreeDOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123<br />
364 Progetto GNUish . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126<br />
365 The valuable DOS Freeware page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />
366 Clean the Clipper 5.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134<br />
367 nanoBase 1997 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />
368 nanoBase 1997 user manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />
Parte lxxiii Braille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315<br />
369 Introduzione al sistema braille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316<br />
370 Sistemi di interazione per non vedenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321<br />
Parte lxxiv Aspetti umani . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325<br />
371 Manifesto GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331<br />
372 Il progetto GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339<br />
373 La rivoluzione del Mimete, ovvero s<strong>of</strong>tware e copyright . . . . . . . . . . . . . . . . . . . . . . . . . .355<br />
374 Il copyright/diritto d’autore del s<strong>of</strong>tware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358<br />
Indice analitico del volume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361<br />
5
Parte lxix<br />
Prevenzione<br />
351 Copie di sicurezza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />
351.1 Scelta del sistema di copia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />
351.2 Strategia nelle copie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />
351.3 Supporti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />
351.4 Compressione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />
351.5 Archiviazione e recupero attraverso tar e gzip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />
351.6 Archiviazione di un file system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
352 Dischetti di emergenza con GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />
352.1 Dischetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />
352.2 Personalizzazione di dischetti di emergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22<br />
352.3 Dischetti Slackware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />
352.4 Kernel per dischetti di emergenza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />
352.5 Cavi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />
352.6 Utenti e gruppi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27<br />
352.7 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />
7
Copie di sicurezza<br />
Capitolo 351<br />
L’amministrazione di un sistema Unix è da sempre un grosso problema sotto tutti i punti di vista.<br />
Il primo tra tutti è quello della salvaguardia dei dati, ma al rischio della loro perdita si pone<br />
rimedio solo attraverso una gestione corretta delle copie di sicurezza.<br />
351.1 Scelta del sistema di copia<br />
Gli strumenti a disposizione per eseguire copie di sicurezza sono molti e si possono distinguere<br />
due estremi possibili:<br />
• copiare i file e le directory;<br />
• copiare una partizione o un disco intero.<br />
La copia di una partizione o di un disco può avere il vantaggio di permettere l’archiviazione<br />
della situazione esatta in cui si trova, problemi inclusi. Inoltre, non avendo un processo di lettura<br />
sui file, la data di lettura di questi non viene modificata. Lo svantaggio fondamentale di tale<br />
tipo di copia è che questa è riferita a un disco particolare (o a una partizione) di una macchina<br />
particolare: è molto poco probabile che si possano recuperare dati archiviati in questo modo in un<br />
disco fisso diverso. Questa tecnica, più che per eseguire delle copie di sicurezza, viene utilizzata<br />
per archiviare dischetti nel loro stato originale.<br />
La copia di file e directory non tiene conto del supporto fisico in cui si trovano e nemmeno del<br />
tipo di file system utilizzato. Questo comporta una serie di conseguenze:<br />
• i file e le directory vengono scanditi in lettura, alterando quindi le date di lettura;<br />
• i collegamenti simbolici vanno copiati come tali e non devono essere copiati gli oggetti a<br />
cui questi puntano;<br />
• i collegamenti fisici potrebbero non essere distinti.<br />
In generale, dal momento che una copia di file e directory è portabile, mentre una copia di un<br />
dispositivo intero non lo è (quando non si tratta di un dispositivo standard come i dischetti),<br />
dovrebbe essere preferibile la prima di queste due soluzioni.<br />
351.1.1 Archiviazione<br />
È intuitiva la ragione per la quale le copie di sicurezza non vanno fatte archiviando un dispositivo<br />
intero come se fosse un file unico. La copia pura e semplice dei file e delle directory è una tecnica<br />
possibile, ma richiede condizioni particolari:<br />
• l’unità di destinazione deve essere in grado di accogliere i dati come sono all’origine, in<br />
pratica dovrebbe trattarsi di un disco;<br />
• deve trattarsi di unità rimovibili;<br />
• la capacità di queste unità deve essere maggiore di quella del file più grande che si deve<br />
archiviare.<br />
8
Copie di sicurezza 9<br />
Di solito si preferisce la tecnica dell’archiviazione dei dati in un file unico (che rappresenta<br />
l’archivio), assieme a tutte le informazioni necessarie per riprodurre i file e le directory originali.<br />
In questo modo si possono utilizzare unità di memorizzazione di qualunque tipo, eventualmente<br />
suddividendo l’archivio in pezzi più piccoli contenibili al loro interno.<br />
351.1.2 Archiviazione di file speciali<br />
Gli oggetti contenibili in un file system possono essere di vario tipo (file puri e semplici, directory,<br />
file di dispositivo, collegamenti, ecc.) e così pure i loro attributi (permessi, date, ecc.). Il sistema<br />
di archiviazione che si utilizza deve essere in grado riprodurre correttamente tutti i dati del tipo<br />
di file system che si utilizza.<br />
Per esempio, non sarebbe possibile archiviare i dati di un file system Unix in un archivio ‘.zip’<br />
che è nato per gli ambienti Dos.<br />
351.1.3 Utenti e gruppi proprietari<br />
Tra gli attributi dei file, è molto importante l’indicazione degli utenti e dei gruppi proprietari.<br />
I programmi di archiviazione potrebbero non essere in grado di memorizzare il numero UID e<br />
GID, limitandosi ad annotare solo i nomi degli utenti e dei gruppi. In tal modo, nel momento del<br />
recupero, i numeri UID e GID verrebbero riprodotti in base alle caratteristiche del sistema, cioè<br />
in base alla particolare configurazione dei file ‘/etc/passwd’ e ‘/etc/group’.<br />
Il fatto che il programma di archiviazione memorizzi i numeri UID e GID, oppure che memorizzi<br />
i nomi di utenti e gruppi, ha delle implicazioni che si traducono, a seconda delle circostanze, in<br />
vantaggi o svantaggi.<br />
Se i dati archiviati devono essere riprodotti in un sistema diverso da quello di origine, in cui ci<br />
sono gli stessi nomi di utenti e di gruppi, che però potrebbero corrispondere a numeri UID e GID<br />
differenti, diventa conveniente un metodo di archiviazione che ignori i numeri degli utenti e dei<br />
gruppi. Tuttavia, se alcuni nomi di utenti o gruppi non sono presenti nel sistema di destinazione,<br />
la proprietà di questi file verrebbe assegnata automaticamente all’utente ‘root’.<br />
Quando si esegue una copia di sicurezza di un intero sistema e poi lo si vuole riprodurre altrove,<br />
si agisce per mezzo di un sistema operativo minimo, avviato probabilmente attraverso dischetti o<br />
CD-ROM. In queste condizioni, lo scopo è quello di riprodurre esattamente il sistema originale,<br />
per cui, i numeri UID e GID andrebbero rispettati fedelmente, nell’attesa che sia ripristinato tutto,<br />
compresi i file ‘/etc/passwd’ e ‘/etc/group’ originali.<br />
Quando il programma di archiviazione memorizza entrambe le informazioni, sia UID/GID che<br />
i nomi, nel momento del recupero si pone il problema di come comportarsi quando questi non<br />
corrispondono. Si presentano queste alternative:<br />
• se i numeri corrispondono ai nomi, non si pongono problemi nell’estrazione;<br />
• se i numeri e i nomi non sono utilizzati nel sistema di destinazione, si possono estrarre i<br />
dati utilizzando i numeri originali, anche se non sono abbinati ad alcun nome;<br />
• se i numeri non sono utilizzati nel sistema di destinazione, mentre i nomi sì, si possono<br />
cambiare i numeri in modo che corrispondano ai nomi;<br />
• se i nomi non sono utilizzati nel sistema di destinazione, mentre i numeri corrispondono<br />
a nomi differenti, non si può fare altro che recuperare i numeri come solo, assegnando in<br />
pratica la proprietà a utenti e gruppi con nomi differenti;
10 volume VIII Argomenti avanzati e accessori<br />
• se sono presenti sia i nomi che i numeri, ma questi non hanno lo stesso abbinamento (cioè<br />
i numeri corrispondono a nomi diversi), dovrebbe essere preferibile cambiare i numeri in<br />
modo che corrispondano ai nomi.<br />
351.1.4 Percorsi assoluti o relativi<br />
Quando si intende archiviare una porzione di file system e quindi solo ciò che si trova a partire da<br />
una certa directory in poi, è importante sapere come si comporta il programma di archiviazione<br />
al riguardo della registrazione dei percorsi (path). Se si vuole archiviare la directory ‘/home/<br />
tizio/esempi/’, il programma di archiviazione potrebbe registrare il suo contenuto in uno dei<br />
tre modi seguenti:<br />
1. ‘/home/tizio/esempi/ * ’<br />
2. ‘home/tizio/esempi/ * ’<br />
3. ‘./ * ’<br />
Naturalmente, ciò dipende anche dal modo in cui vengono date le istruzioni al programma stesso.<br />
Nel primo caso, quando dovesse rendersi necessario il recupero dei dati, questi verrebbero collocati<br />
esattamente nella directory indicata, in modo assoluto. Nel secondo, verrebbero collocati<br />
in modo relativo a partire dalla directory corrente, ottenendo così la directory ‘./home/<br />
tizio/esempi/ * ’. Nel terzo caso si avrebbe il recupero del contenuto di quella directory senza<br />
informazioni sul percorso precedente.<br />
351.2 Strategia nelle copie<br />
Le copie di sicurezza permettono di conservare la situazione dei dati in un istante determinato,<br />
ma i dati sono soggetti a continui aggiornamenti. Per questo occorre una procedura attraverso la<br />
quale si possa avere una gestione ordinata e ragionevolmente sicura delle copie.<br />
A parte i rischi connessi con il tipo di supporto utilizzato per le copie e il luogo in cui queste<br />
vengono conservate, vanno almeno considerate le modalità sequenziali con cui queste possono<br />
essere eseguite. È importante rispettare un paio di regole elementari:<br />
1. non si riutilizzano i supporti contenenti la copia effettuata la volta precedente;<br />
2. non si utilizzano supporti in cattive condizioni.<br />
351.2.1 Generazioni delle copie<br />
Per distinguere una copia effettuata in un momento rispetto a quella fatta in un altro, si parla<br />
di generazione. In pratica, l’ultima copia di sicurezza effettuata è l’ultima generazione, mentre<br />
le altre sono tutte generazioni precedenti. Questo termine si riferisce naturalmente a copie fatte<br />
sullo stesso insieme di dati.<br />
Il buon senso suggerisce di utilizzare almeno tre generazioni di copie: l’ultima, quella precedente<br />
e quella ancora precedente.
Copie di sicurezza 11<br />
351.2.2 Livelli delle copie<br />
La copia di un file system intero comporta solitamente un impegno consistente, sia in termini di<br />
tempo che di supporti impiegati. Il programma che si utilizza per le copie, oppure un gruppetto<br />
opportuno di script di shell, potrebbe permettere di effettuare la copia successiva dei soli file che<br />
sono stati modificati nel frattempo.<br />
Quando si esegue una copia dei soli file che risultano diversi rispetto all’ultima copia completa,<br />
si parla di copia di primo livello; quando se ne esegue un’altra in un momento successivo per le<br />
variazioni avvenute dopo quella di primo livello, si parla di secondo livello e così di seguito.<br />
A parte le difficoltà legate alla conservazione dell’informazione sullo stato dei file (di solito<br />
si tratta della data di modifica e di creazione), si pongono poi dei problemi nel momento in<br />
cui dovesse essere necessario un ripristino dalle copie. Si dovrebbe ripristinare l’ultima copia<br />
completa, seguita da tutte quelle aggiuntive dei soli file modificati, nello stesso ordine in cui<br />
sono state fatte: dalla più vecchia alla più recente.<br />
Sotto questo aspetto, quando non si vuole ripetere una copia completa troppo frequentemente, si<br />
cerca almeno di eseguire copie successive sempre di primo livello (si hanno quindi più generazioni<br />
di copie di primo livello). In tal modo, un eventuale recupero richiederebbe solo il ripristino<br />
dell’ultima generazione di copia completa e dell’ultima generazione di copia di primo livello.<br />
Questo sistema potrebbe non tenere conto dei file cancellati dopo l’ultima generazione di copia<br />
completa: in tal modo, un eventuale recupero dalle copie di sicurezza potrebbe comportare il<br />
ripristino di file che non servono più.<br />
351.2.3 Distribuire le responsabilità<br />
In un sistema monoutente, l’unico utilizzatore è anche l’amministratore del proprio sistema e di<br />
conseguenza anche l’unico responsabile. Sarà quindi lui (o lei) a sapere esattamente cosa ha fatto<br />
e cosa è necessario copiare per sicurezza.<br />
In un sistema multiutente o comunque quando si condividono dati in gruppo, anche se a prima<br />
vista potrebbe sembrare conveniente la gestione delle copie in modo centralizzato, è comunque<br />
utile affidarla in parte anche alla responsabilità dei singoli:<br />
• periodicamente, un amministratore potrebbe occuparsi di eseguire la copia complessiva di<br />
tutto il sistema;<br />
• ogni giorno, gli utenti dovrebbero preoccuparsi di eseguire le copie dei dati di loro<br />
competenza.<br />
Nel momento in cui dovesse essere necessario, si dovrebbero recuperare i dati dalle copie generali<br />
fatte dall’amministratore e successivamente da quelle particolari dei singoli utenti.<br />
Se determinate attività vengono svolte in gruppo, si potrebbe eleggere ugualmente un<br />
responsabile all’interno di questo che si occupi delle copie di quell’attività.<br />
Il vantaggio di questo metodo sta nell’alleggerimento delle responsabilità dell’amministratore e<br />
nella soluzione più facile di piccoli problemi locali:<br />
• se un gruppo di lavoro ha alterato i dati a causa di un’operazione errata, è sufficiente<br />
recuperare i dati di quel gruppo senza disturbare l’intero sistema;<br />
• la distribuzione della responsabilità aumenta la consapevolezza da parte degli utenti.
12 volume VIII Argomenti avanzati e accessori<br />
351.3 Supporti<br />
La scelta del supporto di conservazione della copia è importante e comporta alcune conseguenze:<br />
• il costo;<br />
• la disponibilità di unità in grado di utilizzarli;<br />
• la facilità o difficoltà nel recupero di porzioni dei dati archiviati.<br />
Il supporto tradizionalmente più economico e più diffuso nel passato è il nastro magnetico. Questo<br />
ha però lo svantaggio fondamentale di essere un mezzo di memorizzazione sequenziale: non<br />
è possibile estrarre un file se prima non si scorre tutto il nastro (o tutti i nastri) che c’è prima di<br />
quel dato. Un altro svantaggio importante sta nella necessità di rileggere il suo contenuto, dopo<br />
la copia, per verificare che i dati siano stati registrati correttamente.<br />
Da alcuni anni si possono trovare dischi rimovibili di grandi capacità a prezzi ragionevolmente<br />
bassi, oppure dischi fissi esterni (collegati attraverso la porta USB). Questi hanno il vantaggio di<br />
poter essere utilizzati come dischi normali, pertanto, il recupero di dati parziali diventa molto più<br />
facile, anche quando la copia di sicurezza avviene per mezzo di un’archiviazione tradizionale.<br />
Anche i CD-R sono diventati un ottimo mezzo di archiviazione, data l’economicità dei supporti:<br />
benché sia possibile una sola registrazione, il prezzo di un CD vergine è molto contenuto. La<br />
preparazione di un CD-ROM richiede una certa quantità di spazio libero su disco per la preparazione<br />
dell’immagine prima dell’operazione di «incisione» (burn) e richiede anche l’investimento<br />
del masterizzatore. Si tratta di soldi ben spesi: una copia di sicurezza fatta su CD-ROM può essere<br />
letta ovunque ci sia un lettore, ma questo è ormai un accessorio standard degli elaboratori;<br />
inoltre, il CD-ROM ha una vita media molto lunga, garantendo la durata delle copie di sicurezza.<br />
Esiste tuttavia un problema nuovo: si deve essere prudenti con le copie obsolete. Infatti, quando<br />
le copie di sicurezza sono molto vecchie e non servono più, si può essere tentati di conservare i<br />
CD o di donarli a qualcuno, magari per gioco, o perché li usi come un addobbo. È evidente che<br />
si tratta di un’idea sbagliata: dal momento che questi CD-ROM sono stati usati per delle copie di<br />
sicurezza, contengono potenzialmente informazioni delicate e riservate.<br />
I CD-ROM contenenti copie di sicurezza obsolete vanno distrutti prima di essere gettati! Per<br />
distruggere un CD, basta tagliarlo a metà con una forbice normale.<br />
A fianco dei CD-R ci sarebbero anche i CD-RW, ovvero i CD riscrivibili; tuttavia, il CD-RW<br />
non è altrettanto affidabile di un CD-R, la velocità di scrittura è relativamente più bassa rispetto a<br />
un CD-R e ci possono essere lettori che non sono in grado, successivamente, di accedere al loro<br />
contenuto.<br />
Quando i dati da archiviare sono pochi, può convenire l’utilizzo dei soliti dischetti: sono sicuramente<br />
una scelta economica e le unità a dischetti sono disponibili ovunque. Per quanto riguarda la<br />
facilità di estrazione dei dati, ciò dipende dal modo con cui questi vengono usati: se si registrano<br />
i dati al loro interno senza fare uso di alcun file system, si ottiene un comportamento equivalente<br />
ai nastri; se si utilizzano con un file system, è necessario che l’archivio sia contenibile all’interno<br />
di un solo dischetto.
Copie di sicurezza 13<br />
351.4 Compressione<br />
Il problema della dimensione dei dati da archiviare può essere ridotto parzialmente con l’aiuto<br />
della compressione. La tecnica della compressione può essere applicata all’archiviazione in due<br />
modi possibili:<br />
• prima della costruzione dell’archivio, ottenendo così un’archivio di file compressi;<br />
• dopo la costruzione dell’archivio, ottenendo così un archivio compresso.<br />
La differenza è enorme. La compressione introduce un elemento di rischio maggiore nella perdita<br />
di dati: se una copia di sicurezza viene danneggiata parzialmente, l’effetto di questo danno si<br />
riflette in una quantità di dati maggiore (spesso è compromesso tutto l’archivio).<br />
351.4.1 Compressione prima dell’archiviazione<br />
I programmi di archiviazione compressa maggiormente diffusi negli ambienti Dos utilizzano<br />
la tecnica della compressione prima dell’archiviazione. È questo il caso degli archivi ‘.zip’,<br />
‘.arj’, ‘.lzh’ e di altri ancora. Tale sistema ha il vantaggio di permettere una facile scansione<br />
dell’archivio alla ricerca di file da estrarre (e decomprimere) o un ampliamento dell’archivio in<br />
un momento successivo alla sua creazione. Un altro vantaggio è la minore sensibilità alla perdita<br />
dei dati: se una parte dell’archivio è danneggiato, dovrebbe essere possibile ripristinare almeno il<br />
resto. Lo svantaggio principale è che la compressione fatta in questo modo, a piccoli pezzi, non<br />
è molto efficiente.<br />
351.4.2 Compressione dopo l’archiviazione<br />
La compressione fatta dopo l’archiviazione elimina ogni possibilità di accedere ai dati contenuti<br />
nell’archivio e di poterlo ampliare, se non dopo averlo decompresso. Questo significa anche che<br />
un danneggiamento parziale dell’archivio implica la perdita di tutti i dati da quel punto in poi. 1<br />
Un altro tipo di problema deriva dalla difficoltà di distribuire un archivio compresso suddividendolo<br />
su più unità di memorizzazione. In questo caso però, l’efficienza della compressione è<br />
massima. Negli ambienti Unix, di fatto, è questa la scelta preferita.<br />
351.5 Archiviazione e recupero attraverso tar e gzip<br />
La coppia Tar e Gzip rappresenta lo standard nell’archiviazione dei dati: Tar genera un archivio<br />
non compresso che può comprendere anche collegamenti simbolici e file speciali; Gzip lo<br />
comprime generando un archivio più piccolo.<br />
La coppia funziona così bene che Tar è in grado di utilizzare Gzip direttamente senza dover far<br />
uso di pipeline, purché il risultato dell’archiviazione non debba essere suddiviso su più supporti.<br />
L’origine del nome Tar è Tape archive, ma questo programma permette ugualmente di gestire<br />
qualunque altro tipo di sistema di memorizzazione.<br />
La versione GNU di Tar (quella utilizzata normalmente nelle distribuzioni GNU/Linux), non<br />
memorizza percorsi assoluti.<br />
I programmi Tar e Gzip sono descritti rispettivamente nelle sezioni 74.1.2 e 74.2.1.<br />
1 Ci sono programmi di archiviazione che si comportano così anche se non subiscono compressioni successive.
14 volume VIII Argomenti avanzati e accessori<br />
Negli esempi seguenti si immagina di dover archiviare il contenuto della directory ‘~/<br />
lettere/’, equivalente a ‘/home/tizio/lettere/’, comprese eventuali sottodirectory<br />
discendenti.<br />
Negli esempi si cerca di utilizzare la forma tradizionale per l’indicazione delle opzioni standard<br />
di Tar. Alcune di queste possono fare a meno del trattino iniziale, come nel caso di ‘c’ e ‘x’. Altre<br />
opzioni hanno quel trattino, ma possono essere aggregate in un’unica serie di lettere, come nel<br />
caso di ‘czvf’, dove si ha l’unione di: ‘c’, ‘-z’, ‘-v’ e ‘-f’.<br />
351.5.1 Archiviazione diretta su dispositivi di memorizzazione<br />
L’archiviazione attraverso la registrazione diretta sui dispositivi utilizza completamente il supporto<br />
di memorizzazione destinatario, anche se la quantità di dati da archiviare è molto<br />
piccola.<br />
Quello sotto indicato è un esempio di archiviazione in un nastro magnetico singolo: l’opzione<br />
‘c’ sta per Create; ‘-f’ sta per File e permette di definire la destinazione dell’archiviazione;<br />
‘-z’ attiva la compressione attraverso ‘gzip’. Dal momento che si utilizza la compressione,<br />
l’archiviazione multivolume non è ammissibile.<br />
# tar czf /dev/ftape ~/lettere<br />
I dischetti possono essere utilizzati come i nastri, in modo sequenziale, ma questo lo si fa soltanto<br />
quando l’archivio generato non è contenibile in un solo dischetto: si ha quindi una copia<br />
multivolume e in tal caso non è ammissibile l’uso della compressione.<br />
# tar cf /dev/fd0u1440 -M ~/lettere<br />
In questo caso, l’opzione ‘-M’ sta proprio per Multivolume indicando quindi la possibilità che il<br />
supporto di destinazione non sia in grado di contenere l’intero archivio. In tal modo, Tar si prende<br />
cura di sospendere l’archiviazione ogni volta che viene raggiunta la capienza massima. Tar non<br />
è in grado di determinare da solo questa capacità, per cui, nell’esempio, il file di dispositivo<br />
dell’unità a dischetti è stato indicato in modo da riconoscerne la geometria, ma in alternativa si<br />
poteva utilizzare l’opzione ‘-L’ seguita dalla dimensione:<br />
# tar cf /dev/fd0 -M -L 1440 ~/lettere<br />
Quando si utilizzano in questo modo, i dischetti non contengono un file system e di conseguenza<br />
non possono essere montati. La lettura del loro contenuto avviene nello stesso modo della<br />
scrittura, attraverso il nome del dispositivo.<br />
L’archiviazione su dischetti, attraverso l’indicazione del file di dispositivo, richiede comunque<br />
che questi siano già stati inizializzati (a basso livello) secondo il formato che viene indicato.<br />
Non conta che siano vuoti: è importante che ci siano le tracce e i settori come previsto.
Copie di sicurezza 15<br />
351.5.2 Archiviazione normale su file<br />
Quando l’archiviazione può essere fatta su dischi (con file system ) di dimensione sufficiente<br />
a contenere l’archivio intero, invece di utilizzare l’opzione ‘-f’ per specificare un file di dispositivo,<br />
si può indicare direttamente un normalissimo file al loro interno, come nell’esempio<br />
seguente:<br />
$ tar cf /mnt/mo1/lettere.tar ~/lettere<br />
In pratica, nel caso appena visto, si utilizza un disco montato nella directory ‘/mnt/mo1/’ e si<br />
crea il file ‘lettere.tar’ al suo interno.<br />
L’archiviazione compressa, con l’utilizzo di ‘gzip’, può essere ottenuta semplicemente con<br />
l’opzione ‘-z’, come nell’esempio seguente:<br />
$ tar czf /mnt/mo1/lettere.tar.gz ~/lettere<br />
In tal caso l’estensione standard utilizzata (ma non obbligatoria) è ‘.tar.gz’ che rende esplicito<br />
il fatto che la compressione è stata fatta dopo l’archiviazione. In alternativa si può usare anche<br />
‘.tgz’, diffusa nei sistemi Dos.<br />
351.5.3 Archiviazione e percorsi<br />
Gli esempi seguenti, pur archiviando gli stessi dati, mostrano un modo diverso di registrare i<br />
percorsi all’interno dell’archivio. La directory di lavoro nel momento in cui si avvia il comando,<br />
è ‘/home/tizio/’, corrispondente alla directory personale dell’utente.<br />
/home/tizio$ tar czf /mnt/mo1/lettere.tar.gz ~/lettere<br />
/home/tizio$ tar czf /mnt/mo1/lettere.tar.gz /home/tizio/lettere<br />
/home/tizio$ tar czf /mnt/mo1/lettere.tar.gz lettere<br />
/home/tizio$ tar czf /mnt/mo1/lettere.tar.gz ./lettere<br />
Nei primi due esempi, viene archiviata l’indicazione del percorso precedente, ma pur essendo<br />
stato dato in modo assoluto (‘/home/tizio/lettere’), questo viene reso relativo da Tar, eliminando<br />
la prima barra obliqua che si riferisce alla directory radice. Questo comportamento<br />
riguarda almeno la realizzazione GNU di Tar.<br />
Negli ultimi due esempi, viene archiviata l’indicazione della sola directory ‘lettere/’, sempre<br />
in modo relativo.<br />
351.5.4 Archiviazione di periodi<br />
I file sono forniti di informazioni orarie. In base a queste è possibile eseguire delle copie di sicurezza<br />
riferite a dei periodi. Le copie di sicurezza a più livelli possono essere ottenute in modo<br />
semplificato attraverso l’uso dell’opzione ‘-N’ seguita da una data di partenza: si ottiene l’archiviazione<br />
di quanto variato a partire da una certa data; di solito si utilizza quella dell’ultima archiviazione<br />
completa. Il concetto di variazione, in questo caso, si deve intendere come variazione<br />
del contenuto o degli attributi. Quindi si tratta della data di modifica o della data di «creazione».<br />
$ tar czf /mnt/mo1/lettere.tar.gz -N 20030801 ~/lettere
16 volume VIII Argomenti avanzati e accessori<br />
In questo caso, la data che segue l’opzione ‘-N’ rappresenta la mezzanotte del primo agosto 2003.<br />
$ tar czf /mnt/mo1/lettere.tar.gz -N "20030801 15:30" ~/lettere<br />
Questo ultimo esempio aggiunge alla data l’indicazione di un’ora particolare, 15:30; per evitare<br />
che sia interpretato in maniera errata, il gruppo data-orario viene racchiuso tra virgolette.<br />
351.5.5 Archiviazione limitata a un’unità<br />
Quando si eseguono delle copie di sicurezza, è probabile che si voglia archiviare solo la situazione<br />
di una certa unità di memorizzazione (partizione o directory condivisa in rete). In tal caso si<br />
deve indicare precisamente questo limite con l’opzione ‘-l’ (Limit).<br />
351.5.6 Estrazione dei percorsi<br />
Quando si accede all’archivio per estrarne il contenuto o per compararlo con i dati originali, entra<br />
in gioco il problema dei percorsi. I dati vengono estratti normalmente nella directory corrente,<br />
oppure vengono comparati utilizzando come punto di partenza la directory corrente. Quindi, se<br />
l’archivio contiene la directory degli esempi precedenti, registrata a partire dalla radice (ma come<br />
già spiegato, senza l’indicazione della radice stessa), questi verranno estratti in ‘./home/tizio/<br />
lettere/’, oppure comparati con i dati contenuti a partire da questo percorso.<br />
Se in fase di estrazione o comparazione si vuole fare riferimento a percorsi assoluti, si può utilizzare<br />
l’opzione ‘-P’. In questo modo si afferma esplicitamente che i percorsi indicati nell’archivio<br />
vanno considerati come discendenti dalla directory radice.<br />
Questo particolare della gestione dei percorsi è molto importante quando si fanno le copie di<br />
sicurezza: spesso si hanno dischi montati su punti di innesto provvisori, pertanto non è molto<br />
conveniente memorizzare anche il percorso su cui sono montati.<br />
351.5.7 Recupero<br />
Per poter effettuare un recupero di dati da un archivio è necessario conoscere in particolare il<br />
modo in cui questo era stato creato: normale, compresso, multivolume.<br />
In generale, per recuperare dati da un archivio si utilizza l’opzione ‘x’ (Extract) al posto di ‘c’ e<br />
a essa si devono eventualmente aggiungere ‘-z’ nel caso di estrazione da un archivio compresso<br />
con ‘gzip’ o ‘-M’ nel caso di un archivio multivolume.<br />
Durante il recupero di una copia di sicurezza è importante fare in modo che i dati riprodotti mantengano<br />
gli stessi attributi originali (permessi e proprietà). Per questo si aggiungono le opzioni<br />
‘-p’ (riproduce i permessi) e ‘--same-owner’ (riproduce le proprietà: UID e GID).<br />
L’esempio seguente mostra un recupero da un archivio multivolume su dischetti:<br />
~$ tar x -M -p --same-owner -f /dev/fd0u1440<br />
L’esempio seguente mostra un recupero con percorso assoluto: i percorsi indicati all’interno<br />
dell’archivio vengono aggiunti alla directory radice:<br />
$ tar xz -P -p --same-owner -f /mnt/mo1/lettere.tar.gz
Copie di sicurezza 17<br />
351.5.8 Recupero parziale<br />
Il recupero parziale del contenuto di un archivio Tar può essere fatto per file singoli o per directory,<br />
oppure attraverso l’uso di caratteri jolly. In questo ultimo caso però, occorre fare attenzione<br />
a evitare che la shell esegua l’espansione: è compito di Tar determinare a cosa corrispondano<br />
all’interno dei suoi archivi. Questo è un po’ quello che accade a Find con l’opzione ‘-name’: è<br />
Find stesso ad analizzare i caratteri jolly.<br />
Valgono le regole solite: l’asterisco rappresenta un insieme di caratteri qualunque; il punto interrogativo<br />
rappresenta un carattere qualsiasi; le parentesi quadre rappresentano un carattere a<br />
scelta tra un insieme o tra un intervallo determinato.<br />
Quando si indicano nomi di file o directory, o quando si utilizzano i caratteri jolly, occorre tenere<br />
presente che si sta facendo riferimento ai dati contenuti nell’archivio, con i percorsi memorizzati<br />
originariamente. Inoltre, se con i caratteri jolly si determina la corrispondenza con una directory,<br />
si ottiene l’estrazione del contenuto complessivo di quella.<br />
L’esempio seguente mostra in che modo potrebbero essere recuperate le lettere contenute nella<br />
directory ‘home/tizio/lettere/nuove/’ (l’esempio appare diviso su due righe, a causa della<br />
sua lunghezza):<br />
$ tar xz -P -p --same-owner -f /mnt/mo1/lettere.tar.gz ←↪<br />
↩→home/tizio/lettere/nuove<br />
L’esempio seguente mostra l’estrazione di tutti i file e delle directory corrispondenti a ‘home/<br />
tizio/lettere/ve * ’. Gli apici sono necessari per evitare che intervenga la shell a espandere<br />
l’asterisco, che invece deve essere interpretato da Tar.<br />
$ tar xz -P -p --same-owner -f /mnt/mo1/lettere.tar.gz ←↪<br />
↩→’home/tizio/lettere/ve*’<br />
351.5.9 Elenco e controllo<br />
Per ottenere un elenco del contenuto di un archivio e per compararne il contenuto con i dati<br />
originali, valgono le stesse regole del recupero dei dati. In particolare, al posto dell’opzione ‘x’<br />
si deve utilizzare ‘t’ (List) per gli elenchi e ‘d’ (Diff ) per la comparazione.<br />
351.6 Archiviazione di un file system<br />
L’archiviazione di un file system intero, va fatta considerando le caratteristiche di questo, in particolare<br />
della sua struttura fisica: partizioni e condivisione attraverso la rete. In generale dovrebbe<br />
essere conveniente l’archiviazione separata per ogni partizione e per ogni file system condiviso<br />
in rete.<br />
Oltre a questo occorre evitare di archiviare anche l’archivio che si sta creando: quando la destinazione<br />
dell’archiviazione è un file su disco, questo deve essere montato da qualche parte e per<br />
questo si potrebbe creare un circolo vizioso.<br />
Ci sono directory che, per la loro natura, non conviene o non devono essere archiviate: per<br />
‘/tmp/’ non conviene; con ‘/proc/’ dei sistemi GNU/Linux non si deve. In questi casi si deve<br />
solo ricordare di ricreare queste directory, nel momento in cui fosse necessario il recupero.<br />
Naturalmente non bisogna dimenticare i permessi: ‘/tmp/’ 17778 e ‘/proc/’ 05558.
18 volume VIII Argomenti avanzati e accessori<br />
351.6.1 Strumenti per il recupero<br />
L’archiviazione di copie di sicurezza non è sufficiente a garantirsi contro gli incidenti: in che<br />
modo si può avviare un elaboratore in cui è appena stato sostituito il disco fisso? Evidentemente,<br />
occorre essere più previdenti e predisporre in anticipo gli strumenti necessari per preparare le<br />
partizioni di un nuovo disco fisso e per recuperare i dati archiviati precedentemente.<br />
Questo argomento viene trattato nei prossimi capitoli.<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Dischetti di emergenza con GNU/Linux<br />
Capitolo 352<br />
Nel momento dell’imprevisto si può agire solo se si è stati previdenti, pensando ai tipi di situazioni<br />
che si possono presentare e preparando gli strumenti necessari in anticipo. Le copie di<br />
sicurezza sono la prima cosa da fare per prepararsi ai guai, ma da sole non bastano: occorrono<br />
altri strumenti per rimettere in sesto un sistema prima di poter effettuare un eventuale recupero<br />
dalle copie.<br />
352.1 Dischetti<br />
Di fronte a un problema qualunque di una gravità tale da non permettere l’avvio di un sistema<br />
locale, l’unica possibilità di intervenire è data da strumenti su dischetti (oppure su CD-ROM, ma<br />
non è questo l’argomento del capitolo). Esistono diversi tipi di dischetti che possono essere stati<br />
preparati in precedenza:<br />
• dischetti di avvio;<br />
• dischetti di installazione della distribuzione GNU/Linux;<br />
• dischetti preparati appositamente.<br />
352.1.1 Dischetti di avvio<br />
Un dischetto di avvio può essere utile quando, per qualche motivo, il metodo normale di caricamento<br />
del sistema operativo non funziona più. Esistono almeno tre tipi di dischetti di questo<br />
tipo:<br />
• dischetti con un settore di avvio, ma senza kernel;<br />
• dischetti con un settore di avvio e con il kernel;<br />
• dischetti contenenti solo l’immagine del kernel.<br />
352.1.2 Settore di avvio senza il kernel<br />
La soluzione del dischetto senza kernel non è adatta per avviare un sistema in difficoltà: è solo<br />
un modo per verificare una configurazione di un sistema di avvio come LILO quando non si<br />
vuole interferire con l’MBR del disco fisso. In pratica, nel caso di LILO si ottiene semplicemente<br />
indicando nel file ‘/etc/lilo.conf’ la riga ‘boot=/dev/fd0’, come nell’esempio seguente:<br />
boot=/dev/fd0<br />
prompt<br />
timeout=50<br />
image=/boot/vmlinuz<br />
label=linux<br />
root=/dev/hda2<br />
read-only<br />
Quando viene avviato l’eseguibile ‘lilo’ con questa configurazione, si ottiene la scrittura del<br />
primo settore del primo dischetto (il dischetto deve essere stato inizializzato in precedenza e può<br />
19
20 volume VIII Argomenti avanzati e accessori<br />
anche non contenere alcun file system). Ma in questo modo si intende che i file per il caricamento<br />
del sistema si devono trovare nella directory ‘/boot/’ del momento in cui si esegue ‘lilo’,<br />
ovvero nel file system in funzione in quel momento e non nel dischetto. Inoltre, anche il kernel<br />
‘/boot/vmlinuz’ si intende contenuto in quel file system e non nel dischetto.<br />
Se si utilizza GRUB, il file ‘/boot/grub/menu.lst’ rimane lo stesso, ma si danno dei comandi<br />
differenti per inserire il settore di avvio nel dischetto. Si osservi che il dischetto deve essere<br />
inserito nell’unità prima di avviare l’eseguibile ‘grub’:<br />
# grub [ Invio ]<br />
grub> root (hd0,1) [ Invio ]<br />
Filesystem type is ext2fs, partition type 0x83<br />
grub> setup (fd0) [ Invio ]<br />
Checking if "/boot/grub/stage1" exists... yes<br />
Checking if "/boot/grub/stage2" exists... yes<br />
Checking if "/boot/grub/e2fs_stage1_5" exists... yes<br />
Running "embed /boot/grub/e2fs_stage1_5 (fd0)"... failed (this is not fatal)<br />
Running "embed /boot/grub/e2fs_stage1_5 (hd0,1)"... failed (this is not fatal)<br />
Running "install /boot/grub/stage1 d (fd0) /boot/grub/stage2 p ←↪<br />
↩→/boot/grub/menu.lst"... succeeded<br />
Done.<br />
grub> quit [ Invio ]<br />
Quando si avvia con un dischetto fatto in questo modo, il programma contenuto nel primo settore<br />
va alla ricerca del kernel e degli altri file, necessari per il caricamento del sistema, nel disco fisso<br />
nel momento dell’utilizzo di LILO o di GRUB. Se il sistema non si avvia perché questi file o il<br />
kernel sono stati spostati, a nulla serve un dischetto fatto in questo modo.<br />
352.1.3 Settore di avvio e kernel<br />
Per fare in modo che il dischetto avvii un kernel contenuto al suo interno, è necessario che questo<br />
dischetto contenga un file system e un sistema di avvio.<br />
Nel caso di LILO deve contenere una copia della directory ‘/boot/’ con il suo contenuto, la<br />
directory ‘/etc/’ con il file ‘lilo.conf’ e deve essere riprodotta anche directory ‘/dev/’ con<br />
il file di dispositivo ‘fd0’ (assieme agli altri file di dispositivo necessari a individuare i dischi o<br />
le partizioni a cui si vuole fare riferimento). Quindi è sufficiente eseguire ‘lilo’ con l’opzione<br />
‘-r’, come descritto nella sezione 18.4.<br />
Nel caso di GRUB, il dischetto deve contenere la directory ‘/boot/grub/’ con i file ‘stage1’,<br />
‘stage2’ e ‘menu.lst’. Il file del kernel può trovarsi in qualunque posizione (con qualunque<br />
nome), purché il file ‘menu.lst’ sia stato predisposto di conseguenza. Fatto questo, si rende<br />
avviabile il dischetto nel modo consueto di GRUB:<br />
# grub [ Invio ]<br />
grub> root (fd0) [ Invio ]<br />
grub> setup (fd0) [ Invio ]<br />
grub> quit [ Invio ]
Dischetti di emergenza con GNU/Linux 21<br />
È bene ricordare che esiste anche la possibilità di usare SYSLINUX, che permette di realizzare un<br />
dischetto con le stesse caratteristiche e con meno difficoltà. SYSLINUX è descritto nel capitolo<br />
16.<br />
Rispetto alla prossima tecnica, un dischetto contenente il sistema di avvio e il kernel, come appena<br />
descritto, è uno strumento di avvio più completo perché permette di specificare, sia attraverso<br />
la configurazione del sistema di avvio, sia per mezzo dei comandi che, a seconda del tipo sistema<br />
di avvio, possono essere impartiti prima del caricamento del kernel, alcuni parametri di avvio<br />
particolari del quale il proprio sistema potrebbe avere bisogno.<br />
352.1.4 Immagine del kernel<br />
L’ultima possibilità è la più semplice e, sotto questo aspetto, anche la più sicura: il file del kernel<br />
viene copiato sul dispositivo del dischetto, senza fare uso di alcun file system. Si può utilizzare<br />
uno dei due modi seguenti.<br />
# cp vmlinuz /dev/fd0<br />
# dd if=vmlinuz <strong>of</strong>=/dev/fd0<br />
Evidentemente, il file del kernel è speciale perché riesce ad avviare se stesso. Il kernel da solo,<br />
però, potrebbe non sapere quale dispositivo contiene il file system principale da montare al momento<br />
dell’avvio. È necessario utilizzare il programma ‘rdev’ per inserire questa e altre notizie<br />
nel kernel.<br />
Supponendo che si debba avviare la partizione ‘/dev/hda2’, inizialmente in sola lettura, si<br />
procede come segue per fare queste annotazioni in un kernel copiato in un dispositivo ‘/dev/<br />
fd0’:<br />
# rdev /dev/fd0 /dev/hda2<br />
# rdev -R /dev/fd0 1<br />
352.1.5 Dischetti di una distribuzione<br />
La maggior parte delle distribuzioni GNU/Linux predispone dei dischetti di emergenza che<br />
consentono generalmente di accedere al disco fisso e di fare delle piccole riparazioni.<br />
Tra tutti, i dischetti più rudimentali sono quelli della distribuzione Slackware. La loro semplicità<br />
è da considerare un pregio, dal momento che utilizzandoli ci si trova di fronte un sistema<br />
GNU/Linux più o meno tradizionale, senza ottimizzazioni particolari.<br />
352.1.6 Dischetti realizzati appositamente<br />
Ogni sistema ha le proprie caratteristiche ed esigenze. I dischetti di emergenza preparati da altri,<br />
oppure ottenuti da una distribuzione GNU/Linux, possono adattarsi a un certo insieme di<br />
situazioni, ma non a tutte.<br />
Quando si vuole essere sicuri di avere gli strumenti giusti al momento giusto, occorre che questi<br />
siano stati preparati e collaudati bene, in modo da non sprecare tempo inutilmente. In sostanza,<br />
la realizzazione o la personalizzazione di dischetti di emergenza è una tappa importante per chi<br />
vuole amministrare seriamente il proprio sistema.
22 volume VIII Argomenti avanzati e accessori<br />
352.2 Personalizzazione di dischetti di emergenza<br />
L’utilizzo di dischetti di emergenza preparati da altri è un buon punto di partenza, ma le<br />
particolarità che ogni sistema può avere consigliano almeno una personalizzazione del kernel.<br />
352.2.1 Loopback block device<br />
Per poter costruire o almeno personalizzare dei dischetti di emergenza è particolarmente utile<br />
attivare nel kernel la gestione diretta delle immagini di questi (sezione 29.2.7).<br />
In questo modo, un’immagine non compressa di un dischetto può essere montata con un comando<br />
simile a quello seguente:<br />
mount -o loop -t tipo_di_file_system file_immagine punto_di_innesto<br />
352.2.2 disco RAM<br />
Il file system principale può essere caricato in memoria centrale (RAM) e montato da lì. Si ottiene<br />
un cosiddetto disco RAM. A parte ogni considerazione sui vantaggi che questo può avere nelle<br />
prestazioni del sistema, si tratta di una modalità quasi obbligata per l’utilizzo di dischetti di<br />
emergenza. Infatti, un disco RAM può essere ottenuto a partire da un’immagine compressa: è il<br />
kernel stesso che la espande in memoria all’atto del caricamento. Quindi, si può fare stare in un<br />
dischetto un’immagine di dimensioni superiori alla sua capacità.<br />
Oltre a questo vantaggio, che però richiede la presenza di molta memoria RAM, un dischetto<br />
contenente un file system che è stato trasferito nella RAM, può essere rimosso subito dopo il<br />
suo caricamento, permettendo il riutilizzo dell’unità a dischetti, magari per accedere ad altri<br />
programmi di servizio non inclusi nel disco RAM.<br />
Per la gestione di un disco RAM occorre che il kernel sia configurato appositamente (29.2.7).<br />
352.2.3 Scostamento (<strong>of</strong>fset)<br />
Quando il kernel carica un disco RAM da un’immagine contenuta in un dischetto, deve conoscere<br />
la posizione di inizio di questa immagine. Ciò è importante quando sia il kernel che l’immagine<br />
da caricare risiedono nello stesso dischetto. Quando l’immagine da caricare nel disco RAM è<br />
contenuta in un dischetto separato, questa si troverà normalmente a partire dall’inizio di questo,<br />
cioè da uno scostamento pari a zero.<br />
352.3 Dischetti Slackware<br />
I dischetti della distribuzione Slackware sono i più semplici ed efficaci in situazioni di emergenza.<br />
Per essere avviati necessitano di un dischetto di avvio (boot) contenente il kernel, ma questo può<br />
essere eventualmente predisposto localmente in modo da avere a disposizione la configurazione<br />
più adatta al proprio sistema. Questi dischetti sono reperibili normalmente presso gli indirizzi<br />
seguenti:<br />
<br />
<br />
Il dischetto migliore per la soluzione di problemi è rappresentato dall’immagine compressa<br />
‘rescue.gz’. Se si intende utilizzare anche un dischetto di avvio ottenuto dalla distribuzione,
Dischetti di emergenza con GNU/Linux 23<br />
occorre sceglierlo in base alle indicazioni che si trovano nei file di testo inclusi nelle directory<br />
indicate.<br />
L’immagine ‘rootdsks/rescue.gz’ è compressa e contiene in pratica un disco in formato<br />
Ext2 di qualche mebibyte (simbolo: Mibyte). Questo implica che per poterne fare uso occorre<br />
molta memoria RAM.<br />
Nelle prime versioni della distribuzione Slackware era distribuita un’immagine ‘rescue.gz’<br />
molto più piccola, che poteva essere espansa e collocata comodamente su un dischetto da<br />
1440 Kibyte. Questa immagine è ancora disponibile e si trova nel percorso ‘rootdsks/<br />
obsolete/rescue.gz’. Il fatto di poterla decomprimere su un dischetto da 1440 Kibyte permette<br />
di evitare il caricamento nella RAM. Per elaboratori aventi fino a 8 Mibyte di memoria<br />
RAM, questo è l’unico dischetto di emergenza che possa essere utilizzato ragionevolmente.<br />
Se si intende utilizzare l’immagine ‘rootdsks/obsolete/rescue.gz’, è necessario<br />
avviare con un kernel in grado di gestire i vecchi binari a.out.<br />
352.3.1 Organizzazione dei dischetti Slackware<br />
Come già accennato, la distribuzione Slackware mette a disposizione immagini di dischetti di avvio,<br />
contenenti essenzialmente il kernel, assieme a immagini di dischetti contenenti il file system<br />
principale (root).<br />
Le immagini per l’avvio rappresentano dischetti con un file system normale, contenente un settore<br />
di avvio, la directory ‘/boot/’ e il kernel. Si tratta in pratica di dischetti realizzati in modo<br />
analogo a quanto descritto in precedenza nella sezione 352.1.1, quando si faceva riferimento a<br />
dischetti contenenti questi elementi. Le immagini dei dischetti di avvio, anche se non sono di<br />
dimensioni pari a quelle di un dischetto normale, non dovrebbero essere compresse e si possono<br />
copiare semplicemente sul dispositivo del dischetto di destinazione.<br />
# dd if=net.i <strong>of</strong>=/dev/fd0<br />
Le immagini dei dischetti contenenti il sistema minimo (root), sono invece dischetti di qualche<br />
mebibyte, compressi in modo da poter essere collocati all’interno di un dischetto da 1440 Kibyte,<br />
costringendo però all’uso di un disco RAM.<br />
352.3.2 Utilizzare un kernel personalizzato<br />
Per abbinare un kernel personalizzato a un dischetto contenente il sistema minimo della distribuzione<br />
Slackware, si potrebbe ricostruire un dischetto di avvio seguendo le stesse modalità usate<br />
dalla distribuzione stessa, oppure in maniera più semplice, copiando il kernel in un dischetto<br />
direttamente attraverso il suo dispositivo e poi intervenendo con il programma ‘rdev’. Viene<br />
descritta l’ultima di queste modalità.<br />
# dd if=bzImage <strong>of</strong>=/dev/fd0<br />
La copia di un kernel in un dischetto, attraverso il suo dispositivo, genera il solito dischetto<br />
di avviamento già descritto tante volte. Questo kernel su dischetto deve però essere informato<br />
di dove e come fare il caricamento del sistema. Il file system principale viene caricato da un<br />
dischetto, quindi si scrive questo messaggio nel kernel attraverso ‘rdev’.
24 volume VIII Argomenti avanzati e accessori<br />
# rdev /dev/fd0 /dev/fd0<br />
I dischetti contenenti il sistema minimo della distribuzione Slackware non prevedono il controllo<br />
del file system e il successivo montaggio in lettura e scrittura. In pratica, il file system principale<br />
deve essere montato inizialmente in lettura-scrittura.<br />
# rdev -R /dev/fd0 0<br />
Infine si deve specificare che:<br />
• l’immagine del dischetto contenente il sistema (compressa o meno che sia) si trova in un<br />
dischetto separato e parte dalla posizione iniziale: lo scostamento è pari a zero;<br />
• si vuole, oppure non si vuole, che tale dischetto sia caricato in un disco RAM;<br />
• si vuole un preavviso per sapere quando si può togliere il dischetto del kernel per inserire<br />
il dischetto contenente il sistema.<br />
Per fare questo si agisce su una serie di bit configurabili attraverso ‘rdev’ con l’opzione ‘-r’:<br />
• i primi 11 (dal bit 0 al bit 10) permettono di definire l’indirizzo dello scostamento (in<br />
blocchi di 1024 byte);<br />
• il bit 14 indica che si vuole caricare un disco RAM;<br />
• il bit 15 indica che si vuole avere una pausa per lo scambio dei dischetti.<br />
Se si vuole caricare il file system principale in un disco RAM si deve utilizzare ‘rdev’ nel modo<br />
seguente:<br />
# rdev -r /dev/fd0 49152<br />
infatti, 2 15 + 2 14 + 0 = 49152.<br />
Se invece non si vuole il disco RAM si deve utilizzare ‘rdev’ nel modo seguente:<br />
# rdev -r /dev/fd0 32768<br />
infatti, 2 15 + 0 + 0 = 32768.<br />
352.4 Kernel per dischetti di emergenza<br />
Quando si configura un kernel da utilizzare assieme a dischetti di emergenza, occorre tenere presente<br />
che non è ragionevolmente possibile utilizzare i moduli ed è importante attivare determinate<br />
caratteristiche che di solito non vengono considerate per i sistemi normali.<br />
• Gestione dei binari a.out.<br />
I dischetti di emergenza obsoleti sono nel vecchio formato a.out. Il kernel deve essere stato<br />
predisposto per gestirli:<br />
Kernel support for a.out binaries
Dischetti di emergenza con GNU/Linux 25<br />
• File system Minix.<br />
Il file system più utilizzato in passato per i dischetti di emergenza, specialmente quando<br />
questi dovevano essere di dimensioni minime, è Minix. Anche se adesso i dischetti di<br />
emergenza che si trovano in circolazione sono prevalentemente in formato Ext2, conviene<br />
includere la gestione di questo vecchio tipo di formato:<br />
Minix fs support<br />
• dischi RAM.<br />
Anche se non si intendono utilizzare dischetti caricati in memoria RAM, vale la pena di<br />
preparare un kernel che ne permetta comunque l’utilizzo:<br />
RAM disk support<br />
• Porta parallela PLIP.<br />
Un kernel per un dischetto di emergenza deve permettere la gestione della rete (TCP/IP)<br />
e, in particolare, invece di attivare la gestione della porta parallela per la stampa, conviene<br />
attivare la gestione della connessione PLIP:<br />
PLIP (parallel port) support<br />
352.4.1 Tastiera<br />
Quando si usano dei dischetti di emergenza si hanno già molte limitazioni e a queste si aggiunge<br />
anche la scomodità di una tastiera che non combacia con quella USA.<br />
Si può risolvere il problema direttamente nel kernel senza dover tentare di inserire il programma<br />
‘loadkeys’ in dischetti già troppo piccoli. È sufficiente trovare il file della mappa della tastiera<br />
italiana (di solito si tratta del file ‘it.kmap’ collocato nella directory ‘/usr/share/keymaps/<br />
piattaforma/qwerty/’) e quindi generare il sorgente ‘defkeymap.c’. Si procede come segue,<br />
nel caso si utilizzi la piattaforma i386.<br />
# cd /usr/src/linux/drivers/char<br />
# loadkeys --mktable /usr/share/keymaps/i386/qwerty/it.kmap ←↪<br />
↩→> defkeymap.c<br />
La compilazione successiva di un nuovo kernel utilizzerà la mappa italiana come predefinita e<br />
non ci sarà bisogno di utilizzare ‘loadkeys’.<br />
352.5 Cavi<br />
Quando si ha la disponibilità di più elaboratori, è probabile che il danno presentatosi su uno di<br />
questi non si sia riprodotto in tutti. Una piccola rete locale potrebbe essere di aiuto in situazioni di<br />
emergenza e in sua mancanza potrebbero andare bene anche dei cavi paralleli PLIP. Questo tipo<br />
di cavo viene descritto nella parte lxxxvii. La sua realizzazione non è difficile: basta un piccolo<br />
saldatore, un po’ di stagno, due connettori maschi DB-25 e una piattina multipolare con almeno<br />
13 fili. La schermatura non è necessaria.<br />
Con i dischetti della distribuzione Slackware, preferibilmente con l’immagine ‘resque.gz’, è<br />
possibile stabilire una semplice connessione con un servente NFS.
26 volume VIII Argomenti avanzati e accessori<br />
352.5.1 Ethernet<br />
Attraverso una connessione Ethernet, con un’interfaccia riconosciuta come ‘eth0’, si può agire<br />
come nell’esempio seguente. Si suppone in particolare che l’indirizzo di rete sia 192.168.1.0,<br />
che la maschera di rete sia 255.255.255.0 e di poter utilizzare l’indirizzo IP 192.168.1.17 per<br />
l’elaboratore avviato con i dischetti di emergenza.<br />
# ifconfig eth0 192.168.1.17 netmask 255.255.255.0<br />
# route add -net 192.168.1.0 netmask 255.255.255.0 dev eth0<br />
Per verificare la connessione si può fare un ‘ping’ verso l’elaboratore da raggiungere: potrebbe<br />
trattarsi dell’indirizzo 192.168.1.1.<br />
# ping 192.168.1.1<br />
Se tutto è andato bene si può procedere. Si suppone che l’elaboratore 192.168.1.1 metta a<br />
disposizione il suo file system a partire dalla directory radice.<br />
# mount -t nfs 192.168.1.1:/ /mnt<br />
352.5.2 PLIP<br />
Nel caso di una connessione PLIP, la procedura è un po’ differente. In particolare bisogna ricordare<br />
che l’elaboratore dal quale si vogliono attingere i dati attraverso il protocollo NFS, deve<br />
avere un kernel compilato in modo da gestire questo tipo di connessione.<br />
Si fa riferimento allo stesso esempio riportato nella sezione precedente. L’unica differenza sta<br />
nell’interfaccia usata per la comunicazione: si suppone che sia stata riconosciuta la ‘plip1’ da<br />
entrambi i lati.<br />
Il procedimento di connessione va fatto da entrambi i capi, infatti, raramente un elaboratore<br />
ha una connessione PLIP stabile, per cui non si trova ad avere un indirizzo e una tabella di<br />
instradamento già pronti.<br />
Dal lato dell’elaboratore avviato con i dischetti si procede come segue:<br />
rescue# ifconfig plip1 192.168.1.17 pointopoint 192.168.1.1<br />
rescue# route add -host 192.168.1.17 dev plip1<br />
rescue# route add -host 192.168.1.1 dev plip1<br />
Dal lato dell’elaboratore servente si effettua l’operazione inversa:<br />
server# ifconfig plip1 192.168.1.1 pointopoint 192.168.1.17<br />
server# route add -host 192.168.1.1 dev plip1<br />
server# route add -host 192.168.1.17 dev plip1<br />
Per verificare la connessione si può provare con una richiesta di eco:<br />
rescue# ping 192.168.1.1<br />
Se tutto è andato bene si può procedere montando il file system di rete:
Dischetti di emergenza con GNU/Linux 27<br />
rescue# mount -t nfs 192.168.1.1:/ /mnt<br />
352.5.3 Considerazioni accessorie<br />
Il dischetto di emergenza ha bisogno di un altro punto di innesto per accedere a un disco fisso<br />
locale. È sufficiente creare un’altra directory.<br />
Quando si accede a un servente NFS e non è possibile farlo mantenendo i privilegi dell’utente<br />
‘root’, una semplice copia attraverso ‘cp -dpR’ non dà un risultato garantito: alcuni file potrebbero<br />
risultare inaccessibili in lettura. La cosa si risolve facilmente impacchettando quello che<br />
serve nell’elaboratore di origine e dando a questo archivio tutti i permessi necessari.<br />
352.6 Utenti e gruppi<br />
Quando si utilizza un sistema operativo minimo, avviato attraverso dischetti di emergenza, per<br />
recuperare i dati da uno o più archivi, occorre fare mente locale al problema dell’abbinamento<br />
utenti/gruppi, UID/GID.<br />
Trattandosi di un sistema minimo, conterrà alcuni nomi di utenti e di gruppi, presumibilmente<br />
non «umani», ma comunque esistenti. Solitamente, questi nomi di utenti e di gruppi sono standardizzati,<br />
tuttavia il loro abbinamento con numeri UID/GID non è sempre uniforme. A questo<br />
punto, se si recuperano i dati di un sistema in cui questi nomi non corrispondono esattamente,<br />
si rischia di riprodurre una copia differente, che non sarà valida quando il sistema normale sarà<br />
ripristinato.<br />
Se non ci sono alternative, si può accettare l’inconveniente, riavviare il sistema rigenerato e<br />
ripetere il recupero. In questo modo, i file verranno sovrascritti e le proprietà saranno abbinate in<br />
base ai nuovi file ‘/etc/passwd’ e ‘/etc/group’.<br />
In generale, proprio per questo problema, sarebbe opportuno che il dischetto di emergenza<br />
contenesse esclusivamente l’indicazione dell’utente e del gruppo ‘root’, eliminando<br />
qualunque altro tipo di utente di sistema.<br />
352.7 Riferimenti<br />
• Small Linux<br />
<br />
• LOAF: Linux on a floppy<br />
<br />
• Tomsrtbt: the most GNU/Linux on one floppy<br />
<br />
• Trinux<br />
<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
28 volume VIII Argomenti avanzati e accessori
Parte lxx<br />
Informatica gestionale<br />
353 Codici a barre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
353.1 Codice di controllo «modulo n» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
353.2 UPC-E e UPC-A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />
353.3 EAN-8 e EAN-13 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />
353.4 Code 39 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />
353.5 Code 128 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .39<br />
353.6 ITF, ovvero i25 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />
353.7 Sistemi bidimensionali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />
353.8 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />
354 Barcode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />
354.1 Utilizzo del programma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .46<br />
354.2 Codifica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47<br />
355 Trasformazione in lettere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />
355.1 Da numero a sequenza alfabetica pura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />
355.2 Da numero a numero romano . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .50<br />
355.3 Da numero a lettere, nel senso verbale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .53<br />
29
Codici a barre<br />
Capitolo 353<br />
I codici a barre sono dati memorizzati in forma ottica, attraverso l’uso di barre verticali che<br />
possono essere lette e interpretate facilmente con strumenti non troppo complessi. La tecnica dei<br />
codici a barre nasce negli anni 1960 e si diffonde negli anni 1970, con lo scopo di identificare<br />
rapidamente imballaggi e merci.<br />
Gli standard sui codici a barre sono molti e il problema più importante da risolvere quando<br />
si vogliono usare è il decidere quale sia quello più conveniente per i propri fini. Si parla di<br />
simbologia per fare riferimento al tipo di codice a barre, ovvero allo standard di rappresentazione<br />
dei dati; la simbologia definisce implicitamente il tipo di dati che possono essere memorizzati.<br />
Per fare un esempio abbastanza comune, i codici ISBN dei libri sono scritti usando codici a<br />
barre di tipo EAN-13, che si compongono di 13 cifre numeriche; in questo caso, la simbologia è<br />
EAN-13, con la quale si vanno a rappresentare in pratica i codici ISBN.<br />
Le rappresentazioni normali di un codice a barre sono a una sola dimensione, ovvero, è prevista<br />
una lettura orizzontale unica. Nella lettura vengono attraversate barre verticali nere e spazi bianchi;<br />
queste barre di larghezze differenti e gli spazi di ampiezze diverse sono gli elementi della<br />
simbologia; ogni simbologia usa un proprio numero di elementi differenti. Nel capitolo vengono<br />
descritte brevemente alcune simbologie standard.<br />
353.1 Codice di controllo «modulo n»<br />
Alcuni tipi di codici numerici utilizzano un numero di controllo (o codice di controllo) per permettere<br />
una verifica facile dell’integrità del dato rappresentato. Esiste un genere comune di algoritmi<br />
per il calcolo di tali numeri di controllo, a cui si fa spesso riferimento con la definizione<br />
modulo n, dove n è un numero intero maggiore di uno.<br />
In questo modo si fa riferimento a una somma di valori, ottenuta moltiplicando ogni cifra del<br />
numero di partenza, compreso il numero di controllo, per un certo peso (un altro numero intero<br />
positivo), che deve essere un multiplo del numero n stabilito. Si osservi l’esempio seguente, in<br />
cui il numero di controllo finale è calcolato con i pesi dati, dividendo per il modulo 5:<br />
5 + 12 + 15 + 14 + 4 = 50<br />
Valore 1 3 5 7 4<br />
Peso 5 4 3 2 1<br />
Peso*Valore 5 12 15 14 4<br />
50 è divisibile perfettamente per cinque, senza lasciare resti, garantendo l’integrità del valore.<br />
In pratica, il peso che si dà al valore da usare come numero di controllo è solitamente uno, per<br />
cui diventa facile il calcolo di questa cifra:<br />
5 + 12 + 15 + 14 = 46;<br />
46 / 5 = 9, con il resto di 1;<br />
5 - 1 = 4, ovvero il valore cercato come numero di controllo.<br />
30
Codici a barre 31<br />
353.2 UPC-E e UPC-A<br />
UPC è un insieme di simbologie standard utilizzato in particolare negli Stati Uniti e nel Canada.<br />
Con UPC-E e UPC-A si possono rappresentare solo cifre numeriche: UPC-A consente di rappresentare<br />
11 cifre più una di controllo; UPC-E consente di rappresentare sei cifre, senza codice di<br />
controllo (il controllo di integrità avviene in forma differente).<br />
La figura 353.1 mostra rispettivamente l’esempio di 123456 con UPC-E e di 12345678901 con<br />
UPC-A.<br />
Figura 353.1. Esempi di codici a barre con simbologia UPC-E e UPC-A.<br />
0 123456 5 1 23456 78901 2<br />
Gli elementi utilizzati nella simbologia UPC sono otto, composti da quattro tipi di barre nere e<br />
quattro tipi di spazi.<br />
Il codice di controllo di UPC-A si calcola moltiplicando in modo alterno le cifre che compongono<br />
il numero, per tre, o per uno, sommando alla fine i risultati. Ciò che si ottiene si divide per 10 e<br />
si tiene il resto; infine, 10 meno il resto ottenuto dà il codice di controllo cercato (modulo 10).<br />
Per esempio, nel caso di 12345678901 si ottiene il codice di controllo due, in base al calcolo<br />
seguente:<br />
Valore 1 2 3 4 5 6 7 8 9 0 1<br />
Peso 3 1 3 1 3 1 3 1 3 1 3<br />
Peso*Valore 3 2 9 4 15 6 21 8 27 0 3<br />
Il totale che si ottiene è 98; pertanto: 98/10 = 9 con un resto di 8; 10-8 = 2.<br />
353.3 EAN-8 e EAN-13<br />
EAN (European article number) è un insieme di simbologie standard di origine europea,<br />
utilizzato anche in altri paesi, nato come estensione delle simbologie UPC.<br />
EAN-8 e EAN-13 permettono di rappresentare solo cifre numeriche: EAN-8 consente di rappresentare<br />
sette cifre più una di controllo, mentre EAN-13 consente di rappresentare 12 cifre<br />
numeriche più una di controllo.<br />
La figura 353.2 mostra rispettivamente l’esempio di 1234567 con EAN-8 e di 123456789012<br />
con EAN-13.<br />
Figura 353.2. Esempi di codici a barre con simbologia EAN-8 e EAN-13.<br />
1234 5670 1 234567 890128
32 volume VIII Argomenti avanzati e accessori<br />
Il codice di controllo di EAN-8 e di EAN-13 si calcola nello stesso modo di UPC-A. Per esempio,<br />
nel caso di 1234567 (EAN-8) si ottiene il codice di controllo zero, mentre nel caso di<br />
123456789012 (EAN-13) si ottiene otto.<br />
Valore 1 2 3 4 5 6 7<br />
Peso 3 1 3 1 3 1 3<br />
Peso*Valore 3 2 9 4 15 6 21<br />
Il totale che si ottiene è 60; pertanto: 60/10 = 6 con un resto di 0; 10-0 = 10, da cui si prende<br />
solo l’ultima cifra (lo zero).<br />
Valore 1 2 3 4 5 6 7 8 9 0 1 2<br />
Peso 1 3 1 3 1 3 1 3 1 3 1 3<br />
Peso*Valore 1 6 3 12 5 18 7 24 9 0 1 6<br />
Il totale che si ottiene è 92; pertanto: 92/10 = 9 con un resto di 2; 10-2 = 8.<br />
La rappresentazione di ogni cifra numerica può avere tre forme differenti, a cui si attribuisce<br />
convenzionalmente una lettera alfabetica maiuscola: A, B e C. Nella simbologia EAN-8, le prime<br />
quattro cifre sono rappresentate secondo la forma A, mentre le ultime quattro secondo la forma C.<br />
Invece, la rappresentazione delle cifre nella simbologia EAN-13 è più complessa, per l’esigenza<br />
di essere compatibile con UPC-A.<br />
Con EAN-13 si rappresentano effettivamente solo le ultime 12 cifre (incluso il codice di controllo),<br />
mentre la prima viene determinata in base al modo in cui vengono rappresentate le sei cifre<br />
successive. In pratica, a seconda del valore della prima cifra, si determina la combinazione delle<br />
forme A e B, per le sei cifre che seguono la prima, mentre le ultime sei sono rappresentate con la<br />
forma C.<br />
Valore iniziale<br />
0 A A A A A A<br />
1 A A B A B B<br />
2 A A B B A B<br />
3 A A B B B A<br />
4 A B A A B B<br />
5 A B B A A B<br />
6 A B B B A A<br />
7 A B A B A B<br />
8 A B A B B A<br />
9 A B B A B A<br />
Dallo specchietto si può notare che con una prima cifra pari a zero, le sei cifre successive si<br />
rappresentano secondo la forma A, esattamente come avviene nella simbologia UPC-A. In pratica,<br />
a parte qualche differenza estetica minima, un codice a barre realizzato con la simbologia<br />
EAN-13 è uguale a un altro realizzato con la simbologia UPC-A, quando la prima cifra è pari a<br />
zero, tenendo conto che lo zero iniziale non può cambiare nulla anche nel calcolo del codice di<br />
controllo finale.
Codici a barre 33<br />
353.3.1 Codici UCC ed EAN<br />
In generale, la simbologia EAN-13 viene utilizzata per identificare degli «articoli», intesi principalmente<br />
come prodotti in vendita. Per poter applicare un codice a barre del genere occorre<br />
naturalmente avere ottenuto il numero per uno scopo preciso (l’ente italiano competente per<br />
l’attribuzione dei codici EAN è Indicod); tuttavia esiste un prefisso iniziale che fa parte dello<br />
standard e serve a stabilire l’origine del codice. l’origine è un concetto riferito precisamente a<br />
chi ha rilasciato il numero, che nella maggior parte dei casi si riferisce a un’organizzazione con<br />
competenza nazionale.<br />
Questo prefisso iniziale dipende principalmente da due organizzazioni: UCC (Uniform code<br />
council) ed EAN (European article number). La prima organizzazione, definisce codici in cui<br />
la prima cifra identifica l’origine nell’area nell’ambito di Stati Uniti e Canada, mentre la seconda<br />
copre tutto il mondo, includendo la codifica UCC a cui si aggiunge la cifra iniziale zero.<br />
La tabella 353.6 mostra in pratica un elenco abbastanza completo dei prefissi EAN, che solitamente<br />
si applicano ai codici a barre con simbologia EAN-13. Si può osservare che ormai i codici<br />
assegnati all’area Stati Uniti e Canada non hanno più solo lo zero iniziale; resta comunque l’abbinamento<br />
tra codice UCC e codice EAN, per cui il primo si trasforma nel secondo aggiungendo<br />
uno zero iniziale.<br />
Tabella 353.6. Attribuzione dei prefissi secondo la codifica EAN. Prima parte.<br />
Prefisso Contesto<br />
ISO<br />
3166<br />
Prefisso<br />
Contesto<br />
ISO 3166<br />
00-13 USA, Canada US, CA 14-19<br />
2 uso interno 30-37 Francia FR<br />
380<br />
384<br />
Bulgaria BG 383<br />
385<br />
Slovenia<br />
Croazia<br />
Bosnia<br />
SI<br />
HR<br />
386 387<br />
Erzego- BA<br />
vina<br />
388-<br />
389<br />
400-440<br />
GermaniaFede-<br />
DE<br />
45 Giappone JP 460-469 razione RU<br />
russa<br />
470 471 Taiwan TW<br />
472-<br />
473<br />
475 Lettonia LV<br />
474<br />
476<br />
Estonia<br />
Azerbaijan<br />
EE<br />
AZ<br />
477<br />
479<br />
481<br />
Lituania<br />
Sri Lanka<br />
Belarus<br />
LT<br />
LK<br />
BY<br />
478<br />
480<br />
482<br />
UzbekistanFilippine<br />
Ucraina<br />
UZ<br />
PH<br />
UA<br />
483<br />
485 Armenia AM<br />
484<br />
486<br />
Moldavia<br />
Georgia<br />
MD<br />
GE<br />
487 Kazakistan KZ 488<br />
489 Hong Kong HK 49<br />
Giappone<br />
JP<br />
50 Gran Bretagna UK 51<br />
520 Grecia GR 521-527<br />
528 Libano LB 529 Cipro CY<br />
530 531<br />
Macedonia<br />
MK
34 volume VIII Argomenti avanzati e accessori<br />
Prefisso Contesto<br />
ISO<br />
3166<br />
Prefisso<br />
Contesto<br />
ISO 3166<br />
532-<br />
534<br />
536-<br />
538<br />
54<br />
Belgio,<br />
Lussemburgo<br />
BE, LU<br />
535<br />
539<br />
55<br />
Malta<br />
Irlanda<br />
MT<br />
IE<br />
560 Portogallo PT 561-568<br />
569<br />
58<br />
Islanda IS 57<br />
590<br />
Danimarca<br />
Polonia<br />
DK<br />
PL<br />
591-<br />
593<br />
595-<br />
598<br />
600-<br />
601<br />
Sud Africa ZA<br />
594<br />
599<br />
602-608<br />
RomaniaUngheria<br />
RO<br />
HU<br />
609 Mauritius MU 610<br />
611 Marocco MA 612<br />
613 Algeria DZ 614-615<br />
616 Kenia KE 617-618<br />
619 Tunisia TN 620<br />
621 Siria SY 622 Egitto EG<br />
623 624 Libia LY<br />
625 Giordania JO 626 Iran IR<br />
627 Kuwait KW 628<br />
Arabia<br />
Saudita<br />
SA<br />
629 Emirati AE 63<br />
64 Finlandia FI 65-68<br />
690-<br />
693<br />
70<br />
Cina<br />
Norwegia<br />
CN<br />
NO<br />
694-699<br />
710-728<br />
729 Israele IL 73 Svezia SE<br />
740<br />
742<br />
Guatemala<br />
Honduras<br />
GT<br />
HN<br />
741<br />
743<br />
El SalvadorNicaragua<br />
SV<br />
NI<br />
744 Costa Rica CR 745 Panama PA<br />
746<br />
Repubblica Dominicana<br />
DO 747-749<br />
750 Messico MX 751-758<br />
759 Venezuela VE 76<br />
Svizzera<br />
CH<br />
770 Colombia CO 771-772<br />
773 Uruguay UY 774<br />
775 Perù PE 776<br />
777 Bolivia BO 778<br />
779 Argentina AR 780 Cile CL<br />
781-<br />
783<br />
784<br />
Paraguay<br />
PY<br />
785<br />
787-<br />
788<br />
80-83 Italia IT<br />
786<br />
789<br />
84<br />
Ecuador<br />
Brasile<br />
Spagna<br />
EC<br />
BR<br />
ES<br />
850 Cuba CU 851-857<br />
858 Slovacchia SK 859 Czech CZ<br />
860 Jugoslavia YU 861-866
Codici a barre 35<br />
Prefisso Contesto<br />
ISO<br />
3166<br />
Prefisso<br />
Contesto<br />
ISO 3166<br />
867 Nord Korea KP 868<br />
869 Turchia TR 87 Olanda NL<br />
880 Sud Korea KR 881-884<br />
885 Thailandia TH 886-887<br />
888 Singapore SG 889<br />
890 India IN 891-892<br />
893 Vietnam VN 894-898<br />
899 Indonesia ID 90-91 Austria AT<br />
92 93<br />
94 Nuova Zelanda NZ 950-954<br />
955 Malaysia MY 956-957<br />
958 Macau MO 959-976<br />
977<br />
980<br />
983-<br />
989<br />
periodici<br />
(ISSN)<br />
ricevute di rimborso<br />
(refund<br />
receipts)<br />
978-979<br />
981-982<br />
99<br />
Australia<br />
libri<br />
(ISBN)<br />
tagliandi<br />
di<br />
valuta<br />
(commoncurrencycoupons)tagliandi(coupons)<br />
Si può osservare in particolare che il prefissi 978 e 979 sono riservati per i libri, mentre il prefisso<br />
977 è riservato per i periodici (riviste). Dal momento che il prefisso EAN definiva originariamente<br />
un’area nazionale, era stato attribuito al codice 978 la denominazione bookland (la terra dei<br />
libri). Molta documentazione sui codici a barre e sulla numerazione ISBN fa ancora riferimento<br />
a questo nome per indicare tale prefisso.<br />
Un altro prefisso interessante è il due, che rimane libero. Molti negozi usano codici a barre EAN-<br />
13, con prefisso due per annotare il prezzo di qualcosa che non è identificabile diversamente,<br />
come gli alimentari ottenuti da un banco di salumi e formaggi. La figura 353.3 mostra un esempio<br />
reale in cui, tra le altre cose, si annota un prezzo di 11,24 e.<br />
Figura 353.3. Esempio di un codice a barre con simbologia EAN-13, usato per<br />
annotare un prezzo.<br />
2 000123 011240<br />
AU
36 volume VIII Argomenti avanzati e accessori<br />
353.3.2 ISBN<br />
La simbologia EAN-13 viene usata in diverse situazioni comuni, in particolare per ciò che<br />
riguarda le pubblicazioni.<br />
La codifica ISBN (International standard book number) permette di identificare un libro in una<br />
sua edizione precisa, attraverso un numero composto da 10 cifre. Il numero in questione contiene<br />
quattro parti: l’origine (ovvero l’ente che lo ha rilasciato), l’editore, il titolo (il libro) e un numero<br />
di controllo finale (una sola cifra).<br />
Per facilitare la lettura di queste informazioni, le quattro parti vengono mostrate solitamente<br />
come separate, attraverso un trattino. Per esempio, ‘88-8331-223-6’ indica l’origine 88 (Italia),<br />
l’editore 8331, il titolo 233 e il numero di controllo 6.<br />
Le varie parti in cui si suddivide l’informazione contenuta in un numero ISBN non sono di<br />
lunghezza fissa e la dimensione dell’una limita quella delle altre. In generale sono disponibili i<br />
raggruppamenti seguenti.<br />
1. La prima parte identifica l’area (nazionale, linguistica e geografica) e viene attribuita<br />
dall’agenzia internazionale dell’ISBN. Il numero assegnato all’Italia è 88.<br />
• 0-7<br />
• 80-94<br />
• 950-994<br />
• 9950-9989<br />
• 99900-99999<br />
2. La seconda parte identifica l’editore e viene attribuito dall’agenzia ISBN competente<br />
nell’area di riferimento.<br />
• 00-19<br />
• 200-699<br />
• 7000-8499<br />
• 85000-89999<br />
• 900000-999999<br />
3. La terza parte identifica il titolo, relativamente all’editore a cui si fa riferimento, utilizzando<br />
lo spazio rimanente, escludendo il numero di controllo finale.<br />
4. Il numero di controllo viene calcolato moltiplicando le cifre per un numero che va da 10 a<br />
uno, sommando ciò che si ottiene e dividendo per il «modulo 11». In questo modo, il valore<br />
che si ottiene può andare da 0 a 10, dove il 10 si rappresenta con una lettera «X».<br />
Per comprendere il meccanismo del calcolo del numero di controllo, conviene vedere un esempio<br />
reale, il numero ISBN ‘88-8331-223-6’. In pratica, si tratta di verificare che il numero sei sia<br />
effettivamente il numero di controllo corretto.<br />
Valore 8 8 8 3 3 1 2 2 3 6<br />
Peso 10 9 8 7 6 5 4 3 2 1<br />
Peso*Valore 80 72 64 21 18 5 8 6 6 6
Codici a barre 37<br />
Il totale che si ottiene è 286, che diviso per 11 dà esattamente 26, senza resto, a conferma della<br />
validità del numero di controllo. Non conoscendo il numero di controllo lo si potrebbe calcolare:<br />
la somma che si otterrebbe sarebbe solo 280, che divisa per 11 dà 25 con il resto di 5, per cui, 11<br />
- 5 dà 6, il numero cercato.<br />
Il numero ISBN si trasforma in EAN-13 mettendo anteriormente il valore 978 e togliendo il<br />
numero di controllo finale che va sostituito con quello calcolato secondo lo standard EAN-13;<br />
naturalmente, i trattini di divisione sono perduti. La figura 353.4 mostra l’esempio del codice<br />
ISBN 88-481-0113-5 rappresentato secondo la simbologia EAN-13, che si trasforma nel numero<br />
9788848101134.<br />
Figura 353.4. ISBN 88-481-0113-5.<br />
ISBN 88-481-0113-5<br />
9 788848 101134<br />
A seconda del paese in cui si utilizza il numero ISBN, può essere obbligatorio o meno un codice<br />
a barre aggiuntivo contenente l’informazione sul prezzo.<br />
353.3.3 ISSN<br />
La codifica ISSN permette di identificare una pubblicazione periodica attraverso una tecnica<br />
simile a quella del numero ISBN per i libri. In questo caso, il numero è composto da otto cifre<br />
numeriche (compreso il numero di controllo), che vanno inserite in una simbologia EAN-13<br />
aggiungendo all’inizio il prefisso 977, togliendo il numero di controllo ISSN, aggiungendo due<br />
cifre che rappresentano il codice del prezzo e aggiungendo il codice di controllo EAN-13. Inoltre,<br />
va aggiunto un codice a barre ulteriore per rappresentare due o cinque cifre in cui si indica il<br />
numero del fascicolo.<br />
Per esempio, il numero ISSN ‘1129-1346’ di una rivista potrebbe tradursi nel codice a barre<br />
9771129134006, con l’aggiunta di 10110, dove il codice del prezzo è assente e si fa riferimento<br />
al fascicolo numero 110.<br />
La figura 353.5 mostra l’esempio del codice di due riviste, in cui appare anche un’estensione<br />
contenente il numero della pubblicazione.<br />
Figura 353.5. Esempio di due codici ISSN, riferiti a riviste, con un’estensione<br />
contenente il numero della pubblicazione (rispettivamente 106 e 23).<br />
353.4 Code 39<br />
La simbologia denominata Code 39, ovvero 3 <strong>of</strong> 9, consente di rappresentare 42 simboli, composti<br />
da lettere maiuscole, cifre numeriche e pochi altri segni. La tabella 353.8 riepiloga l’insieme<br />
di caratteri. Un codice a barre Code 39 è composto da un carattere di inizio, dai dati che deve<br />
contenere, da un codice di controllo (che non appare tradotto per la lettura umana) e dal carattere<br />
di fine. Il carattere usato per iniziare e per concludere la sequenza è l’asterisco, che quindi non<br />
può essere utilizzato nei dati contenuti.
38 volume VIII Argomenti avanzati e accessori<br />
Tabella 353.8. Insieme di caratteri per la simbologia Code 39.<br />
Valore Carattere Valore Carattere<br />
0 0 22 M<br />
1 1 23 N<br />
2 2 24 O<br />
3 3 25 P<br />
4 4 26 Q<br />
5 5 27 R<br />
6 6 28 S<br />
7 7 29 T<br />
8 8 30 U<br />
9 9 31 V<br />
10 A 32 W<br />
11 B 33 X<br />
12 C 34 Y<br />
13 D 35 Z<br />
14 E 36 -<br />
15 F 37 .<br />
16 G 38 space<br />
17 H 39 $<br />
18 I 40 /<br />
19 J 41 +<br />
20 K 42 %<br />
21 L inizio/fine *<br />
Figura 353.6. Esempio di codice a barre Code 39.<br />
C I A O<br />
Gli elementi utilizzati nella simbologia Code 39 sono quattro, composti da due tipi di barre nere<br />
e due tipi di spazi. Ogni carattere o segno che può essere rappresentato con questa simbologia, si<br />
avvale di cinque barre e di quattro spazi, per un totale di nove elementi. Il nome della simbologia,<br />
che si può tradurre come «tre su nove», indica il fatto che tre elementi su nove sono sempre di<br />
tipo largo (rispetto agli altri che invece sono stretti).<br />
Il codice di controllo si ottiene sommando assieme i valori abbinati ai segni che si possono<br />
rappresentare, secondo la tabella di conversione 353.8, dividendo per 43. Il resto della divisione<br />
è il codice di controllo. Nel caso dell’esempio che appare in figura 353.6, si tratta della lettera<br />
‘L’:<br />
«CIAO» = 12 + 18 + 10 + 24 = 64<br />
64 / 43 = 1 lasciando un resto di 21 = ‘L’
Codici a barre 39<br />
353.4.1 Code 39 esteso<br />
Esiste anche un’estensione della simbologia Code 39, allo scopo di consentire la rappresentazione<br />
dell’ASCII standard completo. Si ottiene questo risultato scrivendo due simboli normali<br />
al posto di uno. Naturalmente, dal momento che non esiste un modo per distinguere la codifica<br />
standard da quella estesa, è necessario che il lettore di codice a barre sia impostato nel modo più<br />
conveniente. La tabella 353.9 mostra l’insieme di caratteri esteso e la corrispondenza con i segni<br />
della simbologia Code 39 normale.<br />
Tabella 353.9. Insieme di caratteri esteso per la simbologia Code 39.<br />
ASCII Code 39 ASCII Code 39 ASCII Code 39 ASCII Code 39<br />
%U = @ %V ‘ %W<br />
$A ! /A A A a +A<br />
$B " /B B B b +B<br />
$C # /C C C c +C<br />
$D $ /D D D d +D<br />
$E % /E E E e +E<br />
$F & /F F F f +F<br />
$G ’ /G G G g +G<br />
$H ( /H H H h +H<br />
$I ) /I I I i +I<br />
$J * /J J J j +J<br />
$K + /K K K k +K<br />
$L , /L L L l +L<br />
$M - /M M M m +M<br />
$N . /N N N n +N<br />
$O / /O O O o +O<br />
$P 0 0 P P p +P<br />
$Q 1 1 Q Q q +Q<br />
$R 2 2 R R r +R<br />
$S 3 3 S S s +S<br />
$T 4 4 T T t +T<br />
$U 5 5 U U u +U<br />
$V 6 6 V V v +V<br />
$W 7 7 W W w +W<br />
$X 8 8 X X x +X<br />
$Y 9 9 Y Y y +Y<br />
$Z : /Z Z Z z +Z<br />
%A ; %F [ %K { %P<br />
%B < %G \ %L | %Q<br />
%C = %H ] %M } %R<br />
%D > %I ^ %N ~ %S<br />
%E ? %J _ %O %T<br />
353.5 Code 128<br />
La simbologia denominata Code 128, ovvero USS Code 128, consente di rappresentare 106 simboli,<br />
che possono essere interpretati secondo tre insiemi di caratteri, distinti in base a una lettera:<br />
A, B e C. Per questa ragione, un codice a barre realizzato secondo la simbologia Code 128 inizia<br />
sempre con la dichiarazione dell’insieme di caratteri. L’informazione non ha una lunghezza<br />
predeterminata e può essere modificato l’insieme di caratteri quando serve. La simbologia Code<br />
128 prevede l’inserimento di un codice di controllo, calcolato automaticamente per consentire<br />
la verifica della lettura meccanica, ma questa cifra non viene mostrata per la lettura umana.
40 volume VIII Argomenti avanzati e accessori<br />
Tabella 353.10. Insiemi di caratteri per la simbologia Code 128. L’ultima colonna ripor-<br />
ta anche la descrizione della rappresentazione a barre, dove un numero da uno a<br />
tre indica la larghezza della barra, ‘b’, o dello spazio, ‘s’, dalla grandezza più piccola<br />
alla più grande. Si osservi che lo stop ha una barra in più alla fine.<br />
Valore Code A Code B Code C Barre e spazi:<br />
b s b s b s<br />
0 00 2 1 2 2 2 2<br />
1 ! ! 01 2 2 2 1 2 2<br />
2 " " 02 2 2 2 2 2 1<br />
3 # # 03 1 2 1 2 2 3<br />
4 $ $ 04 1 2 1 3 2 2<br />
5 % % 05 1 3 1 2 2 2<br />
6 & & 06 1 2 2 2 1 3<br />
7 ’ ’ 07 1 2 2 3 1 2<br />
8 ( ( 08 1 3 2 2 1 2<br />
9 ) ) 09 2 2 1 2 1 3<br />
10 * * 10 2 2 1 3 1 2<br />
11 + + 11 2 3 1 2 1 2<br />
12 ’ ’ 12 1 1 2 2 3 2<br />
13 - - 13 1 2 2 1 3 2<br />
14 . . 14 1 2 2 2 3 1<br />
15 / / 15 1 1 3 2 2 2<br />
16 0 0 16 1 2 3 1 2 2<br />
17 1 1 17 1 2 3 2 2 1<br />
18 2 2 18 2 2 3 2 1 1<br />
19 3 3 19 2 2 1 1 3 2<br />
20 4 4 20 2 2 1 2 3 1<br />
21 5 5 21 2 1 3 2 1 2<br />
22 6 6 22 2 2 3 1 1 2<br />
23 7 7 23 3 1 2 1 3 1<br />
24 8 8 24 3 1 1 2 2 2<br />
25 9 9 25 3 2 1 1 2 2<br />
26 : : 26 3 2 1 2 2 1<br />
27 ; ; 27 3 1 2 2 1 2<br />
28 < < 28 3 2 2 1 1 2<br />
29 = = 29 3 2 2 2 1 1<br />
30 > > 30 2 1 2 1 2 3<br />
31 ? ? 31 2 1 2 3 2 1<br />
32 @ @ 32 2 3 2 1 2 1<br />
33 A A 33 1 1 1 3 2 3<br />
34 B B 34 1 3 1 1 2 3<br />
35 C C 35 1 3 1 3 2 1<br />
36 D D 36 1 1 2 3 1 3<br />
37 E E 37 1 3 2 1 1 3<br />
38 F F 38 1 3 2 3 1 1<br />
39 G G 39 2 1 1 3 1 3<br />
40 H H 40 2 3 1 1 1 3<br />
41 I I 41 2 3 1 3 1 1<br />
42 J J 42 1 1 2 1 3 3<br />
43 K K 43 1 1 2 3 3 1<br />
44 L L 44 1 3 2 1 3 1<br />
45 M M 45 1 1 3 1 2 3<br />
46 N N 46 1 1 3 3 2 1<br />
47 O O 47 1 3 3 1 2 1<br />
48 P P 48 3 1 3 1 2 1<br />
49 Q Q 49 2 1 1 3 3 1
Codici a barre 41<br />
Valore Code A Code B Code C Barre e spazi:<br />
b s b s b s<br />
50 R R 50 2 3 1 1 3 1<br />
51 S S 51 2 1 3 1 1 3<br />
52 T T 52 2 1 3 3 1 1<br />
53 U U 53 2 1 3 1 3 1<br />
54 V V 54 3 1 1 1 2 3<br />
55 W W 55 3 1 1 3 2 1<br />
56 X X 56 3 3 1 1 2 1<br />
57 Y Y 57 3 1 2 1 1 3<br />
58 Z Z 58 3 1 2 3 1 1<br />
59 [ [ 59 3 3 2 1 1 1<br />
60 \ \ 60 3 1 4 1 1 1<br />
61 ] ] 61 2 2 1 4 1 1<br />
62 ^ ^ 62 4 3 1 1 1 1<br />
63 _ _ 63 1 1 1 2 2 4<br />
64 ‘ 64 1 1 1 4 2 2<br />
65 a 65 1 2 1 1 2 4<br />
66 b 66 1 2 1 4 2 1<br />
67 c 67 1 4 1 1 2 2<br />
68 d 68 1 4 1 2 2 1<br />
69 e 69 1 1 2 2 1 4<br />
70 f 70 1 1 2 4 1 2<br />
71 g 71 1 2 2 1 1 4<br />
72 h 72 1 2 2 4 1 1<br />
73 i 73 1 4 2 1 1 2<br />
74 j 74 1 4 2 2 1 1<br />
75 k 75 2 4 1 2 1 1<br />
76 l 76 2 2 1 1 1 4<br />
77 m 77 4 1 3 1 1 1<br />
78 n 78 2 4 1 1 1 2<br />
79 o 79 1 3 4 1 1 1<br />
80 p 80 1 1 1 2 4 2<br />
81 q 81 1 2 1 1 4 2<br />
82 r 82 1 2 1 2 4 1<br />
83 s 83 1 1 4 2 1 2<br />
84 t 84 1 2 4 1 1 2<br />
85 u 85 1 2 4 2 1 1<br />
86 v 86 4 1 1 2 1 2<br />
87 w 87 4 2 1 1 1 2<br />
88 x 88 4 2 1 2 1 1<br />
89 y 89 2 1 2 1 4 1<br />
90 z 90 2 1 4 1 2 1<br />
91 { 91 4 1 2 1 2 1<br />
92 | 92 1 1 1 1 4 3<br />
93 } 93 1 1 1 3 4 1<br />
94 ~ 94 1 3 1 1 4 1<br />
95 95 1 1 4 1 1 3<br />
96 FNC 3 FNC 3 96 1 1 4 3 1 1<br />
97 FNC 2 FNC 2 97 4 1 1 1 1 3<br />
98 Shift Shift 98 4 1 1 3 1 1<br />
99 Code C Code C 99 1 1 3 1 4 1<br />
100 Code B FNC 4 Code B 1 1 4 1 3 1<br />
101 FNC 4 Code A Code A 3 1 1 1 4 1<br />
102 FNC 1 FNC 1 FNC 1 4 1 1 1 3 1<br />
103 Start A Start A Start A 2 1 1 4 1 2<br />
104 Start B Start B Start B 2 1 1 2 1 4
42 volume VIII Argomenti avanzati e accessori<br />
Valore Code A Code B Code C Barre e spazi:<br />
b s b s b s<br />
105 Start C Start C Start C 2 1 1 2 3 2<br />
Stop Stop Stop 2 3 3 1 1 1 2<br />
Gli insiemi di caratteri A, B e C sono elencati nella tabella 353.10. Come si può vedere, l’insieme<br />
A consente di rappresentare l’alfabeto maiuscolo, le cifre numeriche, vari simboli di punteggiatura<br />
e caratteri di controllo; in pratica, ciò che si può rappresentare con la prima parte della codifica<br />
ASCII, tenendo conto che le posizioni non corrispondono. L’insieme B consente di rappresentare<br />
praticamente tutto l’alfabeto ASCII, compresa la distinzione tra lettere maiuscole e minuscole,<br />
a esclusione dei caratteri di controllo. L’insieme C consente di rappresentare valori numerici a<br />
coppie, per cui, un valore composto da un numero dispari di cifre acquisisce uno zero iniziale.<br />
Figura 353.7. Esempio di due codici Code 128, realizzati usando l’insieme B e l’insieme<br />
C, per rappresentare due dati equivalenti: «Ciao» e 35736579.<br />
Ci ao 35736579<br />
La figura 353.7 mostra la comparazione tra un codice a barre realizzato usando l’insieme B<br />
e un altro con l’insieme C. L’informazione contenuta è la stessa dal punto di vista dei valori<br />
rappresentabili (eventualmente si osservino le tabelle degli insiemi di caratteri). Se fosse possibile<br />
sovrapporre i due codici, si noterebbe che cambia solo la parte iniziale, quella in cui si dichiara<br />
l’insieme di caratteri, e la parte finale, dove si inserisce il codice di controllo. Si può anche<br />
osservare che gli ultimi elementi rimangono uguali e sono quelli che contengono il codice di<br />
conclusione.<br />
Volendo entrare nel dettaglio, l’esempio di figura 353.7 si compone di: ‘Start B’, 35, 73,<br />
65, 79, codice_di_controllo, ‘Stop’; ovvero, nel secondo caso, ‘Start C’, 35, 73, 65, 79,<br />
codice_di_controllo, ‘Stop’.<br />
Quando si vuole cambiare l’insieme di caratteri, si inserisce un simbolo ‘Code A’, ‘Code B’ o<br />
‘Code C’, per introdurre l’insieme a cui si vuole fare riferimento da quel punto in poi.<br />
Il codice di controllo finale si calcola sommando il valore corrispondente alla dichiarazione iniziale<br />
dell’insieme di caratteri alla somma dei valori successivi, moltiplicati per la loro posizione.<br />
La somma complessiva va divisa per 103 e il resto che si ottiene è il codice di controllo finale. Si<br />
osservi l’esempio:<br />
Pertanto:<br />
104 + 35 + 146 + 195 + 316 = 796<br />
Start B C i a o Stop<br />
Peso 1 1 2 3 4<br />
Valore 104 35 73 65 79<br />
Peso*Valore 104 35 146 195 316<br />
796 / 103 = 7 con resto di 75. Il codice di controllo è il simbolo corrispondente al valore 75.<br />
Usando l’insieme di caratteri C la cosa cambia, perché il simbolo iniziale ha il valore 105, per<br />
cui il codice di controllo finale è 76:
Codici a barre 43<br />
Start C 35 73 65 79 Stop<br />
Peso 1 1 2 3 4<br />
Valore 105 35 73 65 79<br />
Peso*Valore 105 35 146 195 316<br />
Dalla simbologia Code 128 derivano diverse applicazioni speciali che si distinguono per avere<br />
una struttura particolare. Esiste anche una variante che consente la rappresentazione di più<br />
caratteri rispetto all’ASCII standard.<br />
353.5.1 UCC/EAN 128<br />
La simbologia UCC/EAN 128 è un’applicazione di Code 128, in cui si inizia dichiarando<br />
l’insieme di caratteri e si inserisce subito dopo il simbolo ‘FNC 1’ (Function code one). 1<br />
Dopo il simbolo ‘FNC 1’ viene indicato un codice che indica il tipo di applicazione. Si fa riferimento<br />
a questo con la sigla AI (Application identifier). L’informazione in questione viene<br />
rappresentata per la lettura umana tra parentesi tonde, proprio per facilitare l’interpretazione, a<br />
sottolineare il fatto che si tratta di un prefisso. Naturalmente, l’informazione può essere anche<br />
più complessa e altre parti dei dati successivi possono essere separate ed evidenziate nello stesso<br />
modo o in modi differenti.<br />
353.6 ITF, ovvero i25<br />
La simbologia ITF, o i25, nota come Interleaved two <strong>of</strong> five, ovvero «interfogliata due su cinque»,<br />
consente la rappresentazione di soli valori numerici, di lunghezza indefinita, purché in numero di<br />
cifre pari. La simbologia prevede una cifra di controllo finale, opzionale.<br />
La simbologia si compone di due tipi di barre e due tipi di spazi. Ogni simbolo si rappresenta<br />
con cinque barre e cinque spazi, dove due barre su cinque e due spazi su cinque sono più larghi.<br />
La simbologia è detta «interfogliata», perché una cifra è codificata nelle barre e la successiva<br />
lo è negli spazi che separano gli elementi del carattere precedente. Prima dei dati è previsto un<br />
simbolo iniziale, composto da una barra sottile, uno spazio breve, una barra sottile e un altro<br />
spazio breve; alla fine c’è un simbolo finale, composto da una barra larga, uno spazio sottile e<br />
una barra sottile.<br />
Figura 353.8. Esempio di codice a barre con simbologia interfogliata due su cinque.<br />
0 1 2 3 4 5 6 7 8<br />
1 L’uso comune è dell’insieme di caratteri C, ma ciò non è imposto dallo standard.
44 volume VIII Argomenti avanzati e accessori<br />
353.7 Sistemi bidimensionali<br />
Il codice a barre comune è a una sola dimensione, nel senso che contiene una sola riga di informazioni,<br />
eventualmente anche molto breve. Semplificando le cose, si può dire che quando si<br />
sovrappongono più righe in un codice a barre, questo diventa a due dimensioni.<br />
Un sistema di codice a barre a due dimensioni, con lo scopo di memorizzare dati, deve essere<br />
organizzato in modo da permettere al lettore meccanico di riconoscere e seguire le righe; inoltre<br />
deve essere previsto un sistema di informazioni ridondanti, anche molto complesso, in modo da<br />
garantire la lettura in presenza di errori.<br />
Lo standard più comune per i codici a barre a due dimensioni è il PDF417, che comunque qui<br />
non viene descritto.<br />
353.8 Riferimenti<br />
• EAN international<br />
<br />
• The EAN.UCC system<br />
<br />
• Tino Hempel, Die Europäische Artikelnummer (EAN)<br />
<br />
• Barcoding for Beginners & Bar Code FAQ<br />
<br />
• Code 39 Barcode FAQ and Tutorial<br />
<br />
• Code 128 / USS Code-128 Barcode FAQ & Tutorial<br />
<br />
• PDF417 Barcode FAQ<br />
<br />
• UPC / EAN Barcode Font Data Sheet<br />
<br />
• PDF417<br />
<br />
• Russ Adams, Barcode 1<br />
<br />
• International ISBN Agency: Coordinator <strong>of</strong> the International Standard Book Number<br />
system<br />
<br />
• International ISBN Agency, The ISBN Users’ Manual<br />
Codici a barre 45<br />
• AIE - Agenzia ISBN<br />
<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Barcode<br />
Capitolo 354<br />
Barcode 1 è una libreria e anche un programma molto semplice per la realizzazione di codici<br />
a barre standard a una sola dimensione. Il codice a barre viene realizzato in forma di file Post-<br />
Script, che successivamente può essere utilizzato direttamente o convertito in altri formati grafici,<br />
attraverso programmi standard.<br />
354.1 Utilizzo del programma<br />
Barcode, come programma, si compone in pratica dell’eseguibile ‘barcode’. Questo genera normalmente<br />
un file PostScript che, salvo l’utilizzo dell’opzione ‘-o’, viene emesso attraverso lo<br />
standard output.<br />
barcode [opzioni]<br />
Teoricamente si può usare Barcode anche senza l’indicazione di alcun argomento, per ottenere<br />
la conversione automatica di quanto inserito attraverso lo standard input, scegliendo la simbologia<br />
in modo automatico. Tuttavia, in genere è opportuno accertarsi di selezionare la simbologia<br />
attraverso l’opzione ‘-e’.<br />
Le opzioni che vengono mostrate qui sono poche; in particolare mancano quelle che servono a<br />
definire la stampa di codici a barre in modo organizzato sul foglio, allo scopo di centrare delle<br />
etichette adesive. Per appr<strong>of</strong>ondire basta leggere la documentazione originale: barcode.info.<br />
Tabella 354.1. Alcune opzioni.<br />
Opzione Descrizione<br />
Consente di specificare la simbologia dei codici a barre che si<br />
vogliono realizzare (encoding). Sono disponibili diverse pa-<br />
-e simbologia<br />
role chiave da usare come argomento dell’opzione, secondo<br />
la tabella 354.2.<br />
Stabilisce il nome di un file contenente un elenco di codici da<br />
trasformare in codici a barre. Se manca questa indicazione e<br />
-i file<br />
se manca anche l’opzione ‘-b’, viene letto lo standard input.<br />
La lettera dell’opzione richiama mnemonicamente la parola<br />
«input».<br />
Consente di indicare una stringa da convertire in un codice a<br />
barre singolo. La stringa deve essere compatibile con i tipi di<br />
dati che possono essere rappresentati con la simbologia pre-<br />
-b stringa<br />
scelta. La lettera dell’opzione richiama mnemonicamente la<br />
parola barcode, ovvero il codice a barre che si vuole ottenere<br />
dalla stringa.<br />
-E Genera un file PostScript incapsulato (EPS).<br />
Segue la descrizione di alcuni esempi.<br />
• $ barcode -E -e i25 -b "12345678" > prova.ps<br />
Converte il numero 12345678 in un codice a barre secondo la simbologia interfogliata due<br />
su cinque, generando il file ‘prova.ps’, di tipo EPS.<br />
• $ barcode -E -e i25 -b "12345678" -o prova.ps<br />
1 Barcode GNU GPL<br />
46
Barcode 47<br />
Esattamente come nell’esempio precedente.<br />
• $ barcode -E -e isbn -b "88-386-4177-3" -o prova.ps<br />
Come nell’esempio precedente, usando la simbologia EAN-13 per rappresentare un codice<br />
ISBN, come indicato con l’opzione ‘-b’.<br />
354.2 Codifica<br />
Generalmente, Barcode viene utilizzato indicando il tipo di simbologia, attraverso una parola<br />
chiave secondo l’elenco della tabella 354.2. In generale, si tratta di nomi che fanno riferimento<br />
al tipo di codice a barre; in alcuni casi, il nome indica anche altre caratteristiche. Per esempio,<br />
la parola chiave ‘code128b’ indica la simbologia Code 128, nella quale si utilizza l’insieme di<br />
caratteri B; inoltre, la parola chiave ‘isbn’ fa riferimento al codice ISBN, che viene rappresentato<br />
correttamente secondo la simbologia EAN-13.<br />
Tabella 354.2. Simbologie disponibili con Barcode.<br />
Simbologia Parola chiave<br />
UPC-A<br />
upc-a<br />
UPC-E<br />
upc-e<br />
UPC-A o UPC-E automaticamente<br />
upc<br />
EAN-8 ean8, ean-8<br />
EAN-13 ean13, ean-13<br />
EAN-8 o EAN-13 automaticamente<br />
ean<br />
Code 39 code39, 39<br />
Code 128 insieme di caratteri B code128b, 128b<br />
Code 128 insieme di caratteri C code128c, 128c<br />
Code 128 insieme di caratteri A, B o C, automaticamente code128, 128<br />
Code 128 libero 128raw<br />
interfogliata due su cinque i25, interleaved 2 <strong>of</strong> 5<br />
Codabar cdr, codabar<br />
Plessey pls, plessey<br />
ISBN attraverso EAN-13 isbn<br />
Nel caso dell’uso della simbologia Code 128, si pone il problema di rappresentare i codici da<br />
a , il codice e le funzioni speciali previste dalla simbologia. Usando l’eseguibile<br />
‘barcode’ diventa difficile indicare questi simboli; con la libreria non ci sono problemi<br />
a indicare i codici ASCII da a e il codice , mentre negli altri casi viene fatta<br />
una trasformazione, come rappresentato nella tabella 354.3.<br />
Tabella 354.3. Rappresentazione dei caratteri speciali per la simbologia Code 128,<br />
quando si usa la libreria Barcode.<br />
Codice o simbolo Ottale Decimale Esadecimale<br />
2008 128 8016<br />
FNC 1 3018 193 C116<br />
FNC 2 3028 194 C216<br />
FNC 3 3038 195 C316<br />
FNC 4 3048 196 C416<br />
Sempre a proposito della simbologia Code 128, è possibile utilizzando la parola chiave ‘128raw’<br />
per indicare un codice attraverso una stringa espressa nella forma:
48 volume VIII Argomenti avanzati e accessori<br />
n_1 n_2... n_n<br />
In pratica, si indicano una serie di numeri separati tra loro da uno spazio. I numeri in questione<br />
rappresentano il valore indicato nella tabella 353.10; inoltre occorre tenere in considerazione che<br />
va fornito anche il valore iniziale, con il quale si definisce solitamente l’insieme di caratteri A, B<br />
o C, mentre il codice di controllo finale e lo stop sono aggiunti automaticamente.<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Trasformazione in lettere<br />
Capitolo 355<br />
Nell’ambito della realizzazione di applicativi gestionali, capitano frequentemente problemi di<br />
conversione di numeri interi in una qualche forma alfabetica. In questo capitolo vengono mostrati<br />
degli algoritmi molto semplici per risolvere questo tipo di problemi.<br />
355.1 Da numero a sequenza alfabetica pura<br />
Esiste un tipo di numerazione in cui si utilizzano solo le lettere dell’alfabeto, dalla «a» alla «z»,<br />
senza accenti o altri simboli speciali, senza distinguere tra maiuscole e minuscole. In generale,<br />
i simboli da «a» a «z» consentono di rappresentare valori da 1 a 26, dove lo zero è escluso.<br />
Per rappresentare valori superiori, si possono accoppiare più lettere, ma il calcolo non è banale,<br />
proprio perché manca lo zero.<br />
Attraverso la pseudocodifica introdotta nel capitolo 286, si può descrivere una funzione che calcoli<br />
la stringa corrispondente a un numero intero positivo, maggiore di zero. Per prima cosa,<br />
occorre definire una sotto funzione che sia in grado di trasformare un numero intero, compreso<br />
tra 1 e 26 nella lettera alfabetica corrispondente; ciò si ottiene abbastanza facilmente, attraverso<br />
la verifica di più condizioni in cascata. Il vero problema, purtroppo, sta nel costruire una stringa<br />
composta da più lettere, quando si vuole rappresentare un valore superiore a 26. Non essendoci<br />
lo zero, diventa difficile fare i calcoli. Se si parte dal presupposto che il numero da convertire<br />
non possa essere superiore a 702, si sa con certezza che servono al massimo due lettere alfabetiche<br />
(perché la stringa «ZZ» corrisponderebbe proprio al numero 702); in tal caso, è sufficiente<br />
dividere il numero per 26, dove la parte intera rappresenta la prima lettera, mentre il resto rappresenta<br />
la seconda. Tuttavia, se la divisione non dà resto, la stringa corretta è quella precedente.<br />
Per esempio, il numero 53 corrisponde alla stringa «BA», perché 53/26 = 2 con un resto di 1.<br />
Nello stesso modo, però, 52 si traduce nella stringa «AZ», perché 53/26 = 2, ma non c’è resto,<br />
pertanto, «B_» diventa «AZ».<br />
La pseudocodifica seguente riepiloga il concetto in modo semplificato, dove, a seconda delle<br />
esigenze, la conversione è sempre limitata a un valore massimo. Le omissioni sono parti di codice<br />
facilmente intuibili.<br />
INTEGER_TO_ALPHABET (N)<br />
ALPHABET_DIGIT (DIGIT)<br />
IF DIGIT = 0<br />
THEN<br />
RETURN ""<br />
ELSE IF DIGIT = 1<br />
THEN<br />
RETURN "A"<br />
ELSE IF DIGIT = 2<br />
THEN<br />
RETURN "B"<br />
...<br />
...<br />
ELSE IF DIGIT = 26<br />
THEN<br />
RETURN "Z"<br />
ELSE<br />
RETURN "##ERROR##"<br />
FI<br />
END ALPHABET_DIGIT<br />
IF N
50 volume VIII Argomenti avanzati e accessori<br />
THEN<br />
RETURN "##ERROR##";<br />
ELSE IF N
Trasformazione in lettere 51<br />
Per risolvere il problema con un algoritmo relativamente semplice, si può scomporre il valore<br />
di partenza in fasce: unità, decine, centinaia e migliaia (la conversione di valori superiori<br />
genererebbe soltanto una serie lunghissima di «M» che risulta poi troppo difficile da leggere).<br />
INTEGER_TO_ROMAN (N)<br />
LOCAL DIGIT_1 INTEGER<br />
LOCAL DIGIT_2 INTEGER<br />
LOCAL DIGIT_3 INTEGER<br />
LOCAL DIGIT_4 INTEGER<br />
DIGIT_1 := 0<br />
DIGIT_2 := 0<br />
DIGIT_3 := 0<br />
DIGIT_4 := 0<br />
DIGIT_1_TO_ROMAN (DIGIT)<br />
IF DIGIT = 0<br />
THEN<br />
RETURN ""<br />
ELSE IF DIGIT = 1<br />
THEN<br />
RETURN "I"<br />
ELSE IF DIGIT = 2<br />
THEN<br />
RETURN "II"<br />
ELSE IF DIGIT = 3<br />
THEN<br />
RETURN "III"<br />
ELSE IF DIGIT = 4<br />
THEN<br />
RETURN "IV"<br />
ELSE IF DIGIT = 5<br />
THEN<br />
RETURN "V"<br />
ELSE IF DIGIT = 6<br />
THEN<br />
RETURN "VI"<br />
ELSE IF DIGIT = 7<br />
THEN<br />
RETURN "VII"<br />
ELSE IF DIGIT = 8<br />
THEN<br />
RETURN "VIII"<br />
ELSE IF DIGIT = 9<br />
THEN<br />
RETURN "IX"<br />
END IF<br />
END DIGIT_1_TO_ROMAN<br />
DIGIT_2_TO_ROMAN (DIGIT)<br />
IF DIGIT = 0<br />
THEN<br />
RETURN ""<br />
ELSE IF DIGIT = 1<br />
THEN<br />
RETURN "X"<br />
ELSE IF DIGIT = 2<br />
THEN<br />
RETURN "XX"<br />
ELSE IF DIGIT = 3<br />
THEN<br />
RETURN "XXX"<br />
ELSE IF DIGIT = 4<br />
THEN
52 volume VIII Argomenti avanzati e accessori<br />
RETURN "XL"<br />
ELSE IF DIGIT = 5<br />
THEN<br />
RETURN "L"<br />
ELSE IF DIGIT = 6<br />
THEN<br />
RETURN "LX"<br />
ELSE IF DIGIT = 6<br />
THEN<br />
RETURN "LXX"<br />
ELSE IF DIGIT = 8<br />
THEN<br />
RETURN "LXXX"<br />
ELSE IF DIGIT = 9<br />
THEN<br />
RETURN "XC"<br />
END IF<br />
END DIGIT_2_TO_ROMAN<br />
DIGIT_3_TO_ROMAN (DIGIT)<br />
IF DIGIT = 0<br />
THEN<br />
RETURN ""<br />
ELSE IF DIGIT = 1<br />
THEN<br />
RETURN "C"<br />
ELSE IF DIGIT = 2<br />
THEN<br />
RETURN "CC"<br />
ELSE IF DIGIT = 3<br />
THEN<br />
RETURN "CCC"<br />
ELSE IF DIGIT = 4<br />
THEN<br />
RETURN "CD"<br />
ELSE IF DIGIT = 5<br />
THEN<br />
RETURN "D"<br />
ELSE IF DIGIT = 6<br />
THEN<br />
RETURN "DC"<br />
ELSE IF DIGIT = 7<br />
THEN<br />
RETURN "DCC"<br />
ELSE IF DIGIT = 8<br />
THEN<br />
RETURN "DCCC"<br />
ELSE IF DIGIT = 9<br />
THEN<br />
RETURN "CM"<br />
END IF<br />
END DIGIT_3_TO_ROMAN<br />
DIGIT_4_TO_ROMAN (DIGIT)<br />
IF DIGIT = 0<br />
THEN<br />
RETURN ""<br />
ELSE IF DIGIT = 1<br />
THEN<br />
RETURN "M"<br />
ELSE IF DIGIT = 2<br />
THEN<br />
RETURN "MM"<br />
ELSE IF DIGIT = 3
Trasformazione in lettere 53<br />
THEN<br />
RETURN "MMM"<br />
ELSE IF DIGIT = 4<br />
THEN<br />
RETURN "MMMM"<br />
ELSE IF DIGIT = 5<br />
THEN<br />
RETURN "MMMMM"<br />
ELSE IF DIGIT = 6<br />
THEN<br />
RETURN "MMMMMM"<br />
ELSE IF DIGIT = 7<br />
THEN<br />
RETURN "MMMMMMM"<br />
ELSE IF DIGIT = 8<br />
THEN<br />
RETURN "MMMMMMMM"<br />
ELSE IF DIGIT = 9<br />
THEN<br />
RETURN "MMMMMMMMM"<br />
END IF<br />
END DIGIT_4_TO_ROMAN<br />
DIGIT_4 := int (N/1000)<br />
N := N - (DIGIT_4 * 1000)<br />
DIGIT_3 := int (N/100)<br />
N := N - (DIGIT_3 * 100)<br />
DIGIT_2 := int (N/10)<br />
N := N - (DIGIT_2 * 10)<br />
DIGIT_1 := N<br />
RETURN DIGIT_4_TO_ROMAN (DIGIT_4)<br />
DIGIT_3_TO_ROMAN (DIGIT_3)<br />
DIGIT_2_TO_ROMAN (DIGIT_2)<br />
DIGIT_1_TO_ROMAN (DIGIT_2)<br />
END INTEGER_TO_ROMAN<br />
Come si vede, dopo aver scomposto il valore in quattro fasce, si utilizzano quattro funzioni<br />
distinte per ottenere la porzione di stringa che traduce il valore relativo. L’istruzione ‘RETURN’<br />
finale intende concatenare tutte le stringhe risultanti.<br />
355.3 Da numero a lettere, nel senso verbale<br />
Quando si trasforma un numero in lettere, per esempio quando si vuole trasformare 123 in «centoventitre»,<br />
l’algoritmo di conversione deve tenere conto delle convenzioni linguistiche e non<br />
esiste una soluzione generale per tutte le lingue.<br />
Per quanto riguarda la lingua italiana, esistono nomi diversi fino al 19, poi ci sono delle particolarità<br />
per i plurali o i singolari. La pseudocodifica seguente risolve il problema in una sola funzione<br />
ricorsiva. Le omissioni dovrebbero essere sufficientemente intuitive.<br />
INTEGER_TO_ITALIAN (N)<br />
LOCAL X INTEGER<br />
LOCAL Y INTEGER
54 volume VIII Argomenti avanzati e accessori<br />
IF N = 0<br />
THEN<br />
RETURN ""<br />
ELSE IF N = 1<br />
THEN<br />
RETURN "UNO"<br />
ELSE IF N = 2<br />
THEN<br />
RETURN "DUE"<br />
ELSE IF N = 3<br />
THEN<br />
RETURN "TRE"<br />
ELSE IF N = 4<br />
THEN<br />
RETURN "QUATTRO"<br />
ELSE IF N = 5<br />
THEN<br />
RETURN "CINQUE"<br />
ELSE IF N = 6<br />
THEN<br />
RETURN "SEI"<br />
ELSE IF N = 7<br />
THEN<br />
RETURN "SETTE"<br />
ELSE IF N = 8<br />
THEN<br />
RETURN "OTTO"<br />
ELSE IF N = 9<br />
THEN<br />
RETURN "NOVE"<br />
ELSE IF N = 10<br />
THEN<br />
RETURN "DIECI"<br />
ELSE IF N = 11<br />
THEN<br />
RETURN "UNDICI"<br />
ELSE IF N = 12<br />
THEN<br />
RETURN "DODICI"<br />
ELSE IF N = 13<br />
THEN<br />
RETURN "TREDICI"<br />
ELSE IF N = 14<br />
THEN<br />
RETURN "QUATTORDICI"<br />
ELSE IF N = 15<br />
THEN<br />
RETURN "QUINDICI"<br />
ELSE IF N = 16<br />
THEN<br />
RETURN "SEDICI"<br />
ELSE IF N = 17<br />
THEN<br />
RETURN "DICIASSETTE"<br />
ELSE IF N = 18<br />
THEN<br />
RETURN "DICIOTTO"<br />
ELSE IF N = 19<br />
THEN<br />
RETURN "DICIANNOVE"<br />
ELSE IF N = 20<br />
THEN<br />
RETURN "VENTI"<br />
ELSE IF N = 21
Trasformazione in lettere 55<br />
THEN<br />
RETURN "VENTUNO"<br />
ELSE IF (N >= 22) AND (N = 32) AND (N = 92) AND (N = 100) AND (N = 200) AND (N = 1000) AND (N = 2000) AND (N = 1000000) AND (N = 2000000) AND (N = 1000000000) AND (N = 2000000000) AND (N
56 volume VIII Argomenti avanzati e accessori<br />
"MILIARDI"<br />
INTEGER_TO_ITALIAN (Y)<br />
ELSE<br />
"##ERROR##"<br />
END IF<br />
END INTEGER_TO_ITALIAN<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Parte lxxi<br />
i86<br />
356 Minix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />
356.1 Procurarsi il s<strong>of</strong>tware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />
356.2 Preparazione all’installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />
356.3 Avvio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />
356.4 Installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />
356.5 Ricompilazione del kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<br />
356.6 Parametri di avvio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69<br />
356.7 Configurazione della rete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />
356.8 Personalizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72<br />
356.9 Tastiera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />
356.10 Altri programmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />
356.11 Copie di sicurezza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />
356.12 Convivenza tra Minix e GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />
356.13 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />
357 ELKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />
357.1 Sperimentare ELKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />
357.2 Immagini di dischetti già pronti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81<br />
357.3 Avvio di ELKS all’interno di DOSEMU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />
357.4 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />
57
Minix<br />
Capitolo 356<br />
Minix 1 è nato originariamente come sistema didattico. Minix non ha avuto il successo e la<br />
diffusione che avrebbe potuto avere a causa delle limitazioni della sua licenza iniziale. In seguito<br />
le cose sono cambiate, fortunatamente, perché Minix resta probabilmente l’unica possibilità reale<br />
per chi vuole utilizzare elaboratori con architettura i286 o inferiore.<br />
Lo scopo di questo capitolo è introdurre all’uso di Minix per poter riutilizzare i vecchi elaboratori<br />
i286, in particolare, collegandoli a una rete locale TCP/IP. Le informazioni seguenti si riferiscono<br />
alla versione 2.0.0.<br />
356.1 Procurarsi il s<strong>of</strong>tware<br />
Minix è ottenibile dalla rete, precisamente a partire dalla sua pagina di presentazione ufficiale,<br />
quella del suo primo autore (La sigla «AST» rappresenta le iniziali di Andrew S. Tanenbaum),<br />
oltre che dai vari siti speculari del relativo FTP.<br />
<br />
Minix è nato assieme a un libro che tuttora dovrebbe essere accompagnato da un CD-ROM<br />
contenente il sistema operativo:<br />
• Andrew S. Tanenbaum, Alber S. Woodhull, Operating Systems: Design and Implementation,<br />
2/e, Prentice-Hall<br />
356.1.1 Pacchetti essenziali<br />
Minix è un sistema molto piccolo e composto da pochi pacchetti. Questi hanno alcune particolarità:<br />
i nomi sono composti con lettere maiuscole e gli archivi compressi utilizzano la combinazione<br />
‘tar’+‘compress’ e sono evidenziati dall’uso dell’estensione ‘.TAZ’.<br />
Per prima cosa è necessario riprodurre la coppia di dischetti ‘ROOT’ e ‘USR’, a partire dai file<br />
omonimi. Il primo è in grado di avviarsi e contiene un file system minimo che si installa in<br />
un disco RAM, il secondo contiene una piccola serie di programmi da montare nella directory<br />
‘/usr/’, che servono per poter installare Minix nel disco fisso. Se si ha poca memoria a disposizione<br />
(i classici 640 Kibyte sono il minimo in assoluto per poter fare funzionare Minix), si può<br />
evitare l’utilizzo del disco RAM fondendo i due file in un solo dischetto. Data l’intenzione di<br />
questo capitolo verrà descritta l’ultima di queste modalità di installazione.<br />
Il mini sistema che si ottiene attraverso i due file appena citati, permette di installare, più o meno<br />
automaticamente, un insieme minimo di programmi contenuto nell’archivio ‘USR.TAZ’<br />
Esistono due versioni di questi tre file: una per architettura i386 o superiore e l’altra per i microprocessori<br />
inferiori. Date le intenzioni, si dovranno utilizzare i file della versione denominata<br />
‘i86’.<br />
1 Minix licenza simile a BSD<br />
58
Minix 59<br />
356.2 Preparazione all’installazione<br />
Il procedimento che viene descritto è valido sia per dischetti da 1440 Kibyte che da 1200 Kibyte.<br />
I due file ‘ROOT’ e ‘USR’ vanno copiati uno di seguito all’altro. Utilizzando GNU/Linux, si può<br />
fare nel modo seguente:<br />
# cat ROOT USR > /dev/fd0<br />
Dal punto di vista di Minix, il dischetto inserito nella prima unità a dischetti corrisponde al dispositivo<br />
‘/dev/fd0’, come per GNU/Linux, ma risulta diviso in partizioni: l’immagine ‘ROOT’<br />
risulta essere ‘/dev/fd0a’ e l’immagine ‘USR’ è ‘/dev/fd0c’ (la partizione ‘b’ è vuota). 2<br />
L’archivio ‘USR.TAZ’ deve essere suddiviso in diversi dischetti, con un procedimento un po’ insolito:<br />
viene semplicemente tagliato a fettine della dimensione massima contenibile dal tipo di dischetti<br />
che si utilizza. Nel caso si tratti di dischetti da 1440 Kibyte, si può utilizzare GNU/Linux,<br />
o un altro sistema Unix, nel modo seguente:<br />
# dd if=/USR.TAZ <strong>of</strong>=/dev/fd0 bs=1440k count=1 skip=0<br />
# dd if=/USR.TAZ <strong>of</strong>=/dev/fd0 bs=1440k count=1 skip=1<br />
# dd if=/USR.TAZ <strong>of</strong>=/dev/fd0 bs=1440k count=1 skip=2<br />
Se si trattasse di dischetti da 1200 Kibyte, occorrerebbe modificare la dimensione del blocco,<br />
come nell’esempio seguente:<br />
# dd if=/USR.TAZ <strong>of</strong>=/dev/fd0 bs=1200k count=1 skip=0<br />
# dd if=/USR.TAZ <strong>of</strong>=/dev/fd0 bs=1200k count=1 skip=1<br />
# dd if=/USR.TAZ <strong>of</strong>=/dev/fd0 bs=1200k count=1 skip=2<br />
356.2.1 Nomi di dispositivo riferiti alle partizioni<br />
Minix viene installato normalmente all’interno di una partizione primaria suddivisa in almeno<br />
due partizioni secondarie. La prima partizione serve a contenere il file system principale ed è<br />
di piccole dimensioni: 1440 Kibyte. La seconda serve per tutto il resto e viene montata in corrispondenza<br />
della directory ‘/usr/’. Inizialmente le partizioni erano tre e ‘/usr/’ era la terza.<br />
Attualmente, ‘/usr/’ continua a essere la terza partizione e si finge che esista una seconda<br />
partizione senza alcuno spazio a disposizione.<br />
Il primo disco fisso viene identificato dal dispositivo ‘/dev/hd0’, il secondo da ‘/dev/hd5’.<br />
Le partizioni primarie del primo disco fisso vanno da ‘/dev/hd1’ a ‘/dev/hd4’; quelle del<br />
secondo disco fisso da ‘/dev/hd6’ a ‘/dev/hd9’. Le partizioni secondarie corrispondono al<br />
nome del dispositivo della partizione primaria con l’aggiunta di una lettera alfabetica che ne<br />
indica l’ordine.<br />
• /dev/hd0<br />
– /dev/hd1<br />
* /dev/hd1a<br />
2 Se si trattasse della seconda unità a dischetti, si parlerebbe di ‘/dev/fd1’, ‘/dev/fd1a’ e ‘/dev/fd1c’.
60 volume VIII Argomenti avanzati e accessori<br />
* /dev/hd1b<br />
* /dev/hd1c<br />
* ...<br />
– /dev/hd2<br />
– /dev/hd3<br />
– /dev/hd4<br />
• /dev/hd5<br />
– /dev/hd6<br />
– /dev/hd7<br />
– /dev/hd8<br />
– /dev/hd9<br />
Minix può essere installato in una partizione primaria qualunque, purché ci siano almeno 40 Mibyte<br />
a disposizione. Utilizzando la versione di Minix ‘i86’, non conviene tentare di superare i<br />
128 Mibyte.<br />
356.3 Avvio<br />
Minix utilizza un sistema di avvio piuttosto s<strong>of</strong>isticato; per fare un paragone con GNU/Linux, si<br />
tratta di qualcosa che compie le stesse funzioni di LILO, o di un cosiddetto bootloader.<br />
Il sistema che svolge questa funzione in Minix si chiama boot monitor ed è importante capire<br />
subito come si utilizza se non si ha molta memoria RAM a disposizione, quanta ne richiederebbe<br />
un disco RAM per l’immagine ‘ROOT’.<br />
Per cominciare, dopo aver preparato il dischetto ‘ROOT’+‘USR’, lo si inserisce senza la protezione<br />
contro la scrittura e si avvia l’elaboratore. Questo è ciò che appare.<br />
Minix boot monitor 2.5<br />
Press ESC to enter the monitor<br />
Hit a key as follows:<br />
= Start Minix<br />
Premendo il tasto [ Esc ] si attiva il boot monitor, mentre premendo [ = ] (si fa riferimento alla<br />
tastiera americana e questo simbolo si trova in corrispondenza della nostra lettera «ì») si avvia<br />
Minix con le impostazioni predefinite.<br />
Dal momento che si immagina di avere a disposizione poca memoria (solo 1 Mibyte), non<br />
si può avviare Minix così, perché il contenuto dell’immagine ‘ROOT’ verrebbe caricato come<br />
disco RAM. È necessario utilizzare subito il boot monitor.<br />
[ Esc ]<br />
[ESC]<br />
fd0><br />
Si ottiene un invito (prompt), attraverso il quale possono essere utilizzati alcuni comandi importanti<br />
per predisporre l’avvio del sistema Minix. Per ottenere aiuto si può utilizzare il comando<br />
‘help’.
Minix 61<br />
fd0> help [ Invio ]<br />
Si ottiene un riepilogo dei comandi e del modo con cui possono essere utilizzati. Le cose più importanti<br />
che si possono fare con il boot monitor sono: l’avvio a partire da una partizione differente<br />
da quella prestabilita; l’assegnamento o il ripristino al valore predefinito di una variabile.<br />
Queste variabili sono solo entità riferite al sistema di avvio e la loro modifica permette di cambiare<br />
il modo con cui si avvia il kernel. Il comando ‘set’ permette di elencare il contenuto di<br />
queste variabili.<br />
fd0> set [ Invio ]<br />
rootdev = (ram)<br />
ramimagedev = (bootdev)<br />
ramsize = (0)<br />
processor = (286)<br />
bus = (at)<br />
memsize = (640)<br />
emssize = (330)<br />
video = (vga)<br />
chrome = (mono)<br />
image = (minix)<br />
main() = (menu)<br />
I valori appaiono tutti tra parentesi tonde perché rappresentano le impostazioni predefinite.<br />
Quando si cambia qualche valore, questo appare senza le parentesi.<br />
La prima cosa da cambiare è il dispositivo di avvio, ‘rootdev’. Si deve assegnare il nome di<br />
dispositivo riferito all’immagine ‘ROOT’ su dischetto. Si tratta di ‘/dev/fd0a’, come dire, la<br />
prima partizione secondaria del dischetto. In questo caso, il nome del dispositivo può anche<br />
essere indicato senza la parte iniziale, limitandolo al solo ‘fd0a’.<br />
fd0> rootdev=fd0a [ Invio ]<br />
fd0> set [ Invio ]<br />
rootdev = fd0a<br />
ramimagedev = (bootdev)<br />
ramsize = (0)<br />
processor = (286)<br />
bus = (at)<br />
memsize = (640)<br />
emssize = (330)<br />
video = (vga)<br />
chrome = (mono)<br />
image = (minix)<br />
main() = (menu)<br />
Per avviare il sistema, basta utilizzare il comando ‘boot’ senza argomenti.<br />
fd0> boot [ Invio ]<br />
In questo modo si lascia il boot monitor e si avvia il kernel. Una volta avviato il sistema, viene<br />
richiesto immediatamente il montaggio della seconda immagine, ‘USR’, contenente gli strumenti<br />
necessari all’installazione. Avendo avviato senza disco RAM, il dischetto contenente l’immagine<br />
‘ROOT’ non può essere tolto e questo è il motivo per il quale deve essere contenuta nello stesso<br />
dischetto insieme a ‘USR’. 3<br />
3 Una cosa da sapere subito è che Minix non utilizza la sequenza [ Ctrl+C ] per interrompere un programma. Per questo<br />
si usa il tasto [ Canc ] da solo.
62 volume VIII Argomenti avanzati e accessori<br />
Minix 2.0.0 Copyright 1997 Prentice-Hall, Inc.<br />
Executing in 16-bit protected mode<br />
Memory size = 970K MINIX = 206K RAM disk = 0K Available = 765K<br />
Mon Nov 3 15:24:15 MET 1997<br />
Finish the name <strong>of</strong> device to mount as /usr: /dev/<br />
Date le premesse, occorre specificare il nome del dispositivo corrispondente all’immagine ‘USR’:<br />
si tratta di ‘fd0c’.<br />
fd0c [ Invio ]<br />
/dev/fd0c is read-write mounted on /usr<br />
Starting standard daemons: update.<br />
Login as root and run ’setup’ to install Minix.<br />
Minix Release 2.0 Version 0<br />
noname login:<br />
root [ Invio ]<br />
#<br />
356.4 Installazione<br />
L’installazione di Minix avviene in tre fasi:<br />
1. preparazione della partizione di destinazione;<br />
2. trasferimento del contenuto del dischetto, ovvero delle immagini ‘ROOT’ e ‘USR’;<br />
3. dopo il riavvio, trasferimento dell’archivio ‘USR.TAZ’ e possibilmente, se si dispone di una<br />
partizione di almeno 40 Mibyte, anche di ‘SYS.TAZ’ e ‘CMD.TAZ’.<br />
356.4.1 Setup<br />
Per iniziare l’installazione, dopo aver avviato il sistema Minix dal dischetto, si utilizza lo script<br />
‘setup’.<br />
# setup [ Invio ]
Minix 63<br />
This is the Minix installation script.<br />
Note 1: If the screen blanks suddenly then hit F3 to select "s<strong>of</strong>tware<br />
scrolling".<br />
Note 2: If things go wrong then hit DEL and start over.<br />
Note 3: The installation procedure is described in the manual page<br />
usage(8). It will be hard without it.<br />
Note 4: Some questions have default answers, like this: [y]<br />
Simply hit RETURN (or ENTER) if you want to choose that answer.<br />
Note 5: If you see a colon (:) then you should hit RETURN to continue.<br />
:<br />
[ Invio ]<br />
Dopo la breve spiegazione, avendo premuto il tasto [ Invio ] si passa all’indicazione del tipo di<br />
tastiera. La scelta è ovvia, ‘italian’, anche se non corrisponde esattamente: la barra verticale<br />
(quella per le pipeline) si trova al posto della lettera «ì» (i accentata). Durante questa fase di<br />
installazione conviene utilizzare la tastiera nazionale (‘italian’) per evitare spiacevoli incidenti<br />
quando si utilizza il programma di gestione delle partizioni.<br />
What type <strong>of</strong> keyboard do you have? You can choose one <strong>of</strong>:<br />
french italian latin-am scandinavn uk us-swap<br />
german japanese olivetti spanish us-std<br />
Keyboard type? [us-std]<br />
italian [ Invio ]<br />
Minix needs one primary partition <strong>of</strong> at least 30 Mb (it fits in 20 Mb, but<br />
it needs 30 Mb if fully recompiled. Add more space to taste.)<br />
If there is no free space on your disk then you have to back up one <strong>of</strong> the<br />
other partitions, shrink, and reinstall. See the appropriate manuals <strong>of</strong> the<br />
the operating systems currently installed. Restart your Minix installation<br />
after you have made space.<br />
To make this partition you will be put in the editor "part". Follow the<br />
advice under the ’!’ key to make a new partition <strong>of</strong> type MINIX. Do not<br />
touch an existing partition unless you know precisely what you are doing!<br />
Please note the name <strong>of</strong> the partition (hd1, hd2, ..., hd9, sd1, sd2, ...<br />
sd9) you make. (See the devices section in usage(8) on Minix device names.)<br />
:<br />
Il programma di Minix che permette di accedere alla tabella delle partizioni è ‘part’ ed è ciò che<br />
sta per essere avviato. Come sempre, l’uso di un programma di questo genere è molto delicato:<br />
un piccolo errore mette fuori uso tutti i dati eventualmente contenuti in altre partizioni.<br />
[ Invio ]
64 volume VIII Argomenti avanzati e accessori<br />
Select device ----first---- --geom/last-- ------sectors-----<br />
Device Cyl Head Sec Cyl Head Sec Base Size Kb<br />
/dev/hd0 ? ? ?<br />
? ? ? ? ? ? ? ? ?<br />
Num Sort Type<br />
? ? ? ? ? ? ? ? ? ? ? ? ?<br />
? ? ? ? ? ? ? ? ? ? ? ? ?<br />
? ? ? ? ? ? ? ? ? ? ? ? ?<br />
? ? ? ? ? ? ? ? ? ? ? ? ?<br />
Type ’+’ or ’-’ to change, ’r’ to read, ’?’ for more help, ’!’ for advice<br />
Prima di utilizzare questo programma conviene leggere la sua guida interna, ottenibile con la<br />
pressione del tasto [ ? ]. Il cursore si presenta inizialmente sull’indicazione del disco, ‘/dev/<br />
hd0’, e può essere cambiato semplicemente premendo i tasti [ + ] o [ - ]. Una volta raggiunto<br />
il disco desiderato (in questo caso il primo disco va bene), si deve leggere la sua tabella delle<br />
partizioni, in modo da rimpiazzare tutti i punti interrogativi che riempiono lo schermo.<br />
[ r ]<br />
Select device ----first---- --geom/last-- ------sectors-----<br />
Device Cyl Head Sec Cyl Head Sec Base Size Kb<br />
/dev/hd0 615 8 17<br />
0 0 0 614 7 16 0 83640 41820<br />
Num Sort Type<br />
1* hd1 86 DOS-BIG 0 1 0 613 7 16 17 83487 41743<br />
2 hd2 00 None 0 0 0 0 0 -1 0 0 0<br />
3 hd3 00 None 0 0 0 0 0 -1 0 0 0<br />
4 hd4 00 None 0 0 0 0 0 -1 0 0 0<br />
Con questo esempio si suppone di avere solo un vecchio disco fisso MFM di circa 40 Mibyte, nel<br />
quale la prima partizione primaria era stata dedicata in precedenza al Dos. Così, basta cambiare<br />
il numero che identifica il tipo di partizione. Per farlo, vi si posiziona sopra il cursore, spostandolo<br />
con i tasti freccia, quindi si usano i tasti [ + ] o [ - ] fino a fare apparire il numero 8116. Al<br />
primo intervento per cambiare un valore qualsiasi, viene richiesto esplicitamente se si intende<br />
modificare effettivamente i dati della tabella delle partizioni.<br />
Do you wish to modify existing partitions (y/n) [ y ]<br />
Una volta modificato il tipo, la prima partizione dovrebbe apparire così come segue:<br />
Num Sort Type<br />
1* hd1 81 MINIX 0 1 0 613 7 16 17 83487 41743<br />
Quindi si conclude.<br />
[ q ]<br />
Save partition table? (y/n) [ y ]<br />
Lo script di configurazione e installazione riprende richiedendo quale sia la partizione su cui<br />
installare Minix. In questo caso si tratta della prima, cioè ‘/dev/hd1’.<br />
Please finish the name <strong>of</strong> the primary partition you have created:<br />
(Just type RETURN if you want to rerun "part") /dev/
Minix 65<br />
hd1 [ Invio ]<br />
You have created a partition named: /dev/hd1<br />
The following subpartitions are about to be created on /dev/hd3:<br />
Root subpartition: /dev/hd1a 1440 kb<br />
/usr subpartition: /dev/hd1c rest <strong>of</strong> hd1<br />
Hit return if everything looks fine, or hit DEL to bail out if you want to<br />
think it over. The next step will destroy /dev/hd1.<br />
:<br />
Come accennato in precedenza, Minix viene installato in due partizioni secondarie: la prima<br />
serve a contenere il file system principale, la seconda per il resto. In seguito si possono montare<br />
anche partizioni successive.<br />
Migrating from floppy to disk...<br />
Scanning /dev/hd1c for bad blocks. (Hit DEL to stop the scan if are absolutely<br />
sure that there can not be any bad blocks. Otherwise just wait.)<br />
La scansione del disco fisso è necessaria se si utilizza un vecchio disco MFM, come si suppone<br />
di avere in questo esempio, mentre può essere inutile con un disco ATA. È importante fare attenzione:<br />
se ci sono settori inutilizzabili, vengono creati alcuni file ‘/usr/.Bad_ * ’ che non vanno<br />
cancellati! Alla fine, lo script procede a copiare il contenuto del dischetto nel disco fisso.<br />
What is the memory size <strong>of</strong> this system in kilobytes? [4096 or more]<br />
La dimensione di memoria RAM disponibile effettivamente è solo di 970 Kibyte, quindi si inserisce<br />
questo valore; se la memoria a disposizione fosse maggiore o uguale a 4 Mibyte, non<br />
occorrerebbe indicare alcunché, basterebbe solo confermare.<br />
970 [ Invio ]<br />
Second level file system block cache set to 0 kb.<br />
A questo punto, termina l’installazione del dischetto nel disco fisso e si può passare a riavviare il<br />
sistema da lì.<br />
Please insert the installation ROOT floppy and type ’halt’ to exit Minix.<br />
You can type ’boot hd1’ to try the newly installed Minix system. See<br />
"TESTING" in the usage manual.<br />
# halt [ Invio ]<br />
System Halted
66 volume VIII Argomenti avanzati e accessori<br />
356.4.2 Avvio del sistema copiato nel disco fisso<br />
Una volta conclusa l’esecuzione dello script di configurazione e installazione, si ritorna sotto il<br />
controllo del boot monitor, attraverso il quale è possibile avviare il sistema dalla prima partizione<br />
del disco fisso.<br />
fd0> boot /dev/hd1 [ Invio ]<br />
Minix 2.0.0 Copyright 1997 Prentice-Hall, Inc.<br />
Executing in 16-bit protected mode<br />
at-hd0: 615x8x17<br />
Memory size = 970K MINIX = 206K RAM disk = 0K Available = 765K<br />
Mon Nov 3 16:01:27 MET 1997<br />
Starting standard daemons: update.<br />
Login as root and run ’setup /usr’ to install floppy sets.<br />
Minix Release 2.0 Version 0<br />
noname login:<br />
# root [ Invio ]<br />
Il suggerimento dato all’avvio ricorda che è possibile installare altre serie di dischetti, a<br />
cominciare da ‘USR.TAZ’, utilizzando il comando ‘setup /usr’.<br />
356.4.3 Installazione delle serie di dischetti<br />
Tra i pacchetti di Minix, ‘USR.TAZ’ è essenziale e cambia a seconda del tipo di architettura (i86<br />
o i386). Però, dal momento che c’è spazio sufficiente nel disco fisso, conviene installare anche<br />
‘SYS.TAZ’ per poter ricompilare il kernel e ‘CMD.TAZ’ che contiene i sorgenti dei vari programmi<br />
di servizio.<br />
Tutti questi pacchetti devono essere suddivisi in dischetti nel modo visto in precedenza per il<br />
caso di ‘USR.TAZ’.<br />
# setup /usr [ Invio ]<br />
Lo script ‘setup’ chiede una serie di conferme.<br />
What is the size <strong>of</strong> the images on the diskettes? [all]<br />
Premendo semplicemente [ Invio ] si intende che i dischetti vadano letti nella loro interezza.<br />
[ Invio ]<br />
What floppy drive to use? [0]<br />
Premendo semplicemente [ Invio ] si fa riferimento alla prima unità, ‘/dev/fd0’.<br />
[ Invio ]<br />
Please insert input volume 1 and hit return
Minix 67<br />
Si inserisce il primo dischetto e si conferma<br />
[ Invio ]<br />
Inizia la fase di estrazione di quanto contenuto nel primo dischetto, a partire dalla directory<br />
‘/usr/’. Quando termina l’estrazione del primo dischetto, viene richiesto il successivo, fino alla<br />
conclusione.<br />
Conviene ripetere la procedura fino a quando sono stati installati anche gli archivi ‘SYS.TAZ’ e<br />
‘CMD.TAZ’.<br />
356.4.4 Dischetto di avvio<br />
Minix è molto semplice e non è necessario un dischetto di avvio realizzato appositamente. È sufficiente<br />
il dischetto utilizzato per iniziare l’installazione. Se si hanno difficoltà con l’avviamento<br />
di Minix dal disco fisso, si può avviare il boot monitor dal dischetto e con quello utilizzare il<br />
comando ‘boot /dev/hd1’.<br />
356.4.5 Conclusione<br />
Per chiudere l’attività di Minix, si può fare nel solito modo comune a quasi tutti i sistemi Unix.<br />
# shutdown -h now [ Invio ]<br />
356.5 Ricompilazione del kernel<br />
Anche Minix, nella sua semplicità, richiede una ricompilazione del kernel per la sua ottimizzazione.<br />
In particolare, per poter attivare la gestione del TCP/IP occorre passare per la configurazione<br />
e ricompilazione.<br />
Il file del kernel, secondo la tradizione di Minix, dovrebbe trovarsi nella directory radice e avere<br />
il nome ‘minix’. Se però, invece di trattarsi di un file, si tratta di una directory, nella fase di avvio<br />
viene eseguito il file più recente contenuto in tale directory. Il kernel normale, cioè quello che si<br />
trova dopo l’installazione, dovrebbe essere ‘/minix/2.0.0’.<br />
Per poter ricompilare il kernel occorre avere installato il pacchetto ‘SYS.TAZ’. Si procede come<br />
segue:<br />
1. si modifica il file ‘/usr/include/minix/config.h’;<br />
2. ci si posiziona nella directory ‘/usr/src/tools/’;<br />
3. si avvia la compilazione con il comando ‘make’.<br />
Al termine si ottiene il file del kernel (o immagine) corrispondente a ‘/usr/src/tools/image’<br />
che si può copiare e rinominare come si ritiene più opportuno.
68 volume VIII Argomenti avanzati e accessori<br />
356.5.1 /usr/include/minix/config.h<br />
La configurazione che viene proposta deriva dagli esempi precedenti, in cui si ha una particolare<br />
penuria di memoria. Seguono solo alcuni pezzi.<br />
/* If ROBUST is set to 1, writes <strong>of</strong> i-node, directory, and indirect blocks<br />
* from the cache happen as soon as the blocks are modified. This gives a more<br />
* robust, but slower, file system. If it is set to 0, these blocks are not<br />
* given any special treatment, which may cause problems if the system crashes.<br />
*/<br />
#define ROBUST 1 /* 0 for speed, 1 for robustness */<br />
La macro ‘ROBUST’ permette di sincronizzare le operazioni di accesso al disco. Nell’esempio<br />
mostrato si attiva questa opzione, in modo da poter utilizzare il sistema con tranquillità (e<br />
ovviamente con maggiore lentezza).<br />
/* Number <strong>of</strong> slots in the process table for user processes. */<br />
#define NR_PROCS 32<br />
Il numero massimo dei processi eseguibili può essere una seria limitazione all’uso simultaneo<br />
dell’elaboratore da parte di più utenti, ma la scarsa memoria a disposizione consiglia di mantenere<br />
basso questo valore.<br />
/* Enable or disable the second level file system cache on the RAM disk. */<br />
#define ENABLE_CACHE2 0<br />
Sempre a causa della carenza di memoria, è opportuno disabilitare la memoria cache.<br />
/* Include or exclude device drivers. Set to 1 to include, 0 to exclude. */<br />
#define ENABLE_NETWORKING 1 /* enable TCP/IP code */<br />
#define ENABLE_AT_WINI 1 /* enable AT winchester driver */<br />
#define ENABLE_BIOS_WINI 1 /* enable BIOS winchester driver */<br />
#define ENABLE_ESDI_WINI 1 /* enable ESDI winchester driver */<br />
#define ENABLE_XT_WINI 0 /* enable XT winchester driver */<br />
#define ENABLE_ADAPTEC_SCSI 0 /* enable ADAPTEC SCSI driver */<br />
#define ENABLE_MITSUMI_CDROM 0 /* enable Mitsumi CD-ROM driver */<br />
#define ENABLE_SB_AUDIO 0 /* enable Soundblaster audio driver */<br />
In questa sezione è importante abilitare ciò che serve ed eliminare il resto. In particolare, è qui<br />
che si attiva la connettività TCP/IP, che non risulta attivata in modo predefinito.<br />
/* NR_CONS, NR_RS_LINES, and NR_PTYS determine the number <strong>of</strong> terminals the<br />
* system can handle.<br />
*/<br />
#define NR_CONS 2 /* # system consoles (1 to 8) */<br />
#define NR_RS_LINES 1 /* # rs232 terminals (0, 1, or 2) */<br />
#define NR_PTYS 2 /* # pseudo terminals (0 to 64) */<br />
Il numero predefinito di console virtuali è due, ma può essere espanso, sempre che ciò possa<br />
avere senso date le limitazioni del sistema. Invece è importante attivare gli pseudoterminali, cioè<br />
il numero massimo di connessioni remote. Volendo gestire la rete, è il caso di indicare almeno<br />
uno pseduoterminale.<br />
Per modificare il file ‘/usr/include/minix/config.h’ si può utilizzare ‘vi’, che è un<br />
collegamento a ‘elvis’, oppure ‘elle’. 4<br />
Si procede con la compilazione.<br />
4 Il programma ‘elvis’ in particolare, è molto tradizionale: i tasti freccia generano proprio le lettere corrispondenti e<br />
quindi non possono essere usati durante la fase di inserimento. ‘elle’ è un Emacs ridotto al minimo.
Minix 69<br />
# cd /usr/src/tools [ Invio ]<br />
# make [ Invio ]<br />
Al termine della compilazione, se non sono occorsi incidenti, si ottiene il file ‘image’.<br />
# cp image /minix/rete.0.1 [ Invio ]<br />
Questo dovrebbe bastare, trattandosi del file più recente nella directory ‘/minix/’, è anche quello<br />
che verrà avviato la prossima volta.<br />
# shutdown -h [ Invio ]<br />
356.5.2 File di dispositivo<br />
Quando si ricompila il kernel è probabile che si renda necessaria la creazione di file di dispositivo<br />
che prima non erano necessari. Nel caso della gestione della rete, sono necessari i file seguenti:<br />
• ‘/dev/eth’;<br />
• ‘/dev/ip’;<br />
• ‘/dev/tcp’;<br />
• ‘/dev/udp’;<br />
• ‘/dev/ttyp0’ e successivi;<br />
• ‘/dev/ptyp0’ e successivi.<br />
Questo ragionamento vale anche per le console virtuali: se si vogliono molte console, forse è<br />
necessario aggiungere i file relativi.<br />
Probabilmente c’è già tutto ciò di cui si può avere bisogno, ma se manca si può creare con lo<br />
script ‘MAKEDEV’.<br />
MAKEDEV dispositivo<br />
Per esempio, trovandosi già nella directory ‘/dev/’, si può creare il dispositivo ‘/dev/tcp’ nel<br />
modo seguente:<br />
# MAKEDEV tcp<br />
356.6 Parametri di avvio<br />
Anche Minix richiede alcuni parametri di avvio in presenza di hardware particolare. La gestione<br />
di questi avviene in modo molto semplice attraverso il boot monitor: basta definire una nuova<br />
variabile, assegnandole il valore corretto.
70 volume VIII Argomenti avanzati e accessori<br />
356.6.1 Scheda di rete<br />
Per gestire una rete occorre una scheda di rete Ethernet. Nell’esempio seguente si immagina di<br />
disporre di una scheda compatibile con il modello NE2000 configurata con indirizzo di I/O 30016<br />
e IRQ 11.<br />
Il parametro di avvio per ottenere il riconoscimento della scheda Ethernet è ‘DPETHn’, dove n è<br />
il numero della scheda, a partire da zero.<br />
DPETHn=indirizzo_i/o:irq:indirizzo_di_memoria<br />
La scheda NE2000 non utilizza alcun indirizzo di memoria, quindi, per il nostro esempio occorre<br />
il parametro seguente:<br />
DPETH0=300:11<br />
Come si vede, l’indirizzo di I/O è espresso implicitamente in esadecimale e l’IRQ in decimale,<br />
mentre l’indirizzo di memoria viene omesso trattandosi di una NE2000. Per inserire tale<br />
parametro si utilizza il boot monitor nel modo seguente:<br />
hd0> DPETH0=300:11 [ Invio ]<br />
hd0> save [ Invio ]<br />
L’ultima istruzione, ‘save’, salva questo parametro che altrimenti dovrebbe essere indicato ogni<br />
volta che si avvia il sistema.<br />
Se la scheda di rete viene riconosciuta, all’avvio appare il messaggio seguente:<br />
Minix 2.0.0 Copyright 1997 Prentice-Hall, Inc.<br />
Executing in 16-bit protected mode<br />
ne2000: NE2000 at 300:11<br />
356.7 Configurazione della rete<br />
La configurazione della rete va fatta con cura, in modo da non avere bisogno di alcuni demoni che<br />
permettono una sorta di autoconfigurazione. Negli esempi seguenti si configura il nuovo sistema<br />
Minix tenendo conto di questa situazione:<br />
• dinkel.brot.dg, IP 192.168.1.1, servizio DNS e router predefinito;<br />
• minix.brot.dg, IP 192.168.1.25, elaboratore Minix.<br />
Per quanto possibile, si fa in modo di non avere bisogno del DNS.
Minix 71<br />
356.7.1 /etc/hosts<br />
Volendo attivare localmente la risoluzione dei nomi e degli indirizzi è necessario il file ‘/etc/<br />
hosts’, che va configurato come al solito, esattamente come si fa con GNU/Linux.<br />
127.0.0.1 localhost<br />
192.168.1.1 dinkel.brot.dg<br />
192.168.1.25 minix.brot.dg<br />
356.7.2 /etc/hostname.file<br />
Il file ‘/etc/hostname.file’ serve solo a definire il nome dell’elaboratore locale, in senso<br />
generale. Non ha niente a che vedere con le interfacce di rete.<br />
# echo "minix.brot.dg" > /etc/hostname.file [ Invio ]<br />
356.7.3 /etc/resolv.conf<br />
Il file ‘/etc/resolv.conf’ permette di indicare gli indirizzi dei nodi che forniscono un servizio<br />
DNS. Nell’esempio proposto si vuole fare in modo che il sistema di risoluzione dei nomi avvenga<br />
localmente, per mezzo di quanto contenuto nel file ‘/etc/hosts’. Per questo viene indicato<br />
come servente DNS anche l’indirizzo locale (loopback).<br />
nameserver 127.0.0.1<br />
nameserver 192.168.1.1<br />
356.7.4 /etc/rc.net<br />
Lo script ‘/etc/rc.net’ viene utilizzato da ‘/etc/rc’ per attivare la rete. Lo si può utilizzare<br />
per attivare l’interfaccia di rete e per definire l’instradamento verso il router (l’instradamento<br />
verso la rete connessa all’interfaccia è predefinito).<br />
# Attiva l’interfaccia e l’instradamento verso la sua rete.<br />
ifconfig -h 192.168.1.25<br />
# Definisce l’instradamento predefinito verso il router<br />
add_route -g 192.168.1.1<br />
356.7.5 /etc/rc<br />
Probabilmente, è utile ritoccare il file ‘/etc/rc’, per eliminare l’avvio automatico di alcuni<br />
demoni inutili dal momento che la rete è configurata. Quello che segue è il pezzo che attiva la<br />
gestione della rete.<br />
# Network initialization.<br />
(
72 volume VIII Argomenti avanzati e accessori<br />
fi<br />
ifconfig -h 192.9.200.1<br />
if [ "$net" ]<br />
then<br />
echo -n "Starting network daemons: "<br />
for daemon in rarpd nonamed irdpd talkd<br />
do<br />
if [ -f /usr/bin/$daemon ]<br />
then<br />
echo -n " $daemon"<br />
$daemon &<br />
fi<br />
done<br />
echo .<br />
fi<br />
# Get the nodename from the DNS and set it.<br />
hostaddr -a >/etc/hostname.file || echo noname >/etc/hostname.file<br />
echo -n "Starting network services:"<br />
for pair in ’shell in.rshd’ ’login in.rld’ \<br />
’telnet in.telnetd’ ’ftp in.ftpd’<br />
do<br />
set $pair<br />
if [ -f /usr/bin/$2 ]<br />
then<br />
echo -n " $1"<br />
tcpd $1 /usr/bin/$2 &<br />
fi<br />
done<br />
echo .<br />
Vale la pena di modificare quanto segue:<br />
if [ "$net" ]<br />
then<br />
echo -n "Starting network daemons: "<br />
for daemon in nonamed talkd ### rarpd nonamed irdpd talkd<br />
do<br />
...<br />
Nel pezzo precedente non vengono avviati i demoni ‘rarpd’ e ‘irdpd’, che sono necessari rispettivamente<br />
per ottenere l’indirizzo IP in base all’indirizzo hardware della scheda Ethernet<br />
e a definire gli instradamenti verso i router. Eventualmente, si potrebbe anche evitare di avviare<br />
‘talkd’ se non si intende utilizzare ‘talk’. Il demone ‘nonamed’ è necessario se non si vuole essere<br />
obbligati ad avere un servizio DNS esterno; in pratica è necessario perché venga interpretato<br />
il contenuto del file ‘/etc/hosts’.<br />
356.8 Personalizzazione<br />
Il sistema risulta configurato in maniera piuttosto disordinata, a cominciare dal fatto che la directory<br />
personale dell’utente ‘root’ corrisponde alla directory radice; così, al suo interno si trovano<br />
i file di configurazione dell’amministratore. Probabilmente, la prima cosa da fare è quella di<br />
creare una directory ‘/root/’, porvi al suo interno i file di configurazione (dovrebbe trattarsi di<br />
‘.ellepro.b1’, ‘.exrc’ e ‘.pr<strong>of</strong>ile’), modificando anche il file ‘/etc/passwd’ in modo da<br />
assegnare all’utente ‘root’ questa nuova directory.
Minix 73<br />
356.8.1 /etc/passwd, /etc/group e /etc/shadow<br />
Minix, nonostante la sua semplicità, utilizza le password shadow. Pertanto, se si tenta di inserire<br />
un utente manualmente, occorre intervenire anche su questo file, ‘/etc/shadow’, altrimenti<br />
l’utente non riuscirà ad accedere.<br />
Il file ‘/etc/group’, se non va bene com’è, deve essere modificato manualmente, mentre per gli<br />
utenti conviene affidarsi allo script ‘adduser’.<br />
adduser utente gruppo directory_home<br />
Dopo aver creato un utente, come al solito è opportuno utilizzare il programma ‘passwd’ per<br />
assegnare la parola d’ordine. 5<br />
356.9 Tastiera<br />
La mappa della tastiera viene definita attraverso il programma ‘loadkeys’ e il file contenente la<br />
mappa desiderata. Per cui,<br />
# loadkeys ./tastiera.map<br />
permette di caricare la mappa del file ‘tastiera.map’ contenuto nella directory corrente.<br />
La mappa della tastiera, secondo la scelta fatta durante l’installazione di Minix, avviene per<br />
mezzo del file ‘/etc/keymap’: se lo script ‘/etc/rc’ lo trova durante la fase di avvio, lo carica<br />
attraverso ‘loadkeys’.<br />
356.9.1 Modifica della mappa<br />
La configurazione della tastiera italiana, per quanto riguarda la versione 2.0 di Minix, non è<br />
perfetta. Per modificare la mappa occorre intervenire sul file ‘/usr/src/kernel/keymaps/<br />
italian.src’. Dopo la modifica si deve compilare il sorgente in modo da ottenere il file<br />
‘/usr/src/kernel/keymaps/italian.map’. Al termine, questo file va copiato e rinominato<br />
in modo da sostituire ‘/etc/keymap’.<br />
Il sorgente corretto potrebbe apparire come nell’esempio seguente, in particolare, per ottenere la<br />
tilde (‘~’) si deve usare la combinazione [ AltGr+ì ], mentre per ottenere l’apostr<strong>of</strong>o inverso (‘‘’)<br />
si deve usare la combinazione [ AltGr+’ ]. I caratteri che si trovano oltre il settimo bit, vengono<br />
rappresentati in ottale.<br />
/* Modified by Daniele Giacomini daniele @ swlibero.org 1998.12.22 */<br />
/* Keymap for Italian standard keyboard, similar to Linux layout. */<br />
u16_t keymap[NR_SCAN_CODES * MAP_COLS] = {<br />
/* scan-code !Shift Shift Alt AltGr Alt+Sh Ctrl */<br />
/* ==================================================================== */<br />
/* 00 - none */ 0, 0, 0, 0, 0, 0,<br />
/* 01 - ESC */ C(’[’), C(’[’), CA(’[’),C(’[’), C(’[’), C(’[’),<br />
/* 02 - ’1’ */ ’1’, ’!’, A(’1’), ’1’, ’!’, C(’A’),<br />
/* 03 - ’2’ */ ’2’, ’"’, A(’2’), ’2’, ’@’, C(’@’),<br />
/* 04 - ’3’ */ ’3’, 0234, A(’3’), ’3’, 0234, C(’C’),<br />
/* 05 - ’4’ */ ’4’, ’$’, A(’4’), ’4’, ’$’, C(’D’),<br />
5 Lo script ‘adduser’ si avvale della directory personale dell’utente ‘ast’ per inserire i file di configurazione iniziali.<br />
Questa directory, corrispondente a ‘/usr/ast/’, svolge il ruolo di scheletro delle directory personali da creare. Volendo<br />
si può realizzare un proprio script per rendere la cosa più elegante.
74 volume VIII Argomenti avanzati e accessori<br />
/* 06 - ’5’ */ ’5’, ’%’, A(’5’), ’5’, ’%’, C(’E’),<br />
/* 07 - ’6’ */ ’6’, ’&’, A(’6’), ’6’, ’&’, C(’F’),<br />
/* 08 - ’7’ */ ’7’, ’/’, A(’7’), ’{’, ’/’, C(’G’),<br />
/* 09 - ’8’ */ ’8’, ’(’, A(’8’), ’[’, ’(’, C(’H’),<br />
/* 10 - ’9’ */ ’9’, ’)’, A(’9’), ’]’, ’)’, C(’I’),<br />
/* 11 - ’0’ */ ’0’, ’=’, A(’0’), ’}’, ’=’, C(’@’),<br />
/* 12 - ’-’ */ ’\’’, ’?’, A(’\’’),’\‘’, ’?’, C(’@’),<br />
/* 13 - ’=’ */ 0215, ’^’, 0215, ’~’, ’^’, C(’^’),<br />
/* 14 - BS */ C(’H’), C(’H’), CA(’H’),C(’H’), C(’H’), 0177,<br />
/* 15 - TAB */ C(’I’), C(’I’), CA(’I’),C(’I’), C(’I’), C(’I’),<br />
/* 16 - ’q’ */ L(’q’), ’Q’, A(’q’), ’q’, ’Q’, C(’Q’),<br />
/* 17 - ’w’ */ L(’w’), ’W’, A(’w’), ’w’, ’W’, C(’W’),<br />
/* 18 - ’e’ */ L(’e’), ’E’, A(’e’), ’e’, ’E’, C(’E’),<br />
/* 19 - ’r’ */ L(’r’), ’R’, A(’r’), ’r’, ’R’, C(’R’),<br />
/* 20 - ’t’ */ L(’t’), ’T’, A(’t’), ’t’, ’T’, C(’T’),<br />
/* 21 - ’y’ */ L(’y’), ’Y’, A(’y’), ’y’, ’Y’, C(’Y’),<br />
/* 22 - ’u’ */ L(’u’), ’U’, A(’u’), ’u’, ’U’, C(’U’),<br />
/* 23 - ’i’ */ L(’i’), ’I’, A(’i’), ’i’, ’I’, C(’I’),<br />
/* 24 - ’o’ */ L(’o’), ’O’, A(’o’), ’o’, ’O’, C(’O’),<br />
/* 25 - ’p’ */ L(’p’), ’P’, A(’p’), ’p’, ’P’, C(’P’),<br />
/* 26 - ’[’ */ 0212, 0202, 0212, ’[’, ’{’, C(’[’),<br />
/* 27 - ’]’ */ ’+’, ’*’, A(’+’), ’]’, ’}’, C(’]’),<br />
/* 28 - CR/LF */ C(’M’), C(’M’), CA(’M’),C(’M’), C(’M’), C(’J’),<br />
/* 29 - Ctrl */ CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,<br />
/* 30 - ’a’ */ L(’a’), ’A’, A(’a’), ’a’, ’A’, C(’A’),<br />
/* 31 - ’s’ */ L(’s’), ’S’, A(’s’), ’s’, ’S’, C(’S’),<br />
/* 32 - ’d’ */ L(’d’), ’D’, A(’d’), ’d’, ’D’, C(’D’),<br />
/* 33 - ’f’ */ L(’f’), ’F’, A(’f’), ’f’, ’F’, C(’F’),<br />
/* 34 - ’g’ */ L(’g’), ’G’, A(’g’), ’g’, ’G’, C(’G’),<br />
/* 35 - ’h’ */ L(’h’), ’H’, A(’h’), ’h’, ’H’, C(’H’),<br />
/* 36 - ’j’ */ L(’j’), ’J’, A(’j’), ’j’, ’J’, C(’J’),<br />
/* 37 - ’k’ */ L(’k’), ’K’, A(’k’), ’k’, ’K’, C(’K’),<br />
/* 38 - ’l’ */ L(’l’), ’L’, A(’l’), ’l’, ’L’, C(’L’),<br />
/* 39 - ’;’ */ 0225, 0207, 0225, ’@’, ’@’, C(’@’),<br />
/* 40 - ’\’’ */ 0205, 0370, 0205, ’#’, ’#’, C(’@’),<br />
/* 41 - ’‘’ */ ’\\’, ’|’, ’\\’, ’\\’, ’|’, C(’\\’),<br />
/* 42 - l. SHIFT*/ SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT,<br />
/* 43 - ’\\’ */ 0227, ’|’, 0227, 0227, ’|’, C(’@’),<br />
/* 44 - ’z’ */ L(’z’), ’Z’, A(’z’), ’z’, ’Z’, C(’Z’),<br />
/* 45 - ’x’ */ L(’x’), ’X’, A(’x’), ’x’, ’X’, C(’X’),<br />
/* 46 - ’c’ */ L(’c’), ’C’, A(’c’), ’c’, ’C’, C(’C’),<br />
/* 47 - ’v’ */ L(’v’), ’V’, A(’v’), ’v’, ’V’, C(’V’),<br />
/* 48 - ’b’ */ L(’b’), ’B’, A(’b’), ’b’, ’B’, C(’B’),<br />
/* 49 - ’n’ */ L(’n’), ’N’, A(’n’), ’n’, ’N’, C(’N’),<br />
/* 50 - ’m’ */ L(’m’), ’M’, A(’m’), ’m’, ’M’, C(’M’),<br />
/* 51 - ’,’ */ ’,’, ’;’, A(’,’), ’,’, ’;’, C(’@’),<br />
/* 52 - ’.’ */ ’.’, ’:’, A(’.’), ’.’, ’:’, C(’@’),<br />
/* 53 - ’/’ */ ’-’, ’_’, A(’-’), ’-’, ’_’, C(’_’),<br />
/* 54 - r. SHIFT*/ SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT,<br />
/* 55 - ’*’ */ ’*’, ’*’, A(’*’), ’*’, ’*’, C(’M’),<br />
/* 56 - ALT */ ALT, ALT, ALT, ALT, ALT, ALT,<br />
/* 57 - ’ ’ */ ’ ’, ’ ’, A(’ ’), ’ ’, ’ ’, C(’@’),<br />
/* 58 - CapsLck */ CALOCK, CALOCK, CALOCK, CALOCK, CALOCK, CALOCK,<br />
/* 59 - F1 */ F1, SF1, AF1, AF1, ASF1, CF1,<br />
/* 60 - F2 */ F2, SF2, AF2, AF2, ASF2, CF2,<br />
/* 61 - F3 */ F3, SF3, AF3, AF3, ASF3, CF3,<br />
/* 62 - F4 */ F4, SF4, AF4, AF4, ASF4, CF4,<br />
/* 63 - F5 */ F5, SF5, AF5, AF5, ASF5, CF5,<br />
/* 64 - F6 */ F6, SF6, AF6, AF6, ASF6, CF6,<br />
/* 65 - F7 */ F7, SF7, AF7, AF7, ASF7, CF7,<br />
/* 66 - F8 */ F8, SF8, AF8, AF8, ASF8, CF8,<br />
/* 67 - F9 */ F9, SF9, AF9, AF9, ASF9, CF9,<br />
/* 68 - F10 */ F10, SF10, AF10, AF10, ASF10, CF10,<br />
/* 69 - NumLock */ NLOCK, NLOCK, NLOCK, NLOCK, NLOCK, NLOCK,
Minix 75<br />
/* 70 - ScrLock */ SLOCK, SLOCK, SLOCK, SLOCK, SLOCK, SLOCK,<br />
/* 71 - Home */ HOME, ’7’, AHOME, AHOME, ’7’, CHOME,<br />
/* 72 - CurUp */ UP, ’8’, AUP, AUP, ’8’, CUP,<br />
/* 73 - PgUp */ PGUP, ’9’, APGUP, APGUP, ’9’, CPGUP,<br />
/* 74 - ’-’ */ NMIN, ’-’, ANMIN, ANMIN, ’-’, CNMIN,<br />
/* 75 - Left */ LEFT, ’4’, ALEFT, ALEFT, ’4’, CLEFT,<br />
/* 76 - MID */ MID, ’5’, AMID, AMID, ’5’, CMID,<br />
/* 77 - Right */ RIGHT, ’6’, ARIGHT, ARIGHT, ’6’, CRIGHT,<br />
/* 78 - ’+’ */ PLUS, ’+’, APLUS, APLUS, ’+’, CPLUS,<br />
/* 79 - End */ END, ’1’, AEND, AEND, ’1’, CEND,<br />
/* 80 - Down */ DOWN, ’2’, ADOWN, ADOWN, ’2’, CDOWN,<br />
/* 81 - PgDown */ PGDN, ’3’, APGDN, APGDN, ’3’, CPGDN,<br />
/* 82 - Insert */ INSRT, ’0’, AINSRT, AINSRT, ’0’, CINSRT,<br />
/* 83 - Delete */ 0177, ’.’, A(0177),0177, ’.’, 0177,<br />
/* 84 - Enter */ C(’M’), C(’M’), CA(’M’),C(’M’), C(’M’), C(’J’),<br />
/* 85 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 86 - ??? */ ’’, A(’’, C(’@’),<br />
/* 87 - F11 */ F11, SF11, AF11, AF11, ASF11, CF11,<br />
/* 88 - F12 */ F12, SF12, AF12, AF12, ASF12, CF12,<br />
/* 89 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 90 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 91 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 92 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 93 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 94 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 95 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 96 - EXT_KEY */ EXTKEY, EXTKEY, EXTKEY, EXTKEY, EXTKEY, EXTKEY,<br />
/* 97 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 98 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/* 99 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*100 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*101 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*102 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*103 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*104 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*105 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*106 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*107 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*108 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*109 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*110 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*111 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*112 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*113 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*114 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*115 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*116 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*117 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*118 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*119 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*120 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*121 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*122 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*123 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*124 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*125 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*126 - ??? */ 0, 0, 0, 0, 0, 0,<br />
/*127 - ??? */ 0, 0, 0, 0, 0, 0<br />
};<br />
Dopo la modifica, si avvia la compilazione.<br />
# cd /usr/src/kernel/keymaps/ [ Invio ]
76 volume VIII Argomenti avanzati e accessori<br />
# make [ Invio ]<br />
Vengono generati tutti i file di configurazione che non siano già presenti (se si vuole ripetere la<br />
compilazione occorre prima rimuovere il file ‘italian.map’).<br />
# cp italian.map /etc/keymap [ Invio ]<br />
Al prossimo riavvio sarà utilizzata la nuova mappa.<br />
356.10 Altri programmi<br />
Il s<strong>of</strong>tware a disposizione per Minix non è molto e può essere trovato negli stessi FTP da cui<br />
si accede ai file del sistema operativo citati qui. In particolare, tra i programmi riferiti alla rete,<br />
vale la pena di ricordare i pacchetti ‘HTTPD.TAZ’ e ‘FROG.TAZ’. Il primo è un servente HTTP<br />
molto semplice e il secondo è un programma per il tracciamento dell’instradamento (simile a<br />
Traceroute). Sono entrambi molto utili e compilabili facilmente.<br />
356.10.1 HTTPD.TAZ<br />
Minix dispone di un servente HTTP elementare e lo si trova distribuito nel pacchetto<br />
‘HTTPD.TAZ’. I pacchetti supplementari, come questo, vanno installati a partire dalla directory<br />
‘/usr/local/’ e i sorgenti vanno collocati in ‘/usr/local/src/’.<br />
# cd /usr/local/src [ Invio ]<br />
Supponendo che il file ‘HTTPD.TAZ’ si trovi nel dischetto, montato nella directory ‘/mnt/’, si<br />
può agire come segue:<br />
# cat /mnt/HTTPD.TAZ | compress -d | tar xvf - [ Invio ]<br />
Si ottiene la creazione della directory ‘httpd/’ a partire dalla posizione corrente, cioè ‘/usr/<br />
local/src/’.<br />
# cd httpd [ Invio ]<br />
Si procede con la compilazione.<br />
# make [ Invio ]<br />
Quindi si installa il programma.<br />
# make install [ Invio ]<br />
L’installazione non si occupa di copiare i file di configurazione: bisogna farlo manualmente.<br />
# cp httpd.conf /etc [ Invio ]<br />
# cp httpd.mtype /etc [ Invio ]<br />
Il demone ‘httpd’, installato in ‘/usr/local/bin/’, ha bisogno di un utente ‘www’, in base<br />
alla configurazione predefinita del file ‘/etc/httpd.conf’ che non serve modificare.<br />
# adduser www operator /usr/home/www [ Invio ]<br />
Naturalmente la scelta della directory personale di questo utente fittizio è solo un fatto di gusto<br />
personale. Sempre in base alla configurazione predefinita, occorre aggiungere alla directory<br />
personale la directory ‘exec/’ e all’interno di questa si devono collocare un paio di file.
Minix 77<br />
# mkdir /usr/home/www/exec [ Invio ]<br />
# cp dir2html /usr/home/www/exec [ Invio ]<br />
# cp dir2html.sh /usr/home/www/exec [ Invio ]<br />
Per ultimo, occorre avviare il demone. Per questo conviene ritoccare il file ‘/etc/rc.net’ in<br />
modo da aggiungere la riga seguente:<br />
tcpd http /usr/local/bin/httpd &<br />
356.10.2 FROG.TAZ<br />
‘frog’ è un programma per il tracciamento dell’instradamento. È semplice, ma anche molto<br />
importante. L’estrazione dell’archivio avviene nel modo solito, così come la compilazione e<br />
l’installazione.<br />
# cd /usr/local/src [ Invio ]<br />
# cat /mnt/FROG.TAZ | compress -d | tar xvf - [ Invio ]<br />
# cd frog [ Invio ]<br />
# make [ Invio ]<br />
# make install [ Invio ]<br />
Tutto qui.<br />
356.11 Copie di sicurezza<br />
Le copie di sicurezza possono essere fatte soltanto utilizzano ‘tar’ e ‘compress’. Dal momento<br />
che il sistema è organizzato in modo piuttosto rigido, con una partizione principale molto piccola<br />
e una partizione ‘/usr/’, normalmente conviene preoccuparsi solo di questa seconda partizione.<br />
Per la prima converrebbe realizzare un dischetto di avvio e installazione con gli stessi file di<br />
configurazione, compresi ‘/etc/passwd’, ‘/etc/group’ e ‘/etc/shadow’.<br />
356.11.1 Archiviazione<br />
Se si dispone di abbastanza spazio libero nella partizione ‘/usr/’, se ne può fare la copia di<br />
sicurezza in un file collocato all’interno della stessa partizione. Successivamente si può scaricare<br />
su dischetti. Si può procedere nel modo seguente:<br />
# cd /usr [ Invio ]<br />
# tar cf - . | compress -c > .BKP.TAZ [ Invio ]<br />
Si ottiene il file ‘/usr/.BKP.TAZ’ contenente la copia di quanto contenuto nella directory corrente<br />
‘/usr/’. Successivamente si può copiare il file ottenuto, a pezzi, su una serie di dischetti<br />
formattati in precedenza. Si comincia con la formattazione e si suppone di disporre di dischetti<br />
da 1440 Kibyte.<br />
# format /dev/fd0 1440 [ Invio ]
78 volume VIII Argomenti avanzati e accessori<br />
...<br />
Una volta preparati i dischetti formattati, si può scaricare il file nei dischetti.<br />
# dd if=/usr/.BKP.TAZ <strong>of</strong>=/dev/fd0 bs=1440k count=1 skip=0 [ Invio ]<br />
# dd if=/usr/.BKP.TAZ <strong>of</strong>=/dev/fd0 bs=1440k count=1 skip=2 [ Invio ]<br />
...<br />
356.11.2 Recupero<br />
Per recuperare un sistema archiviato nel modo mostrato nella sezione precedente, si deve cominciare<br />
dall’installazione con il dischetto iniziale. La cosa migliore sarebbe l’utilizzo di un dischetto<br />
modificato opportunamente in modo che i file di configurazione corrispondano a quanto utilizzato<br />
nel proprio sistema.<br />
Dopo l’installazione iniziale che consiste nel trasferimento di quanto contenuto nel dischetto<br />
iniziale nel disco fisso, si procede con l’installazione della copia (preparata in precedenza) della<br />
partizione collocata a partire da ‘/usr/’.<br />
# setup /usr [ Invio ]<br />
Uno dopo l’altro verranno richiesti tutti i dischetti.<br />
356.12 Convivenza tra Minix e GNU/Linux<br />
Se lo si desidera, si può fare convivere Minix assieme a GNU/Linux, nello stesso disco fisso, su<br />
partizioni distinte. Ma installare Minix in una partizione libera di un disco in cui GNU/Linux è<br />
già stato installato richiede prudenza e attenzione.<br />
• L’installazione di Minix provoca l’alterazione dell’MBR del disco fisso, di conseguenza, al<br />
termine si avvia solo Minix. Quindi, prima di installare Minix occorre preparare uno o più<br />
dischi di avvio di GNU/Linux, in modo da poter in seguito ripristinare il sistema di avvio<br />
attraverso LILO.<br />
• Quando si conclude il lavoro con Minix e si esegue un riavvio con un semplice<br />
[ Ctrl+Alt+Canc ], si ottiene un avvio a caldo (warm boot), ma se dopo si vuole avviare un<br />
kernel Linux, questo non potrà essere caricato. Pertanto, è necessario un riavvio a freddo,<br />
al limite attraverso lo spegnimento e la riaccensione dell’elaboratore.<br />
356.12.1 LILO<br />
Una volta che si è riusciti a fare riavviare il sistema GNU/Linux, con i dischetti di avvio a cui si<br />
faceva riferimento in precedenza, conviene modificare il file ‘/etc/lilo.conf’ in modo che si<br />
possa scegliere tra l’avvio di GNU/Linux, Minix ed eventualmente altro.<br />
Supponendo di avere installato Minix nella seconda partizione del primo disco fisso, le righe<br />
necessarie nel file ‘/etc/lilo.conf’ sono quelle seguenti:<br />
other=/dev/hda2<br />
label=minix<br />
table=/dev/hda
Minix 79<br />
Volendo supporre che Minix sia stato installato nel secondo disco fisso, sempre nella seconda<br />
partizione, le righe sarebbero quelle seguenti:<br />
other=/dev/hdb2<br />
label=minix<br />
table=/dev/hdb<br />
loader=/boot/chain.b<br />
In pratica, è esattamente ciò che si fa quando si vuole controllare l’avvio del Dos.<br />
356.13 Riferimenti<br />
Minix è un sistema operativo molto limitato rispetto a GNU/Linux. Resta comunque l’unica<br />
opportunità, almeno per ora, di fronte a vecchi elaboratori i286 o inferiori.<br />
Molti particolari importanti non sono stati descritti, ma le informazioni relative sono comunque<br />
accessibili dai siti FTP di distribuzione di Minix e dalla documentazione interna costituita delle<br />
pagine di manuale (‘man’).<br />
• Andrew S. Tanenbaum, Alber S. Woodhull, Operating Systems: Design and Implementation,<br />
2/e, Prentice-Hall<br />
• <br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
ELKS<br />
Capitolo 357<br />
Il progetto ELKS (Embeddable linux kernel subset) vuole creare un sistema operativo per i<br />
microprocessori ix86 di fascia bassa, a partire da un sottoinsieme di funzionalità di GNU/Linux.<br />
È possibile avviare un mini sistema composto da un dischetto di avvio (boot) e un dischetto contenente<br />
un sistema minimo; con un po’ di pazienza è anche possibile installarlo in una partizione<br />
del disco fisso.<br />
È disponibile un compilatore da utilizzare con GNU/Linux, per produrre binari ELKS, cioè<br />
tutto il necessario per sviluppare questo nuovo sistema; è possibile eseguire i binari ELKS su<br />
GNU/Linux, attraverso una libreria di emulazione; è possibile avviare ELKS anche all’interno di<br />
DOSEMU.<br />
357.1 Sperimentare ELKS<br />
ELKS non è un sistema completo, quindi necessita di un pacchetto di sviluppo, composto essenzialmente<br />
da un compilatore, da utilizzare in una piattaforma GNU/Linux normale. Questo<br />
pacchetto è Dev86, distribuito normalmente in forma sorgente.<br />
Una volta scaricato il pacchetto di sviluppo, questo può essere espanso a partire dalla directory<br />
‘/usr/src/’, nell’elaboratore GNU/Linux, come mostrato dall’esempio seguente:<br />
# cd /usr/src [ Invio ]<br />
# tar xzvf Dev86src-0.13.4.tar.gz [ Invio ]<br />
Si otterrà la directory ‘/usr/src/linux-86’ che si articola ulteriormente. Terminata<br />
l’installazione occorre compilare questi sorgenti e installarli.<br />
# cd /usr/src/linux-86 [ Invio ]<br />
# make install [ Invio ]<br />
A questo punto si può pensare ai sorgenti del kernel di ELKS e dei vari programmi di sistema e<br />
di servizio. Anche questi vanno installati a partire da ‘/usr/src/’.<br />
# cd /usr/src [ Invio ]<br />
# tar xzvf elks-0.0.67.tar.gz [ Invio ]<br />
# tar xzvf elkscmd.tar.gz [ Invio ]<br />
Si ottengono le directory ‘/usr/src/elks/’ e ‘/usr/src/elkscmd/’. La prima contiene il<br />
kernel, la seconda i programmi di contorno. Per compilare il kernel basta eseguire i passi seguenti.<br />
# cd /usr/src/elks [ Invio ]<br />
# make config [ Invio ]<br />
# make dep ; make clean [ Invio ]<br />
# make [ Invio ]<br />
80
ELKS 81<br />
Si ottiene il file ‘/usr/src/elks/Image’ che può essere trasferito nel modo solito in un<br />
dischetto, attraverso ‘cp’ o ‘dd’.<br />
Per compilare gli altri programmi occorre passare le varie directory in cui si articola ‘/usr/src/<br />
elkscmd/’ e usare il comando ‘make’.<br />
357.2 Immagini di dischetti già pronti<br />
La realizzazione di un sistema ELKS è un po’ difficoltosa in questa fase iniziale del suo progetto<br />
di realizzazione. La cosa migliore è partire dalle immagini già pronte, contenute normalmente in<br />
un pacchetto unico. Per trasferirle nei dischetti ci si comporta nel modo solito, esattamente come<br />
si fa per le immagini di dischetti di GNU/Linux.<br />
Volendo, l’immagine ‘boot’ (quella di avvio) può essere sostituita semplicemente con un kernel<br />
compilato personalmente, mentre l’immagine ‘root’ può essere rielaborata aggiungendo o<br />
sostituendo altri programmi. L’immagine ‘root’ contiene un file system Minix.<br />
Per mettere in funzione il sistema ELKS è sufficiente avviare l’elaboratore con il dischetto ottenuto<br />
dall’immagine ‘boot’, sostituendolo con quello dell’immagine ‘root’, quando il kernel lo<br />
richiede.<br />
357.3 Avvio di ELKS all’interno di DOSEMU<br />
ELKS può essere avviato all’interno di DOSEMU, sia in una console che in una finestra di X.<br />
Per farlo basta avviare l’emulatore in modo che esegua il caricamento dal dischetto. Questo si<br />
ottiene di solito utilizzando l’opzione ‘-A’.<br />
# dos -A [ Invio ]<br />
La figura 357.1 mostra la fase finale dell’avvio di ELKS. Si nota in particolare l’invito della<br />
shell (il prompt), che è molto scarno: per ora non si possono usare i caratteri jolly e tutte le altre<br />
funzioni cui si è abituati con le shell normali.<br />
Figura 357.1. L’avvio di ELKS.
82 volume VIII Argomenti avanzati e accessori<br />
357.4 Riferimenti<br />
• ELKS: the embeddable Linux kernel system<br />
<br />
• Source Forge: ELKS<br />
<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Parte lxxii<br />
Dos<br />
358 Dos: introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />
358.1 Avvio del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />
358.2 Dispositivi secondo il Dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />
358.3 Directory, file ed eseguibili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />
358.4 Comandi e ambiente di avvio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .89<br />
358.5 Caratteri jolly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />
358.6 Invito dell’interprete dei comandi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />
358.7 Comandi interni principali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />
358.8 Flussi standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .97<br />
358.9 Accesso diretto ai dispositivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99<br />
358.10 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99<br />
359 Dos: dischi, file system, directory e file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
359.1 Suddivisione in partizioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
359.2 Inizializzazione di un’unità di memorizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
359.3 Etichetta di un’unità di memorizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />
359.4 Analisi e correzione del file system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />
359.5 Copia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102<br />
359.6 Trasferimento del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />
359.7 Modifica delle unità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />
359.8 Altre particolarità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />
360 Dos: configurazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />
360.1 CONFIG.SYS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />
360.2 AUTOEXEC.BAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />
360.3 Comandi ridondanti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />
360.4 Localizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113<br />
360.5 Orologio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114<br />
361 Dos: script dell’interprete dei comandi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />
361.1 Parametri, variabili ed espansione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />
361.2 Chiamate di altri script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />
361.3 Strutture di controllo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115<br />
361.4 Comandi utili negli script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118<br />
362 Dos: gestione della memoria centrale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .121<br />
83
362.1 Gestione particolare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />
362.2 Comandi appositi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />
362.3 Verifica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />
363 FreeDOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123<br />
363.1 Installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .123<br />
363.2 Impostazione e configurazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />
363.3 RxDOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />
363.4 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />
364 Progetto GNUish . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126<br />
364.1 Programmi di servizio vari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />
364.2 Gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />
364.3 Spreadsheet Calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />
364.4 Ispell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />
364.5 Perl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127<br />
364.6 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />
365 The valuable DOS Freeware page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />
365.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />
365.2 OS and GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
365.3 Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
365.4 Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />
365.5 Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132<br />
365.6 Typesetting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132<br />
365.7 More Dos s<strong>of</strong>tware sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />
365.8 Search engines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />
366 Clean the Clipper 5.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134<br />
366.1 Step 1: try to compile with the /P parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135<br />
366.2 Step 2: understand well the use <strong>of</strong> code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136<br />
366.3 Step 3: understand the object programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />
366.4 Step 4: understand the get object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />
366.5 Step 5: trying to stop using commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />
366.6 Step 6: free yourself from STD.CH - /U . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153<br />
366.7 Step 7: take control over all include files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153<br />
367 nanoBase 1997 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />
367.1 What is it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />
367.2 The dot command line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />
367.3 The menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161<br />
367.4 The macro recording, compiling and execution . . . . . . . . . . . . . . . . . . . . . . . . . . . .161<br />
84
367.5 The report system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />
367.6 The integrated text editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163<br />
367.7 The internal documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />
367.8 Download it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />
367.9 Bugs and known problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165<br />
368 nanoBase 1997 user manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />
368.1 Dos xBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />
368.2 Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171<br />
368.3 How to use nB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173<br />
368.4 Status line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />
368.5 The dot line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175<br />
368.6 The menu system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175<br />
368.7 The text editor DOC() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />
368.8 The help text file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />
368.9 Macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />
368.10 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192<br />
368.11 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200<br />
368.12 Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />
368.13 Code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />
368.14 Standard functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />
368.15 nB functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261<br />
368.16 Normal command substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299<br />
368.17 nB command substitution functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305<br />
368.18 RPT: the nB print function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310<br />
368.19 How can I... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313<br />
368.20 The source files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314<br />
85
Dos: introduzione<br />
Capitolo 358<br />
DOS è acronimo di Disk Operating System e sta a indicare il nome di un sistema operativo per<br />
micro elaboratori basati su microprocessori i86, successore del vecchio CP/M. Probabilmente,<br />
data la sua estrema limitatezza, è un po’ azzardato voler parlare di «sistema operativo», tanto che<br />
qualcuno lo appella: «gestore di interruzioni» (interrupt).<br />
Questo sistema operativo nasce come s<strong>of</strong>tware proprietario; tuttavia, attualmente il progetto più<br />
attivo attorno a questo tipo di sistema è FreeDOS, il cui scopo è quello di realizzarne un’edizione<br />
libera e completa.<br />
358.1 Avvio del sistema<br />
Un sistema Dos è composto essenzialmente da un kernel, un interprete dei comandi e da una<br />
serie di programmi di servizio. Questo concetto è analogo ai sistemi Unix, con la differenza che<br />
il kernel <strong>of</strong>fre funzionalità molto scarse e solo per mezzo di interruzioni s<strong>of</strong>tware (IRQ).<br />
Nelle versioni proprietarie del Dos, il kernel era suddiviso in due file, che raccoglievano funzionalità<br />
distinte in base all’importanza relativa. I nomi usati sono stati differenti e nel caso di<br />
FreeDOS il kernel è contenuto tutto in un solo file (tabella 358.1).<br />
Tabella 358.1. Comparazione tra i nomi dei file che compongono il kernel di un<br />
sistema Dos.<br />
Micros<strong>of</strong>t IBM Novell, Caldera RxDOS FreeDOS<br />
IO.SYS<br />
MSDOS.SYS<br />
IBMBIO.COM<br />
IBMDOS.COM<br />
IBMBIO.COM<br />
IBMDOS.COM<br />
RXDO-<br />
SBIO.SYS<br />
RXDOS.SYS<br />
KERNEL.SYS<br />
--<br />
I file del kernel devono trovarsi nella directory radice della partizione o del dischetto per poter<br />
essere avviati. Per la precisione, l’avvio del kernel viene gestito direttamente dal codice inserito<br />
nel settore di avvio della partizione o del dischetto (512 Kibyte), che a sua volta viene avviato<br />
dal firmware (il BIOS, secondo la terminologia specifica dell’architettura i86 e successiva).<br />
Il kernel, dopo essere stato avviato, non attiva una procedura di avvio, ma si limita a interpretare<br />
uno script speciale, ‘CONFIG.SYS’, e subito dopo avvia l’interprete dei comandi, ovvero<br />
la shell. Tradizionalmente, il programma in questione è ‘COMMAND.COM’. Secondo la tradizione,<br />
l’interprete dei comandi che viene avviato dal kernel si occupa subito di eseguire lo script<br />
‘AUTOEXEC.BAT’. Gli script ‘CONFIG.SYS’ e ‘AUTOEXEC.BAT’ devono trovarsi nella directory<br />
radice del disco o della partizione da cui si avvia il sistema, ovvero quella in cui si trova già il<br />
kernel che viene avviato.<br />
L’interprete dei comandi, ‘COMMAND.COM’, è in grado di eseguire direttamente alcune funzionalità,<br />
attraverso comandi interni che non si traducono in programmi di servizio veri e propri.<br />
Tradizionalmente ‘COMMAND.COM’ si colloca nella directory radice del disco o della partizione<br />
in cui si trova il kernel stesso. Ciò non è propriamente indispensabile, ma conviene attenersi a<br />
questa linea per evitare fastidi inutili.<br />
86
Dos: introduzione 87<br />
358.2 Dispositivi secondo il Dos<br />
I dispositivi secondo il Dos hanno un nome, composto da lettere e cifre numeriche, terminato da<br />
due punti opzionali:<br />
nome_dispositivo[:]<br />
Il nome in questione può essere indicato utilizzando lettere maiuscole o minuscole, senza che la<br />
cosa faccia differenza. I nomi più comuni sono elencati nella tabella 358.2. È il caso di osservare<br />
che i due punti che concludono il nome, vanno usati necessariamente quando questo viene<br />
abbinato ad altre informazioni da cui non potrebbe essere distinto (per esempio un percorso).<br />
Tabella 358.2. Nomi dei dispositivi più comuni in Dos.<br />
Dispositivo Descrizione<br />
‘A:’ Disco nella prima unità a dischetti.<br />
‘B:’ Disco nella seconda unità a dischetti.<br />
‘C:’ Prima partizione Dos nel primo disco fisso.<br />
‘D:’, ‘E:’,... ‘Z:’ Partizione Dos o altro tipo di disco.<br />
‘CON:’ Console: tastiera e schermo.<br />
‘PRN:’ Porta stampante principale.<br />
‘LPT1:’, ‘LPT2:’,... Porte parallele.<br />
‘COM1:’, ‘COM2:’,... Porte seriali.<br />
Il Dos mantiene distinti i dischi e le partizioni, nel senso che questi non devono creare una<br />
struttura unica come avviene nei sistemi Unix. Pertanto, quando si fa riferimento a un percorso<br />
di un file o di una directory, si deve tenere in considerazione anche il disco o la partizione in cui<br />
si trova.<br />
Il modo utilizzato dal Dos per identificare i dischi e le partizioni, di fatto impedisce di accedere a<br />
questi dispositivi in modo indipendente dal file system sottostante. Per intenderci, l’«unità» ‘X:’<br />
può essere una partizione Dos di un disco non meglio identificato; mentre non esiste un modo<br />
univoco per poter raggiungere il dispositivo fisico in cui si trova questo disco.<br />
358.3 Directory, file ed eseguibili<br />
Il Dos è nato dopo Unix e da questo sistema ha ereditato alcuni concetti elementari (forse troppo<br />
pochi). I percorsi di file e directory si separano con una barra obliqua, che però è inversa rispetto<br />
allo Unix. Anche con il Dos c’è una directory radice; tuttavia si aggiunge l’indicazione dell’unità<br />
di memorizzazione (il disco o la partizione). Si può osservare a questo proposito la figura 358.1.<br />
Figura 358.1. Struttura di un percorso in un file system Dos.<br />
C:\PRIMO\SECONDO\TERZO\QUARTO<br />
^ ^ ^ ^ ^<br />
| | | | |<br />
| | | | file o directory finale<br />
| | | |<br />
| | | directory<br />
| | |<br />
| | separazione tra una directory e la successiva<br />
| |<br />
| directory radice<br />
|<br />
unità di memorizzazione
88 volume VIII Argomenti avanzati e accessori<br />
I nomi di file e directory possono essere indicati utilizzando lettere maiuscole o minuscole, senza<br />
che la cosa possa fare differenza. Questi nomi possono essere composti utilizzando anche cifre<br />
numeriche e altri simboli (che comunque è bene usare con parsimonia).<br />
Per la precisione, sono esclusi i simboli: ‘/’, ‘\’, ‘[’, ‘]’, ‘’, ‘+’, ‘=’, ‘;’, ‘:’, ‘,’, ‘?’, ‘*’,<br />
‘{’, ‘}’ e il punto che va usato esattamente come descritto nel seguito.<br />
Tradizionalmente, il Dos utilizza un tipo di file system elementare, denominato FAT (Dos-FAT),<br />
in cui i nomi dei file e delle directory possono essere composti utilizzando al massimo 11 caratteri,<br />
di cui otto compongono un prefisso e tre un suffisso. Il prefisso e il suffisso di questi nomi<br />
appaiono uniti attraverso un punto. Per esempio: ‘CIAO.COM’, ‘LETTERA.TXT’, ‘PIPPO.NB’,...<br />
Questa conformazione dei nomi è una caratteristica fondamentale del Dos, da cui derivano una<br />
serie di consuetudini e di limitazioni molto importanti.<br />
È importante osservare che non è opportuno che i nomi dei file coincidano con quelli dei dispositivi<br />
(senza i due punti finali). In pratica, non conviene creare file del tipo ‘CON:’, ‘PRN:’,<br />
ecc. Tutto dipende dal contesto, ma in generale è bene fare attenzione a questo particolare.<br />
Come nei sistemi Unix il Dos annovera il concetto di directory corrente, a cui si aggiunge il<br />
concetto di unità di memorizzazione corrente. Infatti, la directory va collocata in un disco o<br />
in una partizione. In base a questo principio, si possono indicare dei percorsi relativi, che fanno<br />
riferimento alla posizione corrente (nell’unità di memorizzazione corrente). Tuttavia, in più,<br />
ogni unità di memorizzazione ha una sua directory corrente. Per esempio, fare riferimento a un<br />
file in una certa unità di memorizzazione ‘x:’, senza specificare il percorso, significa indicare<br />
implicitamente la directory corrente di quella unità.<br />
Per esempio, supponendo che la directory corrente dell’unità ‘X:’ sia ‘X:\PRIMO\SECONDO\’,<br />
facendo riferimento al file ‘X:CIAO’, si intende indicare implicitamente il file ‘X:\PRIMO\<br />
SECONDO\CIAO’.<br />
In un percorso si possono usare anche i simboli ‘.’ e ‘..’, con lo stesso significato che hanno in<br />
un sistema Unix: la directory stessa e la directory genitrice.<br />
Il file system tradizionale del Dos consente di annotare solo poche informazioni per i file e le<br />
directory: la data di modifica e quattro indicatori booleani, rappresentati da altrettante lettere:<br />
• H file o directory nascosti;<br />
• S file o directory di sistema;<br />
• R file o directory in sola lettura e non cancellabile;<br />
• A file o directory da archiviare (i dati sono stati modificati).<br />
Si tratta di attributi completamente differenti da quelli di Unix. Si può osservare in particolare la<br />
mancanza di un attributo che specifichi la possibilità di eseguire un programma o di attraversare<br />
una directory. Secondo la tradizione Dos, gli attributi vanno considerati nel modo seguente:<br />
• A viene attivato ogni volta che il file viene scritto o modificato e serve per automatizzare<br />
i sistemi di copia periodica;<br />
• R se attivo, il Dos non consente la scrittura o la rimozione;
Dos: introduzione 89<br />
• S se attivo si tratta di un file di «sistema», ma in pratica si comporta come l’attributo H;<br />
• H se attivo si tratta di un file «nascosto», che così non dovrebbe apparire nelle liste di file<br />
e directory.<br />
In generale, file e directory nascosti o di sistema non dovrebbero essere spostati fisicamente,<br />
nemmeno nell’ambito della stessa unità di memorizzazione. Questa esigenza nasce in particolare<br />
per i file del kernel, che non possono essere spostati se si vuole poter riavviare il sistema<br />
operativo.<br />
Dal momento che il file system non permette di determinare se un file è un eseguibile, l’unico<br />
modo per permettere al sistema di conoscere questa caratteristica sta nell’uso di suffissi convenzionali<br />
nei nomi: i file che terminano con l’estensione ‘.COM’ e ‘.EXE’ sono programmi binari<br />
(la differenza tra i due tipi di estensione riguarda il formato del binario); quelli che terminano per<br />
‘.BAT’ sono script dell’interprete dei comandi (‘COMMAND.COM’).<br />
La prima stranezza che deriva da questa caratteristica del Dos sta nel fatto che per avviare un<br />
eseguibile di questi, è sufficiente indicare il nome del file senza l’estensione, che diventa così<br />
un componente opzionale agli occhi dell’utilizzatore.<br />
358.4 Comandi e ambiente di avvio<br />
L’interprete dei comandi tradizionale dei sistemi Dos è il programma ‘COMMAND.COM’, che viene<br />
avviato direttamente dal kernel. ‘COMMAND.COM’ può essere avviato più volte successive, anche<br />
se di solito ciò è di scarsa utilità, dal momento che il Dos non è un sistema operativo in multiprogrammazione.<br />
In ogni caso, quando viene avviato dal kernel, si occupa di interpretare ed eseguire<br />
lo script ‘AUTOEXEC.BAT’ che si trova nella directory radice dell’unità di avvio.<br />
‘COMMAND.COM’ mostra un invito simile idealmente a quello delle shell Unix, dopo il quale possono<br />
essere inseriti i comandi. A loro volta, questi possono essere riferiti a comandi interni<br />
corrispondenti a funzionalità <strong>of</strong>ferte direttamente dall’interprete, oppure possono rappresentare<br />
la richiesta di avvio di un programma esterno.<br />
Figura 358.2. Riga di comando.<br />
C:\>DIR A: /W<br />
^ ^ ^ ^<br />
| | | |<br />
| | | opzione<br />
| | |<br />
| | argomento<br />
| |<br />
| comando<br />
|<br />
invito<br />
Il Dos ha ereditato da Unix anche il concetto di variabile di ambiente. Il meccanismo è lo stesso<br />
ed è fondamentale la variabile di ambiente ‘PATH’, con la quale si possono indicare i percorsi di<br />
ricerca degli eseguibili. Tuttavia, il Dos ha delle caratteristiche speciali, per cui, è il caso di fare<br />
alcuni esempi di comandi:<br />
• C:\>C:\PRIMO\SECONDO.EXE<br />
questo comando avvia l’esecuzione del file ‘C:\PRIMO\SECONDO.EXE’;
90 volume VIII Argomenti avanzati e accessori<br />
• C:\>C:\PRIMO\SECONDO<br />
questo comando potrebbe avviare l’esecuzione del primo dei file seguenti che riesce a<br />
trovare;<br />
– ‘C:\PRIMO\SECONDO.COM’<br />
– ‘C:\PRIMO\SECONDO.EXE’<br />
– ‘C:\PRIMO\SECONDO.BAT’<br />
• C:\>SECONDO<br />
questo comando potrebbe avviare l’esecuzione del primo dei file seguenti che dovesse riuscire<br />
a trovare, ma in mancanza può continuare la ricerca nei percorsi indicati nella variabile<br />
di ambiente ‘PATH’.<br />
– ‘C:.\SECONDO.COM’<br />
– ‘C:.\SECONDO.EXE’<br />
– ‘C:.\SECONDO.BAT’<br />
I percorsi indicati nella variabile di ambiente ‘PATH’ sono separati da un punto e virgola; per<br />
esempio:<br />
C:\;C:\DOS;C:\FDOS\BIN<br />
Di solito, il Dos dà per scontato che si cerchino gli eseguibili a cominciare dalla directory corrente.<br />
Per questo, occorre considerare che è sempre come se la variabile di ambiente ‘PATH’<br />
contenesse questa indicazione prima delle altre: ‘.;C:\;C:\DOS;C:\FDOS\BIN’. È da osservare<br />
che FreeDOS si comporta in maniera differente, in quanto richiede espressamente<br />
questa indicazione della directory corrente.<br />
358.5 Caratteri jolly<br />
Il Dos imita l’utilizzo dei caratteri jolly come avviene nei sistemi Unix per opera delle shell.<br />
Tuttavia, nel Dos non si tratta di un’espansione che avviene per opera della shell, ma vi deve<br />
provvedere ogni programma per conto proprio. Questo rappresenta una gravissima deficienza del<br />
Dos, che però è irrimediabile.<br />
Su questa base, i comandi tendono a richiedere l’indicazione di un argomento che rappresenta il<br />
nome di uno o più file prima delle opzioni eventuali.<br />
Ma c’è un altro problema. Il punto che divide in due i nomi dei file e delle directory è un muro<br />
insuperabile per i caratteri jolly.<br />
I simboli che si possono utilizzare sono solo l’asterisco e il punto interrogativo. L’asterisco vale<br />
per una sequenza qualunque di caratteri, escluso il punto; il punto interrogativo vale per un<br />
carattere qualunque. 1<br />
1 Ci sono programmi di origine Unix, portati in Dos, che non hanno questa limitazione riferita al punto che separa<br />
l’estensione.
Dos: introduzione 91<br />
Modello<br />
Tabella 358.3. Alcuni esempi.<br />
Corrispondenza<br />
*.* Corrisponde a un nome qualunque.<br />
*.COM Un nome che termina con l’estensione ‘.COM’.<br />
CIAO.X?X<br />
Tutti i nomi che iniziano per ‘CIAO’ e hanno un’estensione composta da un lettera<br />
«X» iniziale e finale, senza specificare cosa ci sia al secondo posto.<br />
* Tutti i nomi che non hanno estensione (che non contengono il punto).<br />
358.6 Invito dell’interprete dei comandi<br />
Esiste un’altra variabile di ambiente fondamentale per il Dos. Si tratta di ‘PROMPT’, che consente<br />
di modificare l’aspetto dell’invito dell’interprete dei comandi. La cosa funziona un po’ come nelle<br />
shell Unix, per cui si assegna una stringa che può contenere dei simboli speciali, praticamente<br />
delle sequenze di escape che vengono espanse prima della visualizzazione. La tabella 358.4 riepiloga<br />
questi simboli particolari. In origine, il Dos mostrava in modo predefinito un invito simile<br />
all’esempio seguente, in cui appare solo l’unità di memorizzazione corrente:<br />
C:><br />
Questo tipo di impostazione corrisponderebbe alla stringa ‘$N$G’. In seguito, si è passati a<br />
un invito simile al prossimo esempio, in cui si aggiunge anche l’informazione della directory<br />
corrente:<br />
C:\BIN\><br />
Questo corrisponde alla stringa ‘$P$G’.<br />
Tabella 358.4. Sequenze di escape per definire dei componenti speciali all’interno di<br />
una stringa di invito.<br />
Simbolo<br />
Corrispondenza<br />
$Q =<br />
$$ $<br />
$T Ora corrente.<br />
$D Data corrente.<br />
$V Numero della versione.<br />
$N Lettera dell’unità corrente.<br />
$G ><br />
$L <<br />
$B |<br />
$H (cancella il carattere precedente)<br />
$E (1B16)<br />
$_ Codice di interruzione di riga.<br />
Cancellando il contenuto della variabile di ambiente ‘PROMPT’ si ripristina la stringa di invito<br />
predefinita.
92 volume VIII Argomenti avanzati e accessori<br />
358.7 Comandi interni principali<br />
I comandi interni sono quelli che non corrispondono a programmi di servizio veri e propri,<br />
ma sono funzionalità svolte direttamente dall’interprete dei comandi. Nelle sezioni seguenti ne<br />
vengono descritti brevemente alcuni.<br />
358.7.1 CH, CHDIR<br />
CH [percorso]<br />
CHDIR [percorso]<br />
‘CH’, o ‘CHDIR’, è un comando interno dell’interprete dei comandi, che consente di visualizzare<br />
o di cambiare la directory corrente. È indifferente l’uso di ‘CD’ o di ‘CHDIR’; se il comando non<br />
è seguito dal percorso, si ottiene solo la visualizzazione della directory corrente. Si osservi che<br />
se si indica un percorso assoluto di unità di memorizzazione, se questa non corrisponde a quella<br />
attuale, si cambia la directory corrente di quella unità.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>CD<br />
Visualizza la directory corrente.<br />
• C:\>CD \TMP\LAVORO<br />
Sposta la directory corrente in ‘\TMP\LAVORO\’.<br />
• C:\TMP\LAVORO>CD DATI\LETTERE<br />
Sposta la directory corrente in ‘DATI\LETTERE\’ che a sua volta discende dalla posizione<br />
iniziale precedente.<br />
• C:\TMP\LAVORO\DATI\LETTERE>CD ..<br />
Sposta la directory corrente nella posizione della directory genitrice di quella iniziale.<br />
• C:\TMP\LAVORO\DATI>CD F:\TMP<br />
Cambia la directory corrente dell’unità ‘F:’, senza intervenire nell’unità corrente.<br />
358.7.2 X:<br />
{A|B| ...|Z}:<br />
Il Dos gestisce le unità di memorizzazione in modo speciale. Per cambiare l’unità di memorizzazione<br />
corrente, non esiste un comando analogo a ‘CD’: si deve indicare il nome dell’unità a cui si<br />
vuole accedere.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>A:<br />
Cambia l’unità di memorizzazione attuale, facendola diventare ‘A:’.
Dos: introduzione 93<br />
• A:\>F:<br />
Cambia l’unità di memorizzazione attuale, facendola diventare ‘F:’.<br />
358.7.3 MD, MKDIR<br />
MD directory<br />
MKDIR directory<br />
‘MD’, o ‘MKDIR’, è un comando interno dell’interprete dei comandi, che consente di creare una<br />
directory vuota.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>MD LAVORO<br />
Crea la directory ‘LAVORO\’ a partire da quella corrente.<br />
• C:\>MD \TMP\DATA<br />
Crea la directory ‘\TMP\DATA\’ nell’unità corrente.<br />
• C:\>MD F:\TMP\DATA<br />
Crea la directory ‘\TMP\DATA\’ nell’unità ‘F:’.<br />
358.7.4 RD, RMDIR<br />
RM directory<br />
RMDIR directory<br />
‘RD’, o ‘RMDIR’, è un comando interno dell’interprete dei comandi, che consente di cancellare<br />
una directory vuota.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>RD LAVORO<br />
Cancella la directory ‘LAVORO\’ a partire da quella corrente.<br />
• C:\>RD \TMP\DATA<br />
Cancella la directory ‘\TMP\DATA\’ nell’unità corrente.<br />
• C:\>RD F:\TMP\DATA<br />
Cancella la directory ‘\TMP\DATA\’ nell’unità ‘F:’.
94 volume VIII Argomenti avanzati e accessori<br />
358.7.5 DIR<br />
DIR [directory|file] [/P] [/W]<br />
‘DIR’ è un comando interno dell’interprete dei comandi, che consente di visualizzare l’elenco del<br />
contenuto di una directory o l’elenco di un gruppo di file. L’argomento del comando può essere<br />
composto utilizzando caratteri jolly, secondo lo standard del Dos, ovvero i simboli ‘*’ e ‘?’.<br />
Tabella 358.5. Alcune opzioni.<br />
Opzione Descrizione<br />
Blocca lo scorrimento dell’elenco in attesa della pressione di<br />
/P<br />
un tasto quando questo è più lungo del numero di righe che<br />
possono apparire sullo schermo.<br />
Visualizza solo i nomi dei file e delle directory, senza altre<br />
/W<br />
informazioni, permettendo così di vedere più nomi assieme in<br />
un’unica schermata.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>DIR *.*<br />
Visualizza l’elenco di tutti i file contenuti nella directory corrente.<br />
• C:\>DIR ESEMPIO.*<br />
Visualizza l’elenco di tutti i file il cui nome inizia per ‘ESEMPIO’ e continua con<br />
un’estensione qualunque.<br />
• C:\>DIR *.DOC<br />
Visualizza l’elenco di tutti i file il cui nome termina con l’estensione ‘.DOC’.<br />
• C:\>DIR F:\DOC\*.*<br />
Visualizza l’elenco di tutti i file contenuti nella directory ‘\DOC\’ dell’unità ‘F:’.<br />
• C:\>DIR F:<br />
Visualizza l’elenco di tutti i file contenuti nella directory corrente dell’unità ‘F:’.<br />
358.7.6 COPY<br />
COPY file_origine [file_destinazione] [opzioni]<br />
COPY file_1 + file_2 [+ ...] [file_destinazione] [opzioni]<br />
‘COPY’ è un comando interno dell’interprete dei comandi, che consente di copiare uno o più file<br />
(sono escluse le directory). Anche qui è consentito l’uso di caratteri jolly, ma al contrario dei<br />
sistemi Unix, i caratteri jolly possono essere usati anche nella destinazione. Il ‘COPY’ del Dos<br />
consente anche di unire assieme più file.
Dos: introduzione 95<br />
Tabella 358.6. Alcune opzioni.<br />
Opzione Descrizione<br />
/V Fa in modo che venga verificato il risultato della copia.<br />
a sì che la copia avvenga in modo «binario». Questa opzione<br />
può servire quando si copia un file su un dispositivo e si<br />
/B<br />
vuole evitare che alcuni codici vengano interpretati in modo<br />
speciale.<br />
Non chiede conferma prima di sovrascrivere i file, se questi<br />
/Y<br />
esistono già nella destinazione.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>COPY ESEMPIO PROVA<br />
Copia il file ‘ESEMPIO’ nella directory corrente ottenendo il file ‘PROVA’, sempre nella<br />
directory corrente.<br />
• C:\>COPY C:\DOS\*.* C:\TMP<br />
Copia tutto il contenuto della directory ‘\DOS\’ dell’unità ‘C:’ nella directory ‘\TMP\’<br />
nella stessa unità ‘C:’, mantenendo gli stessi nomi.<br />
• C:\>COPY TESTA+CORPO+CODA LETTERA<br />
Copia, unendoli, i file ‘TESTA’, ‘CORPO’ e ‘CODA’, ottenendo il file ‘LETTERA’.<br />
• C:\>COPY *.DOC *.TXT<br />
Copia tutti i file che nella directory corrente hanno un nome che termina con l’estensione<br />
‘.DOC’, generando altrettanti file, con lo stesso prefisso, ma con l’estensione ‘.TXT’.<br />
• C:\>COPY PROVA.PRN PRN: /B<br />
Copia il file ‘PROVA.PRN’ nel dispositivo ‘PRN:’, ovvero sulla stampante, assicurandosi<br />
che la copia avvenga senza alterare alcunché.<br />
358.7.7 DEL, ERASE<br />
DEL file<br />
ERASE file<br />
‘DEL’, o ‘ERASE’, è un comando interno dell’interprete dei comandi, che consente di cancellare<br />
uno o più file (sono escluse le directory). È da considerare che i file che hanno l’attributo di sola<br />
lettura attivo, non possono essere modificati e nemmeno cancellati.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\TMP>DEL *.*<br />
Cancella tutti i file nella directory corrente.<br />
• C:\TMP>DEL ESEMPIO.*<br />
Cancella tutti i file contenuti nella directory corrente, il cui nome inizia per ‘ESEMPIO’ e<br />
termina con qualunque estensione.
96 volume VIII Argomenti avanzati e accessori<br />
• C:\TMP>DEL *.BAK<br />
Cancella tutti i file contenuti nella directory corrente, il cui nome termina con l’estensione<br />
‘.BAK’.<br />
358.7.8 REN, RENAME<br />
REN file_origine nome_nuovo<br />
RENAME file_origine nome_nuovo<br />
‘REN’, o ‘RENAME’, è un comando interno dell’interprete dei comandi, che consente di cambiare<br />
il nome di uno o più file (sono escluse le directory). Il primo argomento può essere un percorso<br />
relativo o assoluto, completo anche dell’indicazione dell’unità, mentre il secondo argomento è il<br />
nuovo nome, che implicitamente non può essere collocato altrove.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>REN ESEMPIO PROVA<br />
Cambia il nome del file ‘ESEMPIO’, che si trova nella directory corrente, in ‘PROVA’.<br />
• C:\>REN *.TXT *.DOC<br />
Cambia il nome di tutti i file che, nella directory corrente, hanno l’estensione ‘.TXT’,<br />
trasformandoli in modo tale da avere un’estensione ‘.DOC’.<br />
358.7.9 SET<br />
SET [variabile_di_ambiente=stringa]<br />
‘SET’ è un comando interno dell’interprete dei comandi che ha lo scopo di assegnare un valore<br />
a una variabile di ambiente, oppure di leggere lo stato di tutte le variabili di ambiente esistenti.<br />
Quando si assegna un valore a una variabile, questa viene creata simultaneamente; quando non<br />
si assegna nulla a una variabile, la si elimina.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>SET<br />
Elenca le variabili di ambiente esistenti assieme al loro valore.<br />
• C:\>SET PROMPT=$P$G$G<br />
Assegna alla variabile di ambiente ‘PROMPT’ la stringa ‘$P$G$G’. Questo si traduce nella<br />
modifica dell’aspetto dell’invito dell’interprete dei comandi.<br />
• C:\>SET PATH=.;C:\BIN;D:\BIN<br />
Assegna alla variabile di ambiente ‘PATH’ la stringa ‘.;C:\BIN;D:\BIN’.<br />
• C:\>SET PROMPT=<br />
Elimina la variabile di ambiente ‘PROMPT’, assegnandole la stringa nulla.
Dos: introduzione 97<br />
358.7.10 TYPE<br />
TYPE file<br />
‘TYPE’ è un comando interno dell’interprete dei comandi, che consente di leggere ed emettere<br />
il contenuto di un file attraverso lo standard output. Questo si traduce in pratica nella<br />
visualizzazione del file in questione.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>TYPE LETTERA<br />
Emette il contenuto del file ‘LETTERA’ che si trova nella directory e nell’unità corrente.<br />
• C:\>TYPE C:\DOC\MANUALE<br />
Emette il contenuto del file ‘MANUALE’ che si trova nella directory ‘\DOC\’ dell’unità ‘C:’.<br />
358.8 Flussi standard<br />
Il Dos ha ereditato da Unix anche i concetti legati ai flussi standard. In pratica, i programmi<br />
hanno a disposizione tre flussi predefiniti: uno in lettura rappresentato dallo standard input, due<br />
in scrittura rappresentati dallo standard output e dallo standard error. Il meccanismo è lo stesso di<br />
Unix, anche se non funziona altrettanto bene; infatti, non è possibile ridirigere lo standard error<br />
attraverso l’interprete dei comandi.<br />
Secondo la tradizione delle shell Unix, la ridirezione dello standard output si ottiene con il simbolo<br />
‘>’ posto alla fine del comando interessato, seguito poi dal nome del file che si vuole generare<br />
in questo modo. Per esempio,<br />
C:\>TYPE LETTERA > PRN:<br />
invece di visualizzare il contenuto del file ‘LETTERA’, lo invia al dispositivo di stampa<br />
corrispondente al nome ‘PRN:’; inoltre,<br />
C:\>DIR *.* > ELENCO<br />
invece di visualizzare l’elenco dei file che si trovano nella directory corrente, crea il file ‘ELENCO’<br />
con questi dati.<br />
La ridirezione dello standard output fatta in questo modo, va a cancellare completamente il contenuto<br />
del file di destinazione, se questo esiste già; al contrario, si può utilizzare anche ‘>>’, con<br />
il quale, il file di destinazione viene creato se non esiste, oppure viene solo esteso.<br />
Lo standard input viene ridiretto utilizzando il simbolo ‘SORT < ELENCO > ORDINATO<br />
In questo modo, ‘SORT’ riceve dallo standard input il file ‘ELENCO’ e genera attraverso la<br />
ridirezione dello standard output il file ‘ORDINATO’.
98 volume VIII Argomenti avanzati e accessori<br />
Per mettere in contatto lo standard output di un comando con lo standard input del successivo, si<br />
utilizza il simbolo ‘|’. L’esempio seguente mostra un modo alternativo di ottenere l’ordinamento<br />
di un file:<br />
C:\>TYPE ELENCO | SORT > ORDINATO<br />
In generale, tutti i comandi che generano un risultato visuale che scorre sullo schermo, utilizzano<br />
semplicemente lo standard output, che può essere ridiretto in questo modo. Si osservi ancora<br />
l’esempio seguente che riordina il risultato del comando ‘DIR’, mostrandolo comunque sullo<br />
schermo:<br />
C:\>DIR *.DOC | SORT<br />
Nelle sezioni seguenti vengono mostrati alcuni comandi filtro.<br />
358.8.1 SORT<br />
SORT [opzioni] < file_da_ordinare > file_ordinato<br />
Il comando ‘SORT’, che dovrebbe corrispondere a un programma di servizio vero e proprio, riordina<br />
il file di testo che ottiene dallo standard input, generando un risultato che emette attraverso<br />
lo standard output.<br />
Tabella 358.7. Alcune opzioni.<br />
Opzione Descrizione<br />
/R Riordina in modo decrescente<br />
Riordina in base al testo che inizia a partire dalla colonna in-<br />
/+n_colonna<br />
dicata come argomento (si tratta di un numero a partire da<br />
uno, per indicare la prima colonna).<br />
L’esempio seguente emette l’elenco della directory corrente riordinato in base all’estensione, che<br />
è un’informazione collocata a partire dalla decima colonna:<br />
C:\>DIR *.DOC | SORT /+10<br />
358.8.2 MORE<br />
MORE < file_da_leggere<br />
MORE file_da_leggere<br />
Il comando ‘MORE’ legge un file, fornito come argomento o attraverso lo standard input, mostrandolo<br />
poi sullo schermo una pagina dopo l’altra. In questo modo, è possibile leggere il contenuto<br />
dei file più lunghi delle righe a disposizione sullo schermo.<br />
Per passare alla pagina successiva, basta premere un tasto qualunque, oppure ciò che viene<br />
indicato espressamente.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>DIR | MORE<br />
Permette di controllare lo scorrimento a video del risultato del comando ‘DIR’.
Dos: introduzione 99<br />
• C:\>MORE LETTERA.TXT<br />
Permette di controllare lo scorrimento a video del contenuto del file ‘LETTERA.TXT’.<br />
• C:\>TYPE LETTERA.TXT | MORE<br />
Si ottiene lo stesso risultato dell’esempio precedente, attraverso l’uso di una pipeline.<br />
358.9 Accesso diretto ai dispositivi<br />
Il Dos <strong>of</strong>fre poche occasioni per accedere direttamente ai dispositivi. Si tratta generalmente solo<br />
della console e della porta parallela. L’esempio seguente mostra come «copiare» un file sul<br />
dispositivo di stampa, per ottenere così la sua stampa diretta:<br />
C:\>COPY LETTERA PRN:<br />
La stessa cosa avrebbe potuto essere ottenuta con la ridirezione dei flussi standard:<br />
C:\>TYPE LETTERA > PRN:<br />
Può essere interessante la possibilità di copiare il flusso di ingresso della console in un file:<br />
C:\>COPY CON: LETTERA<br />
In questo caso, l’inserimento nel file ‘LETTERA’ prosegue fino a quando viene ricevuto un codice<br />
EOF, che si ottiene qui con la combinazione di tasti [ Ctrl+z ] seguita da [ Invio ].<br />
È bene ricordare che la console, ovvero il dispositivo ‘CON:’, riceve dati in ingresso attraverso la<br />
tastiera ed emette dati in uscita utilizzando lo schermo. In pratica, quando un programma attende<br />
dati dallo standard input non ridiretto, li riceve dalla console, cioè dalla tastiera; nello stesso<br />
modo, quando un programma emette dati attraverso lo standard output non ridiretto, li invia alla<br />
console, cioè sullo schermo.<br />
358.10 Riferimenti<br />
• FreeDOS<br />
<br />
• OpenDOS Un<strong>of</strong>ficial Home Page<br />
<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Dos: dischi, file system, directory e file<br />
Capitolo 359<br />
La gestione dei dischi, ovvero delle unità di memorizzazione di massa, è molto particolare nel<br />
Dos. In generale, si fa riferimento a queste cose attraverso un lettera che ne rappresenta il dispositivo;<br />
tuttavia, tale dispositivo può indicare un disco intero o solo una partizione, riferendosi<br />
sempre solo a dischi e partizioni Dos.<br />
359.1 Suddivisione in partizioni<br />
Nel Dos, tutti i dischi rimovibili, come i dischetti, non vanno suddivisi in partizioni, mentre i<br />
dischi fissi devono essere preparati in questo modo. Il programma che si usa per queste cose è<br />
‘FDISK’.<br />
Secondo il Dos, le partizioni di un disco possono essere solo quattro. Tuttavia, una partizione<br />
normale può essere suddivisa in sottopartizioni, che vengono definite tradizionalmente «estese»,<br />
dove anche queste possono essere al massimo quattro. Una tale struttura ha condizionato<br />
in pratica anche altri sistemi operativi, per esempio GNU/Linux. Bisogna tenere in considerazione<br />
l’origine storica per comprendere che altri sistemi operativi possono comportarsi in<br />
modo completamente differente.<br />
Di solito, ‘FDISK’ ha una visione delle partizioni tutta orientata verso il Dos. Infatti, consente<br />
di creare una sola partizione primaria (ovvero una partizione normale) e altre partizioni estese<br />
(ovvero altre sottopartizioni di una seconda partizione primaria).<br />
Bisogna considerare che il settore di avvio del Dos viene collocato nel primo settore della partizione<br />
primaria utilizzata per il Dos. In questo modo, manca la sistemazione del primo settore del<br />
disco, l’MBR, che deve contenere il codice necessario a raggiungere il settore di avvio.<br />
FDISK [/MBR]<br />
In generale, sembra che le varie edizioni di ‘FDISK’ per Dos funzionino solo con il primo disco<br />
fisso.<br />
Fondamentalmente, il programma è interattivo, per cui si avvia una maschera con la quale si<br />
interviene per mezzo di un menù. Di norma viene consentito di cancellare le partizioni, di crearne<br />
una primaria e probabilmente una sola di estesa.<br />
Di solito, è possibile riscrivere il settore di avvio MBR attraverso l’opzione ‘/MBR’.<br />
359.2 Inizializzazione di un’unità di memorizzazione<br />
L’inizializzazione di un’unità di memorizzazione, intesa come un dischetto o una partizione, si<br />
ottiene con il comando ‘FORMAT’. Questo si occupa anche di predisporre il file system Dos-FAT<br />
ed eventualmente anche di trasferire il kernel, per renderlo avviabile.<br />
FORMAT lettera_unità: [/N:settori] [/T:cilindri] [/S] [/U]<br />
In alcune edizioni del Dos, questo comando non inizializza l’unità di memorizzazione, ma si<br />
limita a sovrascrivere la parte iniziale. Ciò viene fatto per accelerare il procedimento e per<br />
permettere eventualmente il recupero dei dati, in caso di ripensamenti. In generale, sarebbe<br />
meglio evitare questa scorciatoia quando si tratta di unità corrispondenti ai dischetti; così, per<br />
confermare la richiesta di un’inizializzazione tradizionale, si può aggiungere l’opzione ‘/U’.<br />
100
Dos: dischi, file system, directory e file 101<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>FORMAT A: /U<br />
Inizializza l’unità ‘A:’, corrispondente a un dischetto. L’inizializzazione avviene in modo<br />
completo, essendo stata usata l’opzione ‘/U’; inoltre, dal momento che non sono state<br />
indicate altre cose, il formato usato è quello predefinito in base alla configurazione del<br />
firmware.<br />
• C:\>FORMAT A: /N:9 /T:40 /U<br />
Come nell’esempio precedente, con l’aggiunta dell’indicazione della geometria: nove settori<br />
per traccia e 40 cilindri; si sottintende la presenza di due tracce per cilindro. Pertanto,<br />
dal momento che ogni settore è di 512 byte: 2 * 40 * 9 * 512 byte = 360 Kibyte.<br />
• C:\>FORMAT A: /N:9 /T:80 /U<br />
Come nell’esempio precedente, ma con 80 cilindri: 2 * 80 * 9 * 512 byte = 720 Kibyte.<br />
• C:\>FORMAT A: /N:15 /T:80 /U<br />
Come nell’esempio precedente, ma con 15 settori per traccia: 2 * 80 * 15 * 512 byte =<br />
1200 Kibyte.<br />
• C:\>FORMAT A: /N:18 /T:80 /U<br />
Come nell’esempio precedente, ma con 18 settori per traccia: 2 * 80 * 18 * 512 byte =<br />
1440 Kibyte.<br />
• C:\>FORMAT A: /S<br />
Inizializza il dischetto corrispondente all’unità ‘A:’, trasferendo successivamente il kernel<br />
e probabilmente anche l’interprete dei comandi (‘COMMAND.COM’). Ciò avviene perché è<br />
stata usata l’opzione ‘/S’.<br />
359.3 Etichetta di un’unità di memorizzazione<br />
Tradizionalmente, il Dos prevede la possibilità di attribuire un nome a un’unità di memorizzazione.<br />
Questo nome viene definito solitamente «etichetta» e di fatto viene annotato come un file<br />
speciale nella directory radice (anche se poi non appare nell’elenco). Per modificare o attribuire<br />
questo nome si utilizza il comando ‘LABEL’:<br />
LABEL [lettera_unità:][nome]<br />
Se non si indica la lettera dell’unità di memorizzazione su cui intervenire, si tratta implicitamente<br />
di quella da cui è stato avviato il sistema; se non si indica il nome da attribuire, ‘LABEL’ funziona<br />
in modo interattivo, chiedendo il da farsi.<br />
In linea di principio, l’etichetta di un’unità non serve, salvo il caso di qualche programma che<br />
potrebbe utilizzarla per uno scopo particolare (per esempio i programmi di installazione per<br />
identificare i dischetti).
102 volume VIII Argomenti avanzati e accessori<br />
Esiste anche un altro comando interno per la verifica del nome di un’unità; si tratta di ‘VOL’:<br />
VOL [lettera_unità:]<br />
Il risultato è solo l’informazione del nome stesso, con l’aggiunta del numero di serie se questo<br />
dato è disponibile.<br />
359.4 Analisi e correzione del file system<br />
Esistono pochi strumenti di analisi e correzione degli errori nel file system. In origine si tratta del<br />
comando ‘CHKDSK’, a cui in seguito si è aggiunto ‘SCANDISK’.<br />
CHKDSK lettera_unità: [/F]<br />
‘CHKDSK’ può essere usato solo con l’indicazione di un’unità di memorizzazione; in tal caso<br />
restituisce le informazioni disponibili su questa. Se si aggiunge l’opzione ‘/F’, si richiede<br />
esplicitamente la correzione, per quanto possibile, degli errori rilevati.<br />
L’errore tipico di un file system Dos-FAT si traduce in «concatenamenti perduti», ovvero file,<br />
interi o parziali, di cui non si può conoscere il nome. Questi file potrebbero essere solo dati<br />
temporanei che è bene siano cancellati, ma questa non è la regola. ‘CHKDSK’ tende a salvare<br />
questi file assegnando loro un nome più o meno casuale, lasciando all’utilizzatore l’onere di<br />
decidere cosa farne.<br />
359.5 Copia<br />
Nei sistemi Dos la copia è un’attività piuttosto articolata. In pratica, il comando interno ‘COPY’<br />
consente solo di copiare file puri e semplici. Per copiare un dischetto occorre il comando<br />
‘DISKCOPY’; per copiare file e directory occorre il comando ‘XCOPY’.<br />
359.5.1 DISKCOPY<br />
DISKCOPY unità_di_origine: unità_di_destinazione:<br />
‘DISKCOPY’ permette di eseguire la copia di un’unità di memorizzazione, purché si tratti di un<br />
dischetto. Il dischetto di destinazione dovrebbe essere inizializzato preventivamente.<br />
L’unità indicata come secondo argomento, che rappresenta la destinazione, può essere la stessa<br />
di quella di origine. In questo caso, i dischetti andranno alternati nel dispositivo che li ospita,<br />
seguendo le istruzioni che dà ‘DISKCOPY’ stesso.<br />
L’esempio seguente esegue la copia di un dischetto usando lo stesso dispositivo fisico:<br />
C:\>DISKCOPY A: A:<br />
359.5.2 XCOPY<br />
XCOPY percorso_origine [percorso_destinazione] [/E] [/S] [/H] [/V]<br />
‘XCOPY’ consente di copiare uno o più file assieme alla struttura di directory. In altri termini, ciò<br />
significa che è possibile copiare anche una directory intera.
Dos: dischi, file system, directory e file 103<br />
Tabella 359.1. Alcune opzioni.<br />
Opzione Descrizione<br />
/S Copia solo le directory e le sottodirectory non vuote.<br />
/E Copia tutte le sottodirectory, anche se vuote.<br />
/H Copia anche i file nascosti e di sistema.<br />
/V Verifica la copia.<br />
L’esempio seguente copia tutta la struttura che si articola a partire dalla directory ‘\PIPPO\’,<br />
nella directory ‘\PAPPA\’, includendo anche i file nascosti e quelli di sistema:<br />
C:\>XCOPY \PIPPO\*.* \PAPPA\*.* /E /S /H /V<br />
359.6 Trasferimento del sistema<br />
Il Dos è un sistema operativo elementare. L’essenziale in assoluto è costituito dal kernel e dall’interprete<br />
dei comandi. Per rendere «avviabile» un dischetto o una partizione basta copiare questi<br />
file e sistemare il settore di avvio, in modo che punti correttamente al kernel. Questo si può ottenere<br />
con il comando ‘FORMAT’, quando lo si usa con l’opzione ‘/S’ (cosa che naturalmente<br />
implica anche l’inizializzazione dell’unità), oppure con il comando ‘SYS’, fatto appositamente<br />
per questo:<br />
FORMAT lettera_unità: /S<br />
SYS lettera_unità:<br />
A seconda del tipo di Dos, vengono copiati solo i file del kernel, oppure anche l’interprete dei<br />
comandi (necessario per avviare il sistema).<br />
359.7 Modifica delle unità<br />
La caratteristica del Dos per cui si distinguono le unità di memorizzazione, introduce l’esigenza<br />
di comandi particolari, che vengono descritti brevemente nelle sezioni seguenti. In particolare,<br />
si tratta della possibilità di attribuire una lettera di unità differente e di poter inserire un’unità in<br />
una directory come avviene con l’innesto di un file system nei sistemi Unix.<br />
359.7.1 ASSIGN<br />
ASSIGN lettera_unità_1[:]=lettera_unità_2[:]<br />
ASSIGN /STATUS<br />
ASSIGN<br />
Il comando ‘ASSIGN’ permette di modifica il nome di un’unità di memorizzazione. Per ottenere<br />
questo risultato, rimane attivo come programma residente in memoria. Quando si usa senza<br />
argomenti, ‘ASSIGN’ elimina tutte le ridefinizioni; con l’opzione ‘/STATUS’ si ottiene lo stato<br />
attuale delle ridefinizioni; quando si indicano le lettere di unità, la prima è l’unità virtuale che<br />
viene creata come riproduzione della seconda.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>ASSIGN E:=A:<br />
Dopo questo comando, per accedere all’unità corrispondente al primo dischetto, si potrà<br />
indicare l’unità ‘E:’.
104 volume VIII Argomenti avanzati e accessori<br />
• C:\>ASSIGN<br />
Cancella tutte le ridefinizioni delle unità di memorizzazione.<br />
359.7.2 JOIN<br />
JOIN lettera_unità: percorso<br />
JOIN lettera_unità: /D<br />
JOIN<br />
Il comando ‘JOIN’ permette di attaccare un’unità di memorizzazione in corrispondenza di un<br />
percorso (una directory). Si tratta in pratica di montare l’unità, come avviene nei sistemi Unix.<br />
Quando si usa ‘JOIN’ senza argomenti, si ottiene un elenco degli innesti attivi; quando si usa<br />
l’opzione ‘/D’, si vuole annullare il collegamento dell’unità.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>JOIN A: C:\MNT\A<br />
Innesta l’unità ‘A:’ nella directory ‘C:\MNT\A\’.<br />
• C:\>JOIN A: /D<br />
Distacca l’unità ‘A:’ da un collegamento precedente.<br />
359.7.3 SUBST<br />
SUBST lettera_unità: percorso<br />
SUBST /D<br />
Il comando ‘SUBST’ permette di creare un’unità virtuale a partire da una directory di un’altra<br />
unità. In pratica, si fa in modo di permettere l’identificazione di una certa directory attraverso<br />
l’uso di una lettera di unità.<br />
Quando si usa ‘JOIN’ con l’opzione ‘/D’, si vuole annullare l’unità virtuale relativa.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>SUBST E: C:\EXTRA\E<br />
Crea l’unità virtuale ‘E:’ a partire dal contenuto delle directory ‘C:\EXTRA\E\’.<br />
• C:\>JOIN E: /D<br />
Elimina l’unità virtuale ‘E:’.
Dos: dischi, file system, directory e file 105<br />
359.8 Altre particolarità<br />
La gestione del Dos di file e directory è molto strana. Nelle sezioni seguenti vengono descritti<br />
alcuni programmi tipici dei sistemi Dos riguardanti la gestione di file e directory, che non hanno<br />
trovato un’altra collocazione in questo documento, a causa della loro particolarità.<br />
359.8.1 VERIFY<br />
VERIFY [ON|OFF]<br />
Il comando interno ‘VERIFY’ permette di richiedere al sistema operativo di verificare la registrazione<br />
nelle unità di memorizzazione. Come si vede dallo schema sintattico, si attiva o si disattiva<br />
la modalità, attraverso l’uso delle parole chiave ‘ON’ oppure ‘OFF’. Di solito, questa modalità è<br />
disabilitata ed è difficile definire la reale importanza di questa impostazione.<br />
Se si usa il comando senza alcun argomento, si ottiene di sapere quale sia l’impostazione attuale.<br />
359.8.2 APPEND<br />
APPEND directory<br />
APPEND ;<br />
APPEND<br />
Il comando ‘APPEND’ consente di definire un percorso per la ricerca dei file di dati. In pratica,<br />
si vuole permettere ai programmi di accedere a file di dati anche quando questi si trovano fuori<br />
della collocazione prevista. ‘APPEND’ può essere usato più volte, per aggiungere altre directory.<br />
Se viene usato con l’argomento ‘;’, si intende cancellare tutto l’elenco di directory di ricerca dei<br />
file di dati. Se viene usato senza argomenti, si ottiene l’elenco di queste directory.<br />
L’esempio seguente aggiunge la directory ‘C:\DATI\’ all’elenco dei percorsi di ricerca per i file<br />
di dati:<br />
C:\>APPEND C:\DATI<br />
359.8.3 ATTRIB<br />
ATTRIB [+R|-R] [+A|-A] [+S|-S] [+H|-H] file<br />
Il comando ‘ATTRIB’ permette di visualizzare o cambiare gli attributi del file. In pratica,<br />
utilizzando la forma ‘+x’ si attiva l’attributo x, mentre con ‘-x’ si disattiva l’attributo stesso.<br />
Segue la descrizione di alcuni esempi.<br />
• C:\>ATTRIB *.*<br />
Mostra gli attributi di tutti i file contenuti nella directory corrente.<br />
• C:\>ATTRIB +R *.*<br />
Imposta l’attributo di sola lettura per tutti i file della directory corrente.
106 volume VIII Argomenti avanzati e accessori<br />
359.8.4 DELTREE<br />
DELTREE directory<br />
Il comando ‘DELTREE’ consente di eliminare una directory con tutto il suo contenuto,<br />
ricorsivamente.<br />
L’esempio seguente elimina la directory ‘C:\TEMP\CIAO\’ assieme a tutto il suo contenuto:<br />
C:\>DELTREE C:\TEMP\CIAO<br />
359.8.5 FIND<br />
FIND [opzioni] "stringa" [file]<br />
Il comando ‘FIND’ è uno dei più complessi nei sistemi Dos. Serve per fare una ricerca di una<br />
stringa in uno o più file, in base a quanto indicato nell’ultimo argomento, oppure all’interno<br />
dello standard input. Il risultato normale della ricerca è l’emissione delle righe che contengono<br />
la stringa cercata, assieme all’indicazione del file a cui appartengono.<br />
Tabella 359.2. Alcune opzioni.<br />
Opzione Descrizione<br />
/V<br />
La ricerca avviene per le righe che non contengono la stringa<br />
cercata.<br />
/C<br />
Mostra solo il totale delle righe che contengono la stringa<br />
cercata.<br />
/N Mostra il numero di ogni riga che contiene la stringa cercata.<br />
Ignora la differenza tra maiuscole e minuscole per il confronto<br />
/I<br />
con la stringa di ricerca.<br />
In alcune edizioni del Dos, questa modalità di funzionamento<br />
è predefinita.<br />
Segue al descrizione di alcuni esempi.<br />
• C:\>FIND "ciao" *.*<br />
Cerca la stringa ‘ciao’ in tutti i file della directory corrente.<br />
• C:\>FIND "ciao" < MIO.TXT<br />
Cerca la stringa ‘ciao’ nel file ‘MIO.TXT’ che viene fornito attraverso lo standard input.<br />
359.8.6 MOVE<br />
MOVE file_origine directory_destinazione<br />
MOVE directory_origine directory_destinazione<br />
Il comando ‘MOVE’ consente di spostare file o directory in altre collocazioni. In generale, ‘MOVE’<br />
si occupa di spostare e non di rinominare i file, che invece è una funzione del comando ‘REN’.<br />
Il comando ‘MOVE’ è ambiguo e si comporta in maniera differente da una realizzazione all’altra<br />
dei sistemi Dos. In generale bisogna considerare che la destinazione può esistere o meno,<br />
implicando dei comportamenti differenti da valutare.
Dos: dischi, file system, directory e file 107<br />
L’esempio seguente sposta i file e le directory contenute in ‘C:\CIAO\’ nella directory ‘C:\<br />
MIA\’. Se la directory di destinazione non c’è, questa dovrebbe essere creata automaticamente,<br />
ma la cosa va verificata:<br />
C:\>MOVE C:\CIAO\*.* C:\MIA<br />
359.8.7 TREE<br />
TREE [directory]<br />
Il comando ‘TREE’ consente di visualizzare la struttura della directory corrente, oppure di un’altra<br />
directory indicata come argomento.<br />
L’esempio seguente mostra la struttura della directory ‘C:\CIAO\’:<br />
C:\>TREE C:\CIAO<br />
359.8.8 COMP e FC<br />
COMP file_1 file_2 [opzioni]<br />
FC file_1 file_2 [opzioni]<br />
I comandi ‘COMP’ e ‘FC’ permettono di verificare se due file sono identici, oppure no. Non sono<br />
molto facili da utilizzare, specialmente il primo; probabilmente vale la pena di sapere che ci sono,<br />
senza poi pretendere di sfruttare tutte le loro possibilità.<br />
‘FC’ assomiglia molto vagamente a un comando ‘diff’ di Unix, dal momento che di fronte a file<br />
di testo cerca di comprendere quale cambiamento è stato fatto. In questo senso, è probabile che<br />
‘FC’ sia il più utile tra questi due.<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Dos: configurazione<br />
Capitolo 360<br />
Nel Dos è un po’ difficile scindere i concetti di configurazione e script, perché per configurare il<br />
sistema, occorre predisporre degli script. Si tratta dei file ‘\CONFIG.SYS’ e ‘\AUTOEXEC.BAT’,<br />
collocati nell’unità di avvio. Questo fatto è già stato accennato nel capitolo introduttivo; in questo<br />
si vuole appr<strong>of</strong>ondire un po’ la cosa.<br />
360.1 CONFIG.SYS<br />
Il file ‘CONFIG.SYS’, collocato nella directory radice dell’unità di avvio, è uno script speciale<br />
avviato dal kernel prima dell’interprete dei comandi. In linea di massima, si tratta di una sequenza<br />
di direttive che occupano ognuna una riga; alcune versioni recenti del Dos consentono di<br />
suddividere le direttive in sezioni da scegliere in base a un menù iniziale.<br />
Le direttive di ‘CONFIG.SYS’ hanno la forma seguente:<br />
nome=valore<br />
In pratica, si assegna una stringa (senza delimitatori espliciti) a un nome che ha un significato<br />
particolare.<br />
In questo file, vengono ignorate le righe vuote, quelle bianche e quelle che iniziano con la parola<br />
chiave ‘REM’:<br />
REM annotazione<br />
È importante osservare che i nomi delle direttive non fanno differenza tra lettere maiuscole<br />
e minuscole. In generale, questo vale anche per le stringhe che vengono assegnate a questi<br />
nomi.<br />
360.1.1 BREAK<br />
BREAK={ON|OFF}<br />
Teoricamente, questa istruzione consente di attivare o di disattivare la funzionalità abbinata alla<br />
combinazione di tasti [ Ctrl+c ]. In condizioni normali, quando si assegna la parola chiave ‘ON’, si<br />
attiva il funzionamento della combinazione [ Ctrl+c ].<br />
360.1.2 BUFFERS<br />
BUFFERS=n_buffer[,n_buffer_secondari]<br />
Questa istruzione consente di definire la quantità di memoria tampone per gli accessi ai dischi.<br />
Si assegnano uno o due valori numerici, separati da una virgola. Il primo valore va da 1 a 99 ed<br />
esprime il numero di aree da usare come memoria tampone; il secondo valore, facoltativo, indica<br />
delle memorie tampone secondarie, con valori che vanno da uno a otto.<br />
108
Dos: configurazione 109<br />
360.1.3 COUNTRY<br />
COUNTRY=n_codice_paese[,[n_codifica][,file_informazioni_nazionali]]<br />
Questa istruzione, attraverso quanto contenuto in un file che tradizionalmente si chiama<br />
‘COUNTRY.SYS’, permette di configurare il sistema in base alla nazionalità. Per la precisione,<br />
si può specificare un codice riferito alla nazionalità, attraverso il quale si ottiene una forma particolare<br />
per le date e gli orari, con l’aggiunta eventuale di un altro codice che specifica la codifica<br />
dei caratteri prescelta (codepage). La tabella 360.1 riepiloga questi codici che fanno riferimento<br />
tradizionalmente anche a paesi che non esistono più.<br />
Si può osservare che la stringa assegnata alla direttiva ‘COUNTRY’ può contenere l’indicazione<br />
di un file (con il percorso, completo di unità o meno). Questo file è quello che contiene poi<br />
le indicazioni relative alla nazionalità prescelta; come già accennato, di solito si tratta del file<br />
‘COUNTRY.SYS’.<br />
Tabella 360.1. Codici di nazionalità.<br />
Località Codice di nazionalità Codifiche utili<br />
USA 001 437, 850<br />
Canada francese 002 863, 850<br />
America latina 003 850, 437<br />
Russia 007 866, 437<br />
Olanda 031 850, 437<br />
Belgio 032 850, 437<br />
Francia 033 850, 437<br />
Spagna 034 850, 437<br />
Ungheria 036 850, 852<br />
Jugoslavia 038 850, 852<br />
Italia 039 850, 437<br />
Svizzera 041 850, 437<br />
Cecoslovacchia 042 850, 852<br />
Regno unito 044 850, 437<br />
Danimarca 045 850, 865<br />
Svezia 046 850, 437<br />
Norvegia 047 850, 865<br />
Polonia 048 850, 852<br />
Germania 049 850, 437<br />
Brasile 055 850, 860<br />
Australia 061 850, 437<br />
Giappone 081 932, 437, 850, 942<br />
Corea 082 934, 437, 850, 944<br />
Cina 088 938, 437, 850, 948<br />
Turchia 090 857, 850<br />
Asia (inglese) 099 850, 437<br />
Portogallo 351 850, 860<br />
Islanda 354 850, 861<br />
Finlandia 358 850, 437<br />
L’esempio seguente predispone l’impostazione nazionale per l’Italia, utilizzando la codifica 850,<br />
che ha il vantaggio di essere quella più comune dei paesi che usano l’alfabeto latino:<br />
COUNTRY=039,850,C:\DOS\COUNTRY.SYS
110 volume VIII Argomenti avanzati e accessori<br />
360.1.4 DEVICE, DEVICEHIGH<br />
DEVICE=programma_di_gestione_dispositivo [opzioni]<br />
DEVICEHIGH=programma_di_gestione_dispositivo [opzioni]<br />
Si tratta di un modo per avviare un programma speciale che ha lo scopo di rimanere residente<br />
in memoria. In generale, tali programmi servono per la gestione di qualche dispositivo,<br />
indispensabile prima di avviare l’interprete dei comandi.<br />
La differenza tra le due direttive sta nel fatto che la seconda cerca di caricare il programma nella<br />
memoria «alta».<br />
Le opzioni riguardano il programma.<br />
L’esempio seguente avvia il programma ‘MOUSE.SYS’ che presumibilmente gestisce il mouse<br />
(l’opzione ‘/2’ serve probabilmente a utilizzare il mouse collegato alla seconda porta seriale):<br />
DEVICE=C:\MOUSE\MOUSE.SYS /2<br />
360.1.5 DOS<br />
DOS={HIGH|LOW}[,{UMB|NOUMB}]<br />
DOS=[{HIGH|LOW},]{UMB|NOUMB}<br />
Questa istruzione richiede al kernel di allocarsi nella memoria convenzionale, ‘LOW’, o in quella<br />
alta, ‘HIGH’. La parola chiave ‘UMB’ richiede di mantenere un collegamento tra la UMB e la<br />
memoria convenzionale; la parola chiave ‘NOUMB’ fa sì che questo collegamento non abbia luogo.<br />
360.1.6 DRIVEPARM<br />
DRIVEPARM=[opzioni]<br />
Si tratta di una direttiva attraverso cui si possono definire i parametri relativi ai dispositivi a<br />
blocchi, per la precisione si tratta solo di dischi, se questo può essere necessario. Le opzioni<br />
assomigliano a quelle dei programmi di servizio, iniziando con una barra obliqua normale: ‘/x...’.<br />
Tabella 360.2. Alcune opzioni.<br />
Opzione Descrizione<br />
/d:n_dispositivo_fisico<br />
Consente di indicare il dispositivo attraverso un numero, da 0<br />
a 255. Lo zero corrisponde alla prima unità a dischetti.<br />
/c<br />
Se si utilizza questa opzione, si intende che l’unità fisica è in<br />
grado di sapere se il disco è inserito o meno.<br />
/f:n_formato<br />
Stabilisce il formato del dispositivo fisico; in pratica, fissa la<br />
geometria.<br />
/f:0 Dischetto 160 Kibyte, 180 Kibyte, 320 Kibyte, 360 Kibyte.<br />
/f:1 Dischetto 1200 Kibyte.<br />
/f:2 Dischetto 720 Kibyte.<br />
/f:5 Disco fisso.<br />
/f:6 Nastro.<br />
/f:7 Dischetto 1440 Kibyte.<br />
/f:9 Dischetto 2880 Kibyte.<br />
/h:n_testine Definisce il numero di testine.<br />
/i Indica che si tratta di un dischetto da 3,5 pollici.
Dos: configurazione 111<br />
Opzione Descrizione<br />
/n Si tratta di un disco fisso.<br />
/s:n_settori Definisce il numero di settori per traccia.<br />
/t:n_cilindri<br />
Definisce il numero dei cilindri (in altri termini: il numero di<br />
tracce per faccia).<br />
360.1.7 FCBS<br />
FCBS=n_blocchi<br />
Permette di definire il numero di blocchi di controllo dei file (file control block). Il valore va da 1<br />
a 255, mentre il valore normale è di quattro blocchi.<br />
360.1.8 FILES<br />
FILES=n_blocchi<br />
Permette di indicare il numero massimo di file aperti. Il numero che può essere assegnato va da<br />
8 a 255. Il valore predefinito dovrebbe essere di otto file.<br />
360.1.9 INSTALL<br />
INSTALL=programma [opzioni]<br />
Si tratta di un’istruzione con la quale si può avviare preventivamente un programma (che dovrebbe<br />
essere residente in memoria), prima dell’avvio dell’interprete dei comandi. In questo caso, a<br />
differenza della direttiva ‘DEVICE’, o ‘DEVICEHIGH’, si tratta di un programma normale.<br />
Le opzioni riguardano il programma.<br />
360.1.10 LASTDRIVE<br />
LASTDRIVE=lettera_unità_finale<br />
Consente di specificare l’ultima lettera di unità che può essere richiesta. Questo consente di<br />
risparmiare risorse, se si è consapevoli del fatto che non servono lettere oltre un certo punto. La<br />
lettera in questione può essere indifferentemente maiuscola o minuscola, senza che ciò possa fare<br />
differenza.<br />
360.1.11 SHELL<br />
SHELL=programma [opzioni]<br />
Permette di indicare esplicitamente il programma da avviare alla fine della procedura di avvio<br />
del kernel. In generale si tratta dell’interprete dei comandi. Questa direttiva può consentire di avviare<br />
un interprete alternativo a quello normale, oppure permette di avviarlo da una collocazione<br />
insolita; inoltre permette di dare al programma in questione delle opzioni particolari.<br />
L’esempio seguente avvia il programma ‘COMMAND.COM’ che si trova nella directory ‘C:\DOS\’:<br />
SHELL=C:\DOS\COMMAND.COM
112 volume VIII Argomenti avanzati e accessori<br />
360.1.12 STACK<br />
STACK=n_livelli[,dimensione_in_byte]<br />
Con questa istruzione è possibile fissare la dimensione dello stack, utilizzando valori da 8 a 64,<br />
oltre allo zero. Il valore dopo la virgola indica la dimensione in byte di ogni livello dello stack.<br />
In questo caso i valori vanno da 32 a 512.<br />
360.2 AUTOEXEC.BAT<br />
Il file ‘AUTOEXEC.BAT’ collocato nella directory radice dell’unità di avvio, è inteso essere uno<br />
script che viene eseguito dall’interprete dei comandi, ‘COMMAND.COM’, dopo l’avvio del sistema.<br />
Questo script viene realizzato normalmente in modo sequenziale, senza strutture di controllo.<br />
In generale è importante per due cose: impostare alcune variabili di ambiente fondamentali, per<br />
esempio ‘PATH’; avviare dei programmi che poi restano residenti in memoria, quando questo non<br />
si ottiene già attraverso il file ‘\CONFIG.SYS’.<br />
360.3 Comandi ridondanti<br />
Anche nel Dos è molto importante l’uso delle variabili di ambiente. È già stato mostrato il<br />
comando ‘SET’, attraverso il quale si impostano o si annullano le variabili di ambiente:<br />
SET nome_variabile=stringa_assegnata<br />
Alcune variabili hanno un’importanza particolare, per cui esiste un comando interno apposito<br />
(dell’interprete dei comandi), che serve a inizializzarle senza nemmeno l’uso del comando ‘SET’.<br />
• PROMPT stringa_di_invito<br />
Il comando interno ‘PROMPT’ rappresenta un modo alternativo per impostare la variabile di<br />
ambiente con lo stesso nome. Se si usa il comando senza l’argomento, si ripristina l’invito<br />
predefinito.<br />
• PATH [percorsi_degli_eseguibili]<br />
Il comando interno ‘PATH’ rappresenta un modo alternativo per impostare la variabile di<br />
ambiente con lo stesso nome. Se non si indica l’argomento, si ottiene la visualizzazione<br />
dell’elenco dei percorsi attivo.<br />
Esistono altri comandi particolari che si sovrappongono alle istruzioni del file ‘CONFIG.SYS’.<br />
• BREAK [ON|OFF]<br />
Abilita o disabilita la funzionalità abbinata alla combinazione di tasti [ Ctrl+c ]. Utilizzando<br />
il comando senza argomento, si ottiene la visualizzazione dello stato attuale.
Dos: configurazione 113<br />
360.4 Localizzazione<br />
La localizzazione del Dos si riduce alla configurazione della mappa della tastiera e alla definizione<br />
dell’insieme di caratteri. L’insieme di caratteri dipende dalla scelta della nazionalità, fatta<br />
nel file ‘CONFIG.SYS’, attraverso la direttiva ‘COUNTRY’.<br />
Nelle sezioni seguenti vengono mostrati alcuni comandi utili per le impostazioni che riguardano<br />
la localizzazione.<br />
360.4.1 CHCP<br />
CHCP [n_codifica]<br />
Si tratta di un comando interno dell’interprete dei comandi che interviene nella definizione della<br />
codifica utilizzata. In pratica, se si utilizza senza argomenti, mostra il numero della codifica attiva;<br />
se si indica un numero come argomento, cambia la codifica attiva, purché questa sia una di quelle<br />
ammissibili in base alla nazionalità stabilita con la direttiva ‘COUNTRY’ nel file di configurazione<br />
‘CONFIG.SYS’.<br />
L’esempio seguente fa in modo che sia attivata la codifica corrispondente al numero 850:<br />
C:\>CHCP 850<br />
360.4.2 KEYB<br />
KEYB [sigla_nazionale[,[n_codifica][,file_informazioni_tastiere]]]<br />
‘KEYB’ è un comando esterno che consente di cambiare la configurazione della tastiera secondo<br />
alcuni modelli di nazionalità predefiniti. La sigla nazionale è un codice di due lettere che, assieme<br />
alla nazionalità, dovrebbe indicare anche la lingua utilizzata. La tabella 360.3 elenca queste sigle.<br />
Tabella 360.3. Sigle nazionali-linguistiche per l’impostazione della mappa della<br />
tastiera.<br />
Segue la descrizione di alcuni esempi.<br />
Sigla Corrispondenza<br />
US USA (predefinito)<br />
FR Francia<br />
GR Germania<br />
IT Italia<br />
SP Spagna<br />
UK Gran Bretagna<br />
PO Portogallo<br />
SG Svizzera tedesca<br />
SF Svizzera francese<br />
DK Danimarca<br />
BE Belgio<br />
NL Olanda (Nederland)<br />
NO Norvegia<br />
LA America latina<br />
SV Svezia<br />
SU Finlandia (Suomi)<br />
CF Canada francese
114 volume VIII Argomenti avanzati e accessori<br />
• C:\>KEYB<br />
Mostra la configurazione attuale.<br />
• C:\>KEYB IT<br />
Predispone la mappa dei tasti per la disposizione italiana.<br />
• C:\>KEYB IT,850,C:\DOS\KEYBOARD.SYS<br />
Predispone la mappa dei tasti per la disposizione italiana, specificando l’uso della codifica<br />
850 e del file ‘C:\DOS\KEYBOARD.SYS’ per trovare le impostazioni standard delle tastiere.<br />
360.4.3 GRAFTABL<br />
GRAFTABL [n_codifica]<br />
GRAFTABL /STATUS<br />
‘GRAFTABL’ è un comando esterno che consente di cambiare la codifica per i caratteri visualizzati<br />
sullo schermo. L’opzione ‘/STATUS’ permette di conoscere la situazione attuale, mentre<br />
l’indicazione di un numero di codifica cambia l’impostazione.<br />
L’esempio seguente imposta l’uso della codifica 850:<br />
C:\>GRAFTABL 850<br />
360.5 Orologio<br />
Il Dos consente di accedere all’orologio dell’elaboratore, per leggere la data e l’ora, o per cambiare<br />
tali informazioni. In generale, il Dos non prevede la gestione di un orologio hardware allineato<br />
al tempo universale; pertanto, l’orologio hardware deve corrispondere necessariamente all’ora<br />
locale, lasciando all’utente il problema legato alle variazioni dell’ora estiva.<br />
I comandi per accedere all’orologio sono ‘DATE’ e ‘TIME’:<br />
DATE [data]<br />
TIME [orario]<br />
Se non si indica la data o l’orario, viene mostrato quello attuale e viene richiesto all’utente di<br />
modificarlo o di confermarlo.<br />
Il modo in cui va scritta da data o l’ora, dipende dalla localizzazione. Per conoscere quello giusto,<br />
basta osservare in che modo vengono visualizzate tali informazioni.<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Dos: script dell’interprete dei comandi<br />
Capitolo 361<br />
Uno script dell’interprete dei comandi, conosciuto solitamente con il nome di file batch, potrebbe<br />
essere definito come un file di testo normale in cui può essere indicato un elenco di comandi da<br />
eseguire. Tuttavia, questi script consentono l’uso anche di strutture di controllo elementari, per<br />
cui si possono realizzare dei programmi molto semplici, senza troppe pretese.<br />
È interessante osservare che questi script vengono individuati solo attraverso l’estensione che ha<br />
il nome: ‘.BAT’. Inoltre, non esiste la necessità di renderli «eseguibili» come si fa nei sistemi<br />
Unix.<br />
361.1 Parametri, variabili ed espansione<br />
Gli script dell’interprete dei comandi hanno accesso agli argomenti che vengono loro forniti. Si<br />
possono gestire solo nove di questi argomenti alla volta, attraverso i parametri posizionali relativi,<br />
da ‘%1’ a ‘%9’. Come avviene nelle shell Unix, è disponibile il comando interno ‘SHIFT’ per fare<br />
scorrere in avanti gli argomenti nei parametri disponibili.<br />
Bisogna ricordare che in Dos i caratteri jolly non vengono espansi dalla shell, per cui la<br />
limitazione a soli nove parametri posizionali, non dovrebbe costituire un problema.<br />
Nell’ambito di uno script possono essere dichiarate e utilizzate delle variabili di ambiente. È già<br />
stato mostrato in precedenza l’uso del comando ‘SET’ per impostare o eliminare le variabili di<br />
ambiente. Per fare riferimento al contenuto di una variabile, si usa la notazione seguente:<br />
%nome_variabile%<br />
L’esempio seguente rappresenta il caso tipico di estensione di un percorso di ricerca degli<br />
eseguibili, quando si ritiene che la variabile ‘PATH’ sia già stata usata:<br />
SET PATH=%PATH%;C:\PIPPO<br />
361.2 Chiamate di altri script<br />
Tradizionalmente, il Dos ha un baco molto grave, ormai divenuto una caratteristica fondamentale,<br />
riguardante l’avvio di script all’interno di altri script. In generale, quando si chiama un<br />
programma che in realtà corrisponde a uno script, al termine di questo non riprende l’esecuzione<br />
di quello chiamante. Per ottenere la ripresa dell’interpretazione dello script di partenza occorre<br />
usare il comando speciale ‘CALL’.<br />
CALL nome_script [argomenti_dello_script]<br />
361.3 Strutture di controllo<br />
Le strutture di controllo per la programmazione attraverso gli script dell’interprete dei comandi<br />
sono molto limitate. È disponibile una struttura condizionale semplificata e un ciclo di scansione<br />
di file, che vengono descritti brevemente.<br />
115
116 volume VIII Argomenti avanzati e accessori<br />
361.3.1 IF<br />
IF [NOT] ERRORLEVEL valore_di_uscita_ultimo_comando comando<br />
IF [NOT] stringa_1==stringa_2 comando<br />
IF [NOT] EXIST file comando<br />
La struttura condizionale degli script dell’interprete dei comandi Dos è in pratica un comando<br />
interno dello stesso interprete. Come si può vedere dagli schemi sintattici, viene fornita una<br />
condizione che può essere invertita con la parola chiave ‘NOT’ e il risultato è solo l’esecuzione di<br />
un altro comando se la condizione risulta vera.<br />
Nel primo caso, la condizione si riferisce alla verifica del valore di uscita dell’ultimo comando<br />
eseguito. La condizione si verifica se il numero indicato è inferiore o uguale al valore restituito<br />
effettivamente da tale comando; nel secondo, la condizione si verifica se le due stringhe<br />
(non delimitate) sono identiche; nel terzo si verifica la condizione se il file indicato esiste<br />
effettivamente.<br />
Segue la descrizione di alcuni esempi.<br />
• IF ERRORLEVEL 1 GOTO :errore<br />
Se il comando precedente ha restituito un valore maggiore o uguale a uno, salta all’etichetta<br />
‘:errore’.<br />
• IF %1==ciao ECHO L’argomento è corretto<br />
In questo caso, se l’espansione del parametro ‘%1’, corrispondente al primo argomento<br />
ricevuto all’avvio, si traduce nella stringa ‘ciao’, viene emesso un messaggio per mezzo<br />
del comando ‘ECHO’.<br />
• IF %1x==x ECHO L’argomento è mancante<br />
Quello che si vede è il trucco necessario per poter verificare se un parametro contiene<br />
la stringa nulla: si aggiunge una lettera, in questo caso una «x», verificando che la<br />
corrispondenza avvenga solo con la stessa lettera.<br />
• IF NOT EXIST LETTERA.TXT ECHO Scrivi! > LETTERA.TXT<br />
Qui, se non esiste il file ‘LETTERA.TXT’ nella directory corrente, questo file viene creato<br />
attraverso il comando ‘ECHO’ che invia il suo standard output verso un file con lo stesso<br />
nome.<br />
361.3.2 FOR<br />
FOR [%]%x IN (nome...) DO comando [argomenti_del_comando]<br />
Si tratta di un comando interno che svolge un ciclo di scansione di un gruppo di nomi, generalmente<br />
file, attraverso il quale viene creato un parametro variabile speciale, il cui nome si compone<br />
di una sola lettera, a cui viene assegnato a ogni ciclo uno dei nomi contenuti tra parentesi tonde.<br />
A ogni ciclo viene eseguito il comando, che a sua volta può fare uso del parametro. 1<br />
1 Questo parametro assomiglia a una variabile di ambiente, ma non si comporta allo stesso modo. Si tratta di una<br />
particolarità del comando ‘FOR’.
Dos: script dell’interprete dei comandi 117<br />
Quando viene usato all’interno di uno script dell’interprete dei comandi, il parametro viene<br />
indicato con due simboli di percentuale (‘%%x’); al contrario, se il comando viene impartito<br />
dalla riga di comando, se ne usa uno solo.<br />
Segue la descrizione di alcuni esempi.<br />
• FOR %A IN (uno due tre) DO ECHO %A<br />
•<br />
In questo modo, si ottiene la visualizzazione delle parole ‘uno’, ‘due’ e ‘tre’. In pratica, è<br />
come se fosse stato fatto:<br />
ECHO uno<br />
ECHO due<br />
ECHO tre<br />
Volendo fare la stessa cosa dalla riga di comando, è necessario il raddoppio del simbolo ‘%’:<br />
C:\>FOR %%A IN (uno due tre) DO ECHO %%A<br />
• FOR %A IN (*.TMP *.BAD) DO DEL %A<br />
Cancella, uno a uno, tutti i file che terminano con le estensioni ‘.TMP’ e ‘.BAD’.<br />
361.3.3 GOTO<br />
GOTO etichetta<br />
Gli script dell’interprete dei comandi dispongono dell’istruzione di salto incondizionato, non<br />
avendo di meglio. Anche questa istruzione può essere presa come un comando interno<br />
dell’interprete, con la differenza che non c’è modo di utilizzarlo al di fuori di uno script.<br />
Nel corso di uno script del genere, possono apparire delle righe che contengono solo un’etichetta,<br />
nella forma:<br />
:nome_etichetta<br />
La posizione corrispondente a queste etichette può essere raggiunta con il comando ‘GOTO’, che<br />
può fare riferimento solo al nome dell’etichetta, oppure a tutta l’etichetta, includendo anche i due<br />
punti.<br />
Segue la descrizione di alcuni esempi.<br />
•<br />
•<br />
IF EXIST LETTERA.TXT GOTO riprendi<br />
ECHO Il file LETTERA.TXT è assente<br />
:riprendi<br />
In questo esempio, se il file ‘LETTERA.TXT’ esiste, si salta all’etichetta ‘:riprendi’;<br />
altrimenti si esegue il comando ‘ECHO’.<br />
IF EXIST LETTERA.TXT GOTO :riprendi<br />
ECHO Il file LETTERA.TXT è assente<br />
:riprendi<br />
Esattamente come nell’esempio precedente, con la differenza che il comando ‘GOTO’ indica<br />
l’etichetta con i suoi due punti iniziali.
118 volume VIII Argomenti avanzati e accessori<br />
361.3.4 Emulazione di un ciclo iterativo<br />
Dal momento che non è disponibile una struttura di controllo per il ciclo iterativo, questo può<br />
essere ottenuto solo attraverso l’uso del comando ‘GOTO’. Vale la pena di mostrare in che modo<br />
si può ottenere tale risultato.<br />
:etichetta_di_ingresso<br />
IF condizione GOTO :etichetta_di_uscita<br />
...<br />
...<br />
...<br />
GOTO etichetta_di_ingresso<br />
:etichetta_di_uscita<br />
:etichetta_di_ingresso<br />
...<br />
...<br />
...<br />
IF condizione GOTO :etichetta_di_ingresso<br />
:etichetta_di_uscita<br />
I due modelli sintattici mostrano due esempi di cicli iterativi. Nel primo caso si verifica una<br />
condizione, in base alla quale si decide se proseguire o se terminare il ciclo; nel secondo si<br />
esegue una volta il ciclo e quindi si verifica una condizione per decidere se ripeterlo o se uscire.<br />
361.4 Comandi utili negli script<br />
Alcuni comandi sono particolarmente utili all’interno di script dell’interprete dei comandi.<br />
Vengono descritti brevemente nelle sezioni seguenti.<br />
361.4.1 REM<br />
REM commento<br />
I commenti negli script dell’interprete dei comandi si indicano attraverso un comando apposito:<br />
‘REM’. Il funzionamento è evidente: tutto quello che segue il comando, fino alla fine della riga,<br />
viene ignorato.<br />
Alcune edizioni del Dos hanno introdotto anche l’uso del punto e virgola, come simbolo per<br />
indicare l’inizio di un commento. Segue un esempio tipico di utilizzo di questo comando:<br />
REM<br />
REM (c) 2000 Pinco pallino<br />
REM<br />
361.4.2 ECHO<br />
ECHO [ON|OFF]<br />
ECHO stringa<br />
Il comando interno ‘ECHO’ ha un significato duplice: da una parte consente di visualizzare un testo;<br />
dall’altra controlla la visualizzazione dei comandi contenuti in uno script. Infatti, si distingue<br />
il fatto che l’eco dei comandi sia attivo o meno. utilizzando il comando ‘ECHO’ senza argomenti,<br />
si ottiene l’informazione sul suo stato di attivazione. Di solito si disattiva l’eco dei comandi negli<br />
script.
Dos: script dell’interprete dei comandi 119<br />
Per disattivare l’eco di un comando particolare, senza disattivare l’eco in generale, basta<br />
inserire inizialmente il simbolo ‘@’.<br />
Segue la descrizione di alcuni esempi.<br />
• @ECHO OFF<br />
Disattiva l’eco dei comandi, facendo in modo che anche questo comando non venga<br />
visualizzato (si usa per questo il simbolo ‘@’).<br />
• ECHO Premi un tasto per continuare<br />
Mostra un messaggio per spiegare come comportarsi.<br />
361.4.3 PAUSE<br />
PAUSE<br />
Il comando interno ‘PAUSE’ sospende l’esecuzione di uno script in attesa della pressione di un<br />
tasto. Il comando emette attraverso lo standard output un messaggio di avvertimento in tal senso.<br />
Di solito, per evitare di vedere tale messaggio, si ridirige lo standard output in un file nullo.<br />
L’esempio seguente, prima mostra un messaggio in cui si avverte che per proseguire occorre<br />
premere un tasto, quindi si usa il comando ‘PAUSE’ che sospende l’esecuzione dello script, senza<br />
però mostrare altri messaggi:<br />
ECHO Premere un tasto per proseguire<br />
PAUSE > C:\NULL<br />
361.4.4 CLS<br />
CLS<br />
Il comando interno ‘CLS’ ripulisce lo schermo. Si utilizza senza argomenti.<br />
361.4.5 CHOICE<br />
CHOICE [opzioni] [testo_di_invito]<br />
Il comando ‘CHOICE’ serve a presentare una richiesta per l’inserimento di una lettera, tra un elenco<br />
determinato. La pressione del tasto corrispondente alla lettera scelta, da parte dell’utilizzatore,<br />
provoca la conclusione del funzionamento di ‘CHOICE’ che restituisce un valore corrispondente<br />
alla scelta: zero per la prima lettera, uno per la seconda,...<br />
Si osservi che l’ultimo argomento rappresenta un messaggio che serve all’utente per comprendere<br />
il senso della scelta che sta facendo.
120 volume VIII Argomenti avanzati e accessori<br />
Tabella 361.1. Alcune opzioni.<br />
Opzione Descrizione<br />
Permette di fissare l’elenco di lettere che possono essere usate<br />
/C:lettera[lettera...]<br />
nella risposta. Se non si indica questa opzione, la scelta sarà<br />
solo tra ‘y’ e ‘n’.<br />
Questa opzione fa in modo di escludere la visualizzazione<br />
delle lettere che possono essere scelte. In questo modo si fa<br />
/N<br />
affidamento esclusivamente sul testo indicato come ultimo<br />
argomento.<br />
Distingue tra maiuscole e minuscole per quanto riguarda le<br />
/S<br />
lettere tra cui scegliere.<br />
L’esempio seguente, salta a un punto differente dello script in base alla scelta di una lettera da «a»<br />
a «f». Si osservi che non sarebbe possibile eseguire l’analisi secondo una sequenza differente,<br />
perché ‘IF ERRORLEVEL’ prende in considerazione tutti i valori di uscita maggiori o uguali a<br />
quanto indicato nella condizione.<br />
CHOICE /C:abcdef Inserisci una lettera<br />
IF ERRORLEVEL 5 GOTO :f<br />
IF ERRORLEVEL 4 GOTO :e<br />
IF ERRORLEVEL 3 GOTO :d<br />
IF ERRORLEVEL 2 GOTO :c<br />
IF ERRORLEVEL 1 GOTO :b<br />
IF ERRORLEVEL 0 GOTO :a<br />
...<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Dos: gestione della memoria centrale<br />
Capitolo 362<br />
Quando è nato il Dos non si prevedeva l’uso di memoria centrale oltre il singolo mebibyte (1 Mibyte).<br />
In base a questa considerazione veniva articolata l’architettura hardware degli elaboratori<br />
«XT» e poi «AT», dove si prevedeva l’uso di un massimo di 640 Kibyte di memoria centrale,<br />
riservando la parte successiva, fino alla fine di 1 Mibyte, per la memoria video e altri dispositivi<br />
fisici.<br />
In questo senso, il Dos tradizionale può operare con un massimo di 640 Kibyte di memoria<br />
centrale; per sfruttarne di più occorrono degli accorgimenti non facili da applicare.<br />
362.1 Gestione particolare<br />
Per sfruttare la memoria oltre il primo mebibyte, si fa uso normalmente di due programmi, avviati<br />
attraverso ‘CONFIG.SYS’, prima ancora dell’interprete di comandi. Si tratta di ‘HIMEM.SYS’ e di<br />
‘EMM386.EXE’. In generale, le cose si fanno nel modo seguente:<br />
DEVICE=C:\DOS\HIMEM.SYS<br />
DEVICE=C:\DOS\EMM386.EXE<br />
Il primo dei due programmi può essere utilizzato a partire da architetture i286, mentre il secondo<br />
si può inserire solo a partire da architetture i386.<br />
‘HIMEM.SYS’ è in grado di utilizzare solo una piccola parte di memoria aggiuntiva, mentre<br />
‘EMM386.EXE’ permette teoricamente di sfruttare tutto il resto.<br />
In generale, è molto difficile la gestione ottimale della memoria centrale, perché le applicazioni<br />
si comportano in maniera differente. Di solito si possono solo fare dei tentativi.<br />
362.2 Comandi appositi<br />
Per sfruttare la memoria centrale che supera la soglia convenzionale, sono disponibili alcuni comandi<br />
specifici. In generale, si comincia dalla configurazione con il file ‘CONFIG.SYS’: dopo<br />
l’attivazione dei gestori speciali della memoria, è possibile indicare di collocare parte dell’interprete<br />
dei comandi e dello spazio richiesto dai programmi residenti in memoria, oltre il limite<br />
della memoria convenzionale:<br />
DOS=HIGH,UMB<br />
In seguito, sempre nell’ambito del file ‘CONFIG.SYS’, si può richiedere esplicitamente l’avvio di<br />
programmi nella memoria alta attraverso la direttiva ‘DEVICEHIGH’, come si vede nell’esempio<br />
seguente:<br />
DEVICEHIGH=C:\MOUSE\MOUSE.SYS /2<br />
Per quanto riguarda i programmi avviati attraverso l’interprete dei comandi, è disponibile il<br />
comando ‘LH’, ovvero ‘LOADHIGH’:<br />
LH programma [argomenti_del_programma]<br />
LOADHIGH programma [argomenti_del_programma]<br />
Per esempio, si potrebbe tentare di avviare in questo modo il programma di gestione della tastiera:<br />
C:\>LH KEYB IT<br />
121
122 volume VIII Argomenti avanzati e accessori<br />
362.3 Verifica<br />
Il Dos <strong>of</strong>fre un solo programma molto semplice per la verifica dell’utilizzo della memoria: ‘MEM’.<br />
MEM [opzioni]<br />
Se ‘MEM’ viene usato senza opzioni, visualizza brevemente la quantità di memoria utilizzata rispetto<br />
al totale disponibile. È interessante l’opzione ‘/CLASSIFY’, attraverso la quale è possibile<br />
distinguere l’utilizzo della memoria da parte dei programmi residenti; inoltre è interessante<br />
l’opzione ‘/FREE’, con cui si hanno informazioni dettagliate sulla memoria libera.<br />
Le opzioni disponibili del comando ‘MEM’ variano molto da una realizzazione all’altra. In<br />
generale conviene verificare prima di utilizzarlo, per conoscere le possibilità effettive.<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
FreeDOS<br />
Capitolo 363<br />
FreeDOS è il nome di un progetto per la realizzazione di un sistema operativo libero compatibile<br />
con il Dos. Il Dos, per quanto limitato, ha delle caratteristiche che lo possono rendere ancora<br />
interessante per elaboratori con architettura i86 particolarmente poveri di risorse, come nel caso<br />
dei sistemi cosiddetti embedded.<br />
363.1 Installazione<br />
L’installazione della distribuzione standard di FreeDOS è abbastanza semplice. Si parte da un dischetto<br />
di avvio, con il quale si predispone la partizione e la si inizializza, quindi si prosegue con<br />
il programma di installazione che chiede l’inserimento dei dischetti successivi. La riproduzione<br />
del dischetto di avvio a partire dalla sua immagine avviene come al solito attraverso il programma<br />
‘RAWRITE.EXE’, oppure per mezzo di un sistema Unix nei modi già mostrati per GNU/Linux<br />
e altri sistemi simili.<br />
C:\>RAWRITE FULL.BIN A:<br />
L’esempio mostra l’uso di ‘RAWRITE.EXE’ per ottenere un dischetto dall’immagine<br />
rappresentata dal file ‘FULL.BIN’.<br />
La distribuzione standard di FreeDOS si compone di un file-immagine del dischetto di avvio,<br />
che potrebbe chiamarsi ‘FULL.BIN’, e da una serie di file con estensione ‘.ZIP’ che servono<br />
per ottenere i dischetti successivi. Ognuno di questi file compressi rappresenta il contenuto di un<br />
dischetto, che quindi deve essere prima estratto:<br />
C:\>A:<br />
A:\>UNZIP C:\TMP\BASE1.ZIP<br />
L’esempio mostra in breve il procedimento: ci si sposta nell’unità ‘A:’ e da lì si estrae il file<br />
compresso che probabilmente si trova da qualche parte nel disco fisso.<br />
Questi file compressi rappresentano una raccolta di applicativi e hanno una struttura particolare<br />
che viene descritta nel seguito.<br />
• nome_raccolta.1<br />
L’archivio compresso deve contenere un file che rappresenta il nome della raccolta, con<br />
un’estensione numerica. La raccolta potrebbe essere suddivisa in più archivi ed è per questo<br />
che si usa l’estensione numerica, che indica il numero di sequenza dell’archivio nell’ambito<br />
della raccolta.<br />
Il file contiene l’elenco dei pacchetti contenuti, con l’indicazione dell’opzione di installazione<br />
predefinita o meno. Si osservi l’estratto seguente (la lettera «Y» rappresenta la<br />
conferma all’installazione predefinita):<br />
asgn14x: Y<br />
attr063x: Y<br />
bwb210x: Y<br />
choic20x: Y<br />
• nome_raccolta.END<br />
Si tratta di un file vuoto, che rappresenta la conclusione della raccolta, nel senso che non ci<br />
sono altri dischetti ulteriori.<br />
123
124 volume VIII Argomenti avanzati e accessori<br />
• nome_pacchetto.LSM<br />
Si tratta di un file che descrive un pacchetto applicativo. Quello che segue è l’esempio del<br />
contenuto del file ‘DELTR10X.LSM’:<br />
Begin3<br />
Title: deltree<br />
Version: 1.02b<br />
Entered-date: 27 Jul 1999<br />
Description: Delete a directory and all directories under it<br />
Keywords: freedos delete<br />
Author: raster@highfiber.com<br />
Maintained-by: raster@highfiber.com<br />
Primary-site: http://www.highfiber.com/~raster/freeware.htm<br />
Alternate-site: www.freedos.org<br />
Original-site: http://www.highfiber.com/~raster/freeware.htm<br />
Platforms: dos<br />
Copying-policy: GPL<br />
End<br />
• nome_pacchetto.ZIP<br />
Si tratta dell’archivio compresso che contiene i file dell’applicativo. In base alla struttura<br />
standard di FreeDOS, potrebbe distribuirsi nelle directory ‘BIN\’, ‘DOC\’ e ‘HELP\’.<br />
Dopo aver preparato i dischetti, si può procedere con l’avvio del sistema attraverso il dischetto<br />
di avvio; quindi si passa a predisporre la partizione:<br />
A:\>FDISK<br />
Purtroppo, il kernel di FreeDOS non è in grado di gestire partizioni più grandi di 512 Mibyte,<br />
per cui occorre tenerne conto durante l’uso di ‘FDISK’. Dopo aver preparato la partizione la si<br />
inizializza:<br />
A:\>FORMAT C: /U<br />
Successivamente si trasferisce il sistema, con il comando ‘SYS’:<br />
A:\>SYS C:<br />
Infine si avvia il programma di installazione che provvederà a chiedere la sostituzione dei<br />
dischetti:<br />
A:\>INSTALL<br />
363.2 Impostazione e configurazione<br />
Da quanto è stato descritto sull’installazione di FreeDOS si intende che, pur trattandosi di un<br />
sistema Dos, si cerca di introdurre qualche buona idea proveniente da Unix. In particolare, è<br />
prevista una struttura per la collocazione dei file:<br />
• ‘BIN\’ per contenere i file eseguibili;<br />
• ‘DOC\’ per contenere la documentazione che si articola in altre sottodirectory successive,<br />
come avviene con GNU/Linux<br />
• ‘HELP\’ per contenere i file della guida interna relativa.
FreeDOS 125<br />
Questa struttura potrebbe essere collocata anche a partire da un punto differente della radice<br />
dell’unità, in base alle scelte fatte in fase di installazione. In ogni caso, occorre poi predisporre<br />
coerentemente alcune variabili di ambiente: ‘PAGER’ per indicare il programma da utilizzare per<br />
lo scorrimento dei file delle guide; ‘HELPPATH’ per indicare la directory contenente i file delle<br />
guide; ‘EMACS’ per indicare la directory contenente i file di Emacs.<br />
In condizioni normali, gli applicativi FreeDOS vengono installati a partire dalla directory<br />
‘\FDOS\’, per cui la configurazione si traduce nelle istruzioni seguenti nel file ‘AUTOEXEC.BAT’:<br />
SET PAGER=MORE<br />
SET HELPPATH=C:\FDOS\HELP<br />
SET EMACS=C:\FDOS\EMACS\<br />
In base alla documentazione originale, nel caso della variabile di ambiente ‘EMACS’ deve essere<br />
indicata la barra obliqua inversa finale.<br />
A seconda della distribuzione di FreeDOS, può darsi che il file ‘CONFIG.SYS’ debba essere<br />
sostituito con uno avente un nome differente. Potrebbe trattarsi del file ‘FDCONFIG.SYS’.<br />
363.3 RxDOS<br />
RxDOS è un altro progetto analogo a FreeDOS, scritto in maniera indipendente. È provvisto di<br />
un proprio interprete dei comandi e non ha ancora un suo sistema di installazione. Per provare il<br />
funzionamento di RxDOS ci si può avvalere solo di un dischetto, realizzato nel modo seguente:<br />
1. si inizializza il dischetto in qualche modo, assicurando che alla fine sia disponibile un<br />
file system Dos-FAT; 1<br />
2. si esegue lo script ‘MAKEBOOT.BAT’, il cui scopo è la predisposizione del settore di avvio<br />
nel dischetto;<br />
3. si copiano ordinatamente nel dischetto i file elencati qui sotto.<br />
• ‘RXDOSBIO.SYS’<br />
• ‘RXDOS.SYS’<br />
• ‘RXDOSCMD.EXE’<br />
• ‘RXDVDISK.SYS’<br />
• ‘AUTOEXEC.DEF’<br />
• ‘CONFIG.DEF’<br />
363.4 Riferimenti<br />
• FreeDOS<br />
<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org<br />
1 Il dischetto non deve avere l’etichetta, ovvero non deve avere un nome.
Progetto GNUish<br />
Capitolo 364<br />
Il progetto «GNUish» è una sorta di derivazione povera del progetto GNU, con lo scopo di<br />
rendere disponibile parte del s<strong>of</strong>tware che compone il sistema GNU anche nei sistemi Dos. Il<br />
progetto ha un’importanza molto piccola, ma viene ancora mantenuto. Evidentemente, date le<br />
peculiarità dei sistemi Dos, il s<strong>of</strong>tware che viene adattato non può avere le stesse potenzialità che<br />
ha invece in un sistema Unix.<br />
I siti principali da cui si può ottenere copia del materiale prodotto dal progetto GNUish sono<br />
quelli elencati all’interno dal documento seguente:<br />
• <br />
In questo capitolo viene mostrato il funzionamento di alcuni programmi, nell’ambito del sistema<br />
Dos, per i quali è il caso di spendere qualche parola.<br />
364.1 Programmi di servizio vari<br />
Molti dei programmi di servizio del progetto GNU sono disponibili anche per Dos. Tuttavia, è il<br />
caso di osservare alcune particolarità che possono confondere chi è abituato a usare sistemi Dos.<br />
La prima cosa da notare è il fatto che i percorsi si possono indicare secondo lo stile Unix,<br />
utilizzando barre oblique normali. Per esempio:<br />
C:\>MV C:/PRIMO/SECONDO C:/TERZO<br />
Diversamente, utilizzando lo stesso comando, ma secondo l’indicazione tipica del Dos, la cosa<br />
può funzionare ugualmente, oppure si possono presentare delle segnalazioni di errore. Bisogna<br />
tenere presente la possibilità.<br />
Un’altra cosa da notare è l’uso dei caratteri jolly, che con questi programmi segue la logica<br />
di Unix, dove l’asterisco indica qualunque nome, senza trattare in modo speciale il punto di<br />
separazione dell’estensione:<br />
C:\>CP C:/PRIMO/SECONDO/* C:/TERZO<br />
L’esempio mostra proprio questo fatto: vengono copiati tutti i file contenuti nella directory ‘C:\<br />
PRIMO\SECONDO\’, nella directory ‘C:\TERZO\’.<br />
364.2 Gnuplot<br />
Il funzionamento generale di Gnuplot è descritto nel capitolo 337. Per funzionare, questa edizione<br />
di Gnuplot richiede due file: ‘GNUPLOT.EXE’ e ‘GNUPLOT.GIH’. Il primo dei due è l’eseguibile in<br />
grado di gestire la grafica VGA, mentre il secondo contiene le informazioni della guida interna.<br />
Se si vuole accedere alla guida interna, è necessario che il file ‘GNUPLOT.GIH’ si trovi nella<br />
directory corrente. Forse è sufficiente utilizzare il comando ‘APPEND’ del Dos per risolvere il<br />
problema.<br />
126
Progetto GNUish 127<br />
364.3 Spreadsheet Calculator<br />
Il funzionamento generale di SC (Spreadsheet Calculator) è descritto nel capitolo 336. La versione<br />
per Dos funziona correttamente (è sufficiente disporre dell’eseguibile ‘SC.EXE’), riconoscendo<br />
anche l’uso dei tasti freccia, per cui non si è più costretti a utilizzare le lettere ‘h’, ‘j’, ‘k’ e<br />
‘l’.<br />
364.4 Ispell<br />
Ispell è descritto in generale nel capitolo 273. Questa edizione di Ispell richiede due file:<br />
‘ISPELL.EXE’ e ‘ISPELL.DIC’. Come si intuisce, il primo è l’eseguibile, mentre il secondo<br />
è il file del dizionario. Purtroppo, il file ‘ISPELL.DIC’ non è sostituibile o eliminabile; l’unica<br />
cosa che si può fare è predisporre un dizionario personalizzato che si richiama con l’opzione<br />
‘-p’.<br />
ISPELL [-d dizionario_standard] [-p dizionario_personale] file<br />
Quella che si vede è la sintassi essenziale su cui si può contare nell’edizione di Ispell per Dos. Il<br />
file del dizionario standard, ‘ISPELL.DIC’, può essere collocato nella stessa directory in cui si<br />
trova il file eseguibile; altrimenti si deve usare l’opzione ‘-d’ per indicarlo esplicitamente.<br />
Il dizionario personale è un file di testo normale (Dos), che può anche essere creato inizialmente<br />
dallo stesso Ispell. L’esempio seguente, mostra il caso in cui si voglia analizzare il file<br />
‘LETTERA.TXT’ attraverso il dizionario standard e il dizionario personale ‘VOCAB.TXT’. Se il<br />
file ‘VOCAB.TXT’ non dovesse esistere, verrebbe creato per l’occasione.<br />
C:\LETTERE>ISPELL -p VOCAB.TXT LETTERA.TXT<br />
364.5 Perl<br />
Perl è un linguaggio di programmazione descritto in generale a partire dal capitolo 299. L’edizione<br />
Dos dell’interprete Perl richiede due file: ‘PERL.EXE’ e ‘PERLGLOB.EXE’. È sufficiente che<br />
questi siano disponibili nei percorsi degli eseguibili della variabile di ambiente ‘PATH’.<br />
Bisogna tenere a mente che si tratta di una versione molto vecchia del linguaggio, per cui alcune<br />
novità non saranno disponibili. Inoltre, l’avvio dei programmi può avvenire solo richiamando<br />
direttamente l’interprete:<br />
C:\ESERCIZI>PERL FATT.PL 5<br />
L’esempio mostra l’avvio del programma Perl contenuto nel file ‘FATT.PL’, che riceve un<br />
argomento costituito dal numero cinque.<br />
364.6 Riferimenti<br />
• François Pinard, GNUish MSDOS Project<br />
<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
The valuable DOS Freeware page<br />
Links to valuable free Dos programs working on low equipped computers.<br />
Chapter 365<br />
This material appeared originally at ‘http://www.geocities.com/SiliconValley/<br />
7737/’, in 1996. Now it is incorporated inside the Italian document ‘‘Appunti<br />
di informatica libera’’, and it might be reached at the URI .<br />
Questo materiale è apparso in origine, nel 1996, presso ‘http://www.geocities.com/<br />
SiliconValley/7737/’. Adesso viene incorporato nel documento «Appunti di<br />
informatica libera» e può essere raggiunto attraverso l’URI . L’intento dell’autore è solo quello di continuare a curare<br />
un vecchio lavoro che potrebbe essere ancora utile, nonostante si tratti di riferimenti a<br />
s<strong>of</strong>tware in parte libero e in parte solo gratuito, oltre che evidentemente obsoleto.<br />
365.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />
365.2 OS and GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
365.3 Utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
365.4 Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />
365.5 Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132<br />
365.6 Typesetting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132<br />
365.7 More Dos s<strong>of</strong>tware sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />
365.8 Search engines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />
365.1 Introduction<br />
The Dos operating system meant much for many people. Today, proprietary Dos-like operating<br />
systems seem to be no more developed. In this situation, the only possible future for Dos is the<br />
‘‘free’’ s<strong>of</strong>tware, and it is not just a matter <strong>of</strong> money anymore.<br />
Unfortunately, ‘‘free’’ is a word with many meanings. Today, this is still the biggest obstacle to<br />
the future <strong>of</strong> the Dos world. There is so much s<strong>of</strong>tware for Dos, with so many different license<br />
agreements. The typical Dos user doesn’t mind to it. But this problem prevents the realization <strong>of</strong><br />
big serious projects based on it.<br />
Today, the Dos world needs philosophy, and the GNU idea is still the right one ().<br />
The author <strong>of</strong> this space would like to list here only ‘‘free s<strong>of</strong>tware’’ in the sense stated by the<br />
Free S<strong>of</strong>tware Foundation, but it is impossible, as there isn’t enough good real free s<strong>of</strong>tware for<br />
Dos.<br />
The listed s<strong>of</strong>tware is meant to work on i286 and below.<br />
It is attempted to give some kind <strong>of</strong> classification about the legal condition <strong>of</strong> the s<strong>of</strong>tware presented<br />
here. The definition used might be outdated, or there might be other wrong assumption.<br />
128
The valuable DOS Freeware page 129<br />
In particular, the definition ‘‘public domain’’ means here, in most cases, that there is the source,<br />
but there is no clear license statement.<br />
Beside the URI links <strong>of</strong> some FTP services there is an additional ‘‘search link’’ that queries a<br />
FTP search engine for the same file. These additional links should be used when there are troubles<br />
with the main links.<br />
Anyone can link this document anywhere, so, there is no need to ask for it. Anyway, it is better to<br />
link to this document using at the file name .<br />
In the future, many links may disappear on this page, because <strong>of</strong> more selective choices<br />
concerning s<strong>of</strong>tware license.<br />
365.2 OS and GUI<br />
• FreeDOS 1 <br />
• FreeGEM 2 <br />
365.3 Utility<br />
archive, backup<br />
• Gzip 3 - ‘.GZ’ archive compressor and extractor. <br />
• TAR 4 - portable TAR - DOS/UNIX backup, compressor, with hardware<br />
support. <br />
• Untgz 5 - ‘.TGZ’, ‘.TAR’, ‘.GZ’, ‘.ZIP’ file extractor. <br />
• Info-ZIP 6 - ‘.ZIP’ compatible compression and extraction utility. <br />
<br />
• Restaur 7 - Replacement for Dos Restore, <br />
communication<br />
• DosFax 8 - Send a fax using Dos command line <br />
• Bgfax 9 <br />
• Rifs 10 - Disk sharing over a serial line, <br />
<br />
1<br />
FreeDOS GNU GPL<br />
2<br />
FreeGEM GNU GPL<br />
3<br />
Gzip GNU GPL<br />
4<br />
TAR (Dos) public domain<br />
5<br />
Untgz GNU GPL<br />
6<br />
Info-ZIP free s<strong>of</strong>tware with special license<br />
7<br />
Restaur cannot be sold for pr<strong>of</strong>it<br />
8<br />
DosFax public domain<br />
9<br />
Bgfax promised to become free s<strong>of</strong>tware<br />
10<br />
Rifs cannot be sold for pr<strong>of</strong>it
130 volume VIII Argomenti avanzati e accessori<br />
directory, file<br />
disk<br />
help<br />
shell<br />
system<br />
text<br />
See also:<br />
• WCD 11 - Powerful chdir for Dos and Unix <br />
• Fips 12 - Non-destructive splitting <strong>of</strong> hard disk partitions <br />
• Part 13 - MBR partition manager <br />
• NG_clone 14 - Norton Guides clone <br />
<br />
• DC 15 - The Dos Controller - A Norton Commander clone <br />
• Cmos 16 - Save/Restore extended C/MOS <br />
• KGB 17 - Utility to monitor some Dos functions and reporting into a<br />
log file <br />
• Vim 18 - VI improved, a small text editor that can handle very big files with low<br />
RAM <br />
• Richard L. Green, Free s<strong>of</strong>tware for Dos<br />
<br />
365.4 Network<br />
packet driver<br />
11<br />
WCD GNU GPL<br />
12<br />
Fips GNU GPL<br />
13<br />
Part public domain<br />
14<br />
NG_clone public domain<br />
15<br />
DC public domain (no license at all, and no sources)<br />
16<br />
Cmos public domain<br />
17<br />
KGB public domain<br />
18<br />
Vim free s<strong>of</strong>tware with special license
The valuable DOS Freeware page 131<br />
TCP/IP<br />
See also:<br />
• PC/TCP Packet Driver Collection 19 <br />
• WATTCP 20 - TCP/IP library routines <br />
• DOS PPPD 21 - Dos port <strong>of</strong> Linux PPP packet driver <br />
• Comring 22 - packet driver emulating ethernet over serial link(s) <br />
• WATTCP apps 23 - some common client application using WATTCP library <br />
• MiniTelnet 24 - TELNET client <br />
• Bobcat 25 - Text based web browser (derived<br />
from DosLynx, )<br />
• PCroute 26 - IP routing program for IBM PC <br />
• PPRD 27 - Turn a dedicated PC (XT/AT) into a LPD server <br />
<br />
• NCSA Telnet 28 - Telnet, Ftp,... NCSA <br />
<br />
• NOS (KA9Q) 29 - A complete mini TCP/IP system <br />
To use NOS you need documentation, for example the package <br />
• SSHDOS 30 - SSH client for Dos <br />
• Talk 31 - Talk client for Dos <br />
• ABC-nslookup 32 - DNS query clients for Dos <br />
• Marc S. Ressl, Dos Internet Pages<br />
<br />
• Smash-Co Communications, TCP/IP for MS-DOS<br />
<br />
19<br />
Crynwr packet driver collection GNU GPL<br />
20<br />
WATTCP free <strong>of</strong> charge library<br />
21<br />
DOS PPPD mixed licenses<br />
22<br />
Comring GNU GPL<br />
23<br />
WATTCP apps cannot be sold<br />
24<br />
MiniTelnet free s<strong>of</strong>tware with a special license<br />
25<br />
Bobcat GNU GPL<br />
26<br />
PCroute cannot distribute modifications<br />
27<br />
PPRD s<strong>of</strong>tware non libero: licenza Artistic<br />
28<br />
NCSA Telnet public domain<br />
29<br />
NOS public domain<br />
30<br />
SSHDOS GNU GPL<br />
31<br />
Talk GNU GPL<br />
32<br />
ABC-nslookup UCB BSD
132 volume VIII Argomenti avanzati e accessori<br />
• The U-M S<strong>of</strong>tware Archive<br />
<br />
<br />
365.5 Compilers<br />
assembler<br />
batch<br />
C/C++<br />
Perl<br />
Rexx<br />
xBase<br />
See also:<br />
See the FreeDOS project () for assembler compilers.<br />
• BAT2EXE 33 - Compile batch files for speed <br />
See the FreeDOS project () for C and C++ compilers.<br />
Perl 34 - Practical Extraction Report Language <br />
• BREXX 35 - Rexx interpreter for Dos/Unix <br />
• nanoBase 36 - Mini, but nearly complete xBase <br />
• David Muir Sham<strong>of</strong>f, Catalog <strong>of</strong> free compilers and interpreters<br />
<br />
365.6 Typesetting<br />
• Nro 37 - A Nr<strong>of</strong>f implementation for Dos <br />
<br />
• Ghostscript 38 - ‘‘GNU’’ original edition - PostScript previewing, conversion, and printing<br />
<br />
• emTeX 39 - TeX-LaTeX distribution for Dos <br />
33 BAT2EXE public domain<br />
34 Perl GNU GPL or Artistic<br />
35 BREXX public domain<br />
36 nanoBase GNU GPL<br />
37 Nro public domain<br />
38 Ghostscript GNU GPL<br />
39 emTeX LPPL but some files have different conditions
The valuable DOS Freeware page 133<br />
365.7 More Dos s<strong>of</strong>tware sources<br />
• <br />
• <br />
365.8 Search engines<br />
• <br />
• <br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Clean the Clipper 5.2<br />
Chapter 366<br />
A different way to program using Clipper 5.2 without commands, that is, without the file<br />
‘STD.CH’.<br />
This material appeared originally at ‘http://www.geocities.com/SiliconValley/<br />
7737/clipper52clean.html’, in 1996. Now it is incorporated inside the Italian document<br />
‘‘Appunti di informatica libera’’, and might be reached at the URI .<br />
Questo materiale è apparso in origine, nel 1996, presso ‘http://www.geocities.com/<br />
SiliconValley/7737/clipper52clean.html’. Adesso viene incorporato nel documento<br />
«Appunti di informatica libera» e può essere raggiunto attraverso l’URI . L’intento dell’autore è solo quello di conservare un<br />
vecchio lavoro che potrebbe essere ancora utile, nonostante si tratti di considerazioni su un<br />
compilatore proprietario, ormai obsoleto.<br />
366.1 Step 1: try to compile with the /P parameter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135<br />
366.2 Step 2: understand well the use <strong>of</strong> code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .136<br />
366.3 Step 3: understand the object programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />
366.3.1 Classes and methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .137<br />
366.3.2 Class definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />
366.3.3 Object creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .137<br />
366.3.4 Instantiating an object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />
366.3.5 The ‘‘send’’ symbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />
366.3.6 More about objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />
366.4 Step 4: understand the get object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />
366.5 Step 5: trying to stop using commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />
366.5.1 ?/?? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />
366.5.2 @...BOX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />
366.5.3 @...GET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141<br />
366.5.4 @...SAY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />
366.5.5 @...TO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />
366.5.6 APPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />
366.5.7 APPEND FROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />
366.5.8 CLEAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />
366.5.9 CLOSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />
366.5.10 COMMIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />
366.5.11 CONTINUE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />
366.5.12 COPY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />
366.5.13 COUNT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143<br />
366.5.14 CREATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />
134
Clean the Clipper 5.2 135<br />
366.5.15 DEFAULT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144<br />
366.5.16 DELETE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />
366.5.17 EJECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />
366.5.18 ERASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />
366.5.19 FIND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />
366.5.20 GO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />
366.5.21 INDEX ON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />
366.5.22 JOIN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145<br />
366.5.23 KEYBOARD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145<br />
366.5.24 LABEL FORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145<br />
366.5.25 LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .145<br />
366.5.26 LOCATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145<br />
366.5.27 PACK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146<br />
366.5.28 QUIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146<br />
366.5.29 READ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146<br />
366.5.30 RECALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146<br />
366.5.31 REINDEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146<br />
366.5.32 RELEASE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146<br />
366.5.33 RENAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />
366.5.34 REPLACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />
366.5.35 REPORT FORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />
366.5.36 RESTORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />
366.5.37 RESTORE FROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />
366.5.38 RUN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147<br />
366.5.39 SAVE SCREEN TO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />
366.5.40 SAVE TO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />
366.5.41 SEEK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />
366.5.42 SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />
366.5.43 SET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />
366.5.44 SKIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.45 SORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.46 STORE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.47 SUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.48 TOTAL ON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.49 UNLOCK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.50 UPDATE FROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.51 USE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152<br />
366.5.52 ZAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153<br />
366.6 Step 6: free yourself from STD.CH - /U . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153<br />
366.7 Step 7: take control over all include files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
136 volume VIII Argomenti avanzati e accessori<br />
Clipper 5.2, as the xBase tradition imposes, is not an ordered, clear, simple programming language.<br />
The question is: which is the right way to write a Clipper program? If the intention is not<br />
to make a xBase program, but a Clipper program, maybe it can be decided that it is better to use<br />
Clipper without commands.<br />
366.1 Step 1: try to compile with the /P parameter<br />
Supposing to compile the file ‘TEST.PRG’ this way:<br />
C:\>CLIPPER TEST.PRG /P<br />
It generates a preprocessed output file (‘test.PPO’), that is a source file without comments,<br />
where commands are translated into real Clipper instructions. That is, all the ‘#COMMAND’ substitution<br />
are executed and the translation is sent to the ‘.PPO’ file. It may be difficult to read this<br />
file the first time.<br />
366.2 Step 2: understand well the use <strong>of</strong> code blocks<br />
The code block is a small piece <strong>of</strong> executable program code that can be stored inside a variable,<br />
or can be used as a literal constant. The good <strong>of</strong> it, is that pieces <strong>of</strong> code may be sent to functions.<br />
A code block is something like a little user defined function where only a sequence <strong>of</strong> expressions<br />
(functions and/or assignments) may appear: no loops, no conditional structures.<br />
A code block may receive arguments and return a value after execution, just like a function. The<br />
syntax is the following, where curly brackets are part <strong>of</strong> the code block:<br />
{ | [argument_list] | exp_list }<br />
That is: the argument_list is optional; the exp_list may contain one or more expressions separated<br />
with a comma.<br />
For example, calling the following code block will give the string ‘‘hello world’’ as result.<br />
{ || "hello world" }<br />
The following code block requires a numeric argument and returns the number passed as argument<br />
incremented:<br />
{ | n | n+1 }<br />
The following code block requires two numeric arguments and returns the sum <strong>of</strong> the two square<br />
radix:<br />
{ | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }<br />
But code blocks may contain more expressions and the result <strong>of</strong> the execution <strong>of</strong> the code block<br />
is the result <strong>of</strong> the last expression. The following code block executes in sequence some functions<br />
and gives ‘‘hello world’’ as a result.<br />
{ | a, b | functionOne(a), functionTwo(b), "hello world" }<br />
To start the execution <strong>of</strong> a code block a function is used: ‘EVAL()’. For example, a code block is<br />
assigned to a variable and then executed.<br />
B := { || "hello world" }<br />
EVAL( B ) == "hello world"
Clean the Clipper 5.2 137<br />
Another example with one parameter.<br />
B := { | n | n+1 }<br />
EVAL( B, 1 ) == 2<br />
Another example with two parameters.<br />
B := { | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }<br />
EVAL( B, 2, 4 ) == 20<br />
And so on.<br />
366.3 Step 3: understand the object programming<br />
Clipper 5.2 do not permit to create objects, but it gives some good objects to use: ‘GET’ and<br />
‘TBROWSE’. Before starting to clean programming from commands, it is necessary to understand<br />
how to use well the Clipper objects.<br />
366.3.1 Classes and methods<br />
A class defines the structure <strong>of</strong> a ‘‘black box’’, that is a data container; a method is an action<br />
to make on a piece <strong>of</strong> data contained inside the black box. There is no way to reach the data<br />
contained inside the black box without a method.<br />
The black box can be called object.<br />
The methods may be seen as they where special functions which interact with a specific piece <strong>of</strong><br />
data contained inside the object.<br />
366.3.2 Class definition<br />
Supposing that Clipper permits to define classes (unluckily only predefined classes can be used),<br />
the hypothetical syntax could be:<br />
CLASS ClassName [FROM ParentClass]<br />
VAR Var1 [,Var2[,...VarN]]<br />
METHOD {method_definition_1} [, ...{method_definition_n} ]<br />
ENDCLASS<br />
This way, the class defines a group <strong>of</strong> variables and a group <strong>of</strong> method to use with these variables.<br />
366.3.3 Object creation<br />
The presence <strong>of</strong> classes permits to create objects: the black boxes.<br />
Variable_name := ClassName<br />
This way, a variable contains (is) an object. Please note that inside Clipper, an object may be<br />
generated also from a function, that is, a function can return an object. This way the example can<br />
be:<br />
Variable_name := classfunction( ... )<br />
The next problem is to handle this object.
138 volume VIII Argomenti avanzati e accessori<br />
366.3.4 Instantiating an object<br />
As already stated before, methods are used to handle data contained inside an object. This is said<br />
to be instantiating an object. Clipper permits also to handle directly (apparently without methods)<br />
some variables contained inside objects. These are called ‘‘Exported Instance Variables’’. So, an<br />
object can be instantiated this way:<br />
object:exported_instance_variable := new_value<br />
object:method()<br />
An exported instance variable may be read and/or modified depending on the allowed access to it;<br />
a method, inside Clipper, is something like a function with or without parameters (if parameters<br />
are present, these are usually used to modify data inside the object), that normally returns a value.<br />
366.3.5 The ‘‘send’’ symbol<br />
To instantiate an object or simply to access an exported instance variable, the ‘‘send’’ symbol<br />
(colon) is used.<br />
366.3.6 More about objects<br />
If this is not enough to understand objects inside Clipper, the following document should be read:<br />
Peter M. Freese, o:Clip - An Object Oriented Extension to Clipper 5.01 1991, CyberS<strong>of</strong>t<br />
<br />
366.4 Step 4: understand the get object<br />
What happens with a command like the following:<br />
@ nTop, nLeft GET Var<br />
A get object is created containing all the necessary information for editing the variable Var at<br />
the screen position nTop, nLeft. After that, this get object is added to a get objects array (usually<br />
called ‘GetList’). The get objects array will contain all the get objects used during a ‘READ’.<br />
So, what happens when a ‘READ’ command is encountered. The get objects array (‘GetList’) is<br />
read and the editing <strong>of</strong> all get objects is executed. After that, the get objects array is cleared.<br />
This method hides what Clipper really makes. The suggestion here is to create a ‘GET()’ function<br />
that will substitute the ‘@...GET’ command and to use the ‘READMODAL()’ function to read the get<br />
objects array. Here is an example <strong>of</strong> it:<br />
function GET( aoGet, nRow, nCol, bVar, cGetPicture,<br />
cColorString, bPreValid, bPostValid )<br />
// declare a local get object<br />
local oGet<br />
// create the get object using the function GETENV()<br />
oGet := GETENV( nRow, nCol, bVar, NIL, cGetPicture, cGetColor )<br />
// send to the get object the pre-validation condition code block (WHEN)<br />
oGet:preBlock := bPreValid
Clean the Clipper 5.2 139<br />
// send to the get object the post-validation condition code block (VALID)<br />
oGet:postBlock := bPostValid<br />
// display the get on the screen using the display() method<br />
oGet:display()<br />
// add the get object to the get objects array<br />
AADD( aoGet, oGet )<br />
return NIL<br />
• ‘aoGet’ is the get objects array (so here is explicitly passed). This get objects array is<br />
modified (grown) and there is no need to return it as inside Clipper, arrays are always<br />
passed by reference to functions.<br />
• ‘nRow’ and ‘nCol’ are the screen coordinates where the get field should appear at, as it<br />
works with the ‘@...GET’ command.<br />
• ‘bVar’ is a special code block that permits the editing <strong>of</strong> a variable. If the variable ‘Var’ is<br />
to be edited, the code block is:<br />
{ |x| iif( pcount() > 0, Var := x, Var }<br />
• ‘cGetPicture’ is the picture to use: same as the ‘@...GET’ command.<br />
• ‘cColorString’ is the color string to use: same as the ‘@...GET’ command.<br />
• ‘bPreValid’ is a code block containing the condition that must be valid before the cursor<br />
can reach this get field. It is equivalent to the ‘WHEN’ condition used with the ‘@...GET’<br />
command, but it must be converted into a code block. For example, if the condition is<br />
‘A > B’, the code block is ‘{|| A > B}’<br />
• ‘bPostValid’ is a code block containing the condition that must be valid before the cursor<br />
can leave this get field. It is equivalent to the ‘VALID’ condition used with the ‘@...GET’<br />
command, but it must be converted into a code block. For example, if the condition is<br />
‘A > B’, the code block is ‘{|| A > B}’<br />
If there is a get function like the above one, screen I/O may be performed like the following<br />
example:<br />
function do_some_editing()<br />
// define a variable to use as a get objects array<br />
// and initialise it to the empty array<br />
local aoGet := {}<br />
...<br />
...<br />
// add a new get object to the get objects array<br />
get(;<br />
aoGet,;<br />
10, 10,;<br />
{ |x| iif( pcount() > 0, myVariable := x, myVariable },;<br />
"@s30@",;<br />
"gb+/b, n/w, n, n, w/n",;<br />
{ || .T. },;<br />
{ || .T. };<br />
)
140 volume VIII Argomenti avanzati e accessori<br />
...<br />
// read the get objects array<br />
readmodal( aoGet )<br />
// clear the get objects array<br />
aoGet := {}<br />
...<br />
return ...<br />
If the function ‘GET()’ is not liked, the above I/O may be done as it follows:<br />
function do_some_editing()<br />
// define a variable to use as a get object<br />
local aoGet<br />
// define a variable to use as a get objects array<br />
// and initialise it to the empty array<br />
local aoGet := {}<br />
...<br />
...<br />
// add a new get object to the get objects array<br />
oGet :=;<br />
GETENV(;<br />
10, 10,;<br />
{ |x| iif( pcount() > 0, myVariable := x, myVariable },;<br />
NIL,;<br />
"@s30@",;<br />
"gb+/b, n/w, n, n, w/n",;<br />
)<br />
AADD( aoGet, oGet )<br />
...<br />
// read the get objects array<br />
readmodal( aoGet )<br />
// clear the get objects array<br />
aoGet := {}<br />
...<br />
return ...<br />
366.5 Step 5: trying to stop using commands<br />
To stop using commands, it is important to understand how commands are or may be translated<br />
into functions. Sometimes Clipper uses some undocumented functions: these are functions that<br />
start with a underline.
Clean the Clipper 5.2 141<br />
366.5.1 ?/??<br />
? [exp_list]<br />
qout([exp_list])<br />
?? [exp_list]<br />
qqout([exp_list])<br />
366.5.2 @...BOX<br />
@ nTop, nLeft, nBottom, nRight BOX cnBoxString [COLOR cColorString]<br />
dispbox(nTop, nLeft, nBottom, nRight, [cnBoxString], [cColorString])<br />
366.5.3 @...GET<br />
@ nTop, nLeft GET Var [PICTURE cGetPicture] [COLOR cColorString] [WHEN lPreExpression] ←↪<br />
↩→[VALID lPostExpression]<br />
setpos(nTop, nLeft)<br />
aadd( GetList, _GET_( Var, "Var", cGetPicture, [{|| lPostExpression}],←↪<br />
↩→[{|| lPreExpression}] ):display() ) atail(GetList):colorDisp(cColorString)<br />
This is the command substitution made automatically, but it shouldn’t be used to make clean<br />
programs. The step 4 (366.1) suggests to create a get function.<br />
366.5.4 @...SAY<br />
@ nTop, nLeft SAY exp [COLOR cColorString]<br />
devpos(nTop, nLeft)<br />
devout(exp [, cColorString])<br />
@ nTop, nLeft SAY exp PICTURE cSayPicture [COLOR cColorString]<br />
devpos(nTop, nLeft)<br />
devoutpic(exp, cSayPicture, [cColorString])<br />
366.5.5 @...TO<br />
@ nTop, nLeft TO nBottom, nRight DOUBLE [COLOR cColorString]<br />
dispbox(nTop, nLeft, nBottom, nRight, 2 [,cColorString])<br />
@ nTop, nLeft TO nBottom, nRight [COLOR cColorString]<br />
dispbox(nTop, nLeft, nBottom, nRight, 1 [,cColorString])<br />
@ nTop, nLeft CLEAR [TO nBottom, nRight]<br />
scroll([nTop], [nLeft], [nBottom, nRight])<br />
setpos(nRow, nCol)
142 volume VIII Argomenti avanzati e accessori<br />
366.5.6 APPEND<br />
APPEND BLANK<br />
dbappend()<br />
366.5.7 APPEND FROM<br />
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition]←↪<br />
↩→[FOR lCondition] [VIA xcDriver]<br />
__dbApp( cFileName, [acFields], [bForCondition], [bWhileCondition], [nNextRecords],←↪<br />
↩→[nRecord], [lRest], [cDriver] )<br />
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition] [FOR lCondition]←↪<br />
↩→DELIMITED xcDelimiter<br />
__dbDelim( .f., cFileName, [cDelimiter], [acFields], [bForCondition], [bWhileCondition]<br />
,←↪<br />
↩→[nNextRecords], [nRecord], [lRest] )<br />
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition]←↪<br />
↩→[FOR lCondition] SDF<br />
__dbSDF( .f., cFileName, [acFields], [bForCondition], [bWhileCondition], [nNextRecords]<br />
,←↪<br />
↩→[nRecord], [lRest] )<br />
366.5.8 CLEAR<br />
CLEAR<br />
Scroll()<br />
SetPos(0,0)<br />
ReadKill(.T.)<br />
GetList := {}<br />
CLEAR GETS<br />
ReadKill(.T.)<br />
GetList := {}<br />
CLEAR SCREEN | CLS<br />
Scroll()<br />
SetPos(0,0)<br />
366.5.9 CLOSE<br />
CLOSE<br />
dbCloseArea()<br />
CLOSE idAlias<br />
idAlias->( dbCloseArea() )<br />
CLOSE ALTERNATE<br />
Set(19, "")<br />
CLOSE DATABASES<br />
dbCloseAll()<br />
CLOSE INDEXES<br />
dbClear<strong>Index</strong>()
Clean the Clipper 5.2 143<br />
366.5.10 COMMIT<br />
COMMIT<br />
dbCommitAll()<br />
366.5.11 CONTINUE<br />
CONTINUE<br />
__dbContinue()<br />
366.5.12 COPY<br />
COPY FILE xcSourceFile TO xcTargetFile|xcDevice<br />
__CopyFile( cSourceFile, cTargetFile|cDevice )<br />
COPY STRUCTURE [FIELDS idField_list] TO xcDatabase<br />
__dbCopyStruct( cDatabase, [acFields] )<br />
COPY STRUCTURE EXTENDED TO xcExtendedDatabase<br />
__dbCopyXStruct( cExtendedDatabase )<br />
COPY TO xcFile [FIELDS idField_list] [scope] [WHILE lCondition]←↪<br />
↩→[FOR lCondition] [VIA xcDriver]<br />
__dbCopy( cFileName, [acFields], [bForCondition], [bWhileCondition], [nNextRecords],←↪<br />
↩→[nRecord], [lRest], [cDriver] )<br />
COPY TO xcFile [FIELDS idField_list] [scope] [WHILE lCondition] [FOR lCondition]←↪<br />
↩→DELIMITED xcDelimiter<br />
__dbDelim( .t., cFileName, [cDelimiter], [acFields], [bForCondition], [bWhileCondition]<br />
,←↪<br />
↩→[nNextRecords], [nRecord], [lRest] )<br />
COPY TO xcFile [FIELDS idField_list] [scope] [WHILE lCondition]←↪<br />
↩→[FOR lCondition] SDF<br />
__dbSDF( .t., cFileName, [acFields], [bForCondition], [bWhileCondition], [nNextRecords]<br />
,←↪<br />
↩→[nRecord], [lRest] )<br />
366.5.13 COUNT<br />
COUNT TO idVar [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {||idVar:=idVar+1}, {||lForCondition}, {||lWhileCondition},←↪<br />
↩→nNextRecords, nRecord, lRest )
144 volume VIII Argomenti avanzati e accessori<br />
366.5.14 CREATE<br />
CREATE xcDatabase FROM xcExtendedDatabase [NEW] [ALIAS cAlias] [VIA cDriver]<br />
__dbCreate( cDatabase, cExtendedDatabase, [cDriver], [lNew], [cAlias] )<br />
366.5.15 DEFAULT<br />
DEFAULT xVar TO xDefaultValue<br />
if xVar == NIL<br />
xVar := xDefaultValue<br />
end<br />
366.5.16 DELETE<br />
DELETE<br />
dbDelete()<br />
DELETE [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {||dbDelete()}, {||lForCondition}, {||lWhileCondition},←↪<br />
↩→nNextRecords, nRecord, lRest )<br />
DELETE FILE xcFile<br />
ferase( cFile )<br />
366.5.17 EJECT<br />
EJECT<br />
qqout( chr(13) )<br />
366.5.18 ERASE<br />
ERASE xcFile<br />
ferase( cFile )<br />
366.5.19 FIND<br />
FIND xcSearchString<br />
dbSeek( cSearchString )<br />
366.5.20 GO<br />
GO[TO] nRecord<br />
dbgoto(nRecord)<br />
GO[TO] BOTTOM<br />
dbGoBottom()<br />
GO[TO] TOP<br />
dbgotop()
Clean the Clipper 5.2 145<br />
366.5.21 INDEX ON<br />
INDEX ON expKey TO xc<strong>Index</strong>Name [UNIQUE] [FOR lForCondition]←↪<br />
↩→[WHILE lWhileCondition] [[EVAL lEvalCondition] [EVERY nRecords]] [ASCENDING|<br />
DESCENDING]<br />
ordCondSet( [cForCondition], [bForCondition], , [bWhileCondition],←↪<br />
↩→[bEvalCondition], [nRecords], RECNO(), , , , lDescending )<br />
ordCreate( c<strong>Index</strong>Name, , cExpKey, bExpKey, lUnique )<br />
366.5.22 JOIN<br />
JOIN WITH xcAlias TO xcDatabase [FOR lCondition] [FIELDS idField_list]<br />
__dbJoin( cAlias, cDatabase, [acFields], [bForCondition] )<br />
366.5.23 KEYBOARD<br />
KEYBOARD cString<br />
__Keyboard( [cString] ) --> NIL<br />
366.5.24 LABEL FORM<br />
LABEL FORM xcLabel [TO PRINTER] [TO FILE xcFile] [NOCONSOLE] [scope]←↪<br />
↩→[WHILE lCondition] [FOR lCondition] [SAMPLE]<br />
__LabelForm( cLabel, [lToPrinter], [cFile], [lNoConsole],←↪<br />
↩→[bForCondition], [bWhileCondition], [nNextRecords], [nRecord],←↪<br />
↩→[lRest], [lSample] )<br />
366.5.25 LIST<br />
LIST exp_list [TO PRINTER] [TO FILE xcFile] [scope]←↪<br />
↩→[WHILE lCondition] [FOR lCondition] [OFF]<br />
__dbList( [lToDisplay], abListColumns, [lAll], [bForCondition], [bWhileCondition],←↪<br />
↩→[nNextRecords], [nRecord], [lRest], [lToPrinter], [cFileName] )<br />
366.5.26 LOCATE<br />
LOCATE [scope] FOR lCondition [WHILE lCondition]<br />
__dbLocate( [bForCondition], [bWhileCondition], [nNextRecords], [nRecord], [lRest] )
146 volume VIII Argomenti avanzati e accessori<br />
366.5.27 PACK<br />
PACK<br />
__dbPack()<br />
366.5.28 QUIT<br />
QUIT<br />
__Quit()<br />
366.5.29 READ<br />
READ<br />
ReadModal(GetList)<br />
GetList := {}<br />
READ SAVE<br />
ReadModal(GetList)<br />
366.5.30 RECALL<br />
RECALL<br />
dbRecall()<br />
RECALL [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {||dbRecall()}, {||lForCondition}, {||lWhileCondition},←↪<br />
↩→nNextRecords, nRecord, lRest )<br />
366.5.31 REINDEX<br />
REINDEX [EVAL lEvalCondition] [EVERY nRecords]<br />
ordCondSet(, , , , [bEvalCondition], [nRecords], , , , , , , )<br />
ordListRebuild()<br />
366.5.32 RELEASE<br />
RELEASE idMemvar<br />
__MXRelease( "idMemvar" )<br />
RELEASE ALL<br />
__MRelease("*", .t.)<br />
RELEASE ALL LIKE skeleton<br />
__MRelease( "skeleton", .t. )<br />
RELEASE ALL EXCEPT skeleton<br />
__MRelease( "skeleton", .F. )
Clean the Clipper 5.2 147<br />
366.5.33 RENAME<br />
RENAME xcOldFile TO xcNewFile<br />
frename( cOldFile, cNewFile )<br />
366.5.34 REPLACE<br />
REPLACE idField1 WITH exp1 [, idField2 WITH exp2...]←↪<br />
↩→[FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {|| idField1 := exp1 [, idField2 := exp2...]},←↪<br />
↩→{||lForCondition}, {||lWhileCondition}, nNextRecords,←↪<br />
↩→nRecord, lRest )<br />
REPLACE idField1 WITH exp1<br />
idField1 := exp1<br />
366.5.35 REPORT FORM<br />
REPORT FORM xcReport [TO PRINTER] [TO FILE xcFile] [NOCONSOLE] [scope]←↪<br />
↩→[WHILE lCondition] [FOR lCondition] [PLAIN | HEADING cHeading] [NOEJECT] ←↪<br />
↩→[SUMMARY]<br />
__ReportForm( cForm, [lToPrinter], [cToFile], [lNoConsole], [bForCondition], ←↪<br />
↩→[bWhileCondition], [nNext], [nRecord], [lRest], [lPlain], [cbHeading], ←↪<br />
↩→[lBeforeEject], [lSummary] )<br />
366.5.36 RESTORE<br />
RESTORE SCREEN FROM cScreen<br />
restscreen( 0, 0, Maxrow(), Maxcol(), cScreen )<br />
366.5.37 RESTORE FROM<br />
RESTORE FROM xcMemFile [ADDITIVE]<br />
__MRestore( cMemFileName, [lAdditive] )<br />
366.5.38 RUN<br />
RUN xcCommandLine<br />
__Run( cCommand )
148 volume VIII Argomenti avanzati e accessori<br />
366.5.39 SAVE SCREEN TO<br />
SAVE SCREEN TO cScreen<br />
cScreen := savescreen( 0, 0, maxrow(), maxcol() )<br />
366.5.40 SAVE TO<br />
SAVE TO xcMemFile [ALL [LIKE|EXCEPT skeleton]]<br />
_MSave( cMemFileName, [cSkeleton], [lLike] )<br />
366.5.41 SEEK<br />
SEEK expSearch [SOFTSEEK]<br />
dbSeek( expSearch [, lS<strong>of</strong>tSeek] )<br />
366.5.42 SELECT<br />
SELECT xnWorkArea | idAlias<br />
dbSelectArea( nWorkArea | cIdAlias )<br />
366.5.43 SET<br />
Most <strong>of</strong> the ‘SET...’ commands are translated into the ‘SET()’ function that distinguishes different<br />
modes depending on a number. As this number is difficult to handle during programming<br />
(essentially because it is difficult to remember the meaning <strong>of</strong> it), Clipper <strong>of</strong>fers the ‘SET.CH’<br />
include file that helps with manifest constants.<br />
#define _SET_EXACT 1<br />
#define _SET_FIXED 2<br />
#define _SET_DECIMALS 3<br />
#define _SET_DATEFORMAT 4<br />
#define _SET_EPOCH 5<br />
#define _SET_PATH 6<br />
#define _SET_DEFAULT 7<br />
#define _SET_EXCLUSIVE 8<br />
#define _SET_SOFTSEEK 9<br />
#define _SET_UNIQUE 10<br />
#define _SET_DELETED 11<br />
#define _SET_CANCEL 12<br />
#define _SET_DEBUG 13<br />
#define _SET_TYPEAHEAD 14<br />
#define _SET_COLOR 15<br />
#define _SET_CURSOR 16<br />
#define _SET_CONSOLE 17<br />
#define _SET_ALTERNATE 18<br />
#define _SET_ALTFILE 19<br />
#define _SET_DEVICE 20<br />
#define _SET_EXTRA 21<br />
#define _SET_EXTRAFILE 22<br />
#define _SET_PRINTER 23
Clean the Clipper 5.2 149<br />
#define _SET_PRINTFILE 24<br />
#define _SET_MARGIN 25<br />
#define _SET_BELL 26<br />
#define _SET_CONFIRM 27<br />
#define _SET_ESCAPE 28<br />
#define _SET_INSERT 29<br />
#define _SET_EXIT 30<br />
#define _SET_INTENSITY 31<br />
#define _SET_SCOREBOARD 32<br />
#define _SET_DELIMITERS 33<br />
#define _SET_DELIMCHARS 34<br />
#define _SET_WRAP 35<br />
#define _SET_MESSAGE 36<br />
#define _SET_MCENTER 37<br />
#define _SET_SCROLLBREAK 38<br />
SET ALTERNATE TO xcFile [ADDITIVE]<br />
Set( _SET_ALTFILE, cFile, lAdditive )<br />
SET ALTERNATE ON | OFF | xlToggle<br />
Set( _SET_ALTERNATE, "ON" | "OFF" | lToggle )<br />
SET BELL ON | OFF | xlToggle<br />
Set( _SET_BELL, "ON" | "OFF" | lToggle )<br />
SET COLOR | COLOUR TO (cColorString)<br />
SetColor( cColorString )<br />
SET CONFIRM ON | OFF | xlToggle<br />
Set( _SET_CONFIRM, "ON" | "OFF" | lToggle )<br />
SET CONSOLE ON | OFF | xlToggle<br />
Set( _SET_CONSOLE, "ON" | "OFF" | lToggle )<br />
SET CURSOR ON | OFF | xlToggle<br />
SetCursor( 1 | 0 | iif( lToggle, 1, 0 ) )<br />
SET DATE FORMAT [TO] cDateFormat<br />
Set( _SET_DATEFORMAT, cDateFormat )<br />
SET DECIMALS TO<br />
Set( _SET_DECIMALS, 0 )<br />
SET DECIMALS TO nDecimals<br />
Set( _SET_DECIMALS, nDecimals )<br />
SET DEFAULT TO<br />
Set( _SET_DEFAULT, "" )<br />
SET DEFAULT TO xcPathspec<br />
Set( _SET_DEFAULT, cPathspec )<br />
SET DELETED ON | OFF | xlToggle<br />
Set( _SET_DELETED, "ON" | "OFF" | lToggle )
150 volume VIII Argomenti avanzati e accessori<br />
SET DELIMITERS ON | OFF | xlToggle<br />
Set( _SET_DELIMITERS, "ON" | "OFF" | lToggle )<br />
SET DELIMITERS TO [DEFAULT]<br />
Set( _SET_DELIMCHARS, "::" )<br />
SET DELIMITERS TO cDelimiters<br />
Set( _SET_DELIMCHARS, cDelimiters )<br />
SET DEVICE TO SCREEN | PRINTER<br />
Set( _SET_DEVICE, "SCREEN" | "PRINTER" )<br />
SET EPOCH TO nYear<br />
Set( _SET_EPOCH, nYear )<br />
SET ESCAPE ON | OFF | xlToggle<br />
Set( _SET_ESCAPE, "ON" | "OFF" | lToggle )<br />
SET EXACT ON | OFF | xlToggle<br />
Set( _SET_EXACT, "ON" | "OFF" | lToggle )<br />
SET EXCLUSIVE ON | OFF | xlToggle<br />
Set( _SET_EXCLUSIVE, "ON" | "OFF" | lToggle )<br />
SET FILTER TO<br />
dbclearfilter()<br />
SET FILTER TO lCondition<br />
dbsetfilter( bCondition, cCondition )<br />
SET FIXED ON | OFF | xlToggle<br />
Set( _SET_FIXED, "ON" | "OFF" | lToggle )<br />
SET FUNCTION nFunctionKey TO cString<br />
__SetFunction( nFunctionKey, cString )<br />
SET INDEX TO [xc<strong>Index</strong> [, xc<strong>Index</strong>1... ] ]<br />
ordListClear()<br />
ordListAdd( c<strong>Index</strong> )<br />
ordListAdd( c<strong>Index</strong>1 )<br />
...<br />
SET INTENSITY ON | OFF | xlToggle<br />
Set( _SET_INTENSITY, "ON" | "OFF" | lToggle )<br />
SET KEY nInkeyCode [TO]<br />
SetKey( nInkeyCode, NIL )<br />
SET KEY nInkeyCode TO [idProcedure]<br />
SetKey( nInkeyCode, { |p, l, v| idProcedure(p, l, v)} )<br />
SET MARGIN TO<br />
Set( _SET_MARGIN, 0 )<br />
SET MARGIN TO [nPageOffset]<br />
Set( _SET_MARGIN, nPageOffset )
Clean the Clipper 5.2 151<br />
SET MESSAGE TO<br />
Set( _SET_MESSAGE, 0 )<br />
Set( _SET_MCENTER, .F. )<br />
SET MESSAGE TO [nRow [CENTER | CENTRE]]<br />
Set( _SET_MESSAGE, nRow )<br />
Set( _SET_MCENTER, lCenter )<br />
SET ORDER TO [n<strong>Index</strong>]<br />
ordSetFocus( n<strong>Index</strong> )<br />
SET PATH TO<br />
Set( _SET_PATH, "" )<br />
SET PATH TO [xcPathspec [, cPathspec1... ] ]<br />
Set( _SET_PATH, cPathspec [, cPathspec1... ] )<br />
SET PRINTER ON | OFF | xlToggle<br />
Set( _SET_PRINTER, "ON" | "OFF" | lToggle )<br />
SET PRINTER TO<br />
Set( _SET_PRINTFILE, "" )<br />
SET PRINTER TO [xcDevice|xcFile [ADDITIVE]]<br />
Set( _SET_PRINTFILE, cDevice|cFile, lAdditive )<br />
SET RELATION TO<br />
dbclearrelation()<br />
SET RELATION TO [expKey1 INTO xcAlias1] [, [TO] expKey2 INTO xcAlias2...]<br />
dbClearRel()<br />
dbSetRelation( cAlias1, {||expKey1}, ["expKey1"] )<br />
dbSetRelation( cAlias2, {||expKey2}, ["expKey1"] )<br />
SET RELATION TO [expKey1 INTO xcAlias1]←↪<br />
↩→[, [TO] expKey2 INTO xcAlias2...] ADDITIVE<br />
dbSetRelation( cAlias1, {||expKey1}, ["expKey1"] )<br />
dbSetRelation( cAlias2, {||expKey2}, ["expKey1"] )<br />
SET SCOREBOARD ON | OFF | xlToggle<br />
Set( _SET_SCOREBOARD, "ON" | "OFF" | lToggle )<br />
SET SOFTSEEK ON | OFF | xlToggle<br />
Set( _SET_SOFTSEEK, "ON" | "OFF" | lToggle )<br />
SET TYPEAHEAD TO nKeyboardSise<br />
Set( _SET_TYPEAHEAD, nKeyboardSise )<br />
SET UNIQUE ON | OFF | xlToggle<br />
Set( _SET_UNIQUE, "ON" | "OFF" | lToggle )<br />
SET WRAP ON | OFF | xlToggle<br />
Set( _SET_WRAP, "ON" | "OFF" | lToggle )
152 volume VIII Argomenti avanzati e accessori<br />
366.5.44 SKIP<br />
SKIP [nRecords] [ALIAS idAlias|nWorkArea]<br />
[idAlias|nWorkArea -> ]( dbSkip([nRecords]) )<br />
366.5.45 SORT<br />
SORT TO xcDatabase ON idField1 [/[A|D][C]] [, idField2 [/[A|D][C]] ...]←↪<br />
↩→[scope] [WHILE lCondition] [FOR lCondition]<br />
__dbSort( cDatabase, [acFields], [bForCondition], [bWhileCondition],←↪<br />
↩→[nNextRecords], [nRecord], [lRest] )<br />
366.5.46 STORE<br />
STORE value TO variable<br />
variable := value<br />
366.5.47 SUM<br />
SUM nExp1 [, nExp2...] TO idVar1 [, idVar2...] [FOR lForCondition]←↪<br />
↩→[WHILE lWhileCondition] [NEXT nNextRecords] [RECORD nRecord] [REST] [ALL]<br />
dbeval( {||idVar1:=idVar1+nExp1 [, idVar2:=idVar2+nExp2...] },←↪<br />
↩→{||lForCondition}, {||lWhileCondition}, nNextRecords, nRecord, lRest )<br />
366.5.48 TOTAL ON<br />
TOTAL ON expKey [FIELDS idField_list] TO xcDatabase [scope]←↪<br />
↩→[WHILE lCondition] [FOR lCondition]<br />
__dbTotal( cDatabase, bKey, [acFields], [bForCondition], [bWhileCondition],←↪<br />
↩→[nNextRecords], [nRecord], [lRest] )<br />
366.5.49 UNLOCK<br />
UNLOCK<br />
dbUnlock()<br />
UNLOCK ALL<br />
dbUnlockAll()<br />
366.5.50 UPDATE FROM<br />
UPDATE FROM xcAlias ON expKey [RANDOM] REPLACE idField1←↪<br />
↩→WITH exp [, idField2 WITH exp ...]<br />
__dbUpdate( cAlias, bKey, [lRandom], [bReplacement] )<br />
Example:
Clean the Clipper 5.2 153<br />
__dbUpdate( "INVOICE", {|| LAST}, .T.,; {|| FIELD->TOTAL1 := ←↪<br />
↩→INVOICE->SUM1,; FIELD->TOTAL2 := INVOICE->SUM2 } )<br />
366.5.51 USE<br />
USE<br />
dbclosearea()<br />
USE [xcDatabase]←↪<br />
↩→[INDEX xc<strong>Index</strong>1 [, xc<strong>Index</strong>2...] [ALIAS xcAlias] [EXCLUSIVE|SHARED] [NEW] ←↪<br />
↩→[READONLY] [VIA cDriver]]<br />
dbUseArea( [lNewArea], [cDriver], cDatabase, [cAlias], [lShared], [lReadOnly] )<br />
[dbSet<strong>Index</strong>( c<strong>Index</strong>1 )]<br />
[dbSet<strong>Index</strong>( c<strong>Index</strong>2 )]<br />
...<br />
366.5.52 ZAP<br />
ZAP<br />
dbZap()<br />
366.6 Step 6: free yourself from STD.CH - /U<br />
Now that no command is used, the standard include file ‘STD.CH’ is no more necessary. Clipper<br />
uses ‘STD.CH’ automatically, unless specified differently. Just compile this way:<br />
C:>CLIPPER TEST.PRG /U<br />
366.7 Step 7: take control over all include files<br />
Clipper comes with so many include files (‘ * .CH’). To avoid confusion, a single ‘STANDARD.CH’<br />
file containing all what is needed for the application may be prepared. At least, it is necessary the<br />
following.<br />
*=================================================================<br />
* DISPBOX()<br />
*=================================================================<br />
* Single-line box<br />
#define BOX_SINGLE;<br />
(;<br />
CHR(218) +;<br />
CHR(196) +;<br />
CHR(191) +;<br />
CHR(179) +;<br />
CHR(217) +;<br />
CHR(196) +;<br />
CHR(192) +;<br />
CHR(179);<br />
)<br />
* Double-line box
154 volume VIII Argomenti avanzati e accessori<br />
#define BOX_DOUBLE;<br />
(;<br />
CHR(201) +;<br />
CHR(205) +;<br />
CHR(187) +;<br />
CHR(186) +;<br />
CHR(188) +;<br />
CHR(205) +;<br />
CHR(200) +;<br />
CHR(186);<br />
)<br />
* Single-line top, double-line sides<br />
#define BOX_SINGLE_DOUBLE;<br />
(;<br />
CHR(214) +;<br />
CHR(196) +;<br />
CHR(183) +;<br />
CHR(186) +;<br />
CHR(189) +;<br />
CHR(196) +;<br />
CHR(211) +;<br />
CHR(186);<br />
)<br />
* Double-line top, single-line sides<br />
#define BOX_DOUBLE_SINGLE;<br />
(;<br />
CHR(213) +;<br />
CHR(205) +;<br />
CHR(184) +;<br />
CHR(179) +;<br />
CHR(190) +;<br />
CHR(205) +;<br />
CHR(212) +;<br />
CHR(179);<br />
)<br />
*=================================================================<br />
* ERRORS<br />
*=================================================================<br />
* Severity levels (e:severity)<br />
#define ERROR_SEVERITY_WHOCARES 0<br />
#define ERROR_SEVERITY_WARNING 1<br />
#define ERROR_SEVERITY_ERROR 2<br />
#define ERROR_SEVERITY_CATASTROPHIC 3<br />
* Generic error codes (e:genCode)<br />
#define ERROR_GENERIC_ARG 1<br />
#define ERROR_GENERIC_BOUND 2<br />
#define ERROR_GENERIC_STROVERFLOW 3<br />
#define ERROR_GENERIC_NUMOVERFLOW 4<br />
#define ERROR_GENERIC_ZERODIV 5<br />
#define ERROR_GENERIC_NUMERR 6<br />
#define ERROR_GENERIC_SYNTAX 7<br />
#define ERROR_GENERIC_COMPLEXITY 8<br />
#define ERROR_GENERIC_MEM 11<br />
#define ERROR_GENERIC_NOFUNC 12<br />
#define ERROR_GENERIC_NOMETHOD 13<br />
#define ERROR_GENERIC_NOVAR 14<br />
#define ERROR_GENERIC_NOALIAS 15
Clean the Clipper 5.2 155<br />
#define ERROR_GENERIC_NOVARMETHOD 16<br />
#define ERROR_GENERIC_BADALIAS 17<br />
#define ERROR_GENERIC_DUPALIAS 18<br />
#define ERROR_GENERIC_CREATE 20<br />
#define ERROR_GENERIC_OPEN 21<br />
#define ERROR_GENERIC_CLOSE 22<br />
#define ERROR_GENERIC_READ 23<br />
#define ERROR_GENERIC_WRITE 24<br />
#define ERROR_GENERIC_PRINT 25<br />
#define ERROR_GENERIC_UNSUPPORTED 30<br />
#define ERROR_GENERIC_LIMIT 31<br />
#define ERROR_GENERIC_CORRUPTION 32<br />
#define ERROR_GENERIC_DATATYPE 33<br />
#define ERROR_GENERIC_DATAWIDTH 34<br />
#define ERROR_GENERIC_NOTABLE 35<br />
#define ERROR_GENERIC_NOORDER 36<br />
#define ERROR_GENERIC_SHARED 37<br />
#define ERROR_GENERIC_UNLOCKED 38<br />
#define ERROR_GENERIC_READONLY 39<br />
#define ERROR_GENERIC_APPENDLOCK 40<br />
#define ERROR_GENERIC_LOCK 41<br />
*=================================================================<br />
* INKEY()<br />
*=================================================================<br />
#define K_UP 5 // Up arrow, Ctrl-E<br />
#define K_DOWN 24 // Down arrow, Ctrl-X<br />
#define K_LEFT 19 // Left arrow, Ctrl-S<br />
#define K_RIGHT 4 // Right arrow, Ctrl-D<br />
#define K_HOME 1 // Home, Ctrl-A<br />
#define K_END 6 // End, Ctrl-F<br />
#define K_PGUP 18 // PgUp, Ctrl-R<br />
#define K_PGDN 3 // PgDn, Ctrl-C<br />
#define K_CTRL_UP 397 // * Ctrl-Up arrow<br />
#define K_CTRL_DOWN 401 // * Ctrl-Down arrow<br />
#define K_CTRL_LEFT 26 // Ctrl-Left arrow, Ctrl-Z<br />
#define K_CTRL_RIGHT 2 // Ctrl-Right arrow, Ctrl-B<br />
#define K_CTRL_HOME 29 // Ctrl-Home, Ctrl-<br />
#define K_CTRL_END 23 // Ctrl-End, Ctrl-W<br />
#define K_CTRL_PGUP 31 // Ctrl-PgUp, Ctrl-Hyphen<br />
#define K_CTRL_PGDN 30 // Ctrl-PgDn, Ctrl-^<br />
#define K_ALT_UP 408 // * Alt-Up arrow<br />
#define K_ALT_DOWN 416 // * Alt-Down arrow<br />
#define K_ALT_LEFT 411 // * Alt-Left arrow<br />
#define K_ALT_RIGHT 413 // * Alt-Right arrow<br />
#define K_ALT_HOME 407 // * Alt-Home<br />
#define K_ALT_END 415 // * Alt-End<br />
#define K_ALT_PGUP 409 // * Alt-PgUp<br />
#define K_ALT_PGDN 417 // * Alt-PgDn<br />
#define K_ENTER 13 // Enter, Ctrl-M<br />
#define K_RETURN 13 // Return, Ctrl-M<br />
#define K_SPACE 32 // Space bar<br />
#define K_ESC 27 // Esc, Ctrl-<br />
#define K_CTRL_ENTER 10 // Ctrl-Enter<br />
#define K_CTRL_RETURN 10 // Ctrl-Return
156 volume VIII Argomenti avanzati e accessori<br />
#define K_CTRL_RET 10 // Ctrl-Return (Compat.)<br />
#define K_CTRL_PRTSCR 379 // * Ctrl-Print Screen<br />
#define K_CTRL_QUESTION 309 // Ctrl-?<br />
#define K_ALT_ENTER 284 // * Alt-Enter<br />
#define K_ALT_RETURN 284 // * Alt-Return<br />
#define K_ALT_EQUALS 387 // * Alt-Equals<br />
#define K_ALT_ESC 257 // * Alt-Esc<br />
#define KP_ALT_ENTER 422 // * Keypad Alt-Enter<br />
#define KP_CTRL_5 399 // * Keypad Ctrl-5<br />
#define KP_CTRL_SLASH 405 // * Keypad Ctrl-/<br />
#define KP_CTRL_ASTERISK 406 // * Keypad Ctrl-*<br />
#define KP_CTRL_MINUS 398 // * Keypad Ctrl--<br />
#define KP_CTRL_PLUS 400 // * Keypad Ctrl-+<br />
#define KP_ALT_5 5 // * Keypad Alt-5<br />
#define KP_ALT_SLASH 420 // * Keypad Alt-/<br />
#define KP_ALT_ASTERISK 311 // * Keypad Alt-*<br />
#define KP_ALT_MINUS 330 // * Keypad Alt--<br />
#define KP_ALT_PLUS 334 // * Keypad Alt-+<br />
#define K_INS 22 // Ins, Ctrl-V<br />
#define K_DEL 7 // Del, Ctrl-G<br />
#define K_BS 8 // Backspace, Ctrl-H<br />
#define K_TAB 9 // Tab, Ctrl-I<br />
#define K_SH_TAB 271 // Shift-Tab<br />
#define K_CTRL_INS 402 // * Ctrl-Ins<br />
#define K_CTRL_DEL 403 // * Ctrl-Del<br />
#define K_CTRL_BS 127 // Ctrl-Backspace<br />
#define K_CTRL_TAB 404 // * Ctrl-Tab<br />
#define K_ALT_INS 418 // * Alt-Ins<br />
#define K_ALT_DEL 419 // * Alt-Del<br />
#define K_ALT_BS 270 // * Alt-Backspace<br />
#define K_ALT_TAB 421 // * Alt-Tab<br />
#define K_CTRL_A 1 // Ctrl-A, Home<br />
#define K_CTRL_B 2 // Ctrl-B, Ctrl-Right arrow<br />
#define K_CTRL_C 3 // Ctrl-C, PgDn, Ctrl-ScrollLock<br />
#define K_CTRL_D 4 // Ctrl-D, Right arrow<br />
#define K_CTRL_E 5 // Ctrl-E, Up arrow<br />
#define K_CTRL_F 6 // Ctrl-F, End<br />
#define K_CTRL_G 7 // Ctrl-G, Del<br />
#define K_CTRL_H 8 // Ctrl-H, Backspace<br />
#define K_CTRL_I 9 // Ctrl-I, Tab<br />
#define K_CTRL_J 10 // Ctrl-J<br />
#define K_CTRL_K 11 // Ctrl-K<br />
#define K_CTRL_L 12 // Ctrl-L<br />
#define K_CTRL_M 13 // Ctrl-M, Return<br />
#define K_CTRL_N 14 // Ctrl-N<br />
#define K_CTRL_O 15 // Ctrl-O<br />
#define K_CTRL_P 16 // Ctrl-P<br />
#define K_CTRL_Q 17 // Ctrl-Q<br />
#define K_CTRL_R 18 // Ctrl-R, PgUp<br />
#define K_CTRL_S 19 // Ctrl-S, Left arrow<br />
#define K_CTRL_T 20 // Ctrl-T<br />
#define K_CTRL_U 21 // Ctrl-U<br />
#define K_CTRL_V 22 // Ctrl-V, Ins<br />
#define K_CTRL_W 23 // Ctrl-W, Ctrl-End<br />
#define K_CTRL_X 24 // Ctrl-X, Down arrow<br />
#define K_CTRL_Y 25 // Ctrl-Y
Clean the Clipper 5.2 157<br />
#define K_CTRL_Z 26 // Ctrl-Z, Ctrl-Left arrow<br />
#define K_ALT_A 286 // Alt-A<br />
#define K_ALT_B 304 // Alt-B<br />
#define K_ALT_C 302 // Alt-C<br />
#define K_ALT_D 288 // Alt-D<br />
#define K_ALT_E 274 // Alt-E<br />
#define K_ALT_F 289 // Alt-F<br />
#define K_ALT_G 290 // Alt-G<br />
#define K_ALT_H 291 // Alt-H<br />
#define K_ALT_I 279 // Alt-I<br />
#define K_ALT_J 292 // Alt-J<br />
#define K_ALT_K 293 // Alt-K<br />
#define K_ALT_L 294 // Alt-L<br />
#define K_ALT_M 306 // Alt-M<br />
#define K_ALT_N 305 // Alt-N<br />
#define K_ALT_O 280 // Alt-O<br />
#define K_ALT_P 281 // Alt-P<br />
#define K_ALT_Q 272 // Alt-Q<br />
#define K_ALT_R 275 // Alt-R<br />
#define K_ALT_S 287 // Alt-S<br />
#define K_ALT_T 276 // Alt-T<br />
#define K_ALT_U 278 // Alt-U<br />
#define K_ALT_V 303 // Alt-V<br />
#define K_ALT_W 273 // Alt-W<br />
#define K_ALT_X 301 // Alt-X<br />
#define K_ALT_Y 277 // Alt-Y<br />
#define K_ALT_Z 300 // Alt-Z<br />
#define K_ALT_1 376 // Alt-1<br />
#define K_ALT_2 377 // Alt-2<br />
#define K_ALT_3 378 // Alt-3<br />
#define K_ALT_4 379 // Alt-4<br />
#define K_ALT_5 380 // Alt-5<br />
#define K_ALT_6 381 // Alt-6<br />
#define K_ALT_7 382 // Alt-7<br />
#define K_ALT_8 383 // Alt-8<br />
#define K_ALT_9 384 // Alt-9<br />
#define K_ALT_0 385 // Alt-0<br />
#define K_F1 28 // F1, Ctrl-Backslash<br />
#define K_F2 -1 // F2<br />
#define K_F3 -2 // F3<br />
#define K_F4 -3 // F4<br />
#define K_F5 -4 // F5<br />
#define K_F6 -5 // F6<br />
#define K_F7 -6 // F7<br />
#define K_F8 -7 // F8<br />
#define K_F9 -8 // F9<br />
#define K_F10 -9 // F10<br />
#define K_F11 -40 // * F11<br />
#define K_F12 -41 // * F12<br />
#define K_CTRL_F1 -20 // Ctrl-F1<br />
#define K_CTRL_F2 -21 // Ctrl-F2<br />
#define K_CTRL_F3 -22 // Ctrl-F4<br />
#define K_CTRL_F4 -23 // Ctrl-F3<br />
#define K_CTRL_F5 -24 // Ctrl-F5<br />
#define K_CTRL_F6 -25 // Ctrl-F6<br />
#define K_CTRL_F7 -26 // Ctrl-F7<br />
#define K_CTRL_F8 -27 // Ctrl-F8<br />
#define K_CTRL_F9 -28 // Ctrl-F9<br />
#define K_CTRL_F10 -29 // Ctrl-F10<br />
#define K_CTRL_F11 -44 // * Ctrl-F11<br />
#define K_CTRL_F12 -45 // * Ctrl-F12
158 volume VIII Argomenti avanzati e accessori<br />
#define K_ALT_F1 -30 // Alt-F1<br />
#define K_ALT_F2 -31 // Alt-F2<br />
#define K_ALT_F3 -32 // Alt-F3<br />
#define K_ALT_F4 -33 // Alt-F4<br />
#define K_ALT_F5 -34 // Alt-F5<br />
#define K_ALT_F6 -35 // Alt-F6<br />
#define K_ALT_F7 -36 // Alt-F7<br />
#define K_ALT_F8 -37 // Alt-F8<br />
#define K_ALT_F9 -38 // Alt-F9<br />
#define K_ALT_F10 -39 // Alt-F10<br />
#define K_ALT_F11 -46 // * Alt-F11<br />
#define K_ALT_F12 -47 // * Alt-F12<br />
#define K_SH_F1 -10 // Shift-F1<br />
#define K_SH_F2 -11 // Shift-F2<br />
#define K_SH_F3 -12 // Shift-F3<br />
#define K_SH_F4 -13 // Shift-F4<br />
#define K_SH_F5 -14 // Shift-F5<br />
#define K_SH_F6 -15 // Shift-F6<br />
#define K_SH_F7 -16 // Shift-F7<br />
#define K_SH_F8 -17 // Shift-F8<br />
#define K_SH_F9 -18 // Shift-F9<br />
#define K_SH_F10 -19 // Shift-F10<br />
#define K_SH_F11 -42 // * Shift-F11<br />
#define K_SH_F12 -43 // * Shift-F12<br />
*=================================================================<br />
* MEMOEDIT()<br />
*=================================================================<br />
* User function entry modes<br />
#define MEMOEDIT_IDLE 0 // idle, all keys processed<br />
#define MEMOEDIT_UNKEY 1 // unknown key, memo unaltered<br />
#define MEMOEDIT_UNKEYX 2 // unknown key, memo altered<br />
#define MEMOEDIT_INIT 3 // initialization mode<br />
* User function return codes<br />
#define MEMOEDIT_DEFAULT 0 // perform default action<br />
#define MEMOEDIT_IGNORE 32 // ignore unknown key<br />
#define MEMOEDIT_DATA 33 // treat unknown key as data<br />
#define MEMOEDIT_TOGGLEWRAP 34 // toggle word-wrap mode<br />
#define MEMOEDIT_TOGGLESCROLL 35 // toggle scrolling mode<br />
#define MEMOEDIT_WORDRIGHT 100 // perform word-right operation<br />
#define MEMOEDIT_BOTTOMRIGHT 101 // perform bottom-right operation<br />
*=================================================================<br />
* SET()<br />
*=================================================================<br />
#define _SET_EXACT 1<br />
#define _SET_FIXED 2<br />
#define _SET_DECIMALS 3<br />
#define _SET_DATEFORMAT 4<br />
#define _SET_EPOCH 5<br />
#define _SET_PATH 6<br />
#define _SET_DEFAULT 7<br />
#define _SET_EXCLUSIVE 8<br />
#define _SET_SOFTSEEK 9<br />
#define _SET_UNIQUE 10
Clean the Clipper 5.2 159<br />
#define _SET_DELETED 11<br />
#define _SET_CANCEL 12<br />
#define _SET_DEBUG 13<br />
#define _SET_TYPEAHEAD 14<br />
#define _SET_COLOR 15<br />
#define _SET_CURSOR 16<br />
#define _SET_CONSOLE 17<br />
#define _SET_ALTERNATE 18<br />
#define _SET_ALTFILE 19<br />
#define _SET_DEVICE 20<br />
#define _SET_EXTRA 21<br />
#define _SET_EXTRAFILE 22<br />
#define _SET_PRINTER 23<br />
#define _SET_PRINTFILE 24<br />
#define _SET_MARGIN 25<br />
#define _SET_BELL 26<br />
#define _SET_CONFIRM 27<br />
#define _SET_ESCAPE 28<br />
#define _SET_INSERT 29<br />
#define _SET_EXIT 30<br />
#define _SET_INTENSITY 31<br />
#define _SET_SCOREBOARD 32<br />
#define _SET_DELIMITERS 33<br />
#define _SET_DELIMCHARS 34<br />
#define _SET_WRAP 35<br />
#define _SET_MESSAGE 36<br />
#define _SET_MCENTER 37<br />
#define _SET_SCROLLBREAK 38<br />
*=================================================================<br />
* SETCURSOR()<br />
*=================================================================<br />
#define SETCURSOR_NONE 0 // No cursor<br />
#define SETCURSOR_NORMAL 1 // Normal cursor (underline)<br />
#define SETCURSOR_INSERT 2 // Insert cursor (lower half block)<br />
#define SETCURSOR_SPECIAL1 3 // Special cursor (full block)<br />
#define SETCURSOR_SPECIAL2 4 // Special cursor (upper half block)<br />
*=================================================================<br />
* RDD REQUESTs<br />
*=================================================================<br />
external dbfndx<br />
external dbfntx // default<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
nanoBase 1997<br />
A free xBase for Dos.<br />
Chapter 367<br />
This material appeared originally at ‘http://www.geocities.com/SiliconValley/<br />
7737/nanobase.html’, in 1997. Now it is incorporated inside the Italian document<br />
‘‘Appunti di informatica libera’’, and might be reached at the URI .<br />
Questo materiale è apparso in origine, nel 1997, presso ‘http://www.geocities.com/<br />
SiliconValley/7737/nanobase.html’. Adesso viene incorporato nel documento «Appunti<br />
di informatica libera» e può essere raggiunto attraverso l’URI .<br />
367.1 What is it<br />
nanoBase 1 is a Dos program that works essentially as:<br />
• a dot command line xBase,<br />
• a menu driven xBase,<br />
• a xBase program interpreter.<br />
nanoBase 1997 is compiled in two versions: a small one to be used with old computers (i86 with<br />
640 Kibyte RAM), and a second one to be used with better computers, at least i286 (or better)<br />
with 2 Mibyte RAM.<br />
367.2 The dot command line<br />
Figure 367.1. The dot line.<br />
The dot command line is the first face <strong>of</strong> nanoBase, the one that appears starting the program<br />
normally. It recalls the dot line command <strong>of</strong> the old xBases.<br />
Please note that nanoBase recognise only expressions (that is: no commands).<br />
1 nanoBase GNU GPL<br />
160
nanoBase 1997 161<br />
367.3 The menu<br />
Figure 367.2. The file menu.<br />
Pressing [ F10 ] the nanoBase menu appears.<br />
From this menu the operations are easier than writing all commands on a prompt line, but it is<br />
always possible to come back to the dot line to do an operation not available from the menu.<br />
367.4 The macro recording, compiling and execution<br />
Figure 367.3. The macro menu.<br />
nanoBase is able to record some actions made with the menu and all what is correctly typed from<br />
the dot prompt. This may be the begin for a little program (called macro inside nanoBase) that<br />
can be executed as it is (ASCII), or compiled into another format, faster to execute.<br />
Macros for nanoBase are made with a reduced set <strong>of</strong> the Clipper syntax. The statements recognised<br />
from nanoBase are:<br />
PROCEDURE procedure_name<br />
statements...<br />
[RETURN]<br />
statements...<br />
ENDPROCEDURE
162 volume VIII Argomenti avanzati e accessori<br />
DO PROCEDURE procedure_name<br />
BEGIN SEQUENCE<br />
statements...<br />
[BREAK]<br />
statements...<br />
END<br />
DO CASE<br />
CASE lCondition1<br />
statements...<br />
[CASE lCondition2]<br />
statements...<br />
[OTHERWISE]<br />
statements...<br />
END<br />
WHILE lCondition<br />
statements...<br />
[EXIT]<br />
statements...<br />
[LOOP]<br />
statements...<br />
END<br />
IF lCondition1<br />
statements...<br />
[ELSE]<br />
statements...<br />
END<br />
• the ‘FOR’ loop is not available (too difficult to implement),<br />
• there may be no user defined functions (code blocks may be created instead),<br />
• procedure calls cannot transfer variables,<br />
• there are only public (global) variables.<br />
Beside these limitations, there are many added functions to the standard language that make the<br />
programming easier.<br />
All you need is inside ‘NB.EXE’:<br />
• the utility to handle manually the data,<br />
• the macro compiler,<br />
• the macro executor.
nanoBase 1997 163<br />
367.5 The report system<br />
Figure 367.4. The report menu.<br />
nanoBase can handle label (‘.LBL’) and form (‘.FRM’) files in the dBaseIII format. Labels and<br />
forms may be created and edited inside nanoBase. Beside these old report system there is another<br />
way to make a little bit complicated reports without making a complex macro: it is called RPT.<br />
A RPT file is a ASCII file with text mixed with code. The text may contain variables (usually a<br />
field or an expression containing fields).<br />
To make a complex report some work is needed, but surely less than the time needed to make a<br />
report program.<br />
The main purpose <strong>of</strong> it was to be able to print text with variables (typically names and addresses)<br />
for every record <strong>of</strong> a particular ‘.DBF’ file. Now the RPT system makes something more.<br />
367.6 The integrated text editor<br />
Figure 367.5. The integrated text editor.<br />
nanoBase contains an integrated text editor not particularly good, but very usefull for RPT files<br />
(as the expression insertion is very easy with the use <strong>of</strong> the [ F2 ] key) and whenever there isn’t<br />
any other editor there.
164 volume VIII Argomenti avanzati e accessori<br />
367.7 The internal documentation<br />
Figure 367.6. The internal documentation.<br />
nanoBase’s documentation si translated also inside the HTF format: ‘NB.HLP’. Pressing [ F1 ],<br />
normally, a contextual piece <strong>of</strong> the manual appears.<br />
Some standard functions have its own internal help, contained inside the ‘.EXE’ file. This was<br />
made to help programming with nanoBase.<br />
367.8 Download it<br />
Here is the 1997 edition <strong>of</strong> nanoBase.<br />
• EXE for small computers.<br />
<br />
<br />
• EXE for i286 with more than 2 Mibyte.<br />
<br />
<br />
• Runtime for small computers.<br />
<br />
<br />
• Documentation in many different formats.<br />
<br />
<br />
• Macro programming examples.<br />
<br />
<br />
• Source for version 96.06.16, without mouse support (1996).<br />
<br />
nanoBase 1997 165<br />
• Source for version 1997.<br />
<br />
<br />
367.9 Bugs and known problems<br />
Here is the list <strong>of</strong> known bugs and problems.<br />
• Comparison with floating point numbers may fail. It is better to convert numbers into string<br />
before comparing them.<br />
• Macros may be contained inside ASCII files or a ‘‘compiled’’ ‘.DBF’ file. In the second<br />
case, when nanoBase executes the macro, a work area (the last available one) is used, so it<br />
should not be closed or the macro execution will be stopped. A ‘dbcloseall()’ will stop<br />
execution <strong>of</strong> the macro. In substitution <strong>of</strong> ‘dbcloseall()’, ‘DBCLOSE()’ should be used.<br />
• To simplify the macro interpretation, lines such as this:<br />
qqout( "You can’t do that // you can’t do that!" )<br />
will generate an error as the interpreter will read only:<br />
qqout( "You can’t do that<br />
• nanoBase works good also if you have a screen configuration that permits you to show more<br />
than the usual 80 columns and 25 lines, but the library used to handle the mouse is not able<br />
to work outside the 80×25 area.<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
nanoBase 1997 user manual<br />
Chapter 368<br />
This is the documentation <strong>of</strong> nanoBase 1997, with minor modifications, that appeared originally<br />
at ‘http://www.geocities.com/SiliconValley/7737/nb.htm’. Now it is incorporated<br />
inside the Italian document ‘‘Appunti di informatica libera’’, and might be reached at<br />
the URI .<br />
Questo è il manuale di nanoBase 1997, modificato leggermente, che è apparso inizialmente<br />
presso ‘http://www.geocities.com/SiliconValley/7737/nb.htm’. Adesso<br />
viene incorporato nel documento «Appunti di informatica libera» e può essere raggiunto attraverso<br />
l’URI .<br />
368.1 Dos xBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />
368.2 Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171<br />
368.3 How to use nB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173<br />
368.4 Status line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />
368.5 The dot line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175<br />
368.6 The menu system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175<br />
368.7 The text editor DOC() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />
368.8 The help text file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />
368.9 Macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />
368.10 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192<br />
368.11 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .200<br />
368.12 Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201<br />
368.13 Code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />
368.14 Standard functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />
368.15 nB functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261<br />
368.16 Normal command substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299<br />
368.17 nB command substitution functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305<br />
368.18 RPT: the nB print function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310<br />
368.19 How can I... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313<br />
368.20 The source files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314<br />
nB (‘‘nano Base’’: ‘‘n’’ = ‘‘nano’’ = 10**(-9) = ‘‘very little’’) is a little Dos xBase written in<br />
Clipper 5.2 that can help to access ‘.DBF’ file created with different standards.<br />
nB is:<br />
• a dot command interpreter,<br />
166
nanoBase 1997 user manual 167<br />
• a menu driven xBase,<br />
• a xBase program interpreter.<br />
368.1 Dos xBase<br />
This section is a brief description <strong>of</strong> the functionality <strong>of</strong> a typical Dos xBase.<br />
The first purpose <strong>of</strong> a xBase program is to handle data inside a ‘.DBF’ file. These files may be<br />
indexed with the help <strong>of</strong> index files and more ‘.DBF’ files may be linked with a relation to obtain<br />
something like a relational database.<br />
368.1.1 .DBF files<br />
‘.DBF’ files are files organised in a table structure:<br />
.--------------------------.<br />
| field1 | field2 | field3 | record1<br />
|--------|--------|--------|<br />
| | | | record2<br />
|--------|--------|--------|<br />
| | | | record3<br />
|--------|--------|--------|<br />
| | | | record4<br />
|--------|--------|--------|<br />
| | | | record5<br />
|--------|--------|--------|<br />
| | | | record6<br />
‘--------------------------’<br />
The lines <strong>of</strong> this table are records and the columns are fields. Records are numbered starting from<br />
the first that is number 1.<br />
Columns are defined as fields and fields are distinguished by name and these names are saved<br />
inside the ‘.DBF’ file.<br />
Every field (column) can contain only one specified kind <strong>of</strong> data with a specified dimension:<br />
• ‘C’, character, originally the maximum dimension was 254 characters, minimum is 1;<br />
• ‘N’, numeric, a numeric field that can contain also sign and decimal values;<br />
• ‘D’, date, a field dedicated to date information;<br />
• ‘L’, logic, a filed that may contain only ‘T’ for True or ‘F’ for False used as a boolean<br />
variable;<br />
• ‘M’, memo, a character field with no predefined dimension, not allocated directly inside the<br />
‘.DBF’, but inside a ‘.DBT’ file, automatically linked.<br />
No other field type is available for a typical xBase ‘.DBF’ file.<br />
To access the data contained inside a ‘.DBF’ file the following list <strong>of</strong> action may be followed:<br />
• Open a ‘.DBF’ file inside the current area, where these areas are something like file handlers.<br />
• After the ‘.DBF’ file is opened, it referenced only by the alias name that usually correspond<br />
to the original filename without extention.
168 volume VIII Argomenti avanzati e accessori<br />
• Move the record pointer to the desired location.<br />
• Lock the current record to avoid access from other users.<br />
• Do some editing with the data contained inside the current record using the field names like<br />
they were variables.<br />
• Release the lock.<br />
• Move the record pointer to another desired location.<br />
• Lock the current record to avoid access from other users.<br />
• ...<br />
• Close the alias.<br />
Before you go further, you have to understand that:<br />
• A ‘.DBF’ file is opened using a free WORK AREA that may be associated to the concept<br />
<strong>of</strong> the file handler.<br />
• The ‘.DBF’ file is opened with a alias name that permit to open the same ‘.DBF’ file more<br />
times when using different alias names.<br />
• After the ‘.DBF’ file is opened, we don’t speak any more <strong>of</strong> file, but alias.<br />
• If the work area "n" is used from the alias "myAlias", speaking <strong>of</strong> work area "n" or <strong>of</strong> alias<br />
"myAlias" is the same thing.<br />
368.1.2 <strong>Index</strong> files<br />
‘.DBF’ files are organised with record number, that is, you can reach a specific record and not a<br />
specific information unless that you scan record by record.<br />
To obtain to "see" a ‘.DBF’ file somehow logically ordered (when physically it is not), index files<br />
are used.<br />
A index file, also called INDEX BAG, is a file that contains one or more indexes<br />
<strong>Index</strong>es are rules by which a ‘.DBF’ file may be seen ordered.<br />
A typical index file may contain only one index.<br />
A index file may have the following extention:<br />
• ‘.NDX’, single index, dBase III and dBase III plus;<br />
• ‘.NTX’, single index, Clipper;<br />
• ‘.MBX’, multiple index, dBase IV;<br />
• ‘.CDX’, multiple index, FoxPro.<br />
Every index file may be used only in association with the ‘.DBF’ for what it was made. The<br />
problem is that normally there is no way to avoid errors when the user try to associate the right<br />
‘.DBF’ file with the wrong index.
nanoBase 1997 user manual 169<br />
To access the data contained inside a ‘.DBF’ file the following list <strong>of</strong> action may be followed:<br />
• Open a ‘.DBF’ file.<br />
• Open a index file.<br />
• Select a particular order.<br />
• Search for a key or move the record pointer on a different way.<br />
• Lock the current record to avoid access from other users.<br />
• Do some editing with the data contained inside the current record using the field names like<br />
they were variables.<br />
• Release the lock.<br />
• Move the record pointer to another desired location.<br />
• Lock the current record to avoid access from other users.<br />
• ...<br />
• Close the alias.<br />
Before you go further, you have to understand that:<br />
• As orders are contained inside a INDEX BAG file physically distinguished form the ‘.DBF’<br />
file, it may happen that a ‘.DBF’ file is wrongly opened and edited without the index. In<br />
this case, the INDEX BAG is not updated and when the INDEX BAG will be opened, the<br />
records contained inside the ‘.DBF’ file may not correspond.<br />
• For the same reason, an improper program termination may result in an incomplete data<br />
update. That is: ‘.DBF’ file may be all right, INDEX BAG not.<br />
• This is why xBase programs are "weak" relational databases or they are not relational<br />
databases at all.<br />
• When troubles occurs, indexes must be rebuild.<br />
368.1.3 Relations<br />
Many ‘.DBF’ files with indexes may be opened simultaneously. Data contained inside more<br />
‘.DBF’ files may be somehow connected together. See the example.
170 volume VIII Argomenti avanzati e accessori<br />
.----------------------------------------.<br />
| Date | Time IN | Time OUT | Employee # |<br />
|------|---------|-----------------------|<br />
| xxxx | xxxxxxx | xxxxxxxx | 01 | -------->.<br />
|------|---------|----------|------------| |<br />
| yyyy | yyyyyyy | yyyyyyyy | 02 | |<br />
|------|---------|----------|------------| |<br />
| zzzz | zzzzzzz | zzzzzzzz | 01 | -------->|<br />
‘----------------------------------------’ |<br />
[...] |<br />
|<br />
.| 01 | aaaaaaa | aaaaaaa |.....|<br />
|------------|---------|---------|-----|<br />
| 02 | bbbbbbb | bbbbbbb |.....|<br />
|------------|---------|---------|-----|<br />
| 03 | ccccccc | ccccccc |.....|<br />
‘--------------------------------------’<br />
The first ‘.DBF’ file contains some data that refers to an Employee number that may appear<br />
repeated on more records.<br />
Employee informations are stored inside another ‘.DBF’ file that contains only one record for<br />
every employee.<br />
Establishing a relation from the first ‘.DBF’ file to the second, moving the record pointer <strong>of</strong> the<br />
first ‘.DBF’ file, that is the first alias, the record pointer <strong>of</strong> the second, the child alias, is moved<br />
automatically to the record containing the right data.<br />
The relation is an expression that should result in a number if the child alias is opened without<br />
index, or in a valid index key if the child alias is opened with an index.<br />
To relate two ‘.DBF’ files the following list <strong>of</strong> action may be followed:<br />
• Open the first ‘.DBF’ file.<br />
• Open a index file for the first alias.<br />
• Select a particular order.<br />
• Open the second ‘.DBF’ file.<br />
• Open a index file for the second alias.<br />
• Select a particular order.<br />
• Select the first alias.<br />
• Define a relation form the first alias and the second alias: the child alias.<br />
• Search for a key or move the record pointer <strong>of</strong> the first alias (don’t care about the Child<br />
alias).<br />
• Lock the current record to avoid access from other users.<br />
• If data contained inside the Child alias should be edited (usually it doesn’t happen), lock<br />
the current record <strong>of</strong> the Child alias.
nanoBase 1997 user manual 171<br />
• Do some editing with the data contained inside the current record using the field names like<br />
they were variables.<br />
• Release the lock (also with the Child alias if a lock was made).<br />
• Move the record pointer to another desired location.<br />
• Lock the current record to avoid access from other users.<br />
• [...]<br />
• Release the relation.<br />
• Close the Child alias.<br />
• Close the first alias.<br />
As may be seen, relations are not saved inside files, but are obtained with lines <strong>of</strong> code.<br />
368.2 Composition<br />
nB is composed from the following files, where xx is the the version code.<br />
NBASExx1.ZIP EXEs for small PCs<br />
NBASExx2.ZIP Runtime EXEs for small PCs<br />
NBASExx3.ZIP EXEs for i286 with 2M+<br />
NBASExx4.ZIP DOCs<br />
NBASExx5.ZIP EXAMPLEs<br />
NBASExx6.ZIP SRCs for version 96.06.16<br />
NBASExx7.ZIP SRCs for the current version<br />
Every archive file contains:<br />
‘COPYING.TXT’ GNU General Public License version 2 in Dos text format.<br />
‘README.TXT’ the readme file.<br />
‘FILE_ID.DIZ’ definition.<br />
The file ‘NBASExx1.ZIP’ contains also the following files.<br />
‘NB.EXE’<br />
the executable program for DBFNTX and DBFNDX files,<br />
linked with RTLINK.<br />
‘NB.HLP’ this manual in "Help Text File" format.<br />
The file NBASExx2.ZIP contains also the following files.<br />
‘NB.EXE’<br />
The file ‘NBASExx3.ZIP’ contains also the following files.<br />
the run-time to execute macro programs for DBFNTX and<br />
DBFNDX files handling, linked with RTLINK.<br />
‘NB.EXE’<br />
the executable program for DBFCDX, DBFMDX, DBFNDX<br />
and DBFNTX files, linked with EXOSPACE.<br />
‘NB.HLP’ the user manual in "Help Text File" format.
172 volume VIII Argomenti avanzati e accessori<br />
The file ‘NBASExx4.ZIP’ contains also the following files.<br />
‘NB.PRN’ the user manual in printed text format.<br />
‘NB.RTF’ the user manual in RTF format.<br />
‘NB.TXT’ the user manual in ASCII text format.<br />
‘NB.HTM’ the user manual in HTML format.<br />
The file ‘NBASExx5.ZIP’ contains also the following files.<br />
‘_ADDRESS.DBF’ an example database file.<br />
‘_ADDRESS.NTX’ index file associated to ‘_ADDRESS.DBF’.<br />
‘_ADDRESS.LBL’<br />
a label form file used to print data contained inside<br />
‘_ADDRESS.DBF’ .<br />
‘_ADDRESS.FRM’<br />
a report form file used to print data contained inside<br />
‘_ADDRESS.DBF’ .<br />
‘_ADDRESS.RPT’<br />
a RPT text file<br />
‘_ADDRESS.DBF’ .<br />
used to print data contained inside<br />
‘_MAINMNU.&’<br />
a macro program source example <strong>of</strong> a menu that executes<br />
some others macro programs. This example is made to<br />
demonstrate how nB can execute directly a source code without<br />
compiling it. This example is made only to taste it: it is<br />
very slow and only a speedy machine can give the idea <strong>of</strong> it.<br />
a macro program source example <strong>of</strong> a menu that executes<br />
‘0MAINMNU.&’<br />
some others macro programs. It is the same as ‘_MAINMNU.&’<br />
but it is made to start the execution <strong>of</strong> the compiled macros.<br />
‘0MAINMNU.NB’ compiled macro program ‘0MAINMNU.&’<br />
‘0MAINMNU.BAT’<br />
a batch file to<br />
‘0MAINMNU.NB’<br />
show how to run the execution <strong>of</strong><br />
‘1ADDRESS.&’<br />
a macro program source example for handling a ‘.DBF’ file<br />
containing addresses in various ways.<br />
‘1ADDRESS.NB’ compiled macro ‘1ADDRESS.&’ .<br />
a macro program source example for handling a ‘.DBF’ file<br />
‘2ADDRESS.&’<br />
containing addresses in various ways: a little bit more complicated<br />
than 1ADDRESS.&.<br />
‘2ADDRESS.NB’ compiled macro ‘2ADDRESS.&’ .<br />
a macro program source example for handling a ‘.DBF’ file<br />
‘3ADDRESS.&’<br />
containing addresses in various ways: a little bit more complicated<br />
than ‘2ADDRESS.&’ .<br />
‘3ADDRESS.NB’ compiled macro ‘3ADDRESS.&’.<br />
a macro program source example for handling a ‘.DBF’ file<br />
‘4ADDRESS.&’<br />
containing addresses in various ways: a little bit more complicated<br />
than ‘3ADDRESS.&’ .<br />
‘4ADDRESS.NB’ compiled macro ‘4ADDRESS.&’ .<br />
‘ABIORITM.&’<br />
a macro program source example for calculating the personal<br />
bio wave.<br />
‘ABIORITM.NB’ compiled macro ‘ABIORITM.&’ .<br />
‘_STUDENT.DBF’ a ‘.DBF’ file used inside the BSTUDENT macro example.<br />
‘_STUDENT.NTX’ index file used for ‘_STUDENT.DBF’ .<br />
‘_STUDSTD.DBF’ a ‘.DBF’ file used inside the BSTUDENT macro example.<br />
‘_STUDENT.RPT’<br />
a RPT text file<br />
‘_STUDENT.DBF’ .<br />
used to print data contained inside<br />
‘_STUDSTD.RPT’<br />
a RPT text file<br />
‘_STUDSTD.DBF’ .<br />
used to print data contained inside<br />
‘BSTUDENT.&’<br />
a macro program source example for students evaluation: a<br />
description about students is obtained linking other standard<br />
descriptions.<br />
‘BSTUDENT.NB’ compiled macro ‘BSTUDENT.&’ .
nanoBase 1997 user manual 173<br />
‘CBATMAKE.&’<br />
a macro program source example to generate a batch file to be<br />
used to back up an entire hard disk.<br />
‘CBATMAKE.NB’ compiled macro ‘CBATMAKE.&’ .<br />
‘BROWSE.&’<br />
‘BROWSE.NB’ compiled macro ‘BROWSE.&’ .<br />
a macro program source example to start an automatic<br />
browse.<br />
‘BROWSE.BAT’<br />
batch file to start a ‘.DBF’ browse with the BROWSE macro<br />
program.<br />
‘MENU.&’ a macro program source example for a Dos menu.<br />
‘MENU.NB’ compiled macro ‘MENU.&’ .<br />
‘MENU.BAT’ batch file to use the MENU macro.<br />
The file ‘NBASExx6.ZIP’ contains also the following files: source code for the version 96.06.16.<br />
‘NB.PRG’ the main source file for version 96.06.16.<br />
‘NB_REQ.PRG’ the source file containing links to all the standard functions.<br />
‘NB.LNK’ link file for compilation.<br />
‘NB_NRMAL.RMK’ rmake file to compile with RTLink.<br />
‘NB_EXOSP.RMK’ rmake file to compile with Exospace.<br />
‘NB_RUNTI.RMK’<br />
rmake file to compile with RTLink defining RUNTIME to obtain<br />
a small nB runtime version.<br />
‘MACRO.LNK’ link file to compile and link a macro.<br />
‘MACRO.RMK’ rmake file to compile and link a macro.<br />
The file ‘NBASExx7.ZIP’ contains also the following files: source code for the current version.<br />
‘NB.PRG’ the main source file.<br />
‘REQUEST.PRG’ the source file containing links to all the Clipper functions.<br />
‘STANDARD.PRG’ the source file for standard functions.<br />
‘EXTRA.PRG’ the source file for other standard functions.<br />
‘STANDARD.CH’<br />
general include file that substitutes all include file normally<br />
used for normal Clipper compilations.<br />
‘NB.CH’ include file specific for nB.<br />
‘NB.LNK’ link file for compilation.<br />
‘NB_RUNTI.LNK’ link file for runtime compilation.<br />
‘NB_NRMAL.RMK’ rmake file to compile with RTLink.<br />
‘NB_EXOSP.RMK’ rmake file to compile with Exospace.<br />
‘NB_RUNTI.RMK’<br />
rmake file to compile with RTLink defining RUNTIME to obtain<br />
a small nB runtime version.<br />
‘MACRO.CH’ include file to compile and link a macro.<br />
‘MACRO.LNK’ link file to compile and link a macro.<br />
‘MACRO.RMK’ rmake file to compile and link a macro.<br />
‘CLIPMOUSE.ZIP’<br />
368.3 How to use nB<br />
nB normal syntax is:<br />
nB [nB_parameters] [macro_filename] [macro_parameters]<br />
a simple free library for mouse support under Clipper (c) 1992<br />
Martin Brousseau.<br />
To run nB, just type the word "NB" and press [ Enter ] to execute. It will run in command mode,<br />
this means that it will look like an old xBASE command prompt.
174 volume VIII Argomenti avanzati e accessori<br />
To run the program as a macro interpreter, type the word NB followed from the macro file name<br />
with extention (no default extention is supposed). If parameters are given, after the macro file<br />
name, these will be available inside the public variables: c_Par1, c_Par2, ..., c_Par9. c_Par0 will<br />
contain the macro file name (see the macro file BROWSE.&). nB will terminate execution when<br />
the macro terminates.<br />
These parameters are available for nB:<br />
-c<br />
-w<br />
-?<br />
nB macro "compilation" syntax is:<br />
nB -m source_macro_filename [destination_macro_filename]<br />
Suppress the copyright notice. It is usefull when using nB for<br />
macro interpretation.<br />
Suppress the "Wait-Wheel" if not desired. It is the "Wheel"<br />
that appears at top-left when a macro is interpreted or other<br />
long elaborations are executed.<br />
Shows a short help.<br />
With the -m parameter, nB "compiles" the ASCII source_macro_filename into<br />
destination_macro_filename.<br />
368.4 Status line<br />
nB shows a "status line" at the top <strong>of</strong> the screen when the nB command prompt or the menu<br />
system is active. It shows some important informations.<br />
| |DBFNTX ||*| 1|ADDRESS | 1/ 4|ADDRESS.NTX |<br />
| | | | | | |<br />
| | | | | | |<br />
| | | | | | Last record (7).<br />
| | | | | |<br />
| | | | | Record pointer position (6).<br />
| | | | |<br />
| | | | Active alias (5).<br />
| | | |<br />
| | | Current Work Area (4)<br />
| | |<br />
| | Deleted record appearance (3)<br />
| |<br />
| Actual default database driver (2).<br />
|<br />
Macro recorder indicator (1).<br />
| 1/ 4|ADDRESS.NTX | 1|ADDRESS |<br />
| | |<br />
| | |<br />
| | Order Tag Name (10)<br />
| |<br />
| Order number (9)<br />
|<br />
Order Bag name (8)<br />
(1) This is the place for the macro recorder indicator. The symbol used is "&". Blank means that<br />
the macro recorder is OFF; & blinking means that the macro recorder is ON; & fixed means that<br />
the macro recorder is PAUSED.<br />
(2) The name <strong>of</strong> the default database driver. It is not necessarily the database driver for the active<br />
alias; it is only the database driver that will be used for the next open/create operation.
nanoBase 1997 user manual 175<br />
(3) An asterisk (*) at this position indicates that SET DELETED is OFF. This means that deleted<br />
records are not filtered. When a BLANK is in this place, SET DELETED is ON, so that deleted<br />
records are filtered.<br />
(4) The active work area number, that is, the area <strong>of</strong> the active alias.<br />
(5) The active alias name. Note that the alias name is not necessarily equal to the ‘.DBF’ file<br />
name.<br />
(6) The actual record pointer position for the active alias.<br />
(7) The number <strong>of</strong> records contained inside the active alias.<br />
(8) The Order Bag name; that is the index file name.<br />
(9) The order number.<br />
(10) The order tag (name). When DBFNTX database driver is used, it correspond to the Order<br />
Bag name.<br />
368.5 The dot line<br />
Starting nB without parameters, the dot line appears. This is the place where commands in form<br />
<strong>of</strong> functions may be written and executed like a old xBase.<br />
The functions written inside the command line that don’t result in an error, are saved inside a<br />
history list. This history list may be recalled with [ F2 ] and then the selected history line may be<br />
reused (eventually edited). Key [ up ]/[ down ] may be used to scroll inside the history list without<br />
showing the all list with [ F2 ].<br />
[ Enter ] is used to tell nB to execute the written function.<br />
As the dot line is not an easy way to use such a program, a menu is available pressing [ F10 ] or<br />
[ Alt+M ]. The [ F10 ] key starts the ASSIST() menu. This menu may be started also entering the<br />
name <strong>of</strong> the function: "ASSIST()".<br />
nB includes a simple built-in text editor: DOC(). It may be started from the dot line entering<br />
"DOT()". No special key is dedicated to start this function.<br />
368.6 The menu system<br />
The nB menu system appears differently depending on the place where it is "called". When<br />
available, the menu system appears pressing [ Alt+M ] or [ F10 ].<br />
The Menu system is organised into horizontal menu, vertical menu, and pop-up menu.<br />
The horizontal menu contains selectable items organised horizontally:<br />
One Two Three Four Five<br />
The cursor may be moved on a different position using arrow keys [ Left ]/[ Right ]; [ Esc ] terminates<br />
the menu; [ Enter ] opens a vertical menu.<br />
The vertical menu contains selectable items organised vertically:<br />
One Two Three Four Five<br />
.----------.<br />
|First |<br />
|Second |<br />
|Third |<br />
‘----------’
176 volume VIII Argomenti avanzati e accessori<br />
The cursor may be moved on a different position using arrow keys [ Up ]/[ Down ]; the arrow keys<br />
[ Left ]/[ Right ] change the vertical menu; [ Esc ] closes the vertical the menu; [ Enter ] starts the selected<br />
menu function.<br />
The vertical menu contains selectable items organised vertically:<br />
One Two Three Four Five<br />
.----------.<br />
|First |<br />
|Second >|--------------.<br />
|Third |Sub function 1|<br />
‘----------|Sub function 2|<br />
‘--------------’<br />
The cursor may be moved on a different position using arrow keys [ Up ]/[ Down ]; [ Esc ] closes the<br />
pop-up the menu; [ Enter ] starts the selected menu function.<br />
The following sections describe the menu system.<br />
368.6.1 Menu File<br />
The menu File contains important function on ‘.DBF’ file, indexes, relations and Replaceable<br />
database drivers.<br />
For database files are considered two aspects: the physical aspect, and the logical alias. When a<br />
‘.DBF’ file is opened, it becomes a alias.<br />
<strong>Index</strong>es are considered as index files and index orders.<br />
It follows a brief menu function description.<br />
Change directory<br />
Changes the actual drive and directory.<br />
File .DBF<br />
Contains a pop-up menu for ‘.DBF’ operations.<br />
New .DBF<br />
A ‘.DBF’ file is a table where columns, called Fields, must be specified and lines,<br />
called records, are added, edited and deleted by the program.<br />
Field characteristics are:<br />
the field name must be unique inside the same file, it is<br />
NAME<br />
composed <strong>of</strong> letters, number and underscore (_), but it<br />
must start with a letter and it is not case sensitive.<br />
TYPE the field type determinates the type <strong>of</strong> data it can hold.<br />
is the field total length in characters; it doesn’t matter<br />
LENGTH<br />
DECIMAL<br />
Field Types:<br />
<strong>of</strong> the type <strong>of</strong> data.<br />
is the length <strong>of</strong> positions after decimal point. This information<br />
is used normally for numeric fields. In this<br />
case, take note that the DECIMAL length, together<br />
with the decimal point, will subtract space for the integer<br />
part <strong>of</strong> the number from the total LENGTH <strong>of</strong> the<br />
filed.
nanoBase 1997 user manual 177<br />
C Character<br />
it is a text field long LENGTH characters.<br />
it is a numeric field long LENGTH characters with<br />
DECIMAL characters for decimal positions. Note that<br />
if LENGTH is 4 and DECIMAL is 0 (zero), the<br />
N Numeric<br />
field may contain integers from -999 to 9999; but if<br />
LENGTH is 4 and DECIMAL 1, the field may contain<br />
numbers from -9.9 to 99.9: two position for the integer<br />
part, one position for the decimal point and one position<br />
for decimal.<br />
D Date<br />
it is a date field: it contains only dates; the length<br />
should not be specified as it is automatically 8.<br />
it is a logical (boolean) field: it contains only TRUE,<br />
L Logic<br />
represented by "Y" or "T", or FALSE, represented by<br />
"N" or "F". The length should not be specified as it is<br />
automatically 1.<br />
it is a character field with unknown dimension. It is<br />
recorded into a parallel file with ‘.DBT’ extention. The<br />
M Memo<br />
original ‘.DBF’ file holds a space for a pointer inside<br />
the ‘.DBT’ file. The length <strong>of</strong> a Memo field is automatically<br />
10 and is referred to the memo pointer.<br />
After the function "NEW .DBF" is selected, a table for the field specifications appears.<br />
+--------------------------------+<br />
| Database file structure |<br />
| |<br />
| Field Name Type Length Decimal |<br />
|--------------------------------|<br />
| | | 0| 0 |<br />
| | | | |<br />
| | | | |<br />
| | | | |<br />
| | | | |<br />
| | | | |<br />
| | | | |<br />
To navigate and to edit the table use the following keys:<br />
[ Up ]/[ Down ]/[ Left ][ Right ] move the cursor one position (up, down, left or right);<br />
[ PgUp ] move to previous screen page;<br />
[ PgDn ] move to next screen page;<br />
[ Ctrl+PgUp ] move to top <strong>of</strong> table;<br />
[ Ctrl+PgDn ] move to bottom <strong>of</strong> table;<br />
[ Ctrl+Home ] move to first column;<br />
[ Ctrl+End ] move to last column;<br />
[ Ctrl+Enter ] append a new empty line;<br />
[ Ctrl+F1 ]<br />
delete (cut) the current line and save a copy into the<br />
"clipboard";<br />
[ Ctrl+F2 ] copy current line into the table "clipboard";<br />
insert (paste) the content <strong>of</strong> the "clipboard" in the cur-<br />
[ Ctrl+F3 ]<br />
rent position;<br />
[ Enter ] start editing in the current position;<br />
[ Esc ] terminate;<br />
[ x ] any other key will be written in the current position.<br />
When the editing is terminated, press [ Esc ] and a dialog box will ask for the file name<br />
and the RDD.<br />
xBase files (.DBF) are not all equal, this way, when a new ‘.DBF’ file si created, the<br />
RDD (Replaceable Database Driver) is asked. The normal RDD is DBFNTX, the one<br />
used by Clipper.
178 volume VIII Argomenti avanzati e accessori<br />
Modify .DBF structure<br />
The modification <strong>of</strong> a ‘.DBF’ file structure is a delicate matter if it contains data.<br />
In fact, it is a data transfer from a source ‘.DBF’ file to a destination ‘.DBF’ file with<br />
a different structure. This way, the destination ‘.DBF’ will be updated only for the<br />
fields with the same name <strong>of</strong> the source one. The position may be different, but names<br />
cannot be changed (not so easily).<br />
Mistakes may be dangerous, so, before doing it, it is recommended a backup copy <strong>of</strong><br />
the original ‘.DBF’ file.<br />
Open .DBF<br />
When a ‘.DBF’ file is opened, it becomes a alias, a logical file, placed inside a work<br />
area. The same ‘.DBF’ file may be opened inside different areas with different alias<br />
names.<br />
The required information to open the file are:<br />
File .NTX<br />
FILENAME<br />
ALIAS<br />
RDD<br />
SHARED<br />
READ ONLY<br />
Contains a pop-up menu for physical indexes operations.<br />
the physical file name.<br />
the alias name. If not assigned, it becomes automatically<br />
the same <strong>of</strong> FILENAME without extention.<br />
the Replaceable Database Driver to use to access to this<br />
file.<br />
a logical value: TRUE means that the file will be accessible<br />
to other users, FALSE means use exclusive.<br />
a logical value: TRUE means that the file will be only<br />
readable and no modification will be allowed, FALSE<br />
means that no restriction on editing will be made.<br />
New .NTX / new tag<br />
If the active area is used we have an active alias. In this case a index may be created.<br />
The index is a way to see the active alias ordered without changing the physical<br />
position <strong>of</strong> records.<br />
There are two words to understand: ORDER and INDEX-BAG. The index bag is the<br />
file that contains the information on the record ordering, the order is the rule followed<br />
to order the records. A index bag may contains one or more orders depending on the<br />
Replaceable Database Driver in use.<br />
Typical ‘.NTX’ file are index bag containing only one order.<br />
Depending on the RDD in use the following field may be filled.<br />
INDEX FILENAME<br />
this is the name <strong>of</strong> the index bag.<br />
the expression that defines the rule for the record or-<br />
KEY EXPRESSION<br />
dering.<br />
this is the name to give to the order (tag) when the RDD<br />
permits to have a index bag containing more than one<br />
ORDER NAME<br />
order. In the other case, the index bag name correspond<br />
to the order name.<br />
FOR EXPRESSION<br />
a FOR condition to filter records before indexing.<br />
Open index<br />
If a index file already exists, it can be associated to the active alias simply opening it.<br />
Take note that the system is not able to verify if the index belong the active alias<br />
and if it is not so a error will result.
nanoBase 1997 user manual 179<br />
Alias<br />
Order<br />
INDEX NAME<br />
is the name <strong>of</strong> the index bag file to open.<br />
Contains a pop-up menu for logical databases (alias) operations.<br />
Select<br />
Only one may be the active alias and with this function the active alias may be changed<br />
choosing from the list <strong>of</strong> used areas.<br />
Selecting the area number zero, no alias is active.<br />
Display structure<br />
With this function the active alias structure may be viewed.<br />
Close active alias<br />
Selecting this function the active alias is closed. That is: the ‘.DBF’ file and eventual<br />
indexes are closed.<br />
Close all aliases<br />
With this function all Aliases are closed.<br />
Contains a pop-up menu for logical indexes (orders).<br />
Relation<br />
Order list rebuild<br />
This function rebuild the indexes opened and associated to the active alias.<br />
Order set focus<br />
This function permits to change the active order selecting form the ones opened and<br />
associated to the active alias.<br />
Order list clear<br />
This function closes all orders associated to the active alias.<br />
Contains a pop-up menu for relations (links with other Aliases).<br />
Set relation<br />
This function permits to establish a relation between a alias and a Child alias showing<br />
as a result a unique database.<br />
CHILD is the alias name to connect to the active alias.<br />
is the relation expression that specify the rule for the relation.<br />
The value <strong>of</strong> this expression is the key to access<br />
EXPRESSION<br />
the Child alias: if this Child alias is accessed without<br />
index, it must be the record number, if this Child alias<br />
is accessed via index, it must be a valid index key.<br />
Clear relation<br />
This function eliminates any relation that originate form the active alias.<br />
RDD default<br />
Contains a pop-up menu for Replaceable Database Driver defaults.<br />
Show actual RDD default<br />
It simply shows the actual Replaceable Database Driver.
180 volume VIII Argomenti avanzati e accessori<br />
Set default RDD<br />
Select a new default Replaceable Database Driver.<br />
368.6.2 Menu Edit<br />
The menu Edit contains functions to access data from the active alias (the actual area).<br />
View<br />
This function permits you to view the active alias with eventual relations as a table.<br />
No edit is allowed.<br />
To navigate the table use the following keys.<br />
[ Enter ] start field editing.<br />
[ PgUp ] show previous screen page.<br />
[ PgDn ] show next screen page.<br />
[ Ctrl+PgUp ] show top <strong>of</strong> alias.<br />
[ Ctrl+PgDn ] show bottom <strong>of</strong> file.<br />
[ Ctrl+Home ] show the first column.<br />
[ Ctrl+End ] show last column.<br />
Edit/browse<br />
This function permits you to edit the active alias with eventual relations as a table.<br />
To navigate and edit the table use the following keys.<br />
[ Enter ] start field editing.<br />
[ PgUp ] show previous screen page.<br />
[ PgDn ] show next screen page.<br />
[ Ctrl+PgUp ] show top <strong>of</strong> alias.<br />
[ Ctrl+PgDn ] show bottom <strong>of</strong> file.<br />
[ Ctrl+Home ] show the first column.<br />
[ Ctrl+End ] show last column.<br />
[ Ctrl+Enter ] append a new empty record.<br />
[ Ctrl+F2 ] copy the current record.<br />
[ Ctrl+F3 ] append and paste a record.<br />
[ Ctrl+F4 ]<br />
paste a previously copied record, overwriting the content<br />
<strong>of</strong> the current one.<br />
[ Ctrl+Y ] delete or recall the current record.<br />
[ Ctrl+Del ] delete or recall the current record.<br />
When a memo field is edited:<br />
Replace<br />
[ Esc ] cancel and close the memo window.<br />
[ Ctrl+Y ] line delete.<br />
[ Ctrl+W ] save and close the memo window.<br />
The content <strong>of</strong> a Field <strong>of</strong> the active alias may be replaced with an expression.<br />
The required data is:
nanoBase 1997 user manual 181<br />
Recall<br />
Delete<br />
Pack<br />
FIELD TO REPLACE<br />
NEW VALUE EXPRESSION<br />
WHILE EXPRESSION<br />
FOR EXPRESSION<br />
the Field name to be replaced.<br />
the expression that obtain the new value for the selected<br />
Field.<br />
the WHILE condition expression: the replacement continue<br />
until this expression results True. The constant ‘.T.’<br />
is ever True and is the default.<br />
the FOR condition expression: the replacement is made<br />
for all records that satisfy the condition. The constant<br />
‘.T.’ is ever True and is the default.<br />
The records signed for deletion (deleted but still there), may be recalled (undeleted).<br />
The required data is:<br />
WHILE EXPRESSION<br />
FOR EXPRESSION<br />
the WHILE condition expression: the record recall continue<br />
until this expression results True. The constant ‘.T.’<br />
is ever True and is the default.<br />
the FOR condition expression: the record recall is made<br />
for all records that satisfy the condition. The constant<br />
‘.T.’ is ever True and is the default.<br />
Deletes (sign for deletion) a group <strong>of</strong> record depending on the required conditions.<br />
The required data is:<br />
WHILE EXPRESSION<br />
FOR EXPRESSION<br />
the WHILE condition expression: the record deletion continue<br />
until this expression results True. The constant ‘.T.’<br />
is ever True and is the default.<br />
the FOR condition expression: the record deletion is made<br />
for all records that satisfy the condition. The constant<br />
‘.T.’ is ever True and is the default.<br />
This function eliminates definitely records previously deleted (signed for deletion).<br />
It may work only if the active alias was opened in exclusive mode.<br />
368.6.3 Menu Report<br />
The menu Report contains functions for data report (print). In particular, label files ‘.LBL’ and<br />
report file ‘.RPT’ may be created and used for printing. There is also another way to print, with<br />
the RPT() system that is available inside the nB internal editor DOC().<br />
DBGOTOP()<br />
Moves the record pointer for the active alias at the first logical record.<br />
New label<br />
With this function can be created a standard label file (.LBL under the dBaseIII standard).<br />
Labels may be printed in more than one column and can contain 16 lines maximum.<br />
The label data is the following.
182 volume VIII Argomenti avanzati e accessori<br />
REMARK<br />
a label remark that will not be printed.<br />
HEIGHT the label vertical dimension.<br />
WIDTH the label horizontal dimension.<br />
MARGIN<br />
the left margin in characters.<br />
LINES<br />
the vertical spacing between labels.<br />
SPACES<br />
the horizontal spacing between labels in characters.<br />
ACROSS the number <strong>of</strong> label columns.<br />
LINE 1 The first line inside labels.<br />
LINE n The n-th line inside labels.<br />
LINE 16 The 16th line inside labels.<br />
The number <strong>of</strong> lines inside the labels depend on the HEIGHT and the maximum value is<br />
16.<br />
The label lines can contain constant string and/or string expressions.<br />
See the example below.<br />
Modify label<br />
Margin<br />
<br />
XXXXXXX|XXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXXXXX|XXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXX Height XXXX XXXXXXXXXXXXXXXX<br />
XXXXXXX|XXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXXXXX|XXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
|<br />
| Lines <br />
| Spaces<br />
XX Line 1 XXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XX Line 2 XXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XX Line 3 XXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XX Line 4 XXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XX Line 5 XXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX<br />
| | |<br />
| | |<br />
| | |<br />
+---------------- Across ---------------+<br />
This function permits you to modify a label file.<br />
Label form<br />
This function permits you to print labels with the data provided by the active alias: one<br />
label each record.<br />
The following data is required.<br />
LABEL FILENAME the label filename.<br />
WHILE<br />
the WHILE condition: the label printing goes on as long<br />
as this condition remain True.<br />
FOR<br />
the FOR condition: only the records from the active alias<br />
that satisfy the condition are used for the label print.
nanoBase 1997 user manual 183<br />
New report<br />
This function permits you to create a standard report form file (.FRM under the dBaseIII<br />
standard).<br />
The informations to create a ‘.FRM’ file are divided into two parts: the head and groups; the<br />
columns.<br />
The first part: head and groups, requires the folliwing informations:<br />
PAGE WIDTH<br />
the page width in characters.<br />
LINES PER PAGE<br />
the usable lines per per page.<br />
LEFT MARGIN<br />
the left margin in characters.<br />
DOUBLE SPACED?<br />
double spaced print, yes or no.<br />
PAGE EJECT BEFORE PRINT? form feed before print, yes or no.<br />
PAGE EJECT AFTER PRINT? form feed after print, yes or no.<br />
PLAIN PAGE?<br />
plain page, yes or no.<br />
PAGE HEADER<br />
the page header, max 4 lines (the separation between one<br />
line and the other is obtained writing a semicolon, ";").<br />
GROUP HEADER<br />
the group title.<br />
GROUP EXPRESSION<br />
the group expression (when it changes, the group changes)<br />
SUMMARY REPORT ONLY? only totals and no columns, yes or no.<br />
PAGE EJECT AFTER GROUP? form feed when the group changes, yes or no.<br />
SUB GROUP HEADER<br />
sub group title.<br />
SUB GROUP EXPRESSION the sub group expression.<br />
The second part: columns, requires the following informations structured in table form:<br />
COLUMN HEADER<br />
column head description (it can contain 4 lines separated<br />
with a semicolon).<br />
CONTENT<br />
the column expression.<br />
WIDTH the column width.<br />
DEC.<br />
the decimal length for numeric columns.<br />
TOTALS<br />
totals to be calculated, yes or no (usefull only for numeric<br />
columns).<br />
To navigate and to edit the table use the following keys:<br />
[ Up ]/[ Down ]/[ Left ][ Right ] move the cursor one position (up, down, left or right);<br />
[ PgUp ] move to previous screen page;<br />
[ PgDn ] move to next screen page;<br />
[ Ctrl+PgUp ] move to top <strong>of</strong> table;<br />
[ Ctrl+PgDn ] move to bottom <strong>of</strong> table;<br />
[ Ctrl+Home ] move to first column;<br />
[ Ctrl+End ] move to last column;<br />
[ Ctrl+Enter ] append a new empty line;<br />
[ Ctrl+F1 ]<br />
delete (cut) the current line and save a copy into the "clipboard";<br />
[ Ctrl+F2 ] copy current line into the table "clipboard";<br />
[ Ctrl+F3 ]<br />
insert (paste) the content <strong>of</strong> the "clipboard" in the current<br />
position;<br />
[ Enter ] start editing in the current position;<br />
[ Esc ] terminate;<br />
[ x ] any other key will be written in the current position.<br />
When the editing is terminated, press [ Esc ] and a dialog box will ask for the name to give<br />
to the report form file.<br />
Modify report<br />
This function permits you to modify a standard report form file (.FRM under the dBaseIII
184 volume VIII Argomenti avanzati e accessori<br />
standard).<br />
Report form<br />
This function permits you to print a report form with the data provided by the active alias.<br />
The following data is required.<br />
REPORT FORM FILENAME the label filename.<br />
WHILE<br />
the WHILE condition: the form printing goes on as long<br />
as this condition remain True.<br />
FOR<br />
the FOR condition: only the records from the active alias<br />
that satisfy the condition are used for the report form print.<br />
Create/modify/print text<br />
This function activates the text editor.<br />
368.6.4 Menu HTF<br />
The menu Htf helps on creating and accessing the "Help Text Files". This name, help text file, is<br />
just the name given to it.<br />
A text (Ascii) file prepared like this manual may be transformed into a "Help Text File" that is a<br />
simple text with pointers.<br />
Open help text file<br />
This function permits to open a Help Text File and browse it. The Help Text File name is<br />
required.<br />
New help text file<br />
This function permits to create a new "Help Text File" that is a help file under the nB style.<br />
The source is an Ascii file where three kind <strong>of</strong> information are available: Normal text,<br />
<strong>Index</strong>es and pointers.<br />
<strong>Index</strong>es and Pointers are word or phrases delimited with user defined delimiters; indexes<br />
are placed inside the text to indicate an argument, pointers are placed inside the text to<br />
indicate a reference to indexes.<br />
Inside this manual, indexes are delimited with ## and ##, so the titles are here indexes;<br />
pointers are delimited with < and >.<br />
Only one index per line is allowed, only one pointer per line is allowed.<br />
The Delimiters used do identify indexes and pointers are user defined; the _start_ identifier<br />
symbol can be equal to the _end_ identifier symbol. The symbols used for indexes cannot<br />
be used for the pointers.<br />
So, the informations required are:<br />
SOURCE TEXT FILENAME the filename <strong>of</strong> the text source file.<br />
DESTINATION FILENAME<br />
the filename <strong>of</strong> the destination Help Text File (suggested<br />
‘.HLP’ extention).<br />
INDEX START CODE<br />
the index start symbol; suggested ##.<br />
INDEX END CODE<br />
the index end symbol; suggested ##.<br />
POINTER START CODE<br />
the pointer start symbol; suggested .
nanoBase 1997 user manual 185<br />
New HTML file<br />
This function permits to create a new HTML file form a text file formatted to obtain a HTF<br />
file.<br />
The informations required are:<br />
SOURCE TEXT FILENAME the filename <strong>of</strong> the text source file.<br />
DESTINATION FILENAME<br />
the filename <strong>of</strong> the destination Help Text File (suggested<br />
‘.HLP’ extention).<br />
INDEX START CODE<br />
the index start symbol; suggested ##.<br />
INDEX END CODE<br />
the index end symbol; suggested ##.<br />
POINTER START CODE<br />
the pointer start symbol; suggested .<br />
HTML TITLE the title for the html page.<br />
368.6.5 Menu Macro<br />
The menu Macro helps on creating macros (programs) with a macro recorder, a macro "compiler"<br />
and a macro executor.<br />
Start recording<br />
This function simply starts or pause the macro recording. The menu items that end with<br />
"&", may be recorded by this macro recorder.<br />
Save recording<br />
A recorded macro may be saved into a ASCII file that may be later modified or simply used<br />
as it is. The filename is requested.<br />
Erase recording<br />
While recording or when the macro recorder is paused, it is possible to erase all previous<br />
recording with this function.<br />
Edit recording<br />
While recording or when the macro recorder is paused, it is possible to edit all previous<br />
recording, for example adding more comments or simply to see what the recorder does.<br />
Macro compilation<br />
A macro file (a program) contained inside a ASCII file, may be compiled into a different<br />
file format to speed up execution. The source filename and the destination filename are<br />
requested.<br />
Load + execute macro<br />
A macro file (a program) in ASCII form or compiled, may be executed.<br />
A macro file may require some parameters.<br />
This function asks for the macro filename to start and the possible parameter to pass to it.
186 volume VIII Argomenti avanzati e accessori<br />
368.6.6 Menu Info<br />
The menu Info is the information menu.<br />
ABOUT<br />
a brief copyright notice.<br />
starts the browse <strong>of</strong> ‘NB.HLP’ , the nB Help Text File manual<br />
MANUAL BROWSE<br />
if it is present in the current directory or it is found in the<br />
PATH (the Dos SET PATH).<br />
[F1] HELP [F1] reminder.<br />
[F3] ALIAS INFO<br />
[F3] reminder. It shows all the available information on the<br />
active alias.<br />
[F5] SET OUTPUT TO [F5] reminder. It defines the output peripheral or file.<br />
368.6.7 Menu Doc<br />
This menu actually appears only inside the DOC() function, the nB text editor.<br />
New<br />
Open<br />
Save<br />
Save as<br />
It starts the editing <strong>of</strong> a new empty text.<br />
It opens for editing a new textfile.<br />
It saves the text file under editing.<br />
It saves the text file under editing asking for a new name.<br />
Set output to<br />
It permits to change the default output peripheral: the default is the screen.<br />
Print as it is<br />
It prints on the output peripheral the content <strong>of</strong> the text as it is.<br />
Print with RPT() once<br />
It prints on the output peripheral the content <strong>of</strong> the text only once replacing possible text<br />
variables.<br />
Print with RPT() std<br />
It prints on the output peripheral the content <strong>of</strong> the text repeating this print for every record<br />
contained inside the archive alias.<br />
Exit DOC()<br />
Terminates the use <strong>of</strong> DOC() the text/document editing/print function.
nanoBase 1997 user manual 187<br />
368.7 The text editor DOC()<br />
The function Doc() activates a simple text editor usefull to build some simple reports.<br />
Inside this function a menu is available and is activated pressing [ Alt+M ] or [ F10 ]. The Doc()<br />
menu is part <strong>of</strong> the nB menu system.<br />
DOC() may handle text files <strong>of</strong> a teorical maximum <strong>of</strong> 64K.<br />
DOC() may be particularly useful to create formatted text with variables identified by CHR(174)<br />
and CHR(175) delimiters: when an active alias exists, [ F2 ] gives a list <strong>of</strong> insertable fields.<br />
[ Esc ] Exit DOC().<br />
[ F1 ] Call the help.<br />
[ F2 ] Field list.<br />
[ up ] / [ Ctrl+E ] Line up.<br />
[ down ] / [ Ctrl+X ] Line down.<br />
[ left ] / [ Ctrl+S ] Character left.<br />
[ right ] / [ Ctrl+D ] Character right.<br />
[ Ctrl+right ] / [ Ctrl+A ] Word left.<br />
[ Ctrl+left ] / [ Ctrl+F ] Word right.<br />
[ Home ] Line start.<br />
[ End ] Line end.<br />
[ Ctrl+Home ] Top window.<br />
[ Ctrl+End ] Bottom window.<br />
[ PgUp ] Previous window.<br />
[ PgDn ] Next window.<br />
[ Ctrl+PgUp ] Document start.<br />
[ Ctrl+PgDn ] End document.<br />
[ Del ] Delete character (right).<br />
[ Backspace ] Delete character Left.<br />
[ Tab ] Insert tab.<br />
[ Ins ] Toggle insert/overwrite.<br />
[ Enter ] Next line.<br />
[ Ctrl+Y ] Delete line.<br />
[ Ctrl+T ] Delete word right.<br />
[ F10 ] / [ Alt+M ] DOC() menu.<br />
368.8 The help text file<br />
nB provides a basic hypertext system to build simple help files. A source text file with "indexes"<br />
and "pointers" to indexes is translated into a "help text file" (a ‘.DBF’ file); then, this file is<br />
browsed by nB.<br />
The source file can have a maximum line width <strong>of</strong> 80 characters; each line can terminate with<br />
CR or CR+LF.<br />
"<strong>Index</strong>es" are string delimited by index delimiters (default "##"); "pointers" are string delimited<br />
by pointer delimiters (default "") and refers to indexes.<br />
Inside a text, indexes must be unique; pointers can be repeated anywhere. A text can contain a<br />
maximum <strong>of</strong> 4000 indexes.<br />
Inside this manual, titles are delimited with "##" as they are indexes; strings delimited with "" identify a reference to a title with the same string.
188 volume VIII Argomenti avanzati e accessori<br />
To browse a previously created Help Text File, use the following keys:<br />
[ Esc ] Exit.<br />
[ UpArrow ] Move cursor up.<br />
[ DownArrow ] Move cursor down.<br />
[ PgUp ] Move cursor PageUp.<br />
[ PgDn ] Move cursor Pagedown.<br />
[ Ctrl+PgUp ] Move cursor Top.<br />
[ Ctrl+PgDn ] Move cursor Bottom.<br />
[ Enter ] Select a reference (pointer).<br />
[ ] Go to next selected reference (pointer).<br />
[ Shift+F3 ] Search for a new pattern.<br />
[ F3 ] Repeat previous search.<br />
368.9 Macro<br />
nB can execute (run) macro files. There may be three kind <strong>of</strong> macro files: ASCII (usually with<br />
.& extention); "compiled" (usually with .NB extention); EXE files (compiled with Clipper and<br />
linked).<br />
"Compiled" macro files are executed faster then the ASCII source files.<br />
EXE macro files are the fastest.<br />
368.9.1 Macro statements<br />
The statements recognised from nB are very similar to Clipper, with some restrictions.<br />
Note that: the FOR statement is not included; there is no function declaration; procedure calls<br />
cannot transfer variables; only public variables are allowed.<br />
PROCEDURE<br />
Procedures are the basic building blocks <strong>of</strong> a nB macro.<br />
Procedures are visible only inside the current macro file.<br />
The procedure structure is as follows:<br />
PROCEDURE procedure_name<br />
statements...<br />
[RETURN]<br />
statements...<br />
ENDPROCEDURE<br />
A procedure definition begins with a PROCEDURE declaration followed with the<br />
procedure_name and ends with ENDPROCEDURE.<br />
Inside the PROCEDURE - ENDPROCEDURE declaration are placed the executable<br />
statements which are executed when the procedure is called.<br />
Inside the PROCEDURE - ENDPROCEDURE declaration, the RETURN statement may<br />
appear. In this case, encountering this RETURN statement, the procedure execution is immediately<br />
terminated and control is passed to the statement following the calling one.<br />
The procedure definition do not permit to receive parameters from the calling statement.
nanoBase 1997 user manual 189<br />
DO PROCEDURE<br />
There is only one way to call a procedure:<br />
DO PROCEDURE procedure_name<br />
When the statement DO PROCEDURE is encountered, the control is passed to the begin <strong>of</strong><br />
the called PROCEDURE. After the PROCEDURE execution, the control is returned to the<br />
statement following DO PROCEDURE.<br />
The procedure call do not permit to send parameters to the procedure.<br />
BEGIN SEQUENCE<br />
The BEGIN SEQUENCE - END structure permits to define a sequence <strong>of</strong> operation that<br />
may be broken.<br />
Inside nB, this control structure is useful only because there is the possibility to break the<br />
execution and pass control over the end <strong>of</strong> it.<br />
This way, encountering BREAK means: "go to end".<br />
BEGIN SEQUENCE<br />
statements...<br />
[BREAK]<br />
statements...<br />
END<br />
Inside nB, error exception handling is not supported.<br />
DO CASE<br />
This is a control structure where only the statements following a True CASE condition are<br />
executed.<br />
When the DO CASE statement is encountered, the following CASE statements are tested.<br />
The first time that a condition returns True, the CASE’s statements are executed and then<br />
control is passed over the END case.<br />
That is: only one CASE is taken into consideration.<br />
If no condition is True, the statements following OTHERWISE are executed.<br />
DO CASE<br />
CASE lCondition1<br />
statements...<br />
[CASE lCondition2]<br />
statements...<br />
[OTHERWISE]<br />
statements...<br />
END<br />
WHILE<br />
The structure WHILE - END defines a loop based on a condition: the loop is repeated until<br />
the condition is True.<br />
The loop execution may be broken with the EXIT statement: it transfer control after the<br />
END while.<br />
The LOOP statement may be use to repeat the loop: it transfer the control to the beginning<br />
<strong>of</strong> the loop.<br />
WHILE lCondition<br />
statements...<br />
[EXIT]<br />
statements...<br />
[LOOP]<br />
statements...<br />
END
190 volume VIII Argomenti avanzati e accessori<br />
IF<br />
The IF - END control structure executes a section <strong>of</strong> code if a specified condition is True.<br />
The structure can also specify alternative code to execute if the condition is False.<br />
IF lCondition1<br />
statements...<br />
[ELSE]<br />
statements...<br />
END<br />
368.9.2 Variable declaration<br />
Inside nB, variables are created using a specific function:<br />
MEMPUBLIC( "cVarName" )<br />
For example,<br />
MEMPUBLIC( "Name" )<br />
creates the variable Name.<br />
The scope <strong>of</strong> the created variable is global and there is no way to restrict the visibility <strong>of</strong> it.<br />
When a variable is no more needed or desired, it can be released:<br />
MEMRELEASE( "cVarName" )<br />
The variable declaration do not defines the variable type. Every variable may receive any kind <strong>of</strong><br />
data; that is that the type depends on the type <strong>of</strong> data contained.<br />
368.9.3 Macro structure<br />
A nB macro must be organised as follow. There may be two situations: Macros with procedures<br />
and macros without procedures.<br />
Macro with procedures:<br />
PROCEDURE procedure_name_1<br />
statements...<br />
[RETURN]<br />
statements...<br />
ENDPROCEDURE<br />
PROCEDURE procedure_name_2<br />
statements...<br />
[RETURN]<br />
statements...<br />
ENDPROCEDURE<br />
...<br />
...<br />
DO PROCEDURE procedure_name_n<br />
Macro without procedures:<br />
statements...<br />
statements...<br />
statements...<br />
statements...<br />
statements...<br />
nB Macros may be compiled with Clipper. To do so, the first structure example must be changed<br />
as follows:
nanoBase 1997 user manual 191<br />
#INCLUDE MACRO.CH<br />
DO PROCEDURE procedure_name_nth<br />
...<br />
PROCEDURE procedure_name_1<br />
statements...<br />
[RETURN]<br />
statements...<br />
ENDPROCEDURE<br />
PROCEDURE procedure_name_2<br />
statements...<br />
[RETURN]<br />
statements...<br />
ENDPROCEDURE<br />
...<br />
...<br />
To compile a macro with Clipper, the macro file name can be changed into ‘MACRO.PRG’ and<br />
RTLINK MACRO.RMK [Enter]<br />
should be started.<br />
368.9.4 Macro comments<br />
A nB Macro source file can contain comments. only the "//" comment is recognised! This way:<br />
* and /*...*/ will generate errors!<br />
ATTENTION: to simplify the macro interpretation, lines such as this:<br />
qqout( "You can’t do that // you can’t do that!" )<br />
will generate an error as the interpreter will read only:<br />
qqout( "You can’t do that<br />
Sorry!<br />
368.9.5 Macro long lines split<br />
Inside a nB macro, long lines may be splitted using ";" (semicolon). Please note that: lines can<br />
only be splitted and not joined; a resulting command line cannot be longer then 254 characters.<br />
368.9.6 The macro recorder<br />
Inside the functions ASSIST() and DOC() is available the Macro recorder menu.<br />
When a macro recording is started, a "&" appears on the left side <strong>of</strong> the status bar. It it blinks, the<br />
recording is active, if it is stable, the recording is paused.<br />
The macro recording is not exactly a step-by-step recording <strong>of</strong> all action taken, but a translation<br />
(as good as possible) <strong>of</strong> what you have done.
192 volume VIII Argomenti avanzati e accessori<br />
The macro recorder is able to record only the menu functions that terminates with the "&" symbol<br />
and all what is inserted at the dot command line.<br />
The macro recording can be viewed and edited during the recording. The macro recording can<br />
be saved into a text file (a macro file).<br />
368.10 Data types<br />
The data types supported in the nB macro language are the same as Clipper:<br />
Array<br />
Character<br />
Code Block<br />
Numeric<br />
Date<br />
Logical<br />
Memo<br />
NIL<br />
368.10.1 Character<br />
The character data type identifies character strings <strong>of</strong> a fixed length. The character set corresponds<br />
to: CHR(32) through CHR(255) and the null character, CHR(0).<br />
Valid character strings consist <strong>of</strong> zero or more characters with a theoretical maximum <strong>of</strong> 65535<br />
characters. The real maximum dimension depends on the available memory.<br />
Character string constants are formed by enclosing a valid string <strong>of</strong> characters within a designed<br />
pair <strong>of</strong> delimiters. There are three possible delimiter pairs:<br />
two single quotes like ‘’string_constant’’;<br />
two double quotes like ‘"string_constant"’;<br />
left and right square brackets like ‘[string_constant]’.<br />
These three different kind <strong>of</strong> delimiters are available to resolve some possible problems:<br />
I don’t want it -> "I don’t want it"<br />
She said, "I love hin" -> ’She said, "I love hin"’<br />
He said, "I don’t want it" -> [He said, "I don’t want it"]<br />
The following table shows all operations available inside nB for character data types. These<br />
operations act on one or more character expressions and the result is not necessarily a character<br />
data type.<br />
+ Concatenate.<br />
- Concatenate without intervening spaces.<br />
== Compare for exact equity.<br />
!=, , # Compare for inequity.<br />
< Compare for sorts before
nanoBase 1997 user manual 193<br />
Compare for sorts after.<br />
>= Compare for sorts after or same as.<br />
:= In line assign.<br />
$ Test for substring existence.<br />
ALLTRIM() Remove leading and trailing spaces.<br />
ASC() Convert to numeric ASCII code equivalent.<br />
AT() Locate substring position.<br />
CTOD() Convert to date.<br />
DESCEND() Convert to complemented form.<br />
EMPTY() Test for null or blank string.<br />
ISALPHA() Test for initial letter.<br />
ISDIGIT() Test for initial digit.<br />
ISLOWER() Test for initial lowercase letter.<br />
ISUPPER() Test for initial uppercase letter.<br />
LEFT() Extract substring form the left.<br />
LEN() Compute string length in characters.<br />
LOWER() Convert letters to lowercase.<br />
LTRIM() Remove leading spaces.<br />
PADC() Pad with leading and trailing spaces.<br />
PADL() Pad with leading spaces.<br />
PADR() Pad with trailing spaces.<br />
RAT() Locate substring position starting from the right.<br />
RIGHT() Extract substring form the right.<br />
RTRIM() Remove trailing spaces.<br />
SOUNDEX() Convert to soundex equivalent.<br />
SPACE() Create a blank string <strong>of</strong> a defined length.<br />
STRTRAN() Search and replace substring.<br />
STUFF() Replace substring.<br />
SUBSTR() Extract substring.<br />
TRANSFORM() Convert to formatted string.<br />
UPPER() Convert letters to uppercase<br />
VAL() Convert to numeric.<br />
VALTYPE() Evaluates data type directly.<br />
368.10.2 Memo<br />
The memo data type is used to represent variable length character data that can only exist in the<br />
form <strong>of</strong> a database field.<br />
Memo fields are not stored inside the main database file (.DBF) but inside a separate file (.DBT).<br />
A memo field can contain up to 65535 characters, that is the same maximum dimension <strong>of</strong> character<br />
fields. In fact, originally xBases, couldn’t have character string longer than 254 characters.<br />
As here memo fields are very similar to long character strings, you may forget that there is a<br />
difference.<br />
All the operations that may be applied to character strings, may be used with memo fields; the<br />
following functions may be use especially for memo fields or long character strings.<br />
HARDCR() Replace s<strong>of</strong>t with hard carriage returns.<br />
MEMOEDIT() Edit contents.<br />
MEMOLINE() Extract a line <strong>of</strong> a text.
194 volume VIII Argomenti avanzati e accessori<br />
MEMOREAD() Read form a disk text file.<br />
MEMOTRAN() Replace s<strong>of</strong>t and hard carriage returns.<br />
MEMOWRIT() Write to disk text file.<br />
MLCOUNT() Count lines.<br />
MLPOS() Compute position.<br />
368.10.3 Date<br />
The date data type is used to represent calendar dates.<br />
Supported dates are from 0100.01.01 to 2999.12.31 and null or blank date.<br />
The appearance <strong>of</strong> a date is controlled from SETVERB("DATEFORMAT"). The default is<br />
"dd/mm/yyyy" and it may easily changed for example with SETVERB("DATEFORMAT",<br />
"MM/DD/YYYY") to the US standard.<br />
There is no way to represent date constants; these must be replaced with the CTOD() function.<br />
For example if the date 11/11/1995 is to be written, the right way is:<br />
CTOD( "11/11/1995" )<br />
The character string "11/11/1995" must respect the date format defined as before explained.<br />
The function CTOD() will accept only valid dates, and null dates:<br />
CTOD( "" )<br />
A null date is ever less than any other valid date.<br />
The following table shows all operations available inside nB for date data types. These operations<br />
act on one or more date expressions and the result is not necessarily a character data type.<br />
+ Add a number <strong>of</strong> days to a date.<br />
- Subtract days to a date.<br />
== Compare for equity.<br />
!=, , # Compare for inequity.<br />
< Compare for earlier<br />
Compare for later.<br />
>= Compare for later or same as.<br />
:= In line assign.<br />
CDOW() Compute day <strong>of</strong> week name.<br />
CMONTH() Compute month name.<br />
DAY() Extract day number.<br />
DESCEND() Convert to complemented form.<br />
DOW() Compute day <strong>of</strong> week.<br />
DTOC()<br />
Convert to character string with the format defined with<br />
SETVERB( "DATEFORMAT" ).<br />
DOTOS() Convert to character string in sorting format (YYYYMMDD).<br />
EMPTY() Test for null date.<br />
MONTH() Extract month number.<br />
VALTYPE() Evaluates data type directly.<br />
YEAR() Extract entire year number, including century.
nanoBase 1997 user manual 195<br />
368.10.4 Numeric<br />
The numeric data type identifies real number. The theoretical range is form 10^-308 to 10^308<br />
but the numeric precision is guaranteed up to 16 significant digits, and formatting a numeric<br />
value for display is guaranteed up to a length <strong>of</strong> 32 (30 digits, a sign, and a decimal point). That<br />
is: numbers longer than 32 bytes may be displayed as asterisks, and digits other then most 16<br />
significant ones are displayed as zeroes.<br />
Numeric constants are written without delimiters. The following are valid constant numbers:<br />
12345<br />
12345.678<br />
-156<br />
+1256.789<br />
-.789<br />
If a numeric constant is delimited like character strings, it becomes a character string.<br />
The following table shows all operations available inside nB for numeric data types. These operations<br />
act on one or more numeric expressions and the result is not necessarily a numeric data<br />
type.<br />
+ Add or Unary Positive.<br />
- Subtract or Unary Negative.<br />
*<br />
Multiply.<br />
/ Divide.<br />
% Modulus.<br />
^, ** Exponentiate.<br />
== Compare for equity.<br />
!=, , # Compare for inequity.<br />
< Compare for less than.<br />
>= Compare for less than or equal.<br />
> Compare for greater than.<br />
>= Compare for greater than or equal.<br />
:= In line assign.<br />
ABS() Compute absolute value.<br />
CHR() Convert to ASCII character equivalent.<br />
DESCEND() Convert to complemented form.<br />
EMPTY() Test for zero.<br />
EXP() Exponentiate with e as the base.<br />
INT() Convert to integer.<br />
LOG() Compute natural logarithm.<br />
MAX() Compute maximum.<br />
MIN() Compute minimum.<br />
ROUND() Round up or down()<br />
SQRT() Compute square root.<br />
STR() Convert to character.<br />
TRANSFORM() Convert to formatted string.<br />
VALTYPE() Evaluates data type directly.<br />
Number appearence may be affected by SETVERB("FIXED") and consequently by<br />
SETVERB("DECIMALS"). If SETVERB("FIXED") is True, numbers are displayed with a fixed<br />
decimal position. The number <strong>of</strong> decimal positions is defined by SETVERB("DECIMALS"). For
196 volume VIII Argomenti avanzati e accessori<br />
that reason, the default is SETVERB("FIXED", .F.) and SETVERB("DECIMALS", 2), that is,<br />
no fixed decimal position, but if they will be activated, the default is two decimal digits.<br />
368.10.5 Logical<br />
The logical data type identifies Boolean values.<br />
Logical constants are:<br />
‘.T.’ True.<br />
‘.F.’ False.<br />
When editing a logical field, inputs may be:<br />
y, Y, t, T for True<br />
n, N, f, F for False<br />
The following table shows all operations available inside nB for logical data types. These operations<br />
act on one or more logical expressions and the result is not necessarily a logical data<br />
type.<br />
.AND. And.<br />
.OR. Or.<br />
.NOT. or !<br />
Negate.<br />
== Compare for equity.<br />
!=, , or # Compare for inequity.<br />
Comparing two logical values, False (‘.F.’) is always less than True (‘.T.’).<br />
368.10.6 NIL<br />
NIL is not properly a data type, it represent the value <strong>of</strong> an uninitialised variable.<br />
Inside nB (like what it happens inside Clipper), variables are not declared with the data type that<br />
they will contain. This means that a variable can contain any kind <strong>of</strong> data. In fact, nB variables<br />
are pointer to data and a pointer to "nothing" is NIL.<br />
NIL may be used as constant for assignment or comparing purpose:<br />
NIL<br />
Fields (database fields) cannot contain NIL.<br />
The following table shows all operations available inside nB for the NIL data type. Except for<br />
these operations, attempting to operate on a NIL results in a runtime error.<br />
== Compare for equity.<br />
!=, , # Compare for inequity.<br />
< Compare for less than.<br />
Compare for greater than.<br />
>= Compare for greater than or equal.<br />
:= In line assign.<br />
EMPTY() Test for NIL.<br />
VALTYPE() Evaluates data type directly.
nanoBase 1997 user manual 197<br />
For the purpose <strong>of</strong> comparison, NIL is the only value that is equal to NIL. All other values are<br />
greater than NIL.<br />
Variables are created inside nB with MEMPUBLIC(). This function creates variables which will<br />
be automatically initialised to NIL.<br />
368.10.7 Array<br />
The array data type identifies a collection <strong>of</strong> related data items that share the same name. Each<br />
value in an array is referred to as an element.<br />
Array elements can be <strong>of</strong> any data type except memo (memo is available only inside database<br />
fields). For example the first element can be a character string, the second a number, the third a<br />
date and so on. Arrays can contain other arrays and code blocks as elements.<br />
The variable containing the array does not contains the entire array, but the reference to it.<br />
When the NIL type was described, it was cleared that variables doesn’t contains real data,<br />
but pointer to data. But this happens in a transparent way, that is that when the a variable is<br />
assigned to another (for example A := B) the variable receiving the assignment will receive<br />
a pointer to a new copy <strong>of</strong> the source data. This is not the same with arrays: assigning to a<br />
variable an array, will assign to that variable a pointer to the same source array and not to a<br />
new copy <strong>of</strong> it.<br />
If arrays are to be duplicated, the ACLONE() function is to be used.<br />
An array constant may be expressed using curly brackets {}. See the examples below.<br />
A := { "first_element", "second_element", "third_element" }<br />
With this example, the variable A contain the reference to an array with three element containing<br />
character string.<br />
A[1] == "first_element"<br />
A[2] == "second_element"<br />
A[3] == "third_element"<br />
Arrays may contain also no element: empty array and may be expressed as:<br />
{}<br />
The array element is identified by a number enclosed with square brackets, following the variable<br />
name containing the reference to the array. The first array element is one.<br />
If an array contains arrays, we obtain a multidimensional array. For example:<br />
A := { { 1, 2 }, { 3, 4 }, { 5, 6 } }<br />
is equivalent to the following table.<br />
1 2<br />
3 4<br />
5 6
198 volume VIII Argomenti avanzati e accessori<br />
With this example, the variable A contain the reference to a bidimensional array containing numbers.<br />
A[1,1] or A[1][1] contains 1<br />
A[1,2] or A[1][2] contains 2<br />
A[2,1] or A[2][1] contains 3<br />
and so on.<br />
As arrays may contain mixed data, it is the user who have to handle correctly the element numbers.<br />
For example:<br />
A := { "hello", { 3, 4 }, 1234 }<br />
A[1] == "hello"<br />
A[2] == reference to { 3, 4 }<br />
A[3] == 1234<br />
A[2,1] or A[2][1] contains 3<br />
A[2,2] or A[2][2] contains 4<br />
A[1,1] is an error!<br />
The following table shows all operations available inside nB for arrays.<br />
:= In line assign.<br />
AADD() Add dynamically an element to an array.<br />
ACLONE() Create a copy <strong>of</strong> an array.<br />
ACOPY() Copy element by element an array to another.<br />
ADEL() Delete one element inside an array.<br />
AFILL() Fill all array elements with a value.<br />
AINS() Insert an element inside an array.<br />
ARRAY() Creates an array <strong>of</strong> empty elements.<br />
ASCAN() Scan the array elements.<br />
ASIZE() Resize an array.<br />
ASORT() Sort the array elements.<br />
EMPTY() Test for no elements.<br />
VALTYPE() Evaluates data type directly.<br />
368.10.8 Code block<br />
The code block data type identifies a small piece <strong>of</strong> executable program code.<br />
A code block is something like a little user defined function where only a sequence <strong>of</strong> functions<br />
or assignments may appear: no loops, no IF ELSE END.<br />
A code block may receive argument and return a value after execution, just like a function.<br />
The syntax is:<br />
{ | [argument_list] | exp_list }<br />
That is: the argument_list is optional; the exp_list may contain one or more expressions separated<br />
with a comma.
nanoBase 1997 user manual 199<br />
For example, calling the following code block will give the string "hello world" as result.<br />
{ || "hello world" }<br />
The following code block require a numeric argument an returns the number passed as argument<br />
incremented:<br />
{ | n | n+1 }<br />
The following code block requires two numeric arguments and returns the sum <strong>of</strong> the two square<br />
radix:<br />
{ | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }<br />
But code blocks may contains more expressions and the result <strong>of</strong> the execution <strong>of</strong> the code block<br />
is the result <strong>of</strong> the last expression.<br />
The following code block executes in sequence some functions and give ever "hello world" as a<br />
result.<br />
{ | a, b | functionOne(a), functionTwo(b), "hello world" }<br />
To start the execution <strong>of</strong> a code block a function is used: EVAL()<br />
For example, a code block is assigned to a variable and then executed.<br />
B := { || "hello world" }<br />
EVAL( B ) == "hello world"<br />
Another example with a parameter.<br />
B := { | n | n+1 }<br />
EVAL( B, 1 ) == 2<br />
Another example with two parameters.<br />
B := { | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }<br />
EVAL( B, 2, 4 ) == 20<br />
And so on.<br />
The following table shows some operations available inside nB for code blocks: many functions<br />
use code blocks as argument.<br />
:= In line assign.<br />
AEVAL() Evaluate (execute) a code block for each element in an array.<br />
BCOMPILE() Convert (compile) a character string into a code block.<br />
DBEVAL()<br />
Evaluate (execute) a code block for each record in the active<br />
alias.<br />
EVAL() Evaluate a code block once.<br />
VALTYPE() Evaluates data type directly.
200 volume VIII Argomenti avanzati e accessori<br />
368.11 Operators<br />
Here is a list with a brief description <strong>of</strong> the operators available inside nB.<br />
cString1 $ cString2<br />
Substring comparison.<br />
If cString1 is contained inside cString2 the result is true (‘.T.’).<br />
nNumber1 % nNumber2<br />
Modulus.<br />
The result is the remainder <strong>of</strong> nNumber1 divided by nNuber2.<br />
()<br />
Function or grouping indicator.<br />
nNumber1 * nNumber2<br />
Multiplication.<br />
nNumber1 ** nNumber2<br />
nNumber1 ^ nNumber2<br />
Exponentiation.<br />
nNumber1 + nNumber2<br />
dDate + nNumber<br />
Addition, unary positive.<br />
cString1 + cString2<br />
String concatenation.<br />
The result is a string beginning with the content <strong>of</strong> cString1 and following with the content <strong>of</strong><br />
cString2.<br />
nNumber1 - nNumber2<br />
dDate1 - dDate2<br />
dDate - nNumber<br />
Subtraction, unary negative.<br />
cString1 - cString2<br />
String concatenation.<br />
The result is a string containing cString1 after trimming trailing blanks and cString2.<br />
idAlias->idField<br />
FIELD->idVar<br />
MEMVAR->idVar<br />
Alias assignment.<br />
The alias operator implicitly SELECTs the idAlias before evaluating idField. When the evaluation<br />
is complete, the original work area is SELECTed again.<br />
lCondition1 .AND. lCondition2<br />
Logical AND.<br />
.NOT. lCondition
nanoBase 1997 user manual 201<br />
Logical NOT.<br />
lCondition1 .OR. lCondition2<br />
Logical OR.<br />
nNumber1 / nNumber2<br />
Division.<br />
object:message[(argument list)]<br />
Send.<br />
idVar := exp<br />
Inline assign.<br />
exp1 exp2<br />
Greater than.<br />
exp1 >= exp2<br />
Greater than or equal.<br />
@idVar<br />
Pass-by-reference.<br />
[]<br />
aArray[nSubscript, ...]<br />
aArray[nSubscript1][nSubscript2] ...<br />
Array element indicator.<br />
368.12 Delimiters<br />
Here is the delimiter list recognised from nB.<br />
{ exp_list }<br />
Literal array delimiters.<br />
{ |param_list| exp_list }<br />
Code block delimiters.<br />
"cString"<br />
’cString’<br />
[cString]
202 volume VIII Argomenti avanzati e accessori<br />
String delimiters.<br />
368.13 Code blocks<br />
A code block is a sequence <strong>of</strong> function, assignments and constant like the following:<br />
sqrt(10)<br />
nResult := 10 * n<strong>Index</strong><br />
Suppose that the above sequence <strong>of</strong> operations has a meaning for you. We want to create a box<br />
containing this sequence <strong>of</strong> operation. This box is contained inside a variable:<br />
bBlackBox := { || sqrt(10), nResult := 10 * n<strong>Index</strong> }<br />
Note the comma used as separator.<br />
Now bBlackBox contains the small sequence seen before. To execute this sequence, the function<br />
EVAL() is used:<br />
EVAL(bBlackBox)<br />
The execution <strong>of</strong> the code block gives a result: the value <strong>of</strong> the last operation contained inside<br />
the code block. In this case it is the result <strong>of</strong> 10*n<strong>Index</strong>. For that reason, if the execution <strong>of</strong> the<br />
code block must give a fixed result, it can terminate with a constant.<br />
A code block may receive parameters working like a function. Try to imagine that we need to do<br />
the following.<br />
function multiply( nVar1, nVar2 )<br />
return nVar * nVar2<br />
endfunction<br />
A code block that does the same is:<br />
bMultiply := { | nVar1, nVar2 | nVar1 * nVar2 }<br />
To evaluate it, for example trying to multiply 10 * 5:<br />
nResult := EVAL( bMultiply, 10, 5 )<br />
and nResult will contain 50.<br />
368.14 Standard functions<br />
With nB all Clipper standard functions may be used. Here follows a short description.<br />
368.14.1 AADD()<br />
Array add<br />
AADD(aTarget, expValue) ⇒ Value<br />
aTarget is the array to add a new element to.<br />
expValue is the value assigned to the new element.<br />
It increases the actual length <strong>of</strong> the target array by one. The newly created array element is
nanoBase 1997 user manual 203<br />
assigned the value specified by expValue.<br />
368.14.2 ABS()<br />
Absolute<br />
ABS(nExp) ⇒ nPositive<br />
nExp is the numeric expression to evaluate.<br />
ABS() returns a number representing the absolute value <strong>of</strong> its argument.<br />
368.14.3 ACLONE()<br />
Array clone<br />
ACLONE(aSource) ⇒ aDuplicate<br />
aSource<br />
ACLONE() returns a duplicate <strong>of</strong> aSource.<br />
368.14.4 ACOPY()<br />
Array copy<br />
is the array to duplicate.<br />
ACOPY(aSource, aTarget,<br />
[nStart], [nCount], [nTargetPos]) ⇒ aTarget<br />
aSource<br />
is the array to copy elements from.<br />
aTarget is the array to copy elements to.<br />
is the starting element position in the aSource array. If not<br />
nStart<br />
specified, the default value is one.<br />
is the number <strong>of</strong> elements to copy from the aSource array<br />
beginning at the nStart position. If nCount is not specified,<br />
nCount<br />
all elements in aSource beginning with the starting element<br />
are copied.<br />
is the starting element position in the aTarget array to receive<br />
nTargetPos<br />
elements from aSource. If not specified, the default value is<br />
one.<br />
ACOPY() is an array function that copies elements from the aSource array to the aTarget array.<br />
The aTarget array must already exist and be large enough to hold the copied elements.
204 volume VIII Argomenti avanzati e accessori<br />
368.14.5 ADEL()<br />
Array delete<br />
ADEL(aTarget, nPosition) ⇒ aTarget<br />
aTarget is the array to delete an element from.<br />
nPosition<br />
is the position <strong>of</strong> the target array element to delete.<br />
ADEL() is an array function that deletes an element from an array. The contents <strong>of</strong> the specified<br />
array element is lost, and all elements from that position to the end <strong>of</strong> the array are shifted up one<br />
element. The last element in the array becomes NIL.<br />
368.14.6 AEVAL()<br />
Array evaluation<br />
AEVAL(aArray, bBlock,<br />
[nStart], [nCount]) ⇒ aArray<br />
aArray is the array to be evaluated.<br />
bBlock is a code block to execute for each element encountered.<br />
nStart<br />
is the starting element. If not specified, the default is element<br />
one.<br />
nCount<br />
is the number <strong>of</strong> elements to process from nStart. If not specified,<br />
the default is all elements to the end <strong>of</strong> the array.<br />
AEVAL() is an array function that evaluates a code block once for each element <strong>of</strong> an array,<br />
passing the element value and the element index as block parameters. The return value <strong>of</strong> the<br />
block is ignored. All elements in aArray are processed unless either the nStart or the nCount<br />
argument is specified.<br />
368.14.7 AFILL()<br />
Array fill<br />
AFILL(aTarget, expValue,<br />
[nStart], [nCount]) ⇒ aTarget<br />
aTarget is the array to fill.<br />
expValue<br />
is the value to place in each array element. It can be an expression<br />
<strong>of</strong> any valid data type.<br />
nStart<br />
is the position <strong>of</strong> the first element to fill. If this argument is<br />
omitted, the default value is one.<br />
is the number <strong>of</strong> elements to fill starting with element nStart.<br />
nCount<br />
If this argument is omitted, elements are filled from the starting<br />
element position to the end <strong>of</strong> the array.<br />
AFILL() is an array function that fills the specified array with a single value <strong>of</strong> any data type<br />
(including an array, code block, or NIL) by assigning expValue to each array element in the<br />
specified range.
nanoBase 1997 user manual 205<br />
368.14.8 AINS()<br />
Array insert<br />
AINS(aTarget, nPosition) ⇒ aTarget<br />
aTarget is the array into which a new element will be inserted.<br />
nPosition<br />
is the position at which the new element will be inserted.<br />
AINS() is an array function that inserts a new element into a specified array. The newly inserted<br />
element is NIL data type until a new value is assigned to it. After the insertion, the last element<br />
in the array is discarded, and all elements after the new element are shifted down one position.<br />
368.14.9 ALERT()<br />
ALERT( cMessage, [aOptions] ) ⇒ nChoice<br />
is the message text displayed, centered, in the alert box. If the<br />
cMessage<br />
message contains one or more semicolons, the text after the<br />
semicolons is centered on succeeding lines in the dialog box.<br />
aOptions defines a list <strong>of</strong> up to 4 possible responses to the dialog box.<br />
ALERT() returns a numeric value indicating which option was chosen. If the Esc key is pressed,<br />
the value returned is zero. The ALERT() function creates a simple modal dialog. The user can<br />
respond by moving a highlight bar and pressing the Return or SpaceBar keys, or by pressing<br />
the key corresponding to the first letter <strong>of</strong> the option. If aOptions is not supplied, a single "Ok"<br />
option is presented.<br />
368.14.10 ALIAS()<br />
ALIAS([nWorkArea]) ⇒ cAlias<br />
nWorkArea<br />
is any work area number.<br />
ALIAS() returns the alias <strong>of</strong> the specified work area as a character string. If nWorkArea is not<br />
specified, the alias <strong>of</strong> the current work area is returned. If there is no database file in USE for the<br />
specified work area, ALIAS() returns a null string ("").<br />
368.14.11 ALLTRIM()<br />
ALLTRIM(cString) ⇒ cTrimmedString<br />
cString is the character expression to trim.<br />
ALLTRIM() returns a character string with leading and trailing spaces removed.
206 volume VIII Argomenti avanzati e accessori<br />
368.14.12 ARRAY()<br />
ARRAY(nElements [, nElements...]) ⇒ aArray<br />
nElements<br />
is the number <strong>of</strong> elements in the specified dimension.<br />
ARRAY() is an array function that returns an uninitialized array with the specified number <strong>of</strong><br />
elements and dimensions.<br />
368.14.13 ASC()<br />
ASCII<br />
ASC(cExp) ⇒ nCode<br />
cExp is the character expression to convert to a number.<br />
ASC() returns an integer numeric value in the range <strong>of</strong> zero to 255 , representing the ASCII value<br />
<strong>of</strong> cExp.<br />
368.14.14 ASCAN()<br />
Array scan<br />
ASCAN(aTarget, expSearch,<br />
[nStart], [nCount]) ⇒ nStoppedAt<br />
aTarget is the array to scan.<br />
is either a simple value to scan for, or a code block. If<br />
expSearch<br />
expSearch is a simple value it can be character, date, logical,<br />
or numeric type.<br />
is the starting element <strong>of</strong> the scan. If this argument is not spec-<br />
nStart<br />
ified, the default starting position is one.<br />
is the number <strong>of</strong> elements to scan from the starting position.<br />
nCount<br />
If this argument is not specified, all elements from the starting<br />
element to the end <strong>of</strong> the array are scanned.<br />
ASCAN() returns a numeric value representing the array position <strong>of</strong> the last element scanned.<br />
If expSearch is a simple value, ASCAN() returns the position <strong>of</strong> the first matching element, or<br />
zero if a match is not found. If expSearch is a code block, ASCAN() returns the position <strong>of</strong> the<br />
element where the block returned true (‘.T.’).<br />
368.14.15 ASIZE()<br />
Array size<br />
ASIZE(aTarget, nLength) ⇒ aTarget<br />
aTarget is the array to grow or shrink.<br />
nLength is the new size <strong>of</strong> the array.
nanoBase 1997 user manual 207<br />
ASIZE() is an array function that changes the actual length <strong>of</strong> the aTarget array. The array is<br />
shortened or lengthened to match the specified length. If the array is shortened, elements at the<br />
end <strong>of</strong> the array are lost. If the array is lengthened, new elements are added to the end <strong>of</strong> the array<br />
and assigned NIL.<br />
368.14.16 ASORT()<br />
Array sort<br />
ASORT(aTarget, [nStart],<br />
[nCount], [bOrder]) ⇒ aTarget<br />
aTarget is the array to sort.<br />
nStart<br />
is the first element <strong>of</strong> the sort. If not specified, the default<br />
starting position is one.<br />
nCount<br />
is the number <strong>of</strong> elements to sort. If not specified, all elements<br />
in the array beginning with the starting element are sorted.<br />
bOrder<br />
is an optional code block used to determine sorting order. If<br />
not specified, the default order is ascending.<br />
ASORT() is an array function that sorts all or part <strong>of</strong> an array containing elements <strong>of</strong> a single data<br />
type. Data types that can be sorted include character, date, logical, and numeric. If the bOrder<br />
argument is not specified, the default order is ascending. Each time the block is evaluated, two<br />
elements from the target array are passed as block parameters. The block must return true (‘.T.’)<br />
if the elements are in sorted order.<br />
368.14.17 AT()<br />
AT(cSearch, cTarget) ⇒ nPosition<br />
cSearch<br />
is the character substring for which to search.<br />
cTarget is the character string to search.<br />
AT() returns the position <strong>of</strong> the first instance <strong>of</strong> cSearch within cTarget as an integer numeric<br />
value. If cSearch is not found, AT() returns zero.<br />
AT() is a character function used to determine the position <strong>of</strong> the first occurrence <strong>of</strong> a character<br />
substring within another string.<br />
368.14.18 ATAIL()<br />
Array TAIL<br />
ATAIL(aArray) ⇒ Element<br />
aArray is the array.<br />
ATAIL() is an array function that returns the highest numbered element <strong>of</strong> an array. It can be used<br />
in applications as shorthand for aArray[LEN(aArray)] when you need to obtain the last element<br />
<strong>of</strong> an array.
208 volume VIII Argomenti avanzati e accessori<br />
368.14.19 BIN2I()<br />
Binary to integer<br />
BIN2I(cSignedInt) ⇒ nNumber<br />
cSignedInt<br />
is a character string in the form <strong>of</strong> a 16-bit signed integer<br />
number--least significant byte first.<br />
BIN2I() returns an integer obtained converting the first two byte contained inside cSignedInt.<br />
368.14.20 BIN2L()<br />
Binary to long<br />
BIN2L(cSignedInt) ⇒ nNumber<br />
cSignedInt<br />
is a character string in the form <strong>of</strong> a 32-bit signed integer<br />
number--least significant byte first.<br />
BIN2L() returns an integer obtained from the first tour characters contained in cSignedInt.<br />
368.14.21 BIN2W()<br />
Binary to word<br />
BIN2W(cUnsignedInt) ⇒ nNumber<br />
cUnsignedInt<br />
is a character string in the form <strong>of</strong> a 16-bit unsigned integer<br />
number--least significant byte first.<br />
BIN2W() returns an integer obtained from the first two characters contained in cSignedInt.<br />
368.14.22 BOF()<br />
Begin <strong>of</strong> file<br />
BOF() ⇒ lBoundary<br />
BOF() returns true (‘.T.’) after an attempt to SKIP backward beyond the first logical record in<br />
a database file; otherwise, it returns false (‘.F.’). If there is no database file open in the current<br />
work area, BOF() returns false (‘.F.’). If the current database file contains no records, BOF()<br />
returns true (‘.T.’).
nanoBase 1997 user manual 209<br />
368.14.23 CDOW()<br />
Character day <strong>of</strong> week<br />
CDOW(dExp) ⇒ cDayName<br />
dExp is the date value to convert.<br />
CDOW() returns the name <strong>of</strong> the day <strong>of</strong> the week as a character string. The first letter is uppercase<br />
and the rest <strong>of</strong> the string is lowercase. For a null date value, CDOW() returns a null string ("").<br />
368.14.24 CHR()<br />
Character<br />
CHR(nCode) ⇒ cChar<br />
nCode<br />
is an ASCII code in the range <strong>of</strong> zero to 255.<br />
CHR() returns a single character value whose ASCII code is specified by nCode.<br />
368.14.25 CMONTH()<br />
Character month<br />
CMONTH(dDate) ⇒ cMonth<br />
dDate is the date value to convert.<br />
CMONTH() returns the name <strong>of</strong> the month as a character string from a date value with the first<br />
letter uppercase and the rest <strong>of</strong> the string lowercase. For a null date value, CMONTH() returns a<br />
null string ("").<br />
368.14.26 COL()<br />
Column<br />
COL() ⇒ nCol<br />
COL() is a screen function that returns the current column position <strong>of</strong> the cursor. The value <strong>of</strong><br />
COL() changes whenever the cursor position changes on the screen.<br />
368.14.27 COLORSELECT()<br />
COLORSELECT(nColor<strong>Index</strong>) ⇒ NIL<br />
nColor<strong>Index</strong><br />
is a number corresponding to the ordinal positions in the current<br />
list <strong>of</strong> color attributes, as set by SETCOLOR().<br />
COLORSELECT() activates the specified color pair from the current list <strong>of</strong> color attributes (es-
210 volume VIII Argomenti avanzati e accessori<br />
tablished by SETCOLOR()).<br />
368.14.28 CTOD()<br />
Character to date<br />
CTOD(cDate) ⇒ dDate<br />
cDate<br />
is a character string consisting <strong>of</strong> numbers representing the<br />
month, day, and year separated by any character other than a<br />
number. The month, day, and year digits must be specified in<br />
accordance with the SET DATE format. If the century digits<br />
are not specified, the century is determined by the rules <strong>of</strong><br />
SET EPOCH.<br />
CTOD() returns a date value. If cDate is not a valid date, CTOD() returns an empty date.<br />
368.14.29 CURDIR()<br />
Current directory<br />
CURDIR([cDrivespec]) ⇒ cDirectory<br />
cDrivespec<br />
specifies the letter <strong>of</strong> the disk drive to query. If not specified,<br />
the default is the current DOS drive.<br />
CURDIR() returns the current DOS directory <strong>of</strong> the drive specified by cDrivespec as a character<br />
string without either leading or trailing backslash (\) characters.<br />
368.14.30 DATE()<br />
DATE() ⇒ dSystemDate<br />
DATE() returns the system date as a date value.<br />
368.14.31 DAY()<br />
DAY(dDate) ⇒ nDay<br />
dDate is a date value to convert.<br />
DAY() returns the day number from dDate.
nanoBase 1997 user manual 211<br />
368.14.32 DBAPPEND()<br />
DBAPPEND([lReleaseRecLocks]) ⇒ NIL<br />
lReleaseRecLocks<br />
DBAPPEND() adds a new empty record to the active alias.<br />
368.14.33 DBCLEARFILTER()<br />
DBCLEARFILTER() ⇒ NIL<br />
is a logical data type that if true (‘.T.’), clears all<br />
pending record locks, then appends the next record. If<br />
lReleaseRecLocks is false (‘.F.’), all pending record locks<br />
are maintained and the new record is added to the end <strong>of</strong><br />
the Lock List. The default value <strong>of</strong> lReleaseRecLocks is true<br />
(‘.T.’).<br />
DBCLEARFILTER() clears the logical filter condition, if any, for the current work area.<br />
368.14.34 DBCLEARINDEX()<br />
DBCLEARINDEX() ⇒ NIL<br />
DBCLEARINDEX() closes any active indexes for the active alias.<br />
368.14.35 DBCLEARRELATION()<br />
DBCLEARRELATION() ⇒ NIL<br />
DBCLEARRELATION() clears any active relations for the active alias.<br />
368.14.36 DBCLOSEALL()<br />
DBCLOSEALL() ⇒ NIL<br />
DBCLOSEALL() releases all occupied work areas from use. It is equivalent to calling DB-<br />
CLOSEAREA() on every occupied work area.<br />
Attention: DBCLOSEALL() cannot be used inside a "compiled" macro as this will stop the<br />
macro execution. In substitution, DBCLOSE() should be used.<br />
368.14.37 DBCLOSEAREA()<br />
DBCLOSEAREA() ⇒ NIL<br />
DBCLOSEAREA() releases the current work area from use.
212 volume VIII Argomenti avanzati e accessori<br />
368.14.38 DBCOMMIT()<br />
DBCOMMIT() ⇒ NIL<br />
DBCOMMIT() causes all updates to the current work area to be written to disk. All updated<br />
database and index buffers are written to DOS and a DOS COMMIT request is issued for the<br />
database (.dbf) file and any index files associated with the work area. Inside a network environment,<br />
DBCOMMIT() makes database updates visible to other processes. To insure data integrity,<br />
issue DBCOMMIT() before an UNLOCK operation.<br />
368.14.39 DBCOMMITALL()<br />
DBCOMMITALL() ⇒ NIL<br />
DBCOMMITALL() causes all pending updates to all work areas to be written to disk. It is equivalent<br />
to calling DBCOMMIT() for every occupied work area.<br />
368.14.40 DBCREATE()<br />
DBCREATE(cDatabase, aStruct, [cDriver]) ⇒ NIL<br />
cDatabase<br />
aStruct<br />
cDriver<br />
is the name <strong>of</strong> the new database file, with an optional drive and<br />
directory, specified as a character string. If specified without<br />
an extension (.dbf) is assumed.<br />
is an array that contains the structure <strong>of</strong> cDatabase as a series<br />
<strong>of</strong> subarrays, one per field. Each subarray contains the definition<br />
<strong>of</strong> each field’s attributes and has the following structure:<br />
aStruct[n][1] == cName<br />
aStruct[n][2] == cType<br />
aStruct[n][3] == nLength<br />
aStruct[n][4] == nDecimals<br />
specifies the replaceable database driver (RDD) to use to process<br />
the current work area. cDriver is name <strong>of</strong> the RDD specified<br />
as a character expression.<br />
DBCREATE() is a database function that creates a database file from an array containing the<br />
structure <strong>of</strong> the file.<br />
368.14.41 DBCREATEINDEX()<br />
DBCREATEINDEX(c<strong>Index</strong>Name, cKeyExpr, bKeyExpr, [lUnique])<br />
⇒ NIL<br />
c<strong>Index</strong>Name<br />
cKeyExpr<br />
bKeyExpr<br />
lUnique<br />
is a character value that specifies the filename <strong>of</strong> the index file<br />
(order bag) to be created.<br />
is a character value that expresses the index key expression in<br />
textual form.<br />
is a code block that expresses the index key expression in executable<br />
form.<br />
is an optional logical value that specifies whether a unique<br />
index is to be created. If lUnique is omitted, the current global<br />
_SET_UNIQUE setting is used.
nanoBase 1997 user manual 213<br />
DBCREATEINDEX() creates an index for the active alias. If the alias has active indexes, they<br />
are closed.<br />
368.14.42 DBDELETE()<br />
DBDELETE() ⇒ NIL<br />
DBDELETE() marks the current record as deleted (*). Records marked for deletion can be filtered<br />
using SET DELETED or removed from the file using the PACK command.<br />
368.14.43 DBEVAL()<br />
DB evaluate<br />
DBEVAL(bBlock,<br />
[bForCondition],<br />
[bWhileCondition],<br />
[nNextRecords],<br />
[nRecord],<br />
[lRest]) ⇒ NIL<br />
bBlock<br />
bForCondition<br />
bWhileCondition<br />
nNextRecords<br />
nRecord<br />
lRest<br />
is a code block to execute for each record processed.<br />
the FOR condition expressed as code block.<br />
the WHILE condition expressed as code block.<br />
is an optional number that specifies the number <strong>of</strong> records to<br />
process starting with the current record. It is the same as the<br />
NEXT clause.<br />
is an optional record number to process. If this argument is<br />
specified, bBlock will be evaluated for the specified record.<br />
This argument is the same as the RECORD clause.<br />
is an optional logical value that determines whether the scope<br />
<strong>of</strong> DBEVAL() is all records, or, starting with the current<br />
record, all records to the end <strong>of</strong> file.<br />
DBEVAL() is a database function that evaluates a single block for each record within the active<br />
alias.<br />
368.14.44 DBFILTER()<br />
DBFILTER() ⇒ cFilter<br />
BFILTER() returns the filter condition defined in the current work area as a character string. If<br />
no FILTER has been SET, DBFILTER() returns a null string ("").<br />
368.14.45 DBGOBOTTOM()<br />
DBGOBOTTOM() ⇒ NIL<br />
DBGOBOTTOM() moves to last logical record in the active alias.
214 volume VIII Argomenti avanzati e accessori<br />
368.14.46 DBGOTO()<br />
DBGOTO(nRecordNumber) ⇒ NIL<br />
nRecordNumber<br />
is a numeric value that specifies the record number <strong>of</strong> the desired<br />
record.<br />
DBGOTO() moves to the record whose record number is equal to nRecordNumber. If no such<br />
record exists, the work area is positioned to LASTREC() + 1 and both EOF() and BOF() return<br />
true (‘.T.’).<br />
368.14.47 DBGOTOP()<br />
DBGOTOP() ⇒ NIL<br />
DBGOTOP() moves to the first logical record in the current work area.<br />
368.14.48 DBRECALL()<br />
DBRECALL() ⇒ NIL<br />
DBRECALL() causes the current record to be reinstated if it is marked for deletion.<br />
368.14.49 DBREINDEX()<br />
DBREINDEX() ⇒ NIL<br />
DBREINDEX() rebuilds all active indexes associated with the active alias.<br />
368.14.50 DBRELATION()<br />
DBRELATION(nRelation) ⇒ cLinkExp<br />
nRelation<br />
is the position <strong>of</strong> the desired relation in the list <strong>of</strong> active alias<br />
relations.<br />
DBRELATION() returns a character string containing the linking expression <strong>of</strong> the relation specified<br />
by nRelation. If there is no RELATION SET for nRelation, DBRELATION() returns a null<br />
string ("").<br />
368.14.51 DBRLOCK()<br />
DB record lock<br />
DBRLOCK([nRecNo]) ⇒ lSuccess<br />
nRecNo<br />
is the record number to be locked. The default is the current<br />
record.<br />
DBRLOCK() is a database function that locks the record identified by nRecNo or the current
nanoBase 1997 user manual 215<br />
record.<br />
368.14.52 DBRLOCKLIST()<br />
DBRLOCKLIST() ⇒ aRecordLocks<br />
DBRLOCKLIST() returns a one-dimensional array <strong>of</strong> the locked records in the active alias.<br />
368.14.53 DBRSELECT()<br />
DB relation select<br />
DBRSELECT(nRelation) ⇒ nWorkArea<br />
nRelation<br />
is the position <strong>of</strong> the desired relation in the list <strong>of</strong> current work<br />
area relations.<br />
DBRSELECT() returns the work area number <strong>of</strong> the relation specified by nRelation as an integer<br />
numeric value. If there is no RELATION SET for nRelation, DBRSELECT() returns zero.<br />
368.14.54 DBRUNLOCK()<br />
DB relation unlock<br />
DBRUNLOCK([nRecNo]) ⇒ NIL<br />
nRecNo<br />
is the record number to be unlocked. The default is all previously<br />
locked records.<br />
DBRUNLOCK() is a database function that unlocks the record identified by nRecNo or all<br />
locked records.<br />
368.14.55 DBSEEK()<br />
DBSEEK(expKey, [lS<strong>of</strong>tSeek]) ⇒ lFound<br />
expKey<br />
lS<strong>of</strong>tSeek<br />
is a value <strong>of</strong> any type that specifies the key value associated<br />
with the desired record.<br />
is an optional logical value that specifies whether a s<strong>of</strong>t seek<br />
is to be performed. This determines how the work area is positioned<br />
if the specified key value is not found. If lS<strong>of</strong>tSeek is<br />
omitted, the current global _SET_SOFTSEEK setting is used.<br />
DBSEEK() returns true (‘.T.’) if the specified key value was found; otherwise, it returns false<br />
(‘.F.’).
216 volume VIII Argomenti avanzati e accessori<br />
368.14.56 DBSELECTAREA()<br />
DBSELECTAREA(nArea | cAlias) ⇒ NIL<br />
nArea<br />
cAlias<br />
is a numeric value between zero and 250, inclusive, that specifies<br />
the work area being selected.<br />
is a character value that specifies the alias <strong>of</strong> a currently occupied<br />
work area being selected.<br />
DBSELECTAREA() causes the specified work area to become the current work area. All subsequent<br />
database operations will apply to this work area unless another work area is explicitly<br />
specified for an operation.<br />
368.14.57 DBSETDRIVER()<br />
DBSETDRIVER([cDriver]) ⇒ cCurrentDriver<br />
cDriver<br />
DBSETDRIVER() returns the name <strong>of</strong> the current default driver.<br />
368.14.58 DBSETFILTER()<br />
DBSETFILTER(bCondition, [cCondition]) ⇒ NIL<br />
bCondition<br />
cCondition<br />
is an optional character value that specifies the name <strong>of</strong> the<br />
database driver that should be used to activate and manage<br />
new work areas when no driver is explicitly specified.<br />
is a code block that expresses the filter condition in executable<br />
form.<br />
is a character value that expresses the filter condition in textual<br />
form. If cCondition is omitted, the DBSETFILTER()<br />
function will return an empty string for the work area.<br />
DBSETFILTER() sets a logical filter condition for the current work area. When a filter is set,<br />
records which do not meet the filter condition are not logically visible. That is, database operations<br />
which act on logical records will not consider these records. The filter expression supplied<br />
to DBSETFILTER() evaluates to true (‘.T.’) if the current record meets the filter condition;<br />
otherwise, it should evaluate to false (‘.F.’).<br />
368.14.59 DBSETINDEX()<br />
DBSETINDEX(cOrderBagName) ⇒ NIL<br />
cOrderBagName<br />
is a character value that specifies the filename <strong>of</strong> the index file<br />
(index bag) to be opened.<br />
DBSETINDEX() is a database function that adds the contents <strong>of</strong> an Order Bag into the Order List<br />
<strong>of</strong> the current work area. Any Orders already associated with the work area continue to be active.
nanoBase 1997 user manual 217<br />
If the newly opened Order Bag is the only Order associated with the work area, it becomes the<br />
controlling Order; otherwise, the controlling Order remains unchanged. If the Order Bag contains<br />
more than one Order, and there are no other Orders associated with the work area, the first Order<br />
in the new Order Bag becomes the controlling Order.<br />
368.14.60 DBSETORDER()<br />
DBSETORDER(nOrderNum) ⇒ NIL<br />
nOrderNum<br />
is a numeric value that specifies which <strong>of</strong> the active indexes is<br />
to be the controlling index.<br />
DBSETORDER() controls which <strong>of</strong> the active alias’ active indexes is the controlling index.<br />
368.14.61 DBSETRELATION()<br />
DBSETRELATION(nArea | cAlias, bExpr, [cExpr]) ⇒ NIL<br />
nArea<br />
cAlias<br />
bExpr<br />
cExpr<br />
is a numeric value that specifies the work area number <strong>of</strong> the<br />
child work area.<br />
is a character value that specifies the alias <strong>of</strong> the child work<br />
area.<br />
is a code block that expresses the relational expression in executable<br />
form.<br />
is an optional character value that expresses the relational expression<br />
in textual form. If cExpr is omitted, the DBRELA-<br />
TION() function returns an empty string for the relation.<br />
DBSETRELATION() relates the work area specified by nArea or cAlias (the child work area),<br />
to the current work area (the parent work area). Any existing relations remain active.<br />
368.14.62 DBSKIP()<br />
DBSKIP([nRecords]) ⇒ NIL<br />
nRecords<br />
is the number <strong>of</strong> logical records to move, relative to the current<br />
record. A positive value means to skip forward, and a<br />
negative value means to skip backward. If nRecords is omitted,<br />
a value <strong>of</strong> 1 is assumed.<br />
DBSKIP() moves either forward or backward relative to the current record. Attempting to skip<br />
forward beyond the last record positions the work area to LASTREC() + 1 and EOF() returns<br />
true (‘.T.’). Attempting to skip backward beyond the first record positions the work area to the<br />
first record and BOF() returns true (‘.T.’).
218 volume VIII Argomenti avanzati e accessori<br />
368.14.63 DBSTRUCT()<br />
DBSTRUCT() ⇒ aStruct<br />
DBSTRUCT() returns the structure <strong>of</strong> the current database file in an array whose length is equal<br />
to the number <strong>of</strong> fields in the database file. Each element <strong>of</strong> the array is a subarray containing<br />
information for one field. The subarrays have the following format:<br />
aStruct[n][1] == cName<br />
aStruct[n][2] == cType<br />
aStruct[n][3] == nLength<br />
aStruct[n][4] == nDecimals<br />
If there is no database file in USE in the current work area, DBSTRUCT() returns an empty array<br />
({}).<br />
368.14.64 DBUNLOCK()<br />
DBUNLOCK() ⇒ NIL<br />
DBUNLOCK() releases any record or file locks obtained by the current process for the current<br />
work area. DBUNLOCK() is only meaningful on a shared database in a network environment.<br />
368.14.65 DBUNLOCKALL()<br />
DBUNLOCKALL() ⇒ NIL<br />
DBUNLOCKALL() releases any record or file locks obtained by the current process for any work<br />
area. DBUNLOCKALL() is only meaningful on a shared database in a network environment.<br />
368.14.66 DBUSEAREA()<br />
DBUSEAREA( [lNewArea], [cDriver], cName, [xcAlias],<br />
[lShared], [lReadonly]) ⇒ NIL<br />
lNewArea<br />
cDriver<br />
cName<br />
xcAlias<br />
lShared<br />
is an optional logical value. A value <strong>of</strong> true (‘.T.’) selects the<br />
lowest numbered unoccupied work area as the current work<br />
area before the use operation. If lNewArea is false (‘.F.’)<br />
or omitted, the current work area is used; if the work area is<br />
occupied, it is closed first.<br />
is an optional character value. If present, it specifies the name<br />
<strong>of</strong> the database driver which will service the work area. If<br />
cDriver is omitted, the current default driver is used.<br />
specifies the name <strong>of</strong> the database (.dbf) file to be opened.<br />
is an optional character value. If present, it specifies the alias<br />
to be associated with the work area. The alias must constitute<br />
a valid identifier. A valid xcAlias may be any legal identifier<br />
(i.e., it must begin with an alphabetic character and may contain<br />
numeric or alphabetic characters and the underscore). If<br />
xcAlias is omitted, a default alias is constructed from cName.<br />
is an optional logical value. If present, it specifies whether the<br />
database (.dbf) file should be accessible to other processes<br />
on a network. A value <strong>of</strong> true (‘.T.’) specifies that other processes<br />
should be allowed access; a value <strong>of</strong> false (‘.F.’) specifies<br />
that the current process is to have exclusive access. If<br />
lShared is omitted, the current global _SET_EXCLUSIVE<br />
setting determines whether shared access is allowed.
nanoBase 1997 user manual 219<br />
lReadonly<br />
DBUSEAREA() opens the specified database (.DBF).<br />
368.14.67 DBDELETE()<br />
DELETED() ⇒ lDeleted<br />
is an optional logical value that specifies whether updates to<br />
the work area are prohibited. A value <strong>of</strong> true (‘.T.’) prohibits<br />
updates; a value <strong>of</strong> false (‘.F.’) permits updates. A value<br />
<strong>of</strong> true (‘.T.’) also permits read-only access to the specified<br />
database (.dbf) file. If lReadonly is omitted, the default value<br />
is false (‘.F.’).<br />
DELETED() returns true (‘.T.’) if the current record is marked for deletion; otherwise, it returns<br />
false (‘.F.’). If there is no database file in USE in the current work area, DELETED() returns<br />
false (‘.F.’).<br />
368.14.68 DESCEND()<br />
DESCEND(exp) ⇒ ValueInverted<br />
exp<br />
is any valid expression <strong>of</strong> character, date, logical, or numeric<br />
type.<br />
DESCEND() returns an inverted expression <strong>of</strong> the same data type as the exp, except for dates<br />
which return a numeric value. A DESCEND() <strong>of</strong> CHR(0) always returns CHR(0).<br />
368.14.69 DEVOUT()<br />
Device output<br />
DEVOUT(exp, [cColorString]) ⇒ NIL<br />
exp is the value to display.<br />
cColorString is an optional argument that defines the display color <strong>of</strong> exp.<br />
DEVOUT() is a full-screen display function that writes the value <strong>of</strong> a single expression to the<br />
current device at the current cursor or printhead position.<br />
368.14.70 DEVOUTPICT()<br />
Device output picture<br />
DEVOUTPICT(exp, cPicture, [cColorString]) ⇒ NIL<br />
exp is the value to display.<br />
cPicture<br />
defines the formatting control for the display <strong>of</strong> exp.<br />
cColorString is an optional argument that defines the display color <strong>of</strong> exp.
220 volume VIII Argomenti avanzati e accessori<br />
DEVOUTPICT() is a full-screen display function that writes the value <strong>of</strong> a single expression to<br />
the current device at the current cursor or printhead position.<br />
368.14.71 DEVPOS()<br />
Device position<br />
DEVPOS(nRow, nCol) ⇒ NIL<br />
nRow, nCol<br />
are the new row and column positions <strong>of</strong> the cursor or printhead.<br />
DEVPOS() is an environment function that moves the screen or printhead depending on the<br />
current DEVICE.<br />
368.14.72 DIRECTORY()<br />
DIRECTORY(cDirSpec, [cAttributes]) ⇒ aDirectory<br />
cDirSpec<br />
cAttributes<br />
identifies the drive, directory and file specification for the directory<br />
search. Wildcards are allowed in the file specification.<br />
If cDirSpec is omitted, the default value is *.*.<br />
specifies inclusion <strong>of</strong> files with special attributes in the returned<br />
information. cAttributes is a string containing one or<br />
more <strong>of</strong> the following characters:<br />
H Include hidden files<br />
S Include system files<br />
D Include directories<br />
V Search for the DOS volume label only<br />
Normal files are always included in the search, unless you<br />
specify V.<br />
DIRECTORY() returns an array <strong>of</strong> subarrays, with each subarray containing information about<br />
each file matching cDirSpec. The subarray has the following structure:<br />
aDirectory[n][1] == cName<br />
aDirectory[n][2] == cSize<br />
aDirectory[n][3] == dDate<br />
aDirectory[n][4] == cTime<br />
aDirectory[n][5] == cAttributes<br />
If no files are found matching cDirSpec or if cDirSpec is an illegal path or file specification,<br />
DIRECTORY() returns an empty ({}) array.<br />
368.14.73 DISKSPACE()<br />
DISKSPACE([nDrive]) ⇒ nBytes<br />
nDrive<br />
is the number <strong>of</strong> the drive to query, where one is drive A, two<br />
is B, three is C, etc. The default is the current DOS drive if<br />
nDrive is omitted or specified as zero.
nanoBase 1997 user manual 221<br />
DISKSPACE() returns the number <strong>of</strong> bytes <strong>of</strong> empty space on the specified disk drive as an<br />
integer numeric value.<br />
368.14.74 DISPBOX()<br />
Display box<br />
DISPBOX(nTop, nLeft, nBottom, nRight,<br />
[cnBoxString], [cColorString]) ⇒ NIL<br />
nTop, nLeft, nBottom, nRight define the coordinates <strong>of</strong> the box.<br />
is a numeric or character expression that defines the border<br />
characters <strong>of</strong> the box. If specified as a numeric expression, a<br />
value <strong>of</strong> 1 displays a single-line box and a value <strong>of</strong> 2 displays<br />
cnBoxString<br />
a double-line box. All other numeric values display a singleline<br />
box. If cnBoxString is a character expression, it specifies<br />
the characters to be used in drawing the box. This is a string<br />
<strong>of</strong> eight border characters and a fill character.<br />
cColorString defines the display color <strong>of</strong> the box that is drawn.<br />
DISPBOX() is a screen function that draws a box at the specified display coordinates in the<br />
specified color.<br />
368.14.75 DISPOUT()<br />
Display out<br />
DISPOUT(exp, [cColorString]) ⇒ NIL<br />
exp is the value to display.<br />
cColorString is an optional argument that defines the display color <strong>of</strong> exp.<br />
cColorString is a character expression containing the standard color setting.<br />
DISPOUT() is a simple output function that writes the value <strong>of</strong> a single expression to the display<br />
at the current cursor position. This function ignores the SET DEVICE setting; output always goes<br />
to the screen.<br />
368.14.76 DOW()<br />
Day <strong>of</strong> week<br />
DOW(dDate) ⇒ nDay<br />
dDate is a date value to convert.<br />
DOW() returns the day <strong>of</strong> the week as a number between zero and seven. The first day <strong>of</strong> the<br />
week is one (Sunday) and the last day is seven (Saturday). If dDate is empty, DOW() returns<br />
zero.
222 volume VIII Argomenti avanzati e accessori<br />
368.14.77 DTOC()<br />
Date to character<br />
DTOC(dDate) ⇒ cDate<br />
dDate is the date value to convert.<br />
DTOC() returns a character string representation <strong>of</strong> a date value. The return value is formatted in<br />
the current date format. A null date returns a string <strong>of</strong> spaces equal in length to the current date<br />
format.<br />
368.14.78 DTOS()<br />
Date to sort<br />
DTOS(dDate) ⇒ cDate<br />
dDate is the date value to convert.<br />
DTOS() returns a character string eight characters long in the form, yyyymmdd. When dDate is<br />
a null date (CTOD("")), DTOS() returns a string <strong>of</strong> eight spaces.<br />
368.14.79 EMPTY()<br />
EMPTY(exp) ⇒ lEmpty<br />
exp is an expression <strong>of</strong> any data type.<br />
EMPTY() returns true (‘.T.’) if the expression results in an empty value; otherwise, it returns<br />
false (‘.F.’):<br />
Array {}<br />
Character/Memo<br />
Spaces, tabs, CR/LF, or ""<br />
Numeric 0<br />
Date CTOD("")<br />
Logical ‘.F.’<br />
NIL NIL<br />
368.14.80 EOF()<br />
End <strong>of</strong> file<br />
EOF() ⇒ lBoundary<br />
EOF() returns true (‘.T.’) when an attempt is made to move the record pointer beyond the last<br />
logical record in a database file; otherwise, it returns false (‘.F.’). If there is no database file<br />
open in the current work area, EOF() returns false (‘.F.’). If the current database file contains<br />
no records, EOF() returns true (‘.T.’).
nanoBase 1997 user manual 223<br />
368.14.81 EVAL()<br />
Code block evaluation<br />
EVAL(bBlock, [BlockArg_list]) ⇒ LastBlockValue<br />
bBlock is the code block to evaluate.<br />
BlockArg_list<br />
is a list <strong>of</strong> arguments to send to the code block before it is<br />
evaluated.<br />
To execute or evaluate a code block, call EVAL() with the block value and any parameters.<br />
The parameters are supplied to the block when it is executed. Code blocks may be a series <strong>of</strong><br />
expressions separated by commas. When a code block is evaluated, the returned value is the<br />
value <strong>of</strong> the last expression in the block.<br />
368.14.82 EXP()<br />
Exponent<br />
EXP(nExponent) ⇒ nAntilogarithm<br />
nExponent<br />
is the natural logarithm for which a numeric value is to be<br />
calculated.<br />
EXP() returns a numeric value that is equivalent to the value e raised to the specified power.<br />
368.14.83 FCLOSE()<br />
File close<br />
FCLOSE(nHandle) ⇒ lError<br />
nHandle<br />
is the file handle obtained previously from FOPEN() or<br />
FCREATE().<br />
FCLOSE() is a low-level file function that closes binary files and forces the associated DOS<br />
buffers to be written to disk. If the operation fails, FCLOSE() returns false (‘.F.’). FERROR()<br />
can then be used to determine the reason for the failure.<br />
368.14.84 FCOUNT()<br />
Field count<br />
FCOUNT() ⇒ nFields<br />
FCOUNT() returns the number <strong>of</strong> fields in the database file in the active alias as an integer<br />
numeric value. If there is no database file open, FCOUNT() returns zero.
224 volume VIII Argomenti avanzati e accessori<br />
368.14.85 FCREATE()<br />
Field create<br />
FCREATE(cFile, [nAttribute]) ⇒ nHandle<br />
cFile<br />
nAttribute<br />
is the name <strong>of</strong> the file to create. If the file already exists, its<br />
length is truncated to zero without warning.<br />
is the binary file attribute, the default value is zero.<br />
nAttribute = 0 Normal (default)<br />
nAttribute = 1 Read-only<br />
nAttribute = 2 Hidden<br />
nAttribute = 4 System<br />
FCREATE() returns the DOS file handle number <strong>of</strong> the new binary file in the range <strong>of</strong> zero to<br />
65,535. If an error occurs, FCREATE() returns -1 and FERROR() is set to indicate an error code.<br />
368.14.86 FERASE()<br />
File erase<br />
FERASE(cFile) ⇒ nSuccess<br />
cFile<br />
is the name (with or without path) <strong>of</strong> the file to be deleted<br />
from disk.<br />
FERASE() is a file function that deletes a specified file from disk. FERASE() returns -1 if the<br />
operation fails and zero if it succeeds.<br />
368.14.87 FERROR()<br />
File error<br />
FERROR() ⇒ nErrorCode<br />
FERROR() returns the DOS error from the last file operation as an integer numeric value. If there<br />
is no error, FERROR() returns zero.<br />
nErrorCode value<br />
Meaning<br />
0 Successful<br />
2 File not found<br />
3 Path not found<br />
4<br />
Too many files open<br />
5 Access denied<br />
6 Invalid handle<br />
8<br />
Insufficient memory<br />
15<br />
Invalid drive specified<br />
19 Attempted to write to a write-protected disk<br />
21<br />
Drive not ready<br />
23 Data CRC error<br />
29 Write fault<br />
30 Read fault<br />
32<br />
Sharing violation<br />
33 Lock Violation
nanoBase 1997 user manual 225<br />
FERROR() is a low-level file function that indicates a DOS error after a file function is used.<br />
368.14.88 FIELDBLOCK()<br />
FIELDBLOCK(cFieldName) ⇒ bFieldBlock<br />
cFieldName<br />
is the name <strong>of</strong> the field to which the set-get block will refer.<br />
FIELDBLOCK() returns a code block that, when evaluated, sets (assigns) or gets (retrieves) the<br />
value <strong>of</strong> the given field. If cFieldName does not exist in the current work area, FIELDBLOCK()<br />
returns NIL.<br />
368.14.89 FIELDGET()<br />
FIELDGET(nField) ⇒ ValueField<br />
nField<br />
is the ordinal position <strong>of</strong> the field in the record structure for<br />
the current work area.<br />
FIELDGET() returns the value <strong>of</strong> the specified field. If nField does not correspond to the position<br />
<strong>of</strong> any field in the current database file, FIELDGET() returns NIL.<br />
368.14.90 FIELDNAME()<br />
FIELDNAME(nPosition) ⇒ cFieldName<br />
nPosition<br />
is the position <strong>of</strong> a field in the database file structure.<br />
FIELDNAME() returns the name <strong>of</strong> the specified field as a character string. If nPosition does<br />
not correspond to an existing field in the current database file or if no database file is open in the<br />
current work area, FIELDNAME() returns a null string ("").<br />
368.14.91 FIELDPOS()<br />
Field position<br />
FIELDPOS(cFieldName) ⇒ nFieldPos<br />
cFieldName<br />
is the name <strong>of</strong> a field in the current or specified work area.<br />
FIELDPOS() returns the position <strong>of</strong> the specified field within the list <strong>of</strong> fields associated with<br />
the current or specified work area. If the current work area has no field with the specified name,<br />
FIELDPOS() returns zero.
226 volume VIII Argomenti avanzati e accessori<br />
368.14.92 FIELDPUT()<br />
FIELDPUT(nField, expAssign) ⇒ ValueAssigned<br />
nField<br />
expAssign<br />
is the ordinal position <strong>of</strong> the field in the current database file.<br />
is the value to assign to the given field. The data type <strong>of</strong> this<br />
expression must match the data type <strong>of</strong> the designated field<br />
variable.<br />
FIELDPUT() is a database function that assigns expAssign to the field at ordinal position nField<br />
in the current work area. This function allows you to set the value <strong>of</strong> a field using its position<br />
within the database file structure rather than its field name.<br />
368.14.93 FIELDWBLOCK()<br />
Field work area block<br />
FIELDWBLOCK(cFieldName, nWorkArea) ⇒ bFieldWBlock<br />
cFieldName<br />
nWorkArea<br />
is the name <strong>of</strong> the field specified as a character string.<br />
is the work area number where the field resides specified as a<br />
numeric value.<br />
FIELDWBLOCK() returns a code block that, when evaluated, sets (assigns) or gets (retrieves)<br />
the value <strong>of</strong> cFieldName in the work area designated by nWorkArea. If cFieldName does not<br />
exist in the specified work area, FIELDWBLOCK() returns NIL.<br />
368.14.94 FILE()<br />
FILE(cFilespec) ⇒ lExists<br />
cFilespec<br />
is in the current default directory and path. It is a standard file<br />
specification that can include the wildcard characters * and ?<br />
as well as a drive and path reference.<br />
FILE() returns true (‘.T.’) if there is a match for any file matching the cFilespec pattern; otherwise,<br />
it returns false (‘.F.’).<br />
368.14.95 FLOCK()<br />
File lock<br />
FLOCK() ⇒ lSuccess<br />
FLOCK() tries to lock the active alias and returns true (‘.T.’) if it succeeds; otherwise, it returns<br />
false (‘.F.’).
nanoBase 1997 user manual 227<br />
368.14.96 FOPEN()<br />
File open<br />
FOPEN(cFile, [nMode]) ⇒ nHandle<br />
cFile<br />
nMode<br />
is the name <strong>of</strong> the file to open including the path if there is<br />
one.<br />
is the requested DOS open mode indicating how the opened<br />
file is to be accessed. The open mode is composed <strong>of</strong> the sum<br />
<strong>of</strong> two elements: the Open mode and the Sharing mode.<br />
Open mode:<br />
0 Open for reading (default)<br />
1 Open for writing<br />
2 Open for reading or writing<br />
Sharing mode:<br />
0 Compatibility mode (default)<br />
16 Exclusive use<br />
32 Prevent others from writing<br />
48 Prevent others from reading<br />
64 Allow others to read or write<br />
FOPEN() returns the file handle <strong>of</strong> the opened file in the range <strong>of</strong> zero to 65,535. If an error<br />
occurs, FOPEN() returns -1.<br />
368.14.97 FOUND()<br />
FOUND() ⇒ lSuccess<br />
FOUND() returns true (‘.T.’) if the last search command was successful; otherwise, it returns<br />
false (‘.F.’).<br />
368.14.98 FREAD()<br />
File read<br />
FREAD(nHandle, @cBufferVar, nBytes) ⇒ nBytes<br />
is the file handle obtained from FOPEN(), FCREATE(), or<br />
nHandle<br />
predefined by DOS.<br />
is the name <strong>of</strong> an existing and initialized character variable<br />
used to store data read from the specified file. The length<br />
cBufferVar<br />
<strong>of</strong> this variable must be greater than or equal to nBytes.<br />
cBufferVar must be passed by reference and, therefore, must<br />
be prefaced by the pass-by-reference operator (@).<br />
nBytes is the number <strong>of</strong> bytes to read into the buffer.<br />
FREAD() tries to read nBytes <strong>of</strong> the binary file nHandle inside cBufferVar. It returns the number<br />
<strong>of</strong> bytes successfully read as an integer numeric value. A return value less than nBytes or<br />
zero indicates end <strong>of</strong> file or some other read error.
228 volume VIII Argomenti avanzati e accessori<br />
368.14.99 FREADSTR()<br />
File read string<br />
FREADSTR(nHandle, nBytes) ⇒ cString<br />
nHandle<br />
nBytes<br />
is the file handle obtained from FOPEN(), FCREATE(), or<br />
predefined by DOS.<br />
is the number <strong>of</strong> bytes to read, beginning at the current DOS<br />
file pointer position.<br />
FREADSTR() returns a character string up to 65,535 (64K) bytes. A null return value ("") indicates<br />
an error or end <strong>of</strong> file. FREADSTR() is a low-level file function that reads characters from<br />
an open binary file beginning with the current DOS file pointer position. Characters are read up<br />
to nBytes or until a null character (CHR(0)) is encountered. All characters are read including<br />
control characters except for CHR(0). The file pointer is then moved forward nBytes. If nBytes<br />
is greater than the number <strong>of</strong> bytes from the pointer position to the end <strong>of</strong> the file, the file pointer<br />
is positioned to the last byte in the file.<br />
368.14.100 FRENAME()<br />
File rename<br />
FRENAME(cOldFile, cNewFile) ⇒ nSuccess<br />
cOldFile<br />
cNewFile<br />
is the name <strong>of</strong> the file to rename, including the file extension.<br />
A drive letter and/or path name may also be included as part<br />
<strong>of</strong> the filename.<br />
is the new name <strong>of</strong> the file, including the file extension. A<br />
drive letter and/or path name may also be included as part <strong>of</strong><br />
the name.<br />
FRENAME() returns -1 if the operation fails and zero if it succeeds.<br />
368.14.101 FSEEK()<br />
File seek<br />
FSEEK(nHandle, nOffset, [nOrigin]) ⇒ nPosition<br />
is the file handle obtained from FOPEN(), FCREATE(), or<br />
nHandle<br />
predefined by DOS.<br />
is the number <strong>of</strong> bytes to move the file pointer from the position<br />
defined by nOrigin. It can be a positive or negative<br />
nOffset<br />
number. A positive number moves the pointer forward, and<br />
a negative number moves the pointer backward in the file.<br />
defines the starting location <strong>of</strong> the file pointer before FSEEK()<br />
is executed. The default value is zero, representing the begin-<br />
nOrigin<br />
ning <strong>of</strong> file. If nOrigin is the end <strong>of</strong> file, nOffset must be zero<br />
or negative.<br />
nOrigin == 0 Seek from beginning <strong>of</strong> file<br />
nOrigin == 1 Seek from the current pointer position<br />
nOrigin == 2 Seek from end <strong>of</strong> file
nanoBase 1997 user manual 229<br />
FSEEK() returns the new position <strong>of</strong> the file pointer relative to the beginning <strong>of</strong> file (position<br />
0) as an integer numeric value. This value is without regard to the original position <strong>of</strong> the file<br />
pointer. FSEEK() is a low-level file function that moves the file pointer forward or backward<br />
in an open binary file without actually reading the contents <strong>of</strong> the specified file. The beginning<br />
position and <strong>of</strong>fset are specified as function arguments, and the new file position is returned.<br />
368.14.102 FWRITE()<br />
File write<br />
FWRITE(nHandle, cBuffer, [nBytes]) ⇒ nBytesWritten<br />
nHandle<br />
is the file handle obtained from FOPEN(), FCREATE(), or<br />
predefined by DOS.<br />
cBuffer is the character string to write to the specified file.<br />
nBytes<br />
indicates the number <strong>of</strong> bytes to write beginning at the current<br />
file pointer position. If omitted, the entire content <strong>of</strong> cBuffer<br />
is written.<br />
FWRITE() returns the number <strong>of</strong> bytes written as an integer numeric value. If the value returned<br />
is equal to nBytes, the operation was successful. If the return value is less than nBytes or zero,<br />
either the disk is full or another error has occurred.<br />
368.14.103 GETENV()<br />
Get environment<br />
GETENV(cEnvironmentVariable) ⇒ cString<br />
cEnvironmentVariable<br />
is the name <strong>of</strong> the DOS environment variable. When specifying<br />
this argument, you can use any combination <strong>of</strong> upper and<br />
lowercase letters; GETENV() is not case- sensitive.<br />
GETENV() returns the contents <strong>of</strong> the specified DOS environment variable as a character string.<br />
If the variable cannot be found, GETENV() returns a null string ("").<br />
368.14.104 HARDCR()<br />
Hard carriage return<br />
HARDCR(cString) ⇒ cConvertedString<br />
cString is the character string or memo field to convert.<br />
HARDCR() is a memo function that replaces all s<strong>of</strong>t carriage returns (CHR(141)) with hard carriage<br />
returns (CHR(13)). It is used to display long character strings and memo fields containing<br />
s<strong>of</strong>t carriage returns with console commands.
230 volume VIII Argomenti avanzati e accessori<br />
368.14.105 HEADER()<br />
HEADER() ⇒ nBytes<br />
HEADER() returns the number <strong>of</strong> bytes in the header <strong>of</strong> the current database file as an integer<br />
numeric value. If no database file is in use, HEADER() returns a zero (0).<br />
368.14.106 I2BIN()<br />
Integer to binary<br />
I2BIN(nInteger) ⇒ cBinaryInteger<br />
nInteger<br />
is an integer numeric value to convert. Decimal digits are truncated.<br />
I2BIN() returns a two-byte character string containing a 16-bit binary integer.<br />
368.14.107 IF()<br />
[I]IF(lCondition, expTrue, expFalse) ⇒ Value<br />
lCondition<br />
expTrue<br />
expFalse<br />
is a logical expression to be evaluated.<br />
is the value, a condition-expression, <strong>of</strong> any data type, returned<br />
if lCondition is true (‘.T.’).<br />
is the value, <strong>of</strong> any date type, returned if lCondition is false<br />
(‘.F.’). This argument need not be the same data type as<br />
expTrue.<br />
IF() returns the evaluation <strong>of</strong> expTrue if lCondition evaluates to true (‘.T.’) and expFalse if it<br />
evaluates to false (‘.F.’).<br />
368.14.108 INDEXEXT()<br />
<strong>Index</strong> extention<br />
INDEXEXT() ⇒ cExtension<br />
INDEXEXT() returns the default index file extension by determining which database driver is<br />
currently linked.<br />
368.14.109 INDEXKEY()<br />
INDEXKEY(nOrder) ⇒ cKeyExp<br />
nOrder<br />
is the ordinal position <strong>of</strong> the index in the list <strong>of</strong> index files<br />
opened by the last USE...INDEX or SET INDEX TO command<br />
for the current work area. A zero value specifies the<br />
controlling index, without regard to its actual position in the<br />
list.
nanoBase 1997 user manual 231<br />
INDEXKEY() returns the key expression <strong>of</strong> the specified index as a character string. If there is<br />
no corresponding index or if no database file is open, INDEXKEY() returns a null string ("").<br />
368.14.110 INDEXORD()<br />
<strong>Index</strong> order<br />
INDEXORD() ⇒ nOrder<br />
INDEXORD() returns an integer numeric value. The value returned is equal to the position <strong>of</strong> the<br />
controlling index in the list <strong>of</strong> open indexes for the current work area. A value <strong>of</strong> zero indicates<br />
that there is no controlling index and records are being accessed in natural order. If no database<br />
file is open, INDEXORD() will also return a zero.<br />
368.14.111 INKEY()<br />
Input key<br />
INKEY([nSeconds]) ⇒ nInkeyCode<br />
nSeconds<br />
specifies the number <strong>of</strong> seconds INKEY() waits for a keypress.<br />
You can specify the value in increments as small as<br />
one-tenth <strong>of</strong> a second. Specifying zero halts the program until<br />
a key is pressed. If nSeconds is omitted, INKEY() does not<br />
wait for a keypress.<br />
INKEY() returns an integer numeric value from -39 to 386, identifying the key extracted from<br />
the keyboard buffer. If the keyboard buffer is empty, INKEY() returns zero. INKEY() returns<br />
values for all ASCII characters, function, Alt+function, Ctrl+function, Alt+letter, and Ctrl+letter<br />
key combinations.<br />
nInkeyCode value Key or key combination<br />
5 [ Up arrow ], [ Ctrl ]+E<br />
24 [ Down arrow ], [ Ctrl ]+X<br />
19 [ Left arrow ], [ Ctrl ]+S<br />
4 [ Right arrow ], [ Ctrl ]+D<br />
1 [ Home ], [ Ctrl ]+A<br />
6 [ End ], [ Ctrl ]+F<br />
18 [ PgUp ], [ Ctrl ]+R<br />
3 [ PgDn ], [ Ctrl ]+C<br />
397<br />
[ Ctrl ]+[ Up arrow ]<br />
401<br />
[ Ctrl ]+[ Down arrow ]<br />
26 [ Ctrl ]+[ Left arrow ], [ Ctrl ]+Z<br />
2 [ Ctrl ]+[ Right arrow ], [ Ctrl ]+B<br />
29<br />
[ Ctrl ]+[ Home ]<br />
23 [ Ctrl ]+[ End ], [ Ctrl ]+W<br />
31<br />
[ Ctrl ]+[ PgUp ], [ Ctrl ]+Hyphen<br />
30 [ Ctrl ]+[ PgDn ], [ Ctrl ]+^<br />
408<br />
[ Alt ]+[ Up arrow ]<br />
416<br />
[ Alt ]+[ Down arrow ]<br />
411<br />
[ Alt ]+[ Left arrow ]<br />
413<br />
[ Alt ]+[ Right arrow ]<br />
407<br />
[ Alt ]+[ Home ]
232 volume VIII Argomenti avanzati e accessori<br />
nInkeyCode value Key or key combination<br />
415<br />
[ Alt ]+[ End ]<br />
409<br />
[ Alt ]+[ PgUp ]<br />
417<br />
[ Alt ]+[ PgDn ]<br />
13 [ Enter ], [ Ctrl ]+M<br />
32<br />
Space bar<br />
27 Esc<br />
10<br />
[ Ctrl ]+[ Enter ]<br />
379 [ Ctrl ]+Print Screen<br />
309 [ Ctrl ]+?<br />
284<br />
[ Alt ]+[ Enter ]<br />
387<br />
[ Alt ]+Equals<br />
257 [ Alt ]+Esc<br />
422<br />
Keypad [ Alt ]+[ Enter ]<br />
399 Keypad [ Ctrl ]+5<br />
405<br />
Keypad [ Ctrl ]+/<br />
406<br />
Keypad [ Ctrl ]+*<br />
398 Keypad [ Ctrl ]+-<br />
400<br />
Keypad [ Ctrl ]++<br />
5<br />
Keypad [ Alt ]+5<br />
420<br />
Keypad [ Alt ]+/<br />
311<br />
Keypad [ Alt ]+*<br />
330<br />
Keypad [ Alt ]+-<br />
334<br />
Keypad [ Alt ]++<br />
22 [ Ins ], [ Ctrl ]+V<br />
7 [ Del ], [ Ctrl ]+G<br />
8 [ Backspace ], [ Ctrl ]+H<br />
9 [ Tab ], [ Ctrl ]+I<br />
271<br />
[ Shift ]+[ Tab ]<br />
402<br />
[ Ctrl ]+[ Ins ]<br />
403<br />
[ Ctrl ]+[ Del ]<br />
127<br />
[ Ctrl ]+[ Backspace ]<br />
404<br />
[ Ctrl ]+[ Tab ]<br />
418<br />
[ Alt ]+[ Ins ]<br />
419<br />
[ Alt ]+[ Del ]<br />
270<br />
[ Alt ]+[ Backspace ]<br />
421<br />
[ Alt ]+[ Tab ]<br />
1 [ Ctrl ]+A, [ Home ]<br />
2 [ Ctrl ]+B, [ Ctrl ]+[ Right arrow ]<br />
3 [ Ctrl ]+C, [ PgDn ], [ Ctrl ]+[ ScrollLock ]<br />
4 [ Ctrl ]+D, [ Right arrow ]<br />
5 [ Ctrl ]+E, [ Up arrow ]<br />
6 [ Ctrl ]+F, [ End ]<br />
7 [ Ctrl ]+G, [ Del ]<br />
8 [ Ctrl ]+H, [ Backspace ]<br />
9 [ Ctrl ]+I, [ Tab ]<br />
10 [ Ctrl ]+J<br />
11 [ Ctrl ]+K<br />
12 [ Ctrl ]+L<br />
13 [ Ctrl ]+M, Return<br />
14 [ Ctrl ]+N<br />
15 [ Ctrl ]+O<br />
16 [ Ctrl ]+P<br />
17 [ Ctrl ]+Q
nanoBase 1997 user manual 233<br />
nInkeyCode value Key or key combination<br />
18 [ Ctrl ]+R, [ PgUp ]<br />
19 [ Ctrl ]+S, [ Left arrow ]<br />
20 [ Ctrl ]+T<br />
21 [ Ctrl ]+U<br />
22 [ Ctrl ]+V, [ Ins ]<br />
23 [ Ctrl ]+W, [ Ctrl ]+[ End ]<br />
24 [ Ctrl ]+X, [ Down arrow ]<br />
25 [ Ctrl ]+Y<br />
26 [ Ctrl ]+Z, [ Ctrl ]+[ Left arrow ]<br />
286 [ Alt ]+A<br />
304 [ Alt ]+B<br />
302 [ Alt ]+C<br />
288 [ Alt ]+D<br />
274 [ Alt ]+E<br />
289 [ Alt ]+F<br />
290 [ Alt ]+G<br />
291 [ Alt ]+H<br />
279 [ Alt ]+I<br />
292 [ Alt ]+J<br />
293 [ Alt ]+K<br />
294 [ Alt ]+L<br />
306 [ Alt ]+M<br />
305 [ Alt ]+N<br />
280 [ Alt ]+O<br />
281 [ Alt ]+P<br />
272 [ Alt ]+Q<br />
275 [ Alt ]+R<br />
287 [ Alt ]+S<br />
276 [ Alt ]+T<br />
278 [ Alt ]+U<br />
303 [ Alt ]+V<br />
273 [ Alt ]+W<br />
301 [ Alt ]+X<br />
277 [ Alt ]+Y<br />
300 [ Alt ]+Z<br />
376 [ Alt ]+1<br />
377 [ Alt ]+2<br />
378 [ Alt ]+3<br />
379 [ Alt ]+4<br />
380 [ Alt ]+5<br />
381 [ Alt ]+6<br />
382 [ Alt ]+7<br />
383 [ Alt ]+8<br />
384 [ Alt ]+9<br />
385 [ Alt ]+0<br />
28 F1, [ Ctrl ]+[ Backslash ]<br />
-1 F2<br />
-2 F3<br />
-3 F4<br />
-4 F5<br />
-5 F6<br />
-6 F7<br />
-7 F8
234 volume VIII Argomenti avanzati e accessori<br />
nInkeyCode value Key or key combination<br />
-8 F9<br />
-9 F10<br />
-40 F11<br />
-41 F12<br />
-20 [ Ctrl ]+F1<br />
-21 [ Ctrl ]+F2<br />
-22 [ Ctrl ]+F4<br />
-23 [ Ctrl ]+F3<br />
-24 [ Ctrl ]+F5<br />
-25 [ Ctrl ]+F6<br />
-26 [ Ctrl ]+F7<br />
-27 [ Ctrl ]+F8<br />
-28 [ Ctrl ]+F9<br />
-29 [ Ctrl ]+F10<br />
-44 [ Ctrl ]+F11<br />
-45 [ Ctrl ]+F12<br />
-30 [ Alt ]+F1<br />
-31 [ Alt ]+F2<br />
-32 [ Alt ]+F3<br />
-33 [ Alt ]+F4<br />
-34 [ Alt ]+F5<br />
-35 [ Alt ]+F6<br />
-36 [ Alt ]+F7<br />
-37 [ Alt ]+F8<br />
-38 [ Alt ]+F9<br />
-39 [ Alt ]+F10<br />
-46 [ Alt ]+F11<br />
-47 [ Alt ]+F12<br />
-10 [ Shift ]+F1<br />
-11 [ Shift ]+F2<br />
-12 [ Shift ]+F3<br />
-13 [ Shift ]+F4<br />
-14 [ Shift ]+F5<br />
-15 [ Shift ]+F6<br />
-16 [ Shift ]+F7<br />
-17 [ Shift ]+F8<br />
-18 [ Shift ]+F9<br />
-19 [ Shift ]+F10<br />
-42 [ Shift ]+F11<br />
-43 [ Shift ]+F12<br />
368.14.112 INT()<br />
Integer<br />
INT(nExp) ⇒ nInteger<br />
nExp is a numeric expression to convert to an integer.<br />
INT() is a numeric function that converts a numeric value to an integer by truncating all digits<br />
to the right <strong>of</strong> the decimal point. INT() is useful in operations where the decimal portion <strong>of</strong> a
nanoBase 1997 user manual 235<br />
number is not needed.<br />
368.14.113 ISALPHA()<br />
ISALPHA(cString) ⇒ lBoolean<br />
cString is the character string to examine.<br />
ISALPHA() returns true (‘.T.’) if the first character in cString is alphabetic; otherwise, it returns<br />
false (‘.F.’).<br />
368.14.114 ISCOLOR()<br />
ISCOLOR() | ISCOLOUR() ⇒ lBoolean<br />
ISCOLOR() returns true (‘.T.’) if there is a color graphics card installed; otherwise, it returns<br />
false (‘.F.’).<br />
368.14.115 ISDIGIT()<br />
ISDIGIT(cString) ⇒ lBoolean<br />
cString is the character string to examine.<br />
ISDIGIT() returns true (‘.T.’) if the first character <strong>of</strong> the character string is a digit between zero<br />
and nine; otherwise, it returns false (‘.F.’).<br />
368.14.116 ISLOWER()<br />
ISLOWER(cString) ⇒ lBoolean<br />
cString is the character string to examine.<br />
ISLOWER() returns true (‘.T.’) if the first character <strong>of</strong> the character string is a lowercase letter;<br />
otherwise, it returns false (‘.F.’).<br />
368.14.117 ISPRINTER()<br />
ISPRINTER() ⇒ lReady<br />
ISPRINTER() returns true (‘.T.’) if ‘LPT1:’ is ready; otherwise, it returns false (‘.F.’).
236 volume VIII Argomenti avanzati e accessori<br />
368.14.118 ISUPPER()<br />
ISUPPER(cString) ⇒ lBoolean<br />
cString is the character string to examine.<br />
ISUPPER() returns true (‘.T.’) if the first character is an uppercase letter; otherwise, it returns<br />
false (‘.F.’).<br />
368.14.119 L2BIN()<br />
Long to binary<br />
L2BIN(nExp) ⇒ cBinaryInteger<br />
nExp is the numeric value to convert. Decimal digits are truncated.<br />
L2BIN() returns a four-byte character string formatted as a 32- bit binary integer.<br />
368.14.120 LASTKEY()<br />
LASTKEY() ⇒ nInkeyCode<br />
LASTKEY() is a keyboard function that reports the INKEY() value <strong>of</strong> the last key fetched from<br />
the keyboard buffer by the INKEY() function, or a wait state. LASTKEY() retains its current<br />
value until another key is fetched from the keyboard buffer.<br />
368.14.121 LASTREC()<br />
Last record<br />
LASTREC() ⇒ nRecords<br />
LASTREC() returns the number <strong>of</strong> physical records in the active alias as an integer numeric<br />
value.<br />
368.14.122 LEFT()<br />
LEFT(cString, nCount) ⇒ cSubString<br />
cString is a character string from which to extract characters.<br />
nCount is the number <strong>of</strong> characters to extract.<br />
LEFT() returns the leftmost nCount characters <strong>of</strong> cString as a character string. If nCount is<br />
negative or zero, LEFT() returns a null string (""). If nCount is larger than the length <strong>of</strong> the<br />
character string, LEFT() returns the entire string.
nanoBase 1997 user manual 237<br />
368.14.123 LEN()<br />
Length<br />
LEN(cString | aTarget) ⇒ nCount<br />
cString is the character string to count.<br />
aTarget is the array to count.<br />
LEN() returns the length <strong>of</strong> a character string or the number <strong>of</strong> elements in an array as an integer<br />
numeric value.<br />
368.14.124 LOG()<br />
LOG(nExp) ⇒ nNaturalLog<br />
nExp<br />
is a numeric value greater than zero to convert to its natural<br />
logarithm.<br />
LOG() returns the natural logarithm as a numeric value. If nExp is less than or equal to zero,<br />
LOG() returns a numeric overflow (displayed as a row <strong>of</strong> asterisks).<br />
368.14.125 LOWER()<br />
LOWER(cString) ⇒ cLowerString<br />
cString is a character string to convert to lowercase.<br />
LOWER() returns a copy <strong>of</strong> cString with all alphabetic characters converted to lowercase.<br />
368.14.126 LTRIM()<br />
Left trim<br />
LTRIM(cString) ⇒ cTrimString<br />
cString is the character string to copy without leading spaces.<br />
LTRIM() returns a copy <strong>of</strong> cString with the leading spaces removed.<br />
368.14.127 LUPDATE()<br />
Last update<br />
LUPDATE() ⇒ dModification<br />
LUPDATE() returns the date <strong>of</strong> last change to the open database file in the current work area.
238 volume VIII Argomenti avanzati e accessori<br />
368.14.128 MAX()<br />
MAX(nExp1, nExp2) ⇒ nLarger<br />
MAX(dExp1, dExp2) ⇒ dLarger<br />
nExp1, nExp2 are the numeric values to compare.<br />
dExp1, dExp2 are the date values to compare.<br />
MAX() returns the larger <strong>of</strong> the two arguments. The value returned is the same type as the arguments.<br />
368.14.129 MAXCOL()<br />
Max column<br />
MAXCOL() ⇒ nColumn<br />
MAXCOL() returns the column number <strong>of</strong> the rightmost visible column for display purposes.<br />
368.14.130 MAXROW()<br />
MAXROW() ⇒ nRow<br />
MAXROW() returns the row number <strong>of</strong> the bottommost visible row for display purposes.<br />
368.14.131 MEMOEDIT()<br />
MEMOEDIT([cString],<br />
[nTop], [nLeft],<br />
[nBottom], [nRight],<br />
[lEditMode],<br />
[cUserFunction],<br />
[nLineLength],<br />
[nTabSize],<br />
[nTextBufferRow],<br />
[nTextBufferColumn],<br />
[nWindowRow],<br />
[nWindowColumn]) ⇒ cTextBuffer<br />
cString<br />
nTop, nLeft, nBottom, nRight<br />
lEditMode<br />
cUserFunction<br />
nLineLength<br />
is the character string or memo field to copy to the MEM-<br />
OEDIT() text buffer.<br />
are window coordinates. The default coordinates are 0, 0,<br />
MAXROW(), and MAXCOL().<br />
determines whether the text buffer can be edited or merely<br />
displayed. If not specified, the default value is true (‘.T.’).<br />
is the name <strong>of</strong> a user-defined function that executes when the<br />
user presses a key not recognized by MEMOEDIT() and when<br />
no keys are pending in the keyboard buffer.<br />
determines the length <strong>of</strong> lines displayed in the MEMOEDIT()<br />
window. If a line is greater than nLineLength, it is word<br />
wrapped to the next line in the MEMOEDIT() window. The<br />
default line length is (nRight - nLeft).
nanoBase 1997 user manual 239<br />
nTabSize<br />
nTextBufferRow,<br />
nTextBufferColumn<br />
nWindowRow, nWindowColumn<br />
determines the size <strong>of</strong> a tab character to insert when the user<br />
presses Tab. The default is four.<br />
define the display position <strong>of</strong> the cursor within the text buffer<br />
when MEMOEDIT() is invoked. nTextBufferRow begins<br />
with one and nTextBufferColumn begins with zero. Default<br />
is the beginning <strong>of</strong> MEMOEDIT() window.<br />
define the initial position <strong>of</strong> the cursor within the MEM-<br />
OEDIT() window. Row and column positions begin with zero.<br />
If these arguments are not specified, the initial window position<br />
is row zero and the current cursor column position.<br />
MEMOEDIT() is a user interface and general purpose text editing function that edits memo fields<br />
and long character strings. Editing occurs within a specified window region placed anywhere on<br />
the screen.<br />
[ Uparrow ]/[ Ctrl ]+E Move up one line<br />
[ Dnarrow ]/[ Ctrl ]+X Move down one line<br />
[ Leftarrow ]/[ Ctrl ]+S Move left one character<br />
[ Rightarrow ]/[ Ctrl ]+D Move right one character<br />
[ Ctrl ]-[ Leftarrow ]/[ Ctrl ]+A Move left one word<br />
[ Ctrl ]-[ Rightarrow ]/[ Ctrl ]+F Move right one word<br />
[ Home ] Move to beginning <strong>of</strong> current line<br />
[ End ] Move to end <strong>of</strong> current line<br />
[ Ctrl ]+[ Home ] Move to beginning <strong>of</strong> current window<br />
[ Ctrl ]+[ End ] Move to end <strong>of</strong> current window<br />
[ PgUp ] Move to previous edit window<br />
[ PgDn ] Move to next edit window<br />
[ Ctrl ]+[ PgUp ] Move to beginning <strong>of</strong> memo<br />
[ Ctrl ]+[ PgDn ] Move to end <strong>of</strong> memo<br />
[ Return ] Move to beginning <strong>of</strong> next line<br />
[ Delete ] Delete character at cursor<br />
[ Backspace ] Delete character to left <strong>of</strong> cursor<br />
[ Tab ] Insert tab character or spaces<br />
Printable characters Insert character<br />
[ Ctrl ]+Y Delete the current line<br />
[ Ctrl ]+T Delete word right<br />
[ Ctrl ]+B Reform paragraph<br />
[ Ctrl ]+V/[ Ins ] Toggle insert mode<br />
[ Ctrl ]+W Finish editing with save<br />
[ Esc ] Abort edit and return original<br />
368.14.132 MEMOLINE()<br />
MEMOLINE(cString,<br />
[nLineLength],<br />
[nLineNumber],<br />
[nTabSize],<br />
[lWrap]) ⇒ cLine<br />
cString<br />
nLineLength<br />
is the memo field or character string from which to extract a<br />
line <strong>of</strong> text.<br />
specifies the number <strong>of</strong> characters per line and can be between<br />
four and 254 . If not specified, the default line length is 79.
240 volume VIII Argomenti avanzati e accessori<br />
nLineNumber<br />
is the line number to extract. If not specified, the default value<br />
is one.<br />
nTabSize defines the tab size. If not specified, the default value is four.<br />
lWrap<br />
toggles word wrap on and <strong>of</strong>f. Specifying true (‘.T.’) toggles<br />
word wrap on; false (‘.F.’) toggles it <strong>of</strong>f. If not specified, the<br />
default value is true (‘.T.’).<br />
MEMOLINE() returns the line <strong>of</strong> text specified by nLineNumber in cString as a character string.<br />
If the line has fewer characters than the indicated length, the return value is padded with blanks.<br />
If the line number is greater than the total number <strong>of</strong> lines in cString, MEMOLINE() returns a<br />
null string (""). If lWrap is true (‘.T.’) and the indicated line length breaks the line in the middle<br />
<strong>of</strong> a word, that word is not included as part <strong>of</strong> the return value but shows up at the beginning <strong>of</strong><br />
the next line extracted with MEMOLINE(). If lWrap is false (‘.F.’), MEMOLINE() returns only<br />
the number <strong>of</strong> characters specified by the line length. The next line extracted by MEMOLINE()<br />
begins with the character following the next hard carriage return, and all intervening characters<br />
are not processed.<br />
368.14.133 MEMOREAD()<br />
MEMOREAD(cFile) ⇒ cString<br />
cFile<br />
is the name <strong>of</strong> the file to read from disk. It must include an<br />
extension if there is one, and can optionally include a path.<br />
MEMOREAD() returns the contents <strong>of</strong> a text file as a character string.<br />
368.14.134 MEMORY()<br />
MEMORY(nExp) ⇒ nKbytes<br />
nExp<br />
is a numeric value that determines the type <strong>of</strong> value MEM-<br />
ORY() returns.<br />
MEMORY() returns an integer numeric value representing the amount <strong>of</strong> memory available.<br />
MEMORY(0) Estimated total space available for character values<br />
MEMORY(1) Largest contiguous block available for character values<br />
MEMORY(2) Area available for RUN commands<br />
368.14.135 MEMOTRAN()<br />
Memo translate<br />
MEMOTRAN(cString,<br />
[cReplaceHardCR],<br />
[cReplaceS<strong>of</strong>tCR]) ⇒ cNewString<br />
cString is the character string or memo field to search.<br />
cReplaceHardCR<br />
is the character to replace a hard carriage return/linefeed pair<br />
with. If not specified, the default value is a semicolon (;).
nanoBase 1997 user manual 241<br />
cReplaceS<strong>of</strong>tCR<br />
is the character to replace a s<strong>of</strong>t carriage return/linefeed pair<br />
with. If not specified, the default value is a space.<br />
MEMOTRAN() returns a copy <strong>of</strong> cString with the specified carriage return/linefeed pairs replaced.<br />
368.14.136 MEMOWRIT()<br />
Memo write<br />
MEMOWRIT(cFile, cString) ⇒ lSuccess<br />
cFile<br />
is the name <strong>of</strong> the target disk file including the file extension<br />
and optional path and drive designator.<br />
cString is the character string or memo field to write to cFile.<br />
MEMOWRIT() is a memo function that writes a character string or memo field to a disk file.<br />
If a path is not specified, MEMOWRIT() writes cFile to the current DOS directory and not the<br />
current DEFAULT directory. If cFile already exists, it is overwritten. MEMOWRIT() returns true<br />
(‘.T.’) if the writing operation is successful; otherwise, it returns false (‘.F.’).<br />
368.14.137 MEMVARBLOCK()<br />
MEMVARBLOCK(cMemvarName) ⇒ bMemvarBlock<br />
cMemvarName<br />
is the name <strong>of</strong> the variable referred to by the set-get block,<br />
specified as a character string.<br />
MEMVARBLOCK() returns a code block that when evaluated sets (assigns) or gets (retrieves)<br />
the value <strong>of</strong> the given memory variable. If cMemvarName does not exist, MEMVARBLOCK()<br />
returns NIL.<br />
368.14.138 MIN()<br />
MIN(nExp1, nExp2) ⇒ nSmaller<br />
MIN(dExp1, dExp2) ⇒ dSmaller<br />
nExp1, nExp2 are the numeric values to compare.<br />
dExp1, dExp2 are the date values to compare.<br />
MIN() returns the smaller <strong>of</strong> the two arguments. The value returned is the same data type as the<br />
arguments.
242 volume VIII Argomenti avanzati e accessori<br />
368.14.139 MLCOUNT()<br />
Memo line count<br />
MLCOUNT(cString, [nLineLength],<br />
[nTabSize], [lWrap]) ⇒ nLines<br />
cString is the character string or memo field to count.<br />
nLineLength<br />
specifies the number <strong>of</strong> characters per line and can range from<br />
four to 254 . If not specified, the default line length is 79.<br />
nTabSize defines the tab size. If not specified, the default value is four.<br />
toggles word wrap on and <strong>of</strong>f. Specifying true (‘.T.’) toggles<br />
lWrap<br />
word wrap on; false (‘.F.’) toggles it <strong>of</strong>f. If not specified, the<br />
default value is true (‘.T.’).<br />
MLCOUNT() returns the number <strong>of</strong> lines in cString depending on the nLineLength, the<br />
nTabSize, and whether word wrapping is on or <strong>of</strong>f.<br />
368.14.140 MLCTOPOS()<br />
Memo line column to position<br />
MLCTOPOS(cText, nWidth, nLine,<br />
nCol, [nTabSize], [lWrap]) ⇒ nPosition<br />
cText<br />
nWidth<br />
nLine<br />
nCol<br />
nTabSize<br />
lWrap<br />
is the text string to scan.<br />
is the line length formatting width.<br />
is the line number counting from 1.<br />
is the column number counting from 0.<br />
is the number <strong>of</strong> columns between tab stops. If not specified,<br />
the default is 4.<br />
is the word wrap flag. If not specified, the default is true<br />
(‘.T.’).<br />
MLCTOPOS() returns the byte position within cText counting from 1.<br />
368.14.141 MLPOS()<br />
Memo line position<br />
MLPOS(cString, nLineLength,<br />
nLine, [nTabSize], [lWrap]) ⇒ nPosition<br />
cString is a character string or memo field.<br />
nLineLength specifies the number <strong>of</strong> characters per line.<br />
nLine<br />
specifies the line number.<br />
nTabSize defines the tab size. The default is four.<br />
toggles word wrap on and <strong>of</strong>f. Specifying true (‘.T.’) toggles<br />
lWrap<br />
word wrap on, and false (‘.F.’) toggles it <strong>of</strong>f. The default is<br />
true (‘.T.’).<br />
MLPOS() returns the character position <strong>of</strong> nLine in cString as an integer numeric value. If<br />
nLine is greater than the number <strong>of</strong> lines in cString, MLPOS() returns the length <strong>of</strong> cString.
nanoBase 1997 user manual 243<br />
368.14.142 MONTH()<br />
MONTH(dDate) ⇒ nMonth<br />
dDate is the date value to convert.<br />
MONTH() returns an integer numeric value in the range <strong>of</strong> zero to 12. Specifying a null date<br />
(CTOD("")) returns zero.<br />
368.14.143 MPOSTOLC()<br />
Memo position to line column<br />
MPOSTOLC(cText, nWidth, nPos,<br />
[nTabSize], [lWrap]) ⇒ aLineColumn<br />
cText<br />
nWidth<br />
nPos<br />
nTabSize<br />
lWrap<br />
is a text string.<br />
is the length <strong>of</strong> the formatted line.<br />
is the byte position within text counting from one.<br />
is the number <strong>of</strong> columns between tab stops. If not specified,<br />
the default is four.<br />
is the word wrap flag. If not specified, the default is true<br />
(‘.T.’).<br />
MPOSTOLC() returns an array containing the line and the column values for the specified byte<br />
position, nPos. MPOSTOLC() is a memo function that determines the formatted line and column<br />
corresponding to a particular byte position within cText. Note that the line number returned is<br />
one-relative, the column number is zero-relative. This is compatible with MEMOEDIT(). nPos<br />
is one-relative, compatible with AT(), RAT(), and other string functions.<br />
368.14.144 NETERR()<br />
Net error<br />
NETERR([lNewError]) ⇒ lError<br />
lNewError<br />
if specified sets the value returned by NETERR() to the specified<br />
status. lNewError can be either true (‘.T.’) or false<br />
(‘.F.’). Setting NETERR() to a specified value allows the<br />
runtime error handler to control the way certain file errors are<br />
handled.<br />
NETERR() returns true (‘.T.’) if a USE or APPEND BLANK fails. The initial value <strong>of</strong><br />
NETERR() is false (‘.F.’). If the current process is not running under a network operating system,<br />
NETERR() always returns false (‘.F.’).
244 volume VIII Argomenti avanzati e accessori<br />
368.14.145 NETNAME()<br />
NETNAME() ⇒ cWorkstationName<br />
NETNAME() returns the workstation identification as a character string up to 15 characters in<br />
length. If the workstation identification was never set or the application is not operating under<br />
the IBM PC Network, it returns a null string ("").<br />
368.14.146 NEXTKEY()<br />
NEXTKEY() ⇒ nInkeyCode<br />
NEXTKEY() returns an integer numeric value ranging from -39 to 386. If the keyboard buffer<br />
is empty, NEXTKEY() returns zero. If SET TYPEAHEAD is zero, NEXTKEY() always returns<br />
zero. NEXTKEY() is like the INKEY() function, but differs in one fundamental respect.<br />
INKEY() removes the pending key from the keyboard buffer and updates LASTKEY() with the<br />
value <strong>of</strong> the key. NEXTKEY(), by contrast, reads, but does not remove the key from the keyboard<br />
buffer and does not update LASTKEY().<br />
368.14.147 NOSNOW()<br />
NOSNOW(lToggle) ⇒ NIL<br />
lToggle<br />
NOSNOW() is used to suppress snow on old CGA monitors.<br />
368.14.148 ORDBAGEXT()<br />
ORDBAGEXT() ⇒ cBagExt<br />
is a logical value that toggles the current state <strong>of</strong> snow suppression.<br />
A value <strong>of</strong> true (‘.T.’) enables the snow suppression<br />
on, while a value <strong>of</strong> false (‘.F.’) disables snow suppression.<br />
ORDBAGEXT() returns a character expression that is the default Order Bag extension <strong>of</strong> the<br />
current work area. cBagExt is determined by the RDD active in the current work area.<br />
368.14.149 ORDBAGNAME()<br />
ORDBAGNAME(nOrder | cOrderName) ⇒ cOrderBagName<br />
nOrder<br />
cOrderName<br />
is an integer that identifies the position in the Order List <strong>of</strong> the<br />
target Order whose Order Bag name is sought.<br />
is a character string that represents the name <strong>of</strong> the target Order<br />
whose Order Bag name is sought.<br />
ORDBAGNAME() returns a character string, the Order Bag name <strong>of</strong> the specific Order.
nanoBase 1997 user manual 245<br />
368.14.150 ORDCREATE()<br />
ORDCREATE(cOrderBagName,[cOrderName], cExpKey, [bExpKey],<br />
[lUnique]) ⇒ NIL<br />
cOrderBagName is the name <strong>of</strong> a disk file containing one or more Orders.<br />
cOrderName is the name <strong>of</strong> the Order to be created.<br />
is an expression that returns the key value to place in the Order<br />
cExpKey<br />
for each record in the current work area. The maximum length<br />
<strong>of</strong> the index key expression is determined by the database<br />
driver.<br />
bExpKey<br />
is a code block that evaluates to a key value that is placed in<br />
the Order for each record in the current work area.<br />
lUnique<br />
specifies whether a unique Order is to be created. Default is<br />
the current global _SET_UNIQUE setting.<br />
ORDCREATE() is an Order management function that creates an Order in the current work area.<br />
It works like DBCREATEINDEX() except that it lets you create Orders in RDDs that recognize<br />
multiple Order Bags.<br />
368.14.151 ORDDESTROY()<br />
ORDDESTROY(cOrderName [, cOrderBagName ]) ⇒ NIL<br />
cOrderName<br />
is the name <strong>of</strong> the Order to be removed from the current or<br />
specified work area.<br />
cOrderBagName is the name <strong>of</strong> a disk file containing one or more Orders.<br />
ORDDESTROY() is an Order management function that removes a specified Order from<br />
multiple-Order Bags. ORDDESTROY() is not supported for DBFNDX and DBFNTX.<br />
368.14.152 ORDFOR()<br />
ORDFOR(cOrderName | nOrder [, cOrderBagName]) ⇒ cForExp<br />
cOrderName<br />
is the name <strong>of</strong> the target Order, whose cForExp is sought.<br />
nOrder<br />
is an integer that identifies the position in the Order List <strong>of</strong> the<br />
target Order whose cForExp is sought.<br />
cOrderBagName is the name <strong>of</strong> an Order Bag containing one or more Orders.<br />
ORDFOR() returns a character expression, cForExp, that represents the FOR condition <strong>of</strong> the<br />
specified Order. If the Order was not created using the FOR clause the return value will be an<br />
empty string (""). If the database driver does not support the FOR condition, it may either return<br />
an empty string ("") or raise an "unsupported function" error, depending on the driver.
246 volume VIII Argomenti avanzati e accessori<br />
368.14.153 ORDKEY()<br />
ORDKEY(cOrderName | nOrder [, cOrderBagName]) ⇒ cExpKey<br />
cOrderName<br />
is the name <strong>of</strong> an Order, a logical ordering <strong>of</strong> a database.<br />
nOrder<br />
is an integer that identifies the position in the Order List <strong>of</strong> the<br />
target Order whose cExpKey is sought.<br />
cOrderBagName is the name <strong>of</strong> a disk file containing one or more Orders.<br />
ORDKEY() is an Order management function that returns a character expression, cExpKey, that<br />
represents the key expression <strong>of</strong> the specified Order.<br />
368.14.154 ORDLISTADD()<br />
ORDLISTADD(cOrderBagName [, cOrderName]) ⇒ NIL<br />
cOrderBagName is the name <strong>of</strong> a disk file containing one or more Orders.<br />
the name <strong>of</strong> the specific Order from the Order Bag to be added<br />
to the Order List <strong>of</strong> the current work area. If you do not spec-<br />
cOrderName<br />
ify cOrderName, all orders in the Order Bag are added to the<br />
Order List <strong>of</strong> the current work area.<br />
ORDLISTADD() is an Order management function that adds the contents <strong>of</strong> an Order Bag , or<br />
a single Order in an Order Bag, to the Order List. Any Orders already associated with the work<br />
area continue to be active. If the newly opened Order Bag contains the only Order associated<br />
with the work area, it becomes the controlling Order; otherwise, the controlling Order remains<br />
unchanged.<br />
368.14.155 ORDLISTCLEAR()<br />
ORDLISTCLEAR() ⇒ NIL<br />
ORDLISTCLEAR() is an Order management function that removes all Orders from the Order<br />
List for the current work area.<br />
368.14.156 ORDLISTREBUILD()<br />
ORDLISTREBUILD() ⇒ NIL<br />
ORDLISTREBUILD() is an Order management function that rebuilds all the orders in the current<br />
Order List.<br />
368.14.157 ORDNAME()<br />
ORDNAME(nOrder[,cOrderBagName]) ⇒ cOrderName<br />
nOrder<br />
is an integer that identifies the position in the Order List <strong>of</strong> the<br />
target Order whose database name is sought.<br />
cOrderBagName is the name <strong>of</strong> a disk file containing one or more Orders.
nanoBase 1997 user manual 247<br />
ORDNAME() returns the name <strong>of</strong> the specified Order in the current Order List or the specified<br />
Order Bag if opened in the Current Order list.<br />
368.14.158 ORDNUMBER()<br />
ORDNUMBER(cOrderName [, cOrderBagName]) ⇒ nOrderNo<br />
cOrderName<br />
the name <strong>of</strong> the specific Order whose position in the Order<br />
List is sought.<br />
cOrderBagName is the name <strong>of</strong> a disk file containing one or more Orders.<br />
ORDNUMBER() returns nOrderNo, an integer that represents the position <strong>of</strong> the specified Order<br />
in the Order List.<br />
368.14.159 ORDSETFOCUS()<br />
ORDSETFOCUS([cOrderName | nOrder] [,cOrderBagName])<br />
⇒ cPrevOrderNameInFocus<br />
cOrderName<br />
is the name <strong>of</strong> the selected Order, a logical ordering <strong>of</strong> a<br />
database.<br />
nOrder<br />
is a number representing the position in the Order List <strong>of</strong> the<br />
selected Order.<br />
cOrderBagName is the name <strong>of</strong> a disk file containing one or more Orders.<br />
ORDSETFOCUS() is an Order management function that returns the Order Name <strong>of</strong> the previous<br />
controlling Order and optionally sets the focus to an new Order.<br />
368.14.160 OS()<br />
OS() ⇒ cOsName<br />
OS() returns the operating system name as a character string.<br />
368.14.161 OUTERR()<br />
Output error<br />
OUTERR(exp_list) ⇒ NIL<br />
exp_list<br />
is a list <strong>of</strong> values to display and can consist <strong>of</strong> any combination<br />
<strong>of</strong> data types including memo.<br />
OUTERR() is identical to OUTSTD() except that it writes to the standard error device rather<br />
than the standard output device. Output sent to the standard error device bypasses the console<br />
and output devices as well as any DOS redirection. It is typically used to log error messages in a<br />
manner that will not interfere with the standard screen or printer output.
248 volume VIII Argomenti avanzati e accessori<br />
368.14.162 OUTSTD()<br />
Output standard<br />
OUTSTD(exp_list) ⇒ NIL<br />
exp_list<br />
is a list <strong>of</strong> values to display and can consist <strong>of</strong> any combination<br />
<strong>of</strong> data types including memo.<br />
OUTSTD() is a simple output function similar to QOUT(), except that it writes to the STDOUT<br />
device (instead <strong>of</strong> to the console output stream).<br />
368.14.163 PAD?()<br />
PADL(exp, nLength, [cFillChar]) ⇒ cPaddedString<br />
PADC(exp, nLength, [cFillChar]) ⇒ cPaddedString<br />
PADR(exp, nLength, [cFillChar]) ⇒ cPaddedString<br />
exp<br />
is a character, numeric, or date value to pad with a fill character.<br />
nLength is the length <strong>of</strong> the character string to return.<br />
cFillChar<br />
is the character to pad exp with. If not specified, the default is<br />
a space character.<br />
PADC(), PADL(), and PADR() are character functions that pad character, date, and numeric<br />
values with a fill character to create a new character string <strong>of</strong> a specified length. PADC() centers<br />
exp within nLength adding fill characters to the left and right sides; PADL() adds fill characters<br />
on the left side; and PADR() adds fill characters on the right side.<br />
368.14.164 PCOL()<br />
Printed column<br />
PCOL() ⇒ nColumn<br />
PCOL() returns an integer numeric value representing the last printed column position, plus one.<br />
The beginning column position is zero.<br />
368.14.165 PROW()<br />
Printed row<br />
PROW() ⇒ nRow<br />
PROW() returns an integer numeric value that represents the number <strong>of</strong> the current line sent to<br />
the printer. The beginning row position is zero.
nanoBase 1997 user manual 249<br />
368.14.166 QOUT()<br />
QOUT([exp_list]) ⇒ NIL<br />
QQOUT([exp_list]) ⇒ NIL<br />
exp_list<br />
is a comma-separated list <strong>of</strong> expressions (<strong>of</strong> any data type<br />
other than array or block) to display to the console. If no argument<br />
is specified and QOUT() is specified, a carriage return/linefeed<br />
pair is displayed. If QQOUT() is specified without<br />
arguments, nothing displays.<br />
QOUT() and QQOUT() are console functions. They display the results <strong>of</strong> one or more expressions<br />
to the console. QOUT() outputs carriage return and linefeed characters before displaying<br />
the results <strong>of</strong> exp_list. QQOUT() displays the results <strong>of</strong> exp_list at the current ROW() and COL()<br />
position. When QOUT() and QQOUT() display to the console, ROW() and COL() are updated.<br />
368.14.167 RAT()<br />
Right at<br />
RAT(cSearch, cTarget) ⇒ nPosition<br />
cSearch<br />
is the character string to locate.<br />
cTarget is the character string to search.<br />
RAT() returns the position <strong>of</strong> cSearch within cTarget as an integer numeric value, starting the<br />
search from the right. If cSearch is not found, RAT() returns zero.<br />
368.14.168 RDDLIST()<br />
RDDLIST([nRDDType]) ⇒ aRDDList<br />
nRDDType<br />
is an integer that represents the type <strong>of</strong> the RDD you wish to<br />
list.<br />
nRDDType = 1 Full RDD implementation<br />
nRDDType = 2 Import/Export only driver.<br />
RDDLIST() returns a one-dimensional array <strong>of</strong> the RDD names registered with the application<br />
as nRDDType.<br />
368.14.169 RDDNAME()<br />
RDDNAME() ⇒ cRDDName<br />
RDDNAME() returns a character string, cRDDName, the registered name <strong>of</strong> the active RDD in<br />
the current or specified work area.
250 volume VIII Argomenti avanzati e accessori<br />
368.14.170 RDDSETDEFAULT()<br />
RDDSETDEFAULT([cNewDefaultRDD]) ⇒ cPreviousDefaultRDD<br />
cNewDefaultRDD<br />
is a character string, the name <strong>of</strong> the RDD that is to be made<br />
the new default RDD in the application.<br />
RDDSETDEFAULT() is an RDD function that sets or returns the name <strong>of</strong> the previous default<br />
RDD driver and, optionally, sets the current driver to the new RDD driver specified by<br />
cNewDefaultRDD.<br />
368.14.171 READINSERT()<br />
READINSERT([lToggle]) ⇒ lCurrentMode<br />
lToggle<br />
toggles the insert mode on or <strong>of</strong>f. True (‘.T.’) turns insert on,<br />
while false (‘.F.’) turns insert <strong>of</strong>f. The default is false (‘.F.’)<br />
or the last user-selected mode in READ or MEMOEDIT().<br />
READINSERT() returns the current insert mode state as a logical value.<br />
368.14.172 READMODAL()<br />
READMODAL(aGetList) ⇒ NIL<br />
aGetList<br />
is an array containing a list <strong>of</strong> Get objects to edit.<br />
READMODAL() is like the READ command, but takes a GetList array as an argument and does<br />
not reinitialize the GetList array when it terminates. The GET system is implemented using a<br />
public array called GetList. Each time an @...GET command executes, it creates a Get object and<br />
adds to the currently visible GetList array. The standard READ command is preprocessed into a<br />
call to READMODAL() using the GetList array as its argument.<br />
368.14.173 READVAR()<br />
READVAR() ⇒ cVarName<br />
READVAR() returns the name <strong>of</strong> the variable associated with the current Get object or the variable<br />
being assigned by the current MENU TO command as an uppercase character string.<br />
368.14.174 RECNO()<br />
Record number<br />
RECNO() ⇒ nRecord<br />
RECNO() returns the current record number as an integer numeric value. If the work area contains<br />
a database file with zero records, RECNO() returns one, BOF() and EOF() both return<br />
true (‘.T.’), and LASTREC() returns zero. If the record pointer is moved past the last record,
nanoBase 1997 user manual 251<br />
RECNO() returns LASTREC() + 1 and EOF() returns true (‘.T.’). If an attempt is made to<br />
move before the first record, RECNO() returns the record number <strong>of</strong> the first logical record in the<br />
database file and BOF() returns true (‘.T.’). If no database file is open, RECNO() will return a<br />
zero.<br />
368.14.175 RECSIZE()<br />
Record size<br />
RECSIZE() ⇒ nBytes<br />
RECSIZE() returns, as a numeric value, the record length, in bytes, <strong>of</strong> the database file open in<br />
the current work area. RECSIZE() returns zero if no database file is open.<br />
368.14.176 REPLICATE()<br />
REPLICATE(cString, nCount) ⇒ cRepeatedString<br />
cString is the character string to repeat.<br />
nCount<br />
is the number <strong>of</strong> times to repeat cString.<br />
REPLICATE() returns a character string. Specifying a zero as the nCount argument returns a<br />
null string ("").<br />
368.14.177 RESTSCREEN()<br />
Restore screen<br />
RESTSCREEN([nTop], [nLeft],<br />
[nBottom], [nRight], cScreen) ⇒ NIL<br />
nTop, nLeft, nBottom, nRight<br />
cScreen<br />
define the coordinates <strong>of</strong> the screen information contained in<br />
cScreen. If the cScreen was saved without coordinates to preserve<br />
the entire screen, no screen coordinates are necessary<br />
with RESTSCREEN().<br />
is a character string containing the saved screen region.<br />
RESTSCREEN() is a screen function that redisplays a screen region saved with SAVE-<br />
SCREEN(). The target screen location may be the same as or different than the original location<br />
when the screen region was saved.<br />
368.14.178 RIGHT()<br />
RIGHT(cString, nCount) ⇒ cSubString<br />
cString is the character string from which to extract characters.<br />
nCount is the number <strong>of</strong> characters to extract.<br />
RIGHT() returns the rightmost nCount characters <strong>of</strong> cString. If nCount is zero, RIGHT() returns<br />
a null string (""). If nCount is negative or larger than the length <strong>of</strong> the character string,
252 volume VIII Argomenti avanzati e accessori<br />
RIGHT() returns cString.<br />
368.14.179 RLOCK()<br />
Record lock<br />
RLOCK() ⇒ lSuccess<br />
RLOCK() is a network function that locks the current record, preventing other users from updating<br />
the record until the lock is released. RLOCK() provides a shared lock, allowing other users<br />
read-only access to the locked record while allowing only the current user to modify it. A record<br />
lock remains until another record is locked, an UNLOCK is executed, the current database file is<br />
closed, or an FLOCK() is obtained on the current database file.<br />
368.14.180 ROUND()<br />
ROUND(nNumber, nDecimals) ⇒ nRounded<br />
nNumber is the numeric value to round.<br />
nDecimals<br />
defines the number <strong>of</strong> decimal places to retain. Specifying a<br />
negative nDecimals value rounds whole number digits.<br />
ROUND() is a numeric function that rounds nNumber to the number <strong>of</strong> places specified by<br />
nDecimals. Specifying a zero or negative value for nDecimals allows rounding <strong>of</strong> whole numbers.<br />
A negative nDecimals indicates the number <strong>of</strong> digits to the left <strong>of</strong> the decimal point to<br />
round. Digits between five to nine, inclusive, are rounded up. Digits below five are rounded<br />
down.<br />
368.14.181 ROW()<br />
ROW() ⇒ nRow<br />
ROW() returns the cursor row position as an integer numeric value. The range <strong>of</strong> the return value<br />
is zero to MAXROW().<br />
368.14.182 RTRIM()<br />
Right trim<br />
[R]TRIM(cString) ⇒ cTrimString<br />
cString is the character string to copy without trailing spaces.<br />
RTRIM() returns a copy <strong>of</strong> cString with the trailing spaces removed. If cString is a null string<br />
("") or all spaces, RTRIM() returns a null string ("").
nanoBase 1997 user manual 253<br />
368.14.183 SAVESCREEN()<br />
SAVESCREEN([nTop], [nLeft],<br />
[nBottom], [nRight]) ⇒ cScreen<br />
nTop, nLeft, nBottom, nRight<br />
define the coordinates <strong>of</strong> the screen region to save. Default is<br />
the entire screen.<br />
SAVESCREEN() returns the specified screen region as a character string.<br />
368.14.184 SCROLL()<br />
SCROLL([nTop], [nLeft],<br />
[nBottom], [nRight], [nVert] [nHoriz]) ⇒ NIL<br />
nTop, nLeft, nBottom, nRight define the scroll region coordinates.<br />
nVert<br />
nHoriz<br />
defines the number <strong>of</strong> rows to scroll, vertically. A positive<br />
value scrolls up the specified number <strong>of</strong> rows. A negative<br />
value scrolls down the specified number <strong>of</strong> rows. A value <strong>of</strong><br />
zero disables vertical scrolling. If nVert is not specified, zero<br />
is assumed.<br />
defines the number <strong>of</strong> rows to scroll horizontally. A positive<br />
value scrolls left the specified number <strong>of</strong> columns. A negative<br />
value scrolls right the specified number <strong>of</strong> columns. A value<br />
<strong>of</strong> zero disables horizontal scrolling. If nHoriz is not specified,<br />
zero is assumed. If you supply neither nVert or nHoriz<br />
parameters to SCROLL(), the area specified by the first four<br />
parameters will be blanked.<br />
SCROLL() is a screen function that scrolls a screen region up or down a specified number <strong>of</strong><br />
rows. When a screen scrolls up, the first line <strong>of</strong> the region is erased, all other lines are moved<br />
up, and a blank line is displayed in the current standard color on the bottom line <strong>of</strong> the specified<br />
region. If the region scrolls down, the operation is reversed. If the screen region is scrolled more<br />
than one line, this process is repeated.<br />
368.14.185 SECONDS()<br />
SECONDS() ⇒ nSeconds<br />
SECONDS() returns the system time as a numeric value in the form seconds.hundredths. The numeric<br />
value returned is the number <strong>of</strong> seconds elapsed since midnight, and is based on a twentyfour<br />
hour clock in a range from zero to 86399.<br />
368.14.186 SELECT()<br />
SELECT([cAlias]) ⇒ nWorkArea<br />
cAlias<br />
is the target work area alias name.
254 volume VIII Argomenti avanzati e accessori<br />
SELECT() returns the work area <strong>of</strong> the specified alias as a integer numeric value.<br />
368.14.187 SET()<br />
SET(nSpecifier, [expNewSetting], [lOpenMode])<br />
⇒ CurrentSetting<br />
nSpecifier<br />
expNewSetting<br />
lOpenMode<br />
SET() returns the current value <strong>of</strong> the specified setting.<br />
is a numeric value that identifies the setting to be inspected or<br />
changed.<br />
is an optional argument that specifies a new value for<br />
the nSpecifier. The type <strong>of</strong> expNewSetting depends on<br />
nSpecifier.<br />
is a logical value that indicates whether or not files are opened<br />
for some settings. A value <strong>of</strong> false (‘.F.’) means the file<br />
should be truncated. A value <strong>of</strong> true (‘.T.’) means the file<br />
should be opened in append mode. In either case, if the file<br />
does not exist, it is created. If this argument is not specified,<br />
the default is append mode.<br />
Inside nB, the function SET() is not so easy to use as inside the Clipper environment. This<br />
because nB cannot support manifest constants and a numeric specifier nSpecifier is not easy to<br />
manage. Instead <strong>of</strong> SET() you can use SETVERB().<br />
368.14.188 SETBLINK()<br />
SETBLINK([lToggle]) ⇒ lCurrentSetting<br />
lToggle<br />
SETBLINK() returns the current setting as a logical value.<br />
368.14.189 SETCANCEL()<br />
SETCANCEL([lToggle]) ⇒ lCurrentSetting<br />
lToggle<br />
SETCANCEL() returns the current setting as a logical value.<br />
changes the meaning <strong>of</strong> the asterisk (*) character when it<br />
is encountered in a SETCOLOR() string. Specifying true<br />
(‘.T.’) sets character blinking on and false (‘.F.’) sets background<br />
intensity. The default is true (‘.T.’).<br />
changes the availability <strong>of</strong> Alt-C and Ctrl-Break as termination<br />
keys. Specifying true (‘.T.’) allows either <strong>of</strong> these keys<br />
to terminate an application and false (‘.F.’) disables both<br />
keys. The default is true (‘.T.’).
nanoBase 1997 user manual 255<br />
368.14.190 SETCOLOR()<br />
SETCOLOR([cColorString]) ⇒ cColorString<br />
cColorString<br />
368.14.191 SETCURSOR()<br />
SETCURSOR([nCursorShape]) ⇒ nCurrentSetting<br />
nCursorShape<br />
is a character string containing a list <strong>of</strong> color attribute settings<br />
for subsequent screen painting.<br />
is a number indicating the shape <strong>of</strong> the cursor.<br />
nCursorShape == 0 None<br />
nCursorShape == 1 Underline<br />
nCursorShape == 2 Lower half block<br />
nCursorShape == 3 Full block<br />
nCursorShape == 4 Upper half block<br />
SETCURSOR() returns the current cursor shape as a numeric value.<br />
368.14.192 SETKEY()<br />
SETKEY(nInkeyCode, [bAction]) ⇒ bCurrentAction<br />
nInkeyCode is the INKEY() value <strong>of</strong> the key to be associated or queried.<br />
bAction<br />
specifies a code block that is automatically executed whenever<br />
the specified key is pressed during a wait state.<br />
SETKEY() returns the action block currently associated with the specified key, or NIL if the<br />
specified key is not currently associated with a block.<br />
368.14.193 SETMODE()<br />
SETMODE(nRows, nCols) ⇒ lSuccess<br />
nRows<br />
nCols<br />
is the number <strong>of</strong> rows in the desired display mode.<br />
is the number <strong>of</strong> columns in the desired display mode.<br />
SETMODE() is an environment function that attempts to change the mode <strong>of</strong> the display hardware<br />
to match the number <strong>of</strong> rows and columns specified. The change in screen size is reflected<br />
in the values returned by MAXROW() and MAXCOL().
256 volume VIII Argomenti avanzati e accessori<br />
368.14.194 SETPOS()<br />
Set position<br />
SETPOS(nRow, nCol) ⇒ NIL<br />
nRow, nCol<br />
define the new screen position <strong>of</strong> the cursor. These values may<br />
range from 0, 0 to MAXROW(), MAXCOL().<br />
SETPOS() is an environment function that moves the cursor to a new position on the screen.<br />
After the cursor is positioned, ROW() and COL() are updated accordingly.<br />
368.14.195 SETPRC()<br />
Set printer row column<br />
SETPRC(nRow, nCol) ⇒ NIL<br />
nRow is the new PROW() value.<br />
nCol is the new PCOL() value.<br />
SETPRC() is a printer function that sends control codes to the printer without changing the<br />
tracking <strong>of</strong> the printhead position.<br />
368.14.196 SOUNDEX()<br />
SOUNDEX(cString) ⇒ cSoundexString<br />
cString is the character string to convert.<br />
SOUNDEX() returns a four-digit character string in the form A999.<br />
368.14.197 SPACE()<br />
SPACE(nCount) ⇒ cSpaces<br />
nCount<br />
is the number <strong>of</strong> spaces to return.<br />
SPACE() returns a character string. If nCount is zero, SPACE() returns a null string ("").<br />
368.14.198 SQRT()<br />
SQRT(nNumber) ⇒ nRoot<br />
nNumber<br />
is a positive number to take the square root <strong>of</strong>.<br />
SQRT() returns a numeric value calculated to double precision. The number <strong>of</strong> decimal places<br />
displayed is determined solely by SET DECIMALS regardless <strong>of</strong> SET FIXED. A negative
nanoBase 1997 user manual 257<br />
nNumber returns zero.<br />
368.14.199 STR()<br />
String<br />
STR(nNumber, [nLength], [nDecimals]) ⇒ cNumber<br />
nNumber<br />
nLength<br />
nDecimals<br />
STR() returns nNumber formatted as a character string.<br />
368.14.200 STRTRAN()<br />
STRTRAN(cString, cSearch,<br />
[cReplace], [nStart], [nCount]) ⇒ cNewString<br />
is the numeric expression to convert to a character string.<br />
is the length <strong>of</strong> the character string to return, including decimal<br />
digits, decimal point, and sign.<br />
is the number <strong>of</strong> decimal places to return.<br />
cString is the character string or memo field to search.<br />
cSearch<br />
is the sequence <strong>of</strong> characters to locate.<br />
is the sequence <strong>of</strong> characters with which to replace cSearch.<br />
cReplace<br />
If this argument is not specified, the specified instances <strong>of</strong> the<br />
search argument are replaced with a null string ("").<br />
nStart<br />
is the first occurrence that will be replaced. If this argument is<br />
omitted, the default is one.<br />
nCount<br />
is the number <strong>of</strong> occurrences to replace. If this argument is<br />
not specified, the default is all.<br />
STRTRAN() returns a new character string with the specified instances <strong>of</strong> cSearch replaced with<br />
cReplace.<br />
368.14.201 STUFF()<br />
STUFF(cString, nStart,<br />
nDelete, cInsert) ⇒ cNewString<br />
cString<br />
is the target character string into which characters are inserted<br />
and deleted.<br />
nStart<br />
is the starting position in the target string where the insertion/deletion<br />
occurs.<br />
nDelete is the number <strong>of</strong> characters to delete.<br />
cInsert<br />
is the string to insert.<br />
STUFF() returns a copy <strong>of</strong> cString with the specified characters deleted and with cInsert inserted.
258 volume VIII Argomenti avanzati e accessori<br />
368.14.202 SUBSTR()<br />
Sub string<br />
SUBSTR(cString, nStart, [nCount]) ⇒ cSubstring<br />
cString is the character string from which to extract a substring.<br />
is the starting position in cString. If nStart is positive, it is<br />
nStart<br />
relative to the leftmost character in cString. If nStart is negative,<br />
it is relative to the rightmost character in the cString.<br />
is the number <strong>of</strong> characters to extract. If omitted, the substring<br />
begins at nStart and continues to the end <strong>of</strong> the string. If<br />
nCount<br />
nCount is greater than the number <strong>of</strong> characters from nStart<br />
to the end <strong>of</strong> cString, the extra is ignored.<br />
SUBSTR() is a character function that extracts a substring from another character string or memo<br />
field.<br />
368.14.203 TIME()<br />
TIME() ⇒ cTimeString<br />
TIME() returns the system time as a character string in the form hh:mm:ss. hh is hours in 24-hour<br />
format, mm is minutes, and ss is seconds.<br />
TIME() is a time function that displays the system time on the screen or prints it on a report.<br />
368.14.204 TONE()<br />
TONE(nFrequency, nDuration) ⇒ NIL<br />
nFrequency<br />
nDuration<br />
is a positive numeric value indicating the frequency <strong>of</strong> the<br />
tone to sound.<br />
is a positive numeric value indicating the duration <strong>of</strong> the tone<br />
measured in increments <strong>of</strong> 1/18 <strong>of</strong> a second. For example, an<br />
nDuration value <strong>of</strong> 18 represents one second.<br />
For both arguments, noninteger values are truncated (not rounded) to their integer portion.<br />
368.14.205 TRANSFORM()<br />
TRANSFORM(exp, cSayPicture) ⇒ cFormatString<br />
exp<br />
cSayPicture<br />
is the value to format. This expression can be any valid data<br />
type except array, code block, and NIL.<br />
is a string <strong>of</strong> picture and template characters that describes the<br />
format <strong>of</strong> the returned haracter string.<br />
TRANSFORM() converts exp to a formatted character string as defined by cSayPicture.
nanoBase 1997 user manual 259<br />
368.14.206 TYPE()<br />
TYPE(cExp) ⇒ cType<br />
cExp<br />
TYPE() returns one <strong>of</strong> the following characters:<br />
A<br />
Array<br />
B Block<br />
C Character<br />
D Date<br />
L Logical<br />
M Memo<br />
N Numeric<br />
O<br />
Object<br />
U NIL, local, or static<br />
UE Error syntactical<br />
UI Error indeterminate<br />
is a character expression whose type is to be determined.<br />
cExp can be a field, with or without the alias, a private or<br />
public variable, or an expression <strong>of</strong> any type.<br />
TYPE() is a system function that returns the type <strong>of</strong> the specified expression. TYPE() is like<br />
VALTYPE() but uses the macro operator (&) to determine the type <strong>of</strong> the argument. VALTYPE(),<br />
by contrast, evaluates an expression and determines the data type <strong>of</strong> the return value.<br />
368.14.207 UPDATED()<br />
UPDATED() ⇒ lChange<br />
UPDATED() returns true (‘.T.’) if data in a GET is added or changed; otherwise, it returns false<br />
(‘.F.’).<br />
368.14.208 UPPER()<br />
UPPER(cString) ⇒ cUpperString<br />
cString is the character string to convert.<br />
UPPER() returns a copy <strong>of</strong> cString with all alphabetical characters converted to uppercase. All<br />
other characters remain the same as in the original string.<br />
368.14.209 USED()<br />
USED() ⇒ lDbfOpen<br />
USED() returns true (‘.T.’) if there is a database file in USE in the current work area; otherwise,<br />
it returns false (‘.F.’).
260 volume VIII Argomenti avanzati e accessori<br />
368.14.210 VAL()<br />
Value<br />
VAL(cNumber) ⇒ nNumber<br />
cNumber<br />
is the character expression to convert.<br />
VAL() is a character conversion function that converts a character string containing numeric<br />
digits to a numeric value. When VAL() is executed, it evaluates cNumber until a second decimal<br />
point, the first non-numeric character, or the end <strong>of</strong> the expression is encountered.<br />
368.14.211 VALTYPE()<br />
Value type<br />
VALTYPE(exp) ⇒ cType<br />
exp is an expression <strong>of</strong> any type.<br />
VALTYPE() returns a single character representing the data type returned by exp. VALTYPE()<br />
returns one <strong>of</strong> the following characters:<br />
A<br />
Array<br />
B Block<br />
C Character<br />
D Date<br />
L Logical<br />
M Memo<br />
N Numeric<br />
O<br />
Object<br />
U NIL<br />
VALTYPE() is a system function that takes a single argument, evaluates it, and returns a one<br />
character string describing the data type <strong>of</strong> the return value.<br />
368.14.212 YEAR()<br />
YEAR(dDate) ⇒ nYear<br />
dDate is the date value to convert.<br />
YEAR() returns the year <strong>of</strong> the specified date value including the century digits as a four-digit<br />
numeric value. The value returned is not affected by the current DATE or CENTURY format.<br />
Specifying a null date (CTOD("")) returns zero.
nanoBase 1997 user manual 261<br />
368.15 nB functions<br />
Some functions made into nB are available for macro use. Not all available functions are here<br />
documented.<br />
368.15.1 ACCEPT()<br />
ACCEPT( Field, [cMessage], [cHeader] ) ⇒ updatedField|NIL<br />
It is a prompt function that shows cMessage asking to type something into Field. It returns the<br />
updated data or NIL if [ Esc ] was pressed. The string cHeader is showed centered at the top<br />
window.<br />
368.15.2 ACHOICE()<br />
ACHOICE(nTop, nLeft, nBottom, nRight,<br />
acMenuItems,<br />
[alSelectableItems],<br />
[nInitialItem],<br />
[lButtons | aButtons]) ⇒ nPosition<br />
nTop, nLeft, nBottom, nRight are the window coordinates.<br />
acMenuItems<br />
is an array <strong>of</strong> character strings to display as the menu items.<br />
is a parallel array <strong>of</strong> logical values (one element for each item<br />
in acMenuItems) that specify the selectable menu items. Elements<br />
can be logical values or character strings. If the ele-<br />
alSelectableItems<br />
ment is a character string, it is evaluated as a macro expression<br />
which should evaluate to a logical data type. A value <strong>of</strong><br />
false (‘.F.’) means that the corresponding menu item is not<br />
available, and a value <strong>of</strong> true (‘.T.’) means that it is available.<br />
By default, all menu items are available for selection.<br />
nInitialItem<br />
is the position in the acMenuItems array <strong>of</strong> the item that will<br />
be highlighted when the menu is initially displayed.<br />
lButtons<br />
if True means that default buttons will appear.<br />
aButtons<br />
is an array <strong>of</strong> buttons.<br />
aButtons[n][1] == N the nth button row position;<br />
aButtons[n][2] == N the nth button column position;<br />
aButtons[n][3] == C the nth button text;<br />
aButtons[n][4] == B the nth button code block.<br />
ACHOICE() returns the numeric position in the acMenuItems array <strong>of</strong> the menu item selected.<br />
If no choice is made, ACHOICE() returns zero.<br />
368.15.3 ACHOICEWINDOW()<br />
ACHOICEWINDOW( acMenuItems, [cDescription],<br />
nTop, nLeft, nBottom, nRight,<br />
[alSelectableItems],<br />
[nInitialItem] ) ⇒ nPosition<br />
acMenuItems<br />
is an array <strong>of</strong> character strings to display as the menu items.
262 volume VIII Argomenti avanzati e accessori<br />
cDescription is a header to be shown at the top <strong>of</strong> window.<br />
nTop, nLeft, nBottom, nRight are the window coordinates.<br />
is a parallel array <strong>of</strong> logical values (one element for each item<br />
in acMenuItems) that specify the selectable menu items. Elements<br />
can be logical values or character strings. If the element<br />
is a character string, it is evaluated as a macro expres-<br />
alSelectableItems<br />
sion which should evaluate to a logical data type. A value <strong>of</strong><br />
false (‘.F.’) means that the corresponding menu item is not<br />
available, and a value <strong>of</strong> true (‘.T.’) means that it is available.<br />
By default, all menu items are available for selection.<br />
is the position in the acMenuItems array <strong>of</strong> the item that will<br />
nInitialItem<br />
be highlighted when the menu is initially displayed.<br />
ACHOICEWINDOW() calls ACHOICE() with a window border around the ACHOICE() screen<br />
area.<br />
368.15.4 ALERTBOX()<br />
ALERTBOX( cMessage, [aOptions] ) ⇒ nChoice<br />
is the message text displayed, centered, in the alert box. If the<br />
cMessage<br />
message contains one or more semicolons, the text after the<br />
semicolons is centered on succeeding lines in the dialog box.<br />
aOptions defines a list <strong>of</strong> up to 4 possible responses to the dialog box.<br />
ALERTBOX() returns a numeric value indicating which option was chosen. If the [ Esc ] key is<br />
pressed, the value returned is zero. The ALERTBOX() function creates a simple modal dialog.<br />
The user can respond by moving a highlight bar and pressing the Return or SpaceBar keys, or<br />
by pressing the key corresponding to the first letter <strong>of</strong> the option. If aOptions is not supplied, a<br />
single "Ok" option is presented.<br />
ALERTBOX() is similar to ALERT() but it accept mouse input.<br />
368.15.5 ATB()<br />
ATB( [nTop], [nLeft], [nBottom], [nRight],<br />
aArray, [nSubscript],<br />
[acColSayPic],<br />
[acColTopSep], [acColBodySep], [acColBotSep],<br />
[acColHead], [acColFoot],<br />
[abColValid],<br />
[abColMsg],<br />
[cColor], [abColColors],<br />
[lModify],<br />
[lButtons | aButtons] ) ⇒ NIL<br />
nTop, nLeft, nBottom, nRight defines the screen area where browse have to take place.<br />
aArray bidimensional array to be browsed.<br />
nSubscript starting array position.<br />
acColSayPic is the picture array.<br />
acColTopSep is the top separation array: default is chr(194)+chr(196).
nanoBase 1997 user manual 263<br />
acColBodySep is the body separation array: default is chr(179).<br />
acColBotSep is the bottom separation array: default is chr(193)+chr(196).<br />
acColHead<br />
is the header array for every column.<br />
acColFoot<br />
is the footer array for every column.<br />
abColValid<br />
is the validation array that specify when a field is properly<br />
filled. The condition must be specified in code block format.<br />
is the message array that permits to show information at the<br />
abColMsg<br />
bottom <strong>of</strong> browse area. The array must be composed with<br />
code blocks which result with a character string.<br />
cColor<br />
is the color string: it may be longer than the usual 5 elements.<br />
is the color code block array. The code block receive as pa-<br />
abColColors<br />
rameter the value contained inside the field and must return<br />
an array containing two numbers: they correspond to the two<br />
color couple from cColor.<br />
lModify indicates whether the browse can modify data.<br />
lButtons<br />
if True, default buttons are displayed.<br />
aButtons<br />
array <strong>of</strong> buttons.<br />
aButtons[n][1] N the nth button row position;<br />
aButtons[n][2] N the nth button column position;<br />
aButtons[n][3] C the nth button text;<br />
aButtons[n][4] B the nth button code block.<br />
This function starts the browse <strong>of</strong> a bidimensional array. Only arrays containing monodimensional<br />
array containing the same kind <strong>of</strong> editable data are allowed. The function can handle a<br />
maximum <strong>of</strong> 61 columns.<br />
368.15.6 BCOMPILE()<br />
BCOMPILE( cString ) ⇒ bBlock<br />
Compiles the string cString and returns the code block bBlock<br />
368.15.7 BUTTON()<br />
BUTTON( @aButtons,<br />
[nRow], [nCol], [cText], [cColor],<br />
[bAction] ) ⇒ NIL<br />
aButtons<br />
the array <strong>of</strong> buttons to be increased with a new button array.<br />
nRow and nCol<br />
is the row and column starting position for the button string.<br />
cText<br />
is the text that make up the button.<br />
cColor<br />
is the color string.<br />
bAction is the code block associated to the button.<br />
This function adds to aButtons a new button array. Please note that the button array added is<br />
compatible only with the READ() function and not the other function using array <strong>of</strong> buttons: the<br />
others do not have a color string.
264 volume VIII Argomenti avanzati e accessori<br />
368.15.8 COLORARRAY()<br />
COLORARRAY( cColor ) ⇒ aColors<br />
cColors<br />
a color string to be translated into a color array.<br />
This function transform a color string into a color array. The array has as many elements as the<br />
colors contained inside cColor string.<br />
368.15.9 COORDINATE()<br />
COORDINATE( [@nTop, @nLeft], @nBottom, @nRight,<br />
[cHorizontal], [cVertical] ) ⇒ NIL<br />
nTop, nLeft, nBottom and nRight<br />
cHorozontal<br />
cVertical<br />
are the starting position <strong>of</strong> a window that is to be differently<br />
aligned.<br />
determinates the horizontal alignment:<br />
"L" all left;<br />
"l" middle left;<br />
"C" center;<br />
"c" center;<br />
"R" all right;<br />
"r" middle right.<br />
determinate the vertical alignment:<br />
"T" top;<br />
"t" up;<br />
"C" center;<br />
"c" center;<br />
"B" bottom;<br />
"b" down.<br />
This function helps with the windows alignment recalculating and modifying nTop, nLeft,<br />
nBottom and nRight in the way to obtain the desired alignment.<br />
368.15.10 COPYFILE()<br />
COPYFILE( cSourceFile, cTargetFile|cDevice ) ⇒ NIL<br />
cSourceFile the source filename.<br />
cTargetFile the target filename.<br />
cDevice<br />
the target devicename.<br />
This function copies the cSourceFile to cTargetFile or to cDevice.
nanoBase 1997 user manual 265<br />
368.15.11 DBAPP()<br />
DBAPP( cFileName, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords],<br />
[nRecord],<br />
[lRest],<br />
[cDriver] ) ⇒ NIL<br />
cFileName<br />
acFields<br />
bForCondition<br />
bWhileCondition<br />
nNextRecord<br />
nRecord<br />
lRest<br />
cDriver<br />
the filename containing data to append to the active alias.<br />
array <strong>of</strong> fieldnames indicating the fields that should be updated<br />
on the active alias (default is all).<br />
a code block containing the FOR condition to respect for the<br />
data append. Will be appended data that makes the evaluation<br />
<strong>of</strong> this code block True.<br />
a code block containing the WHILE condition to respect for<br />
the data append. Will be appended data as long as the evaluation<br />
<strong>of</strong> this code block is True: the first time it becomes False,<br />
the data appending is terminated.<br />
if used, means that only the first nNextRecords will be appended.<br />
if used, means that that only the record nRecord will be appended.<br />
this option is not available here also if the function saves a<br />
place for it.<br />
is the optional driver name to use to open the cFileName file.<br />
This function is used to append data to the active alias using data from the cFileName file, that<br />
in this case is a ‘.DBF’ file.<br />
368.15.12 DBCLOSE()<br />
DBCLOSE() ⇒ NIL<br />
It is a substitution function <strong>of</strong> DBCLOSEALL() to use inside "compiled" macros, as a true DB-<br />
CLOSEALL() will close the macro file too.<br />
368.15.13 DBCONTINUE()<br />
DBCONTINUE() ⇒ NIL<br />
This function resumes a pending DBLOCATE().<br />
368.15.14 DBCOPY()<br />
DBCOPY( cFileName, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords],<br />
[nRecord],<br />
[lRest],<br />
[cDriver] ) ⇒ NIL
266 volume VIII Argomenti avanzati e accessori<br />
cFileName<br />
acFields<br />
bForCondition<br />
bWhileCondition<br />
nNextRecord<br />
nRecord<br />
lRest<br />
cDriver<br />
the target filename for the data contained inside the active<br />
alias.<br />
array <strong>of</strong> fieldnames indicating the fields that should be used<br />
from the active alias (default is all).<br />
a code block containing the FOR condition to respect for the<br />
data copy. Will be copied the data that makes the evaluation<br />
<strong>of</strong> this code block True.<br />
a code block containing the WHILE condition to respect for<br />
the data copy. Will be copied data as long as the evaluation<br />
<strong>of</strong> this code block is True: the first time it becomes False, the<br />
data copying is terminated.<br />
if used, means that only the first nNextRecords will be<br />
copied.<br />
if used, means that that only the record nRecord will be<br />
copied.<br />
if used means that only the remaining records inside the active<br />
alias are copied.<br />
is the optional driver name to use to open the cFileName file.<br />
This function is used to copy data to cFileName form the active alias.<br />
368.15.15 DBCOPYSTRUCT()<br />
DBCOPYSTRUCT( cDatabase, [acFields] ) ⇒ NIL<br />
cDatabase<br />
acFields<br />
is a structure ‘.DBF’ file that will be filled with structure information<br />
about the active alias.<br />
is an array <strong>of</strong> fieldnames that should be taken into consideration.<br />
This function creates a structure ‘.DBF’ file copying the structure <strong>of</strong> the active alias.<br />
368.15.16 DBCOPYXSTRUCT()<br />
DBCOPYXSTRUCT( cExtendedDatabase ) ⇒ NIL<br />
cExtendedDatabase<br />
is a structure ‘.DBF’ file that will be filled with structure information<br />
about the active alias, accepting extended structure<br />
informations.<br />
This function creates a structure ‘.DBF’ file copying the structure <strong>of</strong> the active alias. This function<br />
accept non-standard structure, that is, the extended structure available inside Clipper.<br />
368.15.17 DBDELIM()<br />
DBDELIM( lCopyTo, cFileName, [cDelimiter], [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] ) ⇒ NIL
nanoBase 1997 user manual 267<br />
lCopyTo<br />
cFileName<br />
cDelimiter<br />
acFields<br />
bForCondition<br />
bWhileCondition<br />
nNextRecord<br />
nRecord<br />
lRest<br />
if True the function work copying data to cFileName from the<br />
active alias, if False the function work appending data from<br />
cFileName to the active alias.<br />
the filename containing data to append to the active alias or<br />
to use as the target <strong>of</strong> the data copy from the active alias.<br />
the delimiter string (or character) used to separate fields inside<br />
cFileName.<br />
array <strong>of</strong> fieldnames indicating the fields <strong>of</strong> the active alias that<br />
should be taken into consideration (default is all).<br />
a code block containing the FOR condition to respect. The operation<br />
will be made for all records that respect the condition.<br />
a code block containing the WHILE condition to respect. The<br />
first time it becomes False, the operation is terminated.<br />
if used, means that only the first nNextRecords will be appended/copied.<br />
if used, means that that only the record nRecord will be ap-<br />
pended/copied.<br />
if used means that only the remaining records will be taken<br />
into consideration.<br />
This function is used to append data to the active alias using data from the cFileName file or to<br />
copy data into cFileName using the active alias as the source. cFileName is a delimited ASCII<br />
file.<br />
368.15.18 DBISTATUS()<br />
DBISTATUS() ⇒ cDBInformations<br />
This function returns the informations on the active alias in a text form.<br />
368.15.19 DBISTRUCTURE()<br />
DBISTRUCTURE() ⇒ cTextStructure | NIL<br />
This function returns the structure information on the active alias in a text form.<br />
368.15.20 DBJOIN()<br />
DBJOIN( cAlias, cDatabase,<br />
[acFields], [bForCondition] ) ⇒ NIL<br />
cAlias<br />
cDatabase<br />
acFields<br />
the name <strong>of</strong> the alias to use to merge with records from the<br />
active alias.<br />
the target ‘.DBF’ filename.<br />
the array <strong>of</strong> fieldnames which represent the projection <strong>of</strong><br />
fields form both Aliases into the new ‘.DBF’ file. If not specified,<br />
all fields from the primary work area are included in the<br />
target ‘.DBF’ file.<br />
This function creates a new database file by merging selected records and fields form two work<br />
areas (Aliases) based on a general condition. It works by making a complete pass through the<br />
secondary work area cAlias for each record in the primary work area (the active alias), evaluating
268 volume VIII Argomenti avanzati e accessori<br />
the condition for each record in the secondary work area. When bForCondition is evaluated True,<br />
a new record is created in the target database file cDatabase using the fields specified from both<br />
work areas inside acFields.<br />
368.15.21 DBLABELFORM()<br />
DBLABELFORM( cLabel, [lToPrinter], [cFile],<br />
[lNoConsole], [bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest], [lSample] )<br />
⇒ NIL<br />
cLabel<br />
is the name <strong>of</strong> the label file (.LBL) that contains the label<br />
format definition.<br />
lToPrinter<br />
if True, the output is copied to printer (‘LPT1:’).<br />
cFile<br />
if present, it is the name <strong>of</strong> a ASCII file where the output is<br />
copied.<br />
lNoConsole<br />
if True, the output is not sent to the console.<br />
a code block containing the FOR condition to respect for label<br />
bForCondition<br />
print. Only the records contained inside the active alias that<br />
respect the condition will be used for labels.<br />
a code block containing the WHILE condition to respect for<br />
bWhileCondition<br />
the label print. The first time that the condition is False, the<br />
label print terminates.<br />
nNextRecord<br />
if used, means that only the first nNextRecords will be used.<br />
nRecord<br />
if used, means that that only the record nRecord will be used.<br />
lRest<br />
if used means that only the remaining records inside the active<br />
alias will be used.<br />
lSample if True displays test labels as rows <strong>of</strong> asterisks.<br />
This function prints labels to the console.<br />
368.15.22 DBLIST()<br />
DBLIST( [lToDisplay], abListColumns,<br />
[lAll],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest],<br />
[lToPrinter], [cFileName] )<br />
lToDisplay if True the printout is sent to the console screen.<br />
abListColumns<br />
is an array <strong>of</strong> columns expressions to list.<br />
lAll<br />
if True prints all the records contained inside the active alias.<br />
a code block containing the FOR condition to respect. Only<br />
bForCondition<br />
the records contained inside the active alias that respect the<br />
condition will be used for list.<br />
bWhileCondition<br />
a code block containing the WHILE condition to respect. The<br />
first time that the condition is False, the list terminates.<br />
nNextRecord<br />
if used, means that only the first nNextRecords will be used.<br />
nRecord<br />
if used, means that that only the record nRecord will be used.<br />
lRest<br />
if used means that only the remaining records inside the active<br />
alias will be used.<br />
lToPrinter<br />
if True, the output is copied to printer (‘LPT1:’).<br />
cFileName<br />
if present, it is the name <strong>of</strong> a ASCII file where the output is<br />
copied.
nanoBase 1997 user manual 269<br />
This function prints a list <strong>of</strong> records to the console.<br />
368.15.23 DBLOCATE()<br />
DBLOCATE( [bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] ) ⇒ NIL<br />
bForCondition<br />
bWhileCondition<br />
nNextRecord<br />
nRecord<br />
lRest<br />
a code block containing the FOR condition to respect. Only<br />
the records contained inside the active alias that respect the<br />
condition will be taken into consideration.<br />
a code block containing the WHILE condition to respect. The<br />
first time that the condition is False, the locate terminates.<br />
if used, means that only the first nNextRecords will be used.<br />
if used, means that that only the record nRecord will be used.<br />
if used means that only the remaining records inside the active<br />
alias will be used.<br />
This function searches sequentially for the first record matching the FOR and WHILE conditions.<br />
Once a DBLOCATE() has been issued you can resume the search from the current record pointer<br />
position with DBCONTINUE().<br />
The WHILE condition and the scope (nNextRecord, nRecord and lRest) apply only to the initial<br />
DBLOCATE() and are not operational for any subsequent DBCONTINUE() call.<br />
368.15.24 DBOLDCREATE()<br />
DBOLDCREATE( cDatabase, cExtendedDatabase,<br />
[cDriver], [lNew], [cAlias] ) ⇒ NIL<br />
cDatabase<br />
cExtendedDatabase<br />
cDriver<br />
lNew<br />
cAlias<br />
is the name <strong>of</strong> the new database file, with an optional drive and<br />
directory, specified as a character string. If specified without<br />
an extension (.dbf) is assumed.<br />
is a ‘.DBF’ file containing the structure information <strong>of</strong> the file<br />
to create.<br />
specifies the replaceable database driver (RDD) to use to process<br />
the current work area. cDriver is the name <strong>of</strong> the RDD<br />
specified as a character expression.<br />
if True the newly created ‘.DBF’ file is opened using the next<br />
available work area making it the current work area (the active<br />
alias).<br />
if lNew is set to True, this is the alias name to use to open the<br />
file.<br />
This function is a old database function (superseded form DBCREATE() ) that creates a database<br />
file from the structure information contained inside a structure file.
270 volume VIII Argomenti avanzati e accessori<br />
368.15.25 DBPACK()<br />
DBPACK() ⇒ NIL<br />
This function eliminates definitively the active alias records previously signed for deletion. It<br />
works only if the active alias is opened in exclusive mode.<br />
368.15.26 DBSDF()<br />
DBSDF( lCopyTo, cFileName, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] ) ⇒ NIL<br />
lCopyTo<br />
cFileName<br />
acFields<br />
bForCondition<br />
bWhileCondition<br />
nNextRecord<br />
nRercord<br />
lReset<br />
if True the function works copying data to cFileName from<br />
the active alias, if False the function work appending data<br />
from cFileName to the active alias.<br />
the filename containing data to append to the active alias or to<br />
use as the target <strong>of</strong> the data copy from the active alias.<br />
array <strong>of</strong> fieldnames indicating the fields <strong>of</strong> the active alias that<br />
should be taken into consideration (default is all).<br />
a code block containing the FOR condition to respect. The operation<br />
will be made for all records that respect the condition.<br />
a code block containing the WHILE condition to respect. The<br />
first time it becomes False, the operation is terminated.<br />
if used, means that only the first nNextRecords will be appended/copied.<br />
if used, means that that only the record nRecord will be ap-<br />
pended/copied.<br />
if used means that only the remaining records will be taken<br />
into consideration.<br />
This function is used to append data to the active alias using data from the cFileName file or to<br />
copy data into cFileName using the active alias as the source. cFileName is a SDF ASCII file.<br />
368.15.27 DBSORT()<br />
DBSORT( cDatabase, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] ) ⇒ NIL<br />
cDatabase the ‘.DBF’ file to create.<br />
acFields<br />
the array <strong>of</strong> fields to be used to create the new sorted<br />
cDatabase file.<br />
a code block containing the FOR condition to respect. Only<br />
bForCondition<br />
the records contained inside the active alias that respect the<br />
condition will be taken into consideration.<br />
bWhileCondition<br />
a code block containing the WHILE condition to respect. The<br />
first time that the condition is False, the sort terminates.<br />
nNextRecord<br />
if used, means that only the first nNextRecords inside the active<br />
alias will be used.<br />
nRecord<br />
if used, means that that only the record nRecord will be used.<br />
lRest<br />
if used means that only the remaining records inside the active<br />
alias will be used.
nanoBase 1997 user manual 271<br />
Copy the active alias to a ‘.DBF’ file in sorted order.<br />
368.15.28 DBTOTAL()<br />
DBTOTAL( cDatabase, bKey, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] ) ⇒ NIL<br />
cDatabase<br />
bKey<br />
acFields<br />
bForCondition<br />
bWhileCondition<br />
nNextRecords<br />
nRecord<br />
lRest<br />
the ‘.DBF’ file to create that will contain the copy <strong>of</strong> summarised<br />
records.<br />
the code block key expression that should correspond to the<br />
key expression <strong>of</strong> the active index <strong>of</strong> the active alias.<br />
the array <strong>of</strong> fields to be used to create the new cDatabase file.<br />
a code block containing the FOR condition to respect. Only<br />
the records contained inside the active alias that respect the<br />
condition will be taken into consideration.<br />
a code block containing the WHILE condition to respect. The<br />
first time that the condition is False, the sort terminates.<br />
if used, means that only the first nNextRecords inside the active<br />
alias will be used.<br />
if used, means that that only the record nRecord will be used.<br />
if used means that only the remaining records inside the active<br />
alias will be used.<br />
This function summarises records by key value to a ‘.DBF’ file. It sequentially process the active<br />
alias scanning the specified scope <strong>of</strong> records. Records with the same key will be summarised<br />
inside the destination ‘.DBF’ file. The value <strong>of</strong> numeric fields <strong>of</strong> records with the same key are<br />
added.<br />
368.15.29 DBUPDATE()<br />
DBUPDATE( cAlias, bKey, [lRandom], [bReplacement] )<br />
cAlias<br />
bKey<br />
lRandom<br />
bReplacement<br />
is the alias containing data to be used to update the active<br />
alias.<br />
is a code block expression using information form the cAlias<br />
to obtain a key to refer to the active alias.<br />
if True, allows record in the cAlias to be in any order. In this<br />
case, the active alias must be indexed with the same key as<br />
bKey.<br />
is the code block that will be executed when records matches:<br />
it should contains the criteria for data update.<br />
This function updates the active alias with data from another .DBF file.<br />
Example:<br />
dbUpdate( "INVOICE", {|| LAST}, .T.,;<br />
{|| FIELD->TOTAL1 := INVOICE->SUM1,;<br />
FIELD->TOTAL2 := INVOICE->SUM2 } )
272 volume VIII Argomenti avanzati e accessori<br />
368.15.30 DBZAP()<br />
DBZAP() ⇒ NIL<br />
This function erases immediately all the records contained inside the active alias.<br />
368.15.31 DISPBOXCOLOR()<br />
DISPBOXCOLOR( [nColorNumber], [cBaseColor] ) ⇒ cColor<br />
nColorNumber<br />
cBaseColor<br />
may be 1 or 2 and are the two color used to create shadowed<br />
borders. 1 is usually used for the left and top line; 2 is used<br />
for the right and bottom line.<br />
is the starting color string. The default is the actual color.<br />
This function return a color string used for DISPBOXSHADOW() the function that create a<br />
shadowed border around a screen window.<br />
368.15.32 DISPBOXSHADOW()<br />
DISPBOXSHADOW( nTop, nLeft, nBottom, nRight,<br />
[cBoxString], [cColor1], [cColor2] ) ⇒ NIL<br />
nTop, nLeft, nBottom and nRight are the screen coordinate where the box is to be displayed.<br />
cBoxString<br />
is the box string containing the character to use to build the<br />
box. Default is a single line box.<br />
cColor1<br />
is the color string to use for the left and top side <strong>of</strong> the box.<br />
cColor2<br />
is the color string to use for the right and bottom side <strong>of</strong> the<br />
box.<br />
This function draws a screen box like DISPBOX() but allowing the variation <strong>of</strong> colors around the<br />
border to simulate a sort <strong>of</strong> shadow.<br />
368.15.33 DIR()<br />
DIR( [cFileSpec], [lDrives], [lDirs], [lFiles],<br />
[lNoDirReturn], [nSortColumn] ) ⇒ cPathname<br />
cFileSpec the filename or Pathname, also with wildcards, to be searched.<br />
lDrives true (‘.T.’) means: include drives letters.<br />
lDirs<br />
true (‘.T.’) means: include directory names.<br />
lFiles true (‘.T.’) means: include file names.<br />
true (‘.T.’) means: do not return the shown directory if [ Esc ]<br />
lNoRirReturn<br />
is used to exit.<br />
the column number to use to sort the list. The columns are:<br />
Name = 1,<br />
Size = 2,<br />
nSortColumn<br />
Date = 3,<br />
Time = 4,<br />
Attribute = 5.<br />
It is not possible to sort for extention.
nanoBase 1997 user manual 273<br />
It is a window function useful to search a file or a directory. The complete pathname <strong>of</strong> the<br />
selected file is returned.<br />
368.15.34 DOC()<br />
DOC( [cTextFileName] ) ⇒ NIL<br />
cTextFileName<br />
can contain the text file to open and edit; if empty, the editing<br />
<strong>of</strong> ‘UNTITLED.TXT’ will start.<br />
It is the nB Text editor useful for small text files (less then 64K) and contains a complete menu<br />
that can be started with[F10].<br />
Attention: doc() should not be used inside macros.<br />
368.15.35 DOTLINE()<br />
DOTLINE() ⇒ NIL<br />
This function is a "dot" command line useful for calculations resolution. The dot-line content<br />
may be passed to the keyboard buffer.<br />
368.15.36 DTEMONTH()<br />
Date <strong>of</strong> month<br />
DTEMONTH( nMonth, cLanguage ) ⇒ cMonth<br />
nMonth the month number.<br />
cLanguage the language name.<br />
This function translates the nMonth number into the month name translated using the<br />
cLanguage language.<br />
368.15.37 DTEWEEK()<br />
Date <strong>of</strong> week<br />
DTEWEEK( nWeek, cLanguage ) ⇒ cWeek<br />
nWeek<br />
cLanguage<br />
is the week number (1 is Sunday, 7 is Saturday) to be translated<br />
into text.<br />
is the language name into which the week must be expressed.<br />
At the moment it works only for Italian, so cLanguage can<br />
only contain "ITALIANO".<br />
This function translates the week number into the week name translated using the cLanguage<br />
language.
274 volume VIII Argomenti avanzati e accessori<br />
368.15.38 EX()<br />
Execute<br />
EX( cFileMacro ) ⇒ nExitCode<br />
Executes the macro file cFileName. The extention must be specified.<br />
cFileMacro may be the name <strong>of</strong> a "compiled" macro or a text macro file.<br />
368.15.39 GET()<br />
GET( @aGetList,<br />
[nTop], [nLeft],<br />
{ |x| iif( pcount() > 0, Var := x, Var ) }<br />
[cGetPicture], [cColorString],<br />
[bPreExpression], [bValid] )<br />
aGetList<br />
is the get list array that will be increased with this get().<br />
nTop and nLeft define the starting position <strong>of</strong> this get object on the screen.<br />
Var<br />
is the variable that is to be edited with this get. Var is in fact<br />
sent to the GET() function using a code block.<br />
cGetPicture<br />
is the get picture to use for Var.<br />
cColorString is the color string to use for the get.<br />
is a code block that will be evaluated before the get object<br />
bPreExpression<br />
will became active. It must result True to obtain that the get<br />
object became active.<br />
is a code block that will be evaluated after the get object is<br />
bValid<br />
edited. It must result True to obtain that the get object may<br />
become inactive.<br />
Create screen editing masks.<br />
368.15.40 GVADD()<br />
Get validation add<br />
GVADD( @cField, cAdd ) ⇒ .T.<br />
cField the field to fill with more data.<br />
cAdd<br />
is the string to be added to the content <strong>of</strong> cField.<br />
This function is to be used inside GETs for pre/post validation, when a the content <strong>of</strong> a field<br />
should be added with more data.<br />
cField is returned with the same length as before to avoid troubles with current and future GETs.
nanoBase 1997 user manual 275<br />
368.15.41 GVDEFAULT()<br />
Get validation default<br />
GVDEFAULT( @cField, cDefault ) ⇒ .T.<br />
@cField<br />
the field to check and if empty correct with cDefault.<br />
cDefault is the default value to be used to replace cField.<br />
This function is to be used inside GETs for pre/post validation, when a field should have a default<br />
value.<br />
cField is returned with the same length as before to avoid troubles with current and future GETs.<br />
368.15.42 GVFILEDIR()<br />
Get validation file directory<br />
GVFILEDIR( @cWildName ) ⇒ .T.<br />
cWildName<br />
is the file name taken from the current get to be used for search<br />
with DIR().<br />
This function is to be used inside GETs for pre validation: the cWildName is a file name with<br />
wild cards that can be searched with the DIR() function after that a specific key is pressed.<br />
cWildName is returned with the same length as before to avoid troubles with current and future<br />
GETs.<br />
368.15.43 GVFILEEXIST()<br />
GVFILEEXIST( @cNameToTest, [cExtention] ) ⇒ lSuccess<br />
@cNameToTest<br />
is the file name taken from the current get to test for existence.<br />
cExtention is the normal extention <strong>of</strong> the file.<br />
This function is to be used inside GETs for post validation: the file name have to exist.<br />
cNameToTest is returned with the same length as before to avoid troubles with current and future<br />
GETs.<br />
368.15.44 GVFILEEXTENTION()<br />
GVFILEEXTENTION( @cName, cExt ) ⇒ .T.<br />
@cName<br />
the file name to be eventually corrected with file extention.<br />
cExt the file extention to use as default.<br />
This function is to use inside GETs for pre/post validation, when the content <strong>of</strong> a field should<br />
contain a file name that should be corrected adding a default extention if not given from the user.
276 volume VIII Argomenti avanzati e accessori<br />
368.15.45 GVSUBST()<br />
GVSUBST( @cField, cSubst ) ⇒ .T.<br />
@cField<br />
cSubst<br />
the field to be replaced with cSubst.<br />
is the string to be used to replace the content <strong>of</strong> cField.<br />
This function is to use inside GETs for pre/post validation, when the content <strong>of</strong> a field should be<br />
replaced with other data.<br />
cField is returned with the same length as before to avoid troubles with current and future GETs.<br />
368.15.46 HTF()<br />
HTF( [nInitialRecord] ) ⇒ NIL<br />
nInitialRecord<br />
is the record number where to start the Help Text File browse.<br />
Default is the actual record pointer.<br />
This function browse a Help Text File that must be already opened and be the active alias.<br />
368.15.47 ISFILE()<br />
ISFILE( cName ) ⇒ lFileExists<br />
cName<br />
is the file name (with or without path) to be checked for existence.<br />
This function returns true (‘.T.’) if the file cName exists. The difference between this function<br />
and the standard FILE() function is that ISFILE() checks for wildcards before. If cName contains<br />
wildcards, the result is false (‘.F.’).<br />
368.15.48 ISWILD()<br />
ISWILD( cName ) ⇒ lIsWild<br />
cName<br />
This function returns true (‘.T.’) if cName contains wildcards.<br />
368.15.49 ISMEMVAR()<br />
ISMEMVAR( cName ) ⇒ lIsMemvar<br />
cName<br />
is the file name (with or without path) to be checked for wildcards<br />
presence.<br />
is the name <strong>of</strong> a possible memvar.<br />
This function returns true (‘.T.’) if the cName is a declared Memvar.
nanoBase 1997 user manual 277<br />
368.15.50 ISCONSOLEON()<br />
ISCONSOLEON() ⇒ lConsoleIsOn<br />
This function returns true (‘.T.’) if the console will show the result <strong>of</strong> QOUT() and QQOUT().<br />
368.15.51 ISPRINTERON()<br />
ISPRINTERON() ⇒ lPrinterIsOn<br />
This function returns true (‘.T.’) if the default printer will report the the result <strong>of</strong> QOUT() and<br />
QQOUT().<br />
The default printer is ‘PRN:’ or ‘LPT1:’. If SET ALTERNATE TO is configured to send outputs<br />
to ‘LPT2:’ or another printer, the function will report false (‘.F.’).<br />
368.15.52 KEYBOARD()<br />
KEYBOARD( [cString] ) ⇒ NIL<br />
This function stuff a string into the keyboard buffer.<br />
368.15.53 LISTWINDOW()<br />
LISTWINDOW( acMenuItem, [cDescription],<br />
[nTop], [nLeft], [nBottom], [nRight],<br />
[cColorTop], [cColorBody] ) ⇒ nPosition<br />
acMenuItem<br />
is the character array containing the list <strong>of</strong> choices.<br />
cDescription is the header to be shown at the top window.<br />
nTop, nLeft, nBottom, nRight are the window coordinates.<br />
cColorTop is the color to use for window header and footer.<br />
cColorBody<br />
is the color to use for the window body that is the space where<br />
the text appears.<br />
This function is an similar to achoice(), but it shows a header and footer, and it saves the screen,<br />
acting like a window.<br />
368.15.54 MEMOWINDOW()<br />
MEMOWINDOW( cVar, [cDescription], [nTop], [nLeft],<br />
[nBottom], [nRight], [cColorTop], [cColorBody],<br />
[lEditMode], [nLineLength], [nTabSize] ) ⇒ cVar<br />
cVar is the character field (variable) to be edited.<br />
cDescription is the header to be shown at the top window.<br />
nTop, nLeft, nBottom, nRight are the window coordinates.<br />
cColorTop is the color to use for window header and footer.<br />
cColorBody<br />
is the color to use for the window body that is the space where<br />
the text appears.<br />
lEditMode<br />
is equivalent to memoedit().
278 volume VIII Argomenti avanzati e accessori<br />
nLineLength is equivalent to memoedit().<br />
nTabSize is equivalent to memoedit().<br />
This function lets you easily edit a long character field (memo) defining automatically a simple<br />
window and providing a simple help.<br />
368.15.55 MEMPUBLIC()<br />
MEMPUBLIC( cMemvarName|acMemvarNames ) ⇒ NIL<br />
cMemvarName<br />
acMemvarNames<br />
Creates a PUBLIC variables or a group <strong>of</strong> variables.<br />
368.15.56 MEMRELEASE()<br />
MEMRELEASE( cMemvarName|acMemvarNames ) ⇒ NIL<br />
is the name <strong>of</strong> the PUBLIC variable to create (max 10 characters).<br />
is an array <strong>of</strong> PUBLIC variable names to create (max 10 characters).<br />
cMemvarName is the name <strong>of</strong> the PUBLIC variable to be released.<br />
acMemvarNames<br />
is an array <strong>of</strong> PUBLIC variable names to be released.<br />
This function releases a previously created PUBLIC variables or a group <strong>of</strong> variables.<br />
368.15.57 MEMRESTORE()<br />
MEMRESTORE( cMemFileName, [lAdditive] ) ⇒ NIL<br />
cMemFileName<br />
lAdditive<br />
Retrieve memory variables form a memory file (.MEM).<br />
368.15.58 MEMSAVE()<br />
MEMSAVE( cMemFileName, [cSkeleton], [lLike] ) ⇒ NIL<br />
cMemFileName<br />
cSkeleton<br />
lLike<br />
the memory file (.MEM) to load from disk.<br />
if True causes memory variables loaded from the memory file<br />
to be added to the existing pool <strong>of</strong> memory variables. If False,<br />
the existing memory variables are automatically released.<br />
the memory file (.MEM) where public variables should be<br />
saved.<br />
the skeleton mask for defining a group <strong>of</strong> variables. Wildcard<br />
characters may be used: _*_ and _?_.<br />
if True, the variables grouped with cSkeleton are saved, else<br />
only the other variables are saved.
nanoBase 1997 user manual 279<br />
Saves memory variables to a memory file (.MEM).<br />
368.15.59 MENUPROMPT()<br />
MENUPROMPT( @aoGet,<br />
[nRow], [nCol],<br />
[cPrompt], [bBlock] ) ⇒ NIL<br />
aoGet<br />
is an array <strong>of</strong> get objects where a new get is added by<br />
MENUPROMPT(). These gets are read only.<br />
nRow and nCol<br />
are the screen coordinates where the menu prompt will appear.<br />
cPrompt is the menu prompt string.<br />
is the code block to execute when the cursor is on the current<br />
bBlock<br />
menu prompt. It is usually a code block that shows a message<br />
somewhere on the screen.<br />
This function should substitute the @...PROMPT command and handle the mouse.<br />
368.15.60 MENUTO()<br />
MENUTO( aoGet, nPos ) ⇒ nChoice<br />
aoGet<br />
nPos<br />
array <strong>of</strong> get objects.<br />
starting position to be edited.<br />
Like MENU TO. It returns the selected menu item created with MENUPROMPT(). It supports<br />
the mouse.<br />
368.15.61 MESSAGELINE()<br />
MESSAGELINE( [cMessage], [cColor], [nPosTop], [nPosLeft] )<br />
⇒ NIL<br />
aMessage the message to be displayed.<br />
cColor<br />
the color string.<br />
the starting position where the string message would appear<br />
nPosTop and nPosLeft<br />
on the screen. Default values are respectively ROW() and<br />
COL().<br />
MESSAGELINE() is a function that display a message on the screen on the selected position. If<br />
cMessage is NIL, the message is eliminated from screen restoring the previous screen content.
280 volume VIII Argomenti avanzati e accessori<br />
368.15.62 MOUSESCRSAVE()<br />
MOUSESCRSAVE( [nTop], [nLeft], [nBottom], [nRight] )<br />
⇒ cSavedScreen<br />
nTop, nLeft, nBottom and nRight are the screen coordinates that will be to save the screen.<br />
This function works line SAVESCREEN() but it hide the mouse cursor before a screen save is<br />
made.<br />
368.15.63 MOUSESCRRESTORE()<br />
MOUSESCRRESTORE( [nTop], [nLeft], [nBottom], [nRight],<br />
[cScreen] ) ⇒ cSavedScreen<br />
nTop, nLeft, nBottom and nRight<br />
cScreen<br />
are the screen coordinates where the saved screen will be restored.<br />
is the previously saved screen to restore.<br />
This function works line RESTSCREEN() but it hide the mouse cursor before a screen restore is<br />
made.<br />
368.15.64 PICCHRMAX()<br />
PICCHRMAX( [nCol], [nMaxCol] ) ⇒ cPictureString<br />
nCol<br />
nMaxCol<br />
is the starting position on the screen for the get field.<br />
is the end position on the screen <strong>of</strong> the get field.<br />
This function is useful when a character field is to be used on a get object. The generated picture<br />
will be the <strong>of</strong> the maximum possible extention, eventually with scroll.<br />
368.15.65 QUIT()<br />
QUIT() ⇒ NIL<br />
Terminates program execution.<br />
368.15.66 READ()<br />
READ( aoGet, [nPos], [aButtons], [lReadOnly] )<br />
⇒ lUpdated<br />
aoGet<br />
nPos<br />
aButtons<br />
lReadOnly<br />
is the array <strong>of</strong> get objects.<br />
is the starting position.<br />
is the array <strong>of</strong> buttons.<br />
if True, get fields cannot be modified; the default value is<br />
False.
nanoBase 1997 user manual 281<br />
This function is made to substitute the READMODAL() allowing the use <strong>of</strong> the mouse. The array<br />
aButtons is made with the help <strong>of</strong> the function BUTTON().<br />
368.15.67 RF()<br />
RF( cFRMName,<br />
[bForCondition], [bWhileCondition],<br />
[nNext], [nRecord], [lRest], [lPlain],<br />
[cbHeading], [lBeforeEject], [lSummary],<br />
[lDate], [acExtra] ) ⇒ NIL<br />
cFRMName<br />
the form (.FRM) file to use to print the active alias.<br />
bForCondition code block for the FOR condition.<br />
bWhileCondition code block for the WHILE condition.<br />
nNext see REPORT FORM.<br />
nRecord see REPORT FORM<br />
lRest see REPORT FORM<br />
lPlain<br />
if true (‘.T.’), force the print in a simple way.<br />
additional header in character or code block form. If a code<br />
cbHeading<br />
block is sent, the final result must be a character string.<br />
lBeforeEject if true (‘.T.’), force a form feed before the print.<br />
lSummary if true (‘.T.’), force a summary print only.<br />
lDate<br />
if false (‘.F.’), force the print without date at the top <strong>of</strong> page.<br />
a character array that may be used for translating standard<br />
printed report form words and to add vertical and horizontal<br />
separations. The default value <strong>of</strong> acExtra is:<br />
acExtra[1] "Page No."<br />
acExtra<br />
acExtra[2] "** Subtotal **"<br />
acExtra[3] "* Subsubtotal *"<br />
acExtra[4] "*** Total ***"<br />
acExtra[5] " " vertical column separation<br />
axExtra[6] "" horizontal separation: no separation.<br />
This function does the same work <strong>of</strong> REPORT FORM or __ReportForm or dbReportForm, but it<br />
prints where qout() and qqout() print.<br />
368.15.68 RPT()<br />
RPT( cText ) ⇒ NIL<br />
This function prints the text contained into cText using print commands. This function accepts<br />
other parameters here not described, as they are not to be used for macro purpose. The printing<br />
is made using QOUT() and QQOUT(), this way it is sensible to the "alternate" file definition.<br />
368.15.69 RPTMANY()<br />
RPTMANY( cText, [bWhileCondition], [bForCondition] )<br />
⇒ NIL<br />
cText<br />
bWhileCondition<br />
bForCondition<br />
is the text to be printed.<br />
is a code block for a WHILE condition to respect for the<br />
records to print.<br />
is a code block for a FOR condition to respect for the records<br />
to print.
282 volume VIII Argomenti avanzati e accessori<br />
This function prints the text contained into cText many times: one for every record contained<br />
into the active alias.<br />
368.15.70 RPTTRANSLATE()<br />
RPTTRANSLATE( cText ) ⇒ cTranslatedText<br />
This function translates once cText replacing variables with memvars or Fields.<br />
368.15.71 RUN()<br />
RUN( cCommand ) ⇒ NIL<br />
This function start execution <strong>of</strong> cCommand in a DOS session. It works only if there is enough<br />
available memory.<br />
368.15.72 SAY()<br />
SAY( nTop, nLeft, Expr,<br />
[cSayPicture], [cColorString] ) ⇒ NIL<br />
nTop and nLeft<br />
define the starting position on the screen where the Expr<br />
should be displayed.<br />
nLeft is an expression that will be solved and displayed.<br />
cSayPicture is the picture to use to display Expr.<br />
cColorString is the color string to use.<br />
This function displays the result <strong>of</strong> Expr on the screen on the desired position.<br />
368.15.73 SETCOLORSTANDARD()<br />
SETCOLORSTANDARD( [nColor], [cColor|acColor] )<br />
nColor<br />
cColor<br />
acColor<br />
⇒ cPreviousColor|acPreviousColor<br />
is the color number to take into consideration:<br />
0 All colors<br />
1 Base<br />
2 Menu<br />
3 Head<br />
4 Body (Say - Get)<br />
5 Button (Mouse buttons)<br />
6 Message<br />
7 Alert<br />
the color string to be associated with nColor.<br />
it the color array<br />
This function is a way to handle colors inside the application. The functions that display something<br />
use a default color depending on what they does. These colors may be changed with SET-<br />
COLORSTANDARD(), all together or only one.
nanoBase 1997 user manual 283<br />
368.15.74 SETFUNCTION()<br />
SETFUNCTION( nFunctionKey, cString ) ⇒ NIL<br />
nFunctionKey<br />
the number <strong>of</strong> the function key ( 1=F1, 12=F12) to be assigned.<br />
cString the character string.<br />
This function assigns a character string to a function key (obsolete).<br />
368.15.75 SETMOUSE()<br />
SETMOUSE( [lShow] )⇒ lPrevious<br />
lShow<br />
True shows the mouse cursor, False hide the mouse cursor,<br />
NIL reports only the status.<br />
This function is made to show, hide or report only the mouse cursor status.<br />
368.15.76 SETOUTPUT()<br />
SETOUTPUT( [cPeriperal|aPeripheral] )<br />
⇒ aPrevious_Output_Peripherals<br />
cPeripheral is the new output peripheral for qout() and qqout() functions.<br />
aPeripheral<br />
are the new output peripherals configurations for qout() and<br />
qqout() functions.<br />
nB is organised in the way to have only one output peripheral at the time. This function help to<br />
make order inside SET CONSOLE, SET PRINTER and SET ALTERNATE.<br />
If cPeripheral contains:<br />
"CON"<br />
"PRN"<br />
SET CONSOLE is set to ON,<br />
SET PRINTER is set to OFF,<br />
SET ALTERNATE is set to OFF;<br />
SET CONSOLE is set to OFF,<br />
SET PRINTER is set to ON,<br />
SET ALTERNATE is set to OFF;<br />
"LPT1"<br />
same as "PRN";<br />
otherwise<br />
SET CONSOLE is set to OFF,<br />
SET PRINTER is set to OFF,
284 volume VIII Argomenti avanzati e accessori<br />
SET ALTERNATE is set to ON,<br />
SET ALTERNATE TO is set to cPeripheral.<br />
aPeripheral is organised this way:<br />
aPeripheral[1] = _SET_CONSOLE<br />
aPeripheral[2] = _SET_PRINTER<br />
aPeripheral[3] = _SET_ALTERNATE<br />
aPeripheral[4] = _SET_ALTFILE<br />
aPeripheral[5] = _SET_EXTRA<br />
aPeripheral[6] = _SET_EXTRAFILE<br />
This function is necessary because SET ALTERNATE alone is not enough to print on the screen<br />
when the peripheral name is "CON" or to print on the printer when the peripheral name is "PRN"<br />
or "LPT1". In fact, in the first case, ROW() and COL() will not be updated, in the second case,<br />
PROW() and PCOL() will not be updated.<br />
This function returns an array organised in the same way as aPeripheral is, that shows the active<br />
output configuration.<br />
368.15.77 SETRPTEJECT()<br />
SETRPTEJECT( [lbEject] ) ⇒ lPreviousEjectMode<br />
This function is used to set the eject mode after every page print for RPT(). If single sheet paper is<br />
used, then SETRPTEJECT(.T.) must be set; for continuous paper, SETRPTEJECT(.F.) is correct.<br />
The default value is .F..<br />
lbEject<br />
368.15.78 SETRPTLINES()<br />
SETRPTLINES() ⇒ nRemainingLines<br />
logical or code block, is the eject mode to set. Default is no<br />
change, the starting value is ‘.F.’<br />
This function is used to report the number <strong>of</strong> lines available before the completion <strong>of</strong> the page<br />
print for RPT().<br />
368.15.79 SETVERB()<br />
Set verbose<br />
SETVERB( cSpecifier, [xNewSetting], [lOpenMode] )<br />
⇒ xPreviousValueSet<br />
cSpecifier a word that defines the kind <strong>of</strong> set is going to be considered.<br />
xNewSetting is the new value to set up.<br />
lOpenMode used only for some kind <strong>of</strong> set.<br />
This function is analogue to SET() but it uses a character string (with cSpecifier) and not a
nanoBase 1997 user manual 285<br />
number to select the set. This is made to make easier the work with macros.<br />
cSpecifier may contain:<br />
"EXACT"<br />
"FIXED"<br />
"DECIMALS"<br />
"DATEFORMAT"<br />
"EPOCH"<br />
"PATH"<br />
"DEFAULT"<br />
"EXCLUSIVE"<br />
"SOFTSEEK"<br />
"UNIQUE"<br />
"DELETED"<br />
"CANCEL"<br />
"TYPEAHEAD"<br />
"COLOR"<br />
"CURSOR"<br />
"CONSOLE"<br />
"ALTERNATE"<br />
"ALTFILE"<br />
"DEVICE"<br />
"EXTRA"<br />
"EXTRAFILE"<br />
"PRINTER"<br />
"PRINTFILE"<br />
"MARGIN"<br />
"BELL"<br />
"CONFIRM"<br />
"ESCAPE"<br />
"INSERT"<br />
"EXIT"<br />
"INTENSITY"<br />
"SCOREBOARD"<br />
"DELIMITERS"<br />
"DELIMCHARS"<br />
"WRAP"<br />
"MESSAGE"<br />
"MCENTER"<br />
368.15.80 SETVERB("EXACT") (obsolete)<br />
SETVERB( "EXACT", [lExact] ) ⇒ lPrevious<br />
If lExact is True, it forces exact comparison <strong>of</strong> character strings, including length. If it is False,<br />
character strings are compared until the left string length is exhausted; that is that "" (the null<br />
string) is equal to any other string.<br />
Please note that the == operator is a comparison operator for exact match and using it,<br />
SETVERB("EXACT", ‘.F.’) will not work.
286 volume VIII Argomenti avanzati e accessori<br />
The starting value is True; the recommended value is True.<br />
368.15.81 SETVERB("FIXED")<br />
SETVERB( "FIXED", [lFixed] ) ⇒ lPrevious<br />
If lFixed contains True, numeric values are displayed ever with a fixed number <strong>of</strong> decimal digits,<br />
depending on the value set by SETVERB("DECIMALS").<br />
The starting value is False.<br />
The recommended value is False: if you have to display a fixed number <strong>of</strong> decimal digits it is<br />
better to define a good display picture.<br />
368.15.82 SETVERB("DECIMALS")<br />
SETVERB( "DECIMALS", [nDecimals] ) ⇒ nPrevious<br />
nDecimals is the number <strong>of</strong> digits to display after the decimal position. This set is enabled <strong>of</strong><br />
disabled with SETVERB("FIXED").<br />
The starting value is 8.<br />
368.15.83 SETVERB("DATEFORMAT")<br />
SETVERB( "DATEFORMAT", [cDateFormat] ) ⇒ cPrevious<br />
cDateFormat is a character expression that specifies the date format.<br />
The starting value is "dd/mm/yyyy".<br />
Some date format examples:<br />
AMERICAN<br />
ANSI<br />
BRITISH<br />
FRENCH<br />
GERMAN<br />
ITALIAN<br />
JAPAN<br />
USA<br />
368.15.84 SETVERB("EPOCH")<br />
SETVERB( "EPOCH", [nYear] ) ⇒ nPrevious<br />
"mm/dd/yyyy"<br />
"yyyy.mm.dd"<br />
"dd/mm/yyyy"<br />
"dd/mm/yyyy"<br />
"dd.mm.yyyy"<br />
"dd-mm-yyyy"<br />
"yyyy/mm/dd"<br />
"mm-dd-yyyy"<br />
nYear specifies the base year <strong>of</strong> 100-year period in which all dates containing only two year<br />
digits are assumed to fall.<br />
The starting value is 1900.
nanoBase 1997 user manual 287<br />
368.15.85 SETVERB("PATH")<br />
SETVERB( "PATH", [cPath] ) ⇒ cPrevious<br />
cPath identifies the paths that nB uses when searching for a file not found in the current directory.<br />
The list <strong>of</strong> paths can be separated by commas or semicolons.<br />
The starting value is "".<br />
368.15.86 SETVERB("DEFAULT")<br />
SETVERB( "DEFAULT", [cPath] ) ⇒ cPrevious<br />
cPath identifies the default disk drive and directory.<br />
The starting value is "".<br />
368.15.87 SETVERB("EXCLUSIVE")<br />
SETVERB( "EXCLUSIVE", [lExclusive] ) ⇒ lPrevious<br />
If lPath is True, the default database (.DBF) file open is made in exclusive mode; in the other<br />
case, in shared mode.<br />
The starting value is True.<br />
368.15.88 SETVERB("SOFTSEEK")<br />
SETVERB( "SOFTSEEK", [lS<strong>of</strong>tSeek] ) ⇒ lPrevious<br />
If lS<strong>of</strong>tSeek is True, if a DBSEEK() index search fails, the record pointer is moved to the next<br />
record with a higher key. If it is False, in case <strong>of</strong> a DBSEEK() index search failure, the record<br />
pointer is moved at EOF().<br />
The starting value is False.<br />
368.15.89 SETVERB("UNIQUE") (obsolete)<br />
SETVERB( "UNIQUE", [lUnique] ) ⇒ lPrevious<br />
If lUnique is True, during creation or update <strong>of</strong> ‘.DBF’ indexes, if two or more records are found<br />
with the same key, only the first record will be included inside the index.<br />
If lUnique is False, duplicated record keys are allowed.<br />
The starting value is False.
288 volume VIII Argomenti avanzati e accessori<br />
368.15.90 SETVERB("DELETED")<br />
SETVERB( "DELETED", [lDeleted] ) ⇒ lPrevious<br />
If lDeleted is True, record signed for deletion are not filtered, that is, these are still normally<br />
visible as they were not deleted. In the other case, they hare (in most cases) hidden to the user.<br />
The starting value is False.<br />
368.15.91 SETVERB("CANCEL")<br />
SETVERB( "CANCEL", [lCancel] ) ⇒ lPrevious<br />
If lCancel is True, enables [ Alt+c ] and [ Ctrl+Break ] as termination keys. In the other case, not.<br />
The starting value is True.<br />
368.15.92 SETVERB("TYPEAHEAD")<br />
SETVERB( "TYPEAHEAD", [nTypeAhead] ) ⇒ nPrevious<br />
nTypeAhead is the number <strong>of</strong> keystrokes the keyboard buffer can hold from a minimum <strong>of</strong> zero<br />
to a maximum <strong>of</strong> 4096.<br />
The starting value is 15.<br />
368.15.93 SETVERB("COLOR")<br />
SETVERB( "COLOR", [cColorString] ) ⇒ cPrevious<br />
nColorString defines the normal screen colors. There are five couple <strong>of</strong> colors, but only three are<br />
really operative:<br />
standard<br />
This is the standard color used for screen output.<br />
enhanced<br />
This is the color used for highlighted screen output.<br />
border<br />
Normally unused.<br />
background Normally unused.<br />
unselected This is the color used for GET fields without focus.<br />
The default color string is "BG+/B,N/W,N/N,N/N,W/N" that is:<br />
standard<br />
bright Cyan on Blue<br />
enhanced Black on White<br />
border Black on Black<br />
background Black on Black<br />
unselected White on Black<br />
The following table explains the use <strong>of</strong> letters inside the color string. Note that the plus sign (+)<br />
means high intensity, the star (*) means blink and that + and * can be allowed only to the first<br />
letter inside a couple.<br />
Color Letter Monochrome<br />
Black N, Space Black
nanoBase 1997 user manual 289<br />
Color Letter Monochrome<br />
Blue B Underline<br />
Green G White<br />
Cyan BG White<br />
Red R White<br />
Magenta RB White<br />
Brown GR White<br />
White W White<br />
Gray N+ Black<br />
Bright Blue B+ Bright Underline<br />
Bright Green G+ Bright White<br />
Bright Cyan BG+ Bright White<br />
Bright Red R+ Bright White<br />
Bright Magenta RB+ Bright White<br />
Bright Brown GR+ Bright White<br />
Bright White W+ Bright White<br />
Black U Underline<br />
Inverse Video I Inverse Video<br />
Blank X Blank<br />
368.15.94 SETVERB("CURSOR")<br />
SETVERB( "CURSOR", [lCursor] ) ⇒ lPrevious<br />
If lCursor is True, the cursor is showed, else it is hidden.<br />
The starting value is True.<br />
368.15.95 SETVERB("CONSOLE")<br />
SETVERB( "CONSOLE", [lConsole] ) ⇒ lPrevious<br />
If lConsole is True, the output <strong>of</strong> console commands is displayed on the screen, else it is not.<br />
The starting value is True.<br />
368.15.96 SETVERB("ALTERNATE")<br />
SETVERB( "ALTERNATE", [lAlternate] ) ⇒ lPrevious<br />
If lAlternate is True, the output <strong>of</strong> console commands is send also to a standard ASCII text file.<br />
The starting value is False.<br />
368.15.97 SETVERB("ALTFILE")<br />
SETVERB( "ALTFILE", [cAlternateFilename], [lAdditive] )<br />
⇒ cPrevious<br />
If SETVERB("ALTERNATE") is True, the output <strong>of</strong> the console is send also to<br />
cAlternateFilename, a standard ASCII file.
290 volume VIII Argomenti avanzati e accessori<br />
If lAdditive is True, the output is appended to the ASCII file if it already exists, else it is erased<br />
first.<br />
368.15.98 SETVERB("DEVICE")<br />
SETVERB( "DEVICE", [cDevice] ) ⇒ cPrevious<br />
cDevice is the name <strong>of</strong> the device where SAY() will display its output.<br />
The starting value is "SCREEN", the alternative is "PRINTER".<br />
The recommended value is "SCREEN".<br />
368.15.99 SETVERB("EXTRA")<br />
SETVERB( "EXTRA", [lExtra] ) ⇒ lPrevious<br />
If lExtra is True, the output <strong>of</strong> console commands is send also to a standard ASCII text file.<br />
The starting value is False.<br />
368.15.100 SETVERB("EXTRAFILE")<br />
SETVERB( "EXTRAFILE", [cExtraFilename], [lAdditive] )<br />
⇒ cPrevious<br />
If SETVERB("EXTRA") is True, the output <strong>of</strong> the console is send also to cExtraFilename, a<br />
standard ASCII file.<br />
If lAdditive is True, the output is appended to the ASCII file if it already exists, else it is erased<br />
first.<br />
368.15.101 SETVERB("PRINTER")<br />
SETVERB( "PRINTER", [lPrinter] ) ⇒ lPrevious<br />
If lPrinter is True, the output <strong>of</strong> console commands is also printed, else it is not.<br />
The starting value is False.<br />
368.15.102 SETVERB("PRINTFILE")<br />
SETVERB( "PRINTFILE", [cPrintFileName] ) ⇒ cPrevious<br />
cPrintFileName is the name <strong>of</strong> the printer peripheral name.<br />
The starting value is "" (null string).
nanoBase 1997 user manual 291<br />
368.15.103 SETVERB("MARGIN")<br />
SETVERB( "MARGIN", [nPageOffset] ) ⇒ nPrevious<br />
nPageOffset is the positive number <strong>of</strong> column to be used as a left margin for all printer output.<br />
The starting value is 0.<br />
368.15.104 SETVERB("BELL")<br />
SETVERB( "BELL", [lBell] ) ⇒ lPrevious<br />
If lBell is True, the sound <strong>of</strong> the bell is used to get the attention <strong>of</strong> the user when some wrong<br />
actions are made.<br />
The starting value is False.<br />
368.15.105 SETVERB("CONFIRM")<br />
SETVERB( "CONFIRM", [lConfirm] ) ⇒ lPrevious<br />
If lConfirm is False, the GET is simply terminated typing over the end <strong>of</strong> the get field; in the<br />
other case (True), the GET is terminated only pressing an "exit key". The starting value is True.<br />
368.15.106 SETVERB("ESCAPE")<br />
SETVERB( "ESCAPE", [lEscape] ) ⇒ lPrevious<br />
If lEscape is True, the [ Esc ] key is enabled to be a READ exit key, in the other case not.<br />
The starting value is True.<br />
The recommended value is True.<br />
368.15.107 SETVERB("INSERT")<br />
SETVERB( "INSERT", [lInsert] ) ⇒ lPrevious<br />
If lInsert is True, the data editing is in INSERT mode, in the other case, it is in OVERWRITE<br />
mode.<br />
The starting value is True.<br />
368.15.108 SETVERB("EXIT")<br />
SETVERB( "EXIT", [lExit] ) ⇒ lPrevious<br />
If lExit is True,[Up] and[Down] key may be used as exit key when the cursor is (respectively)<br />
on the first or on the last GET field. In the other case not.<br />
The starting value is False.<br />
The recommended value is False.
292 volume VIII Argomenti avanzati e accessori<br />
368.15.109 SETVERB("INTENSITY")<br />
SETVERB( "INTENSITY", [lIntensity] ) ⇒ lPrevious<br />
If lIntensitiy is True, the display <strong>of</strong> standard and enhanced display colors are enabled. In the<br />
other case, only standard colors are enabled.<br />
The starting value is True.<br />
The recommended value is True.<br />
368.15.110 SETVERB("SCOREBOARD")<br />
SETVERB( "SCOREBOARD", [lScoreboard] ) ⇒ lPrevious<br />
If lScoreboard is True, the display <strong>of</strong> messages from READ() and MEMOREAD() is allowed;<br />
in the order case not.<br />
The starting value is False.<br />
The recommended value is False: nB do not support scoreboard.<br />
368.15.111 SETVERB("DELIMITERS")<br />
SETVERB( "DELIMITERS", [lDelimiters] ) ⇒ lPrevious<br />
If lDelimiters is True, GET variables appear on the screen delimited with the delimiter symbols.<br />
In the other case, GET variables are not delimited this way, but only with the use <strong>of</strong> different<br />
colors.<br />
The starting value is False.<br />
The recommended value is False: the use <strong>of</strong> delimiters creates one more trouble when designing<br />
a screen mask.<br />
368.15.112 SETVERB("DELIMCHARS")<br />
SETVERB( "DELIMCHARS", [cDelimterCharacters] ) ⇒ cPrevious<br />
cDelimterCharacters are the delimiter characters used to delimit a GET field when<br />
SETVERB("DELIMITERS") is True.<br />
The starting value is "::".<br />
368.15.113 SETVERB("WRAP")<br />
SETVERB( "WRAP", [lWrap] ) ⇒ lPrevious<br />
If lWrap is True, the wrapping <strong>of</strong> the highlight in MENUs should be active, but this option is<br />
actually not active and all works as it is False.<br />
The starting value is False.
nanoBase 1997 user manual 293<br />
368.15.114 SETVERB("MESSAGE")<br />
SETVERB( "MESSAGE", [nMessageRow] ) ⇒ nPrevious<br />
nMessageRow is the row number where the @..PROMPT message line should appear on the<br />
screen. This option is not supported.<br />
The starting value is 0.<br />
368.15.115 SETVERB("MCENTER")<br />
SETVERB( "MCENTER", [lMessageCenter] ) ⇒ lPrevious<br />
If lMessageCenter is True, the @..PROMPT message line should appear centered on the screen.<br />
This option is not supported.<br />
The starting value is False.<br />
368.15.116 STRADDEXTENTION()<br />
STRADDEXTENTION( cName, cExt ) ⇒ cCompleteName<br />
cName<br />
the file name (with or without path) that is probably without<br />
extention.<br />
cExt the extention that must be added to cName if it has not one.<br />
This function check cName for the presence <strong>of</strong> an extention. It it has not one, cExt will be added.<br />
368.15.117 STRCUTEXTENTION()<br />
STRCUTEXTENTION( cName ) ⇒ cName<br />
cName<br />
the file name (with or without path) that is probably with extention.<br />
This function check cName for the presence <strong>of</strong> an extention. It it has one, the extention is removed.<br />
368.15.118 STRDRIVE()<br />
STRDRIVE( cName ) ⇒ cDrive<br />
cName<br />
the file name (with or without path) that contains the drive<br />
letter.<br />
This function tries to extract the drive letter information from cName.
294 volume VIII Argomenti avanzati e accessori<br />
368.15.119 STREXTENTION()<br />
STREXTENTION( cName ) ⇒ cExtention<br />
cName<br />
the file name (with or without path) that contains an extention.<br />
This function tries to extract the extention information from cName.<br />
368.15.120 STRFILE()<br />
STRFILE( cName ) ⇒ cFileName<br />
cName<br />
the file name with or without path.<br />
This function tries to extract the file name without path from cName.<br />
368.15.121 STRFILEFIND()<br />
STRFILEFIND( cName, cPath ) ⇒ cFileName<br />
cName<br />
cPath<br />
the file name or pathname containing the file name to search<br />
inside the cPath list.<br />
a list <strong>of</strong> paths separated with semicolon (just like Dos does),<br />
where cFile should be searched.<br />
If your file is to be found on different possible positions, this function search the first place where<br />
the file is found and returns a valid pathname to that file.<br />
368.15.122 STRGETLEN()<br />
STRGETLEN( xExpr, cPicture ) ⇒ nFieldLength<br />
xExpr a generic expression.<br />
cPicture<br />
the picture string.<br />
This function returns the length <strong>of</strong> field when using xExpr with cPicture.<br />
368.15.123 STRLISTASARRAY()<br />
STRLISTASARRAY( cList, [cDelimiter] ) ⇒ aList<br />
cList<br />
cDelimiter<br />
This function transform a character string list into an array.<br />
a character string containing a list separated with cDelimiter.<br />
the delimiter used to separate the elements contained inside<br />
the list.
nanoBase 1997 user manual 295<br />
368.15.124 STROCCURS()<br />
STROCCURS( cSearch, cTarget ) ⇒ nOccurrence<br />
cSearch<br />
the search string to find inside cTarget.<br />
cTarget the string to be searched for the presence <strong>of</strong> cSearch.<br />
This function returns the number <strong>of</strong> occurrence that cSearch is contained inside cTarget.<br />
368.15.125 STRPARENT()<br />
STRPARENT( cName ) ⇒ cParentPath<br />
cName<br />
the pathname.<br />
This function tries to return a parent path from cName.<br />
368.15.126 STRPATH()<br />
STRPATH( cName ) ⇒ cPath<br />
cName<br />
the pathname.<br />
This function tries to extract the path from cName.<br />
368.15.127 STRTEMPPATH()<br />
STRTEMPPATH() ⇒ cTempPath<br />
This function returns a temporary path searching for possible definitions inside the environmental<br />
variables.<br />
368.15.128 STRXTOSTRING()<br />
STRXTOSTRING( xVar, [cType] ) ⇒ cTrasformed_to_string<br />
xVar<br />
is the data <strong>of</strong> any type to be converted into string.<br />
cType is the type <strong>of</strong> the data contained inside xVar.<br />
This function returns xVar transformed into a character string.
296 volume VIII Argomenti avanzati e accessori<br />
368.15.129 TB()<br />
TB( [nTop], [nLeft], [nBottom], [nRight],<br />
[acCol], [acColSayPic],<br />
[acColTopSep], [acColBodySep], [acColBotSep],<br />
[acColHead], [acColFoot],<br />
[alColCalc],<br />
[abColValid],<br />
[abColMsg],<br />
[cColor], [abColColors],<br />
[nFreeze],<br />
[lModify],<br />
[lAppend],<br />
[lDelete],<br />
[lButtons | aButtons] ) ⇒ NIL<br />
nTop, nLeft, nBottom, nRight defines the screen area where browse have to take place.<br />
acCol<br />
is the columns array to be included into the browse.<br />
acColSayPic is the picture array.<br />
acColTopSep is the top separation array: default is chr(194)+chr(196).<br />
acColBodySep is the body separation array: default is chr(179).<br />
acColBotSep is the bottom separation array: default is chr(193)+chr(196).<br />
acColHead<br />
is the header array for every column.<br />
acColFoot<br />
is the footer array for every column.<br />
alColCalc<br />
is the array that identify the calculated column (not editable).<br />
True (‘.T.’) means calculated.<br />
abColValid<br />
is the validation array that specify when a field is properly<br />
filled. The condition must be specified in code block format.<br />
is the message array that permits to show information at the<br />
abColMsg<br />
bottom <strong>of</strong> browse area. The array must be composed with<br />
code blocks which result with a character string.<br />
cColor<br />
is the color string: it may be longer than the usual 5 elements.<br />
is the color code block array. The code block receive as pa-<br />
abColColors<br />
rameter the value contained inside the field and must return<br />
an array containing two numbers: they correspond to the two<br />
color couple from cColor.<br />
nFreeze<br />
indicates the number <strong>of</strong> columns to be left frozen on the left<br />
side.<br />
lModify indicates whether the browse can modify data.<br />
lDelete indicates whether the browse can delete and recall records.<br />
lButtons<br />
if True, default buttons are displayed.<br />
aButtons<br />
array <strong>of</strong> buttons.<br />
aButtons[n][1] N the nth button row position;<br />
aButtons[n][2] N the nth button column position;<br />
aButtons[n][3] C the nth button text;<br />
aButtons[n][4] B the nth button code block.<br />
This function, called without parameters, starts the browse <strong>of</strong> the active alias, and if relations are<br />
established, the browse includes also related data.<br />
Please note that due to an unresolved problem, the field names contained inside acCol should<br />
better contain also the alias (ALIAS->FIELD_NAME). See also the examples.
nanoBase 1997 user manual 297<br />
368.15.130 TEXT()<br />
TEXT( cText ) ⇒ NIL<br />
Shows the text contained into cText.<br />
368.15.131 TGLINSERT()<br />
TGLINSERT() ⇒ NIL<br />
Toggle the global insert mode and the cursor shape.<br />
368.15.132 TIMEX2N()<br />
TIMEX2N( [nHH], [nMM], [nSS] ) ⇒ nTime<br />
nHH is the number <strong>of</strong> hours.<br />
nMM is the number <strong>of</strong> minutes.<br />
nSS is the number <strong>of</strong> seconds.<br />
This function calculate the "time number" that is a number representing days and/or portion <strong>of</strong> a<br />
day: 1 is 1 day or 24 hours, 0.5 is 12 hours, and so on.<br />
368.15.133 TIMEN2H()<br />
TIMEN2H( nTime ) ⇒ nHours<br />
nTime<br />
is the "time number" that is a number representing days and/or<br />
portion <strong>of</strong> a day: 1 is 1 day or 24 hours, 0.5 is 12 hours, and<br />
so on.<br />
This function returns the integer number <strong>of</strong> hours contained inside nTime.<br />
368.15.134 TIMEN2M()<br />
TIMEN2M( nTime ) ⇒ nMinutes<br />
nTime<br />
is the "time number" that is a number representing days and/or<br />
portion <strong>of</strong> a day: 1 is 1 day or 24 hours, 0.5 is 12 hours, and<br />
so on.<br />
This function returns the integer number <strong>of</strong> minutes contained inside nTime after subtracting the<br />
hours.
298 volume VIII Argomenti avanzati e accessori<br />
368.15.135 TIMEN2S()<br />
TIMEN2S( nTime ) ⇒ nSeconds<br />
nTime<br />
is the "time number" that is a number representing days and/or<br />
portion <strong>of</strong> a day: 1 is 1 day or 24 hours, 0.5 is 12 hours, and<br />
so on.<br />
This function returns the number <strong>of</strong> seconds (with eventual decimals) contained inside nTime<br />
after subtracting the hours and the minutes.<br />
368.15.136 TRUESETKEY()<br />
TRUESETLEY( nInkeyCode, bAction ) ⇒ .T.<br />
This function is equivalent to SETKEY() but it returns always ‘.T.’<br />
368.15.137 WAITFILEEVAL()<br />
WAITFILEEVAL( lClose ) ⇒ .T.<br />
Shows a wait bar calling WAITPROGRESS() for operation on records <strong>of</strong> a database.<br />
If there is no index active, it is equivalent to WAITPROGRES(RECNO()/LASTREC()).<br />
if an index is active, this cannot work, so an increment for each call is made: WAITPRO-<br />
GRES((nIncrement++)/LASTREC()).<br />
This function must be closed calling it with the lClose parameter to true (‘.T.’). This way,<br />
internal counters are closed and WAITPROGRESS() is closed too.<br />
368.15.138 WAITFOR()<br />
WAITFOR( [cMessage] ) ⇒ NIL<br />
Shows cMessage until it is called again. The wait window is closed when called without parameter<br />
or with NIL.<br />
368.15.139 WAITPROGRESS()<br />
WAITPROGRESS( [nPercent] ) ⇒ .T.<br />
Shows a wait bar on the screen top depending on the value contained into nPercent. nPercent<br />
starts form 0 and ends to 1 (100%). If a value <strong>of</strong> one or more, or NIL is passed, the wait window<br />
is closed.
nanoBase 1997 user manual 299<br />
368.16 Normal command substitution<br />
Clipper works only with functions and commands that are converted into function using the<br />
‘STD.CH’. Here are described some command replacement that can be used also with nB macros.<br />
?<br />
@BOX<br />
@TO<br />
@GET<br />
@SAY<br />
? [exp_list]<br />
qout([exp_list])<br />
?? [exp_list]<br />
qqout([exp_list])<br />
@ nTop, nLeft, nBottom, nRight BOX cnBoxString [COLOR cColorString]<br />
dispbox(nTop, nLeft, nBottom, nRight, [cnBoxString], [cColorString])<br />
@ nTop, nLeft TO nBottom, nRight DOUBLE [COLOR cColorString]<br />
dispbox(nTop, nLeft, nBottom, nRight, 2 [,cColorString])<br />
@ nTop, nLeft TO nBottom, nRight [COLOR cColorString]<br />
dispbox(nTop, nLeft, nBottom, nRight, 1 [,cColorString])<br />
@ nTop, nLeft CLEAR [TO nBottom, nRight]<br />
scroll([nTop], [nLeft], [nBottom, nRight])<br />
setpos(nRow, nCol)<br />
@ nTop, nLeft GET Var [PICTURE cGetPicture] [COLOR cColorString] [WHEN lPreExpression] ←↪<br />
↩→[VALID lPostExpression]<br />
setpos(nTop, nLeft)<br />
aadd( GetList, _GET_( Var, "Var", cGetPicture, [{|| lPostExpression}],←↪<br />
↩→[{|| lPreExpression}] ):display() ) atail(GetList):colorDisp(cColorString)<br />
@ nTop, nLeft SAY exp [COLOR cColorString]<br />
devpos(nTop, nLeft)<br />
devout(exp [, cColorString])<br />
@ nTop, nLeft SAY exp PICTURE cSayPicture [COLOR cColorString]<br />
devpos(nTop, nLeft)<br />
devoutpic(exp, cSayPicture, [cColorString])<br />
APPEND<br />
CLEAR<br />
APPEND BLANK<br />
dbappend()<br />
CLEAR<br />
Scroll()<br />
SetPos(0,0)
300 volume VIII Argomenti avanzati e accessori<br />
CLOSE<br />
ReadKill(.T.)<br />
GetList := {}<br />
CLEAR GETS<br />
ReadKill(.T.)<br />
GetList := {}<br />
CLEAR SCREEN | CLS<br />
Scroll()<br />
SetPos(0,0)<br />
CLOSE<br />
dbCloseArea()<br />
CLOSE idAlias<br />
idAlias->( dbCloseArea() )<br />
CLOSE ALTERNATE<br />
Set(19, "")<br />
CLOSE DATABASES<br />
dbCloseAll()<br />
CLOSE INDEXES<br />
dbClear<strong>Index</strong>()<br />
COMMIT<br />
COMMIT<br />
COUNT<br />
dbCommitAll()<br />
COUNT TO idVar [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {||idVar:=idVar+1}, {||lForCondition}, {||lWhileCondition},←↪<br />
↩→nNextRecords, nRecord, lRest )<br />
DEFAULT<br />
DEFAULT xVar TO xDefaultValue<br />
DEFAULT( @xVar, xDefaultValue ) ⇒ xVar<br />
DELETE<br />
EJECT<br />
DELETE<br />
dbDelete()<br />
DELETE [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {||dbDelete()}, {||lForCondition}, {||lWhileCondition},←↪<br />
↩→nNextRecords, nRecord, lRest )<br />
DELETE FILE xcFile<br />
ferase( cFile )<br />
EJECT<br />
ERASE<br />
qqout( chr(13) )<br />
ERASE xcFile<br />
ferase( cFile )
nanoBase 1997 user manual 301<br />
FIND<br />
GO<br />
FIND xcSearchString<br />
dbSeek( cSearchString )<br />
GO[TO] nRecord<br />
dbgoto(nRecord)<br />
GO[TO] BOTTOM<br />
dbGoBottom()<br />
GO[TO] TOP<br />
dbgotop()<br />
INDEX ON<br />
READ<br />
INDEX ON expKey TO xc<strong>Index</strong>Name [UNIQUE] [FOR lForCondition]←↪<br />
↩→[WHILE lWhileCondition] [[EVAL lEvalCondition] [EVERY nRecords]] [ASCENDING|<br />
DESCENDING]<br />
ordCondSet( [cForCondition], [bForCondition], , [bWhileCondition],←↪<br />
↩→[bEvalCondition], [nRecords], RECNO(), , , , lDescending )<br />
ordCreate( c<strong>Index</strong>Name, , cExpKey, bExpKey, lUnique )<br />
READ<br />
ReadModal(GetList)<br />
GetList := {}<br />
READ SAVE<br />
ReadModal(GetList)<br />
RECALL<br />
RECALL<br />
dbRecall()<br />
RECALL [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {||dbRecall()}, {||lForCondition}, {||lWhileCondition},←↪<br />
↩→nNextRecords, nRecord, lRest )<br />
REINDEX<br />
REINDEX [EVAL lEvalCondition] [EVERY nRecords]<br />
ordCondSet(, , , , [bEvalCondition], [nRecords], , , , , , , )<br />
ordListRebuild()<br />
RENAME<br />
RENAME xcOldFile TO xcNewFile<br />
frename( cOldFile, cNewFile )<br />
REPLACE<br />
REPLACE idField1 WITH exp1 [, idField2 WITH exp2...]←↪<br />
↩→[FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]←↪<br />
↩→[RECORD nRecord] [REST] [ALL]<br />
dbeval( {|| idField1 := exp1 [, idField2 := exp2...]},←↪<br />
↩→{||lForCondition}, {||lWhileCondition}, nNextRecords,←↪<br />
↩→nRecord, lRest )
302 volume VIII Argomenti avanzati e accessori<br />
REPLACE idField1 WITH exp1<br />
idField1 := exp1<br />
RESTORE<br />
SAVE<br />
SEEK<br />
RESTORE SCREEN FROM cScreen<br />
restscreen( 0, 0, Maxrow(), Maxcol(), cScreen )<br />
SAVE SCREEN TO cScreen<br />
cScreen := savescreen( 0, 0, maxrow(), maxcol() )<br />
SEEK expSearch [SOFTSEEK]<br />
dbSeek( expSearch [, lS<strong>of</strong>tSeek] )<br />
SELECT<br />
SET<br />
SELECT xnWorkArea | idAlias<br />
dbSelectArea( nWorkArea | cIdAlias )<br />
SET ALTERNATE TO xcFile [ADDITIVE]<br />
Set( 19, cFile, lAdditive )<br />
SET ALTERNATE ON | OFF | xlToggle<br />
Set( 18, "ON" | "OFF" | lToggle )<br />
SET BELL ON | OFF | xlToggle<br />
Set( 26, "ON" | "OFF" | lToggle )<br />
SET COLOR | COLOUR TO (cColorString)<br />
SetColor( cColorString )<br />
SET CONFIRM ON | OFF | xlToggle<br />
Set( 27, "ON" | "OFF" | lToggle )<br />
SET CONSOLE ON | OFF | xlToggle<br />
Set( 17, "ON" | "OFF" | lToggle )<br />
SET CURSOR ON | OFF | xlToggle<br />
SetCursor( 1 | 0 | iif( lToggle, 1, 0 ) )<br />
SET DATE FORMAT [TO] cDateFormat<br />
Set( 4, cDateFormat )<br />
SET DECIMALS TO<br />
Set( 3, 0 )<br />
SET DECIMALS TO nDecimals<br />
Set( 3, nDecimals )<br />
SET DEFAULT TO<br />
Set( 7, "" )<br />
SET DEFAULT TO xcPathspec<br />
Set( 7, cPathspec )
nanoBase 1997 user manual 303<br />
SET DELETED ON | OFF | xlToggle<br />
Set( 11, "ON" | "OFF" | lToggle )<br />
SET DELIMITERS ON | OFF | xlToggle<br />
Set( 33, "ON" | "OFF" | lToggle )<br />
SET DELIMITERS TO [DEFAULT]<br />
Set( 34, "::" )<br />
SET DELIMITERS TO cDelimiters<br />
Set( 34, cDelimiters )<br />
SET DEVICE TO SCREEN | PRINTER<br />
Set( 20, "SCREEN" | "PRINTER" )<br />
SET EPOCH TO nYear<br />
Set( 5, nYear )<br />
SET ESCAPE ON | OFF | xlToggle<br />
Set( 28, "ON" | "OFF" | lToggle )<br />
SET EXACT ON | OFF | xlToggle<br />
Set( 1, "ON" | "OFF" | lToggle )<br />
SET EXCLUSIVE ON | OFF | xlToggle<br />
Set( 8, "ON" | "OFF" | lToggle )<br />
SET FILTER TO<br />
dbclearfilter()<br />
SET FILTER TO lCondition<br />
dbsetfilter( bCondition, cCondition )<br />
SET FIXED ON | OFF | xlToggle<br />
Set( 2, "ON" | "OFF" | lToggle )<br />
SET INDEX TO [xc<strong>Index</strong> [, xc<strong>Index</strong>1... ] ]<br />
ordListClear()<br />
ordListAdd( c<strong>Index</strong> )<br />
ordListAdd( c<strong>Index</strong>1 )<br />
...<br />
SET INTENSITY ON | OFF | xlToggle<br />
Set( 31, "ON" | "OFF" | lToggle )<br />
SET KEY nInkeyCode [TO]<br />
SetKey( nInkeyCode, NIL )<br />
SET KEY nInkeyCode TO [idProcedure]<br />
SetKey( nInkeyCode, { |p, l, v| idProcedure(p, l, v)} )<br />
SET MARGIN TO<br />
Set( 25, 0 )<br />
SET MARGIN TO [nPageOffset]<br />
Set( 25, nPageOffset )<br />
SET MESSAGE TO<br />
Set( 36, 0 )
304 volume VIII Argomenti avanzati e accessori<br />
SKIP<br />
STORE<br />
Set( 37, .F. )<br />
SET MESSAGE TO [nRow [CENTER | CENTRE]]<br />
Set( 36, nRow )<br />
Set( 37, lCenter )<br />
SET ORDER TO [n<strong>Index</strong>]<br />
ordSetFocus( n<strong>Index</strong> )<br />
SET PATH TO<br />
Set( 6, "" )<br />
SET PATH TO [xcPathspec [, cPathspec1... ] ]<br />
Set( 6, cPathspec [, cPathspec1... ] )<br />
SET PRINTER ON | OFF | xlToggle<br />
Set( 23, "ON" | "OFF" | lToggle )<br />
SET PRINTER TO<br />
Set( 24, "" )<br />
SET PRINTER TO [xcDevice|xcFile [ADDITIVE]]<br />
Set( 24, cDevice|cFile, lAdditive )<br />
SET RELATION TO<br />
dbclearrelation()<br />
SET RELATION TO [expKey1 INTO xcAlias1]<br />
[, [TO] expKey2 INTO xcAlias2...]<br />
[ADDITIVE]<br />
if !lAdditive<br />
dbClearRel()<br />
end<br />
dbSetRelation( cAlias1, {|| expKey1}, ["expKey1"] )<br />
dbSetRelation( cAlias2, {|| expKey2}, ["expKey1"] )<br />
SET SCOREBOARD ON | OFF | xlToggle<br />
Set( 32, "ON" | "OFF" | lToggle )<br />
SET SOFTSEEK ON | OFF | xlToggle<br />
Set( 9, "ON" | "OFF" | lToggle )<br />
SET TYPEAHEAD TO nKeyboardSise<br />
Set( 14, nKeyboardSise )<br />
SET UNIQUE ON | OFF | xlToggle<br />
Set( 10, "ON" | "OFF" | lToggle )<br />
SET WRAP ON | OFF | xlToggle<br />
Set( 35, "ON" | "OFF" | lToggle )<br />
SKIP [nRecords] [ALIAS idAlias|nWorkArea]<br />
[idAlias|nWorkArea -> ]( dbSkip([nRecords]) )<br />
STORE value TO variable
nanoBase 1997 user manual 305<br />
SUM<br />
variable := value<br />
SUM nExp1 [, nExp2...] TO idVar1 [, idVar2...] [FOR lForCondition]←↪<br />
↩→[WHILE lWhileCondition] [NEXT nNextRecords] [RECORD nRecord] [REST] [ALL]<br />
dbeval( {||idVar1:=idVar1+nExp1 [, idVar2:=idVar2+nExp2...] },←↪<br />
↩→{||lForCondition}, {||lWhileCondition}, nNextRecords, nRecord, lRest )<br />
UNLOCK<br />
USE<br />
UNLOCK<br />
dbUnlock()<br />
UNLOCK ALL<br />
dbUnlockAll()<br />
USE<br />
dbclosearea()<br />
USE [xcDatabase]←↪<br />
↩→[INDEX xc<strong>Index</strong>1 [, xc<strong>Index</strong>2...] [ALIAS xcAlias] [EXCLUSIVE|SHARED] [NEW] [READONLY<br />
] [VIA cDriver]]<br />
dbUseArea( [lNewArea], [cDriver], cDatabase, [cAlias], [lShared], [lReadOnly] )<br />
[dbSet<strong>Index</strong>( c<strong>Index</strong>1 )]<br />
[dbSet<strong>Index</strong>( c<strong>Index</strong>2 )]<br />
...<br />
368.17 nB command substitution functions<br />
Inside nB there are many functions made only in substitution to other Clipper commands.<br />
GET<br />
aGetList<br />
SAY<br />
@ nTop, nLeft GET Var<br />
[PICTURE cGetPicture]<br />
[COLOR cColorString]<br />
[WHEN lPreExpression]<br />
[VALID lPostExpression]<br />
Get( @aGetList,<br />
[nTop], [nLeft],<br />
{ |x| iif( pcount() > 0, Var := x, Var ) }<br />
[cGetPicture], [cColorString],<br />
[bPreExpression], [bValid] )<br />
@ nTop, nLeft SAY exp<br />
PICTURE cSayPicture<br />
[COLOR cColorString]<br />
Say( nTop, nLeft, cVar, [cSayPicture], [cColorString] )<br />
is the get list array that will be increased with this get().
306 volume VIII Argomenti avanzati e accessori<br />
APPEND FROM<br />
APPEND FROM xcFile<br />
[FIELDS idField_list]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
[VIA xcDriver]<br />
dbApp( cFileName, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords],<br />
[nRecord],<br />
[lRest],<br />
[cDriver] )<br />
APPEND FROM xcFile<br />
[FIELDS idField_list]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
DELIMITED xcDelimiter<br />
dbDelim( .f., cFileName, [cDelimiter], [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] )<br />
APPEND FROM xcFile<br />
[FIELDS idField_list]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
SDF<br />
dbSDF( .f., cFileName, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] )<br />
CONTINUE<br />
COPY<br />
CONTINUE<br />
dbContinue()<br />
COPY FILE xcSourceFile TO xcTargetFile|xcDevice<br />
CopyFile( cSourceFile, cTargetFile|cDevice )<br />
COPY STRUCTURE [FIELDS idField_list]<br />
TO xcDatabase<br />
dbCopyStruct( cDatabase, [acFields] )<br />
COPY STRUCTURE EXTENDED<br />
TO xcExtendedDatabase<br />
dbCopyXStruct( cExtendedDatabase )<br />
COPY TO xcFile<br />
[FIELDS idField_list]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
[VIA xcDriver]
nanoBase 1997 user manual 307<br />
dbCopy( cFileName, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords],<br />
[nRecord],<br />
[lRest],<br />
[cDriver] )<br />
COPY TO xcFile<br />
[FIELDS idField_list]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
DELIMITED xcDelimiter<br />
dbDelim( .t., cFileName, [cDelimiter], [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] )<br />
COPY TO xcFile<br />
[FIELDS idField_list]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
SDF<br />
dbSDF( .t., cFileName, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] )<br />
CREATE<br />
JOIN<br />
CREATE xcDatabase<br />
FROM xcExtendedDatabase<br />
[NEW]<br />
[ALIAS cAlias]<br />
[VIA cDriver]<br />
dbOldCreate( cDatabase, cExtendedDatabase,<br />
[cDriver], [lNew], [cAlias] )<br />
JOIN WITH xcAlias TO xcDatabase<br />
[FOR lCondition] [FIELDS idField_list]<br />
dbJoin( cAlias, cDatabase,<br />
[acFields], [bForCondition] )<br />
KEYBOARD<br />
KEYBOARD cString<br />
Keyboard( [cString] ) ⇒ NIL<br />
LABEL FORM<br />
LABEL FORM xcLabel<br />
[TO PRINTER]<br />
[TO FILE xcFile]<br />
[NOCONSOLE]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
[SAMPLE]<br />
dbLabelForm( cLabel, [lToPrinter], [cFile],<br />
[lNoConsole], [bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest], [lSample] )
308 volume VIII Argomenti avanzati e accessori<br />
LIST<br />
LIST exp_list<br />
[TO PRINTER]<br />
[TO FILE xcFile]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
[OFF]<br />
dbList( [lToDisplay], abListColumns,<br />
[lAll],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest],<br />
[lToPrinter], [cFileName] )<br />
LOCATE<br />
PACK<br />
LOCATE [scope] FOR lCondition<br />
[WHILE lCondition]<br />
dbLocate( [bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] )<br />
PACK<br />
dbPack()<br />
PUBLIC<br />
QUIT<br />
PUBLIC idMemvar<br />
MemPublic( cMemvarName|acMemvarNames )<br />
QUIT<br />
Quit()<br />
RELEASE<br />
RELEASE idMemvar<br />
MemRelease( cMemvarName|acMemvarNames )<br />
REPORT FORM<br />
REPORT FORM xcReport<br />
[TO PRINTER]<br />
[TO FILE xcFile]<br />
[NOCONSOLE]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
[PLAIN | HEADING cHeading]<br />
[NOEJECT] [SUMMARY]<br />
RF( cForm,<br />
[bForCondition], [bWhileCondition],<br />
[nNext], [nRecord], [lRest], [lPlain],<br />
[cbHeading], [lBeforeEject], [lSummary],<br />
[lDate], [acExtra] ) ⇒ NIL<br />
RESTORE FROM<br />
RESTORE FROM xcMemFile [ADDITIVE]<br />
MemRestore( cMemFileName, [lAdditive] )
nanoBase 1997 user manual 309<br />
RUN<br />
RUN xcCommandLine<br />
Run( cCommand )<br />
SAVE TO<br />
SAVE TO xcMemFile<br />
[ALL [LIKE|EXCEPT skeleton]]<br />
MemSave( cMemFileName, [cSkeleton], [lLike] )<br />
SET FUNCTION<br />
SORT<br />
TOTAL<br />
SET FUNCTION nFunctionKey TO cString<br />
SetFunction( nFunctionKey, cString )<br />
SORT TO xcDatabase<br />
ON idField1 [/[A|D][C]]<br />
[, idField2 [/[A|D][C]] ...]<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
dbSort( cDatabase, [acFields],<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord], [lRest] )<br />
TOTAL ON expKey<br />
[FIELDS idField_list] TO xcDatabase<br />
[scope]<br />
[WHILE lCondition]<br />
[FOR lCondition]<br />
dbTotal( cDatabase, bKey, [acFields,<br />
[bForCondition], [bWhileCondition],<br />
[nNextRecords], [nRecord]], [lRest] )<br />
UPDATE<br />
ZAP<br />
UPDATE FROM xcAlias<br />
ON expKey [RANDOM]<br />
REPLACE idField1 WITH exp<br />
[, idField2 WITH exp ...]<br />
dbUpdate( cAlias, bKey, [lRandom], [bReplacement] )<br />
Example:<br />
ZAP<br />
dbZap()<br />
dbUpdate( "INVOICE", {|| LAST}, .T.,;<br />
{|| FIELD->TOTAL1 := INVOICE->SUM1,;<br />
FIELD->TOTAL2 := INVOICE->SUM2 } )
310 volume VIII Argomenti avanzati e accessori<br />
368.18 RPT: the nB print function<br />
The function RPT() helps to print ASCII file containing Memvars, Fields and print commands.<br />
RPT() is accessible from the DOC() menu.<br />
368.18.1 Memvars and fields<br />
As usual with standard word processors, variables are written delimited with "" (Alt+175).<br />
Inside these delimiters can find place character Memvars, character Fields and functions giving<br />
a character result.<br />
The RPT() function generates a public variable n_Lines that contains the available lines inside<br />
the actual sheet. Every time a line is written, this value is reduced, until a new page is reached and<br />
then it will start again from the maximum value. It is useful to read this variable to determinate<br />
if there is enough space or it is better to change page.<br />
368.18.2 Commands<br />
The function RPT() recognise some print commands. These commands starts with the asterisk<br />
(*) symbol. This means that "*" is a print command prefix.<br />
It follows the command syntax.<br />
*COMMAND<br />
*COMMAND<br />
cStatement<br />
cStatement<br />
...<br />
*END<br />
The lines contained inside *COMMAND - *END are executed with the nB macro interpreter.<br />
*DBSKIP<br />
*DBSKIP [nSkip]<br />
It Executes a dbskip() on the active alias.<br />
*FOOT<br />
*FOOT<br />
cFooter<br />
cFooter<br />
...<br />
*END<br />
The lines contained inside *FOOT - *END are printed each time at the bottom <strong>of</strong> pages.<br />
*HEAD<br />
*HEAD<br />
cHeader<br />
cHeader<br />
...<br />
*END<br />
The lines contained inside *HEAD - *END are printed each time at the top <strong>of</strong> pages.
nanoBase 1997 user manual 311<br />
*IF<br />
*IF lCondition<br />
...<br />
...<br />
*END<br />
If the condition lCondition is true, the lines contained inside *IF - *END are printed.<br />
*INSERT<br />
*LEFT<br />
*LPP<br />
*INSERT cFileName<br />
Includes the text contained into the file cFileName.<br />
*LEFT nLeftBorder<br />
The nLeftBorder is the number <strong>of</strong> column to be left blank as a left border.<br />
*LPP nLinesPerPage<br />
It determinates the page length expressed in lines. After printing the nLinesPerPageth line,<br />
a form feed is sent.<br />
*NEED<br />
*PA<br />
*NEED nLinesNeeded<br />
If the available lines are less then nLinesNeeded, the follwing text will be printed on the<br />
next page.<br />
*PA<br />
*REM<br />
Jumps to a new page.<br />
*REM | *COMMENT [comment_line]<br />
It adds a comment that will not be printed.<br />
*WHILE<br />
*WHILE lCondition<br />
...<br />
...<br />
*END<br />
The lines contained inside *WHILE - *END are printed as long as lCondition is true.<br />
368.18.3 Examples<br />
It follows some example <strong>of</strong> text to be printed with the RPT() function. Example’s lines are numbered.<br />
Line numbers must not be part <strong>of</strong> a real RPT text files.<br />
PAGE DEFINITION<br />
Margins are defined with *HEAD, *FOOT and *LEFT commands. In the following example<br />
is defined:
312 volume VIII Argomenti avanzati e accessori<br />
Top 2 lines;<br />
Bottom 2 lines;<br />
Left 10 characters.<br />
The right margin is not defined as it depends on the lines length that will be printed.<br />
The only considered page dimension is the height, *LPP (lines per page):<br />
Page height 66 lines.<br />
Here starts the example:<br />
001 *lpp 66<br />
002 *head<br />
003<br />
004<br />
005 *end<br />
006 *foot<br />
007<br />
008<br />
009 *end<br />
010 *left 10<br />
011 ... text text text<br />
012 ... test text text<br />
...<br />
At line 001 is defined the page height in lines. At line 002 is defined the header; it contains<br />
two empty lines (003 and 004) which will be printed at the top <strong>of</strong> every page. At line 006<br />
starts the footer definition that contains two empty lines (007 and 008) that will be printed<br />
at the end <strong>of</strong> every page. At line 010 is defined the space on the left that will be added to<br />
every line printed. From line 011 starts the normal text.<br />
HEADER AND FOOTER<br />
The commands *HEAD and *FOOT are used to define the top and bottom border if they<br />
contains empty lines, it these lines are not empty, they became real head and foot.<br />
The dimensions are as it follows:<br />
Top 6 lines (should be one inch);<br />
Bottom 6 lines;<br />
Left 10 characters (should be an inch).<br />
Page height 66 lines (should be 11 inch).<br />
At position 0.5 in (after 3 lines) a one line header appears.
nanoBase 1997 user manual 313<br />
001 *lpp 66<br />
002 *head<br />
003<br />
004<br />
005<br />
006 ------------------- MYFILE.TXT -------------------<br />
007<br />
008<br />
009 *end<br />
010 *foot<br />
011<br />
012<br />
013<br />
014<br />
015<br />
016<br />
017 *end<br />
018 *left 10<br />
019 ... text text text<br />
020 ... test text text<br />
...<br />
At line 006 (the fourth header line) a text appears. It will be printed on every page at the<br />
absolute fourth page line.<br />
CODE INSERTION<br />
Pieces <strong>of</strong> code can be inserted inside *COMMAND - *END. It can be useful to make<br />
complicated reports.<br />
The following example declares a public variable used to number pages.<br />
001 *command<br />
002 mempublic("PageNo")<br />
003 PageNo := 0<br />
004 *end<br />
005 *lpp 66<br />
006 *head<br />
007 *command<br />
008 PageNo := PageNo +1<br />
009 *end<br />
010<br />
011<br />
012 *end<br />
013 *foot<br />
014<br />
015 Page <br />
016<br />
017 *end<br />
018 *left 10<br />
019 ... text text text<br />
020 ... test text text<br />
...<br />
At line 001 starts a *COMMAND definition: lines 002 and 003 will be interpreted from the<br />
function EX(), the nB interpreter. These lines define a public variable and initialize it at 0.<br />
This variable will be use to count pages.<br />
At line 007, inside the header (nested), start another *COMMAND definition that contains<br />
an increment for the "PageNo" variable. As the header is read and "executed" for every new<br />
page, and that before the footer, the variable "PageNo" will contain the right page number.<br />
At line 015, inside the footer, a reference to "PageNo" appears. Here will be printed the<br />
page number.<br />
A more complicated example can be found in ‘ADDRESS.TXT’ the RPT text file used for<br />
the ADDRESS.& macro examples.
314 volume VIII Argomenti avanzati e accessori<br />
368.19 How can I...<br />
nB is a little bit complicated as it may do many things. Here are some examples.<br />
Create a UDF function<br />
UDF means User Defined Function. Inside nB there isn’t the possibility to create functions,<br />
but there is an alternative: code blocks.<br />
Create a big code block<br />
A code block cannot be longer than 254 characters, as any other instruction inside nB.<br />
So, there is no way to make a bigger code block, but a code block can call another code<br />
block, and so on. For example:<br />
mempublic( { "first", "second", "third" } )<br />
first := {|| eval( second, "hello" ) }<br />
second := {|x| eval( third, x ) }<br />
third := {|x| alertbox( x ) }<br />
eval( first )<br />
This stupid example simply will show the alert box containing the word "hello".<br />
368.20 The source files<br />
The nB source is composed <strong>of</strong> four files:<br />
‘NB.PRG’ The main source file containing essentially the nB menu.<br />
‘REQUEST.PRG’ Contains a link to all Clipper standard functions.<br />
‘STANDARD.PRG’ Contains the most important standard functions.<br />
‘EXTRA.PRG’<br />
Contains some extra function not absolutely necessary during<br />
macro execution.<br />
The file ‘REQUEST.PRG’ source file generates some warnings because not all functions listed<br />
there are directly called form nB. Don’t worry about that warning message.<br />
Different ‘.RMK’ (rmake) files are included to compile nB differently, including/excluding some<br />
program parts, for example to obtain a runtime executor.<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Parte lxxiii<br />
Braille<br />
369 Introduzione al sistema braille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316<br />
369.1 Origini e caratteristiche del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316<br />
369.2 Codifica semplificata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317<br />
369.3 Braille a otto punti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318<br />
369.4 Tabelle di conversione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318<br />
369.5 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320<br />
370 Sistemi di interazione per non vedenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321<br />
370.1 Lettura di ciò che appare sullo schermo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321<br />
370.2 Terminali braille . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321<br />
370.3 Brltty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323<br />
370.4 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324<br />
315
Introduzione al sistema braille<br />
Capitolo 369<br />
Lo scopo di questo capitolo è quello di descrivere brevemente il codice usato dal sistema braille,<br />
in modo di facilitare la comprensione del funzionamento di un terminale per non vedenti. Ciò<br />
potrebbe servire per verificare l’installazione e la configurazione corretta di un dispositivo del<br />
genere.<br />
369.1 Origini e caratteristiche del sistema<br />
Il sistema di scrittura per non vedenti è stato inventato da Louis Braille nel 1829, da cui viene<br />
il nome. Luis Braille era francese e in questo senso vanno viste le scelte che possono sembrare<br />
insolite, per chi è abituato a convenzioni derivanti dalla lingua inglese.<br />
Il sistema codifica 63 simboli rappresentati ognuno da una cella in cui possono essere collocati<br />
un massimo di sei punti in rilievo:<br />
.----.<br />
|* *|<br />
|* *|<br />
|* *|<br />
‘----’<br />
Tanto per fare un esempio, se si possono immaginare gli asterischi della figura seguente come<br />
altrettanti punti in rilievo, la parola «ciao!» si può rappresentare in questo modo:<br />
* * * * *<br />
* * * *<br />
* *<br />
Il sistema braille è fatto fondamentalmente per una scrittura manuale, che avviene attraverso<br />
l’uso di una tavoletta speciale, come si può vedere nelle figure 369.3 e 369.4.<br />
Figura 369.3. Tavoletta di scrittura braille normale.<br />
316
Introduzione al sistema braille 317<br />
La scrittura avviene su un foglio di cartoncino bloccato sulla tavoletta, con l’aiuto di un punteruolo,<br />
guidato dalle feritoie poste su un regolo mobile (nel caso della tavoletta tascabile, il regolo<br />
è fisso). Dal momento che la scrittura avviene attraverso l’incisione del cartoncino, la lettura tattile,<br />
in rilievo, potrà avvenire solo sull’altro lato; pertanto, per quanto riguarda le lingue latine, la<br />
scrittura avviene da destra verso sinistra e la lettura da sinistra a destra.<br />
Figura 369.4. Tavoletta di scrittura braille tascabile. La fase si scrittura avviene inciden-<br />
do il cartoncino. In questo caso, non si vede la fila superiore, perché rimane coperta<br />
dall’ombra.<br />
Figura 369.5. Testo inciso da destra verso sinistra.<br />
Figura 369.6. Testo in rilievo da sinistra verso destra.<br />
Il braille standard è composto da celle con un massimo di sei punti in rilievo, per un massimo<br />
di 2 6 -1 segni, più lo spazio; tuttavia, possono esistere anche dispositivi braille predisposti per<br />
un massimo di otto punti in rilievo.<br />
369.2 Codifica semplificata<br />
La disposizione classica della codifica del braille è sintetizzata dalle figure 369.9 e 369.10. Chi<br />
volesse studiare ed esercitarsi con il braille, farebbe bene a copiare le due figure in modo da<br />
mettere a sinistra quella dei segni in scrittura e a destra quella dei segni in lettura.<br />
Come si può comprendere a livello intuitivo, i 63 simboli non consentono di distinguere le lettere<br />
minuscole da quelle maiuscole; in generale si tratta sempre solo di lettere minuscole che<br />
diventano maiuscole se precedute dal segno relativo. Per esempio, «Daniele» si scrive così:<br />
* * * * * * * * * *<br />
* * * * * *<br />
* * *
318 volume VIII Argomenti avanzati e accessori<br />
Nello stesso modo, come si vede, non sono previsti i numeri. Questi si ottengono indicando il<br />
segno di numero davanti alle prime 10 lettere alfabetiche. Per esempio, 123 si indica così:<br />
* * * * *<br />
* *<br />
* *<br />
Pertanto, a differenza delle maiuscole, il segno di numero vale per tutta la sequenza di simboli<br />
successiva.<br />
Esistono naturalmente altri dettagli molto importanti per chi deve usare il braille, che però qui<br />
non vengono descritti. Purtroppo, i segni a disposizione sono molto pochi e di conseguenza, tutto<br />
quanto ha sempre un valore relativo al contesto.<br />
369.3 Braille a otto punti<br />
La codifica a otto punti consente di utilizzare una sola cella per indicare una lettera maiuscola o<br />
un numero. Ciò diventa particolarmente importante in un terminale braille, in cui è bene che si<br />
possa mantenere una corrispondenza tra celle e caratteri.<br />
369.4 Tabelle di conversione<br />
L’abbinamento del braille all’informatica, impone l’introduzione di tabelle di conversione dalla<br />
codifica dei caratteri al braille stesso. In pratica, in base alla nazionalità, si utilizza una codifica<br />
particolare; oltre a questo, deve essere definito un abbinamento tra codice binario (ASCII, ISO<br />
8859-n, ecc.) e rappresentazione braille. Quando si utilizza un terminale braille o un sistema di<br />
stampa braille, occorre stabilire anche questo tipo di conversione.
Introduzione al sistema braille 319<br />
Figura 369.9. La codifica braille per la scrittura da destra verso sinistra, secondo<br />
l’ordine classico.<br />
j i h g f e d c b a<br />
* . * . . * * * * * . * * * * * . * . *<br />
* * . * * * * * . * * . * . . . . * . .<br />
. . . . . . . . . . . . . . . . . . . .<br />
t s r q p o n m l k<br />
* . * . . * * * * * . * * * * * . * . *<br />
* * . * * * * * . * * . * . . . . * . .<br />
. * . * . * . * . * . * . * . * . * . *<br />
ù è à é ç z y x v u<br />
* . * . . * * * * * . * * * * * . * . *<br />
* * . * * * * * . * * . * . . . . * . .<br />
* * * * * * * * * * * * * * * * * * * *<br />
w æ ü ï ë û ô î ê â<br />
* . * . . * * * * * . * * * * * . * . *<br />
* * . * * * * * . * * . * . . . . * . .<br />
* . * . * . * . * . * . * . * . * . * .<br />
« * » () ! ? . : ; ,<br />
. . . . . . . . . . . . . . . . . . . .<br />
* . * . . * * * * * . * * * * * . * . *<br />
* * . * * * * * . * * . * . . . . * . .<br />
numero ò verso ì lineetta apostr<strong>of</strong>o<br />
* . * . * . * * . . . .<br />
* . . . * . . . . . . .<br />
* * * * . * * . * * . *<br />
maiuscole corsivo<br />
. . . . * . . . * . * . * .<br />
. . * . . . * . * . * . . .<br />
* . * . * . . . * . . . . .
320 volume VIII Argomenti avanzati e accessori<br />
Figura 369.10. La codifica braille per la lettura da sinistra verso destra, secondo<br />
l’ordine classico.<br />
a b c d e f g h i j<br />
* . * . * * * * * . * * * * * . . * . *<br />
. . * . . . . * . * * . * * * * * . * *<br />
. . . . . . . . . . . . . . . . . . . .<br />
k l m n o p q r s t<br />
* . * . * * * * * . * * * * * . . * . *<br />
. . * . . . . * . * * . * * * * * . * *<br />
* . * . * . * . * . * . * . * . * . * .<br />
u v x y z ç é à è ù<br />
* . * . * * * * * . * * * * * . . * . *<br />
. . * . . . . * . * * . * * * * * . * *<br />
* * * * * * * * * * * * * * * * * * * *<br />
â ê î ô û ë ï ü æ w<br />
* . * . * * * * * . * * * * * . . * . *<br />
. . * . . . . * . * * . * * * * * . * *<br />
. * . * . * . * . * . * . * . * . * . *<br />
, ; : . ? ! () « * »<br />
. . . . . . . . . . . . . . . . . . . .<br />
* . * . * * * * * . * * * * * . . * . *<br />
. . * . . . . * . * * . * * * * * . * *<br />
apostr<strong>of</strong>o lineetta ì verso ò numero<br />
. . . . * * . * . * . *<br />
. . . . . . . * . . . *<br />
* . * * . * * . * * * *<br />
corsivo maiuscole<br />
. * . * . * . . . * . . . .<br />
. . . * . * . * . . . * . .<br />
. . . . . * . . . * . * . *<br />
369.5 Riferimenti<br />
• Dottless braille<br />
<br />
• A (slightly) different introduction to braille<br />
<br />
Appunti di informatica libera 2003.06.29 --- Copyright © 2000-2003 Daniele Giacomini -- daniele @ swlibero.org
Sistemi di interazione per non vedenti<br />
Capitolo 370<br />
I sistemi standard di interazione per non vedenti con un elaboratore sono di due tipi, che si<br />
integrano convenientemente assieme: il terminale braille e la lettura automatica di ciò che appare<br />
sullo schermo. Il terminale braille è un’unità che si collega generalmente a una porta seriale o<br />
parallela e richiede la presenza di un programma in grado di leggere ciò che appare sullo schermo<br />
normale; il sistema di lettura automatica richiede naturalmente un programma simile.<br />
Un sistema di lettura automatico è apparentemente un problema semplice da risolvere; in pratica<br />
le cose non sono così, perché deve anche essere in grado di individuare la struttura del testo (si<br />
pensi a un’organizzazione in più colonne). Il sistema che sembra essere più efficace per la lettura<br />
sonora del testo è Emacspeack, che comunque qui non viene descritto. Si vedano eventualmente<br />
i riferimenti bibliografici alla fine del capitolo.<br />
370.1 Lettura di ciò che appare sullo schermo<br />
Qualunque sistema di lettura per non vedenti (braille o audio), deve avere un modo per accedere<br />
a ciò che appare sullo schermo. Esistono evidentemente due modi: ciò che appare sullo schermo<br />
è controllato direttamente dal programma di lettura, oppure questo programma deve interagire<br />
con il sistema operativo per ottenere una copia dello schermo.<br />
Un programma che controlla ciò che si deve leggere potrebbe essere una shell, oppure una sorta<br />
di navigatore ipertestuale, che eventualmente incorpori anche delle funzionalità per la creazione<br />
e la modifica dei documenti (dovrebbe essere questo il caso di Emacspeack).<br />
Nel caso di GNU/Linux si accede a una copia di ciò che appare sullo schermo della console<br />
attiva attraverso il file di dispositivo ‘/dev/vcsa’ o ‘/dev/vcsa0’. In particolare questi file di<br />
dispositivo consentono di ottenere informazioni anche sugli attributi del testo, cosa che permette<br />
di localizzare il cursore, per esempio; esistono infatti anche i file di dispositivo ‘/dev/vcs * ’<br />
che consentono di ottenere una pura copia testuale delle console virtuali.<br />
Questi file di dispositivo sono normalmente inaccessibili a utenti diversi dall’amministratore;<br />
pertanto, per consentire una lettura a programmi con privilegi limitati, occorre intervenire nei<br />
permessi. Supponendo di dover creare da zero il file di dispositivo ‘/dev/vcsa0’, probabilmente<br />
si dovrebbe agire come segue:<br />
# mknod /dev/vcsa0 c 7 128 [ Invio ]<br />
# chown root.tty /dev/vcsa0 [ Invio ]<br />
# chmod 660 /dev/vcsa0 [ Invio ]<br />
In pratica, si arriva alla fine a dare i permessi di lettura e scrittura anche al gruppo, supponendo<br />
che il programma che deve utilizzarlo funzioni, in questo caso, con i privilegi del gruppo ‘tty’<br />
(SGID-‘tty’). Ciò consente di mantenere un minimo di riservatezza, nonostante il problema<br />
contingente da risolvere.<br />
Volendo verificare che il file di dispositivo ‘/dev/vcsa0’ consente di accedere al contenuto<br />
dello schermo della console virtuale attuale, si può inviarne una copia in una console inattiva o<br />
comunque non utilizzata. Per esempio:<br />
# cat /dev/vcsa0 > /dev/tty12 [ Invio ]<br />
321
322 volume VIII Argomenti avanzati e accessori<br />
Manda una copia alla 12-esima console virtuale e si può verificare facilmente con la<br />
combinazione di tasti [ Alt+F12 ].<br />
370.2 Terminali braille<br />
Il terminale braille è solitamente un componente da collocare al di sotto della tastiera normale,<br />
attraverso il quale è possibile leggere una riga di testo, senza allontanare troppo le dita dalla<br />
tastiera stessa.<br />
Vicino alla barra contenente le celle braille, devono essere disponibili alcuni tasti per il controllo<br />
del terminale stesso, per poter navigare sulla superficie di quello che appare sullo schermo. Infatti,<br />
di solito si dispone di una sola riga di celle braille, ma anche se potessero essere disponibili più di<br />
una, non sarebbero mai quante le righe che si vedono su uno schermo normale; inoltre, anche la<br />
quantità di celle è limitata, per cui diventa necessario poter spostare la «visualizzazione» braille<br />
anche in orizzontale.<br />
Figura 370.1. Collocazione tipica di un terminale braille, sotto la tastiera o sotto un<br />
elaboratore portatile.<br />
La figura 370.2 mostra in particolare un dettaglio delle celle di un terminale braille a otto punti.<br />
Figura 370.2. Dettaglio delle celle di un terminale braille.
Sistemi di interazione per non vedenti 323<br />
370.3 Brltty<br />
Brltty 1 è un programma in grado di comunicare con un terminale braille, allo scopo di inviargli<br />
ciò che accade sullo schermo della console virtuale attiva di un sistema GNU/Linux.<br />
Il funzionamento del programma è relativamente semplice: si tratta di un demone, ‘brltty’, da<br />
avviare e fermare automaticamente attraverso la procedura di inizializzazione del sistema, che<br />
comunica con il terminale braille seguendo la configurazione relativa al terminale stesso e la<br />
configurazione della conversione braille.<br />
In pratica, Brltty deve conoscere il tipo di terminale braille utilizzato e deve disporre di una tabella<br />
di conversione adatta per quanto riguarda la codifica usata e l’alfabeto braille dell’utilizzatore.<br />
370.3.1 Configurazione<br />
Brltty è accompagnato da una serie di file di libreria, per l’adattamento alle caratteristiche del<br />
terminale braille e per la conversione finale della codifica in braille. Questi file dovrebbero essere<br />
collocati nella directory ‘/etc/brltty/’.<br />
Il file di configurazione in cui occorre intervenire dovrebbe essere ‘/etc/brltty.conf’, il cui<br />
contenuto potrebbe apparire come nell’esempio seguente:<br />
braille-device /dev/ttyS0<br />
braille-driver ec<br />
dot-translation text.us.tbl<br />
Si comprende intuitivamente il significato delle direttive: il terminale viene connesso alla prima<br />
porta seriale, corrispondente al file di dispositivo ‘/dev/ttyS0’; il terminale braille viene gestito<br />
attraverso un protocollo definito dalla sigla ‘ec’; la trasformazione della codifica in braille<br />
avviene secondo il modello denominato ‘text.us.tbl’, che in pratica è un file contenuto nella<br />
directory ‘/etc/brltty/’, facente riferimento a un adattamento per la lingua inglese.<br />
Tabella 370.1. Sigle attraverso le quali si abbinano le librerie di controllo del terminale<br />
braille.<br />
Sigla Terminale corrispondente<br />
al<br />
Alva (ABT3xx/Delphi)<br />
b1 BrailleLite 18<br />
b4 BrailleLite 40<br />
cb Tieman CombiBraille<br />
ec EcoBraille<br />
eu EuroBraille<br />
md<br />
pm<br />
MDV braille<br />
Papenmeier<br />
ts TSI (PowerBraille/Navigator)<br />
va BAUM Vario<br />
Brltty è anche in grado di gestire terminali parlanti. Eventualmente, si può usare la direttiva<br />
‘speech-driver’ per il controllo della sintesi vocale. Di solito, la funzionalità è disabilitata,<br />
con la direttiva seguente:<br />
speech-driver no<br />
1 Brltty GNU GPL
324 volume VIII Argomenti avanzati e accessori<br />
Tabella 370.2. Sigle relative alla gestione della sintesi vocale.<br />
Sigla Sintesi vocale<br />
no No Speech<br />
al<br />
Alva (Delphi)<br />
bl BrailleLite<br />
cb Tieman CombiBraille<br />
fv<br />
Festival Text to Speech Package<br />
gs Generic Say (invia allo standard input di ‘/usr/local/bin/say’)<br />
tv Televox Speech Interface<br />
370.3.2 Accesso alla copia della console virtuale corrente<br />
Come già spiegato in precedenza, anche Brltty deve poter accedere a una copia della console<br />
virtuale corrente. Ciò avviene precisamente attraverso il file di dispositivo ‘/dev/vcsa0’, che in<br />
alcuni sistemi GNU/Linux potrebbe anche essere assente, perché equivalente a ‘/dev/vcsa’. Si<br />
riepilogano nuovamente i passi necessari a creare il file e ad attribuirgli i permessi necessari per<br />
il funzionamento corretto con Brltty.<br />
# mknod /dev/vcsa0 c 7 128 [ Invio ]<br />
# chown root.root /dev/vcsa0 [ Invio ]<br />
# chmod 600 /dev/vcsa0 [ Invio ]<br />
In questo caso, si presume che il demone ‘brltty’ sia avviato attraverso la procedura di inizializzazione<br />
del sistema, in modo tale da funzionare con tutti i privilegi dell’utente ‘root’.<br />
Diversamente, occorre cambiare strategia per quanto riguarda i permessi e la proprietà del file di<br />
dispositivo.<br />
370.4 Riferimenti<br />
• BRLTTY - <strong>of</strong>ficial home<br />
<br />
• BRLSPEAK: a braille and speech mini-distribution <strong>of</strong> GNU/Linux<br />
<br />
• Blind + Linux = BLINUX<br />
Parte lxxiv<br />
Aspetti umani<br />
371 Manifesto GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331<br />
372 Il progetto GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339<br />
372.1 La prima comunità di condivisione del s<strong>of</strong>tware . . . . . . . . . . . . . . . . . . . . . . . . . . . 339<br />
372.2 La comunità si dissolve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339<br />
372.3 Una difficile scelta morale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341<br />
372.4 "Free" come libero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342<br />
372.5 S<strong>of</strong>tware GNU e il sistema GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342<br />
372.6 L’inizio del progetto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343<br />
372.7 I primi passi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343<br />
372.8 GNU Emacs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343<br />
372.9 Un programma è libero per tutti? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344<br />
372.10 Il permesso d’autore (copyleft) e la GNU GPL . . . . . . . . . . . . . . . . . . . . . . . . . . . 344<br />
372.11 La Free S<strong>of</strong>tware Foundation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345<br />
372.12 Il supporto per il s<strong>of</strong>tware libero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .346<br />
372.13 Obiettivi tecnici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346<br />
372.14 Donazioni di computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347<br />
372.15 L’elenco dei compiti GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .347<br />
372.16 La licenza GNU per le librerie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347<br />
372.17 Togliersi il prurito? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348<br />
372.18 Sviluppi inattesi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349<br />
372.19 GNU-Hurd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349<br />
372.20 Alix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349<br />
372.21 Linux e GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349<br />
372.22 Le sfide che ci aspettano . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350<br />
372.23 Hardware segreto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350<br />
372.24 Librerie non libere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350<br />
372.25 Brevetti sul s<strong>of</strong>tware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351<br />
372.26 Documentazione libera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352<br />
372.27 Dobbiamo parlare di libertà . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353<br />
372.28 "Open Source" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353<br />
372.29 Prova! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353<br />
373 La rivoluzione del Mimete, ovvero s<strong>of</strong>tware e copyright . . . . . . . . . . . . . . . . . . . . . . . . . .355<br />
373.1 Che cosa è il s<strong>of</strong>tware? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355<br />
373.2 Cenni di storia del s<strong>of</strong>tware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356<br />
325
374 Il copyright/diritto d’autore del s<strong>of</strong>tware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358<br />
374.1 Una breve storia del diritto d’autore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358<br />
374.2 I sei punti della rivoluzione digitale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359<br />
374.3 I vantaggi del «free s<strong>of</strong>tware» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360<br />
Indice analitico del volume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361<br />
375 Configurazione di una distribuzione Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
375.1 Procedura di inizializzazione del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
375.2 Configurazione del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13<br />
375.3 Configurazione di shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />
375.4 Utenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />
375.5 Stampa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15<br />
375.6 Configurazione del nome del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16<br />
375.7 Configurazione dei permessi degli eseguibili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />
375.8 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />
376 Accorgimenti per una distribuzione Debian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />
376.1 Raccogliere gli aggiornamenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />
376.2 Realizzazione di una copia personale della distribuzione . . . . . . . . . . . . . . . . . . . . 23<br />
376.3 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />
377 nanoRouter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
377.1 Kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
377.2 Lo stretto indispensabile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
377.3 Dimensioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />
377.4 File system in sola lettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />
378 nanoLinux II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .33<br />
378.1 Lavoro di cesello . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />
378.2 Dischi più grandi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .37<br />
378.3 Provare nanoLinux II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />
378.4 Organizzazione di nanoLinux II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />
378.5 Personalizzazione della procedura di inizializzazione del sistema . . . . . . . . . . . . 46<br />
379 Dischetti di emergenza delle distribuzioni GNU/Linux e di altre fonti . . . . . . . . . . . . . . . 48<br />
379.1 SuSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />
380 Accorgimenti per usare GNU/Linux nella didattica di massa . . . . . . . . . . . . . . . . . . . . . . . 52<br />
380.1 Utente speciale per uno scopo speciale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />
380.2 Spegnimento da parte di utenti comuni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
380.3 Autorizzare chiunque ad aggiungersi come nuovo utente . . . . . . . . . . . . . . . . . . . . 55<br />
326
380.4 Sincronizzazione di file di configurazione senza NIS . . . . . . . . . . . . . . . . . . . . . . . .56<br />
381 Introduzione a SMB con GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .59<br />
381.1 Nomi NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />
381.2 Trasporto TCP/IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />
381.3 Servente SMB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />
381.4 Cliente SMB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />
381.5 Connessione con una rete NetBIOS-TCP/IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<br />
381.6 Stampa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71<br />
381.7 Montare una risorsa di condivisione dei file nel file system GNU/Linux . . . . . . .72<br />
381.8 Riferimenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />
382 DOSEMU: l’emulatore di hardware DOS compatibile . . . . . . . . . . . . . . . . . . . . . . . . . . . . .75<br />
382.1 Predisporre un ambiente adatto al Dos all’interno di DOSEMU . . . . . . . . . . . . . . 75<br />
382.2 La configurazione di DOSEMU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />
382.3 Installare e utilizzare il Dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />
383 LeeOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83<br />
Indice analitico del volume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />
384 Amministrazione del sistema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26<br />
384.1 Installazione di GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />
384.2 Avvio e arresto del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
384.3 Tipi di file system e partizioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />
384.4 Swap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />
384.5 Montare i dischi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />
384.6 LILO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />
384.7 Kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />
384.8 Moduli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64<br />
384.9 Configurazione del sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .65<br />
384.10 Utenti e password . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />
384.11 Permessi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />
384.12 File, collegamenti (link) e directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />
384.13 Configurazione della console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />
384.14 File di log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />
384.15 Cron e At . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />
384.16 Processi ed utilizzo delle risorse del sistema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104<br />
384.17 Risoluzione di problemi di una certa entità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107<br />
384.18 Caratteri speciali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />
384.19 Documentazione di aiuto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />
385 Reti e rete Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />
327
385.1 Generalità e configurazione di una rete locale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />
385.2 FTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116<br />
385.3 Telnet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118<br />
385.4 SSH. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122<br />
385.5 La condivisione delle risorse in rete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122<br />
385.6 Terminali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />
385.7 Server web (Apache, ecc.) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />
385.8 Samba . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />
385.9 Plip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />
385.10 Connessione al provider - ppp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />
385.11 Connessione remota tra macchine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />
385.12 Posta elettronica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145<br />
385.13 Navigatori (browser) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153<br />
385.14 Gruppi di discussione (newsgroup) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154<br />
385.15 IRC - chat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .157<br />
385.16 Scaricamento file - riproduzione (mirror) di siti . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />
386 Programmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />
386.1 Installazione ed esecuzione programmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160<br />
386.2 File ‘core’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />
386.3 I pacchetti - generalità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163<br />
386.4 I pacchetti - ‘tar.gz’, ‘tgz’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />
386.5 I pacchetti - ‘deb’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166<br />
386.6 I pacchetti - RPM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171<br />
386.7 La compressione - ‘.gz’ ‘.bz2’ ‘.zip’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172<br />
387 X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />
387.1 Avvio, conclusione, configurazione e risoluzione . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />
387.2 Gnome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181<br />
387.3 X - Gestori delle finestre (window manager) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182<br />
387.4 Terminale grafico (‘xterm’) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184<br />
388 Applicazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />
388.1 Editor di testi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />
388.2 Applicazioni per comunicazioni telefoniche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />
388.3 Applicazioni fax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188<br />
388.4 Applicazioni grafica bidimensionale non vettoriale . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />
388.5 Applicazioni matematiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189<br />
388.6 Applicazioni base di dati (database) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .189<br />
389 Stampa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192<br />
328
389.1 Impostazioni generali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192<br />
389.2 Stampa da riga di comando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194<br />
390 Editoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />
390.1 Conversione tra formati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />
390.2 I file PostScript (‘.ps’) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />
390.3 I file ‘.pdf’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />
390.4 I File ‘.sgml’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195<br />
390.5 I file ‘.doc’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196<br />
390.6 Compatibilità formati GNU/Linux-Dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196<br />
391 I Caratteri (font) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197<br />
391.1 Impostazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197<br />
392 Immagini . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200<br />
392.1 Generalità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200<br />
393 Masterizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />
393.1 Masterizzare da riga di comando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202<br />
394 Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208<br />
394.1 Impostazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208<br />
394.2 CD audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210<br />
394.3 mp3, wav, ecc. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210<br />
395 Programmazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218<br />
395.1 Script per la shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218<br />
395.2 Linguaggio C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227<br />
395.3 Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227<br />
395.4 Cobol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228<br />
395.5 Perl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .228<br />
396 Computer portatili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230<br />
396.1 Problematiche di installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230<br />
397 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232<br />
397.1 Processori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232<br />
397.2 Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232<br />
397.3 Dispositivi video (scheda, telecamera, ecc.) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232<br />
397.4 Tastiera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233<br />
397.5 Mouse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .237<br />
397.6 Disco fisso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238<br />
397.7 CD-ROM e masterizzatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238<br />
329
397.8 Schede di rete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243<br />
397.9 Scheda audio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .244<br />
397.10 Lettori ZIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250<br />
397.11 Nastri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252<br />
397.12 RAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253<br />
397.13 Scanner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254<br />
397.14 Modem. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .254<br />
397.15 Stampante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255<br />
397.16 Periferiche SCSI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257<br />
397.17 Unità disco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260<br />
397.18 Periferiche Plug & Play . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260<br />
397.19 Porte (seriale, parallela, PS/2, USB, ecc.) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261<br />
Indice analitico del volume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264<br />
398 Licenza GNU GPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
399 Traduzione della licenza GNU GPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />
400 Licenza GNU LGPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18<br />
401 Licenza GNU FDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />
402 Licenza Artistic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />
403 Licenza UCB BSD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />
404 Licenza MIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .35<br />
405 Licenza LPPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36<br />
406 Licenza QPL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />
407 Licenza SSLeay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41<br />
408 Licenza DSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />
409 Licenza Open publication license . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />
410 Licenze e altri dettagli sul s<strong>of</strong>tware citato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />
330
Manifesto GNU<br />
Testo originale: <br />
Traduzione originale: <br />
Copyright (C) 1985, 1993 Free S<strong>of</strong>tware Foundation, Inc.<br />
Capitolo 371<br />
non modificabile<br />
Chiunque è autorizzato a fare o distribuire copie letterali di questo documento, con qualsiasi<br />
mezzo, a condizione che siano riprodotte la nota sul copyright e la nota di autorizzazione, e che<br />
il distributore conceda al destinatario l’autorizzazione di ridistribuirlo a sua volta alle condizioni<br />
permesse da questa nota.<br />
Non sono consentite versioni modificate.<br />
Il Manifesto GNU<br />
Il Manifesto GNU (che appare sotto) venne scritto da Richard Stallman all’inizio<br />
del progetto GNU, per sollecitare sostegno e partecipazione. Durante i primi anni il<br />
manifesto venne lievemente aggiornato per tener conto degli sviluppi, ma adesso la<br />
scelta migliore sembra essere quella di lasciarlo immutato nella forma in cui molti lo<br />
hanno visto.<br />
Da allora abbiamo preso atto di alcuni fraintendimenti che si potrebbero evitare con<br />
una diversa scelta di termini. Le note in calce aggiunte nel 1993 aiutano a chiarire<br />
questi punti.<br />
Per informazioni aggiornate sulla disponibilità del s<strong>of</strong>tware GNU, consultate quelle<br />
disponibili sul nostro server web, in particolare il nostro elenco del s<strong>of</strong>tware.<br />
Cos’è GNU? Gnu Non è Unix!<br />
GNU, che sta per "Gnu’s Not Unix" (Gnu Non è Unix), è il nome del sistema s<strong>of</strong>tware completo<br />
e Unix-compatibile che sto scrivendo per distribuirlo liberamente a chiunque lo possa utilizzare. 1<br />
Molti altri volontari mi stanno aiutando. Abbiamo gran necessità di contributi in tempo, denaro,<br />
programmi e macchine.<br />
Fino ad ora abbiamo un editor Emacs fornito di Lisp per espanderne i comandi, un debugger simbolico,<br />
un generatore di parser compatibile con yacc, un linker e circa 35 utility. È quasi pronta<br />
una shell (interprete di comandi). Un nuovo compilatore C portabile e ottimizzante ha compilato<br />
se stesso e potrebbe essere pubblicato quest’anno. Esiste un inizio di kernel, ma mancano molte<br />
delle caratteristiche necessarie per emulare Unix. Una volta terminati il kernel e il compilatore<br />
sarà possibile distribuire un sistema GNU utilizzabile per lo sviluppo di programmi. Useremo<br />
1 La scelta delle parole è stata poco accurata. L’intenzione era che nessuno dovesse pagare per il *permesso* di usare<br />
il sistema GNU. Ma le parole non lo esprimono chiaramente, e la gente le interpreta spesso come asserzione che GNU<br />
debba sempre essere distribuito in forma gratuita o a basso prezzo. Non è mai stato questo l’intento; più oltre il manifesto<br />
parla della possibile esistenza di aziende che forniscano il servizio di distribuzione a scopo di lucro. Di conseguenza ho<br />
imparato a distinguere tra "free" nel senso di libero e "free" nel senso di gratuito. Il s<strong>of</strong>tware libero è il s<strong>of</strong>tware che gli<br />
utenti sono liberi di distribuire e modificare. Alcuni lo avranno gratuitamente, altri dovranno pagare per ottenere le loro<br />
copie, e se dei finanziamenti aiutano a migliorare il s<strong>of</strong>tware tanto meglio. La cosa importante è che chiunque ne abbia<br />
una copia sia libero di cooperare con altri nell’usarlo.<br />
331
332 volume VIII Argomenti avanzati e accessori<br />
TeX come formattatore di testi, ma lavoriamo anche su un nr<strong>of</strong>f. Useremo inoltre il sistema a<br />
finestre portabile libero X. Dopo di che aggiungeremo un Common Lisp portabile, il gioco Empire,<br />
un foglio elettronico e centinaia di altre cose, oltre alla documentazione in linea. Speriamo<br />
di fornire, col tempo, tutte le cose utili che normalmente si trovano in un sistema Unix, ed anche<br />
di più.<br />
GNU sarà in grado di far girare programmi Unix, ma non sarà identico a Unix. Apporteremo tutti<br />
i miglioramenti che sarà ragionevole fare basandoci sull’esperienza maturata con altri sistemi<br />
operativi. In particolare abbiamo in programma nomi più lunghi per i file, numeri di versione per<br />
i file, un filesystem a prova di crash, forse completamento automatico dei nomi dei file, supporto<br />
indipendente dal terminale per la visualizzazione e forse col tempo un sistema a finestre basato<br />
sul Lisp, attraverso il quale più programmi Lisp e normali programmi Unix siano in grado di<br />
condividere lo schermo. Sia C che Lisp saranno linguaggi per la programmazione di sistema. Per<br />
le comunicazioni vedremo di supportare UUCP, Chaosnet del MIT ed i protocolli di Internet.<br />
GNU è inizialmente orientato alle macchine della classe 68000/16000 con memoria virtuale,<br />
perché sono quelle su cui è più facile farlo girare. Lasceremo agli interessati il lavoro necessario<br />
a farlo girare su macchine più piccole.<br />
Vi preghiamo, per evitare confusioni, di pronunciare la ’G’ nella parola ’GNU’ quando indica il<br />
nome di questo progetto. [N.d.T.: questa avvertenza serve ad evitare che in inglese "GNU" sia<br />
pronunciato come la parola "new"].<br />
Perché devo scrivere GNU<br />
Io credo che il punto fondamentale sia che, se a me piace un programma, io debba condividerlo<br />
con altre persone a cui piace. I venditori di s<strong>of</strong>tware usano il criterio "divide et impera" con<br />
gli utenti, facendo sì che non condividano il s<strong>of</strong>tware con altri. Io mi rifiuto di spezzare così<br />
la solidarietà con gli altri utenti. La mia coscienza non mi consente di firmare un accordo per<br />
non rivelare informazioni o per una licenza d’uso del s<strong>of</strong>tware. Ho lavorato per anni presso<br />
il laboratorio di intelligenza artificiale per resistere a queste tendenze e ad altri atteggiamenti<br />
sgradevoli, ma col tempo queste sono andate troppo oltre: non potevo rimanere in una istituzione<br />
dove ciò viene fatto a mio nome contro la mia volontà.<br />
Per poter continuare ad usare i computer senza disonore, ho deciso di raccogliere un corpus di<br />
s<strong>of</strong>tware libero in modo da andare avanti senza l’uso di alcun s<strong>of</strong>tware che non sia libero. Mi<br />
sono dimesso dal laboratorio di Intelligenza Artificiale per togliere al MIT ogni scusa legale che<br />
mi impedisca di distribuire GNU.<br />
Perché GNU sarà compatibile con Unix<br />
Unix non è il mio sistema ideale, ma non è poi così male. Le caratteristiche essenziali di Unix<br />
paiono essere buone e penso di poter colmare le lacune di Unix senza rovinarne le caratteristiche.<br />
E adottare un sistema compatibile con Unix può risultare pratico anche per molti altri.<br />
Come sarà reso disponibile GNU<br />
GNU non è di pubblico dominio. A tutti sarà permesso di modificare e ridistribuire GNU, ma a<br />
nessun distributore sarà concesso di porre restrizioni sulla sua ridistribuzione. Questo vuol dire<br />
che non saranno permesse modifiche proprietarie. Voglio essere sicuro che tutte le versioni di<br />
GNU rimangano libere.<br />
Perché molti altri programmatori desiderano essere d’aiuto<br />
Ho trovato molti altri programmatori molto interessati a GNU che vogliono dare una mano.<br />
Molti programmatori sono scontenti della commercializzazione del s<strong>of</strong>tware di sistema. Li può<br />
aiutare a far soldi, ma li costringe in generale a sentirsi in conflitto con gli altri programmatori,
Manifesto GNU 333<br />
invece che solidali. L’atto di amicizia fondamentale tra programmatori è condividere programmi;<br />
le politiche di commercializzazione attualmente in uso essenzialmente proibiscono ai programmatori<br />
di trattare gli altri come amici. Gli acquirenti del s<strong>of</strong>tware devono decidere tra l’amicizia<br />
e l’obbedienza alle leggi. Naturalmente molti decidono che l’amicizia è più importante. Ma quelli<br />
che credono nella legge non si sentono a proprio agio con queste scelte. Diventano cinici e<br />
pensano che programmare sia solo un modo per fare soldi.<br />
Lavorando e utilizzando GNU invece che programmi proprietari, possiamo comportarci amichevolmente<br />
con tutti e insieme rispettare la legge. Inoltre GNU è un esempio che ispira gli altri e<br />
una bandiera che li chiama a raccolta perché si uniscano a noi nel condividere il s<strong>of</strong>tware. Questo<br />
ci può dare una sensazione di armonia che sarebbe irraggiungibile se usassimo s<strong>of</strong>tware che non<br />
sia libero. Per circa la metà dei programmatori che conosco è una soddisfazione importante, che<br />
il denaro non può sostituire.<br />
Come si può contribuire<br />
Chiedo ai produttori di computer donazioni in denaro e macchine, ed ai privati donazioni in<br />
programmi e lavoro.<br />
Donare delle macchine può far sì che su di esse giri ben presto GNU. Le macchine devono<br />
essere sistemi completi e pronti all’uso approvati per l’utilizzo in aree residenziali e non devono<br />
richiedere raffreddamento o alimentazione di tipo s<strong>of</strong>isticato.<br />
Ho conosciuto moltissimi programmatori desiderosi di contribuire a GNU part-time. Per la gran<br />
parte dei progetti, un lavoro part-time distribuito risulterebbe troppo difficile da coordinare, perché<br />
le varie parti scritte indipendentemente non funzionerebbero insieme. Ma per scrivere un<br />
sostituto di Unix questo problema non si pone, perché un sistema Unix completo contiene centinaia<br />
di programmi di servizio, ognuno con la propria documentazione separata, e con gran parte<br />
delle specifiche di interfaccia date dalla compatibilità con Unix. Se ogni partecipante scrive un<br />
solo programma da usare al posto di una utility di Unix, il quale funzioni correttamente al posto<br />
dell’originale su un sistema Unix, allora questi programmi funzioneranno bene una volta messi<br />
assieme. Anche considerando qualche imprevisto dovuto a Murphy, assemblare tali componenti<br />
è un lavoro fattibile. Il kernel invece richiederà una più stretta cooperazione, e verrà sviluppato<br />
da un gruppo piccolo e affiatato.<br />
Donazioni in denaro possono mettermi in grado di assumere alcune persone a tempo pieno o parttime.<br />
Lo stipendio non sarà alto rispetto agli standard dei programmatori, ma io cerco persone<br />
per le quali lo spirito della comunità GNU sia importante quanto il denaro. Io lo vedo come un<br />
modo di permettere a degli appassionati di dedicare tutte le loro energie al lavoro su GNU senza<br />
essere costretti a guadagnarsi da vivere in un altro modo.<br />
Perché tutti gli utenti dei computer ne trarranno beneficio<br />
Una volta scritto GNU, ognuno potrà avere liberamente del buon s<strong>of</strong>tware di sistema, così come<br />
può avere l’aria. 2<br />
Questo significa molto di più che far risparmiare a ciascuno il costo di una licenza Unix: vuol dire<br />
evitare l’inutile spreco di ripetere ogni volta lo sforzo della programmazione di sistema. Queste<br />
energie possono essere invece impiegate ad avanzare lo stato dell’arte.<br />
I sorgenti completi del sistema saranno a disposizione di tutti. Di conseguenza, un utente che<br />
abbia necessità di apportare dei cambiamenti al sistema sarà sempre in grado di farlo da solo o<br />
di commissionare i cambiamenti ad un programmatore o ad un’impresa. Gli utenti non saranno<br />
2 Questo è un altro punto dove non sono riuscito a distinguere chiaramente tra i due significati di "free". La frase, così<br />
com’è, non è falsa, si possono ottenere gratuitamente copie del s<strong>of</strong>tware GNU, o dagli amici o attraverso la rete. Ma in<br />
effetti suggerisce un’idea sbagliata.
334 volume VIII Argomenti avanzati e accessori<br />
più in balia di un solo programmatore o di una impresa che, avendo la proprietà esclusiva dei<br />
sorgenti, sia la sola a poter fare le modifiche.<br />
Le scuole avranno la possibilità di fornire un ambiente molto più educativo, incoraggiando gli<br />
studenti a studiare e migliorare il s<strong>of</strong>tware di sistema. I laboratori di informatica di Harvard avevano<br />
una politica per cui nessun programma poteva essere installato nel sistema senza che i sorgenti<br />
fossero pubblicamente consultabili, e la praticarono rifiutandosi effettivamente di installare<br />
alcuni programmi. Questo comportamento mi è stato di grande ispirazione.<br />
Infine, scompariranno le necessità burocratiche di tener conto di chi sia il proprietario del<br />
s<strong>of</strong>tware di sistema e di chi abbia il diritto di farci cosa.<br />
Ogni sistema per imporre tariffe d’uso di un programma, comprese le licenze d’uso per le copie,<br />
è sempre estremamente costoso in termini sociali a causa del complesso meccanismo necessario<br />
per decidere quanto (cioè per quali programmi) ognuno debba pagare, e solo uno stato di polizia<br />
può costringere tutti all’obbedienza. Immaginate una stazione spaziale dove l’aria deve essere<br />
prodotta artificialmente ad un costo elevato: far pagare ogni litro d’aria consumato può essere<br />
giusto, ma indossare la maschera col contatore tutto il giorno e tutta la notte è intollerabile,<br />
anche se tutti possono permettersi di pagare la bolletta. E le videocamere poste in ogni dove per<br />
controllare che nessuno si tolga mai la maschera sono <strong>of</strong>fensive. Meglio finanziare l’impianto di<br />
ossigenazione con una tassa pro capite e buttar via le maschere.<br />
Copiare un programma in tutto o in parte è tanto naturale per un programmatore quanto respirare<br />
ed è altrettanto produttivo. Dovrebbe essere altrettanto libero.<br />
Alcune obiezioni facilmente confutabili agli obiettivi GNU<br />
«La gente non lo userà se è gratuito, perché non potrà avere l’assistenza.»<br />
«Un programma deve essere a pagamento, per poter fornire supporto adeguato.»<br />
Se la gente preferisse pagare per GNU più l’assistenza piuttosto che avere GNU gratis senza<br />
assistenza, allora un’impresa che fornisse assistenza a chi si è procurato GNU gratis potrebbe<br />
operare con pr<strong>of</strong>itto. 3<br />
Si deve distinguere tra il supporto sotto forma di lavoro di programmazione e la semplice gestione.<br />
Il primo non è ottenibile da un venditore di s<strong>of</strong>tware. Se il problema non è sentito da un<br />
numero sufficiente di clienti allora il venditore dirà al cliente di arrangiarsi.<br />
Per chi deve poter contare su questo tipo di supporto l’unica soluzione è di disporre dei sorgenti<br />
e degli strumenti necessari, in modo da poter commissionare il lavoro a chi sia disposto a farlo,<br />
invece che rimanere in balia di qualcuno. Con Unix il prezzo dei sorgenti rende ciò improponibile<br />
per la maggior parte delle imprese. Con GNU questo sarà invece facile. Si darà sempre il caso<br />
che non siano disponibili persone competenti, ma questo non potrà essere imputato al sistema di<br />
distribuzione. GNU non elimina tutti i problemi del mondo, solo alcuni.<br />
Allo stesso tempo, gli utenti che non sanno nulla di computer hanno bisogno di manutenzione,<br />
cioè di cose che potrebbero fare facilmente da soli ma che non sono in grado di fare.<br />
Servizi di questo genere potrebbero essere forniti da aziende che vendono solo gestione e manutenzione.<br />
Se è vero che gli utenti sono disposti a pagare per un prodotto con servizio, allora<br />
saranno anche disposti a pagare per il servizio avendo avuto il prodotto gratuitamente. Le aziende<br />
di servizi si faranno concorrenza sul prezzo e sulla qualità; gli utenti d’altra parte non saranno<br />
legati a nessuna di esse in particolare. Nel frattempo, coloro che non avranno bisogno del servizio<br />
saranno sempre in grado di usare il programma senza pagare il servizio.<br />
3 Adesso esistono effettivamente molte ditte di questo tipo.
Manifesto GNU 335<br />
«Non si può raggiungere molta gente senza pubblicità, e per finanziarla si deve far pagare il<br />
programma.»<br />
«È inutile reclamizzare un programma gratuito.»<br />
Ci sono molte forme di pubblicità gratuita o a basso costo che possono essere usate per informare<br />
un gran numero di utenti di computer riguardo a cose come GNU. Ma può essere vero che la<br />
pubblicità può raggiungere molti più utenti di microcomputer. Se fosse veramente così, una ditta<br />
che reclamizzasse il servizio di copia e spedizione per posta di GNU a pagamento dovrebbe<br />
aver abbastanza successo commerciale da rientrare dai costi della pubblicità e da guadagnarci. In<br />
questo modo, pagano la pubblicità solo gli utenti che ne beneficiano.<br />
D’altro canto, se molta gente ottiene GNU da amici e queste aziende non hanno successo, vorrà<br />
dire che la pubblicità non era necessaria per diffondere GNU. Perché tutti questi difensori del<br />
libero mercato non vogliono lasciare che sia il libero mercato a decidere? 4<br />
«La mia azienda ha bisogno di un sistema operativo proprietario per essere più avanti della<br />
concorrenza.»<br />
Con GNU, i sistemi operativi non rientreranno più fra gli elementi di concorrenza. La vostra<br />
azienda non potrà essere concorrenziale in quest’area, ma egualmente non potranno esserlo i<br />
concorrenti. Vi farete concorrenza in altre aree, mentre in questa godrete di mutui benefici. Se<br />
vendete sistemi operativi non apprezzerete GNU, ma è un problema vostro. Se avete un’attività<br />
di altro tipo, GNU vi può evitare di essere spinti nel costoso campo della vendita di sistemi<br />
operativi.<br />
Mi piacerebbe che lo sviluppo di GNU fosse sostenuto da donazioni da parte di numerosi<br />
produttori ed utenti, riducendo così la spesa per tutti. 5<br />
«Ma i programmatori non meritano una ricompensa per la loro creatività?»<br />
Se qualcosa merita una ricompensa questo è il contribuire al bene sociale. La creatività può essere<br />
un contributo al bene sociale, ma solo nella misura in cui la società è libera di usarne i risultati.<br />
Se i programmatori meritano una ricompensa per la creazione di programmi innovativi, allora<br />
con la stessa logica meritano una punizione se pongono restrizioni all’uso di questi programmi.<br />
«Un programmatore non dovrebbe poter chiedere una ricompensa per la sua creatività?»<br />
Non c’è niente di male nel chiedere di esser pagati per il proprio lavoro, o mirare ad incrementare<br />
le proprie entrate, fintanto che non si utilizzino metodi che siano distruttivi. Ma i metodi comuni<br />
nel campo del s<strong>of</strong>tware, al giorno d’oggi, sono distruttivi.<br />
Spremere denaro dagli utenti di un programma imponendo restrizioni sull’uso è distruttivo perché<br />
riduce i modi in cui il programma può essere usato. Questo diminuisce la quantità di ricchezza<br />
che l’umanità ricava dal programma. Quando c’è una scelta deliberata di porre restrizioni, le<br />
conseguenze dannose sono distruzione deliberata.<br />
La ragione per cui un buon cittadino non usa questi metodi distruttivi per diventare più ricco è che,<br />
se lo facessero tutti, diventeremmo tutti più poveri a causa delle distruzioni reciproche. Questa<br />
è etica kantiana, la Regola Aurea: poiché non mi piacciono le conseguenze che risulterebbero<br />
se tutti impedissero l’accesso alle informazioni, devo considerare sbagliato che uno lo faccia.<br />
4 La Free S<strong>of</strong>tware Foundation raccoglie la maggior parte dei suoi fondi da un servizio di distribuzione, anche se<br />
è più un ente senza fini di lucro che un’azienda. Se *nessuno* sceglie di ottenere copie del s<strong>of</strong>tware ordinandole alla<br />
FSF, questa sarà impossibilitata a proseguire la propria opera. Ma questo non vuole dire che siano giustificate restrizioni<br />
proprietarie per costringere gli utenti a pagare. Se una piccola frazione degli utenti ordina le sue copie dalla FSF, questo<br />
sarà sufficiente per tenerla a galla. Quindi chiediamo agli utenti di aiutarci in questo modo. Hai fatto la tua parte?<br />
5 Un gruppo di imprese di s<strong>of</strong>tware ha recentemente costituito dei finanziamenti per sostenere la manutenzione del<br />
nostro compilatore C.
336 volume VIII Argomenti avanzati e accessori<br />
In particolare, il desiderio di una ricompensa per la propria creatività non giustifica il privare il<br />
mondo nel suo insieme di tutta o parte di questa creatività.<br />
«Ma i programmatori non moriranno di fame?»<br />
Potrei rispondere che nessuno è obbligato a fare il programmatore. La maggior parte di noi non è<br />
in grado di andare per strada a fare il mimo, ma ciò non vuol dire che siamo condannati a passare<br />
la vita per strada a fare i mimi, e morire di fame. Facciamo un altro lavoro.<br />
Ma è la risposta sbagliata, perché accetta l’assunzione implicita di chi pone la domanda, e cioè<br />
che senza proprietà del s<strong>of</strong>tware non è possibile pagare ai programmatori il becco di un quattrino.<br />
Un’assunzione del tipo tutto o niente.<br />
La vera ragione per cui i programmatori non moriranno di fame è che sarà per loro egualmente<br />
possibile essere pagati per programmare, solo non pagati così tanto come ora.<br />
Porre restrizioni sulle copie non è l’unico modello di affari nel campo del s<strong>of</strong>tware. È il modello<br />
più comune perché è il più redditizio. Se fosse vietato, o rifiutato dagli utenti, l’industria del<br />
s<strong>of</strong>tware si sposterebbe su altri modelli organizzativi, adottandone altri ora meno comuni. Ci<br />
sono sempre numerosi modi per organizzare un qualunque tipo di affari.<br />
Probabilmente programmare nel nuovo modello organizzativo non sarà più così redditizio come<br />
lo è ora. Ma questo non è un argomento contro il cambiamento. Che gli addetti alle vendite<br />
ricevano i salari che ora ricevono non è considerata un’ingiustizia. Se i programmatori avessero<br />
gli stessi stipendi (in pratica guadagnerebbero molto di più), non sarebbe nemmeno quella<br />
un’ingiustizia.<br />
«Ma le persone non hanno diritto di controllare come la loro creatività viene usata?»<br />
Il "controllo sull’uso delle proprie idee" in realtà costituisce un controllo sulle vite degli altri; e<br />
di solito viene usato per rendere più difficili le loro vite.<br />
Le persone che hanno studiato con cura i vari aspetti del diritto alla proprietà intellettuale (come<br />
gli avvocati) dicono che non c’è alcun diritto intrinseco alla proprietà intellettuale. I tipi dei<br />
supposti diritti alla proprietà intellettuale riconosciuti dal governo furono creati da specifici atti<br />
legislativi per scopi specifici.<br />
Per esempio la legislazione sui brevetti fu introdotta per incoraggiare gli inventori a rivelare i<br />
dettagli delle loro invenzioni. Lo scopo era avvantaggiare la società più che avvantaggiare gli<br />
inventori. A quel tempo la validità di 17 anni per un brevetto era breve se confrontata con la<br />
velocità di avanzamento dello stato dell’arte. Poiché i brevetti riguardano solo i produttori, per<br />
i quali il costo e lo sforzo degli accordi di licenza sono piccoli in confronto all’organizzazione<br />
della produzione, spesso i brevetti non costituiscono un gran danno. E non ostacolano la gran<br />
parte degli individui che usano prodotti coperti da brevetto.<br />
L’idea del copyright non esisteva in tempi antichi, quando gli autori copiavano estesamente altri<br />
autori in opere non narrative. Questa pratica era utile, ed è il solo modo attraverso cui almeno<br />
parte del lavoro di alcuni autori è sopravvissuto. La legislazione sul copyright fu creata espressamente<br />
per incoraggiare l’originalità. Nel campo per cui fu inventata, cioè i libri, che potevano<br />
essere copiati a basso costo solo con apparecchiature tipografiche, non fece molto danno e non<br />
pose ostacoli alla maggior parte dei lettori.<br />
Tutti i diritti di proprietà intellettuale sono solo licenze concesse dalla società perché si riteneva,<br />
correttamente o meno, che concederle avrebbe giovato alla società nel suo complesso. Ma data<br />
una situazione particolare dobbiamo chiederci: facciamo realmente bene a concedere queste<br />
licenze? Che atti permettiamo di compiere con esse?
Manifesto GNU 337<br />
Il caso dei programmi ai giorni nostri differisce enormemente da quello dei libri un secolo fa. Il<br />
fatto che la via più facile per passare una copia di un programma sia da persona a persona, che il<br />
programma abbia un codice sorgente ed un codice oggetto che sono cose distinte, ed infine il fatto<br />
che un programma venga usato più che letto e gustato, combinandosi creano una situazione in<br />
cui qualcuno che impone un copyright minaccia la società nel suo insieme, sia materialmente che<br />
spiritualmente, una situazione in cui quel qualcuno non dovrebbe farlo, che la legge lo permetta<br />
o no.<br />
«La competizione fa sì che le cose siano fatte meglio.»<br />
Il paradigma della competizione è la gara: premiando il vincitore incoraggia ognuno a correre più<br />
veloce. Quando veramente il capitalismo funziona in questo modo, fa un buon lavoro; ma chi lo<br />
difende ha torto nell’asserire che agisce sempre così. Se i corridori dimenticano il motivo per cui<br />
è <strong>of</strong>ferto il premio e si concentrano solo sul vincere non curandosi di come, possono trovare altre<br />
strategie, come ad esempio attaccare gli altri concorrenti. Se i corridori si azzuffano, arrivano<br />
tutti in ritardo al traguardo.<br />
Il s<strong>of</strong>tware proprietario e segreto è l’equivalente morale dei corridori che si azzuffano. Triste a<br />
dirsi, l’unico arbitro che abbiamo pare non muovere alcuna obiezione alle zuffe, al più le regolamenta<br />
("ogni dieci metri puoi tirare un pugno"). Dovrebbe invece dividerli e penalizzarli anche<br />
se solo provassero a combattere.<br />
«Ma senza un incentivo economico non smetterebbero tutti di programmare?»<br />
In realtà molta gente programmerebbe senza alcun incentivo economico. Programmare ha un<br />
fascino irresistibile per alcune persone, solitamente per quelli che ci riescono meglio. Non mancano<br />
certo i musicisti pr<strong>of</strong>essionisti che insistono pur non avendo speranza di guadagnarsi da<br />
vivere suonando.<br />
Ma in realtà questa domanda, benché posta spesso, non è appropriata. La paga per i programmatori<br />
non sparirà, semplicemente diminuirà. Quindi la domanda corretta è: «qualcuno si metterà<br />
mai a programmare per un minore incentivo economico?». La mia esperienza dice che sì, ci si<br />
metterà.<br />
Per più di dieci anni molti tra i migliori programmatori del mondo hanno lavorato nel laboratorio<br />
di Intelligenza Artificiale per molti meno soldi di quanti ne avrebbero potuti ricevere in ogni<br />
altro posto. Hanno avuto soddisfazioni non economiche di moltissimi tipi, ad esempio fama e<br />
riconoscenza. E la creatività è anche divertente, un premio di per sé.<br />
Poi molti se ne sono andati quando hanno avuto la possibilità di fare lo stesso interessante lavoro<br />
per un mucchio di soldi.<br />
Ciò che i fatti mostrano è che la gente programma per altre ragioni che non siano il denaro; ma<br />
se viene data la possibilità di fare la stessa cosa per un mucchio di soldi, allora cominceranno ad<br />
aspettarseli e a richiederli. Le organizzazioni che pagano poco sono svantaggiate in confronto a<br />
quelle che pagano molto, ma non sarebbero necessariamente in questa posizione se quelle che<br />
pagano molto fossero bandite.<br />
«Abbiamo un disperato bisogno dei programmatori. Se ci chiedono di smettere di aiutare i nostri<br />
vicini dobbiamo obbedire.»<br />
Non si è mai così disperati da dover obbedire a questo genere di pretese. Ricorda: milioni in<br />
difesa, ma non un centesimo in tributi [N.d.T.: è una famosa frase di George Washington].<br />
«I programmatori devono guadagnarsi da vivere in qualche modo.»<br />
A breve termine è vero. Ma ci sono un’infinità di modi in cui i programmatori possono guadagnarsi<br />
da vivere senza vendere i diritti d’uso dei programmi. Questo metodo è comune ai giorni
338 volume VIII Argomenti avanzati e accessori<br />
nostri perché porta la maggior quantità di denaro a programmatori e aziende, non perché sia l’unica<br />
strada per guadagnarsi da vivere. È facile trovarne altre se se ne vogliono trovare. Ecco una<br />
serie di esempi.<br />
Un produttore che immette sul mercato un nuovo computer pagherà per il porting dei sistemi<br />
operativi sul nuovo hardware.<br />
I servizi a pagamento di insegnamento, gestione e manutenzione possono impiegare dei<br />
programmatori.<br />
Persone con idee nuove possono distribuire i programmi gratuitamente, chiedendo donazioni<br />
agli utenti soddisfatti, o vendendo servizi di gestione. Ho incontrato persone che già lavorano<br />
con successo in questo modo.<br />
Utenti con necessità simili possono formare gruppi e pagare. Un gruppo potrebbe stipulare un<br />
contratto con un’impresa di programmazione per scrivere i programmi che i membri del gruppo<br />
vorrebbero usare.<br />
Tutti i tipi di sviluppo possono essere finanziati da una Tassa per il S<strong>of</strong>tware:<br />
Supponiamo che chiunque compri un computer debba pagare un x per cento del costo del computer<br />
come tassa per il s<strong>of</strong>tware. Il governo girerebbe questi fondi ad un’agenzia come la NSF<br />
[N.d.T.: più o meno l’equivalente del nostro CNR] per impiegarli nello sviluppo del s<strong>of</strong>tware.<br />
Ma se l’acquirente fa lui stesso una donazione per lo sviluppo del s<strong>of</strong>tware, potrebbe ottenere<br />
un credito nei confronti di queste tasse. Potrebbe fare una donazione ad un progetto di sua scelta<br />
-- tipicamente scelto perché spera di usarne i risultati quando questo verrà completato. Potrebbe<br />
ottenere un credito per ogni donazione fatta, fino al valore totale della tassa che dovrebbe pagare.<br />
Il gettito complessivo di questa tassa potrebbe essere deciso dal voto di chi la paga, pesato<br />
secondo l’ammontare pagato.<br />
Le conseguenze:<br />
• La comunità degli utenti di computer sosterrebbe lo sviluppo del s<strong>of</strong>tware.<br />
• La comunità sceglierebbe il livello di sostegno necessario.<br />
• Gli utenti che fossero interessati a sapere su che progetto vengano spesi i loro soldi<br />
avrebbero la possibilità di gestire personalmente la cosa.<br />
Nel lungo periodo, rendere liberi i programmi è un passo verso l’epoca della fine del bisogno,<br />
quando nessuno sarà obbligato a lavorare molto duramente solo per guadagnarsi di che vivere.<br />
La gente sarà libera di dedicarsi ad attività divertenti, come programmare, dopo aver passato le<br />
dieci ore settimanali necessarie in compiti come legiferare, fare consulenza familiare, riparare i<br />
robot e prevedere il moto degli asteroidi. Non ci sarà bisogno di guadagnarsi da vivere con la<br />
programmazione.<br />
Abbiamo già ridotto moltissimo la quantità di lavoro che la società nel suo complesso deve fare<br />
per ottenere la sua produttività attuale, ma poco di questo si è tradotto in benessere per i lavoratori<br />
perché è necessario accompagnare l’attività produttiva con molta attività non produttiva. Le cause<br />
principali sono la burocrazia e gli sforzi a tutto campo contro la concorrenza. Il s<strong>of</strong>tware libero<br />
ridurrà di molto questo drenaggio di risorse nell’area della produzione del s<strong>of</strong>tware. Dobbiamo<br />
farlo affinché i guadagni tecnici in produttività si traducano in meno lavoro per noi.
Il progetto GNU<br />
Testo originale: <br />
Traduzione originale: <br />
Copyright © 1998 Richard Stallman<br />
Capitolo 372<br />
non modificabile<br />
La copia letterale e la distribuzione di questo articolo nella sua integrità sono permesse con ogni<br />
mezzo, a patto che questa nota sia riprodotta.<br />
1<br />
372.1 La prima comunità di condivisione del s<strong>of</strong>tware<br />
Quando cominciai a lavorare nel laboratorio di Intelligenza Artificiale del MIT [N.d.T. Massachusset<br />
Institute <strong>of</strong> Technology] nel 1971, entrai a far parte di una comunità in cui ci si scambiavano<br />
i programmi, che esisteva già da molti anni. La condivisione del s<strong>of</strong>tware non si limitava<br />
alla nostra comunità; è un cosa vecchia quanto i computer, proprio come condividere le ricette è<br />
antico come il cucinare. Ma noi lo facevamo più di quasi chiunque altro.<br />
Il laboratorio di Intelligenza Artificiale usava un sistema operativo a partizione di tempo (timesharing)<br />
chiamato ITS (Incompatible Timesharing System) che il gruppo di hacker 2 del laboratorio<br />
aveva progettato e scritto in linguaggio assembler per il Digital PDP-10, uno dei grossi<br />
elaboratori di quel periodo. Come membro di questa comunità, hacker di sistema nel gruppo<br />
laboratorio, il mio compito era migliorare questo sistema.<br />
Non chiamavamo il nostro s<strong>of</strong>tware "s<strong>of</strong>tware libero", poiché questa espressione ancora non esisteva,<br />
ma si trattava proprio di questo. Quando persone di altre università o di qualche società volevano<br />
convertire il nostro programma per il proprio sistema ed utilizzarlo, erano le benvenute. Se<br />
si vedeva qualcuno usare un programma sconosciuto ed interessante, si poteva sempre chiedere di<br />
vederne il codice sorgente, in modo da poterlo leggere, modificare, o prenderne (cannibalizzarne)<br />
alcune parti per creare un nuovo programma.<br />
372.2 La comunità si dissolve<br />
La situazione cambiò drasticamente all’inizio degli anni ’80 quando la Digital smise di produrre<br />
la serie PDP-10. La sua architettura, elegante e potente negli anni ’60, non poteva essere estesa in<br />
modo naturale ai più grandi spazi di indirizzamento che si stavano rendendo possibili negli anni<br />
’80. Questo significò che quasi tutti i programmi che formavano ITS divennero obsoleti.<br />
La comunità di hacker del laboratorio di Intelligenza Artificiale si era già dissolta non molto<br />
tempo prima. Nel 1981 la Symbolics, nata da una costola del laboratorio stesso, gli aveva sottratto<br />
quasi tutti gli hacker; l’ormai esiguo gruppo rimasto fu dunque incapace di sostenersi (il libro<br />
1 [NdR: il testo che appare qui è stato ritoccato leggermente per correggere alcuni errori evidenti.]<br />
2 L’uso del termine "hacker" nel senso di "pirata" è una confusione di termini creata dai mezzi di informazione. Noi<br />
hacker ci rifiutiamo di riconoscere questo significato, e continuiamo ad utilizzare la parola nel senso di "uno che ami<br />
programmare, e a cui piaccia essere bravo a farlo".<br />
339
340 volume VIII Argomenti avanzati e accessori<br />
"Hackers" di Steve Levy narra questi eventi, oltre a fornire una fedele ricostruzione di questa<br />
comunità ai suoi inizi). Quando il laboratorio di Intelligenza Artificiale nel 1982 acquistò un<br />
nuovo PDP-10, i sistemisti decisero di utilizzare il sistema timesharing non libero della Digital<br />
piuttosto che ITS.<br />
I moderni elaboratori di quell’epoca, come il VAX o il 68020, avevano il proprio sistema operativo,<br />
ma nessuno di questi era libero: si doveva firmare un accordo di non-diffusione persino per<br />
ottenerne una copia eseguibile.<br />
Questo significava che il primo passo per usare un computer era promettere di negare aiuto al<br />
proprio vicino. Una comunità cooperante era vietata. La regola creata dai proprietari di s<strong>of</strong>tware<br />
proprietario era: «se condividi il s<strong>of</strong>tware col tuo vicino sei un pirata. Se vuoi modifiche, pregaci<br />
di farle».<br />
L’idea che la concezione sociale di s<strong>of</strong>tware proprietario -- cioè il sistema che impone che il<br />
s<strong>of</strong>tware non possa essere condiviso o modificato -- sia antisociale, contraria all’etica, semplicemente<br />
sbagliata, può apparire sorprendente a qualche lettore. Ma che altro possiamo dire di un<br />
sistema che si basa sul dividere utenti e lasciarli senza aiuto? Quei lettori che trovano sorprendente<br />
l’idea possono aver data per scontata la concezione sociale di s<strong>of</strong>tware proprietario, o averla<br />
giudicata utilizzando lo stesso metro suggerito dal mercato del s<strong>of</strong>tware proprietario. I produttori<br />
di s<strong>of</strong>tware hanno lavorato a lungo e attivamente per diffondere la convinzione che c’è un solo<br />
modo di vedere la cosa.<br />
Quando i produttori di s<strong>of</strong>tware parlano di "difendere" i propri "diritti" o di "fermare la pirateria",<br />
quello che dicono è in realtà secondario. Il vero messaggio in quelle affermazioni sta nelle<br />
assunzioni inespresse, che essi danno per scontate; vogliono che siano accettate acriticamente.<br />
Esaminiamole, dunque.<br />
Una prima assunzione è che le aziende produttrici di s<strong>of</strong>tware abbiano il diritto naturale indiscutibile<br />
di proprietà sul s<strong>of</strong>tware, e di conseguenza, abbiano controllo su tutti i suoi utenti. Se<br />
questo fosse un diritto naturale, non potremmo sollevare obiezioni, indipendentemente dal danno<br />
che possa recare ad altri. È interessante notare che, negli Stati Uniti, sia la costituzione che<br />
la giurisprudenza rifiutano questa posizione: il diritto d’autore non è un diritto naturale, ma un<br />
monopolio imposto dal governo che limita il diritto naturale degli utenti ad effettuare delle copie.<br />
Un’altra assunzione inespressa è che la sola cosa importante del s<strong>of</strong>tware sia il lavoro che consente<br />
di fare -- vale a dire che noi utenti non dobbiamo preoccuparci del tipo di società in cui ci<br />
è permesso vivere.<br />
Una terza assunzione è che non avremmo s<strong>of</strong>tware utilizzabile (o meglio, che non potremmo mai<br />
avere un programma per fare questo o quell’altro particolare lavoro) se non riconoscessimo ai<br />
produttori il controllo sugli utenti di quei programmi. Questa assunzione avrebbe potuto sembrare<br />
plausibile, prima che il movimento del s<strong>of</strong>tware libero dimostrasse che possiamo scrivere quantità<br />
di programmi utili senza bisogno di metterci dei catenacci.<br />
Se rifiutiamo di accettare queste assunzioni, giudicando queste questioni con comuni criteri di<br />
moralità e di buon senso dopo aver messo al primo posto gli interessi degli utenti, tenendo conto<br />
che gli utenti vengono prima di tutto, arriviamo a conclusioni del tutto differenti. Chi usa un<br />
calcolatore dovrebbe essere libero di modificare i programmi per adattarli alle proprie necessità,<br />
ed essere libero di condividere il s<strong>of</strong>tware, poiché aiutare gli altri è alla base della società.<br />
Non c’è modo in questa sede di trattare appr<strong>of</strong>onditamente i ragionamenti che portano a questa<br />
conclusione; il lettore interessato può cercare le informazioni in rete a questo indirizzo: .
Il progetto GNU 341<br />
372.3 Una difficile scelta morale<br />
Una volta che il mio gruppo si fu sciolto, continuare come prima fu impossible. Mi trovai di<br />
fronte ad una difficile scelta morale.<br />
La scelta facile sarebbe stata quella di unirsi al mondo del s<strong>of</strong>tware proprietario, firmando accordi<br />
di non-diffusione e promettendo di non aiutare i miei compagni hacker. Con ogni probabilità<br />
avrei anche sviluppato s<strong>of</strong>tware che sarebbe stato distribuito secondo accordi di non-diffusione,<br />
contribuendo così alla pressione su altri perché a loro volta tradissero i propri compagni.<br />
In questo modo avrei potuto guadagnare, e forse mi sarei divertito a programmare. Ma sapevo<br />
che al termine della mia carriera mi sarei voltato a guardare indietro, avrei visto anni spesi a<br />
costruire muri per dividere le persone, e avrei compreso di aver contribuito a rendere il mondo<br />
peggiore.<br />
Avevo già sperimentato cosa significasse un accordo di non diffusione per chi lo firmava, quando<br />
qualcuno rifiutò a me e al laboratorio AI del MIT il codice sorgente del programma di controllo<br />
della nostra stampante; l’assenza di alcune funzionalità nel programma rendeva oltremodo frustrante<br />
l’uso della stampante. Per cui non mi potevo dire che gli accordi di non-diffusione fossero<br />
innocenti. Ero molto arrabbiato quando quella persona si rifiutò di condividere il programma con<br />
noi; non potevo far finta di niente e fare lo stesso con tutti gli altri.<br />
Un’altra possibile scelta, semplice ma spiacevole, sarebbe stata quella di abbandonare l’informatica.<br />
In tal modo le mie capacità non sarebbero state mal utilizzate, tuttavia sarebbero state<br />
sprecate. Non sarei mai stato colpevole di dividere o imporre restrizioni agli utenti di calcolatori,<br />
ma queste cose sarebbero comunque successe.<br />
Allora cercai un modo in cui un programmatore potesse fare qualcosa di buono. Mi chiesi dunque:<br />
c’erano un programma o dei programmi che io potessi scrivere, per rendere nuovamente possibile<br />
l’esistenza di una comunità?<br />
La risposta era semplice: innanzitutto serviva un sistema operativo. Questo è difatti il s<strong>of</strong>tware<br />
fondamentale per iniziare ad usare un computer. Con un sistema operativo si possono fare molte<br />
cose; senza, non è proprio possibile far funzionare il computer. Con un sistema operativo libero,<br />
avremmo potuto avere nuovamente una comunità in cui hacker possono cooperare, e invitare<br />
chiunque ad unirsi al gruppo. E chiunque sarebbe stato in grado di usare un calcolatore, senza<br />
dover cospirare fin dall’inizio per sottrarre qualcosa ai propri amici.<br />
Essendo un programmatore di sistemi, possedevo le competenze adeguate per questo lavoro.<br />
Così, anche se non davo il successo per scontato, mi resi conto di essere la persona giusta per<br />
farlo. Scelsi di rendere il sistema compatibile con Unix, in modo che fosse portabile, e che gli<br />
utenti Unix potessero passare facilmente ad esso. Il nome GNU fu scelto secondo una tradizione<br />
hacker, come acronimo ricorsivo che significa "GNU’s Not Unix" [N.d.T. GNU non è Unix].<br />
Un sistema operativo non si limita solo al suo nucleo, che è proprio il minimo per eseguire<br />
altri programmi. Negli anni ’70, qualsiasi sistema operativo degno di questo nome includeva<br />
interpreti di comandi, assemblatori, compilatori, interpreti di linguaggi, debugger, editor di testo,<br />
programmi per la posta e molto altro. ITS li aveva, Multics li aveva, VMS li aveva e Unix li<br />
aveva. Anche il sistema operativo GNU li avrebbe avuti.<br />
Tempo dopo venni a conoscenza di questa massima, attribuita a Hillel:<br />
3<br />
detto.<br />
3 Essendo ateo, non seguo alcuna guida religiosa, ma a volte mi trovo ad ammirare qualcosa che qualcuno di loro ha
342 volume VIII Argomenti avanzati e accessori<br />
Se non sono per me stesso, chi sarà per me?<br />
E se sono solo per me stesso, che cosa sono?<br />
E se non ora, quando?<br />
La decisione di iniziare il progetto GNU si basò su uno spirito simile.<br />
372.4 "Free" come libero<br />
Il termine "free s<strong>of</strong>tware" [N.d.T. il termine free in inglese significa sia gratuito che libero] a volte<br />
è mal interpretato: non ha niente a che vedere col prezzo del s<strong>of</strong>tware; si tratta di libertà. Ecco,<br />
dunque, la definizione di s<strong>of</strong>tware libero: un programma è s<strong>of</strong>tware libero per un dato utente se:<br />
• l’utente ha la libertà di eseguire il programma per qualsiasi scopo;<br />
• l’utente ha la libertà di modificare il programma secondo i propri bisogni (perché questa<br />
libertà abbia qualche effetto in pratica, è necessario avere accesso al codice sorgente<br />
del programma, poiché apportare modifiche ad un programma senza disporre del codice<br />
sorgente è estremamente difficile);<br />
• l’utente ha la libertà di distribuire copie del programma, gratuitamente o dietro compenso;<br />
• l’utente ha la libertà di distribuire versioni modificate del programma, così che la comunità<br />
possa fruire dei miglioramenti apportati.<br />
Poiché "free" si riferisce alla libertà e non al prezzo, vendere copie di un programma non contraddice<br />
il concetto di s<strong>of</strong>tware libero. In effetti, la libertà di vendere copie di programmi è essenziale:<br />
raccolte di s<strong>of</strong>tware libero vendute su CD-ROM sono importanti per la comunità, e la loro vendita<br />
è un modo di raccogliere fondi importante per lo sviluppo del s<strong>of</strong>tware libero. Di conseguenza,<br />
un programma che non può essere liberamente incluso in tali raccolte non è s<strong>of</strong>tware libero.<br />
A causa dell’ambiguità del termine "free", si è cercata a lungo un’alternativa, ma nessuno ne ha<br />
trovata una valida. La lingua inglese ha più termini e sfumature di ogni altra, ma non ha una<br />
parola semplice e non ambigua che significhi libero; "unfettered" è la parola più vicina come<br />
significato [NdT: unfettered è una parola di tono aulico o arcaico che significa libero da ceppi,<br />
vincoli o inibizioni]. Alternative come "liberated", "freedom" e "open" hanno altri significati o<br />
non sono adatte per altri motivi [NdT: rispettivamente, liberato, libertà, aperto].<br />
372.5 S<strong>of</strong>tware GNU e il sistema GNU<br />
Sviluppare un intero sistema è un progetto considerevole. Per raggiungere l’obiettivo decisi di<br />
adattare e usare parti di s<strong>of</strong>tware libero tutte le volte che fosse possibile. Per esempio, decisi fin<br />
dall’inizio di usare TeX come il principale programma di formattazione di testo; qualche anno<br />
più tardi, decisi di usare l’X Window System piuttosto che scrivere un altro sistema a finestre per<br />
GNU.<br />
A causa di questa decisione, il sistema GNU e la raccolta di tutto il s<strong>of</strong>tware GNU non sono<br />
la stessa cosa. Il sistema GNU comprende programmi che non sono GNU, sviluppati da altre<br />
persone o gruppi di progetto per i propri scopi, ma che possiamo usare in quanto s<strong>of</strong>tware libero.
Il progetto GNU 343<br />
372.6 L’inizio del progetto<br />
Nel gennaio 1984 lasciai il mio posto al MIT e cominciai a scrivere s<strong>of</strong>tware GNU. Dovetti<br />
lasciare il MIT, per evitare che potesse interferire con la distribuzione di GNU come s<strong>of</strong>tware<br />
libero. Se fossi rimasto, il MIT avrebbe potuto rivendicare la proprietà del lavoro, ed avrebbe<br />
potuto imporre i propri termini di distribuzione, o anche farne un pacchetto proprietario. Non<br />
avevo alcuna intenzione di fare tanto lavoro solo per vederlo reso inutilizzabile per il suo scopo<br />
originario: creare una nuova comunità di condivisione di s<strong>of</strong>tware. Ad ogni buon conto, il pr<strong>of</strong>essor<br />
Winston -- allora responsabile del laboratorio AI del MIT -- mi propose gentilmente di<br />
continuare ad utilizzare le attrezzature del laboratorio stesso.<br />
372.7 I primi passi<br />
Poco dopo aver iniziato il progetto GNU, venni a sapere del Free University Compiler Kit, noto<br />
anche come VUCK (la parola olandese che sta per "free" inizia con la V). Era un compilatore<br />
progettato per trattare più linguaggi, fra cui C e Pascal, e per generare codice binario per diverse<br />
architetture. Scrissi al suo autore chiedendo se GNU avesse potuto usarlo. Rispose in modo<br />
canzonatorio, dicendo che l’università era sì libera, ma non il compilatore. Decisi allora che<br />
il mio primo programma per il progetto GNU sarebbe stato un compilatore multilinguaggio e<br />
multipiattaforma.<br />
Sperando di evitare di dover scrivere da me l’intero compilatore, ottenni il codice sorgente del<br />
Pastel, un compilatore multipiattaforma sviluppato ai Laboratori Lawrence Livermore. Il linguaggio<br />
supportato da Pastel, in cui il Pastel stesso era scritto, era una versione estesa del Pascal,<br />
pensata come linguaggio di programmazione di sistemi. Io vi aggiunsi un frontend per il C, e cominciai<br />
il porting per il processore Motorola 68000, ma fui costretto a rinunciare quando scoprii<br />
che il compilatore richiedeva diversi megabyte di memoria sullo stack, mentre il sistema Unix<br />
disponibile per il processore 68000 ne permetteva solo 64K.<br />
Mi resi conto allora che il compilatore Pastel interpretava tutto il file di ingresso creandone un<br />
albero sintattico, convertiva questo in una catena di "istruzioni", e quindi generava l’intero file di<br />
uscita senza mai liberare memoria. A questo punto, conclusi che avei dovuto scrivere un nuovo<br />
compilatore da zero. Quel nuovo compilatore è ora noto come Gcc; non utilizza niente del compilatore<br />
Pastel, ma riuscii ad adattare e riutilizzare il frontend per il C che avevo scritto. Questo<br />
però avvenne qualche anno dopo; prima, lavorai su GNU Emacs.<br />
372.8 GNU Emacs<br />
Cominciai a lavorare su GNU Emacs nel settembre 1984, e all’inizio del 1985 cominciava ad<br />
essere utilizzabile. Così potei iniziare ad usare sistemi Unix per scrivere; fino ad allora, avevo<br />
scritto sempre su altri tipi di macchine, non avendo nessun interesse ad imparare vi né ed.<br />
A questo punto alcuni cominciarono a voler usare GNU Emacs, il che pose il problema di come<br />
distribuirlo. Naturalmente lo misi sul server ftp anonimo del computer che usavo al MIT (questo<br />
computer, prep.ai.mit.edu, divenne così il sito ftp primario di distribuzione di GNU; quando<br />
alcuni anni dopo andò fuori servizio, trasferimmo il nome sul nostro nuovo ftp server). Ma allora<br />
molte delle persone interessate non erano su Internet e non potevano ottenere una copia via ftp,<br />
così mi si pose il problema di cosa dir loro.<br />
Avrei potuto dire: «trova un amico che è in rete disposto a farti una copia». Oppure avrei potuto<br />
fare quel che feci con l’originario Emacs su PDP-10, e cioè dir loro: «spediscimi una busta
344 volume VIII Argomenti avanzati e accessori<br />
affrancata ed un nastro, ed io te lo rispedisco con sopra Emacs». Ma ero senza lavoro, e cercavo<br />
un modo di far soldi con il s<strong>of</strong>tware libero. E così feci sapere che avrei spedito un nastro a chi lo<br />
voleva per 150 dollari. In questo modo, creai un’impresa di distribuzione di s<strong>of</strong>tware libero, che<br />
anticipava le compagnie che oggi distribuiscono interi sistemi GNU basati su Linux.<br />
372.9 Un programma è libero per tutti?<br />
Se un programma è s<strong>of</strong>tware libero quando esce dalle mani del suo autore, non significa necessariamente<br />
che sarà s<strong>of</strong>tware libero per chiunque ne abbia una copia. Per esempio, il s<strong>of</strong>tware<br />
di pubblico dominio (s<strong>of</strong>tware senza copyright) è s<strong>of</strong>tware libero, ma chiunque può farne una<br />
versione modificata proprietaria. Analogamente, molti programmi liberi sono protetti da diritto<br />
d’autore, ma vengono distribuiti con semplici licenze permissive che permettono di farne versioni<br />
modificate proprietarie.<br />
L’esempio emblematico della questione è l’X Window System. Sviluppato al MIT, e pubblicato<br />
come s<strong>of</strong>tware libero con una licenza permissiva, fu rapidamente adottato da diverse società informatiche.<br />
Queste aggiunsero X ai loro sistemi Unix proprietari, solo in forma binaria, e coperto<br />
dello stesso accordo di non-diffusione. Queste copie di X non erano s<strong>of</strong>tware più libero di quanto<br />
lo fosse Unix.<br />
Gli autori dell’X Window System non ritenevano che questo fosse un problema, anzi se lo aspettavano<br />
ed era loro intenzione che accadesse. Il loro scopo non era la libertà, ma semplicemente<br />
il "successo", definito come "avere tanti utenti". Non erano interessati che questi utenti fossero<br />
liberi, ma solo che fossero numerosi.<br />
Questo sfociò in una situazione paradossale, in cui due modi diversi di misurare la quantità di<br />
libertà risultavano in risposte diverse alla domanda «questo programma è libero»? Giudicando<br />
sulla base della libertà <strong>of</strong>ferta dai termini distributivi usati dal MIT, si sarebbe dovuto dire che X<br />
era s<strong>of</strong>tware libero. Ma misurando la libertà dell’utente medio di X, si sarebbe dovuto dire che<br />
X era s<strong>of</strong>tware proprietario. La maggior parte degli utenti di X usavano le versioni proprietarie<br />
fornite con i sistemi Unix, non la versione libera.<br />
372.10 Il permesso d’autore (copyleft) e la GNU GPL<br />
Lo scopo di GNU consisteva nell’<strong>of</strong>frire libertà agli utenti, non solo nell’ottenere ampia diffusione.<br />
Avevamo quindi bisogno di termini di distribuzione che evitassero che il s<strong>of</strong>tware GNU fosse<br />
trasformato in s<strong>of</strong>tware proprietario. Il metodo che usammo si chiama "permesso d’autore".<br />
4<br />
Il permesso d’autore (copyleft) 5 usa le leggi sul diritto d’autore (copyright), ma le capovolge per<br />
ottenere lo scopo opposto: invece che un metodo per privatizzare il s<strong>of</strong>tware, diventa infatti un<br />
mezzo per mantenerlo libero.<br />
Il succo dell’idea di permesso d’autore consiste nel dare a chiunque il permesso di eseguire il programma,<br />
copiare il programma, modificare il programma, e distribuirne versioni modificate, ma<br />
senza dare il permesso di aggiungere restrizioni. In tal modo, le libertà essenziali che definiscono<br />
il "free s<strong>of</strong>tware" (s<strong>of</strong>tware libero) sono garantite a chiunque ne abbia una copia, e diventano<br />
diritti inalienabili.<br />
4 Nel 1984 o 1985, Don Hopkins, persona molto creativa, mi mandò una lettera. Sulla busta aveva scritto diverse<br />
frasi argute, fra cui questa: "Permesso d’autore--tutti i diritti rovesciati". Utilizzai l’espressione "permesso d’autore" per<br />
battezzare il concetto di distribuzione che allora andavo elaborando.<br />
5 [NdT: si tratta di un gioco di parole, che qui viene reso con "permesso di autore": copyright (diritto di autore) è<br />
formato dalle parola "copy" (copia) e "right" (diritto, ma anche destra), opposto di "left" (sinistra, ma anche lasciato).]
Il progetto GNU 345<br />
Perché un permesso d’autore sia efficace, anche le versioni modificate devono essere libere. Ciò<br />
assicura che ogni lavoro basato sul nostro sia reso disponibile per la nostra comunità, se pubblicato.<br />
Quando dei programmatori pr<strong>of</strong>essionisti lavorano su s<strong>of</strong>tware GNU come volontari, è<br />
il permesso d’autore che impedisce ai loro datori di lavoro di dire: «non puoi distribuire quei<br />
cambiamenti, perché abbiamo intenzione di usarli per creare la nostra versione proprietaria del<br />
programma».<br />
La clausola che i cambiamenti debbano essere liberi è essenziale se vogliamo garantire libertà<br />
a tutti gli utenti del programma. Le aziende che privatizzarono l’X Window System di solito<br />
avevano apportato qualche modifica per per portare il programma sui loro sistemi e sulle loro<br />
macchine. Si trattava di modifiche piccole rispetto alla mole di X, ma non banali. Se apportare<br />
modifiche fosse una scusa per negare libertà agli utenti, sarebbe facile per chiunque appr<strong>of</strong>ittare<br />
di questa scusa.<br />
Una problematica correlata è quella della combinazione di un programma libero con codice non<br />
libero. Una tale combinazione sarebbe inevitabilmente non libera; ogni libertà che manchi dalla<br />
parte non libera mancherebbe anche dall’intero programma. Permettere tali combinazioni aprirebbe<br />
non uno spiraglio, ma un buco grosso come una casa. Quindi un requisito essenziale per il<br />
permesso d’autore è tappare il buco: tutto ciò che venga aggiunto o combinato con un programma<br />
protetto da permesso d’autore dev’essere tale che il programma risultante sia anch’esso libero e<br />
protetto da permesso d’autore.<br />
La specifica implementazione di permesso d’autore che utilizziamo per la maggior parte del<br />
s<strong>of</strong>tware GNU è la GNU General Public License (licenza pubblica generica GNU), abbreviata in<br />
GNU GPL. Abbiamo altri tipi di permesso d’autore che sono utilizzati in circostanze specifiche.<br />
I manuali GNU sono anch’essi protetti da permesso d’autore, ma ne usano una versione molto<br />
più semplice, perché per i manuali non è necessaria la complessità della GPL.<br />
372.11 La Free S<strong>of</strong>tware Foundation<br />
Man mano che l’interesse per Emacs aumentava, altre persone parteciparono al progetto GNU,<br />
e decidemmo che era di nuovo ora di cercare finanziamenti. Così nel 1985 fondammo la Free<br />
S<strong>of</strong>tware Foundation (Fondazione per il s<strong>of</strong>tware libero), una organizzazione senza fini di lucro<br />
per lo sviluppo di s<strong>of</strong>tware libero. La FSF fra l’altro si prese carico della distribuzione dei nastri<br />
di Emacs; più tardi estese l’attività aggiungendo sul nastro altro s<strong>of</strong>tware libero (sia GNU che<br />
non GNU) e vendendo manuali liberi.<br />
La FSF accetta donazioni, ma gran parte delle sue entrate è sempre stata costituita dalle vendite:<br />
copie di s<strong>of</strong>tware libero e servizi correlati. Oggi vende CD-ROM di codice sorgente, CD-ROM<br />
di programmi compilati, manuali stampati pr<strong>of</strong>essionalmente (tutti con libertà di ridistribuzione<br />
e modifica), e distribuzioni Deluxe (nelle quali compiliamo l’intera scelta di s<strong>of</strong>tware per una<br />
piattaforma a richiesta).<br />
I dipendenti della Free S<strong>of</strong>tware Foundation hanno scritto e curato la manutenzione di diversi<br />
pacchetti GNU. Fra questi spiccano la libreria C e la shell. La libreria C di GNU è utilizzata da<br />
ogni programma che gira su sistemi GNU/Linux per comunicare con Linux. È stata sviluppata da<br />
un membro della squadra della Free S<strong>of</strong>tware Foundation, Roland McGrath. La shell usata sulla<br />
maggior parte dei sistemi GNU/Linux è Bash, la Bourne Again Shell 6 , che è stata sviluppata da<br />
Brian Fox, dipendente della FSF.<br />
6 "Bourne Again Shell" è un gioco di parole sul nome "Bourne Shell", che era la normale shell di Unix [NdT: "Bourne<br />
again" richiama l’espressione cristiana "born again", "rinato" (in Cristo)].
346 volume VIII Argomenti avanzati e accessori<br />
Finanziammo lo sviluppo di questi programmi perché il progetto GNU non riguardava solo strumenti<br />
di lavoro o un ambiente di sviluppo: il nostro obiettivo era un sistema operativo completo,<br />
e questi programmi erano necessari per raggiungere quell’obiettivo.<br />
372.12 Il supporto per il s<strong>of</strong>tware libero<br />
La filos<strong>of</strong>ia del s<strong>of</strong>tware libero rigetta una diffusa pratica commerciale in particolare, ma non<br />
è contro il commercio. Quando un’impresa rispetta la libertà dell’utente, c’è da augurarle ogni<br />
successo.<br />
La vendita di copie di Emacs esemplifica un modo di condurre affari col s<strong>of</strong>tware libero. Quando<br />
la FSF prese in carico quest’attività, dovetti trovare un’altra fonte di sostentamento. La trovai<br />
nella vendita di servizi relativi al s<strong>of</strong>tware libero che avevo sviluppato, come insegnare argomenti<br />
quali programmazione di Emacs e personalizzazione di GCC, oppure sviluppare s<strong>of</strong>tware,<br />
soprattutto adattamento di GCC a nuove architetture.<br />
Oggi tutte queste attività collegate al s<strong>of</strong>tware libero sono esercitate da svariate aziende. Alcune<br />
distribuiscono raccolte di s<strong>of</strong>tware libero su CD-ROM, altre <strong>of</strong>frono consulenza a diversi livelli,<br />
dall’aiutare gli utenti in difficoltà, alla correzione di errori, all’aggiunta di funzionalità non banali.<br />
Si cominciano anche a vedere aziende di s<strong>of</strong>tware che si fondano sul lancio di nuovi programmi<br />
liberi.<br />
Attenzione, però: diverse aziende che si fregiano del marchio "open source" (s<strong>of</strong>tware aperto) in<br />
realtà fondano le loro attività su s<strong>of</strong>tware non libero che funziona insieme con s<strong>of</strong>tware libero.<br />
Queste non sono aziende di s<strong>of</strong>tware libero, sono aziende di s<strong>of</strong>tware proprietario i cui prodotti<br />
attirano gli utenti lontano dalla libertà. Loro li chiamano "a valore aggiunto", il che riflette i valori<br />
che a loro farebbe comodo che adottassimo: la convenienza prima della libertà. Se noi riteniamo<br />
che la libertà abbia più valore, li dovremmo chiamare prodotti "a libertà sottratta".<br />
372.13 Obiettivi tecnici<br />
L’obiettivo principale di GNU era essere s<strong>of</strong>tware libero. Anche se GNU non avesse avuto alcun<br />
vantaggio tecnico su Unix, avrebbe avuto sia un vantaggio sociale, permettendo agli utenti di<br />
cooperare, sia un vantaggio etico, rispettando la loro libertà.<br />
Tuttavia risultò naturale applicare al lavoro le regole classiche di buona programmazione;<br />
per esempio, allocare le strutture dati dinamicamente per evitare limitazioni arbitrarie sulla<br />
dimensione dei dati, o gestire tutti i possibili codici a 8 bit in tutti i casi ragionevoli.<br />
Inoltre, al contrario di Unix che era pensato per piccole dimensioni di memoria, decidemmo di<br />
non supportare le macchine a 16 bit (era chiaro che le macchine a 32 bit sarebbero state la norma<br />
quando il sistema GNU sarebbe stato completo), e di non preoccuparci di ridurre l’occupazione<br />
di memoria a meno che eccedesse il megabyte. In programmi per i quali non era essenziale la<br />
gestione di file molto grandi, spingemmo i programmatori a leggere in memoria l’intero file di<br />
ingresso per poi analizzare il file senza doversi preoccupare delle operazioni di I/O.<br />
Queste decisioni fecero sì che molti programmi GNU superassero i loro equivalenti Unix sia in<br />
affidabilità che in velocità di esecuzione.
Il progetto GNU 347<br />
372.14 Donazioni di computer<br />
Man mano che la reputazione del progetto GNU andava crescendo, alcune persone iniziarono<br />
a donare macchine su cui girava Unix. Queste macchine erano molto utili, perché il modo più<br />
semplice di sviluppare componenti per GNU era di farlo su di un sistema Unix così da sostituire<br />
pezzo per pezzo i componenti di quel sistema. Ma queste macchine sollevavano anche una<br />
questione etica: se fosse giusto per noi anche solo possedere una copia di Unix.<br />
Unix era (ed è) s<strong>of</strong>tware proprietario, e la filos<strong>of</strong>ia del progetto GNU diceva che non avremmo<br />
dovuto usare s<strong>of</strong>tware proprietario. Ma, applicando lo stesso ragionamento per cui la violenza<br />
è ammessa per autodifesa, conclusi che fosse legittimo usare un pacchetto proprietario, se ciò<br />
fosse stato importante nel crearne un sostituto libero che permettesse ad altri di smettere di usare<br />
quello proprietario.<br />
Tuttavia, benchè fosse un male giustificabile, era pur sempre un male. Oggi non abbiamo più<br />
alcuna copia di Unix, perché le abbiamo sostituite con sistemi operativi liberi. Quando non fu<br />
possibile sostituire il sistema operativo di una macchina con uno libero, sostituimmo la macchina.<br />
372.15 L’elenco dei compiti GNU<br />
Mentre il progetto GNU avanzava, ed un numero sempre maggiore di componenti di sistema<br />
venivano trovati o sviluppati, diventò utile stilare un elenco delle parti ancora mancanti. Usammo<br />
questo elenco per ingaggiare programmatori che scrivessero tali parti, e l’elenco prese il nome<br />
di elenco dei compiti GNU. In aggiunta ai componenti Unix mancanti inserimmo nell’elenco<br />
svariati progetti utili di programmazione o di documentazione che a nostro parere non dovrebbero<br />
mancare in un sistema operativo veramente completo.<br />
Oggi non compare quasi nessun componente Unix nell’elenco dei compiti GNU; tutti questi<br />
lavori, a parte qualcuno non essenziale, sono già stati svolti. D’altro canto l’elenco è pieno di<br />
quei progetti che qualcuno chiamerebbe "applicazioni": ogni programma che interessi ad una<br />
fetta non trascurabile di utenti sarebbe un’utile aggiunta ad un sistema operativo.<br />
L’elenco comprende anche dei giochi, e così è stato fin dall’inizio: Unix comprendeva dei giochi,<br />
perciò era naturale che così fosse anche per GNU. Ma poiché non c’erano esigenze di compatibilità<br />
per i giochi, non ci attenemmo alla scelta di giochi presenti in Unix, preferendo piuttosto<br />
fornire un elenco di diversi tipi di giochi potenzialmente graditi agli utenti.<br />
372.16 La licenza GNU per le librerie<br />
La libreria C del sistema GNU utilizza un tipo speciale di permesso d’autore, la "Licenza Pubblica<br />
GNU per le Librerie" 7 , che permette l’uso della libreria da parte di s<strong>of</strong>tware proprietario.<br />
Perché quest’eccezione?<br />
Non si tratta di questioni di principio: non c’è nessun principio che dica che i prodotti s<strong>of</strong>tware<br />
proprietari abbiano il diritto di includere il nostro codice (perché contribuire ad un progetto<br />
fondato sul rifiuto di condividere con noi?). L’uso della licenza LGPL per la libreria C, o per<br />
qualsiasi altra libreria, è una questione di strategia.<br />
La libreria C svolge una funzione generica: ogni sistema operativo proprietario ed ogni compilatore<br />
includono una libreria C. Di conseguenza, rendere disponibile la nostra libreria C solo<br />
7 [NdT: nel 1999 la FSF ha cambiato nome alla licenza LGPL che ora si chiama "Lesser GPL", GPL attenuata, per<br />
non suggerire che si tratti della forma di licenza preferenziale per le librerie.]
348 volume VIII Argomenti avanzati e accessori<br />
per i programmi liberi non avrebbe dato nessun vantaggio a tali programmi liberi, avrebbe solo<br />
disincentivato l’uso della nostra libreria.<br />
C’è un’eccezione a questa situazione: sul sistema GNU (termine che include GNU/Linux) l’unica<br />
libreria C disponibile è quella GNU. Quindi i termini di distribuzione della nostra libreria C<br />
determinano se sia possibile o meno compilare un programma proprietario per il sistema GNU.<br />
Non ci sono ragioni etiche per permettere l’uso di applicazioni proprietarie sul sistema GNU, ma<br />
strategicamente sembra che impedirne l’uso servirebbe più a scoraggiare l’uso del sistema GNU<br />
che non a incoraggiare lo sviluppo di applicazioni libere.<br />
Ecco perché l’uso della licenza LGPL è una buona scelta strategica per la libreria C, mentre per<br />
le altre librerie la strategia va valutata caso per caso. Quando una libreria svolge una funzione<br />
particolare che può aiutare a scrivere certi tipi di programmi, distribuirla secondo la GPL, quindi<br />
limitandone l’uso ai soli programmi liberi, è un modo per aiutare gli altri autori di s<strong>of</strong>tware libero,<br />
dando loro un vantaggio nei confronti del s<strong>of</strong>tware proprietario.<br />
Prendiamo come esempio GNU-Readline, una libreria scritta per fornire a Bash la modificabilità<br />
della linea di comando: Readline è distribuita secondo la normale licenza GPL, non la LGPL. Ciò<br />
probabilmente riduce l’uso di Readline, ma questo non rappresenta una perdita per noi; d’altra<br />
parte almeno una applicazione utile è stata resa s<strong>of</strong>tware libero proprio al fine di usare Readline,<br />
e questo è un guadagno tangibile per la comunità.<br />
Chi sviluppa s<strong>of</strong>tware proprietario ha vantaggi economici, gli autori di programmi liberi hanno<br />
bisogno di avvantaggiarsi a vicenda. Spero che un giorno possiamo avere una grande raccolta di<br />
librerie coperte dalla licenza GPL senza che esista una raccolta equivalente per chi scrive s<strong>of</strong>tware<br />
proprietario. Tale libreria fornirebbe utili moduli da usare come i mattoni per costruire nuovi<br />
programmi liberi, e costituendo un sostanziale vantaggio per la scrittura di ulteriori programmi<br />
liberi.<br />
372.17 Togliersi il prurito?<br />
Eric Raymond afferma che «ogni buon programma nasce dall’iniziativa di un programmatore<br />
che si vuole togliere un suo personale prurito». È probabile che talvolta succeda così, ma molte<br />
parti essenziali del s<strong>of</strong>tware GNU sono state sviluppate al fine di completare un sistema operativo<br />
libero. Derivano quindi da una idea e da un progetto, non da una necessità contingente.<br />
Per esempio, abbiamo sviluppato la libreria C di GNU perché un sistema di tipo Unix ha bisogno<br />
di una libreria C, la Bourne-Again Shell (bash) perché un sistema di tipo Unix ha bisogno di una<br />
shell, e GNU tar perché un sistema di tipo Unix ha bisogno un programma tar. Lo stesso vale per<br />
i miei programmi: il compilatore GNU, GNU Emacs, GDB, GNU Make.<br />
Alcuni programmi GNU sono stati sviluppati per fronteggiare specifiche minacce alla nostra<br />
libertà: ecco perché abbiamo sviluppato gzip come sostituto per il programma Compress, che la<br />
comunità aveva perduto a causa dei brevetti sull’algoritmo LZW. Abbiamo trovato persone che<br />
sviluppassero LessTif, e più recentemente abbiamo dato vita ai progetti GNOME e Harmony per<br />
affrontare i problemi causati da alcune librerie proprietarie (come descritto più avanti). Stiamo<br />
sviluppando la GNU Privacy Guard per sostituire i diffusi programmi di crittografia non liberi,<br />
perché gli utenti non siano costretti a scegliere tra riservatezza e libertà.<br />
Naturalmente, i redattori di questi programmi sono coinvolti nel loro lavoro, e varie persone<br />
vi hanno aggiunto diverse funzionalità secondo le loro personali necessità ed i loro interessi.<br />
Tuttavia non è questa la ragione dell’esistenza di tali programmi.
Il progetto GNU 349<br />
372.18 Sviluppi inattesi<br />
All’inizio del progetto GNU pensavo che avremmo sviluppato l’intero sistema GNU e poi lo<br />
avremmo reso disponibile tutto insieme, ma le cose non andarono così.<br />
Poiché i componenti del sistema GNU sono stati implementati su un sistema Unix, ognuno di<br />
essi poteva girare su sistemi Unix molto prima che esistesse un sistema GNU completo. Alcuni<br />
di questi programmi divennero diffusi e gli utenti iniziarono ad estenderli e a renderli utilizzabili<br />
su nuovi sistemi: sulle varie versioni di Unix, incompatibili tra loro, e talvolta anche su altri<br />
sistemi.<br />
Questo processo rese tali programmi molto più potenti e attirò finanziamenti e collaboratori al<br />
progetto GNU; tuttavia probabilmente ritardò di alcuni anni la realizzazione di un sistema minimo<br />
funzionante, perché il tempo degli autori GNU veniva impiegato a curare la compatibilità di<br />
questi programmi con altri sistemi e ad aggiungere nuove funzionalità ai componenti esistenti,<br />
piuttosto che a proseguire nella scrittura di nuovi componenti.<br />
372.19 GNU-Hurd<br />
Nel 1990 il sistema GNU era quasi completo, l’unica parte significativa ancora mancante era il<br />
kernel. Avevamo deciso di implementare il nostro kernel come un gruppo di processi server che<br />
girassero sul sistema Mach. Mach è un microkernel sviluppato alla Carnegie Mellon University<br />
e successivamente all’Università dello Utah; GNU Hurd è un gruppo di server (o "herd <strong>of</strong> gnus":<br />
mandria di gnu) che gira su Mach svolgendo le funzioni del kernel Unix. L’inizio dello sviluppo<br />
fu ritardato nell’attesa che Mach fosse reso disponibile come s<strong>of</strong>tware libero, come era stato<br />
promesso.<br />
Una ragione di questa scelta progettuale fu di evitare quella che sembrava la parte più complessa<br />
del lavoro: effettuare il debugging del kernel senza un debugger a livello sorgente. Questo lavoro<br />
era già stato fatto, appunto in Mach, e avevamo previsto di effettuare il debugging dei server<br />
Hurd come programmi utente, con GDB. Ma questa fase si rivelò molto lunga, ed il debugging<br />
dei server multi-thread che si scambiano messaggi si è rivelato estremamente complesso. Per<br />
rendere Hurd robusto furono così necessari molti anni.<br />
372.20 Alix<br />
Originariamente il kernel GNU non avrebbe dovuto chiamarsi Hurd; il suo nome originale era<br />
Alix, come la donna di cui ero innamorato in quel periodo. Alix, che era amministratrice di<br />
sistemi Unix, aveva sottolineato come il suo nome corrispondesse ad un comune schema usato per<br />
battezzare le versioni del sistema Unix: scherzosamente diceva ai suoi amici: «qualcuno dovrebbe<br />
chiamare un kernel come me». Io non dissi nulla ma decisi di farle una sorpresa scrivendo un<br />
kernel chiamato Alix.<br />
Le cose non andarono così. Michael Bushnell (ora Thomas), principale autore del kernel, preferì<br />
il nome Hurd, e chiamò Alix una parte del kernel, quella che serviva a intercettare le chiamate di<br />
sistema e a gestirle inviando messaggi ai server che compongono HURD.<br />
Infine io e Alix ci lasciammo e lei cambiò nome; contemporaneamente la struttura di Hurd veniva<br />
cambiata in modo che la libreria C mandasse messaggi direttamente ai server, e così il componente<br />
Alix scomparve dal progetto. Prima che questo accadesse, però, un amico di Alix si accorse<br />
della presenza del suo nome nel codice sorgente di Hurd e glielo disse. Così il nome raggiunse il<br />
suo scopo.
350 volume VIII Argomenti avanzati e accessori<br />
372.21 Linux e GNU/Linux<br />
GNU Hurd non è pronto per un uso non sperimentale, ma per fortuna è disponibile un altro<br />
kernel: nel 1991 Linus Torvalds sviluppò un Kernel compatibile con Unix e lo chiamò Linux.<br />
Attorno al 1992, la combinazione di Linux con il sistema GNU ancora incompleto produsse un<br />
sistema operativo libero completo (naturalmente combinarli fu un notevole lavoro di per sé). È<br />
grazie a Linux che oggi possiamo utilizzare una versione del sistema GNU.<br />
Chiamiamo GNU/Linux questa versione del sistema, per indicare la sua composizione come una<br />
combinazione del sistema GNU col kernel Linux.<br />
372.22 Le sfide che ci aspettano<br />
Abbiamo dimostrato la nostra capacità di sviluppare un’ampia gamma di s<strong>of</strong>tware libero, ma<br />
questo non significa che siamo invincibili e inarrestabili. Diverse sfide rendono incerto il futuro<br />
del s<strong>of</strong>tware libero, e affrontarle richiederà perseveranza e sforzi costanti, talvolta per anni. Sarà<br />
necessaria quella determinazione che le persone sanno dimostrare quando danno valore alla<br />
propria libertà e non permettono a nessuno di sottrargliela. Le quattro sezioni seguenti parlano di<br />
queste sfide.<br />
372.23 Hardware segreto<br />
Sempre più spesso, i costruttori di hardware tendono a mantenere segrete le specifiche delle<br />
loro apparecchiature; questo rende difficile la scrittura di driver liberi che permettano a Linux e<br />
XFree86 di supportare nuove periferiche. Anche se oggi abbiamo sistemi completamente liberi,<br />
potremmo non averli domani se non saremo in grado di supportare i calcolatori di domani.<br />
Esistono due modi per affrontare il problema. Un programmatore può ricostruire le specifiche<br />
dell’hardware usando tecniche di reverse engineering. Oppure si può scegliere hardware supportato<br />
dai programmi liberi: man mano che il nostro numero aumenta, la segretezza delle specifiche<br />
diventerà una pratica controproducente.<br />
Il reverse engineering è difficile: avremo programmatori sufficientemente determinati da dedicarvisi?<br />
Sì, se avremo costruito una forte consapevolezza che avere programmi liberi sia una<br />
questione di principio e che i driver non liberi non sono accettabili. E succederà che molti di noi<br />
accettino di spendere un po’ di più o perdere un po’ più di tempo per poter usare driver liberi?<br />
Sì, se il desiderio di libertà e la determinazione ad ottenerla saranno diffusi.<br />
372.24 Librerie non libere<br />
Una libreria non libera che giri su sistemi operativi liberi funziona come una trappola per i creatori<br />
di programmi liberi. Le funzionalità attraenti della libreria fungono da esca; chi usa la libreria<br />
cade nella trappola, perché il programma che crea è inutile come parte di un sistema operativo<br />
libero (a rigore, il programma potrebbe esservi incluso, ma non funzionerebbe, visto che manca<br />
la libreria). Peggio ancora, se un programma che usa la libreria proprietaria diventa diffuso, può<br />
attirare altri ignari programmatori nella trappola.<br />
Il problema si concretizzò per la prima volta con la libreria Motif, negli anni ’80. Sebbene non<br />
ci fossero ancora sistemi operativi liberi, i problemi che Motif avrebbe causato loro erano già<br />
chiari. Il progetto GNU reagì in due modi: interessandosi presso diversi progetti di s<strong>of</strong>tware<br />
libero perché supportassero gli strumenti grafici X liberi in aggiunta a Motif, e cercando qualcuno
Il progetto GNU 351<br />
che scrivesse un sostituto libero di Motif. Il lavoro richiese molti anni: solo nel 1997 LessTif,<br />
sviluppato dagli "Hungry Programmers", divenne abbastanza potente da supportare la maggior<br />
parte delle applicazioni Motif.<br />
Tra il 1996 e il 1998 un’altra libreria non libera di strumenti grafici, chiamata Qt, veniva usata in<br />
una significativa raccolta di s<strong>of</strong>tware libero: l’ambiente grafico KDE.<br />
I sistemi liberi GNU/Linux non potevano usare KDE, perché non potevamo usare la libreria;<br />
tuttavia, alcuni distributori commerciali di sistemi GNU/Linux, non scrupolosi nell’attenersi solo<br />
ai programmi liberi, aggiunsero KDE ai loro sistemi, ottenendo così sistemi che <strong>of</strong>frivano più<br />
funzionalità, ma meno libertà. Il gruppo che sviluppava KDE incoraggiava esplicitamente altri<br />
programmatori ad usare Qt, e milioni di nuovi "utenti Linux" non sospettavano minimamente che<br />
questo potesse costituire un problema. La situazione si faceva pericolosa.<br />
La comunità del s<strong>of</strong>tware libero affrontò il problema in due modi: GNOME e Harmony.<br />
GNOME (GNU Network Object Model Environment, modello di ambiente per oggetti di rete)<br />
è il progetto GNU per l’ambiente grafico (desktop). Intrapreso nel 1997 da Miguel de Icaza e<br />
sviluppato con il supporto di Red Hat S<strong>of</strong>tware, GNOME si ripromise di fornire funzionalità<br />
grafiche simili a quelle di KDE, ma usando esclusivamente s<strong>of</strong>tware libero. GNOME <strong>of</strong>fre anche<br />
dei vantaggi tecnici, come il supporto per svariati linguaggi di programmazione, non solo il C++.<br />
Ma il suo scopo principale era la libertà: non richiedere l’uso di alcun programma che non fosse<br />
libero.<br />
Harmony è una libreria compatibile con Qt, progettata per rendere possibile l’uso del s<strong>of</strong>tware<br />
KDE senza dover usare Qt.<br />
Nel novembre 1998 gli autori di Qt annunciarono un cambiamento di licenza che, una volta<br />
operativo, avrebbe reso Qt s<strong>of</strong>tware libero. Non c’è modo di esserne certi, ma credo che questo<br />
fu in parte dovuto alla decisa risposta della comunità al problema posto da Qt quando non era<br />
libero (la nuova licenza è scomoda ed iniqua, per cui rimane comunque preferibile evitare l’uso<br />
di Qt).<br />
Come risponderemo alla prossima allettante libreria non libera? Riuscirà la comunità in toto a<br />
comprendere l’importanza di evitare la trappola? Oppure molti di noi preferiranno la convenienza<br />
alla libertà, creando così ancora un grave problema? Il nostro futuro dipende dalla nostra filos<strong>of</strong>ia.<br />
372.25 Brevetti sul s<strong>of</strong>tware<br />
Il maggior pericolo a cui ci troviamo di fronte è quello dei brevetti sul s<strong>of</strong>tware, che possono<br />
rendere inaccessibili al s<strong>of</strong>tware libero algoritmi e funzionalità per un tempo che può estendersi<br />
fino a vent’anni. I brevetti sugli algoritmi di compressione LZW furono depositati nel 1983, e<br />
ancor oggi non possiamo distribuire programmi liberi che producano immagini GIF compresse.<br />
Nel 1998 un programma libero per produrre audio compresso MP3 venne ritirato sotto minaccia<br />
di una causa per violazione di brevetto.<br />
Ci sono modi per affrontare la questione brevetti: possiamo cercare prove che un brevetto non sia<br />
valido oppure possiamo cercare modi alternativi per ottenere lo stesso risultato. Ognuna di queste<br />
tecniche, però, funziona solo in certe circostanze; quando entrambe falliscono un brevetto può<br />
obbligare tutto il s<strong>of</strong>tware libero a rinunciare a qualche funzionalità che gli utenti desiderano.<br />
Cosa dobbiamo fare quando ciò accade?<br />
Chi fra noi apprezza il s<strong>of</strong>tware libero per il valore della libertà rimarrà comunque dalla parte dei<br />
programmi liberi; saremo in grado di svolgere il nostro lavoro senza le funzionalità coperte da<br />
brevetto. Ma coloro che apprezzano il s<strong>of</strong>tware libero perché si aspettano che sia tecnicamente
352 volume VIII Argomenti avanzati e accessori<br />
superiore probabilmente grideranno al fallimento quando un brevetto ne impedisce lo sviluppo.<br />
Perciò, nonostante sia utile parlare dell’efficacia pratica del modello di sviluppo "a cattedrale",<br />
e dell’affidabilità e della potenza di un dato programma libero, non ci dobbiamo fermare qui;<br />
dobbiamo parlare di libertà e di principi.<br />
372.26 Documentazione libera<br />
La più grande carenza nei nostri sistemi operativi liberi non è nel s<strong>of</strong>tware, quanto nella carenza<br />
di buoni manuali liberi da includere nei nostri sistemi. La documentazione è una parte<br />
essenziale di qualunque pacchetto s<strong>of</strong>tware; quando un importante pacchetto s<strong>of</strong>tware libero non<br />
viene accompagnato da un buon manuale libero si tratta di una grossa lacuna. E di queste lacune<br />
attualmente ne abbiamo molte.<br />
La documentazione libera, come il s<strong>of</strong>tware libero, è una questione di libertà, non di prezzo. Il<br />
criterio per definire libero un manuale è fondamentalmente lo stesso che per definire libero un<br />
programma: si tratta di <strong>of</strong>frire certe libertà a tutti gli utenti. Deve essere permessa la redistribuzione<br />
(compresa la vendita commerciale), sia in formato elettronico che cartaceo, in modo che il<br />
manuale possa accompagnare ogni copia del programma.<br />
Autorizzare la modifica è anch’esso un aspetto cruciale; in generale, non credo sia essenziale<br />
permettere alle persone di modificare articoli e libri di qualsiasi tipo. Per esempio, non credo che<br />
voi o io dobbiamo sentirci in dovere di autorizzare la modifica di articoli come questo, articoli<br />
che descrivono le nostre azioni e il nostro punto di vista.<br />
Ma c’è una ragione particolare per cui la libertà di modifica è cruciale per la documentazione<br />
dei programmi liberi. Quando qualcuno esercita il proprio diritto di modificare il programma,<br />
aumentandone o alterandone le funzionalità, se è coscienzioso modificherà anche il manuale,<br />
in modo da poter fornire una documentazione utile e accurata insieme al programma modificato.<br />
Un manuale che non permetta ai programmatori di essere coscienziosi e completare il loro lavoro<br />
non soddisfa i bisogni della nostra comunità.<br />
Alcuni limiti sulla modificabilità non pongono alcun problema; per esempio, le richieste di conservare<br />
la nota di copyright dell’autore originale, i termini di distribuzione e la lista degli autori<br />
vanno bene. Non ci sono problemi nemmeno nel richiedere che le versioni modificate dichiarino<br />
esplicitamente di essere tali, così pure che intere sezioni non possano essere rimosse o modificate,<br />
finché queste sezioni vertono su questioni non tecniche. Restrizioni di questo tipo non creano<br />
problemi perché non impediscono al programmatore coscienzioso di adattare il manuale perché<br />
rispecchi il programma modificato. In altre parole, non impediscono alla comunità del s<strong>of</strong>tware<br />
libero di beneficiare appieno dal manuale.<br />
D’altro canto, deve essere possibile modificare tutto il contenuto tecnico del manuale e poter<br />
distribuire il risultato in tutti i formati usuali, attraverso tutti i normali canali di distribuzione;<br />
diversamente, le restrizioni creerebbero un ostacolo per la comunità, il manuale non sarebbe<br />
libero e avremmo bisogno di un altro manuale.<br />
Gli sviluppatori di s<strong>of</strong>tware libero avranno la consapevolezza e la determinazione necessarie a<br />
produrre un’intera gamma di manuali liberi? Ancora una volta, il nostro futuro dipende dalla<br />
nostra filos<strong>of</strong>ia.
Il progetto GNU 353<br />
372.27 Dobbiamo parlare di libertà<br />
Stime recenti valutano in dieci milioni il numero di utenti di sistemi GNU/Linux quali Debian<br />
GNU/Linux e Red Hat Linux. Il s<strong>of</strong>tware libero ha creato tali vantaggi pratici che gli utenti<br />
stanno approdando ad esso per pure ragioni pratiche.<br />
Gli effetti positivi di questa situazione sono evidenti: maggior interesse a sviluppare s<strong>of</strong>tware<br />
libero, più clienti per le imprese di s<strong>of</strong>tware libero e una migliore capacità di incoraggiare le<br />
aziende a sviluppare s<strong>of</strong>tware commerciale libero invece che prodotti s<strong>of</strong>tware proprietari.<br />
L’interesse per il s<strong>of</strong>tware, però, sta crescendo più in fretta della coscienza della filos<strong>of</strong>ia su cui è<br />
basato, e questa disparità causa problemi. La nostra capacità di fronteggiare le sfide e le minacce<br />
descritte in precedenza dipende dalla determinazione nell’essere impegnati per la libertà. Per<br />
essere sicuri che la nostra comunità abbia tale determinazione, dobbiamo diffondere l’idea presso<br />
i nuovi utenti man mano che entrano a far parte della comunità.<br />
Ma in questo stiamo fallendo: gli sforzi per attrarre nuovi utenti nella comunità sono di gran lunga<br />
maggiori degli sforzi per l’educazione civica della comunità stessa. Dobbiamo fare entrambe le<br />
cose, e dobbiamo mantenere un equilibrio fra i due impegni.<br />
372.28 "Open Source"<br />
Parlare di libertà ai nuovi utenti è diventato più difficile dal 1998, quando una parte della<br />
comunità decise di smettere di usare il termine "free s<strong>of</strong>tware" e usare al suo posto "open source".<br />
Alcune delle persone che suggerirono questo termine intendevano evitare che si confondesse<br />
"free" con "gratis", un valido obiettivo. D’altra parte, altre persone intendevano mettere da parte<br />
lo spirito del principio che aveva dato la spinta al movimento del s<strong>of</strong>tware libero e al progetto<br />
GNU, puntando invece ad attrarre i dirigenti e gli utenti commerciali, molti dei quali afferiscono<br />
ad una ideologia che pone il pr<strong>of</strong>itto al di sopra della libertà, della comunità, dei principi. Perciò la<br />
retorica di "open source" si focalizza sul possibilità di creare s<strong>of</strong>tware di buona qualità e potente<br />
ma evita deliberatamente le idee di libertà, comunità, principio.<br />
Le riviste che si chiamano "Linux..." sono un chiaro esempio di ciò: sono piene di pubblicità di<br />
s<strong>of</strong>tware proprietario che gira sotto GNU/Linux; quando ci sarà il prossimo Motif o Qt, queste<br />
riviste avvertiranno i programmatori di starne lontano o accetteranno la sua pubblicità?<br />
L’appoggio delle aziende può contribuire alla comunità in molti modi; a parità di tutto il resto è<br />
una cosa utile. Ma ottenere questo appoggio parlando ancor meno di libertà e principi può essere<br />
disastroso; rende ancora peggiore lo sbilanciamento descritto tra diffusione ed educazione civica.<br />
"S<strong>of</strong>tware libero" (free s<strong>of</strong>tware) e "sorgente aperto" (open source) descrivono più o meno la<br />
stessa categoria di s<strong>of</strong>tware, ma dicono cose differenti sul s<strong>of</strong>tware e sui valori. Il progetto GNU<br />
continua ad usare il termine "s<strong>of</strong>tware libero" per esprimere l’idea che la libertà sia importante,<br />
non solo la tecnologia.<br />
372.29 Prova!<br />
La filos<strong>of</strong>ia di Yoda ("Non c’è provare") suona bene, ma per me non funziona. Ho fatto la maggior<br />
parte del mio lavoro angustiato dal timore di non essere in grado di svolgere il mio compito e nel<br />
dubbio, se fossi riuscito, che non fosse sufficiente per raggiungere l’obiettivo. Ma ci ho provato<br />
in ogni caso perché nessuno tranne me si poneva tra il nemico e la mia città. Sorprendendo me<br />
stesso, qualche volta sono riuscito.
354 volume VIII Argomenti avanzati e accessori<br />
A volte ho fallito, alcune delle mie città sono cadute; poi ho trovato un’altra città minacciata e<br />
mi sono preparato ad un’altra battaglia. Con l’andar del tempo ho imparato a cercare le possibili<br />
minacce e a mettermi tra loro e la mia città, facendo appello ad altri hacker perché venissero e si<br />
unissero a me.<br />
Oggigiorno spesso non sono da solo. È un sollievo ed una gioia quando vedo un reggimento di<br />
hacker che scavano trincee per difendere il confine e quando mi rendo conto che questa città<br />
può sopravvivere; per ora. Ma i pericoli diventano più grandi ogni anno, ed ora Micros<strong>of</strong>t ha<br />
esplicitamente preso di mira la nostra comunità. Non possiamo dare per scontato il futuro della<br />
libertà; non diamolo per scontato! Se volete mantenere la vostra libertà dovete essere pronti a<br />
difenderla.
Capitolo 373<br />
La rivoluzione del Mimete, ovvero s<strong>of</strong>tware e<br />
copyright<br />
di Giulio Mazzolini giuliomazzolini @ libero.it<br />
non modificabile<br />
Lo scrittore Primo Levi immaginò un particolare tipo di duplicatore, chiamato Mimete, capace<br />
di duplicare un oggetto esattamente come l’originale. Da una parte si poteva inserire un foglio<br />
protocollo con i bolli, dall’altra usciva un foglio protocollo identico all’originale con su dei bolli<br />
veri, un clone perfetto. Il protagonista prova quindi a duplicare vari oggetti, dapprima una banconota,<br />
poi un diamante, poi ancora una salamandra, riuscendoci felicemente. Alla fine duplicò<br />
la moglie e poi, stanco di avere due mogli, duplicò se stesso, per riformare due coppie uguali...<br />
Ci sono delle macchine per fotocopie che fanno delle copie «quasi» uguali all’originale, ma non<br />
perfettamente uguali, se continuiamo a fare una copia dall’ultima copia, la qualità degraderà più<br />
o meno velocemente in funzione della qualità della macchina. Quindi non è un Mimete.<br />
Eppure la fantasia dello scrittore ha visto giusto, esiste un Mimete e molti di voi l’hanno in casa.<br />
Non duplica tutto, ma duplica perfettamente il s<strong>of</strong>tware. La copia di un dischetto è esattamente<br />
uguale all’originale, non c’è modo di capire quale è l’originale e quale la copia, posso fare quante<br />
copie voglio, l’ultima copia sarà esattamente uguale all’originale. Il vostro PC è un Mimete<br />
limitato al s<strong>of</strong>tware e la sua capacità di duplicazione è un fatto assolutamente rivoluzionario.<br />
Non solo è possibile duplicare, ma costa poco e lo possono fare tutti.<br />
Si tratta di una rivoluzione importante, che mi piace chiamare «La rivoluzione del Mimete» in<br />
onore di Primo Levi.<br />
373.1 Che cosa è il s<strong>of</strong>tware?<br />
Il s<strong>of</strong>tware non è altro che una ricetta, un qualcosa di immateriale che congiungendosi a qualcosa<br />
di materiale, l’hardware, trasfigura la materia informe facendola diventare qualcosa di ordinato e<br />
utilizzabile.<br />
Dire che il s<strong>of</strong>tware sia un’opera d’autore assimilabile a un’opera letteraria è sicuramente forzato,<br />
inoltre la legislazione corrente che protegge il s<strong>of</strong>tware è molto più severa di quella per esempio<br />
che protegge i libri.<br />
Un libro posso leggerlo così com’è, ne godo direttamente, non devo metterlo in una macchina<br />
per goderne. Un libro posso imprestarlo a un amico, in ufficio posso tenere una sola copia del<br />
«Manuale dell’ingegnere» anche se ci sono dieci ingegneri che lo usano. Esistono biblioteche<br />
pubbliche dove posso prendere in prestito un libro e leggerlo, quindi «usarlo» completamente<br />
per quello che è stato fatto, con poca spesa.<br />
È vero che gli editori che fanno libri per la scuola si lamentano del fenomeno delle fotocopie, in<br />
Francia si è trovata una soluzione che prevede il versamento da parte delle scuole di un tantum<br />
a un fondo che risarcisce autori ed editori. Non so se sia il sistema migliore, ma sicuramente<br />
prende atto della facilità di copiare e cerca una soluzione non poliziesca.<br />
355
356 volume VIII Argomenti avanzati e accessori<br />
373.2 Cenni di storia del s<strong>of</strong>tware<br />
La prima macchina che si considera essere un calcolatore digitale moderno è l’ENIAC, costruito<br />
nei laboratori della Moore School <strong>of</strong> Electrical Engineering dell’Università della Pensilvania,<br />
agli inizi degli anni 1940. Iniziò a lavorare nel 1946, venne spento nel 1955. Vale la pena di<br />
accennare all’architettura della macchina: 18000 valvole, memoria a flip-flop, quindi ancora a<br />
valvole, 20 parole di memoria.<br />
Usa un sistema digitale e non più analogico, ma non ancora il sistema binario. La macchina<br />
seguente, progettata da Von Neumann mentre l’ENIAC era in fase di realizzazione, usa ancora<br />
valvole, ma per la memoria usa una linea di ritardo acustica a mercurio, ed è una delle prime a<br />
usare il codice binario, propugnato appunto da Von Neumann ed ha un’architettura che sarà poi<br />
seguita da quasi tutte le macchine seguenti. La macchina di Von Neumann entra in operatività<br />
nel 1950.<br />
Entrambe le macchine furono costruite su iniziativa dell’Esercito Americano e furono usate per<br />
fare calcoli balistici, le usò anche Fermi per i laboratori di Los Alamos. Infatti i calcolatori<br />
precedenti a relè elettromeccanici erano molto più lenti, circa un secondo per una moltiplicazione,<br />
mentre l’ENIAC impiegava circa un millisecondo.<br />
In quegli anni i dati venivano inseriti tramite schede perforate, i programmi venivano scritti in<br />
linguaggio mnemonico e poi tradotti da umani in codice binario. Solo nel 1949 si iniziò a tradurre<br />
il codice mnemonico in binario con uno speciale s<strong>of</strong>tware di traduzione.<br />
Il primo vero linguaggio per calcolatori fu il Fortran, che iniziato nel 1954 e ultimato nel 1957,<br />
divenne il linguaggio più diffuso al mondo.<br />
I calcolatori conobbero una prima rivoluzione con l’introduzione dei transistor, nel 1956 infatti<br />
appare il TX-0, una macchina molto più piccola, che non usava schede per l’input ma la flexowriter,<br />
un perforatore di nastro cartaceo che molti di voi avranno visto sui telex in uso fino a qualche<br />
anno fa.<br />
La seconda rivoluzione delle macchine è l’introduzione dei circuiti integrati, 1961. Le macchine<br />
diventano ancora più piccole e potenti, la memoria aumenta e la velocità di calcolo pure.<br />
Nel 1959 John McCarty, padre dell’intelligenza artificiale, inizia a scrivere il linguaggio LISP,<br />
nel 1961 arriva al MIT il PDP-1, una macchina con schermo ma con input ancora a nastro,<br />
prototipo di una lunga serie di macchine PDP che assomigliano sempre di più ai calcolatori<br />
moderni. Nei primi anni 1960 John Kemeny scrive il Basic, nello stesso periodo l’agenzia ARPA<br />
(Advanced Research Project Agency) dell’Esercito USA inizia a finanziare progetti di ricerca sui<br />
calcolatori.<br />
Siamo ancora nella preistoria del s<strong>of</strong>tware, ci sono pochi programmi o non ce ne sono affatto, i<br />
ricercatori si scrivono i codici di cui hanno bisogno e se lo passano liberamente senza problemi.<br />
Le macchine vengono vendute con un po’ di s<strong>of</strong>tware come fosse un set di istruzioni per l’uso.<br />
Ogni anno segna un progresso importante, nel 1967, appare il primo floppy disk, nel 1969 inizia<br />
lo sviluppo di UNIX nel laboratori Bell di AT&T, nel 1970 Intel, con la collaborazione di<br />
Federico Faggin, produce il 4004.<br />
Se vogliamo dare una data alla fine del periodo iniziale questa potrebbe essere il 1968, per il nuovo<br />
atteggiamento dell’opinione pubblica e in particolare degli studenti che vedono con sospetto<br />
le ricerche fatte al MIT con i finanziamenti dell’Esercito, che culmina con l’assalto ai laboratori.<br />
In quel periodo nasce e si sviluppa un movimento per portare il computer al popolo, di cui un<br />
protagonista è stato Lee Feldestain.
La rivoluzione del Mimete, ovvero s<strong>of</strong>tware e copyright 357<br />
L’IBM, pressata dagli ambienti antimonopolisti, decise una mossa che voleva dimostrare come<br />
essa monopolista non fosse: scorporò il prezzo delle macchine, l’hardware, da quello del<br />
s<strong>of</strong>tware, il famoso «unbundling», dando così spazio a potenziali concorrenti nel settore del<br />
s<strong>of</strong>tware.<br />
Gli anni seguenti sono di grande fermento, nasce il primo PC, una macchina venduta in kit che si<br />
chiamava Altair. Molti di voi l’avranno vista nel film «War Games», era una scatola con dentro<br />
un microprocessore, sul fronte delle levette per l’input e delle lucine per l’output! Costava 300 $<br />
e aveva 256 byte di memoria. Non serviva praticamente a niente, eppure ebbe un grandissimo<br />
successo, portava finalmente in casa di tutti un computer, quello che Lee Feldstein e i suoi amici<br />
predicavano da tempo.<br />
Poi ancora una accelerazione incredibile: nel 1976 appare il Sol, progettato da Lee e nel 1977<br />
l’Apple. Nel 1974 Brian Kernighan e Dennis Ritchie sviluppano il linguaggio C.<br />
Il 1976 segna la nascita del s<strong>of</strong>tware proprietario e dei principi che ci stanno dietro. Infatti assieme<br />
all’Altair si poteva comperare una versione del Basic, a circa 150 $. L’autore del programma<br />
che chiedeva un prezzo così esoso era Bill Gates.<br />
A causa del prezzo elevato qualcuno fece delle copie del programma (allora i programmi stavano<br />
su nastro perforato), Gates molto irritato, scrisse una storica lettera sui giornali letti allora dagli<br />
hacker, nella quale lamentava il fatto che si copiasse senza pagare e che questo fatto avrebbe<br />
ostacolato che del buon s<strong>of</strong>tware venisse scritto.<br />
Chi può affrontare di fare del lavoro pr<strong>of</strong>essionale per nulla? Quale hobbista può<br />
mettere tre anni di tempo-uomo nella programmazione, trovare tutti i bug, documentare<br />
il suo prodotto, il tutto gratuitamente?... Francamente, la cosa che voi fate è<br />
rubare.<br />
1<br />
Argomentazioni sulle quali Bill ha costruito i suo impero, certamente con buona parte di verità ma<br />
che non tengono conto che già allora esisteva un Mimete con il quale si poteva copiare facilmente,<br />
velocemente e a basso costo.<br />
Sul Doctor Dobbs Journal, Jim Warren scriveva:<br />
Quando sarà gratis o così poco costoso che sarà più facile pagarlo che duplicarlo,<br />
non verrà più rubato<br />
Tim Pittman scrisse allora un Tiny Basic e lo mise in vendita a 5 $! Lo fa teorizzando che il<br />
s<strong>of</strong>tware deve essere disponibile per tutti e che quindi deve costare il meno possibile.<br />
Oggi questo discorso è stato ripreso dal mondo del s<strong>of</strong>tware libero, con ben maggior<br />
consapevolezza e forza.<br />
1 Bill Gates, lettera aperta sulla pirateria, apparsa sul bollettino dell’Homebrew Computer Club, il 03/02/1976.
Il copyright/diritto d’autore del s<strong>of</strong>tware<br />
di Giulio Mazzolini giuliomazzolini @ libero.it<br />
Capitolo 374<br />
non modificabile<br />
Fino a circa la fine degli anni 1980, il s<strong>of</strong>tware veniva ceduto assieme alla macchina o veniva<br />
scritto su richiesta dei clienti. Se c’erano dei pacchetti pronti, questi dovevano venir personalizzati<br />
per ogni utente. È solo con la nascita del PC IBM, 1981, quando il computer si diffonde in<br />
milioni di pezzi che nasce una richiesta di massa di s<strong>of</strong>tware.<br />
Su come proteggere i diritti dell’autore del programma s<strong>of</strong>tware esisteva un dibattito teorico sin<br />
da una decina d’ anni. In Francia nel 1968, una legge dichiarava il s<strong>of</strong>tware non brevettabile.<br />
Negli USA, con approccio più pragmatico, semplicemente il s<strong>of</strong>tware non veniva brevettato in<br />
quanto l’ufficio brevetti non aveva la più pallida idea di come si potesse brevettare un programma<br />
s<strong>of</strong>tware. Il problema esiste tuttora, essendo quasi impossibile riconoscere se un s<strong>of</strong>tware in<br />
qualche modo lede i diritti brevettuali di un altro.<br />
Oggi tuttavia si brevettano gli algoritmi, una assurdità totale, che però sull’onda del successo<br />
del concetto di «proprietà intellettuale», riesce a venir accettata dai legislatori e dall’opinione<br />
comune.<br />
Sarebbe come se oggi la tabellina del nove o i logaritmi fossero brevettati e doveste pagare per<br />
usarli.<br />
Nel 1980, su pressione dei produttori di s<strong>of</strong>tware, il governo americano promulgò il Copyright<br />
Act con il quale si riconosceva al s<strong>of</strong>tware lo stesso tipo di protezione accordata sino ad allora ai<br />
testi letterari o alle altre forme d’opere d’arte.<br />
Non sfuggiva ai legislatori l’effetto «Mimete», ma venne semplicemente risolto vietando severamente<br />
ogni forma di duplicazione del s<strong>of</strong>tware. Tanto era rigida la legge che un po’ dopo<br />
dovettero chiarire che la duplicazione per uso di «back-up» era lecita!<br />
Senza entrare nei dettagli, voglio solo far notare con l’ultima legge anti pirateria italiana, la copia<br />
illecita di s<strong>of</strong>tware è punita con reclusione da tre mesi a tre anni, come mi ha ricordato vigorosamente<br />
un immenso cartellone a Malpensa: ci vogliono 3 minuti per copiare un programma ma ti<br />
può costare 3 anni...<br />
374.1 Una breve storia del diritto d’autore<br />
L’idea del copyright e la legislazione relativa nasce dopo l’invenzione della macchina da stampa<br />
di Gutemberg (1400-1468). L’idea era semplice: stampare un libro costa, quindi se lo stampo io<br />
non deve poterlo stampare un altro.<br />
La legislazione originale quindi proteggeva gli interessi degli stampatori, l’autore non veniva<br />
preso in considerazione, anche perché spesso poi i libri contenevano testi di antichi scrittori<br />
morti da secoli. Il libro più stampato infatti era la Bibbia.<br />
Il monopolio librario relegava gli autori in una posizione palesemente subalterna o inesistente.<br />
Dal 1709 (data che segna la nascita del diritto positivo del copyright) fino al 1774, la proprietà<br />
letteraria dell’autore fu affermata a beneficio degli editori più che degli autori.<br />
Solo nel 1777 gli Editti che precedono la Rivoluzione Francese, riconoscono il diritto d’autore,<br />
nasce allora la concezione moderna della tutela dell’autore. Il diritto d’autore è la proprietà più<br />
sacra in quanto si considera «inscindibile l’oggetto dal soggetto».<br />
358
Il copyright/diritto d’autore del s<strong>of</strong>tware 359<br />
Si riconosce finalmente la figura dell’autore e se ne tutelano i suoi diritti. L’autore dell’opera<br />
possiede tutti i diritti per il semplice fatto di esserne l’autore. Può poi cedere alcuni o tutti i diritti<br />
a terzi con un patto esplicito. Se si tratta di un testo, in genere i diritti sono quelli di riprodurre il<br />
testo in un libro, eventualmente di farne delle traduzione e ancora delle ristampe. Se l’opera è un<br />
quadro, l’ autore può cedere il diritto di copia dell’opera, per esempio per farne una copertina, o<br />
un manifesto.<br />
Un autore può tutelare la sua opera anche se ha ceduto i diritti di riproduzione. Può esigere che<br />
l’opera resti integra, o che non subisca modificazioni. Hanno quindi ragione quei registi che<br />
pretendono che il loro film passi senza interruzioni pubblicitarie, o che rifiutano che vengano<br />
tagliati (o censurati) in alcune scene.<br />
In via generale se comperate un quadro, con il possesso e la proprietà legittima dello stesso, non<br />
avete automaticamente il diritto di riprodurlo.<br />
I diritti d’autore sono ereditari, per cui gli eredi potranno godere dei vantaggi economici derivanti<br />
dai diritti d’autore anche dopo la morte dell’autore.<br />
Le multinazionali (americane) del cinema, della musica e del s<strong>of</strong>tware sono riuscite a ottenere il<br />
prolungamento della durata dei diritti d’autore fino a 70 anni dopo la morte.<br />
Quando il legislatore dice «autore» intende «di opera artistica». Negli USA il concetto di copyright<br />
tende a venir esteso anche in mancanza di un’opera d’arte. Persino una lettera commerciale<br />
è stata considerata soggetta a copyright.<br />
Negli USA è oramai prassi brevettare anche il s<strong>of</strong>tware, non programmi interi, ma pezzi particolari.<br />
È brevettato il cestino dell’Apple, l’algoritmo di compressione usato dal programma Zip,<br />
l’XOR del puntatore grafico. La Micros<strong>of</strong>t deposita migliaia di brevetti e così pure le altre grandi<br />
case.<br />
Oggi nessuno può seriamente pensare di scrivere del s<strong>of</strong>tware commerciale se non ha capitali<br />
molto grandi. Infatti deve utilizzare schiere di avvocati a tempo pieno per assistere chi scrive,<br />
affinché non incorra in infrazioni di brevetti o di copyright. Poiché è impossibile che uno studio<br />
di avvocati conosca tutti i brevetti di s<strong>of</strong>tware, c’è la quasi certezza di incappare in qualche azione<br />
legale. Cause che costano molto o si chiudono con costosi accordi.<br />
Avevamo detto che la legislazione USA ha assimilato il s<strong>of</strong>tware a una opera d’autore e quindi<br />
ha utilizzato il corpo legislativo del copyright per proteggerlo.<br />
374.2 I sei punti della rivoluzione digitale<br />
L’avvocato Pamela Samuelson ha così voluto riassumere i sei punti principali della rivoluzione<br />
digitale:<br />
1. È molto facile duplicare, si fa presto, costa poco, le copie sono dei duplicati<br />
perfetti dell’originale.<br />
2. È facilissimo trasmettere i dati e si trasmettono quasi istantaneamente,<br />
si trasmettono in tutto il mondo scavalcando barriere nazionali, doganali,<br />
censorie.<br />
3. Il dato digitale è malleabile, si può trasformare quanto si vuole, si può deformare<br />
quanto si vuole, un originale ne diventa facilmente un altro deformato o<br />
rielaborato.<br />
4. Le opere letterarie, sonore, grafiche, una volta messe in forma digitale, subiscono<br />
la stessa sorte, sono indistinguibili nel supporto, non sono più differenziate
360 volume VIII Argomenti avanzati e accessori<br />
tra libro, quadro e disco, mettendo in crisi i concetti di copyright che sono diversi<br />
se si tratta di quadro disco o libro.<br />
5. Il dato digitale è compatto, è piccolo si trasporta facilmente.<br />
6. Il dato digitale non si visita più linearmente come si fa con un libro, ma in modo<br />
non lineare. Tutti coloro che hanno visitato un sito in Internet non hanno letto<br />
pagina dopo pagina, ma sono saltati da una pagina a un altro sito, creandosi<br />
percorsi individuali.<br />
Ciascuna delle caratteristiche precedenti è sufficiente a causare una rottura delle dottrine<br />
esistenti sulla proprietà intellettuale. Tutte e sei assieme sicuramente costringeranno<br />
i legislatori a una modifica radicale del concetto di copyright e di proprietà<br />
intellettuale.<br />
374.3 I vantaggi del «free s<strong>of</strong>tware»<br />
Le sei caratteristiche citate da Pamela Samuelson riguardano in generale tutti gli aspetti del digitale,<br />
per quanto riguarda in particolare il s<strong>of</strong>tware, invece questi sono gli argomenti principali a<br />
favore del s<strong>of</strong>tware libero.<br />
1. La diffusione del sapere funziona se l’informazione circola: Jefferson ha detto che se alla<br />
luce di una candela studiano due persone, il sapere dell’umanità aumenta, senza che per<br />
questo si consumino più candele.<br />
2. Le limitazioni imposte dai «privilegi» del copyright e dei brevetti impediscono lo sviluppo<br />
tecnologico e scientifico, facilitando i monopoli.<br />
3. Il mantenimento delle licenze con le quali il s<strong>of</strong>tware oggi è venduto, e la relativa assimilazione<br />
del s<strong>of</strong>tware a una opera letteraria, induce una legislazione oppressiva assurda e la<br />
sua applicazione necessita di un sistema poliziesco da grande fratello.<br />
4. Il s<strong>of</strong>tware libero è meglio per gli utilizzatori, in quanto hanno a disposizione il codice sorgente<br />
per fare delle modifiche a degli adattamenti alle loro necessità specifiche rapidamente<br />
e senza esborsi onerosi.<br />
5. Il s<strong>of</strong>tware libero è meglio per i programmatori, che non devono avere un avvocato alle<br />
spalle e in quanto hanno a disposizione dei codici che possono utilizzare per scrivere altro<br />
codice, in un processo di accumulazione e di sviluppo del sapere.<br />
6. Il «free» è meglio per gli utenti perché non ci sono licenze da pagare.<br />
Ci sono al mondo 6 miliardi di individui e 100 milioni di PC, il «free» è il futuro, non soppianterà<br />
il s<strong>of</strong>tware proprietario per quanto riguarda applicazioni complesse pr<strong>of</strong>essionali, ma lo costringerà<br />
a tornare a prendere in considerazione la vecchia affermazione di Jim Warren: «quando<br />
costerà così poco che sarà più facile comperarlo che copiarlo»...
Indice analitico del volume<br />
/dev/vcsa*, 321<br />
/dev/vcs*, 321<br />
/etc/brltty.conf, 323<br />
/etc/brltty/, 323<br />
backup, 8<br />
Barcode, 46<br />
braille, 316<br />
Code 128, 39<br />
Code 3 <strong>of</strong> 9, 37<br />
Code 39, 37<br />
Code 39 esteso, 39<br />
codice a barre, 30, 46<br />
copia di sicurezza, 8<br />
copia di sicurezza: generazioni, 10<br />
copia di sicurezza: livelli, 11<br />
dischetto di emergenza, 19<br />
dischetto di emergenza: Slackware, 22<br />
DOS: APPEND, 105<br />
DOS: ASSIGN, 103<br />
DOS: ATTRIB, 105<br />
DOS: AUTOEXEC.BAT, 112<br />
DOS: BREAK, 108<br />
DOS: BUFFERS, 108<br />
DOS: CALL, 115<br />
DOS: CH, 92<br />
DOS: CHCP, 113<br />
DOS: CHDIR, 92<br />
DOS: CHKDSK, 101<br />
DOS: CHOICE, 119<br />
DOS: CLS, 119<br />
DOS: COMP, 107<br />
DOS: CONFIG.SYS, 108<br />
DOS: COPY, 94<br />
DOS: COUNTRY, 109<br />
DOS: DATE, 114<br />
DOS: DEL, 95<br />
DOS: DELTREE, 106<br />
DOS: DEVICE, 110<br />
DOS: DEVICEHIGH, 110<br />
DOS: DIR, 94<br />
DOS: DISKCOPY, 102<br />
DOS: DOS, 110<br />
DOS: DRIVEPARM, 110<br />
DOS: ECHO, 118<br />
DOS: ERASE, 95<br />
DOS: FC, 107<br />
DOS: FCBS, 111<br />
DOS: FILES, 111<br />
DOS: FIND, 106<br />
361
DOS: FOR, 116<br />
DOS: FORMAT, 100<br />
DOS: GOTO, 117<br />
DOS: GRAFTABL, 114<br />
DOS: IF, 116<br />
DOS: INSTALL, 111<br />
DOS: JOIN, 104<br />
DOS: KEYB, 113<br />
DOS: LABEL, 101<br />
DOS: LASTDRIVE, 111<br />
DOS: LH, 121<br />
DOS: LOADHIGH, 121<br />
DOS: MD, 92<br />
DOS: MEM, 121<br />
DOS: MKDIR, 92<br />
DOS: MORE, 98<br />
DOS: MOVE, 106<br />
DOS: PAUSE, 119<br />
DOS: REM, 118<br />
DOS: REN, 96<br />
DOS: RENAME, 96<br />
DOS: RM, 93<br />
DOS: RMDIR, 93<br />
DOS: SET, 96<br />
DOS: SHELL, 111<br />
DOS: SHIFT, 115<br />
DOS: SORT, 98<br />
DOS: STACK, 111<br />
DOS: SUBST, 104<br />
DOS: SYS, 103<br />
DOS: TIME, 114<br />
DOS: TREE, 107<br />
DOS: TYPE, 97<br />
DOS: VERIFY, 105<br />
DOS: VOL, 101<br />
DOS: XCOPY, 102<br />
EAN: European Article Number, 33<br />
EAN-13, 31<br />
EAN-8, 31<br />
ELKS, 80<br />
Ethernet, 26<br />
GNU: Manifesto, 331<br />
Gnuplot, 126<br />
i25, 43<br />
interfogliata due su cinque, 43<br />
Interleaved two <strong>of</strong> five, 43<br />
ISBN, 36<br />
Ispell, 127<br />
ISSN, 37<br />
ITF, 43<br />
Minix, 58<br />
362
Perl, 127<br />
PLIP, 26<br />
SC, 127<br />
Slackware, 22<br />
Spreadsheet Calculator, 127<br />
UCC/EAN 128, 43<br />
UCC: Uniform Code Council, 33<br />
UPC-A, 31<br />
UPC-E, 31<br />
USS Code 128, 39<br />
363
364