OSDN Git Service

config/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / src / debug.cc
1 // Debugging mode support code -*- C++ -*-
2
3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 // <http://www.gnu.org/licenses/>.
25
26 #include <debug/debug.h>
27 #include <debug/safe_sequence.h>
28 #include <debug/safe_iterator.h>
29 #include <algorithm>
30 #include <cassert>
31 #include <cstring>
32 #include <cctype>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <functional>
36
37 using namespace std;
38
39 namespace
40 {
41   /** Returns different instances of __mutex depending on the passed address
42    *  in order to limit contention without breaking current library binary
43    *  compatibility. */
44   __gnu_cxx::__mutex&
45   get_safe_base_mutex(void* __address)
46   {
47     const size_t mask = 0xf;
48     static __gnu_cxx::__mutex safe_base_mutex[mask + 1];
49     const size_t index = _Hash_impl::hash(__address) & mask;
50     return safe_base_mutex[index];
51   }
52
53   void
54   swap_seq(__gnu_debug::_Safe_sequence_base& __lhs,
55            __gnu_debug::_Safe_sequence_base& __rhs)
56   {
57     swap(__lhs._M_iterators, __rhs._M_iterators);
58     swap(__lhs._M_const_iterators, __rhs._M_const_iterators);
59     swap(__lhs._M_version, __rhs._M_version);
60     __gnu_debug::_Safe_iterator_base* __iter;
61     for (__iter = __rhs._M_iterators; __iter; __iter = __iter->_M_next)
62       __iter->_M_sequence = &__rhs;
63     for (__iter = __lhs._M_iterators; __iter; __iter = __iter->_M_next)
64       __iter->_M_sequence = &__lhs;
65     for (__iter = __rhs._M_const_iterators; __iter; __iter = __iter->_M_next)
66       __iter->_M_sequence = &__rhs;
67     for (__iter = __lhs._M_const_iterators; __iter; __iter = __iter->_M_next)
68       __iter->_M_sequence = &__lhs;
69   }
70 } // anonymous namespace
71
72 namespace __gnu_debug
73 {
74   const char* _S_debug_messages[] = 
75   {
76     "function requires a valid iterator range [%1.name;, %2.name;)",
77     "attempt to insert into container with a singular iterator",
78     "attempt to insert into container with an iterator"
79     " from a different container",
80     "attempt to erase from container with a %2.state; iterator",
81     "attempt to erase from container with an iterator"
82     " from a different container",
83     "attempt to subscript container with out-of-bounds index %2;,"
84     " but container only holds %3; elements",
85     "attempt to access an element in an empty container",
86     "elements in iterator range [%1.name;, %2.name;)"
87     " are not partitioned by the value %3;",
88     "elements in iterator range [%1.name;, %2.name;)"
89     " are not partitioned by the predicate %3; and value %4;",
90     "elements in iterator range [%1.name;, %2.name;) are not sorted",
91     "elements in iterator range [%1.name;, %2.name;)"
92     " are not sorted according to the predicate %3;",
93     "elements in iterator range [%1.name;, %2.name;) do not form a heap",
94     "elements in iterator range [%1.name;, %2.name;)"
95     " do not form a heap with respect to the predicate %3;",
96     "attempt to write through a singular bitset reference",
97     "attempt to read from a singular bitset reference",
98     "attempt to flip a singular bitset reference",
99     "attempt to splice a list into itself",
100     "attempt to splice lists with inequal allocators",
101     "attempt to splice elements referenced by a %1.state; iterator",
102     "attempt to splice an iterator from a different container",
103     "splice destination %1.name;"
104     " occurs within source range [%2.name;, %3.name;)",
105     "attempt to initialize an iterator that will immediately become singular",
106     "attempt to copy-construct an iterator from a singular iterator",
107     "attempt to construct a constant iterator"
108     " from a singular mutable iterator",
109     "attempt to copy from a singular iterator",
110     "attempt to dereference a %1.state; iterator",
111     "attempt to increment a %1.state; iterator",
112     "attempt to decrement a %1.state; iterator",
113     "attempt to subscript a %1.state; iterator %2; step from"
114     " its current position, which falls outside its dereferenceable range",
115     "attempt to advance a %1.state; iterator %2; steps,"
116     " which falls outside its valid range",
117     "attempt to retreat a %1.state; iterator %2; steps,"
118     " which falls outside its valid range",
119     "attempt to compare a %1.state; iterator to a %2.state; iterator",
120     "attempt to compare iterators from different sequences",
121     "attempt to order a %1.state; iterator to a %2.state; iterator",
122     "attempt to order iterators from different sequences",
123     "attempt to compute the difference between a %1.state;"
124     " iterator to a %2.state; iterator",
125     "attempt to compute the different between two iterators"
126     " from different sequences",
127     "attempt to dereference an end-of-stream istream_iterator",
128     "attempt to increment an end-of-stream istream_iterator",
129     "attempt to output via an ostream_iterator with no associated stream",
130     "attempt to dereference an end-of-stream istreambuf_iterator"
131     " (this is a GNU extension)",
132     "attempt to increment an end-of-stream istreambuf_iterator",
133     "attempt to insert into container after an end iterator",
134     "attempt to erase from container after a %2.state; iterator not followed"
135     " by a dereferenceable one",
136     "function requires a valid iterator range (%2.name;, %3.name;)"
137     ", \"%2.name;\" shall be before and not equal to \"%3.name;\""
138   };
139
140   void
141   _Safe_sequence_base::
142   _M_detach_all()
143   {
144     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
145     for (_Safe_iterator_base* __iter = _M_iterators; __iter;)
146       {
147         _Safe_iterator_base* __old = __iter;
148         __iter = __iter->_M_next;
149         __old->_M_reset();
150       }
151     _M_iterators = 0;
152     
153     for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;)
154       {
155         _Safe_iterator_base* __old = __iter2;
156         __iter2 = __iter2->_M_next;
157         __old->_M_reset();
158       }
159     _M_const_iterators = 0;
160   }
161
162   void
163   _Safe_sequence_base::
164   _M_detach_singular()
165   {
166     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
167     for (_Safe_iterator_base* __iter = _M_iterators; __iter;)
168       {
169         _Safe_iterator_base* __old = __iter;
170         __iter = __iter->_M_next;
171         if (__old->_M_singular())
172           __old->_M_detach_single();
173       }
174
175     for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;)
176       {
177         _Safe_iterator_base* __old = __iter2;
178         __iter2 = __iter2->_M_next;
179         if (__old->_M_singular())
180           __old->_M_detach_single();
181       }
182   }
183
184   void
185   _Safe_sequence_base::
186   _M_revalidate_singular()
187   {
188     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
189     for (_Safe_iterator_base* __iter = _M_iterators; __iter;
190          __iter = __iter->_M_next)
191       __iter->_M_version = _M_version;
192
193     for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;
194          __iter2 = __iter2->_M_next)
195       __iter2->_M_version = _M_version;
196   }
197
198   void
199   _Safe_sequence_base::
200   _M_swap(_Safe_sequence_base& __x)
201   {
202     // We need to lock both sequences to swap
203     using namespace __gnu_cxx;
204     __mutex *__this_mutex = &_M_get_mutex();
205     __mutex *__x_mutex = &__x._M_get_mutex();
206     if (__this_mutex == __x_mutex)
207       {
208         __scoped_lock __lock(*__this_mutex);
209         swap_seq(*this, __x);
210       }
211     else
212       {
213         __scoped_lock __l1(__this_mutex < __x_mutex
214                              ? *__this_mutex : *__x_mutex);
215         __scoped_lock __l2(__this_mutex < __x_mutex
216                              ? *__x_mutex : *__this_mutex);
217         swap_seq(*this, __x);
218       }
219   }
220
221   __gnu_cxx::__mutex&
222   _Safe_sequence_base::
223   _M_get_mutex() throw ()
224   { return get_safe_base_mutex(this); }
225
226   void
227   _Safe_sequence_base::
228   _M_attach(_Safe_iterator_base* __it, bool __constant)
229   {
230     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
231     _M_attach_single(__it, __constant);
232   }
233
234   void
235   _Safe_sequence_base::
236   _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw ()
237   {
238     _Safe_iterator_base*& __its =
239       __constant ? _M_const_iterators : _M_iterators;
240     __it->_M_next = __its;
241     if (__it->_M_next)
242       __it->_M_next->_M_prior = __it;
243     __its = __it;
244   }
245
246   void
247   _Safe_sequence_base::
248   _M_detach(_Safe_iterator_base* __it)
249   {
250     // Remove __it from this sequence's list
251     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
252     _M_detach_single(__it);
253   }
254
255   void
256   _Safe_sequence_base::
257   _M_detach_single(_Safe_iterator_base* __it) throw ()
258   {
259     // Remove __it from this sequence's list
260     if (__it->_M_prior)
261       __it->_M_prior->_M_next = __it->_M_next;
262     if (__it->_M_next)
263       __it->_M_next->_M_prior = __it->_M_prior;
264         
265     if (_M_const_iterators == __it)
266       _M_const_iterators = __it->_M_next;
267     if (_M_iterators == __it)
268       _M_iterators = __it->_M_next;
269   }
270
271   void
272   _Safe_iterator_base::
273   _M_attach(_Safe_sequence_base* __seq, bool __constant)
274   {
275     _M_detach();
276     
277     // Attach to the new sequence (if there is one)
278     if (__seq)
279       {
280         _M_sequence = __seq;
281         _M_version = _M_sequence->_M_version;
282         _M_sequence->_M_attach(this, __constant);
283       }
284   }
285   
286   void
287   _Safe_iterator_base::
288   _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw ()
289   {
290     _M_detach_single();
291     
292     // Attach to the new sequence (if there is one)
293     if (__seq)
294       {
295         _M_sequence = __seq;
296         _M_version = _M_sequence->_M_version;
297         _M_sequence->_M_attach_single(this, __constant);
298       }
299   }
300
301   void
302   _Safe_iterator_base::
303   _M_detach()
304   {
305     if (_M_sequence)
306       {
307         _M_sequence->_M_detach(this);
308       }
309
310     _M_reset();
311   }
312
313   void
314   _Safe_iterator_base::
315   _M_detach_single() throw ()
316   {
317     if (_M_sequence)
318       {
319         _M_sequence->_M_detach_single(this);
320       }
321
322     _M_reset();
323   }
324
325   void
326   _Safe_iterator_base::
327   _M_reset() throw ()
328   {
329     _M_sequence = 0;
330     _M_version = 0;
331     _M_prior = 0;
332     _M_next = 0;
333   }
334
335   bool
336   _Safe_iterator_base::
337   _M_singular() const throw ()
338   { return !_M_sequence || _M_version != _M_sequence->_M_version; }
339     
340   bool
341   _Safe_iterator_base::
342   _M_can_compare(const _Safe_iterator_base& __x) const throw ()
343   {
344     return (!_M_singular() 
345             && !__x._M_singular() && _M_sequence == __x._M_sequence);
346   }
347
348   __gnu_cxx::__mutex&
349   _Safe_iterator_base::
350   _M_get_mutex() throw ()
351   { return get_safe_base_mutex(_M_sequence); }
352
353   void
354   _Error_formatter::_Parameter::
355   _M_print_field(const _Error_formatter* __formatter, const char* __name) const
356   {
357     assert(this->_M_kind != _Parameter::__unused_param);
358     const int __bufsize = 64;
359     char __buf[__bufsize];
360     
361     if (_M_kind == __iterator)
362       {
363         if (strcmp(__name, "name") == 0)
364           {
365             assert(_M_variant._M_iterator._M_name);
366             __formatter->_M_print_word(_M_variant._M_iterator._M_name);
367           }
368         else if (strcmp(__name, "address") == 0)
369           {
370             __formatter->_M_format_word(__buf, __bufsize, "%p", 
371                                         _M_variant._M_iterator._M_address);
372             __formatter->_M_print_word(__buf);
373           }
374         else if (strcmp(__name, "type") == 0)
375           {
376             if (!_M_variant._M_iterator._M_type)
377               __formatter->_M_print_word("<unknown type>");
378             else
379               // TBD: demangle!
380               __formatter->_M_print_word(_M_variant._M_iterator.
381                                          _M_type->name());
382           }
383         else if (strcmp(__name, "constness") == 0)
384           {
385             static const char* __constness_names[__last_constness] =
386               {
387                 "<unknown>",
388                 "constant",
389                 "mutable"
390               };
391             __formatter->_M_print_word(__constness_names[_M_variant.
392                                                          _M_iterator.
393                                                          _M_constness]);
394           }
395         else if (strcmp(__name, "state") == 0)
396           {
397             static const char* __state_names[__last_state] = 
398               {
399                 "<unknown>",
400                 "singular",
401                 "dereferenceable (start-of-sequence)",
402                 "dereferenceable",
403                 "past-the-end",
404                 "before-begin"
405               };
406             __formatter->_M_print_word(__state_names[_M_variant.
407                                                      _M_iterator._M_state]);
408           }
409         else if (strcmp(__name, "sequence") == 0)
410           {
411             assert(_M_variant._M_iterator._M_sequence);
412             __formatter->_M_format_word(__buf, __bufsize, "%p", 
413                                         _M_variant._M_iterator._M_sequence);
414             __formatter->_M_print_word(__buf);
415           }
416         else if (strcmp(__name, "seq_type") == 0)
417           {
418             if (!_M_variant._M_iterator._M_seq_type)
419               __formatter->_M_print_word("<unknown seq_type>");
420             else
421               // TBD: demangle!
422               __formatter->_M_print_word(_M_variant._M_iterator.
423                                          _M_seq_type->name());
424           }
425         else
426           assert(false);
427       }
428     else if (_M_kind == __sequence)
429       {
430         if (strcmp(__name, "name") == 0)
431           {
432             assert(_M_variant._M_sequence._M_name);
433             __formatter->_M_print_word(_M_variant._M_sequence._M_name);
434           }
435         else if (strcmp(__name, "address") == 0)
436           {
437             assert(_M_variant._M_sequence._M_address);
438             __formatter->_M_format_word(__buf, __bufsize, "%p", 
439                                         _M_variant._M_sequence._M_address);
440             __formatter->_M_print_word(__buf);
441           }
442         else if (strcmp(__name, "type") == 0)
443           {
444             if (!_M_variant._M_sequence._M_type)
445               __formatter->_M_print_word("<unknown type>");
446             else
447               // TBD: demangle!
448               __formatter->_M_print_word(_M_variant._M_sequence.
449                                          _M_type->name());
450           }
451         else
452           assert(false);
453       }
454     else if (_M_kind == __integer)
455       {
456         if (strcmp(__name, "name") == 0)
457           {
458             assert(_M_variant._M_integer._M_name);
459             __formatter->_M_print_word(_M_variant._M_integer._M_name);
460           }
461         else
462         assert(false);
463       }
464     else if (_M_kind == __string)
465       {
466         if (strcmp(__name, "name") == 0)
467           {
468             assert(_M_variant._M_string._M_name);
469             __formatter->_M_print_word(_M_variant._M_string._M_name);
470           }
471         else
472           assert(false);
473       }
474     else
475       {
476         assert(false);
477       }
478   }
479   
480   void
481   _Error_formatter::_Parameter::
482   _M_print_description(const _Error_formatter* __formatter) const
483   {
484     const int __bufsize = 128;
485     char __buf[__bufsize];
486     
487     if (_M_kind == __iterator)
488       {
489         __formatter->_M_print_word("iterator ");
490         if (_M_variant._M_iterator._M_name)
491           {
492             __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", 
493                                         _M_variant._M_iterator._M_name);
494             __formatter->_M_print_word(__buf);
495           }
496         
497         __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", 
498                                     _M_variant._M_iterator._M_address);
499         __formatter->_M_print_word(__buf);
500         if (_M_variant._M_iterator._M_type)
501           {
502             __formatter->_M_print_word("type = ");
503             _M_print_field(__formatter, "type");
504             
505             if (_M_variant._M_iterator._M_constness != __unknown_constness)
506               {
507                 __formatter->_M_print_word(" (");
508                 _M_print_field(__formatter, "constness");
509                 __formatter->_M_print_word(" iterator)");
510               }
511             __formatter->_M_print_word(";\n");
512           }
513         
514         if (_M_variant._M_iterator._M_state != __unknown_state)
515           {
516             __formatter->_M_print_word("  state = ");
517             _M_print_field(__formatter, "state");
518             __formatter->_M_print_word(";\n");
519           }
520         
521         if (_M_variant._M_iterator._M_sequence)
522           {
523             __formatter->_M_print_word("  references sequence ");
524             if (_M_variant._M_iterator._M_seq_type)
525               {
526                 __formatter->_M_print_word("with type `");
527                 _M_print_field(__formatter, "seq_type");
528                 __formatter->_M_print_word("' ");
529               }
530             
531             __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n", 
532                                         _M_variant._M_sequence._M_address);
533             __formatter->_M_print_word(__buf);
534           }
535         __formatter->_M_print_word("}\n");
536       }
537     else if (_M_kind == __sequence)
538       {
539         __formatter->_M_print_word("sequence ");
540         if (_M_variant._M_sequence._M_name)
541           {
542             __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", 
543                                         _M_variant._M_sequence._M_name);
544             __formatter->_M_print_word(__buf);
545           }
546         
547         __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", 
548                                     _M_variant._M_sequence._M_address);
549         __formatter->_M_print_word(__buf);
550         
551         if (_M_variant._M_sequence._M_type)
552           {
553             __formatter->_M_print_word("  type = ");
554             _M_print_field(__formatter, "type");
555             __formatter->_M_print_word(";\n");
556           }       
557         __formatter->_M_print_word("}\n");
558       }
559   }
560
561   const _Error_formatter&
562   _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
563   { return this->_M_message(_S_debug_messages[__id]); }
564   
565   void
566   _Error_formatter::_M_error() const
567   {
568     const int __bufsize = 128;
569     char __buf[__bufsize];
570     
571     // Emit file & line number information
572     _M_column = 1;
573     _M_wordwrap = false;
574     if (_M_file)
575       {
576         _M_format_word(__buf, __bufsize, "%s:", _M_file);
577         _M_print_word(__buf);
578         _M_column += strlen(__buf);
579       }
580     
581     if (_M_line > 0)
582       {
583         _M_format_word(__buf, __bufsize, "%u:", _M_line);
584         _M_print_word(__buf);
585         _M_column += strlen(__buf);
586       }
587     
588     if (_M_max_length)
589       _M_wordwrap = true;
590     _M_print_word("error: ");
591     
592     // Print the error message
593     assert(_M_text);
594     _M_print_string(_M_text);
595     _M_print_word(".\n");
596     
597     // Emit descriptions of the objects involved in the operation
598     _M_wordwrap = false;
599     bool __has_noninteger_parameters = false;
600     for (unsigned int __i = 0; __i < _M_num_parameters; ++__i)
601       {
602         if (_M_parameters[__i]._M_kind == _Parameter::__iterator
603             || _M_parameters[__i]._M_kind == _Parameter::__sequence)
604           {
605             if (!__has_noninteger_parameters)
606               {
607                 _M_first_line = true;
608                 _M_print_word("\nObjects involved in the operation:\n");
609                 __has_noninteger_parameters = true;
610               }
611             _M_parameters[__i]._M_print_description(this);
612           }
613       }
614     
615     abort();
616   }
617
618   template<typename _Tp>
619     void
620     _Error_formatter::_M_format_word(char* __buf, 
621                                      int __n __attribute__ ((__unused__)), 
622                                      const char* __fmt, _Tp __s) const throw ()
623     {
624 #ifdef _GLIBCXX_USE_C99
625       std::snprintf(__buf, __n, __fmt, __s);
626 #else
627       std::sprintf(__buf, __fmt, __s);
628 #endif
629     }
630
631   
632   void 
633   _Error_formatter::_M_print_word(const char* __word) const
634   {
635     if (!_M_wordwrap) 
636       {
637         fprintf(stderr, "%s", __word);
638         return;
639       }
640     
641     size_t __length = strlen(__word);
642     if (__length == 0)
643       return;
644     
645     if ((_M_column + __length < _M_max_length)
646         || (__length >= _M_max_length && _M_column == 1)) 
647       {
648         // If this isn't the first line, indent
649         if (_M_column == 1 && !_M_first_line)
650           {
651             char __spacing[_M_indent + 1];
652             for (int i = 0; i < _M_indent; ++i)
653               __spacing[i] = ' ';
654             __spacing[_M_indent] = '\0';
655             fprintf(stderr, "%s", __spacing);
656             _M_column += _M_indent;
657           }
658         
659         fprintf(stderr, "%s", __word);
660         _M_column += __length;
661         
662         if (__word[__length - 1] == '\n') 
663           {
664             _M_first_line = false;
665             _M_column = 1;
666           }
667       }
668     else
669       {
670         _M_column = 1;
671         _M_print_word("\n");
672         _M_print_word(__word);
673       }
674   }
675   
676   void
677   _Error_formatter::
678   _M_print_string(const char* __string) const
679   {
680     const char* __start = __string;
681     const char* __finish = __start;
682     const int __bufsize = 128;
683     char __buf[__bufsize];
684
685     while (*__start)
686       {
687         if (*__start != '%')
688           {
689             // [__start, __finish) denotes the next word
690             __finish = __start;
691             while (isalnum(*__finish))
692               ++__finish;
693             if (__start == __finish)
694               ++__finish;
695             if (isspace(*__finish))
696               ++__finish;
697             
698             const ptrdiff_t __len = __finish - __start;
699             assert(__len < __bufsize);
700             memcpy(__buf, __start, __len);
701             __buf[__len] = '\0';
702             _M_print_word(__buf);
703             __start = __finish;
704             
705             // Skip extra whitespace
706             while (*__start == ' ') 
707               ++__start;
708             
709             continue;
710           } 
711         
712         ++__start;
713         assert(*__start);
714         if (*__start == '%')
715           {
716             _M_print_word("%");
717             ++__start;
718             continue;
719           }
720         
721         // Get the parameter number
722         assert(*__start >= '1' && *__start <= '9');
723         size_t __param = *__start - '0';
724         --__param;
725         assert(__param < _M_num_parameters);
726       
727         // '.' separates the parameter number from the field
728         // name, if there is one.
729         ++__start;
730         if (*__start != '.')
731           {
732             assert(*__start == ';');
733             ++__start;
734             __buf[0] = '\0';
735             if (_M_parameters[__param]._M_kind == _Parameter::__integer)
736               {
737                 _M_format_word(__buf, __bufsize, "%ld", 
738                                _M_parameters[__param]._M_variant._M_integer._M_value);
739                 _M_print_word(__buf);
740               }
741             else if (_M_parameters[__param]._M_kind == _Parameter::__string)
742               _M_print_string(_M_parameters[__param]._M_variant._M_string._M_value);
743             continue;
744           }
745         
746         // Extract the field name we want
747         enum { __max_field_len = 16 };
748         char __field[__max_field_len];
749         int __field_idx = 0;
750         ++__start;
751         while (*__start != ';')
752           {
753             assert(*__start);
754             assert(__field_idx < __max_field_len-1);
755             __field[__field_idx++] = *__start++;
756           }
757         ++__start;
758         __field[__field_idx] = 0;
759         
760         _M_parameters[__param]._M_print_field(this, __field);             
761       }
762   }
763
764   void
765   _Error_formatter::_M_get_max_length() const throw ()
766   {
767     const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
768     if (__nptr)
769       {
770         char* __endptr;
771         const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
772         if (*__nptr != '\0' && *__endptr == '\0')
773           _M_max_length = __ret;
774       }
775   }
776
777   // Instantiations.
778   template
779     void
780     _Error_formatter::_M_format_word(char*, int, const char*, 
781                                      const void*) const;
782
783   template
784     void
785     _Error_formatter::_M_format_word(char*, int, const char*, long) const;
786
787   template
788     void
789     _Error_formatter::_M_format_word(char*, int, const char*, 
790                                      std::size_t) const;
791
792   template
793     void
794     _Error_formatter::_M_format_word(char*, int, const char*, 
795                                      const char*) const;
796 } // namespace __gnu_debug