4 * Date: Sun Apr 11 21:31:32 2010
6 * GNU recutils - Field Expressions
10 /* Copyright (C) 2010-2019 Jose E. Marchesi */
12 /* This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 #define _(str) dgettext (PACKAGE, str)
33 #include <rec-utils.h>
53 #define REC_FEX_MAX_ELEMS 256
59 rec_fex_elem_t elems
[REC_FEX_MAX_ELEMS
];
63 * Static function declarations.
66 static void rec_fex_init (rec_fex_t fex
);
68 static bool rec_fex_parse_str_simple (rec_fex_t
new, const char *str
, const char *sep
);
69 static bool rec_fex_parse_str_subscripts (rec_fex_t
new, const char *str
);
70 static bool rec_fex_parse_elem (rec_fex_elem_t elem
, const char *str
);
77 rec_fex_new (const char *str
,
78 enum rec_fex_kind_e kind
)
83 new = malloc (sizeof (struct rec_fex_s
));
90 for (i
= 0; i
< REC_FEX_MAX_ELEMS
; i
++)
97 /* Parse the string, using the proper parsing routine
98 depending on the kind of field expression requested by
101 if (kind
== REC_FEX_SUBSCRIPTS
)
103 if (!rec_fex_parse_str_subscripts (new, str
))
105 /* Out of memory or parse error. */
110 else if (kind
== REC_FEX_SIMPLE
)
112 if (!rec_fex_parse_str_simple (new, str
, " \t\n"))
114 /* Out of memory or parse error. */
119 else /* REC_FEX_CSV */
121 if (!rec_fex_parse_str_simple (new, str
, ","))
123 /* Out of memory or parse error. */
135 rec_fex_destroy (rec_fex_t fex
)
141 for (i
= 0; i
< fex
->num_elems
; i
++)
143 free (fex
->elems
[i
]->rewrite_to
);
144 free (fex
->elems
[i
]->field_name
);
145 free (fex
->elems
[i
]->str
);
146 free (fex
->elems
[i
]);
155 rec_fex_dup (rec_fex_t fex
)
157 rec_fex_t copy
= NULL
;
160 copy
= malloc (sizeof (struct rec_fex_s
));
165 copy
->num_elems
= fex
->num_elems
;
166 copy
->str
= strdup (fex
->str
);
170 rec_fex_destroy (copy
);
174 for (i
= 0; i
< fex
->num_elems
; i
++)
176 if (fex
->elems
[i
] == NULL
)
178 copy
->elems
[i
] = NULL
;
182 copy
->elems
[i
] = malloc (sizeof (struct rec_fex_elem_s
));
186 rec_fex_destroy (copy
);
190 copy
->elems
[i
]->max
= fex
->elems
[i
]->max
;
191 copy
->elems
[i
]->min
= fex
->elems
[i
]->min
;
193 #define REC_COPY_STR_MAYBE_RETURN(FNAME) \
196 if (!fex->elems[i]->FNAME) \
198 copy->elems[i]->FNAME = NULL; \
202 copy->elems[i]->FNAME = strdup (fex->elems[i]->FNAME); \
203 if (!copy->elems[i]->FNAME) \
205 /* Out of memory. */ \
206 rec_fex_destroy (copy); \
212 REC_COPY_STR_MAYBE_RETURN (str
);
213 REC_COPY_STR_MAYBE_RETURN (field_name
);
214 REC_COPY_STR_MAYBE_RETURN (rewrite_to
);
215 REC_COPY_STR_MAYBE_RETURN (function_name
);
223 rec_fex_check (const char *str
, enum rec_fex_kind_e kind
)
231 regexp_str
= "^" REC_FNAME_LIST_RE
"$";
236 regexp_str
= "^" REC_FNAME_LIST_CS_RE
"$";
239 case REC_FEX_SUBSCRIPTS
:
241 regexp_str
= "^" REC_FNAME_LIST_SUB_RE
"$";
251 return rec_match (str
, regexp_str
);
255 rec_fex_size (rec_fex_t fex
)
257 return fex
->num_elems
;
261 rec_fex_get (rec_fex_t fex
,
264 if ((position
< 0) || (position
>= fex
->num_elems
))
269 return fex
->elems
[position
];
273 rec_fex_elem_field_name (rec_fex_elem_t elem
)
275 return elem
->field_name
;
279 rec_fex_elem_set_field_name (rec_fex_elem_t elem
,
282 free (elem
->field_name
);
283 elem
->field_name
= strdup (fname
);
284 return (elem
->field_name
!= NULL
);
288 rec_fex_elem_min (rec_fex_elem_t elem
)
294 rec_fex_elem_max (rec_fex_elem_t elem
)
300 rec_fex_elem_rewrite_to (rec_fex_elem_t elem
)
302 return elem
->rewrite_to
;
306 rec_fex_sort (rec_fex_t fex
)
312 /* XXX: this code only works when 'max' is not specified. */
314 for (i
= 1; i
< fex
->num_elems
; i
++)
322 /* If elems[j] > aux */
323 if ((fex
->elems
[j
]->min
== -1) || (fex
->elems
[j
]->min
> aux
->min
))
325 fex
->elems
[j
+ 1] = fex
->elems
[j
];
338 fex
->elems
[j
+ 1] = aux
;
343 rec_fex_str (rec_fex_t fex
,
344 enum rec_fex_kind_e kind
)
353 buf
= rec_buf_new (&result
, &result_size
);
356 char *field_str
= NULL
;
358 for (i
= 0; i
< fex
->num_elems
; i
++)
362 if (kind
== REC_FEX_SIMPLE
)
364 rec_buf_putc (' ', buf
);
368 rec_buf_putc (',', buf
);
372 field_str
= strdup (fex
->elems
[i
]->field_name
);
380 rec_buf_puts (field_str
, buf
);
383 if (kind
== REC_FEX_SUBSCRIPTS
)
385 if ((fex
->elems
[i
]->min
!= -1)
386 || (fex
->elems
[i
]->max
!= -1))
388 rec_buf_putc ('[', buf
);
389 if (fex
->elems
[i
]->min
!= -1)
391 if (asprintf (&tmp
, "%d", fex
->elems
[i
]->min
) != -1)
393 rec_buf_puts (tmp
, buf
);
397 if (fex
->elems
[i
]->max
!= -1)
399 if (asprintf (&tmp
, "-%d", fex
->elems
[i
]->max
) != -1)
401 rec_buf_puts (tmp
, buf
);
406 rec_buf_putc (']', buf
);
418 rec_fex_member_p (rec_fex_t fex
,
426 for (i
= 0; i
< fex
->num_elems
; i
++)
428 if (rec_field_name_equal_p (fname
,
429 fex
->elems
[i
]->field_name
)
430 && ((min
== -1) || (fex
->elems
[i
]->min
== min
))
431 && ((max
== -1) || (fex
->elems
[i
]->max
== max
)))
442 rec_fex_append (rec_fex_t fex
,
447 rec_fex_elem_t new_elem
;
449 if (fex
->num_elems
>= REC_FEX_MAX_ELEMS
)
451 fprintf (stderr
, _("internal error: REC_FEX_MAX_ELEMS exceeded. Please report this.\n"));
455 new_elem
= malloc (sizeof (struct rec_fex_elem_s
));
458 memset (new_elem
, 0, sizeof (*new_elem
));
459 new_elem
->field_name
= strdup (fname
);
460 if (!new_elem
->field_name
)
467 new_elem
->str
= strdup (fname
);
471 free (new_elem
->field_name
);
478 fex
->elems
[fex
->num_elems
++] = new_elem
;
485 rec_fex_elem_function_name (rec_fex_elem_t elem
)
487 return elem
->function_name
;
491 rec_fex_elem_function_data (rec_fex_elem_t elem
)
493 return elem
->function_data
;
497 rec_fex_all_calls_p (rec_fex_t fex
)
502 for (i
= 0; i
< fex
->num_elems
; i
++)
504 if (fex
->elems
[i
]->function_name
== NULL
)
519 rec_fex_init (rec_fex_t fex
)
521 /* Initialize the field expression structure so it can be safely
522 passed to rec_fex_destroy even if its contents are not completely
523 initialized with real values. */
525 memset (fex
, 0 /* NULL */, sizeof (struct rec_fex_s
));
529 rec_fex_parse_str_simple (rec_fex_t
new,
535 char *fex_str
, *fex_str_orig
;
544 fex_str
= strdup (str
);
549 fex_str_orig
= fex_str
;
553 elem_str
= strsep (&fex_str
, sep
);
556 if (strlen (elem_str
) > 0)
558 if ((elem
= malloc (sizeof (struct rec_fex_elem_s
))))
560 const char *p
= elem_str
;
562 /* Get the field name. */
564 if (!rec_parse_regexp (&p
,
566 &(elem
->field_name
)))
574 /* Get the subname, if any, and modify the name
579 char *subname
= NULL
;
582 if (!rec_parse_regexp (&p
,
587 free (elem
->field_name
);
593 /* Concatenate the field name and the subname. */
594 elem
->field_name
= rec_concat_strings (elem
->field_name
, "_", subname
);
597 /* Check that there are no extra stuff at the end of the
602 free (elem
->field_name
);
608 /* Initialize other attributes of the fex entry. */
610 elem
->function_name
= NULL
;
611 elem
->function_data
= NULL
;
612 elem
->rewrite_to
= NULL
;
613 elem
->str
= strdup (elem_str
);
616 new->elems
[new->num_elems
++] = elem
;
625 while ((elem_str
= strsep (&fex_str
, sep
)));
627 if (new->num_elems
== 0)
629 /* No elements were recognized. */
635 new->str
= strdup (str
);
639 /* Destroy parsed elements. */
640 for (i
= 0; i
< new->num_elems
; i
++)
642 free (new->elems
[i
]->rewrite_to
);
643 free (new->elems
[i
]->field_name
);
644 free (new->elems
[i
]->str
);
645 free (new->elems
[i
]);
654 rec_fex_parse_str_subscripts (rec_fex_t
new,
659 char *fex_str
, *fex_str_orig
;
665 fex_str
= strdup (str
);
670 fex_str_orig
= fex_str
;
672 elem_str
= strsep (&fex_str
, ",");
675 elem
= malloc (sizeof (struct rec_fex_elem_s
));
683 if (!rec_fex_parse_elem (elem
, elem_str
))
686 for (i
= 0; i
< new->num_elems
; i
++)
688 free (new->elems
[i
]->field_name
);
689 free (new->elems
[i
]->str
);
690 free (new->elems
[i
]);
698 /* Add the elem to the FEX. */
699 new->elems
[new->num_elems
++] = elem
;
701 while ((elem_str
= strsep (&fex_str
, ",")));
705 new->str
= strdup (str
);
713 rec_fex_parse_elem (rec_fex_elem_t elem
,
723 elem
->field_name
= NULL
;
724 elem
->function_name
= NULL
;
725 elem
->function_data
= NULL
;
727 elem
->rewrite_to
= NULL
;
731 /* The 'str' field keeps a copy of the textual entry. */
733 elem
->str
= strdup (str
);
735 /* Each FEX element can be either a function call or a field name
736 with an optional subscript. */
738 if (rec_match (p
, "^" REC_FEX_CALL
))
740 /* Get the function name and the field argument and store them
741 in the FEX element. */
743 if (!rec_parse_regexp (&p
,
744 "^" REC_FEX_FUNCTION_NAME
,
745 &(elem
->function_name
)))
752 p
++; /* Skip the ( */
755 /* Get the field name. */
757 if (!rec_parse_regexp (&p
,
759 &(elem
->field_name
)))
766 /* Get the subname and modify the name accordingly, if it
771 char *subname
= NULL
;
774 if (!rec_parse_regexp (&p
,
783 /* Concatenate the field_name and the subname. */
784 elem
->field_name
= rec_concat_strings (elem
->field_name
, "_", subname
);
787 /* Get the subscripts if they are present. */
791 /* First subscript in range. */
792 if (!rec_parse_int (&p
, &(elem
->min
)))
796 free (elem
->field_name
);
803 /* Second subscript in range. */
804 if (!rec_parse_int (&p
, &(elem
->max
)))
808 free (elem
->field_name
);
817 free (elem
->field_name
);
820 p
++; /* Skip the ] */
823 if (elem
->function_name
)
825 p
++; /* Skip the ) */
828 /* Get the rewrite rule if it is present. */
832 if (!rec_parse_regexp (&p
,
834 &(elem
->rewrite_to
)))
838 free (elem
->field_name
);
846 free (elem
->field_name
);
847 free (elem
->rewrite_to
);
854 /* End of rec-fex.c */