home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / value-read.C < prev    next >
C/C++ Source or Header  |  1998-10-23  |  23KB  |  980 lines

  1. // $Id: value-read.C,v 1.86 1998/10/23 21:58:42 zeller Exp $
  2. // Read variable values in string representation
  3.  
  4. // Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>
  6. // and Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  7. // 
  8. // This file is part of DDD.
  9. // 
  10. // DDD is free software; you can redistribute it and/or
  11. // modify it under the terms of the GNU General Public
  12. // License as published by the Free Software Foundation; either
  13. // version 2 of the License, or (at your option) any later version.
  14. // 
  15. // DDD is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18. // See the GNU General Public License for more details.
  19. // 
  20. // You should have received a copy of the GNU General Public
  21. // License along with DDD -- see the file COPYING.
  22. // If not, write to the Free Software Foundation, Inc.,
  23. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  24. // 
  25. // DDD is the data display debugger.
  26. // For details, see the DDD World-Wide-Web page, 
  27. // `http://www.cs.tu-bs.de/softech/ddd/',
  28. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  29.  
  30. char value_read_rcsid[] =
  31.     "$Id: value-read.C,v 1.86 1998/10/23 21:58:42 zeller Exp $";
  32.  
  33. #ifdef __GNUG__
  34. #pragma implementation
  35. #endif
  36.  
  37. #ifndef LOG_DETERMINE_TYPE
  38. #define LOG_DETERMINE_TYPE 0
  39. #endif
  40.  
  41. //-----------------------------------------------------------------------------
  42. // Read variable values in string representation
  43. //-----------------------------------------------------------------------------
  44.  
  45. #include "value-read.h"
  46. #include <ctype.h>
  47.  
  48. #include "string-fun.h"
  49. #include "assert.h"
  50. #include "comm-manag.h"
  51. #include "cook.h"
  52. #include "ddd.h"
  53. #include "regexps.h"
  54. #include "GDBAgent.h"
  55. #include "PosBuffer.h"
  56.  
  57. static void read_token(const char *value, int& pos);
  58. static void read_leading_junk(string& value);
  59. static void read_leading_comment(string& value);
  60.  
  61. //-----------------------------------------------------------------------------
  62.  
  63. #if RUNTIME_REGEX
  64. static regex rxindex("[[]-?[0-9][0-9]*].*");
  65. static regex rxvtable(
  66.     RXADDRESS " <[^ \n>]* v(irtual )?t(a)?bl(e)?>[^{},]*[{].*");
  67. static regex rxdbx_baseclass("[ \t\n]*[a-zA-Z_$][^({\n=]*:[(]");
  68. #endif
  69.  
  70. // Determine the type of VALUE.
  71. static DispValueType _determine_type (string& value)
  72. {
  73.     strip_leading_space(value);
  74.  
  75.     // DBX on DEC prepends `[N]' before array member N
  76.     if (value.matches(rxindex))
  77.     value = value.after(']');
  78.  
  79.     // References.
  80.     if (value.contains('(', 0))
  81.     {
  82.     int ref_index = value.index(')') + 1;
  83.     while (ref_index < int(value.length()) && isspace(value[ref_index]))
  84.         ref_index++;
  85. #if RUNTIME_REGEX
  86.     static regex rxreference(
  87.         "@ *(0(0|x)[0-9a-f]+|[(]nil[)]) *:.*");
  88. #endif
  89.     if (value.matches(rxreference, ref_index))
  90.         return Reference;
  91.     }
  92.  
  93.     // Vtables.
  94.     if (value.matches(rxvtable))
  95.     return Array;
  96.  
  97.     // Scalars.
  98.     if (gdb->has_scalars())
  99.     {
  100.     // DBX uses this representation for out-of-range Pascal/Modula-2
  101.     // enumerations.
  102.     if (value.contains("(scalar = ", 0))
  103.         return Simple;
  104.     }
  105.  
  106.     // AIX DBX prepends `BASECLASS:' before base class structs.
  107.     if (value.contains(rxdbx_baseclass, 0))
  108.     return Struct;
  109.  
  110.     // Structs.
  111.     // XDB and JDB prepend the address before each struct.  JDB also
  112.     // prepends the class name.
  113. #if RUNTIME_REGEX
  114.     static regex rxstruct_begin(
  115.     "(" RXADDRESS ")? *"
  116.     "([(]|[{]|record\n|RECORD\n|RECORD |OBJECT "
  117.     "|struct|class|union).*");
  118.     static regex rxstruct_end("([)]|[}]|end\n|END\n|end;|END;)");
  119. #endif
  120.  
  121.     if (value.matches(rxstruct_begin))
  122.     {
  123.     // Check for empty struct.
  124.     char *v = value;
  125.     string addr;
  126.     bool ok = (read_struct_begin(value, addr) && 
  127.            value.contains(rxstruct_end, 0));
  128.     value = v;
  129.     if (ok)
  130.         return Struct;
  131.  
  132.     // Check for leading keywords.
  133. #if RUNTIME_REGEX
  134.     static regex rxstruct_keyword_begin(
  135.         "(" RXADDRESS ")? *"
  136.         "(record\n|RECORD\n|RECORD |OBJECT "
  137.         "|struct|class|union).*");
  138. #endif
  139.     if (value.matches(rxstruct_keyword_begin))
  140.         return Struct;
  141.  
  142.     // Check for leading braces.  DEC DBX uses `{' for arrays as
  143.     // well as for structs; likewise, AIX DBX uses `(' for arrays
  144.     // and structs.  To disambiguate between arrays and structs,
  145.     // we check for some struct member -- that is, a ` = ' before
  146.     // any other sub-struct or struct end.
  147.  
  148.     // Go behind leading `{' or '('
  149.     int i = 0;
  150.     while (i < int(value.length()) && value[i] != '(' && value[i] != '{')
  151.         i++;
  152.     i++;
  153.  
  154.     // Check for further `{' or '('
  155.     while (i < int(value.length()))
  156.     {
  157.         switch(value[i++])
  158.         {
  159.         case ':':
  160.         if (gdb->program_language() == LANGUAGE_JAVA)
  161.             return Struct;
  162.         break;
  163.  
  164.         case '=':
  165.         {
  166.         // We have a member.
  167.         //
  168.         // DEC DBX issues arrays of strings as
  169.         //
  170.         //     {
  171.         //         [0] 0x400188 = "Pioneering"
  172.         //         [1] 0x10000dd0 = "women"
  173.         //         [2] 0x10000dcc = "in"
  174.         //     }
  175.         //
  176.         // Avoid interpreting these addresses as struct members.
  177.  
  178.         int j = i - 2;    // Character before `='
  179.         while (j >= 0 && isspace(value[j]))
  180.             j--;
  181.         int end_of_member_name = j + 1;
  182.         while (j >= 0 && !isspace(value[j]))
  183.             j--;
  184.         j++;
  185.         string first_member = value(j, end_of_member_name - j);
  186.         strip_space(first_member);
  187.         if (first_member.contains(rxint, 0) || 
  188.             first_member.contains(rxaddress, 0))
  189.         {
  190.             // The first `member' is a number or an address.
  191.             // This is not a struct; it's an array.
  192.             return Array;
  193.         }
  194.  
  195.         // In all other cases, we have a struct.
  196.         return Struct;
  197.         }
  198.  
  199.         case '(':
  200.         case '{':
  201.         case ')':
  202.         case '}':
  203.         goto next;        // Something else, possibly an array
  204.         }
  205.     }
  206.     next: ;
  207.     }
  208.  
  209.     // Pointers.
  210.  
  211.     int pointer_index = 0;
  212.     if (gdb->has_typed_pointers() &&
  213.     (value.contains('(', 0) || value.contains('{', 0)))
  214.     {
  215.     // GDB and JDB prepend the exact pointer type enclosed in
  216.     // `(...)'.  If the pointer type contains `(...)' itself (such
  217.     // as in pointers to functions), GDB uses '{...}' instead (as
  218.     // in `{int ()} 0x2908 <main>').
  219.  
  220.     read_token(value, pointer_index);
  221.     while (pointer_index < int(value.length()) && 
  222.            isspace(value[pointer_index]))
  223.         pointer_index++;
  224.     }
  225.  
  226.     int addr_len = rxaddress.match(value, value.length(), pointer_index);
  227.     if (addr_len > 0)
  228.     {
  229.     // We have an address.
  230.     // In JDB, an address may still be followed by a struct.
  231.     int brace = pointer_index + addr_len;
  232.     while (brace < int(value.length()) && isspace(value[brace]))
  233.         brace++;
  234.     if (brace < int(value.length()) && value[brace] == '{')
  235.     {
  236.         int nl = value.index('\n', pointer_index + addr_len);
  237.         if (nl >= 0 && brace < nl)
  238.         return Struct;
  239.     }
  240.  
  241.     // We have an ordinary pointer
  242.     return Pointer;
  243.     }
  244.  
  245.     // In GDB and JDB, Java pointers may be printed as `[TYPE]@ADDR'
  246.     int at_index = value.index('@');
  247.     if (at_index >= 0)
  248.     {
  249.     string id   = value.before(at_index);
  250.     string addr = value.from(at_index);
  251.     if (id.matches(rxidentifier) && addr.contains(rxaddress, 0))
  252.     {
  253.         // We have a Java pointer
  254.         return Pointer;
  255.     }
  256.     }
  257.  
  258.     // In Perl, pointers are printed as `TYPE(ADDR)'
  259.     if (value.contains(rxperlref, 0))
  260.     return Pointer;
  261.  
  262.     // Arrays.
  263.     if (value.contains('{', 0))
  264.     return Array;
  265.     if (value.contains('[', 0))
  266.     return Array;
  267.     if (value.contains('(', 0))
  268.     return Array;
  269.  
  270.     // Simple values.
  271.     // Everything else failed - assume simple value.
  272.     return Simple;
  273. }
  274.  
  275. DispValueType determine_type(const string& value)
  276. {
  277. #if LOG_DETERMINE_TYPE
  278.     clog << quote(value);
  279. #endif
  280.  
  281.     char *v = value;
  282.     DispValueType type = _determine_type((string &)value);
  283.     ((string &)value) = v;
  284.  
  285. #if LOG_DETERMINE_TYPE
  286.     clog << " has type " << type << "\n";
  287. #endif
  288.  
  289.     return type;
  290. }
  291.  
  292.  
  293. // Read tokens up to character DELIM
  294. static bool read_up_to(const char *value, int& pos, char delim)
  295. {
  296.     if (value[pos] == '\0')
  297.     return false;
  298.  
  299.     // Add opening delimiter
  300.     pos++;
  301.  
  302.     // Read up to closing delimiter
  303.     while (value[pos] && value[pos] != delim)
  304.     read_token(value, pos);
  305.  
  306.     if (value[pos] == '\0')
  307.     return false;
  308.  
  309.     // Add closing delimiter
  310.     pos++;
  311.  
  312.     return true;
  313. }
  314.  
  315. // Read tokens up to word DELIM
  316. static bool read_up_to(const char *value, int& pos, char* delim)
  317. {
  318.     if (value[pos] == '\0')
  319.     return false;
  320.  
  321.     int len = strlen(delim);
  322.  
  323.     // Read up to closing delimiter
  324.     while (value[pos] && strncmp(value + pos, delim, len))
  325.     read_token(value, pos);
  326.  
  327.     if (value[pos] == '\0')
  328.     return false;
  329.  
  330.     // Add closing delimiter
  331.     pos += len;
  332.  
  333.     return true;
  334. }
  335.  
  336. // Read a string enclosed in DELIM.  We do accept `\n' in strings.
  337. static bool read_string(const char *value, int& pos, char delim)
  338. {
  339.     if (value[pos] == '\0')
  340.     return false;
  341.  
  342.     // Add opening delimiter
  343.     pos++;
  344.  
  345.     // Read up to closing delimiter
  346.     while (value[pos] != '\0')
  347.     {
  348.     if (value[pos] == '\\' && value[pos + 1] != '\0')
  349.         pos += 2;
  350.     else if (value[pos] == delim)
  351.         break;
  352.     else
  353.         pos++;
  354.     }
  355.  
  356.     if (value[pos] == '\0')
  357.     return false;        // Could not find end
  358.  
  359.     // Add closing delimiter
  360.     pos++;
  361.  
  362.     return true;
  363. }
  364.  
  365.  
  366. // Read a C-like token.
  367. static void read_token(const char *value, int& pos)
  368. {
  369.     if (value[pos] == '\0')
  370.     return;
  371.  
  372.     int start = pos;
  373.     bool ok = true;
  374.  
  375.     string token;
  376.     
  377.     switch (value[pos])
  378.     {
  379.     case '\\':
  380.     if (value[pos + 1] != '\0')
  381.         pos += 2;
  382.     else
  383.         pos++;
  384.     break;
  385.  
  386.     case '(':
  387.     ok = read_up_to(value, pos, ')');
  388.     break;
  389.  
  390.     case '[':
  391.     ok = read_up_to(value, pos, ']');
  392.     break;
  393.  
  394.     case '{':
  395.     ok = read_up_to(value, pos, '}');
  396.     break;
  397.  
  398.     case '\"':
  399.     case '\'':
  400.     ok = read_string(value, pos, value[pos]);
  401.     break;
  402.  
  403.     case '<':
  404.     if (gdb->has_print_r_option())
  405.     {
  406.         // David Kirwan <David-Kirwan@vertel.com> reports that SUN
  407.         // DBX 3.0 has trouble issuing templates - the closing `>'
  408.         // is missing, as in `TSL_map<unsigned = { ...'.  Hence,
  409.         // don't check for the closing `>'.
  410.         pos++;
  411.     }
  412.     else
  413.     {
  414.         ok = read_up_to(value, pos, '>');
  415.     }
  416.     break;
  417.  
  418.     default:
  419.     if (isalnum(value[pos]))
  420.     {
  421.         // Name or number
  422.         int start = pos;
  423.         pos++;
  424.         while (isalnum(value[pos]))
  425.         pos++;
  426.  
  427.         if (gdb->program_language() != LANGUAGE_JAVA)
  428.         {
  429.         string name(value + start, pos - start);
  430.         if (name == "record")
  431.             read_up_to(value, pos, "end");
  432.         else if (name == "RECORD")
  433.             read_up_to(value, pos, "END");
  434.         else if (name == "OBJECT")
  435.             read_up_to(value, pos, "END");
  436.         }
  437.     }
  438.     else if (isspace(value[0]))
  439.     {
  440.         // Whitespace
  441.         pos++;
  442.         while (isspace(value[pos]))
  443.         pos++;
  444.     }
  445.     else
  446.     {
  447.         // Single-character token
  448.         pos++;
  449.     }
  450.     break;
  451.     }
  452.  
  453.     if (!ok)
  454.     {
  455.     // Could not find closing delimiter.  Treat as one-character token.
  456.     pos = start + 1;
  457.     }
  458. }
  459.  
  460. // Read next token from VALUE.
  461. string read_token(string& value)
  462. {
  463.     if (value == "")
  464.     return "";
  465.  
  466.     int pos = 0;
  467.     read_token(value, pos);
  468.     string token = string(value, pos);
  469.     value = value.from(pos);
  470.  
  471.     // clog << "read_token() = " << quote(token) << "\n";
  472.     return token;
  473. }
  474.  
  475. bool is_ending(const string& value)
  476. {
  477.     int i = 0;
  478.     while (i < int(value.length()) && isspace(value[i]))
  479.     i++;
  480.     if (i >= int(value.length()))
  481.     return false;        // At end of value
  482.  
  483.     return value.contains('}', i)
  484.     || value.contains(')', i)
  485.     || value.contains(']', i)
  486.     || value.contains("end\n", i)
  487.     || value.contains("END\n", i)
  488.     || value.from(i) == "end"
  489.     || value.from(i) == "END";
  490. }
  491.  
  492. bool is_delimited(const string& value)
  493. {
  494.     if (value.contains('\n', 0)
  495.     || value.contains(',', 0)
  496.     || value.contains(';', 0)
  497.     || value == ""
  498.     || value.matches(rxwhite))
  499.     return true;
  500.  
  501.     return is_ending(value);
  502. }
  503.  
  504. // Read a simple value from VALUE.
  505. string read_simple_value(string& value, int depth, bool ignore_repeats)
  506. {
  507.     // Read values up to [)}],\n]
  508.  
  509.     read_leading_junk(value);
  510.  
  511.     string ret = "";
  512.     while (value != "" && value[0] != '\n' && 
  513.        (depth == 0 || (!is_delimited(value))))
  514.     {
  515.     ret += read_token(value);
  516.  
  517.     if (ignore_repeats)
  518.     {
  519.         // Don't read in `<repeats N times>'
  520.         int index = 0;
  521.         while (index < int(value.length()) && isspace(value[index]))
  522.         index++;
  523.  
  524.         if (index < int(value.length()) && 
  525.         value.contains('<', index) && 
  526.         value.contains(rxrepeats, index))
  527.         break;
  528.     }
  529.     }
  530.  
  531.     strip_trailing_space(ret);
  532.  
  533.     // clog << "read_simple_value() = " << quote(ret) << "\n";
  534.     return ret;
  535. }
  536.  
  537. // Read a pointer value.
  538. string read_pointer_value (string& value, bool ignore_repeats)
  539. {
  540.     return read_simple_value(value, 1, ignore_repeats);
  541. }
  542.  
  543. // Read the beginning of an array from VALUE.  Return false iff failure.
  544. bool read_array_begin(string& value, string& addr)
  545. {
  546.     addr = "";
  547.     strip_leading_space(value);
  548.  
  549.     // GDB has a special format for vtables
  550.     if (value.matches(rxvtable))
  551.     value = value.from("{");
  552.  
  553.     int pointer_index = 0;
  554.     if (gdb->has_typed_structs() && value.contains('(', 0))
  555.     {
  556.     // JDB prepends the array type and address, as in 
  557.     // `list = (List)0x4070ee90 { ... }'.  Skip the type.
  558.     read_token(value, pointer_index);
  559.     while (pointer_index < int(value.length()) && 
  560.            isspace(value[pointer_index]))
  561.         pointer_index++;
  562.     }
  563.  
  564.     // XDB and JDB prepend the address before each struct.  Save it.
  565.     int addr_len = rxaddress.match(value, value.length(), pointer_index);
  566.     if (addr_len > 0)
  567.     {
  568.     addr  = value.at(pointer_index, addr_len);
  569.     value = value.after(pointer_index + addr_len);
  570.     strip_leading_space(value);
  571.     }
  572.  
  573.     // DBX on DEC prepends `struct' or `class' before each struct;
  574.     // XDB also appends the struct type name.
  575.     if (value.contains("struct", 0)
  576.     || value.contains("class", 0)
  577.     || value.contains("union", 0))
  578.     value = value.from('{');
  579.  
  580.     if (value.contains('{', 0))
  581.     value = value.after(0);
  582.     else if (value.contains('(', 0))
  583.     value = value.after(0);
  584.     else if (value.contains('[', 0))
  585.     value = value.after(0);
  586.     else if (value.contains("record", 0))
  587.     value = value.after("record");
  588.     else if (value.contains("RECORD", 0))
  589.     value = value.after("RECORD");
  590.     else if (value.contains("OBJECT", 0))
  591.     value = value.after("OBJECT");
  592.     else
  593.     return false;
  594.  
  595.     strip_leading_space (value);
  596.  
  597.     // DBX on DEC prepends `[N]' before array member N
  598.     if (value.matches(rxindex))
  599.     value = value.after(']');
  600.  
  601.     return true;
  602. }
  603.  
  604. // Read next array element from VALUE.  Return false iff done.
  605. bool read_array_next(string& value)
  606. {
  607.     read_leading_junk(value);
  608.  
  609.     // DBX on DEC prepends `[N]' before array member N
  610.     if (value.matches(rxindex))
  611.     {
  612.     value = value.after(']');
  613.     read_leading_junk(value);
  614.     }
  615.  
  616.     // XDB and M3GDB append `;' after each struct element; others use `,'
  617.     if (value.contains(',', 0) || value.contains(';', 0))
  618.     {
  619.     value = value.after(0);
  620.     read_leading_junk (value);
  621.     return value != "" 
  622.         && !value.contains("END", 0)
  623.         && !value.contains('}', 0)
  624.         && !value.contains(')', 0)
  625.         && !value.contains(']', 0); // More stuff follows
  626.     }
  627.  
  628.     if (value.contains('{', 0)
  629.     || value.contains('(', 0)
  630.     || value.contains('[', 0)
  631.     || value.contains("record\n", 0)
  632.     || value.contains("RECORD\n", 0)
  633.     || value.contains("OBJECT\n", 0))
  634.     {
  635.     // DBX on Solaris issues arrays of structs without special delimiter
  636.     return true;
  637.     }
  638.  
  639.     return value != "" && !is_ending(value);
  640. }
  641.  
  642. // Read end of array from VALUE.  Return false iff done.
  643. void read_array_end(string& value)
  644. {
  645.     read_leading_junk(value);
  646.  
  647.     if (value.contains("end\n", 0))
  648.     {
  649.     value = value.after("end");
  650.     return;
  651.     }
  652.  
  653.     if (value.contains("END\n", 0))
  654.     {
  655.     value = value.after("END");
  656.     return;
  657.     }
  658.  
  659.     if (value.contains("END;", 0))
  660.     {
  661.     value = value.after("END");
  662.     return;
  663.     }
  664.  
  665.     if (value.contains('}', 0)
  666.     || value.contains(')', 0)
  667.     || value.contains(']', 0))
  668.     {
  669.     value = value.after(0);
  670.  
  671.     // XDB appends `;' after each struct
  672.     if (value.contains(';', 0))
  673.         value = value.after(0);
  674.  
  675.     return;
  676.     }
  677. }
  678.  
  679. // Read `<repeats N times>'; return N (1 if no repeat)
  680. int read_repeats(string& value)
  681. {
  682.     int repeats = 1;
  683.  
  684.     strip_leading_space(value);
  685.     if (value.contains('<', 0) && value.contains(rxrepeats, 0))
  686.     {
  687.     value = value.from(rxint);
  688.     repeats = atoi(value);
  689.     value = value.after('>');
  690.     }
  691.  
  692.     return repeats;
  693. }
  694.  
  695. // Read the beginning of a struct from VALUE.  Return false iff done.
  696. bool read_struct_begin (string& value, string& addr)
  697. {
  698.     return read_array_begin(value, addr);
  699. }
  700.  
  701. // Read next struct element from VALUE.  Return false iff done.
  702. bool read_struct_next (string& value)
  703. {
  704.     return read_array_next(value);
  705. }
  706.  
  707. // Read end of struct from VALUE.  Return false iff done.
  708. void read_struct_end(string& value)
  709. {
  710.     read_array_end(value);
  711. }
  712.  
  713. // Some DBXes issue the local variables via a frame line, just like
  714. // `set_date(d = 0x10003060, day_of_week = Sat, day = 24, month = 12,
  715. // year = 1994) LOCATION', where LOCATION is either `[FRAME]' (DEC
  716. // DBX) or `, line N in FILE' (AIX DBX).  Make this more readable.
  717. void munch_dump_line (string& value)
  718. {
  719.     if (gdb->type() == DBX)
  720.     {
  721.     string initial_line = value.before('\n');
  722.     strip_trailing_space(initial_line);
  723.  
  724. #if RUNTIME_REGEX
  725.     static regex rxdbxframe("[a-zA-Z_$][a-zA-Z_$0-9]*[(].*[)].*"
  726.                 "([[].*[]]|, line .*)");
  727. #endif
  728.     if (initial_line.matches(rxdbxframe))
  729.     {
  730.         // Strip enclosing parentheses
  731.         initial_line = initial_line.after('(');
  732.         int index = initial_line.index(')', -1);
  733.         initial_line = initial_line.before(index);
  734.  
  735.         // Place one arg per line
  736.         initial_line.gsub(", ", "\n");
  737.  
  738.         value = initial_line + value.from('\n');
  739.     }
  740.     }
  741. }
  742.  
  743. // Skip `members of SUBCLASS:' in VALUE.  Return false iff failure.
  744. bool read_members_prefix (string& value)
  745. {
  746. #if RUNTIME_REGEX
  747.     static regex rxmembers_of_nl("members of [^\n]+: ?\n");
  748. #endif
  749.  
  750.     read_leading_junk(value);
  751.     if (value.contains(rxmembers_of_nl, 0))
  752.     {
  753.     value = value.after('\n');
  754.     return true;
  755.     }
  756.  
  757.     return false;
  758. }
  759.  
  760.  
  761. // Read member name; return "" upon error
  762. string read_member_name (string& value)
  763. {
  764.     read_leading_junk(value);
  765.  
  766.     if (value.contains(')', 0)
  767.     || value.contains('}', 0)
  768.     || value.contains(']', 0)
  769.     || value.contains(',', 0))
  770.     {
  771.     // No value
  772.     return "";
  773.     }
  774.  
  775.     if (value.contains('(', 0)
  776.     || value.contains('{', 0)
  777.     || value.contains('[', 0))
  778.     {
  779.     // No value
  780.     return "";
  781.     }
  782.  
  783.     if (value.contains('=', 0))
  784.     {
  785.     // Missing member name: anonymous union or likewise
  786.     value = value.after(0);
  787.     read_leading_junk(value);
  788.     return " ";
  789.     }
  790.  
  791.     if (value.contains(rxdbx_baseclass, 0))
  792.     {
  793.     // AIX DBX base class name
  794.     string base = value.before(":(");
  795.     value = value.from("(");
  796.  
  797.     // Simulate GDB base class name
  798.     return "<" + base + ">";
  799.     }
  800.  
  801.     string v;
  802.     if (value.contains('\n'))
  803.     v = value.before('\n');
  804.     else
  805.     v = value;
  806.  
  807.     bool strip_qualifiers = true;
  808.  
  809.     // GDB, DBX, and XDB separate member names and values by ` = '; 
  810.     // GDB using the Java language uses `: ' instead.
  811.     // JDB printing classes uses `:\n' for the interface list.
  812.     // GDB with GNAT support and Perl use `=> '.
  813.     string member_name;
  814.     string sep = gdb->member_separator();
  815.     string sepnl = sep;
  816.     strip_trailing_space(sepnl);
  817.     sepnl += '\n';
  818.  
  819.     if (v.contains("Virtual table at ", 0))
  820.     {
  821.     // `Virtual table at 0x1234' or likewise.  WDB gives us such things.
  822.     member_name = v.before(" at ");
  823.     value = value.after(" at ");
  824.     strip_qualifiers = false;
  825.     }
  826.     else if (v.contains(" = "))
  827.     {
  828.     member_name = v.before(" = ");
  829.     value = value.after(" = ");
  830.     }
  831.     else if (v.contains(sep))
  832.     {
  833.     member_name = v.before(sep);
  834.     value = value.after(sep);
  835.     }
  836.     else if (v.contains(sepnl))
  837.     {
  838.     member_name = v.before(sepnl);
  839.     value = value.after(sepnl);
  840.     }
  841.     else
  842.     {
  843.     // Member value in unknown format
  844.     // Should we treat this as anonymous union?  (FIXME)
  845.     return "";
  846.     }
  847.  
  848.     if (!is_BaseClass_name(member_name))
  849.     {
  850.     // Work around buggy member names as generated by Centerline CC.
  851.     // Reported by eggert@igd.fhg.de (Lars Eggert)
  852.     string m = member_name;
  853.     while (m.index("::") > 1)
  854.         m = m.after("::");
  855.     if (m.index("(") > 1)
  856.         m = m.before("(");
  857.     if (m != "")
  858.         member_name = m;
  859.     }
  860.  
  861.     read_leading_junk (member_name);
  862.  
  863.     if (member_name == "")
  864.     {
  865.     // Anonymous union
  866.     return " ";
  867.     }
  868.  
  869.     if (strip_qualifiers)
  870.     {
  871.     // Strip leading qualifiers.  <Gyula.Kun-Szabo@eth.ericsson.se>
  872.     // reports that his GDB reports static members as `static j = 45'.
  873.     // JDB also qualifies member names (`private String name = Ada`)
  874.     for (;;)
  875.     {
  876.         strip_space(member_name);
  877.         string qualifier = member_name.before(' ');
  878.         if (qualifier != "" && qualifier.matches(rxidentifier))
  879.         member_name = member_name.after(' ');
  880.         else
  881.         break;
  882.     }
  883.     }
  884.  
  885.     return member_name;
  886. }
  887.  
  888. // Read `vtable entries' prefix.  Return "" if not found.
  889. string read_vtable_entries (string& value)
  890. {
  891. #if RUNTIME_REGEX
  892.     static regex rxvtable_entries("[0-9][0-9]* vtable entries,");
  893. #endif
  894.  
  895.     strip_leading_space (value);
  896.     if (value.contains(rxvtable_entries, 0))
  897.     {
  898.     string vtable_entries = value.before(',');
  899.     value = value.after(',');
  900.     return vtable_entries;
  901.     }
  902.  
  903.     return "";
  904. }
  905.  
  906.  
  907. // Return true iff NAME is a baseclass name (enclosed in <>).
  908. bool is_BaseClass_name (const string& name)
  909. {
  910.     return name.length() >= 2
  911.     && name[0] == '<' && name[name.length() - 1] == '>';
  912. }
  913.  
  914. // Remove baseclass names. 
  915. // "foo.<Base>" becomes "foo"; "foo-><Base>" becomes "*foo"
  916. void cut_BaseClass_name (string& full_name)
  917. {
  918.     int index = full_name.index (".<", -1);
  919.     if (index > 0) {
  920.     full_name = full_name.before(index);
  921.     }
  922.     else if ((index = full_name.index ("-><", -1)) > 0) {
  923.     full_name = full_name.before(index);
  924.     full_name.prepend ("*");
  925.     }
  926. }
  927.  
  928. // Skip blanks, M3 comments, and GDB warnings
  929. static void read_leading_junk (string& value)
  930. {
  931. #if RUNTIME_REGEX
  932.     static regex rxm3comment("\\(\\*.*\\*\\).*");
  933. #endif
  934.   
  935.     strip_leading_space(value);
  936.   
  937.     while (value.matches(rxm3comment))
  938.     {
  939.     read_leading_comment(value);
  940.     strip_leading_space(value);
  941.     }
  942.  
  943.     while (value.contains("warning: ", 0))
  944.     {
  945.     value = value.after('\n');
  946.     strip_leading_space(value);
  947.     }
  948. }
  949.  
  950. // Read leading M2/M3 comment.
  951. static void read_leading_comment (string& value)
  952. {
  953.     int i = 2;
  954.     bool sf = false;
  955.  
  956.     while (i < int(value.length()))
  957.     {
  958.     switch (value[i])
  959.     {
  960.     case '*': 
  961.         sf = true;
  962.         break;
  963.  
  964.     case ')': 
  965.         if (sf)
  966.         {
  967.         value = value.from(i + 1);
  968.         return;
  969.         }
  970.  
  971.     default: 
  972.         sf = false; 
  973.         break;
  974.     }
  975.     i++;
  976.     }
  977.  
  978.     value = value.from(i);
  979. }
  980.