/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 1998-2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include "initialize.h"

#ifndef TEXT_DOMAIN
/*
 * TEXT_DOMAIN should have been set by build environment.
 */
#define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
#endif /* TEXT_DOMAIN */

/*
 * /dev/zero, output file, stdin, stdout, and stderr
 */
#define	N_FILES_ALREADY_OPEN	5

static const char *filename_stdin = "STDIN";
const char *filename_stdout = "STDOUT";

static sigjmp_buf signal_jmp_buf;
static volatile sig_atomic_t signal_delivered;

static void
set_signal_jmp(void)
{
	if (sigsetjmp(signal_jmp_buf, 1))
		exit(127 + signal_delivered);
}

static void
sig_handler(int signo)
{
	signal_delivered = signo;
	siglongjmp(signal_jmp_buf, 1);
}

void
initialize_pre(sort_t *S)
{
	/*
	 * Initialize sort structure.
	 */
	(void) memset(S, 0, sizeof (sort_t));

	S->m_stats = safe_realloc(NULL, sizeof (sort_statistics_t));
	__S(stats_init(S->m_stats));

	S->m_default_species = ALPHA;

	/*
	 * Simple localization issues.
	 */
	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

#ifndef DEBUG_FORCE_WIDE
	S->m_c_locale = xstreql("C", setlocale(LC_COLLATE, NULL));
	S->m_single_byte_locale = SGN(MB_CUR_MAX == 1);
#else /* DEBUG_FORCE_WIDE */
	S->m_c_locale = 0;
	S->m_single_byte_locale = 0;
#endif /* DEBUG_FORCE_WIDE */

	/*
	 * We use a constant seed so that our sorts on a given file are
	 * reproducible.
	 */
	srand(3459871433U);

	if (atexit(atexit_handler) < 0)
		warn(gettext("atexit() handler installation failed"));

	/*
	 * Establish signal handlers and sufficient state for clean up.
	 */
	if (signal(SIGTERM, sig_handler) == SIG_ERR)
		die(EMSG_SIGNAL, "SIGTERM");
	if (signal(SIGHUP, sig_handler) == SIG_ERR)
		die(EMSG_SIGNAL, "SIGHUP");
	if (signal(SIGPIPE, sig_handler) == SIG_ERR)
		die(EMSG_SIGNAL, "SIGPIPE");

	set_signal_jmp();
}

static int
strcoll_cmp(void *s1, void *s2, flag_t f __unused)
{
	return (strcoll(s1, s2));
}

static int
wcscoll_cmp(void *s1, void *s2, flag_t f __unused)
{
	return (wcscoll(s1, s2));
}

void
initialize_post(sort_t *S)
{
	field_t	*F;

	S->m_memory_available = available_memory(S->m_memory_limit);

	set_file_template(&S->m_tmpdir_template);

	/*
	 * Initialize locale-specific ops vectors.
	 */
	field_initialize(S);

	if (S->m_single_byte_locale) {
		S->m_compare_fn = strcoll_cmp;
		S->m_coll_convert = field_convert;
		F = S->m_fields_head;

		while (F != NULL) {
			switch (F->f_species) {
			case ALPHA:
				if (F->f_options &
				    (FIELD_IGNORE_NONPRINTABLES |
				    FIELD_DICTIONARY_ORDER |
				    FIELD_FOLD_UPPERCASE))
					F->f_convert = field_convert_alpha;
				else
					F->f_convert =
					    field_convert_alpha_simple;
				break;
			case NUMERIC:
				F->f_convert = field_convert_numeric;
				break;
			case MONTH:
				F->f_convert = field_convert_month;
				break;
			default:
				die(EMSG_UNKN_FIELD, F->f_species);
				break;
			}
			F = F->f_next;
		}
	} else {
		S->m_compare_fn = wcscoll_cmp;
		S->m_coll_convert = field_convert_wide;

		F = S->m_fields_head;
		while (F != NULL) {
			switch (F->f_species) {
			case ALPHA:
				F->f_convert = field_convert_alpha_wide;
				break;
			case NUMERIC:
				F->f_convert =
				    field_convert_numeric_wide;
				break;
			case MONTH:
				F->f_convert = field_convert_month_wide;
				break;
			default:
				die(EMSG_UNKN_FIELD, F->f_species);
				break;
			}
			F = F->f_next;
		}
	}

	/*
	 * Validate and obtain sizes, inodes for input streams.
	 */
	stream_stat_chain(S->m_input_streams);
	__S(stats_set_input_files(stream_count_chain(S->m_input_streams)));

	/*
	 * Output guard.
	 */
	establish_output_guard(S);

	/*
	 * Ready stdin for usage as stream.
	 */
	if (S->m_input_from_stdin) {
		stream_t *str;

		if (S->m_single_byte_locale) {
			str = stream_new(STREAM_SINGLE | STREAM_NOTFILE);
			str->s_element_size = sizeof (char);
		} else {
			str = stream_new(STREAM_WIDE | STREAM_NOTFILE);
			str->s_element_size = sizeof (wchar_t);
		}
		str->s_filename = (char *)filename_stdin;
		stream_push_to_chain(&S->m_input_streams, str);
		__S(stats_incr_input_files());
	}
}