1/* Demangler for the D programming language
2   Copyright 2014 Free Software Foundation, Inc.
3   Written by Iain Buclaw (ibuclaw@gdcproject.org)
4
5This file is part of the libiberty library.
6Libiberty is free software; you can redistribute it and/or
7modify it under the terms of the GNU Library General Public
8License as published by the Free Software Foundation; either
9version 2 of the License, or (at your option) any later version.
10
11In addition to the permissions in the GNU Library General Public
12License, the Free Software Foundation gives you unlimited permission
13to link the compiled version of this file into combinations with other
14programs, and to distribute those combinations without any restriction
15coming from the use of this file.  (The Library Public License
16restrictions do apply in other respects; for example, they cover
17modification of the file, and distribution when not linked into a
18combined executable.)
19
20Libiberty is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23Library General Public License for more details.
24
25You should have received a copy of the GNU Library General Public
26License along with libiberty; see the file COPYING.LIB.
27If not, see <http://www.gnu.org/licenses/>.  */
28
29/* This file exports one function; dlang_demangle.
30
31   This file imports strtol and strtod for decoding mangled literals.  */
32
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
36
37#include "safe-ctype.h"
38
39#include <sys/types.h>
40#include <string.h>
41#include <stdio.h>
42
43#ifdef HAVE_STDLIB_H
44#include <stdlib.h>
45#else
46extern long strtol (const char *nptr, char **endptr, int base);
47extern double strtod (const char *nptr, char **endptr);
48#endif
49
50#include <demangle.h>
51#include "libiberty.h"
52
53/* A mini string-handling package */
54
55typedef struct string		/* Beware: these aren't required to be */
56{				/*  '\0' terminated.  */
57  char *b;			/* pointer to start of string */
58  char *p;			/* pointer after last character */
59  char *e;			/* pointer after end of allocated space */
60} string;
61
62static void
63string_need (string *s, int n)
64{
65  int tem;
66
67  if (s->b == NULL)
68    {
69      if (n < 32)
70	{
71	  n = 32;
72	}
73      s->p = s->b = XNEWVEC (char, n);
74      s->e = s->b + n;
75    }
76  else if (s->e - s->p < n)
77    {
78      tem = s->p - s->b;
79      n += tem;
80      n *= 2;
81      s->b = XRESIZEVEC (char, s->b, n);
82      s->p = s->b + tem;
83      s->e = s->b + n;
84    }
85}
86
87static void
88string_delete (string *s)
89{
90  if (s->b != NULL)
91    {
92      XDELETEVEC (s->b);
93      s->b = s->e = s->p = NULL;
94    }
95}
96
97static void
98string_init (string *s)
99{
100  s->b = s->p = s->e = NULL;
101}
102
103static int
104string_length (string *s)
105{
106  if (s->p == s->b)
107    {
108      return 0;
109    }
110  return s->p - s->b;
111}
112
113static void
114string_setlength (string *s, int n)
115{
116  if (n - string_length (s) < 0)
117    {
118      s->p = s->b + n;
119    }
120}
121
122static void
123string_append (string *p, const char *s)
124{
125  int n = strlen (s);
126  string_need (p, n);
127  memcpy (p->p, s, n);
128  p->p += n;
129}
130
131static void
132string_appendn (string *p, const char *s, int n)
133{
134  if (n != 0)
135    {
136      string_need (p, n);
137      memcpy (p->p, s, n);
138      p->p += n;
139    }
140}
141
142static void
143string_prependn (string *p, const char *s, int n)
144{
145  char *q;
146
147  if (n != 0)
148    {
149      string_need (p, n);
150      for (q = p->p - 1; q >= p->b; q--)
151	{
152	  q[n] = q[0];
153	}
154      memcpy (p->b, s, n);
155      p->p += n;
156    }
157}
158
159static void
160string_prepend (string *p, const char *s)
161{
162  if (s != NULL && *s != '\0')
163    {
164      string_prependn (p, s, strlen (s));
165    }
166}
167
168/* Prototypes for forward referenced functions */
169static const char *dlang_function_args (string *, const char *);
170
171static const char *dlang_type (string *, const char *);
172
173static const char *dlang_value (string *, const char *, const char *, char);
174
175static const char *dlang_parse_symbol (string *, const char *);
176
177static const char *dlang_parse_tuple (string *, const char *);
178
179static const char *dlang_parse_template (string *, const char *, long);
180
181
182/* Demangle the calling convention from MANGLED and append it to DECL.
183   Return the remaining string on success or NULL on failure.  */
184static const char *
185dlang_call_convention (string *decl, const char *mangled)
186{
187  if (mangled == NULL || *mangled == '\0')
188    return mangled;
189
190  switch (*mangled)
191    {
192    case 'F': /* (D) */
193      mangled++;
194      break;
195    case 'U': /* (C) */
196      mangled++;
197      string_append (decl, "extern(C) ");
198      break;
199    case 'W': /* (Windows) */
200      mangled++;
201      string_append (decl, "extern(Windows) ");
202      break;
203    case 'V': /* (Pascal) */
204      mangled++;
205      string_append (decl, "extern(Pascal) ");
206      break;
207    case 'R': /* (C++) */
208      mangled++;
209      string_append (decl, "extern(C++) ");
210      break;
211    default:
212      return NULL;
213    }
214
215  return mangled;
216}
217
218/* Demangle the D function attributes from MANGLED and append it to DECL.
219   Return the remaining string on success or NULL on failure.  */
220static const char *
221dlang_attributes (string *decl, const char *mangled)
222{
223  if (mangled == NULL || *mangled == '\0')
224    return mangled;
225
226  while (*mangled == 'N')
227    {
228      mangled++;
229      switch (*mangled)
230	{
231	case 'a': /* pure */
232	  mangled++;
233	  string_append (decl, "pure ");
234	  continue;
235	case 'b': /* nothrow */
236	  mangled++;
237	  string_append (decl, "nothrow ");
238	  continue;
239	case 'c': /* ref */
240	  mangled++;
241	  string_append (decl, "ref ");
242	  continue;
243	case 'd': /* @property */
244	  mangled++;
245	  string_append (decl, "@property ");
246	  continue;
247	case 'e': /* @trusted */
248	  mangled++;
249	  string_append (decl, "@trusted ");
250	  continue;
251	case 'f': /* @safe */
252	  mangled++;
253	  string_append (decl, "@safe ");
254	  continue;
255	case 'g':
256	case 'h':
257	  /* inout parameter is represented as 'Ng'.
258	     vector parameter is represented as 'Nh'.
259	     If we see this, then we know we're really in the
260	     parameter list.  Rewind and break.  */
261	  mangled--;
262	  break;
263	case 'i': /* @nogc */
264	  mangled++;
265	  string_append (decl, "@nogc ");
266	  continue;
267	}
268      break;
269    }
270
271  return mangled;
272}
273
274/* Demangle the function type from MANGLED and append it to DECL.
275   Return the remaining string on success or NULL on failure.  */
276static const char *
277dlang_function_type (string *decl, const char *mangled)
278{
279  string attr, args, type;
280  size_t szattr, szargs, sztype;
281
282  if (mangled == NULL || *mangled == '\0')
283    return mangled;
284
285  /* The order of the mangled string is:
286	CallConvention FuncAttrs Arguments ArgClose Type
287
288     The demangled string is re-ordered as:
289	CallConvention Type Arguments FuncAttrs
290   */
291  string_init (&attr);
292  string_init (&args);
293  string_init (&type);
294
295  /* Function call convention.  */
296  mangled = dlang_call_convention (decl, mangled);
297
298  /* Function attributes.  */
299  mangled = dlang_attributes (&attr, mangled);
300  szattr = string_length (&attr);
301
302  /* Function arguments.  */
303  mangled = dlang_function_args (&args, mangled);
304  szargs = string_length (&args);
305
306  /* Function return type.  */
307  mangled = dlang_type (&type, mangled);
308  sztype = string_length (&type);
309
310  /* Append to decl in order. */
311  string_appendn (decl, type.b, sztype);
312  string_append (decl, "(");
313  string_appendn (decl, args.b, szargs);
314  string_append (decl, ") ");
315  string_appendn (decl, attr.b, szattr);
316
317  string_delete (&attr);
318  string_delete (&args);
319  string_delete (&type);
320  return mangled;
321}
322
323/* Demangle the argument list from MANGLED and append it to DECL.
324   Return the remaining string on success or NULL on failure.  */
325static const char *
326dlang_function_args (string *decl, const char *mangled)
327{
328  size_t n = 0;
329
330  while (mangled && *mangled != '\0')
331    {
332      switch (*mangled)
333	{
334	case 'X': /* (variadic T t...) style.  */
335	  mangled++;
336	  string_append (decl, "...");
337	  return mangled;
338	case 'Y': /* (variadic T t, ...) style.  */
339	  mangled++;
340	  string_append (decl, ", ...");
341	  return mangled;
342	case 'Z': /* Normal function.  */
343	  mangled++;
344	  return mangled;
345	}
346
347      if (n++)
348	string_append (decl, ", ");
349
350      if (*mangled == 'M') /* scope(T) */
351	{
352	  mangled++;
353	  string_append (decl, "scope ");
354	}
355
356      switch (*mangled)
357	{
358	case 'J': /* out(T) */
359	  mangled++;
360	  string_append (decl, "out ");
361	  break;
362	case 'K': /* ref(T) */
363	  mangled++;
364	  string_append (decl, "ref ");
365	  break;
366	case 'L': /* lazy(T) */
367	  mangled++;
368	  string_append (decl, "lazy ");
369	  break;
370	}
371      mangled = dlang_type (decl, mangled);
372    }
373
374  return mangled;
375}
376
377/* Demangle the type from MANGLED and append it to DECL.
378   Return the remaining string on success or NULL on failure.  */
379static const char *
380dlang_type (string *decl, const char *mangled)
381{
382  if (mangled == NULL || *mangled == '\0')
383    return mangled;
384
385  switch (*mangled)
386    {
387    case 'O': /* shared(T) */
388      mangled++;
389      string_append (decl, "shared(");
390      mangled = dlang_type (decl, mangled);
391      string_append (decl, ")");
392      return mangled;
393    case 'x': /* const(T) */
394      mangled++;
395      string_append (decl, "const(");
396      mangled = dlang_type (decl, mangled);
397      string_append (decl, ")");
398      return mangled;
399    case 'y': /* immutable(T) */
400      mangled++;
401      string_append (decl, "immutable(");
402      mangled = dlang_type (decl, mangled);
403      string_append (decl, ")");
404      return mangled;
405    case 'N':
406      mangled++;
407      if (*mangled == 'g') /* wild(T) */
408	{
409	  mangled++;
410	  string_append (decl, "inout(");
411	  mangled = dlang_type (decl, mangled);
412	  string_append (decl, ")");
413	  return mangled;
414	}
415      else if (*mangled == 'h') /* vector(T) */
416	{
417	  mangled++;
418	  string_append (decl, "__vector(");
419	  mangled = dlang_type (decl, mangled);
420	  string_append (decl, ")");
421	  return mangled;
422	}
423      else
424	return NULL;
425    case 'A': /* dynamic array (T[]) */
426      mangled++;
427      mangled = dlang_type (decl, mangled);
428      string_append (decl, "[]");
429      return mangled;
430    case 'G': /* static array (T[N]) */
431    {
432      const char *numptr;
433      size_t num = 0;
434      mangled++;
435
436      numptr = mangled;
437      while (ISDIGIT (*mangled))
438	{
439	  num++;
440	  mangled++;
441	}
442      mangled = dlang_type (decl, mangled);
443      string_append (decl, "[");
444      string_appendn (decl, numptr, num);
445      string_append (decl, "]");
446      return mangled;
447    }
448    case 'H': /* associative array (T[T]) */
449    {
450      string type;
451      size_t sztype;
452      mangled++;
453
454      string_init (&type);
455      mangled = dlang_type (&type, mangled);
456      sztype = string_length (&type);
457
458      mangled = dlang_type (decl, mangled);
459      string_append (decl, "[");
460      string_appendn (decl, type.b, sztype);
461      string_append (decl, "]");
462
463      string_delete (&type);
464      return mangled;
465    }
466    case 'P': /* pointer (T*) */
467      mangled++;
468      mangled = dlang_type (decl, mangled);
469      string_append (decl, "*");
470      return mangled;
471    case 'I': /* ident T */
472    case 'C': /* class T */
473    case 'S': /* struct T */
474    case 'E': /* enum T */
475    case 'T': /* typedef T */
476      mangled++;
477      return dlang_parse_symbol (decl, mangled);
478    case 'D': /* delegate T */
479      mangled++;
480      mangled = dlang_function_type (decl, mangled);
481      string_append (decl, "delegate");
482      return mangled;
483    case 'B': /* tuple T */
484      mangled++;
485      return dlang_parse_tuple (decl, mangled);
486
487    /* Function types */
488    case 'F': case 'U': case 'W':
489    case 'V': case 'R':
490      mangled = dlang_function_type (decl, mangled);
491      string_append (decl, "function");
492      return mangled;
493
494    /* Basic types */
495    case 'n':
496      mangled++;
497      string_append (decl, "none");
498      return mangled;
499    case 'v':
500      mangled++;
501      string_append (decl, "void");
502      return mangled;
503    case 'g':
504      mangled++;
505      string_append (decl, "byte");
506      return mangled;
507    case 'h':
508      mangled++;
509      string_append (decl, "ubyte");
510      return mangled;
511    case 's':
512      mangled++;
513      string_append (decl, "short");
514      return mangled;
515    case 't':
516      mangled++;
517      string_append (decl, "ushort");
518      return mangled;
519    case 'i':
520      mangled++;
521      string_append (decl, "int");
522      return mangled;
523    case 'k':
524      mangled++;
525      string_append (decl, "uint");
526      return mangled;
527    case 'l':
528      mangled++;
529      string_append (decl, "long");
530      return mangled;
531    case 'm':
532      mangled++;
533      string_append (decl, "ulong");
534      return mangled;
535    case 'f':
536      mangled++;
537      string_append (decl, "float");
538      return mangled;
539    case 'd':
540      mangled++;
541      string_append (decl, "double");
542      return mangled;
543    case 'e':
544      mangled++;
545      string_append (decl, "real");
546      return mangled;
547
548    /* Imaginary and Complex types */
549    case 'o':
550      mangled++;
551      string_append (decl, "ifloat");
552      return mangled;
553    case 'p':
554      mangled++;
555      string_append (decl, "idouble");
556      return mangled;
557    case 'j':
558      mangled++;
559      string_append (decl, "ireal");
560      return mangled;
561    case 'q':
562      mangled++;
563      string_append (decl, "cfloat");
564      return mangled;
565    case 'r':
566      mangled++;
567      string_append (decl, "cdouble");
568      return mangled;
569    case 'c':
570      mangled++;
571      string_append (decl, "creal");
572      return mangled;
573
574    /* Other types */
575    case 'b':
576      mangled++;
577      string_append (decl, "bool");
578      return mangled;
579    case 'a':
580      mangled++;
581      string_append (decl, "char");
582      return mangled;
583    case 'u':
584      mangled++;
585      string_append (decl, "wchar");
586      return mangled;
587    case 'w':
588      mangled++;
589      string_append (decl, "dchar");
590      return mangled;
591
592    default: /* unhandled */
593      return NULL;
594    }
595}
596
597/* Extract the identifier from MANGLED and append it to DECL.
598   Return the remaining string on success or NULL on failure.  */
599static const char *
600dlang_identifier (string *decl, const char *mangled)
601{
602  if (mangled == NULL || *mangled == '\0')
603    return mangled;
604
605  if (ISDIGIT (*mangled))
606    {
607      char *endptr;
608      long i = strtol (mangled, &endptr, 10);
609
610      if (endptr == NULL || i <= 0 || strlen (endptr) < (size_t) i)
611	return NULL;
612
613      mangled = endptr;
614
615      /* May be a template instance.  */
616      if (i >= 5 && strncmp (mangled, "__T", 3) == 0)
617	{
618	  /* Template symbol.  */
619	  if (ISDIGIT (mangled[3]) && mangled[3] != '0')
620	    return dlang_parse_template (decl, mangled, i);
621
622	  return NULL;
623	}
624
625      if (strncmp (mangled, "__ctor", i) == 0)
626	{
627	  /* Constructor symbol for a class/struct.  */
628	  string_append (decl, "this");
629	  mangled += i;
630	  return mangled;
631	}
632      else if (strncmp (mangled, "__dtor", i) == 0)
633	{
634	  /* Destructor symbol for a class/struct.  */
635	  string_append (decl, "~this");
636	  mangled += i;
637	  return mangled;
638	}
639      else if (strncmp (mangled, "__postblit", i) == 0)
640	{
641	  /* Postblit symbol for a struct.  */
642	  string_append (decl, "this(this)");
643	  mangled += i;
644	  return mangled;
645	}
646      else if (strncmp (mangled, "__initZ", i+1) == 0)
647	{
648	  /* The static initialiser for a given symbol.  */
649	  string_append (decl, "init$");
650	  mangled += i + 1;
651	  return mangled;
652	}
653      else if (strncmp (mangled, "__ClassZ", i+1) == 0)
654	{
655	  /* The classinfo symbol for a given class.  */
656	  string_prepend (decl, "ClassInfo for ");
657	  string_setlength (decl, string_length (decl) - 1);
658	  mangled += i + 1;
659	  return mangled;
660	}
661      else if (strncmp (mangled, "__vtblZ", i+1) == 0)
662	{
663	  /* The vtable symbol for a given class.  */
664	  string_prepend (decl, "vtable for ");
665	  string_setlength (decl, string_length (decl) - 1);
666	  mangled += i + 1;
667	  return mangled;
668	}
669      else if (strncmp (mangled, "__InterfaceZ", i+1) == 0)
670	{
671	  /* The interface symbol for a given class.  */
672	  string_prepend (decl, "Interface for ");
673	  string_setlength (decl, string_length (decl) - 1);
674	  mangled += i + 1;
675	  return mangled;
676	}
677      else if (strncmp (mangled, "__ModuleInfoZ", i+1) == 0)
678	{
679	  /* The ModuleInfo symbol for a given module.  */
680	  string_prepend (decl, "ModuleInfo for ");
681	  string_setlength (decl, string_length (decl) - 1);
682	  mangled += i + 1;
683	  return mangled;
684	}
685
686      string_appendn (decl, mangled, i);
687      mangled += i;
688    }
689  else
690    return NULL;
691
692  return mangled;
693}
694
695/* Extract the integer value from MANGLED and append it to DECL,
696   where TYPE is the type it should be represented as.
697   Return the remaining string on success or NULL on failure.  */
698static const char *
699dlang_parse_integer (string *decl, const char *mangled, char type)
700{
701  if (type == 'a' || type == 'u' || type == 'w')
702    {
703      /* Parse character value.  */
704      char value[10];
705      int pos = 10;
706      int width = 0;
707      char *endptr;
708      long val = strtol (mangled, &endptr, 10);
709
710      if (endptr == NULL || val < 0)
711	return NULL;
712
713      string_append (decl, "'");
714
715      if (type == 'a' && val >= 0x20 && val < 0x7F)
716	{
717	  /* Represent as a character literal.  */
718	  char c = (char) val;
719	  string_appendn (decl, &c, 1);
720	}
721      else
722	{
723	  /* Represent as a hexadecimal value.  */
724	  switch (type)
725	    {
726	    case 'a': /* char */
727	      string_append (decl, "\\x");
728	      width = 2;
729	      break;
730	    case 'u': /* wchar */
731	      string_append (decl, "\\u");
732	      width = 4;
733	      break;
734	    case 'w': /* dchar */
735	      string_append (decl, "\\U");
736	      width = 8;
737	      break;
738	    }
739
740	  while (val > 0)
741	    {
742	      int digit = val % 16;
743
744	      if (digit < 10)
745		value[--pos] = (char)(digit + '0');
746	      else
747		value[--pos] = (char)((digit - 10) + 'a');
748
749	      val /= 16;
750	      width--;
751	    }
752
753	  for (; width > 0; width--)
754	    value[--pos] = '0';
755
756	  string_appendn (decl, &(value[pos]), 10 - pos);
757	}
758      string_append (decl, "'");
759      mangled = endptr;
760    }
761  else if (type == 'b')
762    {
763      /* Parse boolean value.  */
764      char *endptr;
765      long val = strtol (mangled, &endptr, 10);
766
767      if (endptr == NULL || val < 0)
768	return NULL;
769
770      string_append (decl, val ? "true" : "false");
771      mangled = endptr;
772    }
773  else
774    {
775      /* Parse integer value.  */
776      const char *numptr = mangled;
777      size_t num = 0;
778
779      while (ISDIGIT (*mangled))
780	{
781	  num++;
782	  mangled++;
783	}
784      string_appendn (decl, numptr, num);
785
786      /* Append suffix.  */
787      switch (type)
788	{
789	case 'h': /* ubyte */
790	case 't': /* ushort */
791	case 'k': /* uint */
792	  string_append (decl, "u");
793	  break;
794	case 'l': /* long */
795	  string_append (decl, "L");
796	  break;
797	case 'm': /* ulong */
798	  string_append (decl, "uL");
799	  break;
800	}
801    }
802
803  return mangled;
804}
805
806/* Extract the floating-point value from MANGLED and append it to DECL.
807   Return the remaining string on success or NULL on failure.  */
808static const char *
809dlang_parse_real (string *decl, const char *mangled)
810{
811  char buffer[64];
812  int len = 0;
813  double value;
814  char *endptr;
815
816  /* Handle NAN and +-INF.  */
817  if (strncmp (mangled, "NAN", 3) == 0)
818    {
819      string_append (decl, "NaN");
820      mangled += 3;
821      return mangled;
822    }
823  else if (strncmp (mangled, "INF", 3) == 0)
824    {
825      string_append (decl, "Inf");
826      mangled += 3;
827      return mangled;
828    }
829  else if (strncmp (mangled, "NINF", 4) == 0)
830    {
831      string_append (decl, "-Inf");
832      mangled += 4;
833      return mangled;
834    }
835
836  /* Hexadecimal prefix and leading bit.  */
837  if (*mangled == 'N')
838    {
839      buffer[len++] = '-';
840      mangled++;
841    }
842
843  if (!ISXDIGIT (*mangled))
844    return NULL;
845
846  buffer[len++] = '0';
847  buffer[len++] = 'x';
848  buffer[len++] = *mangled;
849  buffer[len++] = '.';
850  mangled++;
851
852  /* Significand.  */
853  while (ISXDIGIT (*mangled))
854    {
855      buffer[len++] = *mangled;
856      mangled++;
857    }
858
859  /* Exponent.  */
860  if (*mangled != 'P')
861    return NULL;
862
863  buffer[len++] = 'p';
864  mangled++;
865
866  if (*mangled == 'N')
867    {
868      buffer[len++] = '-';
869      mangled++;
870    }
871
872  while (ISDIGIT (*mangled))
873    {
874      buffer[len++] = *mangled;
875      mangled++;
876    }
877
878  /* Convert buffer from hexadecimal to floating-point.  */
879  buffer[len] = '\0';
880  value = strtod (buffer, &endptr);
881
882  if (endptr == NULL || endptr != (buffer + len))
883    return NULL;
884
885  len = snprintf (buffer, sizeof(buffer), "%#g", value);
886  string_appendn (decl, buffer, len);
887  return mangled;
888}
889
890/* Convert VAL from an ascii hexdigit to value.  */
891static char
892ascii2hex (char val)
893{
894  if (val >= 'a' && val <= 'f')
895    return (val - 'a' + 10);
896
897  if (val >= 'A' && val <= 'F')
898    return (val - 'A' + 10);
899
900  if (val >= '0' && val <= '9')
901    return (val - '0');
902
903  return 0;
904}
905
906/* Extract the string value from MANGLED and append it to DECL.
907   Return the remaining string on success or NULL on failure.  */
908static const char *
909dlang_parse_string (string *decl, const char *mangled)
910{
911  char type = *mangled;
912  char *endptr;
913  long len;
914
915  mangled++;
916  len = strtol (mangled, &endptr, 10);
917
918  if (endptr == NULL || len < 0)
919    return NULL;
920
921  mangled = endptr;
922  if (*mangled != '_')
923    return NULL;
924
925  mangled++;
926  string_append (decl, "\"");
927  while (len--)
928    {
929      if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
930	{
931	  char a = ascii2hex (mangled[0]);
932	  char b = ascii2hex (mangled[1]);
933	  char val = (a << 4) | b;
934	  string_appendn (decl, &val, 1);
935	}
936      else
937	return NULL;
938
939      mangled += 2;
940    }
941  string_append (decl, "\"");
942
943  if (type != 'a')
944    string_appendn (decl, &type, 1);
945
946  return mangled;
947}
948
949/* Extract the static array value from MANGLED and append it to DECL.
950   Return the remaining string on success or NULL on failure.  */
951static const char *
952dlang_parse_arrayliteral (string *decl, const char *mangled)
953{
954  char *endptr;
955  long elements = strtol (mangled, &endptr, 10);
956
957  if (endptr == NULL || elements < 0)
958    return NULL;
959
960  mangled = endptr;
961  string_append (decl, "[");
962  while (elements--)
963    {
964      mangled = dlang_value (decl, mangled, NULL, '\0');
965      if (elements != 0)
966	string_append (decl, ", ");
967    }
968
969  string_append (decl, "]");
970  return mangled;
971}
972
973/* Extract the associative array value from MANGLED and append it to DECL.
974   Return the remaining string on success or NULL on failure.  */
975static const char *
976dlang_parse_assocarray (string *decl, const char *mangled)
977{
978  char *endptr;
979  long elements = strtol (mangled, &endptr, 10);
980
981  if (endptr == NULL || elements < 0)
982    return NULL;
983
984  mangled = endptr;
985  string_append (decl, "[");
986  while (elements--)
987    {
988      mangled = dlang_value (decl, mangled, NULL, '\0');
989      string_append (decl, ":");
990      mangled = dlang_value (decl, mangled, NULL, '\0');
991
992      if (elements != 0)
993	string_append (decl, ", ");
994    }
995
996  string_append (decl, "]");
997  return mangled;
998}
999
1000/* Extract the struct literal value for NAME from MANGLED and append it to DECL.
1001   Return the remaining string on success or NULL on failure.  */
1002static const char *
1003dlang_parse_structlit (string *decl, const char *mangled, const char *name)
1004{
1005  char *endptr;
1006  long args = strtol (mangled, &endptr, 10);
1007
1008  if (endptr == NULL || args < 0)
1009    return NULL;
1010
1011  mangled = endptr;
1012  if (name != NULL)
1013    string_append (decl, name);
1014
1015  string_append (decl, "(");
1016  while (args--)
1017    {
1018      mangled = dlang_value (decl, mangled, NULL, '\0');
1019      if (args != 0)
1020	string_append (decl, ", ");
1021    }
1022
1023  string_append (decl, ")");
1024  return mangled;
1025}
1026
1027/* Extract the value from MANGLED and append it to DECL.
1028   Return the remaining string on success or NULL on failure.  */
1029static const char *
1030dlang_value (string *decl, const char *mangled, const char *name, char type)
1031{
1032  if (mangled == NULL || *mangled == '\0')
1033    return mangled;
1034
1035  switch (*mangled)
1036    {
1037      /* Null value.  */
1038    case 'n':
1039      mangled++;
1040      string_append (decl, "null");
1041      break;
1042
1043      /* Integral values.  */
1044    case 'N':
1045      mangled++;
1046      string_append (decl, "-");
1047      mangled = dlang_parse_integer (decl, mangled, type);
1048      break;
1049
1050    case 'i':
1051      mangled++;
1052      if (*mangled < '0' || *mangled > '9')
1053	return NULL;
1054      /* Fall through */
1055    case '0': case '1': case '2': case '3': case '4':
1056    case '5': case '6': case '7': case '8': case '9':
1057      mangled = dlang_parse_integer (decl, mangled, type);
1058      break;
1059
1060      /* Real value.  */
1061    case 'e':
1062      mangled++;
1063      mangled = dlang_parse_real (decl, mangled);
1064      break;
1065
1066      /* Complex value.  */
1067    case 'c':
1068      mangled++;
1069      mangled = dlang_parse_real (decl, mangled);
1070      string_append (decl, "+");
1071      if (mangled == NULL || *mangled != 'c')
1072	return NULL;
1073      mangled++;
1074      mangled = dlang_parse_real (decl, mangled);
1075      string_append (decl, "i");
1076      break;
1077
1078      /* String values.  */
1079    case 'a': /* UTF8 */
1080    case 'w': /* UTF16 */
1081    case 'd': /* UTF32 */
1082      mangled = dlang_parse_string (decl, mangled);
1083      break;
1084
1085      /* Array values.  */
1086    case 'A':
1087      mangled++;
1088      if (type == 'H')
1089	mangled = dlang_parse_assocarray (decl, mangled);
1090      else
1091	mangled = dlang_parse_arrayliteral (decl, mangled);
1092      break;
1093
1094      /* Struct values.  */
1095    case 'S':
1096      mangled++;
1097      mangled = dlang_parse_structlit (decl, mangled, name);
1098      break;
1099
1100    default:
1101      return NULL;
1102    }
1103
1104  return mangled;
1105}
1106
1107static int
1108dlang_call_convention_p (const char *mangled)
1109{
1110  size_t i;
1111
1112  switch (*mangled)
1113    {
1114    case 'F': case 'U': case 'V':
1115    case 'W': case 'R':
1116      return 1;
1117
1118    case 'M': /* Prefix for functions needing 'this' */
1119      i = 1;
1120      if (mangled[i] == 'x')
1121	i++;
1122
1123      switch (mangled[i])
1124	{
1125	case 'F': case 'U': case 'V':
1126	case 'W': case 'R':
1127	  return 1;
1128	}
1129
1130    default:
1131      return 0;
1132    }
1133}
1134
1135/* Extract and demangle the symbol in MANGLED and append it to DECL.
1136   Returns the remaining signature on success or NULL on failure.  */
1137static const char *
1138dlang_parse_symbol (string *decl, const char *mangled)
1139{
1140  size_t n = 0;
1141  do
1142    {
1143      if (n++)
1144	string_append (decl, ".");
1145
1146      mangled = dlang_identifier (decl, mangled);
1147
1148      if (mangled && dlang_call_convention_p (mangled))
1149	{
1150	  int saved;
1151
1152	  /* Skip over 'this' parameter.  */
1153	  if (*mangled == 'M')
1154	    mangled += (mangled[1] == 'x') ? 2 : 1;
1155
1156	  /* Skip over calling convention and attributes in qualified name.  */
1157	  saved = string_length (decl);
1158	  mangled = dlang_call_convention (decl, mangled);
1159	  mangled = dlang_attributes (decl, mangled);
1160	  string_setlength (decl, saved);
1161
1162	  string_append (decl, "(");
1163	  mangled = dlang_function_args (decl, mangled);
1164	  string_append (decl, ")");
1165
1166	  /* Demangle the function return type as a kind of sanity test.  */
1167	  if (mangled && !ISDIGIT (*mangled))
1168	    {
1169	      saved = string_length (decl);
1170	      mangled = dlang_type (decl, mangled);
1171	      string_setlength (decl, saved);
1172	    }
1173	}
1174    }
1175  while (mangled && ISDIGIT (*mangled));
1176
1177  return mangled;
1178}
1179
1180/* Demangle the tuple from MANGLED and append it to DECL.
1181   Return the remaining string on success or NULL on failure.  */
1182static const char *
1183dlang_parse_tuple (string *decl, const char *mangled)
1184{
1185  char *endptr;
1186  long elements = strtol (mangled, &endptr, 10);
1187
1188  if (endptr == NULL || elements < 0)
1189    return NULL;
1190
1191  mangled = endptr;
1192  string_append (decl, "Tuple!(");
1193
1194  while (elements--)
1195    {
1196      mangled = dlang_type (decl, mangled);
1197      if (elements != 0)
1198	string_append (decl, ", ");
1199    }
1200
1201  string_append (decl, ")");
1202  return mangled;
1203}
1204
1205/* Demangle the argument list from MANGLED and append it to DECL.
1206   Return the remaining string on success or NULL on failure.  */
1207static const char *
1208dlang_template_args (string *decl, const char *mangled)
1209{
1210  size_t n = 0;
1211
1212  while (mangled && *mangled != '\0')
1213    {
1214      switch (*mangled)
1215	{
1216	case 'Z': /* End of parameter list.  */
1217	  mangled++;
1218	  return mangled;
1219	}
1220
1221      if (n++)
1222	string_append (decl, ", ");
1223
1224      switch (*mangled)
1225	{
1226	case 'S': /* Symbol parameter.  */
1227	  mangled++;
1228	  mangled = dlang_parse_symbol (decl, mangled);
1229	  break;
1230	case 'T': /* Type parameter.  */
1231	  mangled++;
1232	  mangled = dlang_type (decl, mangled);
1233	  break;
1234	case 'V': /* Value parameter.  */
1235	{
1236	  string name;
1237	  char type;
1238
1239	  /* Peek at the type.  */
1240	  mangled++;
1241	  type = *mangled;
1242
1243	  /* In the few instances where the type is actually desired in
1244	     the output, it should precede the value from dlang_value.  */
1245	  string_init (&name);
1246	  mangled = dlang_type (&name, mangled);
1247	  string_need (&name, 1);
1248	  *(name.p) = '\0';
1249
1250	  mangled = dlang_value (decl, mangled, name.b, type);
1251	  string_delete (&name);
1252	  break;
1253	}
1254
1255	default:
1256	  return NULL;
1257	}
1258    }
1259
1260  return mangled;
1261}
1262
1263/* Extract and demangle the template symbol in MANGLED, expected to
1264   be made up of LEN characters, and append it to DECL.
1265   Returns the remaining signature on success or NULL on failure.  */
1266static const char *
1267dlang_parse_template (string *decl, const char *mangled, long len)
1268{
1269  const char *start = mangled;
1270
1271  /* Template instance names have the types and values of its parameters
1272     encoded into it.
1273
1274	TemplateInstanceName:
1275	    Number __T LName TemplateArgs Z
1276		   ^
1277     The start pointer should be at the above location, and LEN should be
1278     the value of the decoded number.
1279   */
1280  if (strncmp (mangled, "__T", 3) != 0)
1281    return NULL;
1282
1283  mangled += 3;
1284
1285  /* Template identifier.  */
1286  mangled = dlang_identifier (decl, mangled);
1287
1288  /* Template arguments.  */
1289  string_append (decl, "!(");
1290  mangled = dlang_template_args (decl, mangled);
1291  string_append (decl, ")");
1292
1293  /* Check for template name length mismatch.  */
1294  if (mangled && (mangled - start) != len)
1295    return NULL;
1296
1297  return mangled;
1298}
1299
1300/* Extract and demangle the symbol in MANGLED.  Returns the demangled
1301   signature on success or NULL on failure.  */
1302
1303char *
1304dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
1305{
1306  string decl;
1307  char *demangled = NULL;
1308
1309  if (mangled == NULL || *mangled == '\0')
1310    return NULL;
1311
1312  if (strncmp (mangled, "_D", 2) != 0)
1313    return NULL;
1314
1315  string_init (&decl);
1316
1317  if (strcmp (mangled, "_Dmain") == 0)
1318    {
1319      string_append (&decl, "D main");
1320    }
1321  else
1322    {
1323      mangled += 2;
1324
1325      if (dlang_parse_symbol (&decl, mangled) == NULL)
1326	string_delete (&decl);
1327    }
1328
1329  if (string_length (&decl) > 0)
1330    {
1331      string_need (&decl, 1);
1332      *(decl.p) = '\0';
1333      demangled = decl.b;
1334    }
1335
1336  return demangled;
1337}
1338
1339