michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: michael@0: michael@0: /* michael@0: michael@0: Copyright 1987, 1988 by the Student Information Processing Board michael@0: of the Massachusetts Institute of Technology michael@0: michael@0: Permission to use, copy, modify, and distribute this software michael@0: and its documentation for any purpose and without fee is michael@0: hereby granted, provided that the above copyright notice michael@0: appear in all copies and that both that copyright notice and michael@0: this permission notice appear in supporting documentation, michael@0: and that the names of M.I.T. and the M.I.T. S.I.P.B. not be michael@0: used in advertising or publicity pertaining to distribution michael@0: of the software without specific, written prior permission. michael@0: M.I.T. and the M.I.T. S.I.P.B. make no representations about michael@0: the suitability of this software for any purpose. It is michael@0: provided "as is" without express or implied warranty. michael@0: michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include "prmem.h" michael@0: #include "prerror.h" michael@0: michael@0: #define ERRCODE_RANGE 8 /* # of bits to shift table number */ michael@0: #define BITS_PER_CHAR 6 /* # bits to shift per character in name */ michael@0: michael@0: #ifdef NEED_SYS_ERRLIST michael@0: extern char const * const sys_errlist[]; michael@0: extern const int sys_nerr; michael@0: #endif michael@0: michael@0: /* List of error tables */ michael@0: struct PRErrorTableList { michael@0: struct PRErrorTableList *next; michael@0: const struct PRErrorTable *table; michael@0: struct PRErrorCallbackTablePrivate *table_private; michael@0: }; michael@0: static struct PRErrorTableList * Table_List = (struct PRErrorTableList *) NULL; michael@0: michael@0: /* Supported languages */ michael@0: static const char * default_languages[] = { "i-default", "en", 0 }; michael@0: static const char * const * callback_languages = default_languages; michael@0: michael@0: /* Callback info */ michael@0: static struct PRErrorCallbackPrivate *callback_private = 0; michael@0: static PRErrorCallbackLookupFn *callback_lookup = 0; michael@0: static PRErrorCallbackNewTableFn *callback_newtable = 0; michael@0: michael@0: michael@0: static const char char_set[] = michael@0: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; michael@0: michael@0: static const char * michael@0: error_table_name (PRErrorCode num) michael@0: { michael@0: static char buf[6]; /* only used if internal code problems exist */ michael@0: michael@0: long ch; michael@0: int i; michael@0: char *p; michael@0: michael@0: /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */ michael@0: p = buf; michael@0: num >>= ERRCODE_RANGE; michael@0: /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */ michael@0: num &= 077777777; michael@0: /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */ michael@0: for (i = 4; i >= 0; i--) { michael@0: ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1); michael@0: if (ch != 0) michael@0: *p++ = char_set[ch-1]; michael@0: } michael@0: *p = '\0'; michael@0: return(buf); michael@0: } michael@0: michael@0: PR_IMPLEMENT(const char *) michael@0: PR_ErrorToString(PRErrorCode code, PRLanguageCode language) michael@0: { michael@0: /* static buffer only used if code is using inconsistent error message michael@0: * numbers, so just ignore the possible thread contention michael@0: */ michael@0: static char buffer[25]; michael@0: michael@0: const char *msg; michael@0: int offset; michael@0: PRErrorCode table_num; michael@0: struct PRErrorTableList *et; michael@0: int started = 0; michael@0: char *cp; michael@0: michael@0: for (et = Table_List; et; et = et->next) { michael@0: if (et->table->base <= code && michael@0: et->table->base + et->table->n_msgs > code) { michael@0: /* This is the right table */ michael@0: if (callback_lookup) { michael@0: msg = callback_lookup(code, language, et->table, michael@0: callback_private, et->table_private); michael@0: if (msg) return msg; michael@0: } michael@0: michael@0: return(et->table->msgs[code - et->table->base].en_text); michael@0: } michael@0: } michael@0: michael@0: if (code >= 0 && code < 256) { michael@0: return strerror(code); michael@0: } michael@0: michael@0: offset = (int) (code & ((1<= 100) { michael@0: *cp++ = (char)('0' + offset / 100); michael@0: offset %= 100; michael@0: started++; michael@0: } michael@0: if (started || offset >= 10) { michael@0: *cp++ = (char)('0' + offset / 10); michael@0: offset %= 10; michael@0: } michael@0: *cp++ = (char)('0' + offset); michael@0: *cp = '\0'; michael@0: return(buffer); michael@0: } michael@0: michael@0: PR_IMPLEMENT(const char *) michael@0: PR_ErrorToName(PRErrorCode code) michael@0: { michael@0: struct PRErrorTableList *et; michael@0: michael@0: for (et = Table_List; et; et = et->next) { michael@0: if (et->table->base <= code && michael@0: et->table->base + et->table->n_msgs > code) { michael@0: /* This is the right table */ michael@0: return(et->table->msgs[code - et->table->base].name); michael@0: } michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: PR_IMPLEMENT(const char * const *) michael@0: PR_ErrorLanguages(void) michael@0: { michael@0: return callback_languages; michael@0: } michael@0: michael@0: PR_IMPLEMENT(PRErrorCode) michael@0: PR_ErrorInstallTable(const struct PRErrorTable *table) michael@0: { michael@0: struct PRErrorTableList * new_et; michael@0: michael@0: new_et = (struct PRErrorTableList *) michael@0: PR_Malloc(sizeof(struct PRErrorTableList)); michael@0: if (!new_et) michael@0: return errno; /* oops */ michael@0: new_et->table = table; michael@0: if (callback_newtable) { michael@0: new_et->table_private = callback_newtable(table, callback_private); michael@0: } else { michael@0: new_et->table_private = 0; michael@0: } michael@0: new_et->next = Table_List; michael@0: Table_List = new_et; michael@0: return 0; michael@0: } michael@0: michael@0: PR_IMPLEMENT(void) michael@0: PR_ErrorInstallCallback(const char * const * languages, michael@0: PRErrorCallbackLookupFn *lookup, michael@0: PRErrorCallbackNewTableFn *newtable, michael@0: struct PRErrorCallbackPrivate *cb_private) michael@0: { michael@0: struct PRErrorTableList *et; michael@0: michael@0: assert(strcmp(languages[0], "i-default") == 0); michael@0: assert(strcmp(languages[1], "en") == 0); michael@0: michael@0: callback_languages = languages; michael@0: callback_lookup = lookup; michael@0: callback_newtable = newtable; michael@0: callback_private = cb_private; michael@0: michael@0: if (callback_newtable) { michael@0: for (et = Table_List; et; et = et->next) { michael@0: et->table_private = callback_newtable(et->table, callback_private); michael@0: } michael@0: } michael@0: }