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