Tizen 2.0 Release
[external/mawk.git] / split.c
1
2 /********************************************
3 split.c
4 copyright 1991, Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 /* $Log: split.c,v $
14  * Revision 1.3  1996/02/01  04:39:42  mike
15  * dynamic array scheme
16  *
17  * Revision 1.2  1993/07/15  01:55:03  mike
18  * rm SIZE_T & indent
19  *
20  * Revision 1.1.1.1  1993/07/03  18:58:21  mike
21  * move source to cvs
22  *
23  * Revision 5.4  1993/05/08  18:06:00  mike
24  * null_split
25  *
26  * Revision 5.3  1993/01/01  21:30:48  mike
27  * split new_STRING() into new_STRING and new_STRING0
28  *
29  * Revision 5.2  1992/07/08  21:19:09  brennan
30  * patch2
31  * change in split() requires that
32  * bi_split() call load_array() even
33  * when cnt is 0.
34  *
35  * Revision 5.1  1991/12/05  07:56:31  brennan
36  * 1.1 pre-release
37  *
38 */
39
40 /* split.c */
41
42
43 /* For all splitting up to MAX_SPLIT fields go into
44    split_buff[], the rest go onto split_ov_list ( split
45    overflow list)
46
47    We can split one of three ways:
48      (1) By space:
49          space_split() and space_ov_split()
50      (2) By regular expression:
51          re_split()    and re_ov_split()
52      (3) By "" (null -- split into characters)
53          null_split() and null_ov_split()
54 */
55
56 #define  TEMPBUFF_GOES_HERE
57
58 #include "mawk.h"
59 #include "symtype.h"
60 #include "bi_vars.h"
61 #include "bi_funct.h"
62 #include "memory.h"
63 #include "scan.h"
64 #include "regexp.h"
65 #include "field.h"
66
67 SPLIT_OV *split_ov_list ;
68
69 static int PROTO(re_ov_split, (char *, PTR)) ;
70 static int PROTO(space_ov_split, (char *, char *)) ;
71 static int PROTO(null_ov_split, (char *)) ;
72
73 /* split string s of length slen on SPACE without changing s.
74    load the pieces into STRINGS and ptrs into
75    split_buff[]
76    return the number of pieces */
77
78 int
79 space_split(s, slen)
80    register char *s ;
81    unsigned slen ;
82 {
83    char *back = s + slen ;
84    int i = 0 ;
85    int len ;
86    char *q ;
87    STRING *sval ;
88    int lcnt = MAX_SPLIT / 3 ;
89
90 #define EAT_SPACE()   while ( scan_code[*(unsigned char*)s] ==\
91                               SC_SPACE )  s++
92 #define EAT_NON_SPACE()   \
93     *back = ' ' ; /* sentinel */\
94     while ( scan_code[*(unsigned char*)s] != SC_SPACE )  s++ ;\
95     *back = 0
96
97
98    while (lcnt--)
99    {
100       EAT_SPACE() ;
101       if (*s == 0)  goto done ;
102       /* mark the front with q */
103       q = s++ ;
104       EAT_NON_SPACE() ;
105       sval = split_buff[i++] = new_STRING0(len = s - q) ;
106       memcpy(sval->str, q, len) ;
107
108       EAT_SPACE() ;
109       if (*s == 0)  goto done ;
110       q = s++ ;
111       EAT_NON_SPACE() ;
112       sval = split_buff[i++] = new_STRING0(len = s - q) ;
113       memcpy(sval->str, q, len) ;
114
115       EAT_SPACE() ;
116       if (*s == 0)  goto done ;
117       q = s++ ;
118       EAT_NON_SPACE() ;
119       sval = split_buff[i++] = new_STRING0(len = s - q) ;
120       memcpy(sval->str, q, len) ;
121
122    }
123    /* we've overflowed */
124    return i + space_ov_split(s, back) ;
125
126  done:
127    return i ;
128 }
129
130 static int
131 space_ov_split(s, back)
132    register char *s ;
133    char *back ;
134
135 {
136    SPLIT_OV dummy ;
137    register SPLIT_OV *tail = &dummy ;
138    char *q ;
139    int cnt = 0 ;
140    unsigned len ;
141
142    while (1)
143    {
144       EAT_SPACE() ;
145       if (*s == 0)  break ;                 /* done */
146       q = s++ ;
147       EAT_NON_SPACE() ;
148
149       tail = tail->link = ZMALLOC(SPLIT_OV) ;
150       tail->sval = new_STRING0(len = s - q) ;
151       memcpy(tail->sval->str, q, len) ;
152       cnt++ ;
153    }
154
155    tail->link = (SPLIT_OV *) 0 ;
156    split_ov_list = dummy.link ;
157    return cnt ;
158 }
159
160 /* match a string with a regular expression, but
161    only matches of positive length count */
162 char *
163 re_pos_match(s, re, lenp)
164    register char *s ;
165 PTR re ; unsigned *lenp ;
166 {
167    while ((s = REmatch(s, re, lenp)))
168       if (*lenp)  return s ;
169       else if (*s == 0)  break ;
170       else  s++ ;
171
172    return (char *) 0 ;
173 }
174
175 int
176 re_split(s, re)
177    char *s ;
178    PTR re ;
179 {
180    register char *t ;
181    int i = 0 ;
182    unsigned mlen, len ;
183    STRING *sval ;
184    int lcnt = MAX_SPLIT / 3 ;
185
186    while (lcnt--)
187    {
188       if (!(t = re_pos_match(s, re, &mlen)))  goto done ;
189       sval = split_buff[i++] = new_STRING0(len = t - s) ;
190       memcpy(sval->str, s, len) ;
191       s = t + mlen ;
192
193       if (!(t = re_pos_match(s, re, &mlen)))  goto done ;
194       sval = split_buff[i++] = new_STRING0(len = t - s) ;
195       memcpy(sval->str, s, len) ;
196       s = t + mlen ;
197
198       if (!(t = re_pos_match(s, re, &mlen)))  goto done ;
199       sval = split_buff[i++] = new_STRING0(len = t - s) ;
200       memcpy(sval->str, s, len) ;
201       s = t + mlen ;
202    }
203    /* we've overflowed */
204    return i + re_ov_split(s, re) ;
205
206 done:
207    split_buff[i++] = new_STRING(s) ;
208    return i ;
209 }
210
211 /*
212   we've overflowed split_buff[] , put
213   the rest on the split_ov_list
214   return number of pieces
215 */
216
217 static int
218 re_ov_split(s, re)
219    char *s ;
220    PTR re ;
221 {
222    SPLIT_OV dummy ;
223    register SPLIT_OV *tail = &dummy ;
224    int cnt = 1 ;
225    char *t ;
226    unsigned len, mlen ;
227
228    while ((t = re_pos_match(s, re, &mlen)))
229    {
230       tail = tail->link = ZMALLOC(SPLIT_OV) ;
231       tail->sval = new_STRING0(len = t - s) ;
232       memcpy(tail->sval->str, s, len) ;
233       s = t + mlen ;
234       cnt++ ;
235    }
236    /* and one more */
237    tail = tail->link = ZMALLOC(SPLIT_OV) ;
238    tail->sval = new_STRING(s) ;
239    tail->link = (SPLIT_OV *) 0 ;
240    split_ov_list = dummy.link ;
241
242    return cnt ;
243 }
244
245
246 int
247 null_split(s)
248    char *s ;
249 {
250    int cnt = 0 ;                 /* number of fields split */
251    STRING *sval ;
252    int i = 0 ;                   /* indexes split_buff[] */
253
254    while (*s)
255    {
256       if (cnt == MAX_SPLIT)  return cnt + null_ov_split(s) ;
257
258       sval = new_STRING0(1) ;
259       sval->str[0] = *s++ ;
260       split_buff[i++] = sval ;
261       cnt++ ;
262    }
263    return cnt ;
264 }
265
266 static int
267 null_ov_split(s)
268    char *s ;
269 {
270    SPLIT_OV dummy ;
271    SPLIT_OV *ovp = &dummy ;
272    int cnt = 0 ;
273
274    while (*s)
275    {
276       ovp = ovp->link = ZMALLOC(SPLIT_OV) ;
277       ovp->sval = new_STRING0(1) ;
278       ovp->sval->str[0] = *s++ ;
279       cnt++ ;
280    }
281    ovp->link = (SPLIT_OV *) 0 ;
282    split_ov_list = dummy.link ;
283    return cnt ;
284 }
285
286
287 /*  split(s, X, r)
288     split s into array X on r
289
290     entry: sp[0] holds r
291            sp[-1] pts at X
292            sp[-2] holds s
293 */
294 CELL *
295 bi_split(sp)
296    register CELL *sp ;
297 {
298    int cnt ;                     /* the number of pieces */
299
300
301    if (sp->type < C_RE)  cast_for_split(sp) ;
302    /* can be C_RE, C_SPACE or C_SNULL */
303    sp -= 2 ;
304    if (sp->type < C_STRING)  cast1_to_s(sp) ;
305
306    if (string(sp)->len == 0)    /* nothing to split */
307       cnt = 0 ;
308    else
309       switch ((sp + 2)->type)
310       {
311          case C_RE:
312             cnt = re_split(string(sp)->str, (sp + 2)->ptr) ;
313             break ;
314
315          case C_SPACE:
316             cnt = space_split(string(sp)->str, string(sp)->len) ;
317             break ;
318
319          case C_SNULL:          /* split on empty string */
320             cnt = null_split(string(sp)->str) ;
321             break ;
322
323          default:
324             bozo("bad splitting cell in bi_split") ;
325       }
326
327
328    free_STRING(string(sp)) ;
329    sp->type = C_DOUBLE ;
330    sp->dval = (double) cnt ;
331
332    array_load((ARRAY) (sp + 1)->ptr, cnt) ;
333
334    return sp ;
335 }