summaryrefslogtreecommitdiff
path: root/do/vec
blob: 37101adc280a41b338901daff1df1f721d17a93c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
int
do_vec(lvalue,astr,arglast)
int lvalue;
STR *astr;
int *arglast;
{
    STR **st = stack->ary_array;
    int sp = arglast[0];
    register STR *TARG = st[++sp];
    register int offset = (int)str_gnum(st[++sp]);
    register int size = (int)str_gnum(st[++sp]);
    unsigned char *s = (unsigned char*)str_get(TARG);
    unsigned long retnum;
    int len;

    sp = arglast[1];
    offset *= size;		/* turn into bit offset */
    len = (offset + size + 7) / 8;
    if (offset < 0 || size < 1)
	retnum = 0;
    else if (!lvalue && len > TARG->str_cur)
	retnum = 0;
    else {
	if (len > TARG->str_cur) {
	    STR_GROW(TARG,len);
	    (void)memzero(TARG->str_ptr + TARG->str_cur, len - TARG->str_cur);
	    TARG->str_cur = len;
	}
	s = (unsigned char*)str_get(TARG);
	if (size < 8)
	    retnum = (s[offset >> 3] >> (offset & 7)) & ((1 << size) - 1);
	else {
	    offset >>= 3;
	    if (size == 8)
		retnum = s[offset];
	    else if (size == 16)
		retnum = ((unsigned long) s[offset] << 8) + s[offset+1];
	    else if (size == 32)
		retnum = ((unsigned long) s[offset] << 24) +
			((unsigned long) s[offset + 1] << 16) +
			(s[offset + 2] << 8) + s[offset+3];
	}

	if (lvalue) {                      /* it's an lvalue! */
	    struct lstring *lstr = (struct lstring*)astr;

	    astr->str_magic = TARG;
	    st[sp]->str_rare = 'v';
	    lstr->lstr_offset = offset;
	    lstr->lstr_len = size;
	}
    }

    str_numset(astr,(double)retnum);
    st[sp] = astr;
    return sp;
}