248 lines
6.5 KiB
C
248 lines
6.5 KiB
C
/* recdel.c - Deleting records. */
|
|
|
|
/* Copyright (C) 2009-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 <getopt.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <gettext.h>
|
|
#define _(str) gettext (str)
|
|
#include <xalloc.h>
|
|
|
|
#include <rec.h>
|
|
#include <recutl.h>
|
|
|
|
/*
|
|
* Global variables
|
|
*/
|
|
|
|
char *recutl_type = NULL;
|
|
bool recdel_comment = false;
|
|
rec_sex_t recutl_sex = NULL;
|
|
char *recutl_quick_str = NULL;
|
|
char *recutl_sex_str = NULL;
|
|
bool recutl_insensitive = false;
|
|
bool recdel_force = false;
|
|
bool recdel_verbose = false;
|
|
bool recdel_external = true;
|
|
size_t recutl_random = 0;
|
|
char *recdel_file = NULL; /* File from where to delete the
|
|
records. */
|
|
|
|
/*
|
|
* Command line options management
|
|
*/
|
|
|
|
enum
|
|
{
|
|
COMMON_ARGS,
|
|
RECORD_SELECTION_ARGS,
|
|
COMMENT_ARG,
|
|
FORCE_ARG,
|
|
VERBOSE_ARG,
|
|
NO_EXTERNAL_ARG
|
|
};
|
|
|
|
static const struct option GNU_longOptions[] =
|
|
{
|
|
COMMON_LONG_ARGS,
|
|
RECORD_SELECTION_LONG_ARGS,
|
|
{"comment", no_argument, NULL, COMMENT_ARG},
|
|
{"force", no_argument, NULL, FORCE_ARG},
|
|
{"verbose", no_argument, NULL, VERBOSE_ARG},
|
|
{"no-external", no_argument, NULL, NO_EXTERNAL_ARG},
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
|
|
void
|
|
recutl_print_help (void)
|
|
{
|
|
/* TRANSLATORS: --help output, recdel synopsis.
|
|
no-wrap */
|
|
printf (_("\
|
|
Usage: recdel [OPTIONS]... [-t TYPE] [-n NUM | -e RECORD_EXPR | -q STR | -m NUM] [FILE]\n"));
|
|
|
|
/* TRANSLATORS: --help output, recdel short description.
|
|
no-wrap */
|
|
fputs (_("\
|
|
Remove (or comment out) records from a rec file.\n"),
|
|
stdout);
|
|
|
|
puts ("");
|
|
/* TRANSLATORS: --help output, recdel arguments.
|
|
no-wrap */
|
|
fputs (_("\
|
|
-c, --comment comment out the matching records instead of\n\
|
|
deleting them.\n\
|
|
--force delete even in potentially dangerous situations,\n\
|
|
and if the deletion is violating record restrictions.\n\
|
|
--no-external don't use external descriptors.\n\
|
|
--verbose give a detailed report if the integrity check\n\
|
|
fails.\n"),
|
|
stdout);
|
|
|
|
recutl_print_help_common ();
|
|
|
|
puts ("");
|
|
recutl_print_help_record_selection ();
|
|
|
|
puts ("");
|
|
/* TRANSLATORS: --help output, notes on recdel.
|
|
no-wrap */
|
|
fputs (_("\
|
|
If no FILE is specified then the command acts like a filter, getting\n\
|
|
the data from standard input and writing the result to standard output.\n"),
|
|
stdout);
|
|
|
|
puts ("");
|
|
recutl_print_help_footer ();
|
|
}
|
|
|
|
void
|
|
recdel_delete_records (rec_db_t db)
|
|
{
|
|
/* Make sure that the user selected an existing record set from
|
|
which to delete records. */
|
|
if (!rec_db_type_p (db, recutl_type))
|
|
recutl_fatal (_("no records of type %s found.\n"),
|
|
recutl_type ? recutl_type : "<default>");
|
|
|
|
/* Invoke the library to perform the requested deletions. */
|
|
{
|
|
int flags = 0;
|
|
|
|
if (recutl_insensitive)
|
|
flags = flags | REC_F_ICASE;
|
|
|
|
if (recdel_comment)
|
|
flags = flags | REC_F_COMMENT_OUT;
|
|
|
|
if (!rec_db_delete (db,
|
|
recutl_type,
|
|
recutl_index (),
|
|
recutl_sex,
|
|
recutl_quick_str,
|
|
recutl_random,
|
|
flags))
|
|
recutl_out_of_memory ();
|
|
}
|
|
|
|
|
|
/* Check the integrity of the resulting database. */
|
|
if (!recdel_force && db)
|
|
recutl_check_integrity (db, recdel_verbose, recdel_external);
|
|
}
|
|
|
|
void
|
|
recdel_parse_args (int argc,
|
|
char **argv)
|
|
{
|
|
int ret;
|
|
char c;
|
|
|
|
while ((ret = getopt_long (argc,
|
|
argv,
|
|
RECORD_SELECTION_SHORT_ARGS
|
|
"c",
|
|
GNU_longOptions,
|
|
NULL)) != -1)
|
|
{
|
|
c = ret;
|
|
switch (c)
|
|
{
|
|
COMMON_ARGS_CASES
|
|
RECORD_SELECTION_ARGS_CASES
|
|
case FORCE_ARG:
|
|
recdel_force = true;
|
|
break;
|
|
case VERBOSE_ARG:
|
|
recdel_verbose = true;
|
|
break;
|
|
case NO_EXTERNAL_ARG:
|
|
recdel_external = false;
|
|
break;
|
|
case COMMENT_ARG:
|
|
case 'c':
|
|
recdel_comment = true;
|
|
break;
|
|
default:
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
/* Require the usage of --force for potentially dangerous
|
|
operations, such as the request of deleting a whole record
|
|
set. */
|
|
|
|
if ((recutl_num_indexes() == 0) && !recutl_sex_str && !recutl_quick_str
|
|
&& !recdel_force && (recutl_random == 0))
|
|
{
|
|
recutl_error (_("ignoring a request to delete all records of type %s.\n"),
|
|
recutl_type ? recutl_type : "unknown");
|
|
recutl_fatal (_("use --force if you really want to proceed,\
|
|
or use either -n or -e.\n"));
|
|
}
|
|
|
|
if (recutl_sex_str)
|
|
{
|
|
recutl_sex = rec_sex_new (recutl_insensitive);
|
|
if (!rec_sex_compile (recutl_sex, recutl_sex_str))
|
|
recutl_fatal (_("invalid selection expression.\n"));
|
|
}
|
|
|
|
/* Read the name of the file where to delete the records. */
|
|
if (optind < argc)
|
|
{
|
|
if ((argc - optind) != 1)
|
|
{
|
|
recutl_print_help ();
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
recdel_file = argv[optind++];
|
|
}
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
rec_db_t db;
|
|
|
|
recutl_init ("recdel");
|
|
|
|
recdel_parse_args (argc, argv);
|
|
|
|
db = recutl_read_db_from_file (recdel_file);
|
|
if (!db)
|
|
recutl_fatal (_("cannot read file %s\n"), recdel_file);
|
|
|
|
if (((recutl_num_indexes() != 0) || recutl_sex || recutl_quick_str)
|
|
|| recdel_force || (recutl_random > 0))
|
|
recdel_delete_records (db);
|
|
|
|
if (!recutl_file_is_writable (recdel_file))
|
|
{
|
|
recutl_error (_("file %s is not writable.\n"), recdel_file);
|
|
return EXIT_FAILURE;
|
|
}
|
|
recutl_write_db_to_file (db, recdel_file);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|