Code cleanup for avoid compiler warnings
[midnight-commander.git] / src / charsets.c
blob1f281424ac659b9f2129d66de9e16961969a62fe
1 /* Text conversion from one charset to another.
3 Copyright (C) 2001 Walery Studennikov <despair@sama.ru>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 /** \file charsets.c
21 * \brief Source: Text conversion from one charset to another
24 #include <config.h>
26 #ifdef HAVE_CHARSET
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "lib/global.h"
33 #include "lib/strutil.h" /* utf-8 functions */
34 #include "lib/fileloc.h"
36 #include "charsets.h"
37 #include "main.h"
39 GPtrArray *codepages = NULL;
41 unsigned char conv_displ[256];
42 unsigned char conv_input[256];
44 const char *cp_display = NULL;
45 const char *cp_source = NULL;
47 static codepage_desc *
48 new_codepage_desc (const char *id, const char *name)
50 codepage_desc *desc;
52 desc = g_new (codepage_desc, 1);
53 desc->id = g_strdup (id);
54 desc->name = g_strdup (name);
56 return desc;
59 static void
60 free_codepage_desc (gpointer data, gpointer user_data)
62 codepage_desc *desc = (codepage_desc *) data;
63 (void) user_data;
65 g_free (desc->id);
66 g_free (desc->name);
67 g_free (desc);
70 /* returns display codepage */
71 static void
72 load_codepages_list_from_file (GPtrArray **list, const char *fname)
74 FILE *f;
75 guint i;
76 char buf[BUF_MEDIUM];
77 char *default_codepage = NULL;
79 f = fopen (fname, "r");
80 if (f == NULL)
81 return;
83 for (i = 0; fgets (buf, sizeof buf, f) != NULL; )
85 /* split string into id and cpname */
86 char *p = buf;
87 size_t buflen = strlen (buf);
89 if (*p == '\n' || *p == '\0' || *p == '#')
90 continue;
92 if (buflen > 0 && buf[buflen - 1] == '\n')
93 buf[buflen - 1] = '\0';
94 while (*p != '\t' && *p != ' ' && *p != '\0')
95 ++p;
96 if (*p == '\0')
97 goto fail;
99 *p++ = '\0';
100 g_strstrip (p);
101 if (*p == '\0')
102 goto fail;
104 if (strcmp (buf, "default") == 0)
105 default_codepage = g_strdup (p);
106 else
108 const char *id = buf;
110 if (*list == NULL)
112 *list = g_ptr_array_sized_new (16);
113 g_ptr_array_add (*list, new_codepage_desc (id, p));
115 else
117 /* whether id is already present in list */
118 /* if yes, overwrite description */
119 for (i = 0; i < (*list)->len; i++)
121 codepage_desc *desc;
123 desc = (codepage_desc *) g_ptr_array_index (*list, i);
125 if (strcmp (id, desc->id) == 0)
127 /* found */
128 g_free (desc->name);
129 desc->name = g_strdup (p);
130 break;
134 /* not found */
135 if (i == (*list)->len)
136 g_ptr_array_add (*list, new_codepage_desc (id, p));
141 if (default_codepage != NULL)
143 display_codepage = get_codepage_index (default_codepage);
144 g_free (default_codepage);
147 fail:
148 fclose (f);
151 void
152 load_codepages_list (void)
154 char *fname;
156 /* 1: try load /usr/share/mc/mc.charsets */
157 fname = g_build_filename (mc_home_alt, CHARSETS_LIST, (char *) NULL);
158 load_codepages_list_from_file (&codepages, fname);
159 g_free (fname);
161 /* 2: try load /etc/mc/mc.charsets */
162 fname = g_build_filename (mc_home, CHARSETS_LIST, (char *) NULL);
163 load_codepages_list_from_file (&codepages, fname);
164 g_free (fname);
166 if (codepages == NULL)
168 /* files are not found, add defaullt codepage */
169 fprintf (stderr, "%s\n", _("Warning: cannot load codepages list"));
171 codepages = g_ptr_array_new ();
172 g_ptr_array_add (codepages, new_codepage_desc ("ASCII", _("7-bit ASCII")));
176 void
177 free_codepages_list (void)
179 g_ptr_array_foreach (codepages, free_codepage_desc, NULL);
180 g_ptr_array_free (codepages, TRUE);
183 #define OTHER_8BIT "Other_8_bit"
185 const char *
186 get_codepage_id (const int n)
188 return (n < 0) ? OTHER_8BIT : ((codepage_desc *) g_ptr_array_index (codepages, n))->id;
192 get_codepage_index (const char *id)
194 size_t i;
195 if (strcmp (id, OTHER_8BIT) == 0)
196 return -1;
197 if (codepages == NULL)
198 return -1;
199 for (i = 0; i < codepages->len; i++)
200 if (strcmp (id, ((codepage_desc *) g_ptr_array_index (codepages, i))->id) == 0)
201 return i;
202 return -1;
205 /** Check if specified encoding can be used in mc.
206 * @param encoding name of encoding
207 * @returns TRUE if encoding has supported by mc, FALSE otherwise
209 gboolean
210 is_supported_encoding (const char *encoding)
212 gboolean result = FALSE;
213 guint t;
215 for (t = 0; t < codepages->len; t++)
217 const char *id = ((codepage_desc *) g_ptr_array_index (codepages, t))->id;
218 result |= (g_ascii_strncasecmp (encoding, id, strlen (id)) == 0);
221 return result;
224 static char
225 translate_character (GIConv cd, char c)
227 gchar *tmp_buff = NULL;
228 gsize bytes_read, bytes_written = 0;
229 const char *ibuf = &c;
230 char ch = UNKNCHAR;
232 int ibuflen = 1;
234 tmp_buff = g_convert_with_iconv (ibuf, ibuflen, cd, &bytes_read, &bytes_written, NULL);
235 if ( tmp_buff )
236 ch = tmp_buff[0];
237 g_free (tmp_buff);
238 return ch;
242 * FIXME: This assumes that ASCII is always the first encoding
243 * in mc.charsets
245 #define CP_ASCII 0
247 char *
248 init_translation_table (int cpsource, int cpdisplay)
250 int i;
251 GIConv cd;
253 /* Fill inpit <-> display tables */
255 if (cpsource < 0 || cpdisplay < 0 || cpsource == cpdisplay) {
256 for (i = 0; i <= 255; ++i) {
257 conv_displ[i] = i;
258 conv_input[i] = i;
259 cp_source = cp_display;
261 return NULL;
264 for (i = 0; i <= 127; ++i) {
265 conv_displ[i] = i;
266 conv_input[i] = i;
268 cp_source = ((codepage_desc *) g_ptr_array_index (codepages, cpsource))->id;
269 cp_display = ((codepage_desc *) g_ptr_array_index (codepages, cpdisplay))->id;
271 /* display <- inpit table */
273 cd = g_iconv_open (cp_display, cp_source);
274 if (cd == INVALID_CONV)
275 return g_strdup_printf (_("Cannot translate from %s to %s"), cp_source, cp_display);
277 for (i = 128; i <= 255; ++i)
278 conv_displ[i] = translate_character (cd, i);
280 g_iconv_close (cd);
282 /* inpit <- display table */
284 cd = g_iconv_open (cp_source, cp_display);
285 if (cd == INVALID_CONV)
286 return g_strdup_printf (_("Cannot translate from %s to %s"), cp_display, cp_source);
288 for (i = 128; i <= 255; ++i) {
289 unsigned char ch;
290 ch = translate_character (cd, i);
291 conv_input[i] = (ch == UNKNCHAR) ? i : ch;
294 g_iconv_close (cd);
296 return NULL;
299 void
300 convert_to_display (char *str)
302 if (!str)
303 return;
305 while (*str) {
306 *str = conv_displ[(unsigned char) *str];
307 str++;
311 GString *
312 str_convert_to_display (char *str)
314 return str_nconvert_to_display (str, -1);
318 GString *
319 str_nconvert_to_display (char *str, int len)
321 GString *buff;
322 GIConv conv;
324 if (!str)
325 return g_string_new("");
327 if (cp_display == cp_source)
328 return g_string_new(str);
330 conv = str_crt_conv_from (cp_source);
332 buff = g_string_new("");
333 str_nconvert (conv, str, len, buff);
334 str_close_conv (conv);
335 return buff;
338 void
339 convert_from_input (char *str)
341 if (!str)
342 return;
344 while (*str) {
345 *str = conv_input[(unsigned char) *str];
346 str++;
350 GString *
351 str_convert_to_input (char *str)
353 return str_nconvert_to_input (str, -1);
356 GString *
357 str_nconvert_to_input (char *str, int len)
359 GString *buff;
360 GIConv conv;
362 if (!str)
363 return g_string_new("");
365 if (cp_display == cp_source)
366 return g_string_new(str);
368 conv = str_crt_conv_to (cp_source);
370 buff = g_string_new("");
371 str_nconvert (conv, str, len, buff);
372 str_close_conv (conv);
373 return buff;
376 unsigned char
377 convert_from_utf_to_current (const char *str)
379 unsigned char buf_ch[6 + 1];
380 unsigned char ch = '.';
381 GIConv conv;
382 const char *cp_to;
384 if (!str)
385 return '.';
387 cp_to = get_codepage_id ( source_codepage );
388 conv = str_crt_conv_to ( cp_to );
390 if (conv != INVALID_CONV) {
391 switch (str_translate_char (conv, str, -1, (char *)buf_ch, sizeof(buf_ch))) {
392 case ESTR_SUCCESS:
393 ch = buf_ch[0];
394 break;
395 case ESTR_PROBLEM:
396 case ESTR_FAILURE:
397 ch = '.';
398 break;
400 str_close_conv (conv);
403 return ch;
407 unsigned char
408 convert_from_utf_to_current_c (const int input_char, GIConv conv)
410 unsigned char str[6 + 1];
411 unsigned char buf_ch[6 + 1];
412 unsigned char ch = '.';
414 int res = 0;
416 res = g_unichar_to_utf8 (input_char, (char *)str);
417 if ( res == 0 ) {
418 return ch;
420 str[res] = '\0';
422 switch (str_translate_char (conv, (char *)str, -1, (char *)buf_ch, sizeof(buf_ch))) {
423 case ESTR_SUCCESS:
424 ch = buf_ch[0];
425 break;
426 case ESTR_PROBLEM:
427 case ESTR_FAILURE:
428 ch = '.';
429 break;
431 return ch;
435 convert_from_8bit_to_utf_c (const char input_char, GIConv conv)
437 unsigned char str[2];
438 unsigned char buf_ch[6 + 1];
439 int ch = '.';
440 int res = 0;
442 str[0] = (unsigned char) input_char;
443 str[1] = '\0';
445 switch (str_translate_char (conv, (char *)str, -1, (char *)buf_ch, sizeof(buf_ch))) {
446 case ESTR_SUCCESS:
447 res = g_utf8_get_char_validated ((char *)buf_ch, -1);
448 if ( res < 0 ) {
449 ch = buf_ch[0];
450 } else {
451 ch = res;
453 break;
454 case ESTR_PROBLEM:
455 case ESTR_FAILURE:
456 ch = '.';
457 break;
459 return ch;
463 convert_from_8bit_to_utf_c2 (const char input_char)
465 unsigned char str[2];
466 unsigned char buf_ch[6 + 1];
467 int ch = '.';
468 int res = 0;
469 GIConv conv;
470 const char *cp_from;
472 str[0] = (unsigned char) input_char;
473 str[1] = '\0';
475 cp_from = get_codepage_id ( source_codepage );
476 conv = str_crt_conv_to (cp_from);
478 if (conv != INVALID_CONV) {
479 switch (str_translate_char (conv, (char *) str, -1, (char *) buf_ch, sizeof(buf_ch))) {
480 case ESTR_SUCCESS:
481 res = g_utf8_get_char_validated ((char *) buf_ch, -1);
482 if ( res < 0 ) {
483 ch = buf_ch[0];
484 } else {
485 ch = res;
487 break;
488 case ESTR_PROBLEM:
489 case ESTR_FAILURE:
490 ch = '.';
491 break;
493 str_close_conv (conv);
495 return ch;
498 #endif /* HAVE_CHARSET */