home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / locale / setlocale.c < prev   
Encoding:
C/C++ Source or Header  |  1994-08-30  |  15.9 KB  |  611 lines

  1. /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <localeinfo.h>
  21. #include <errno.h>
  22. #include <locale.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25.  
  26. #if defined(__linux__)
  27. #include <ctype.h>
  28. #include <fcntl.h>
  29. #include <unistd.h>
  30. #include <paths.h>
  31.  
  32. extern CONST unsigned short int __ctype_b_C[];
  33. extern CONST unsigned char __ctype_tolower_C[];
  34. extern CONST unsigned char __ctype_toupper_C[];
  35. extern CONST struct ctype_info __ctype_C;
  36.  
  37. extern CONST struct collate_info __collate_C;
  38. extern CONST struct monetary_info __monetary_C;
  39. extern CONST struct numeric_info __numeric_C;
  40. extern CONST struct response_info __response_C;
  41. extern CONST struct time_info __time_C;
  42.  
  43. extern CONST unsigned short int __ctype_b_ISO_8859_1[];
  44. extern CONST unsigned char __ctype_tolower_ISO_8859_1[];
  45. extern CONST unsigned char __ctype_toupper_ISO_8859_1[];
  46. extern CONST struct ctype_info __ctype_ISO_8859_1;
  47.  
  48. extern CONST unsigned short int __ctype_b_KOI_8[];
  49. extern CONST unsigned char __ctype_tolower_KOI_8[];
  50. extern CONST unsigned char __ctype_toupper_KOI_8[];
  51. extern CONST struct ctype_info __ctype_KOI_8;
  52.  
  53. static int loc_open __P ((CONST unsigned char *, CONST unsigned char *));
  54. static int guard_check __P ((CONST int, CONST unsigned char *));
  55. static int loc_rdline __P ((CONST int, unsigned char *, CONST int, unsigned char **[]));
  56.  
  57. static int loc_collate __P ((CONST int, CONST unsigned char *));
  58. static int loc_ctype __P ((CONST int, CONST unsigned char *));
  59. static int loc_monetary __P ((CONST int, CONST unsigned char *));
  60. static int loc_numeric __P ((CONST int, CONST unsigned char *));
  61. static int loc_time __P ((CONST int, CONST unsigned char *));
  62. static int loc_response __P ((CONST int, CONST unsigned char *));
  63.  
  64. #endif /* __linux__ */
  65.  
  66.  
  67. /* Switch to the locale called NAME in CATEGORY.
  68.    Return a string describing the locale.  This string can
  69.    be used as the NAME argument in a later call.
  70.    If NAME is NULL, don't switch locales, but return the current one.
  71.    If NAME is "", switch to a locale based on the environment variables,
  72.    as per POSIX.  Return NULL on error.  */
  73. char *
  74. DEFUN (setlocale, (category, name), int category AND CONST char *name)
  75. {
  76. #if defined(__linux__)
  77.     /* Don't ask me why I did this. H.J. */
  78.  
  79.     /* Fixed up setlocale() by Mitch (m.dsouza@mrc-apu.cam.ac.uk) */
  80.     /* Nickolay Saukh <nms@ussr.EU.net> was here */
  81.     /* as was Steve Robbins <steve@nyongwa.montreal.qc.ca> */
  82.  
  83.     static struct message_struct {
  84.     int category;
  85.     CONST char *name;
  86.     char *locale;
  87.     char *saved_locale;
  88.     } ms[] = {
  89.     { LC_COLLATE, "LC_COLLATE", "C" },
  90.     { LC_CTYPE, "LC_CTYPE", "C" },
  91.     { LC_MONETARY, "LC_MONETARY", "C" },
  92.     { LC_NUMERIC, "LC_NUMERIC", "C" },
  93.     { LC_TIME, "LC_TIME", "C" },
  94.     { LC_RESPONSE, "LC_RESPONSE", "C" },
  95.     { LC_MESSAGES, "LC_MESSAGES", "C" },
  96.     /*
  97.      * New categories go in between here.
  98.      */
  99.     { LC_ALL, "LC_ALL", "C" },
  100.     };
  101.  
  102. #define SIZE_MS (sizeof (ms) / sizeof (struct message_struct))
  103.  
  104.     int i, j, len;
  105.     char *ptr;
  106.  
  107.     if (name == NULL) {        /* We just asking for current settings */
  108.     for (i = 0; i < SIZE_MS; i++) {
  109.         if (category == ms[i].category)
  110.           return (char *) ms[i].locale;
  111.     }
  112.     errno = EINVAL;
  113.     return NULL;        /* Not a valid category */
  114.     }
  115.  
  116.     /*
  117.      * What the category asked (excluding LC_ALL)?
  118.      */
  119.     if (category != LC_ALL) {
  120.     for (i = 0; i < SIZE_MS - 1; i++) {
  121.         if (category != ms[i].category)
  122.           continue;
  123.         
  124.       /* If "" is given as the locale then we check environment vars */
  125.       if (*name == '\0') {
  126.           if ((ptr = getenv ("LC_ALL")) == NULL &&
  127.           (ptr = getenv (ms[i].name)) == NULL &&
  128.           (ptr = getenv ("LANG")) == NULL) {
  129.           /*
  130.            * Can't find a relevant variable; POSIX says the result
  131.            * is implementation-dependent.  Let's just return the
  132.            * previous setting, so that setlocale (LC_ALL, "") doesn't
  133.            * always fail.
  134.            */
  135.           return (char *) ms[i].locale;
  136.           }
  137.       } else
  138.         ptr = (char *)name;
  139.  
  140.         if (!strcmp (ptr, ms[i].locale))
  141.           return (char *) ms[i].locale;
  142.  
  143. #define C_LOCALE (!strcmp (ptr, "C") || !strcmp (ptr, "POSIX"))
  144.  
  145.         switch (category) {
  146.         int fd;
  147.  
  148.           case LC_COLLATE:
  149.         if (C_LOCALE) {
  150.             _collate_info = &__collate_C;
  151.         } else if ((fd = loc_open (ptr, ms[i].name)) < 0 ||
  152.                !loc_collate (fd, ptr)) {
  153.             errno = ENOENT;
  154.             return NULL;    /* Unknown locale */
  155.         }
  156.         break;
  157.           case LC_CTYPE:
  158.         if (C_LOCALE) {
  159.             __ctype_b = __ctype_b_C + 1;
  160.             __ctype_tolower = __ctype_tolower_C + 1;
  161.             __ctype_toupper = __ctype_toupper_C + 1;
  162.             _ctype_info = &__ctype_C;
  163.         } else if (!strcmp (ptr, "ISO-8859-1")) {
  164.             __ctype_b = __ctype_b_ISO_8859_1 + 1;
  165.             __ctype_tolower = __ctype_tolower_ISO_8859_1 + 1;
  166.             __ctype_toupper = __ctype_toupper_ISO_8859_1 + 1;
  167.             _ctype_info = &__ctype_ISO_8859_1;
  168.         } else if (!strcmp (ptr, "koi8-r")) {
  169.             __ctype_b = __ctype_b_KOI_8 + 1;
  170.             __ctype_tolower = __ctype_tolower_KOI_8 + 1;
  171.             __ctype_toupper = __ctype_toupper_KOI_8 + 1;
  172.             _ctype_info = &__ctype_KOI_8;
  173.         } else if ((fd = loc_open (ptr, ms[i].name)) < 0 ||
  174.                !loc_ctype (fd, ptr)) {
  175.             errno = ENOENT;
  176.             return NULL;    /* Unknown locale */
  177.         }
  178.         break;
  179.           case LC_MONETARY:
  180.         if (C_LOCALE) {
  181.             _monetary_info = &__monetary_C;
  182.         } else if ((fd = loc_open (ptr, ms[i].name)) < 0 ||
  183.                !loc_monetary (fd, ptr)) {
  184.             errno = ENOENT;
  185.             return NULL;    /* Unknown locale */
  186.         }
  187.         break;
  188.           case LC_NUMERIC:
  189.         if (C_LOCALE) {
  190.             _numeric_info = &__numeric_C;
  191.         } else if ((fd = loc_open (ptr, ms[i].name)) < 0 ||
  192.                !loc_numeric (fd, ptr)) {
  193.             errno = ENOENT;
  194.             return NULL;    /* Unknown locale */
  195.         }
  196.         break;
  197.           case LC_TIME:
  198.         if (C_LOCALE) {
  199.             _time_info = &__time_C;
  200.         } else if ((fd = loc_open (ptr, ms[i].name)) < 0 ||
  201.                !loc_time (fd, ptr)) {
  202.             errno = ENOENT;
  203.             return NULL;    /* Unknown locale */
  204.         }
  205.         break;
  206.           case LC_RESPONSE:
  207.         if (C_LOCALE) {
  208.             _response_info = &__response_C;
  209.         } else if ((fd = loc_open (ptr, ms[i].name)) < 0 ||
  210.                !loc_response (fd, ptr)) {
  211.             errno = ENOENT;
  212.             return NULL;    /* Unknown locale */
  213.         }
  214.         break;
  215.           case LC_MESSAGES:
  216.         if (ptr == NULL) {
  217.             errno = ENOENT;
  218.             return NULL;    /* Unknown locale */
  219.         }
  220.         
  221.         /* Some interaction with nls required to
  222.          * ensure correct settings
  223.          */
  224.         break;
  225.           default:
  226.         /*
  227.          * Invalid category requested
  228.          */
  229.         errno = EINVAL;
  230.         return NULL;
  231.         }
  232.  
  233.         if ((ms[i].locale = malloc (strlen (ptr) + 1)) == NULL) {
  234.         errno = ENOMEM;
  235.         return NULL;
  236.         }
  237.         strcpy (ms[i].locale, ptr);
  238.         return (ms[i].locale);
  239.     }
  240.     }
  241.     
  242.     /*
  243.      * If we here, then LC_ALL was requested
  244.      * Save total length of all locale strings in 'len'
  245.      */
  246.  
  247.     len = 0;
  248.     for (i = 0; i < SIZE_MS - 1; i++) {
  249.     /* Save current setting */
  250.     ms[i].saved_locale = setlocale (ms[i].category, NULL);
  251.     
  252.     if ((ptr = setlocale (ms[i].category, name)) == NULL) {
  253.         /* Oops! Recover original state */
  254.         int se = errno;
  255.         
  256.         for (j = 0; j < i; j++)
  257.           (void) setlocale (ms[j].category, ms[j].saved_locale);
  258.         
  259.         errno = se;
  260.         return NULL;
  261.     }
  262.     len += strlen (ptr) + 1; /* include one for the slash */
  263.     }
  264.     
  265.     /* if we here, then all individual locales were installed */
  266.     if ((ms[i].locale = malloc (len + 1)) == NULL) {
  267.     errno = ENOMEM;
  268.     return NULL;
  269.     }
  270.     *(ms[i].locale) = 0;
  271.     for (j = 0; j < SIZE_MS - 1; ++j) {
  272.     strcat (ms[i].locale, ms[j].locale);
  273.     strcat (ms[i].locale, "/");
  274.     }
  275.     return (char *) ms[i].locale;
  276.     
  277. #else
  278.  
  279.   /* Braindead implementation until I finish the fancy one.  */
  280.  
  281.   if (name == NULL || name[0] == '\0')
  282.       return (char *) "C";
  283.  
  284.   if (!strcmp (name, "C") || !strcmp (name, "POSIX"))
  285.     return (char *) name;
  286.  
  287.   errno = EINVAL;
  288.   return NULL;
  289. #endif
  290. }
  291.  
  292. #if defined(__linux__) && defined(USE_ISO_8859_1)
  293.  
  294. static int
  295. DEFUN (loc_open, (loc_name, cat_name), CONST unsigned char *loc_name AND CONST unsigned char *cat_name)
  296. {
  297.   unsigned char buffer[128];
  298.  
  299.   (void) strcpy (buffer, _PATH_LOCALE);
  300.   (void) strcat (buffer, "/");
  301.   (void) strcat (buffer, loc_name);
  302.   (void) strcat (buffer, "/");
  303.   (void) strcat (buffer, cat_name);
  304.  
  305.   return open (buffer, O_RDONLY);
  306. }
  307.  
  308. static int
  309. DEFUN (guard_check, (fd, cname), CONST int fd AND CONST unsigned char *cname)
  310. {
  311. #ifndef NOGUARD
  312.   unsigned char fcname[256];
  313.  
  314.   /*
  315.    * Guard check (overkill?)
  316.    */
  317.  
  318.   fcname[sizeof (fcname) - 1] = '\0';
  319.   if (read (fd, fcname, sizeof (fcname) - 1) < strlen (cname) + 1)
  320.     {
  321.       (void) close (fd);
  322.       return 0;
  323.     }
  324.   else if (strcmp (cname, fcname))
  325.     {
  326.       (void) close (fd);
  327.       return 0;
  328.     }
  329.  
  330. #endif
  331.  
  332.   return 1;
  333. }
  334.  
  335. static int
  336. DEFUN (loc_collate, (fd, cname), CONST int fd AND CONST unsigned char *cname)
  337. {
  338.   static unsigned char values[UCHAR_MAX + 1];
  339.   static unsigned char offsets[UCHAR_MAX + 1];
  340.   static struct collate_info cinfo =
  341.   {
  342.     0,
  343.     NULL,
  344.     values,
  345.     offsets
  346.   };
  347.  
  348.   if (read (fd, values, sizeof (values)) != sizeof (values))
  349.     {
  350.       (void) close (fd);
  351.       return 0;
  352.     }
  353.   if (read (fd, offsets, sizeof (offsets)) != sizeof (offsets))
  354.     {
  355.       (void) close (fd);
  356.       return 0;
  357.     }
  358.   if (read (fd, &cinfo.nsubsts, sizeof (cinfo.nsubsts)) != sizeof (cinfo.nsubsts))
  359.     {
  360.       (void) close (fd);
  361.       return 0;
  362.     }
  363.   /*
  364.    * XXX: for a while a did not like substitutions
  365.    */
  366.   if (cinfo.nsubsts)
  367.     {
  368.       (void) close (fd);
  369.       return 0;
  370.     }
  371.  
  372.   if (!guard_check (fd, cname))
  373.     return 0;
  374.  
  375.   (void) close (fd);
  376.  
  377.   _collate_info = &cinfo;
  378.  
  379.   return 1;
  380. }
  381.  
  382. static int
  383. DEFUN (loc_ctype, (fd, cname), CONST int fd AND CONST unsigned char *cname)
  384. {
  385.   /*
  386.    * There is no urgent need for multibytes
  387.    */
  388.   extern CONST struct ctype_mbchar_info __ctype_mbchar_C;
  389.   static struct ctables
  390.     {
  391.       unsigned short int xtype[UCHAR_MAX + 2];
  392.       unsigned char xlower[UCHAR_MAX + 2];
  393.       unsigned char xupper[UCHAR_MAX + 2];
  394.     }
  395.   ctables;
  396.   static struct ctype_ctype_info c2info =
  397.   {
  398.     ctables.xtype,
  399.     ctables.xlower,
  400.     ctables.xupper
  401.   };
  402.   static CONST struct ctype_info cinfo =
  403.   {
  404.     &c2info,
  405.     (struct ctype_mbchar_info *) &__ctype_mbchar_C    /* No multibytes!!! */
  406.   };
  407.  
  408.   if (read (fd, &ctables, sizeof (ctables)) != sizeof (ctables))
  409.     {
  410.       (void) close (fd);
  411.       return 0;
  412.     }
  413.  
  414.   if (!guard_check (fd, cname))
  415.     return 0;
  416.  
  417.   (void) close (fd);
  418.  
  419.   __ctype_b = ctables.xtype + 1;
  420.   __ctype_tolower = ctables.xlower + 1;
  421.   __ctype_toupper = ctables.xupper + 1;
  422.  
  423.   _ctype_info = &cinfo;
  424.  
  425.   return 1;
  426. }
  427.  
  428. static int
  429. DEFUN (loc_rdline, (fd, buf, buflen, target), CONST int fd AND unsigned char *buf AND CONST int buflen AND unsigned char **target[])
  430. {
  431.   int i;
  432.   short len;
  433.   unsigned char *cp = buf;
  434.  
  435.   for (i = 0; target[i] != NULL; i++)
  436.     {
  437.       if (read (fd, &len, sizeof (len)) != sizeof (len) ||
  438.       len > buflen - (cp - buf) ||
  439.       read (fd, cp, len) != len ||
  440.       *(cp + len - 1) != '\0')
  441.     {
  442.       (void) close (fd);
  443.       return 0;
  444.     }
  445.       *target[i] = cp;
  446.       cp += len;
  447.     }
  448.   return 1;
  449. }
  450.  
  451. static int
  452. DEFUN (loc_monetary, (fd, cname), CONST int fd AND CONST unsigned char *cname)
  453. {
  454.   static struct monetary_info minfo;
  455.   static unsigned char **lines[] =
  456.   {
  457.     (unsigned char **) &minfo.int_curr_symbol,
  458.     (unsigned char **) &minfo.currency_symbol,
  459.     (unsigned char **) &minfo.mon_decimal_point,
  460.     (unsigned char **) &minfo.mon_thousands_sep,
  461.     (unsigned char **) &minfo.mon_grouping,
  462.     (unsigned char **) &minfo.positive_sign,
  463.     (unsigned char **) &minfo.negative_sign,
  464.     NULL
  465.   };
  466.   static unsigned char mbuffer[128];    /* Hope it long enough */
  467.  
  468.   if (!loc_rdline (fd, mbuffer, sizeof (mbuffer), lines))
  469.     return 0;
  470.  
  471. #define fclen (((&minfo.n_sign_posn) - (&minfo.int_frac_digits)) + sizeof (minfo.n_sign_posn))
  472.  
  473.   if (read (fd, &minfo.int_frac_digits, fclen) != fclen)
  474.     {
  475.       (void) close (fd);
  476.       return 0;
  477.     }
  478.  
  479. #undef fclen
  480.  
  481.   if (!guard_check (fd, cname))
  482.     return 0;
  483.  
  484.   (void) close (fd);
  485.  
  486.   _monetary_info = &minfo;
  487.  
  488.   return 1;
  489. }
  490.  
  491. static int
  492. DEFUN (loc_numeric, (fd, cname), CONST int fd AND CONST unsigned char *cname)
  493. {
  494.   static struct numeric_info ninfo;
  495.   static unsigned char **lines[] =
  496.   {
  497.     (unsigned char **) &ninfo.decimal_point,
  498.     (unsigned char **) &ninfo.thousands_sep,
  499.     (unsigned char **) &ninfo.grouping,
  500.     NULL
  501.   };
  502.   static unsigned char nbuffer[64];    /* Hope it long enough */
  503.  
  504.   if (!loc_rdline (fd, nbuffer, sizeof (nbuffer), lines))
  505.     return 0;
  506.  
  507.   if (!guard_check (fd, cname))
  508.     return 0;
  509.  
  510.   (void) close (fd);
  511.  
  512.   _numeric_info = &ninfo;
  513.  
  514.   return 1;
  515. }
  516.  
  517. static int
  518. DEFUN (loc_time, (fd, cname), CONST int fd AND CONST unsigned char *cname)
  519. {
  520.   static struct time_info tinfo;
  521.   static unsigned char **lines[] =
  522.   {
  523.     (unsigned char **) &tinfo.abbrev_wkday[0],
  524.     (unsigned char **) &tinfo.abbrev_wkday[1],
  525.     (unsigned char **) &tinfo.abbrev_wkday[2],
  526.     (unsigned char **) &tinfo.abbrev_wkday[3],
  527.     (unsigned char **) &tinfo.abbrev_wkday[4],
  528.     (unsigned char **) &tinfo.abbrev_wkday[5],
  529.     (unsigned char **) &tinfo.abbrev_wkday[6],
  530.     (unsigned char **) &tinfo.full_wkday[0],
  531.     (unsigned char **) &tinfo.full_wkday[1],
  532.     (unsigned char **) &tinfo.full_wkday[2],
  533.     (unsigned char **) &tinfo.full_wkday[3],
  534.     (unsigned char **) &tinfo.full_wkday[4],
  535.     (unsigned char **) &tinfo.full_wkday[5],
  536.     (unsigned char **) &tinfo.full_wkday[6],
  537.     (unsigned char **) &tinfo.abbrev_month[0],
  538.     (unsigned char **) &tinfo.abbrev_month[1],
  539.     (unsigned char **) &tinfo.abbrev_month[2],
  540.     (unsigned char **) &tinfo.abbrev_month[3],
  541.     (unsigned char **) &tinfo.abbrev_month[4],
  542.     (unsigned char **) &tinfo.abbrev_month[5],
  543.     (unsigned char **) &tinfo.abbrev_month[6],
  544.     (unsigned char **) &tinfo.abbrev_month[7],
  545.     (unsigned char **) &tinfo.abbrev_month[8],
  546.     (unsigned char **) &tinfo.abbrev_month[9],
  547.     (unsigned char **) &tinfo.abbrev_month[10],
  548.     (unsigned char **) &tinfo.abbrev_month[11],
  549.     (unsigned char **) &tinfo.full_month[0],
  550.     (unsigned char **) &tinfo.full_month[1],
  551.     (unsigned char **) &tinfo.full_month[2],
  552.     (unsigned char **) &tinfo.full_month[3],
  553.     (unsigned char **) &tinfo.full_month[4],
  554.     (unsigned char **) &tinfo.full_month[5],
  555.     (unsigned char **) &tinfo.full_month[6],
  556.     (unsigned char **) &tinfo.full_month[7],
  557.     (unsigned char **) &tinfo.full_month[8],
  558.     (unsigned char **) &tinfo.full_month[9],
  559.     (unsigned char **) &tinfo.full_month[10],
  560.     (unsigned char **) &tinfo.full_month[11],
  561.     (unsigned char **) &tinfo.ampm[0],
  562.     (unsigned char **) &tinfo.ampm[1],
  563.     (unsigned char **) &tinfo.date_time,
  564.     (unsigned char **) &tinfo.date,
  565.     (unsigned char **) &tinfo.time,
  566.     (unsigned char **) &tinfo.ut0,
  567.     (unsigned char **) &tinfo.tz,
  568.     NULL
  569.   };
  570.   static unsigned char tbuffer[1024];    /* Hope it long enough */
  571.  
  572.   if (!loc_rdline (fd, tbuffer, sizeof (tbuffer), lines))
  573.     return 0;
  574.  
  575.   if (!guard_check (fd, cname))
  576.     return 0;
  577.  
  578.   (void) close (fd);
  579.  
  580.   _time_info = &tinfo;
  581.  
  582.   return 1;
  583. }
  584.  
  585. static int
  586. DEFUN (loc_response, (fd, cname), CONST int fd AND CONST unsigned char *cname)
  587. {
  588.   static struct response_info rinfo;
  589.   static unsigned char **lines[] =
  590.   {
  591.     (unsigned char **) &rinfo.yesexpr,
  592.     (unsigned char **) &rinfo.noexpr,
  593.     NULL
  594.   };
  595.   static unsigned char rbuffer[64];    /* Hope it long enough */
  596.  
  597.   if (!loc_rdline (fd, rbuffer, sizeof (rbuffer), lines))
  598.     return 0;
  599.  
  600.   if (!guard_check (fd, cname))
  601.     return 0;
  602.  
  603.   (void) close (fd);
  604.  
  605.   _response_info = &rinfo;
  606.  
  607.   return 1;
  608. }
  609.  
  610. #endif
  611.