1 /*
   2  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
   3  * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
   4  * All rights reserved.
   5  *
   6  * Copyright (c) 2011 The FreeBSD Foundation
   7  * All rights reserved.
   8  * Portions of this software were developed by David Chisnall
   9  * under sponsorship from the FreeBSD Foundation.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  * 1. Redistributions of source code must retain the above copyright
  15  *    notice, this list of conditions and the following disclaimer.
  16  * 2. Redistributions in binary form must reproduce the above copyright
  17  *    notice, this list of conditions and the following disclaimer in the
  18  *    documentation and/or other materials provided with the distribution.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 #include "lint.h"
  34 #include <limits.h>
  35 #include "ldpart.h"
  36 #include "lnumeric.h"
  37 #include "../i18n/_locale.h"
  38 
  39 extern const char *__fix_locale_grouping_str(const char *);
  40 
  41 #define LCNUMERIC_SIZE (sizeof (struct lc_numeric_T) / sizeof (char *))
  42 
  43 static char     numempty[] = { CHAR_MAX, '\0' };
  44 
  45 static const struct lc_numeric_T _C_numeric_locale = {
  46         ".",            /* decimal_point */
  47         "",             /* thousands_sep */
  48         numempty        /* grouping */
  49 };
  50 
  51 static void
  52 destruct_numeric(void *v)
  53 {
  54         struct xlocale_numeric *l = v;
  55 
  56         if (l->buffer != NULL)
  57                 free(l->buffer);
  58 
  59         free(l);
  60 }
  61 
  62 struct xlocale_numeric __xlocale_global_numeric;
  63 
  64 static int
  65 numeric_load_locale(struct xlocale_numeric *loc, int *using_locale,
  66     int *changed, const char *name)
  67 {
  68         int leg;
  69         int ret;
  70         struct lc_numeric_T *l = &loc->locale;
  71 
  72         ret = __part_load_locale(name, using_locale,
  73             &loc->buffer, "LC_NUMERIC",
  74             LCNUMERIC_SIZE, LCNUMERIC_SIZE,
  75             (const char **)l);
  76         if (ret != _LDP_ERROR)
  77                 *changed = 1;
  78 
  79         if (ret == _LDP_LOADED) {
  80                 /* Can't be empty according to C99 */
  81                 if (*l->decimal_point == '\0')
  82                         l->decimal_point =
  83                             _C_numeric_locale.decimal_point;
  84                 l->grouping =
  85                     __fix_locale_grouping_str(l->grouping);
  86                 // XXX leg = (const struct lc_numeric_T *)&_numeric_locale;
  87         }
  88         /* This is Solaris legacy, required for ABI compatability */
  89         // _numeric[0] = *leg->decimal_point;
  90         // _numeric[1] = *leg->grouping;
  91         return (ret);
  92 }
  93 
  94 int
  95 __numeric_load_locale(const char *name)
  96 {
  97         return (numeric_load_locale(&__xlocale_global_numeric,
  98             &__xlocale_global_locale.using_numeric_locale,
  99             &__xlocale_global_locale.numeric_locale_changed, name));
 100 }
 101 
 102 void *
 103 __numeric_load(const char *name, locale_t l)
 104 {
 105         struct xlocale_numeric *new;
 106 
 107         new = calloc(sizeof(struct xlocale_numeric), 1);
 108         if (new == NULL)
 109                 return (NULL);
 110 
 111         new->header.header.destructor = destruct_numeric;
 112         if (numeric_load_locale(new, &l->using_numeric_locale,
 113             &l->numeric_locale_changed, name) == _LDP_ERROR) {
 114                 xlocale_release(new);
 115                 return (NULL);
 116         }
 117 
 118         return (new);
 119 }
 120 
 121 struct lc_numeric_T *
 122 __get_current_numeric_locale(locale_t loc)
 123 {
 124         return (loc->using_numeric_locale
 125             ? &((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale
 126             : (struct lc_numeric_T *)&_C_numeric_locale);
 127 }