[gcc r17-3244] cobol: Refactor the use of cbl_char_t for big-endian architecture.
Robert Dubner via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:15acadc08ca83c2993fe96bcf185079587ba95bb commit r17-3244-g15acadc08ca83c2993fe96bcf185079587ba95bb Author: Robert Dubner <[email protected]> Date: Wed Aug 12 18:38:20 2026 -0400 cobol: Refactor the use of cbl_char_t for big-endian architecture. One of the features of GCOBOL is that it can function with the -fexec-charset set to ASCII, EBCDIC, UTF16LE, UTF16BE, UTF32LE, or UTF32BE. When I recently started work on getting the compiler to work properly on a big-endian IBM System Z, I realized I had built in a lot of little-endian assumptions that got in the way of handling big- and little-endian character sets on a big-endian machine. These changes eliminate some of those assumptions, so that the 32-bit cbl_char_t means the same thing on both big- and little-endian architectures. gcc/cobol/ChangeLog: * genapi.cc (get_level_88_domain): Expanded comment. (create_and_call): Handle CALL USING BY VALUE ZERO. * structs.cc: Updated comment. * util.cc: Prevent segfault when the procedures_t(size_t) constructor is invoked with exactly 512 symbols. libgcobol/ChangeLog: * charmaps.h (ascii_at): New define for '@', (charmap_load_unaligned): Eliminate. (charmap_store_unaligned): Eliminate. (store_uint16): Eliminate. (store_uint32): Eliminate. (class charmap_t): Make m_ascii_sign_bit, ::getch, ::putch, and ::memset behave for big-endian architectures. * gfileio.cc (write_a_char): Behave properly on big-endian architectures. (sequential_file_write): Likewise. (line_sequential_file_read_sbc): Likewise. (line_sequential_file_read): Likewise. * libgcobol.cc (edited_to_binary): Simplified. (int128_to_field): Proper big-endian behavior. (uber_compare): Proper big-endian behavior, simplified ABI. (__gg__dirty_to_binary): Simplified. (compare_strings): Use new uber_compare call. (__gg__compare_2): Likewise. Diff: --- gcc/cobol/genapi.cc | 23 +++- gcc/cobol/structs.cc | 2 +- gcc/cobol/util.cc | 5 +- libgcobol/charmaps.h | 320 ++++++++++++++++++++++++++++++------------------- libgcobol/gfileio.cc | 39 ++++-- libgcobol/libgcobol.cc | 199 +++++++++++++----------------- 6 files changed, 330 insertions(+), 258 deletions(-) diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc index 5fc6c8d726e8..33b5f09aaf10 100644 --- a/gcc/cobol/genapi.cc +++ b/gcc/cobol/genapi.cc @@ -461,6 +461,25 @@ get_level_88_domain(size_t parent_capacity, cbl_field_t *var, size_t &returned_s // Numerics are converted to strings, and handled as above + /* For example: + + 77 var-1 PIC 99V9. + 88 var-1-z VALUE zero THRU 10. + 88 var-1-big VALUE 20 THRU 40. + 88 var-1-huge VALUE 40 THRU 999. + 88 var-1-asc VALUE "U2" THRU "XYZZY". + + Creates these four string segments: + + "1FZ2A10" + "2A202A40" + "2A403A999" + "2AU25AXYZZY" + + Each gets converted to UTF-32 as the initial value. + + */ + size_t retval_capacity = 64; char *retval = static_cast<char *>(xmalloc(retval_capacity)); size_t output_index = 0; @@ -12754,7 +12773,9 @@ create_and_call(size_t narg, // These have to be passed to be passed by value. crv = by_value_e; } - else if( crv == by_value_e && args[i].refer.field->type == FldAlphanumeric) + else if( crv == by_value_e + && args[i].refer.field->type == FldAlphanumeric + && (args[i].refer.field->attr & FIGCONST_MASK) != zero_value_e ) { // Maybe passing an alphanumeric BY VALUE should be a syntax error? crv = by_content_e; diff --git a/gcc/cobol/structs.cc b/gcc/cobol/structs.cc index 37b2b0c878a4..cacd6b4f73eb 100644 --- a/gcc/cobol/structs.cc +++ b/gcc/cobol/structs.cc @@ -308,7 +308,7 @@ typedef struct cblc_file_t int errnum; // most recent errno; can't reuse "errno" as the name file_status_t io_status; // See 2014 standard, section 9.1.12 int padding; // Actually a char - uint32_t delimiter; // ends a record; defaults to '\n'. + uint32_t delimiter; // This is four bytes in encoding order. int stride; // Width of a character int flags; // cblc_file_flags_t uint32_t recent_char; // This is the most recent char sent to the file diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index 4a44eb2ae511..c4927a9c4592 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -2684,8 +2684,9 @@ namespace match_proc { public: procedures_t( size_t program ) { // find sections and paragraphs - for( symbol_elem_t *e = symbols_begin(program+1); e->program == program; e++ ) { - if( e->type == SymLabel ) { + for( symbol_elem_t *e = symbols_begin(program+1); + e < symbols_end() && e->program == program; e++ ) { + if( e->type == SymLabel ) { const auto& L = *cbl_label_of(e); auto isym = e - symbols_begin(); switch(L.type) { diff --git a/libgcobol/charmaps.h b/libgcobol/charmaps.h index 3f212ac93bc1..626ef3852340 100644 --- a/libgcobol/charmaps.h +++ b/libgcobol/charmaps.h @@ -271,6 +271,7 @@ enum #define ascii_query ((uint8_t)('?')) #define ascii_lbrace ((uint8_t)('{')) #define ascii_rbrace ((uint8_t)('}')) +#define ascii_at ((uint8_t)('@')) #define ascii_ff ((uint8_t)('\f')) #define ascii_return ((uint8_t)('\r')) #define ascii_newline ((uint8_t)('\n')) @@ -340,40 +341,6 @@ charmap_as_unsigned_chars(const char *p) return reinterpret_cast<const unsigned char *>(p); } -template <typename T> -static T -charmap_load_unaligned(const void *p) - { - static_assert(std::is_trivially_copyable<T>::value, - "charmap_load_unaligned requires a trivially copyable type"); - T retval; - std::memcpy(&retval, p, sizeof(retval)); - return retval; - } - -template <typename T> -static void -charmap_store_unaligned(void *p, T value) - { - static_assert(std::is_trivially_copyable<T>::value, - "charmap_store_unaligned requires a trivially copyable type"); - std::memcpy(p, &value, sizeof(value)); - } - -static inline void -store_uint16(unsigned char *p, uint16_t value) - { - // This routine is handling encoded characters, so the storage is literal - memcpy(p, &value, 2); - } - -static inline void -store_uint32(unsigned char *p, uint32_t value) - { - // This routine is handling encoded characters, so the storage is literal - memcpy(p, &value, 4); - } - class charmap_t; /* @@ -470,26 +437,27 @@ class charmap_t sign_type_ebcdic, } m_numeric_sign_type; + // In numeric display with sign internal, this bit gets turned on in either + // the leading or trailing digit to indicate the value is negative. It + // is the single bit turned on for the `@` character. + uint8_t m_ascii_sign_bit[4]; + // This map retains the ASCII-to-encoded value in m_encoding, so that // iconv need be called but once for each ASCII value. std::unordered_map<cbl_char_t, cbl_char_t> m_map_of_encodings; - const unsigned char * - skip_bom(const unsigned char *p, size_t outlength) const - { - if( m_has_bom && outlength >= 2 * m_stride ) - { - p += m_stride; - } - return p; - } - cbl_char_t get_encoded_char(const void *base_, size_t location) const { + // The idea here is that we look into a stream of encoded characters. + // Starting at base_+location, we pick up m_stride characters and put + // them into the cbl_char_t (which is 32-bit unsigned integer) so that + // retval is not dependent on endianness of either the host machine or + // the target machine. + const unsigned char *base = static_cast<const unsigned char *>(base_); const unsigned char *p = base + location; - cbl_char_t retval = 0; + cbl_char_t retval; switch(m_stride) { @@ -501,17 +469,31 @@ class charmap_t case 2: { - uint16_t c; - memcpy(&c, p, 2); - retval = c; + if(m_is_big_endian) + { + // The first byte is the high-order byte + retval = (p[0]<<8) + p[1]; + } + else + { + // The first byte is the low-order byte + retval = (p[1]<<8) + p[0]; + } break; } default: { - uint32_t c; - memcpy(&c, p, 4); - retval = c; + if(m_is_big_endian) + { + // The first byte is the high-order byte + retval = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; + } + else + { + // The first byte is the low-order byte + retval = (p[3]<<24) + (p[2]<<16) + (p[1]<<8) + p[0]; + } break; } } @@ -522,6 +504,9 @@ class charmap_t void put_encoded_char(cbl_char_t ch, void *base_, size_t location) const { + // This is the reverse of get encoded character. The value in ch is + // placed in memory + unsigned char *base = static_cast<unsigned char *>(base_); unsigned char *p = base + location; @@ -532,11 +517,39 @@ class charmap_t break; case 2: - store_uint16(p, static_cast<uint16_t>(ch)); + { + if(m_is_big_endian) + { + // The first byte is the high-order byte + p[0] = ch>>8; + p[1] = ch; + } + else + { + // The first byte is the low-order byte + p[1] = ch>>8; + p[0] = ch; + } break; + } default: - store_uint32(p, ch); + if(m_is_big_endian) + { + // The first byte is the high-order byte + p[0] = ch>>24; + p[1] = ch>>16; + p[2] = ch>>8; + p[3] = ch; + } + else + { + // The first byte is the low-order byte + p[3] = ch>>24; + p[2] = ch>>16; + p[1] = ch>>8; + p[0] = ch; + } break; } } @@ -671,12 +684,25 @@ class charmap_t &outbuf, &outbytesleft); outlength = sizeof(response_) - outbytesleft; m_is_like_utf8 = (outlength == 3); + + if( !is_like_ebcdic() ) + { + memset(m_ascii_sign_bit, 0x00, 4); + if( m_is_big_endian ) + { + m_ascii_sign_bit[m_stride-1] = 0x40; + } + else + { + m_ascii_sign_bit[0] = 0x40; + } + } } - bool is_valid() const { return m_is_valid ; } - bool is_big_endian() const { return m_is_big_endian; } - bool has_bom() const { return m_has_bom ; } - uint8_t stride() const { return m_stride ; } + bool is_valid() const { return m_is_valid ; } + bool is_big_endian() const { return m_is_big_endian ; } + bool has_bom() const { return m_has_bom ; } + uint8_t stride() const { return m_stride ; } cbl_char_t mapped_character(unsigned char ch) @@ -696,45 +722,12 @@ class charmap_t { retval = 0; size_t outlength = 0; - char *mapped = __gg__iconverter(DEFAULT_SOURCE_ENCODING, - m_encoding, - &ch, - 1, - &outlength); - size_t data_length = outlength; - const unsigned char *p = charmap_as_unsigned_chars(mapped); - if( m_has_bom && data_length >= 2 * stride() ) - { - p = skip_bom(p, data_length); - data_length -= stride(); - } - - switch(stride()) - { - case 1: - { - uint8_t c; - memcpy(&c, mapped, m_stride); - retval = c; - break; - } - - case 2: - { - uint16_t c; - memcpy(&c, mapped, m_stride); - retval = c; - break; - } - - case 4: - { - uint32_t c; - memcpy(&c, mapped, m_stride); - retval = c; - break; - } - } + const char *mapped = __gg__iconverter(DEFAULT_SOURCE_ENCODING, + m_encoding, + &ch, + 1, + &outlength); + retval = get_encoded_char(mapped, 0); m_map_of_encodings[ch] = retval; } return retval; @@ -821,7 +814,7 @@ class charmap_t switch(m_numeric_sign_type) { case sign_type_ascii: - retval = !!(digit & NUMERIC_DISPLAY_SIGN_BIT_ASCII); + retval = !!(digit & m_ascii_sign_bit[m_stride-1]); break; case sign_type_ebcdic: @@ -838,34 +831,31 @@ class charmap_t // ebcdic. switch(m_numeric_sign_type) { + // We need to do this in a loop because of the headaches caused by + // dealing with, for instance, little-endian characters on a big-endian + // architecture. case sign_type_ascii: { - uint32_t the_bit = m_is_big_endian - ? NUMERIC_DISPLAY_SIGN_BIT_ASCII << (m_stride-1) * 8 - : NUMERIC_DISPLAY_SIGN_BIT_ASCII; if( is_negative ) { - digit |= the_bit; + digit |= m_ascii_sign_bit[m_stride-1]; } else { - digit &= ~the_bit; + digit &= ~m_ascii_sign_bit[m_stride-1]; } break; } case sign_type_ebcdic: { - uint32_t the_bit = m_is_big_endian - ? NUMERIC_DISPLAY_SIGN_BIT_EBCDIC << (m_stride-1) * 8 - : NUMERIC_DISPLAY_SIGN_BIT_EBCDIC; if( is_negative ) { - digit &= ~the_bit; + digit &= ~NUMERIC_DISPLAY_SIGN_BIT_EBCDIC; } else { - digit |= the_bit; + digit |= NUMERIC_DISPLAY_SIGN_BIT_EBCDIC; } break; } @@ -873,6 +863,52 @@ class charmap_t return digit; } + void + set_streamed_digit_negative(uint8_t *digit, bool is_negative) + { + // Enter with digit pointing to a digit that needs to be adjusted for + // numeric-display internal signededness. + + // The loop might look odd, but it's how I decided to handle issues of + // big-endian characters on little-endian architectures, and + // little-endian characters on big-endian architectures, and so on. + switch(m_numeric_sign_type) + { + case sign_type_ascii: + { + if( is_negative ) + { + for(int i=0; i<m_stride; i++ ) + { + digit[i] |= m_ascii_sign_bit[i]; + } + } + else + { + for(int i=0; i<m_stride; i++ ) + { + digit[i] &= ~m_ascii_sign_bit[i]; + } + } + break; + } + + case sign_type_ebcdic: + { + if( is_negative ) + { + *digit &= ~NUMERIC_DISPLAY_SIGN_BIT_EBCDIC; + } + else + { + *digit |= NUMERIC_DISPLAY_SIGN_BIT_EBCDIC; + } + break; + } + } + } + + bool is_like_ebcdic() const { @@ -888,6 +924,10 @@ class charmap_t void memset(void *dest_, cbl_char_t ch, size_t bytelength) { + uint8_t byte3 = ch >> 24; + uint8_t byte2 = ch >> 16; + uint8_t byte1 = ch >> 8; + uint8_t byte0 = ch ; unsigned char *dest = static_cast<unsigned char *>(dest_); switch(m_stride) { @@ -902,10 +942,6 @@ class charmap_t { // We are being asked to fill a byte-wide buffer with a multi-byte // character. - unsigned char byte3 = static_cast<unsigned char>(ch >> 24); - unsigned char byte2 = static_cast<unsigned char>(ch >> 16); - unsigned char byte1 = static_cast<unsigned char>(ch >> 8); - unsigned char byte0 = static_cast<unsigned char>(ch); size_t i = 0; if( byte3 ) { @@ -949,31 +985,56 @@ class charmap_t // We know the target has an even number of bytes available. We also // know that each codepoint is usually one, but sometimes two, pairs // of bytes. - uint16_t top_half = static_cast<uint16_t>(ch >> 16); - uint16_t bottom_half = static_cast<uint16_t>(ch); size_t i = 0; while( i < bytelength ) { - if( top_half ) + if( byte3 | byte2 ) { if( i + 4 <= bytelength ) { - store_uint16(dest + i, top_half); - i += 2; - store_uint16(dest + i, bottom_half); - i += 2; + if( m_is_big_endian ) + { + dest[i+0] = byte3; + dest[i+1] = byte2; + dest[i+2] = byte1; + dest[i+3] = byte0; + } + else + { + dest[i+3] = byte3; + dest[i+2] = byte2; + dest[i+1] = byte1; + dest[i+0] = byte0; + } + i += 4; } else { - store_uint16(dest + i, - static_cast<uint16_t>( - mapped_character(ascii_space))); + if( m_is_big_endian) + { + dest[i+1] = ascii_space; + dest[i+0] = 0; + } + else + { + dest[i+1] = 0; + dest[i+0] = ascii_space; + } i += 2; } } else { - store_uint16(dest + i, bottom_half); + if( m_is_big_endian ) + { + dest[i+0] = byte1; + dest[i+1] = byte0; + } + else + { + dest[i+1] = byte1; + dest[i+0] = byte0; + } i += 2; } } @@ -986,7 +1047,20 @@ class charmap_t // We know the target has a multiple of four bytes available. for( size_t i = 0; i < bytelength; i += 4 ) { - store_uint32(dest + i, ch); + if( m_is_big_endian ) + { + dest[i+0] = byte3; + dest[i+1] = byte2; + dest[i+2] = byte1; + dest[i+3] = byte0; + } + else + { + dest[i+3] = byte3; + dest[i+2] = byte2; + dest[i+1] = byte1; + dest[i+0] = byte0; + } } break; } diff --git a/libgcobol/gfileio.cc b/libgcobol/gfileio.cc index dba7001237b8..934541e08ea9 100644 --- a/libgcobol/gfileio.cc +++ b/libgcobol/gfileio.cc @@ -360,7 +360,7 @@ __gg__file_init( { if( !(file->flags & file_flag_initialized_e) ) { - charmap_t *charmap = __gg__get_charmap(encoding); + const charmap_t *charmap = __gg__get_charmap(encoding); file->name = strdup(name); file->symbol_table_index = symbol_table_index; @@ -386,7 +386,6 @@ __gg__file_init( file->access = (cbl_file_access_t)access ; file->errnum = 0 ; file->io_status = FsSuccess ; - file->delimiter = charmap->mapped_character(ascii_newline) ; file->stride = charmap->stride(); file->flags = file_flag_none_e; file->flags |= (optional ? file_flag_optional_e : file_flag_none_e) @@ -398,6 +397,18 @@ __gg__file_init( file->encoding = encoding; file->alphabet = alphabet; + // Note: eventually the delimiter needs to be a variable; it can be set + // by the programmer. + size_t nbytes; + const char ch = ascii_newline; + const char *delim = __gg__iconverter(DEFAULT_SOURCE_ENCODING, + file->encoding, + &ch, + 1, + &nbytes); + memset(&file->delimiter, 0, 4); + memcpy(&file->delimiter, delim, file->stride); + if( file->access == file_inaccessible_e ) { file->access = file_access_seq_e; @@ -2669,9 +2680,11 @@ static void write_a_char(cblc_file_t *file, cbl_char_t ch) { size_t nbytes; + // Whether big- or little-endian, this will give us the character we want + unsigned char uch = ch % 256; const char *converted = __gg__iconverter(DEFAULT_SOURCE_ENCODING, file->encoding, - &ch, + &uch, 1, &nbytes); fwrite(converted, nbytes, 1, file->file_pointer); @@ -2730,7 +2743,7 @@ sequential_file_write(cblc_file_t *file, if( file->org == file_line_sequential_e ) { - // If file-sequential, then trailing spaces are removed: + // If line-sequential, then trailing spaces are removed: while(bytes_to_write > 0 && charmap->getch(location, bytes_to_write-stride) == charmap->mapped_character(ascii_space) ) @@ -3187,8 +3200,9 @@ line_sequential_file_read_sbc(cblc_file_t *file, char space) } // Much hinges on where the next newline is to be found: pstart = file->buffer+file->buffer_pos; + char ch = reinterpret_cast<const char *>(&file->delimiter)[0]; pnewline = reinterpret_cast<const char *>(memchr(pstart, - static_cast<char>(file->delimiter), + ch, file->buffer_len - file->buffer_pos)); if( file->buffer_pos >= file->buffer_len ) { @@ -3313,8 +3327,9 @@ line_sequential_file_read_sbc(cblc_file_t *file, char space) } } pstart = file->buffer+file->buffer_pos; + char ch = reinterpret_cast<const char *>(&file->delimiter)[0]; pnewline = reinterpret_cast<const char *>(memchr(pstart, - static_cast<char>(file->delimiter), + ch, file->buffer_len - file->buffer_pos)); if( pnewline ) { @@ -3380,7 +3395,7 @@ line_sequential_file_read( cblc_file_t *file) // it makes more sense to me. // We first stage the data into the record area. - cbl_char_t ch; + uint8_t ch[4]; long fpos = static_cast<long>(file->file_fpos); @@ -3427,11 +3442,10 @@ line_sequential_file_read( cblc_file_t *file) // There are still characters in the file->buffer, and we are still looking // to fill the record_area, and we are still looking for a end-of-line. - ch = 0; - memcpy(&ch, file->buffer+file->buffer_pos, stride); + memcpy(ch, file->buffer+file->buffer_pos, stride); file->buffer_pos += stride; file->file_fpos += stride; - if( ch == file->delimiter ) + if( memcmp(ch, &file->delimiter, stride) == 0) { break; } @@ -3485,13 +3499,12 @@ line_sequential_file_read( cblc_file_t *file) goto done; } } - ch = 0; - memcpy(&ch, file->buffer+file->buffer_pos, stride); + memcpy(ch, file->buffer+file->buffer_pos, stride); file->buffer_pos += stride; file->file_fpos += stride; // We can't use handle_ferror() directly, because an EOF is // a legitimate way to end the last line. - if( ch == file->delimiter ) + if( memcmp(ch, &file->delimiter, stride) == 0 ) { clearerr(file->file_pointer); break; diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc index cdc65d6b488c..52e3d929c75d 100644 --- a/libgcobol/libgcobol.cc +++ b/libgcobol/libgcobol.cc @@ -679,13 +679,10 @@ __gg__decimal_point_is_comma() static __int128 edited_to_binary( const cblc_field_t *field, - char *ps_, - size_t length, - int *rdigits) + const char *ps_, + size_t length, + int *rdigits) { - charmap_t *charmap = __gg__get_charmap(field->encoding); - - const unsigned char *ps = as_unsigned_chars(ps_); // This routine is used for converting NumericEdited strings to // binary. @@ -697,7 +694,13 @@ edited_to_binary( const cblc_field_t *field, // result as negative. We are going to look for a decimal point and count up // the numerical digits to the right of it. And we are going to pretend // that nothing else matters. - + size_t nbytes; + const unsigned char *ps = reinterpret_cast<unsigned char *> + (__gg__iconverter(field->encoding, + DEFAULT_SOURCE_ENCODING, + ps_, + length, + &nbytes)); int hyphen = 0; *rdigits = 0; @@ -716,37 +719,28 @@ edited_to_binary( const cblc_field_t *field, while( index < length ) { - cbl_char_t ch = charmap->getch(ps, &index); + unsigned char ch = ps[index++]; // Save the last two characters for the DB/CR test: chm2 = chm1; chm1 = ch; - if( ch == charmap->mapped_character(__gg__decimal_point) ) + if( ch == __gg__decimal_point ) { delta_r = 1; continue; } - if( ch == charmap->mapped_character(ascii_minus) ) + if( ch == ascii_minus ) { hyphen = 1; continue; } - if( ch >= charmap->mapped_character(ascii_0) - && ch <= charmap->mapped_character(ascii_9) ) + if( ch >= ascii_0 + && ch <= ascii_9 ) { - uint8_t the_byte; - if( charmap->is_big_endian() ) - { - the_byte = ch >> ((charmap->stride()-1)*8); - } - else - { - the_byte = ch; - } result *= 10; - result += the_byte & 0x0F ; + result += ch & 0x0F ; *rdigits += delta_r ; continue; } @@ -756,17 +750,17 @@ edited_to_binary( const cblc_field_t *field, // is negative: if( !hyphen && length >= 2) { - if( ( chm2 == charmap->mapped_character(ascii_D) - || chm2 == charmap->mapped_character(ascii_d)) - && ( chm1 == charmap->mapped_character(ascii_B) - || chm1 == charmap->mapped_character(ascii_b)) ) + if( ( chm2 == ascii_D + || chm2 == ascii_d) + && ( chm1 == ascii_B + || chm1 == ascii_b) ) { hyphen = 1; } - else if( ( chm2 == charmap->mapped_character(ascii_C) - || chm2 == charmap->mapped_character(ascii_c)) - && ( chm1 == charmap->mapped_character(ascii_R) - || chm1 == charmap->mapped_character(ascii_r)) ) + else if( ( chm2 == ascii_C + || chm2 == ascii_c) + && ( chm1 == ascii_R + || chm1 == ascii_r) ) { hyphen = 1; } @@ -2245,10 +2239,10 @@ int128_to_field(cblc_field_t *var, // First, convert the binary value to the correct-length string size_error = - __gg__binary_to_string_encoded(as_chars( location), - var->digits, - value, - var->encoding); + __gg__binary_to_string_encoded(as_chars( location), + var->digits, + value, + var->encoding); // Check for a size error on a negative value. It conceivably // was truncated down to zero, in which case we need to @@ -2256,8 +2250,7 @@ int128_to_field(cblc_field_t *var, if( size_error && is_negative ) { // If all of the digits are zero, then the result is zero, - // and - // we have to kill the is_negative flag: + // and we have to kill the is_negative flag: is_negative = false; size_t index = 0; while(index<length) @@ -2272,13 +2265,10 @@ int128_to_field(cblc_field_t *var, } unsigned char *sign_location = - var->attr & leading_e ? location - : location + length - stride; - cbl_char_t sign_digit = charmap->getch(sign_location, - (size_t)0); - sign_digit = charmap->set_digit_negative(sign_digit, - is_negative); - charmap->putch(sign_digit, sign_location, (size_t)0); + var->attr & leading_e ? location + : location + length - stride; + charmap->set_streamed_digit_negative(sign_location, + is_negative); } } else @@ -2739,24 +2729,13 @@ uint32_t collation_position( cbl_char_t ch ) static cbl_char_t uber_compare(cbl_char_t ch_left, - cbl_char_t ch_right, - const charmap_t *charmap) + cbl_char_t ch_right) { - if( charmap->is_big_endian() ) - { - // This simple hack works when the big-endian characters nonetheless fit - // into zero through 255. This is short-sighted. I need glasses. Again, - // I do not know how to fix this until multi-byte collation is addressed. - ch_left >>= 8*(charmap->stride()-1); - ch_right >>= 8*(charmap->stride()-1); - } - + // This is where collation is going to have to be fixed for multi-byte + // encodings. For now, if both characters fit into 0xFF, then we will + // use the current collation. Otherwise, we just compare them. if( ((ch_left | ch_right) & 0xFFFFFF00) == 0x00000000 ) { - // This is where collation is going to have to be fixed for multi-byte - // encodings. For now, if both characters fit into 0xFF, then we will - // use the current collation. Otherwise, we just compare them - // Both characters fit into the current DISPLAY codeset, so assume we // are using the DISPLAY collation: ch_left = collated(ch_left); @@ -2770,7 +2749,6 @@ uber_compare(cbl_char_t ch_left, return retval; } - extern "C" int __gg__setop_compare( @@ -2945,9 +2923,9 @@ __gg__dirty_to_binary_source(const char *dirty, extern "C" __int128 -__gg__dirty_to_binary(const char *dirty, +__gg__dirty_to_binary(const char *dirty_in, cbl_encoding_t encoding, - int length, + int length_in, int *rdigits) { // This routine is used for converting uncontrolled strings to a @@ -2969,17 +2947,12 @@ __gg__dirty_to_binary(const char *dirty, // We are limiting the number of digits in the number to // MAX_FIXED_POINT_DIGITS - charmap_t *charmap = __gg__get_charmap(encoding); - int stride = charmap->stride(); - - cbl_char_t mapped_minus = charmap->mapped_character(ascii_minus); - cbl_char_t mapped_plus = charmap->mapped_character(ascii_plus); - cbl_char_t mapped_decimal_point = - charmap->mapped_character(__gg__decimal_point); - cbl_char_t mapped_0 = charmap->mapped_character(ascii_0); - cbl_char_t mapped_9 = charmap->mapped_character(ascii_9); - cbl_char_t mapped_E = charmap->mapped_character(ascii_E); - cbl_char_t mapped_e = charmap->mapped_character(ascii_e); + size_t length; + const char *dirty = __gg__iconverter(encoding, + DEFAULT_SOURCE_ENCODING, + dirty_in, + length_in, + &length); __int128 retval = 0; @@ -2993,37 +2966,33 @@ __gg__dirty_to_binary(const char *dirty, int delta_r = 0; // We now loop over the remaining input characters: - cbl_char_t ch = '\0'; + char ch = '\0'; size_t chindex = 0; if(length > 0) { - length -= stride; - ch = charmap->getch(dirty, &chindex); - if( ch == mapped_minus ) + length -= 1; + ch = dirty[chindex++]; + if( ch == ascii_minus ) { hyphen = 1; } - else if( ch == mapped_plus ) + else if( ch == ascii_plus ) { // A plus sign is okay } - else if( ch == mapped_decimal_point ) + else if( ch == __gg__decimal_point ) { delta_r = 1; } - else if( ch >= mapped_0 - && ch <= mapped_9 ) + else if( ch >= ascii_0 + && ch <= ascii_9 ) { - retval = ch - mapped_0 ; + retval = ch - ascii_0 ; if( retval ) { digit_count += 1; } - if( charmap->is_big_endian() ) - { - retval >>= 8*(stride-1); - } } else { @@ -3036,17 +3005,16 @@ __gg__dirty_to_binary(const char *dirty, while( length > 0 ) { - length -= stride; - ch = charmap->getch(dirty, &chindex); - if( ch == mapped_decimal_point && delta_r == 0 ) + ch = dirty[chindex++]; + if( ch == __gg__decimal_point && delta_r == 0 ) { // This is the first decimal point we've seen, so we // can start counting rdigits: delta_r = 1; continue; } - if( ch < mapped_0 - || ch > mapped_9 ) + if( ch < ascii_0 + || ch > ascii_9 ) { // When we hit something that isn't a digit, then we are done break; @@ -3054,12 +3022,7 @@ __gg__dirty_to_binary(const char *dirty, if( digit_count < MAX_FIXED_POINT_DIGITS ) { retval *= 10; - ch -= mapped_0; - if( charmap->is_big_endian() ) - { - ch >>= 8*(stride-1); - } - + ch -= ascii_0; retval += ch ; *rdigits += delta_r; if( retval ) @@ -3070,38 +3033,38 @@ __gg__dirty_to_binary(const char *dirty, } // Let's check for an exponent: - if( ch == mapped_E - || ch == mapped_e ) + if( ch == ascii_E + || ch == ascii_e ) { int exponent = 0; int exponent_sign = 1; if( length > 0 ) { - ch = charmap->getch(dirty, chindex); - if( ch == mapped_plus) + ch = dirty[chindex]; + if( ch == ascii_plus) { - length -= stride; - dirty += stride; + length -= 1; + dirty += 1; } - else if( ch == mapped_minus ) + else if( ch == ascii_minus ) { exponent_sign = -1; - length -= stride; - dirty += stride; + length -= 1; + dirty += 1; } } while(length > 0) { - length -= stride; - ch = charmap->getch(dirty, &chindex); - if( ch < mapped_0 - || ch > mapped_9 ) + length -= 1; + ch = dirty[chindex++]; + if( ch < ascii_0 + || ch > ascii_9 ) { // When we hit something that isn't a digit, then we are done break; } exponent *= 10; - exponent += ch - mapped_0 ; + exponent += ch - ascii_0 ; } exponent *= exponent_sign; // We need to adjust the retval and the rdigits based on the exponent. @@ -5054,7 +5017,7 @@ compare_strings(char *left_string, { cbl_char_t ch_left = charmap_left->getch(left_string, &index_left); cbl_char_t ch_right = charmap_right->getch(right_string, &index_right); - retval = uber_compare(ch_left, ch_right, charmap_left); + retval = uber_compare(ch_left, ch_right); } // We need to space-extend the shorter value. That's because @@ -5065,7 +5028,7 @@ compare_strings(char *left_string, { cbl_char_t ch_left = charmap_left->getch(left_string, &index_left); cbl_char_t ch_right = charmap_right->mapped_character(ascii_space); - retval = uber_compare(ch_left, ch_right, charmap_left); + retval = uber_compare(ch_left, ch_right); } } else @@ -5077,7 +5040,7 @@ compare_strings(char *left_string, index_right %= right_length; cbl_char_t ch_left = charmap_left->getch(left_string, &index_left); cbl_char_t ch_right = charmap_right->getch(right_string, &index_right); - retval = uber_compare(ch_left, ch_right, charmap_left); + retval = uber_compare(ch_left, ch_right); } } @@ -5087,7 +5050,7 @@ compare_strings(char *left_string, { cbl_char_t ch_left = charmap_left->mapped_character(ascii_space); cbl_char_t ch_right = charmap_right->getch(right_string, &index_right); - retval = uber_compare(ch_left, ch_right, charmap_left); + retval = uber_compare(ch_left, ch_right); } } else @@ -5097,7 +5060,7 @@ compare_strings(char *left_string, index_left %= left_length; cbl_char_t ch_left = charmap_left->mapped_character(ascii_space); cbl_char_t ch_right = charmap_right->getch(right_string, &index_right); - retval = uber_compare(ch_left, ch_right, charmap_left); + retval = uber_compare(ch_left, ch_right); } } @@ -5174,7 +5137,7 @@ __gg__compare_2(cblc_field_t *left_side, if( left_figconst && right_figconst ) { // We are comparing two figurative constants - retval = uber_compare(fig_left, fig_right, charmap_left); + retval = uber_compare(fig_left, fig_right); compare = true; goto fixup_retval; } @@ -5213,7 +5176,7 @@ __gg__compare_2(cblc_field_t *left_side, cbl_char_t fig_of_right = charmap_left->figconst_character(right_figconst); cbl_char_t left_ch = charmap_left->getch(left_location, i); - retval = uber_compare(left_ch, fig_of_right, charmap_left); + retval = uber_compare(left_ch, fig_of_right); if( retval ) { break; @@ -5271,7 +5234,7 @@ __gg__compare_2(cblc_field_t *left_side, unsigned int fig_of_right = charmap_left->figconst_character(right_figconst); cbl_char_t ch_left = charmap_left->getch(left_location, i); - retval = uber_compare(ch_left, fig_of_right, charmap_left); + retval = uber_compare(ch_left, fig_of_right); if( retval ) { break;