4 * Date: Wed Dec 22 18:20:20 2010
6 * GNU recutils - recfmt
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/>.
34 #define _(str) gettext (str)
39 /* Forward prototypes. */
40 void recfmt_parse_args (int argc
, char **argv
);
41 bool recfmt_process_data (rec_db_t db
);
42 void recfmt_process_db (rec_db_t db
, char *template);
43 char *recfmt_apply_template (rec_record_t record
, char *template);
44 char *recfmt_get_subst (rec_record_t record
, char *str
);
50 char *recfmt_template
= NULL
;
53 * Command line options management.
62 static const struct option GNU_longOptions
[] =
65 {"file", required_argument
, NULL
, FILE_ARG
},
74 recutl_print_help (void)
76 /* TRANSLATORS: --help output, recfmt synopsis.
79 Usage: recfmt [OPTION]... [TEMPLATE]\n"));
81 /* TRANSLATORS: --help output, recfmt arguments.
84 Apply a template to records read from standard input.\n"), stdout
);
87 /* TRANSLATORS: --help output, recfmt arguments.
90 -f, --file=FILENAME read the template to apply from a file.\n"),
93 recutl_print_help_common ();
95 recutl_print_help_footer ();
99 recfmt_parse_args (int argc
,
105 while ((ret
= getopt_long (argc
,
118 /* Read the template from the specified file and store it
119 in recfmt_template. */
120 recfmt_template
= recutl_read_file (optarg
);
121 if (!recfmt_template
)
123 recutl_fatal (_("can't open file %s for reading.\n"),
136 /* See if the template is specified in the command line. */
141 recutl_fatal (_("don't specify a template in the command line and -f at the same time.\n"));
144 if ((argc
- optind
) != 1)
146 recutl_print_help ();
150 recfmt_template
= xstrdup (argv
[optind
++]);
155 recfmt_get_subst (rec_record_t record
,
161 sex
= rec_sex_new (false);
162 if (!rec_sex_compile (sex
, str
))
164 recutl_fatal (_("invalid expression in a template slot.\n"));
167 res
= rec_sex_eval_str (sex
, record
);
170 recutl_fatal (_("error evaluating expression in a template slot.\n"));
173 rec_sex_destroy (sex
);
179 recfmt_apply_template (rec_record_t record
,
182 rec_buf_t result_buf
;
192 /* Replace occurrences of:
196 where Name[N] is the name of a field with an optional subscript.
197 If the subscript is not present then it is assumed to be 0. If
198 the contents between {{...}} are not a field name then replace the
199 slot with the empty string.
202 if (regcomp (®exp
, "\\{\\{" "[^}]*" "\\}\\}", REG_EXTENDED
) != 0)
204 recutl_fatal (_("recfmt_apply_template: error compiling regexp. Please report this.\n"));
207 result_buf
= rec_buf_new (&result
, &result_size
);
210 && (regexec (®exp
, p
, 1, &matches
, 0) == 0)
211 && (matches
.rm_so
!= -1))
213 /* Add the prolog, if any. */
214 if (matches
.rm_so
> 0)
216 tmp
= xmalloc (matches
.rm_so
+ 1);
217 memcpy (tmp
, p
, matches
.rm_so
);
218 tmp
[matches
.rm_so
] = '\0';
219 rec_buf_puts (tmp
, result_buf
);
224 tmp_size
= matches
.rm_eo
- matches
.rm_so
- 4;
225 tmp
= xmalloc (tmp_size
+ 1);
226 memcpy (tmp
, p
+ matches
.rm_so
+ 2, tmp_size
);
227 tmp
[tmp_size
] = '\0';
230 p
= p
+ matches
.rm_eo
;
232 /* Get the substitution text and append it to the result. */
233 subst_str
= recfmt_get_subst (record
, tmp
);
236 rec_buf_puts (subst_str
, result_buf
);
242 /* Add the epilog, if any. */
245 rec_buf_puts (p
, result_buf
);
248 rec_buf_close (result_buf
);
254 recfmt_process_db (rec_db_t db
, char *template)
260 rec_mset_iterator_t iter
;
262 /* Iterate on all the record sets. */
263 for (n_rset
= 0; n_rset
< rec_db_size (db
); n_rset
++)
265 rset
= rec_db_get_rset (db
, n_rset
);
267 /* Iterate on all the records. */
269 iter
= rec_mset_iterator (rec_rset_mset (rset
));
270 while (rec_mset_iterator_next (&iter
, MSET_RECORD
, (const void**) &record
, NULL
))
272 /* Apply the template to this record. */
273 result
= recfmt_apply_template (record
, template);
274 if (result
&& (*result
!= '\0'))
276 printf ("%s", result
);
281 rec_mset_iterator_free (&iter
);
286 main (int argc
, char *argv
[])
290 recutl_init ("recfmt");
292 recfmt_parse_args (argc
, argv
);
294 db
= recutl_read_db_from_file (NULL
);
295 if (db
&& recfmt_template
)
297 recfmt_process_db (db
, recfmt_template
);
303 /* End of recfmt.c */