root/usr/src/cmd/geniconvtbl/itm_util.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 (c) 1999 by Sun Microsystems, Inc.
 * All rights reserved.
 * Copyright 2015 PALO, Richard.
 */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <libintl.h>
#include <strings.h>
#include "iconv_tm.h"
#include "itmcomp.h"
#include "itm_util.h"
#include "hash.h"
#include "maptype.h"


static size_t   map_table_resultlen(itmc_map_t *);
static int      data_pair_compare(itmc_data_pair_t **, itmc_data_pair_t **);
static long     data_to_long(itm_data_t *);

static itm_tbl_hdr_t    *map_table_indexed_fixed(itmc_data_pair_t **,
                                itm_size_t, itm_data_t *, long, itm_num_t);
static itm_tbl_hdr_t    *map_table_dense_encoding(itmc_data_pair_t **,
                                itm_size_t, itm_data_t *, unsigned long,
                                unsigned char *, unsigned char *, long,
                                itm_num_t);
static itm_tbl_hdr_t    *map_table_lookup_fixed(itmc_data_pair_t **,
                                itm_size_t, itm_data_t *, long, itm_size_t);
static itm_tbl_hdr_t    *map_table_hash(itmc_data_pair_t **, itm_size_t,
                                itm_data_t *, long, long, itm_size_t,
                                itm_num_t);
static itm_tbl_hdr_t    *map_table_lookup_var();
static void             put_dense_encoding_default(char *, unsigned char *,
                        unsigned char *, unsigned char *, long, long, long);
static size_t           map_table_resultlen(itmc_map_t *);
static void             map_range_adjust_byte_seq(unsigned char *,
                                unsigned char *, long, itmc_data_pair_t *);
static void             map_range_make_result(char *, itm_size_t, itm_size_t,
                                char *, itm_size_t);
static size_t           map_table_num_range(itmc_data_pair_t *);
static itmc_map_type_t  check_map_type(itmc_map_attr_t *);


static itmc_name_t      *name_lookup(itm_data_t *, itm_type_t);
static itmc_name_t      *name_refer(itm_data_t *, itm_type_t, itmc_ref_t *);
static itmc_name_t      *name_register(itm_data_t *, itm_type_t, itmc_ref_t *);
static void             op_hirarchy(itm_tbl_hdr_t *, itmc_obj_t *);
static obj_array_t      obj_list_to_array(itm_size_t, itmc_obj_t *, itm_size_t);


void
itm_def_process(itm_data_t      *itm_name)
{
        itm_hdr_t       *itm_hdr;
        long            len;

        TRACE_MESSAGE('y', ("itm_def_process\n"));


        itm_hdr = malloc_vital(sizeof (itm_hdr_t));
        (void) memset(itm_hdr, 0, sizeof (itm_hdr_t));

        if ((NULL != cmd_opt.interpreter) &&
            (0 < (len = strlen(cmd_opt.interpreter)))) {
                itm_hdr->interpreter = *(str_to_data(len, cmd_opt.interpreter));
        }
        if ((sizeof (itm_place_t)) < itm_hdr->interpreter.size) {
                (void) obj_register(ITMC_OBJ_STRING, NULL,
                    (void *)itm_hdr->interpreter.place.itm_ptr,
                    itm_hdr->interpreter.size,
                    &(itm_hdr->interpreter.place),
                    OBJ_REG_HEAD);
        }

        itm_hdr->type_id = *itm_name;
        if ((sizeof (itm_place_t)) < itm_hdr->type_id.size) {
                (void) obj_register(ITMC_OBJ_STRING, NULL,
                    (void *)itm_hdr->type_id.place.itm_ptr,
                    itm_hdr->type_id.size,
                    &(itm_hdr->type_id.place),
                    OBJ_REG_HEAD);
        }

        (void) assemble(itm_hdr);
}



itmc_obj_t *
direction_unit(
        itmc_ref_t      *cond,
        itm_data_t      *cond_name,
        itmc_action_t   *act,
        itm_data_t      *act_name)
{
        itmc_obj_t      *du;
        itm_direc_t     *direc;

        du = malloc_vital(sizeof (itmc_obj_t));
        du->type = ITMC_OBJ_DIREC;
        du->name = NULL;
        du->obj = direc = malloc_vital(sizeof (itm_direc_t));

        if (NULL != cond) {
                direc->condition.itm_ptr = (uintptr_t)NULL;
                cond->referencer = &(direc->condition);
                du->ref[0] = cond;
        } else if (NULL != cond_name) {
                direc->condition.itm_ptr = (itm_place2_t)(cond_name);
                du->ref[0] = obj_register(ITMC_OBJ_COND, cond_name, NULL, 0,
                    &(direc->condition), OBJ_REG_TAIL);
        } else {
                direc->condition.itm_ptr = 0;
                du->ref[0] = NULL;
        }


        if (NULL != act_name) {
                direc->action.itm_ptr = (itm_place2_t)(act_name);
                du->ref[1] = obj_register(ITMC_OBJ_ACTION, act_name, NULL, 0,
                    &(direc->action), OBJ_REG_TAIL);
        } else if (NULL != act && act->tbl_hdr != NULL) {
                direc->action.itm_ptr = (itm_place2_t)(act->tbl_hdr);
                du->ref[1] = obj_register(act->type,
                    (itm_data_t *)(act->tbl_hdr->name.itm_ptr),
                    act->tbl_hdr, act->tbl_hdr->size,
                    &(direc->action), OBJ_REG_TAIL);
        } else {
                return (NULL);
        }

        du->ref[2] = NULL;
        return  (du);
}



itm_tbl_hdr_t *
obj_table(itm_type_t    tbl_type,
        itm_data_t      *name,
        itmc_obj_t      *obj_list,
        itm_size_t      obj_size)
{
        itm_tbl_hdr_t   *tbl;
        obj_array_t     obj_array;

        obj_array = obj_list_to_array(sizeof (itm_tbl_hdr_t),
            obj_list, obj_size);
        tbl = obj_array.obj;

        tbl->type = tbl_type;
        if (name) {
#if !defined(_LP64)
                tbl->name.itm_pad = 0;
#endif
                tbl->name.itm_ptr = (itm_place2_t)name;
        } else {
#if !defined(_LP64)
                tbl->name.itm_pad = 0;
#endif
                tbl->name.itm_ptr = (uintptr_t)NULL;
        }
        tbl->size = (sizeof (itm_tbl_hdr_t)) + (obj_array.num   *obj_size);
        tbl->number = obj_array.num;

        if ((ITM_TBL_MASK&tbl->type) == ITM_TBL_OP) {
                op_hirarchy(tbl, obj_list);
        }
        return  (tbl);
}

/*
 *
 */
static obj_array_t
obj_list_to_array(itm_size_t hdr_size, itmc_obj_t       *obj_list,
                        itm_size_t size)
{
        obj_array_t     obj_array;
        itm_size_t      offset;
        itmc_obj_t      *ol;

        for (obj_array.num = 0, ol = obj_list;
            ol; obj_array.num += 1, ol = ol->next) {
                /* NOP */;
        }

        obj_array.obj = malloc_vital(hdr_size + (size * obj_array.num));

        if (obj_array.num == 0)
                return  (obj_array);

        for (offset = hdr_size, ol = obj_list;
            ol; offset += size, ol = ol->next) {
                (void) memcpy((char *)(obj_array.obj) + offset, ol->obj, size);
                if (ol->ref[0]) {
                        ol->ref[0]->referencer =
                            (void *)((char *)(ol->ref[0]->referencer) +
                            ((char *)(obj_array.obj) -
                            (char *)(ol->obj) + offset));
                }
                if (ol->ref[1]) {
                        ol->ref[1]->referencer =
                            (void *)((char *)(ol->ref[1]->referencer) +
                            ((char *)(obj_array.obj) -
                            (char *)(ol->obj) + offset));
                }
                if (ol->ref[2]) {
                        ol->ref[2]->referencer =
                            (void *)((char *)(ol->ref[2]->referencer) +
                            ((char *)(obj_array.obj) -
                            (char *)(ol->obj) + offset));
                }
        }

        return  (obj_array);
}

static void
op_hirarchy(itm_tbl_hdr_t       *optbl,
        itmc_obj_t              *obj_list)
{
        itm_op_outer_t  *o;
        itm_op_inner_t  *in;
        itmc_obj_t      *ol;

        TRACE_MESSAGE('l', ("op_hirarchy (optbl=%x)\n", optbl));
        o = malloc_vital(sizeof (itm_op_outer_t));
        o->link = itm_op_outer;
        itm_op_outer = o;
        o->in = NULL;
        o->optbl = optbl;

        for (ol = obj_list; ol != NULL; ol = ol->next) {
                if ((ol->type == ITMC_OBJ_OP) &&
                    (((itm_op_t *)ol->obj)->type == ITM_OP_OPERATION)) {
                        in = malloc_vital(sizeof (itm_op_inner_t));
                        in->in = o->in;
                        o->in = in;
                        TRACE_MESSAGE('L', ("o->in(%x) in->in(%x)\n",
                            o->in, in->in));
                        in->ref = ol->ref[0];
                }
        }

#ifdef ENABLE_TRACE
        for (in = o->in; in != NULL; in = in->in) {
                TRACE_MESSAGE('L', ("o=%x in=%x in->in=%x\n",
                    o, in, in->in));
                TRACE_MESSAGE('L', ("o(table)%x->in(ref)=%x\n",
                    o->optbl, in->ref));
        }
#endif

}

itmc_obj_t *
obj_list_append(itmc_obj_t      *obj_list, itmc_obj_t   *obj)
{
        if (0 == obj) {
                return  (obj_list);
        }

        obj->next = NULL;
        obj->last = obj;

        if (obj_list) {
                obj_list->last->next = obj;
                obj_list->last = obj;
                return  (obj_list);
        } else {
                return  (obj);
        }
}


