perl 5.0 alpha 3
[perl.git] / do / splice
1 int
2 do_splice(ary,gimme,arglast)
3 register ARRAY *ary;
4 int gimme;
5 int *arglast;
6 {
7     register STR **st = stack->ary_array;
8     register int sp = arglast[1];
9     int max = arglast[2] + 1;
10     register STR **src;
11     register STR **dst;
12     register int i;
13     register int offset;
14     register int length;
15     int newlen;
16     int after;
17     int diff;
18     STR **tmparyval;
19
20     if (++sp < max) {
21         offset = (int)str_gnum(st[sp]);
22         if (offset < 0)
23             offset += ary->ary_fill + 1;
24         else
25             offset -= arybase;
26         if (++sp < max) {
27             length = (int)str_gnum(st[sp++]);
28             if (length < 0)
29                 length = 0;
30         }
31         else
32             length = ary->ary_max + 1;          /* close enough to infinity */
33     }
34     else {
35         offset = 0;
36         length = ary->ary_max + 1;
37     }
38     if (offset < 0) {
39         length += offset;
40         offset = 0;
41         if (length < 0)
42             length = 0;
43     }
44     if (offset > ary->ary_fill + 1)
45         offset = ary->ary_fill + 1;
46     after = ary->ary_fill + 1 - (offset + length);
47     if (after < 0) {                            /* not that much array */
48         length += after;                        /* offset+length now in array */
49         after = 0;
50         if (!ary->ary_alloc) {
51             afill(ary,0);
52             afill(ary,-1);
53         }
54     }
55
56     /* At this point, sp .. max-1 is our new LIST */
57
58     newlen = max - sp;
59     diff = newlen - length;
60
61     if (diff < 0) {                             /* shrinking the area */
62         if (newlen) {
63             New(451, tmparyval, newlen, STR*);  /* so remember insertion */
64             Copy(st+sp, tmparyval, newlen, STR*);
65         }
66
67         sp = arglast[0] + 1;
68         if (gimme == G_ARRAY) {                 /* copy return vals to stack */
69             if (sp + length >= stack->ary_max) {
70                 astore(stack,sp + length, Nullstr);
71                 st = stack->ary_array;
72             }
73             Copy(ary->ary_array+offset, st+sp, length, STR*);
74             if (ary->ary_flags & ARF_REAL) {
75                 for (i = length, dst = st+sp; i; i--)
76                     str_2mortal(*dst++);        /* free them eventualy */
77             }
78             sp += length - 1;
79         }
80         else {
81             st[sp] = ary->ary_array[offset+length-1];
82             if (ary->ary_flags & ARF_REAL) {
83                 str_2mortal(st[sp]);
84                 for (i = length - 1, dst = &ary->ary_array[offset]; i > 0; i--)
85                     str_free(*dst++);   /* free them now */
86             }
87         }
88         ary->ary_fill += diff;
89
90         /* pull up or down? */
91
92         if (offset < after) {                   /* easier to pull up */
93             if (offset) {                       /* esp. if nothing to pull */
94                 src = &ary->ary_array[offset-1];
95                 dst = src - diff;               /* diff is negative */
96                 for (i = offset; i > 0; i--)    /* can't trust Copy */
97                     *dst-- = *src--;
98             }
99             Zero(ary->ary_array, -diff, STR*);
100             ary->ary_array -= diff;             /* diff is negative */
101             ary->ary_max += diff;
102         }
103         else {
104             if (after) {                        /* anything to pull down? */
105                 src = ary->ary_array + offset + length;
106                 dst = src + diff;               /* diff is negative */
107                 Move(src, dst, after, STR*);
108             }
109             Zero(&ary->ary_array[ary->ary_fill+1], -diff, STR*);
110                                                 /* avoid later double free */
111         }
112         if (newlen) {
113             for (src = tmparyval, dst = ary->ary_array + offset;
114               newlen; newlen--) {
115                 *dst = Str_new(46,0);
116                 str_sset(*dst++,*src++);
117             }
118             Safefree(tmparyval);
119         }
120     }
121     else {                                      /* no, expanding (or same) */
122         if (length) {
123             New(452, tmparyval, length, STR*);  /* so remember deletion */
124             Copy(ary->ary_array+offset, tmparyval, length, STR*);
125         }
126
127         if (diff > 0) {                         /* expanding */
128
129             /* push up or down? */
130
131             if (offset < after && diff <= ary->ary_array - ary->ary_alloc) {
132                 if (offset) {
133                     src = ary->ary_array;
134                     dst = src - diff;
135                     Move(src, dst, offset, STR*);
136                 }
137                 ary->ary_array -= diff;         /* diff is positive */
138                 ary->ary_max += diff;
139                 ary->ary_fill += diff;
140             }
141             else {
142                 if (ary->ary_fill + diff >= ary->ary_max)       /* oh, well */
143                     astore(ary, ary->ary_fill + diff, Nullstr);
144                 else
145                     ary->ary_fill += diff;
146                 dst = ary->ary_array + ary->ary_fill;
147                 for (i = diff; i > 0; i--) {
148                     if (*dst)                   /* TARG was hanging around */
149                         str_free(*dst);         /*  after $#foo */
150                     dst--;
151                 }
152                 if (after) {
153                     dst = ary->ary_array + ary->ary_fill;
154                     src = dst - diff;
155                     for (i = after; i; i--) {
156                         *dst-- = *src--;
157                     }
158                 }
159             }
160         }
161
162         for (src = st+sp, dst = ary->ary_array + offset; newlen; newlen--) {
163             *dst = Str_new(46,0);
164             str_sset(*dst++,*src++);
165         }
166         sp = arglast[0] + 1;
167         if (gimme == G_ARRAY) {                 /* copy return vals to stack */
168             if (length) {
169                 Copy(tmparyval, st+sp, length, STR*);
170                 if (ary->ary_flags & ARF_REAL) {
171                     for (i = length, dst = st+sp; i; i--)
172                         str_2mortal(*dst++);    /* free them eventualy */
173                 }
174                 Safefree(tmparyval);
175             }
176             sp += length - 1;
177         }
178         else if (length--) {
179             st[sp] = tmparyval[length];
180             if (ary->ary_flags & ARF_REAL) {
181                 str_2mortal(st[sp]);
182                 while (length-- > 0)
183                     str_free(tmparyval[length]);
184             }
185             Safefree(tmparyval);
186         }
187         else
188             st[sp] = &str_undef;
189     }
190     return sp;
191 }
192