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.