/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
/* Header file */
#ifdef VX
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <private/mathP.h>
#endif
#include "js-runtime.h"
#include "js-scriptable.h"
#include "js-utils.h"

/* External data */
const jsString_t jsnullString = "";

/* Procedures */
void JS_MarkVal(JSContext * cx, jsVal_t val)
{
    JSGCHeap *gcHeap = &cx->runtime->gcHeap;

    if (JS_VAL_IS_OBJECT(val)) {
        if (val != JS_VAL_NULL) {
            JSScriptable *scriptable = JS_VAL_TO_OBJECT(val);

            scriptable->mark(cx);
        }
    }
    else if (JS_VAL_IS_STRING(val)) {
        jsString_t string;

        string = JS_VAL_TO_STRING(val);
        gcHeap->markObj(string);
    }
    else if (JS_VAL_IS_DOUBLE(val)) {
        double *dp;

        dp = JS_VAL_TO_DOUBLE(val);
        gcHeap->markObj(dp);
    }
}
jsString_t JS_Substring(JSContext * cx, jsString_t string, int beginIndex, int endIndex)
{
    jsString_t substr = (jsString_t) JS_NewZoneObj(cx, (endIndex - beginIndex + 1)
            * sizeof(*substr));
    memcpy(substr, string + beginIndex, (endIndex - beginIndex) * sizeof(*substr));
    substr[endIndex - beginIndex] = '\0';
    return substr;
}

#ifdef VX
static jsBool_t hasNull(int32_t i)
{
    return ((i - 0x01010101) & ~i & 0x80808080) != 0;
}
static void copy32(int32_t * dp, int32_t i)
{
    uint32_t mask = 0xff000000;

    if ((i & mask) == 0) {
        *((int8_t *) dp) = '\0';
        return;
    }
    *((int16_t *) dp) = i >> 16;

    mask >>= 8;
    if ((i & mask) == 0)
        return;

    mask >>= 8;
    if ((i & mask) == 0) {
        ((int8_t *) dp)[2] = '\0';
        return;
    }
    ((int16_t *) dp)[1] = i;
}
static int compare32(int32_t i1, int32_t i2)
{
    int c1, c2;

    c1 = (i1 >> 24) & 0xff;
    c2 = (i2 >> 24) & 0xff;
    if (c1 != c2) {
        return (c1 - c2);
    }
    if (c1 == '\0')
        return 0;

    c1 = (i1 >> 16) & 0xff;
    c2 = (i2 >> 16) & 0xff;
    if (c1 != c2) {
        return (c1 - c2);
    }
    if (c1 == '\0')
        return 0;

    c1 = (i1 >> 8) & 0xff;
    c2 = (i2 >> 8) & 0xff;
    if (c1 != c2) {
        return (c1 - c2);
    }
    if (c1 == '\0')
        return 0;

    c1 = i1 & 0xff;
    c2 = i2 & 0xff;
    return (c1 - c2);
}
static int length32(int32_t c)
{
    uint32_t mask = 0xff000000;

    if ((c & mask) == 0) {
        return 0;
    }
    mask >>= 8;
    if ((c & mask) == 0) {
        return 1;
    }
    mask >>= 8;
    if ((c & mask) == 0) {
        return 2;
    }
    return 3;
}
char *JS_strcpy(char *dst, const char *src)
{
    char *result = dst;
    int offset;
    int32_t c;

    offset = (uint32_t) dst % sizeof(int32_t);
    while (offset != 0) {
        c = *dst++ = *src++;
        if (c == '\0')
            return result;
        offset += 1;
        offset %= sizeof(int32_t);
    }
    int32_t *dp, *sp;

    offset = (uint32_t) src % sizeof(int32_t);
    dp = (int32_t *) dst;
    if (offset != 0) {
        int32_t leftShift = offset * 8;
        int32_t rightShift = sizeof(int32_t) * 8 - leftShift;

        sp = (int32_t *) (src - offset);
        c = *sp++;
        switch (offset) {
        case 1:
            if ((c & 0xff0000) == 0) {
                *dst = '\0';
                return result;
            }
            if ((c & 0xff00) == 0) {
                *((int16_t *) dst) = c >> 8;
                return result;
            }
            if ((c & 0xff) == 0) {
                *((int16_t *) dst) = c >> 8;
                *dst = '\0';
                return result;
            }
            break;
        case 2:
            if ((c & 0xff00) == 0) {
                *dst = '\0';
                return result;
            }
            else if ((c & 0xff) == 0) {
                *((int16_t *) dst) = c;
                return result;
            }
            break;
        case 3:
            if ((c & 0xff) == 0) {
                *dst = '\0';
                return result;
            }
            break;
        }
        int32_t val;

        while (TRUE) {
            val = c << leftShift;
            c = *sp++;
            val |= ((uint32_t) c) >> ((uint32_t) rightShift);
            if (hasNull(val))
                break;
            *dp++ = val;
        }
        copy32(dp, val);
    }
    else {
        sp = (int32_t *) src;
        while (TRUE) {
            c = *sp++;
            if (hasNull(c))
                break;
            *dp++ = c;
        }
        copy32(dp, c);
    }
    return result;
}
int JS_strcmp(const char *s1, const char *s2)
{
    int offset;

    offset = (uint32_t) s1 % sizeof(int32_t);
    while (offset != 0) {
        if (*s1 == *s2) {
            if (*s1 != '\0') {
                s1++;
                s2++;
            }
            else {
                return 0;
            }
        }
        else {
            return (*s1 - *s2);
        }
        offset += 1;
        offset %= sizeof(int32_t);
    }
    int32_t *sp1, *sp2;
    int32_t i1, i2;

    offset = (uint32_t) s2 % sizeof(int32_t);
    sp1 = (int32_t *) s1;
    if (offset != 0) {
        int32_t leftShift = offset * 8;
        int32_t rightShift = sizeof(int32_t) * 8 - leftShift;

        sp2 = (int32_t *) (s2 - offset);
        i2 = *sp2++;
        switch (offset) {
        case 1:
            if ((i2 & 0xff0000) == 0) {
                return *s1 - '\0';
            }
            if ((i2 & 0xff00) == 0 || (i2 & 0xff) == 0) {
                i1 = *sp1;
                return compare32(i1, i2 << 8);
            }
            break;
        case 2:
            if ((i2 & 0xff00) == 0) {
                return *s1 - '\0';
            }
            else if ((i2 & 0xff) == 0) {
                i1 = *sp1;
                return compare32(i1, i2 << 16);
            }
            break;
        case 3:
            if ((i2 & 0xff) == 0) {
                return *s1 - '\0';
            }
            break;
        }
        int32_t val;

        while (TRUE) {
            i1 = *sp1++;
            val = i2 << leftShift;
            i2 = *sp2++;
            val |= ((uint32_t) i2) >> ((uint32_t) rightShift);
            if (i1 != val)
                break;
            if (hasNull(i1))
                return 0;
        }
        return compare32(i1, val);
    }
    else {
        sp2 = (int32_t *) s2;
        while (TRUE) {
            i1 = *sp1++;
            i2 = *sp2++;
            if (i1 != i2)
                break;
            if (hasNull(i1))
                return 0;
        }
        return compare32(i1, i2);
    }
}

