swig/Source/Swig/stype.c
Dave Beazley 9b3c9e12d2 Fixed infinite loop on enum.
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@859 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2000-09-19 16:40:54 +00:00

1649 lines
42 KiB
C

/* -----------------------------------------------------------------------------
* stype.c
*
* This file provides general support for datatypes that are encoded in
* the form of simple strings.
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 1999-2000. The University of Chicago
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
static char cvsroot[] = "$Header$";
#include "swig.h"
#include <ctype.h>
/* -----------------------------------------------------------------------------
* Synopsis
*
* The purpose of this module is to provide a general purpose type representation
* based on simple text strings.
*
* General idea:
*
* Types are represented by a base type (e.g., "int") and a collection of
* type operators applied to the base (e.g., pointers, arrays, etc...).
*
* Encoding:
*
* Types are encoded as strings of type constructors such as follows:
*
* String Encoding C Example
* --------------- ---------
* p.p.int int **
* a(300).a(400).int int [300][400]
* p.q(const).char char const *
*
* All type constructors are denoted by a trailing '.':
*
* 'p.' = Pointer
* 'r.' = Reference
* 'a(n).' = Array of size n
* 'f(..,..).' = Function with arguments
* 'q(str).' = Qualifier (such as const or volatile)
* 't(...).' = Template specifier???
*
* The encoding follows the order that you might describe a type in words.
* For example "p.a(200).int" is "A pointer to array of int's" and
* "p.q(const).char" is "a pointer to a const char".
*
* This representation of types is fairly convenient because ordinary string
* operations can be used for type manipulation. For example, a type could be
* formed by combining two strings such as the following:
*
* "p.p." + "a(400).int" = "p.p.a(400).int"
*
* Similarly, one could strip a 'const' declaration from a type doing something
* like this:
*
* Replace(t,"q(const).","",DOH_REPLACE_ANY)
*
* For the most part, this module tries to minimize the use of special
* characters (*, [, <, etc...) in its type encoding. One reason for this
* is that SWIG might be extended to encode data in formats such as XML
* where you might want to do this:
*
* <function>
* <type>p.p.int</type>
* ...
* </function>
*
* Or alternatively,
*
* <function type="p.p.int" ...>blah</function>
*
* In either case, it's probably best to avoid characters such as '&', '*', or '<'.
*
* Why not use C syntax? Well, C syntax is fairly complicated to parse
* and not particularly easy to manipulate---especially for adding, deleting and
* composing type constructors. The string representation presented here makes
* this pretty easy.
*
* Why not use a bunch of nested data structures? Are you kidding? How
* would that be easier to use than a few simple string operations?
* ----------------------------------------------------------------------------- */
SwigType *NewSwigType(int t) {
switch(t) {
case T_BOOL:
return NewString("bool");
break;
case T_INT:
return NewString("int");
break;
case T_UINT:
return NewString("unsigned int");
break;
case T_SHORT:
return NewString("short");
break;
case T_USHORT:
return NewString("unsigned short");
break;
case T_LONG:
return NewString("long");
break;
case T_ULONG:
return NewString("unsigned long");
break;
case T_FLOAT:
return NewString("float");
break;
case T_DOUBLE:
return NewString("double");
break;
case T_CHAR:
return NewString("char");
break;
case T_SCHAR:
return NewString("signed char");
break;
case T_UCHAR:
return NewString("unsigned char");
break;
case T_VOID:
return NewString("void");
break;
default :
return NewString("");
break;
}
}
/* -----------------------------------------------------------------------------
* SwigType_add_pointer()
*
* Adds a pointer constructor to a type
* ----------------------------------------------------------------------------- */
void
SwigType_add_pointer(SwigType *t) {
Insert(t,0,"p.");
}
void
SwigType_del_pointer(SwigType *t) {
char *c = Char(t);
if (strncmp(c,"p.",2)) {
printf("Fatal error. SwigType_del_pointer applied to non-pointer.\n");
abort();
}
Replace(t,"p.","", DOH_REPLACE_ANY | DOH_REPLACE_FIRST);
}
/* -----------------------------------------------------------------------------
* SwigType_add_array()
*
* Adds an array constructor to a type
* ----------------------------------------------------------------------------- */
void
SwigType_add_array(SwigType *t, String *size) {
char temp[256];
sprintf(temp,"a(%s).", Char(size));
Insert(t,0,temp);
}
/* -----------------------------------------------------------------------------
* SwigType_add_reference()
*
* Adds a reference constructor to a type.
* ----------------------------------------------------------------------------- */
void
SwigType_add_reference(SwigType *t) {
Insert(t,0,"r.");
}
/* -----------------------------------------------------------------------------
* SwigType_add_qualifier()
*
* Adds a qualifier to a type
* ----------------------------------------------------------------------------- */
void
SwigType_add_qualifier(SwigType *t, String *qual) {
char temp[256];
sprintf(temp,"q(%s).",Char(qual));
Insert(t,0,temp);
}
/* -----------------------------------------------------------------------------
* SwigType_add_function()
*
* Adds a function to a type. Accepts a list of abstract types as parameters.
* These abstract types should be passed as a list of type-strings.
* ----------------------------------------------------------------------------- */
void
SwigType_add_function(SwigType *t, List *parms) {
String *pstr;
int i,l;
Insert(t,0,").");
pstr = NewString("f(");
l = Len(parms);
for (i = 0; i < l; i++) {
Printf(pstr,"%s",Getitem(parms,i));
if (i < (l-1))
Putc(',',pstr);
}
Insert(t,0,pstr);
Delete(pstr);
}
/* -----------------------------------------------------------------------------
* static isolate_element()
*
* Isolate a single element of a type string (delimeted by periods)
* ----------------------------------------------------------------------------- */
static String *
isolate_element(char *c) {
String *result = NewString("");
while (*c) {
if (*c == '.') {
Putc(*c,result);
return result;
}
else if (*c == '(') {
int nparen = 1;
Putc(*c,result);
c++;
while(*c) {
Putc(*c,result);
if (*c == '(') nparen++;
if (*c == ')') {
nparen--;
if (nparen == 0) break;
}
c++;
}
} else {
Putc(*c,result);
}
if (*c) c++;
}
return result;
}
/* -----------------------------------------------------------------------------
* SwigType_split()
*
* Splits a type into it's component parts and returns a list of string.
* ----------------------------------------------------------------------------- */
List *SwigType_split(SwigType *t) {
DOH *item;
List *list;
char *c;
int len;
c = Char(t);
list = NewList();
while (*c) {
item = isolate_element(c);
len = Len(item);
if (len) {
Append(list,item);
Delete(item);
} else {
Delete(item);
break;
}
c = c + len;
if (*c == '.') c++;
}
return list;
}
/* -----------------------------------------------------------------------------
* SwigType_pop()
*
* Pop off the first type-constructor object and updates the type
* ----------------------------------------------------------------------------- */
String *SwigType_pop(SwigType *t)
{
String *result;
char *c;
if (Len(t) == 0) return 0;
c = Char(t);
result = isolate_element(c);
Replace(t,result,"",DOH_REPLACE_ANY | DOH_REPLACE_FIRST);
c = Char(t);
if (*c == '.') {
Delitem(t,0);
}
return result;
}
/* -----------------------------------------------------------------------------
* SwigType_push()
*
* Push a type constructor onto the type
* ----------------------------------------------------------------------------- */
void SwigType_push(SwigType *t, String *cons)
{
if (!cons) return;
if (!Len(cons)) return;
if (Len(t)) {
char *c = Char(cons);
if (c[strlen(c)-1] != '.')
Insert(t,0,".");
}
Insert(t,0,cons);
}
/* -----------------------------------------------------------------------------
* SwigType_parmlist()
*
* Splits a comma separated list of components into strings.
* ----------------------------------------------------------------------------- */
List *SwigType_parmlist(String *p) {
DOH *item;
List *list;
char *c;
c = Char(p);
while (*c && (*c != '(') && (*c != '.')) c++;
if (!*c || (*c == '.')) return 0;
c++;
list = NewList();
item = NewString("");
while (*c) {
if (*c == ',') {
Append(list,item);
Delete(item);
item = NewString("");
} else if (*c == '(') {
int nparens = 1;
Putc(*c,item);
c++;
while (*c) {
Putc(*c,item);
if (*c == '(') nparens++;
if (*c == ')') {
nparens--;
if (nparens == 0) break;
}
c++;
}
} else if (*c == ')') {
break;
} else {
Putc(*c,item);
}
if (*c)
c++;
}
Append(list,item);
Delete(item);
return list;
}
/* -----------------------------------------------------------------------------
* SwigType_parm()
*
* Returns the parameter of an operator as a string
* ----------------------------------------------------------------------------- */
String *SwigType_parm(SwigType *t) {
String *result;
char *c;
int nparens = 0;
c = Char(t);
while (*c && (*c != '(') && (*c != '.')) c++;
if (!*c || (*c == '.')) return 0;
c++;
result = NewString("");
while (*c) {
if (*c == ')') {
if (nparens == 0) return result;
nparens--;
} else if (*c == '(') {
nparens++;
}
Putc(*c,result);
c++;
}
return result;
}
/* -----------------------------------------------------------------------------
* SwigType_ispointer()
* SwigType_isarray()
* SwigType_isreference()
* SwigType_isfunction()
* SwigType_isqualifier()
*
* Testing functions for querying a datatype
* ----------------------------------------------------------------------------- */
int SwigType_ispointer(SwigType *t) {
char *c;
c = Char(t);
if (strncmp(c,"p.",2) == 0) {
return 1;
}
return 0;
}
int SwigType_isreference(SwigType *t) {
char *c;
c = Char(t);
if (strncmp(c,"r.",2) == 0) {
return 1;
}
return 0;
}
int SwigType_isarray(SwigType *t) {
char *c;
c = Char(t);
if (strncmp(c,"a(",2) == 0) {
return 1;
}
return 0;
}
int SwigType_isfunction(SwigType *t) {
char *c;
c = Char(t);
if (strncmp(c,"f(",2) == 0) {
return 1;
}
return 0;
}
int SwigType_isqualifier(SwigType *t) {
char *c;
c = Char(t);
if (strncmp(c,"q(",2) == 0) {
return 1;
}
return 0;
}
int SwigType_isconst(SwigType *t) {
char *c;
c = Char(t);
if (strncmp(c,"q(const)",8) == 0) {
return 1;
}
return 0;
}
int SwigType_isenum(SwigType *t) {
char *c = Char(t);
if (strncmp(c,"enum ",5) == 0) {
return 1;
}
return 0;
}
/* -----------------------------------------------------------------------------
* SwigType_base()
*
* Returns the base name of a datatype.
* ----------------------------------------------------------------------------- */
SwigType *SwigType_base(SwigType *t) {
char *c, *d;
c = Char(t);
d = c + strlen(c);
while (d > c) {
d--;
if (*d == '.') return Swig_temp_result(NewString(d+1));
}
return Swig_temp_result(NewString(c));
}
void SwigType_setbase(SwigType *t, String_or_char *n) {
SwigType *p;
p = SwigType_prefix(t);
Clear(t);
Append(t,p);
Append(t,n);
Delete(p);
}
/* -----------------------------------------------------------------------------
* SwigType_prefix()
*
* Returns the prefix of a datatype
* ----------------------------------------------------------------------------- */
String *SwigType_prefix(SwigType *t) {
char *c, *d;
String *r = 0;
c = Char(t);
d = c + strlen(c);
while (d > c) {
d--;
if (*d == '.') {
char t = *(d+1);
*(d+1) = 0;
r = NewString(c);
*(d+1) = t;
return r;
}
}
return NewString("");
}
/* -----------------------------------------------------------------------------
* SwigType_array_ndim()
*
* Returns the number of dimensions of an array.
* ----------------------------------------------------------------------------- */
int SwigType_array_ndim(SwigType *t) {
int ndim = 0;
char *c = Char(t);
while (c && (strncmp(c,"a(",2) == 0)) {
c = strchr(c,'.');
c++;
ndim++;
}
return ndim;
}
/* -----------------------------------------------------------------------------
* SwigType_array_getdim()
*
* Get the value of the nth dimension.
* ----------------------------------------------------------------------------- */
String *SwigType_array_getdim(SwigType *t, int n) {
char *c = Char(t);
while (c && (strncmp(c,"a(",2) == 0) && (n > 0)) {
c = strchr(c,'.');
c++;
n--;
}
if (n == 0) return Swig_temp_result(SwigType_parm(c));
return 0;
}
/* -----------------------------------------------------------------------------
* SwigType_array_setdim()
*
* Replace the nth dimension of an array to a new value.
* ----------------------------------------------------------------------------- */
void SwigType_array_setdim(SwigType *t, int n, String_or_char *rep) {
String *result = 0;
char temp;
char *start;
char *c = Char(t);
start = c;
if (strncmp(c,"a(",2)) abort;
while (c && (strncmp(c,"a(",2) == 0) && (n > 0)) {
c = strchr(c,'.');
c++;
n--;
}
if (n == 0) {
temp = *c;
*c = 0;
result = NewString(start);
Printf(result,"a(%s)",rep);
*c = temp;
c = strchr(c,'.');
Append(result,c);
}
Clear(t);
Append(t,result);
Delete(result);
}
/* -----------------------------------------------------------------------------
* SwigType_default()
*
* Create the default string for this datatype. This takes a type and strips it
* down to its most primitive form--resolving all typedefs and removing operators.
*
* Rules:
* Pointers: p.SWIGPOINTER
* References: r.SWIGREFERENCE
* Arrays: a().SWIGARRAY
* Types: SWIGTYPE
*
* ----------------------------------------------------------------------------- */
static Hash *default_cache = 0;
SwigType *SwigType_default(SwigType *t) {
String *r1, *def;
String *r = 0;
if (!default_cache) default_cache = NewHash();
r = Getattr(default_cache,t);
if (r) return Copy(r);
r = t;
while ((r1 = SwigType_typedef_resolve(r))) {
if (r != t) Delete(r);
r = r1;
}
if (SwigType_ispointer(r)) {
def = NewString("p.SWIGPOINTER");
} else if (SwigType_isreference(r)) {
def = NewString("r.SWIGREFERENCE");
} else if (SwigType_isarray(r)) {
def = NewString("a().SWIGARRAY");
} else {
def = NewString("SWIGTYPE");
}
if (r != t) Delete(r);
Setattr(default_cache,t,Copy(def));
return def;
}
/* -----------------------------------------------------------------------------
* SwigType_str(DOH *s, DOH *id)
*
* Create a C string representation of a datatype.
* ----------------------------------------------------------------------------- */
String *
SwigType_str(SwigType *s, const String_or_char *id)
{
String *result;
String *element = 0, *nextelement;
List *elements;
int nelements, i;
if (id) {
result = NewString(Char(id));
} else {
result = NewString("");
}
elements = SwigType_split(s);
nelements = Len(elements);
if (nelements > 0) {
element = Getitem(elements,0);
}
/* Now, walk the type list and start emitting */
for (i = 0; i < nelements; i++) {
if (i < (nelements - 1)) {
nextelement = Getitem(elements,i+1);
} else {
nextelement = 0;
}
if (SwigType_ispointer(element)) {
Insert(result,0,"*");
if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
Insert(result,0,"(");
Append(result,")");
}
}
else if (SwigType_isreference(element)) Insert(result,0,"&");
else if (SwigType_isarray(element)) {
DOH *size;
Append(result,"[");
size = SwigType_parm(element);
Append(result,size);
Append(result,"]");
Delete(size);
} else if (SwigType_isfunction(element)) {
DOH *parms, *p;
int j, plen;
Append(result,"(");
parms = SwigType_parmlist(element);
plen = Len(parms);
for (j = 0; j < plen; j++) {
p = SwigType_str(Getitem(parms,j),0);
Append(result,p);
if (j < (plen-1)) Append(result,",");
}
Append(result,")");
Delete(parms);
} else if (SwigType_isqualifier(element)) {
DOH *q = 0;
q = SwigType_parm(element);
Insert(result,0," ");
Insert(result,0,q);
Delete(q);
} else {
Insert(result,0," ");
Insert(result,0,element);
}
element = nextelement;
}
Delete(elements);
return Swig_temp_result(result);
}
/* -----------------------------------------------------------------------------
* SwigType_lstr(DOH *s, DOH *id)
*
* Produces a type-string that is suitable as a lvalue in an expression.
* That is, a type that can be freely assigned a value without violating
* any C assignment rules.
*
* - Qualifiers such as 'const' and 'volatile' are stripped.
* - Arrays are converted into a *single* pointer (i.e.,
* double [][] becomes double *).
* - References are converted into a pointer.
* - Typedef names that refer to read-only types will be replaced
* with an equivalent assignable version.
* -------------------------------------------------------------------- */
String *
SwigType_lstr(SwigType *s, const String_or_char *id)
{
String *result;
String *element = 0, *nextelement;
List *elements;
int nelements, i;
int firstarray = 1;
SwigType *td, *rs, *tc = 0;
if (id) {
result = NewString(Char(id));
} else {
result = NewString("");
}
if (SwigType_isconst(s)) {
tc = Copy(s);
Delete(SwigType_pop(tc));
rs = tc;
} else {
rs = s;
}
td = SwigType_typedef_resolve(rs);
if ((td) && (SwigType_isconst(td) || SwigType_isarray(td))) {
elements = SwigType_split(td);
} else if (td && SwigType_isenum(td)) {
elements = SwigType_split("int");
} else {
elements = SwigType_split(rs);
}
if (td) Delete(td);
nelements = Len(elements);
if (nelements > 0) {
element = Getitem(elements,0);
}
/* Now, walk the type list and start emitting */
for (i = 0; i < nelements; i++) {
if (i < (nelements - 1)) {
nextelement = Getitem(elements,i+1);
} else {
nextelement = 0;
}
if (SwigType_ispointer(element)) {
Insert(result,0,"*");
if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
Insert(result,0,"(");
Append(result,")");
}
firstarray = 0;
} else if (SwigType_isreference(element)) {
Insert(result,0,"*");
} else if (SwigType_isarray(element)) {
if (firstarray) {
Insert(result,0,"*");
while (nextelement && (SwigType_isarray(nextelement))) {
i++;
nextelement = Getitem(elements,i+1);
}
if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
Insert(result,0,"(");
Append(result,")");
}
firstarray = 0;
} else {
DOH *size;
Append(result,"[");
size = SwigType_parm(element);
Append(result,size);
Append(result,"]");
Delete(size);
}
} else if (SwigType_isfunction(element)) {
DOH *parms, *p;
int j, plen;
Append(result,"(");
parms = SwigType_parmlist(element);
plen = Len(parms);
for (j = 0; j < plen; j++) {
p = SwigType_str(Getitem(parms,j),0);
Append(result,p);
if (j < (plen-1)) Append(result,",");
}
Append(result,")");
Delete(parms);
} else if (SwigType_isqualifier(element)) {
} else {
Insert(result,0," ");
Insert(result,0,element);
}
element = nextelement;
}
Delete(elements);
if (tc) Delete(tc);
return Swig_temp_result(result);
}
/* -----------------------------------------------------------------------------
* SwigType_ltype(SwigType *ty)
*
* Returns a type object corresponding to the string created by lstr
* ----------------------------------------------------------------------------- */
SwigType *
SwigType_ltype(SwigType *s) {
String *result;
String *element, *nextelement;
SwigType *td, *rs, *tc = 0;
List *elements;
int nelements, i;
int firstarray = 1;
result = NewString("");
if (SwigType_isconst(s)) {
tc = Copy(s);
Delete(SwigType_pop(tc));
rs = tc;
} else {
rs = s;
}
td = SwigType_typedef_resolve(rs);
if ((td) && (SwigType_isconst(td) || SwigType_isarray(td))) {
elements = SwigType_split(td);
} else if (td && SwigType_isenum(td)) {
elements = SwigType_split("int");
} else {
elements = SwigType_split(rs);
}
if (td) Delete(td);
nelements = Len(elements);
/* Now, walk the type list and start emitting */
for (i = 0; i < nelements; i++) {
element = Getitem(elements,i);
if (SwigType_ispointer(element)) {
Append(result,element);
firstarray = 0;
} else if (SwigType_isreference(element)) {
Append(result,"p.");
} else if (SwigType_isarray(element)) {
if (firstarray) {
Append(result,"p.");
while (i < (nelements - 1)) {
element = Getitem(elements,i+1);
if (!SwigType_isarray(element)) break;
i++;
}
firstarray = 0;
} else {
Append(result,element);
}
} else if (SwigType_isfunction(element)) {
Append(result,element);
} else if (SwigType_isqualifier(element)) {
} else {
Append(result,element);
}
element = nextelement;
}
Delete(elements);
if (tc) Delete(tc);
return result;
}
/* -----------------------------------------------------------------------------
* SwigType_rcaststr()
*
* Produces a casting string that maps the type returned by lstr() to the real
* datatype printed by str().
* ----------------------------------------------------------------------------- */
String *SwigType_rcaststr(SwigType *s, const String_or_char *name) {
String *result, *cast;
String *element = 0, *nextelement;
SwigType *td, *rs, *tc = 0;
List *elements;
int nelements, i;
int clear = 1;
int firstarray = 1;
result = NewString("");
if (SwigType_isconst(s)) {
tc = Copy(s);
Delete(SwigType_pop(tc));
rs = tc;
} else {
rs = s;
}
td = SwigType_typedef_resolve(rs);
if ((td) && (SwigType_isconst(td) || SwigType_isarray(td))) {
elements = SwigType_split(td);
} else if (td && SwigType_isenum(td)) {
elements = SwigType_split(rs);
clear = 0;
} else {
elements = SwigType_split(rs);
}
if (td) Delete(td);
nelements = Len(elements);
if (nelements > 0) {
element = Getitem(elements,0);
}
/* Now, walk the type list and start emitting */
for (i = 0; i < nelements; i++) {
if (i < (nelements - 1)) {
nextelement = Getitem(elements,i+1);
} else {
nextelement = 0;
}
if (SwigType_ispointer(element)) {
Insert(result,0,"*");
if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) {
Insert(result,0,"(");
Append(result,")");
}
firstarray = 0;
} else if (SwigType_isreference(element)) {
Insert(result,0,"&");
} else if (SwigType_isarray(element)) {
DOH *size;
if (firstarray) {
Append(result,"(*)");
firstarray = 0;
} else {
Append(result,"[");
size = SwigType_parm(element);
Append(result,size);
Append(result,"]");
Delete(size);
clear = 0;
}
} else if (SwigType_isfunction(element)) {
DOH *parms, *p;
int j, plen;
Append(result,"(");
parms = SwigType_parmlist(element);
plen = Len(parms);
for (j = 0; j < plen; j++) {
p = SwigType_str(Getitem(parms,j),0);
Append(result,p);
if (j < (plen-1)) Append(result,",");
}
Append(result,")");
Delete(parms);
} else if (SwigType_isqualifier(element)) {
DOH *q = 0;
q = SwigType_parm(element);
Insert(result,0," ");
Insert(result,0,q);
Delete(q);
clear = 0;
} else {
Insert(result,0," ");
Insert(result,0,element);
}
element = nextelement;
}
Delete(elements);
if (clear) {
cast = NewString("");
} else {
cast = NewStringf("(%s)",result);
}
if (name) {
if (SwigType_isreference(s)) {
Append(cast,"*");
}
Append(cast,name);
}
Delete(result);
Delete(tc);
return Swig_temp_result(cast);
}
/* -----------------------------------------------------------------------------
* SwigType_lcaststr()
*
* Casts a variable from the real type to the local datatype.
* ----------------------------------------------------------------------------- */
String *SwigType_lcaststr(SwigType *s, const String_or_char *name) {
String *result;
result = NewString("");
if (SwigType_isarray(s)) {
Printf(result,"(%s)%s", SwigType_lstr(s,0),name);
} else if (SwigType_isreference(s)) {
Printf(result,"(%s)", SwigType_lstr(s,0));
if (name)
Printf(result,"&%s", name);
} else if (SwigType_isqualifier(s)) {
Printf(result,"(%s)%s", SwigType_lstr(s,0),name);
} else {
if (name)
Append(result,name);
}
return Swig_temp_result(result);
}
String *SwigType_manglestr_default(SwigType *s) {
char *c;
String *result;
if (SwigType_istypedef(s))
result = Copy(s);
else
result = SwigType_ltype(s);
Replace(result,"struct ","", DOH_REPLACE_ANY);
Replace(result,"class ","", DOH_REPLACE_ANY);
Replace(result,"union ","", DOH_REPLACE_ANY);
c = Char(result);
while (*c) {
if (!isalnum(*c)) *c = '_';
c++;
}
Insert(result,0,"_");
return Swig_temp_result(result);
}
String *SwigType_manglestr(SwigType *s) {
return SwigType_manglestr_default(s);
}
/* -----------------------------------------------------------------------------
* Scope handling
*
* These functions are used to manipulate typedefs and scopes.
* ----------------------------------------------------------------------------- */
#define MAX_SCOPE 8
static Hash *type_scopes = 0; /* Hash table of scope names */
static Hash *scopes[MAX_SCOPE]; /* List representing the current scope */
static String *scopenames[MAX_SCOPE]; /* Names of the various scopes */
static int scope_level = 0;
static void init_scopes() {
if (type_scopes) return;
type_scopes = NewHash();
scopes[scope_level] = NewHash();
scopenames[scope_level] = NewString("::");
Setattr(type_scopes,"::",scopes[scope_level]);
}
/* -----------------------------------------------------------------------------
* SwigType_typedef()
*
* Defines a new typedef. Returns -1 if the type name is already defined.
* ----------------------------------------------------------------------------- */
int SwigType_typedef(SwigType *type, String_or_char *name) {
init_scopes();
if (Getattr(scopes[scope_level],name)) return -1;
if (Cmp(type,name) == 0) {
return 0;
}
Setattr(scopes[scope_level],name,type);
if (default_cache)
Delattr(default_cache,type);
return 0;
}
/* -----------------------------------------------------------------------------
* SwigType_new_scope()
*
* Creates a new scope
* ----------------------------------------------------------------------------- */
void SwigType_new_scope() {
init_scopes();
scope_level++;
scopes[scope_level] = NewHash();
scopenames[scope_level] = NewString("");
}
/* -----------------------------------------------------------------------------
* SwigType_reset_scopes()
*
* Reset the scope system
* ----------------------------------------------------------------------------- */
void SwigType_reset_scopes() {
Delete(type_scopes);
type_scopes = 0;
init_scopes();
}
/* -----------------------------------------------------------------------------
* SwigType_set_scope_name()
*
* Set the name of the current scope. Note: this will create an entry in the
* type_scopes hash.
* ----------------------------------------------------------------------------- */
void SwigType_set_scope_name(String_or_char *name) {
String *key;
int i;
init_scopes();
scopenames[scope_level] = NewString(Char(name));
key = NewString("");
for (i = 1; i <= scope_level; i++) {
Append(key,scopenames[scope_level]);
if (i < scope_level) Append(key,"::");
}
Setattr(type_scopes,key,scopes[scope_level]);
}
/* -----------------------------------------------------------------------------
* SwigType_merge_scope()
*
* Merges the contents of one scope into the current scope.
* ----------------------------------------------------------------------------- */
void SwigType_merge_scope(Hash *scope, String_or_char *prefix) {
String *name;
String *key;
String *type;
init_scopes();
key = Firstkey(scope);
while (key) {
type = Getattr(scope,key);
if (prefix) {
name = NewStringf("%s::%s",prefix,key);
} else {
name = NewString(key);
}
Setattr(scopes[scope_level],name,type);
key = Nextkey(scope);
}
}
/* -----------------------------------------------------------------------------
* SwigType_pop_scope()
*
* Pop off the last scope and perform a merge operation. Returns the hash
* table for the scope that was popped off.
* ----------------------------------------------------------------------------- */
Hash *SwigType_pop_scope() {
Hash *s;
String *prefix;
init_scopes();
if (scope_level == 0) return 0;
prefix = scopenames[scope_level];
s = scopes[scope_level--];
SwigType_merge_scope(s,prefix);
return s;
}
/* -----------------------------------------------------------------------------
* SwigType_typedef_resolve()
*
* Resolves a typedef and returns a new type string. Returns 0 if there is no
* typedef mapping.
* ----------------------------------------------------------------------------- */
SwigType *SwigType_typedef_resolve(SwigType *t) {
String *base;
String *type;
String *r;
int level;
init_scopes();
base = SwigType_base(t);
level = scope_level;
while (level >= 0) {
/* See if we know about this type */
type = Getattr(scopes[scope_level],base);
if (type) break;
level--;
}
if (level < 0) {
return 0;
}
r = SwigType_prefix(t);
Append(r,type);
return r;
}
/* -----------------------------------------------------------------------------
* SwigType_typedef_resolve_all()
*
* Fully resolve a type down to its most basic datatype
* ----------------------------------------------------------------------------- */
SwigType *SwigType_typedef_resolve_all(SwigType *t) {
SwigType *n;
SwigType *r = Copy(t);
while ((n = SwigType_typedef_resolve(r))) {
Delete(r);
r = n;
}
return r;
}
/* -----------------------------------------------------------------------------
* SwigType_istypedef()
*
* Checks a typename to see if it is a typedef.
* ----------------------------------------------------------------------------- */
int SwigType_istypedef(SwigType *t) {
String *base, *type;
int level;
init_scopes();
base = SwigType_base(t);
level = scope_level;
while (level >= 0) {
/* See if we know about this type */
type = Getattr(scopes[scope_level],base);
if (type) {
return 1;
}
level--;
}
return 0;
}
/* -----------------------------------------------------------------------------
* SwigType_cmp()
*
* Compares two type-strings using all available typedef information. Returns 0
* if equal, 1 if not.
* ----------------------------------------------------------------------------- */
int SwigType_cmp(SwigType *tpat, SwigType *type) {
String *r, *s;
char *p, *t;
p = Char(tpat);
t = Char(type);
if (strcmp(p,t) == 0) return 0;
r = SwigType_typedef_resolve(type);
while (r) {
t = Char(r);
if (strcmp(p,t) == 0) {
Delete(r);
return 0;
}
s = SwigType_typedef_resolve(r);
Delete(r);
r = s;
}
return 1;
}
/* -----------------------------------------------------------------------------
* SwigType_type()
*
* Returns an integer code describing the datatype. This is only used for
* compatibility with SWIG1.1 language modules and is likely to go away once
* everything is based on typemaps.
* ----------------------------------------------------------------------------- */
int SwigType_type(SwigType *t)
{
char *c;
/* Check for the obvious stuff */
c = Char(t);
if (strncmp(c,"p.",2) == 0) {
if (SwigType_type(c+2) == T_CHAR) return T_STRING;
else return T_POINTER;
}
if (strncmp(c,"a(",2) == 0) return T_ARRAY;
if (strncmp(c,"r.",2) == 0) return T_REFERENCE;
if (strncmp(c,"q(",2) == 0) {
while(*c && (*c != '.')) c++;
if (*c) return SwigType_type(c+1);
return T_ERROR;
}
if (strncmp(c,"f(",2) == 0) return T_FUNCTION;
/* Look for basic types */
if (strcmp(c,"int") == 0) return T_INT;
if (strcmp(c,"long") == 0) return T_LONG;
if (strcmp(c,"short") == 0) return T_SHORT;
if (strcmp(c,"unsigned") == 0) return T_UINT;
if (strcmp(c,"unsigned short") == 0) return T_USHORT;
if (strcmp(c,"unsigned long") == 0) return T_ULONG;
if (strcmp(c,"unsigned int") == 0) return T_UINT;
if (strcmp(c,"char") == 0) return T_CHAR;
if (strcmp(c,"signed char") == 0) return T_SCHAR;
if (strcmp(c,"unsigned char") == 0) return T_UCHAR;
if (strcmp(c,"float") == 0) return T_FLOAT;
if (strcmp(c,"double") == 0) return T_DOUBLE;
if (strcmp(c,"void") == 0) return T_VOID;
if (strcmp(c,"bool") == 0) return T_BOOL;
if (strncmp(c,"enum ",5) == 0) return T_INT;
/* Hmmm. Unknown type */
if (SwigType_istypedef(t)) {
int r;
SwigType *nt = SwigType_typedef_resolve(t);
r = SwigType_type(nt);
Delete(nt);
return r;
}
return T_USER;
}
/* -----------------------------------------------------------------------------
* SwigType_remember()
*
* This function "remembers" a datatype that was used during wrapper code generation
* so that a type-checking table can be generated later on. It is up to the language
* modules to actually call this function--it is not done automatically.
*
* Type tracking is managed through two separate hash tables. The hash 'r_mangled'
* is mapping between mangled type names (used in the target language) and
* fully-resolved C datatypes used in the source input. The second hash 'r_resolved'
* is the inverse mapping that maps fully-resolved C datatypes to all of the mangled
* names in the scripting languages. For example, consider the following set of
* typedef declarations:
*
* typedef double Real;
* typedef double Float;
* typedef double Point[3];
*
* Now, suppose that the types 'double *', 'Real *', 'Float *', 'double[3]', and
* 'Point' were used in an interface file and "remembered" using this function.
* The hash tables would look like this:
*
* r_mangled {
* _p_double : [ p.double, a(3).double ]
* _p_Real : [ p.double ]
* _p_Float : [ p.double ]
* _Point : [ a(3).double ]
*
* r_resolved {
* p.double : [ _p_double, _p_Real, _p_Float ]
* a(3).double : [ _p_double, _Point ]
* }
*
* Together these two hash tables can be used to determine type-equivalency between
* mangled typenames. To do this, we view the two hash tables as a large graph and
* compute the transitive closure.
* ----------------------------------------------------------------------------- */
static Hash *r_mangled = 0; /* Hash mapping mangled types to fully resolved types */
static Hash *r_resolved = 0; /* Hash mapping resolved types to mangled types */
static Hash *r_ltype = 0; /* Hash mapping mangled names to their local c type */
void SwigType_remember(SwigType *t) {
String *mt;
SwigType *lt;
Hash *h;
SwigType *fr;
if (!r_mangled) {
r_mangled = NewHash();
r_resolved = NewHash();
r_ltype = NewHash();
}
mt = SwigType_manglestr(t); /* Create mangled string */
if (SwigType_istypedef(t))
lt = Copy(t);
else
lt = SwigType_ltype(t);
Setattr(r_ltype, mt, lt);
fr = SwigType_typedef_resolve_all(t); /* Create fully resolved type */
h = Getattr(r_mangled,mt);
if (!h) {
h = NewHash();
Setattr(r_mangled,mt,h);
Delete(h);
}
Setattr(h,fr,mt);
h = Getattr(r_resolved, fr);
if (!h) {
h = NewHash();
Setattr(r_resolved,fr,h);
Delete(h);
}
Setattr(h,mt,fr);
}
/* -----------------------------------------------------------------------------
* SwigType_equivalent_mangle()
*
* Return a list of all of the mangled typenames that are equivalent to another
* mangled name. This works as follows: For each fully qualified C datatype
* in the r_mangled hash entry, we collect all of the mangled names from the
* r_resolved hash and combine them together in a list (removing duplicate entries).
* ----------------------------------------------------------------------------- */
List *SwigType_equivalent_mangle(String *ms, Hash *checked, Hash *found) {
List *l;
Hash *h;
Hash *ch;
Hash *mh;
if (found) {
h = found;
} else {
h = NewHash();
}
if (checked) {
ch = checked;
} else {
ch = NewHash();
}
if (Getattr(ch,ms)) goto check_exit; /* Already checked this type */
Setattr(h,ms,"1");
Setattr(ch, ms, "1");
mh = Getattr(r_mangled,ms);
if (mh) {
String *key;
key = Firstkey(mh);
while (key) {
Hash *rh;
if (Getattr(ch,key)) {
key = Nextkey(mh);
continue;
}
Setattr(ch,key,"1");
rh = Getattr(r_resolved,key);
if (rh) {
String *rkey;
rkey = Firstkey(rh);
while (rkey) {
Setattr(h,rkey,"1");
SwigType_equivalent_mangle(rkey,ch,h);
rkey = Nextkey(rh);
}
}
key = Nextkey(mh);
}
}
check_exit:
if (!found) {
l = Hash_keys(h);
Delete(h);
Delete(ch);
return l;
} else {
return 0;
}
}
/* -----------------------------------------------------------------------------
* SwigType_inherit()
*
* Record information about inheritance. We keep a hash table that keeps
* a mapping between base classes and all of the classes that are derived
* from them.
*
* subclass is a hash that maps base-classes to all of the classes derived from them.
* ----------------------------------------------------------------------------- */
static Hash *subclass = 0;
static Hash *conversions = 0;
void
SwigType_inherit(String *derived, String *base) {
Hash *h;
if (!subclass) subclass = NewHash();
h = Getattr(subclass,base);
if (!h) {
h = NewHash();
Setattr(subclass,base,h);
}
Setattr(h,derived,"1");
}
/* -----------------------------------------------------------------------------
* SwigType_inherit_equiv()
*
* Modify the type table to handle C++ inheritance
* ----------------------------------------------------------------------------- */
void SwigType_inherit_equiv(File *out) {
String *rkey, *bkey, *ckey;
String *prefix, *base;
Hash *sub;
Hash *rh;
if (!conversions) conversions = NewHash();
if (!subclass) subclass = NewHash();
rkey = Firstkey(r_resolved);
while (rkey) {
/* rkey is actually a fully qualified type */
base = SwigType_base(rkey);
sub = Getattr(subclass,base);
if (!sub) {
rkey = Nextkey(r_resolved);
continue;
}
rh = Getattr(r_resolved, rkey);
/* Hmmm. We actually got a base-class match. We're going to try and patch things up */
bkey = Firstkey(sub);
while (bkey) {
prefix= SwigType_prefix(rkey);
Append(prefix,bkey);
Setattr(rh,SwigType_manglestr(prefix),prefix);
ckey = NewStringf("%s+%s",SwigType_manglestr(prefix), SwigType_manglestr(rkey));
if (!Getattr(conversions,ckey)) {
Printf(out,"static void *%sTo%s(void *x) {\n", SwigType_manglestr(prefix), SwigType_manglestr(rkey));
Printf(out," return (void *)((%s) ((%s) x));\n", SwigType_lstr(rkey,0), SwigType_lstr(prefix,0));
Printf(out,"}\n");
SetInt(conversions,ckey,1);
}
Delete(ckey);
Delete(prefix);
bkey = Nextkey(sub);
}
rkey = Nextkey(r_resolved);
}
}
/* -----------------------------------------------------------------------------
* SwigType_type_table()
*
* Generate the type-table for the type-checker.
* ----------------------------------------------------------------------------- */
void
SwigType_emit_type_table(File *f_forward, File *f_table) {
DOH *key;
String *types, *table;
int i = 0;
if (!r_mangled) {
r_mangled = NewHash();
r_resolved = NewHash();
}
Printf(f_table,"\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */\n\n");
SwigType_inherit_equiv(f_table);
#ifdef DEBUG
Printf(stdout,"---r_mangled---\n");
Printf(stdout,"%s\n", r_mangled);
Printf(stdout,"---r_resolved---\n");
Printf(stdout,"%s\n", r_resolved);
Printf(stdout,"---r_ltype---\n");
Printf(stdout,"%s\n", r_ltype);
Printf(stdout,"---subclass---\n");
Printf(stdout,"%s\n", subclass);
Printf(stdout,"---scopes[0]---\n");
Printf(stdout,"%s\n", scopes[0]);
#endif
table = NewString("");
types = NewString("");
Printf(table,"static swig_type_info *swig_types_initial[] = {\n");
key = Firstkey(r_mangled);
Printf(f_forward,"\n/* -------- TYPES TABLE (BEGIN) -------- */\n\n");
while (key) {
List *el;
String *en;
Printf(f_forward,"#define SWIGTYPE%s swig_types[%d] \n", key, i);
Printv(types,"static swig_type_info _swigt_", key, "[] = {", 0);
Printv(types,"{\"", key, "\", 0, \"", SwigType_str(Getattr(r_ltype,key),0),"\"},", 0);
el = SwigType_equivalent_mangle(key,0,0);
for (en = Firstitem(el); en; en = Nextitem(el)) {
String *ckey;
ckey = NewStringf("%s+%s", en, key);
if (Getattr(conversions,ckey)) {
Printf(types,"{\"%s\", %sTo%s},", en, en, key);
} else {
Printf(types,"{\"%s\"},", en);
}
Delete(ckey);
}
Delete(el);
Printf(types,"{0}};\n");
Printv(table, "_swigt_", key, ", \n", 0);
key = Nextkey(r_mangled);
i++;
}
Printf(table, "0\n};\n");
Printf(f_forward,"static swig_type_info *swig_types[%d];\n", i+1);
Printf(f_forward,"\n/* -------- TYPES TABLE (END) -------- */\n\n");
Printf(f_table,"%s\n", types);
Printf(f_table,"%s\n", table);
Printf(f_table,"\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */\n\n");
Delete(types);
Delete(table);
}