summaryrefslogtreecommitdiff
path: root/strings/my_vsnprintf.c
diff options
context:
space:
mode:
authorMichael Widenius <monty@askmonty.org>2012-05-30 00:37:55 +0300
committerMichael Widenius <monty@askmonty.org>2012-05-30 00:37:55 +0300
commitaa81e025a88d13c5040bb3fe808d70fd6d1e560c (patch)
treeb4c742ede7e98215c740c143681d91ad53dce998 /strings/my_vsnprintf.c
parent3f4ef5928e72faf2b7fd0c98c8705ac649d2faf9 (diff)
downloadmariadb-git-aa81e025a88d13c5040bb3fe808d70fd6d1e560c.tar.gz
Added text for errno in error messages by:
- Adding %M my_sprintf() modifier that prints error number - system-error-text - Modified mysys, mysql_client and SQL error messages to use %M instead of %d - Added my_strerror() Updated handler errors to 5.6 error numbers Updated text for a few error messages (to match 5.6) Increased length of command name in error output extra/comp_err.c: Added support for %M include/my_base.h: Updated handler errors to 5.6 error numbers include/my_sys.h: Added my_strerror() libmysql/errmsg.c: Updated error messages to use %M mysql-test/r/errors.result: Updated result as error message have changed mysql-test/r/innodb_mysql_sync.result: Updated result with text for errno mysql-test/r/myisam-system.result: Updated result with text for errno mysql-test/r/myisam.result: Updated result as error message have changed mysql-test/r/myisampack.result: Updated result with text for errno mysql-test/r/mysql.result: Updated result with text for errno mysql-test/r/mysql_upgrade.result: Updated result with text for errno mysql-test/r/partition_datatype.result: Updated result as error message have changed mysql-test/r/partition_innodb_plugin.result: Updated result with text for errno mysql-test/r/ps_1general.result: Updated result with text for errno mysql-test/r/trigger.result: Updated result with text for errno mysql-test/r/type_bit.result: Updated result as error message have changed mysql-test/r/type_bit_innodb.result: Updated result as error message have changed mysql-test/r/type_blob.result: Updated result as error message have changed mysql-test/suite/archive/archive.result: Updated result with text for errno mysql-test/suite/binlog/r/binlog_index.result: Updated result with text for errno mysql-test/suite/binlog/r/binlog_ioerr.result: Updated result with text for errno mysql-test/suite/csv/csv.result: Updated result with text for errno mysql-test/suite/federated/federated_bug_35333.result: Updated result with text for errno mysql-test/suite/innodb/r/innodb-create-options.result: Updated result with text for errno mysql-test/suite/innodb/r/innodb-index.result: Updated result with text for errno mysql-test/suite/innodb/r/innodb-zip.result: Updated result as error message have changed mysql-test/suite/innodb/r/innodb.result: Updated result with text for errno mysql-test/suite/innodb/r/innodb_bug21704.result: Updated result with text for errno mysql-test/suite/innodb/r/innodb_bug46000.result: Updated result with text for errno mysql-test/suite/innodb/r/innodb_bug53591.result: Updated result as error message have changed mysql-test/suite/innodb/r/innodb_corrupt_bit.result: New error numbers mysql-test/suite/innodb/r/innodb_prefix_index_liftedlimit.result: Updated result as error message have changed mysql-test/suite/innodb/t/innodb-create-options.test: Added regexp to avoid system error text mysql-test/suite/innodb/t/innodb-zip.test: Added regexp to avoid system error text mysql-test/suite/maria/maria-recovery2.result: Updated supression rule mysql-test/suite/maria/maria-recovery2.test: Updated supression rule mysql-test/suite/maria/maria.result: Updated result as error message have changed mysql-test/suite/parts/r/partition_bit_innodb.result: Updated result as error message have changed mysql-test/suite/parts/r/partition_bit_myisam.result: Updated result as error message have changed mysql-test/suite/percona/percona_innodb_fake_changes.result: Updated result with text for errno mysql-test/suite/perfschema/r/dml_cond_instances.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_events_waits_current.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_events_waits_history.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_events_waits_history_long.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_ews_by_instance.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_ews_by_thread_by_event_name.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_ews_global_by_event_name.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_file_instances.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_file_summary_by_event_name.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_file_summary_by_instance.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_mutex_instances.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_performance_timers.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_rwlock_instances.result: Updated result as error message have changed mysql-test/suite/perfschema/r/dml_threads.result: Updated result as error message have changed mysql-test/suite/perfschema/r/misc.result: Updated result with text for errno mysql-test/suite/perfschema/r/privilege.result: Updated result with text for errno mysql-test/suite/rpl/r/rpl_EE_err.result: Updated result with text for errno mysql-test/suite/rpl/r/rpl_binlog_errors.result: Updated result with text for errno mysql-test/suite/rpl/r/rpl_drop_db.result: Updated result with text for errno mysys/errors.c: Updated error messages to use %M Changed all errors to use Errcode: consistenly mysys/my_handler_errors.h: Updated handler errors to 5.6 error numbers sql/share/errmsg-utf8.txt: Updated error messages to use %M sql/sys_vars.cc: Added error number to ER_EVENT_SET_VAR_ERROR strings/my_vsnprintf.c: Added %M my_sprintf() modifier that prints error number - system-error-text Simplify code Movied common code to function Removed some casts that was not necessary when reading integer/unsigned int stored in longlong Added my_strerror() unittest/mysys/my_vsnprintf-t.c: Added testing of %M
Diffstat (limited to 'strings/my_vsnprintf.c')
-rw-r--r--strings/my_vsnprintf.c185
1 files changed, 143 insertions, 42 deletions
diff --git a/strings/my_vsnprintf.c b/strings/my_vsnprintf.c
index 64c37ca0537..7ace577130f 100644
--- a/strings/my_vsnprintf.c
+++ b/strings/my_vsnprintf.c
@@ -17,10 +17,14 @@
#include "strings_def.h"
#include <m_ctype.h>
#include <stdarg.h>
+#include <my_sys.h>
+#include <my_base.h>
+#include <../mysys/my_handler_errors.h>
#define MAX_ARGS 32 /* max positional args count*/
#define MAX_PRINT_INFO 32 /* max print position count */
+#define MAX_WIDTH 65535
#define LENGTH_ARG 1
#define WIDTH_ARG 2
@@ -65,6 +69,7 @@ struct print_info
static const char *get_length(const char *fmt, size_t *length, uint *pre_zero)
{
+
for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
{
*length= *length * 10 + (uint)(*fmt - '0');
@@ -75,23 +80,27 @@ static const char *get_length(const char *fmt, size_t *length, uint *pre_zero)
}
-/**
- Calculates print width or index of positional argument
+/*
+ Get argument for '*' parameter
@param fmt processed string
- @param width print width or index of positional argument
+ @param args_arr Arguments to printf
+ @param arg_count Number of arguments to printf
+ @param length returns length of argument
+ @param flag returns flags with PREZERO_ARG set if necessary
- @retval
- string position right after width digits
+ @return new fmt
*/
-static const char *get_width(const char *fmt, size_t *width)
+static const char *get_length_arg(const char *fmt, ARGS_INFO *args_arr,
+ uint *arg_count, size_t *length, uint *flags)
{
- for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
- {
- *width= *width * 10 + (uint)(*fmt - '0');
- }
- return fmt;
+ fmt= get_length(fmt+1, length, flags);
+ *arg_count= max(*arg_count, (uint) *length);
+ (*length)--;
+ DBUG_ASSERT(*fmt == '$' && *length < MAX_ARGS);
+ args_arr[*length].arg_type= 'd';
+ return fmt+1;
}
/**
@@ -123,6 +132,8 @@ static const char *check_longlong(const char *fmt, uint *have_longlong)
fmt++;
*have_longlong= (sizeof(size_t) == sizeof(longlong));
}
+ if (*fmt == 'p')
+ *have_longlong= (sizeof(void *) == sizeof(longlong));
return fmt;
}
@@ -227,7 +238,7 @@ static char *process_bin_arg(char *to, char *end, size_t width, char *par)
static char *process_dbl_arg(char *to, char *end, size_t width,
double par, char arg_type)
{
- if (width == SIZE_T_MAX)
+ if (width == MAX_WIDTH)
width= FLT_DIG; /* width not set, use default */
else if (width >= NOT_FIXED_DEC)
width= NOT_FIXED_DEC - 1; /* max.precision for my_fcvt() */
@@ -338,42 +349,31 @@ start:
/* Get print length */
if (*fmt == '*')
{
- fmt++;
- fmt= get_length(fmt, &print_arr[idx].length, &print_arr[idx].flags);
- print_arr[idx].length--;
- DBUG_ASSERT(*fmt == '$' && print_arr[idx].length < MAX_ARGS);
- args_arr[print_arr[idx].length].arg_type= 'd';
+ fmt= get_length_arg(fmt, args_arr, &arg_count, &print_arr[idx].length,
+ &print_arr[idx].flags);
print_arr[idx].flags|= LENGTH_ARG;
- arg_count= max(arg_count, print_arr[idx].length + 1);
- fmt++;
}
else
fmt= get_length(fmt, &print_arr[idx].length, &print_arr[idx].flags);
if (*fmt == '.')
{
+ uint flags= 0;
fmt++;
/* Get print width */
if (*fmt == '*')
{
- fmt++;
- fmt= get_width(fmt, &print_arr[idx].width);
- print_arr[idx].width--;
- DBUG_ASSERT(*fmt == '$' && print_arr[idx].width < MAX_ARGS);
- args_arr[print_arr[idx].width].arg_type= 'd';
+ fmt= get_length_arg(fmt, args_arr, &arg_count, &print_arr[idx].width,
+ &flags);
print_arr[idx].flags|= WIDTH_ARG;
- arg_count= max(arg_count, print_arr[idx].width + 1);
- fmt++;
}
else
- fmt= get_width(fmt, &print_arr[idx].width);
+ fmt= get_length(fmt, &print_arr[idx].width, &flags);
}
else
- print_arr[idx].width= SIZE_T_MAX;
+ print_arr[idx].width= MAX_WIDTH;
fmt= check_longlong(fmt, &args_arr[arg_index].have_longlong);
- if (*fmt == 'p')
- args_arr[arg_index].have_longlong= (sizeof(void *) == sizeof(longlong));
args_arr[arg_index].arg_type= print_arr[idx].arg_type= *fmt;
print_arr[idx].arg_idx= arg_index;
@@ -412,6 +412,7 @@ start:
else
args_arr[i].longlong_arg= va_arg(ap, uint);
break;
+ case 'M':
case 'c':
args_arr[i].longlong_arg= va_arg(ap, int);
break;
@@ -472,17 +473,34 @@ start:
? (size_t)args_arr[print_arr[i].length].longlong_arg
: print_arr[i].length;
- if (args_arr[print_arr[i].arg_idx].have_longlong)
- larg = args_arr[print_arr[i].arg_idx].longlong_arg;
- else if (print_arr[i].arg_type == 'd' || print_arr[i].arg_type == 'i' )
- larg = (int) args_arr[print_arr[i].arg_idx].longlong_arg;
- else
- larg= (uint) args_arr[print_arr[i].arg_idx].longlong_arg;
-
+ larg = args_arr[print_arr[i].arg_idx].longlong_arg;
to= process_int_arg(to, end, length, larg, print_arr[i].arg_type,
print_arr[i].flags);
break;
}
+ case 'M':
+ {
+ longlong larg;
+ char *org_to= to;
+ char errmsg_buff[MYSYS_STRERROR_SIZE];
+
+ length= (print_arr[i].flags & WIDTH_ARG)
+ ? (size_t)args_arr[print_arr[i].width].longlong_arg
+ : print_arr[i].width;
+
+ larg = args_arr[print_arr[i].arg_idx].longlong_arg;
+ to= process_int_arg(to, end, 0, larg, 'd', print_arr[i].flags);
+ width-= (to - org_to);
+ if (width <= 4)
+ break;
+ *to++= ' ';
+ *to++= '-';
+ *to++= ' ';
+ my_strerror(errmsg_buff, sizeof(errmsg_buff), (int) larg);
+ to= process_str_arg(cs, to, end, width, errmsg_buff,
+ print_arr[i].flags);
+ break;
+ }
default:
break;
}
@@ -490,6 +508,7 @@ start:
if (to == end)
break;
+ /* Copy data after the % format expression until next % */
length= min(end - to , print_arr[i].end - print_arr[i].begin);
if (to + length < end)
length++;
@@ -501,13 +520,14 @@ start:
}
else
{
+ uint flags= 0;
/* Process next positional argument*/
DBUG_ASSERT(*fmt == '%');
print_arr[idx].end= fmt - 1;
idx++;
fmt++;
arg_index= 0;
- fmt= get_width(fmt, &arg_index);
+ fmt= get_length(fmt, &arg_index, &flags);
DBUG_ASSERT(*fmt == '$');
fmt++;
arg_count= max(arg_count, arg_index);
@@ -585,6 +605,7 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
if (*fmt == '.')
{
+ uint flags= 0;
fmt++;
if (*fmt == '*')
{
@@ -592,10 +613,10 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
width= va_arg(ap, int);
}
else
- fmt= get_width(fmt, &width);
+ fmt= get_length(fmt, &width, &flags);
}
else
- width= SIZE_T_MAX;
+ width= MAX_WIDTH;
fmt= check_longlong(fmt, &have_longlong);
@@ -622,8 +643,6 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
{
/* Integer parameter */
longlong larg;
- if (*fmt == 'p')
- have_longlong= (sizeof(void *) == sizeof(longlong));
if (have_longlong)
larg = va_arg(ap,longlong);
@@ -644,6 +663,24 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
*to++= (char) larg;
continue;
}
+ else if (*fmt == 'M')
+ {
+ const char *org_to= to;
+ int larg= va_arg(ap, int);
+ to= process_int_arg(to, end, 0, larg, 'd', print_type);
+ width-= (to - org_to);
+ if ((end - to) >= 4 && (int) width >= 4)
+ {
+ char errmsg_buff[MYSYS_STRERROR_SIZE];
+ *to++= ' ';
+ *to++= '-';
+ *to++= ' ';
+ width-= 3;
+ my_strerror(errmsg_buff, sizeof(errmsg_buff), larg);
+ to= process_str_arg(cs, to, end, width, errmsg_buff, print_type);
+ }
+ continue;
+ }
/* We come here on '%%', unknown code or too long parameter */
if (to == end)
@@ -697,3 +734,67 @@ int my_vfprintf(FILE *stream, const char* format, va_list args)
(void) my_vsnprintf(cvtbuf, sizeof(cvtbuf), format, args);
return fprintf(stream, "%s\n", cvtbuf);
}
+
+
+/*
+ Return system error text for given error number
+
+ @param buf Buffer (of size MYSYS_STRERROR_SIZE)
+ @param len Length of buffer
+ @param nr Error number
+*/
+
+void my_strerror(char *buf, size_t len, int nr)
+{
+ char *msg= NULL;
+
+ buf[0]= '\0'; /* failsafe */
+
+ if (nr <= 0)
+ {
+ strmake(buf, (nr == 0 ?
+ "Internal error/check (Not system error)" :
+ "Internal error < 0 (Not system error)"),
+ len-1);
+ return;
+ }
+
+ /*
+ These (handler-) error messages are shared by perror, as required
+ by the principle of least surprise.
+ */
+ if ((nr >= HA_ERR_FIRST) && (nr <= HA_ERR_LAST))
+ {
+ msg= (char *) handler_error_messages[nr - HA_ERR_FIRST];
+ strmake(buf, msg, len - 1);
+ }
+ else
+ {
+ /*
+ On Windows, do things the Windows way. On a system that supports both
+ the GNU and the XSI variant, use whichever was configured (GNU); if
+ this choice is not advertised, use the default (POSIX/XSI). Testing
+ for __GNUC__ is not sufficient to determine whether this choice exists.
+ */
+#if defined(__WIN__)
+ strerror_s(buf, len, nr);
+#elif ((defined _POSIX_C_SOURCE && (_POSIX_C_SOURCE >= 200112L)) || \
+ (defined _XOPEN_SOURCE && (_XOPEN_SOURCE >= 600))) && \
+ ! defined _GNU_SOURCE
+ strerror_r(nr, buf, len); /* I can build with or without GNU */
+#elif defined _GNU_SOURCE
+ char *r= strerror_r(nr, buf, len);
+ if (r != buf) /* Want to help, GNU? */
+ strmake(buf, r, len - 1); /* Then don't. */
+#else
+ strerror_r(nr, buf, len);
+#endif
+ }
+
+ /*
+ strerror() return values are implementation-dependent, so let's
+ be pragmatic.
+ */
+ if (!buf[0])
+ strmake(buf, "unknown error", len - 1);
+}