itmc_ref_t *
obj_register(itm_type_t type, itm_data_t        *name,
                void    *obj, size_t size, itm_place_t  *ref,
                itm_type_t reg_place)
{
        itmc_ref_t      *refp;

        TRACE_MESSAGE('O', ("obj_register: %6ld %08p %08p %08ld %08p %ld\n",
            type, name, obj, size, ref, reg_place));

        refp = malloc_vital(sizeof (itmc_ref_t));
        refp->name = NULL;
        refp->referencee = obj;
#if !defined(_LP64)
        refp->reloc.itm_pad = 0;
#endif
        refp->reloc.itm_ptr = 0;
        refp->size = size;
        refp->referencer = ref;
        refp->next = NULL;

        if (NULL == obj) { /* reference to named object */
                if (NULL == name) {
                        if (0 == error_deferred) {
                                /* should never happen */
                                itm_error(
                                    gettext("internal error: "
                                    "obj_register: (NULL == obj) "
                                    "&& (NULL == name)\n"));
                                exit(ITMC_STATUS_SYS2);
                        }
                        return (NULL);
                }
                refp->name = name_refer(name, type, refp);
                return  (refp);
        } else if ((NULL != name) && (0 < name->size)) {
                /* definition of named object */
                refp->name = name_register(name, type, refp);
        }

        if ((ITMC_OBJ_FIRST <= type) && (type <= ITMC_OBJ_LAST)) {
                switch (reg_place) {
                case OBJ_REG_HEAD:
                        refp->next = ref_first[type];
                        ref_first[type] = refp;
                        if (NULL == ref_last[type]) {
                                ref_last[type] = refp;
                        }
                        break;
                case OBJ_REG_TAIL:
                        if (ref_first[type]) {
                                ref_last[type]->next = refp;
                        } else {
                                ref_first[type] = refp;
                        }
                        ref_last[type] = refp;
                        break;
                }
        } else {
                itm_error(gettext("obj_register: illegal object type\n"));
                exit(ITMC_STATUS_SYS2);
        }

        return  (refp);
}


itm_tbl_hdr_t *
range_table(itm_data_t          *name, itmc_obj_t       *obj_list)
{
        itm_num_t               num;
        itmc_obj_t              *ol;
        itmc_data_pair_t        *rp;
        itm_range_hdr_t         *rh;
        itm_tbl_hdr_t           *table;
        itm_size_t              length = 0;
        itm_num_t               i;
        char                    *p;
        itm_size_t              table_size;

        /* count range, determine length */
        for (num = 0, ol = obj_list; ol; ol = ol->next, num++) {
                rp = (itmc_data_pair_t *)(ol->obj);
                if (length == 0) {
                        if (rp->data0.size == 0) {
                                itm_error(gettext("between has null range\n"));
                                error_deferred += 1;
                                return  (NULL);
                        }
                        length = rp->data0.size;
                }
                if ((rp->data0.size != length) ||
                    (rp->data1.size != length)) {
                        itm_error(gettext(
                            "length of source sequences must be the same\n"));
                        error_deferred += 1;
                        return  (NULL);
                }
        }
        if (num == 0) {
                itm_error(gettext("between has no ranges\n"));
                error_deferred += 1;
                return  (NULL);
        }
        table_size = ((sizeof (itm_tbl_hdr_t)) +
            (sizeof (itm_range_hdr_t)) + (length * num) * 2);
        table_size = ITMROUNDUP(table_size);

        table = malloc_vital(table_size);
        table->type = ITM_TBL_RANGE;
        if (NULL != name)
                table->name.itm_ptr = (itm_place2_t)name;
        table->size = table_size;
        table->number = num;

        rh = (itm_range_hdr_t *)(table + 1);
        rh->len = length;

        p = (char *)(rh + 1);
        for (ol = obj_list, i = 0; ol; ol = ol->next, i++) {
                rp = (itmc_data_pair_t *)(ol->obj);
                (void) memcpy(p, (NSPTR(&(rp->data0))), length);
                p += length;
                (void) memcpy(p, (NSPTR(&(rp->data1))), length);
                p += length;
        }

        return  (table);
}

/*
 *      escape sequence table for stateful code set sequence
 */
itm_tbl_hdr_t *
escseq_table(itm_data_t         *name, itmc_obj_t       *obj_list)
{
        itm_num_t               num;
        itmc_obj_t              *ol;
        itm_data_t              *ep;
        itm_escapeseq_hdr_t     *eh;
        itm_tbl_hdr_t           *table;
        itm_size_t              len_max = 0;
        itm_size_t              len_min;
        itm_num_t               i;
        itm_size_t              table_size;

        ol = obj_list;
        len_min = ((itm_data_t *)(ol->obj))->size;
        for (num = 0; NULL != ol; ol = ol->next, num++) {
                ep = (itm_data_t *)(ol->obj);
                if (ep->size < len_min)  len_min = ep->size;
                if (ep->size > len_max)  len_max = ep->size;
        }
        if (num == 0) {
                itm_error(gettext
                    ("escape sequence is defined without sequence\n"));
                error_deferred += 1;
                return  (NULL);
        } else if (0 == len_min) {
                itm_error(gettext("null sequence\n"));
                error_deferred += 1;
                return  (NULL);
        }

        table_size = ((sizeof (itm_tbl_hdr_t)) +
            (sizeof (itm_escapeseq_hdr_t)) +
            (sizeof (itm_data_t) * num));
        table_size = ITMROUNDUP(table_size);
        table = malloc_vital(table_size);
        table->type = ITM_TBL_ESCAPESEQ;
        if (NULL != name)
                table->name.itm_ptr = (itm_place2_t)name;
        table->size = table_size;
        table->number = num;

        eh = (itm_escapeseq_hdr_t *)(table + 1);
        eh->len_max = len_max;
        eh->len_min = len_min;

        for (ol = obj_list, ep = (itm_data_t *)(eh + 1);
            ol != NULL;
            ol = ol->next, ep++) {
                *ep = *((itm_data_t *)(ol->obj));
                if ((sizeof (itm_place_t)) < ep->size) {
                        (void) obj_register(ITMC_OBJ_DATA, NULL,
                            (void *)(ep->place.itm_ptr), ep->size,
                            &(ep->place), OBJ_REG_TAIL);
                }
        }
        (void) qsort((itm_data_t *)(eh + 1), num, sizeof (itm_data_t),
            (int (*)(const void *, const void *))data_compare);

        for (i = 0, ep = (itm_data_t *)(eh + 1);
            i < num - 1;
            i++, ep++) {
                if (0 <= data_compare(ep, (ep + 1))) {
                        itm_error(
                            gettext(
                            "same escape sequences are defined: "
                            "0x%1$s 0x%2$s\n"),
                            data_to_hexadecimal(ep),
                            data_to_hexadecimal(ep + 1));
                        error_deferred += 1;
                        return  (NULL);
                }
        }
        return  (table);
}




