summaryrefslogtreecommitdiffstats
path: root/mysys/my_error.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--mysys/my_error.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/mysys/my_error.c b/mysys/my_error.c
new file mode 100644
index 00000000..106e51de
--- /dev/null
+++ b/mysys/my_error.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <m_string.h>
+#include <stdarg.h>
+#include <m_ctype.h>
+
+/* Max length of a error message. Should be kept in sync with MYSQL_ERRMSG_SIZE. */
+#define ERRMSGSIZE (512)
+
+/* Define some external variables for error handling */
+
+/*
+ WARNING!
+ my_error family functions have to be used according following rules:
+ - if message have not parameters use my_message(ER_CODE, ER(ER_CODE), MYF(N))
+ - if message registered use my_error(ER_CODE, MYF(N), ...).
+ - With some special text of errror message use:
+ my_printf_error(ER_CODE, format, MYF(N), ...)
+*/
+
+/*
+ Message texts are registered into a linked list of 'my_err_head' structs.
+ Each struct contains (1.) an array of pointers to C character strings with
+ '\0' termination, (2.) the error number for the first message in the array
+ (array index 0) and (3.) the error number for the last message in the array
+ (array index (last - first)).
+ The array may contain gaps with NULL pointers and pointers to empty strings.
+ Both kinds of gaps will be translated to "Unknown error %d.", if my_error()
+ is called with a respective error number.
+ The list of header structs is sorted in increasing order of error numbers.
+ Negative error numbers are allowed. Overlap of error numbers is not allowed.
+ Not registered error numbers will be translated to "Unknown error %d.".
+*/
+static struct my_err_head
+{
+ struct my_err_head *meh_next; /* chain link */
+ const char** (*get_errmsgs)(int nr); /* returns error message format */
+ uint meh_first; /* error number matching array slot 0 */
+ uint meh_last; /* error number matching last slot */
+} my_errmsgs_globerrs=
+{NULL, get_global_errmsgs, EE_ERROR_FIRST, EE_ERROR_LAST};
+
+static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
+
+
+/**
+ @brief Get an error format string from one of the my_error_register()ed sets
+
+ @note
+ NULL values are possible even within a registered range.
+
+ @param nr Errno
+
+ @retval NULL if no message is registered for this error number
+ @retval str C-string
+*/
+
+const char *my_get_err_msg(uint nr)
+{
+ const char *format;
+ struct my_err_head *meh_p;
+
+ /* Search for the range this error is in. */
+ for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next)
+ if (nr <= meh_p->meh_last)
+ break;
+
+ /*
+ If we found the range this error number is in, get the format string.
+ If the string is empty, or a NULL pointer, or if we're out of return,
+ we return NULL.
+ */
+ if (!(format= (meh_p && (nr >= meh_p->meh_first)) ?
+ meh_p->get_errmsgs(nr)[nr - meh_p->meh_first] : NULL) ||
+ !*format)
+ return NULL;
+
+ return format;
+}
+
+
+/**
+ Fill in and print a previously registered error message.
+
+ @note
+ Goes through the (sole) function registered in error_handler_hook
+
+ @param nr error number
+ @param MyFlags Flags
+ @param ... variable list matching that error format string
+*/
+
+void my_error(uint nr, myf MyFlags, ...)
+{
+ const char *format;
+ va_list args;
+ char ebuff[ERRMSGSIZE];
+ DBUG_ENTER("my_error");
+ DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d", nr, MyFlags, errno));
+ if (!(format = my_get_err_msg(nr)))
+ (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr);
+ else
+ {
+ va_start(args,MyFlags);
+ (void) my_vsnprintf_ex(&my_charset_utf8mb3_general_ci, ebuff,
+ sizeof(ebuff), format, args);
+ va_end(args);
+ }
+ (*error_handler_hook)(nr, ebuff, MyFlags);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Print an error message.
+
+ @note
+ Just like my_error, but for cases when the error message is not ER(error)
+
+ @param error error number
+ @param format format string
+ @param MyFlags Flags
+ @param ... variable list matching that error format string
+*/
+
+void my_printf_error(uint error, const char *format, myf MyFlags, ...)
+{
+ va_list args;
+ char ebuff[ERRMSGSIZE];
+ DBUG_ENTER("my_printf_error");
+ DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d format: %s",
+ error, MyFlags, errno, format));
+
+ va_start(args,MyFlags);
+ (void) my_vsnprintf_ex(&my_charset_utf8mb3_general_ci, ebuff,
+ sizeof(ebuff), format, args);
+ va_end(args);
+ (*error_handler_hook)(error, ebuff, MyFlags);
+ DBUG_VOID_RETURN;
+}
+
+/**
+ Print an error message.
+
+ @note
+ Goes through the (sole) function registered in error_handler_hook
+
+ @param error error number
+ @param format format string
+ @param MyFlags Flags
+ @param ap variable list matching that error format string
+*/
+
+void my_printv_error(uint error, const char *format, myf MyFlags, va_list ap)
+{
+ char ebuff[ERRMSGSIZE];
+ DBUG_ENTER("my_printv_error");
+ DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d format: %s",
+ error, MyFlags, errno, format));
+
+ (void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap);
+ (*error_handler_hook)(error, ebuff, MyFlags);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Print an error message.
+
+ @note
+ Goes through the (sole) function registered in error_handler_hook
+
+ @param error error number
+ @param str error message
+ @param MyFlags Flags
+*/
+
+void my_message(uint error, const char *str, register myf MyFlags)
+{
+ (*error_handler_hook)(error, str, MyFlags);
+}
+
+
+/**
+ Register error messages for use with my_error().
+
+ @description
+
+ The pointer array is expected to contain addresses to NUL-terminated
+ C character strings. The array contains (last - first + 1) pointers.
+ NULL pointers and empty strings ("") are allowed. These will be mapped to
+ "Unknown error" when my_error() is called with a matching error number.
+ This function registers the error numbers 'first' to 'last'.
+ No overlapping with previously registered error numbers is allowed.
+
+ @param errmsgs array of pointers to error messages
+ @param first error number of first message in the array
+ @param last error number of last message in the array
+
+ @retval 0 OK
+ @retval != 0 Error
+*/
+
+int my_error_register(const char** (*get_errmsgs)(int error), uint first,
+ uint last)
+{
+ struct my_err_head *meh_p;
+ struct my_err_head **search_meh_pp;
+
+ /* Allocate a new header structure. */
+ if (! (meh_p= (struct my_err_head*) my_malloc(key_memory_my_err_head,
+ sizeof(struct my_err_head),
+ MYF(MY_WME))))
+ return 1;
+ meh_p->get_errmsgs= get_errmsgs;
+ meh_p->meh_first= first;
+ meh_p->meh_last= last;
+
+ /* Search for the right position in the list. */
+ for (search_meh_pp= &my_errmsgs_list;
+ *search_meh_pp;
+ search_meh_pp= &(*search_meh_pp)->meh_next)
+ {
+ if ((*search_meh_pp)->meh_last > first)
+ break;
+ }
+
+ /* Error numbers must be unique. No overlapping is allowed. */
+ if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last))
+ {
+ my_free(meh_p);
+ return 1;
+ }
+
+ /* Insert header into the chain. */
+ meh_p->meh_next= *search_meh_pp;
+ *search_meh_pp= meh_p;
+ return 0;
+}
+
+
+/**
+ Unregister formerly registered error messages.
+
+ @description
+
+ This function unregisters the error numbers 'first' to 'last'.
+ These must have been previously registered by my_error_register().
+ 'first' and 'last' must exactly match the registration.
+ If a matching registration is present, the header is removed from the
+ list and the pointer to the error messages pointers array is returned.
+ (The messages themselves are not released here as they may be static.)
+ Otherwise, NULL is returned.
+
+ @param first error number of first message
+ @param last error number of last message
+
+ @retval NULL Error, no such number range registered.
+ @retval non-NULL OK, returns address of error messages pointers array.
+*/
+
+my_bool my_error_unregister(uint first, uint last)
+{
+ struct my_err_head *meh_p;
+ struct my_err_head **search_meh_pp;
+
+ /* Search for the registration in the list. */
+ for (search_meh_pp= &my_errmsgs_list;
+ *search_meh_pp;
+ search_meh_pp= &(*search_meh_pp)->meh_next)
+ {
+ if (((*search_meh_pp)->meh_first == first) &&
+ ((*search_meh_pp)->meh_last == last))
+ break;
+ }
+ if (! *search_meh_pp)
+ return TRUE;
+
+ /* Remove header from the chain. */
+ meh_p= *search_meh_pp;
+ *search_meh_pp= meh_p->meh_next;
+
+ my_free(meh_p);
+
+ return FALSE;
+}
+
+
+/**
+ Unregister all formerly registered error messages.
+
+ @description
+
+ This function unregisters all error numbers that previously have
+ been previously registered by my_error_register().
+ All headers are removed from the list; the messages themselves are
+ not released here as they may be static.
+*/
+
+void my_error_unregister_all(void)
+{
+ struct my_err_head *cursor, *saved_next;
+
+ for (cursor= my_errmsgs_globerrs.meh_next; cursor != NULL; cursor= saved_next)
+ {
+ /* We need this ptr, but we're about to free its container, so save it. */
+ saved_next= cursor->meh_next;
+
+ my_free(cursor);
+ }
+ my_errmsgs_globerrs.meh_next= NULL; /* Freed in first iteration above. */
+
+ my_errmsgs_list= &my_errmsgs_globerrs;
+}