2020
2121#include "config.h"
2222#include "cobc.h"
23+ #include "tree.h" /* for cb_note */
2324
2425#include <stdio.h>
2526
2627#ifdef HAVE_ICONV
2728
2829#include <iconv.h>
30+ #include <limits.h>
2931#include <errno.h>
30- #include <time.h>
3132
32- #define TABLE_SIZE 256
3333#define LINE_SIZE 16
3434#define EBCDIC_SUBST_CHAR (char)0x3F
35-
36- static int
37- current_year (void )
38- {
39- time_t t = time (NULL );
40- struct tm * tm = localtime (& t );
41- return tm -> tm_year + 1900 ;
42- }
43-
44- static void
45- output_license (FILE * stream )
46- {
47- fprintf (stream ,
48- "# Copyright (C) %04d Free Software Foundation, Inc.\n"
49- "# Written by David Declerck.\n"
50- "#\n"
51- "# This file is part of the GnuCOBOL runtime.\n"
52- "#\n"
53- "# The GnuCOBOL runtime is free software: you can redistribute it\n"
54- "# and/or modify it under the terms of the GNU Lesser General Public License\n"
55- "# as published by the Free Software Foundation, either version 3 of the\n"
56- "# License, or (at your option) any later version.\n"
57- "#\n"
58- "# GnuCOBOL is distributed in the hope that it will be useful,\n"
59- "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
60- "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
61- "# GNU General Public License for more details.\n"
62- "#\n"
63- "# You should have received a copy of the GNU Lesser General Public License\n"
64- "# along with GnuCOBOL. If not, see <https://www.gnu.org/licenses/>.\n" ,
65- current_year ());
66- }
35+ #define ASCII_SUBST_CHAR (char)0x1A
6736
6837static void
6938output_table (FILE * stream , const char * table )
7039{
71- int i ;
72- for (i = 0 ; i < TABLE_SIZE ; ++ i ) {
40+ unsigned short i ;
41+ for (i = 0 ; i <= UCHAR_MAX ; ++ i ) {
7342 fprintf (stream , "%02X%c" , (unsigned char )table [i ],
74- ((i + 1 ) % LINE_SIZE == 0 ) ? '\n' : ' ' );
43+ ((i + 1 ) % LINE_SIZE == 0 ) ? '\n' : ' ' );
7544 }
7645}
7746
78- static int
79- translate_single_char (iconv_t ic , char * ebcdic_char , char * ascii_char )
80- {
81- size_t ebcdic_size = 1 , ascii_size = 1 ;
82- size_t res = iconv (ic , & ebcdic_char , & ebcdic_size , & ascii_char , & ascii_size );
83- iconv (ic , NULL , NULL , NULL , NULL );
84- return (res == (size_t )0 ? 0 : -1 );
85- }
86-
87- /* We assume fromcode to be an EBCDIC variant and tocode to be an ASCII-based encoding */
47+ /* Build a pair of EBCDIC/ASCII translation tables using iconv */
8848int
89- gentable (FILE * stream , const char * fromcode , const char * tocode )
49+ gentable (FILE * stream , const char * code_ebcdic , const char * code_ascii )
9050{
91- char ebcdic [TABLE_SIZE ], ascii [TABLE_SIZE ] = { 0 };
51+ char ebcdic [UCHAR_MAX + 1 ], ascii [UCHAR_MAX + 1 ] = { 0 };
9252 char * ebcdic_ptr = ebcdic , * ascii_ptr = ascii ;
93- size_t ebcdic_size = TABLE_SIZE , ascii_size = TABLE_SIZE ;
94- char ebcdic_subst = EBCDIC_SUBST_CHAR , ascii_subst = 0 ;
53+ size_t ascii_size = UCHAR_MAX + 1 ;
54+ unsigned short i , nb_irreversible = 0 ;
9555 iconv_t ic ;
96- size_t res ;
97- int i , nb_irreversible = 0 ;
9856
99- for (i = 0 ; i < TABLE_SIZE ; ++ i ) {
57+ for (i = 0 ; i <= UCHAR_MAX ; ++ i ) {
10058 ebcdic [i ] = (char )i ;
10159 }
10260
103- ic = iconv_open (tocode , fromcode );
61+ ic = iconv_open (code_ascii , code_ebcdic );
10462 if (ic == (iconv_t )- 1 ) {
105- fprintf ( stderr , "Conversion from %s to %s is not supported by your iconv implementation.\n" , fromcode , tocode );
63+ cb_error ( _ ( "conversion from %s to %s is not supported by your iconv implementation" ), code_ascii , code_ebcdic );
10664 return -1 ;
10765 }
10866
@@ -111,67 +69,61 @@ gentable (FILE *stream, const char *fromcode, const char *tocode)
11169 and returns the number of such non-reversible conversions performed.
11270 GNU iconv instead sets errno to EILSEQ (unless //TRANSLIT is used).
11371 To cope with these differences, we convert the table character by
114- character and when encountering an untranslatable character, we
115- "translate" it to the substitution character translated from the
116- EBCDIC substitution character (0x3F). */
117-
118- if (translate_single_char (ic , & ebcdic_subst , & ascii_subst ) != 0 ) {
119- fprintf (stderr , "Can not convert the substitution character from %s to %s.\n" , fromcode , tocode );
120- return -1 ;
121- }
122-
123- for (i = 0 ; i < TABLE_SIZE ; ++ i ) {
124- ebcdic_size = 1 ;
125- res = iconv (ic , & ebcdic_ptr , & ebcdic_size , & ascii_ptr , & ascii_size );
126- if (res == (size_t )-1 ) {
127- switch (errno ) {
128- /* GNU iconv: an untranslatable character was met */
129- case EILSEQ :
130- * ascii_ptr = ascii_subst ;
72+ character, and when encountering an untranslatable character, we
73+ map it to the ASCII substitution character (0x1A). This leaves a
74+ number of unused ASCII characters: in the reverse translation table,
75+ those are mapped to the EBCDIC substitution character (0x3F). */
76+
77+ for (i = 0 ; i <= UCHAR_MAX ; ++ i ) {
78+ size_t ebcdic_size = 1 ;
79+ size_t res = iconv (ic , & ebcdic_ptr , & ebcdic_size , & ascii_ptr , & ascii_size );
80+
81+ if (res != 0 ) {
82+ if (res == (size_t )-1 ) {
83+ if (errno == EILSEQ ) {
84+ /* GNU iconv: an untranslatable character was met */
85+ * ascii_ptr = ASCII_SUBST_CHAR ;
13186 ++ ebcdic_ptr ; ++ ascii_ptr ;
132- ++ ebcdic_size ; ++ ascii_size ;
87+ -- ascii_size ;
13388 ++ nb_irreversible ;
134- break ;
135- case EINVAL :
136- case E2BIG :
137- default :
138- fprintf (stderr , "An error occurred after converting %ld characters.\n" , (ebcdic_ptr - ebcdic ));
89+ } else {
90+ cb_error (_ ("an error occurred after converting %ld characters" ), (ebcdic_ptr - ebcdic ));
13991 iconv_close (ic );
14092 return -1 ;
93+ }
94+ } else {
95+ /* POSIX iconv: a substitution was performed */
96+ * (ascii_ptr - 1 ) = ASCII_SUBST_CHAR ;
97+ ++ nb_irreversible ;
14198 }
142- /* POSIX iconv: a substitution was performed */
143- } else if (res != (size_t )0 ) {
144- * (ascii_ptr - 1 ) = ascii_subst ;
145- nb_irreversible += (int )res ;
14699 }
147100 }
148101
149102 iconv_close (ic );
150103
151- fprintf (stream , "# GnuCOBOL %s/%s translation tables\n\n" , fromcode , tocode );
152- output_license (stream );
104+ fprintf (stream , "# GnuCOBOL %s <-> %s translation tables\n" , code_ebcdic , code_ascii );
153105
154- fprintf (stream , "\n# %s to %s translation table\n\n" , fromcode , tocode );
106+ fprintf (stream , "\n# %s to %s translation table\n\n" , code_ebcdic , code_ascii );
155107 output_table (stream , ascii );
156108
157- fprintf (stream , "\n# %s to %s translation table\n\n" , tocode , fromcode );
109+ fprintf (stream , "\n# %s to %s translation table\n\n" , code_ascii , code_ebcdic );
158110 if (nb_irreversible <= 0 ) {
159- fprintf (stream , "# This translation being symmetric, the table is built from the previous one.\n\n" );
111+ fprintf (stream , "# This translation being symmetric, the table is built from the previous one.\n\n" );
160112 } else {
161113 /* Build the (partial) reverse translation table */
162- memset (ebcdic , ebcdic_subst , TABLE_SIZE );
163- for (i = 0 ; i < TABLE_SIZE ; ++ i ) {
114+ memset (ebcdic , EBCDIC_SUBST_CHAR , UCHAR_MAX + 1 );
115+ for (i = 0 ; i <= UCHAR_MAX ; ++ i ) {
164116 ebcdic [(unsigned char )ascii [i ]] = (char )i ;
165117 }
166118
167- /* Restore the substitution character, as it is used
168- several times, we can't just reverse the table */
169- ebcdic [(unsigned char )ascii_subst ] = ebcdic_subst ;
119+ /* Restore the substitution character: as it is used several
120+ times, the loop above probably did not set it correctly */
121+ ebcdic [(unsigned char )ASCII_SUBST_CHAR ] = EBCDIC_SUBST_CHAR ;
170122
171123 output_table (stream , ebcdic );
172- fprintf (stream , "\n" );
124+ fprintf (stream , "\n" );
173125
174- fprintf ( stderr , "Warning: %d non-reversible conversions were performed, you might want to review the generated table.\n" , nb_irreversible );
126+ cb_note ( COB_WARNOPT_NONE , 0 , _ ( " %d non-reversible conversions were performed, you might want to review the generated table" ) , nb_irreversible );
175127 }
176128
177129 return 0 ;
@@ -180,13 +132,14 @@ gentable (FILE *stream, const char *fromcode, const char *tocode)
180132#else
181133
182134int
183- gentable (FILE * stream , const char * fromcode , const char * tocode )
135+ gentable (FILE * stream , const char * code_ebcdic , const char * code_ascii )
184136{
185137 COB_UNUSED (stream );
186- COB_UNUSED (fromcode );
187- COB_UNUSED (tocode );
138+ COB_UNUSED (code_ebcdic );
139+ COB_UNUSED (code_ascii );
188140
189- fprintf (stderr , "Error: GnuCOBOL was not compiled with iconv support; translation table generation is not available.\n" );
141+ cb_error (_ ("runtime is not configured to support %s" ), "iconv" );
142+ cb_error (_ ("translation table generation is not available" ));
190143
191144 return -1 ;
192145}
0 commit comments