Files
calc/blkcpy.c
Landon Curt Noll ac0d84eef8 Release v2.12.9.0
Added notes to help/unexpected about:

    display() will limit the number of digits printed after decimal point

    %d will format after the decimal point for non-integer numeric values

    %x will format as fractions for non-integer numeric values

    fprintf(fd, "%d\n", huge_value) may need fflush(fd) to finish

Fixed Makefile dependencies for the args.h rule.

Fixed Makefile cases where echo with -n is used.  On some systems,
/bin/sh does not use -n, so we must call /bin/echo -n instead
via the ${ECHON} Makefile variable.

Add missing standard tools to sub-Makefiles to make them
easier to invoke directly.

Sort lists of standard tool Makefile variables and remove duplicates.

Declare the SHELL at the top of Makefiles.

Fixed the depend rule in the custom Makefile.

Improved the messages produced by the depend in the Makefiles.

Changed the UNUSED define in have_unused.h to be a macro with
a parameter.  Changed all use of UNUSED in *.c to be UNUSED(x).

Removed need for HAVE_UNUSED in building the have_unused.h file.

 CCBAN is given to ${CC} in order to control if banned.h is in effect.

 The banned.h attempts to ban the use of certain dangerous functions
 that, if improperly used, could compromise the computational integrity
 if calculations.

 In the case of calc, we are motivated in part by the desire for calc
 to correctly calculate: even during extremely long calculations.

 If UNBAN is NOT defined, then calling certain functions
 will result in a call to a non-existent function (link error).

 While we do NOT encourage defining UNBAN, there may be
 a system / compiler environment where re-defining a
 function may lead to a fatal compiler complication.
 If that happens, consider compiling as:

    make clobber all chk CCBAN=-DUNBAN

 as see if this is a work-a-round.

 If YOU discover a need for the -DUNBAN work-a-round, PLEASE tell us!
 Please send us a bug report.  See the file:

    BUGS

 or the URL:

    http://www.isthe.com/chongo/tech/comp/calc/calc-bugrept.html

 for how to send us such a bug report.

 Added the building of have_ban_pragma.h, which will determine
 if "#pragma GCC poison func_name" is supported.  If it is not,
 or of HAVE_PRAGMA_GCC_POSION=-DHAVE_NO_PRAGMA_GCC_POSION, then
 banned.h will have no effect.

 Fixed building of the have_getpgid.h file.
 Fixed building of the have_getprid.h file.
 Fixed building of the have_getsid.h file.
 Fixed building of the have_gettime.h file.
 Fixed building of the have_strdup.h file.
 Fixed building of the have_ustat.h file.
 Fixed building of the have_rusage.h file.

 Added HAVE_NO_STRLCPY to control if we want to test if
 the system has a strlcpy() function.  This in turn produces
 the have_strlcpy.h file wherein the symbol HAVE_STRLCPY will
 be defined, or not depending if the system comes with a
 strlcpy() function.

 If the system does not have a strlcpy() function, we
 compile our own strlcpy() function.  See strl.c for details.

 Added HAVE_NO_STRLCAT to control if we want to test if
 the system has a strlcat() function.  This in turn produces
 the have_strlcat.h file wherein the symbol HAVE_STRLCAT will
 be defined, or not depending if the system comes with a
 strlcat() function.

 If the system does not have a strlcat() function, we
 compile our own strlcat() function.  See strl.c for details.

 Fixed places were <string.h>, using #ifdef HAVE_STRING_H
 for legacy systems that do not have that include file.

 Added ${H} Makefile symbol to control the announcement
 of forming and having formed hsrc related files.  By default
 H=@ (announce hsrc file formation) vs. H=@: to silence hsrc
 related file formation.

 Explicitly turn off quiet mode (set Makefile variable ${Q} to
 be empty) when building rpms.

 Improved and fixed the hsrc build process.

 Forming rpms is performed in verbose mode to assist debugging
 to the rpm build process.

 Compile custom code, if needed, after main code is compiled.
