pymite / src / lib / string.py

# This file is Copyright 2009 Dean Hall.
# This file is part of the Python-on-a-Chip libraries.
# This software is licensed under the MIT License.
# See the LICENSE file for details.

## @file

## @package string
#  @brief Provides PyMite's string module.
#


"""__NATIVE__
#include <stdlib.h>
#include <string.h>
"""


__name__ = "string"


class _Autobox:
    def join(self, l):
        return join(self.obj, l)

    def count(self, s):
        return count(self.obj, s)

    def find(self, s):
        return find(self.obj, s)


digits = "0123456789"
hexdigits = "0123456789abcdefABCDEF"
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"


#
# Returns the integer represented by the string a [in base b].
# Optional int arg, b, may be 0 or 2 through 36; otherwise it is a ValueError.
#
def atoi(a, b):
    """__NATIVE__
    pPmObj_t pa;
    pPmObj_t pb;
    char const *pc;
    char *pend;
    long i;
    int8_t base;
    pPmObj_t pi;
    PmReturn_t retval = PM_RET_OK;

    /* Raise TypeError if it's not a string or wrong number of args, */
    pa = NATIVE_GET_LOCAL(0);
    if ((OBJ_GET_TYPE(pa) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() < 1)
        || (NATIVE_GET_NUM_ARGS() > 2))
    {
        PM_RAISE(retval, PM_RET_EX_TYPE);
        return retval;
    }

    /* Get the base, if it exists; otherwise assume 10 */
    base = 10;
    if (NATIVE_GET_NUM_ARGS() == 2)
    {
        pb = NATIVE_GET_LOCAL(1);

        /* Raise a TypeError if 2nd arg is not an int */
        if (OBJ_GET_TYPE(pb) != OBJ_TYPE_INT)
        {
            PM_RAISE(retval, PM_RET_EX_TYPE);
            return retval;
        }

        base = ((pPmInt_t)pb)->val;

        /* Raise ValueError if base is out of range */
        if ((base < 0) || (base == 1) || (base > 36))
        {
            PM_RAISE(retval, PM_RET_EX_VAL);
            return retval;
        }
    }

    /* Perform conversion */
    pend = C_NULL;
    pc = (char const *)&(((pPmString_t)pa)->val);
    i = strtol(pc, &pend, base);

    /* Raise ValueError if there was a conversion error */
    if (*pend != C_NULL)
    {
        PM_RAISE(retval, PM_RET_EX_VAL);
        return retval;
    }

    /* Create an int object to hold the result of the conversion */
    retval = int_new(i, &pi);

    NATIVE_SET_TOS(pi);

    return retval;
    """
    pass


#
# Returns the number of occurrences of substring s2 in string s1.
# WARNING: Does not match Python's behavior if s1 contains a null character.
#
def count(s1, s2):
    """__NATIVE__
    pPmObj_t ps1;
    pPmObj_t ps2;
    uint8_t *pc1;
    uint8_t *pc2;
    uint8_t *pscan;
    uint8_t *pmatch;
    uint8_t pc2c0;
    uint16_t pc1len;
    uint16_t pc2len;
    uint16_t n;
    uint16_t remaining;
    uint16_t cmp;
    pPmObj_t pn;
    PmReturn_t retval = PM_RET_OK;

    /* Raise TypeError if it's not a string or wrong number of args, */
    ps1 = NATIVE_GET_LOCAL(0);
    ps2 = NATIVE_GET_LOCAL(1);
    if ((OBJ_GET_TYPE(ps1) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() != 2)
        || (OBJ_GET_TYPE(ps2) != OBJ_TYPE_STR))
    {
        PM_RAISE(retval, PM_RET_EX_TYPE);
        return retval;
    }

    pc1 = ((pPmString_t)ps1)->val;
    pc2 = ((pPmString_t)ps2)->val;
    pc1len = ((pPmString_t)ps1)->length;
    pc2len = ((pPmString_t)ps2)->length;
    n = 0;

    /* Handle some quick special cases (order of if-clauses is important) */
    if (pc2len == 0)
    {
        n = pc1len + 1;
    }
    else if (pc1len == 0)
    {
        n = 0;
    }

    /* Count the number of matches */
    else
    {
        n = 0;
        remaining = pc1len;
        pscan = pc1;
        pc2c0 = pc2[0];
        while (pscan <= (pc1 + (pc1len - pc2len)))
        {
            /* Find the next possible start */
            pmatch = (uint8_t *)memchr(pscan, pc2c0, remaining);
            if (pmatch == C_NULL) break;
            remaining -= (pmatch - pscan);
            pscan = pmatch;

            /* If it matches, increase the count, else try the next char */
            cmp = memcmp(pscan, pc2, pc2len);
            if (cmp == 0)
            {
                n++;
                pscan += pc2len;
                remaining -= pc2len;
            }
            else
            {
                pscan++;
                remaining--;
            }
        }
    }

    retval = int_new(n, &pn);

    NATIVE_SET_TOS(pn);

    return retval;
    """
    pass


#
# Returns the lowest index in s1 where substring s2 is found or -1 on failure.
# WARNING: Does not accept optional start,end arguments.
#
def find(s1, s2):
    """__NATIVE__
    pPmObj_t ps1;
    pPmObj_t ps2;
    uint8_t *pc1;
    uint8_t *pc2;
    uint8_t *pmatch;
    uint16_t pc1len;
    uint16_t pc2len;
    int32_t n;
    pPmObj_t pn;
    PmReturn_t retval = PM_RET_OK;

    /* Raise TypeError if it's not a string or wrong number of args, */
    ps1 = NATIVE_GET_LOCAL(0);
    ps2 = NATIVE_GET_LOCAL(1);
    if ((OBJ_GET_TYPE(ps1) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() != 2)
        || (OBJ_GET_TYPE(ps2) != OBJ_TYPE_STR))
    {
        PM_RAISE(retval, PM_RET_EX_TYPE);
        return retval;
    }

    pc1 = ((pPmString_t)ps1)->val;
    pc2 = ((pPmString_t)ps2)->val;
    pc1len = ((pPmString_t)ps1)->length;
    pc2len = ((pPmString_t)ps2)->length;
    n = -1;

    /* Handle a quick special case */
    if (pc2len == 0)
    {
        n = 0;
    }

    /* Try to find the index of the substring */
    else
    {
        /* Find the next possible start */
        pmatch = (uint8_t *)memchr(pc1, pc2[0], pc1len);
        if (pmatch != C_NULL)
        {
            /* If it matches, calculate the index */
            if (memcmp(pmatch, pc2, pc2len) == 0)
            {
                n = pmatch - pc1;
            }
        }
    }

    retval = int_new(n, &pn);

    NATIVE_SET_TOS(pn);

    return retval;
    """
    pass


def join(s, sep=' '):
    len_s = len(s)
    if len_s == 0:
        return ''
    rs = s[0]
    i = 1
    while i < len_s:
        rs = rs + sep + s[i]
        i += 1
    return rs


# :mode=c:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.