itm_tbl_hdr_t *
map_table(itm_data_t    *name, itmc_map_t       *map_list,
                itmc_map_attr_t *attr)
{
        itm_size_t              num;
        itm_size_t              num2;
        itmc_map_t              *ml;
        itmc_data_pair_t        **tpp;
        itm_tbl_hdr_t           *table;
        long                    source_len = 0;
        long                    result_len = 0;
        long                    source_fixed_len = 1;
        long                    pass_through = 0;
        long                    default_count = 0;
        itm_data_t              *default_data = NULL;
        long                    error_deferred_local = 0;
        unsigned long           dense_encoded_map_ent;
        unsigned long           simple_indexed_map_ent;
        itm_size_t              source_start;
        itm_size_t              source_end;
        unsigned long           u;
        unsigned char           *byte_seq_min;
        unsigned char           *byte_seq_max;
        unsigned char           *p;
        long                    i;
        itmc_map_type_t         map_type = ITMC_MAP_UNKNOWN;
        itmc_map_name_type_t    *map_name_type;
        long                    hash_factor;
        long                    result_len_specfied = 0;
        size_t                  j;
        long                    n;
        itmc_data_pair_t        **dp1;
        itm_num_t               error_count = 0;

        if (attr != NULL) {
                map_type = check_map_type(attr);
        }
        if (ITMC_MAP_UNKNOWN == map_type) {
                map_type = ITMC_MAP_AUTOMATIC;
        }
        hash_factor = ((NULL != attr) && (attr->hash_factor != 0)) ?
            attr->hash_factor :
            200;

        map_name_type = cmd_opt.map_name_type;
        for (; map_name_type; map_name_type = map_name_type->next) {
                if ('\0' == *(map_name_type->name)) {
                        map_type = map_name_type->type;
                        hash_factor = map_name_type->hash_factor;
                        break;
                }
        }
        map_name_type = cmd_opt.map_name_type;
        if ((NULL != name) && (NULL != cmd_opt.map_name_type)) {
                p = NSPTR(name);
                for (; map_name_type; map_name_type = map_name_type->next) {
                        if (0 == strcmp(map_name_type->name, (char *)p)) {
                                map_type = map_name_type->type;
                                hash_factor = map_name_type->hash_factor;
                                break;
                        }
                }
        }

        if (NULL != attr) {
                if (MAXSEQUENCE < attr->resultlen) {
                        itm_error(
                        gettext("output_byte_length must be less than %1$d\n"),
                            MAXSEQUENCE);
                        error_deferred += 1;
                        return  (NULL);
                }
                result_len_specfied = attr->resultlen;
        } else {
                result_len_specfied = 0;
        }

        for (num = 0, ml = map_list; ml; ml = ml->next, num++) {

                /* default */
                if (0 == ml->data_pair.data0.size) {
                        if (0 == ml->data_pair.data1.size) {
                                pass_through += 1;
                                default_data = (itm_data_t *)(-1);
                        } else {
                                default_count += 1;
                                default_data = &(ml->data_pair.data1);
                        }
                        --num;


                } else if (0 == ml->data_pair.data1.size) {
                        /* error source sequence */
                        continue;
                }

                /* fixed length */
                if ((0 < source_len) &&
                    (0 < ml->data_pair.data0.size) &&
                    (source_len != ml->data_pair.data0.size)) {
                        source_fixed_len = 0;
                }

                /* maximum length */
                if (source_len < ml->data_pair.data0.size) {
                        source_len = ml->data_pair.data0.size;
                }
                if (result_len < ml->data_pair.data1.size) {
                        result_len = ml->data_pair.data1.size;
                }

                /* map source has range */
                if (0 < ml->data_pair.range.size) {
                        if (ml->data_pair.range.size !=
                            ml->data_pair.data0.size) {
                                itm_error(
                                    gettext("length of source range must be "
                                    "the same: 0x%1$s 0x%2$s\n"),
                                    data_to_hexadecimal(&(ml->data_pair.data0)),
                                    data_to_hexadecimal(
                                    &(ml->data_pair.range)));
                                error_deferred += 1;
                                return  (NULL);
                        }
                        if (0 <= data_compare(&(ml->data_pair.data0),
                            &((ml->data_pair.range)))) {
                                itm_error(
                                gettext("source range error: 0x%1$s 0x%2$s\n"),
                                    data_to_hexadecimal(
                                    &(ml->data_pair.data0)),
                                    data_to_hexadecimal(
                                    &(ml->data_pair.range)));
                                error_deferred += 1;
                                return  (NULL);
                        }
                        j = map_table_resultlen(ml);
                        if (result_len < j) {
                                result_len = j;
                        }
                }
        }
        if (num == 0) {
                itm_error(
                    gettext("no mapping pair\n"));
                error_deferred += 1;
                return  (NULL);
        }

        if (0 != result_len_specfied) {
                if (result_len > result_len_specfied) {
                        itm_error(
                            gettext("result value length is "
                            "over specifed output_byte_length(%1$ld)\n"),
                            result_len_specfied);
                        error_deferred += 1;
                        return  (NULL);
                }
                result_len = result_len_specfied;
        }
        byte_seq_min = malloc_vital((sizeof (unsigned char)) * source_len);
        byte_seq_max = malloc_vital((sizeof (unsigned char)) * source_len);
        for (num = 0, ml = map_list; ml; ml = ml->next, num++) {
                if (0 == ml->data_pair.data0.size) {
                        continue;
                }

                p = (unsigned char *)(NSPTR(&((ml->data_pair).data0)));
                for (i = 0; i < source_len; i++) {
                        *(byte_seq_min + i) = *(p + i);
                        *(byte_seq_max + i) = *(p + i);
                }
                break;
        }
        for (num = 0, ml = map_list; ml; ml = ml->next, num++) {
                if (0 == ml->data_pair.data0.size) {
                        num--;
                        continue;
                }
                if (ml->data_pair.range.size > 0) {
                        map_range_adjust_byte_seq(byte_seq_min, byte_seq_max,
                            source_len, &(ml->data_pair));
                } else {
                        p = (unsigned char *)(NSPTR(&((ml->data_pair).data0)));
                        for (i = 0; i < source_len; i++) {
                                if (*(p + i) < *(byte_seq_min + i)) {
                                        *(byte_seq_min + i) = *(p + i);
                                }
                                if (*(byte_seq_max + i) < *(p + i)) {
                                        *(byte_seq_max + i) = *(p + i);
                                }
                        }
                }
        }
        for (dense_encoded_map_ent = 1, i = 0; i < source_len; i++) {
                u = dense_encoded_map_ent;
                dense_encoded_map_ent *=
                    (*(byte_seq_max + i) - *(byte_seq_min + i) + 1);
                if (dense_encoded_map_ent < u) {
                        dense_encoded_map_ent = (ulong_t)(~0);
                        break;
                }
        }
#if defined(DEBUG)
        if (TRACE('m')) {
                int     i;
                TRACE_MESSAGE('m', ("map_table: ent=%lu num=%lu ",
                    dense_encoded_map_ent, num));
                TRACE_MESSAGE('m', ("byte_seq_min=0x"));
                for (i = 0; i < source_len; i++) {
                        TRACE_MESSAGE('m', ("%02x", *(byte_seq_min + i)));
                }
                TRACE_MESSAGE('m', ("  byte_seq_max=0x"));
                for (i = 0; i < source_len; i++) {
                        TRACE_MESSAGE('m', ("%02x", *(byte_seq_max + i)));
                }
                TRACE_MESSAGE('m', ("\n"));
        }
#endif /* DEBUG */

        tpp = malloc_vital((sizeof (itmc_data_pair_t *)) * num);
        for (num = 0, num2 = 0, ml = map_list; ml; ml = ml->next) {
                if (0 < ml->data_pair.data0.size) {
                        itm_num_t range_num;
                        *(tpp + num) = &(ml->data_pair);
                        num++;
                        range_num = 1;
                        if (ml->data_pair.range.size > 0) {
                                range_num +=
                                    map_table_num_range(&(ml->data_pair));
                        }
                        num2 += range_num;
                        if (0 == ml->data_pair.data1.size) {
                                /* specified error sequence */
                                error_count += range_num;
                        }
                }
        }
        (void) qsort(tpp, num, sizeof (itmc_data_pair_t *),
            (int (*)(const void *, const void *))data_pair_compare);

        /* check if map_pair range and next map_pair are overrapped */
        for (n = 0, dp1 = tpp; n < (num-1); n++, dp1++) {
                if (((*(dp1+0))->range.size != 0) &&
                    (0 <= data_compare(&((*(dp1+0))->range),
                    &((*(dp1+1))->data0)))) {
                        itm_error(
                            gettext("ranges of source sequences "
                            "overrapped: %1$s %2$s\n"),
                            data_to_hexadecimal(&((*(dp1+0))->range)),
                            data_to_hexadecimal(&((*(dp1+1))->data0)));
                        error_deferred += 1;
                        return  (NULL);
                }
        }

        if (1 < default_count) {
                itm_error(
                    gettext("default is specified %1$d times in a map\n"),
                    default_count);
                error_deferred_local += 1;
        }
        if ((1 == default_count) && (!source_fixed_len)) {
                itm_error(
                    gettext("default is specified,"
                    " but length of source data is not fixed\n"));
                error_deferred_local += 1;
        }
        if ((1 <= pass_through) && (source_len != result_len)) {
                itm_error(
                    gettext("\"default no_change_copy\" is "
                    "specified, but size does not match\n"));
                error_deferred_local += 1;
        }

        if (error_deferred_local) {
                error_deferred += error_deferred_local;
                return  (NULL);
        }

        if (source_fixed_len) {
                source_start = data_to_long(&((*(tpp + 0))->data0));
                source_end = data_to_long(&((*(tpp + num - 1))->data0));
                if (0 < (*(tpp + num - 1))->range.size) {
                        source_end = data_to_long(&((*(tpp + num - 1))->range));
                }

                simple_indexed_map_ent = source_end - source_start + 1;

                TRACE_MESSAGE('m', ("map_table: simple_indexed_map_ent=%lu\n",
                    simple_indexed_map_ent));

                switch (map_type) {
                case ITMC_MAP_AUTOMATIC:
                        if ((source_len <= 2) &&
                            (((ulong_t)(~0) == dense_encoded_map_ent) ||
                            (simple_indexed_map_ent <
                            (dense_encoded_map_ent * 2)))) {
                                /*
                                 * for small source sequence,
                                 * if dense table is not so large
                                 * compared with simple table,
                                 * use simple.
                                 */
                                map_type = ITMC_MAP_SIMPLE_INDEX;
                        } else if (cmd_opt.large_table) {
                                if ((sizeof (long)) < source_len) {
                                        itm_error(
                                        gettext("length of source is too long "
                                            "for large table: %ld\n"),
                                            source_len);
                                        error_deferred += 1;
                                        return  (NULL);
                                }
                                map_type = ITMC_MAP_SIMPLE_INDEX;
                        } else if (((ulong_t)(~0) == dense_encoded_map_ent) ||
                            ((0xffff < dense_encoded_map_ent) &&
                            ((num2 * 8) < dense_encoded_map_ent))) {
                                /*
                                 * if dense can be used and not too large
                                 * ( less than (hash table entry * 8),
                                 * use dense.
                                 */
                                map_type = ITMC_MAP_SIMPLE_HASH;
                        } else {
                                map_type = ITMC_MAP_DENSE_ENCODING;
                        }
                        break;
                case ITMC_MAP_SIMPLE_INDEX:
                        if ((sizeof (long)) < source_len) {
                                itm_error(
                                gettext("length of source is too long "
                                    "for index lookup: %ld\n"),
                                    source_len);
                                error_deferred += 1;
                                return  (NULL);
                        }
                        break;
                case ITMC_MAP_SIMPLE_HASH:
                        for (i = 2, u = 256; i < (sizeof (long)); i++) {
                                u *= 256;
                        }
                        if (u < num2) {
                                itm_error(
                                gettext("map is too large for hashing: %lu\n"),
                                    num2);
                                error_deferred += 1;
                                return  (NULL);
                        }
                        break;
                case ITMC_MAP_DENSE_ENCODING:
                        for (i = 2, u = 256; i < (sizeof (long)); i++) {
                                u *= 256;
                        }
                        if (u < dense_encoded_map_ent) {
                                itm_error(
                                    gettext(
                                    "map is too large for dense encoding: "
                                    "%lu\n"),
                                    dense_encoded_map_ent);
                                error_deferred += 1;
                                return  (NULL);
                        }
                        break;
                case ITMC_MAP_BINARY_SEARCH:
                        for (i = 2, u = 256; i < (sizeof (long)); i++) {
                                u *= 256;
                        }
                        if (u < num2) {
                                itm_error(
                                gettext("length of source is too long for "
                                    "binary search: %ld\n"),
                                    source_len);
                                error_deferred += 1;
                                return  (NULL);
                        }
                        break;
                default:
                        break;
                }
                switch (map_type) {
                case ITMC_MAP_SIMPLE_INDEX:
                        table = map_table_indexed_fixed(
                            tpp, num, default_data,
                            result_len, error_count);
                        break;
                case ITMC_MAP_SIMPLE_HASH:
                        table = map_table_hash(tpp, num, default_data,
                            hash_factor, result_len, num2,
                            error_count);
                        break;
                case ITMC_MAP_DENSE_ENCODING:
                        table = map_table_dense_encoding(tpp, num,
                            default_data,
                            dense_encoded_map_ent,
                            byte_seq_min, byte_seq_max,
                            result_len, error_count);
                        break;
                case ITMC_MAP_BINARY_SEARCH:
                        table = map_table_lookup_fixed(tpp, num,
                            default_data,
                            result_len, num2);
                        break;
                }
        } else {
                table = map_table_lookup_var();
        }

        if ((NULL != name) && (NULL != table)) {
                table->name.itm_ptr = (itm_place2_t)name;
        }

        return  (table);
}


static itmc_map_type_t
check_map_type(itmc_map_attr_t *attr)
{
        int i;

        if (NULL == attr->type) {
                return (0);
        }
        for (i = 0; NULL != map_type_name[i].name; i++) {
                if (0 == strncmp(((char *)&(attr->type->place)),
                    map_type_name[i].name, attr->type->size)) {
                        return (map_type_name[i].type);
                }
        }
        return (0);
}


