feat: 增加参数范围检查处理功能函数和宏定义

This commit is contained in:
const_zpc@163.com 2023-06-17 23:54:49 +08:00
parent 05e19eebba
commit 5eddb6be6b
4 changed files with 246 additions and 47 deletions

View File

@ -307,30 +307,68 @@
#define _PARAM_STR_PARAM_DEF(name, def, min_or_max) (strcpy(name, def##_##name))
#define _PARAM_STR_PARAM_MIN_MAX(name, def, min_or_max) (0)
/**
* @brief 使 PARAM_DEFINE_DAT_RANGE
*
* @attention 使使 PARAM_EXTERN_DAT
* @param name
* @param opt
* @arg PARAM_NONE, ,
* @arg PARAM_DEF,
* @arg PARAM_MIN_MAX, , ; ,
* @return 0,; 1,; 2,
*/
#define PARAM_DAT_CHECK_RANGE(name, opt) \
(PARAM_DAT_CUR_VALUE(name) < PARAM_DAT_MIN_VALUE(name) ? (_PARAM_DAT_##opt(name, def, min), 1) : \
PARAM_DAT_CUR_VALUE(name) > PARAM_DAT_MAX_VALUE(name) ? (_PARAM_DAT_##opt(name, def, max), 2) : 0)
/**
* @brief 使 PARAM_DEFINE_STR_RANGE
*
* @attention 使使 PARAM_EXTERN_STR
* @param name
* @param opt
* @arg PARAM_NONE, ,
* @arg PARAM_DEF,
* @arg PARAM_MIN_MAX, , ; ,
* @return 0,; 1,; 2,
*/
#define PARAM_STR_CHECK_RANGE(name, opt) \
(strlen(PARAM_STR_CUR_VALUE(name)) < PARAM_STR_MIN_LENGTH(name) ? (_PARAM_STR_##opt(name, def, min), 1) : \
strlen(PARAM_STR_CUR_VALUE(name)) > PARAM_STR_MAX_LENGTH(name) ? (_PARAM_STR_##opt(name, def, max), 2) : 0)
/**
* @brief 使 PARAM_DEFINE_DAT_RANGE
*
* @attention 使使 PARAM_EXTERN_DAT
* @param name
* @param val
* @param opt PARAM_NONE,PARAM_DEF,PARAM_MIN_MAX,
* @return 0,-1,1,
* @param opt
* @arg PARAM_NONE, ,
* @arg PARAM_DEF,
* @arg PARAM_MIN_MAX, ,
* @return 0,; 1,; 2,
*/
#define PARAM_DAT_SET_NEW_VALUE(name, val, opt) \
(val < PARAM_DAT_MIN_VALUE(name) ? (_PARAM_DAT_##opt(name, def, min), -1) : \
val > PARAM_DAT_MAX_VALUE(name) ? (_PARAM_DAT_##opt(name, def, max), 1) : \
(val < PARAM_DAT_MIN_VALUE(name) ? (_PARAM_DAT_##opt(name, def, min), 1) : \
val > PARAM_DAT_MAX_VALUE(name) ? (_PARAM_DAT_##opt(name, def, max), 2) : \
(PARAM_DAT_CUR_VALUE(name) = val, 0))
/**
* @brief 使 PARAM_DEFINE_STR_RANGE
*
* @attention 使使 PARAM_EXTERN_STR
* @param name
* @param val
* @param opt PARAM_NONE PARAM_MIN_MAX,, PARAM_DEF,
* @return 0,-1,1,
* @param opt
* @arg PARAM_NONE, ,
* @arg PARAM_DEF,
* @arg PARAM_MIN_MAX, , ,
* @return 0,; 1,; 2,
*/
#define PARAM_STR_SET_NEW_VALUE(name, str, opt) \
(strlen(str) < PARAM_STR_MIN_LENGTH(name) ? (_PARAM_STR_##opt(name, def, min), -1) : \
strlen(str) > PARAM_STR_MAX_LENGTH(name) ? (_PARAM_STR_##opt(name, def, max), 1) : \
(strlen(str) < PARAM_STR_MIN_LENGTH(name) ? (_PARAM_STR_##opt(name, def, min), 1) : \
strlen(str) > PARAM_STR_MAX_LENGTH(name) ? (_PARAM_STR_##opt(name, def, max), 2) : \
(strcpy(PARAM_STR_CUR_VALUE(name), str), 0))
// 得到参数表的元素数目
@ -349,6 +387,8 @@ extern const ParamInfo_t *Param_FindParamByName(ParamManager_t *manager, const c
extern const ParamInfo_t *Param_FindParamByID(ParamManager_t* manager, uint16_t id);
extern const ParamInfo_t *Param_FindParamByParamPtr(ParamManager_t* manager, const void *curParamPtr);
extern int Param_CheckRange(const ParamInfo_t *param, uint8_t opt);
extern int Param_SetNewValue(const ParamInfo_t *param, const void *value, uint8_t opt);
extern bool Param_ResetDefaultValue(const ParamInfo_t *param);
extern bool Param_ResetMinValue(const ParamInfo_t *param);

View File

@ -28,7 +28,7 @@ typedef union
uint64_t u64val;
int64_t s64val;
double fVal;
char str[PARAM_STRING_MAX_LENGTH];
char str[PARAM_STRING_MAX_LENGTH + 2];
} Value_u;
static uint8_t *SerializeUint(uint8_t *ptr, uint64_t value, uint8_t len)
@ -394,7 +394,7 @@ const ParamInfo_t *Param_FindParamByParamPtr(ParamManager_t *manager, const void
// 验证参数是否在指定范围内
int ValidateRange(const ParamInfo_t *param, const Value_u *pval)
static int ValidateRange(const ParamInfo_t *param, const Value_u *pval)
{
if (!(param->attr & PARAM_ATTR_RANGE))
{
@ -406,125 +406,125 @@ int ValidateRange(const ParamInfo_t *param, const Value_u *pval)
case PARAM_INT8:
if (pval->s64val < *param->unMinValuePtr.pInt8)
{
return -1;
return 1;
}
else if (pval->s64val > *param->unMaxValuePtr.pInt8)
{
return 1;
return 2;
}
break;
case PARAM_INT16:
if (pval->s64val < *param->unMinValuePtr.pInt16)
{
return -1;
return 1;
}
else if (pval->s64val > *param->unMaxValuePtr.pInt16)
{
return 1;
return 2;
}
break;
case PARAM_INT32:
if (pval->s64val < *param->unMinValuePtr.pInt32)
{
return -1;
return 1;
}
else if (pval->s64val > *param->unMaxValuePtr.pInt32)
{
return 1;
return 2;
}
break;
case PARAM_INT64:
if (pval->s64val < *param->unMinValuePtr.pInt64)
{
return -1;
return 1;
}
else if (pval->s64val > *param->unMaxValuePtr.pInt64)
{
return 1;
return 2;
}
break;
case PARAM_UINT8:
if (pval->u64val < *param->unMinValuePtr.pUint8)
{
return -1;
return 1;
}
else if (pval->u64val > *param->unMaxValuePtr.pUint8)
{
return 1;
return 2;
}
break;
case PARAM_UINT16:
if (pval->u64val < *param->unMinValuePtr.pUint16)
{
return -1;
return 1;
}
else if (pval->u64val > *param->unMaxValuePtr.pUint16)
{
return 1;
return 2;
}
break;
case PARAM_UINT32:
if (pval->u64val < *param->unMinValuePtr.pUint32)
{
return -1;
return 1;
}
else if (pval->u64val > *param->unMaxValuePtr.pUint32)
{
return 1;
return 2;
}
break;
case PARAM_UINT64:
if (pval->u64val < *param->unMinValuePtr.pUint64)
{
return -1;
return 1;
}
else if (pval->u64val > *param->unMaxValuePtr.pUint64)
{
return 1;
return 2;
}
break;
case PARAM_FLOAT:
if (pval->fVal < *param->unMinValuePtr.pFloat)
{
return -1;
return 1;
}
else if (pval->fVal > *param->unMaxValuePtr.pFloat)
{
return 1;
return 2;
}
break;
case PARAM_DOUBLE:
if (pval->fVal < *param->unMinValuePtr.pDouble)
{
return -1;
return 1;
}
else if (pval->fVal > *param->unMaxValuePtr.pDouble)
{
return 1;
return 2;
}
break;
case PARAM_STRING:
if (strlen(pval->str) < *param->unMinValuePtr.pStringLength)
{
return -1;
return 1;
}
else if (strlen(pval->str) > *param->unMaxValuePtr.pStringLength)
{
return 1;
return 2;
}
break;
default:
return -2;
return -1;
}
return 0;
@ -577,23 +577,64 @@ static int ValidateRangeByVoid(const ParamInfo_t *param, const void *pval)
break;
case PARAM_STRING:
memcpy(uValue.str, pval, strlen(pval) > PARAM_STRING_MAX_LENGTH ? PARAM_STRING_MAX_LENGTH - 1 : strlen(pval));
memcpy(uValue.str, pval, strlen(pval) > PARAM_STRING_MAX_LENGTH ? PARAM_STRING_MAX_LENGTH + 2 : strlen(pval) + 1);
uValue.str[PARAM_STRING_MAX_LENGTH + 2] = '\0';
break;
default:
return -2;
return -1;
}
return ValidateRange(param, &uValue);
}
/**
* @brief
*
* @param param
* @param opt
* @arg PARAM_NONE, ,
* @arg PARAM_DEF,
* @arg PARAM_MIN_MAX, , ; ,
* @return 0,; 1,(); 2,(); <0,
*/
int Param_CheckRange(const ParamInfo_t *param, uint8_t opt)
{
int ret;
if (param == NULL)
{
return -1; // 参数验证失败
}
ret = ValidateRangeByVoid(param, param->unCurValuePtr.pVoid);
if (ret != 0)
{
if (opt == PARAM_DEF)
{
ResetParamValue(param);
}
else if (opt == PARAM_MIN_MAX)
{
ret == 1 ? ResetParamMinValue(param) : ResetParamMaxValue(param);
}
return ret;
}
return 0;
}
/**
* @brief
*
* @attention PARAM_MIN_MAX PARAM_NONE
* @param param
* @param value
* @param opt PARAM_NONE,PARAM_DEF,PARAM_MIN_MAX,
* @return 0,-1,1,
* @param opt
* @arg PARAM_NONE, ,
* @arg PARAM_DEF,
* @arg PARAM_MIN_MAX, , ; ,
* @return 0,; 1,(); 2,(); <0,
*/
int Param_SetNewValue(const ParamInfo_t *param, const void *value, uint8_t opt)
{
@ -601,7 +642,7 @@ int Param_SetNewValue(const ParamInfo_t *param, const void *value, uint8_t opt)
if (param == NULL)
{
return -2; // 参数验证失败
return -1;
}
ret = ValidateRangeByVoid(param, value);
@ -614,7 +655,7 @@ int Param_SetNewValue(const ParamInfo_t *param, const void *value, uint8_t opt)
}
else if (opt == PARAM_MIN_MAX)
{
ret == -1 ? ResetParamMinValue(param) : ResetParamMaxValue(param);
ret == 1 ? ResetParamMinValue(param) : ResetParamMaxValue(param);
}
return ret;

View File

View File

@ -263,31 +263,146 @@ void test_FindParam(void)
TEST_ASSERT_EQUAL_PTR(NULL, paramInfo);
}
void test_CheckRange(void)
{
g_test_u16 = 60;
TEST_ASSERT_EQUAL_INT(1, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), PARAM_NONE));
g_test_u16 = 120;
TEST_ASSERT_EQUAL_INT(0, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), PARAM_NONE));
g_test_u16 = 4000;
TEST_ASSERT_EQUAL_INT(2, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), PARAM_NONE));
g_test_u16 = 60;
TEST_ASSERT_EQUAL_INT(1, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
g_test_u16 = 4000;
TEST_ASSERT_EQUAL_INT(2, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
g_test_u16 = 60;
TEST_ASSERT_EQUAL_INT(1, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
g_test_u16 = 4000;
TEST_ASSERT_EQUAL_INT(2, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(3000, PARAM_DAT_CUR_VALUE(g_test_u16));
snprintf(g_test_str, sizeof(g_test_str), "ABCDEF");
TEST_ASSERT_EQUAL_INT(0, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), PARAM_NONE));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
snprintf(g_test_str, sizeof(g_test_str), "AB");
TEST_ASSERT_EQUAL_INT(1, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("AB", g_test_str);
snprintf(g_test_str, sizeof(g_test_str), "abcdefg123456");
TEST_ASSERT_EQUAL_INT(0, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("abcdefg12", g_test_str);
snprintf(g_test_str, sizeof(g_test_str), "AB");
TEST_ASSERT_EQUAL_INT(1, Param_CheckRange(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), PARAM_DEF));
TEST_ASSERT_EQUAL_STRING("abcdef", g_test_str);
}
void test_CheckRangeMacroDefine(void)
{
g_test_u16 = 60;
TEST_ASSERT_EQUAL_INT(1, PARAM_DAT_CHECK_RANGE(g_test_u16, PARAM_NONE));
g_test_u16 = 120;
TEST_ASSERT_EQUAL_INT(0, PARAM_DAT_CHECK_RANGE(g_test_u16, PARAM_NONE));
g_test_u16 = 4000;
TEST_ASSERT_EQUAL_INT(2, PARAM_DAT_CHECK_RANGE(g_test_u16, PARAM_NONE));
g_test_u16 = 60;
TEST_ASSERT_EQUAL_INT(1, PARAM_DAT_CHECK_RANGE(g_test_u16, PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
g_test_u16 = 4000;
TEST_ASSERT_EQUAL_INT(2, PARAM_DAT_CHECK_RANGE(g_test_u16, PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
g_test_u16 = 60;
TEST_ASSERT_EQUAL_INT(1, PARAM_DAT_CHECK_RANGE(g_test_u16, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
g_test_u16 = 4000;
TEST_ASSERT_EQUAL_INT(2, PARAM_DAT_CHECK_RANGE(g_test_u16, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(3000, PARAM_DAT_CUR_VALUE(g_test_u16));
snprintf(g_test_str, sizeof(g_test_str), "ABCDEF");
TEST_ASSERT_EQUAL_INT(0, PARAM_STR_CHECK_RANGE(g_test_str, PARAM_NONE));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
snprintf(g_test_str, sizeof(g_test_str), "AB");
TEST_ASSERT_EQUAL_INT(1, PARAM_STR_CHECK_RANGE(g_test_str, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("AB", g_test_str);
snprintf(g_test_str, sizeof(g_test_str), "abcdefg123456");
TEST_ASSERT_EQUAL_INT(0, PARAM_STR_CHECK_RANGE(g_test_str, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("abcdefg12", g_test_str);
snprintf(g_test_str, sizeof(g_test_str), "AB");
TEST_ASSERT_EQUAL_INT(1, PARAM_STR_CHECK_RANGE(g_test_str, PARAM_DEF));
TEST_ASSERT_EQUAL_STRING("abcdef", g_test_str);
}
void test_SetNewValue(void)
{
PARAM_UINT16_T tmp = 60;
tmp = 60;
TEST_ASSERT_EQUAL_INT(-1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_NONE));
TEST_ASSERT_EQUAL_INT(1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_NONE));
tmp = 120;
TEST_ASSERT_EQUAL_INT(0, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_NONE));
tmp = 4000;
TEST_ASSERT_EQUAL_INT(1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_NONE));
TEST_ASSERT_EQUAL_INT(2, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_NONE));
tmp = 60;
TEST_ASSERT_EQUAL_INT(-1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
tmp = 4000;
TEST_ASSERT_EQUAL_INT(1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
tmp = 4000;
TEST_ASSERT_EQUAL_INT(2, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
tmp = 60;
TEST_ASSERT_EQUAL_INT(-1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_INT(1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
tmp = 4000;
TEST_ASSERT_EQUAL_INT(1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_INT(2, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, &g_test_u16), &tmp, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(3000, PARAM_DAT_CUR_VALUE(g_test_u16));
TEST_ASSERT_EQUAL_INT(0, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), "ABCDEF", PARAM_NONE));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
TEST_ASSERT_EQUAL_INT(1, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), "AB", PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
TEST_ASSERT_EQUAL_INT(2, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), "abcdefg123456", PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
TEST_ASSERT_EQUAL_INT(2, Param_SetNewValue(Param_FindParamByParamPtr(&sg_tParamManager, g_test_str), "abcdefg123456", PARAM_DEF));
TEST_ASSERT_EQUAL_STRING("abcdef", g_test_str);
}
void test_SetNewValueMacroDefine(void)
{
PARAM_UINT16_T tmp = 60;
tmp = 60;
TEST_ASSERT_EQUAL_INT(1, PARAM_DAT_SET_NEW_VALUE(g_test_u16, tmp, PARAM_NONE));
tmp = 120;
TEST_ASSERT_EQUAL_INT(0, PARAM_DAT_SET_NEW_VALUE(g_test_u16, tmp, PARAM_NONE));
tmp = 4000;
TEST_ASSERT_EQUAL_INT(2, PARAM_DAT_SET_NEW_VALUE(g_test_u16, tmp, PARAM_NONE));
tmp = 60;
TEST_ASSERT_EQUAL_INT(1, PARAM_DAT_SET_NEW_VALUE(g_test_u16, tmp, PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
tmp = 4000;
TEST_ASSERT_EQUAL_INT(2, PARAM_DAT_SET_NEW_VALUE(g_test_u16, tmp, PARAM_DEF));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
tmp = 60;
TEST_ASSERT_EQUAL_INT(1, PARAM_DAT_SET_NEW_VALUE(g_test_u16, tmp, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(100, PARAM_DAT_CUR_VALUE(g_test_u16));
tmp = 4000;
TEST_ASSERT_EQUAL_INT(2, PARAM_DAT_SET_NEW_VALUE(g_test_u16, tmp, PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_UINT(3000, PARAM_DAT_CUR_VALUE(g_test_u16));
TEST_ASSERT_EQUAL_INT(0, PARAM_STR_SET_NEW_VALUE(g_test_str, "ABCDEF", PARAM_NONE));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
TEST_ASSERT_EQUAL_INT(1, PARAM_STR_SET_NEW_VALUE(g_test_str, "AB", PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
TEST_ASSERT_EQUAL_INT(2, PARAM_STR_SET_NEW_VALUE(g_test_str, "abcdefg123456", PARAM_MIN_MAX));
TEST_ASSERT_EQUAL_STRING("ABCDEF", g_test_str);
TEST_ASSERT_EQUAL_INT(2, PARAM_STR_SET_NEW_VALUE(g_test_str, "abcdefg123456", PARAM_DEF));
TEST_ASSERT_EQUAL_STRING("abcdef", g_test_str);
}
void test_ResetValue(void)
@ -313,7 +428,10 @@ int main(void)
RUN_TEST(test_SaveAndLoadParam);
RUN_TEST(test_IterateParam);
RUN_TEST(test_FindParam);
RUN_TEST(test_CheckRange);
RUN_TEST(test_CheckRangeMacroDefine);
RUN_TEST(test_SetNewValue);
RUN_TEST(test_SetNewValueMacroDefine);
RUN_TEST(test_ResetValue);
UNITY_END();