root/usr/src/lib/libmp/common/util.c
/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */


/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */
/*      Portions Copyright(c) 1988, Sun Microsystems Inc.       */
/*      All Rights Reserved                                     */

/*
 * Copyright (c) 1997, by Sun Microsystems, Inc.
 * All rights reserved.
 */

#include <stdio.h>
#include <mp.h>
#include <sys/types.h>
#include "libmp.h"
#include <stdlib.h>
#include <unistd.h>

void
_mp_move(MINT *a, MINT *b)
{
        int i, j;

        _mp_xfree(b);
        b->len = a->len;
        if ((i = a->len) < 0) {
                i = -i;
        }
        if (i == 0) {
                return;
        }
        b->val = _mp_xalloc(i, "_mp_move");
        for (j = 0; j < i; j++) {
                b->val[j] = a->val[j];
        }
}

short *
_mp_xalloc(int nint, char *s __unused)
{
        short *i;

        i = malloc(sizeof (short) * ((unsigned)nint + 2)); /* ??? 2 ??? */
#ifdef DEBUG
        (void) fprintf(stderr, "%s: %p\n", s, i);
#endif
        if (i == NULL) {
                _mp_fatal("mp: no free space");
        }
        return (i);
}

void
_mp_fatal(char *s)
{
        (void) fprintf(stderr, "%s\n", s);
        (void) fflush(stdout);
        (void) sleep(2);
        abort();
}

void
_mp_xfree(MINT *c)
{
#ifdef DBG
        (void) fprintf(stderr, "xfree ");
#endif
        if (c->len != 0) {
                free(c->val);
                c->len = 0;
        }
}

void
_mp_mcan(MINT *a)
{
        int i, j;

        if ((i = a->len) == 0) {
                return;
        }
        if (i < 0) {
                i = -i;
        }
        for (j = i; j > 0 && a->val[j-1] == 0; j--)
                ;
        if (j == i) {
                return;
        }
        if (j == 0) {
                _mp_xfree(a);
                return;
        }
        if (a->len > 0) {
                a->len = j;
        } else {
                a->len = -j;
        }
}


MINT *
mp_itom(short n)
{
        MINT *a;

        a = malloc(sizeof (MINT));
        if (n > 0) {
                a->len = 1;
                a->val = _mp_xalloc(1, "mp_itom1");
                *a->val = n;
        } else if (n < 0) {
                a->len = -1;
                a->val = _mp_xalloc(1, "mp_itom2");
                *a->val = -n;
        } else {
                a->len = 0;
        }
        return (a);
}

int
mp_mcmp(MINT *a, MINT *b)
{
        MINT c;
        int res;

        _mp_mcan(a);
        _mp_mcan(b);
        if (a->len != b->len) {
                return (a->len - b->len);
        }
        c.len = 0;
        mp_msub(a, b, &c);
        res = c.len;
        _mp_xfree(&c);
        return (res);
}

/*
 * Convert hex digit to binary value
 */
static short
xtoi(char c)
{
        if (c >= '0' && c <= '9') {
                return (c - '0');
        } else if (c >= 'a' && c <= 'f') {
                return (c - 'a' + 10);
        } else if (c >= 'A' && c <= 'F') {
                return (c - 'A' + 10);
        } else {
                return (-1);
        }
}


/*
 * Convert hex key to MINT key
 */
MINT *
mp_xtom(char *key)
{
        short digit;
        MINT *m = mp_itom(0);
        MINT *d;
        MINT *sixteen;

        sixteen = mp_itom(16);
        for (; *key; key++) {
                digit = xtoi(*key);
                if (digit < 0) {
                        return (NULL);
                }
                d = mp_itom(digit);
                mp_mult(m, sixteen, m);
                mp_madd(m, d, m);
                mp_mfree(d);
        }
        mp_mfree(sixteen);
        return (m);
}

static char
itox(short d)
{
        d &= 15;
        if (d < 10) {
                return ('0' + d);
        } else {
                return ('a' - 10 + d);
        }
}

/*
 * Convert MINT key to hex key
 */
char *
mp_mtox(MINT *key)
{
        MINT *m = mp_itom(0);
        MINT *zero = mp_itom(0);
        short r;
        char *p;
        char c;
        char *s;
        char *hex;
        int size;

#define BASEBITS        (8 * (unsigned int)sizeof (short) - 1)

        if (key->len >= 0) {
                size = key->len;
        } else {
                size = -key->len;
        }
        hex = malloc((size_t)((size * BASEBITS + 3)) / 4 + (size ? 1 : 2));
        if (hex == NULL) {
                return (NULL);
        }
        _mp_move(key, m);
        p = hex;
        do {
                mp_sdiv(m, 16, m, &r);
                *p++ = itox(r);
        } while (mp_mcmp(m, zero) != 0);
        mp_mfree(m);
        mp_mfree(zero);

        *p = 0;
        for (p--, s = hex; s < p; s++, p--) {
                c = *p;
                *p = *s;
                *s = c;
        }
        return (hex);
}

/*
 * Deallocate a multiple precision integer
 */
void
mp_mfree(MINT *a)
{
        _mp_xfree(a);
        free(a);
}