/*
 * 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;
}
/*
 * Parse the next command line argument - similar to UNIX getopts().  Allow a
 * flag to specify that a file contains further arguments.
 */
static char parseopt(int argc, char **argv, char *opts, char **flags,
        int *optnrp, char **optargp)
{
    char arg, *op, *fname;
    int optnr;
    static FILE *fp = NULL;

    optnr = *optnrp;

    /* Deal with any file first. */

    fname = *flags;

    /* Support the sip5 method of passing arguments in a file. */
    if (fname == NULL && optnr < argc && argv[optnr][0] == '@')
    {
        fname = *flags = &argv[optnr][1];
        *optnrp = ++optnr;
    }

    if (fname != NULL && fp == NULL && (fp = fopen(fname,"r")) == NULL)
        fatal("Unable to open %s\n",fname);

    if (fp != NULL)
    {
        char buf[200], *cp, *fname;
        int ch;

        fname = *flags;
        cp = buf;

        while ((ch = fgetc(fp)) != EOF)
        {
            /* Skip leading whitespace. */

            if (cp == buf && isspace(ch))
                continue;

            if (ch == '\n')
                break;

            if (cp == &buf[sizeof (buf) - 1])
                fatal("A flag in %s is too long\n",fname);

            *cp++ = (char)ch;
        }

        *cp = '\0';

        if (ch == EOF)
        {
            fclose(fp);
            fp = NULL;
            *flags = NULL;
        }

        /*
         * Get the option character and any optional argument from the
         * line.
         */

        if (buf[0] != '\0')
        {
            if (buf[0] != '-' || buf[1] == '\0')
                fatal("An non-flag was given in %s\n",fname);

            arg = buf[1];

            /* Find any optional argument. */

            for (cp = &buf[2]; *cp != '\0'; ++cp)
                if (!isspace(*cp))
                    break;

            if (*cp == '\0')
                cp = NULL;
            else
                cp = sipStrdup(cp);

            *optargp = cp;

            if ((op = strchr(opts,arg)) == NULL)
                fatal("An invalid flag was given in %s\n",fname);

            if (op[1] == ':' && cp == NULL)
                fatal("Missing flag argument in %s\n",fname);

            if (op[1] != ':' && cp != NULL)
                fatal("Unexpected flag argument in %s\n",fname);

            return arg;
        }
    }

    /* Check there is an argument and it is a switch. */

    if (optnr >= argc || argv[optnr] == NULL || argv[optnr][0] != '-')
        return '\0';

    /* Check it is a valid switch. */

    arg = argv[optnr][1];

    if (arg == '\0' || (op = strchr(opts,arg)) == NULL)
        usage();

    /* Check for the switch parameter, if any. */

    if (op[1] == ':')
    {
        if (argv[optnr][2] != '\0')
        {
            *optargp = &argv[optnr][2];
            ++optnr;
        }
        else if (optnr + 1 >= argc || argv[optnr + 1] == NULL)
            usage();
        else
        {
            *optargp = argv[optnr + 1];
            optnr += 2;
        }
    }
    else if (argv[optnr][2] != '\0')
        usage();
    else
    {
        *optargp = NULL;
        ++optnr;
    }

    *optnrp = optnr;

    return arg;
}
Example #3
0
/*
 * Initialise a slot, returning 0 if there was no error.  If the signal was a
 * Qt signal, then the slot may be a Python signal or a Python slot.  If the
 * signal was a Python signal, then the slot may be anything.
 */
int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot)
{
    sp -> weakSlot = NULL;

    if (slot == NULL)
    {
        sp -> name = NULL;

        if (PyMethod_Check(rxObj))
        {
            /*
             * Python creates methods on the fly.  We could increment the
             * reference count to keep it alive, but that would keep "self"
             * alive as well and would probably be a circular reference.
             * Instead we remember the component parts and hope they are still
             * valid when we re-create the method when we need it.
             */
            sipSaveMethod(&sp -> meth,rxObj);

            /* Notice if the class instance disappears. */
            sp -> weakSlot = getWeakRef(sp -> meth.mself);

            /* This acts a flag to say that the slot is a method. */
            sp -> pyobj = NULL;
        }
        else
        {
            PyObject *self;

            /*
             * We know that it is another type of callable, ie. a
             * function/builtin.
             */

            if (PyCFunction_Check(rxObj) &&
                (self = PyCFunction_GET_SELF(rxObj)) != NULL &&
                PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type))
            {
                /*
                 * It is a wrapped C++ class method.  We can't keep a copy
                 * because they are generated on the fly and we can't take a
                 * reference as that may keep the instance (ie. self) alive.
                 * We therefore treat it as if the user had specified the slot
                 * at "obj, SLOT('meth()')" rather than "obj.meth" (see below).
                 */

                const char *meth;

                /* Get the method name. */
                meth = ((PyCFunctionObject *)rxObj) -> m_ml -> ml_name;

                if ((sp -> name = (char *)sip_api_malloc(strlen(meth) + 2)) == NULL)
                    return -1;

                /*
                 * Copy the name and set the marker that it needs converting to
                 * a built-in method.
                 */
                sp -> name[0] = '\0';
                strcpy(&sp -> name[1],meth);

                sp -> pyobj = self;
                sp -> weakSlot = getWeakRef(self);
            }
            else
            {
                /*
                 * Give the slot an extra reference to keep it alive and
                 * remember we have done so by treating weakSlot specially.
                 */
                Py_INCREF(rxObj);
                sp->pyobj = rxObj;

                Py_INCREF(Py_True);
                sp->weakSlot = Py_True;
            }
        }
    }
    else if ((sp -> name = sipStrdup(slot)) == NULL)
        return -1;
    else if (isQtSlot(slot))
    {
        /*
         * The user has decided to connect a Python signal to a Qt slot and
         * specified the slot as "obj, SLOT('meth()')" rather than "obj.meth".
         */

        char *tail;

        /* Remove any arguments. */
        if ((tail = strchr(sp -> name,'(')) != NULL)
            *tail = '\0';

        /*
         * A bit of a hack to indicate that this needs converting to a built-in
         * method.
         */
        sp -> name[0] = '\0';

        /* Notice if the class instance disappears. */
        sp -> weakSlot = getWeakRef(rxObj);

        sp -> pyobj = rxObj;
    }
    else
        /* It's a Qt signal. */
        sp -> pyobj = rxObj;

    return 0;
}