static itm_tbl_hdr_t *
map_table_indexed_fixed(
        itmc_data_pair_t        **tpp,
        itm_size_t              num,
        itm_data_t              *default_data,
        long                    resultlen,
        itm_num_t               error_count)
{
        itm_tbl_hdr_t           *header;
        itm_map_idx_fix_hdr_t   *sub_hdr;
        char                    *table;
        char                    *error_table;
        itm_size_t              source_start;
        itm_size_t              source_end;
        itm_size_t              entry_num;
        itm_size_t              table_size;
        itm_size_t              j;
        itm_size_t              i;
        itm_size_t              k;
        char                    *p;
        itm_data_t              *source;

        TRACE_MESSAGE('m', ("map_table_range : %ld\n", num));

        source = &((*(tpp + 0))->data0);
        assert((sizeof (itm_place_t)) >= source->size);

        if ((1 == source->size) &&
            (1 == resultlen)) {
                source_start = 0;
                source_end = 255;
        } else {
                source_start = data_to_long(&((*(tpp + 0))->data0));
                source_end = data_to_long(&((*(tpp + num - 1))->data0));
                if (0 < (*(tpp + num - 1))->range.size)
                        source_end = data_to_long(&((*(tpp + num - 1))->range));
        }

        entry_num = source_end - source_start + 1;

        table_size = ((sizeof (itm_tbl_hdr_t)) +
            (sizeof (itm_map_idx_fix_hdr_t)) +
            (resultlen * entry_num));
        if (0 < error_count) {
                table_size += entry_num;
        }
        if (NULL == default_data) {
                if ((num < entry_num) ||
                    (error_count <= 0)) {
                        table_size += entry_num;
                }
        } else if ((itm_data_t *)(-1) != default_data) {
                table_size += resultlen;
        }

        table_size = ITMROUNDUP(table_size);
        header = malloc_vital(table_size);
        sub_hdr = (itm_map_idx_fix_hdr_t *)(header + 1);
        table = (char *)(sub_hdr + 1);

        if ((1 == (*tpp)->data0.size) &&
            (1 == (*tpp)->data1.size)) {
                header->type = ITM_TBL_MAP_INDEX_FIXED_1_1;
        } else {
                header->type = ITM_TBL_MAP_INDEX_FIXED;
        }
        header->name.itm_ptr = 0;
        header->size = table_size;
        header->number = entry_num;

        sub_hdr->source_len = (*tpp)->data0.size;
        sub_hdr->result_len = resultlen;
        sub_hdr->start.itm_ptr = source_start;
        sub_hdr->end.itm_ptr = source_end;
        sub_hdr->error_num = error_count; /* > 0; so pad4 = 0 */

        if (NULL != default_data) {
                if ((itm_data_t *)(-1) == default_data) {
                        sub_hdr->default_error = -1;
#if !defined(_LP64)
                        sub_hdr->pad3_num = (pad_t)(~0);
#endif
                } else {
                        sub_hdr->default_error = 0;
                }
        } else {
                if (num < entry_num) {
                        sub_hdr->default_error = 1;
                } else {
                        sub_hdr->default_error = 2;
                }
        }

        error_table = (table + (resultlen * entry_num));
        if (-1 == sub_hdr->default_error) {
                if (source->size != resultlen) {
                        itm_error(
                            gettext("\"default no_change_copy\" is "
                            "specified, but size does not match\n"));
                        exit(ITMC_STATUS_BT);
                }

                for (i = 0, j = 0;
                    i < (entry_num);
                    i++, j += resultlen) {
                        for (k = 0; k < resultlen; k++) {
                                *(table + j + k) =
                                    (((source_start + i) >>
                                    ((resultlen - k - 1) * 8)) &
                                    0x00ff);
                        }
                }
        } else if (0 == sub_hdr->default_error) {
                error_table += resultlen;
                if (default_data->size <= (sizeof (itm_place_t))) {
                        for (i = 0, j = 0;
                            i < (entry_num + 1); /* last one is for default */
                            i++, j += resultlen) {
                                (void) memcpy(table + j +
                                    (resultlen - default_data->size),
                                    (void *)(&(default_data->place.itm_64d)),
                                    default_data->size);
                        }
                } else {
                        for (i = 0, j = 0;
                            i < (entry_num + 1); /* last one is for default */
                            i++, j += resultlen) {
                                (void) memcpy(table + j +
                                    (resultlen - default_data->size),
                                    (void *)(default_data->place.itm_ptr),
                                    default_data->size);
                        }
                }
        }
        if (1 == sub_hdr->default_error) {
                (void) memset(error_table, 1, entry_num);
                for (i = 0; i < num; i++) {
                        if (0 == (*(tpp + i))->data1.size) {
                                continue; /* error sequence */
                        }
                        j = data_to_long(&((*(tpp + i))->data0)) -
                            source_start;
                        k = ((*(tpp + i))->range.size) == 0 ? j :
                            data_to_long(&((*(tpp + i))->range)) -
                            source_start;
                        for (; j <= k; j++) {
                                *(error_table + j) = 0;
                        }
                }
        } else if (0 < error_count) {
                (void) memset(error_table, 0, entry_num);
                for (i = 0; i < num; i++) {
                        if (0 == (*(tpp + i))->data1.size) {
                                /* error sequence */
                                j = data_to_long(&((*(tpp + i))->data0)) -
                                    source_start;
                                k = ((*(tpp + i))->range.size) == 0 ? j :
                                    data_to_long(&((*(tpp + i))->range)) -
                                    source_start;
                                for (; j <= k; j++) {
                                        *(error_table + j) = 1;
                                }
                        }
                }
        }

        p = malloc_vital(sizeof (uchar_t *) * resultlen);
        for (i = 0; i < num; i++) {
                j = data_to_long(&((*(tpp + i))->data0)) - source_start;
                if (0 != (*(tpp + i))->range.size)
                        k = data_to_long(&((*(tpp + i))->range)) -
                            source_start;
                else
                        k = j;
                (void) memset(p, 0, sizeof (uchar_t *) * resultlen);
                (void) memcpy(p + (resultlen  - (*(tpp + i))->data1.size),
                    ((caddr_t)NSPTR(&((*(tpp + i))->data1))),
                    (*(tpp + i))->data1.size);
                map_range_make_result(table, j, k, p, resultlen);
        }
        free(p);

        return  (header);
}




static itm_tbl_hdr_t *
map_table_lookup_fixed(
        itmc_data_pair_t        **tpp,
        itm_size_t              num,
        itm_data_t              *default_data,
        long                    resultlen,
        itm_size_t              num2)
{
        itm_tbl_hdr_t           *header;
        itm_map_lookup_hdr_t    *sub_hdr;
        char                    *table;
        itm_size_t              table_size;
        itm_size_t              j;
        itm_size_t              i;
        itm_size_t              k;
        itm_size_t              h;
        itm_data_t              *source;
        uchar_t                 *source_data;
        uchar_t                 *result_data;

        TRACE_MESSAGE('m', ("map_table_lookup_fixed : %ld(%ld) 0x%lx\n",
            num, num2, default_data));

        source = &((*(tpp + 0))->data0);

        table_size = ((sizeof (itm_tbl_hdr_t)) +
            (sizeof (itm_map_idx_fix_hdr_t)) +
            ((source->size + 1 + resultlen) * num2));
        if ((NULL != default_data) &&
            (((itm_data_t *)(-1)) != default_data)) {
                table_size += (source->size + 1 + resultlen);
        }
        table_size = ITMROUNDUP(table_size);
        header = malloc_vital(table_size);
        sub_hdr = (itm_map_lookup_hdr_t *)(header + 1);
        table = (char *)(sub_hdr + 1);

        header->type = ITM_TBL_MAP_LOOKUP;
        header->name.itm_ptr = 0;
        header->size = table_size;
        header->number = num2;
        if (NULL != default_data) {
                if ((itm_data_t *)(-1) == default_data) {
#if !defined(_LP64)
                        sub_hdr->pad3_num = (pad_t)(~0);
#endif
                        sub_hdr->default_error = -1;
                } else {
                        sub_hdr->default_error = 0;
                }
        } else {
                sub_hdr->default_error = 2;
        }

        sub_hdr->source_len = source->size;
        sub_hdr->result_len = resultlen;

        /* specified map */
        source_data = malloc_vital(source->size);
        result_data = malloc_vital(resultlen);
        for (i = 0, j = 0; i < num; i++) {
                (void) memcpy(table + j,
                    NSPTR(&((*(tpp + i))->data0)), source->size);
                j += source->size;
                if (0 == (*(tpp + i))->data1.size) {
                        *(table + j) = 1; /* specified error */
                        j += 1;
                } else {
                        /* *(table + j) = 0; ** valid */
                        j += 1;
                        (void) memcpy(table + j +
                            (resultlen  - (*(tpp + i))->data1.size),
                            NSPTR(&((*(tpp + i))->data1)),
                            (*(tpp + i))->data1.size);
                }
                j += resultlen;

                if ((*(tpp + i))->range.size != 0) {
                        (void) memcpy(source_data,
                            NSPTR(&((*(tpp + i))->data0)),
                            source->size);
                        (void) memset(result_data, 0, resultlen);
                        (void) memcpy(result_data +
                            (resultlen  - (*(tpp + i))->data1.size),
                            NSPTR(&((*(tpp + i))->data1)),
                            (*(tpp + i))->data1.size);
                        h = map_table_num_range((*(tpp + i)));
                        for (k = 0; k < h; k++) {
                                uchar_t         *dp;
                                itm_size_t      m;

                                for (m = 0,
                                    dp = (uchar_t *)
                                    (source_data + source->size - 1);
                                    m < source->size;
                                    m++, dp--) {
                                        if (0xff != *dp) {
                                                (*dp) += (char)1;
                                                for (++dp; m > 0; m--, dp++) {
                                                        (*dp) = 0x00;
                                                }
                                                break;
                                        }
                                }
                                (void) memcpy(table + j,
                                    source_data, source->size);
                                j += source->size;

                                if (0 == (*(tpp + i))->data1.size) {
                                        *(table + j) = 1; /* specified error */
                                        j += 1;
                                } else {
                                        /* *(table + j) = 0; ** valid */
                                        j += 1;
                                        for (m = 0, dp = (uchar_t *)
                                            (result_data + resultlen - 1);
                                            m < resultlen;
                                            m++, dp--) {
                                                if (0xff != *dp) {
                                                        (*dp) += 1;
                                                        for (++dp;
                                                            m > 0;
                                                            m--, dp++) {
                                                                (*dp) = 0x00;
                                                        }
                                                        break;
                                                }
                                        }
                                        (void) memcpy(table + j, result_data,
                                            resultlen);
                                }
                                j += resultlen;
                        }
                }
        }
        free(source_data);
        free(result_data);

        /* default */
        if ((NULL != default_data) &&
            (((itm_data_t *)(-1)) != default_data)) {
                (void) memset(table + j, 0, source->size + 1 + resultlen);
                (void) memcpy(table + j + source->size + 1 +
                    (resultlen  - default_data->size),
                    NSPTR(default_data), default_data->size);
        }
        return  (header);
}




