/*
 * Create a new type hint for a raw string.
 */
typeHintDef *newTypeHint(char *raw_hint)
{
    typeHintDef *thd = sipMalloc(sizeof (typeHintDef));

    thd->status = needs_parsing;
    thd->raw_hint = raw_hint;

    return thd;
}
/*
 * Copy the root node of a type hint.
 */
static typeHintNodeDef *copyTypeHintNode(sipSpec *pt, typeHintDef *thd,
        int out)
{
    typeHintNodeDef *node;

    parseTypeHint(pt, thd, out);

    if (thd->root == NULL)
        return NULL;

    node = sipMalloc(sizeof (typeHintNodeDef));
    *node = *thd->root;
    node->next = NULL;

    return node;
}
/*
 * Append a string to a list of them.
 */
void appendString(stringList **headp, const char *s)
{
    stringList *sl;

    /* Create the new entry. */

    sl = sipMalloc(sizeof (stringList));

    sl -> s = s;
    sl -> next = NULL;

    /* Append it to the list. */

    while (*headp != NULL)
        headp = &(*headp) -> next;

    *headp = sl;
}
/*
 * Look up a qualified Python type and return the corresponding node (or NULL
 * if the type should be omitted because of a recursive definition).
 */
static typeHintNodeDef *lookupType(sipSpec *pt, char *name, int out)
{
    char *sp, *ep;
    classDef *scope_cd;
    mappedTypeDef *scope_mtd;
    typeHintDef *thd;
    typeHintNodeDef *node;

    /* Start searching at the global level. */
    scope_cd = NULL;
    scope_mtd = NULL;

    sp = name;
    ep = NULL;

    while (*sp != '\0')
    {
        enumDef *ed;

        /* Isolate the next part of the name. */
        if ((ep = strchr(sp, '.')) != NULL)
            *ep = '\0';

        /* See if it's an enum. */
        if ((ed = lookupEnum(pt, sp, scope_cd, scope_mtd)) != NULL)
        {
            /* Make sure we have used the whole name. */
            if (ep == NULL)
            {
                node = sipMalloc(sizeof (typeHintNodeDef));
                node->type = enum_node;
                node->u.ed = ed;

                return node;
            }

            /* There is some left so the whole lookup has failed. */
            break;
        }

        /*
         * If we have a mapped type scope then we must be looking for an enum,
         * which we have failed to find.
         */
        if (scope_mtd != NULL)
            break;

        if (scope_cd == NULL)
        {
            mappedTypeDef *mtd;

            /*
             * We are looking at the global level, so see if it is a mapped
             * type.
             */
            if ((mtd = lookupMappedType(pt, sp)) != NULL)
            {
                /*
                 * If we have used the whole name then the lookup has
                 * succeeded.
                 */
                if (ep == NULL)
                {
                    thd = (out ? mtd->typehint_out : mtd->typehint_in);

                    if (thd != NULL && thd->status != being_parsed)
                        return copyTypeHintNode(pt, thd, out);

                    /*
                     * If we get here we have a recursively defined mapped type
                     * so we simply omit it.
                     */
                    return NULL;
                }

                /* Otherwise this is the scope for the next part. */
                scope_mtd = mtd;
            }
        }

        if (scope_mtd == NULL)
        {
            classDef *cd;

            /* If we get here then it must be a class. */
            if ((cd = lookupClass(pt, sp, scope_cd)) == NULL)
                break;

            /* If we have used the whole name then the lookup has succeeded. */
            if (ep == NULL)
            {
                thd = (out ? cd->typehint_out : cd->typehint_in);

                if (thd != NULL && thd->status != being_parsed)
                    return copyTypeHintNode(pt, thd, out);

                node = sipMalloc(sizeof (typeHintNodeDef));
                node->type = class_node;
                node->u.cd = cd;

                return node;
            }

            /* Otherwise this is the scope for the next part. */
            scope_cd = cd;
        }

        /* If we have run out of name then the lookup has failed. */
        if (ep == NULL)
            break;

        /* Repair the name and go on to the next part. */
        *ep++ = '.';
        sp = ep;
    }

    /* Repair the name. */
    if (ep != NULL)
        *ep = '.';

    /* Nothing was found. */
    node = sipMalloc(sizeof (typeHintNodeDef));
    node->type = other_node;
    node->u.name = sipStrdup(name);

    return node;
}
/*
 * Recursively parse a type hint.  Return FALSE if the parse failed.
 */