size_t JS_strlen(const char *s)
{
    int offset = (uint32_t) s % sizeof(int32_t);
    int n = 0;
    int32_t c;

    if (offset != 0) {
        if (offset != 2) {
            if (*s == '\0')
                return 0;
            s += 1;
            n += 1;
        }
        if (offset <= 2) {
            c = *((uint16_t *) s);
            if ((c >> 8) == '\0')
                return n;
            if ((c & 0xff) == '\0')
                return n + 1;
            s += 2;
            n += 2;
        }
    }
    int32_t *sp = (int32_t *) s;

    while (TRUE) {
        c = *sp++;
        if (hasNull(c))
            break;
        n += 4;
    }
    return n + length32(c);
}
int JS_strcasecmp(const char *s1, const char *s2)
{
    int i;

    for (i = 0; (s1[i] != '\0') && (s2[i] != '\0')
            && (tolower(s1[i]) == tolower(s2[i])); ++i);

    return (tolower(s1[i]) - tolower(s2[i]));
}
double JS_fmod(double x, double y)
{
    const double NaN = 0.0 / 0.0;
    double sign, absX, absY;

    if (isNan(x) || isNan(y))
        return NaN;
    if (y == 0.0) {
        errno = EDOM;
        return NaN;
    }
    if (x == POSITIVE_INFINITY)
        return NaN;
    if (x == 0.0)
        return x;
    if (y == POSITIVE_INFINITY)
        return x;

    sign = x >= 0.0 ? 1.0 : -1.0;
    absX = fabs(x);
    absY = fabs(y);
    return (sign * (absX - floor(absX / absY) * absY));
}
#endif /* VX */

