1 /*
2 * Copyright (C) 2014 Akihiro Tsukada
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation version 2.1 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 #include <config.h>
19 #include "libdvbv5/countries.h"
20
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <strings.h>
25
26 struct cCountry {
27 enum dvb_country_t id;
28 const char *alpha2_name;
29 const char *alpha3_name;
30 const char *short_name;
31 };
32
33 /*
34 * constants from ISO 3166-1.
35 * sorted alphabetically by two-letter(alpha-2) country name and
36 * in the same order with enum dvb_country_t.
37 */
38 static const struct cCountry country_list[] = {
39 /* id, alpha-2, alpha-3, short name */
40
41 { COUNTRY_UNKNOWN, "", "", "(Unknown Country)" },
42
43 { AD, "AD", "AND", "Andorra" },
44 { AE, "AE", "ARE", "United Arab Emirates" },
45 { AF, "AF", "AFG", "Afghanistan" },
46 { AG, "AG", "ATG", "Antigua and Barbuda" },
47 { AI, "AI", "AIA", "Anguilla" },
48 { AL, "AL", "ALB", "Albania" },
49 { AM, "AM", "ARM", "Armenia" },
50 { AO, "AO", "AGO", "Angola" },
51 { AQ, "AQ", "ATA", "Antarctica" },
52 { AR, "AR", "ARG", "Argentina" },
53 { AS, "AS", "ASM", "American Samoa" },
54 { AT, "AT", "AUT", "Austria" },
55 { AU, "AU", "AUS", "Australia" },
56 { AW, "AW", "ABW", "Aruba" },
57 { AX, "AX", "ALA", "Aland Islands" },
58 { AZ, "AZ", "AZE", "Azerbaijan" },
59 { BA, "BA", "BIH", "Bosnia and Herzegovina" },
60 { BB, "BB", "BRB", "Barbados" },
61 { BD, "BD", "BGD", "Bangladesh" },
62 { BE, "BE", "BEL", "Belgium" },
63 { BF, "BF", "BFA", "Burkina Faso" },
64 { BG, "BG", "BGR", "Bulgaria" },
65 { BH, "BH", "BHR", "Bahrain" },
66 { BI, "BI", "BDI", "Burundi" },
67 { BJ, "BJ", "BEN", "Benin" },
68 { BL, "BL", "534", "Saint Barthelemy" },
69 { BM, "BM", "BMU", "Bermuda" },
70 { BN, "BN", "BRN", "Brunei Darussalam" },
71 { BO, "BO", "BOL", "Plurinational State of Bolivia" },
72 { BQ, "BQ", "BES", "Bonaire, Saint Eustatius and Saba" },
73 { BR, "BR", "BRA", "Brazil" },
74 { BS, "BS", "BHS", "Bahamas" },
75 { BT, "BT", "BTN", "Bhutan" },
76 { BV, "BV", "BVT", "Bouvet Island" },
77 { BW, "BW", "BWA", "Botswana" },
78 { BY, "BY", "BLR", "Belarus" },
79 { BZ, "BZ", "BLZ", "Belize" },
80 { CA, "CA", "CAN", "Canada" },
81 { CC, "CC", "CCK", "Cocos (Keeling) Islands" },
82 { CD, "CD", "COD", "The Democratic Republic of the Congo" },
83 { CF, "CF", "CAF", "Central African Republic" },
84 { CG, "CG", "COG", "Congo" },
85 { CH, "CH", "CHE", "Switzerland" },
86 { CI, "CI", "CIV", "Cote d'Ivoire" },
87 { CK, "CK", "COK", "Cook Islands" },
88 { CL, "CL", "CHL", "Chile" },
89 { CM, "CM", "CMR", "Cameroon" },
90 { CN, "CN", "CHN", "China" },
91 { CO, "CO", "COL", "Colombia" },
92 { CR, "CR", "CRI", "Costa Rica" },
93 { CU, "CU", "CUB", "Cuba" },
94 { CV, "CV", "CPV", "Cape Verde" },
95 { CW, "CW", "CUW", "Curacao" },
96 { CX, "CX", "CXR", "Christmas Island" },
97 { CY, "CY", "CYP", "Cyprus" },
98 { CZ, "CZ", "CZE", "Czech Republic" },
99 { DE, "DE", "DEU", "Germany" },
100 { DJ, "DJ", "DJI", "Djibouti" },
101 { DK, "DK", "DNK", "Denmark" },
102 { DM, "DM", "DMA", "Dominica" },
103 { DO, "DO", "DOM", "Dominican Republic" },
104 { DZ, "DZ", "DZA", "Algeria" },
105 { EC, "EC", "ECU", "Ecuador" },
106 { EE, "EE", "EST", "Estonia" },
107 { EG, "EG", "EGY", "Egypt" },
108 { EH, "EH", "ESH", "Western Sahara" },
109 { ER, "ER", "ERI", "Eritrea" },
110 { ES, "ES", "ESP", "Spain" },
111 { ET, "ET", "ETH", "Ethiopia" },
112 { FI, "FI", "FIN", "Finland" },
113 { FJ, "FJ", "FJI", "Fiji" },
114 { FK, "FK", "FLK", "Falkland Islands (Malvinas)" },
115 { FM, "FM", "FSM", "Federated States of Micronesia" },
116 { FO, "FO", "534", "Faroe Islands" },
117 { FR, "FR", "FRA", "France" },
118 { GA, "GA", "GAB", "Gabon" },
119 { GB, "GB", "GBR", "United Kingdom" },
120 { GD, "GD", "GRD", "Grenada" },
121 { GE, "GE", "GEO", "Georgia" },
122 { GF, "GF", "GUF", "French Guiana" },
123 { GG, "GG", "GGY", "Guernsey" },
124 { GH, "GH", "GHA", "Ghana" },
125 { GI, "GI", "GIB", "Gibraltar" },
126 { GL, "GL", "GRL", "Greenland" },
127 { GM, "GM", "GMB", "Gambia" },
128 { GN, "GN", "GIN", "Guinea" },
129 { GP, "GP", "GLP", "Guadeloupe" },
130 { GQ, "GQ", "GNQ", "Equatorial Guinea" },
131 { GR, "GR", "GRC", "Greece" },
132 { GS, "GS", "SGS", "South Georgia and the South Sandwich Islands" },
133 { GT, "GT", "GTM", "Guatemala" },
134 { GU, "GU", "GUM", "Guam" },
135 { GW, "GW", "GNB", "Guinea-Bissau" },
136 { GY, "GY", "GUY", "Guyana" },
137 { HK, "HK", "HKG", "Hong Kong" },
138 { HM, "HM", "HMD", "Heard Island and McDonald Islands" },
139 { HN, "HN", "HND", "Honduras" },
140 { HR, "HR", "HRV", "Croatia" },
141 { HT, "HT", "HTI", "Haiti" },
142 { HU, "HU", "HUN", "Hungary" },
143 { ID, "ID", "IDN", "Indonesia" },
144 { IE, "IE", "IRL", "Ireland" },
145 { IL, "IL", "ISR", "Israel" },
146 { IM, "IM", "IMN", "Isle of Man" },
147 { IN, "IN", "IND", "India" },
148 { IO, "IO", "IOT", "British Indian Ocean Territory" },
149 { IQ, "IQ", "IRQ", "Iraq" },
150 { IR, "IR", "IRN", "Islamic Republic of Iran" },
151 { IS, "IS", "ISL", "Iceland" },
152 { IT, "IT", "ITA", "Italy" },
153 { JE, "JE", "JEY", "Jersey" },
154 { JM, "JM", "JAM", "Jamaica" },
155 { JO, "JO", "JOR", "Jordan" },
156 { JP, "JP", "JPN", "Japan" },
157 { KE, "KE", "KEN", "Kenya" },
158 { KG, "KG", "KGZ", "Kyrgyzstan" },
159 { KH, "KH", "KHM", "Cambodia" },
160 { KI, "KI", "KIR", "Kiribati" },
161 { KM, "KM", "COM", "Comoros" },
162 { KN, "KN", "KNA", "Saint Kitts and Nevis" },
163 { KP, "KP", "PRK", "Democratic People's Republic of Korea" },
164 { KR, "KR", "KOR", "Republic of Korea" },
165 { KW, "KW", "KWT", "Kuwait" },
166 { KY, "KY", "CYM", "Cayman Islands" },
167 { KZ, "KZ", "KAZ", "Kazakhstan" },
168 { LA, "LA", "LAO", "Lao People's Democratic Republic" },
169 { LB, "LB", "LBN", "Lebanon" },
170 { LC, "LC", "LCA", "Saint Lucia" },
171 { LI, "LI", "LIE", "Liechtenstein" },
172 { LK, "LK", "LKA", "Sri Lanka" },
173 { LR, "LR", "LBR", "Liberia" },
174 { LS, "LS", "LSO", "Lesotho" },
175 { LT, "LT", "LTU", "Lithuania" },
176 { LU, "LU", "LUX", "Luxembourg" },
177 { LV, "LV", "LVA", "Latvia" },
178 { LY, "LY", "LBY", "Libyan Arab Jamahiriya" },
179 { MA, "MA", "MAR", "Morocco" },
180 { MC, "MC", "MCO", "Monaco" },
181 { MD, "MD", "MDA", "Republic of Moldova" },
182 { ME, "ME", "MNE", "Montenegro" },
183 { MF, "MF", "MAF", "Saint Martin (French part)" },
184 { MG, "MG", "MDG", "Madagascar" },
185 { MH, "MH", "MHL", "Marshall Islands" },
186 { MK, "MK", "MKD", "The Former Yugoslav Republic of Macedonia" },
187 { ML, "ML", "MLI", "Mali" },
188 { MM, "MM", "MMR", "Myanmar" },
189 { MN, "MN", "MNG", "Mongolia" },
190 { MO, "MO", "MAC", "Macao" },
191 { MP, "MP", "MNP", "Northern Mariana Islands" },
192 { MQ, "MQ", "MTQ", "Martinique" },
193 { MR, "MR", "MRT", "Mauritania" },
194 { MS, "MS", "MSR", "Montserrat" },
195 { MT, "MT", "MLT", "Malta" },
196 { MU, "MU", "MUS", "Mauritius" },
197 { MV, "MV", "MDV", "Maldives" },
198 { MW, "MW", "MWI", "Malawi" },
199 { MX, "MX", "MEX", "Mexico" },
200 { MY, "MY", "MYS", "Malaysia" },
201 { MZ, "MZ", "MOZ", "Mozambique" },
202 { NA, "NA", "NAM", "Namibia" },
203 { NC, "NC", "NCL", "New Caledonia" },
204 { NE, "NE", "NER", "Niger" },
205 { NF, "NF", "NFK", "Norfolk Island" },
206 { NG, "NG", "NGA", "Nigeria" },
207 { NI, "NI", "NIC", "Nicaragua" },
208 { NL, "NL", "NLD", "Netherlands" },
209 { NO, "NO", "NOR", "Norway" },
210 { NP, "NP", "NPL", "Nepal" },
211 { NR, "NR", "NRU", "Nauru" },
212 { NU, "NU", "NIU", "Niue" },
213 { NZ, "NZ", "NZL", "New Zealand" },
214 { OM, "OM", "OMN", "Oman" },
215 { PA, "PA", "PAN", "Panama" },
216 { PE, "PE", "PER", "Peru" },
217 { PF, "PF", "PYF", "French Polynesia" },
218 { PG, "PG", "PNG", "Papua New Guinea" },
219 { PH, "PH", "PHL", "Philippines" },
220 { PK, "PK", "PAK", "Pakistan" },
221 { PL, "PL", "POL", "Poland" },
222 { PM, "PM", "SPM", "Saint Pierre and Miquelon" },
223 { PN, "PN", "PCN", "Pitcairn" },
224 { PR, "PR", "PRI", "Puerto Rico" },
225 { PS, "PS", "PSE", "Occupied Palestinian Territory" },
226 { PT, "PT", "PRT", "Portugal" },
227 { PW, "PW", "PLW", "Palau" },
228 { PY, "PY", "PRY", "Paraguay" },
229 { QA, "QA", "QAT", "Qatar" },
230 { RE, "RE", "REU", "Reunion" },
231 { RO, "RO", "ROU", "Romania" },
232 { RS, "RS", "SRB", "Serbia" },
233 { RU, "RU", "RUS", "Russian Federation" },
234 { RW, "RW", "RWA", "Rwanda" },
235 { SA, "SA", "SAU", "Saudi Arabia" },
236 { SB, "SB", "SLB", "Solomon Islands" },
237 { SC, "SC", "SYC", "Seychelles" },
238 { SD, "SD", "SDN", "Sudan" },
239 { SE, "SE", "SWE", "Sweden" },
240 { SG, "SG", "SGP", "Singapore" },
241 { SH, "SH", "SHN", "Saint Helena, Ascension and Tristan da Cunha" },
242 { SI, "SI", "SVN", "Slovenia" },
243 { SJ, "SJ", "534", "Svalbard and Jan Mayen" },
244 { SK, "SK", "SVK", "Slovakia" },
245 { SL, "SL", "SLE", "Sierra Leone" },
246 { SM, "SM", "SMR", "San Marino" },
247 { SN, "SN", "SEN", "Senegal" },
248 { SO, "SO", "SOM", "Somalia" },
249 { SR, "SR", "SUR", "Suriname" },
250 { SS, "SS", "SSD", "South Sudan" },
251 { ST, "ST", "STP", "Sao Tome and Principe" },
252 { SV, "SV", "SLV", "El Salvador" },
253 { SX, "SX", "SXM", "Sint Maarten (Dutch part)" },
254 { SY, "SY", "SYR", "Syrian Arab Republic" },
255 { SZ, "SZ", "SWZ", "Swaziland" },
256 { TC, "TC", "TCA", "Turks and Caicos Islands" },
257 { TD, "TD", "TCD", "Chad" },
258 { TF, "TF", "ATF", "French Southern Territories" },
259 { TG, "TG", "TGO", "Togo" },
260 { TH, "TH", "THA", "Thailand" },
261 { TJ, "TJ", "TJK", "Tajikistan" },
262 { TK, "TK", "TKL", "Tokelau" },
263 { TL, "TL", "TLS", "Timor-Leste" },
264 { TM, "TM", "TKM", "Turkmenistan" },
265 { TN, "TN", "TUN", "Tunisia" },
266 { TO, "TO", "TON", "Tonga" },
267 { TR, "TR", "TUR", "Turkey" },
268 { TT, "TT", "TTO", "Trinidad and Tobago" },
269 { TV, "TV", "TUV", "Tuvalu" },
270 { TW, "TW", "TWN", "Taiwan, Province of China" },
271 { TZ, "TZ", "TZA", "United Republic of Tanzania" },
272 { UA, "UA", "UKR", "Ukraine" },
273 { UG, "UG", "UGA", "Uganda" },
274 { UM, "UM", "UMI", "United States Minor Outlying Islands" },
275 { US, "US", "USA", "United States" },
276 { UY, "UY", "URY", "Uruguay" },
277 { UZ, "UZ", "UZB", "Uzbekistan" },
278 { VA, "VA", "VAT", "Holy See (Vatican City State)" },
279 { VC, "VC", "VCT", "Saint Vincent and The Grenadines" },
280 { VE, "VE", "VEN", "Bolivarian Republic of Venezuela" },
281 { VG, "VG", "VGB", "British Virgin Islands" },
282 { VI, "VI", "VIR", "U.S. Virgin Islands" },
283 { VN, "VN", "VNM", "Viet Nam" },
284 { VU, "VU", "VUT", "Vanuatu" },
285 { WF, "WF", "WLF", "Wallis and Futuna" },
286 { WS, "WS", "WSM", "Samoa" },
287 { YE, "YE", "YEM", "Yemen" },
288 { YT, "YT", "MYT", "Mayotte" },
289 { ZA, "ZA", "ZAF", "South Africa" },
290 { ZM, "ZM", "ZMB", "Zambia" },
291 { ZW, "ZW", "ZWE", "Zimbabwe" },
292 };
293
294 #define COUNTRY_COUNT (sizeof(country_list)/sizeof(struct cCountry))
295
cmp_alpha2(const void * key,const void * b)296 static int cmp_alpha2(const void *key, const void *b)
297 {
298 const struct cCountry *elem = b;
299
300 return strcasecmp(key, elem->alpha2_name);
301 }
302
cmp_alpha3(const void * key,const void * b)303 static int cmp_alpha3(const void *key, const void *b)
304 {
305 const struct cCountry *elem = b;
306
307 return strcasecmp(key, elem->alpha3_name);
308 }
309
310
311 /* convert ISO 3166-1 two-letter constant (alpha-2)
312 * to index number
313 * return 0(COUNTRY_UNKNOWN) if not found.
314 */
dvb_country_a2_to_id(const char * name)315 enum dvb_country_t dvb_country_a2_to_id(const char *name)
316 {
317 const struct cCountry *p;
318
319 p = bsearch(name, country_list,
320 COUNTRY_COUNT, sizeof(country_list[0]), cmp_alpha2);
321 return p ? p->id : COUNTRY_UNKNOWN;
322 }
323
324 /* convert ISO 3166-1 three-letter constant (alpha-3)
325 * to index number
326 * return 0(COUNTRY_UNKNOWN) if not found.
327 */
dvb_country_a3_to_id(const char * name)328 enum dvb_country_t dvb_country_a3_to_id(const char *name)
329 {
330 const struct cCountry *p;
331
332 p = bsearch(name, country_list,
333 COUNTRY_COUNT, sizeof(country_list[0]), cmp_alpha3);
334 return p ? p->id : COUNTRY_UNKNOWN;
335 }
336
337
338 /* convert index number
339 * to ISO 3166-1 two-letter constant
340 * return NULL if not found.
341 */
dvb_country_to_2letters(int idx)342 const char *dvb_country_to_2letters(int idx)
343 {
344 return (idx >= 1 && idx < COUNTRY_COUNT)
345 ? country_list[idx].alpha2_name : NULL;
346 }
347
348 /* convert index number
349 * to ISO 3166-1 three-letter constant
350 * return NULL if not found.
351 */
dvb_country_to_3letters(int idx)352 const char *dvb_country_to_3letters(int idx)
353 {
354 return (idx >= 1 && idx < COUNTRY_COUNT)
355 ? country_list[idx].alpha3_name : NULL;
356 }
357
358 /* convert index number
359 * to country name
360 * return NULL if not found.
361 */
dvb_country_to_name(int idx)362 const char *dvb_country_to_name(int idx)
363 {
364 return (idx >= 1 && idx < COUNTRY_COUNT)
365 ? country_list[idx].short_name : NULL;
366 }
367
368 #ifndef HAVE_SECURE_GETENV
369 # ifdef HAVE___SECURE_GETENV
370 # define secure_getenv __secure_getenv
371 # else
372 # define secure_getenv getenv
373 # endif
374 #endif
375
376 #define MIN(X,Y) (X < Y ? X : Y)
377
378 static const char * cats[] = {
379 "LC_ALL", "LC_CTYPE", "LC_COLLATE", "LC_MESSAGES", "LANG"
380 };
381
dvb_guess_user_country(void)382 enum dvb_country_t dvb_guess_user_country(void)
383 {
384 char * buf, * pch, * pbuf;
385 unsigned cat;
386 enum dvb_country_t id = COUNTRY_UNKNOWN;
387
388 for (cat = 0; cat < sizeof(cats)/sizeof(cats[0]); cat++) {
389
390 // the returned char * should be "C", "POSIX" or something valid.
391 // If valid, we can only *guess* which format is returned.
392 // Assume here something like "de_DE.iso8859-1@euro" or "de_DE.utf-8"
393 buf = secure_getenv(cats[cat]);
394 if (! buf || strlen(buf) < 2)
395 continue;
396
397 if (! strncmp(buf, "POSIX", MIN(strlen(buf), 5)) ||
398 ! (strncmp(buf, "en", MIN(strlen(buf), 2)) && !isalpha(buf[2])) )
399 continue;
400
401 buf = strdup(buf);
402 pbuf= buf;
403
404 // assuming 'language_country.encoding@variant'
405
406 // country after '_', if given
407 if ((pch = strchr(buf, '_')))
408 pbuf = pch + 1;
409
410 // remove all after '@', including '@'
411 if ((pch = strchr(pbuf, '@')))
412 *pch = 0;
413
414 // remove all after '.', including '.'
415 if ((pch = strchr(pbuf, '.')))
416 *pch = 0;
417
418 if (strlen(pbuf) == 2)
419 id = dvb_country_a2_to_id(pbuf);
420 free(buf);
421 if (id != COUNTRY_UNKNOWN)
422 return id;
423 }
424
425 return COUNTRY_UNKNOWN;
426 }
427