acclanglist.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <stdlib.h>
  42. #include "i18n.h"
  43. /*
  44. * Accept-Language = "Accept-Language" ":"
  45. * 1#( language-range [ ";" "q" "=" qvalue ] )
  46. * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
  47. *
  48. * NLS_AccLangList() assumes that "Accept-Language:" has already
  49. * been stripped off. It takes as input
  50. *
  51. * 1#( ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) [ ";" "q" "=" qvalue ] )
  52. *
  53. * and returns a list of languages, ordered by qvalues, in
  54. * the array NLS_ACCEPT_LANGUAGE_LIST.
  55. *
  56. * If there are to many languages (>NLS_MAX_ACCEPT_LANGUAGE) the excess
  57. * is ignored. If the language-range is too long (>NLS_MAX_ACCEPT_LENGTH),
  58. * the language-range is ignored. In these cases, NLS_AccLangList()
  59. * will quietly return, perhaps with numLang = 0. numLang is
  60. * returned by the function.
  61. */
  62. static size_t
  63. AcceptLangList(const char* AcceptLanguage,
  64. ACCEPT_LANGUAGE_LIST AcceptLanguageList)
  65. {
  66. char* input;
  67. char* cPtr;
  68. char* cPtr1;
  69. char* cPtr2;
  70. int i;
  71. int j;
  72. int countLang = 0;
  73. input = strdup(AcceptLanguage);
  74. if (input == (char*)NULL){
  75. return 0;
  76. }
  77. cPtr1 = input-1;
  78. cPtr2 = input;
  79. /* put in standard form */
  80. while (*(++cPtr1)) {
  81. if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
  82. else if (isspace(*cPtr1)); /* ignore any space */
  83. else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
  84. else if (*cPtr1=='*'); /* ignore "*" */
  85. else *cPtr2++ = *cPtr1; /* else unchanged */
  86. }
  87. *cPtr2 = '\0';
  88. countLang = 0;
  89. if (strchr(input,';')) {
  90. /* deal with the quality values */
  91. float qvalue[MAX_ACCEPT_LANGUAGE];
  92. float qSwap;
  93. float bias = 0.0f;
  94. char* ptrLanguage[MAX_ACCEPT_LANGUAGE];
  95. char* ptrSwap;
  96. cPtr = strtok(input,",");
  97. while (cPtr) {
  98. qvalue[countLang] = 1.0f;
  99. if ((cPtr1 = strchr(cPtr,';'))) {
  100. sscanf(cPtr1,";q=%f",&qvalue[countLang]);
  101. *cPtr1 = '\0';
  102. }
  103. if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
  104. qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
  105. ptrLanguage[countLang++] = cPtr;
  106. if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
  107. }
  108. cPtr = strtok(NULL,",");
  109. }
  110. /* sort according to decending qvalue */
  111. /* not a very good algorithm, but count is not likely large */
  112. for ( i=0 ; i<countLang-1 ; i++ ) {
  113. for ( j=i+1 ; j<countLang ; j++ ) {
  114. if (qvalue[i]<qvalue[j]) {
  115. qSwap = qvalue[i];
  116. qvalue[i] = qvalue[j];
  117. qvalue[j] = qSwap;
  118. ptrSwap = ptrLanguage[i];
  119. ptrLanguage[i] = ptrLanguage[j];
  120. ptrLanguage[j] = ptrSwap;
  121. }
  122. }
  123. }
  124. for ( i=0 ; i<countLang ; i++ ) {
  125. strcpy(AcceptLanguageList[i],ptrLanguage[i]);
  126. }
  127. } else {
  128. /* simple case: no quality values */
  129. cPtr = strtok(input,",");
  130. while (cPtr) {
  131. if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
  132. strcpy(AcceptLanguageList[countLang++],cPtr);
  133. if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
  134. }
  135. cPtr = strtok(NULL,",");
  136. }
  137. }
  138. free(input);
  139. return countLang;
  140. }
  141. /*
  142. * Get prioritized locale list from NLS_AcceptLangList
  143. *
  144. * Add additonal language to the list for fallback if locale
  145. * name is language_region
  146. *
  147. */
  148. int
  149. XP_AccLangList(char* AcceptLanguage,
  150. ACCEPT_LANGUAGE_LIST AcceptLanguageList)
  151. {
  152. int i;
  153. int n;
  154. char *defaultLanguage = "en";
  155. ACCEPT_LANGUAGE_LIST curLanguageList;
  156. int index = 0;
  157. char lang[3];
  158. int k;
  159. n = AcceptLangList(AcceptLanguage, curLanguageList);
  160. if (n == 0)
  161. return 0;
  162. memset(lang, 0, 3);
  163. for (i = 0; i < n; i++) {
  164. if (*lang && (strncmp(lang, curLanguageList[i], 2) != 0)) {
  165. /* add lang if current language is the last occurence in the list */
  166. for (k = i+1; (k < n) && strncmp(curLanguageList[k],lang,2); k++);
  167. if (k == n) {
  168. strcpy(AcceptLanguageList[index++], lang);
  169. *lang = '\0';
  170. }
  171. }
  172. strcpy(AcceptLanguageList[index++], curLanguageList[i]);
  173. /* Add current language for future appending.,make sure it's not on list */
  174. if ((strlen(curLanguageList[i]) > 2) && (curLanguageList[i][2] == '_')) {
  175. strncpy(lang, curLanguageList[i], 2);
  176. for (k = 0; (k < index) && strcmp(AcceptLanguageList[k], lang); k++);
  177. if (k != index) lang[0] = '\0';
  178. }
  179. }
  180. if (lang[0] != '\0')
  181. strcpy(AcceptLanguageList[index++], lang); /* add new lang */
  182. /* Append defaultLanguage if it's not in the list */
  183. for (i = 0; (i < index) && strcmp(AcceptLanguageList[i], defaultLanguage); i++);
  184. if (i == index)
  185. strcpy(AcceptLanguageList[index++], defaultLanguage);
  186. return index;
  187. }