static itm_tbl_hdr_t *
map_table_hash(
        itmc_data_pair_t        **tpp,
        itm_size_t              num,
        itm_data_t              *default_data,
        long                    hash_factor,
        long                    resultlen,
        itm_size_t              num2,
        itm_num_t               error_count)
{
        itm_tbl_hdr_t           *header;
        itm_map_hash_hdr_t      *sub_hdr;
        itm_size_t              table_size;
        char                    *error_table;
        char                    *hash_table;
        itm_size_t              hash_table_num;
        char                    *of_table;
        itm_size_t              of_table_num;
        itm_size_t              pair_size;
        itm_size_t              i;
        itm_size_t              j;
        itm_size_t              k;
        char                    *p;
        itm_data_t              *source;
        long                    hash_value;
#if defined(DEBUG)
        long                    hash_none;
        long                    hash_one;
        long                    hash_conflict;
#endif /* DEBUG */
        uchar_t                 *source_data;
        uchar_t                 *result_data;
        uchar_t                 *dp;
        itm_size_t              m;
        itm_size_t              n;
        itm_size_t              h;

        TRACE_MESSAGE('m', ("map_table_hash : %ld(%ld) 0x%lx\n",
            num, num2, default_data));
        source = &((*(tpp + 0))->data0);
        pair_size = (source->size + 1 + resultlen);

        if (100 <= hash_factor) {
                hash_table_num = (num2 * (hash_factor / 100.0));
        } else {
                hash_table_num = (num2 * 2);
        }
        if (hash_table_num < 256) {
                hash_table_num = 256;
        }
        source_data = malloc_vital(source->size);
        result_data = malloc_vital(resultlen);

        hash_table = malloc_vital(hash_table_num);
        for (i = 0, of_table_num = 0; i < num; i++) {
                hash_value = hash(NSPTR(&((*(tpp + i))->data0)),
                    (*(tpp + i))->data0.size,
                    hash_table_num);
                if (0 == *(hash_table + hash_value)) {
                        *(hash_table + hash_value) = 1;
                } else {
                        *(hash_table + hash_value) = 2;
                        of_table_num += 1;
                }

                if ((*(tpp + i))->range.size != 0) {
                        (void) memcpy(source_data,
                            NSPTR(&((*(tpp + i))->data0)),
                            source->size);
                        h = map_table_num_range((*(tpp + i)));
                        for (n = 0; n < h; n++) {
                                for (m = 0,
                                    dp = (uchar_t *)
                                    (source_data + source->size - 1);
                                    m < source->size;
                                    m++, dp--) {
                                        if (0xff != *dp) {
                                                (*dp) += 1;
                                                for (++dp; m > 0; m--, dp++) {
                                                        (*dp) = 0x00;
                                                }
                                                break;
                                        }
                                }
                                hash_value = hash((char *)source_data,
                                    source->size,
                                    hash_table_num);

                                if (0 == *(hash_table + hash_value)) {
                                        *(hash_table + hash_value) = 1;
                                } else {
                                        *(hash_table + hash_value) = 2;
                                        of_table_num += 1;
                                }
                        }
                }
        }

#if defined(DEBUG)
        if (TRACE('s')) {
                hash_none = 0;
                hash_one = 0;
                hash_conflict = 0;
                j = 0;
                for (i = 0; i < hash_table_num; i++) {
                        if (2 == *(hash_table + i)) {
                                (void) putchar('2');
                                hash_conflict += 1;
                        } else if (1 == *(hash_table + i)) {
                                (void) putchar('1');
                                hash_one += 1;
                        } else if (0 == *(hash_table + i)) {
                                (void) putchar('-');
                                hash_none += 1;
                        } else {
                                (void) putchar('*');
                        }
                        if (63 <= j) {
                                j = 0;
                                (void) putchar('\n');
                        } else {
                                j += 1;
                        }
                }
                (void) putchar('\n');
                (void) printf("null=%ld one=%ld conflict=%ld\n",
                    hash_none, hash_one, hash_conflict);
        }
#endif /* DEBUG */

        free(hash_table);
        table_size = ((sizeof (itm_tbl_hdr_t)) +
            (sizeof (itm_map_hash_hdr_t)) +
            (hash_table_num) +
            (pair_size * hash_table_num) +
            (pair_size * of_table_num));
        if ((NULL != default_data) &&
            (((itm_data_t *)(-1)) != default_data)) {
                table_size += pair_size;
        }
        table_size = ITMROUNDUP(table_size);
        header = malloc_vital(table_size);
        sub_hdr = (itm_map_hash_hdr_t *)(header + 1);
        error_table = (char *)(sub_hdr + 1);
        hash_table = error_table + hash_table_num;
        of_table = hash_table + (pair_size * hash_table_num);

        header->type = ITM_TBL_MAP_HASH;
        header->name.itm_ptr = 0;
        header->size = table_size;
        header->number = num2;
        if (NULL != default_data) {
                if ((itm_data_t *)(-1) == default_data) {
                        sub_hdr->default_error = -1;
#if !defined(_LP64)
                        sub_hdr->pad7_num = (pad_t)(~0);
#endif
                } else {
                        sub_hdr->default_error = 0;
                }
        } else {
                sub_hdr->default_error = 2;
        }

        sub_hdr->source_len = source->size;
        sub_hdr->result_len = resultlen;
        sub_hdr->hash_tbl_size = (pair_size * hash_table_num);
        sub_hdr->hash_tbl_num = hash_table_num;
        sub_hdr->hash_of_size =
            (pair_size * of_table_num);
        sub_hdr->hash_of_num = of_table_num;
        sub_hdr->error_num = error_count; /* > 0; so pad4 = 0 */

        /* specified map */
        for (i = 0, j = 0, k = 0; i < num; i++) {
                hash_value = hash(NSPTR(&((*(tpp + i))->data0)),
                    (*(tpp + i))->data0.size,
                    hash_table_num);
                p = error_table + hash_value;
                if (*p) {       /* conflict */
                        if (*p < 63) {
                                *p += 1;
                        }
                        p = of_table + k;
                        k += pair_size;
                } else {
                        *p = 1;
                        p = hash_table + (pair_size * hash_value);
                }

                (void) memcpy(p, NSPTR(&((*(tpp + i))->data0)), source->size);
                p += source->size;
                if (0 == (*(tpp + i))->data1.size) {
                        (*p) = 1; /* specified error */
                        p++;
                } else {
                        /* (*p) = 0; ** valid */
                        p++;
                        (void) memset(p, 0,
                            (resultlen - (*(tpp + i))->data1.size));
                        (void) memcpy(p +
                            (resultlen - (*(tpp + i))->data1.size),
                            NSPTR(&((*(tpp + i))->data1)),
                            (*(tpp + i))->data1.size);
                }

                if ((*(tpp + i))->range.size != 0) {
                        (void) memcpy(source_data,
                            NSPTR(&((*(tpp + i))->data0)),
                            source->size);
                        (void) memset(result_data, 0,
                            (resultlen  - (*(tpp + i))->data1.size));
                        (void) memcpy(result_data +
                            (resultlen  - (*(tpp + i))->data1.size),
                            NSPTR(&((*(tpp + i))->data1)),
                            (*(tpp + i))->data1.size);
                        h = map_table_num_range((*(tpp + i)));
                        for (n = 0; n < h; n++) {
                                for (m = 0,
                                    dp = (uchar_t *)
                                    (source_data + source->size - 1);
                                    m < source->size;
                                    m++, dp--) {
                                        if (0xff != *dp) {
                                                (*dp) += 1;
                                                for (++dp; m > 0; m--, dp++) {
                                                        (*dp) = 0x00;
                                                }
                                                break;
                                        }
                                }

                                hash_value = hash((char *)source_data,
                                    source->size,
                                    hash_table_num);
                                p = error_table + hash_value;
                                if (*p) {       /* conflict */
                                        if (*p < 63) {
                                                *p += 1;
                                        }
                                        p = of_table + k;
                                        k += pair_size;
                                } else {
                                        *p = 1;
                                        p = hash_table +
                                            (pair_size * hash_value);
                                }
                                (void) memcpy(p, source_data, source->size);
                                p += source->size;

                                if (0 == (*(tpp + i))->data1.size) {
                                        (*p) = 1; /* specified error */
                                        p += 1;
                                } else {
                                        /* (*p) = 0; ** valid */
                                        p += 1;
                                        for (m = 0, dp = (uchar_t *)
                                            (result_data + resultlen - 1);
                                            m < resultlen;
                                            m++, dp--) {
                                                if (0xff != *dp) {
                                                        (*dp) += 1;
                                                        for (++dp; m > 0;
                                                            m--, dp++) {
                                                                (*dp) = 0x00;
                                                        }
                                                        break;
                                                }
                                        }
                                        (void) memcpy(p,
                                            result_data, resultlen);
                                }
                        }
                }
        }
        free(source_data);
        free(result_data);

        /* default */
        if ((NULL != default_data) &&
            (((itm_data_t *)(-1)) != default_data)) {
                j = ((pair_size * hash_table_num) +
                    (pair_size * of_table_num));
                (void) memcpy(hash_table + j + (resultlen - default_data->size),
                    NSPTR(default_data), default_data->size);
        }
#if defined(ENABLE_TRACE)
        for (i = 0, p = of_table; i < of_table_num; i++, p += 5) {
                (void) printf("0x%02x%02x%02x%02x       0x%02x\n",
                    ((unsigned char)(*(p + 0))),
                    ((unsigned char)(*(p + 1))),
                    ((unsigned char)(*(p + 2))),
                    ((unsigned char)(*(p + 3))),
                    ((unsigned char)(*(p + 4))));
        }
#endif
        return  (header);
}




