/* Error Message Registration and Decoding error_message.c ** ======================================= ** ** This module emulates the VAX/VMS error message reporting system to a ** limited extent. The philosophy is that any error generated is tagged ** with a facility code and a severity. The severity allows modules which ** do not know how to interpret the code completely to decide what to do about it. ** The facility number allows it to be decoded when eventually it is returned ** to a high level. ** ** The format of the error code is ** **2^ 31 15 0 ** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ** |Res- |N| Facility |F| Message number | Sev | ** | erved |D| |W| | | ** +-------+-------+-------+-------+-------+-------+-------+-------+ ** ** Reserved: Include a few flags used by other systems. ** ND: This bit is set to indicate a Non-Digital Facility number ** Facility: These bits give a facility number. ** FW: If this bit is set, message is facility wide, ** message number must be interprested w.r.t that facility. ** If bit clear, message number refers to a standard set (facility ** zero). ** Message No This is a message number - See FW for interpretation. ** ** Sev This is the severity according to the list: ** ** 0 Warning Operation completed not fully as expected. ** 1 Success Operation completed as expected. ** 2 Error Operation failed, other operations may be possible. ** 3 Information Error code reports information only. ** 4 Fatal Operation failed, others will probably fail too. ** ** ** Any facility may generate a block of message information, and attach it ** to this lookup service by calling err_register(). The program "msgstring" ** automatically generates such a block, and the call to initialise it, ** using data in the listfile produced by the VAX/MESSAGE utility. ** ** Under unix, and compatible systems, the internal "errno" codes are given ** a special facility code. ** This module will then interpret them using the built-in system tables. ** ** Under VMS, these error messages are generated un VMS style, e.g.: ** ** on vms: %RMS-E-FILNOTFOU, File not found ** ** elsewhere: RMS Error FILNOTFOU: File not found **_____________________________________________________________________________ ** ** VAX/VMS, VAX/MESSAGE, and Digital are trademarks of Digital Equipment, Inc. ** ** This code is copyright CERN -- implies free distribution if not for profit ** to certain institutes under certain terms - ask for details. ** ** ** HISTORY: ** 5 Dec 89 Written Tim Berners-Lee CERN/DD ** ** PREPROCESSOR TOKENS: ** ** USE_SYS_ERRLIST If defined, uses sys_errlist for errno values. */ #ifdef unix # define USE_SYS_ERRLIST #endif #ifdef __TURBOC__ # define USE_SYS_ERRLIST #endif #define CRITICAL /* Code to protect if err_root shared */ #define NONCRITICAL /* End of protected region */ #ifdef OSK # include #else # include /* ANSI name. is obsolete */ #endif #include "errmsg.h" /* Constant Data ** ------------- */ static char *severity_name[8] = { #ifdef vms "W", "S", "E", "I", "F", "?", "?", "?" }; /* Severity codes */ #else "Warning", "Success", "Error", "Information", "Fatal", "(severity 5?)", "(severity 6?)", "(severity 7?)" }; /* Severity codes */ #endif static struct err_block_struct default_facility = { 0, /* next */ 0, /* Facility number */ "SYS", /* Prefix */ "NONAME", /* Facility name */ 0 /* Pointer to array */ }; /* struct */ #ifdef USE_SYS_ERRLIST #define UNIX_FACILITY 0x55 /* Facility number for errno values */ static struct err_block_struct errno_facility = { 0, /* next */ 0x55, /* Facility number */ "E", /* Prefix */ "errno", /* Facility name */ 0 /* Pointer to array */ }; /* struct */ extern char* sys_errlist[]; /* System error message table */ extern int sys_nerr; /* Number of entries in sys_errlist */ #endif /* Variable Data ** ------------- ** ** Global for disgnostics only. */ err_pointer err_root = 0; /* Warning: Not ROMable */ /* Translate Error Code Into String err_translate() ** ================================ ** ** On entry, ** ** error_code is the 32 bit standard error code ** buffer is the address of the user buffer ** buffer_length is the length of the buffer in bytes, including space ** for a terminating zero. ** ** On succesful exit, ** ** returns A status with severity Success ** buffer[] Contains the error message, zero terminated ** ** If the buffer was too small, ** ** returns A status with severity Warning ** buffer[] Contains the error message trucated and zero terminated. ** ** If the code could not be translated, ** ** returns A status with severity Error ** buffer[] Contains a default error message truncated if necessary */ #ifdef __STDC__ err_status err_translate( err_code error_code, char *buffer, int buffer_length) #else err_status err_translate(error_code, buffer, buffer_length) err_code error_code; char *buffer; int buffer_length; #endif { int facility = (error_code >> 16) & 0x7ff; /* Get facility code */ int code = (error_code >> 3) & 0xfff; /* Get message number */ int severity = error_code & 7; /* Get severity */ char temp[256]; err_translation *found_translation = 0; /* Points to match if found */ err_pointer found_facility =0; /* Points to facility */ err_pointer scan; int reference_facility; #ifdef USE_SYS_ERRLIST static err_translation dynamic_translation /* for filling in by hand */ = { 0, "ERRNO", 0 }; #endif /* The "Facility wide but means the reference facility is the actual ** facility: Otherwise, the facility refers to facility 0. */ reference_facility = (error_code & 0x8000) ? facility : 0; #ifdef USE_SYS_ERRLIST if (facility == UNIX_FACILITY) found_facility = &errno_facility; if (reference_facility == UNIX_FACILITY) { if (code < sys_nerr) { found_translation = &dynamic_translation; dynamic_translation.message = sys_errlist[code]; } } #endif for (scan=err_root; (scan) && (!found_facility || !found_translation); scan = scan->next) { if (scan->facility_number == facility) found_facility = scan; if (scan->facility_number == reference_facility) { int msg; for (msg=0; scan->array[msg].message; msg++) { if (scan->array[msg].code == code) { found_translation = &scan->array[msg]; break; } /* If code match */ } /* for each code*/ } /*if facility match */ } /* for each registered facility */ if (!found_facility) found_facility = &default_facility; #ifdef vms if (found_translation) { sprintf(temp, "%%%s-%s-%s, %s", /* Two % give one on the screen*/ found_facility->name, severity_name[severity], found_translation->symbol, found_translation->message); } else { sprintf(temp, "%%%s-%s-NONAME: Unknown error code, hex %lx", found_facility->name, severity_name[severity], error_code); } /* if no translation */ #else if (found_translation) { sprintf(temp, "%s %s %s: %s", found_facility->name, severity_name[severity], found_translation->symbol, found_translation->message); } else { sprintf(temp, "Unknown %s error code: hex %lx", severity_name[severity], error_code); } /* if no translation */ #endif if (buffer_length < strlen(temp)) { strncpy(buffer, temp, buffer_length); /* Fill users's buffer */ buffer[buffer_length-1] = 0; /* Terminate user's buffer */ return found_translation ? ERR_S_BUFFER_OVERFLOW /* Buffer Overflow */ : ERR_S_NO_TRANSLATION; /* Overflow on default message*/ } else { strcpy(buffer, temp); /* Return user's string */ return found_translation ? ERR_S_NORMAL /* Buffer Overflow */ : ERR_S_NO_TRANSLATION; /* Overflow on default message*/ } } /* error_message */ /* Register Error Messages err_register() ** ======================= ** ** On entry, ** pblock points to a valid struct err_block_struct which may ** or may not be already registerd. ** ** On exit, ** The facility has been incorporated in the queue. ** ** returns ERR_S_ALREADY_REGISTERED if it was already ** ERR_S_NORMAL if it has just been */ #ifdef __STDC__ err_status err_register(err_pointer pblock) #else err_status err_register(pblock) err_pointer pblock; #endif { err_pointer scan; /* For safety, we check whether it's on the list already */ for (scan=err_root; scan; scan = scan->next) if (scan==pblock) return ERR_S_ALREADY_REGISTERED; CRITICAL pblock->next = err_root; /* Put onto head of list */ err_root = pblock; NONCRITICAL return ERR_S_NORMAL; } /* Unregister Error Messages err_unregister() ** ========================= ** ** This reverses the effect of err_register. It may be called more than ** once with no ill effect. ** ** On entry, ** pblock points to a valid struct err_block_struct. ** ** On exit, ** The facility has been removed from the queue if it had been registered. ** ** returns ERR_S_NORMAL if it has been removed ** ERR_S_NOT_REGISTERED if it never was registered ** */ #ifdef __STDC__ err_status err_unregister(err_pointer pblock) #else err_status err_unregister(pblock) err_pointer pblock; #endif { err_pointer scan, last; CRITICAL for (last=(err_pointer)(&err_root), scan=last->next; scan; last=scan, scan=last->next) if (scan==pblock) { last->next = scan->next; /* Remove from queue */ NONCRITICAL return ERR_S_NORMAL; } NONCRITICAL return ERR_S_NOT_REGISTERED; /* Wasn't on it. */ }