2021-03-11 01:54:28 -08:00

1113 lines
22 KiB
C

/*
* blkcpy - general values and related routines used by the calculator
*
* Copyright (C) 1999-2007,2021 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 "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_COPY13;
if (dvp->v_subtype & V_NOCOPYTO)
return E_COPY14;
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_COPY15;
sblk = svp->v_nblock->blk;
if (sblk->data == NULL)
return E_COPY8;
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_COPY9;
}
/*
* determine/check destination type
*/
switch(dvp->v_type) {
case V_NBLOCK:
if (dvp->v_nblock->subtype & V_NOCOPYTO)
return E_COPY16;
noreloc |=((dvp->v_nblock->subtype & V_NOREALLOC) != 0);
dblk = dvp->v_nblock->blk;
if (dblk->data == NULL)
return E_COPY10;
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_COPY11;
}
/*
* 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_COPY12;
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_COPY12;
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_COPY12;
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_COPY12; /* not yet - XXX */
case V_LIST:
/* copy to a list */
return E_COPY12; /* 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_COPY12; /* 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_COPY12; /* 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_COPY12;
}
/*
* 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_COPY2;
if (num < 0)
num = smat->m_size - ssi;
if (ssi + num > smat->m_size)
return E_COPY5;
if (num == 0)
return 0;
if (dsi < 0)
dsi = 0;
if (dsi + num > dmat->m_size)
return E_COPY7;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for mat-to-mat copy");
/*NOTREACHED*/
}
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_COPY2;
if (num < 0)
num = blk->datalen - ssi;
if (ssi + num > blk->datalen)
return E_COPY5;
if (num == 0)
return 0;
if (dsi < 0)
dsi = 0;
if (dsi + num > dmat->m_size)
return E_COPY7;
op = blk->data + ssi;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for block-to-matrix copy");
/*NOTREACHED*/
}
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_COPY2;
if (num < 0)
num = smat->m_size - ssi;
if (num == 0)
return 0;
if (ssi + num > smat->m_size)
return E_COPY5;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + num;
if (newlen <= 0)
return E_COPY7;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY17;
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");
/*NOTREACHED*/
}
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_COPY2;
if (num < 0)
num = smat->m_size - ssi;
if (num == 0)
return 0;
if (ssi + num > smat->m_size)
return E_COPY5;
if (dsi < 0)
dsi = 0;
if (dsi + num > lp->l_count)
return E_COPY7;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for matrix-to-list copy");
/*NOTREACHED*/
}
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_COPY2;
if (num < 0)
num = lp->l_count - ssi;
if (num == 0)
return 0;
if (ssi + num > lp->l_count)
return E_COPY5;
if (dsi < 0)
dsi = 0;
if (dsi + num > dmat->m_size)
return E_COPY7;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for list-to-matrix copy");
/*NOTREACHED*/
}
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_COPY2;
if (num < 0)
num = slp->l_count - ssi;
if (num == 0)
return 0;
if (ssi + num > slp->l_count)
return E_COPY5;
if (dsi < 0)
dsi = 0;
if (dsi + num > dlp->l_count)
return E_COPY7;
vtemp = (VALUE *) malloc(num * sizeof(VALUE));
if (vtemp == NULL) {
math_error("Out of memory for list-to-list copy");
/*NOTREACHED*/
}
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_COPY2;
if (num < 0)
num = sblk->datalen - ssi;
if (num == 0)
return 0;
fiop = findid(id, TRUE);
if (fiop == NULL)
return E_COPYF1;
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_COPYF2;
}
numw = fwrite(sblk->data + ssi, 1, num, fp);
if (numw < num)
return E_COPYF3;
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_COPYF1;
fiop = findid(id, FALSE);
if (fiop == NULL)
return E_COPYF1;
fp = fiop->fp;
if (get_open_siz(fp, &fsize))
return E_COPYF2;
if (zge31b(fsize)) {
zfree(fsize);
return E_COPY5;
}
filelen = ztoi(fsize);
zfree(fsize);
if (ssi > filelen)
return E_COPY2;
if (num < 0)
num = filelen - ssi;
if (num == 0)
return 0;
if (ssi + num > filelen)
return E_COPY5;
if (fseek(fp, ssi, 0)) /* using system fseek XXX */
return E_COPYF2;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + num;
if (newlen <= 0)
return E_COPY7;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY17;
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");
/*NOTREACHED*/
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
numw = fread(dblk->data + dsi, 1, num, fp);
if (numw < num)
return E_COPYF4;
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_COPY2;
if (num < 0)
num = len - ssi;
if (num <= 0) /* Nothing to be copied */
return 0;
if (ssi + num > len)
return E_COPY5; /* Insufficient memory in str */
fiop = findid(id, TRUE);
if (fiop == NULL)
return E_COPYF1;
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_COPYF2;
}
numw = fwrite(str->s_str + ssi, 1, num, fp);
if (numw < num)
return E_COPYF3;
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_COPY2;
if (num < 0)
num = sblk->datalen - ssi;
if (num == 0) /* Nothing to be copied */
return 0;
if (ssi + num > sblk->datalen)
return E_COPY5;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + num;
if (newlen <= 0)
return E_COPY7;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY17;
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");
/*NOTREACHED*/
}
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_COPY2;
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_COPY7;
if (newlen >= dblk->maxsize) {
if (noreloc)
return E_COPY17;
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");
/*NOTREACHED*/
}
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_COPY2;
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_COPY7;
if (newlen >= (size_t)dblk->maxsize) {
if (noreloc)
return E_COPY17;
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");
/*NOTREACHED*/
}
dblk->data = newdata;
dblk->maxsize = newsize;
}
memmove(dblk->data + dsi, str + ssi, num);
if (newlen > (size_t)dblk->datalen)
dblk->datalen = newlen;
return 0;
}
#if !defined(HAVE_MEMMOVE)
/*
* memmove - simulate the memory move function that deals with overlap
*
* Copying between objects that overlap will take place correctly.
*
* given:
* s1 destination
* s2 source
* n octet count
*
* returns:
* s1
*/
void *
memmove(void *s1, CONST void *s2, MEMMOVE_SIZE_T n)
{
/*
* firewall
*/
if (s1 == NULL || s2 == NULL) {
math_error("bogus memmove NULL ptr");
/*NOTREACHED*/
}
if (n <= 0) {
/* neg or 0 count does nothing */
return s1;
}
if ((char *)s1 == (char *)s2) {
/* copy to same location does nothing */
return s1;
}
/*
* determine if we need to deal with overlap copy
*/
if ((char *)s1 > (char *)s2 && (char *)s1 < (char *)s2+n) {
/*
* we have to copy backwards ... slowly
*/
while (n-- > 0) {
((char *)s1)[n] = ((char *)s2)[n];
}
} else {
/*
* safe ... no overlap problems
*/
(void) memcpy(s1, s2, n);
}
return s1;
}
#endif
/*
* 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_COPY2;
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_COPY5;
if (dsi < 0)
dsi = dblk->datalen;
newlen = dsi + (num*sizeof(HALF));
if (newlen <= 0)
return E_COPY7;
if (newlen >= (size_t)dblk->maxsize) {
if (noreloc)
return E_COPY17;
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");
/*NOTREACHED*/
}
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_COPY2;
if (num < 0)
num = sblk->datalen - ssi;
if (num == 0) /* Nothing to be copied */
return 0;
if (ssi + num > sblk->datalen)
return E_COPY5;
if (dsi < 0)
dsi = dnum->num.len;
newlen = dsi + ((num+sizeof(HALF)-1)/sizeof(HALF));
if (newlen <= 0)
return E_COPY7;
/* 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");
/*NOTREACHED*/
}
/* 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;
}