Git init
[external/mawk.git] / field.c
1
2 /********************************************
3 field.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: field.c,v $
14  * Revision 1.5  1995/06/18  19:17:47  mike
15  * Create a type Int which on most machines is an int, but on machines
16  * with 16bit ints, i.e., the PC is a long.  This fixes implicit assumption
17  * that int==long.
18  *
19  * Revision 1.4  1994/10/08  19:15:38  mike
20  * remove SM_DOS
21  *
22  * Revision 1.3  1993/07/14  12:32:39  mike
23  * run thru indent
24  *
25  * Revision 1.2  1993/07/14  12:22:11  mike
26  * rm SIZE_T and (void) casts
27  *
28  * Revision 1.1.1.1  1993/07/03  18:58:12  mike
29  * move source to cvs
30  *
31  * Revision 5.7  1993/05/08  18:06:00  mike
32  * null_split
33  *
34  * Revision 5.6  1993/02/13  21:57:25  mike
35  * merge patch3
36  *
37  * Revision 5.5  1993/01/01  21:30:48  mike
38  * split new_STRING() into new_STRING and new_STRING0
39  *
40  * Revision 5.4.1.2  1993/01/20  12:53:08  mike
41  * d_to_l()
42  *
43  * Revision 5.4.1.1  1993/01/15  03:33:42  mike
44  * patch3: safer double to int conversion
45  *
46  * Revision 5.4  1992/11/29  22:52:11  mike
47  * double->string conversions uses long ints for 16/32 bit
48  * compatibility.
49  * Fixed small LM_DOS bozo.
50  *
51  * Revision 5.3  1992/08/17  14:21:10  brennan
52  * patch2: After parsing, only bi_sprintf() uses string_buff.
53  *
54  * Revision 5.2  1992/07/10  16:17:10  brennan
55  * MsDOS: remove NO_BINMODE macro
56  *
57  * Revision 5.1  1991/12/05  07:55:57  brennan
58  * 1.1 pre-release
59  *
60 */
61
62
63 /* field.c */
64
65 #include "mawk.h"
66 #include "field.h"
67 #include "init.h"
68 #include "memory.h"
69 #include "scan.h"
70 #include "bi_vars.h"
71 #include "repl.h"
72 #include "regexp.h"
73
74 CELL field[FBANK_SZ + NUM_PFIELDS] ;
75
76 CELL *fbank[NUM_FBANK] =
77 {field} ;
78
79 static int max_field = MAX_SPLIT ;       /* maximum field actually created*/
80
81 static void PROTO(build_field0, (void)) ;
82 static void PROTO(set_rs_shadow, (void)) ;
83 static void PROTO(load_pfield, (char *, CELL *)) ;
84 static void PROTO(load_field_ov, (void)) ;
85
86
87
88 /* a description of how to split based on RS.
89    If RS is changed, so is rs_shadow */
90 SEPARATOR rs_shadow =
91 {SEP_CHAR, '\n'} ;
92 /* a splitting CELL version of FS */
93 CELL fs_shadow =
94 {C_SPACE} ;
95 int nf ;
96  /* nf holds the true value of NF.  If nf < 0 , then
97      NF has not been computed, i.e., $0 has not been split
98   */
99
100 static void
101 set_rs_shadow()
102 {
103    CELL c ;
104    STRING *sval ;
105    char *s ;
106    unsigned len ;
107
108    if (posix_space_flag && mawk_state == EXECUTION)
109       scan_code['\n'] = SC_UNEXPECTED ;
110
111    if (rs_shadow.type == SEP_STR)
112      {
113        free_STRING((STRING *) rs_shadow.ptr) ;
114      }
115
116    cast_for_split(cellcpy(&c, RS)) ;
117    switch (c.type)
118    {
119       case C_RE:
120          if ((s = is_string_split(c.ptr, &len)))
121          {
122             if (len == 1)
123             {
124                rs_shadow.type = SEP_CHAR ;
125                rs_shadow.c = s[0] ;
126             }
127             else
128             {
129                rs_shadow.type = SEP_STR ;
130                rs_shadow.ptr = (PTR) new_STRING(s) ;
131             }
132          }
133          else
134          {
135             rs_shadow.type = SEP_RE ;
136             rs_shadow.ptr = c.ptr ;
137          }
138          break ;
139
140       case C_SPACE:
141          rs_shadow.type = SEP_CHAR ;
142          rs_shadow.c = ' ' ;
143          break ;
144
145       case C_SNULL:             /* RS becomes one or more blank lines */
146          if (mawk_state == EXECUTION)  scan_code['\n'] = SC_SPACE ;
147          rs_shadow.type = SEP_MLR ;
148          sval = new_STRING("\n\n+") ;
149          rs_shadow.ptr = re_compile(sval) ;
150          free_STRING(sval) ;
151          break ;
152
153       default:
154          bozo("bad cell in set_rs_shadow") ;
155    }
156 }
157
158 static void
159 load_pfield(name, cp)
160    char *name ;
161    CELL *cp ;
162 {
163    SYMTAB *stp ;
164
165    stp = insert(name) ; stp->type = ST_FIELD ;
166    stp->stval.cp = cp ;
167 }
168
169 /* initialize $0 and the pseudo fields */
170 void
171 field_init()
172 {
173    field[0].type = C_STRING ;
174    field[0].ptr = (PTR) & null_str ;
175    null_str.ref_cnt++ ;
176
177    load_pfield("NF", NF) ;
178    NF->type = C_DOUBLE ;
179    NF->dval = 0.0 ;
180
181    load_pfield("RS", RS) ;
182    RS->type = C_STRING ;
183    RS->ptr = (PTR) new_STRING("\n") ;
184    /* rs_shadow already set */
185
186    load_pfield("FS", FS) ;
187    FS->type = C_STRING ;
188    FS->ptr = (PTR) new_STRING(" ") ;
189    /* fs_shadow is already set */
190
191    load_pfield("OFMT", OFMT) ;
192    OFMT->type = C_STRING ;
193    OFMT->ptr = (PTR) new_STRING("%.6g") ;
194
195    load_pfield("CONVFMT", CONVFMT) ;
196    CONVFMT->type = C_STRING ;
197    CONVFMT->ptr = OFMT->ptr ;
198    string(OFMT)->ref_cnt++ ;
199 }
200
201
202
203 void
204 set_field0(s, len)
205    char *s ;
206    unsigned len ;
207 {
208    cell_destroy(&field[0]) ;
209    nf = -1 ;
210
211    if (len)
212    {
213       field[0].type = C_MBSTRN ;
214       field[0].ptr = (PTR) new_STRING0(len) ;
215       memcpy(string(&field[0])->str, s, len) ;
216    }
217    else
218    {
219       field[0].type = C_STRING ;
220       field[0].ptr = (PTR) & null_str ;
221       null_str.ref_cnt++ ;
222    }
223 }
224
225
226
227 /* split field[0] into $1, $2 ... and set NF  */
228
229 void
230 split_field0()
231 {
232    register CELL *cp ;
233    register int cnt ;
234    CELL c ;                      /* copy field[0] here if not string */
235
236
237    if (field[0].type < C_STRING)
238    {
239       cast1_to_s(cellcpy(&c, field + 0)) ;
240       cp = &c ;
241    }
242    else  cp = &field[0] ;
243
244    if (string(cp)->len == 0)  nf = 0 ;
245    else
246    {
247       switch (fs_shadow.type)
248       {
249          case C_SNULL:          /* FS == "" */
250             nf = null_split(string(cp)->str) ;
251             break ;
252
253          case C_SPACE:
254             nf = space_split(string(cp)->str, string(cp)->len) ;
255             break ;
256
257          default:
258             nf = re_split(string(cp)->str, fs_shadow.ptr) ;
259             break ;
260       }
261
262    }
263
264    cell_destroy(NF) ;
265    NF->type = C_DOUBLE ;
266    NF->dval = (double) nf ;
267
268    if (nf > MAX_SPLIT)
269    {
270       cnt = MAX_SPLIT ; load_field_ov() ;
271    }
272    else  cnt = nf ;
273
274    while (cnt > 0)
275    {
276       cell_destroy(field + cnt) ;
277       field[cnt].ptr = (PTR) split_buff[cnt - 1] ;
278       field[cnt--].type = C_MBSTRN ;
279    }
280
281    if (cp == &c) { free_STRING(string(cp)) ; }
282 }
283
284 /*
285   assign CELL *cp to field or pseudo field
286   and take care of all side effects
287 */
288
289 void
290 field_assign(fp, cp)
291    register CELL *fp ;
292    CELL *cp ;
293 {
294    CELL c ;
295    int i, j ;
296
297    /* the most common case first */
298    if (fp == field)
299    {
300       cell_destroy(field) ;
301       cellcpy(fp, cp) ;
302       nf = -1 ;
303       return ;
304    }
305
306    /* its not important to do any of this fast */
307
308    if (nf < 0)  split_field0() ;
309
310 #ifdef  MSDOS
311    if (!SAMESEG(fp, field))
312    {
313       i = -1 ;
314       goto lm_dos_label ;
315    }
316 #endif
317
318    switch (i = (fp - field))
319    {
320
321       case NF_field:
322
323          cell_destroy(NF) ;
324          cellcpy(NF, cellcpy(&c, cp)) ;
325          if (c.type != C_DOUBLE)  cast1_to_d(&c) ;
326
327          if ((j = d_to_i(c.dval)) < 0)
328             rt_error("negative value assigned to NF") ;
329
330          if (j > nf)
331             for (i = nf + 1; i <= j; i++)
332             {
333                cp = field_ptr(i) ;
334                cell_destroy(cp) ;
335                cp->type = C_STRING ;
336                cp->ptr = (PTR) & null_str ;
337                null_str.ref_cnt++ ;
338             }
339
340          nf = j ;
341          build_field0() ;
342          break ;
343
344       case RS_field:
345          cell_destroy(RS) ;
346          cellcpy(RS, cp) ;
347          set_rs_shadow() ;
348          break ;
349
350       case FS_field:
351          cell_destroy(FS) ;
352          cast_for_split(cellcpy(&fs_shadow, cellcpy(FS, cp))) ;
353          break ;
354
355       case OFMT_field:
356       case CONVFMT_field:
357          /* If the user does something stupid with OFMT or CONVFMT,
358            we could crash.
359            We'll make an attempt to protect ourselves here.  This is
360            why OFMT and CONVFMT are pseudo fields.
361
362            The ptrs of OFMT and CONVFMT always have a valid STRING,
363            even if assigned a DOUBLE or NOINIT
364         */
365
366          free_STRING(string(fp)) ;
367          cellcpy(fp, cp) ;
368          if (fp->type < C_STRING)       /* !! */
369             fp->ptr = (PTR) new_STRING("%.6g") ;
370          else if (fp == CONVFMT)
371          {
372             /* It's a string, but if it's really goofy and CONVFMT,
373              it could still damage us. Test it .
374           */
375             char xbuff[512] ;
376
377             xbuff[256] = 0 ;
378             sprintf(xbuff, string(fp)->str, 3.1459) ;
379             if (xbuff[256])
380                rt_error("CONVFMT assigned unusable value") ;
381          }
382          break ;
383
384 #ifdef MSDOS
385        lm_dos_label:
386 #endif
387
388       default:                  /* $1 or $2 or ... */
389
390
391          cell_destroy(fp) ;
392          cellcpy(fp, cp) ;
393
394          if (i < 0 || i > MAX_SPLIT)  i = field_addr_to_index(fp) ;
395
396          if (i > nf)
397          {
398             for (j = nf + 1; j < i; j++)
399             {
400                cp = field_ptr(j) ;
401                cell_destroy(cp) ;
402                cp->type = C_STRING ;
403                cp->ptr = (PTR) & null_str ;
404                null_str.ref_cnt++ ;
405             }
406             nf = i ;
407             cell_destroy(NF) ;
408             NF->type = C_DOUBLE ;
409             NF->dval = (double) i ;
410          }
411
412          build_field0() ;
413
414    }
415 }
416
417
418 /* construct field[0] from the other fields */
419
420 static void
421 build_field0()
422 {
423
424
425 #ifdef DEBUG
426    if (nf < 0)  bozo("nf <0 in build_field0") ;
427 #endif
428
429    cell_destroy(field + 0) ;
430
431    if (nf == 0)
432    {
433       field[0].type = C_STRING ;
434       field[0].ptr = (PTR) & null_str ;
435       null_str.ref_cnt++ ;
436    }
437    else if (nf == 1)
438    {
439       cellcpy(field, field + 1) ;
440    }
441    else
442    {
443       CELL c ;
444       STRING *ofs, *tail ;
445       unsigned len ;
446       register CELL *cp ;
447       register char *p, *q ;
448       int cnt ;
449       CELL **fbp, *cp_limit ;
450
451
452       cast1_to_s(cellcpy(&c, OFS)) ;
453       ofs = (STRING *) c.ptr ;
454       cast1_to_s(cellcpy(&c, field_ptr(nf))) ;
455       tail = (STRING *) c.ptr ;
456       cnt = nf - 1 ;
457
458       len = cnt * ofs->len + tail->len ;
459
460       fbp = fbank ; cp_limit = field + FBANK_SZ ;
461       cp = field + 1 ;
462
463       while (cnt-- > 0)
464       {
465          if (cp->type < C_STRING)
466          {                      /* use the string field temporarily */
467             if (cp->type == C_NOINIT)
468             {
469                cp->ptr = (PTR) & null_str ;
470                null_str.ref_cnt++ ;
471             }
472             else  /* its a double */
473             {
474                Int ival ;
475                char xbuff[260] ;
476
477                ival = d_to_I(cp->dval) ;
478                if (ival == cp->dval)  sprintf(xbuff, INT_FMT, ival) ;
479                else  sprintf(xbuff, string(CONVFMT)->str, cp->dval) ;
480
481                cp->ptr = (PTR) new_STRING(xbuff) ;
482             }
483          }
484
485          len += string(cp)->len ;
486
487          if (++cp == cp_limit)
488          {
489             cp = *++fbp ;
490             cp_limit = cp + FBANK_SZ ;
491          }
492
493       }
494
495       field[0].type = C_STRING ;
496       field[0].ptr = (PTR) new_STRING0(len) ;
497
498       p = string(field)->str ;
499
500       /* walk it again , putting things together */
501       cnt = nf-1 ; fbp = fbank ;
502       cp = field+1 ; cp_limit = field + FBANK_SZ ;
503       while (cnt-- > 0)
504       {
505          memcpy(p, string(cp)->str, string(cp)->len) ;
506          p += string(cp)->len ;
507          /* if not really string, free temp use of ptr */
508          if (cp->type < C_STRING) { free_STRING(string(cp)) ; }
509          if (++cp == cp_limit)
510          {
511             cp = *++fbp ;
512             cp_limit = cp + FBANK_SZ ;
513          }
514          /* add the separator */
515          q = ofs->str ;  while( *q )  *p++ = *q++ ;
516       }
517       /* tack tail on the end */
518       memcpy(p, tail->str, tail->len) ;
519
520       /* cleanup */
521       free_STRING(tail) ; free_STRING(ofs) ;
522    }
523 }
524
525 /* We are assigning to a CELL and we aren't sure if its
526    a field */
527
528 void
529 slow_cell_assign(target, source)
530    register CELL *target ;
531    CELL *source ;
532 {
533    if (
534
535 #ifdef MSDOS            /* the dreaded segment nonsense */
536          SAMESEG(target, field) &&
537 #endif
538          target >= field && target <= LAST_PFIELD)
539       field_assign(target, source) ;
540    else
541    {
542       CELL **p = fbank + 1 ;
543
544       while (*p)
545       {
546          if (
547 #ifdef  MSDOS
548                SAMESEG(target, *p) &&
549 #endif
550                target >= *p && target < *p + FBANK_SZ)
551          {
552             field_assign(target, source) ;
553             return ;
554          }
555          p++ ;
556       }
557       /* its not a field */
558       cell_destroy(target) ;
559       cellcpy(target, source) ;
560    }
561 }
562
563 int
564 field_addr_to_index(cp)
565    CELL *cp ;
566 {
567    CELL **p = fbank ;
568
569    while (
570
571 #ifdef MSDOS
572             !SAMESEG(cp, *p) ||
573 #endif
574
575             cp < *p || cp >= *p + FBANK_SZ)
576       p++ ;
577
578    return ((p - fbank) << FB_SHIFT) + (cp - *p) ;
579 }
580
581 /*------- more than 1 fbank needed  ------------*/
582
583 /*
584   compute the address of a field with index
585   > MAX_SPLIT
586 */
587
588 CELL *
589 slow_field_ptr(i)
590    register int i ;
591 {
592
593    if (i > max_field)
594    {
595       int j ;
596
597       if (i > MAX_FIELD)
598          rt_overflow("maximum number of fields", MAX_FIELD) ;
599
600       j = 1 ;
601       while (fbank[j])  j++ ;
602
603       do
604       {
605          fbank[j] = (CELL *) zmalloc(sizeof(CELL) * FBANK_SZ) ;
606          memset(fbank[j], 0, sizeof(CELL) * FBANK_SZ) ;
607          j++ ;
608          max_field += FBANK_SZ ;
609       }
610       while (i > max_field);
611    }
612
613    return &fbank[i >> FB_SHIFT][i & (FBANK_SZ - 1)] ;
614 }
615
616 /*
617   $0 split into more than MAX_SPLIT fields,
618   $(MAX_FIELD+1) ... are on the split_ov_list.
619   Copy into fields which start at fbank[1]
620 */
621
622 static void
623 load_field_ov()
624 {
625    register SPLIT_OV *p ;        /* walks split_ov_list */
626    register CELL *cp ;           /* target of copy */
627    int j ;                       /* current fbank[] */
628    CELL *cp_limit ;              /* change fbank[] */
629    SPLIT_OV *q ;                 /* trails p */
630
631    /* make sure the fields are allocated */
632    slow_field_ptr(nf) ;
633
634    p = split_ov_list ; split_ov_list = (SPLIT_OV*) 0 ;
635    j = 1 ; cp = fbank[j] ; cp_limit = cp + FBANK_SZ ;
636    while (p)
637    {
638       cell_destroy(cp) ;
639       cp->type = C_MBSTRN ;
640       cp->ptr = (PTR) p->sval ;
641
642       if (++cp == cp_limit)
643       {
644          cp = fbank[++j] ; cp_limit = cp + FBANK_SZ ;
645       }
646
647       q = p ; p = p->link ; ZFREE(q) ;
648    }
649 }
650
651
652 #if  MSDOS
653
654 int
655 binmode()                       /* read current value of BINMODE */
656 {
657    CELL c ;
658
659    cast1_to_d(cellcpy(&c, BINMODE)) ;
660    return d_to_i(c.dval) ;
661 }
662
663 /* set BINMODE and RS and ORS
664    from environment or -W binmode=   */
665
666 void
667 set_binmode(x)
668    int x ;
669 {
670    CELL c ;
671
672    /* set RS */
673    c.type = C_STRING ;
674    c.ptr = (PTR) new_STRING((x & 1) ? "\r\n" : "\n") ;
675    field_assign(RS, &c) ;
676    free_STRING(string(&c)) ;
677
678    /* set ORS */
679    cell_destroy(ORS) ;
680    ORS->type = C_STRING ;
681    ORS->ptr = (PTR) new_STRING((x & 2) ? "\r\n" : "\n") ;
682
683    cell_destroy(BINMODE) ;
684    BINMODE->type = C_DOUBLE ;
685    BINMODE->dval = (double) x ;
686 }
687
688 #endif /* MSDOS */