diff --git a/libcob/ChangeLog b/libcob/ChangeLog index 2416a161..2fb01f1d 100644 --- a/libcob/ChangeLog +++ b/libcob/ChangeLog @@ -49,7 +49,7 @@ * fileio.c (apply_file_paths): extracted from cob_chk_file_mapping to factor out duplicated code -2023-06-02 Simon Sobisch +2024-06-02 Simon Sobisch * fisam.c (isam_read_next): use ISSTAT only for COB_WITH_STATUS_02, fixing compile errors with VBISAM @@ -59,6 +59,11 @@ * common.h [__MINGW32__]: drop ancient redefinition of strcasecmp and strncasecmp +2023-04-27 Simon Sobisch + + * move.c (cob_move_display_to_packed), numeric.c (cob_decimal_get_packed): + simplify code, following idea by of Chuck Haatveet + 2023-04-26 Simon Sobisch * general: only include coblocal.h which includes common.h already diff --git a/libcob/move.c b/libcob/move.c index 22b316d1..6c77fe4c 100644 --- a/libcob/move.c +++ b/libcob/move.c @@ -475,13 +475,20 @@ cob_move_display_to_packed (cob_field *f1, cob_field *f2) { register unsigned char *q = f2->data + i / 2; const unsigned int i_end = digits2 + i; - const unsigned char *p_end = data1 + digits1; /* FIXME: get rid of that, adjust i_end accordingly */ - for (; i < i_end && p < p_end; ++i) { - if ((i & 1) == 0) { /* -> i % 2 == 0 */ - *q = (unsigned char)(*p++ << 4); /* -> dropping the higher bits = no use in COB_D2I */ - } else { - *q++ += COB_D2I (*p++); - } + /* FIXME: get rid of that, adjust i_end accordingly and always end at sign byte */ + const unsigned char *p_end = data1 + digits1; + + if ((i % 2) == 1) { + *q++ = COB_D2I (*p++); + i++; + } + /* note: for performance reasons we write "full bytes" only, this means that for COMP-3 + we'll read 1 byte "too much = after" from the DISPLAY data; + it is believed that this won't raise a SIGBUS anywhere, but we will need to "clean" + the half-byte before setting the sign */ + for (; i < i_end && p < p_end; ++i, q++, p += 2) { + *q = (unsigned char) (*p << 4) /* -> dropping the higher bits = no use in COB_D2I */ + + COB_D2I (*(p + 1)); } } @@ -490,27 +497,14 @@ cob_move_display_to_packed (cob_field *f1, cob_field *f2) return; } - p = f2->data + f2->size - 1; -#if 0 /* FIXME: this should work, but in some cases (seen in ACOS test) - we do have written one half-byte too much, which we need to drop. */ - /* add half-byte for sign, - note: we can directly use |= as it was zeroed out above */ + p = f2->data + f2->size - 1; /* TODO: ending at the sign byte means we can drop that */ if (!COB_FIELD_HAVE_SIGN (f2)) { *p |= 0x0F; - } else if (sign == -1) { - *p |= 0x0D; - } else { - *p |= 0x0C; - } -#else - if (!COB_FIELD_HAVE_SIGN (f2)) { - *p = (*p & 0xF0) | 0x0F; } else if (sign == -1) { *p = (*p & 0xF0) | 0x0D; } else { *p = (*p & 0xF0) | 0x0C; } -#endif } static void @@ -743,7 +737,7 @@ cob_move_binary_to_display (cob_field *f1, cob_field *f2) cob_u64_t val; int i; int sign; - char buff[32]; + unsigned char buff[32]; sign = 1; if (f2->size > 18 diff --git a/libcob/numeric.c b/libcob/numeric.c index a2821bf8..e7b3693f 100644 --- a/libcob/numeric.c +++ b/libcob/numeric.c @@ -1218,7 +1218,7 @@ cob_decimal_get_packed (cob_decimal *d, cob_field *f, const int opt) memset (data, 0, f->size); /* calculate starting half-byte */ - size = (unsigned int)strlen (buff); + size = (unsigned int) strlen (buff); diff = (unsigned int) digits - size; if (COB_FIELD_NO_SIGN_NIBBLE (f)) { @@ -1233,12 +1233,15 @@ cob_decimal_get_packed (cob_decimal *d, cob_field *f, const int opt) { register unsigned char *q = (unsigned char *)buff; register unsigned int i = diff; + + if ((i % 2) == 1) { + *p++ += COB_D2I (*q++); + i++; + } while (i < size) { - if ((i++ & 1) == 0) { /* -> i % 2 == 0 */ - *p = (unsigned char) (*q++ << 4); /* -> dropping the higher bits = no use in COB_D2I */ - } else { - *p++ += COB_D2I (*q++); - } + *p++ = (unsigned char) (*q << 4) /* -> dropping the higher bits = no use in COB_D2I */ + + COB_D2I (*(q + 1)); + q += 2; i += 2; } } @@ -1247,7 +1250,8 @@ cob_decimal_get_packed (cob_decimal *d, cob_field *f, const int opt) } /* add half-byte for sign, - note: we can directly use |= as it was zeroed out above */ + note: we can directly use |= as we set the last half-bte to the trailing low-value + we got from mpz_get_str above */ p = data + f->size - 1; if (!COB_FIELD_HAVE_SIGN (f)) { *p |= 0x0FU;