]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libstdc++-v3/contrib/libstdc++-v3-4.6/src/debug.cc
update
[l4.git] / l4 / pkg / libstdc++-v3 / contrib / libstdc++-v3-4.6 / 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     __it->_M_unlink();
261     if (_M_const_iterators == __it)
262       _M_const_iterators = __it->_M_next;
263     if (_M_iterators == __it)
264       _M_iterators = __it->_M_next;
265   }
266
267   void
268   _Safe_iterator_base::
269   _M_attach(_Safe_sequence_base* __seq, bool __constant)
270   {
271     _M_detach();
272     
273     // Attach to the new sequence (if there is one)
274     if (__seq)
275       {
276         _M_sequence = __seq;
277         _M_version = _M_sequence->_M_version;
278         _M_sequence->_M_attach(this, __constant);
279       }
280   }
281   
282   void
283   _Safe_iterator_base::
284   _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw ()
285   {
286     _M_detach_single();
287     
288     // Attach to the new sequence (if there is one)
289     if (__seq)
290       {
291         _M_sequence = __seq;
292         _M_version = _M_sequence->_M_version;
293         _M_sequence->_M_attach_single(this, __constant);
294       }
295   }
296
297   void
298   _Safe_iterator_base::
299   _M_detach()
300   {
301     if (_M_sequence)
302       {
303         _M_sequence->_M_detach(this);
304       }
305
306     _M_reset();
307   }
308
309   void
310   _Safe_iterator_base::
311   _M_detach_single() throw ()
312   {
313     if (_M_sequence)
314       {
315         _M_sequence->_M_detach_single(this);
316       }
317
318     _M_reset();
319   }
320
321   void
322   _Safe_iterator_base::
323   _M_reset() throw ()
324   {
325     _M_sequence = 0;
326     _M_version = 0;
327     _M_prior = 0;
328     _M_next = 0;
329   }
330
331   bool
332   _Safe_iterator_base::
333   _M_singular() const throw ()
334   { return !_M_sequence || _M_version != _M_sequence->_M_version; }
335     
336   bool
337   _Safe_iterator_base::
338   _M_can_compare(const _Safe_iterator_base& __x) const throw ()
339   {
340     return (!_M_singular() 
341             && !__x._M_singular() && _M_sequence == __x._M_sequence);
342   }
343
344   __gnu_cxx::__mutex&
345   _Safe_iterator_base::
346   _M_get_mutex() throw ()
347   { return get_safe_base_mutex(_M_sequence); }
348
349   void
350   _Error_formatter::_Parameter::
351   _M_print_field(const _Error_formatter* __formatter, const char* __name) const
352   {
353     assert(this->_M_kind != _Parameter::__unused_param);
354     const int __bufsize = 64;
355     char __buf[__bufsize];
356     
357     if (_M_kind == __iterator)
358       {
359         if (strcmp(__name, "name") == 0)
360           {
361             assert(_M_variant._M_iterator._M_name);
362             __formatter->_M_print_word(_M_variant._M_iterator._M_name);
363           }
364         else if (strcmp(__name, "address") == 0)
365           {
366             __formatter->_M_format_word(__buf, __bufsize, "%p", 
367                                         _M_variant._M_iterator._M_address);
368             __formatter->_M_print_word(__buf);
369           }
370         else if (strcmp(__name, "type") == 0)
371           {
372             if (!_M_variant._M_iterator._M_type)
373               __formatter->_M_print_word("<unknown type>");
374             else
375               // TBD: demangle!
376               __formatter->_M_print_word(_M_variant._M_iterator.
377                                          _M_type->name());
378           }
379         else if (strcmp(__name, "constness") == 0)
380           {
381             static const char* __constness_names[__last_constness] =
382               {
383                 "<unknown>",
384                 "constant",
385                 "mutable"
386               };
387             __formatter->_M_print_word(__constness_names[_M_variant.
388                                                          _M_iterator.
389                                                          _M_constness]);
390           }
391         else if (strcmp(__name, "state") == 0)
392           {
393             static const char* __state_names[__last_state] = 
394               {
395                 "<unknown>",
396                 "singular",
397                 "dereferenceable (start-of-sequence)",
398                 "dereferenceable",
399                 "past-the-end",
400                 "before-begin"
401               };
402             __formatter->_M_print_word(__state_names[_M_variant.
403                                                      _M_iterator._M_state]);
404           }
405         else if (strcmp(__name, "sequence") == 0)
406           {
407             assert(_M_variant._M_iterator._M_sequence);
408             __formatter->_M_format_word(__buf, __bufsize, "%p", 
409                                         _M_variant._M_iterator._M_sequence);
410             __formatter->_M_print_word(__buf);
411           }
412         else if (strcmp(__name, "seq_type") == 0)
413           {
414             if (!_M_variant._M_iterator._M_seq_type)
415               __formatter->_M_print_word("<unknown seq_type>");
416             else
417               // TBD: demangle!
418               __formatter->_M_print_word(_M_variant._M_iterator.
419                                          _M_seq_type->name());
420           }
421         else
422           assert(false);
423       }
424     else if (_M_kind == __sequence)
425       {
426         if (strcmp(__name, "name") == 0)
427           {
428             assert(_M_variant._M_sequence._M_name);
429             __formatter->_M_print_word(_M_variant._M_sequence._M_name);
430           }
431         else if (strcmp(__name, "address") == 0)
432           {
433             assert(_M_variant._M_sequence._M_address);
434             __formatter->_M_format_word(__buf, __bufsize, "%p", 
435                                         _M_variant._M_sequence._M_address);
436             __formatter->_M_print_word(__buf);
437           }
438         else if (strcmp(__name, "type") == 0)
439           {
440             if (!_M_variant._M_sequence._M_type)
441               __formatter->_M_print_word("<unknown type>");
442             else
443               // TBD: demangle!
444               __formatter->_M_print_word(_M_variant._M_sequence.
445                                          _M_type->name());
446           }
447         else
448           assert(false);
449       }
450     else if (_M_kind == __integer)
451       {
452         if (strcmp(__name, "name") == 0)
453           {
454             assert(_M_variant._M_integer._M_name);
455             __formatter->_M_print_word(_M_variant._M_integer._M_name);
456           }
457         else
458         assert(false);
459       }
460     else if (_M_kind == __string)
461       {
462         if (strcmp(__name, "name") == 0)
463           {
464             assert(_M_variant._M_string._M_name);
465             __formatter->_M_print_word(_M_variant._M_string._M_name);
466           }
467         else
468           assert(false);
469       }
470     else
471       {
472         assert(false);
473       }
474   }
475   
476   void
477   _Error_formatter::_Parameter::
478   _M_print_description(const _Error_formatter* __formatter) const
479   {
480     const int __bufsize = 128;
481     char __buf[__bufsize];
482     
483     if (_M_kind == __iterator)
484       {
485         __formatter->_M_print_word("iterator ");
486         if (_M_variant._M_iterator._M_name)
487           {
488             __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", 
489                                         _M_variant._M_iterator._M_name);
490             __formatter->_M_print_word(__buf);
491           }
492         
493         __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", 
494                                     _M_variant._M_iterator._M_address);
495         __formatter->_M_print_word(__buf);
496         if (_M_variant._M_iterator._M_type)
497           {
498             __formatter->_M_print_word("type = ");
499             _M_print_field(__formatter, "type");
500             
501             if (_M_variant._M_iterator._M_constness != __unknown_constness)
502               {
503                 __formatter->_M_print_word(" (");
504                 _M_print_field(__formatter, "constness");
505                 __formatter->_M_print_word(" iterator)");
506               }
507             __formatter->_M_print_word(";\n");
508           }
509         
510         if (_M_variant._M_iterator._M_state != __unknown_state)
511           {
512             __formatter->_M_print_word("  state = ");
513             _M_print_field(__formatter, "state");
514             __formatter->_M_print_word(";\n");
515           }
516         
517         if (_M_variant._M_iterator._M_sequence)
518           {
519             __formatter->_M_print_word("  references sequence ");
520             if (_M_variant._M_iterator._M_seq_type)
521               {
522                 __formatter->_M_print_word("with type `");
523                 _M_print_field(__formatter, "seq_type");
524                 __formatter->_M_print_word("' ");
525               }
526             
527             __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n", 
528                                         _M_variant._M_sequence._M_address);
529             __formatter->_M_print_word(__buf);
530           }
531         __formatter->_M_print_word("}\n");
532       }
533     else if (_M_kind == __sequence)
534       {
535         __formatter->_M_print_word("sequence ");
536         if (_M_variant._M_sequence._M_name)
537           {
538             __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", 
539                                         _M_variant._M_sequence._M_name);
540             __formatter->_M_print_word(__buf);
541           }
542         
543         __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", 
544                                     _M_variant._M_sequence._M_address);
545         __formatter->_M_print_word(__buf);
546         
547         if (_M_variant._M_sequence._M_type)
548           {
549             __formatter->_M_print_word("  type = ");
550             _M_print_field(__formatter, "type");
551             __formatter->_M_print_word(";\n");
552           }       
553         __formatter->_M_print_word("}\n");
554       }
555   }
556
557   const _Error_formatter&
558   _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
559   { return this->_M_message(_S_debug_messages[__id]); }
560   
561   void
562   _Error_formatter::_M_error() const
563   {
564     const int __bufsize = 128;
565     char __buf[__bufsize];
566     
567     // Emit file & line number information
568     _M_column = 1;
569     _M_wordwrap = false;
570     if (_M_file)
571       {
572         _M_format_word(__buf, __bufsize, "%s:", _M_file);
573         _M_print_word(__buf);
574         _M_column += strlen(__buf);
575       }
576     
577     if (_M_line > 0)
578       {
579         _M_format_word(__buf, __bufsize, "%u:", _M_line);
580         _M_print_word(__buf);
581         _M_column += strlen(__buf);
582       }
583     
584     if (_M_max_length)
585       _M_wordwrap = true;
586     _M_print_word("error: ");
587     
588     // Print the error message
589     assert(_M_text);
590     _M_print_string(_M_text);
591     _M_print_word(".\n");
592     
593     // Emit descriptions of the objects involved in the operation
594     _M_wordwrap = false;
595     bool __has_noninteger_parameters = false;
596     for (unsigned int __i = 0; __i < _M_num_parameters; ++__i)
597       {
598         if (_M_parameters[__i]._M_kind == _Parameter::__iterator
599             || _M_parameters[__i]._M_kind == _Parameter::__sequence)
600           {
601             if (!__has_noninteger_parameters)
602               {
603                 _M_first_line = true;
604                 _M_print_word("\nObjects involved in the operation:\n");
605                 __has_noninteger_parameters = true;
606               }
607             _M_parameters[__i]._M_print_description(this);
608           }
609       }
610     
611     abort();
612   }
613
614   template<typename _Tp>
615     void
616     _Error_formatter::_M_format_word(char* __buf, 
617                                      int __n __attribute__ ((__unused__)), 
618                                      const char* __fmt, _Tp __s) const throw ()
619     {
620 #ifdef _GLIBCXX_USE_C99
621       std::snprintf(__buf, __n, __fmt, __s);
622 #else
623       std::sprintf(__buf, __fmt, __s);
624 #endif
625     }
626
627   
628   void 
629   _Error_formatter::_M_print_word(const char* __word) const
630   {
631     if (!_M_wordwrap) 
632       {
633         fprintf(stderr, "%s", __word);
634         return;
635       }
636     
637     size_t __length = strlen(__word);
638     if (__length == 0)
639       return;
640     
641     if ((_M_column + __length < _M_max_length)
642         || (__length >= _M_max_length && _M_column == 1)) 
643       {
644         // If this isn't the first line, indent
645         if (_M_column == 1 && !_M_first_line)
646           {
647             char __spacing[_M_indent + 1];
648             for (int i = 0; i < _M_indent; ++i)
649               __spacing[i] = ' ';
650             __spacing[_M_indent] = '\0';
651             fprintf(stderr, "%s", __spacing);
652             _M_column += _M_indent;
653           }
654         
655         fprintf(stderr, "%s", __word);
656         _M_column += __length;
657         
658         if (__word[__length - 1] == '\n') 
659           {
660             _M_first_line = false;
661             _M_column = 1;
662           }
663       }
664     else
665       {
666         _M_column = 1;
667         _M_print_word("\n");
668         _M_print_word(__word);
669       }
670   }
671   
672   void
673   _Error_formatter::
674   _M_print_string(const char* __string) const
675   {
676     const char* __start = __string;
677     const char* __finish = __start;
678     const int __bufsize = 128;
679     char __buf[__bufsize];
680
681     while (*__start)
682       {
683         if (*__start != '%')
684           {
685             // [__start, __finish) denotes the next word
686             __finish = __start;
687             while (isalnum(*__finish))
688               ++__finish;
689             if (__start == __finish)
690               ++__finish;
691             if (isspace(*__finish))
692               ++__finish;
693             
694             const ptrdiff_t __len = __finish - __start;
695             assert(__len < __bufsize);
696             memcpy(__buf, __start, __len);
697             __buf[__len] = '\0';
698             _M_print_word(__buf);
699             __start = __finish;
700             
701             // Skip extra whitespace
702             while (*__start == ' ') 
703               ++__start;
704             
705             continue;
706           } 
707         
708         ++__start;
709         assert(*__start);
710         if (*__start == '%')
711           {
712             _M_print_word("%");
713             ++__start;
714             continue;
715           }
716         
717         // Get the parameter number
718         assert(*__start >= '1' && *__start <= '9');
719         size_t __param = *__start - '0';
720         --__param;
721         assert(__param < _M_num_parameters);
722       
723         // '.' separates the parameter number from the field
724         // name, if there is one.
725         ++__start;
726         if (*__start != '.')
727           {
728             assert(*__start == ';');
729             ++__start;
730             __buf[0] = '\0';
731             if (_M_parameters[__param]._M_kind == _Parameter::__integer)
732               {
733                 _M_format_word(__buf, __bufsize, "%ld", 
734                                _M_parameters[__param]._M_variant._M_integer._M_value);
735                 _M_print_word(__buf);
736               }
737             else if (_M_parameters[__param]._M_kind == _Parameter::__string)
738               _M_print_string(_M_parameters[__param]._M_variant._M_string._M_value);
739             continue;
740           }
741         
742         // Extract the field name we want
743         enum { __max_field_len = 16 };
744         char __field[__max_field_len];
745         int __field_idx = 0;
746         ++__start;
747         while (*__start != ';')
748           {
749             assert(*__start);
750             assert(__field_idx < __max_field_len-1);
751             __field[__field_idx++] = *__start++;
752           }
753         ++__start;
754         __field[__field_idx] = 0;
755         
756         _M_parameters[__param]._M_print_field(this, __field);             
757       }
758   }
759
760   void
761   _Error_formatter::_M_get_max_length() const throw ()
762   {
763     const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
764     if (__nptr)
765       {
766         char* __endptr;
767         const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
768         if (*__nptr != '\0' && *__endptr == '\0')
769           _M_max_length = __ret;
770       }
771   }
772
773   // Instantiations.
774   template
775     void
776     _Error_formatter::_M_format_word(char*, int, const char*, 
777                                      const void*) const;
778
779   template
780     void
781     _Error_formatter::_M_format_word(char*, int, const char*, long) const;
782
783   template
784     void
785     _Error_formatter::_M_format_word(char*, int, const char*, 
786                                      std::size_t) const;
787
788   template
789     void
790     _Error_formatter::_M_format_word(char*, int, const char*, 
791                                      const char*) const;
792 } // namespace __gnu_debug