mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
1102 lines
22 KiB
C
1102 lines
22 KiB
C
/*
|
|
* blkcpy - general values and related routines used by the calculator
|
|
*
|
|
* Copyright (C) 1999 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.
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* @(#) $Revision: 29.2 $
|
|
* @(#) $Id: blkcpy.c,v 29.2 2000/06/07 14:02:13 chongo Exp $
|
|
* @(#) $Source: /usr/local/src/cmd/calc/RCS/blkcpy.c,v $
|
|
*
|
|
* 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 "value.h"
|
|
#include "file.h"
|
|
#include "blkcpy.h"
|
|
#include "string.h"
|
|
|
|
|
|
/*
|
|
* 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;
|
|
short subtype;
|
|
|
|
if (ssi > smat->m_size)
|
|
return E_COPY2;
|
|
|
|
if (num < 0)
|
|
num = smat->m_size - ssi;
|
|
if ((USB32) ssi + num > smat->m_size)
|
|
return E_COPY5;
|
|
if (num == 0)
|
|
return 0;
|
|
if (dsi < 0)
|
|
dsi = 0;
|
|
if ((USB32) 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;
|
|
short subtype;
|
|
|
|
if (ssi > blk->datalen)
|
|
return E_COPY2;
|
|
if (num < 0)
|
|
num = blk->datalen - ssi;
|
|
if ((USB32) ssi + num > blk->datalen)
|
|
return E_COPY5;
|
|
if (num == 0)
|
|
return 0;
|
|
if (dsi < 0)
|
|
dsi = 0;
|
|
if ((USB32) 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 ((USB32) 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;
|
|
|
|
if (ssi > smat->m_size)
|
|
return E_COPY2;
|
|
if (num < 0)
|
|
num = smat->m_size - ssi;
|
|
if (num == 0)
|
|
return 0;
|
|
if ((USB32) ssi + num > smat->m_size)
|
|
return E_COPY5;
|
|
if (dsi < 0)
|
|
dsi = 0;
|
|
if ((USB32) 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) {
|
|
freevalue(&ep->e_value);
|
|
ep->e_value = *vq++;
|
|
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;
|
|
short subtype;
|
|
|
|
if (ssi > lp->l_count)
|
|
return E_COPY2;
|
|
if (num < 0)
|
|
num = lp->l_count - ssi;
|
|
if (num == 0)
|
|
return 0;
|
|
if ((USB32) ssi + num > lp->l_count)
|
|
return E_COPY5;
|
|
if (dsi < 0)
|
|
dsi = 0;
|
|
if ((USB32) 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;
|
|
|
|
if (ssi > slp->l_count)
|
|
return E_COPY2;
|
|
if (num < 0)
|
|
num = slp->l_count - ssi;
|
|
if (num == 0)
|
|
return 0;
|
|
if ((USB32) ssi + num > slp->l_count)
|
|
return E_COPY5;
|
|
if (dsi < 0)
|
|
dsi = 0;
|
|
if ((USB32) 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) {
|
|
freevalue(&dep->e_value);
|
|
dep->e_value = *vp++;
|
|
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;
|
|
unsigned int numw;
|
|
|
|
if (ssi > sblk->datalen)
|
|
return E_COPY2;
|
|
if (num < 0)
|
|
num = sblk->datalen - ssi;
|
|
if (num == 0)
|
|
return 0;
|
|
|
|
fiop = findid(id, 'w');
|
|
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;
|
|
unsigned int numw;
|
|
ZVALUE fsize;
|
|
long filelen;
|
|
long newlen;
|
|
long newsize;
|
|
OCTET *newdata;
|
|
|
|
if (id < 3) /* excludes copying from stdin */
|
|
return E_COPYF1;
|
|
fiop = findid(id, 'r');
|
|
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 ((USB32) 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;
|
|
unsigned int 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 ((USB32) ssi + num > len)
|
|
return E_COPY5; /* Insufficient memory in str */
|
|
fiop = findid(id, 'w');
|
|
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 ((unsigned int) 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 || 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 (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 (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)
|
|
{
|
|
long len;
|
|
char *c, *c1;
|
|
|
|
len = (long)strlen(sstr);
|
|
|
|
if (num < 0 || ssi + num > len)
|
|
num = len - ssi;
|
|
if (num <= 0) /* Nothing to be copied */
|
|
return 0;
|
|
if (dsi < 0)
|
|
dsi = 0; /* Default destination index */
|
|
if (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)
|
|
{
|
|
int len;
|
|
int newlen;
|
|
int newsize;
|
|
USB8 *newdata;
|
|
|
|
len = strlen(str) + 1;
|
|
|
|
if (ssi > len)
|
|
return E_COPY2;
|
|
if (num < 0 || (unsigned long) 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 >= 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 > 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, CALC_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)
|
|
{
|
|
long newlen;
|
|
long 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 ((unsigned long) ssi + num > snum->num.len)
|
|
return E_COPY5;
|
|
if (dsi < 0)
|
|
dsi = dblk->datalen;
|
|
newlen = dsi + (long)(num*sizeof(HALF));
|
|
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 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 > 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)
|
|
{
|
|
long 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 ounded 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 ((unsigned long) ssi + num > sblk->datalen)
|
|
return E_COPY5;
|
|
if (dsi < 0)
|
|
dsi = dnum->num.len;
|
|
newlen = dsi + (long)((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;
|
|
}
|