/*                                                                         
     +----------------------------------------------------------------------+
     | MySQL User Defined Functions Library & Plugin Library                |
     +----------------------------------------------------------------------+
     | Copyright (c) 2007 MySqdLib                                          |
     +----------------------------------------------------------------------+
     | 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; either version 2 of the License, or    |
     | (at your option) any later version.                                  |
     |                                                                      |
     | 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 |
     | USA                                                                  |
     +----------------------------------------------------------------------+
     | Authors: MMMed <momed @ users dot1 sourceforge dot2 net>       |
     +----------------------------------------------------------------------+
*/

/**
* MYSQL_UDF_API 
* 	i hop that ...
*	is a set of C macro to keep our code clean, clear and to make it easy to change more quickly 
* 	if MYSQL change here mined about UDF Interface on their SERVER/CLIENT products in the future, 
* 	or mabye I, will do :d 
*/

#if defined(WIN32) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#	define DLLEXP __declspec(dllexport) 
#	include <windows.h>
#else
#	define DLLEXP
#endif

#ifdef	__cplusplus
#	define EXTERN extern "C"
#endif

#ifdef STANDARD
#	include <stdlib.h>
#	include <stdio.h>
#	include <string.h>
#	ifdef __WIN__
		typedef unsigned __int64 ulonglong;
		typedef __int64 longlong;
#	else
		typedef unsigned long long ulonglong;
		typedef long long longlong;
#	endif
#else
#	include <my_global.h>
#	include <my_sys.h>
#	include <m_string.h> 
#endif

#include <mysql.h>
#include <ctype.h> 

#define MYSQL_UDF_API_VERSION                      1.0

#if defined(MYSQL_UDF_API_VERSION)

/* ERRORs handling, */ 
#   define INIT_ERROR(msg)          			   strcpy( message, msg ); return 1

/* ARGUMENTs processing (count, value, length and type), */
#   define ARGC                                    args->arg_count 
#   define ARGV(offset)                            args->args[offset]
#   define ARGL(offset)                            args->lengths[offset]
#   define ARGT(offset)                            args->arg_type[offset]

#   define IS_STRING_ARG(id)                       ARGT(id) == STRING_RESULT
#   define IS_DECIMAL_ARG(id)                      ARGT(id) == DECIMAL_RESULT
#   define IS_REAL_ARG(id)                         ARGT(id) == REAL_RESULT
#   define IS_INT_ARG(id)                          ARGT(id) == INT_RESULT

#   define TO_STRING_ARG(id)                       ARGT(id) = STRING_RESULT
#   define TO_DECIMAL_ARG(id)                      ARGT(id) = DECIMAL_RESULT
#   define TO_REAL_ARG(id)                         ARGT(id) = REAL_RESULT
#   define TO_INT_ARG(id)                          ARGT(id) = INT_RESULT

#   define TO_STRING_ARG_ALL                       for (uint i=0 ; i < ARGC; i++) TO_STRING_ARG(i)
#   define TO_DECIMAL_ARG_ALL                      for (uint i=0 ; i < ARGC; i++) TO_DECIMAL_ARG(i)
#   define TO_REAL_ARG_ALL                         for (uint i=0 ; i < ARGC; i++) TO_REAL_ARG(i)
#   define TO_INT_ARG_ALL                          for (uint i=0 ; i < ARGC; i++) TO_INT_ARG(i)

/* RETURNs macro, */
#   define RETURN_STRING(string)                   strcpy(result, (char *)string); *length = strlen(result); return result
#   define RETURN_DOUBLE(value)                    return (double) value
#   define RETURN_LONG(value)                      return (longlong) value
#   define RETURN_NULL                             return NULL

/* OTHERs macro, */
#   define ISNULL                                  *is_null = 1
#   define ISERROR                                 *error   = 1
#   define NOTNULL                                 *is_null = 0
#   define NOTERROR                                *error   = 0

/* FUNCTIONs definitions, */
#   define INIT_FUNCTION(function_name)            DLLEXP my_bool function_name##_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
#   define DEINIT_FUNCTION(function_name)          DLLEXP void    function_name##_deinit(UDF_INIT *initid)

#   define DEFINE_FUNCTION(function_name)          EXTERN INIT_FUNCTION(function_name); EXTERN DEINIT_FUNCTION(function_name)

#   define DEFINE_STRING_FUNCTION(function_name)   DEFINE_FUNCTION(function_name); EXTERN STRING_FUNCTION(function_name)
#   define DEFINE_DOUBLE_FUNCTION(function_name)   DEFINE_FUNCTION(function_name); EXTERN DOUBLE_FUNCTION(function_name)
#   define DEFINE_LONG_FUNCTION(function_name)     DEFINE_FUNCTION(function_name); EXTERN LONG_FUNCTION(function_name)

#   define LONG_FUNCTION(function_name)            DLLEXP longlong	function_name(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
#   define DOUBLE_FUNCTION(function_name)          DLLEXP double 	function_name(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
#   define STRING_FUNCTION(function_name)          DLLEXP char*  	function_name(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)

#   define MAYEBE_NULL(maybe_null)                 initid->maybe_null = maybe_null
#   define MAX_LENGTH(max_len)                     initid->max_length = max_len
#   define DECIMALS(decimals)                      initid->decimals   = decimals

/*THE 3 on one line, with the very basic args_type paraser, */
#   define FUNCTION(fname, ftype, arg_t, arg_c, maybenull, maxlen, usage)                                   \
        DEFINE_##ftype##_FUNCTION( fname );                                                                 \
                                                                                                            \
        INIT_FUNCTION( fname )                                                                              \
    	{                                                                                                   \
            int i = 0, j = 0 ;                                                                              \
                                                                                                            \
        	if ( ARGC < arg_c )                                                                             \
            {                                                                                               \
                INIT_ERROR( usage );                                                                        \
            }                                                                                               \
                                                                                                            \
        	for (; i < strlen( arg_t ); i++ )                                                               \
        	{                                                                                               \
                switch ( arg_t[i] )                                                                         \
                {                                                                                           \
                    case 'S': TO_STRING_ARG( j ); break;                                                    \
                    case 'R': TO_REAL_ARG( j );   break;                                                    \
                    case 'I': TO_INT_ARG( j );    break;                                                    \
                    case ';': j++ ;               break;                                                    \
                    default : INIT_ERROR( "ierror : error while parsing params in FUNCTION " );             \
                }                                                                                           \
            }                                                                                               \
                                                                                                            \
            initid->maybe_null = maybenull;                                                                 \
            initid->max_length = maxlen;                                                                    \
                                                                                                            \
        	return 0;                                                                                       \
        }                                                                                                   \
                                                                                                            \
        DEINIT_FUNCTION( fname )                                                                            \
    	{                                                                                                   \
        }                                                                                                   \
                                                                                                            \
        ftype##_FUNCTION( fname )                                                                           \

#endif

/* ____ENDOFFILE____ */