Tizen 2.1 base
[external/mawk.git] / re_cmpl.c
1
2 /********************************************
3 re_cmpl.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: re_cmpl.c,v $
14  * Revision 1.6  1994/12/13  00:14:58  mike
15  * \\ -> \ on second replacement scan
16  *
17  * Revision 1.5  1994/10/08  19:15:51  mike
18  * remove SM_DOS
19  *
20  * Revision 1.4  1993/07/21  01:17:53  mike
21  * handle "&" as replacement correctly
22  *
23  * Revision 1.3  1993/07/17  13:23:10  mike
24  * indent and general code cleanup
25  *
26  * Revision 1.2  1993/07/15  23:38:23  mike
27  * SIZE_T and indent
28  *
29  * Revision 1.1.1.1  1993/07/03  18:58:19  mike
30  * move source to cvs
31  *
32  * Revision 5.2  1993/01/01  21:30:48  mike
33  * split new_STRING() into new_STRING and new_STRING0
34  *
35  * Revision 5.1  1991/12/05  07:56:25  brennan
36  * 1.1 pre-release
37  *
38 */
39
40
41 /*  re_cmpl.c  */
42
43 #include "mawk.h"
44 #include "memory.h"
45 #include "scan.h"
46 #include "regexp.h"
47 #include "repl.h"
48
49
50 static CELL *PROTO(REPL_compile, (STRING *)) ;
51
52 typedef struct re_node
53 {
54    STRING *sval ;
55    PTR re ;
56    struct re_node *link ;
57 } RE_NODE ;
58
59 /* a list of compiled regular expressions */
60 static RE_NODE *re_list ;
61
62 static char efmt[] = "regular expression compile failed (%s)\n%s" ;
63
64 /* compile a STRING to a regular expression machine.
65    Search a list of pre-compiled strings first
66 */
67 PTR
68 re_compile(sval)
69    STRING *sval ;
70 {
71    register RE_NODE *p ;
72    RE_NODE *q ;
73    char *s ;
74
75    /* search list */
76    s = sval->str ;
77    p = re_list ;
78    q = (RE_NODE *) 0 ;
79    while (p)
80    {
81       if (strcmp(s, p->sval->str) == 0) /* found */
82       {
83          if (!q)                /* already at front */
84             goto _return ;
85          else  /* delete from list for move to front */
86          {
87             q->link = p->link ; goto found ; 
88          }
89
90       }
91       else
92       {
93          q = p ; p = p->link ; 
94       }
95    }
96
97    /* not found */
98    p = ZMALLOC(RE_NODE) ;
99    p->sval = sval ;
100
101    sval->ref_cnt++ ;
102    if (!(p->re = REcompile(s)))
103    {
104       if (mawk_state == EXECUTION)
105          rt_error(efmt, REerrlist[REerrno], s) ;
106       else  /* compiling */
107       {
108          compile_error(efmt, REerrlist[REerrno], s) ;
109          return (PTR) 0 ;
110       }
111    }
112
113
114 found :
115 /* insert p at the front of the list */
116    p->link = re_list ; re_list = p ;
117
118 _return :
119
120 #ifdef  DEBUG
121    if (dump_RE)  REmprint(p->re, stderr) ;
122 #endif
123    return p->re ;
124 }
125
126
127
128 /* this is only used by da() */
129
130
131 char *
132 re_uncompile(m)
133    PTR m ;
134 {
135    register RE_NODE *p ;
136
137    for (p = re_list; p; p = p->link)
138       if (p->re == m)  return p->sval->str ;
139 #ifdef  DEBUG
140    bozo("non compiled machine") ;
141 #else
142    return NULL;
143 #endif
144 }
145
146
147
148 /*=================================================*/
149 /*  replacement  operations   */
150
151 /* create a replacement CELL from a STRING *  */
152
153 static CELL *
154 REPL_compile(sval)
155    STRING *sval ;
156 {
157    int i = 0 ;
158    register char *p = sval->str ;
159    register char *q ;
160    char *xbuff ;
161    CELL *cp ;
162
163    q = xbuff = (char *) zmalloc(sval->len + 1) ;
164
165    while (1)
166    {
167       switch (*p)
168       {
169          case 0:
170             *q = 0 ;
171             goto done ;
172
173          case '\\':
174             if (p[1] == '&'|| p[1] == '\\')
175             {
176                *q++ = p[1] ;
177                p += 2 ;
178                continue ;
179             }
180             else  break ;
181
182          case '&':
183             /* if empty we don't need to make a node */
184             if (q != xbuff)
185             {
186                *q = 0 ;
187                split_buff[i++] = new_STRING(xbuff) ;
188             }
189             /* and a null node for the '&'  */
190             split_buff[i++] = (STRING *) 0 ;
191             /*  reset  */
192             p++ ;  q = xbuff ;
193             continue ;
194
195          default:
196             break ;
197       }
198
199       *q++ = *p++ ;
200    }
201
202 done :
203    /* if we have one empty string it will get made now */
204    if (q > xbuff || i == 0)  split_buff[i++] = new_STRING(xbuff) ;
205
206    /* This will never happen */
207    if (i > MAX_SPLIT)  overflow("replacement pieces", MAX_SPLIT) ;
208
209    cp = ZMALLOC(CELL) ;
210    if (i == 1 && split_buff[0])
211    {
212       cp->type = C_REPL ;
213       cp->ptr = (PTR) split_buff[0] ;
214    }
215    else
216    {
217       STRING **sp = (STRING **)
218       (cp->ptr = zmalloc(sizeof(STRING *) * i)) ;
219       int j = 0 ;
220
221       while (j < i)  *sp++ = split_buff[j++] ;
222
223       cp->type = C_REPLV ;
224       cp->vcnt = i ;
225    }
226    zfree(xbuff, sval->len + 1) ;
227    return cp ;
228 }
229
230 /* free memory used by a replacement CELL  */
231
232 void
233 repl_destroy(cp)
234    register CELL *cp ;
235 {
236    register STRING **p ;
237    unsigned cnt ;
238
239    if (cp->type == C_REPL)  free_STRING(string(cp)) ;
240    else  /* an C_REPLV        */
241    {
242       p = (STRING **) cp->ptr ;
243       for (cnt = cp->vcnt; cnt; cnt--)
244       {
245          if (*p) { free_STRING(*p) ; }
246          p++ ;
247       }
248       zfree(cp->ptr, cp->vcnt * sizeof(STRING *)) ;
249    }
250 }
251
252 /* copy a C_REPLV cell to another CELL */
253
254 CELL *
255 replv_cpy(target, source)
256    CELL *target, *source ;
257 {
258    STRING **t, **s ;
259    unsigned cnt ;
260
261    target->type = C_REPLV ;
262    cnt = target->vcnt = source->vcnt ;
263    target->ptr = (PTR) zmalloc(cnt * sizeof(STRING *)) ;
264
265    t = (STRING **) target->ptr ;
266    s = (STRING **) source->ptr ;
267    while (cnt)
268    {
269       cnt-- ;
270       if ( *s ) (*s)->ref_cnt++ ;
271       *t++ = *s++ ;
272    }
273    return target ;
274 }
275
276
277 /* here's our old friend linked linear list with move to the front
278    for compilation of replacement CELLs  */
279
280 typedef struct repl_node
281 {
282    struct repl_node *link ;
283    STRING *sval ;                /* the input */
284    CELL *cp ;                    /* the output */
285 } REPL_NODE ;
286
287 static REPL_NODE *repl_list ;
288
289 /* search the list (with move to the front) for a compiled
290    separator.
291    return a ptr to a CELL (C_REPL or C_REPLV)
292 */
293
294 CELL *
295 repl_compile(sval)
296    STRING *sval ;
297 {
298    register REPL_NODE *p ;
299    REPL_NODE *q ;
300    char *s ;
301
302    /* search the list */
303    s = sval->str ;
304    p = repl_list ;
305    q = (REPL_NODE *) 0 ;
306    while (p)
307    {
308       if (strcmp(s, p->sval->str) == 0) /* found */
309       {
310          if (!q)                /* already at front */
311             return p->cp ;
312          else  /* delete from list for move to front */
313          {
314             q->link = p->link ;
315             goto found ;
316          }
317
318       }
319       else
320       {
321          q = p ; p = p->link ; 
322       }
323    }
324
325    /* not found */
326    p = ZMALLOC(REPL_NODE) ;
327    p->sval = sval ;
328    sval->ref_cnt++ ;
329    p->cp = REPL_compile(sval) ;
330
331 found :
332 /* insert p at the front of the list */
333    p->link = repl_list ; repl_list = p ;
334    return p->cp ;
335 }
336
337 /* return the string for a CELL or type REPL or REPLV,
338    this is only used by da()  */
339
340
341 char *
342 repl_uncompile(cp)
343    CELL *cp ;
344 {
345    register REPL_NODE *p = repl_list ;
346
347    if (cp->type == C_REPL)
348    {
349       while (p)
350       {
351          if (p->cp->type == C_REPL && p->cp->ptr == cp->ptr)
352             return p->sval->str ;
353          else  p = p->link ;
354       }
355    }
356    else
357    {
358       while (p)
359       {
360          if (p->cp->type == C_REPLV &&
361              memcmp(cp->ptr, p->cp->ptr, cp->vcnt * sizeof(STRING *))
362              == 0)
363             return p->sval->str ;
364          else  p = p->link ;
365       }
366    }
367
368 #if  DEBUG
369    bozo("unable to uncompile an repl") ;
370 #else
371    return NULL;
372 #endif
373 }
374
375 /*
376   convert a C_REPLV to  C_REPL
377      replacing the &s with sval
378 */
379
380 CELL *
381 replv_to_repl(cp, sval)
382 CELL *cp ; STRING *sval ;
383 {
384    register STRING **p ;
385    STRING **sblock = (STRING **) cp->ptr ;
386    unsigned cnt, vcnt = cp->vcnt ;
387    unsigned len ;
388    char *target ;
389
390 #ifdef  DEBUG
391    if (cp->type != C_REPLV)  bozo("not replv") ;
392 #endif
393
394    p = sblock ; cnt = vcnt ; len = 0 ;
395    while (cnt--)
396    {
397       if (*p)  len += (*p++)->len ;
398       else
399       {
400          *p++ = sval ;
401          sval->ref_cnt++ ;
402          len += sval->len ;
403       }
404    }
405    cp->type = C_REPL ;
406    cp->ptr = (PTR) new_STRING0(len) ;
407
408    p = sblock ; cnt = vcnt ; target = string(cp)->str ;
409    while (cnt--)
410    {
411       memcpy(target, (*p)->str, (*p)->len) ;
412       target += (*p)->len ;
413       free_STRING(*p) ;
414       p++ ;
415    }
416
417    zfree(sblock, vcnt * sizeof(STRING *)) ;
418    return cp ;
419 }