static int parseTypeHintNode(sipSpec *pt, int out, int top_level, char *start,
        char *end, typeHintNodeDef **thnp)
{
    char *cp, *name_start, *name_end;
    int have_brackets = FALSE;
    typeHintNodeDef *node, *children = NULL;

    /* Assume there won't be a node. */
    *thnp = NULL;

    /* Find the name and any opening and closing bracket. */
    strip_leading(&start, end);
    name_start = start;

    strip_trailing(start, &end);
    name_end = end;

    for (cp = start; cp < end; ++cp)
        if (*cp == '[')
        {
            typeHintNodeDef **tail = &children;

            /* The last character must be a closing bracket. */
            if (end[-1] != ']')
                return FALSE;

            /* Find the end of any name. */
            name_end = cp;
            strip_trailing(name_start, &name_end);

            for (;;)
            {
                char *pp;
                int depth;

                /* Skip the opening bracket or comma. */
                ++cp;

                /* Find the next comma, if any. */
                depth = 0;

                for (pp = cp; pp < end; ++pp)
                    if (*pp == '[')
                    {
                        ++depth;
                    }
                    else if (*pp == ']' && depth != 0)
                    {
                        --depth;
                    }
                    else if ((*pp == ',' || *pp == ']') && depth == 0)
                    {
                        typeHintNodeDef *child;

                        /* Recursively parse this part. */
                        if (!parseTypeHintNode(pt, out, FALSE, cp, pp, &child))
                            return FALSE;

                        if (child != NULL)
                        {
                            /*
                             * Append the child to the list of children.  There
                             * might not be a child if we have detected a
                             * recursive definition.
                             */
                            *tail = child;
                            tail = &child->next;
                        }

                        cp = pp;
                        break;
                    }

                if (pp == end)
                    break;
            }

            have_brackets = TRUE;

            break;
        }

    /* We must have a name unless we have empty brackets. */
    if (name_start == name_end)
    {
        if (top_level && have_brackets && children == NULL)
            return FALSE;

        /* Return the representation of empty brackets. */
        node = sipMalloc(sizeof (typeHintNodeDef));
        node->type = brackets_node;
    }
    else
    {
        char saved;
        const char *typing;

        /* Isolate the name. */
        saved = *name_end;
        *name_end = '\0';

        /* See if it is an object in the typing module. */
        if ((typing = typingModule(name_start)) != NULL)
        {
            if (strcmp(typing, "Union") == 0)
            {
                /*
                 * If there are no children assume it is because they have been
                 * omitted.
                 */
                if (children == NULL)
                    return TRUE;

                children = flatten_unions(children);
            }

            node = sipMalloc(sizeof (typeHintNodeDef));
            node->type = typing_node;
            node->u.name = typing;
            node->children = children;
        }
        else
        {
            /* Search for the type. */
            node = lookupType(pt, name_start, out);
        }

        *name_end = saved;

        /* Only objects from the typing module can have brackets. */
        if (typing == NULL && have_brackets)
            return FALSE;
    }

    *thnp = node;

    return TRUE;
}
Exemplo n.º 6
0
// Convert the Python values to a raw array.
static void *convert_values(Array *array, PyObject *values, GLenum gl_type,
        sipErrorState *estate)
{
#if PY_VERSION_HEX >= 0x02060300
    int rc = sipGetBufferInfo(values, &array->buffer);

    if (rc < 0)
    {
        *estate = sipErrorFail;
        return 0;
    }

    if (rc > 0)
    {
        // Check the buffer is compatible with what we need.
        GLenum array_type;

        switch (*array->buffer.bi_format)
        {
        case 'b':
            array_type = GL_BYTE;
            break;

        case 'B':
            array_type = GL_UNSIGNED_BYTE;
            break;

        case 'h':
            array_type = GL_SHORT;
            break;

        case 'H':
            array_type = GL_UNSIGNED_SHORT;
            break;

        case 'i':
            array_type = GL_INT;
            break;

        case 'I':
            array_type = GL_UNSIGNED_INT;
            break;

        case 'f':
            array_type = GL_FLOAT;
            break;

#if defined(SIP_FEATURE_PyQt_Desktop_OpenGL)
        case 'd':
            array_type = GL_DOUBLE;
            break;
#endif

        default:
            PyErr_Format(PyExc_TypeError, "unsupported buffer type '%s'",
                    array->buffer.bi_format);
            *estate = sipErrorFail;
            return 0;
        }

        if (array_type != gl_type)
        {
            PyErr_SetString(PyExc_TypeError,
                    "the buffer type is not the same as the array type");
            *estate = sipErrorFail;
            return 0;
        }

        return array->buffer.bi_buf;
    }
#else
    PyBufferProcs *bf = Py_TYPE(values)->tp_as_buffer;

    if (bf && bf->bf_getreadbuffer && bf->bf_getsegcount)
    {
        if (bf->bf_getsegcount(values, 0) != 1)
        {
            PyErr_SetString(PyExc_TypeError,
                    "single-segment buffer object expected");
            *estate = sipErrorFail;
            return 0;
        }

        if (bf->bf_getreadbuffer(values, 0, reinterpret_cast<void **>(&array)) < 0)
        {
            *estate = sipErrorFail;
            return 0;
        }

        Py_INCREF(values);
        array->buffer = values;

        return array;
    }
#endif

    PyObject *seq = PySequence_Fast(values,
            "array must be a sequence or a buffer");

    if (!seq)
    {
        *estate = sipErrorContinue;
        return 0;
    }

    Py_ssize_t nr_items = Sequence_Fast_Size(seq);

    if (nr_items < 1)
    {
        Py_DECREF(seq);

        PyErr_SetString(PyExc_TypeError,
                "array must have at least one element");
        *estate = sipErrorFail;
        return 0;
    }

    void (*convertor)(PyObject *, void *, Py_ssize_t);
    size_t element_size;

    switch (gl_type)
    {
    case GL_BYTE:
        convertor = convert_byte;
        element_size = sizeof (GLbyte);
        break;

    case GL_UNSIGNED_BYTE:
        convertor = convert_ubyte;
        element_size = sizeof (GLubyte);
        break;

    case GL_SHORT:
        convertor = convert_short;
        element_size = sizeof (GLshort);
        break;

    case GL_UNSIGNED_SHORT:
        convertor = convert_ushort;
        element_size = sizeof (GLushort);
        break;

    case GL_INT:
        convertor = convert_int;
        element_size = sizeof (GLint);
        break;

    case GL_UNSIGNED_INT:
        convertor = convert_uint;
        element_size = sizeof (GLuint);
        break;

    case GL_FLOAT:
        convertor = convert_float;
        element_size = sizeof (GLfloat);
        break;

#if defined(SIP_FEATURE_PyQt_Desktop_OpenGL)
#if GL_DOUBLE != GL_FLOAT
    case GL_DOUBLE:
        convertor = convert_double;
        element_size = sizeof (GLdouble);
        break;
#endif
#endif

    default:
        Py_DECREF(seq);

        PyErr_SetString(PyExc_TypeError, "unsupported GL element type");
        *estate = sipErrorFail;
        return 0;
    }

    void *data = sipMalloc(nr_items * element_size);

    if (!data)
    {
        Py_DECREF(seq);

        *estate = sipErrorFail;
        return 0;
    }

    for (Py_ssize_t i = 0; i < nr_items; ++i)
    {
        PyErr_Clear();

        convertor(Sequence_Fast_GetItem(seq, i), data, i);

        if (PyErr_Occurred())
        {
            sipFree(data);
            Py_DECREF(seq);

            *estate = sipErrorFail;
            return 0;
        }
    }

    Py_DECREF(seq);

    array->data = data;

    return data;
}