extern char *sys_errlist[]; extern int errno; extern int _doserrno;L'array sys_errlist contiene i puntatori alle stringhe che descrivono i diversi errori[1]. Vi è una funzione dedicata alla gestione dei messaggi d'errore, perror(), che richiede una stringa quale parametro, la scrive sullo standard error seguita da ":", dalla stringa che costituisce l'elemento di sys_errlist corrispondente all'errore verificatosi e dal carattere "\n". L'utilizzo di perror() non presenta difficoltà:
#include <stdio.h> // prototipi di fopen() e perror()
#define PRG_NAME "MYPROG"
....
if(!(stream = fopen(filename,"r"))) {
perror(PRG_NAME);
return(0);
}
Nell'ipotesi che filename contenga un pathname errato, fopen()
non riesce ad aprire il file e restituisce NULL; la perror()
produce il seguente output:
MYPROG: path not foundCome riesce perror() a individuare il messaggio? Semplice: si basa sul valore assunto dalla variabile errno, che può essere validamente utilizzata come indice. In altre parole, sys_errlist[errno] è la stringa che descrive l'errore. Dietro le quinte, tutte le funzioni di libreria che per svolgere il proprio compito utilizzano servizi DOS[2], se ricevono da questo un codice di errore lo passano ad una funzione (generalmente non documentata), la __IOerror() [3], che lo assegna a _doserrno, la quale contiene perciò il codice di errore DOS, e, tramite un'apposita tabella di conversione, ricava il valore appropriato da assegnare ad errno.
int pascal __IOerror(int dosErr);La parola riservata pascal ha lo scopo di modificare lo stile di chiamata della funzione: a tutte le funzioni dichiarate pascal, secondo lo standard di questo linguaggio, i parametri attuali sono passati in ordine diretto, cioè dal primo a sinistra all'ultimo a destra, e non viceversa, secondo quanto previsto invece, per default, dalle regole del C. Lo scopo è ottenere una chiamata più efficiente; la perdita della possibilità di gestire un numero variabile di parametri, in questo caso, non ha alcuna importanza, in quanto __IOerror() ne riceve uno solo, dosErr, che rappresenta il codice di errore restituito dalla routine DOS (solitamente nel registro AX). La __IOerror() restituisce sempre 1.
| Input | AX
BL |
4409h
Drive (00h = default, 01h = A:, 02h = B:, etc.) |
| Output | DX | Se CarryFlag = 0, il bit 12 di DX a 1 indica che il drive è remoto; Se CarryFlag = 1 allora AX contiene il codice di errore. |
/********************
BARNINGA_Z! - 1991
ISREMOTE.C - isDriveRemote()
int cdecl isDriveRemote(int driveNum);
int driveNum; drive da testare (0 = default, 1 = A:, ...)
Restituisce: 0 = drive locale
1 = drive remoto
-1 = errore (errno e _doserrno gestite come standard)
COMPILABILE CON BORLAND C++ 3.0
bcc -O -d -c -mx isremote.c
dove -mx puo' essere -mt -ms -mc -mm -ml -mh
********************/
#pragma inline
#include <dos.h> // per geninterrupt()
int pascal __IOerror(int dosErr);
int cdecl isDriveRemote(int driveNum)
{
_BL = (char)driveNum;
_AX = 0x4409;
geninterrupt(0x21);
asm jc JOB_ERROR; // Se CarryFlag = 1 c'e' stato un errore
asm and dx,01000000000000b;
asm mov ax,dx;
return(_AX);
JOB_ERROR:
return(__IOerror(_AX));
}
La funzione isDriveRemote() restituisce 1 in caso
di errore, 0 se il drive è locale, 1 se è
remoto. Il parametro è un intero che esprime il drive su cui effettuare
il test (0 indica il drive di default, 1 indica il drive
A:, 2 il drive B:, etc.). Quando la funzione
restituisce 1 è possibile chiamare perror()
per scrivere su stderr la descrizione dell'errore verificatosi:
if(isDriveRemote(0) == -1)
perror("What a pity");
E' immediato constatare che il comportamento di isDriveRemote()
è conforme a quello delle altre funzioni di libreria che interagiscono
con il DOS. Per altri esempi di utilizzo della __IOerror() in
funzioni di libreria vedere le funzioni
per la gestione della command
line.