2 * blkcpy - general values and related routines used by the calculator
4 * Copyright (C) 1999-2007 Landon Curt Noll and Ernest Bowen
6 * Primary author: Landon Curt Noll
8 * Calc is open software; you can redistribute it and/or modify it under
9 * the terms of the version 2.1 of the GNU Lesser General Public License
10 * as published by the Free Software Foundation.
12 * Calc is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 * Public License for more details.
17 * A copy of version 2.1 of the GNU Lesser General Public License is
18 * distributed with calc under the filename COPYING-LGPL. You should have
19 * received a copy with calc; if not, write to Free Software Foundation, Inc.
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * @(#) $Revision: 30.2 $
23 * @(#) $Id: blkcpy.c,v 30.2 2013/08/11 08:41:38 chongo Exp $
24 * @(#) $Source: /usr/local/src/bin/calc/RCS/blkcpy.c,v $
26 * Under source code control: 1997/04/18 20:41:26
27 * File existed as early as: 1997
29 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
34 #include <sys/types.h>
43 * copystod - copy num indexed items from source value to destination value
46 * ssi = source starting index
47 * num = number of items (octets or values) to be copied
48 * sdi = destination starting index
51 * zero if successful, otherwise error-code number
54 copystod(VALUE
*svp
, long ssi
, long num
, VALUE
*dvp
, long dsi
)
66 if (svp
->v_subtype
& V_NOCOPYFROM
)
68 if (dvp
->v_subtype
& V_NOCOPYTO
)
70 noreloc
= ((dvp
->v_subtype
& V_NOREALLOC
) != 0);
73 * determine/check source type
77 if (svp
->v_nblock
->subtype
& V_NOCOPYFROM
)
79 sblk
= svp
->v_nblock
->blk
;
80 if (sblk
->data
== NULL
)
98 * determine/check destination type
100 switch(dvp
->v_type
) {
102 if (dvp
->v_nblock
->subtype
& V_NOCOPYTO
)
104 noreloc
|=((dvp
->v_nblock
->subtype
& V_NOREALLOC
) != 0);
105 dblk
= dvp
->v_nblock
->blk
;
106 if (dblk
->data
== NULL
)
110 noreloc
= ((dvp
->v_subtype
& V_NOREALLOC
) != 0);
124 * copy based on source
126 switch (svp
->v_type
) {
132 switch(dvp
->v_type
) {
135 return copyblk2blk(sblk
, ssi
, num
, dblk
, dsi
, noreloc
);
138 NUMBER
*n
; /* modified number */
139 int rt
; /* return code */
141 /* copy to a number */
142 rt
= copyblk2num(sblk
, ssi
, num
, dvp
->v_num
, dsi
, &n
);
150 return copyblk2file(sblk
, ssi
, num
, dvp
->v_file
, dsi
);
152 return copyblk2mat(sblk
, ssi
, num
, dvp
->v_mat
, dsi
);
154 return copyblk2str(sblk
, ssi
, num
, dvp
->v_str
, dsi
);
159 switch(dvp
->v_type
) {
162 /* copy to a block */
163 return copystr2blk(svp
->v_str
, ssi
, num
, dblk
, dsi
,
166 return copystr2file(svp
->v_str
, ssi
, num
,
169 return copystr2str(svp
->v_str
, ssi
, num
, dvp
->v_str
,
175 switch(dvp
->v_type
) {
178 return copyostr2blk((char *) svp
->v_octet
, ssi
, num
,
181 return copyostr2str((char *) svp
->v_octet
, ssi
, num
,
192 /* copy to a block */
193 return copynum2blk(svp
->v_num
, ssi
, num
, dblk
,
196 switch (dvp
->v_type
) {
198 /* copy to a matrix */
199 return E_COPY12
; /* not yet - XXX */
202 return E_COPY12
; /* not yet - XXX */
211 /* copy to a block */
212 return copyfile2blk(svp
->v_file
, ssi
, num
,
215 switch (dvp
->v_type
) {
217 /* copy to a number */
218 return E_COPY12
; /* not yet - XXX */
228 /* copy to a block */
229 return copymat2blk(svp
->v_mat
, ssi
, num
, dblk
,
232 switch (dvp
->v_type
) {
234 /* copy to a matrix */
235 return copymat2mat(svp
->v_mat
, ssi
, num
,
239 return copymat2list(svp
->v_mat
, ssi
, num
,
250 /* copy to a block */
251 return E_COPY12
; /* not yet - XXX */
253 switch (dvp
->v_type
) {
255 /* copy to a matrix */
256 return copylist2mat(svp
->v_list
, ssi
, num
,
260 return copylist2list(svp
->v_list
, ssi
, num
,
267 * unsupported copy combination
274 * copymat2mat - copy matrix to matrix
277 copymat2mat(MATRIX
*smat
, long ssi
, long num
, MATRIX
*dmat
, long dsi
)
283 unsigned short subtype
;
285 if (ssi
> smat
->m_size
)
289 num
= smat
->m_size
- ssi
;
290 if (ssi
+ num
> smat
->m_size
)
296 if (dsi
+ num
> dmat
->m_size
)
298 vtemp
= (VALUE
*) malloc(num
* sizeof(VALUE
));
300 math_error("Out of memory for mat-to-mat copy");
303 vp
= smat
->m_table
+ ssi
;
307 copyvalue(vp
++, vq
++);
309 vq
= dmat
->m_table
+ dsi
;
310 for (i
= num
; i
> 0; i
--, vp
++, vq
++) {
311 subtype
= vq
->v_subtype
;
314 vq
->v_subtype
|= subtype
;
322 * copyblk2mat - copy block to matrix
325 copyblk2mat(BLOCK
*blk
, long ssi
, long num
, MATRIX
*dmat
, long dsi
)
332 unsigned short subtype
;
334 if (ssi
> blk
->datalen
)
337 num
= blk
->datalen
- ssi
;
338 if (ssi
+ num
> blk
->datalen
)
344 if (dsi
+ num
> dmat
->m_size
)
346 op
= blk
->data
+ ssi
;
347 vtemp
= (VALUE
*) malloc(num
* sizeof(VALUE
));
349 math_error("Out of memory for block-to-matrix copy");
356 vp
->v_subtype
= V_NOSUBTYPE
;
357 vp
->v_num
= itoq((long) *op
++);
361 vq
= dmat
->m_table
+ dsi
;
362 for (i
= num
; i
> 0; i
--, vp
++, vq
++) {
363 subtype
= vq
->v_subtype
;
366 vq
->v_subtype
|= subtype
;
374 * copymat2blk - copy matrix to block
377 copymat2blk(MATRIX
*smat
, long ssi
, long num
, BLOCK
*dblk
, long dsi
,
387 if (ssi
> smat
->m_size
)
390 num
= smat
->m_size
- ssi
;
393 if (ssi
+ num
> smat
->m_size
)
400 if (newlen
>= dblk
->maxsize
) {
403 newsize
= (1 + newlen
/dblk
->blkchunk
) * dblk
->blkchunk
;
404 newdata
= (USB8
*) realloc(dblk
->data
, newsize
);
405 if (newdata
== NULL
) {
406 math_error("Out of memory for matrix-to-block copy");
409 dblk
->data
= newdata
;
410 dblk
->maxsize
= newsize
;
412 vp
= smat
->m_table
+ ssi
;
413 op
= dblk
->data
+ dsi
;
414 for (i
= num
; i
> 0; i
--)
415 copy2octet(vp
++, op
++);
416 if (newlen
> dblk
->datalen
)
417 dblk
->datalen
= newlen
;
423 * copymat2list - copy matrix to list
426 copymat2list(MATRIX
*smat
, long ssi
, long num
, LIST
*lp
, long dsi
)
433 unsigned short subtype
;
435 if (ssi
> smat
->m_size
)
438 num
= smat
->m_size
- ssi
;
441 if (ssi
+ num
> smat
->m_size
)
445 if (dsi
+ num
> lp
->l_count
)
447 vtemp
= (VALUE
*) malloc(num
* sizeof(VALUE
));
449 math_error("Out of memory for matrix-to-list copy");
452 vp
= smat
->m_table
+ ssi
;
456 copyvalue(vp
++, vq
++);
458 ep
= listelement(lp
, (long) dsi
);
461 subtype
= ep
->e_value
.v_subtype
;
462 freevalue(&ep
->e_value
);
464 ep
->e_value
.v_subtype
|= subtype
;
473 * copymat2list - copy list to matrix
476 copylist2mat(LIST
*lp
, long ssi
, long num
, MATRIX
*dmat
, long dsi
)
483 unsigned short subtype
;
485 if (ssi
> lp
->l_count
)
488 num
= lp
->l_count
- ssi
;
491 if (ssi
+ num
> lp
->l_count
)
495 if (dsi
+ num
> dmat
->m_size
)
497 vtemp
= (VALUE
*) malloc(num
* sizeof(VALUE
));
499 math_error("Out of memory for list-to-matrix copy");
502 ep
= listelement(lp
, (long) ssi
);
506 copyvalue(&ep
->e_value
, vp
++);
510 vq
= dmat
->m_table
+ dsi
;
511 for (i
= num
; i
> 0; i
--, vp
++, vq
++) {
512 subtype
= vq
->v_subtype
;
515 vq
->v_subtype
|= subtype
;
523 * copylist2list - copy list to list
526 copylist2list(LIST
*slp
, long ssi
, long num
, LIST
*dlp
, long dsi
)
533 unsigned short subtype
;
535 if (ssi
> slp
->l_count
)
538 num
= slp
->l_count
- ssi
;
541 if (ssi
+ num
> slp
->l_count
)
545 if (dsi
+ num
> dlp
->l_count
)
547 vtemp
= (VALUE
*) malloc(num
* sizeof(VALUE
));
549 math_error("Out of memory for list-to-list copy");
552 sep
= listelement(slp
, (long) ssi
);
556 copyvalue(&sep
->e_value
, vp
++);
559 dep
= listelement(dlp
, (long) dsi
);
563 subtype
= dep
->e_value
.v_subtype
;
564 freevalue(&dep
->e_value
);
565 dep
->e_value
= *vp
++;
566 dep
->e_value
.v_subtype
|= subtype
;
575 * copyblk2file - copy block to file
578 copyblk2file(BLOCK
*sblk
, long ssi
, long num
, FILEID id
, long dsi
)
584 if (ssi
> sblk
->datalen
)
587 num
= sblk
->datalen
- ssi
;
591 fiop
= findid(id
, TRUE
);
595 if (id
== 1 || id
== 2) {
596 numw
= idfputstr(id
, (char *)sblk
->data
+ ssi
); /* XXX */
600 if (fseek(fp
, dsi
, 0))
603 numw
= fwrite(sblk
->data
+ ssi
, 1, num
, fp
);
612 * copyfile2blk - copy file to block
615 copyfile2blk(FILEID id
, long ssi
, long num
, BLOCK
*dblk
, long dsi
, BOOL noreloc
)
626 if (id
< 3) /* excludes copying from stdin */
628 fiop
= findid(id
, FALSE
);
634 if (get_open_siz(fp
, &fsize
))
640 filelen
= ztoi(fsize
);
649 if (ssi
+ num
> filelen
)
651 if (fseek(fp
, ssi
, 0)) /* using system fseek XXX */
658 if (newlen
>= dblk
->maxsize
) {
661 newsize
= (1 + newlen
/dblk
->blkchunk
) * dblk
->blkchunk
;
662 newdata
= (USB8
*) realloc(dblk
->data
, newsize
);
663 if (newdata
== NULL
) {
664 math_error("Out of memory for block-to-block copy");
667 dblk
->data
= newdata
;
668 dblk
->maxsize
= newsize
;
670 numw
= fread(dblk
->data
+ dsi
, 1, num
, fp
);
673 if (newlen
> dblk
->datalen
)
674 dblk
->datalen
= newlen
;
680 * copystr2file - copy string to file
683 copystr2file(STRING
*str
, long ssi
, long num
, FILEID id
, long dsi
)
696 if (num
<= 0) /* Nothing to be copied */
699 return E_COPY5
; /* Insufficient memory in str */
700 fiop
= findid(id
, TRUE
);
704 if (id
== 1 || id
== 2) {
705 numw
= idfputstr(id
, str
->s_str
+ ssi
); /* XXX */
709 if (fseek(fp
, dsi
, 0))
712 numw
= fwrite(str
->s_str
+ ssi
, 1, num
, fp
);
721 * copyblk2blk - copy block to block
724 copyblk2blk(BLOCK
*sblk
, long ssi
, long num
, BLOCK
*dblk
, long dsi
,
731 if (ssi
> sblk
->datalen
)
734 num
= sblk
->datalen
- ssi
;
735 if (num
== 0) /* Nothing to be copied */
737 if (ssi
+ num
> sblk
->datalen
)
744 if (newlen
>= dblk
->maxsize
) {
747 newsize
= (1 + newlen
/dblk
->blkchunk
) * dblk
->blkchunk
;
748 newdata
= (USB8
*) realloc(dblk
->data
, newsize
);
749 if (newdata
== NULL
) {
750 math_error("Out of memory for block-to-block copy");
753 dblk
->data
= newdata
;
754 dblk
->maxsize
= newsize
;
756 memmove(dblk
->data
+ dsi
, sblk
->data
+ ssi
, num
);
757 if (newlen
> dblk
->datalen
)
758 dblk
->datalen
= newlen
;
764 * copystr2blk - copy string to block
767 copystr2blk(STRING
*str
, long ssi
, long num
, BLOCK
*dblk
, long dsi
,
781 if (num
<= 0) /* Nothing to be copied */
785 newlen
= dsi
+ num
+ 1;
788 if (newlen
>= dblk
->maxsize
) {
791 newsize
= (1 + newlen
/dblk
->blkchunk
) * dblk
->blkchunk
;
792 newdata
= (USB8
*) realloc(dblk
->data
, newsize
);
793 if (newdata
== NULL
) {
794 math_error("Out of memory for string-to-block copy");
797 dblk
->data
= newdata
;
798 dblk
->maxsize
= newsize
;
800 memmove(dblk
->data
+ dsi
, str
->s_str
+ ssi
, num
);
801 dblk
->data
[dsi
+ num
] = '\0';
802 if (newlen
> dblk
->datalen
)
803 dblk
->datalen
= newlen
;
809 * copystr2str - copy up to num characters from sstr (starting at
810 * index ssi) to dstr (starting at index dsi); num is reduced if there
811 * are insufficient characters in sstr or insufficient space in dstr.
814 copystr2str(STRING
*sstr
, long ssi
, long num
, STRING
*dstr
, long dsi
)
818 if (num
< 0 || (size_t)(ssi
+ num
) > sstr
->s_len
)
819 num
= sstr
->s_len
- ssi
;
821 return 0; /* Nothing to be copied */
822 if (dsi
< 0) /* default destination index */
824 if ((size_t)(dsi
+ num
) > dstr
->s_len
)
825 num
= dstr
->s_len
- dsi
;
826 c1
= sstr
->s_str
+ ssi
;
827 c
= dstr
->s_str
+ dsi
;
835 * copyblk2str - copy up to num characters from sblk (starting at
836 * index ssi) to str (starting at index dsi); num is reduced if there
837 * is insufficient data in blk or insufficient space in str
840 copyblk2str(BLOCK
*sblk
, long ssi
, long num
, STRING
*dstr
, long dsi
)
844 if (num
< 0 || ssi
+ num
> sblk
->datalen
)
845 num
= sblk
->datalen
- ssi
;
847 return 0; /* Nothing to be copied */
848 if (dsi
< 0) /* default destination index */
850 if ((size_t)(dsi
+ num
) > dstr
->s_len
)
851 num
= dstr
->s_len
- dsi
;
852 c1
= sblk
->data
+ ssi
;
853 c
= (USB8
*)dstr
->s_str
+ dsi
;
859 * copyostr2str - copy octet-specified string to string
862 copyostr2str(char *sstr
, long ssi
, long num
, STRING
*dstr
, long dsi
)
869 if (num
< 0 || (size_t)(ssi
+ num
) > len
)
871 if (num
<= 0) /* Nothing to be copied */
874 dsi
= 0; /* Default destination index */
875 if ((size_t)(dsi
+ num
) > dstr
->s_len
)
876 num
= dstr
->s_len
- dsi
;
878 c
= dstr
->s_str
+ dsi
;
886 * copyostr2blk - copy octet-specified string to block
889 copyostr2blk(char *str
,long ssi
,long num
,BLOCK
*dblk
,long dsi
,BOOL noreloc
)
896 len
= strlen(str
) + 1;
898 if (ssi
> 0 && (size_t)ssi
> len
)
900 if (num
< 0 || (size_t)(ssi
+ num
) > len
)
902 if (num
<= 0) /* Nothing to be copied */
905 dsi
= dblk
->datalen
; /* Default destination index */
909 if (newlen
>= (size_t)dblk
->maxsize
) {
912 newsize
= (1 + newlen
/dblk
->blkchunk
) * dblk
->blkchunk
;
913 newdata
= (USB8
*) realloc(dblk
->data
, newsize
);
914 if (newdata
== NULL
) {
915 math_error("Out of memory for string-to-block copy");
918 dblk
->data
= newdata
;
919 dblk
->maxsize
= newsize
;
921 memmove(dblk
->data
+ dsi
, str
+ ssi
, num
);
922 if (newlen
> (size_t)dblk
->datalen
)
923 dblk
->datalen
= newlen
;
926 #if !defined(HAVE_MEMMOVE)
928 * memmove - simulate the memory move function that deals with overlap
930 * Copying between objects that overlap will take place correctly.
941 memmove(void *s1
, CONST
void *s2
, MEMMOVE_SIZE_T n
)
946 if (s1
== NULL
|| s2
== NULL
) {
947 math_error("bogus memmove NULL ptr");
951 /* neg or 0 count does nothing */
954 if ((char *)s1
== (char *)s2
) {
955 /* copy to same location does nothing */
960 * determine if we need to deal with overlap copy
962 if ((char *)s1
> (char *)s2
&& (char *)s1
< (char *)s2
+n
) {
965 * we have to copy backwards ... slowly
968 ((char *)s1
)[n
] = ((char *)s2
)[n
];
974 * safe ... no overlap problems
976 (void) memcpy(s1
, s2
, n
);
985 * copynum2blk - copy number numerator to block
988 copynum2blk(NUMBER
*snum
, long ssi
, long num
, BLOCK
*dblk
, long dsi
,
994 #if CALC_BYTE_ORDER == BIG_ENDIAN
995 ZVALUE
*swnum
; /* byte swapped numerator */
998 if (ssi
> snum
->num
.len
)
1001 num
= snum
->num
.len
- ssi
;
1002 if (num
== 0) /* Nothing to be copied */
1004 if (ssi
+ num
> snum
->num
.len
)
1007 dsi
= dblk
->datalen
;
1008 newlen
= dsi
+ (num
*sizeof(HALF
));
1011 if (newlen
>= (size_t)dblk
->maxsize
) {
1014 newsize
= (1 + newlen
/dblk
->blkchunk
) * dblk
->blkchunk
;
1015 newdata
= (USB8
*) realloc(dblk
->data
, newsize
);
1016 if (newdata
== NULL
) {
1017 math_error("Out of memory for num-to-block copy");
1020 dblk
->data
= newdata
;
1021 dblk
->maxsize
= newsize
;
1023 #if CALC_BYTE_ORDER == LITTLE_ENDIAN
1024 memmove(dblk
->data
+dsi
, (char *)(snum
->num
.v
+ssi
), num
*sizeof(HALF
));
1026 swnum
= swap_b8_in_ZVALUE(NULL
, &(snum
->num
), FALSE
);
1027 memmove(dblk
->data
+dsi
, (char *)(swnum
->v
+ssi
), num
*sizeof(HALF
));
1030 if (newlen
> (size_t)dblk
->datalen
)
1031 dblk
->datalen
= newlen
;
1037 * copyblk2num - copy block to number
1040 copyblk2num(BLOCK
*sblk
, long ssi
, long num
, NUMBER
*dnum
, long dsi
,
1044 NUMBER
*ret
; /* cloned and modified numerator */
1045 #if CALC_BYTE_ORDER == BIG_ENDIAN
1046 HALF
*swapped
; /* byte swapped input data */
1047 unsigned long halflen
; /* length of the input ounded up to HALFs */
1048 HALF
*h
; /* copy byteswap pointer */
1052 if (ssi
> sblk
->datalen
)
1055 num
= sblk
->datalen
- ssi
;
1056 if (num
== 0) /* Nothing to be copied */
1058 if (ssi
+ num
> sblk
->datalen
)
1061 dsi
= dnum
->num
.len
;
1062 newlen
= dsi
+ ((num
+sizeof(HALF
)-1)/sizeof(HALF
));
1066 /* quasi-clone the numerator to the new size */
1068 ret
->num
.sign
= dnum
->num
.sign
;
1069 ret
->num
.v
= alloc(newlen
);
1070 ret
->num
.len
= newlen
;
1071 /* ensure that any trailing octets will be zero filled */
1072 ret
->num
.v
[newlen
-1] = 0;
1073 zcopyval(dnum
->num
, ret
->num
);
1074 if (!zisunit(ret
->den
)) {
1075 ret
->den
.len
= dnum
->den
.len
;
1076 ret
->den
.v
= alloc(dnum
->den
.len
);
1077 zcopyval(dnum
->den
, ret
->den
);
1081 #if CALC_BYTE_ORDER == LITTLE_ENDIAN
1082 memmove((char *)(ret
->num
.v
+ dsi
), sblk
->data
+ ssi
, num
);
1084 /* form a HALF aligned copy of the input */
1085 halflen
= (num
+sizeof(HALF
)-1) / sizeof(HALF
);
1086 swapped
= (HALF
*)malloc(halflen
* sizeof(HALF
));
1087 if (swapped
== NULL
) {
1088 math_error("Out of memory for block-to-num copy");
1091 /* ensure that any trailing octets will be zero filled */
1092 swapped
[halflen
-1] = 0;
1093 memcpy(swapped
, sblk
->data
+ ssi
, num
);
1094 /* byte swap the copy of the input */
1095 for (i
=0, h
=swapped
; i
< halflen
; ++i
, ++h
) {
1096 SWAP_B8_IN_HALF(h
, h
);
1098 /* copy over whole byte-swapped HALFs */
1099 memcpy((char *)(ret
->num
.v
+ dsi
), swapped
,
1100 (num
/sizeof(HALF
))*sizeof(HALF
));
1101 /* copy over any octets in the last partial HALF */
1102 i
= num
% sizeof(HALF
);
1104 memcpy((char *)(ret
->num
.v
+ dsi
)+num
-i
,
1105 (char *)swapped
+ num
-i
, i
);
1109 /* save new number */