159 lines
5.0 KiB
C
159 lines
5.0 KiB
C
/* -*- 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <bash/config.h>
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
#include <rec.h>
|
|
|
|
#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 */
|
|
};
|