/* * 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; }
/* * 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; }