static itm_tbl_hdr_t *
map_table_dense_encoding(
        itmc_data_pair_t        **tpp,
        itm_size_t              num,
        itm_data_t              *default_data,
        unsigned long           entry_num,
        unsigned char           *byte_seq_min,
        unsigned char           *byte_seq_max,
        long                    resultlen,
        itm_num_t               error_count)
{

        itm_tbl_hdr_t           *header;
        itm_map_dense_enc_hdr_t *sub_hdr;
        char                    *table;
        char                    *error_table;
        itm_size_t              table_size;
        itm_size_t              j;
        itm_size_t              i;
        itm_size_t              k;
        char                    *p;
        itm_data_t              *source;
        unsigned char           *byte_seq_def;

        TRACE_MESSAGE('m', ("map_table_dense_encoding : %ld\n", num));

        source = &((*(tpp + 0))->data0);


        table_size = ((sizeof (itm_tbl_hdr_t)) +
            (sizeof (itm_map_dense_enc_hdr_t)) +
            (source->size + source->size) +
            (resultlen * entry_num));
        if (0 < error_count) {
                table_size += entry_num;
        }
        if (NULL == default_data) {
                if ((num < entry_num) ||
                    (error_count <= 0)) {
                        table_size += entry_num;
                }
        } else if ((itm_data_t *)(-1) != default_data) {
                table_size += resultlen;
        }

        table_size = ITMROUNDUP(table_size);
        header = malloc_vital(table_size);
        sub_hdr = (itm_map_dense_enc_hdr_t *)(header + 1);
        table = (char *)(sub_hdr + 1) + source->size + source->size;

        header->type = ITM_TBL_MAP_DENSE_ENC;
        header->name.itm_ptr = 0;
        header->size = table_size;
        header->number = entry_num;

        sub_hdr->source_len = (*tpp)->data0.size;
        sub_hdr->result_len = resultlen;
        sub_hdr->error_num = error_count; /* > 0; so pad4 = 0 */

        if (NULL != default_data) {
                if ((itm_data_t *)(-1) == default_data) {
                        sub_hdr->default_error = -1;
#if !defined(_LP64)
                        sub_hdr->pad3_num = (pad_t)(~0);
#endif

                } else {
                        sub_hdr->default_error = 0;
                }
        } else {
                if (num < entry_num) {
                        sub_hdr->default_error = 1;
                } else {
                        sub_hdr->default_error = 2;
                }
        }

        (void) memcpy((char *)(sub_hdr + 1), byte_seq_min, source->size);
        (void) memcpy((char *)(sub_hdr + 1) + source->size,
            byte_seq_max, source->size);

        if (-1 == sub_hdr->default_error) {
                byte_seq_def = malloc_vital((sizeof (unsigned char *)) *
                    resultlen);
                if (source->size != resultlen) {
                        itm_error(
                        gettext("\"default no_change_copy\" is "
                            "specified, but size does not match\n"));
                        exit(ITMC_STATUS_BT);
                }
                put_dense_encoding_default(
                    table, byte_seq_min, byte_seq_max, byte_seq_def,
                    resultlen - 1, 0, 0);
                free(byte_seq_def);
        } else if (0 == sub_hdr->default_error) {
                if (default_data->size <= (sizeof (itm_place_t))) {
                        for (i = 0, j = 0;
                            i < (entry_num + 1); /* 1:default data */
                            i++, j += resultlen) {
                                (void) memcpy(table + j +
                                    (resultlen - default_data->size),
                                    (void *)(&(default_data->place.itm_64d)),
                                    default_data->size);
                        }
                } else {
                        for (i = 0, j = 0;
                            i < (entry_num + 1);  /* 1:default data */
                            i++, j += resultlen) {
                                (void) memcpy(table + j +
                                    (resultlen - default_data->size),
                                    (void *)(default_data->place.itm_ptr),
                                    default_data->size);
                        }
                }
        }
        if (1 == sub_hdr->default_error) {
                (void) memset(table + (resultlen * entry_num), 1, entry_num);
                error_table = (table + (resultlen * entry_num));
                for (i = 0; i < num; i++) {
                        if (0 == (*(tpp + i))->data1.size) {
                                continue; /* error sequence */
                        }
                        j = hash_dense_encoding(NSPTR(&((*(tpp + i))->data0)),
                            (*(tpp + i))->data0.size,
                            byte_seq_min, byte_seq_max);
                        k = ((*(tpp + i))->range.size) == 0 ? j :
                            hash_dense_encoding(NSPTR(&((*(tpp + i))->range)),
                            (*(tpp + i))->data0.size,
                            byte_seq_min, byte_seq_max);
                        for (; j <= k; j++) {
                                *(error_table + j) = 0;
                        }
                }
        } else if (0 < error_count) {
                error_table = (table + (resultlen * entry_num));
                if (0 == sub_hdr->default_error) {
                        error_table += resultlen;
                }
                (void) memset(error_table, 0, entry_num);
                for (i = 0; i < num; i++) {
                        if (0 == (*(tpp + i))->data1.size) {
                                j = hash_dense_encoding(
                                    NSPTR(&((*(tpp + i))->data0)),
                                    (*(tpp + i))->data0.size,
                                    byte_seq_min, byte_seq_max);
                                k = ((*(tpp + i))->range.size) == 0 ? j :
                                    hash_dense_encoding(
                                    NSPTR(&((*(tpp + i))->range)),
                                    (*(tpp + i))->data0.size,
                                    byte_seq_min, byte_seq_max);
                                for (; j <= k; j++) {
                                        *(error_table + j) = 1; /* specified */
                                }
                        }
                }
        }


        p = malloc_vital(resultlen);
        for (i = 0; i < num; i++) {
                j = hash_dense_encoding(NSPTR(&((*(tpp + i))->data0)),
                    (*(tpp + i))->data0.size,
                    byte_seq_min, byte_seq_max);

                if (0 != (*(tpp + i))->range.size)
                        k = hash_dense_encoding(
                            NSPTR(&((*(tpp + i))->range)),
                            (*(tpp + i))->range.size,
                            byte_seq_min, byte_seq_max);
                else
                        k = j;
                (void) memset(p, 0, (resultlen   - (*(tpp + i))->data1.size));
                (void) memcpy(p + (resultlen  - (*(tpp + i))->data1.size),
                    ((caddr_t)NSPTR(&((*(tpp + i))->data1))),
                    (*(tpp + i))->data1.size);
                map_range_make_result(table, j, k, p, resultlen);
        }
        free(p);

        return  (header);
}


static void
put_dense_encoding_default(
        char    *table,
        unsigned char   *byte_seq_min,
        unsigned char   *byte_seq_max,
        unsigned char   *byte_seq_def,
        long            pos_max,
        long            position,
        long            dense_encoded_value)
{
        uchar_t i;

        if (position < pos_max) {
                for (i = *(byte_seq_min + position);
                    i <= *(byte_seq_max + position); i++) {
                        *(byte_seq_def + position) = i;
                        put_dense_encoding_default(
                            table,
                            byte_seq_min, byte_seq_max,
                            byte_seq_def,
                            pos_max, position + 1,
                            ((dense_encoded_value + i) *
                            (*(byte_seq_max + position) -
                            *(byte_seq_min + position) + 1)));
                }
                return;
        }

        for (i = *(byte_seq_min + position);
            i <= *(byte_seq_max + position); i++) {
                *(byte_seq_def + position) = i;
                (void) memcpy(table +
                    ((pos_max + 1) * (dense_encoded_value + i - 1)),
                    byte_seq_def, pos_max + 1);
        }
}


char *
dense_enc_index_to_byte_seq(
        long            value,
        long            length,
        unsigned char   *byte_seq_min,
        unsigned char   *byte_seq_max)
{
        static char     *buf;
        static long     buf_len;
        char            *p;
        int             i;
        int             l;
        int             residue;

        if (buf_len < (2 + (length * 2) + 1)) {
                free(buf);
                buf_len = (2 + (length * 2) + 1) + 16;
                buf = malloc_vital(buf_len);
        }

        *(buf + (length * 2)) = '\0';
        *(buf + 0) = '0';
        *(buf + 1) = 'x';
        p = buf + 2;
        for (i = length - 1; 0 <= i; --i) {
                residue = value % (*(byte_seq_max + i) -
                    *(byte_seq_min + i) + 1);
                value /= (*(byte_seq_max + i) -
                    *(byte_seq_min + i) + 1);

                residue += *(byte_seq_min + i);
                l = ((0xf0 & residue) >> 4);
                if (l < 10) {
                        *(p + (i * 2)) = ('0' + l);
                } else {
                        *(p + (i * 2)) = ('a' + l - 10);
                }
                l = (0x0f & residue);
                if (l < 10) {
                        *(p + (i * 2) + 1) = ('0' + l);
                } else {
                        *(p + (i * 2) + 1) = ('a' + l - 10);
                }
        }
        return  (buf);
}


itm_tbl_hdr_t *
map_table_lookup_var()
{
        itm_error(gettext(
            "length of all source sequences must be the same\n"));
        error_deferred += 1;
        return  (NULL);
}



static void
map_range_adjust_byte_seq(
        unsigned char           *byte_seq_min,
        unsigned char           *byte_seq_max,
        long                    source_len,
        itmc_data_pair_t        *pair)
{
        unsigned char           *p, *p2;
        int                     i;
        int                     flag;

        p  = (unsigned char *)(NSPTR(&((pair)->data0)));
        p2 = (unsigned char *)(NSPTR(&((pair)->range)));
        flag = 0;
        for (i = 0; i < source_len; i++) {
                if (flag != 0) {
                        break;
                }
                if (*(p + i) != *(p2 + i))
                        flag = 1;
                if (*(p + i) < *(byte_seq_min + i)) {
                        *(byte_seq_min + i) = *(p + i);
                }
                if (*(byte_seq_max + i) < *(p2 + i)) {
                        *(byte_seq_max + i) = *(p2 + i);
                }
        }
        for (; i < source_len; i++) {
                *(byte_seq_min + i) = 0x00;
                *(byte_seq_max + i) = 0xff;
        }
}

/*
 *      result value + (source range value - source base value)
 *      and just caluculate its length
 */
