Files
calc/blkcpy.c
Landon Curt Noll d9245844aa removed use of have_memmv.c and HAVE_MEMMOVE, prep for version 2.15.1.2
Removed use of HAVE_MEMMOVE as well have_memmv.c.  Removed the
building and including of have_memmv.h.  Removed the memmove()
function in blkcpy.c, used when HAVE_MEMMOVE was NOT defined.
The libc memmove(3) function as defined by <string.h> is now
required to compile calc because the replacement code in
blkcpy.c q was problematic, especially when regions overlap.
The HAVE_MEMMOVE make symbol was removed from Makefile.config.
Thanks to GitHub user @skeeto for reporting this problem.
2025-08-13 12:42:45 -07:00

1058 lines
31 KiB
C

/*
* blkcpy - general values and related routines used by the calculator
*
* Copyright (C) 1999-2007,2021-2023,2025 Landon Curt Noll and Ernest Bowen
*
* Primary author: Landon Curt Noll
*
* Calc is open software; you can redistribute it and/or modify it under
* the terms of the version 2.1 of the GNU Lesser General Public License
* as published by the Free Software Foundation.
*
* Calc is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
* Public License for more details.
*
* A copy of version 2.1 of the GNU Lesser General Public License is
* distributed with calc under the filename COPYING-LGPL. You should have
* received a copy with calc; if not, write to Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Under source code control: 1997/04/18 20:41:26
* File existed as early as: 1997
*
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
*/
#include <stdio.h>
#include <sys/types.h>
#include "calc.h"
#include "alloc.h"
#include "value.h"
#include "file.h"
#include "blkcpy.h"
#include "str.h"
#include "errtbl.h"
#include "banned.h" /* include after system header <> includes */
/*
* copystod - copy num indexed items from source value to destination value
*
* given:
* ssi = source starting index
* num = number of items (octets or values) to be copied
* sdi = destination starting index
*
* returns:
* zero if successful, otherwise error-code number
*/
int
copystod(VALUE *svp, long ssi, long num, VALUE *dvp, long dsi)
{
BLOCK *sblk;
BLOCK *dblk;
bool noreloc;
sblk = NULL;
dblk = NULL;
/*
* check protections
*/
if (svp->v_subtype & V_NOCOPYFROM)
return E_COPY_13;
if (dvp->v_subtype & V_NOCOPYTO)
return E_COPY_14;
noreloc = ((dvp->v_subtype & V_NOREALLOC) != 0);
/*
* determine/check source type
*/
switch(svp->v_type) {
case V_NBLOCK:
if (svp->v_nblock->subtype & V_NOCOPYFROM)
return E_COPY_15;
sblk = svp->v_nblock->blk;
if (sblk->data == NULL)
return E_COPY_08;
break;
case V_BLOCK:
sblk = svp->v_block;
break;
case V_STR:
case V_OCTET:
case V_NUM:
case V_FILE:
case V_MAT:
case V_LIST:
break;
default:
return E_COPY_09;
}
/*
* determine/check destination type
*/
switch(dvp->v_type) {
case V_NBLOCK:
if (dvp->v_nblock->subtype & V_NOCOPYTO)
return E_COPY_16;
noreloc |=((dvp->v_nblock->subtype & V_NOREALLOC) != 0);
dblk = dvp->v_nblock->blk;
if (dblk->data == NULL)
return E_COPY_10;
break;
case V_BLOCK:
noreloc = ((dvp->v_subtype & V_NOREALLOC) != 0);
dblk = dvp->v_block;
break;
case V_STR:
case V_NUM:
case V_FILE:
case V_MAT:
case V_LIST:
break;
default:
return E_COPY_11;
}
/*
* copy based on source
*/
switch (svp->v_type) {
case V_BLOCK:
case V_NBLOCK:
/*
* copy from a block
*/
switch(dvp->v_type) {
case V_BLOCK:
case V_NBLOCK:
return copyblk2blk(sblk, ssi, num, dblk, dsi, noreloc);
case V_NUM:
{
NUMBER *n; /* modified number */
int rt; /* return code */
/* copy to a number */
rt = copyblk2num(sblk, ssi, num, dvp->v_num, dsi, &n);
if (rt == 0) {
qfree(dvp->v_num);
dvp->v_num = n;
}
return rt;
}
case V_FILE:
return copyblk2file(sblk, ssi, num, dvp->v_file, dsi);
case V_MAT:
return copyblk2mat(sblk, ssi, num, dvp->v_mat, dsi);
case V_STR:
return copyblk2str(sblk, ssi, num, dvp->v_str, dsi);
}
return E_COPY_12;
case V_STR:
switch(dvp->v_type) {
case V_BLOCK:
case V_NBLOCK:
/* copy to a block */
return copystr2blk(svp->v_str, ssi, num, dblk, dsi,
noreloc);
case V_FILE:
return copystr2file(svp->v_str, ssi, num,
dvp->v_file, dsi);
case V_STR:
return copystr2str(svp->v_str, ssi, num, dvp->v_str,
dsi);
}
return E_COPY_12;
case V_OCTET:
switch(dvp->v_type) {
case V_BLOCK:
case V_NBLOCK:
return copyostr2blk((char *) svp->v_octet, ssi, num,
dblk, dsi, noreloc);
case V_STR:
return copyostr2str((char *) svp->v_octet, ssi, num,
dvp->v_str, dsi);
}
return E_COPY_12;
case V_NUM:
/*
* copy from a number
*/
if (dblk != NULL) {
/* copy to a block */
return copynum2blk(svp->v_num, ssi, num, dblk,
dsi, noreloc);
}
switch (dvp->v_type) {
case V_MAT:
/* copy to a matrix */
return E_COPY_12; /* not yet - XXX */
case V_LIST:
/* copy to a list */
return E_COPY_12; /* not yet - XXX */
}
break;
case V_FILE:
/*
* copy from a file
*/
if (dblk != NULL) {
/* copy to a block */
return copyfile2blk(svp->v_file, ssi, num,
dblk, dsi, noreloc);
}
switch (dvp->v_type) {
case V_NUM:
/* copy to a number */
return E_COPY_12; /* not yet - XXX */
}
break;
case V_MAT:
/*
* copy from a matrix
*/
if (dblk != NULL) {
/* copy to a block */
return copymat2blk(svp->v_mat, ssi, num, dblk,
dsi, noreloc);
}
switch (dvp->v_type) {
case V_MAT:
/* copy to a matrix */
return copymat2mat(svp->v_mat, ssi, num,
dvp->v_mat, dsi);
case V_LIST:
/* copy to a list */
return copymat2list(svp->v_mat, ssi, num,
dvp->v_list, dsi);
}
break;
case V_LIST:
/*
* copy from a list
*/
if (dblk != NULL) {
/* copy to a block */
return E_COPY_12; /* not yet - XXX */
}
switch (dvp->v_type) {
case V_MAT:
/* copy to a matrix */
return copylist2mat(svp->v_list, ssi, num,
dvp->v_mat, dsi);
case V_LIST:
/* copy to a list */
return copylist2list(svp->v_list, ssi, num,
dvp->v_list, dsi);
}
break;
}
/*
* unsupported copy combination
*/
return E_COPY_12;
}
/*
* copymat2mat - copy matrix to matrix
*/
int
copymat2mat(MATRIX *smat, long ssi, long num, MATRIX *dmat, long dsi)
{
long i;
VALUE *vp;
VALUE *vq;
VALUE *vtemp;
unsigned short subtype;
if (ssi > smat->m_size)
return E_COPY_02;
if (num < 0)
num = smat->m_size - ssi;
if (ssi + num > smat->m_size)
return E_COPY_05;
if (num == 0)
return 0;
if (dsi < 0)
dsi = 0;
if (dsi + num > dmat->m_size)
return E_COPY_07;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for mat-to-mat copy");
not_reached();
}
vp = smat->m_table + ssi;
vq = vtemp;
i = num;
while (i-- > 0)
copyvalue(vp++, vq++);
vp = vtemp;
vq = dmat->m_table + dsi;
for (i = num; i > 0; i--, vp++, vq++) {
subtype = vq->v_subtype;
freevalue(vq);
*vq = *vp;
vq->v_subtype |= subtype;
}
free(vtemp);
return 0;
}
/*
* copyblk2mat - copy block to matrix
*/
int
copyblk2mat(BLOCK *blk, long ssi, long num, MATRIX *dmat, long dsi)
{
OCTET *op;
VALUE *vp;
VALUE *vq;
VALUE *vtemp;
long i;
unsigned short subtype;
if (ssi > blk->datalen)
return E_COPY_02;
if (num < 0)
num = blk->datalen - ssi;
if (ssi + num > blk->datalen)
return E_COPY_05;
if (num == 0)
return 0;
if (dsi < 0)
dsi = 0;
if (dsi + num > dmat->m_size)
return E_COPY_07;
op = blk->data + ssi;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for block-to-matrix copy");
not_reached();
}
vp = vtemp;
i = num;
while (i-- > 0) {
vp->v_type = V_NUM;
vp->v_subtype = V_NOSUBTYPE;
vp->v_num = itoq((long) *op++);
vp++;
}
vp = vtemp;
vq = dmat->m_table + dsi;
for (i = num; i > 0; i--, vp++, vq++) {
subtype = vq->v_subtype;
freevalue(vq);
*vq = *vp;
vq->v_subtype |= subtype;
}
free(vtemp);
return 0;
}
/*
* copymat2blk - copy matrix to block
*/
int
copymat2blk(MATRIX *smat, long ssi, long num, BLOCK *dblk, long dsi,
bool noreloc)
{
long i;
long newlen;
long newsize;
USB8 *newdata;
VALUE *vp;
OCTET *op;
if (ssi > smat->m_size)
return E_COPY_02;
if (num < 0)
num = smat->m_size - ssi;
if (num == 0)
return 0;
if (ssi + num > smat->m_size)
return E_COPY_05;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + num;
if (newlen <= 0)
return E_COPY_07;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY_17;
newsize = (1 + newlen/dblk->blkchunk) * dblk->blkchunk;
newdata = (USB8*) realloc(dblk->data, newsize);
if (newdata == NULL) {
math_error("Out of memory for matrix-to-block copy");
not_reached();
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
vp = smat->m_table + ssi;
op = dblk->data + dsi;
for (i = num; i > 0; i--)
copy2octet(vp++, op++);
if (newlen > dblk->datalen)
dblk->datalen = newlen;
return 0;
}
/*
* copymat2list - copy matrix to list
*/
int
copymat2list(MATRIX *smat, long ssi, long num, LIST *lp, long dsi)
{
VALUE *vp;
VALUE *vq;
LISTELEM *ep;
VALUE *vtemp;
long i;
unsigned short subtype;
if (ssi > smat->m_size)
return E_COPY_02;
if (num < 0)
num = smat->m_size - ssi;
if (num == 0)
return 0;
if (ssi + num > smat->m_size)
return E_COPY_05;
if (dsi < 0)
dsi = 0;
if (dsi + num > lp->l_count)
return E_COPY_07;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for matrix-to-list copy");
not_reached();
}
vp = smat->m_table + ssi;
vq = vtemp;
i = num;
while (i-- > 0)
copyvalue(vp++, vq++);
vq = vtemp;
ep = listelement(lp, (long) dsi);
i = num;
while (i-- > 0) {
subtype = ep->e_value.v_subtype;
freevalue(&ep->e_value);
ep->e_value = *vq++;
ep->e_value.v_subtype |= subtype;
ep = ep->e_next;
}
free(vtemp);
return 0;
}
/*
* copymat2list - copy list to matrix
*/
int
copylist2mat(LIST *lp, long ssi, long num, MATRIX *dmat, long dsi)
{
VALUE *vp;
VALUE *vq;
LISTELEM *ep;
VALUE *vtemp;
long i;
unsigned short subtype;
if (ssi > lp->l_count)
return E_COPY_02;
if (num < 0)
num = lp->l_count - ssi;
if (num == 0)
return 0;
if (ssi + num > lp->l_count)
return E_COPY_05;
if (dsi < 0)
dsi = 0;
if (dsi + num > dmat->m_size)
return E_COPY_07;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for list-to-matrix copy");
not_reached();
}
ep = listelement(lp, (long) ssi);
vp = vtemp;
i = num;
while (i-- > 0) {
copyvalue(&ep->e_value, vp++);
ep = ep->e_next;
}
vp = vtemp;
vq = dmat->m_table + dsi;
for (i = num; i > 0; i--, vp++, vq++) {
subtype = vq->v_subtype;
freevalue(vq);
*vq = *vp;
vq->v_subtype |= subtype;
}
free(vtemp);
return 0;
}
/*
* copylist2list - copy list to list
*/
int
copylist2list(LIST *slp, long ssi, long num, LIST *dlp, long dsi)
{
long i;
LISTELEM *sep;
LISTELEM *dep;
VALUE *vtemp;
VALUE *vp;
unsigned short subtype;
if (ssi > slp->l_count)
return E_COPY_02;
if (num < 0)
num = slp->l_count - ssi;
if (num == 0)
return 0;
if (ssi + num > slp->l_count)
return E_COPY_05;
if (dsi < 0)
dsi = 0;
if (dsi + num > dlp->l_count)
return E_COPY_07;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for list-to-list copy");
not_reached();
}
sep = listelement(slp, (long) ssi);
vp = vtemp;
i = num;
while (i-- > 0) {
copyvalue(&sep->e_value, vp++);
sep = sep->e_next;
}
dep = listelement(dlp, (long) dsi);
vp = vtemp;
i = num;
while (i-- > 0) {
subtype = dep->e_value.v_subtype;
freevalue(&dep->e_value);
dep->e_value = *vp++;
dep->e_value.v_subtype |= subtype;
dep = dep->e_next;
}
free(vtemp);
return 0;
}
/*
* copyblk2file - copy block to file
*/
int
copyblk2file(BLOCK *sblk, long ssi, long num, FILEID id, long dsi)
{
FILEIO *fiop;
FILE *fp;
long numw;
if (ssi > sblk->datalen)
return E_COPY_02;
if (num < 0)
num = sblk->datalen - ssi;
if (num == 0)
return 0;
fiop = findid(id, true);
if (fiop == NULL)
return E_COPYF_1;
fp = fiop->fp;
if (id == 1 || id == 2) {
numw = idfputstr(id, (char *)sblk->data + ssi); /* XXX */
return 0;
}
if (dsi >= 0) {
if (fseek(fp, dsi, 0))
return E_COPYF_2;
}
numw = fwrite(sblk->data + ssi, 1, num, fp);
if (numw < num)
return E_COPYF_3;
fflush(fp);
return 0;
}
/*
* copyfile2blk - copy file to block
*/
int
copyfile2blk(FILEID id, long ssi, long num, BLOCK *dblk, long dsi, bool noreloc)
{
FILEIO *fiop;
FILE *fp;
long numw;
ZVALUE fsize;
long filelen;
long newlen;
long newsize;
OCTET *newdata;
if (id < 3) /* excludes copying from stdin */
return E_COPYF_1;
fiop = findid(id, false);
if (fiop == NULL)
return E_COPYF_1;
fp = fiop->fp;
if (get_open_siz(fp, &fsize))
return E_COPYF_2;
if (zge31b(fsize)) {
zfree(fsize);
return E_COPY_05;
}
filelen = ztoi(fsize);
zfree(fsize);
if (ssi > filelen)
return E_COPY_02;
if (num < 0)
num = filelen - ssi;
if (num == 0)
return 0;
if (ssi + num > filelen)
return E_COPY_05;
if (fseek(fp, ssi, 0)) /* using system fseek XXX */
return E_COPYF_2;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + num;
if (newlen <= 0)
return E_COPY_07;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY_17;
newsize = (1 + newlen/dblk->blkchunk) * dblk->blkchunk;
newdata = (USB8*) realloc(dblk->data, newsize);
if (newdata == NULL) {
math_error("Out of memory for block-to-block copy");
not_reached();
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
numw = fread(dblk->data + dsi, 1, num, fp);
if (numw < num)
return E_COPYF_4;
if (newlen > dblk->datalen)
dblk->datalen = newlen;
return 0;
}
/*
* copystr2file - copy string to file
*/
int
copystr2file(STRING *str, long ssi, long num, FILEID id, long dsi)
{
long len;
FILEIO *fiop;
long numw;
FILE *fp;
len = str->s_len;
if (ssi >= len)
return E_COPY_02;
if (num < 0)
num = len - ssi;
if (num <= 0) /* Nothing to be copied */
return 0;
if (ssi + num > len)
return E_COPY_05; /* Insufficient memory in str */
fiop = findid(id, true);
if (fiop == NULL)
return E_COPYF_1;
fp = fiop->fp;
if (id == 1 || id == 2) {
numw = idfputstr(id, str->s_str + ssi); /* XXX */
return 0;
}
if (dsi >= 0) {
if (fseek(fp, dsi, 0))
return E_COPYF_2;
}
numw = fwrite(str->s_str + ssi, 1, num, fp);
if (numw < num)
return E_COPYF_3;
fflush(fp);
return 0;
}
/*
* copyblk2blk - copy block to block
*/
int
copyblk2blk(BLOCK *sblk, long ssi, long num, BLOCK *dblk, long dsi,
bool noreloc)
{
long newlen;
long newsize;
USB8 *newdata;
if (ssi > sblk->datalen)
return E_COPY_02;
if (num < 0)
num = sblk->datalen - ssi;
if (num == 0) /* Nothing to be copied */
return 0;
if (ssi + num > sblk->datalen)
return E_COPY_05;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + num;
if (newlen <= 0)
return E_COPY_07;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY_17;
newsize = (1 + newlen/dblk->blkchunk) * dblk->blkchunk;
newdata = (USB8*) realloc(dblk->data, newsize);
if (newdata == NULL) {
math_error("Out of memory for block-to-block copy");
not_reached();
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
memmove(dblk->data + dsi, sblk->data + ssi, num);
if (newlen > dblk->datalen)
dblk->datalen = newlen;
return 0;
}
/*
* copystr2blk - copy string to block
*/
int
copystr2blk(STRING *str, long ssi, long num, BLOCK *dblk, long dsi,
bool noreloc)
{
long len;
long newlen;
long newsize;
USB8 *newdata;
len = str->s_len;
if (ssi >= len)
return E_COPY_02;
if (num < 0)
num = len - ssi;
if (num <= 0) /* Nothing to be copied */
return 0;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + num + 1;
if (newlen <= 0)
return E_COPY_07;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY_17;
newsize = (1 + newlen/dblk->blkchunk) * dblk->blkchunk;
newdata = (USB8*) realloc(dblk->data, newsize);
if (newdata == NULL) {
math_error("Out of memory for string-to-block copy");
not_reached();
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
memmove(dblk->data + dsi, str->s_str + ssi, num);
dblk->data[dsi + num] = '\0';
if (newlen > dblk->datalen)
dblk->datalen = newlen;
return 0;
}
/*
* copystr2str - copy up to num characters from sstr (starting at
* index ssi) to dstr (starting at index dsi); num is reduced if there
* are insufficient characters in sstr or insufficient space in dstr.
*/
int
copystr2str(STRING *sstr, long ssi, long num, STRING *dstr, long dsi)
{
char *c, *c1;
if (num < 0 || (size_t)(ssi + num) > sstr->s_len)
num = sstr->s_len - ssi;
if (num <= 0)
return 0; /* Nothing to be copied */
if (dsi < 0) /* default destination index */
dsi = 0;
if ((size_t)(dsi + num) > dstr->s_len)
num = dstr->s_len - dsi;
c1 = sstr->s_str + ssi;
c = dstr->s_str + dsi;
while (num-- > 0)
*c++ = *c1++;
return 0;
}
/*
* copyblk2str - copy up to num characters from sblk (starting at
* index ssi) to str (starting at index dsi); num is reduced if there
* is insufficient data in blk or insufficient space in str
*/
int
copyblk2str(BLOCK *sblk, long ssi, long num, STRING *dstr, long dsi)
{
USB8 *c, *c1;
if (num < 0 || ssi + num > sblk->datalen)
num = sblk->datalen - ssi;
if (num <= 0)
return 0; /* Nothing to be copied */
if (dsi < 0) /* default destination index */
dsi = 0;
if ((size_t)(dsi + num) > dstr->s_len)
num = dstr->s_len - dsi;
c1 = sblk->data + ssi;
c = (USB8 *)dstr->s_str + dsi;
while (num-- > 0)
*c++ = *c1++;
return 0;
}
/*
* copyostr2str - copy octet-specified string to string
*/
int
copyostr2str(char *sstr, long ssi, long num, STRING *dstr, long dsi)
{
size_t len;
char *c, *c1;
len = strlen(sstr);
if (num < 0 || (size_t)(ssi + num) > len)
num = len - ssi;
if (num <= 0) /* Nothing to be copied */
return 0;
if (dsi < 0)
dsi = 0; /* Default destination index */
if ((size_t)(dsi + num) > dstr->s_len)
num = dstr->s_len - dsi;
c1 = sstr + ssi;
c = dstr->s_str + dsi;
while (num-- > 0)
*c++ = *c1++;
return 0;
}
/*
* copyostr2blk - copy octet-specified string to block
*/
int
copyostr2blk(char *str,long ssi,long num,BLOCK *dblk,long dsi,bool noreloc)
{
size_t len;
size_t newlen;
size_t newsize;
USB8 *newdata;
len = strlen(str) + 1;
if (ssi > 0 && (size_t)ssi > len)
return E_COPY_02;
if (num < 0 || (size_t)(ssi + num) > len)
num = len - ssi;
if (num <= 0) /* Nothing to be copied */
return 0;
if (dsi < 0)
dsi = dblk->datalen; /* Default destination index */
newlen = dsi + num;
if (newlen <= 0)
return E_COPY_07;
if (newlen >= (size_t)dblk->maxsize) {
if (noreloc)
return E_COPY_17;
newsize = (1 + newlen/dblk->blkchunk) * dblk->blkchunk;
newdata = (USB8*) realloc(dblk->data, newsize);
if (newdata == NULL) {
math_error("Out of memory for string-to-block copy");
not_reached();
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
memmove(dblk->data + dsi, str + ssi, num);
if (newlen > (size_t)dblk->datalen)
dblk->datalen = newlen;
return 0;
}
/*
* copynum2blk - copy number numerator to block
*/
int
copynum2blk(NUMBER *snum, long ssi, long num, BLOCK *dblk, long dsi,
bool noreloc)
{
size_t newlen;
size_t newsize;
USB8 *newdata;
#if CALC_BYTE_ORDER == BIG_ENDIAN
ZVALUE *swnum; /* byte swapped numerator */
#endif
if (ssi > snum->num.len)
return E_COPY_02;
if (num < 0)
num = snum->num.len - ssi;
if (num == 0) /* Nothing to be copied */
return 0;
if (ssi + num > snum->num.len)
return E_COPY_05;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + (num*sizeof(HALF));
if (newlen <= 0)
return E_COPY_07;
if (newlen >= (size_t)dblk->maxsize) {
if (noreloc)
return E_COPY_17;
newsize = (1 + newlen/dblk->blkchunk) * dblk->blkchunk;
newdata = (USB8*) realloc(dblk->data, newsize);
if (newdata == NULL) {
math_error("Out of memory for num-to-block copy");
not_reached();
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
#if CALC_BYTE_ORDER == LITTLE_ENDIAN
memmove(dblk->data+dsi, (char *)(snum->num.v+ssi), num*sizeof(HALF));
#else
swnum = swap_b8_in_ZVALUE(NULL, &(snum->num), false);
memmove(dblk->data+dsi, (char *)(swnum->v+ssi), num*sizeof(HALF));
zfree(*swnum);
#endif
if (newlen > (size_t)dblk->datalen)
dblk->datalen = newlen;
return 0;
}
/*
* copyblk2num - copy block to number
*/
int
copyblk2num(BLOCK *sblk, long ssi, long num, NUMBER *dnum, long dsi,
NUMBER **res)
{
size_t newlen;
NUMBER *ret; /* cloned and modified numerator */
#if CALC_BYTE_ORDER == BIG_ENDIAN
HALF *swapped; /* byte swapped input data */
unsigned long halflen; /* length of the input rounded up to HALFs */
HALF *h; /* copy byteswap pointer */
unsigned long i;
#endif
if (ssi > sblk->datalen)
return E_COPY_02;
if (num < 0)
num = sblk->datalen - ssi;
if (num == 0) /* Nothing to be copied */
return 0;
if (ssi + num > sblk->datalen)
return E_COPY_05;
if (dsi < 0)
dsi = dnum->num.len;
newlen = dsi + ((num+sizeof(HALF)-1)/sizeof(HALF));
if (newlen <= 0)
return E_COPY_07;
/* quasi-clone the numerator to the new size */
ret = qalloc();
ret->num.sign = dnum->num.sign;
ret->num.v = alloc(newlen);
ret->num.len = newlen;
/* ensure that any trailing octets will be zero filled */
ret->num.v[newlen-1] = 0;
zcopyval(dnum->num, ret->num);
if (!zisunit(ret->den)) {
ret->den.len = dnum->den.len;
ret->den.v = alloc(dnum->den.len);
zcopyval(dnum->den, ret->den);
}
/* move the data */
#if CALC_BYTE_ORDER == LITTLE_ENDIAN
memmove((char *)(ret->num.v + dsi), sblk->data + ssi, num);
#else
/* form a HALF aligned copy of the input */
halflen = (num+sizeof(HALF)-1) / sizeof(HALF);
swapped = (HALF *)malloc(halflen * sizeof(HALF));
if (swapped == NULL) {
math_error("Out of memory for block-to-num copy");
not_reached();
}
/* ensure that any trailing octets will be zero filled */
swapped[halflen-1] = 0;
memcpy(swapped, sblk->data + ssi, num);
/* byte swap the copy of the input */
for (i=0, h=swapped; i < halflen; ++i, ++h) {
SWAP_B8_IN_HALF(h, h);
}
/* copy over whole byte-swapped HALFs */
memcpy((char *)(ret->num.v + dsi), swapped,
(num/sizeof(HALF))*sizeof(HALF));
/* copy over any octets in the last partial HALF */
i = num % sizeof(HALF);
if (i != 0) {
memcpy((char *)(ret->num.v + dsi)+num-i,
(char *)swapped + num-i, i);
}
free(swapped);
#endif
/* save new number */
*res = ret;
return 0;
}