mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
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.
1113 lines
22 KiB
C
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;
|
|
}
|