static size_t
map_table_resultlen(itmc_map_t          *ml)
{
        size_t  j;
        size_t  len;
        int     m;
        uchar_t *c1;
        uchar_t *c2;
        uchar_t *c3;

        j = ml->data_pair.data0.size;
        if (j < ml->data_pair.data1.size) j = ml->data_pair.data1.size;
        if (j < ml->data_pair.range.size) j = ml->data_pair.range.size;
        c1 = (uchar_t *)(NSPTR(&((ml->data_pair).data0))) +
            ml->data_pair.data0.size - 1;
        c2 = (uchar_t *)(NSPTR(&((ml->data_pair).data1))) +
            ml->data_pair.data1.size - 1;
        c3 = (uchar_t *)(NSPTR(&((ml->data_pair.range)))) +
            ml->data_pair.range.size - 1;
        m = 0;
        for (len = 0; len < j; len++, c1--, c2--, c3--) {
                if (len < ml->data_pair.data0.size) m -= *c1;
                if (len < ml->data_pair.data1.size) m += *c2;
                if (len < ml->data_pair.range.size) m += *c3;
                m >>= 8;
        }
        if (m > 0) {
                len += 1;
        }
        TRACE_MESSAGE('g', ("map_table_resutlen: source(0x%s..0x%s), "
            "result(0x%s.... len= %ld)\n",
            data_to_hexadecimal(&(ml->data_pair.data0)),
            data_to_hexadecimal(&(ml->data_pair.range)),
            data_to_hexadecimal(&(ml->data_pair.data1)),
            len));
        return (len);
}

/*
 *
 */
static void
map_range_make_result(
        char            *table,
        itm_size_t      range_start,
        itm_size_t      range_end,
        char            *result_data,
        itm_size_t      result_size)
{
        itm_size_t      i;
        itm_size_t      j;
        itm_size_t      p;
        uchar_t         *dp; /* unsigned for ++ operation */

        for (i = range_start, p = i * result_size;
            i <= range_end; i++, p += result_size) {
                (void) memcpy(table + p, result_data, result_size);
                for (j = 0, dp = (uchar_t *)(result_data + result_size - 1);
                    j < result_size;
                    j++, dp--) {
                        if (0xff != *dp) {
                                (*dp) += 1;
                                for (++dp; j > 0; j--, dp++) {
                                        (*dp) = 0x00;
                                }
                                break;
                        }
                }
        }
}

/*
 *
 */
static size_t
map_table_num_range(itmc_data_pair_t    *pair)
{
        size_t          i, j;
        itm_num_t       num;
        itm_num_t       num2;
        uchar_t         *c1;
        uchar_t         *c2;

        assert(0 < pair->range.size);
        j = pair->data0.size;
        if (j < pair->range.size)
                j = pair->range.size;
        c1 = ((uchar_t *)(NSPTR(&(pair->data0)))) + pair->data0.size - 1;
        c2 = ((uchar_t *)(NSPTR(&(pair->range)))) + pair->range.size - 1;
        num = 0;
        for (i = 0; i < j; i++, c1--, c2--) {
                if (i < pair->range.size) num2 = *c2;
                if (i < pair->data0.size) num2 -= *c1;
                TRACE_MESSAGE('G', (" num += %d(=%d-%d)\n ",
                    *c2 - *c1, *c2, *c1));
                num2 <<= (i*8);
                num += num2;
        }
        TRACE_MESSAGE('g', ("map_table_num_range: source(0x%s..0x%s), "
            "num= %ld\n",
            data_to_hexadecimal(&(pair->data0)),
            data_to_hexadecimal(&(pair->range)),
            num));
        return (num);
}

/*
 *
 */
itmc_map_t *
map_list_append(itmc_map_t      *map_list, itmc_map_t   *map_pair)
{
        if (0 == map_pair) {
                return  (map_list);
        }

        map_pair->next = NULL;
        map_pair->last = map_pair;

        if (map_list) {
                map_list->last->next = map_pair;
                map_list->last = map_pair;
                return  (map_list);
        } else {
                return  (map_pair);
        }
}



itmc_obj_t *
op_self(itm_op_type_t type)
{
        return (op_unit(type, NULL, 0, NULL, 0, NULL, 0));
}


itmc_obj_t *
op_unary(itm_op_type_t type, void       *data, size_t data_size)
{
        return (op_unit(type, data, data_size, NULL, 0, NULL, 0));
}

itmc_obj_t *
op_unit(itm_op_type_t   type,
        void    *data0, size_t data0_size,
        void    *data1, size_t data1_size,
        void    *data2, size_t data2_size)
{
        itm_op_t        *op;
        itmc_obj_t      *obj;

        op = malloc_vital(sizeof (itm_op_t));
        op->type = type;
        op->data.operand[0].itm_ptr = (itm_place2_t)(data0);
        op->data.operand[1].itm_ptr = (itm_place2_t)(data1);
        op->data.operand[2].itm_ptr = (itm_place2_t)(data2);

        obj = malloc_vital(sizeof (itmc_obj_t));
        obj->type = ITMC_OBJ_OP;
        obj->name = NULL;
        obj->obj = op;
        obj->ref[0] = obj->ref[1] = obj->ref[2] = NULL;
        if (NULL != data0) {
                obj->ref[0] = obj_register(ITMC_OBJ_EXPR, NULL,
                    data0, data0_size,
                    &(op->data.operand[0]),
                    OBJ_REG_TAIL);
        }
        if (NULL != data1) {
                obj->ref[1] = obj_register(ITMC_OBJ_EXPR, NULL,
                    data1, data1_size,
                    &(op->data.operand[1]),
                    OBJ_REG_TAIL);
        }
        if (NULL != data2) {
                obj->ref[2] = obj_register(ITMC_OBJ_EXPR, NULL,
                    data2, data2_size,
                    &(op->data.operand[2]),
                    OBJ_REG_TAIL);
        }
        obj->next = NULL;
        obj->last = NULL;

        return  (obj);
}


itmc_obj_t *
op_self_num(itm_op_type_t type, itm_num_t data)
{
        itm_op_t        *op;
        itmc_obj_t      *obj;

        op = malloc_vital(sizeof (itm_op_t));
        op->type = type;
        op->data.itm_opnum = data;
#if !defined(_LP64)
        op->data.itm_oppad = (data < 0) ? (pad_t)(~0) : 0;
#endif
        obj = malloc_vital(sizeof (itmc_obj_t));
        obj->type = ITMC_OBJ_OP;
        obj->name = NULL;
        obj->obj = op;
        obj->ref[0] = obj->ref[1] = obj->ref[2] = NULL;

        return  (obj);
}


itm_expr_t *
expr_self_num(itm_expr_type_t type, itm_num_t data)
{
        itm_expr_t      *expr;

        expr = malloc_vital(sizeof (itm_expr_t));
        expr->type = type;
        expr->data.itm_exnum = data;
#if !defined(_LP64)
        expr->data.itm_expad = (data < 0) ? (pad_t)(~0) : 0;
#endif
        return  (expr);
}


itm_expr_t *
expr_self(itm_expr_type_t type, itm_data_t      *data)
{
        itm_expr_t      *expr;
        itmc_name_t     *name;

        expr = malloc_vital(sizeof (itm_expr_t));
        expr->type = type;
        if (NULL == data) {
                expr->data.value.size = 0;
                expr->data.value.place.itm_ptr = 0;
        } else {
                expr->data.value = *(data);
        }

        switch (type) {
        case ITM_EXPR_NAME: /* register */
                name = name_lookup(data, ITMC_OBJ_REGISTER);
                if (&name_lookup_error == name) {
                        return  (NULL);
                } else if (NULL == name) {
                        if (reg_id >= MAXREGID) {
                                itm_error(
                                    gettext(
                                    "more than %d variables are used\n"),
                                    MAXREGID);
                                exit(ITMC_STATUS_BT2);
                        }
                        name = name_register(data, ITMC_OBJ_REGISTER, NULL);
                        name->reg_id = (reg_id++);
                }
                expr->type = ITM_EXPR_REG;
                expr->data.itm_exnum = name->reg_id;
#if !defined(_LP64)
                expr->data.itm_expad =
                    (expr->data.itm_exnum < 0) ? (pad_t)(~0) : 0;
#endif
                break;
        case ITM_EXPR_SEQ:
                if ((sizeof (itm_place_t)) < data->size) {
                        (void) obj_register(ITMC_OBJ_DATA, NULL,
                            (void *)(data->place.itm_ptr), data->size,
                            &(expr->data.value.place), OBJ_REG_TAIL);
                }
                break;
        }
        return  (expr);
}


itm_expr_t *
expr_unary(itm_expr_type_t type, itm_expr_t *data0)
{
        itm_expr_t      *expr;

        expr = malloc_vital(sizeof (itm_expr_t));
        expr->type = type;
        expr->data.operand[0].itm_ptr = (itm_place2_t)(data0);
        (void) obj_register(ITMC_OBJ_EXPR, NULL,
            data0, sizeof (itm_expr_t),
            &(expr->data.operand[0]), OBJ_REG_TAIL);

        return  (expr);
}


itm_expr_t *
expr_binary(itm_expr_type_t type,
            itm_expr_t          *data0, itm_expr_t      *data1)
{
        itm_expr_t      *expr;
        itm_num_t       num;
        unsigned char   *p;
        int             i;

        expr = malloc_vital(sizeof (itm_expr_t));
        expr->type = type;

        if (ITM_EXPR_SEQ == data0->type) {
                p = (unsigned char *)NSPTR(&(data0->data.value));
                for (i = 0, num = 0; i < data0->data.value.size; i++, p++) {
                        num = ((num << 8) | *p);
                }
                data0 = expr_self_num(ITM_EXPR_INT, num);
        }
        if (ITM_EXPR_SEQ == data1->type) {
                p = (unsigned char *)NSPTR(&(data1->data.value));
                for (i = 0, num = 0; i < data1->data.value.size; i++, p++) {
                        num = ((num << 8) | *p);
                }
                data1 = expr_self_num(ITM_EXPR_INT, num);
        }

        expr->data.operand[0].itm_ptr = (itm_place2_t)(data0);
        expr->data.operand[1].itm_ptr = (itm_place2_t)(data1);

        (void) obj_register(ITMC_OBJ_EXPR, NULL,
            data0, sizeof (itm_expr_t),
            &(expr->data.operand[0]), OBJ_REG_TAIL);
        (void) obj_register(ITMC_OBJ_EXPR, NULL,
            data1, sizeof (itm_expr_t),
            &(expr->data.operand[1]), OBJ_REG_TAIL);

        return  (expr);
}


