aboutsummaryrefslogtreecommitdiff
path: root/src/lzma/main.c
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2008-11-19 23:52:24 +0200
committerLasse Collin <lasse.collin@tukaani.org>2008-11-19 23:52:24 +0200
commit1880a3927b23f265f63b2adb86fbdb81ea09eb06 (patch)
tree2fe1b65d21f81b28f46eb707378d97f553e99ee1 /src/lzma/main.c
parentOh well, big messy commit again. Some highlights: (diff)
downloadxz-1880a3927b23f265f63b2adb86fbdb81ea09eb06.tar.xz
Renamed lzma to xz and lzmadec to xzdec. We create symlinks
lzma, unlzma, and lzcat in "make install" for backwards compatibility with LZMA Utils 4.32.x; I'm not sure if this should be the default though.
Diffstat (limited to 'src/lzma/main.c')
-rw-r--r--src/lzma/main.c402
1 files changed, 0 insertions, 402 deletions
diff --git a/src/lzma/main.c b/src/lzma/main.c
deleted file mode 100644
index 4e24b98d..00000000
--- a/src/lzma/main.c
+++ /dev/null
@@ -1,402 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file main.c
-/// \brief main()
-//
-// Copyright (C) 2007 Lasse Collin
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 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
-// Lesser General Public License for more details.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include "private.h"
-#include "open_stdxxx.h"
-#include <ctype.h>
-
-
-volatile sig_atomic_t user_abort = false;
-
-/// Exit status to use. This can be changed with set_exit_status().
-static enum exit_status_type exit_status = E_SUCCESS;
-
-/// If we were interrupted by a signal, we store the signal number so that
-/// we can raise that signal to kill the program when all cleanups have
-/// been done.
-static volatile sig_atomic_t exit_signal = 0;
-
-/// Mask of signals for which have have established a signal handler to set
-/// user_abort to true.
-static sigset_t hooked_signals;
-
-/// signals_block() and signals_unblock() can be called recursively.
-static size_t signals_block_count = 0;
-
-
-static void
-signal_handler(int sig)
-{
- exit_signal = sig;
- user_abort = true;
- return;
-}
-
-
-static void
-establish_signal_handlers(void)
-{
- // List of signals for which we establish the signal handler.
- static const int sigs[] = {
- SIGINT,
- SIGTERM,
-#ifdef SIGHUP
- SIGHUP,
-#endif
-#ifdef SIGPIPE
- SIGPIPE,
-#endif
-#ifdef SIGXCPU
- SIGXCPU,
-#endif
-#ifdef SIGXFSZ
- SIGXFSZ,
-#endif
- };
-
- // Mask of the signals for which we have established a signal handler.
- sigemptyset(&hooked_signals);
- for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i)
- sigaddset(&hooked_signals, sigs[i]);
-
- struct sigaction sa;
-
- // All the signals that we handle we also blocked while the signal
- // handler runs.
- sa.sa_mask = hooked_signals;
-
- // Don't set SA_RESTART, because we want EINTR so that we can check
- // for user_abort and cleanup before exiting. We block the signals
- // for which we have established a handler when we don't want EINTR.
- sa.sa_flags = 0;
- sa.sa_handler = &signal_handler;
-
- for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) {
- // If the parent process has left some signals ignored,
- // we don't unignore them.
- struct sigaction old;
- if (sigaction(sigs[i], NULL, &old) == 0
- && old.sa_handler == SIG_IGN)
- continue;
-
- // Establish the signal handler.
- if (sigaction(sigs[i], &sa, NULL))
- message_signal_handler();
- }
-
- return;
-}
-
-
-extern void
-signals_block(void)
-{
- if (signals_block_count++ == 0) {
- const int saved_errno = errno;
- sigprocmask(SIG_BLOCK, &hooked_signals, NULL);
- errno = saved_errno;
- }
-
- return;
-}
-
-
-extern void
-signals_unblock(void)
-{
- assert(signals_block_count > 0);
-
- if (--signals_block_count == 0) {
- const int saved_errno = errno;
- sigprocmask(SIG_UNBLOCK, &hooked_signals, NULL);
- errno = saved_errno;
- }
-
- return;
-}
-
-
-extern void
-set_exit_status(enum exit_status_type new_status)
-{
- assert(new_status == E_WARNING || new_status == E_ERROR);
-
- if (exit_status != E_ERROR)
- exit_status = new_status;
-
- return;
-}
-
-
-extern void
-my_exit(enum exit_status_type status)
-{
- // Close stdout. If something goes wrong, print an error message
- // to stderr.
- {
- const int ferror_err = ferror(stdout);
- const int fclose_err = fclose(stdout);
- if (ferror_err || fclose_err) {
- // If it was fclose() that failed, we have the reason
- // in errno. If only ferror() indicated an error,
- // we have no idea what the reason was.
- message(V_ERROR, _("Writing to standard output "
- "failed: %s"),
- fclose_err ? strerror(errno)
- : _("Unknown error"));
- status = E_ERROR;
- }
- }
-
- // Close stderr. If something goes wrong, there's nothing where we
- // could print an error message. Just set the exit status.
- {
- const int ferror_err = ferror(stderr);
- const int fclose_err = fclose(stderr);
- if (fclose_err || ferror_err)
- status = E_ERROR;
- }
-
- // If we have got a signal, raise it to kill the program.
- const int sig = exit_signal;
- if (sig != 0) {
- struct sigaction sa;
- sa.sa_handler = SIG_DFL;
- sigfillset(&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction(sig, &sa, NULL);
- raise(exit_signal);
-
- // If, for some weird reason, the signal doesn't kill us,
- // we safely fall to the exit below.
- }
-
- exit(status);
-}
-
-
-static const char *
-read_name(const args_info *args)
-{
- // FIXME: Maybe we should have some kind of memory usage limit here
- // like the tool has for the actual compression and uncompression.
- // Giving some huge text file with --files0 makes us to read the
- // whole file in RAM.
- static char *name = NULL;
- static size_t size = 256;
-
- // Allocate the initial buffer. This is never freed, since after it
- // is no longer needed, the program exits very soon. It is safe to
- // use xmalloc() and xrealloc() in this function, because while
- // executing this function, no files are open for writing, and thus
- // there's no need to cleanup anything before exiting.
- if (name == NULL)
- name = xmalloc(size);
-
- // Write position in name
- size_t pos = 0;
-
- // Read one character at a time into name.
- while (!user_abort) {
- const int c = fgetc(args->files_file);
-
- if (ferror(args->files_file)) {
- // Take care of EINTR since we have established
- // the signal handlers already.
- if (errno == EINTR)
- continue;
-
- message_error(_("%s: Error reading filenames: %s"),
- args->files_name, strerror(errno));
- return NULL;
- }
-
- if (feof(args->files_file)) {
- if (pos != 0)
- message_error(_("%s: Unexpected end of input "
- "when reading filenames"),
- args->files_name);
-
- return NULL;
- }
-
- if (c == args->files_delim) {
- // We allow consecutive newline (--files) or '\0'
- // characters (--files0), and ignore such empty
- // filenames.
- if (pos == 0)
- continue;
-
- // A non-empty name was read. Terminate it with '\0'
- // and return it.
- name[pos] = '\0';
- return name;
- }
-
- if (c == '\0') {
- // A null character was found when using --files,
- // which expects plain text input separated with
- // newlines.
- message_error(_("%s: Null character found when "
- "reading filenames; maybe you meant "
- "to use `--files0' instead "
- "of `--files'?"), args->files_name);
- return NULL;
- }
-
- name[pos++] = c;
-
- // Allocate more memory if needed. There must always be space
- // at least for one character to allow terminating the string
- // with '\0'.
- if (pos == size) {
- size *= 2;
- name = xrealloc(name, size);
- }
- }
-
- return NULL;
-}
-
-
-int
-main(int argc, char **argv)
-{
- // Make sure that stdin, stdout, and and stderr are connected to
- // a valid file descriptor. Exit immediatelly with exit code ERROR
- // if we cannot make the file descriptors valid. Maybe we should
- // print an error message, but our stderr could be screwed anyway.
- open_stdxxx(E_ERROR);
-
- // This has to be done before calling any liblzma functions.
- lzma_init();
-
- // Set up the locale.
- setlocale(LC_ALL, "");
-
-#ifdef ENABLE_NLS
- // Set up the message translations too.
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-#endif
-
- // Set the program invocation name used in various messages, and
- // do other message handling related initializations.
- message_init(argv[0]);
-
- // Set hardware-dependent default values. These can be overriden
- // on the command line, thus this must be done before parse_args().
- hardware_init();
-
- // Parse the command line arguments and get an array of filenames.
- // This doesn't return if something is wrong with the command line
- // arguments. If there are no arguments, one filename ("-") is still
- // returned to indicate stdin.
- args_info args;
- args_parse(&args, argc, argv);
-
- // Tell the message handling code how many input files there are if
- // we know it. This way the progress indicator can show it.
- if (args.files_name != NULL)
- message_set_files(0);
- else
- message_set_files(args.arg_count);
-
- // Refuse to write compressed data to standard output if it is
- // a terminal and --force wasn't used.
- if (opt_mode == MODE_COMPRESS) {
- if (opt_stdout || (args.arg_count == 1
- && strcmp(args.arg_names[0], "-") == 0)) {
- if (is_tty_stdout()) {
- message_try_help();
- my_exit(E_ERROR);
- }
- }
- }
-
- if (opt_mode == MODE_LIST) {
- message_fatal("--list is not implemented yet.");
- }
-
- // Hook the signal handlers. We don't need these before we start
- // the actual action, so this is done after parsing the command
- // line arguments.
- establish_signal_handlers();
-
- // Process the files given on the command line. Note that if no names
- // were given, parse_args() gave us a fake "-" filename.
- for (size_t i = 0; i < args.arg_count && !user_abort; ++i) {
- if (strcmp("-", args.arg_names[i]) == 0) {
- // Processing from stdin to stdout. Unless --force
- // was used, check that we aren't writing compressed
- // data to a terminal or reading it from terminal.
- if (!opt_force) {
- if (opt_mode == MODE_COMPRESS) {
- if (is_tty_stdout())
- continue;
- } else if (is_tty_stdin()) {
- continue;
- }
- }
-
- // It doesn't make sense to compress data from stdin
- // if we are supposed to read filenames from stdin
- // too (enabled with --files or --files0).
- if (args.files_name == stdin_filename) {
- message_error(_("Cannot read data from "
- "standard input when "
- "reading filenames "
- "from standard input"));
- continue;
- }
-
- // Replace the "-" with a special pointer, which is
- // recognized by process_file() and other things.
- // This way error messages get a proper filename
- // string and the code still knows that it is
- // handling the special case of stdin.
- args.arg_names[i] = (char *)stdin_filename;
- }
-
- // Do the actual compression or uncompression.
- process_file(args.arg_names[i]);
- }
-
- // If --files or --files0 was used, process the filenames from the
- // given file or stdin. Note that here we don't consider "-" to
- // indicate stdin like we do with the command line arguments.
- if (args.files_name != NULL) {
- // read_name() checks for user_abort so we don't need to
- // check it as loop termination condition.
- while (true) {
- const char *name = read_name(&args);
- if (name == NULL)
- break;
-
- // read_name() doesn't return empty names.
- assert(name[0] != '\0');
- process_file(name);
- }
-
- if (args.files_name != stdin_filename)
- (void)fclose(args.files_file);
- }
-
- my_exit(exit_status);
-}