904d29ae72dafc5ffd8a2d3660afe6cb4d6825cf
[perl.git] / do / split
1 int
2 do_split(TARG,spat,limit,gimme,arglast)
3 STR *TARG;
4 register SPAT *spat;
5 register int limit;
6 int gimme;
7 int *arglast;
8 {
9     register ARRAY *ary = stack;
10     STR **st = ary->ary_array;
11     register int sp = arglast[0] + 1;
12     register char *s = str_get(st[sp]);
13     char *strend = s + st[sp--]->str_cur;
14     register STR *dstr;
15     register char *m;
16     int iters = 0;
17     int maxiters = (strend - s) + 10;
18     int i;
19     char *orig;
20     int origlimit = limit;
21     int realarray = 0;
22
23     if (!spat || !s)
24         fatal("panic: do_split");
25     else if (spat->spat_runtime) {
26         nointrp = "|)";
27         sp = eval(spat->spat_runtime,G_SCALAR,sp);
28         st = stack->ary_array;
29         m = str_get(dstr = st[sp--]);
30         nointrp = "";
31         if (*m == ' ' && dstr->str_cur == 1) {
32             str_set(dstr,"\\s+");
33             m = dstr->str_ptr;
34             spat->spat_flags |= SPAT_SKIPWHITE;
35         }
36         if (spat->spat_regexp) {
37             regfree(spat->spat_regexp);
38             spat->spat_regexp = Null(REGEXP*);  /* avoid possible double free */
39         }
40         spat->spat_regexp = regcomp(m,m+dstr->str_cur,
41             spat->spat_flags & SPAT_FOLD);
42         if (spat->spat_flags & SPAT_KEEP ||
43             (spat->spat_runtime->arg_type == O_ITEM &&
44               (spat->spat_runtime[1].arg_type & A_MASK) == A_SINGLE) ) {
45             arg_free(spat->spat_runtime);       /* it won't change, so */
46             spat->spat_runtime = Nullarg;       /* no point compiling again */
47         }
48     }
49 #ifdef DEBUGGING
50     if (debug & 8) {
51         deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
52     }
53 #endif
54     ary = stab_xarray(spat->spat_repl[1].arg_ptr.arg_stab);
55     if (ary && (gimme != G_ARRAY || (spat->spat_flags & SPAT_ONCE))) {
56         realarray = 1;
57         if (!(ary->ary_flags & ARF_REAL)) {
58             ary->ary_flags |= ARF_REAL;
59             for (i = ary->ary_fill; i >= 0; i--)
60                 ary->ary_array[i] = Nullstr;    /* don't free mere refs */
61         }
62         ary->ary_fill = -1;
63         sp = -1;        /* temporarily switch stacks */
64     }
65     else
66         ary = stack;
67     orig = s;
68     if (spat->spat_flags & SPAT_SKIPWHITE) {
69         while (isSPACE(*s))
70             s++;
71     }
72     if (!limit)
73         limit = maxiters + 2;
74     if (strEQ("\\s+",spat->spat_regexp->precomp)) {
75         while (--limit) {
76             /*SUPPRESS 530*/
77             for (m = s; m < strend && !isSPACE(*m); m++) ;
78             if (m >= strend)
79                 break;
80             dstr = Str_new(30,m-s);
81             str_nset(dstr,s,m-s);
82             if (!realarray)
83                 str_2mortal(dstr);
84             (void)astore(ary, ++sp, dstr);
85             /*SUPPRESS 530*/
86             for (s = m + 1; s < strend && isSPACE(*s); s++) ;
87         }
88     }
89     else if (strEQ("^",spat->spat_regexp->precomp)) {
90         while (--limit) {
91             /*SUPPRESS 530*/
92             for (m = s; m < strend && *m != '\n'; m++) ;
93             m++;
94             if (m >= strend)
95                 break;
96             dstr = Str_new(30,m-s);
97             str_nset(dstr,s,m-s);
98             if (!realarray)
99                 str_2mortal(dstr);
100             (void)astore(ary, ++sp, dstr);
101             s = m;
102         }
103     }
104     else if (spat->spat_short) {
105         i = spat->spat_short->str_cur;
106         if (i == 1) {
107             int fold = (spat->spat_flags & SPAT_FOLD);
108
109             i = *spat->spat_short->str_ptr;
110             if (fold && isUPPER(i))
111                 i = tolower(i);
112             while (--limit) {
113                 if (fold) {
114                     for ( m = s;
115                           m < strend && *m != i &&
116                             (!isUPPER(*m) || tolower(*m) != i);
117                           m++)                  /*SUPPRESS 530*/
118                         ;
119                 }
120                 else                            /*SUPPRESS 530*/
121                     for (m = s; m < strend && *m != i; m++) ;
122                 if (m >= strend)
123                     break;
124                 dstr = Str_new(30,m-s);
125                 str_nset(dstr,s,m-s);
126                 if (!realarray)
127                     str_2mortal(dstr);
128                 (void)astore(ary, ++sp, dstr);
129                 s = m + 1;
130             }
131         }
132         else {
133 #ifndef lint
134             while (s < strend && --limit &&
135               (m=fbminstr((unsigned char*)s, (unsigned char*)strend,
136                     spat->spat_short)) )
137 #endif
138             {
139                 dstr = Str_new(31,m-s);
140                 str_nset(dstr,s,m-s);
141                 if (!realarray)
142                     str_2mortal(dstr);
143                 (void)astore(ary, ++sp, dstr);
144                 s = m + i;
145             }
146         }
147     }
148     else {
149         maxiters += (strend - s) * spat->spat_regexp->nparens;
150         while (s < strend && --limit &&
151             regexec(spat->spat_regexp, s, strend, orig, 1, Nullstr, TRUE) ) {
152             if (spat->spat_regexp->subbase
153               && spat->spat_regexp->subbase != orig) {
154                 m = s;
155                 s = orig;
156                 orig = spat->spat_regexp->subbase;
157                 s = orig + (m - s);
158                 strend = s + (strend - m);
159             }
160             m = spat->spat_regexp->startp[0];
161             dstr = Str_new(32,m-s);
162             str_nset(dstr,s,m-s);
163             if (!realarray)
164                 str_2mortal(dstr);
165             (void)astore(ary, ++sp, dstr);
166             if (spat->spat_regexp->nparens) {
167                 for (i = 1; i <= spat->spat_regexp->nparens; i++) {
168                     s = spat->spat_regexp->startp[i];
169                     m = spat->spat_regexp->endp[i];
170                     dstr = Str_new(33,m-s);
171                     str_nset(dstr,s,m-s);
172                     if (!realarray)
173                         str_2mortal(dstr);
174                     (void)astore(ary, ++sp, dstr);
175                 }
176             }
177             s = spat->spat_regexp->endp[0];
178         }
179     }
180     if (realarray)
181         iters = sp + 1;
182     else
183         iters = sp - arglast[0];
184     if (iters > maxiters)
185         fatal("Split loop");
186     if (s < strend || origlimit) {      /* keep field after final delim? */
187         dstr = Str_new(34,strend-s);
188         str_nset(dstr,s,strend-s);
189         if (!realarray)
190             str_2mortal(dstr);
191         (void)astore(ary, ++sp, dstr);
192         iters++;
193     }
194     else {
195 #ifndef I286x
196         while (iters > 0 && ary->ary_array[sp]->str_cur == 0)
197             iters--,sp--;
198 #else
199         char *zaps;
200         int   zapb;
201
202         if (iters > 0) {
203                 zaps = str_get(afetch(ary,sp,FALSE));
204                 zapb = (int) *zaps;
205         }
206         
207         while (iters > 0 && (!zapb)) {
208             iters--,sp--;
209             if (iters > 0) {
210                 zaps = str_get(afetch(ary,iters-1,FALSE));
211                 zapb = (int) *zaps;
212             }
213         }
214 #endif
215     }
216     if (realarray) {
217         ary->ary_fill = sp;
218         if (gimme == G_ARRAY) {
219             sp++;
220             astore(stack, arglast[0] + 1 + sp, Nullstr);
221             Copy(ary->ary_array, stack->ary_array + arglast[0] + 1, sp, STR*);
222             return arglast[0] + sp;
223         }
224     }
225     else {
226         if (gimme == G_ARRAY)
227             return sp;
228     }
229     sp = arglast[0] + 1;
230     str_numset(TARG,(double)iters);
231     STABSET(TARG);
232     st[sp] = TARG;
233     return sp;
234 }
235