/* -*- mode: C -*-
*
* File: readrec.c
* Date: Fri Aug 23 18:38:08 2013
*
* GNU recutils - readrec bash loadable builtin.
*
*/
/* Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2022
* Jose E. Marchesi */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include "builtins.h"
#include "shell.h"
#include "common.h"
#include "builtins/bashgetopt.h"
/* The function implementing the builtin. It uses internal_getopt to
parse options. It is the same as getopt(3), but it takes a pointer
to a WORD_LIST.
If the builtin takes no options, call no_options(list) before doing
anything else. If it returns a non-zero value, your builtin should
immediately return EX_USAGE.
A builtin command returns EXECUTION_SUCCESS for success and
EXECUTION_FAILURE to indicate failure. */
int
readrec_builtin (WORD_LIST *list)
{
SHELL_VAR *var;
rec_parser_t parser;
rec_record_t record;
if (no_options (list) != 0)
return EX_USAGE;
/* Create a librec parser to operate on the standard input and try
to read a record. If there is a parse error then report it and
fail. */
parser = rec_parser_new (stdin, "stdin");
if (!parser)
return EXECUTION_FAILURE;
if (!rec_parse_record (parser, &record))
{
return EXECUTION_FAILURE;
}
{
size_t record_str_size = 0;
char *record_str = NULL;
char *record_str_dequoted = NULL;
rec_writer_t writer = rec_writer_new_str (&record_str, &record_str_size);
if (!writer || !rec_write_record (writer, record))
return EXIT_FAILURE;
rec_writer_destroy (writer);
/* Set the REPLY_REC environment variable to the read record. */
record_str_dequoted = dequote_string (record_str);
var = bind_variable ("REPLY_REC", record_str_dequoted, 0);
VUNSETATTR (var, att_invisible);
xfree (record_str_dequoted);
/* Set the environment variables for the fields. */
{
rec_field_t field = NULL;
rec_mset_iterator_t iter = rec_mset_iterator (rec_record_mset (record));
// rec_record_reset_marks (record);
while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **) &field, NULL))
{
char *var_name = rec_field_name (field);
size_t num_fields = rec_record_get_num_fields_by_name (record, var_name);
// if (rec_record_field_mark (record, field))
// continue;
#if defined ARRAY_VARS
if (num_fields > 1)
{
/* In case several fields share the same field name, create
an array variable containing all the values. */
size_t i = 0;
for (; i < num_fields; i++)
{
// rec_record_mark_field (record, field, true);
field = rec_record_get_field_by_name (record, var_name, i);
var = bind_array_variable (var_name, i, rec_field_value (field), 0);
VUNSETATTR (var, att_invisible);
}
}
else
{
/* Bind a normal variable. */
char *var_value = rec_field_value (field);
var = bind_variable (var_name, var_value, 0);
VUNSETATTR (var, att_invisible);
}
#endif /* ARRAY_VARS */
}
rec_mset_iterator_free (&iter);
}
}
return EXECUTION_SUCCESS;
}
/* An array of strings forming the `long' documentation for the builtin,
which is printed by `help xxx'. It must end with a NULL. By convention,
the first line is a short description. */
char *readrec_doc[] = {
"Read a recutils record from the standard input.",
"",
"The read record is stored in the REPLY_REC variable. Additional variables",
"are set named after the fields in the record.",
"",
"Exit Status:",
"The return code is zero, unless end-of-file is encountered.",
(char *) NULL
};
/* The standard structure describing a builtin command. bash keeps an
array of these structures. The flags must include BUILTIN_ENABLED
so the builtin can be used. */
struct builtin readrec_struct = {
"readrec", /* builtin name */
readrec_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
readrec_doc, /* array of long documentation strings. */
"readrec", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};