1/* -----------------------------------------------------------------------------
2 * See the LICENSE file for information on copyright, usage and redistribution
3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
4 *
5 * typeobj.c
6 *
7 * This file provides functions for constructing, manipulating, and testing
8 * type objects.   Type objects are merely the raw low-level representation
9 * of C++ types.   They do not incorporate high-level type system features
10 * like typedef, namespaces, etc.
11 * ----------------------------------------------------------------------------- */
12
13char cvsroot_typeobj_c[] = "$Id: typeobj.c 11080 2009-01-24 13:15:51Z bhy $";
14
15#include "swig.h"
16#include <ctype.h>
17
18/* -----------------------------------------------------------------------------
19 * Synopsis
20 *
21 * This file provides a collection of low-level functions for constructing and
22 * manipulating C++ data types.   In SWIG, C++ datatypes are encoded as simple
23 * text strings.  This representation is compact, easy to debug, and easy to read.
24 *
25 * General idea:
26 *
27 * Types are represented by a base type (e.g., "int") and a collection of
28 * type operators applied to the base (e.g., pointers, arrays, etc...).
29 *
30 * Encoding:
31 *
32 * Types are encoded as strings of type constructors such as follows:
33 *
34 *        String Encoding                 C Example
35 *        ---------------                 ---------
36 *        p.p.int                         int **
37 *        a(300).a(400).int               int [300][400]
38 *        p.q(const).char                 char const *
39 *
40 * All type constructors are denoted by a trailing '.':
41 *
42 *  'p.'                = Pointer (*)
43 *  'r.'                = Reference (&)
44 *  'a(n).'             = Array of size n  [n]
45 *  'f(..,..).'         = Function with arguments  (args)
46 *  'q(str).'           = Qualifier (such as const or volatile) (const, volatile)
47 *  'm(qual).'          = Pointer to member (qual::*)
48 *
49 * The encoding follows the order that you might describe a type in words.
50 * For example "p.a(200).int" is "A pointer to array of int's" and
51 * "p.q(const).char" is "a pointer to a const char".
52 *
53 * This representation of types is fairly convenient because ordinary string
54 * operations can be used for type manipulation. For example, a type could be
55 * formed by combining two strings such as the following:
56 *
57 *        "p.p." + "a(400).int" = "p.p.a(400).int"
58 *
59 * For C++, typenames may be parameterized using <(...)>.  Here are some
60 * examples:
61 *
62 *       String Encoding                  C++ Example
63 *       ---------------                  ------------
64 *       p.vector<(int)>                  vector<int> *
65 *       r.foo<(int,p.double)>            foo<int,double *> &
66 *
67 * Contents of this file:
68 *
69 * Most of this functions in this file pertain to the low-level manipulation
70 * of type objects.   There are constructor functions like this:
71 *
72 *       SwigType_add_pointer()
73 *       SwigType_add_reference()
74 *       SwigType_add_array()
75 *
76 * These are used to build new types.  There are also functions to undo these
77 * operations.  For example:
78 *
79 *       SwigType_del_pointer()
80 *       SwigType_del_reference()
81 *       SwigType_del_array()
82 *
83 * In addition, there are query functions
84 *
85 *       SwigType_ispointer()
86 *       SwigType_isreference()
87 *       SwigType_isarray()
88 *
89 * Finally, there are some data extraction functions that can be used to
90 * extract array dimensions, template arguments, and so forth.
91 *
92 * It is very important for developers to realize that the functions in this
93 * module do *NOT* incorporate higher-level type system features like typedef.
94 * For example, you could have C code like this:
95 *
96 *        typedef  int  *intptr;
97 *
98 * In this case, a SwigType of type 'intptr' will be treated as a simple type and
99 * functions like SwigType_ispointer() will evaluate as false.  It is strongly
100 * advised that developers use the TypeSys_* interface to check types in a more
101 * reliable manner.
102 * ----------------------------------------------------------------------------- */
103
104
105/* -----------------------------------------------------------------------------
106 * NewSwigType()
107 *
108 * Constructs a new type object.   Eventually, it would be nice for this function
109 * to accept an initial value in the form a C/C++ abstract type (currently unimplemented).
110 * ----------------------------------------------------------------------------- */
111
112#ifdef NEW
113SwigType *NewSwigType(const_String_or_char_ptr initial) {
114  return NewString(initial);
115}
116
117#endif
118
119/* The next few functions are utility functions used in the construction and
120   management of types */
121
122/* -----------------------------------------------------------------------------
123 * static element_size()
124 *
125 * This utility function finds the size of a single type element in a type string.
126 * Type elements are always delimited by periods, but may be nested with
127 * parentheses.  A nested element is always handled as a single item.
128 *
129 * Returns the integer size of the element (which can be used to extract a
130 * substring, to chop the element off, or for other purposes).
131 * ----------------------------------------------------------------------------- */
132
133static int element_size(char *c) {
134  int nparen;
135  char *s = c;
136  while (*c) {
137    if (*c == '.') {
138      c++;
139      return (int) (c - s);
140    } else if (*c == '(') {
141      nparen = 1;
142      c++;
143      while (*c) {
144	if (*c == '(')
145	  nparen++;
146	if (*c == ')') {
147	  nparen--;
148	  if (nparen == 0)
149	    break;
150	}
151	c++;
152      }
153    }
154    if (*c)
155      c++;
156  }
157  return (int) (c - s);
158}
159
160/* -----------------------------------------------------------------------------
161 * SwigType_del_element()
162 *
163 * Deletes one type element from the type.
164 * ----------------------------------------------------------------------------- */
165
166SwigType *SwigType_del_element(SwigType *t) {
167  int sz = element_size(Char(t));
168  Delslice(t, 0, sz);
169  return t;
170}
171
172/* -----------------------------------------------------------------------------
173 * SwigType_pop()
174 *
175 * Pop one type element off the type.
176 * ----------------------------------------------------------------------------- */
177
178SwigType *SwigType_pop(SwigType *t) {
179  SwigType *result;
180  char *c;
181  int sz;
182
183  c = Char(t);
184  if (!*c)
185    return 0;
186
187  sz = element_size(c);
188  result = NewStringWithSize(c, sz);
189  Delslice(t, 0, sz);
190  c = Char(t);
191  if (*c == '.') {
192    Delitem(t, 0);
193  }
194  return result;
195}
196
197/* -----------------------------------------------------------------------------
198 * SwigType_parm()
199 *
200 * Returns the parameter of an operator as a string
201 * ----------------------------------------------------------------------------- */
202
203String *SwigType_parm(SwigType *t) {
204  char *start, *c;
205  int nparens = 0;
206
207  c = Char(t);
208  while (*c && (*c != '(') && (*c != '.'))
209    c++;
210  if (!*c || (*c == '.'))
211    return 0;
212  c++;
213  start = c;
214  while (*c) {
215    if (*c == ')') {
216      if (nparens == 0)
217	break;
218      nparens--;
219    } else if (*c == '(') {
220      nparens++;
221    }
222    c++;
223  }
224  return NewStringWithSize(start, (int) (c - start));
225}
226
227/* -----------------------------------------------------------------------------
228 * SwigType_split()
229 *
230 * Splits a type into it's component parts and returns a list of string.
231 * ----------------------------------------------------------------------------- */
232
233List *SwigType_split(const SwigType *t) {
234  String *item;
235  List *list;
236  char *c;
237  int len;
238
239  c = Char(t);
240  list = NewList();
241  while (*c) {
242    len = element_size(c);
243    item = NewStringWithSize(c, len);
244    Append(list, item);
245    Delete(item);
246    c = c + len;
247    if (*c == '.')
248      c++;
249  }
250  return list;
251}
252
253/* -----------------------------------------------------------------------------
254 * SwigType_parmlist()
255 *
256 * Splits a comma separated list of parameters into its component parts
257 * The input is expected to contain the parameter list within () brackets
258 * Returns 0 if no argument list in the input, ie there are no round brackets ()
259 * Returns an empty List if there are no parameters in the () brackets
260 * For example:
261 *
262 *     Foo(std::string,p.f().Bar<(int,double)>)
263 *
264 * returns 2 elements in the list:
265 *    std::string
266 *    p.f().Bar<(int,double)>
267 * ----------------------------------------------------------------------------- */
268
269List *SwigType_parmlist(const String *p) {
270  String *item = 0;
271  List *list;
272  char *c;
273  char *itemstart;
274  int size;
275
276  assert(p);
277  c = Char(p);
278  while (*c && (*c != '(') && (*c != '.'))
279    c++;
280  if (!*c)
281    return 0;
282  assert(*c != '.'); /* p is expected to contain sub elements of a type */
283  c++;
284  list = NewList();
285  itemstart = c;
286  while (*c) {
287    if (*c == ',') {
288      size = (int) (c - itemstart);
289      item = NewStringWithSize(itemstart, size);
290      Append(list, item);
291      Delete(item);
292      itemstart = c + 1;
293    } else if (*c == '(') {
294      int nparens = 1;
295      c++;
296      while (*c) {
297	if (*c == '(')
298	  nparens++;
299	if (*c == ')') {
300	  nparens--;
301	  if (nparens == 0)
302	    break;
303	}
304	c++;
305      }
306    } else if (*c == ')') {
307      break;
308    }
309    if (*c)
310      c++;
311  }
312  size = (int) (c - itemstart);
313  if (size > 0) {
314    item = NewStringWithSize(itemstart, size);
315    Append(list, item);
316  }
317  Delete(item);
318  return list;
319}
320
321/* -----------------------------------------------------------------------------
322 *                                 Pointers
323 *
324 * SwigType_add_pointer()
325 * SwigType_del_pointer()
326 * SwigType_ispointer()
327 *
328 * Add, remove, and test if a type is a pointer.  The deletion and query
329 * functions take into account qualifiers (if any).
330 * ----------------------------------------------------------------------------- */
331
332SwigType *SwigType_add_pointer(SwigType *t) {
333  Insert(t, 0, "p.");
334  return t;
335}
336
337SwigType *SwigType_del_pointer(SwigType *t) {
338  char *c, *s;
339  c = Char(t);
340  s = c;
341  /* Skip qualifiers, if any */
342  if (strncmp(c, "q(", 2) == 0) {
343    c = strchr(c, '.');
344    assert(c);
345    c++;
346  }
347  if (strncmp(c, "p.", 2)) {
348    printf("Fatal error. SwigType_del_pointer applied to non-pointer.\n");
349    abort();
350  }
351  Delslice(t, 0, (c - s) + 2);
352  return t;
353}
354
355int SwigType_ispointer(SwigType *t) {
356  char *c;
357  if (!t)
358    return 0;
359  c = Char(t);
360  /* Skip qualifiers, if any */
361  if (strncmp(c, "q(", 2) == 0) {
362    c = strchr(c, '.');
363    if (!c)
364      return 0;
365    c++;
366  }
367  if (strncmp(c, "p.", 2) == 0) {
368    return 1;
369  }
370  return 0;
371}
372
373/* -----------------------------------------------------------------------------
374 *                                 References
375 *
376 * SwigType_add_reference()
377 * SwigType_del_reference()
378 * SwigType_isreference()
379 *
380 * Add, remove, and test if a type is a reference.  The deletion and query
381 * functions take into account qualifiers (if any).
382 * ----------------------------------------------------------------------------- */
383
384SwigType *SwigType_add_reference(SwigType *t) {
385  Insert(t, 0, "r.");
386  return t;
387}
388
389SwigType *SwigType_del_reference(SwigType *t) {
390  char *c = Char(t);
391  int check = strncmp(c, "r.", 2);
392  assert(check == 0);
393  Delslice(t, 0, 2);
394  return t;
395}
396
397int SwigType_isreference(SwigType *t) {
398  char *c;
399  if (!t)
400    return 0;
401  c = Char(t);
402  if (strncmp(c, "r.", 2) == 0) {
403    return 1;
404  }
405  return 0;
406}
407
408/* -----------------------------------------------------------------------------
409 *                                  Qualifiers
410 *
411 * SwigType_add_qualifier()
412 * SwigType_del_qualifier()
413 * SwigType_is_qualifier()
414 *
415 * Adds type qualifiers like "const" and "volatile".   When multiple qualifiers
416 * are added to a type, they are combined together into a single qualifier.
417 * Repeated qualifications have no effect.  Moreover, the order of qualifications
418 * is alphabetical---meaning that "const volatile" and "volatile const" are
419 * stored in exactly the same way as "q(const volatile)".
420 * ----------------------------------------------------------------------------- */
421
422SwigType *SwigType_add_qualifier(SwigType *t, const_String_or_char_ptr qual) {
423  char temp[256], newq[256];
424  int sz, added = 0;
425  char *q, *cqual;
426
427  char *c = Char(t);
428  cqual = Char(qual);
429
430  if (!(strncmp(c, "q(", 2) == 0)) {
431    sprintf(temp, "q(%s).", cqual);
432    Insert(t, 0, temp);
433    return t;
434  }
435
436  /* The type already has a qualifier on it.  In this case, we first check to
437     see if the qualifier is already specified.  In that case do nothing.
438     If it is a new qualifier, we add it to the qualifier list in alphabetical
439     order */
440
441  sz = element_size(c);
442  strncpy(temp, c, (sz < 256) ? sz : 256);
443
444  if (strstr(temp, cqual)) {
445    /* Qualifier already added */
446    return t;
447  }
448
449  /* Add the qualifier to the existing list. */
450
451  strcpy(newq, "q(");
452  q = temp + 2;
453  q = strtok(q, " ).");
454  while (q) {
455    if (strcmp(cqual, q) < 0) {
456      /* New qualifier is less that current qualifier.  We need to insert it */
457      strcat(newq, cqual);
458      strcat(newq, " ");
459      strcat(newq, q);
460      added = 1;
461    } else {
462      strcat(newq, q);
463    }
464    q = strtok(NULL, " ).");
465    if (q) {
466      strcat(newq, " ");
467    }
468  }
469  if (!added) {
470    strcat(newq, " ");
471    strcat(newq, cqual);
472  }
473  strcat(newq, ").");
474  Delslice(t, 0, sz);
475  Insert(t, 0, newq);
476  return t;
477}
478
479SwigType *SwigType_del_qualifier(SwigType *t) {
480  char *c = Char(t);
481  int check = strncmp(c, "q(", 2);
482  assert(check == 0);
483  Delslice(t, 0, element_size(c));
484  return t;
485}
486
487int SwigType_isqualifier(SwigType *t) {
488  char *c;
489  if (!t)
490    return 0;
491  c = Char(t);
492  if (strncmp(c, "q(", 2) == 0) {
493    return 1;
494  }
495  return 0;
496}
497
498/* -----------------------------------------------------------------------------
499 *                                Function Pointers
500 * ----------------------------------------------------------------------------- */
501
502int SwigType_isfunctionpointer(SwigType *t) {
503  char *c;
504  if (!t)
505    return 0;
506  c = Char(t);
507  if (strncmp(c, "p.f(", 4) == 0) {
508    return 1;
509  }
510  return 0;
511}
512
513/* -----------------------------------------------------------------------------
514 * SwigType_functionpointer_decompose
515 *
516 * Decompose the function pointer into the parameter list and the return type
517 * t - input and on completion contains the return type
518 * returns the function's parameters
519 * ----------------------------------------------------------------------------- */
520
521SwigType *SwigType_functionpointer_decompose(SwigType *t) {
522  String *p;
523  assert(SwigType_isfunctionpointer(t));
524  p = SwigType_pop(t);
525  Delete(p);
526  p = SwigType_pop(t);
527  return p;
528}
529
530/* -----------------------------------------------------------------------------
531 *                                Member Pointers
532 *
533 * SwigType_add_memberpointer()
534 * SwigType_del_memberpointer()
535 * SwigType_ismemberpointer()
536 *
537 * Add, remove, and test for C++ pointer to members.
538 * ----------------------------------------------------------------------------- */
539
540SwigType *SwigType_add_memberpointer(SwigType *t, const_String_or_char_ptr name) {
541  String *temp = NewStringf("m(%s).", name);
542  Insert(t, 0, temp);
543  Delete(temp);
544  return t;
545}
546
547SwigType *SwigType_del_memberpointer(SwigType *t) {
548  char *c = Char(t);
549  int check = strncmp(c, "m(", 2);
550  assert(check == 0);
551  Delslice(t, 0, element_size(c));
552  return t;
553}
554
555int SwigType_ismemberpointer(SwigType *t) {
556  char *c;
557  if (!t)
558    return 0;
559  c = Char(t);
560  if (strncmp(c, "m(", 2) == 0) {
561    return 1;
562  }
563  return 0;
564}
565
566/* -----------------------------------------------------------------------------
567 *                                    Arrays
568 *
569 * SwigType_add_array()
570 * SwigType_del_array()
571 * SwigType_isarray()
572 *
573 * Utility functions:
574 *
575 * SwigType_array_ndim()        - Calculate number of array dimensions.
576 * SwigType_array_getdim()      - Get array dimension
577 * SwigType_array_setdim()      - Set array dimension
578 * SwigType_array_type()        - Return array type
579 * SwigType_pop_arrays()        - Remove all arrays
580 * ----------------------------------------------------------------------------- */
581
582SwigType *SwigType_add_array(SwigType *t, const_String_or_char_ptr size) {
583  char temp[512];
584  strcpy(temp, "a(");
585  strcat(temp, Char(size));
586  strcat(temp, ").");
587  Insert(t, 0, temp);
588  return t;
589}
590
591SwigType *SwigType_del_array(SwigType *t) {
592  char *c = Char(t);
593  int check = strncmp(c, "a(", 2);
594  assert(check == 0);
595  Delslice(t, 0, element_size(c));
596  return t;
597}
598
599int SwigType_isarray(SwigType *t) {
600  char *c;
601  if (!t)
602    return 0;
603  c = Char(t);
604  if (strncmp(c, "a(", 2) == 0) {
605    return 1;
606  }
607  return 0;
608}
609/*
610 * SwigType_prefix_is_simple_1D_array
611 *
612 * Determine if the type is a 1D array type that is treated as a pointer within SWIG
613 * eg Foo[], Foo[3] return true, but Foo[3][3], Foo*[], Foo*[3], Foo**[] return false
614 */
615int SwigType_prefix_is_simple_1D_array(SwigType *t) {
616  char *c = Char(t);
617
618  if (c && (strncmp(c, "a(", 2) == 0)) {
619    c = strchr(c, '.');
620    c++;
621    return (*c == 0);
622  }
623  return 0;
624}
625
626
627/* Remove all arrays */
628SwigType *SwigType_pop_arrays(SwigType *t) {
629  String *ta;
630  assert(SwigType_isarray(t));
631  ta = NewStringEmpty();
632  while (SwigType_isarray(t)) {
633    SwigType *td = SwigType_pop(t);
634    Append(ta, td);
635    Delete(td);
636  }
637  return ta;
638}
639
640/* Return number of array dimensions */
641int SwigType_array_ndim(SwigType *t) {
642  int ndim = 0;
643  char *c = Char(t);
644
645  while (c && (strncmp(c, "a(", 2) == 0)) {
646    c = strchr(c, '.');
647    c++;
648    ndim++;
649  }
650  return ndim;
651}
652
653/* Get nth array dimension */
654String *SwigType_array_getdim(SwigType *t, int n) {
655  char *c = Char(t);
656  while (c && (strncmp(c, "a(", 2) == 0) && (n > 0)) {
657    c = strchr(c, '.');
658    c++;
659    n--;
660  }
661  if (n == 0) {
662    String *dim = SwigType_parm(c);
663    if (SwigType_istemplate(dim)) {
664      String *ndim = SwigType_namestr(dim);
665      Delete(dim);
666      dim = ndim;
667    }
668
669    return dim;
670  }
671
672  return 0;
673}
674
675/* Replace nth array dimension */
676void SwigType_array_setdim(SwigType *t, int n, const_String_or_char_ptr rep) {
677  String *result = 0;
678  char temp;
679  char *start;
680  char *c = Char(t);
681
682  start = c;
683  if (strncmp(c, "a(", 2))
684    abort();
685
686  while (c && (strncmp(c, "a(", 2) == 0) && (n > 0)) {
687    c = strchr(c, '.');
688    c++;
689    n--;
690  }
691  if (n == 0) {
692    temp = *c;
693    *c = 0;
694    result = NewString(start);
695    Printf(result, "a(%s)", rep);
696    *c = temp;
697    c = strchr(c, '.');
698    Append(result, c);
699  }
700  Clear(t);
701  Append(t, result);
702  Delete(result);
703}
704
705/* Return base type of an array */
706SwigType *SwigType_array_type(SwigType *ty) {
707  SwigType *t;
708  t = Copy(ty);
709  while (SwigType_isarray(t)) {
710    Delete(SwigType_pop(t));
711  }
712  return t;
713}
714
715
716/* -----------------------------------------------------------------------------
717 *                                    Functions
718 *
719 * SwigType_add_function()
720 * SwigType_del_function()
721 * SwigType_isfunction()
722 * SwigType_pop_function()
723 *
724 * Add, remove, and test for function types.
725 * ----------------------------------------------------------------------------- */
726
727/* Returns the function type, t, constructed from the parameters, parms */
728SwigType *SwigType_add_function(SwigType *t, ParmList *parms) {
729  String *pstr;
730  Parm *p;
731
732  Insert(t, 0, ").");
733  pstr = NewString("f(");
734  p = parms;
735  for (p = parms; p; p = nextSibling(p)) {
736    if (p != parms)
737      Putc(',', pstr);
738    Append(pstr, Getattr(p, "type"));
739  }
740  Insert(t, 0, pstr);
741  Delete(pstr);
742  return t;
743}
744
745SwigType *SwigType_pop_function(SwigType *t) {
746  SwigType *f = 0;
747  SwigType *g = 0;
748  char *c = Char(t);
749  if (strncmp(c, "q(", 2) == 0) {
750    f = SwigType_pop(t);
751    c = Char(t);
752  }
753  if (strncmp(c, "f(", 2)) {
754    printf("Fatal error. SwigType_pop_function applied to non-function.\n");
755    abort();
756  }
757  g = SwigType_pop(t);
758  if (f)
759    SwigType_push(g, f);
760  Delete(f);
761  return g;
762}
763
764int SwigType_isfunction(SwigType *t) {
765  char *c;
766  if (!t) {
767    return 0;
768  }
769  c = Char(t);
770  if (strncmp(c, "q(", 2) == 0) {
771    /* Might be a 'const' function.  Try to skip over the 'const' */
772    c = strchr(c, '.');
773    if (c)
774      c++;
775    else
776      return 0;
777  }
778  if (strncmp(c, "f(", 2) == 0) {
779    return 1;
780  }
781  return 0;
782}
783
784ParmList *SwigType_function_parms(SwigType *t) {
785  List *l = SwigType_parmlist(t);
786  Hash *p, *pp = 0, *firstp = 0;
787  Iterator o;
788
789  for (o = First(l); o.item; o = Next(o)) {
790    p = NewParm(o.item, 0);
791    if (!firstp)
792      firstp = p;
793    if (pp) {
794      set_nextSibling(pp, p);
795      Delete(p);
796    }
797    pp = p;
798  }
799  Delete(l);
800  return firstp;
801}
802
803int SwigType_isvarargs(const SwigType *t) {
804  if (Strcmp(t, "v(...)") == 0)
805    return 1;
806  return 0;
807}
808
809/* -----------------------------------------------------------------------------
810 *                                    Templates
811 *
812 * SwigType_add_template()
813 *
814 * Template handling.
815 * ----------------------------------------------------------------------------- */
816
817/* -----------------------------------------------------------------------------
818 * SwigType_add_template()
819 *
820 * Adds a template to a type.   This template is encoded in the SWIG type
821 * mechanism and produces a string like this:
822 *
823 *  vector<int *> ----> "vector<(p.int)>"
824 * ----------------------------------------------------------------------------- */
825
826SwigType *SwigType_add_template(SwigType *t, ParmList *parms) {
827  Parm *p;
828
829  Append(t, "<(");
830  p = parms;
831  for (p = parms; p; p = nextSibling(p)) {
832    String *v;
833    if (Getattr(p, "default"))
834      continue;
835    if (p != parms)
836      Append(t, ",");
837    v = Getattr(p, "value");
838    if (v) {
839      Append(t, v);
840    } else {
841      Append(t, Getattr(p, "type"));
842    }
843  }
844  Append(t, ")>");
845  return t;
846}
847
848
849/* -----------------------------------------------------------------------------
850 * SwigType_templateprefix()
851 *
852 * Returns the prefix before the first template definition.
853 * For example:
854 *
855 *     Foo<(p.int)>::bar
856 *
857 * returns "Foo"
858 * ----------------------------------------------------------------------------- */
859
860String *SwigType_templateprefix(const SwigType *t) {
861  const char *s = Char(t);
862  const char *c = strstr(s, "<(");
863  return c ? NewStringWithSize(s, c - s) : NewString(s);
864}
865
866/* -----------------------------------------------------------------------------
867 * SwigType_templatesuffix()
868 *
869 * Returns text after a template substitution.  Used to handle scope names
870 * for example:
871 *
872 *        Foo<(p.int)>::bar
873 *
874 * returns "::bar"
875 * ----------------------------------------------------------------------------- */
876
877String *SwigType_templatesuffix(const SwigType *t) {
878  const char *c;
879  c = Char(t);
880  while (*c) {
881    if ((*c == '<') && (*(c + 1) == '(')) {
882      int nest = 1;
883      c++;
884      while (*c && nest) {
885	if (*c == '<')
886	  nest++;
887	if (*c == '>')
888	  nest--;
889	c++;
890      }
891      return NewString(c);
892    }
893    c++;
894  }
895  return NewStringEmpty();
896}
897
898/* -----------------------------------------------------------------------------
899 * SwigType_templateargs()
900 *
901 * Returns the template arguments
902 * For example:
903 *
904 *     Foo<(p.int)>::bar
905 *
906 * returns "<(p.int)>"
907 * ----------------------------------------------------------------------------- */
908
909String *SwigType_templateargs(const SwigType *t) {
910  const char *c;
911  const char *start;
912  c = Char(t);
913  while (*c) {
914    if ((*c == '<') && (*(c + 1) == '(')) {
915      int nest = 1;
916      start = c;
917      c++;
918      while (*c && nest) {
919	if (*c == '<')
920	  nest++;
921	if (*c == '>')
922	  nest--;
923	c++;
924      }
925      return NewStringWithSize(start, c - start);
926    }
927    c++;
928  }
929  return 0;
930}
931
932/* -----------------------------------------------------------------------------
933 * SwigType_istemplate()
934 *
935 * Tests a type to see if it includes template parameters
936 * ----------------------------------------------------------------------------- */
937
938int SwigType_istemplate(const SwigType *t) {
939  char *ct = Char(t);
940  ct = strstr(ct, "<(");
941  if (ct && (strstr(ct + 2, ")>")))
942    return 1;
943  return 0;
944}
945
946/* -----------------------------------------------------------------------------
947 * SwigType_base()
948 *
949 * This function returns the base of a type.  For example, if you have a
950 * type "p.p.int", the function would return "int".
951 * ----------------------------------------------------------------------------- */
952
953SwigType *SwigType_base(const SwigType *t) {
954  char *c;
955  char *lastop = 0;
956  c = Char(t);
957
958  lastop = c;
959
960  /* Search for the last type constructor separator '.' */
961  while (*c) {
962    if (*c == '.') {
963      if (*(c + 1)) {
964	lastop = c + 1;
965      }
966      c++;
967      continue;
968    }
969    if (*c == '<') {
970      /* Skip over template---it's part of the base name */
971      int ntemp = 1;
972      c++;
973      while ((*c) && (ntemp > 0)) {
974	if (*c == '>')
975	  ntemp--;
976	else if (*c == '<')
977	  ntemp++;
978	c++;
979      }
980      if (ntemp)
981	break;
982      continue;
983    }
984    if (*c == '(') {
985      /* Skip over params */
986      int nparen = 1;
987      c++;
988      while ((*c) && (nparen > 0)) {
989	if (*c == '(')
990	  nparen++;
991	else if (*c == ')')
992	  nparen--;
993	c++;
994      }
995      if (nparen)
996	break;
997      continue;
998    }
999    c++;
1000  }
1001  return NewString(lastop);
1002}
1003
1004/* -----------------------------------------------------------------------------
1005 * SwigType_prefix()
1006 *
1007 * Returns the prefix of a datatype.  For example, the prefix of the
1008 * type "p.p.int" is "p.p.".
1009 * ----------------------------------------------------------------------------- */
1010
1011String *SwigType_prefix(const SwigType *t) {
1012  char *c, *d;
1013  String *r = 0;
1014
1015  c = Char(t);
1016  d = c + strlen(c);
1017
1018  /* Check for a type constructor */
1019  if ((d > c) && (*(d - 1) == '.'))
1020    d--;
1021
1022  while (d > c) {
1023    d--;
1024    if (*d == '>') {
1025      int nest = 1;
1026      d--;
1027      while ((d > c) && (nest)) {
1028	if (*d == '>')
1029	  nest++;
1030	if (*d == '<')
1031	  nest--;
1032	d--;
1033      }
1034    }
1035    if (*d == ')') {
1036      /* Skip over params */
1037      int nparen = 1;
1038      d--;
1039      while ((d > c) && (nparen)) {
1040	if (*d == ')')
1041	  nparen++;
1042	if (*d == '(')
1043	  nparen--;
1044	d--;
1045      }
1046    }
1047
1048    if (*d == '.') {
1049      char t = *(d + 1);
1050      *(d + 1) = 0;
1051      r = NewString(c);
1052      *(d + 1) = t;
1053      return r;
1054    }
1055  }
1056  return NewStringEmpty();
1057}
1058
1059/* -----------------------------------------------------------------------------
1060 * SwigType_strip_qualifiers()
1061 *
1062 * Strip all qualifiers from a type and return a new type
1063 * ----------------------------------------------------------------------------- */
1064
1065SwigType *SwigType_strip_qualifiers(SwigType *t) {
1066  static Hash *memoize_stripped = 0;
1067  SwigType *r;
1068  List *l;
1069  Iterator ei;
1070
1071  if (!memoize_stripped)
1072    memoize_stripped = NewHash();
1073  r = Getattr(memoize_stripped, t);
1074  if (r)
1075    return Copy(r);
1076
1077  l = SwigType_split(t);
1078  r = NewStringEmpty();
1079
1080  for (ei = First(l); ei.item; ei = Next(ei)) {
1081    if (SwigType_isqualifier(ei.item))
1082      continue;
1083    Append(r, ei.item);
1084  }
1085  Delete(l);
1086  {
1087    String *key, *value;
1088    key = Copy(t);
1089    value = Copy(r);
1090    Setattr(memoize_stripped, key, value);
1091    Delete(key);
1092    Delete(value);
1093  }
1094  return r;
1095}
1096