itm_expr_t *
expr_binary2(itm_expr_type_t type,
                itm_expr_t *data0, itm_expr_t *data1)
{
        itm_expr_t      *expr;
        itm_num_t       num;
        unsigned char   *p;
        int             i;

        if ((NULL == data0) || (NULL == data1)) {
                return (NULL);
        }
        expr = malloc_vital(sizeof (itm_expr_t));
        expr->type = type;

        switch (data0->type) {
        case ITM_EXPR_SEQ:
                p = (unsigned char *)NSPTR(&(data0->data.value));
                for (i = 0, num = 0; i < data0->data.value.size; i++, p++) {
                        num = ((num << 8) | *p);
                }
                data0 = expr_self_num(ITM_EXPR_INT, num);
                expr->data.operand[0].itm_ptr = (itm_place2_t)(data0);
                (void) obj_register(ITMC_OBJ_EXPR, NULL,
                    data0, sizeof (itm_expr_t),
                    &(expr->data.operand[0]), OBJ_REG_TAIL);
                break;
        case ITM_EXPR_INT:
        case ITM_EXPR_REG:
        case ITM_EXPR_IN_VECTOR_D:
                expr->data.operand[0] = data0->data.operand[0];
                break;
        default:
                expr->data.operand[0].itm_ptr = (itm_place2_t)(data0);
                (void) obj_register(ITMC_OBJ_EXPR, NULL,
                    data0, sizeof (itm_expr_t),
                    &(expr->data.operand[0]), OBJ_REG_TAIL);
                break;
        }

        switch (data1->type) {
        case ITM_EXPR_SEQ:
                p = (unsigned char *)NSPTR(&(data1->data.value));
                for (i = 0, num = 0; i < data1->data.value.size; i++, p++) {
                        num = ((num << 8) | *p);
                }
                data1 = expr_self_num(ITM_EXPR_INT, num);
                expr->data.operand[1].itm_ptr = (itm_place2_t)(data1);
                (void) obj_register(ITMC_OBJ_EXPR, NULL,
                    data1, sizeof (itm_expr_t),
                    &(expr->data.operand[1]), OBJ_REG_TAIL);
                break;
        case ITM_EXPR_INT:
        case ITM_EXPR_REG:
        case ITM_EXPR_IN_VECTOR_D:
                expr->data.operand[1] = data1->data.operand[0];
                break;
        default:
                expr->data.operand[1].itm_ptr = (itm_place2_t)(data1);
                (void) obj_register(ITMC_OBJ_EXPR, NULL,
                    data1, sizeof (itm_expr_t),
                    &(expr->data.operand[1]), OBJ_REG_TAIL);
                break;
        }
        return  (expr);
}


itm_expr_t *
expr_assign(itm_expr_type_t type,
            itm_data_t          *data0, itm_expr_t      *data1)
{
        itm_expr_t      *expr;
        itmc_name_t     *name;

        expr = malloc_vital(sizeof (itm_expr_t));
        expr->type = type;
        expr->data.operand[1].itm_ptr = (itm_place2_t)(data1);

        name = name_lookup(data0, ITMC_OBJ_REGISTER);
        if (&name_lookup_error == name) {
                free(expr);
                exit(ITMC_STATUS_BT);
        } else if (NULL == name) {
                name = name_register(data0, ITMC_OBJ_REGISTER, NULL);
                name->reg_id = (reg_id++);
        }
        expr->data.operand[0].itm_ptr = name->reg_id;

        (void) obj_register(ITMC_OBJ_EXPR, NULL,
            data1, sizeof (itm_expr_t),
            &(expr->data.operand[1]), OBJ_REG_TAIL);
        return  (expr);
}


itm_expr_t *
expr_seq_to_int(itm_expr_t      *expr)
{
        itm_num_t       num;
        unsigned char   *p;
        int             i;

        if (ITM_EXPR_SEQ == expr->type) {
                if ((sizeof (itm_place_t)) < expr->data.value.size) {
                        p = (unsigned char *)(expr->data.value.place.itm_ptr);
                } else {
                        p = (unsigned char *)&(expr->data.value.place.itm_64d);
                }
                for (i = 0, num = 0;
                    i < expr->data.value.size;
                    i++, p++) {
                        num = ((num << 8) | *p);
                }
                free(expr);
                expr = expr_self_num(ITM_EXPR_INT, num);
        }
        return  (expr);
}


itmc_name_t *
name_lookup(itm_data_t          *name, itm_type_t type)
{
        itmc_name_t     *p;

        TRACE_MESSAGE('N', ("name_lookup\t: \"%-16s\" %2ld %2ld %2ld\n",
            name_to_str(name), name->size, type, name_id));

        if (0 == name->size)
                return  (NULL);
        for (p = name_first; p; p = p->next) {
                if ((name->size != p->name.size) ||
                    (memcmp(NSPTR(name), NSPTR(&(p->name)), name->size))) {
                        continue;
                }
                if ((type != p->type) &&
                    (((ITMC_OBJ_ACTION  != type) &&
                    (ITMC_OBJ_ACTION    != p->type)) ||
                    ((ITMC_OBJ_ACTION   == type) &&
                    (ITMC_OBJ_DIREC     != p->type) &&
                    (ITMC_OBJ_OP        != p->type) &&
                    (ITMC_OBJ_MAP       != p->type)) ||
                    ((ITMC_OBJ_ACTION   == p->type) &&
                    (ITMC_OBJ_DIREC     != type) &&
                    (ITMC_OBJ_OP        != type) &&
                    (ITMC_OBJ_MAP       != type)))) {
                        itm_error(
                            gettext("name type conflict: \"%1$s\" "
                            "%2$s %3$s\n"),
                            name_to_str(name),
                            itm_name_type_name[type],
                            itm_name_type_name[p->type]);
                        error_deferred += 1;
                        return (&name_lookup_error);
                } else {
                        return  (p);
                }
        }
        return  (NULL);
}


itmc_name_t *
name_refer(itm_data_t   *name, itm_type_t type, itmc_ref_t      *refp)
{
        itmc_name_t             *p;
        itmc_ref_link_t         *rl;

        p = name_lookup(name, type);

        TRACE_MESSAGE('N', ("name_refer\t: \"%-16s\" %2ld %2ld %08p %2d %08p\n",
            name_to_str(name), name->size, type, refp, name_id, p));

        if (&name_lookup_error == p) {
                return  (NULL);
        }

        rl = malloc_vital(sizeof (itmc_ref_link_t));

        rl->ref = refp;
        rl->next = NULL;

        if (NULL != p) {
                if (p->ref_last) {
                        p->ref_last->next = rl;
                } else {
                        p->ref_first = rl;
                }
                p->ref_last = rl;
        } else {
                p = malloc_vital(sizeof (itmc_name_t));
                p->id = (name_id++);
                p->reg_id = 0;
                p->name = *name;
                p->type = type;
#if !defined(_LP64)
                p->reloc.itm_pad = 0;
#endif
                p->reloc.itm_ptr = 0;
                p->ref_first = rl;
                p->ref_last = rl;
                p->next = NULL;

                if (name_last) {
                        name_last->next = p;
                } else {
                        name_first = p;
                }
                name_last = p;
        }
        return  (p);
}


itmc_name_t *
name_register(itm_data_t        *name, itm_type_t type, itmc_ref_t      *refp)
{
        itmc_name_t     *p;

        TRACE_MESSAGE('N', ("name_register\t: \"%-16s\" %2ld %2ld %08p %2ld\n",
            name_to_str(name), name->size, type, refp, name_id));


        p = name_lookup(name, type);
        if (&name_lookup_error == p) {
                return  (NULL);
        }
        if (NULL != p) {
                if (NULL != p->object) {
                        itm_error(gettext(
                            "same names are specified: %1$s\n"),
                            name_to_str(name));
                        error_deferred += 1;
                        return (NULL);
                }
                p->object = refp;
        } else {
                p = malloc_vital(sizeof (itmc_name_t));
                p->id = (name_id++);
                p->reg_id = 0;
                p->name = *name;
                p->type = type;
                p->object = refp;
                p->reloc.itm_ptr = 0;
#if !defined(_LP64)
                p->reloc.itm_pad = 0;
#endif
                p->ref_first = NULL;
                p->ref_last = NULL;
                p->next = NULL;

                if (name_last) {
                        name_last->next = p;
                } else {
                        name_first = p;
                }
                name_last = p;
        }

        return  (p);
}


int
data_compare(const itm_data_t   *d0, const itm_data_t   *d1)
{
        if (d0->size < d1->size) {
                if (memcmp(NSPTR(d0), NSPTR(d1), d0->size) < 0) {
                        return (-1);
                } else {
                        return  (1);
                }
        } else if (d0->size == d1->size) {
                return (memcmp(NSPTR(d0), NSPTR(d1), d0->size));
        } else /* (d0->size > d1->size) */ {
                if (memcmp(NSPTR(d0), NSPTR(d1), d1->size) <= 0) {
                        return (-1);
                } else {
                        return  (1);
                }
        }
}

int
data_pair_compare(itmc_data_pair_t      **p0, itmc_data_pair_t  **p1)
{
        int             r;
        itm_data_t      *d0;
        itm_data_t      *d1;
        uchar_t         *c0;
        uchar_t         *c1;
        size_t          s;
        int             i;

        d0 = &((*p0)->data0);
        d1 = &((*p1)->data0);
        c0 = NSPTR(d0);
        c1 = NSPTR(d1);
        if (d0->size == d1->size) {
                s = d0->size;
        } else if (d0->size < d1->size) {
                s = d1->size - d0->size;
                for (i = 0; i < s; i++, c1++) {
                        if (0x00 != *c1) {
                                return (-1);
                        }
                }
                s = d0->size;
        } else {
                assert(d0->size > d1->size);
                s = d0->size - d1->size;
                for (i = 0; i < s; i++, c0++) {
                        if (0x00 != *c0) {
                                return  (1);
                        }
                }
                s = d1->size;
        }
        r = memcmp(c0, c1, s);
        if (0 == r) {
                itm_data_t      *d;
                if (c0 == NSPTR(d0)) {
                        d = d0;
                } else {
                        assert(c1 == NSPTR(d0));
                        d = d1;
                }
                itm_error(gettext(
                    "distinct source values are specified: 0x%1$s\n"),
                    data_to_hexadecimal(d));
                error_deferred += 1;
        }
        return  (r);
}


static long
data_to_long(itm_data_t         *data)
{
        long            l;
        int             i;
        unsigned char   *p;

        if ((sizeof (itm_place_t)) < data->size) {
                return (0);
        }
        for (l = 0, i = 0, p = (unsigned char *)&(data->place);
            i < data->size;
            i++, p++) {
                l <<= 8;
                l |= *p;
        }
        return  (l);
}