1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * LC_TIME database generation routines for localedef.
  18  */
  19 
  20 #include <stdio.h>
  21 #include <stdlib.h>
  22 #include <errno.h>
  23 #include <sys/types.h>
  24 #include <string.h>
  25 #include <unistd.h>
  26 #include "localedef.h"
  27 #include "parser.tab.h"
  28 #include "timelocal.h"
  29 
  30 struct lc_time_T tm;
  31 
  32 void
  33 init_time(void)
  34 {
  35         (void) memset(&tm, 0, sizeof (tm));
  36 }
  37 
  38 void
  39 add_time_str(wchar_t *wcs)
  40 {
  41         char    *str;
  42 
  43         if ((str = to_mb_string(wcs)) == NULL) {
  44                 INTERR;
  45                 return;
  46         }
  47         free(wcs);
  48 
  49         switch (last_kw) {
  50         case T_D_T_FMT:
  51                 tm.c_fmt = str;
  52                 break;
  53         case T_D_FMT:
  54                 tm.x_fmt = str;
  55                 break;
  56         case T_T_FMT:
  57                 tm.X_fmt = str;
  58                 break;
  59         case T_T_FMT_AMPM:
  60                 tm.ampm_fmt = str;
  61                 break;
  62         case T_DATE_FMT:
  63                 /*
  64                  * This one is a Solaris extension, Too bad date just
  65                  * doesn't use %c, which would be simpler.
  66                  */
  67                 tm.date_fmt = str;
  68                 break;
  69         case T_ERA_D_FMT:
  70         case T_ERA_T_FMT:
  71         case T_ERA_D_T_FMT:
  72                 /* Silently ignore it. */
  73                 break;
  74         default:
  75                 free(str);
  76                 INTERR;
  77                 break;
  78         }
  79 }
  80 
  81 static void
  82 add_list(const char *ptr[], char *str, int limit)
  83 {
  84         int     i;
  85         for (i = 0; i < limit; i++) {
  86                 if (ptr[i] == NULL) {
  87                         ptr[i] = str;
  88                         return;
  89                 }
  90         }
  91         errf(_("too many list elements"));
  92 }
  93 
  94 void
  95 add_time_list(wchar_t *wcs)
  96 {
  97         char *str;
  98 
  99         if ((str = to_mb_string(wcs)) == NULL) {
 100                 INTERR;
 101                 return;
 102         }
 103         free(wcs);
 104 
 105         switch (last_kw) {
 106         case T_ABMON:
 107                 add_list(tm.mon, str, 12);
 108                 break;
 109         case T_MON:
 110                 add_list(tm.month, str, 12);
 111                 break;
 112         case T_ABDAY:
 113                 add_list(tm.wday, str, 7);
 114                 break;
 115         case T_DAY:
 116                 add_list(tm.weekday, str, 7);
 117                 break;
 118         case T_AM_PM:
 119                 if (tm.am == NULL) {
 120                         tm.am = str;
 121                 } else if (tm.pm == NULL) {
 122                         tm.pm = str;
 123                 } else {
 124                         errf(_("too many list elements"));
 125                 }
 126                 break;
 127         case T_ALT_DIGITS:
 128         case T_ERA:
 129                 free(str);
 130                 break;
 131         default:
 132                 free(str);
 133                 INTERR;
 134                 break;
 135         }
 136 }
 137 
 138 void
 139 check_time_list(void)
 140 {
 141         switch (last_kw) {
 142         case T_ABMON:
 143                 if (tm.mon[11] != NULL)
 144                         return;
 145                 break;
 146         case T_MON:
 147                 if (tm.month[11] != NULL)
 148                         return;
 149                 break;
 150         case T_ABDAY:
 151                 if (tm.wday[6] != NULL)
 152                         return;
 153                 break;
 154         case T_DAY:
 155                 if (tm.weekday[6] != NULL)
 156                         return;
 157                 break;
 158         case T_AM_PM:
 159                 if (tm.pm != NULL)
 160                         return;
 161                 break;
 162         case T_ERA:
 163         case T_ALT_DIGITS:
 164                 return;
 165         default:
 166                 errf(_("unknown list"));
 167                 break;
 168         }
 169 
 170         errf(_("too few items in list (%d)"), last_kw);
 171 }
 172 
 173 void
 174 reset_time_list(void)
 175 {
 176         int i;
 177         switch (last_kw) {
 178         case T_ABMON:
 179                 for (i = 0; i < 12; i++) {
 180                         free((char *)tm.mon[i]);
 181                         tm.mon[i] = NULL;
 182                 }
 183                 break;
 184         case T_MON:
 185                 for (i = 0; i < 12; i++) {
 186                         free((char *)tm.month[i]);
 187                         tm.month[i] = NULL;
 188                 }
 189                 break;
 190         case T_ABDAY:
 191                 for (i = 0; i < 7; i++) {
 192                         free((char *)tm.wday[i]);
 193                         tm.wday[i] = NULL;
 194                 }
 195                 break;
 196         case T_DAY:
 197                 for (i = 0; i < 7; i++) {
 198                         free((char *)tm.weekday[i]);
 199                         tm.weekday[i] = NULL;
 200                 }
 201                 break;
 202         case T_AM_PM:
 203                 free((char *)tm.am);
 204                 tm.am = NULL;
 205                 free((char *)tm.pm);
 206                 tm.pm = NULL;
 207                 break;
 208         }
 209 }
 210 
 211 
 212 void
 213 dump_time(void)
 214 {
 215         FILE *f;
 216         int i;
 217 
 218         if ((f = open_category()) == NULL) {
 219                 return;
 220         }
 221 
 222         for (i = 0; i < 12; i++) {
 223                 if (putl_category(tm.mon[i], f) == EOF) {
 224                         return;
 225                 }
 226         }
 227         for (i = 0; i < 12; i++) {
 228                 if (putl_category(tm.month[i], f) == EOF) {
 229                         return;
 230                 }
 231         }
 232         for (i = 0; i < 7; i++) {
 233                 if (putl_category(tm.wday[i], f) == EOF) {
 234                         return;
 235                 }
 236         }
 237         for (i = 0; i < 7; i++) {
 238                 if (putl_category(tm.weekday[i], f) == EOF) {
 239                         return;
 240                 }
 241         }
 242 
 243         /*
 244          * NOTE: If date_fmt is not specified, then we'll default to
 245          * using the %c for date.  This is reasonable for most
 246          * locales, although for reasons that I don't understand
 247          * Solaris historically has had a seperate format for date.
 248          */
 249         if ((putl_category(tm.X_fmt, f) == EOF) ||
 250             (putl_category(tm.x_fmt, f) == EOF) ||
 251             (putl_category(tm.c_fmt, f) == EOF) ||
 252             (putl_category(tm.am, f) == EOF) ||
 253             (putl_category(tm.pm, f) == EOF) ||
 254             (putl_category(tm.date_fmt ? tm.date_fmt : tm.c_fmt, f) == EOF) ||
 255             (putl_category(tm.ampm_fmt, f) == EOF)) {
 256                 return;
 257         }
 258         close_category(f);
 259 }