root/usr/src/cmd/sort/initialize.c
/*
 * 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());
        }
}