/******************************************************************** * COPYRIGHT: * Copyright (c) 1997-2001, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /******************************************************************************* * * File CNMDPTST.C * * Madhu Katragadda Creation * Modification History: * * Date Name Description * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes ******************************************************************************* */ /* C DEPTH TEST FOR NUMBER FORMAT */ #include "unicode/uloc.h" #include "unicode/utypes.h" #include "unicode/unum.h" #include "unicode/ustring.h" #include "cintltst.h" #include "cnmdptst.h" #include "cmemory.h" #define CHECK(status,str) if (U_FAILURE(status)) { log_err("FAIL: %s\n", str); return; } void addNumFrDepTest(TestNode** root); static void TestCurrencyPreEuro(); void addNumFrDepTest(TestNode** root) { addTest(root, &TestPatterns, "tsformat/cnmdptst/TestPatterns"); addTest(root, &TestQuotes, "tsformat/cnmdptst/TestQuotes"); addTest(root, &TestExponential, "tsformat/cnmdptst/TestExponential"); addTest(root, &TestCurrencySign, "tsformat/cnmdptst/TestCurrencySign"); addTest(root, &TestCurrency, "tsformat/cnmdptst/TestCurrency"); addTest(root, &TestCurrencyPreEuro, "tsformat/cnmdptst/TestCurrencyPreEuro"); addTest(root, &TestRounding487, "tsformat/cnmdptst/TestRounding487"); addTest(root, &TestDoubleAttribute, "tsformat/cnmdptst/TestDoubleAttribute"); addTest(root, &TestSecondaryGrouping, "tsformat/cnmdptst/TestSecondaryGrouping"); } /*Test Various format patterns*/ static void TestPatterns(void) { int32_t pat_length, i, lneed; UNumberFormat *fmt; UChar upat[5]; UChar unewpat[5]; UChar unum[5]; UChar *unewp=NULL; UChar *str=NULL; UErrorCode status = U_ZERO_ERROR; const char* pat[] = { "#.#", "#.", ".#", "#" }; const char* newpat[] = { "#0.#", "#0.", "#.0", "#" }; const char* num[] = { "0", "0.", ".0", "0" }; log_verbose("\nTesting different format patterns\n"); pat_length = sizeof(pat) / sizeof(pat[0]); for (i=0; i < pat_length; ++i) { status = U_ZERO_ERROR; u_uastrcpy(upat, pat[i]); fmt= unum_open(UNUM_IGNORE,upat, u_strlen(upat), "en_US",NULL, &status); if (U_FAILURE(status)) { log_err("FAIL: Number format constructor failed for pattern %s\n", pat[i]); continue; } lneed=0; lneed=unum_toPattern(fmt, FALSE, NULL, lneed, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status= U_ZERO_ERROR; unewp=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); unum_toPattern(fmt, FALSE, unewp, lneed+1, &status); } if(U_FAILURE(status)){ log_err("FAIL: Number format extracting the pattern failed for %s\n", pat[i]); } u_uastrcpy(unewpat, newpat[i]); if(u_strcmp(unewp, unewpat) != 0) log_err("FAIL: Pattern %s should be transmute to %s; %s seen instead\n", pat[i], newpat[i], austrdup(unewp) ); lneed=0; lneed=unum_format(fmt, 0, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); unum_format(fmt, 0, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } u_uastrcpy(unum, num[i]); if (u_strcmp(str, unum) != 0) { log_err("FAIL: Pattern %s should format zero as %s; %s Seen instead\n", pat[i], num[i], austrdup(str) ); } uprv_free(unewp); uprv_free(str); unum_close(fmt); } } /* Test the handling of quotes*/ static void TestQuotes(void) { int32_t lneed; UErrorCode status=U_ZERO_ERROR; UChar pat[15]; UChar res[15]; UChar *str=NULL; UNumberFormat *fmt; char tempBuf[256]; log_verbose("\nTestting the handling of quotes in number format\n"); u_uastrcpy(pat, "a'fo''o'b#"); fmt =unum_open(UNUM_IGNORE,pat, u_strlen(pat), "en_US",NULL, &status); if(U_FAILURE(status)){ log_err("Error in number format costruction using pattern \"a'fo''o'b#\"\n"); } lneed=0; lneed=unum_format(fmt, 123, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); unum_format(fmt, 123, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } log_verbose("Pattern \"%s\" \n", u_austrcpy(tempBuf, pat) ); log_verbose("Format 123 -> %s\n", u_austrcpy(tempBuf, str) ); u_uastrcpy(res, "afo'ob123"); if(u_strcmp(str, res) != 0) log_err("FAIL: Expected afo'ob123"); uprv_free(str); unum_close(fmt); u_uastrcpy(pat, ""); u_uastrcpy(pat, "a''b#"); fmt =unum_open(UNUM_IGNORE,pat, u_strlen(pat), "en_US",NULL, &status); if(U_FAILURE(status)){ log_err("Error in number format costruction using pattern \"a''b#\"\n"); } lneed=0; lneed=unum_format(fmt, 123, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); unum_format(fmt, 123, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } log_verbose("Pattern \"%s\" \n", u_austrcpy(tempBuf, pat) ); log_verbose("Format 123 -> %s\n", u_austrcpy(tempBuf, str) ); u_uastrcpy(res, ""); u_uastrcpy(res, "a'b123"); if(u_strcmp(str, res) != 0) log_err("FAIL: Expected a'b123\n"); uprv_free(str); unum_close(fmt); } /* Test exponential pattern*/ static void TestExponential(void) { int32_t pat_length, val_length, lval_length; int32_t ival, ilval, p, v, lneed; UNumberFormat *fmt; int32_t ppos; UChar *upat; UChar pattern[20]; UChar *str=NULL; UChar uvalfor[20], ulvalfor[20]; char tempMsgBug[256]; double a; UErrorCode status = U_ZERO_ERROR; #ifdef OS390 double val[] = { 0.01234, 123456789, 1.23e75, -3.141592653e-78 }; #else double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 }; #endif const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" }; int32_t lval[] = { 0, -1, 1, 123456789 }; const char* valFormat[] = { "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271", "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272", "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273", "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]" }; const char* lvalFormat[] = { "0E0", "-1E0", "1E0", "1.2346E8", "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07", "0E000", "-1E000", "1E000", "123.4568E006", "0E0", "[1E0]", "1E0", "1.235E8" }; double valParse[] = { #ifdef OS390 0.01234, 123460000, 1.23E75, -3.1416E-78, 0.01234, 123460000, 1.23E75, -3.1416E-78, 0.01234, 123456800, 1.23E75, -3.141593E-78, 0.01234, 123500000, 1.23E75, -3.142E-78 #else 0.01234, 123460000, 1.23E300, -3.1416E-271, 0.01234, 123460000, 1.23E300, -3.1416E-271, 0.01234, 123456800, 1.23E300, -3.141593E-271, 0.01234, 123500000, 1.23E300, -3.142E-271 #endif }; int32_t lvalParse[] = { 0, -1, 1, 123460000, 0, -1, 1, 123460000, 0, -1, 1, 123456800, 0, -1, 1, 123500000 }; pat_length = sizeof(pat) / sizeof(pat[0]); val_length = sizeof(val) / sizeof(val[0]); lval_length = sizeof(lval) / sizeof(lval[0]); ival = 0; ilval = 0; for (p=0; p < pat_length; ++p) { upat=(UChar*)uprv_malloc(sizeof(UChar) * (strlen(pat[p])+1) ); u_uastrcpy(upat, pat[p]); fmt=unum_open(UNUM_IGNORE,upat, u_strlen(upat), "en_US",NULL, &status); if (U_FAILURE(status)) { log_err("FAIL: Bad status returned by Number format construction with pattern %s\n, pat[i]"); continue; } lneed= u_strlen(upat) + 1; unum_toPattern(fmt, FALSE, pattern, lneed, &status); log_verbose("Pattern \" %s \" -toPattern-> \" %s \" \n", upat, u_austrcpy(tempMsgBug, pattern) ); for (v=0; v %e\n", ppos, a); uprv_free(str); } for (v=0; v %s\n", lval[v], austrdup(str) );*/ u_uastrcpy(ulvalfor, lvalFormat[v+ilval]); if(u_strcmp(str, ulvalfor) != 0) log_err("FAIL: Expected %s ( %s )\n", valFormat[v+ilval], austrdup(ulvalfor) ); /*parsing*/ ppos=0; a=unum_parseDouble(fmt, str, u_strlen(str), &ppos, &status); if (ppos== u_strlen(str)) { /*printf(" Parse -> %e\n", a);*/ if (a != lvalParse[v+ilval]) log_err("FAIL: Expected : %e\n", valParse[v+ival]); } else log_err(" FAIL: Partial parse ( %d chars ) -> %e\n", ppos, a); uprv_free(str); } ival += val_length; ilval += lval_length; unum_close(fmt); uprv_free(upat); } } /** * Test the handling of the currency symbol in patterns. */ static void TestCurrencySign(void) { int32_t lneed; UNumberFormat *fmt; UChar *pattern=NULL; UChar *str=NULL; UChar *pat=NULL; UChar *res=NULL; UErrorCode status = U_ZERO_ERROR; char tempBuf[256]; pattern=(UChar*)uprv_malloc(sizeof(UChar) * (strlen("*#,##0.00;-*#,##0.00") + 1) ); u_uastrcpy(pattern, "*#,##0.00;-*#,##0.00"); pattern[0]=pattern[11]=0xa4; /* insert latin-1 currency symbol */ fmt = unum_open(UNUM_IGNORE,pattern, u_strlen(pattern), "en_US",NULL, &status); if(U_FAILURE(status)){ log_err("Error in number format construction with pattern \"\\xA4#,##0.00;-\\xA4#,##0.00\\\" \n"); } lneed=0; lneed=unum_formatDouble(fmt, 1234.56, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, 1234.56, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } lneed=0; lneed=unum_toPattern(fmt, FALSE, NULL, lneed, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; pat=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, FALSE, pat, lneed+1, NULL, &status); } log_verbose("Pattern \" %s \" \n", u_austrcpy(tempBuf, pat)); log_verbose("Format 1234.56 -> %s\n", u_austrcpy(tempBuf, str) ); res=(UChar*)uprv_malloc(sizeof(UChar) * (strlen("$1,234.56")+1) ); u_uastrcpy(res, "$1,234.56"); if (u_strcmp(str, res) !=0) log_err("FAIL: Expected $1,234.56\n"); uprv_free(str); uprv_free(res); uprv_free(pat); lneed=0; lneed=unum_formatDouble(fmt, -1234.56, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, -1234.56, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } res=(UChar*)uprv_malloc(sizeof(UChar) * (strlen("-$1,234.56")+1) ); u_uastrcpy(res, "-$1,234.56"); if (u_strcmp(str, res) != 0) log_err("FAIL: Expected -$1,234.56\n"); uprv_free(str); uprv_free(res); unum_close(fmt); uprv_free(pattern); } /** * Test localized currency patterns. */ static void TestCurrency(void) { UNumberFormat *currencyFmt; UChar *str=NULL, *res=NULL; int32_t lneed, i; UFieldPosition pos; char cStr[100]; UErrorCode status = U_ZERO_ERROR; const char* locale[]={"fr_CA", "de_DE_PREEURO", "fr_FR_PREEURO"}; const char* result[]={"1,50 $", "1,50 DM", "1,50 F"}; log_verbose("\nTesting the number format with different currency patterns\n"); for(i=0; i < 3; i++) { cStr[0]=0; currencyFmt = unum_open(UNUM_CURRENCY, NULL,0,locale[i],NULL, &status); if(U_FAILURE(status)){ log_err("Error in the construction of number format with style currency:\n%s\n", myErrorName(status)); } lneed=0; lneed= unum_formatDouble(currencyFmt, 1.50, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); pos.field = 0; unum_formatDouble(currencyFmt, 1.50, str, lneed+1, &pos, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status) ); } res=(UChar*)uprv_malloc(sizeof(UChar) * (strlen(result[i])+1) ); u_uastrcpy(res, result[i]); u_UCharsToChars(str,cStr,u_strlen(res)); if (u_strcmp(str, res) != 0){ log_err("FAIL: Expected %s Got: %s for locale: %s\n", result[i],cStr,locale[i]); } unum_close(currencyFmt); uprv_free(str); uprv_free(res); } } /** * Test localized currency patterns for PREEURO variants. */ static void TestCurrencyPreEuro(void) { UNumberFormat *currencyFmt; UChar *str=NULL, *res=NULL; int32_t lneed, i; UFieldPosition pos; UErrorCode status = U_ZERO_ERROR; const char* locale[]={ "ca_ES_PREEURO", "de_LU_PREEURO", "en_IE_PREEURO", "fi_FI_PREEURO", "fr_LU_PREEURO", "it_IT_PREEURO", "pt_PT_PREEURO", "de_AT_PREEURO", "el_GR_PREEURO", "es_ES_PREEURO", "fr_BE_PREEURO", "ga_IE_PREEURO", "nl_BE_PREEURO", "de_DE_PREEURO", "en_BE_PREEURO", "eu_ES_PREEURO", "fr_FR_PREEURO", "gl_ES_PREEURO", "nl_NL_PREEURO", }; const char* result[]={ "Pts 2", "2 F", "IR\\u00A31.50", "1,50 mk", "1,50 F", "L. 2", "2 Esc.", "\\u00F6S 1,50", "1,50 \\u0394\\u03C1\\u03C7", "2 Pts", "1,50 FB", "\\u00a31.50", "1,50 BF", "1,50 DM", "1,50 BF", "Pts 1,5", "1,50 F", "Pta 1,5", "fl 1,50" }; log_verbose("\nTesting the number format with different currency patterns\n"); for(i=0; i < 19; i++) { char cStr[20]={0}; currencyFmt = unum_open(UNUM_CURRENCY, NULL,0,locale[i],NULL, &status); if(U_FAILURE(status)){ log_err("Error in the construction of number format with style currency:\n%s\n", myErrorName(status)); } lneed=0; lneed= unum_formatDouble(currencyFmt, 1.50, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); pos.field = 0; unum_formatDouble(currencyFmt, 1.50, str, lneed+1, &pos, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status) ); } res=(UChar*)uprv_malloc(sizeof(UChar) * (strlen(result[i])+1) ); u_unescape(result[i],res,strlen(result[i])+1); u_UCharsToChars(str,cStr,u_strlen(str)); if (u_strcmp(str, res) != 0){ log_err("FAIL: Expected %s Got: %s for locale: %s\n", result[i],cStr,locale[i]); } unum_close(currencyFmt); uprv_free(str); uprv_free(res); } } /** * Test proper rounding by the format method. */ static void TestRounding487(void) { UNumberFormat *nnf; UErrorCode status = U_ZERO_ERROR; /* this is supposed to open default date format, but later on it treats it like it is "en_US" - very bad if you try to run the tests on machine where default locale is NOT "en_US" */ /* nnf = unum_open(UNUM_DEFAULT, NULL, &status); */ nnf = unum_open(UNUM_DEFAULT, NULL,0,"en_US",NULL, &status); if(U_FAILURE(status)){ log_err("FAIL: failure in the construction of number format: %s\n", myErrorName(status)); } roundingTest(nnf, 0.00159999, 4, "0.0016"); roundingTest(nnf, 0.00995, 4, "0.01"); roundingTest(nnf, 12.3995, 3, "12.4"); roundingTest(nnf, 12.4999, 0, "12"); roundingTest(nnf, - 19.5, 0, "-20"); unum_close(nnf); } /*-------------------------------------*/ static void roundingTest(UNumberFormat* nf, double x, int32_t maxFractionDigits, const char* expected) { UChar *out = NULL; UChar *res; UFieldPosition pos; UErrorCode status; int32_t lneed; status=U_ZERO_ERROR; unum_setAttribute(nf, UNUM_MAX_FRACTION_DIGITS, maxFractionDigits); lneed=0; lneed=unum_formatDouble(nf, x, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; out=(UChar*)uprv_malloc(sizeof(UChar) * (lneed+1) ); pos.field=0; unum_formatDouble(nf, x, out, lneed+1, &pos, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status) ); } /*Need to use log_verbose here. Problem with the float*/ /*printf("%f format with %d fraction digits to %s\n", x, maxFractionDigits, austrdup(out) );*/ res=(UChar*)uprv_malloc(sizeof(UChar) * (strlen(expected)+1) ); u_uastrcpy(res, expected); if (u_strcmp(out, res) != 0) log_err("FAIL: Expected: %s or %s\n", expected, austrdup(res) ); uprv_free(res); if(out != NULL) { uprv_free(out); } } /* * Testing unum_getDoubleAttribute and unum_setDoubleAttribute() */ static void TestDoubleAttribute(void) { double mydata[] = { 1.11, 22.22, 333.33, 4444.44, 55555.55, 666666.66, 7777777.77, 88888888.88, 999999999.99}; double dvalue; int i; UErrorCode status=U_ZERO_ERROR; UNumberFormatAttribute attr; UNumberFormatStyle style= UNUM_DEFAULT; UNumberFormat *def; def=unum_open(style, NULL,0,NULL,NULL, &status); log_verbose("\nTesting get and set DoubleAttributes\n"); attr=UNUM_ROUNDING_INCREMENT; dvalue=unum_getDoubleAttribute(def, attr); for (i = 0; i<9 ; i++) { dvalue = mydata[i]; unum_setDoubleAttribute(def, attr, dvalue); if(unum_getDoubleAttribute(def,attr)!=mydata[i]) log_err("Fail: error in setting and getting double attributes for UNUM_ROUNDING_INCREMENT\n"); else log_verbose("Pass: setting and getting double attributes for UNUM_ROUNDING_INCREMENT works fine\n"); } unum_close(def); } /** * Test the functioning of the secondary grouping value. */ static void TestSecondaryGrouping(void) { UErrorCode status = U_ZERO_ERROR; UNumberFormat *f = NULL, *g= NULL; UNumberFormat *us = unum_open(UNUM_DECIMAL,NULL,0, "en_US", NULL,&status); UFieldPosition pos; UChar resultBuffer[512]; int32_t l = 1876543210L; UBool ok = TRUE; UChar buffer[512]; int32_t i; UBool expectGroup = FALSE, isGroup = FALSE; u_uastrcpy(buffer, "#,##,###"); f = unum_open(UNUM_IGNORE,buffer, -1, "en_US",NULL, &status); CHECK(status, "DecimalFormat ct"); pos.field = 0; unum_format(f, (int32_t)123456789L, resultBuffer, 512 , &pos, &status); u_uastrcpy(buffer, "12,34,56,789"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: Formatting \"#,##,###\" pattern with 123456789 got %s, expected %s\n", resultBuffer, "12,34,56,789"); } if (pos.beginIndex != 0 && pos.endIndex != 12) { log_err("Fail: Formatting \"#,##,###\" pattern pos = (%d, %d) expected pos = (0, 12)\n", pos.beginIndex, pos.endIndex); } memset(resultBuffer,0, sizeof(UChar)*512); unum_toPattern(f, FALSE, resultBuffer, 512, &status); u_uastrcpy(buffer, "#,##,###"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: toPattern() got %s, expected %s\n", resultBuffer, "#,##,###"); } memset(resultBuffer,0, sizeof(UChar)*512); u_uastrcpy(buffer, "#,###"); unum_applyPattern(f, FALSE, buffer, -1,NULL,NULL); if (U_FAILURE(status)) { log_err("Fail: applyPattern call failed\n"); } unum_setAttribute(f, UNUM_SECONDARY_GROUPING_SIZE, 4); unum_format(f, (int32_t)123456789L, resultBuffer, 512 , &pos, &status); u_uastrcpy(buffer, "12,3456,789"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: Formatting \"#,###\" pattern with 123456789 got %s, expected %s\n", resultBuffer, "12,3456,789"); } memset(resultBuffer,0, sizeof(UChar)*512); unum_toPattern(f, FALSE, resultBuffer, 512, &status); u_uastrcpy(buffer, "#,####,###"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: toPattern() got %s, expected %s\n", resultBuffer, "#,####,###"); } memset(resultBuffer,0, sizeof(UChar)*512); g = unum_open(UNUM_DECIMAL, NULL,0,"hi_IN",NULL, &status); if (U_FAILURE(status)) { log_err("Fail: Cannot create UNumberFormat for \"hi_IN\" locale.\n"); } unum_format(g, l, resultBuffer, 512, &pos, &status); unum_close(g); /* expect "1,87,65,43,210", but with Hindi digits */ /* 01234567890123 */ if (u_strlen(resultBuffer) != 14) { ok = FALSE; } else { for (i=0; i \"1,87,65,43,210\" (with Hindi digits), got %s\n", "1876543210L", resultBuffer); } unum_close(f); unum_close(us); }