diff --git a/cobj/codegen.c b/cobj/codegen.c index f0242a74..8770cc13 100644 --- a/cobj/codegen.c +++ b/cobj/codegen.c @@ -79,6 +79,8 @@ static const char *excp_current_program_id = NULL; static const char *excp_current_section = NULL; static const char *excp_current_paragraph = NULL; static struct cb_program *current_prog; +static size_t *sgmt_sizes = NULL; +static size_t sgmt_count = 0; extern int cb_default_byte_specified; extern unsigned char cb_default_byte; @@ -463,6 +465,7 @@ struct string_literal_cache { enum cb_string_category category; char *var_name; struct string_literal_cache *next; + size_t *segment_sizes; /* segment sizes for strings concatenated with '&' */ }; int string_literal_id = 0; @@ -531,7 +534,8 @@ static enum cb_string_category get_string_category(const unsigned char *s, } static void joutput_string_write(const unsigned char *s, int size, - enum cb_string_category category) { + enum cb_string_category category, + const size_t *tmp_sgmt_sizes) { int i; #ifdef I18N_UTF8 @@ -552,7 +556,11 @@ static void joutput_string_write(const unsigned char *s, int size, } else { joutput("CobolUtil.stringToBytes("); } - + if (tmp_sgmt_sizes) { + joutput_indent_level += 2; + joutput_newline(); + joutput_prefix(); + } joutput("\""); #ifdef I18N_UTF8 @@ -568,6 +576,8 @@ static void joutput_string_write(const unsigned char *s, int size, } #else int output_multibyte = 0; + int sum_sgmt_size = 0; + int sgmt_index = 0; for (i = 0; i < size; i++) { int c = s[i]; if (!output_multibyte && (c == '\"' || c == '\\')) { @@ -577,11 +587,33 @@ static void joutput_string_write(const unsigned char *s, int size, } else { joutput("%c", c); } + + // insert line breaks between segments concatenated with '&' + if (tmp_sgmt_sizes && i < size - 1) { + size_t segment_end_position = + sum_sgmt_size + tmp_sgmt_sizes[sgmt_index] - 1; + if (i == segment_end_position) { + joutput("\" + "); + joutput_newline(); + joutput_prefix(); + joutput("\""); + sum_sgmt_size += tmp_sgmt_sizes[sgmt_index]; + sgmt_index++; + } + } output_multibyte = !output_multibyte && ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef)); } #endif - joutput("\")"); + if (tmp_sgmt_sizes) { + joutput("\""); + joutput_newline(); + joutput_indent_level -= 2; + joutput_prefix(); + joutput(")"); + } else { + joutput("\")"); + } } else { if (param_wrap_string_flag) { joutput("CobolDataStorage.makeCobolDataStorage("); @@ -631,6 +663,16 @@ static void joutput_string(const unsigned char *s, int size) { new_literal_cache->var_name[var_name_length + 1 + i] = '\0'; } + // set segment sizes to new cache + if (sgmt_sizes) { + new_literal_cache->segment_sizes = cobc_malloc(sizeof(size_t) * sgmt_count); + memcpy(new_literal_cache->segment_sizes, sgmt_sizes, + sizeof(size_t) * sgmt_count); + sgmt_sizes = NULL; + } else { + new_literal_cache->segment_sizes = NULL; + } + // add the new cache to string_literal_list new_literal_cache->next = string_literal_list; string_literal_list = new_literal_cache; @@ -658,7 +700,8 @@ static void joutput_all_string_literals() { joutput_prefix(); joutput("public static final %s %s = ", data_type, l->var_name); param_wrap_string_flag = l->param_wrap_string_flag; - joutput_string_write(l->string_value, l->size, l->category); + joutput_string_write(l->string_value, l->size, l->category, + l->segment_sizes); joutput(";\n"); l = l->next; } @@ -2280,6 +2323,13 @@ static void joutput_initialize_one(struct cb_initialize *p, cb_tree x) { /* Initialize by value */ if (p->val && f->values) { cb_tree value = CB_VALUE(f->values); + struct cb_literal *l = CB_LITERAL_P(value) ? CB_LITERAL(value) : NULL; + // save the size information of '&' concatenated segments + if (l && l->segment_count > 0) { + sgmt_sizes = cobc_malloc(sizeof(size_t) * l->segment_count); + memcpy(sgmt_sizes, l->segment_sizes, sizeof(size_t) * l->segment_count); + sgmt_count = l->segment_count; + } /* NATIONAL also needs no editing but mbchar conversion. */ if (CB_TREE_CATEGORY(x) == CB_CATEGORY_NATIONAL) { @@ -2340,7 +2390,6 @@ static void joutput_initialize_one(struct cb_initialize *p, cb_tree x) { /* We do not use joutput_move here because we do not want to have the value be edited. */ - struct cb_literal *l = CB_LITERAL(value); static char *buff = NULL; static int lastsize = 0; if (!buff) { diff --git a/cobj/tree.c b/cobj/tree.c index 3bd85e75..d0462bb3 100644 --- a/cobj/tree.c +++ b/cobj/tree.c @@ -455,6 +455,31 @@ struct cb_literal *build_literal(enum cb_category category, return p; } +struct cb_literal *build_concat_literal(enum cb_category category, + const unsigned char *data, size_t size1, + size_t size2, size_t *sgmt_sizes, + size_t sgmt_count) { + struct cb_literal *p; + size_t size = size1 + size2; + p = make_tree(CB_TAG_LITERAL, category, sizeof(struct cb_literal)); + p->data = cobc_malloc((size_t)(size + 1)); + p->size = size; + memcpy(p->data, data, (size_t)size); + + // set segment sizes + if (!sgmt_sizes) { + p->segment_sizes = cobc_malloc(sizeof(size_t) * 2); + p->segment_sizes[0] = size1; + } else { + p->segment_sizes = cobc_malloc(sizeof(size_t) * (sgmt_count + 1)); + memcpy(p->segment_sizes, sgmt_sizes, sizeof(size_t) * sgmt_count); + } + p->segment_sizes[sgmt_count] = size2; + p->segment_count = sgmt_count + 1; + + return p; +} + char *cb_name(cb_tree x) { if (!treenamebuff) { treenamebuff = cobc_malloc(COB_NORMAL_BUFF); @@ -1030,6 +1055,22 @@ cb_tree cb_build_national_literal(const unsigned char *data, size_t size) { return CB_TREE(build_literal(CB_CATEGORY_NATIONAL, data, size)); } +cb_tree cb_build_concat_alphanumeric_literal(const unsigned char *data, + size_t size1, size_t size2, + size_t *sgmt_sizes, + size_t sgmt_count) { + return CB_TREE(build_concat_literal(CB_CATEGORY_ALPHANUMERIC, data, size1, + size2, sgmt_sizes, sgmt_count)); +} + +cb_tree cb_build_concat_national_literal(const unsigned char *data, + size_t size1, size_t size2, + size_t *sgmt_sizes, + size_t sgmt_count) { + return CB_TREE(build_concat_literal(CB_CATEGORY_NATIONAL, data, size1, size2, + sgmt_sizes, sgmt_count)); +} + cb_tree cb_concat_literals(cb_tree x1, cb_tree x2) { unsigned char *buff; cb_tree x; @@ -1037,14 +1078,17 @@ cb_tree cb_concat_literals(cb_tree x1, cb_tree x2) { unsigned char *data2; size_t size1; size_t size2; + struct cb_literal *l; if (x1 == cb_error_node || x2 == cb_error_node) { return cb_error_node; } if (CB_LITERAL_P(x1)) { + l = CB_LITERAL(x1); data1 = CB_LITERAL(x1)->data; size1 = CB_LITERAL(x1)->size; } else if (CB_CONST_P(x1)) { + l = CB_LITERAL(x1); size1 = 1; if (x1 == cb_space) { data1 = (unsigned char *)" "; @@ -1090,8 +1134,18 @@ cb_tree cb_concat_literals(cb_tree x1, cb_tree x2) { buff = cobc_malloc(size1 + size2 + 3); memcpy(buff, data1, size1); memcpy(buff + size1, data2, size2); - x = cb_build_alphanumeric_literal(buff, size1 + size2); + if (!l->segment_count) { + l->segment_count = 1; + } + if (x1->category == CB_CATEGORY_NATIONAL) { + x = cb_build_concat_national_literal(buff, size1, size2, l->segment_sizes, + l->segment_count); + } else { + x = cb_build_concat_alphanumeric_literal( + buff, size1, size2, l->segment_sizes, l->segment_count); + } free(buff); + return x; } diff --git a/cobj/tree.h b/cobj/tree.h index 167c76b7..c652cd63 100644 --- a/cobj/tree.h +++ b/cobj/tree.h @@ -467,9 +467,17 @@ extern cb_tree cb_build_system_name(enum cb_system_name_category category, * Literal */ +struct cb_literal_segment { + size_t size; + unsigned char *data; + struct cb_literal_segment *next; +}; + struct cb_literal { struct cb_tree_common common; size_t size; + size_t *segment_sizes; /* segment sizes for strings concatenated with '&' */ + size_t segment_count; unsigned char *data; signed char all; signed char sign; /* unsigned: 0 negative: -1 positive: 1 */ @@ -489,6 +497,14 @@ extern cb_tree cb_build_alphanumeric_literal(const unsigned char *data, extern cb_tree cb_build_national_literal(const unsigned char *data, size_t size); extern cb_tree cb_concat_literals(cb_tree x1, cb_tree x2); +extern cb_tree cb_build_concat_alphanumeric_literal(const unsigned char *data, + size_t size1, size_t size2, + size_t *sgmt_sizes, + size_t sgmt_count); +extern cb_tree cb_build_concat_national_literal(const unsigned char *data, + size_t size1, size_t size2, + size_t *sgmt_sizes, + size_t sgmt_count); /* * Decimal @@ -1438,6 +1454,10 @@ extern void level_except_error(cb_tree x, const char *clause); struct cb_literal *build_literal(enum cb_category category, const unsigned char *data, size_t size); +struct cb_literal *build_concat_literal(enum cb_category category, + const unsigned char *data, size_t size1, + size_t size2, size_t *sgmt_sizes, + size_t sgmt_count); /* field.c */ extern size_t cb_needs_01; diff --git a/tests/Makefile.am b/tests/Makefile.am index 0006440a..9e3053e1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -262,7 +262,8 @@ misc_DEPENDENCIES = \ misc.src/display-numeric-NUMERIC-class.at \ misc.src/display-inspect-sign.at \ misc.src/comp1-comp2.at \ - misc.src/variable-length-file.at + misc.src/variable-length-file.at \ + misc.src/convert-string-concat.at \ EXTRA_DIST = $(srcdir)/package.m4 \ $(TESTS) \ diff --git a/tests/Makefile.in b/tests/Makefile.in index a37c42d2..fc0413a9 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -801,7 +801,8 @@ misc_DEPENDENCIES = \ misc.src/display-numeric-NUMERIC-class.at \ misc.src/display-inspect-sign.at \ misc.src/comp1-comp2.at \ - misc.src/variable-length-file.at + misc.src/variable-length-file.at \ + misc.src/convert-string-concat.at \ EXTRA_DIST = $(srcdir)/package.m4 \ $(TESTS) \ diff --git a/tests/misc.at b/tests/misc.at index af958f71..1db81ab4 100644 --- a/tests/misc.at +++ b/tests/misc.at @@ -57,3 +57,4 @@ m4_include([display-numeric-NUMERIC-class.at]) m4_include([display-inspect-sign.at]) m4_include([comp1-comp2.at]) m4_include([variable-length-file.at]) +m4_include([convert-string-concat.at]) diff --git a/tests/misc.src/convert-string-concat.at b/tests/misc.src/convert-string-concat.at new file mode 100644 index 00000000..44926293 --- /dev/null +++ b/tests/misc.src/convert-string-concat.at @@ -0,0 +1,40 @@ +AT_SETUP([convert '&' concatenated strings to Java]) + +AT_DATA([prog.cbl], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 X-CONCAT PIC X(25) VALUE "abcde" + & "fghij" + & "klmno" + & "pqrst" + & "uvwxy". + 01 N-CONCAT PIC N(25) VALUE "あいうえお" + & "かきくけこ" + & "さしすせそ" + & "たちつてと" + & "なにぬねの". + PROCEDURE DIVISION. + MAIN-RTN. + DISPLAY X-CONCAT. + DISPLAY N-CONCAT. + STOP RUN. +]) + +AT_CHECK([${COMPILE} prog.cbl]) +AT_CHECK([java prog], [0], +[abcdefghijklmnopqrstuvwxy +あいうえおかきくけこさしすせそたちつてとなにぬねの +]) +AT_CHECK([grep -q ' "abcde" +' prog.java]) +AT_CHECK([grep -q ' "fghij" +' prog.java]) +AT_CHECK([grep -q ' "klmno" +' prog.java]) +AT_CHECK([grep -q ' "pqrst" +' prog.java]) +AT_CHECK([grep -q ' "uvwxy"' prog.java]) +AT_CHECK([grep -q ' "あいうえお" +' prog.java]) +AT_CHECK([grep -q ' "かきくけこ" +' prog.java]) +AT_CHECK([grep -q ' "さしすせそ" +' prog.java]) +AT_CHECK([grep -q ' "たちつてと" +' prog.java]) +AT_CHECK([grep -q ' "なにぬねの"' prog.java]) +AT_CLEANUP